Skip to content
Open
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
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"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.9.2"
"version": "1.9.3"
},
{
"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 @@ -11,7 +11,7 @@
## Features
- `features/backfill-and-origin-metadata.md` — `/backfill-knowledge` significance bar + origin-reconstruction cascade
- `features/statusline-integration.md` — Status-line segments: plugins can't own `statusLine.command`; marker-block injection; the `[ks …]` + `[ws …]` two-segment coexistence and ws's never-block-on-network PR cache
- `features/herdr-kickoff-automation.md` — herdr `herdr-launch.sh`: `launch` (`/kickoff`) + `resume` (`/continue <task>` reopens an `/exit`-closed tab)
- `features/herdr-kickoff-automation.md` — herdr `herdr-launch.sh`: `launch` (`/kickoff` + `/adopt`, which references kickoff's step 12/13 prose to avoid drift) + `resume` (`/continue <task>` reopens an `/exit`-closed tab)
- `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
Expand Down
40 changes: 32 additions & 8 deletions .claude/knowledge/features/herdr-kickoff-automation.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
---
title: "herdr /kickoff + /continue-reopen Automation"
createdAt: 2026-06-24
updatedAt: 2026-07-21
updatedAt: 2026-07-23
createdFrom: "PR #17"
updatedFrom: "session: 2026-07-21 (fully-qualify kickoff's /continue)"
pluginVersion: 1.9.2
updatedFrom: "session: 2026-07-23 (adopt auto-launch reuses launch)"
pluginVersion: 1.9.3
prime: false
reindexedAt: 2026-07-12
---
Expand All @@ -14,7 +14,8 @@ reindexedAt: 2026-07-12
Inside a herdr session, `/kickoff` replaces its manual "open a terminal yourself"
block with an automated tab launch. The launch lives in one shared, testable
helper — `plugins/work-system/scripts/herdr-launch.sh` — with two subcommands:
`launch` (called from `skills/kickoff/SKILL.md` step 13) and `resume` (called from
`launch` (called from **both** `skills/kickoff/SKILL.md` step 13 and
`skills/adopt/SKILL.md` step 13 — see the adopt note below) and `resume` (called from
`skills/continue/SKILL.md`'s reopen path — the main session with a `<task>` arg, or
a *different* task's name given from inside a worktree). The helper is the source of
truth; this entry captures the durable design and one non-obvious gotcha.
Expand All @@ -23,10 +24,10 @@ truth; this entry captures the durable design and one non-obvious gotcha.

- **Encapsulate the launch in a script, not skill prose.** The deterministic
sequence (gate → `agent start` → robust pane-id parse → `pane move` → exit code)
lives in `herdr-launch.sh` so it can be `bash`-tested and reused (e.g. by a
future `/adopt` automation), per the project's helper-script convention and the
"prose skill logic drifts" memory. The skill only derives the label and branches
on the helper's `moved=yes|no` / exit code.
lives in `herdr-launch.sh` so it can be `bash`-tested and reused — realized in
work-system 1.9.3 by `/adopt` (see the adopt note below) — per the project's
helper-script convention and the "prose skill logic drifts" memory. The skill only
derives the label and branches on the helper's `moved=yes|no` / exit code.
- **Spawn the worker as argv, never type it into a shell.** The launch is
`herdr agent start "<label>" … -- <worker argv>`, which execs the worker binary
directly. As of work-system 1.9.0 the worker argv is **resolved from the chosen
Expand Down Expand Up @@ -113,6 +114,29 @@ truth; this entry captures the durable design and one non-obvious gotcha.
in all of this — every case above, plus the stdout contract, as regression
coverage the first round shipped without.

## `/adopt` auto-launch: reference kickoff's prose, don't duplicate it

work-system 1.9.3 gave `/adopt` the same in-herdr tab launch as `/kickoff`: after it
builds the worktree from an existing branch, `skills/adopt/SKILL.md` step 13 calls the
identical `herdr-launch.sh launch "$LABEL" "$WORKTREE" "$HERDR_WORKSPACE_ID" "$SELECTOR"`
(step 12 resolves the worker selector exactly as kickoff does — `/adopt` grew an
optional `[agent-selector]` arg for it). Two durable decisions:

- **One copy of the intricate branching.** The launch *helper* is already the single
source of truth for the mechanics, but the *skill prose* around it (the picker/announce
rules of step 12, and the exit-0-`moved`/exit-2/exit-3/non-zero result branching of
step 13) is stateful logic that drifts if copied — the "prose skill logic drifts"
memory. So adopt's steps **reference** `kickoff/SKILL.md` step 12/13 for that shared
logic and inline only the adopt-specific deltas, rather than a full paraphrase that
would silently diverge under later edits.
- **Adopt-specific deltas that must stay inline.** (1) The `LABEL` derives from the
*resolved* task name (prefix-stripped), because `/adopt` may **keep the original
branch name** rather than rename to `task/<name>` — deriving from the branch would
give a nonsense label. (2) The success/manual templates show `<current-branch-name>`
(the adopted branch, possibly not `task/<name>`), not kickoff's assumed `task/<name>`.
(3) The worktree path is built from the `<main-repo>` captured in adopt step 1, never a
possibly-drifted CWD (adopt runs in the main-repo session — its whole cwd-safety spine).

## `resume` mode: reopen a task tab a `/exit` closed

A kickoff tab runs Claude as its **root pane** (argv-exec above), so a clean `/exit`
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Lightweight, native knowledge management for Claude Code projects. Three layers

### Work System

Generic task and worktree workflow system. Manage tasks as markdown files, work in isolated git worktrees, and track progress through the full lifecycle. `/kickoff` runs the repo's default worker agent (Claude, codex, or grok — a single committed per-project default), or, when none is set, shows a picker and offers to save your choice; override per run with flags like `--opus`/`--sol` or `--pick`. Inside a [herdr](plugins/work-system/README.md#herdr-integration) session it auto-opens a tab (named after the task, shortened for the sidebar and prefixed with the task's state glyph — `●` active, `◇` in review, `◆` approved, `✓` merged) with the worktree as cwd, starts the chosen worker, and — for a Claude worker — runs `/work-system:continue` for you (plugin-qualified, since a Claude Code built-in `/continue` shadows the bare skill); `/work-system:continue <task>` from the main session reopens that tab and resumes it if a stray `/exit` closed it; and `/close` tears the tab down again when the task is merged.
Generic task and worktree workflow system. Manage tasks as markdown files, work in isolated git worktrees, and track progress through the full lifecycle. `/kickoff` runs the repo's default worker agent (Claude, codex, or grok — a single committed per-project default), or, when none is set, shows a picker and offers to save your choice; override per run with flags like `--opus`/`--sol` or `--pick`. Inside a [herdr](plugins/work-system/README.md#herdr-integration) session it auto-opens a tab (named after the task, shortened for the sidebar and prefixed with the task's state glyph — `●` active, `◇` in review, `◆` approved, `✓` merged) with the worktree as cwd, starts the chosen worker, and — for a Claude worker — runs `/work-system:continue` for you (plugin-qualified, since a Claude Code built-in `/continue` shadows the bare skill); `/adopt` auto-opens the same tab once it has built the worktree from an existing branch; `/work-system:continue <task>` from the main session reopens that tab and resumes it if a stray `/exit` closed it; and `/close` tears the tab down again when the task is merged.

**Commands:** `/define`, `/kickoff`, `/adopt`, `/continue`, `/status`, `/close`, `/list`, `/statusline`

Expand Down
2 changes: 1 addition & 1 deletion plugins/work-system/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "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.9.2",
"version": "1.9.3",
"author": {
"name": "gering"
},
Expand Down
22 changes: 16 additions & 6 deletions plugins/work-system/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,18 +188,22 @@ note into the worktree is an optional way to give them standing task guidance.
## herdr integration

When you run the work system inside a **herdr** session (herdr is a terminal
multiplexer for AI coding agents), `/kickoff` and `/close` automate the terminal
juggling you'd otherwise do by hand — `/kickoff` opens the task's tab, `/close`
tears it down. They activate when `HERDR_ENV=1`, a herdr workspace id is set, and
multiplexer for AI coding agents), `/kickoff`, `/adopt`, and `/close` automate the
terminal juggling you'd otherwise do by hand — `/kickoff` and `/adopt` open the
task's tab, `/close` tears it down. They activate when `HERDR_ENV=1`, a herdr workspace id is set, and
both `herdr` and `python3` are on `PATH`; if any prerequisite is missing or the
socket is unreachable they fall back to the plain, herdr-free behaviour, so you're
never left stranded. Outside herdr, every skill behaves exactly as documented above.

### `/kickoff` opens a named tab
### `/kickoff` and `/adopt` open a named tab

Inside herdr, `/kickoff` doesn't just create the worktree and print manual
instructions — it opens a new herdr **tab** in the *same* workspace, with the
worktree as its cwd, and starts the task there for you:
worktree as its cwd, and starts the task there for you. `/adopt` does exactly the
same once it has created the worktree from an existing branch — same helper, same
tab, same worker selection (`--opus`/`--sol`/`--grok`/`--pick`, or the repo default);
its tab label comes from the *resolved* task name, so it's sensible even when `/adopt`
keeps the original branch name rather than renaming it to `task/<name>`:

- The tab is **named after the task** (shortened for a readable sidebar — see
`skills/kickoff/SKILL.md` step 13 for the exact rule), so the sidebar shows one
Expand Down Expand Up @@ -306,14 +310,20 @@ keep the plain label, since those are stable identities.
Already started work on a branch outside the work system? Use `/adopt` to bring it in:

```
> /adopt feature/dark-mode
> /adopt feature/dark-mode # repo default worker
> /adopt feature/dark-mode --opus # claude on opus
> /adopt feature/dark-mode --sol # codex on gpt-5.6-sol
> /adopt feature/dark-mode --pick # force the interactive picker
```

This will:
1. Analyze your branch's commit history and changed files
2. Generate a task file from that context
3. Optionally rename the branch to `task/<name>` for consistency
4. Create a worktree and set everything up
5. Inside a [herdr](#herdr-integration) session, open the task's tab and start the
chosen worker there (same auto-launch as `/kickoff`); outside herdr it prints the
manual launch command instead

After adoption, the standard workflow applies (`/continue`, `/status`, `/close`).

Expand Down
91 changes: 82 additions & 9 deletions plugins/work-system/skills/adopt/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ user_invocable: true

## Arguments

- `$ARGUMENTS` - Optional: branch name to adopt
- `$ARGUMENTS` — `<branch> [agent-selector]`: optional branch name to adopt, plus an
optional worker-agent selector (same set as `/kickoff`: `--opus`, `--sol`, `--grok`,
`--codex`, `--agent <cli[:model]>`, `--pick`). The selector chooses the worker the
herdr auto-launch (step 13) starts; omit it to use the repo default.

## Critical: never persist a `cd` into the worktree

Expand Down Expand Up @@ -116,7 +119,73 @@ The Bash tool persists CWD between calls — a bare `cd .claude/worktrees/<task>
- Run: `pwd` and compare to the `<main-repo>` path captured by the helper in step 1.
- If they differ, **stop and report an error**: "Session CWD drifted into the worktree during adopt — investigate which step ran a persistent `cd`." Do not silently continue.

12. **Final output for the user** (display this block — do *not* execute the `cd`):
12. **Select the worker agent** — same as `/kickoff` step 12. Turn the selector
portion of `$ARGUMENTS` (anything after the branch name) into a concrete
`SELECTOR` for the launch helper, and set `OFFER_DEFAULT` (`no`, flipped to `yes`
only when the picker asks to save). With
`REG="${CLAUDE_PLUGIN_ROOT}/scripts/agent-registry.sh"`: an explicit flag
(`--opus`/`--sol`/`--grok`/`--codex`/`--agent <cli[:model]>`) is used verbatim, no
default offer; no flag reads the repo default (`SELECTOR="$(bash "$REG" default
get)"` — announce it before launching when it's a non-claude worker, then launch;
empty → the picker); `--pick`, or no flag with no default set, runs the picker
(`bash "$REG" list` → **AskUserQuestion**, plus a "Save as project default?"
question that sets `OFFER_DEFAULT=yes` only on Yes). **The picker/announce rules are
identical to `skills/kickoff/SKILL.md` step 12 — follow that one copy, not a
divergent paraphrase.** The helper (step 13) resolves and validates `SELECTOR`, so
don't resolve models/availability yourself.

13. **Launch the worktree session** — automate inside herdr, otherwise show the
manual block. Inside herdr this replaces the old "print manual instructions" final
step: `/adopt` now opens the task's tab for you, exactly like `/kickoff`.

Gate (same as kickoff): automate **only** when `[ "${HERDR_ENV:-}" = "1" ]`, a
non-empty `$HERDR_WORKSPACE_ID`, and both `command -v herdr` and `command -v
python3` succeed. Otherwise show the manual block (b). The helper re-checks these
and exits non-zero if it cannot automate, so a broken socket degrades to (b) too.

**a) Inside herdr — open a named tab that auto-continues.** Derive a short,
sidebar-friendly `LABEL` from the **resolved task name** (`<task-name>` from step 3,
which already stripped `task/`/`feature/`/`fix/`… prefixes — so the label stays
sensible even when step 8 kept the *original* branch name). Drop filler words,
hard-cap ~32 chars, pass it PLAIN (the helper prefixes the task's state glyph onto
the tab label). The worktree path is absolute — build it from the `<main-repo>`
captured in step 1 (never from a drifted CWD):

```sh
WORKTREE="<main-repo>/.claude/worktrees/<task-name>" # absolute path
LABEL="<short sidebar label>"
bash "${CLAUDE_PLUGIN_ROOT}/scripts/herdr-launch.sh" launch "$LABEL" "$WORKTREE" "$HERDR_WORKSPACE_ID" "$SELECTOR"
```

This is the **same helper and call `/kickoff` uses** — the single source of truth
for selector resolution, argv-launch, tab-move, and exit codes. **Branch on its
result exactly as `skills/kickoff/SKILL.md` step 13a describes** (exit 0 `moved=yes`
→ new background tab; `moved=no` → running as a split in *this* tab, relay the
helper's stderr; the `OFFER_DEFAULT=yes` → `bash "$REG" default set "<agent>"`
persistence after a successful launch; exit 2 unknown selector → re-offer the
picker; exit 3 unavailable agent → report `unavailable=`/`note=` verbatim, re-offer;
other non-zero → relay stderr, then the manual block). Do not re-implement that
branching here — following one copy keeps adopt and kickoff from drifting.

Success report (adopt keeps the *adopted* branch name — use `<current-branch-name>`,
which is `task/<task-name>` only if step 8 renamed it):
```
Branch adopted and launched in herdr!

Tab: <LABEL> (workspace <HERDR_WORKSPACE_ID>, opened in the background)
Agent: <cli:model> (the helper's `agent=` line)
Worktree: .claude/worktrees/<task-name>
Branch: <current-branch-name>

The new tab is already running the worker. Switch to it to work there.
```

**b) Outside herdr (or on any fallback) — manual instructions.** Resolve the
selector to the exact launch command (registry-driven — do not hand-write it per
CLI): `bash "$REG" resolve "$SELECTOR" --session "<task-name>"`. Take the `argv=`
lines in order and **shell-quote each word** (the codex/grok bootstrap prompt is one
`argv=` word containing spaces; space-joining raw would split it). Display this block
— do **not** execute the `cd`:
```
Branch adopted into work system!

Expand All @@ -130,14 +199,18 @@ The Bash tool persists CWD between calls — a bare `cd .claude/worktrees/<task>
session — this session stays in the main repo) and run:

cd .claude/worktrees/<task-name>
claude -n "<task-name>" "/work-system:continue"
<the argv= words, each shell-quoted>
```
`-n "<task-name>"` names the session (shown in `/resume` and the terminal title);
the `/work-system:continue` initial prompt runs the resume flow (load TASK.md, recent
commits, progress) deterministically — both in one launch. Use the plugin-qualified
form: a Claude Code built-in `/continue` shadows the bare skill name. Do **not** execute
the `cd` yourself
— it is for the user's new terminal.
For a **claude** worker that is `claude --model <m> -n "<task-name>"
"/work-system:continue"` — `-n` names the session (shown in `/resume`),
`/work-system:continue` runs the resume flow (load TASK.md, commits, progress).
Use the plugin-qualified form: a Claude Code built-in `/continue` shadows the bare
skill. For **codex/grok** it's `codex -m <model> '<bootstrap prompt>'`. Do **not**
execute the `cd` yourself — it is for the user's new terminal. If `resolve` exits
non-zero (2 unknown / 3 unavailable), surface that instead and re-offer the picker.
On the picker's "save default" path, persist only after the user confirms the worker
is up (see kickoff step 13b) — you (this main-repo session) then run
`bash "$REG" default set "<name>"`; it writes the committed `.claude/work-system-agent`.

## Remember

Expand Down
Loading