convertible-cli 0.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. convertible_cli-0.1.2/.claude/skills/agent-config/SKILL.md +82 -0
  2. convertible_cli-0.1.2/.claude/skills/agent-config/data/backend-fingerprints.yaml +30 -0
  3. convertible_cli-0.1.2/.claude/skills/agent-config/scripts/show.sh +136 -0
  4. convertible_cli-0.1.2/.claude/skills/assign-to-workforce/SKILL.md +242 -0
  5. convertible_cli-0.1.2/.claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh +212 -0
  6. convertible_cli-0.1.2/.claude/skills/cicd/SKILL.md +208 -0
  7. convertible_cli-0.1.2/.claude/skills/cicd/scripts/_resolve-nick.sh +43 -0
  8. convertible_cli-0.1.2/.claude/skills/cicd/scripts/portability-lint.sh +57 -0
  9. convertible_cli-0.1.2/.claude/skills/cicd/scripts/pr-reply.sh +77 -0
  10. convertible_cli-0.1.2/.claude/skills/cicd/scripts/pr-status.sh +163 -0
  11. convertible_cli-0.1.2/.claude/skills/cicd/scripts/workflow.sh +157 -0
  12. convertible_cli-0.1.2/.claude/skills/communicate/SKILL.md +336 -0
  13. convertible_cli-0.1.2/.claude/skills/communicate/scripts/fetch-issues.sh +59 -0
  14. convertible_cli-0.1.2/.claude/skills/communicate/scripts/mesh-message.sh +74 -0
  15. convertible_cli-0.1.2/.claude/skills/communicate/scripts/post-comment.sh +65 -0
  16. convertible_cli-0.1.2/.claude/skills/communicate/scripts/post-issue.sh +71 -0
  17. convertible_cli-0.1.2/.claude/skills/communicate/scripts/templates/skill-new-brief.md +85 -0
  18. convertible_cli-0.1.2/.claude/skills/communicate/scripts/templates/skill-update-brief.md +101 -0
  19. convertible_cli-0.1.2/.claude/skills/doc-test-alignment/SKILL.md +56 -0
  20. convertible_cli-0.1.2/.claude/skills/doc-test-alignment/scripts/check.sh +24 -0
  21. convertible_cli-0.1.2/.claude/skills/pypi-maintainer/SKILL.md +76 -0
  22. convertible_cli-0.1.2/.claude/skills/pypi-maintainer/scripts/switch-source.sh +102 -0
  23. convertible_cli-0.1.2/.claude/skills/run-tests/SKILL.md +51 -0
  24. convertible_cli-0.1.2/.claude/skills/run-tests/scripts/test.sh +52 -0
  25. convertible_cli-0.1.2/.claude/skills/sonarclaude/SKILL.md +85 -0
  26. convertible_cli-0.1.2/.claude/skills/sonarclaude/scripts/sonar.sh +263 -0
  27. convertible_cli-0.1.2/.claude/skills/spec-to-plan/SKILL.md +230 -0
  28. convertible_cli-0.1.2/.claude/skills/spec-to-plan/scripts/spec-to-plan.sh +102 -0
  29. convertible_cli-0.1.2/.claude/skills/think/SKILL.md +201 -0
  30. convertible_cli-0.1.2/.claude/skills/think/scripts/think.sh +101 -0
  31. convertible_cli-0.1.2/.claude/skills/version-bump/SKILL.md +67 -0
  32. convertible_cli-0.1.2/.claude/skills/version-bump/scripts/bump.py +178 -0
  33. convertible_cli-0.1.2/.claude/skills.local.yaml.example +16 -0
  34. convertible_cli-0.1.2/.flake8 +7 -0
  35. convertible_cli-0.1.2/.github/workflows/publish.yml +88 -0
  36. convertible_cli-0.1.2/.github/workflows/tests.yml +131 -0
  37. convertible_cli-0.1.2/.gitignore +225 -0
  38. convertible_cli-0.1.2/.markdownlint-cli2.yaml +23 -0
  39. convertible_cli-0.1.2/CHANGELOG.md +57 -0
  40. convertible_cli-0.1.2/CLAUDE.md +28 -0
  41. convertible_cli-0.1.2/LICENSE +21 -0
  42. convertible_cli-0.1.2/PKG-INFO +73 -0
  43. convertible_cli-0.1.2/README.md +56 -0
  44. convertible_cli-0.1.2/convertible/__init__.py +13 -0
  45. convertible_cli-0.1.2/convertible/__main__.py +10 -0
  46. convertible_cli-0.1.2/convertible/cli/__init__.py +136 -0
  47. convertible_cli-0.1.2/convertible/cli/_commands/__init__.py +1 -0
  48. convertible_cli-0.1.2/convertible/cli/_commands/cli.py +43 -0
  49. convertible_cli-0.1.2/convertible/cli/_commands/doctor.py +122 -0
  50. convertible_cli-0.1.2/convertible/cli/_commands/explain.py +38 -0
  51. convertible_cli-0.1.2/convertible/cli/_commands/learn.py +88 -0
  52. convertible_cli-0.1.2/convertible/cli/_commands/overview.py +112 -0
  53. convertible_cli-0.1.2/convertible/cli/_commands/whoami.py +106 -0
  54. convertible_cli-0.1.2/convertible/cli/_errors.py +42 -0
  55. convertible_cli-0.1.2/convertible/cli/_output.py +53 -0
  56. convertible_cli-0.1.2/convertible/explain/__init__.py +24 -0
  57. convertible_cli-0.1.2/convertible/explain/catalog.py +129 -0
  58. convertible_cli-0.1.2/culture.yaml +3 -0
  59. convertible_cli-0.1.2/docs/skill-sources.md +64 -0
  60. convertible_cli-0.1.2/pyproject.toml +72 -0
  61. convertible_cli-0.1.2/sonar-project.properties +24 -0
  62. convertible_cli-0.1.2/tests/__init__.py +0 -0
  63. convertible_cli-0.1.2/tests/test_cli.py +115 -0
  64. convertible_cli-0.1.2/tests/test_cli_introspection.py +91 -0
  65. convertible_cli-0.1.2/uv.lock +478 -0
