# Dev Review Loop

> Strategy skill for emploke/coordinator — the dev → review+designer iterate-to-clean orchestration: case bank, brief templates, placeholder resolution, stop condition, failure-mode coverage

- Skill: `langsensei/dev-review-loop` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add langsensei/dev-review-loop`
- Raw SKILL.md: https://api.skillmd.com/api/skills/langsensei/dev-review-loop/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: langsensei (https://skillmd.com/u/langsensei)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/langsensei/dev-review-loop

---


# Emploke Development-Loop Strategy Skill

Strategy: dispatch a single `emploke/dev` worker; on success, fan out to parallel `emploke/review` + `emploke/frontend-designer` reviewers; finish succeeded if both verdicts come back clean (APPROVE with at most minor findings), else dispatch the next `emploke/dev` iteration with prior verdicts available, and loop. Loaded by the `emploke/coordinator` agent alongside the generic `emploke/coordinator` skill at every coord wake-up.

---

## Case bank

Match own direct parents against these cases — exactly one matches per wake-up (the case bank is total over expected shapes; see "Failure-mode coverage"). Unexpected shapes (3 parents, an unknown agent FQN, etc.) are bugs in workflow construction; terminate with `workflow finish --outcome failed --message "coord saw unexpected DAG shape under emploke/dev-review-loop: <describe>"`.

```
CASE "no parents" (initial coord node):
  addSubgraph:
    dev (worker, agent=emploke/dev, brief=<template-dev-iter-1>)
       parents = [self]
    next-coord (coordinator, agent=emploke/coordinator)
       parents = [dev]
  exit

CASE "one parent, worker, agent=emploke/dev, status=succeeded":
  addSubgraph:
    review   (worker, agent=emploke/review,            brief=<template-review>)
       parents = [self]
    designer (worker, agent=emploke/frontend-designer, brief=<template-designer>)
       parents = [self]
    next-coord (coordinator, agent=emploke/coordinator)
       parents = [review, designer]
  exit

CASE "one parent, worker, agent=emploke/dev, status in (failed, cancelled)":
  finishWorkflow(failed, "dev iteration ended in {status}")
  exit

CASE "two parents, both worker, agents in {emploke/review, emploke/frontend-designer}":
  for each parent:
    fetch task:    emploke task show --tid <parent.taskId> --json
    fetch verdict: read <task-workdir>/verdict.json (parse per §C of generic skill)
  blockers_and_majors = [
    f for v in verdicts for f in v.findings if f.severity in ('blocker', 'major')
  ]
  if blockers_and_majors is empty:
    finishWorkflow(succeeded, summary={
      "iterations": <count of dev nodes in DAG>,
      "minor_findings_remaining": <count if any>
    })
  else:
    addSubgraph:
      dev (worker, agent=emploke/dev, brief=<template-dev-iter-2-plus>)
         parents = [self]
      next-coord (coordinator)
         parents = [dev]
  exit

CASE "two parents, both worker, any status in (failed, cancelled)":
  finishWorkflow(failed, "reviewer iteration ended in {status}; coord cannot decide without verdict")
  exit
```

Use the §B "Batch-mutate the DAG atomically" `add-subgraph` payload shape from the generic skill; substitute `<self-node-id>` with the actual id from the DAG snapshot.

---

## Brief templates

Coord at dispatch time substitutes `${PLACEHOLDER}` slots per the resolution table below; do not paraphrase template prose — workers receive these as their primary contract.

### Template: template-dev-iter-1 (the initial dev call)

```
Implement the feature per the workflow brief.

# Workflow context
- Workflow id: ${WORKFLOW_ID}
- Workflow brief (verbatim from creator):
  ${WORKFLOW_BRIEF}
- Workflow details (verbatim from creator):
  ${WORKFLOW_DETAILS}

# Output expectations
Follow your normal dev workflow (branch, PR, etc.). The coord will pick
up your PR via the workflow DAG; no special output protocol on your end.
```

### Template: template-dev-iter-2-plus (after a review round)

```
Re-implement the feature for iteration ${ITERATION_NUMBER}.

# Workflow context
- Workflow id: ${WORKFLOW_ID}
- Workflow brief (verbatim):
  ${WORKFLOW_BRIEF}
- Workflow details (verbatim):
  ${WORKFLOW_DETAILS}

# Prior iteration outputs (you must fetch these yourself)
- Prior review verdict + narrative:
    emploke task show --tid ${PRIOR_REVIEW_TASK_ID} --json
    then read <task-workdir>/verdict.json and <task-workdir>/review.md
- Prior designer verdict + narrative:
    emploke task show --tid ${PRIOR_DESIGNER_TASK_ID} --json
    then read <task-workdir>/verdict.json and <task-workdir>/review.md

# What to do
Address every finding marked severity=blocker or major. Apply your own
judgment on severity=minor findings — fix what you'd fix as a
professional.

Keep working on branch ${BRANCH_NAME} (already-pushed prior iteration
commits are visible; rebase / amend as you see fit).
```

### Template: template-review (same every iteration)

```
Review the latest dev iteration in this workflow.

# Workflow context
- Workflow id: ${WORKFLOW_ID}
- Workflow brief (verbatim):
  ${WORKFLOW_BRIEF}

# What to review
The dev node immediately preceding you in the workflow DAG. Find it via:
  emploke workflow dag --wfid ${WORKFLOW_ID} --json
