From henkaten-council
Use this skill to bootstrap a new henkaten-council governance baseline in a trine-eval project. Invoke it once per project before running any council review cycle. It creates the complete .council/ directory structure, seeds all required state files, writes the governance signal to .harness/config.json, and delegates initial sprint planning to /trine-eval:harness-kickoff (or /trine-eval:harness-sprint for subsequent sprints).
How this skill is triggered — by the user, by Claude, or both
Slash command
/henkaten-council:council-kickoffThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill bootstraps the complete `.council/` governance baseline for a
This skill bootstraps the complete .council/ governance baseline for a
project that is managed by the trine-eval harness. Run it once, in the target
project's root directory, before invoking any other council skill.
The kickoff skill is a procedural document — it specifies what the invoking
agent (Orchestrator) must do, in what order, with what idempotency guards. It is
not an executable script. Actual .council/ creation is performed by the
Orchestrator at runtime; end-to-end validation is covered in sprint 6 (S4).
Before writing any file, the Orchestrator must verify the environment.
If .harness/ does not exist in the project root, the council cannot function
because trine-eval has not been initialized. In this case:
/trine-eval:harness-kickoff first, then re-invoke
/henkaten-council:council-kickoff."/trine-eval:harness-kickoff now via Task dispatch?"Task to /trine-eval:harness-kickoff
and wait for completion before continuing..council/ checkIf .council/ already exists:
.council/config.json,
.council/henka-register.jsonl, 3 other files").henka-register.jsonl, decision-log.jsonl, audit-log.jsonl).
These are governance artifacts; overwriting them is an irreversible action
requiring Level 5 approval.Collect the following before writing any configuration:
package.json, pyproject.toml, or ask the user.
This becomes target_project in .council/config.json (Step 2).package.json →
javascript, pyproject.toml → python, go.mod → go, Cargo.toml →
rust). Note: this is not stored in .council/config.json — the
council-config schema has no such field. Toolchain context lives only on the
harness side: .harness/config.json's project_type is the trine-eval
rubric type (e.g. cli-tool, web-app, api-service). It is normal for the
toolchain (python) and the rubric (cli-tool) to differ; the kickoff skill
must not overwrite the harness-side value.orchestrator, architect, scope-guardian, henkaten-detector). These are
recorded in .council/council-manifest.json (Step 3). Ask if the user wants to
enable optional agents (qa-regression, rag-source).Verify that the required hooks are registered in Claude Code's hook system:
hooks/enforce-append-only.sh (or hooks/win/enforce-append-only.ps1 on
Windows) must be registered as a PreToolUse hook.hooks/enforce-reversibility.sh (or hooks/win/enforce-reversibility.ps1)
must also be registered as a PreToolUse hook.hooks/log-tool-call.sh (or hooks/win/log-tool-call.ps1) must be registered
as a PostToolUse hook.hooks/session-stopped-marker.sh (or hooks/win/session-stopped-marker.ps1)
must be registered as a Stop hook.Two registration paths are supported. Check them in order.
The plugin ships hooks/hooks.json which Claude Code reads at install time
and registers as plugin-level hooks. Verify by checking that
${CLAUDE_PLUGIN_ROOT}/hooks/hooks.json exists and declares all four required
events: PreToolUse with matcher Write|Edit, PreToolUse with matcher
Bash, PostToolUse with matcher *, and Stop. If all four are present,
the hook self-check passes — proceed to Step 1e.
If ${CLAUDE_PLUGIN_ROOT} is not resolvable (older Claude Code), or if
hooks/hooks.json is absent (pre-v0.1.2 install, or a direct-path install
that did not register plugin-level hooks), fall through to the manual
registration check in 1d.1 / 1d.2.
Read the target project's .claude/settings.local.json (creating an empty
{ "permissions": {}, "hooks": {} } object if absent) and check for a hooks
key with entries pointing at the four hook scripts above.
If hooks is absent or any of the four hooks is missing, surface the following
copyable JSON to the user as the exact registration command (this is what
goes into .claude/settings.local.json). Paths use ${CLAUDE_PLUGIN_ROOT},
which Claude Code resolves to the plugin's installed directory at hook-fire
time. If the runtime does not resolve that variable, the user should substitute
the absolute path to the plugin install (e.g.
/home/<user>/.claude/plugins/cache/henkaten-council/<version>/).
{
"permissions": { "allow": [], "ask": [], "deny": [] },
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{ "type": "command", "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/enforce-append-only.sh" }
]
},
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/enforce-reversibility.sh" }
]
}
],
"PostToolUse": [
{
"matcher": "*",
"hooks": [
{ "type": "command", "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/log-tool-call.sh" }
]
}
],
"Stop": [
{
"hooks": [
{ "type": "command", "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/session-stopped-marker.sh" }
]
}
]
}
}
On Windows targets, replace each bash ${CLAUDE_PLUGIN_ROOT}/hooks/<name>.sh
command with pwsh -NoLogo -NoProfile -File ${CLAUDE_PLUGIN_ROOT}/hooks/win/<name>.ps1.
The PowerShell hooks ship functional parity with the bash siblings per v2.1
amendment A7 — same envelope parsing, same allow/block exit codes, same audit
log entry format. The four PS1 paths are:
hooks/win/enforce-append-only.ps1 (PreToolUse matcher: Write|Edit)hooks/win/enforce-reversibility.ps1 (PreToolUse matcher: Bash)hooks/win/log-tool-call.ps1 (PostToolUse matcher: *)hooks/win/session-stopped-marker.ps1 (Stop hook)If Step 1d.0 auto-registration is unavailable and any of the four hooks
is absent from .claude/settings.local.json, do NOT proceed past Step 1d.
Report to the user:
"Hook
<name>is not registered. The council cannot enforce append-only log protection without it. Paste the snippet above into your.claude/settings.local.jsonhooksblock, then re-invoke/henkaten-council:council-kickoff."
The council-kickoff skill must never modify .claude/settings.local.json
automatically. Hook registration is a user-driven action; the skill surfaces
the snippet but does not write it.
Run the projection-cost measurement script and surface the result to the user. This step is informational only; it does not block kickoff completion.
python ${CLAUDE_PLUGIN_ROOT}/scripts/measure-projection-cost.py --json
On Windows targets, substitute python with python.exe if the bare command
is not on PATH. The script reads .claude-plugin/plugin.json from the
plugin install directory, sums per-file token estimates for the always-projected
file set (CLAUDE.md + skills + agents), and reports the total against
an 8,000-token advisory budget.
Surface to the user:
"Plugin projection-cost baseline:
<total>of 8,000 tokens (<headroom>remaining). Methodology and re-baseline rules:instructions/projection-cost.md."
If the measurement reports over_budget: true, append:
"WARNING: the always-projected surface is over budget by
<delta>tokens. Seedocs/design/adr-0002-projection-cost-budget.mdfor remediation paths (trim, promote to on-demand, or re-baseline via a follow-up ADR)."
This step is idempotent: re-running kickoff against an already-bootstrapped project re-runs the measurement and re-surfaces the result. The script does not write any files; it emits to stdout only.
.council/config.jsonWrite .council/config.json with the following content structure (idempotent:
skip if already present and idempotent mode is active):
{
"council_version": "<plugin version, e.g. 0.1.2>",
"target_project": "<detected or user-provided>",
"autonomy_level": 4,
"review_frequency": "every-sprint",
"andon_takt_seconds": 600,
"dynamic_autonomy_thresholds": {
"andon_stop_distinct_originators_required": 2,
"andon_stop_consecutive_count": 3,
"consecutive_sprint_fails_for_floor_drop": 2
}
}
Key values to note:
council_version is the plugin version (e.g. 0.1.2); target_project is
the project name gathered in Step 1c. The agent roster lives in
council-manifest.json (Step 3), not here, and the toolchain project_type
is harness-side (.harness/config.json) — neither belongs in
council-config (the schema is additionalProperties: false).andon_takt_seconds: 600 — raised from 300 per v2.1 amendment A6. This is
the maximum wall-clock seconds the Orchestrator waits for swarm agents to
respond to an andon_signal: alert before timing out and escalating.andon_stop_distinct_originators_required: 2 — per v2.1 amendment A2, a
dynamic autonomy floor drop triggered by andon stops requires the stops to
originate from at least 2 distinct agent identities. Same-agent repeated
stops are tracked as quality-defect-anomaly henkaten records, not floor-drop
triggers.Schema reference: schemas/council-config.schema.json
.council/council-manifest.jsonWrite .council/council-manifest.json (idempotent):
{
"manifest_version": "<plugin version, e.g. 0.1.2>",
"created_at": "<ISO-8601-now>",
"plugin_version": "<plugin version, e.g. 0.1.2>",
"council_state_path": ".council/",
"active_sprint": null,
"agents": [
{
"agent_id": "orchestrator",
"agent_file": "agents/orchestrator.md",
"autonomy_level": 4,
"status": "active",
"context": "inherit",
"tools": ["Read", "Glob", "Grep", "Bash", "Write", "Task"],
"in_default_fanout": true
},
{
"agent_id": "architect",
"agent_file": "agents/architect.md",
"autonomy_level": 2,
"status": "active",
"context": "fork",
"tools": ["Read", "Glob", "Grep"],
"in_default_fanout": true
},
{
"agent_id": "scope-guardian",
"agent_file": "agents/scope-guardian.md",
"autonomy_level": 2,
"status": "active",
"context": "fork",
"tools": ["Read", "Glob", "Grep"],
"in_default_fanout": true
},
{
"agent_id": "henkaten-detector",
"agent_file": "agents/henkaten-detector.md",
"autonomy_level": 1,
"status": "active",
"context": "fork",
"tools": ["Read", "Glob", "Grep"],
"in_default_fanout": true
}
]
}
The agent role/name labels from earlier drafts are not part of the schema;
the manifest keys an agent by agent_id and records its autonomy_level and
status. context, tools, and in_default_fanout are optional but
recommended (they mirror the agent contracts).
Schema reference: schemas/council-manifest.schema.json
The three governance logs are append-only. Apply the following idempotency rule: create if the file does not exist; never overwrite if it does (unless the user explicitly chose full-overwrite in Step 1b and confirmed the irreversible action).
henka-register.jsonlIf .council/henka-register.jsonl does not exist: create an empty file.
Do not write any seed record; the first henkaten record will be appended by
scripts/append-henka.py when the first change point is detected.
decision-log.jsonlIf .council/decision-log.jsonl does not exist: create the file with a
single seed entry representing the kickoff decision:
{"decision_id":"DEC-0001","timestamp":"<ISO-8601-now>","decision_type":"kickoff","decision_outcome":"applied","council_agents_involved":["orchestrator"],"evidence_cited":[],"applied_automatically":true,"user_approval_required":false,"affected_files":[".council/config.json",".council/council-manifest.json"],"sprint_context":0,"autonomy_level_used":4,"effective_autonomy_at_decision":4,"reversibility":"reversible","nemawashi_walkthrough_version":null,"description":"Council baseline created (kickoff)."}
audit-log.jsonlIf .council/audit-log.jsonl does not exist: create an empty file. The
hooks/log-tool-call.sh hook will populate it at runtime.
.council/standard-work.jsonWrite .council/standard-work.json with a seed baseline (idempotent). The
schema requires a non-empty procedures array (see the negative fixture
tests/schemas/standard-work/invalid/empty-procedures.json), so seed one
bootstrap procedure:
{
"version": "1.0.0",
"updated_at": "<ISO-8601-now>",
"updated_by": "council-kickoff",
"procedures": [
{
"procedure_id": "PROC-001",
"name": "Council baseline kickoff",
"steps": [
"Read .harness/spec.md and .harness/sprints.json to establish sprint context",
"Verify the .council/ governance baseline exists (config, manifest, append-only logs, state)",
"Run /henkaten-council:council-autorun per sprint to fan out the council review"
]
}
]
}
Schema reference: schemas/standard-work.schema.json
Create the following six directories under .council/ if they do not already
exist (idempotent — mkdir -p semantics, no error if present):
.council/course-corrections/.council/proposed/.council/proposed/archive/.council/retrospectives/.council/sessions/.council/state/The proposed/archive/ path is required by v2.1 amendment A4: after a position
paper is ratified via the nemawashi walkthrough (Step 1D in the autorun skill),
the position paper file is moved from proposed/ to proposed/archive/. This
preserves the nemawashi_walkthrough_version path reference in the
decision-log.jsonl entry indefinitely. If the archive directory were absent,
ratified-paper paths would resolve to 404 errors during later audit reviews.
The state/ directory is required because state/effective-autonomy.json is
written in Step 7 below. It must exist before that write.
.council/state/effective-autonomy.jsonWrite the initial autonomy state file (idempotent: skip if already present in idempotent mode):
{
"level": 4,
"last_change": "<ISO-8601-now>",
"reason": "initial",
"restored_when": null,
"trigger_history": []
}
Key values:
level: 4 — default is Level 4 (Coordinate Sequences Under Supervision).
This matches the Orchestrator's designation in agents/orchestrator.md.trigger_history: [] — initialized as an empty array. The
scripts/update-effective-autonomy.py script (Sprint 4 deliverable) appends
entries here on every floor change. Entries track what event triggered the
change, the timestamp, and the originating agent.Schema reference: schemas/effective-autonomy.schema.json
The file path state/effective-autonomy.json (relative to .council/) is the
canonical location. The Orchestrator reads this file at the start of every
sprint loop iteration.
.harness/config.jsonWrite (or merge) the governance block into .harness/config.json. Use
scripts/inject-governance.py rather than hand-editing the file — manual
JSON merge is error-prone and can corrupt unrelated harness keys (mode,
project_type, components_enabled, etc.). The helper script preserves every
key the harness owns and only updates governance.
python ${CLAUDE_PLUGIN_ROOT}/scripts/inject-governance.py --file .harness/config.json
The script is idempotent: a second invocation when the governance block already
matches exits 0 with OK: governance block already correct. If the user has
previously set governance.enabled: false (opt-out), the script preserves that
setting and exits 2 with a warning — the council-kickoff skill should treat
this as a user-driven veto and not override it.
The block written has the following shape:
{
"governance": {
"enabled": true,
"plugin": "henkaten-council",
"council_state_path": ".council/",
"review_frequency": "every-sprint"
}
}
This signal tells the trine-eval harness that the henkaten-council plugin
is active for this project. Trine-eval reads governance.enabled before
deciding whether to include governance report sections in sprint evaluation
output.
Note: .harness/config.json is the only .harness/ file that the council
plugin writes to. The sacred files (.harness/spec.md, .harness/features.json,
.harness/sprints.json) are read-only from the council's perspective and require
Level 5 approval to modify (see instructions/controlled-artifacts.md).
After the council baseline is in place, delegate to trine-eval for harness
initialization or sprint evaluation via Task:
.harness/spec.md does not yet exist): call
/trine-eval:harness-kickoff to produce .harness/spec.md,
.harness/features.json, and .harness/sprints.json./trine-eval:harness-sprint NN where NN is the sprint number being
evaluated.The delegation syntax for the Orchestrator is a Task call, not a direct
invocation:
Task: /trine-eval:harness-kickoff
or
Task: /trine-eval:harness-sprint 01
The council-kickoff skill does not implement trine-eval logic. It delegates and waits for the result before continuing to Step 10.
Display the following one-time setup note to the user after all files are written:
One-time setup note:
git mergeis in thedenytier by default in.claude/settings.json. This means the Orchestrator will never propose or execute a merge without your explicit override. If you want the Orchestrator to propose merges when a sprint PASSes, movegit merge *from thedenyarray to theaskarray in.claude/settings.json.This is a one-time per-project configuration step. The ask tier requires user confirmation before each merge, so it is safe to enable.
Offer to show the user the exact line to edit:
"ask": [
...existing entries...,
"git merge *"
]
Remove the corresponding entry from deny:
"deny": [
...entries without "git merge *"...
]
This is presented as a user choice, not an automatic change. The
council-kickoff skill must never modify .claude/settings.json automatically.
The git merge configuration is surfaced here because the ask tier in
.claude/settings.json is the correct mechanism per §9.3. Moving git merge
to ask is the only supported way to enable orchestrator-proposed merges; the
skill must not describe any other path.
Present a summary of all files created or verified:
Council baseline complete:
.council/config.json [created / already present]
.council/council-manifest.json [created / already present]
.council/henka-register.jsonl [created / already present]
.council/decision-log.jsonl [created / already present]
.council/audit-log.jsonl [created / already present]
.council/standard-work.json [created / already present]
.council/state/effective-autonomy.json [created / already present]
.council/course-corrections/ [created / already present]
.council/proposed/ [created / already present]
.council/proposed/archive/ [created / already present]
.council/retrospectives/ [created / already present]
.council/sessions/ [created / already present]
.harness/config.json [governance signal written]
Hook self-check: [pass / gap reported]
If any file could not be created (permission error, disk full, etc.), report the failure explicitly and do not mark the baseline as complete.
After confirming the baseline, inform the user that /henkaten-council:council-autorun
is the next skill to invoke when they are ready to start the sprint review loop
(available from Sprint 4 onward).
| File / Directory | Guard |
|---|---|
.council/config.json | Skip if present (idempotent mode) |
.council/council-manifest.json | Skip if present (idempotent mode) |
.council/henka-register.jsonl | Create only if absent |
.council/decision-log.jsonl | Create only if absent |
.council/audit-log.jsonl | Create only if absent |
.council/standard-work.json | Skip if present (idempotent mode) |
.council/state/effective-autonomy.json | Skip if present (idempotent mode) |
| All six directories | mkdir -p semantics (no error if present) |
.harness/config.json | Merge governance key; do not overwrite |
| Error Condition | Behavior |
|---|---|
.harness/ missing | Pause; offer trine-eval kickoff delegation |
.council/ exists | Ask user for idempotent vs full-overwrite |
| Hook missing | Report gap; pause until user confirms installation |
| File write fails | Report failure; do not mark baseline complete |
| trine-eval delegation fails | Report error; mark trine-eval step as incomplete |
| User declines git merge opt-in | Acknowledge; proceed; do not modify settings.json |
agents/orchestrator.mdagents/architect.mdschemas/council-config.schema.jsonschemas/council-manifest.schema.jsonschemas/effective-autonomy.schema.jsonschemas/standard-work.schema.jsoninstructions/controlled-artifacts.mdinstructions/andon-protocol.mdinstructions/evidence-first.mdinstructions/human-approval.md.claude/settings.jsonnpx claudepluginhub ats-kinoshita-iso/henka-council --plugin henkaten-councilProvides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Fetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.