Skip to content

Commit 44ea67f

Browse files
jwaldripclaude
andcommitted
feat(plugin): per-unit workflows with design discipline support
Units can now specify their own workflow via a `workflow:` frontmatter field that overrides the intent-level workflow. This enables different hat sequences for different types of work within the same intent. Added `design` workflow (planner -> designer -> reviewer) for UI/UX units that produce design artifacts before implementation. Design as its own disciplined unit means a human can own design while AI handles other units. Changes: - Add `design` workflow to workflows.yml - Add `workflow:` field to unit frontmatter template - Construct resolves per-unit workflow at spawn time, stores in unitStates for hat advancement - Advance/fail skills use unit's workflow instead of global - Elaborate suggests workflows per discipline (design, adversarial, default) during decomposition Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent bc83082 commit 44ea67f

File tree

5 files changed

+83
-24
lines changed

5 files changed

+83
-24
lines changed

plugin/skills/advance/SKILL.md

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,20 @@ STATE=$(han keep load iteration.json --quiet)
3838
### Step 2: Determine Next Hat (or Handle Completion)
3939

4040
```javascript
41-
const workflow = state.workflow || ["planner", "builder", "reviewer"];
42-
const currentIndex = workflow.indexOf(state.hat);
41+
// Resolve workflow for this unit: per-unit workflow takes priority, then intent-level fallback
42+
const currentUnit = state.currentUnit;
43+
const unitWorkflow = (currentUnit && state.unitStates?.[currentUnit]?.workflow)
44+
|| state.workflow
45+
|| ["planner", "builder", "reviewer"];
46+
const currentIndex = unitWorkflow.indexOf(state.hat);
4347
const nextIndex = currentIndex + 1;
4448

45-
if (nextIndex >= workflow.length) {
49+
if (nextIndex >= unitWorkflow.length) {
4650
// At last hat - check DAG status to determine next action
4751
// See Steps 2b-2d below
4852
}
4953

50-
const nextHat = workflow[nextIndex];
54+
const nextHat = unitWorkflow[nextIndex];
5155
```
5256
5357
### Step 2b: Last Hat Logic (Completion/Loop/Block)
@@ -304,20 +308,26 @@ The integrator specifies which units need rework. For each rejected unit:
304308
305309
```bash
306310
source "${CLAUDE_PLUGIN_ROOT}/lib/dag.sh"
307-
WORKFLOW_HATS=$(echo "$STATE" | han parse json workflow)
308-
FIRST_HAT=$(echo "$WORKFLOW_HATS" | jq -r '.[0]')
311+
INTENT_WORKFLOW_HATS=$(echo "$STATE" | han parse json workflow)
309312

310313
# Re-queue each rejected unit
311314
for UNIT_FILE in $REJECTED_UNITS; do
312315
update_unit_status "$UNIT_FILE" "pending"
313316

314-
# Reset hat to first workflow hat in unitStates (teams mode)
317+
# Reset hat to first hat of this unit's workflow (per-unit or intent-level fallback)
315318
UNIT_NAME=$(basename "$UNIT_FILE" .md)
316-
STATE=$(echo "$STATE" | han parse json --set "unitStates.${UNIT_NAME}.hat=${FIRST_HAT}" --set "unitStates.${UNIT_NAME}.retries=0")
319+
UNIT_WORKFLOW=$(echo "$STATE" | han parse json "unitStates.${UNIT_NAME}.workflow" 2>/dev/null || echo "")
320+
[ -z "$UNIT_WORKFLOW" ] || [ "$UNIT_WORKFLOW" = "null" ] && UNIT_WORKFLOW="$INTENT_WORKFLOW_HATS"
321+
FIRST_HAT=$(echo "$UNIT_WORKFLOW" | jq -r '.[0]')
322+
STATE=$(echo "$STATE" | han parse json \
323+
--set "unitStates.${UNIT_NAME}.hat=${FIRST_HAT}" \
324+
--set "unitStates.${UNIT_NAME}.retries=0" \
325+
--set "unitStates.${UNIT_NAME}.workflow=${UNIT_WORKFLOW}")
317326
done
318327
319328
# Reset integrator state
320-
STATE=$(echo "$STATE" | han parse json --set "hat=${FIRST_HAT}" --set "integratorComplete=false")
329+
GLOBAL_FIRST_HAT=$(echo "$INTENT_WORKFLOW_HATS" | jq -r '.[0]')
330+
STATE=$(echo "$STATE" | han parse json --set "hat=${GLOBAL_FIRST_HAT}" --set "integratorComplete=false")
321331
han keep save iteration.json "$STATE"
322332
323333
# Output: "Integrator rejected. Re-queued units: {list}. Run /construct to continue."

plugin/skills/construct/SKILL.md

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -393,9 +393,8 @@ Loop over ALL ready units from the DAG (not just one):
393393
source "${CLAUDE_PLUGIN_ROOT}/lib/dag.sh"
394394
READY_UNITS=$(find_ready_units "$INTENT_DIR")
395395

396-
# Determine first construction hat
397-
WORKFLOW_HATS=$(echo "$STATE" | han parse json workflow)
398-
FIRST_HAT=$(echo "$WORKFLOW_HATS" | jq -r '.[0]')
396+
# Intent-level workflow (default fallback)
397+
INTENT_WORKFLOW_HATS=$(echo "$STATE" | han parse json workflow)
399398
```
400399