The dev node is your direct parent. Read dev's task via its taskId, see
what changed, apply your normal review standards.

If this is review iteration 2 or later, fetch the prior review node
(same agent as you, lower phase in the DAG) — read its verdict.json
to confirm previously-flagged findings are now addressed.

# Required output protocol
Write to <task-workdir>/verdict.json:
{
  "verdict":  "APPROVE" | "REQUEST_CHANGES",
  "findings": [
    {
      "id":       "F1",                                       // unique within this verdict
      "severity": "blocker" | "major" | "minor",
      "summary":  "<≤200 chars, single line>",
      "detail":   "<free-form, any length>"
    }
  ]
}

Validation rules:
- verdict == "APPROVE"           ⇒ findings MAY be [] OR contain only "minor" items
- verdict == "REQUEST_CHANGES"   ⇒ findings MUST contain ≥1 "blocker" or "major"
- findings[].id must be unique within this verdict

Coord decision rule (so you understand the impact):
- All verdicts APPROVE with only minor findings → workflow finishes succeeded
- Any blocker/major → next dev iteration dispatched, current findings 
  propagated to next dev brief (it will read your verdict.json itself)

Optionally write <task-workdir>/review.md for free-form narrative. The
next dev iteration will read it for context if produced.
```

### Template: template-designer (same every iteration)

```
Review the latest dev iteration's UI / UX in this workflow.

# Workflow context
- Workflow id: ${WORKFLOW_ID}
- Workflow brief (verbatim):
  ${WORKFLOW_BRIEF}

# What to review
The dev node immediately preceding you in the workflow DAG. Find it via:
  emploke workflow dag --wfid ${WORKFLOW_ID} --json
Apply your normal frontend / design review standards.

If this is designer iteration 2 or later, fetch the prior designer node
(same agent as you, lower phase) and confirm previously-flagged findings 
are resolved.

# Required output protocol
Identical to review's protocol (verdict.json + optional review.md).
See template-review above for the schema and validation rules.
```

---

## Placeholder resolution table

Plain string replacement; placeholders with no value (e.g. `${WORKFLOW_DETAILS}` when the creator passed nothing) substitute the empty string rather than leaving the literal `${...}` in the dispatched brief.

| Placeholder | Source | Notes |
| --- | --- | --- |
| `${WORKFLOW_ID}` | `workflow.id` from `emploke workflow show` | string |
| `${WORKFLOW_BRIEF}` | `workflow.brief` | verbatim, no rewriting |
| `${WORKFLOW_DETAILS}` | `workflow.details` (may be `null` → emit empty string) | verbatim |
| `${ITERATION_NUMBER}` | count of `emploke/dev` worker nodes already in the DAG, +1 | integer; `template-dev-iter-2-plus` only |
| `${PRIOR_REVIEW_TASK_ID}` | `taskId` of the most recent `agent=emploke/review` worker parent of the prior coord | string; `template-dev-iter-2-plus` only |
| `${PRIOR_DESIGNER_TASK_ID}` | `taskId` of the most recent `agent=emploke/frontend-designer` worker parent of the prior coord | string; `template-dev-iter-2-plus` only |
| `${BRANCH_NAME}` | branch the prior dev node pushed (derive from prior dev task's terminal result or its `<task-workdir>/branch.txt`) | string; `template-dev-iter-2-plus` only |

`${PRIOR_*_TASK_ID}` lookups use the "Find prior-iter siblings" snippet from the generic skill §B (same agent FQN, lower phase).

---

## Stop condition

Trigger `finishWorkflow(succeeded, ...)` in the "two parents, both reviewers" case when both verdicts parse cleanly per §C and the union of findings filtered to `severity in ('blocker', 'major')` is empty. The success `summary` records `iterations` (count of `emploke/dev` nodes in the final DAG) and `minor_findings_remaining` (visibility — the work ships with them outstanding). No iteration cap in v1; an iteration cap is deferred per `coord-design.md` §7 and will land as a sibling case in the case bank when added.

---

## Failure-mode coverage

Every `(parent role, parent terminal status)` cell on every expected parent role matches exactly one case in the case bank — verify here when editing.

| Coord wake-up shape | Parent role | Parent status | Matched case | Action |
| --- | --- | --- | --- | --- |
| 0 parents (initial coord node) | — | — | "no parents" | addSubgraph dev + next-coord |
| 1 parent | `emploke/dev` worker | `succeeded` | "one parent, dev, succeeded" | addSubgraph review + designer + next-coord |
| 1 parent | `emploke/dev` worker | `failed` | "one parent, dev, failed/cancelled" | finish(failed, "dev iteration ended in failed") |
| 1 parent | `emploke/dev` worker | `cancelled` | "one parent, dev, failed/cancelled" | finish(failed, "dev iteration ended in cancelled") |
| 2 parents | both reviewers (review + designer) | both `succeeded` AND `verdict.json` parseable | "two parents, both reviewers" | finish(succeeded) OR addSubgraph next dev iter, per blockers/majors count |
| 2 parents | reviewer | `failed` | "two parents, any failed/cancelled" | finish(failed, "reviewer iteration ended in failed") |
| 2 parents | reviewer | `cancelled` | "two parents, any failed/cancelled" | finish(failed, "reviewer iteration ended in cancelled") |
| 2 parents | reviewer | `succeeded` but `verdict.json` missing / unparseable | "two parents, both reviewers" → §C parse failure | finish(failed, "reviewer <agent> did not produce valid verdict.json") |