@@ -0,0 +1,82 @@
1
+ ---
2
+ name: agent-config
3
+ description: >
4
+ Show a Culture agent's full configuration in one read-only view: its
5
+ system-prompt file (CLAUDE.md / AGENTS.md / GEMINI.md), the parallel
6
+ culture.yaml, and the agent's local .claude/skills index. Use when an
7
+ operator says "show agent <name>", "what does <agent> look like", or before
8
+ teaching/onboarding an agent and you need to see its current kit + config.
9
+ Backs the `guild show` verb. Vendored from steward (cite-don't-import);
10
+ inventory only — it reports, it does not judge alignment or drift.
11
+ type: command
12
+ ---
13
+
14
+ # agent-config — surface a Culture agent's config in one view
15
+
16
+ guildmaster is the mesh's skills supplier and owns the **inventory** surfaces:
17
+ "what kit + config does this agent have?" This skill answers exactly that for a
18
+ single agent, showing the three artifacts that together define it:
19
+
20
+ 1. **System-prompt file** (`CLAUDE.md` / `AGENTS.md` / `GEMINI.md`) — the
21
+ prompt-side guidance for the agent's backend. The script detects which file
22
+ is present from a backend-fingerprint registry.
23
+ 2. **`culture.yaml`** — the runtime-side config (`agents:` list with `suffix`,
24
+ `backend`, `model`, `system_prompt`, `channels`, `tags`, `acp_command`,
25
+ `extras`). Lives parallel to the prompt file at the project root.
26
+ 3. **`.claude/skills/*/SKILL.md`** — the per-project skills the agent can
27
+ invoke, one line each (name + truncated description).
28
+
29
+ This is the **inventory half** of the steward → guildmaster split
30
+ ([issue #12](https://github.com/agentculture/guildmaster/issues/12)): it reports
31
+ the config, it does **not** interpret drift or judge alignment. The relationship
32
+ graph and the "is this agent aligned?" judgment stay with `steward overview` /
33
+ `steward doctor`.
34
+
35
+ ## When to use
36
+
37
+ - Before `guild teach` / `guild onboard` — see an agent's current kit + config.
38
+ - When an operator asks "show me agent `<name>`" or "what does `<agent>` run".
39
+ - Read it, don't guess — before answering a question about what an agent does.
40
+
41
+ ## How to run
42
+
43
+ One script, two ways to call it (or just run `guild show`, which wraps it):
44
+
45
+ ```bash
46
+ # Path mode — point at any directory with a prompt file + culture.yaml
47
+ .claude/skills/agent-config/scripts/show.sh ../culture
48
+
49
+ # Suffix mode — resolve a registered agent suffix via the Culture server's
50
+ # manifest (location set by culture_server_yaml in skills.local.yaml)
51
+ .claude/skills/agent-config/scripts/show.sh daria
52
+ ```
53
+
54
+ Output is three sections: the detected system-prompt file, `culture.yaml` (or
55
+ `(missing)`), and a one-line summary per local skill (name + description,
56
+ truncated to 120 chars).
57
+
58
+ ## What to look at in `culture.yaml`
59
+
60
+ | Field | Why it matters |
61
+ |-------|----------------|
62
+ | `suffix` | Identifies the agent on the mesh. |
63
+ | `backend` | One of `claude` / `codex` / `copilot` / `acp`. The all-backends rule means a feature in one must land in all four. |
64
+ | `model` | Drift here changes behavior silently. |
65
+ | `system_prompt` | Should not contradict the prompt file. |
66
+ | `channels` | Where the agent listens. |
67
+ | `tags`, `extras`, `acp_command` | Backend-specific. |
68
+
69
+ ## Notes
70
+
71
+ - **Read-only.** The script never edits agent files. It reports; it does not
72
+ flag or fix drift — that judgment is steward's lane.
73
+ - **Backend-aware.** Prompt-file detection comes from
74
+ `data/backend-fingerprints.yaml` (the `prompt:` mapping), falling back to the
75
+ built-in `(CLAUDE.md AGENTS.md GEMINI.md)` list if the registry is absent.
76
+ - **Per-machine config.** Suffix mode reads `culture_server_yaml` from
77
+ `.claude/skills.local.yaml` (git-ignored), falling back to
78
+ `.claude/skills.local.yaml.example`.
79
+ - **Vendored from steward** (`agent-config`). guildmaster owns this copy and may
80
+ diverge; re-sync from steward's canonical copy when it changes. Divergences:
81
+ the SKILL.md is reframed for guildmaster's inventory role and adds
82
+ `type: command` for the culture backend's skill loader.
@@ -0,0 +1,30 @@
1
+ # Canonical backend fingerprint registry. Vendored from steward's agent-config
2
+ # skill (cite-don't-import); guildmaster owns this copy. Read by the agent-config
3
+ # show.sh (bash), which `guild show` shells out to. Upstream steward also reads
4
+ # it from a Python detector; guildmaster has no parallel detector, so only the
5
+ # `backends:` prompt mapping below is load-bearing here. Keep that mapping in
6
+ # sync with upstream when re-syncing.
7
+ #
8
+ # `prompt` — the backend's system-prompt filename at the repo root.
9
+ # `steering` — files/dirs distinctive enough to attribute to this backend.
10
+ # `shared_steering` — files/dirs that belong to NO specific backend. A repo
11
+ # declared as any backend may have these without triggering a
12
+ # mismatch. `.agents` is a generic Culture agent-config
13
+ # convention. `.claude/settings.json` and
14
+ # `.claude/settings.local.json` are generic Claude Code
15
+ # (editor/CLI) workspace config files — they appear in any
16
+ # repo that uses Claude Code as the development tool,
17
+ # regardless of the agent backend, so they must never be used
18
+ # to infer the backend or flag a mismatch. The claude backend
19
+ # is identified solely by its `CLAUDE.md` prompt file.
20
+ # `.github/copilot-instructions.md` is generic GitHub Copilot
21
+ # editor/IDE config — any repo may have it regardless of the
22
+ # declared agent backend, so it must not trigger a mismatch.
23
+ backends:
24
+ claude: { prompt: CLAUDE.md, steering: [] }
25
+ codex: { prompt: AGENTS.md, steering: [".codex"] }
26
+ acp: { prompt: AGENTS.md, steering: [".kiro"] }
27
+ copilot: { prompt: AGENTS.md, steering: [] }
28
+ gemini: { prompt: GEMINI.md, steering: [".gemini"] }
29
+ shared_steering: [".agents", ".claude/settings.json", ".claude/settings.local.json", ".github/copilot-instructions.md"]
30
+ prompt_fallback: AGENTS.md
@@ -0,0 +1,136 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ # Show a Culture agent's full configuration in one view:
4
+ # the detected system-prompt file (CLAUDE.md / AGENTS.md / GEMINI.md), the
5
+ # parallel culture.yaml, and the .claude/skills/ index.
6
+ #
7
+ # Usage: show.sh <path-or-agent-suffix>
8
+ #
9
+ # Path mode: show.sh ../culture
10
+ # Suffix mode: show.sh daria (resolved via culture_server_yaml in skills.local.yaml)
11
+ #
12
+ # Exit codes:
13
+ # 0 success
14
+ # 1 environment error (missing manifest, missing PyYAML for suffix mode)
15
+ # 2 user error (no target given, unknown suffix, target path doesn't exist)
16
+
17
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
18
+ SKILL_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
19
+ REPO_ROOT="$(cd "$SKILL_DIR/../../.." && pwd)"
20
+
21
+ CFG="$REPO_ROOT/.claude/skills.local.yaml"
22
+ [ -f "$CFG" ] || CFG="$REPO_ROOT/.claude/skills.local.yaml.example"
23
+
24
+ # Read a top-level YAML scalar from CFG. Schema is intentionally tiny:
25
+ # key: value (with optional surrounding quotes / trailing comment)
26
+ # No PyYAML dependency.
27
+ read_cfg() {
28
+ awk -v key="$1" '
29
+ $0 ~ ("^" key ":[[:space:]]*") {
30
+ sub("^" key ":[[:space:]]*", "")
31
+ sub(/[[:space:]]*#.*$/, "")
32
+ sub(/^[[:space:]]+/, ""); sub(/[[:space:]]+$/, "")
33
+ sub(/^["\047]/, ""); sub(/["\047]$/, "")
34
+ print
35
+ exit
36
+ }
37
+ ' "$CFG"
38
+ }
39
+
40
+ target="${1:-}"
41
+ if [ -z "$target" ]; then
42
+ echo "Usage: $(basename "$0") <path-or-agent-suffix>" >&2
43
+ exit 2
44
+ fi
45
+
46
+ if [ -d "$target" ]; then
47
+ DIR="$target"
48
+ else
49
+ SERVER_YAML_RAW="$(read_cfg culture_server_yaml)"
50
+ SERVER_YAML="${SERVER_YAML_RAW/#\~/$HOME}"
51
+ if [ ! -f "$SERVER_YAML" ]; then
52
+ echo "no server manifest at $SERVER_YAML — set culture_server_yaml in $CFG" >&2
53
+ echo "or pass an explicit path instead of suffix '$target'" >&2
54
+ exit 1
55
+ fi
56
+ # Suffix mode parses Culture's server manifest, whose schema is dictated by
57
+ # Culture (not by us) and includes nested mappings — too rich for awk.
58
+ # We use python+PyYAML here, with a friendly install hint if it's missing.
59
+ if ! python3 -c 'import yaml' 2>/dev/null; then
60
+ echo "suffix mode needs Python + PyYAML to parse $SERVER_YAML" >&2
61
+ echo " install: pip install --user pyyaml (or: uv pip install pyyaml)" >&2
62
+ echo " or pass an explicit path instead of suffix '$target'" >&2
63
+ exit 1
64
+ fi
65
+ # Use a dedicated exit code (2) for "unknown suffix" so the steward CLI
66
+ # wrapper can distinguish user errors (typo'd suffix) from env errors
67
+ # (missing manifest / PyYAML).
68
+ if ! DIR=$(python3 - "$SERVER_YAML" "$target" <<'PY'
69
+ import sys, yaml, pathlib
70
+ manifest_path, suffix = sys.argv[1], sys.argv[2]
71
+ m = yaml.safe_load(pathlib.Path(manifest_path).read_text()) or {}
72
+ agents = m.get('agents', {})
73
+ entry = agents.get(suffix)
74
+ if entry is None:
75
+ print(f"no agent registered with suffix {suffix!r} in {manifest_path}", file=sys.stderr)
76
+ sys.exit(2)
77
+ print(entry['directory'] if isinstance(entry, dict) else entry)
78
+ PY
79
+ ); then
80
+ exit 2
81
+ fi
82
+ fi
83
+
84
+ DIR="${DIR/#\~/$HOME}"
85
+
86
+ # Recognized prompt filenames come from the shared registry (single source
87
+ # of truth with the Python detector). Fall back to the built-in list if the
88
+ # registry isn't present (e.g. skill vendored without the data file).
89
+ REGISTRY="$SKILL_DIR/data/backend-fingerprints.yaml"
90
+ prompt_files=()
91
+ if [ -f "$REGISTRY" ]; then
92
+ while IFS= read -r pf; do
93
+ [ -n "$pf" ] && prompt_files+=("$pf")
94
+ done < <(grep -oE 'prompt:[[:space:]]*[^,}[:space:]]+' "$REGISTRY" | awk '{print $NF}' | sort -u)
95
+ fi
96
+ [ ${#prompt_files[@]} -eq 0 ] && prompt_files=(CLAUDE.md AGENTS.md GEMINI.md)
97
+
98
+ shown=0
99
+ for pf in "${prompt_files[@]}"; do
100
+ if [ -f "$DIR/$pf" ]; then
101
+ echo "=== $DIR/$pf ==="
102
+ cat "$DIR/$pf"
103
+ echo
104
+ shown=1
105
+ fi
106
+ done
107
+ if [ "$shown" -eq 0 ]; then
108
+ echo "=== $DIR (system prompt) ==="
109
+ echo "(no recognized prompt file: ${prompt_files[*]})"
110
+ echo
111
+ fi
112
+ echo "=== $DIR/culture.yaml ==="
113
+ if [ -f "$DIR/culture.yaml" ]; then cat "$DIR/culture.yaml"; else echo "(missing)"; fi
114
+ echo
115
+ echo "=== $DIR/.claude/skills/ ==="
116
+ found=0
117
+ for s in "$DIR"/.claude/skills/*/SKILL.md; do
118
+ [ -f "$s" ] || continue
119
+ found=1
120
+ name=$(awk '/^name:/{print $2; exit}' "$s")
121
+ desc=$(awk '
122
+ /^description:/ {
123
+ sub(/^description:[[:space:]]*/, "")
124
+ buf = $0
125
+ flag = 1
126
+ next
127
+ }
128
+ flag && /^[a-z_-]+:/ { flag = 0 }
129
+ flag { buf = buf " " $0 }
130
+ END { gsub(/^[[:space:]]+|[[:space:]]+$/, "", buf); print buf }
131
+ ' "$s")
132
+ printf " %-30s %s\n" "$name" "${desc:0:120}"
133
+ done
134
+ if [ "$found" -eq 0 ]; then
135
+ echo " (no skills)"
136
+ fi
@@ -0,0 +1,242 @@
1
+ ---
2
+ name: assign-to-workforce
3
+ type: command
4
+ description: >
5
+ Fan out a converged devague plan's dependency waves to parallel agents in
6
+ isolated git worktrees, one agent per task per wave, with TDD-gated merges
7
+ by the main agent. Human gates: the exported spec, the implementation split
8
+ plan (task map + per-task agent/model proposal + go/no-go), and the final PR.
9
+ The devague CLI stays deterministic and non-orchestrating (#20) — it only
10
+ *describes* the graph via `devague plan waves`; the operator (main agent)
11
+ performs the fan-out. Use when the user says "assign to workforce",
12
+ "fan out the plan", "parallel subagents", or after /spec-to-plan exports a
13
+ plan. Authored and maintained in agentculture/devague (origin = devague);
14
+ steward pulls this skill from here and broadcasts it to the AgentCulture
15
+ mesh — it is NOT vendored from steward like the other skills here.
16
+ ---
17
+
18
+ # assign-to-workforce — fan out a converged plan's waves to parallel agents
19
+
20
+ The skill is named **`assign-to-workforce`**; the product/CLI it reads is the
21
+ **`devague plan waves`** command. (The prior leg — turning a spec into a plan —
22
+ is the sibling **`/spec-to-plan`** skill.)
23
+
24
+ `assign-to-workforce` takes a **converged devague plan** and fans out its
25
+ dependency waves to parallel agents (subagents, teammate agents, or generalist
26
+ agents) — one agent per task per wave — each working in an **isolated git
27
+ worktree**. The main agent merges each completed worktree gated by TDD. The
28
+ human owns exactly three gates: the exported spec, the implementation split
29
+ plan, and the final PR.
30
+
31
+ The devague CLI is **never orchestrated by devague itself** — `devague plan
32
+ waves` describes the dependency graph (#20); it does not spawn agents, manage
33
+ worktrees, mark tasks done, or pick a backend. The fan-out is the *operator's*
34
+ job — this skill and the main agent perform it.
35
+
36
+ ## How to run
37
+
38
+ The entry point is `scripts/assign-to-workforce.sh`. Invoke it from the
39
+ repository whose plan you are implementing (plans persist under `.devague/`
40
+ in the current directory):
41
+
42
+ ```bash
43
+ bash .claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh split-plan [--plan <slug>]
44
+ bash .claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh waves [--plan <slug>] [--json]
45
+ bash .claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh help
46
+ ```
47
+
48
+ It resolves the CLI portably — an installed `devague` on `PATH` (the normal
49
+ case), falling back to `uv run devague` when you are inside the devague
50
+ checkout, else an install hint. The `split-plan` subcommand reads
51
+ `devague plan waves --json` and renders the human-facing implementation split
52
+ plan: task map, proposed per-task agent + model assignment, and the go/no-go
53
+ question. The `waves` subcommand forwards to `devague plan waves` verbatim.
54
+
55
+ ### Usage
56
+
57
+ | Subcommand | What it does |
58
+ |------------|--------------|
59
+ | `split-plan [--plan S]` | Read `devague plan waves` and print the implementation split plan — task map with per-task agent + model proposal — ready for human go/no-go review. |
60
+ | `waves [--plan S] [--json]` | Forward to `devague plan waves [--json]`. Read-only; lists wave batches. On a converged plan exits 0 listing the waves. |
61
+ | `help` | Print usage. |
62
+
63
+ ## The full flow
64
+
65
+ The flow has three human gates and one automated TDD merge loop.
66
+
67
+ ### Human gate 1 — the exported spec
68
+
69
+ The plan is seeded from a converged frame (`devague plan new --frame <slug>`).
70
+ The human reviewed and approved the spec when it was exported by the `/think`
71
+ skill. No re-approval needed here — the spec gate is already closed.
72
+
73
+ ### Human gate 2 — the implementation split plan
74
+
75
+ Before any task is assigned, the main agent presents the **implementation split
76
+ plan** for human go/no-go. This is the only gate the human owns at the
77
+ implementation stage (per task, the TDD gate is the main agent's).
78
+
79
+ The split plan contains:
80
+
81
+ 1. **Task map** — every task id, its one-line summary, acceptance criteria, and
82
+ the wave it belongs to (from `devague plan waves`).
83
+ 2. **Per-task agent + model proposal** — for each task: the proposed agent type
84
+ (subagent / teammate / generalist), the proposed model (e.g. a cheaper/faster
85
+ model for a well-scoped task), and the scope justification (why this task is
86
+ safe to delegate).
87
+ 3. **Go/no-go question** — explicit human decision: "Approve this split and
88
+ assign the plan to the workforce, or edit it first?"
89
+
90
+ The human may edit any row (agent type, model, scope) before approving. The
91
+ plan is model-agnostic — devague does not pick a backend (#20).
92
+
93
+ Run `split-plan` to print the proposed table:
94
+
95
+ ```bash
96
+ bash .claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh split-plan
97
+ ```
98
+
99
+ Do not proceed to fan-out until the human approves the split plan.
100
+
101
+ ### Fan-out — one agent per task per wave in isolated worktrees
102
+
103
+ Once the human approves, the main agent fans out each wave in order:
104
+
105
+ 1. **Create an isolated git worktree** for each task in the current wave:
106
+
107
+ ```bash
108
+ git worktree add ../worktrees/agent-<task-id> -b agent/<task-id>
109
+ ```
110
+
111
+ 2. **Spawn a task agent** inside that worktree (using the approved model from
112
+ the split plan), with:
113
+ - The task id, summary, and acceptance criteria as its brief.
114
+ - Instruction to work **test-first** (TDD): write the failing test(s) that
115
+ match the acceptance criteria before implementing.
116
+ - Instruction to commit its work to the worktree branch.
117
+
118
+ 3. **Same-wave tasks run in parallel** (within-wave tasks have no
119
+ inter-task dependency; the dependency graph guarantees this). Same-file
120
+ overlap surfaces as a merge conflict at reconcile time, not a live race —
121
+ isolated worktrees prevent clobbering.
122
+
123
+ 4. **Wait for all tasks in the wave to complete** before starting the next wave.
124
+
125
+ ### TDD-gated merge — main agent, no human per task
126
+
127
+ For each completed task worktree, the main agent:
128
+
129
+ 1. **Runs the task's tests before merge** (on the main branch): baseline must
130
+ pass (or the relevant tests must be absent — the task adds them).
131
+ 2. **Merges the worktree branch** into the main branch:
132
+
133
+ ```bash
134
+ git merge --no-ff agent/<task-id>
135
+ ```
136
+
137
+ 3. **Runs the task's tests after merge**: they must pass. If they do not, the
138
+ merge is reverted and the task agent is given the failure output to fix.
139
+ 4. **Removes the worktree** once the merge is accepted:
140
+
141
+ ```bash
142
+ git worktree remove ../worktrees/agent-<task-id>
143
+ ```
144
+
145
+ The human does **not** review individual task merges. Per-task acceptance is
146
+ the main agent's responsibility — the TDD gate (tests pass before AND after
147
+ merge) plus the task's acceptance criteria. This mirrors the non-authoritative
148
+ working state pattern of the Human Review Loop (#17): per-task merge records
149
+ are uncommitted working state; the authoritative human gate is the final PR.
150
+
151
+ Advance to the next wave only after all tasks in the current wave are merged
152
+ and their tests pass.
153
+
154
+ ### Human gate 3 — the final PR
155
+
156
+ Once all waves are merged and the full test suite passes, the main agent opens
157
+ a PR via the `cicd` skill (`agex pr open`). The human reviews and merges. This
158
+ is the last and only remaining human gate.
159
+
160
+ ## Hard rules (do not violate)
161
+
162
+ These protect the human-gate contract and the TDD guarantee.
163
+
164
+ - **Present the split plan before any fan-out.** Never spawn a task agent
165
+ without prior human approval of the implementation split plan (gate 2). The
166
+ split plan is the human's only implementation-stage decision.
167
+ - **One worktree per task.** Never run two tasks in the same worktree — file
168
+ contention is managed by isolation, not by trust in the dependency graph.
169
+ The dependency graph guarantees *logical* independence within a wave, not
170
+ *file* disjointness. Conflicts surface at merge time.
171
+ - **Tests before AND after merge — no exceptions.** The TDD gate must pass on
172
+ both sides. A merge that makes tests pass only after (not before) means the
173
+ baseline was already broken — fix the baseline first.
174
+ - **Human does not gate per-task merges.** The TDD contract replaces the
175
+ human here. Do not pause for human approval between wave tasks.
176
+ - **devague CLI is not orchestrated.** `devague plan waves` is read-only
177
+ scheduling metadata (#20). Never run `devague plan` commands inside a task
178
+ worktree to "mark a task done" or modify plan state from a subagent.
179
+ - **Three gates only.** The human's gates are: (1) the exported spec, (2) the
180
+ implementation split plan, (3) the final PR. No silent fourth gate.
181
+ - **No LLM calls in the devague CLI.** The CLI is deterministic. This skill
182
+ adds orchestration convention, not CLI behavior.
183
+
184
+ ## Output contract
185
+
186
+ The `split-plan` subcommand prints to **stdout** and exits 0 when a converged
187
+ plan is found. On error (no plan, cyclic graph) it exits non-zero with a
188
+ `hint:` line on stderr. The `waves` subcommand forwards the CLI's own output
189
+ contract (stdout, `--json` for structured output, exit 0 on success).
190
+
191
+ ## Worked example
192
+
193
+ Picking up after `/spec-to-plan` exported a plan for the frame `my-feature`:
194
+
195
+ ```bash
196
+ a() { bash .claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh "$@"; }
197
+
198
+ # 1. Inspect the waves
199
+ a waves
200
+
201
+ # 2. Present the implementation split plan for human review
202
+ a split-plan
203
+
204
+ # --- HUMAN: review the table, edit agent/model assignments if needed,
205
+ # then say "approved" to proceed ---
206
+
207
+ # 3. Fan out wave 1 (t1, t2, t3 are independent — run in parallel)
208
+ git worktree add ../worktrees/agent-t1 -b agent/t1
209
+ git worktree add ../worktrees/agent-t2 -b agent/t2
210
+ git worktree add ../worktrees/agent-t3 -b agent/t3
211
+ # ... spawn task agents in each worktree, await completion ...
212
+
213
+ # 4. TDD-gated merge for each wave-1 task (no human per task)
214
+ git merge --no-ff agent/t1 # tests pass before + after
215
+ git worktree remove ../worktrees/agent-t1
216
+ git merge --no-ff agent/t2
217
+ git worktree remove ../worktrees/agent-t2
218
+ git merge --no-ff agent/t3
219
+ git worktree remove ../worktrees/agent-t3
220
+
221
+ # 5. Advance to wave 2 (t4 depends on t1–t3 being merged)
222
+ git worktree add ../worktrees/agent-t4 -b agent/t4
223
+ # ... spawn, await, merge with TDD gate, remove worktree ...
224
+
225
+ # 6. Open the final PR (human gate 3)
226
+ bash .claude/skills/cicd/scripts/workflow.sh open
227
+ ```
228
+
229
+ The exported plan-md from `devague plan export` is the standing brief for
230
+ each task agent — its task id, summary, acceptance criteria, and the targets
231
+ it covers are already in that file.
232
+
233
+ ## Provenance
234
+
235
+ This is a **first-party** skill — its origin is `agentculture/devague`, where
236
+ the devague agent maintains it alongside the tools it operates (dogfooding),
237
+ next to its siblings `/think` and `/spec-to-plan`. It is the *third* skill in
238
+ that outbound family, covering the implementation leg after a plan converges.
239
+ The flow runs the *opposite* direction of the vendored steward skills: steward
240
+ pulls this **from** devague and broadcasts it to the rest of the AgentCulture
241
+ mesh. The `cite, don't import` policy still holds: downstream repos copy it,
242
+ they don't symlink or depend on it. See `docs/skill-sources.md`.