401400
**Include repo URL for cowork**: If operating in a cloned workspace, include the repo URL in each teammate's prompt: "Repository: `<remote-url>`. Clone and checkout `ai-dlc/<intent-slug>` if you don't have local access." This enables teammates to clone independently in cowork mode.
@@ -426,10 +425,35 @@ fi
426425
update_unit_status "$UNIT_FILE" "in_progress"
427426
```
428427

429-
3. **Initialize unit state in `unitStates`**:
428+
3. **Resolve per-unit workflow** — read the unit's `workflow:` frontmatter field. If present, resolve it to a hat sequence. If absent, fall back to the intent-level workflow:
429+
430+
```bash
431+
UNIT_WORKFLOW_NAME=$(han parse yaml workflow -r --default "" < "$UNIT_FILE" 2>/dev/null || echo "")
432+
433+
if [ -n "$UNIT_WORKFLOW_NAME" ]; then
434+
# Resolve unit-specific workflow
435+
UNIT_WORKFLOW_HATS=""
436+
if [ -f ".ai-dlc/workflows.yml" ]; then
437+
UNIT_WORKFLOW_HATS=$(han parse yaml "${UNIT_WORKFLOW_NAME}.hats" < ".ai-dlc/workflows.yml" 2>/dev/null || echo "")
438+
fi
439+
if [ -z "$UNIT_WORKFLOW_HATS" ] && [ -f "${CLAUDE_PLUGIN_ROOT}/workflows.yml" ]; then
440+
UNIT_WORKFLOW_HATS=$(han parse yaml "${UNIT_WORKFLOW_NAME}.hats" < "${CLAUDE_PLUGIN_ROOT}/workflows.yml" 2>/dev/null || echo "")
441+
fi
442+
[ -z "$UNIT_WORKFLOW_HATS" ] && UNIT_WORKFLOW_HATS="$INTENT_WORKFLOW_HATS"
443+
else
444+
UNIT_WORKFLOW_HATS="$INTENT_WORKFLOW_HATS"
445+
fi
446+
447+
FIRST_HAT=$(echo "$UNIT_WORKFLOW_HATS" | jq -r '.[0]')
448+
```
449+
450+
4. **Initialize unit state in `unitStates`** (includes the resolved workflow):
430451

431452
```bash
432-
STATE=$(echo "$STATE" | han parse json --set "unitStates.${UNIT_NAME}.hat=${FIRST_HAT}" --set "unitStates.${UNIT_NAME}.retries=0")
453+
STATE=$(echo "$STATE" | han parse json \
454+
--set "unitStates.${UNIT_NAME}.hat=${FIRST_HAT}" \
455+
--set "unitStates.${UNIT_NAME}.retries=0" \
456+
--set "unitStates.${UNIT_NAME}.workflow=${UNIT_WORKFLOW_HATS}")
433457
han keep save iteration.json "$STATE"
434458
```
435459

@@ -523,8 +547,9 @@ The lead processes auto-delivered teammate messages. Handle each event type:
523547
When a teammate reports successful completion:
524548

525549
1. Read current hat for this unit from `unitStates.{unit}.hat`
526-
2. Find current hat's index in the `workflow` array
527-
3. Determine next hat: `workflow[currentIndex + 1]`
550+
2. Read this unit's workflow from `unitStates.{unit}.workflow` (per-unit workflow, already resolved at spawn time)
551+
3. Find current hat's index in the unit's workflow array
552+
4. Determine next hat: `unitWorkflow[currentIndex + 1]`
528553

529554
**If next hat exists** (not at end of workflow):
530555

@@ -878,14 +903,16 @@ The `iteration.json` is extended with `unitStates` for parallel hat tracking:
878903
"workflow": ["planner", "builder", "reviewer"],
879904
"teamName": "ai-dlc-my-intent",
880905
"unitStates": {
881-
"unit-01-foundation": { "hat": "reviewer", "retries": 0 },
882-
"unit-02-dag-view": { "hat": "builder", "retries": 1 }
906+
"unit-01-foundation": { "hat": "reviewer", "retries": 0, "workflow": ["planner", "builder", "reviewer"] },
907+
"unit-02-design-dashboard": { "hat": "designer", "retries": 0, "workflow": ["planner", "designer", "reviewer"] },
908+
"unit-03-dag-view": { "hat": "builder", "retries": 1, "workflow": ["planner", "builder", "reviewer"] }
883909
}
884910
}
885911
```
886912

