plugin-maintenance
GitHub指导 Chorus 插件及多平台(Claude Code, Codex, TRAE CLI等)技能文档的修改、同步与版本发布流程。
触发场景
安装
npx skills add Chorus-AIDLC/Chorus --skill plugin-maintenance -g -y
SKILL.md
Frontmatter
{
"name": "plugin-maintenance",
"license": "AGPL-3.0",
"metadata": {
"author": "chorus",
"version": "0.5.1",
"category": "development"
},
"description": "Guide for modifying the Chorus plugin (Claude Code, Codex\/TRAE CLI, OpenClaw, Kiro, Pi, dsh, and Hermes ports), updating skill documentation, and releasing new plugin versions."
}
Chorus Plugin & Skill Maintenance
How to modify the Chorus plugin, update skill documentation, and release new versions. Seven plugin packages are maintained in parallel — Claude Code, Codex, OpenClaw, Kiro, Pi, dsh (DeepSeek Harness), and Hermes Agent — plus the standalone skill surface. That is eight skill surfaces total; when you change skill content, sweep all eight (see Skill Content Changes — Seven Surfaces, which also lists the Hermes copy). The Hermes port has its own section: Hermes Agent port.
TRAE CLI is not an eighth package. TRAE CLI (traecli, a Codex fork) installs the Codex package plugins/chorus/ unchanged: it reads .agents/plugins/marketplace.json and .codex-plugin/plugin.json. TRAE has no separate skill copy, version sequence, or installer. The one package serves two runtimes, so every Codex-package change must keep working under both. See Codex/TRAE plugin hooks.
File Structure
.claude-plugin/
marketplace.json ← Claude Code marketplace registry (version here)
public/chorus-plugin/ ← Claude Code plugin package
.claude-plugin/
plugin.json ← Plugin metadata (version here)
hooks.json ← Hook definitions (SubagentStart, etc.)
bin/ ← Hook scripts (bash) — stateful via API state-get/set
skills/
chorus/SKILL.md ← Core skill
develop/ idea/ proposal/ quick-dev/ review/ yolo/SKILL.md
agents/ ← Reviewer agents as .md (Claude Code style)
proposal-reviewer.md
task-reviewer.md
plugins/chorus/ ← Codex plugin package (separate from Claude Code); also installed by TRAE CLI
.codex-plugin/
plugin.json ← Plugin metadata (version here; shared by Codex + TRAE)
hooks.json ← NEVER change the command strings (forces users to re-trust hooks)
hooks/ ← Hook scripts (bash) — intentionally stateless, shared by both runtimes
on-session-start.sh
on-post-submit-proposal.sh
on-post-submit-for-verify.sh
on-post-verify-task.sh
hook-runtime.sh ← Codex-vs-TRAE runtime detection + tool_response UUID parsing
chorus-mcp-call.sh ← MCP helper (has hardcoded clientInfo version)
hook-output.sh
skills/
chorus/SKILL.md ← Codex port — mentions $skill syntax, ~/.codex/config.toml
develop/ idea/ proposal/ quick-dev/ review/ yolo/SKILL.md
chorus-proposal-reviewer/SKILL.md ← Reviewers as skills in Codex (no agents/)
chorus-task-reviewer/SKILL.md
packages/openclaw-plugin/ ← OpenClaw plugin package (TS runtime + skills)
openclaw.plugin.json ← Plugin manifest (id, skills dir, activation, configSchema) — NO version field
package.json ← npm package (version here; `openclaw` block: extensions, runtimeExtensions, install/compat)
src/ ← TypeScript runtime (index.ts, mcp-client.ts, sse-listener.ts, event-router.ts, wake.ts)
— real-time SSE event bridge + MCP registration; NOT bash hooks
dist/ ← Compiled JS (npm install loads this; linked install loads src/ via jiti)
skills/
chorus/SKILL.md ← OpenClaw port — tools namespaced `chorus__<tool>`, inline OpenSpec detection
develop/ idea/ proposal/ quick-dev/ review/ yolo/ brainstorm/ openspec-aware/SKILL.md
proposal-reviewer/SKILL.md ← Reviewers as skills (like Codex, no agents/)
task-reviewer/SKILL.md
public/kiro-plugin/ ← Kiro CLI plugin (loose .kiro/ template tree + install script)
.kiro/
settings/mcp.json ← Chorus remote MCP server (${env:CHORUS_API_KEY} bearer, disabled:false)
skills/chorus-*/SKILL.md ← the chorus-PREFIXED skills (no bare names — global-install distinctiveness)
agents/chorus.json ← main agent (.json — Kiro CLI, NOT .md); hosts all hooks via __CHORUS_BIN__ placeholder
agents/chorus.md ← main-agent system-prompt sidecar (file://./chorus.md)
agents/chorus-*-reviewer.json ← 3 read-only reviewer subagents (tools:["read","@chorus"])
steering/chorus.md ← platform overview + AI-DLC context (folds in the `chorus` overview skill)
bin/ ← Hook scripts (bash, 3.2-safe) + chorus-api.sh + test-syntax.sh
installer copies these into <KIRO_DIR>/chorus-bin/ and resolves __CHORUS_BIN__
(public/install-kiro.sh) ← deprecation stub → redirects to `chorus agents add`; the .kiro/ tree is installed by cli/init/file-template.mjs (asset list: public/kiro-plugin/manifest.txt)
packages/chorus-pi/ ← Pi coding agent package (TS extension + skills)
package.json ← npm package + Pi manifest (version here)
extensions/chorus.ts ← Native Pi event handlers; auto checkin/session lifecycle/reviewer nudges
lib/lib.ts ← Pure helpers used by the extension and unit tests
bin/chorus-mcp-call.sh ← MCP helper for byte-exact OpenSpec document mirroring
skills/
chorus/SKILL.md ← Core skill; Pi `/skill:<name>` syntax
develop/ idea/ proposal/ quick-dev/ review/ yolo/ openspec-aware/SKILL.md
agents/ ← 3 read-only reviewer agents copied to ~/.pi/agent/agents/
test/ ← Static, helper-unit, extension-event, and manual-session verification
packages/chorus-dsh/ ← DeepSeek Harness (dsh) plugin — published npm bundle @chorus-aidlc/chorus-dsh
package.json ← npm package + dsh bundle patch (version here; tracks the APP version, e.g. 0.16.3)
src/index.ts ← Cordis plugin apply(): injects skills/persona/MCP wrapper; daemon-backend gate
cordis.patch.yml ← dsh composition patch shipped in the bundle
bin/chorus-mcp-call.mjs ← Node MCP-over-HTTP helper (clientInfo.version auto-read from package.json — no manual bump)
skills/
chorus/SKILL.md ← Core overview (dsh HAS a chorus/ overview, unlike Kiro)
<stage>-chorus/SKILL.md ← 13 stage/reviewer skills, `-chorus` SUFFIX (brainstorm/develop/idea/
proposal/quick-dev/review/yolo/docs/orchestrate/openspec-aware/
code-reviewer/proposal-reviewer/task-reviewer)
packages/chorus-hermes/ ← Hermes Agent (Nous Research) port — NOT on npm/PyPI; installed from a git subdir pinned to a SHA
chorus/ ← native plugin (plugin.yaml + register(ctx)); see "Hermes Agent port"
chorus-mcp/ ← portable Agent Plugins v1 package (plugin.json + mcp.json): the chorus MCP server
public/skill/ ← Standalone skill (any MCP-compatible agent)
chorus/SKILL.md ← Same structure, softer language, IDE-agnostic
proposal-chorus/SKILL.md
quick-dev-chorus/SKILL.md
Plugin key differences
| Aspect | Claude Code | Codex | OpenClaw | Kiro CLI | Pi |
|---|---|---|---|---|---|
| Skill invocation | /chorus:develop |
$develop |
/develop |
/chorus-develop |
/skill:develop |
| Tool names | chorus_<tool> |
chorus_<tool> |
chorus__<tool> |
chorus_<tool> / @chorus matcher |
Native mcp__chorus__chorus_<tool> (direct/codemode); legacy adapter5 direct chorus_chorus_<tool> or bare; extension uses backend names |
| MCP config | .mcp.json |
~/.codex/config.toml |
Plugin config | ~/.kiro/settings/mcp.json |
Native global ~/.pi/agent/mcp.json / trusted project .pi/mcp.json; legacy adapter5 global mcp-adapter.json |
| Session lifecycle | SubagentStart/Stop hooks | Manual/stateless | Manual | agentSpawn/stop hooks |
Automatic via mutable subagent_spawn and subagent_manage events |
| Reviewers | agents/*.md via Task |
Skills mounted in spawn_agent |
Reviewer skills via sessions_spawn |
Native JSON subagents | agents/chorus-*-reviewer.md via pi-subagents |
| User interaction | AskUserQuestion |
Plain text | Plain text | Plain text | Plain text |
| OpenSpec detection | SessionStart hook | SessionStart hook | Inline | agentSpawn hook |
session_start extension event |
| Runtime/hooks | Stateful bash hooks | Stateless bash hooks | TypeScript SSE runtime | Bash 3.2 hooks in chorus.json |
TypeScript native extension; shell only for OpenSpec mirroring |
| Task execution | Agent Teams waves | spawn_agent |
Main-agent waves | Kiro subagents | subagent_spawn workers |
| Install | Marketplace | install-codex.sh |
OpenClaw plugin manager | install-kiro.sh |
npm (pi install npm:@chorus-aidlc/chorus-pi) |
TRAE CLI runtime of the Codex package. Same column as Codex, except for these differences:
- MCP config lives in
~/.trae/traecli.toml(or$TRAE_HOME). - Sub-agents/reviewers are spawned with the
Agenttool, notspawn_agent. - Skill routing uses
${PLUGIN_ROOT}/skills/<name>/SKILL.md. - Plugin hooks run only after the user trusts them in traecli.
- Hook processes do not receive
TRAE_HOME. The only runtime marker isPLUGIN_ROOTresolving under${TRAE_HOME:-$HOME/.trae}/plugins/;CHORUS_HOOK_RUNTIME=trae|codexoverrides it. tool_responsemay arrive as a JSON-encoded string.- Install is
chorus agents add --agents trae, which runstraecli plugin marketplace add+traecli plugin install chorus@chorus-plugins --yes. traecli has no npm plugin source.
When porting a change between plugins, preserve these intentional differences. Don't add state files to the Codex/OpenClaw plugins, don't use $-prefix outside Codex, keep OpenClaw's chorus__ names and manual-session/inline-detection wording, and preserve Kiro's chorus- skill prefix, @chorus/<tool> matchers, and __CHORUS_BIN__ placeholder. For Pi, use /skill:<name>, subagent_spawn, native extension events, and plain-text interaction; do not introduce Claude hooks or Codex session wording.
dsh (DeepSeek Harness) is a published npm bundle (@chorus-aidlc/chorus-dsh) added to a dsh profile via dsh plugin --profile <name> add -w. It is Cordis-based: src/index.ts's apply() injects the -chorus-suffixed skills, persona, and a Node MCP wrapper. Skills use the -chorus suffix (like standalone) but it keeps a chorus/SKILL.md overview. Its version tracks the app version (0.16.3+), NOT the 0.9.x skill sequence. The dsh daemon backend (cli/dsh-spawner.mjs / dsh-managed-config.mjs) is currently de-listed / offline — kept dormant, not advertised; do NOT re-add it to the daemon install menu, CLI --agent help, or DAEMON.md / MCP_TOOLS.md without bringing the backend back online.
When to Update What
"All six plugin skills" = Claude Code + Codex + OpenClaw + Kiro + Pi + dsh. "All seven surfaces" additionally includes standalone public/skill/. Note the Kiro surface has no chorus/SKILL.md — its overview lives in steering/chorus.md, and its stage skills are chorus-prefixed; dsh keeps a chorus/SKILL.md overview and uses -chorus-suffixed stage skills.
| Change | Files to update |
|---|---|
| New MCP tool added | src/mcp/tools/*.ts + docs/MCP_TOOLS.md + all six plugin overviews (Kiro: steering/chorus.md) + standalone overview |
| MCP tool description changed | src/mcp/tools/*.ts only (skill docs reference tool names, not descriptions) |
| Skill content / wording (e.g. AC now required) | The matching stage skill in all seven surfaces |
| New workflow step | All six plugin stage skills + standalone equivalent |
| New Idea/Task status | All six plugin overviews + standalone overview + locale messages |
| New execution rule | All six plugin overviews + standalone overview (softer wording) |
| Permission model change | All six plugin overviews + affected stage skills + runtime checks where applicable |
| Hook script change (Claude Code) | public/chorus-plugin/bin/*.sh + hooks.json if new hook. Never copy hook changes blindly into plugins/chorus/hooks/ — Codex hooks are intentionally stateless and lack subagent events. OpenClaw has no bash hooks at all. |
| Hook script change (Codex / TRAE) | plugins/chorus/hooks/*.sh — four hooks (session-start, post-submit-proposal, post-submit-for-verify, post-verify-task), shared by Codex and TRAE. Put runtime-specific wording behind hook-runtime.sh, never in a forked copy. Keep hooks.json command strings unchanged. Run plugins/chorus/hooks/tests/test-shared-hooks.sh (both runtimes) and public/chorus-plugin/bin/tests/test-on-post-verify-task.sh. If bumping plugin version, also update the hardcoded clientInfo.version in chorus-mcp-call.sh. |
| OpenClaw runtime change | packages/openclaw-plugin/src/*.ts (TS SSE/MCP runtime) + npm run typecheck + npm run test. Not bash hooks — this is a compiled TypeScript extension. |
| Pi runtime change | packages/chorus-pi/extensions/*.ts + lib/*.ts; run bash test/all.sh from the package directory |
| Any plugin change | Bump version in every file for that package (see Version Bump Checklist) |
Version Bump Checklist
Every time any plugin package changes, bump the version in all of that package's locations. There are two version sequences in play:
- Skill-frontmatter sequence — shared by corresponding
SKILL.mdfiles across the six plugin ports. When the same skill content ships to multiple plugins, bump them together. - Per-package plugin sequences — Claude Code + Codex share one (
marketplace.json/ bothplugin.json, currently0.9.x); OpenClaw'spackage.jsonhas its own sequence (currently0.5.x). These are independent files — edit each.
Claude Code plugin — bump together
.claude-plugin/marketplace.json—"version": "X.Y.Z"public/chorus-plugin/.claude-plugin/plugin.json—"version": "X.Y.Z"- Every skill under
public/chorus-plugin/skills/*/SKILL.md—metadata.version: "X.Y.Z"(all skills, includingquick-dev/, now use the standard nestedmetadata:block)
Codex plugin — bump together
plugins/chorus/.codex-plugin/plugin.json—"version": "X.Y.Z"- Every skill under
plugins/chorus/skills/*/SKILL.md—metadata.version: "X.Y.Z"(all skills, includingquick-dev/, now use the standard nestedmetadata:block). Don't forget the two reviewer skills:chorus-proposal-reviewer/SKILL.mdandchorus-task-reviewer/SKILL.md. plugins/chorus/hooks/chorus-mcp-call.sh— hardcodedclientInfo.versionstring in the JSON-RPCinitializepayload
OpenClaw plugin — bump together
packages/openclaw-plugin/package.json—"version": "X.Y.Z"using OpenClaw's own sequence (0.5.x), NOT the skill sequence.openclaw.plugin.jsonhas no version field — nothing to edit there.- Every skill under
packages/openclaw-plugin/skills/*/SKILL.md—metadata.version: "X.Y.Z"on the skill sequence (0.9.x, matching the other plugins' skills). Includes the two reviewer skillsproposal-reviewer/SKILL.mdandtask-reviewer/SKILL.md.- Do NOT touch
src/mcp-client.ts'sclientInfo.version(0.1.0) — it is a static MCP client identifier, not the plugin version.
- Do NOT touch
Kiro plugin — bump together
Kiro has no plugin.json / marketplace registry (it reads loose .kiro/ files), so the only versioned files are the skill frontmatters.
10. Every skill under public/kiro-plugin/.kiro/skills/chorus-*/SKILL.md — metadata.version: "X.Y.Z" on the shared skill sequence (all chorus-* skills). The agents/*.json and steering/chorus.md carry no version field — nothing to edit there.
11. public/kiro-plugin/bin/chorus-api.sh — hardcoded clientInfo.version string in the JSON-RPC initialize payload (same as the Codex chorus-mcp-call.sh helper).
Pi package — bump together
packages/chorus-pi/package.json—"version": "X.Y.Z".- Every skill under
packages/chorus-pi/skills/*/SKILL.md—metadata.version: "X.Y.Z", includingopenspec-aware. packages/chorus-pi/extensions/chorus.ts— hardcoded MCPclientInfo.version.
dsh (DeepSeek Harness) plugin — bump together
dsh tracks the app version (currently 0.16.3), NOT the 0.9.x skill sequence.
16. packages/chorus-dsh/package.json — "version": "X.Y.Z" (the published @chorus-aidlc/chorus-dsh bundle).
17. Every skill under packages/chorus-dsh/skills/*/SKILL.md — metadata.version: "X.Y.Z" (the chorus/ overview + all -chorus-suffixed stage/reviewer skills).
- Do NOT hardcode a version in
bin/chorus-mcp-call.mjs— itsclientInfo.versionis auto-read frompackage.json, so it never drifts.
Coordinated npm release identity
When cutting an application release, the four public npm packages are one
lockstep release unit. Set the same X.Y.Z in:
- root
package.json(@chorus-aidlc/chorus); packages/openclaw-plugin/package.json(@chorus-aidlc/chorus-openclaw-plugin) and refresh its standalonepackage-lock.json;packages/chorus-dsh/package.json(@chorus-aidlc/chorus-dsh);packages/chorus-pi/package.json(@chorus-aidlc/chorus-pi) — no standalone lockfile to refresh (it rides the workspacepnpm-lock.yaml); a plain version bump does not dirty the lockfile, but if you changed its deps runpnpm install --lockfile-onlyat the repo root (the release preflight runspnpm install --frozen-lockfile).
Publishing GitHub Release vX.Y.Z triggers
.github/workflows/publish-npm.yml. The workflow completes all four package
build/pack contracts before any upload, then publishes CLI → OpenClaw → dsh →
chorus-pi. The older interactive package publish scripts are maintenance tools,
not the CI release entry point.
For all four npm package settings, Trusted Publisher must use the exact
workflow filename publish-npm.yml in the matching GitHub repository. Leave
the npm Environment field blank while the workflow job has no environment;
if an Environment is introduced, configure the exact same case-sensitive name
on npm and on the workflow job. Keep id-token: write, do not add
NPM_TOKEN, NODE_AUTH_TOKEN, or a setup-node token placeholder, and do not
disable npm's automatic provenance. A zero exit status from npm publish
completes the upload and is recorded as accepted-by-npm. Registry visibility
and provenance metadata can lag behind acceptance; the workflow does not poll
them or use them to gate subsequent packages.
@chorus-aidlc/chorus-pi is the newest package: its Trusted Publisher must be
registered on npmjs.org before its first coordinated publish, or the run stops
at chorus-pi with the first three already published — a human/ops step, not
something to fake or token-shim around.
For partial publication, repair the external problem and choose Re-run jobs
on the same failed Actions run. Do not create a replacement Release/version.
The rerun skips exact versions already confirmed in npm and resumes in fixed
order. A failed registry lookup is not a skip and must stop the run; the job
summary identifies failed and not-attempted packages for diagnosis.
Standalone skills — independent versioning
public/skill/*/SKILL.md— bump only the standalone skills that changed, using their own version sequence.
Quick way to check all versions:
grep -rn '"version"\|^ version:\|^version:\|clientInfo' \
.claude-plugin/marketplace.json \
public/chorus-plugin/.claude-plugin/plugin.json \
public/chorus-plugin/skills/*/SKILL.md \
plugins/chorus/.codex-plugin/plugin.json \
plugins/chorus/skills/*/SKILL.md \
plugins/chorus/hooks/chorus-mcp-call.sh \
packages/openclaw-plugin/package.json \
packages/openclaw-plugin/skills/*/SKILL.md \
public/kiro-plugin/.kiro/skills/*/SKILL.md \
public/kiro-plugin/bin/chorus-api.sh \
packages/chorus-pi/package.json \
packages/chorus-pi/skills/*/SKILL.md \
packages/chorus-pi/extensions/chorus.ts \
packages/chorus-dsh/package.json \
packages/chorus-dsh/skills/*/SKILL.md \
public/skill/*/SKILL.md
Users update via:
/plugin update chorus@chorus-plugins # Claude Code
codex plugin update chorus@chorus-plugins # Codex
traecli plugin marketplace upgrade chorus-plugins && traecli plugin install chorus@chorus-plugins --yes # TRAE CLI (or: chorus upgrade --plugins)
# OpenClaw: reinstall/update via the OpenClaw plugin manager (npm spec @chorus-aidlc/chorus-openclaw-plugin)
# Kiro: re-run `chorus agents add --agents kiro` (idempotent; installs the .kiro/ tree via the file-template installer)
# Pi: pi install npm:@chorus-aidlc/chorus-pi (reinstall to pull the latest published extension)
Pi is published to npm as @chorus-aidlc/chorus-pi and installs with pi install npm:@chorus-aidlc/chorus-pi — the same path chorus agents add automates (select Pi, or --agents pi). The old sparse-git-checkout / local-path workaround is no longer needed; local-path pi install ./packages/chorus-pi is now only for developing chorus-pi from the repo checkout.
Skill Content Changes — Seven Surfaces
Chorus skill content lives in seven parallel surfaces. A content change must sweep all seven:
public/chorus-plugin/skills/<skill>/SKILL.md— Claude Codeplugins/chorus/skills/<skill>/SKILL.md— Codexpackages/openclaw-plugin/skills/<skill>/SKILL.md— OpenClawpublic/kiro-plugin/.kiro/skills/chorus-<skill>/SKILL.md— Kiro (note thechorus-prefix; the overview lives insteering/chorus.md, not achorus/SKILL.md)packages/chorus-pi/skills/<skill>/SKILL.md— Pipackages/chorus-dsh/skills/<skill>-chorus/SKILL.md— dsh (note the-chorussuffix; keeps achorus/SKILL.mdoverview)- plus
packages/chorus-hermes/chorus/skills/<skill>/SKILL.md— Hermes (bare names, loaded asskill_view("chorus:<skill>"); reviewers arechorus-<kind>-reviewerskills, not agent files). See Hermes Agent port.
- plus
public/skill/<skill>-chorus/SKILL.md— standalone (note the-chorussuffix and flatter set)
Sweep command — find every occurrence before editing so nothing is missed:
grep -rniE "<your-search-term>" \
public/chorus-plugin/skills/ plugins/chorus/skills/ \
packages/openclaw-plugin/skills/ public/kiro-plugin/.kiro/skills/ \
packages/chorus-pi/skills/ packages/chorus-dsh/skills/ \
packages/chorus-hermes/chorus/skills/ public/skill/
Then bump the relevant version sequences (shared skill frontmatter across plugin surfaces 1–5, independent standalone version for #6, and per-package versions as needed).
Porting Changes Between Plugins
Whenever you change content in one plugin, mirror it into the other plugin surfaces unless the difference is intentional. Typical workflow:
- Make the change in
public/chorus-plugin/skills/<skill>/SKILL.md - Diff-check the counterparts:
diff public/chorus-plugin/skills/<skill>/SKILL.md plugins/chorus/skills/<skill>/SKILL.mddiff public/chorus-plugin/skills/<skill>/SKILL.md packages/openclaw-plugin/skills/<skill>/SKILL.mddiff public/chorus-plugin/skills/<skill>/SKILL.md packages/chorus-pi/skills/<skill>/SKILL.md
- Apply the same semantic change to every port, but preserve intentional phrasing:
- Codex:
.mcp.json→~/.codex/config.toml,Task tool→spawn_agent,/chorus:X→$X, "sessions auto-managed" → "sessions are optional / stateless port". These skills are also read by TRAE CLI. Where an instruction names the sub-agent tool, add a short TRAE note (Agenttool) rather than forking the skill. - OpenClaw: tool names
chorus_<tool>→chorus__<tool>,AskUserQuestion→ plain-text prompt, reviewers viasessions_spawn, OpenSpec detection is inline (no SessionStart hook), sessions are manual - Kiro:
chorus-skill prefix, native JSON subagents,@chorustools, and hook-driven context - Pi:
/skill:X,subagent_spawn, plain-text prompts, reviewer.mdagents, extension-managed worker sessions
- Codex:
- Bump all affected plugins' versions (all files in the Version Bump Checklist)
- For the Codex plugin, also verify
chorus-mcp-call.shclientInfo.versionmatches
Plugin vs Standalone Skill: Tone Differences
The plugin skill targets Claude Code specifically. The standalone skill targets any MCP-compatible agent (Cursor, Kiro, etc.).
| Aspect | Plugin (public/chorus-plugin/skills/) |
Standalone (public/skill/) |
|---|---|---|
| AskUserQuestion | "ALWAYS use... NEVER display as text" | "prefer your IDE's interactive prompt if available" |
| Session management | "Do NOT create sessions — plugin handles it" | "Create or reopen a session before starting work" |
| Skip elaboration | "you MUST ask the user for permission first" | "confirm with the user first" |
| Hook references | References specific hooks (SubagentStart, etc.) | No hook references |
Rule of thumb: Plugin version uses MUST/NEVER/ALWAYS. Standalone version uses "prefer", "confirm", "consider".
Adding a New MCP Tool — Full Checklist
- Implement in
src/mcp/tools/*.ts(pm.ts, public.ts, etc.) - Add to
docs/MCP_TOOLS.md - Update permission tables and tool lists in all seven overview surfaces:
public/chorus-plugin/skills/chorus/SKILL.mdplugins/chorus/skills/chorus/SKILL.mdpackages/openclaw-plugin/skills/chorus/SKILL.md(use thechorus__<tool>namespaced form)public/kiro-plugin/.kiro/steering/chorus.md(Kiro has nochorus/SKILL.md— the overview is the steering doc)packages/chorus-pi/skills/chorus/SKILL.mdpackages/chorus-dsh/skills/chorus/SKILL.mdpublic/skill/chorus/SKILL.md
- If it changes a stage workflow, update the matching stage skill in all seven locations.
- Bump every affected plugin's versions (see Version Bump Checklist)
- Run
npx tsc --noEmitto verify
Modifying Hook Scripts
Claude Code plugin hooks (public/chorus-plugin/bin/)
on-session-start.sh— SessionStart hook (cachesagent_permissionsvia"$API" state-set)on-user-prompt.sh— UserPromptSubmit hookon-subagent-start.sh— SubagentStart hookon-subagent-stop.sh— SubagentStop hook (readsagent_permissionsviastate-get)on-teammate-idle.sh— TeammateIdle hookon-pre-enter-plan.sh,on-pre-exit-plan.sh— Plan mode hookson-task-completed.sh— TaskCompleted hookon-post-submit-proposal.sh,on-post-submit-for-verify.sh— PostToolUse reviewer reminders
Codex plugin hooks (plugins/chorus/hooks/)
These scripts are shared by the Codex and TRAE CLI runtimes. There are no per-runtime copies or dispatcher.
on-session-start.sh— SessionStart hook (stateless; no caching)on-post-submit-proposal.sh— PostToolUse forchorus_pm_submit_proposalon-post-submit-for-verify.sh— PostToolUse forchorus_submit_for_verifyon-post-verify-task.sh— PostToolUse forchorus_admin_verify_task(archive / completion-report / code-review reminders)hook-runtime.sh— sourced helper. It detects the runtime (Codex default; TRAE whenPLUGIN_ROOTis under the TRAE plugins dir) and extracts UUIDs from object or stringtool_response. Use it for any wording that must differ (banner,spawn_agentvsAgent).chorus-mcp-call.sh— shared MCP-over-HTTP helper (bumpclientInfo.versionon release)hook-output.sh— stdout-formatting helper
Rules for these hooks:
- Never change
hooks.jsoncommand strings: every user would have to re-trust the hooks. - MCP list calls must use
pageSize≤ 100 (the server maximum). A larger value fails, and the hook exits silently. - Codex
spawn_agentskill items need aname. - Escape backticks inside unquoted heredocs.
Codex has no SubagentStart/Stop events — do not try to port lifecycle hooks from the Claude Code plugin. Instead, session management is documented as a main-agent responsibility in plugins/chorus/skills/develop/SKILL.md and $yolo.
OpenClaw plugin — TypeScript runtime, not bash hooks (packages/openclaw-plugin/src/)
OpenClaw has no bash hooks at all. Its real-time behavior is a compiled TypeScript extension declared in package.json's openclaw block (extensions: ["./src/index.ts"], runtimeExtensions: ["./dist/index.js"]):
index.ts— entry point / activation (activation.onStartupinopenclaw.plugin.json)mcp-client.ts,mcp-registration.ts— registers Chorus MCP tools (namespacedchorus__<tool>)sse-listener.ts,event-router.ts,wake.ts— SSE event stream → agent wake (the OpenClaw analogue of the other plugins' notification hooks)config.ts,commands.ts— config schema handling and slash commands
After modifying the runtime: cd packages/openclaw-plugin && npm run typecheck && npm run test. A linked install loads src/ directly via jiti; an npm install requires the compiled dist/ (npm run build). Bash 3.2 rules do not apply here (it's TypeScript, not shell). Two known runtime gotchas: a linked install loads TS via jiti (no dist) while an npm install needs compiled dist + runtimeExtensions; and SSE→agent wake requires activation.onStartup + runEmbeddedAgent with an explicit provider/model.
Kiro plugin hooks (public/kiro-plugin/bin/)
Kiro hooks are bash (Bash-3.2 rules apply) but declared inside agents/chorus.json (Kiro has no standalone hooks.json), and each hook's STDOUT is added to the agent context as plain text (there is no additionalContext JSON envelope like Claude Code). Scripts:
on-agent-spawn.sh—agentSpawnhook:chorus_checkin→ startup context (owner/permissions/idea-tracker). "Not configured" if Chorus env is unset; never aborts the spawn.on-stop.sh—stophook: best-effort session heartbeat/checkout; never blocks the turn.on-post-submit-proposal.sh/on-post-submit-for-verify.sh/on-post-verify-task.sh—postToolUsehooks matched to@chorus/chorus_pm_submit_proposal/@chorus/chorus_submit_for_verify/@chorus/chorus_admin_verify_task; emit a nudge to spawn the matching reviewer subagent. Exit 0 with no output if no parseable UUID.chorus-api.sh— the reused MCP-over-HTTP wrapper (bump the hardcodedclientInfo.versionon release, like Codex'schorus-mcp-call.sh). Hook scripts reference it via a path relative to their own location, never a hard-coded repo path.test-syntax.sh— Bash-3.2 parse + mock-event smoke test harness.
Hook command strings in the repo chorus.json use the __CHORUS_BIN__ placeholder; public/install-kiro.sh copies bin/*.sh into <KIRO_DIR>/chorus-bin/, chmod +x, and substitutes __CHORUS_BIN__ with that absolute path. Never commit a concrete machine path in the repo copy — only the installed copy is concretized.
Pi extension (packages/chorus-pi/extensions/)
Pi uses a native TypeScript extension instead of lifecycle bash hooks:
session_startperforms checkin, OpenSpec detection, and startup notification.before_agent_startinjects checkin context once.- Mutable
tool_callonsubagent_spawncreates a session only forworkerand injects its UUID/workflow. tool_resultandtool_execution_endmap spawned agent IDs, close sessions, and emit reviewer nudges.session_shutdownretries retained session closures.
Keep pure parsing/path/banner helpers in lib/lib.ts. Preserve failed-close mappings for shutdown retry, and do not create sessions for scout/planner/reviewer/custom agents. The OpenSpec shell wrapper must resolve both env and .mcp.json configuration, but it is not a lifecycle hook.
After modifying the Pi package, run cd packages/chorus-pi && bash test/all.sh. This covers static checks, pure helper tests, and extension-event tests; update test/verify-pi-session.md when behavior requires live Pi verification.
CRITICAL: All hook scripts MUST be compatible with Bash 3.2. macOS ships with /bin/bash 3.2 (due to GPL licensing) and Claude Code + Codex + Kiro all use it to execute hooks. Do NOT use Bash 4+ features:
| Bash 4+ (FORBIDDEN) | Bash 3.2 alternative |
|---|---|
${VAR,,} (lowercase) |
$(printf '%s' "$VAR" | tr '[:upper:]' '[:lower:]') |
${VAR^^} (uppercase) |
$(printf '%s' "$VAR" | tr '[:lower:]' '[:upper:]') |
declare -A (associative arrays) |
Use separate variables or jq |
readarray / mapfile |
while IFS= read -r line loop |
|& (pipe stderr) |
2>&1 | |
&>> (append both) |
>> file 2>&1 |
After modifying:
- Run
/bin/bash public/chorus-plugin/bin/test-syntax.sh(Claude Code + Codex hooks) and/bin/bash public/kiro-plugin/bin/test-syntax.sh(Kiro hooks) on macOS to verify Bash 3.2 compatibility — OpenClaw and Pi lifecycle code are TypeScript - Test locally:
claude --plugin-dir public/chorus-plugin(Claude Code), install viacodex plugin installand reload (Codex), for TRAE use an isolatedTRAE_HOMEunder~/.cache(not/tmp; traecli refuses helper binaries there) withtraecli plugin marketplace add "$PWD"+traecli plugin install chorus@chorus-plugins --yes, re-installing after each edit (TRAE CLI), re-runinstall-kiro.sh(Kiro), orpi install "$PWD/packages/chorus-pi"from the Chorus checkout (Pi) - Bump plugin version for whichever packages changed (all affected packages)
- Users must restart the affected agent after updating (Kiro: re-run the installer; Pi: reinstall the package)
Testing Plugin Changes
# Claude Code — load plugin locally (no install needed)
claude --plugin-dir public/chorus-plugin
# Or update installed plugin
/plugin update chorus@chorus-plugins
# Verify plugin loaded
/plugin list
# OpenClaw — typecheck + test the TypeScript runtime
cd packages/openclaw-plugin && npm run typecheck && npm run test
# Kiro — dry-run the installer into a throwaway HOME, then assert the tree
HOME=$(mktemp -d) CHORUS_URL=https://example.com CHORUS_API_KEY=cho_test \
bash public/install-kiro.sh < /dev/null
# verify hook scripts parse under Bash 3.2
bash public/kiro-plugin/bin/test-syntax.sh
# Pi — static checks + helper and extension-event tests
cd packages/chorus-pi && bash test/all.sh
# dsh — typecheck + lint + unit tests + published-bundle validation
cd packages/chorus-dsh && pnpm run typecheck && pnpm run lint && pnpm test && pnpm run check:package
# Hermes — pytest (fakes only; node for prompt parity; no Hermes install needed)
python -m pytest packages/chorus-hermes/chorus/tests
Hermes Agent port
Source: packages/chorus-hermes/. User docs: packages/chorus-hermes/README.md (install, configure,
troubleshooting, Hermes compatibility notes with file:line evidence) and docs/CONNECT_HERMES{,.zh}.md.
Design/spec: openspec/changes/add-hermes-plugin/. Verified against Hermes commit 2b52acc2d.
Layout — two directories, installed separately
packages/chorus-hermes/
README.md
chorus/ ← native plugin, installed as ~/.hermes/plugins/chorus
plugin.yaml ← name: chorus, kind: standalone (no "general" kind), version, provides_hooks
__init__.py ← register(ctx): hooks, skills, gateway platform, approval transport
chorus_hermes/ ← config, mcp_client, rest, hooks, reminders, spec_mode, skills (reviewer guard),
sse, router, prompts (port of cli/prompts.mjs), adapter, turns, approval
skills/<name>/SKILL.md ← independent Hermes copy (see below)
tests/ ← pytest; fixtures/ holds the prompt-parity fixtures + node renderer
chorus-mcp/ ← portable package, installed as ~/.hermes/plugins/chorus-mcp
plugin.json ← name: chorus-mcp, version
mcp.json ← chorus server, LITERAL http://localhost:8637/api/mcp + Bearer ${CHORUS_API_KEY}
Why two: Hermes declares MCP servers only in portable packages, and only a native plugin can register
hooks, skills, a platform and an approval transport. Keep mcp.json out of chorus/ and Python out of
chorus-mcp/ (enforced by test_package.py). Portable mcp.json URLs are not ${VAR}-expanded, so do
NOT "fix" the literal loopback URL; remote Chorus uses a native mcp_servers.chorus entry, which
chorus agents add writes (cli/init/hermes-mcp-config.mjs). Keep provides_hooks in plugin.yaml
equal to what register() registers, or hermes plugins validate fails. Both directories must keep
scanning safe — git installs are community trust and a caution verdict blocks the install (the
scanner flags phrases like "you are … now"; see the _NOW workaround in prompts.py).
Runtime model: online scheduling through the chorus gateway platform (SSE client type hermes), like
OpenClaw — not the Chorus daemon (agent-type-map.mjs maps hermes → offline). Operation turns
(research_requested, idea_creation_requested) are skipped by the router, same as OpenClaw.
Version sync
Hermes manifests are not npm packages, but they track the app version (root package.json) and
pytest fails on drift. On every release bump, set X.Y.Z in:
packages/chorus-hermes/chorus/plugin.yaml—version:packages/chorus-hermes/chorus-mcp/plugin.json—"version"- every
packages/chorus-hermes/chorus/skills/*/SKILL.md—metadata.version(test_skills.py::test_frontmatter)
The gateway's SSE clientVersion is read from plugin.yaml at runtime (adapter._client_version), and mcp_client.py sends no initialize/clientInfo — no version is hardcoded in Python.
Independent skill copy
chorus/skills/ is its own copy (started from packages/chorus-pi/skills), registered with
ctx.register_skill and resolved as chorus:<name>. These skills are not listed in <available_skills>,
so the session-start Quick Reference tells the model to skill_view("chorus:<name>"). When porting a
skill change:
- human questions → elaboration rounds / Chorus comments (no
AskUserQuestion); - sub-agents →
delegate_task(goal, context)(noTask/Agent/spawn_agent/subagent); - no
${CLAUDE_PLUGIN_ROOT}, Codex paths or/skill:syntax; - reviewers are skills
chorus-{proposal,task,code}-reviewer. The parent'sdelegate_taskcontext starts with[chorus-reviewer:<kind>], andskills.pymakes that child read-only. Keep the marker kinds equal to the skill names (test_reviewer_marker_kinds_match_skill_names).test_skills.pygreps for foreign-tool references and scan-triggering phrases. Run it after every edit.
Prompt parity
chorus_hermes/prompts.py is a byte-exact Python port of cli/prompts.mjs (wake prompts for every
WAKE_ACTIONS action). tests/test_prompts_parity.py renders tests/fixtures/prompt_fixtures.json with
node tests/fixtures/render_prompts.mjs and compares the output with the Python output. Any change to
cli/prompts.mjs must be mirrored in prompts.py and, for a new action or edge case, gets a fixture.
The test skips without node. CI/dev must have it.
Also mirror changes in cli/event-router.mjs (NOTIFICATION_ACTION_TO_TURN_TRIGGER) into router.py
ACTION_TO_TURN_TRIGGER. Reminder text mirrors the semantics of plugins/chorus/hooks/on-post-*.sh under the Codex runtime (Codex parity), but uses Hermes delegate_task wording. When those hooks change, for example a new reminder branch or a fixed condition, update reminders.py to match. Ignore the TRAE-only wording.
Release = the tag's SHA is the install ref
Hermes --ref accepts only a full 40-hex commit SHA, and a release commit cannot contain its own SHA. So
never commit a SHA (test_no_commit_sha_committed). The release tag vX.Y.Z is the release:
chorus agents add --agents hermes (installHermes in cli/init/install-methods.mjs) resolves
v<CLI version> with git ls-remote — peeled ^{} first, then the unpeeled ref (Chorus tags are
lightweight) — and fails closed if the tag is missing. The tag must therefore be pushed to
github.com/Chorus-AIDLC/Chorus before the matching CLI is published to npm, or new installs fail.
Users update by re-running chorus agents add --agents hermes, which offers to reinstall with
--force at the new tag's SHA (automatic under --yes), then hermes gateway restart.
chorus upgrade --plugins does NOT cover Hermes: it only reinstalls daemon-backed agents.
If you change the post-install checklist (hermesFollowUpChecklist), update the README "Configure"
section, docs/CONNECT_HERMES{,.zh}.md, and the Hermes tab in
src/components/install-guide/AgentInstallGuide.tsx (+ messages/{en,zh,ja,ko}.json).
An end-to-end run against a real Hermes is optional and not part of version alignment. If the hermes
CLI happens to be installed, hermes plugins validate packages/chorus-hermes/chorus (and …/chorus-mcp)
is a cheap extra manifest check.
版本历史
-
0377f81
当前 2026-10-19 10:17
新增 TRAE CLI (traecli) 后端支持,将并行维护的插件包从6个增至7个,并适配8个技能表面;实现 TRAE 专属 hook 分发与脚本共享机制。
- 9620180 2026-09-28 02:48
-
8cc534f
2026-09-09 09:33
优化 Pi 插件以对齐 Claude Code 功能,新增 npm 包发布、子代理模式及唤醒后端支持,修复跨表面技能文档问题。
-
e147e86
2026-09-03 10:40
新增自动化npm协调发布工作流,支持无令牌GitHub Actions发布CLI、OpenClaw和dsh插件,包含可重现包门控、来源验证和安全重试机制。
-
96a2f67
2026-08-20 02:30
新增dsh (DeepSeek Harness)插件支持,维护插件数量由4个增至6个,技能表面由5个增至7个。
- c08357a 2026-07-25 08:34


