Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
{
"name": "work-system",
"source": "./plugins/work-system",
"description": "Generic task and worktree workflow system for Claude Code. Manage tasks as markdown files, run them in isolated git worktrees with a choice of worker agent (Claude, codex, or grok), and track progress across the define/kickoff/continue/status/close lifecycle.",
"version": "1.10.0"
"description": "Generic task and worktree workflow system for Claude Code. Manage tasks as markdown files, run them in isolated git worktrees with a choice of worker agent (Claude, codex, grok, or kimi), and track progress across the define/kickoff/continue/status/close lifecycle.",
"version": "1.11.0"
},
{
"name": "pr-flow",
Expand Down
2 changes: 1 addition & 1 deletion .claude/knowledge/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
- `features/lane-registry.md` — `lanes.sh` + `herdr-agent.sh` (Wave 1): the one herdr-agent wrapper (degrade-not-block, bounded wait) + centralized `$HERDR_MATCH_PRELUDE` cwd↔worktree match (consumed by herdr-tab-glyph, regression-guarded via live snapshot); lanes.sh joins states+liveness keyed by worktree_path with a worktree-tab-state degrade tri-state; env test-seams for hermetic join tests
- `features/herdr-close-automation.md` — `/close` in herdr: cwd-tab teardown, plugin SessionEnd hook, the one TUI-exit primitive, detached self-exit onto idle
- `features/herdr-tab-glyphs.md` — Task-state glyphs (`○ ● ◇ ◆ ✓`) + main-root `◉` on herdr tab labels: `states` mode in the self-contained renderer, sync-vs-`--cached` PR refresh per caller, exact-cwd rename rules, soft pr-flow shim
- `features/kickoff-agent-selection.md` — `/kickoff` worker choice: single committed per-repo default (no global/fallback/ranking) else picker; `agent-registry.sh` as SoT; bounded model-aware grok probe (inconclusive→trust-auth); non-claude "document, don't fake" degradation; announce-not-prompt for external defaults
- `features/kickoff-agent-selection.md` — `/kickoff` worker choice: single committed per-repo default (no global/fallback/ranking) else picker; `agent-registry.sh` as SoT; bounded model-aware grok/kimi probes (inconclusive→trust-auth); kimi's two-phase seed+continue argv + `argv_shell=`; non-claude "document, don't fake" degradation; announce-not-prompt for external defaults
- `features/task-archiving-on-close.md` — `/close` archives (not deletes) the task file; adaptive commit + ff-push to main; per-repo `.claude/work-system-close-autocommit` opt-in skips the ask
- `features/swarm-backend-adapter.md` — 0.6.0 read+web posture: OS secret-jail (denylist, worktree-aware, git-config-safe), per-voice fail-closed degrade, `jail` verb, prompt egress guard + residual risks; plus verified codex/grok CLI facts (schema JSON, effort mapping, model-aware readiness)
- `features/swarm-review-pipeline.md` — `/swarm:review` pipeline: skill↔Workflow wiring, family-consensus, 0.5.0 lens clusters + design-kind verify, `--fix`/`--loop` (deterministic close-out via `loop-closeout.py`), `--pr` publish via deterministic `pr-post.py`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ implementation is spawned across tasks `add-lane-registry`, `spike-agent-mail-su
- **Manager** = the Claude Code session at the main repo root (herdr `◉` tab). A
*coordinator*, not a merge robot — the human stays merge authority unless
explicitly delegated at kickoff.
- **Worker** = one {claude|codex|grok} session per worktree, driving its task to a
- **Worker** = one {claude|codex|grok|kimi} session per worktree, driving its task to a
reviewed, mergeable PR.
- **Lane** = `(worktree_path, task, branch)`. **Identity = worktree_path** — the one
key stable across agent types and restarts. herdr pane/tab, `agent_status`,
Expand Down
5 changes: 4 additions & 1 deletion .claude/knowledge/features/herdr-kickoff-automation.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ truth; this entry captures the durable design and one non-obvious gotcha.
`claude --model <m> -n "<label>" "/work-system:continue"` (plugin-qualified — see
the shadowing gotcha below), while codex/grok get their own
`-m` form — `codex -m <model> "<bootstrap prompt>"` /
`grok -m <model> "<bootstrap prompt>"` (see [[kickoff-agent-selection]]).
`grok -m <model> "<bootstrap prompt>"`, and kimi (1.11.0) a two-phase
`sh -c 'kimi -m "$1" -p "$2" || …; exec kimi -c --auto' …` — it has no positional
launch prompt (see [[kickoff-agent-selection]]). `emit_argv` is the SoT; never
reconstruct an argv from this list.
herdr-launch stays CLI-agnostic — it just execs the resolved `argv=` words. The
`-- argv` form sidesteps the interactive shell entirely, so there is no keystroke
race against shell startup (see the gotcha below) and no readiness handshake to
Expand Down
82 changes: 73 additions & 9 deletions .claude/knowledge/features/kickoff-agent-selection.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
---
title: "Kickoff Agent Selection: registry, per-repo default, honest degradation"
createdAt: 2026-07-17
updatedAt: 2026-07-17
updatedAt: 2026-08-05
createdFrom: "session: 2026-07-17 (task/kickoff-agent-selection)"
updatedFrom: "session: 2026-07-17"
pluginVersion: 1.9.0
updatedFrom: "session: 2026-08-05 (task/add-kimi-worker-support, post-swarm)"
pluginVersion: 1.11.0
prime: false
---

Expand All @@ -25,7 +25,7 @@ nothing more. `--pick` forces the picker even when a default exists.

## Registry is the single source of truth
`scripts/agent-registry.sh` owns aliases (`--fable`/`--opus`/`--codex`/`--sol`/
`--grok`/`--agent cli[:model]`), the launch argv per CLI, availability, and
`--grok`/`--kimi`/`--agent cli[:model]`), the launch argv per CLI, availability, and
`default get`/`set`. `herdr-launch.sh` stays CLI-agnostic: it execs the resolved
`argv=` words (argv-exec, no shell-typing race — same reason as the kickoff
launch). Skills never hardcode the CLI list. `default get` **validates** its
Expand All @@ -43,16 +43,80 @@ never hangs. A failed *or* empty-but-successful (reformatted) `grok models` is
or format drift must not disable the backend. codex/claude stay auth-only (no
clean model-list command). See [[swarm-backend-adapter]] for the sibling probe.

## kimi: the launch shape a CLI's flags can force on you
kimi (added 1.11.0, `--kimi` → `kimi:kimi-code/k3-256k`) is the first worker whose
argv is not `<cli> -m <model> <prompt>`, because **no such form exists**. Probed
live on 0.31.1: no positional launch prompt (`kimi "text"` → "unknown command"),
no initial-prompt env var, and piped stdin only prefills the input box without
submitting — and in a pane it would steal the TUI's tty anyway. `-p` is the sole
entry point but is mutually exclusive with **both** `--auto` and `-y` and exits
after one answer, so it cannot *be* the worker. What makes it work: `-p` runs
tools unattended, and `kimi -c` inherits its session history. Hence two phases:

sh -c 'kimi -m "$1" -p "$2" || <report+wait>; exec kimi -c --auto' \
kimi-worker <model> <prompt> # exact text: KIMI_LAUNCH_SCRIPT

`exec` re-roots the pane at kimi (herdr then watches the real process). A failed
seed must neither kill the pane (`&&`) nor pass unnoticed (a bare `;` — the TUI's
first repaint scrolls the error away, leaving a tab that looks like a working
worker but never read TASK.md), so the script **reports and waits for a keypress**
before handing over. Verified: a failed seed in a fresh worktree yields a NEW empty
session, never a foreign one — `kimi -c` is scoped to the working directory, so two
worktrees cannot cross-resume. Values ride as
`"$1"`/`"$2"` positionals, never spliced into the script text — `-p` swallows the
next token, so a concatenated argv is one reordering away from silently eating a
flag (`kimi -p --auto "…"` makes `--auto` the prompt). The test asserts the exact
word list *and* executes the argv against a logging stub, because string checks
can't prove the shell binds values the way you think. Two more traps: `-m` needs
the **qualified** alias (`kimi-code/k3-256k`; the bare name aborts at startup like
an unknown model — hence model-aware readiness), and auth lives in
`credentials/`, not the same-named `oauth/` dir, which stays 0 bytes when logged
in. `kimi doctor` only validates config syntax; it is not an auth check.

**JSON breaks grok's "empty = inconclusive" rule.** grok treats empty output as
drift and trusts auth. For kimi's `provider list --json`, `{"models": {}}` is
non-empty yet a *real* "no models" answer. So the gate is the **section's
presence**: no `"models"` key → drift → trust auth; present but no match → truly
unavailable. Transplanting the sibling's rule verbatim would have mislabeled
either case.

## kimi's unattended posture is a decision, not an oversight
kimi is the only worker without tool-approval prompts: the seed can't have them
(`-p` refuses `--auto`/`-y`, and `-p` is the only way to deliver the task) and
phase 2 opts into `--auto` because a worker should keep going. Reviewed twice as
a security finding and **kept deliberately** (2026-08-05) — the mitigation is
visibility, matching the announce-not-prompt precedent below: `/kickoff` states
the unattended start whenever the worker resolves to kimi, `/adopt` additionally
warns because its TASK.md is summarized from someone else's commits. Dropping
`--auto` was rejected as a half-measure: it would leave the seed — the phase that
does the work — just as unattended. If this is ever revisited, the real lever is
a second registry entry (interactive `--kimi` vs. opt-in autonomous), not the
`--auto` flag alone.

## `argv_shell=`: quoting belongs to the registry, not to prose
`resolve` emits, next to the `argv=` words, one `argv_shell=` line with the same
words POSIX-single-quoted (`shell_quote`, not `printf %q` — bash 3.2 renders that
as per-character backslashes and `$'…'` for non-ASCII: correct but unreadable and
bash/zsh-only). The skills print that line **verbatim** for their outside-herdr
block. Before this, quoting was a *prose rule* the model had to follow; for kimi
that is safety-critical, because its argv carries `;` and `exec` — a mis-quoted
render would run the `;` in the **user's own interactive shell** and replace it
with an unattended agent. Same reason the seed message stays ASCII-only: any
backslash escape or non-ASCII char forces the unreadable `$'…'` form.

## Non-claude degradation: document, don't fake
codex/grok have no work-system skills, so a launched worker gets a bootstrap
codex/grok/kimi have no work-system skills, so a launched worker gets a bootstrap
prompt (read TASK.md → commit → PR) instead of `/continue`. Everything
git/PR-derived (`/status`, `/list`, `[ws]` statusline, `/close` tab teardown)
is CLI-agnostic. `/close` Scenario B (`/exit` self-teardown) is claude-only *by
is CLI-agnostic — `agent_name` comes from the registry's `name=`, never argv[0],
and `agent_status` from herdr's own pane hooks, so kimi's `sh -c` wrapper changes
nothing. `/close` Scenario B (`/exit` self-teardown) is claude-only *by
construction* (only a claude session can invoke `/close` from inside its tab).
`/continue` reopen **always sends `claude -c`** — the worker is not persisted
per task (per-task agent memory is a deliberate later idea), so for a codex/grok
task the user resumes the real worker themselves; the skill surfaces this inline
rather than pretending. `supports=` in the registry is **reserved** metadata
per task (per-task agent memory is a deliberate later idea), so for a
codex/grok/kimi task the user resumes the real worker themselves (`codex resume
--last` / `grok -c` / `kimi -c`); the skill surfaces this inline rather than
pretending. `supports=` in the registry is **reserved** metadata
(the seed for the manager/worker-orchestration design) — not yet consumed.

## Security: announce, don't prompt
Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ entries are grouped per plugin, newest first.

## work-system

### 1.11.0 — 2026-08-03
- `/kickoff` can launch the **kimi CLI** (kimi-code) as a worker: `--kimi` → `kimi:kimi-code/k3-256k`, joining claude/codex/grok in `agent-registry.sh`. It appears in the picker and can be saved as the repo default, where it announces like the other third-party workers.
- kimi is the first worker without a `<cli> -m <model> <prompt>` launch form — it has no positional launch prompt, no initial-prompt env var, and piped stdin only prefills the input box (and would steal the TUI's tty). Its `-p` flag is the only entry point, but it cannot be combined with `--auto`/`-y` and exits after one answer. Since `-p` does run tools unattended and `kimi -c` inherits its history, the launch is two-phase: `sh -c 'kimi -m "$1" -p "$2" || <report+wait>; exec kimi -c --auto' …` — the seed works the task through once, then `exec` hands over to the interactive autonomous session. So a kimi tab has already made progress by the time you switch to it.
- The model and prompt travel as `"$1"`/`"$2"` positionals rather than spliced into the script text: `-p` consumes the next token, so a concatenated argv can silently swallow a flag (`kimi -p --auto "…"` turns `--auto` into the prompt). Tests assert the exact word list, that structure, and — by executing the resolved argv against a logging stub — what each phase actually received.
- Readiness is model-aware via `kimi provider list --json` (bounded), because an unconfigured `-m` id aborts kimi at startup; the id must be the **qualified** alias (`kimi-code/k3-256k`). Auth probes `credentials/kimi-code.json`, not the same-named `oauth/` file, which stays 0 bytes even when logged in. A listing without the `models` section counts as format drift and falls back to trusting auth, while a well-formed listing offering nothing means unavailable — grok's "empty output = inconclusive" rule doesn't transfer to JSON.
- `/continue`'s reopen caveat and the README now name `kimi -c` alongside `codex resume --last` / `grok -c`. Lifecycle is unchanged: `agent_name` comes from the registry and `agent_status` from herdr's pane hooks, so the `sh -c` wrapper (which `exec`s into kimi) doesn't affect tab teardown or state.
- `resolve` now also emits `argv_shell=` — the same words POSIX-single-quoted — and `/kickoff`/`/adopt` print that line verbatim in their outside-herdr block instead of re-deriving the quoting from a prose rule. For kimi this is safety-critical: its argv carries `;` and `exec`, so a mis-quoted render would run the `;` in the user's own interactive shell.
- A failed kimi seed is no longer silent. `&&` would kill the pane and a bare `;` let the error scroll away behind the TUI's first repaint, leaving a tab that looked like a working worker; the launch script now reports the failure and waits for a keypress before handing over to an (empty) session. Covered by a test that runs the resolved argv against a stub whose seed exits non-zero.
- kimi's model check matches the alias in **key** position (`"<model>":`) instead of anywhere in the document, so the alias appearing as a value (a `default_model`-style field) can't report an empty `models` set as available. The real listing is flat-qualified, verified live.
- `/kickoff` announces kimi's **unattended** start (no tool-approval prompts in either phase) whenever the resolved worker is kimi, and `/adopt` warns additionally — its TASK.md is summarized from another branch's commits, so it is the one path where an unattended worker acts on content the user did not write. Announce, not prompt: the autonomy is the intended shape.
- Selector surfaces swept for the new worker: `/kickoff`'s description + flag table, `/adopt`'s two selector enumerations and its manual-launch block (incl. the `sh -c` quoting caution), `/close`'s worker-degradation prose, `herdr-launch.sh`'s usage header, `plugin.json`'s description, and the `herdr-kickoff-automation` knowledge entry. `/kickoff`'s non-claude announce rule now tests "not `claude:`" instead of a per-CLI allowlist, so a future registry entry is covered without another edit.

### 1.10.0 — 2026-07-24
- `/close` step 10's commit+push prompt is now skippable per repo: a committed `.claude/work-system-close-autocommit` flag (mirrors the `.claude/work-system-agent` default precedent) routes straight to `archive-task.sh commit-push` — no `AskUserQuestion` — and reports the result exactly as the manual path does. Off by default; unset repos keep today's ask-once behavior. Per-repo only, no global default. `archive-task.sh` grew an `autocommit get|set|unset` subcommand as the single source of truth for the flag.
- The flag is honored **only once committed**: `get` reads the value from the committed object on the default branch (`git show refs/heads/<main-branch>:<rel>` — fully qualified, so a same-named tag cannot shadow the branch), never from the working tree, so a file a tool or a worktree agent merely wrote cannot waive the prompt — and neither can a working-tree edit hidden behind `git update-index --assume-unchanged`/`--skip-worktree`, which fools a diff-based guard. A locally edited flag still falls back to asking, so deliberate local disabling works. Scope stated honestly: this raises the bar from "any file write" to "a commit", not to "human-reviewed"; `commit-push`'s own guards (archive-scoped pathspec, ff-only, never force-push, refusal on unpushed history) are what bound the damage.
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ This is a **Claude Code plugin marketplace** (monorepo) containing plugins that
## Current Plugins

- **knowledge-system** (v1.9.x) — Knowledge management with three layers: Rules, Knowledge, Memory. Skills: `/init`, `/query`, `/curate`, `/reindex`, `/backfill-knowledge`, `/migrate`, `/statusline`
- **work-system** (v1.10.x) — Task and worktree workflow. Skills: `/define`, `/kickoff`, `/adopt`, `/continue`, `/status`, `/close`, `/list`, `/statusline`
- **work-system** (v1.11.x) — Task and worktree workflow (workers: Claude/codex/grok/kimi). Skills: `/define`, `/kickoff`, `/adopt`, `/continue`, `/status`, `/close`, `/list`, `/statusline`
- **pr-flow** (v1.3.x) — PR review feedback loop. Skills: `/open`, `/cycle`, `/check`, `/fix`, `/rebase`, `/merge`
- **swarm** (v0.7.x) — Local mixture-of-agents code review (external `codex`/`grok` CLIs — grok-4.5 — plus Claude lenses: 11 in 4 clusters). Every voice fans out per gated cluster; externals get file-read + web research under an OS secret-jail. P2: `/swarm:review` pipeline (scope→fan-out→merge→verify); P5: `--fix`/`--loop` apply the findings you agreed with. Skills: `/swarm:review`, `/swarm:agents`
- **settings** (v0.1.x) — Per-plugin TOML config resolved over schema defaults; each plugin owns its `schema/settings.schema.json`. Skill: `/settings` (list/show/get/set/validate). Phase 1: config surface only.
Expand Down
Loading
Loading