887913
- `hat`: Current hat for this specific unit
888914
- `retries`: Number of reviewer rejection cycles (max 3 before escalating to blocked)
915+
- `workflow`: The hat sequence for this unit (resolved from unit frontmatter `workflow:` field, falling back to intent-level workflow)
889916
- Units are added when spawned, removed when completed
890917

891918
---

plugin/skills/elaborate/SKILL.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,20 @@ Do NOT ask the user whether to decompose. Assess the complexity from the domain
480480

481481
1. **Units MUST NOT span dependency boundaries.** If a piece of work depends on another piece being done first, those are two separate units with an explicit `depends_on` edge. This applies regardless of change strategy (`unit` or `intent`). A unit that contains both "set up the database schema" and "build the API that uses it" is a bad unit — those are two units where the API unit depends on the schema unit.
482482

483-
2. **Units MUST NOT span domains.** A unit has exactly one discipline (frontend, backend, api, documentation, devops, etc.). No unit should mix frontend and backend work, or API and documentation, etc. If a feature needs both a backend endpoint and a frontend view, those are two units — the frontend unit `depends_on` the backend unit.
483+
2. **Units MUST NOT span domains.** A unit has exactly one discipline (frontend, backend, api, documentation, devops, design, etc.). No unit should mix frontend and backend work, or API and documentation, etc. If a feature needs both a backend endpoint and a frontend view, those are two units — the frontend unit `depends_on` the backend unit.
484+
485+
3. **Design work is its own unit.** If a feature needs UI/UX design work (mockups, component design, interaction flows), create a separate unit with `discipline: design` and `workflow: design`. The design workflow runs `planner → designer → reviewer`. Frontend implementation units should `depends_on` the design unit so builders have finalized designs to implement against. This also enables a human to own the design unit while AI handles other units.
486+
487+
**Per-unit workflow suggestions:** Different units may benefit from different workflows based on their discipline or risk profile. When decomposing, suggest an appropriate workflow for each unit:
488+
489+
| Discipline / Concern | Suggested Workflow | Rationale |
490+
|---|---|---|
491+
| `backend`, `api`, `devops`, `documentation` | `default` (planner → builder → reviewer) | Standard implementation cycle |
492+
| `design` | `design` (planner → designer → reviewer) | Design artifacts need design hat, not builder |
493+
| Security-sensitive units | `adversarial` (planner → builder → red-team → blue-team → reviewer) | Adversarial testing for auth, crypto, data handling |
494+
| Units without a clear workflow need | (omit `workflow:` field) | Inherits the intent-level workflow |
495+
496+
Set the `workflow:` frontmatter field on units that need a non-default workflow. Omit it (or leave empty) for units that should use the intent-level workflow.
484497

485498
Define each unit with **enough detail that a builder with zero prior context builds the right thing**:
486499

@@ -777,7 +790,8 @@ problem space.}
777790
status: pending
778791
depends_on: []
779792
branch: ai-dlc/{intent-slug}/NN-{unit-slug}
780-
discipline: {discipline} # frontend, backend, api, documentation, devops, etc.
793+
discipline: {discipline} # frontend, backend, api, documentation, devops, design, etc.
794+
workflow: "" # Per-unit workflow override (optional — omit or leave empty to use intent-level workflow)
781795
ticket: "" # Ticketing provider ticket key (auto-populated if ticketing provider configured)
782796
---
783797

plugin/skills/fail/SKILL.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,20 @@ STATE=$(han keep load iteration.json --quiet)
3535
### Step 2: Determine Previous Hat
3636

3737
```javascript
38-
const workflow = state.workflow || ["planner", "builder", "reviewer"];
39-
const currentIndex = workflow.indexOf(state.hat);
38+
// Resolve workflow for this unit: per-unit workflow takes priority, then intent-level fallback
39+
const currentUnit = state.currentUnit;
40+
const unitWorkflow = (currentUnit && state.unitStates?.[currentUnit]?.workflow)
41+
|| state.workflow
42+
|| ["planner", "builder", "reviewer"];
43+
const currentIndex = unitWorkflow.indexOf(state.hat);
4044
const prevIndex = currentIndex - 1;
4145

4246
if (prevIndex < 0) {
4347
// Already at first hat - cannot go back
44-
return "Cannot fail before the first hat (planner).";
48+
return "Cannot fail before the first hat.";
4549
}
4650

47-
const prevHat = workflow[prevIndex];
51+
const prevHat = unitWorkflow[prevIndex];
4852
```
4953
5054
### Step 3: Document Why

plugin/workflows.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ adversarial:
1616
description: Security-focused with Red/Blue team phases
1717
hats: [planner, builder, red-team, blue-team, reviewer]
1818

19+
design:
20+
description: Design workflow for UI/UX units that produce design artifacts
21+
hats: [planner, designer, reviewer]
22+
1923
hypothesis:
2024
description: Scientific debugging for investigating bugs
2125
hats: [observer, hypothesizer, experimenter, analyst]

0 commit comments

Comments
 (0)