| name | assign-to-workforce |
| description | Fan out a converged devague plan's dependency waves to parallel agents in isolated git worktrees, one agent per task per wave, with TDD-gated merges by the main agent. Human gates: the exported spec, the implementation split plan (task map + per-task agent/model proposal + go/no-go), and the final PR. The devague CLI stays deterministic and non-orchestrating (#20) — it only *describes* the graph via `devague plan waves`; the operator (main agent) performs the fan-out. Use when the user says "assign to workforce", "fan out the plan", "parallel subagents", or after /spec-to-plan exports a plan. Authored and maintained in agentculture/devague (origin = devague); guildmaster pulls this skill from here and broadcasts it to the AgentCulture mesh — it is NOT vendored from guildmaster like the inbound skills here.
|
| type | command |
assign-to-workforce — fan out a converged plan's waves to parallel agents
The skill is named assign-to-workforce; the product/CLI it reads is the
devague plan waves command. (The prior leg — turning a spec into a plan —
is the sibling /spec-to-plan skill.)
assign-to-workforce takes a converged devague plan and fans out its
dependency waves to parallel agents (subagents, teammate agents, or generalist
agents) — one agent per task per wave — each working in an isolated git
worktree. The main agent merges each completed worktree gated by TDD. The
human owns exactly three gates: the exported spec, the implementation split
plan, and the final PR.
The devague CLI is never orchestrated by devague itself — devague plan waves describes the dependency graph (#20); it does not spawn agents, manage
worktrees, mark tasks done, or pick a backend. The fan-out is the operator's
job — this skill and the main agent perform it.
How to run
The entry point is scripts/assign-to-workforce.sh. Invoke it from the
repository whose plan you are implementing (plans persist under .devague/
in the current directory):
bash .claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh split-plan [--plan <slug>]
bash .claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh waves [--plan <slug>] [--json]
bash .claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh help
It resolves the CLI portably — an installed devague on PATH (the normal
case), falling back to uv run devague when you are inside the devague
checkout, else an install hint. The split-plan subcommand reads
devague plan waves --json — the enriched payload (devague#53 t9) that
carries every active task's summary, instruction, acceptance criteria, and
covered targets keyed by task id — and renders the human-facing
implementation split plan: task map (task id, wave, summary verbatim, whether
an instruction is present, acceptance-criteria count), proposed per-task
agent + model assignment, the go/no-go question, and — last — an End state
section that is the verbatim output of devague plan deliverables (#70),
degrading to a one-line hint on a devague too old to have the verb. The
waves subcommand forwards to devague plan waves verbatim.
Usage
| Subcommand | What it does |
|---|
split-plan [--plan S] | Read devague plan waves --json and print the implementation split plan — task map (summary/instruction/acceptance-criteria count, verbatim) with per-task agent + model proposal, go/no-go, and a trailing End state section quoting devague plan deliverables verbatim (one-line hint on an older devague) — ready for human go/no-go review. |
waves [--plan S] [--json] | Forward to devague plan waves [--json]. Read-only; lists wave batches. On a converged plan exits 0 listing the waves. |
help | Print usage. |
The full flow
The flow has three human gates and one automated TDD merge loop.
Human gate 1 — the exported spec
The plan is seeded from a converged frame (devague plan new --frame <slug>).
The human reviewed and approved the spec when it was exported by the /think
skill. No re-approval needed here — the spec gate is already closed.
Human gate 2 — the implementation split plan
Before any task is assigned, the main agent presents the implementation split
plan for human go/no-go. This is the only gate the human owns at the
implementation stage (per task, the TDD gate is the main agent's).
The split plan contains:
- Task map — every task id, its one-line summary (verbatim), whether it
carries a working instruction, its acceptance-criteria count, and the wave
it belongs to — all read straight from
devague plan waves --json (no
operator paraphrasing).
- Per-task agent + model proposal — for each task: the proposed agent type
(subagent / teammate / generalist), the proposed model (e.g. a cheaper/faster
model for a well-scoped task), and the scope justification (why this task is
safe to delegate).
- Go/no-go question — explicit human decision: "Approve this split and
assign the plan to the workforce, or edit it first?"
- End state — the verbatim output of
devague plan deliverables (#70):
what the plan actually produces — confirmed after-state claims, terminal
tasks with acceptance criteria, and surviving open items. Present this to
the human alongside the go/no-go question, not just the task map — approving
a fan-out without seeing the world it produces is the gap this closes. On a
devague too old to have the verb, this degrades to a one-line hint naming
the minimum version instead of failing the split plan.
The human may edit any row (agent type, model, scope) before approving. The
plan is model-agnostic — devague does not pick a backend (#20).
Run split-plan to print the proposed table:
bash .claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh split-plan
Do not proceed to fan-out until the human approves the split plan.
The waves --json payload — the single source for every brief
devague plan waves --json emits {"plan": "<slug>", "waves": [[...], ...], "tasks": {...}} — the ordered dependency-wave batches plus a top-level
tasks object keyed by task id, each entry carrying that task's full working
contract:
{
"plan": "<slug>",
"waves": [["t1"], ["t2", "t3"]],
"tasks": {
"t1": {
"summary": "<task summary>",
"instruction": "<verbatim instruction, or \"\" if none>",
"acceptance_criteria": ["<criterion>", "..."],
"covers": ["<c*/h* id>", "..."]
}
}
}
This one payload is enough to build a per-subagent brief with no external
context — no need to also read devague plan show --json or the exported
plan-md. split-plan reads it to render the task map above; the fan-out step
below reads the same payload to build each task agent's brief. Quote
summary, instruction, acceptance_criteria, and covers verbatim
into every brief — never paraphrase them. (Documented identically in the
sibling /spec-to-plan skill, since both skills consume the same payload —
stay consistent if either changes.)
Fan-out — one agent per task per wave in isolated worktrees
Once the human approves, the main agent fans out each wave in order:
-
Create an isolated git worktree for each task in the current wave:
git worktree add ../worktrees/agent-<task-id> -b agent/<task-id>
-
Spawn a task agent inside that worktree (using the approved model from
the split plan), with:
- The task id, summary, working instruction, acceptance criteria, and
covered targets as its brief — quoted verbatim from
devague plan waves --json (see The waves --json payload above). No operator
paraphrasing anywhere in this flow: the plan text is the contract the
user confirmed, and a reworded brief silently drifts from it. If a task
has no instruction (""), say so rather than inventing one.
- Instruction to work test-first (TDD): write the failing test(s) that
match the acceptance criteria before implementing.
- Instruction to commit its work to the worktree branch.
-
Same-wave tasks run in parallel (within-wave tasks have no
inter-task dependency; the dependency graph guarantees this). Same-file
overlap surfaces as a merge conflict at reconcile time, not a live race —
isolated worktrees prevent clobbering.
-
Wait for all tasks in the wave to complete before starting the next wave.
TDD-gated merge — main agent, no human per task
For each completed task worktree, the main agent:
-
Runs the task's tests before merge (on the main branch): baseline must
pass (or the relevant tests must be absent — the task adds them).
-
Merges the worktree branch into the main branch:
git merge --no-ff agent/<task-id>
-
Runs the task's tests after merge: they must pass. If they do not, the
merge is reverted and the task agent is given the failure output to fix.
-
Removes the worktree once the merge is accepted:
git worktree remove ../worktrees/agent-<task-id>
The human does not review individual task merges. Per-task acceptance is
the main agent's responsibility — the TDD gate (tests pass before AND after
merge) plus the task's acceptance criteria. This mirrors the non-authoritative
working state pattern of the Human Review Loop (#17): per-task merge records
are uncommitted working state; the authoritative human gate is the final PR.
Advance to the next wave only after all tasks in the current wave are merged
and their tests pass.
Human gate 3 — the final PR
Once all waves are merged and the full test suite passes, the main agent opens
a PR via the cicd skill (devex pr open). The human reviews and merges. This
is the last and only remaining human gate.
After the final PR — summarize the delivery
Once the final PR is merged, close the execution loop cleanly instead of
stopping at a green merge:
- Summarize the delivery. Run the sibling
/summarize-delivery skill —
the delivery-side closure leg. It turns the run into a committed
accountability artifact (docs/deliveries/<created-date>-<slug>.md) that
records planned-versus-actual delivery, the mid-work decisions the workforce
made, where execution drifted from the plan, evidence-backed delivery claims
(a claim without evidence stays unverified, never asserted as done), and
any remaining work. The devague plan waves --json payload you fanned out is
the planned-work baseline it compares actuals against.
- It closes partial and failed runs too.
/summarize-delivery does not
require every wave to have merged — a run that shipped only some tasks, or
none, still produces a truthful artifact: the failure lands under drift and
remaining work, and no claim says done without evidence.
This is the accountability wrap-up after the three gates, not a fourth gate —
/summarize-delivery is method-only and read-only (#20): it summarizes the run,
it does not orchestrate, gate merges, or mutate devague state. Don't stop at
"PR merged" — the standing flow is merge, then /summarize-delivery.
Hard rules (do not violate)
These protect the human-gate contract and the TDD guarantee.
- Present the split plan before any fan-out. Never spawn a task agent
without prior human approval of the implementation split plan (gate 2). The
split plan is the human's only implementation-stage decision.
- One worktree per task. Never run two tasks in the same worktree — file
contention is managed by isolation, not by trust in the dependency graph.
The dependency graph guarantees logical independence within a wave, not
file disjointness. Conflicts surface at merge time.
- Tests before AND after merge — no exceptions. The TDD gate must pass on
both sides. A merge that makes tests pass only after (not before) means the
baseline was already broken — fix the baseline first.
- Human does not gate per-task merges. The TDD contract replaces the
human here. Do not pause for human approval between wave tasks.
- devague CLI is not orchestrated.
devague plan waves is read-only
scheduling metadata (#20). Never run devague plan commands inside a task
worktree to "mark a task done" or modify plan state from a subagent.
- Three gates only. The human's gates are: (1) the exported spec, (2) the
implementation split plan, (3) the final PR. No silent fourth gate.
- No LLM calls in the devague CLI. The CLI is deterministic. This skill
adds orchestration convention, not CLI behavior.
Output contract
The split-plan subcommand prints to stdout and exits 0 when a converged
plan is found. On error (no plan, cyclic graph) it exits non-zero with a
hint: line on stderr. The waves subcommand forwards the CLI's own output
contract (stdout, --json for structured output, exit 0 on success).
The trailing End state section (#70) never fails split-plan: on a devague
new enough to have plan deliverables, it quotes that command's stdout
verbatim under an End state (from \devague plan deliverables`):header; on an olderdevague, it prints exactly one hint line naming the minimum version (e.g. hint: End state view requires devague >= 0.18.0 (devague plan
deliverables)) and split-plan` still exits 0.
Worked example
Picking up after /spec-to-plan exported a plan for the frame my-feature:
a() { bash .claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh "$@"; }
a waves
a split-plan
git worktree add ../worktrees/agent-t1 -b agent/t1
git worktree add ../worktrees/agent-t2 -b agent/t2
git worktree add ../worktrees/agent-t3 -b agent/t3
git merge --no-ff agent/t1
git worktree remove ../worktrees/agent-t1
git merge --no-ff agent/t2
git worktree remove ../worktrees/agent-t2
git merge --no-ff agent/t3
git worktree remove ../worktrees/agent-t3
git worktree add ../worktrees/agent-t4 -b agent/t4
bash .claude/skills/cicd/scripts/workflow.sh open
devague plan waves --json is the standing brief for each task agent — its
task id, summary, instruction, acceptance criteria, and the targets it covers
are all in that one payload. Quote those fields verbatim into each task
agent's brief; the fan-out is honest only if what the subagent builds against
is exactly what the user confirmed in the plan.
Provenance
This is a first-party skill — its origin is agentculture/devague, where
the devague agent maintains it alongside the tools it operates (dogfooding),
next to its siblings /think and /spec-to-plan. It is the third skill in
that outbound family, covering the implementation leg after a plan converges.
The flow runs the opposite direction of the vendored guildmaster skills:
guildmaster pulls this from devague and broadcasts it to the rest of the
AgentCulture mesh. The cite, don't import policy still holds: downstream repos copy it,
they don't symlink or depend on it. See docs/skill-sources.md.