Skip to content

About

Contains an agentic coding development workflow for multiple harnesses

Resources

Stars

2 stars

Watchers

1 watching

Forks

Repository files navigation

ai-dev-workflow

A lean AI development workflow for Claude Code, Codex, and OpenCode: one agent-dev skill that takes a change from an (optional) ticket to a pull request by running the unmodified superpowers workflow, generated per project from one small config file.

The generator is a zero-dependency Node script, published to npm as @strobl_dev/adw. The consuming project does not need to be a Node project. It works in any repo (C#/.NET, Go, Rust, …) — the only requirement is Node on the machine that runs the generator (your dev box and CI). Pin a version (e.g. @0.30.0) so devs and CI stay in sync.

What lands in your repo

File / dir Owner Committed?
ai-project.json you — project identity + ticketing backend choice yes
AGENTS.md you — create with your coding agent's native /init; agent-dev reads it first (add an End-to-end testing section for agent-run e2e checks) yes
agent-custom/ you (optional) — per-project tweaks to the skill body (see Customizing the skill) yes
docs/superpowers/{specs,plans}/ written by superpowers when a change needs them; the agreed scope is also posted to the ticket yes
.agents/skills/show-me/, .claude/skills/show-me, skills-lock.json third-party show-me skill, installed by init/upgrade with npx skills at the commit this adw version pins; never rendered or checked yes
.claude/, .codex/, .opencode/, .agents/ generated output yes (review diffs on update)
.mcp.json merged (azure-devops backend only) — the shared ado server entry; other servers preserved yes
.codex/config.toml merged (azure-devops backend only) — the Codex project-local ado MCP server entry; other Codex settings preserved yes

Everything else (the skill source, ticketing/cost includes, the generator) lives in the package and updates with it. See agent-src/README.md for how the sources are authored.

Quick start (any project, incl. C# — no package.json needed)

npx runs the bin straight from npm — nothing is installed into the repo:

# 1. run the guided onboarding — writes ai-project.json, prints the recommended tooling
npx @strobl_dev/adw@0.30.0 init

# 2. (the interview sets project identity, repository, and ticketing.backend.
#    For azure-devops it also captures org/project + process template and pre-fills
#    the state mapping; generate then merges the `ado` server into .mcp.json
#    and .codex/config.toml.
#    Install the tooling it lists — see Tooling below — then create AGENTS.md
#    with your coding agent's native /init.)

# 3. generate the platform files
npx @strobl_dev/adw@0.30.0 generate

# 4. commit ai-project.json and the generated dirs

Pin the version (@0.30.0) so devs and CI stay in sync — a C# repo has no lockfile to do it for you.

Versions up to v0.23.0 were only distributed from Git (npx github:marxxxx/ai-dev-workflow#v0.23.0). npm 12 refuses git specs by default (EALLOWGIT); add --allow-git=all if you still need one.

Tooling

init prints this list. You install them — for whichever of Claude Code / Codex / OpenCode you run. This workflow deliberately does not carry install instructions: they differ per harness and go stale. Follow each project's own docs.

Tool What agent-dev uses it for
superpowers required The whole workflow: brainstorming → worktree → plan → implementation (TDD, review, verification) → finishing the branch
serena recommended MCP server: semantic, symbol-level code navigation and editing
playwright recommended MCP server: drives a real browser for the optional end-to-end check
context7 recommended MCP server: up-to-date library and framework documentation
ccusage recommended CLI behind the cost summary; without it the summary names the gap
show-me installed for you Compact views of a spec or plan for your review — see below

For the azure-devops backend, generate merges the ado MCP server (pinned to @azure-devops/mcp@2, whose tool names the Azure DevOps ticketing include is written against) into .mcp.json and .codex/config.toml — nothing to install by hand.

The gitea backend requires tea, Gitea's official CLI, installed and logged in — see Gitea backend setup.

Commands

Command Effect
generate (default) Render all platform files to the project root
check Render in memory and diff against disk; exit 1 on drift (CI / pre-commit gate)
upgrade The command for every version bump. Deletes the files the pre-v0.23 workflow generated and strips obsolete keys from ai-project.json, then generates, then installs or updates the pinned show-me skill (unless "skills": { "show-me": false }). Only deletes files carrying the generator's banner for a removed unit; other skills and subagents are never touched. A failed skill install is a warning with the manual command, never an error. --dry-run lists the changes without writing anything. See Updating.
init Interactive onboarding: prompts for project name, repository, ticketing backend (for azure-devops, the org/project and process template, pre-filling the state mapping; for gitea, the tea login profile), asks whether to install the show-me skill (default yes; runs npx skills add), then writes ai-project.json. It prints the tooling for you to install, and points you to create AGENTS.md with your coding agent's native /init. Falls back to a template scaffold when stdin is not a TTY. Never overwrites without confirmation.
e2e adw e2e <base-commit|.> <ticket> [harness]: replay agent-dev on one of your tickets in a throwaway clone and score the result. See E2E on your project.

All commands accept --root <dir> to target a project root other than the current directory.

Customizing the skill

ai-project.json and per-unit tokens cover most tuning. To change the instructions of the shipped skill, add a committed agent-custom/ directory that mirrors the source layout (agent-custom/skills/<name>/). Two knobs:

File Effect
agent-custom/skills/agent-dev/append.md Appended to the package body. The safe default — upstream improvements keep flowing on update.
agent-custom/skills/agent-dev/body.md Full override — replaces the package body. You then own that body (it no longer tracks upstream).

Both files support the same {{tokens}} as package bodies ({{project.name}}, {{repo.slug}}, …); an unresolved token fails the generator with a clear error. Example:

<!-- agent-custom/skills/agent-dev/append.md -->
## House rules
Always run `npm run lint` before finishing the branch.

Then generate and commit. agent-custom/ files are inputs to generation, so check still passes and still catches hand-edits to the generated files.

The agent-dev workflow

Run /agent-dev [ticket-id] (Codex: $agent-dev). The skill adds only what superpowers doesn't know about — the ticket and its comments — and otherwise follows the superpowers skills as written:

  1. Start — record the start time, read AGENTS.md; with a ticket, read it and move it to in-progress. Without one, it asks whether to create a ticket; if you say yes, it creates one once brainstorming has settled the scope and uses it for the rest of the run. A ticket already in-progress resumes where the earlier run stopped: straight to planning if a spec file was approved, to the next unfinished plan task if a plan exists (offering a partial cost summary for the interrupted session), otherwise back into brainstorming with the ticket as context.
  2. Brainstorming — the full requirements interview with you. A ticket (often an upstream ticket with too little detail to implement from) is only background context; it never replaces the interview. For changes with user-visible behavior it also asks whether the agent should test end to end or you prefer to test manually. Superpowers sizes the work: a quick task goes ahead, a small change is agreed in chat, a larger one gets a written spec in docs/superpowers/specs/. Once the scope is agreed, the ticket must say what gets built: the spec, or the agreements from the conversation, is posted as an Approved Spec comment (split into numbered comments if it exceeds the backend's limit; the file backend gets just a spec's path); nothing is posted if the ticket already said everything. The plan, if any, stays in the repo.
  3. The rest of the superpowers workflow — whatever superpowers chains from brainstorming (today: worktree, plan, implementation with TDD and review, finishing the branch). agent-dev does not restate that chain; it only hooks in at events (scope agreed, branch created, integration offered or the workflow finished), so superpowers releases need no changes here. If you chose agent testing, an end-to-end check runs before integrating. Instead of superpowers' merge/PR/keep menu, the run always ends with a draft PR (Gitea: a WIP: title), so a human reviews and tests before publishing it.
  4. Close-out — with a ticket, post an Implementation Summary comment (approach, consequences, possible side effects, what to watch when testing) and a Cost Summary comment, then move the ticket to review. Without a ticket, both are printed instead.

Names derive from the ticket's number and a short version of its title: branch <number>_<short_title_slug> (e.g. 42_user_login_form), PR title <number>: <short title> (e.g. 42: User login form). Without a ticket, both drop the number.

Ticket states are just new → in-progress → review; acceptance and closing stay with the human. Nothing beyond the agreed scope and those two comments is written to the ticket.

Reviewing specs and plans with show-me

Superpowers' specs and plans are thorough, which makes them long. When one is handed to you for review, agent-dev leads with a compact view of its design from HumanLayer's show-me skill — pseudocode, call and file trees, diff-shaped changes, Mermaid diagrams — so you can judge the approach before reading the file. The file stays the record. show-me is user-invoked only (/show-me works any time); agent-dev reads it at those two moments. init and upgrade install it into the project at the commit the adw version pins; generate and check print a note (exit code unchanged) when it is missing or outdated. Opt out with "skills": { "show-me": false } in ai-project.json.

End-to-end testing

Superpowers itself never starts your app: its verification is satisfied by passing tests. So agent-dev adds one decision and one step. During brainstorming, for a change with user-visible behavior (UI, user flows), it asks whether you want the agent to test it end to end or you prefer to test it manually, and records the answer in the agreed scope. If you chose the agent, it starts the app, exercises the changed flows in a browser via Playwright, captures evidence, and shuts the app down before opening the draft PR. The Implementation Summary always states the outcome: tested by the agent (with what was checked), left to manual testing at your request, or not tested and why. A missing setup, missing browser tooling, or a failed startup never blocks the PR; it is reported there instead.

The workflow ships no start/stop scripts, because starting the app differs per stack and per OS. Describe it in prose in an End-to-end testing section of your AGENTS.md, and the agent turns that into commands for the OS it runs on. Cover:

  • the backing services to start (database, cache, broker) and any migrate/seed steps;
  • how to start the app and how to tell it's reachable;
  • the base URL and ports;
  • the test-locator attribute to select elements by (for example data-testid).

Without that section, the agent tells you during brainstorming if you ask it to test end to end.

Cost summary

One total per run — tokens and estimated USD — from a single ccusage@20 session --json report, which covers every harness in one JSON shape. It counts the sessions active in the run's time window, which includes Codex/OpenCode subagent sessions with no bookkeeping during the run. The report has no project field, so on a shared host other sessions active in that window are counted too; the comment lists every counted session. In the container runtime the home volume is per project, so the count is project-scoped there. ccusage's JSON is not a stable API, which is why the major version is pinned; models ccusage cannot price are named instead of shown as $0. If a run fails, is abandoned, or is interrupted, agent-dev offers a partial cost summary so failed attempts still count; a ticket can therefore carry several cost comments, which together are its cost. Cost reporting never blocks the close-out. The procedure lives in the generated .agents/includes/cost.md.

In a Node project

Add it as a dev dependency with an exact version, and wire up scripts:

"devDependencies": {
  "@strobl_dev/adw": "0.25.0"
},
"scripts": {
  "agents:generate": "adw generate",
  "agents:upgrade":  "adw upgrade",
  "agents:check":    "adw check"
}

Updating

npx @strobl_dev/adw@<new-version> upgrade --dry-run   # list what would change
npx @strobl_dev/adw@<new-version> upgrade             # or bump the pinned version, then `upgrade`

upgrade cleans up what older versions left behind, generates, and brings the pinned third-party skills (show-me) to this version's commit. Review the diff in .claude//.codex//.agents/ and commit. generate never touches ai-project.json; upgrade only removes keys that are obsolete and records the skills opt-in. Run check in CI to catch a stale or mismatched version. Every generated file carries a DO NOT EDIT — generated from agent-src/… banner.

adw e2e first-run setup. The first adw e2e run after this update starts a new baseline (e2e.language changes the config hash); no upgrade step is needed.

Upgrading to v0.30.0. agent-dev now names the superpowers skills by bare id (brainstorming, not superpowers:brainstorming), which OpenCode 2 needs; upgrade regenerates it.

Upgrading to v0.29.1. The compose.ai-dev.yml that init wrote lacked the KILL capability, so the container's init process (tini) could not forward signals to the agent and stopped the container with Unexpected error when forwarding signal: 'Operation not permitted' (for example on a terminal resize). The file is project-owned and upgrade does not change it; upgrade, generate and check print a note until you add - KILL under cap_add of the ai-dev-workflow service.

Upgrading to v0.29.0. adw now installs the show-me skill. Run upgrade instead of generate: it records "skills": { "show-me": true } in ai-project.json and installs the skill with npx skills (needs network access to npm and GitHub). To decline, set "show-me": false first. Until it is installed, generate and check print a note, and agent-dev mentions it once per review.

Upgrading to v0.25.0. New upgrade command: it cleans up after the pre-v0.23 workflow (see v0.23.0 below). init no longer asks for the project slug, Serena project name, description or default branch, and {{project.slug}}, {{project.serena}}, {{project.description}} and {{repo.defaultBranch}} are no longer tokens. upgrade removes those keys from ai-project.json; generate ignores them. The generated output is unchanged unless an agent-custom/ file used one of these tokens.

Upgrading to v0.24.0. The package moved to the npm registry as @strobl_dev/adw; replace github:marxxxx/ai-dev-workflow#vX.Y.Z with @strobl_dev/adw@X.Y.Z in scripts, CI and devDependencies. The generated output is unchanged. The bin is now adw; ai-dev-workflow still works as an alias.

Upgrading to v0.23.0. The custom multi-agent workflow is replaced by the single agent-dev skill. dev-cycle, product-architect, the developer / code-reviewer / qa-engineer agents, the developer journal/handoff, and the e2e include are gone; ticket states shrink to new → in-progress → review. superpowers is now required. generate does not delete files it no longer produces; run upgrade instead, which removes them and then generates:

npx @strobl_dev/adw@0.30.0 upgrade --dry-run   # list what would change
npx @strobl_dev/adw@0.30.0 upgrade

It deletes these files, but only where they still carry the generator's DO NOT EDIT banner (a hand-written file with the same name is kept and reported), plus the unit directories left empty:

.claude/agents/{developer,code-reviewer,qa-engineer}.md
.codex/agents/{developer,code-reviewer,qa-engineer}.toml
.opencode/agents/{developer,code-reviewer,qa-engineer}.md
.claude/skills/{dev-cycle,product-architect}/SKILL.md
.agents/skills/{dev-cycle,product-architect}/{SKILL.md,agents/openai.yaml}
.opencode/skills/{dev-cycle,product-architect}/SKILL.md
.agents/includes/{handoff,e2e-runtime}.md

It also removes the keys nothing reads anymore from ai-project.json: git.branchPattern (branch and PR names now derive from the ticket), ticketing.azureDevOps.stateMapping.{test,failed,acceptance-test}, project.{slug,serenaProject,description}, repository.defaultBranch, and the older ticketing.itemNoun, e2e.{up,down,readinessTimeout,logsDir}, app and handoff blocks (the rest of e2e is adw e2e's settings and stays). If a project's tokens or agent-custom/ files used {{project.slug}}, {{project.serena}}, {{project.description}} or {{repo.defaultBranch}}, generation now fails on that token; replace it, or define it under tokens in ai-project.json.

agent-custom/ files for the removed units and the scripts/e2e-up / scripts/e2e-down scaffolded by early versions are project-owned: upgrade reports them but leaves them in place. Move anything you still need to agent-custom/skills/agent-dev/append.md. Tickets left in retired states (test, failed, acceptance-test) need a manual move.

Upgrading to v0.20.0. The generator now requires Node >= 24 (previously >=18). Upgrade Node on dev boxes and CI runners before bumping the pinned tag — older runtimes are unsupported and only get an engine warning, not a clear error.

E2E on your project

adw e2e replays the agent-dev workflow on one of your real tickets, at a fixed commit, and scores the outcome. Compare runs after you change agent-custom/, AGENTS.md, the model or the adw version.

npx @strobl_dev/adw e2e <base-commit|.> <ticket> [claude-code|codex|opencode] [--repetitions n] [--model m] \
  [--ticket-file <file>] [--baseline <runDir>] [--no-input] [--answers <file>] [--reconfigure]

The ticket is read once from your real backend and never written: gh issue view, tea api, az boards work-item show (the host needs az with the azure-devops extension, logged in or with AZURE_DEVOPS_EXT_PAT set), or the file backend. --ticket-file <file> is the manual fallback: a Markdown file whose first line is # <title>, followed by the body. --baseline <runDir> compares with that run (.adw/e2e/<ticket>/runs/<ts>/<harness>) instead of the newest earlier one.

Every run happens in a throwaway clone at <base-commit> on the file ticketing backend, with its remote pointing at a local bare repo, so nothing reaches your tracker or your real remote. Opening the draft PR (gh, tea or az) is recorded and answered with a placeholder link, never sent to your git host. Its containers publish no host ports, so a run does not clash with your own ./ai-dev.sh. The first run asks you the spec questions and confirms drafted acceptance criteria; later runs replay your stored answers. When the agent only reports progress and asks nothing, the run tells it to carry on (counted as nudged) instead of asking you.

Prerequisites: Docker and a git repo. On the first run adw e2e asks for the rest and writes it:

  • ai-project.json, if there is none: it offers the init interview first;
  • the container files (compose.ai-dev.yml), if init did not write them. The run builds a thin layer with acpx and the ACP adapters on your dev image (about 480 MB, cached until the image or the pins change; older layers are removed; the build uses your proxy variables and AGENT_CA_DIR);
  • the e2e block of ai-project.json: the agent's harness and model, the judge model, testCommand, provider variables and the language, shown before it is written;
  • values that e2e.env names but nothing sets (secrets are read without echo). They can be saved to .env.ai-dev next to the project, which the containers read;
  • the ticket, when your backend cannot be read from the host: it is fetched in your dev container, then by opening $EDITOR (both interactive only). --ticket-file skips this;
  • the logins, see below;
  • an AGENTS.md section "End-to-end testing" saying how to start and exercise the app, for the app-level check. If it is missing you can have the answerer role's harness and model draft it from your committed files ([d]raft), answer four questions ([a]sk) or [s]kip it; it is appended only after you confirm. e2e.testCommand optionally runs your own tests too.

--no-input asks nothing, on a terminal too, and fails on what is missing; without a terminal nothing is asked either. --answers <file> answers the questions from a JSON file nested by the dotted question keys, e.g. {"setup":{"writeE2e":"y"},"e2e":{"agent":{"harness":"codex"}}}; every yes/no question it leaves out counts as "no", so nothing is written without an explicit answer. --reconfigure asks the e2e questions again, with the stored values as defaults. .adw/e2e/local.json (git-ignored) keeps this machine's choices: the volume logins and a skipped AGENTS.md section are not asked again; delete it to be asked again. When the base commit predates the AGENTS.md section, the run overlays the current one onto the clone.

. as the base commit runs on your working tree: uncommitted changes and untracked files on top of HEAD, without committing anything (git-ignored files such as .env.ai-dev stay out; .adw/e2e/ stays as committed). Use it to try a change, e.g. to AGENTS.md, before you commit it: adw e2e . 1 codex. The run is compared with the newest run on the committed HEAD, and is itself never picked as a baseline; its report says + working tree.

Logins: the containers never share the project's agent-home volume, they get a login staged from the host.

  • Codex: ~/.codex/auth.json on the host, or OPENAI_API_KEY. If you only logged in through ./ai-dev.sh, the setup offers to copy the login from the project's volume.
  • OpenCode: ~/.config/adw/opencode-credentials.json, an opencode auth export file, or provider variables in e2e.env. The containers import it with opencode auth import. If the file is missing, the setup offers to export the login of the project's volume (after ./ai-dev.sh opencode auth login) and prints the host command.
  • Claude Code: a long-lived token, never taken from the volume. Run claude setup-token on the host and export CLAUDE_CODE_OAUTH_TOKEN, or let the setup run it (docker run --rm -it --entrypoint claude <dev image> setup-token; it asks you to paste the token without echo and offers to save it to .env.ai-dev). For Bedrock or Vertex set CLAUDE_CODE_USE_BEDROCK / CLAUDE_CODE_USE_VERTEX and that provider's variables in e2e.env.

Each of the four LLM roles (agent, answerer, verifier, review) has its own harness and model, so a project can stay inside the providers it may use. In ai-project.json:

"e2e": {
  "agent":    { "harness": "codex",       "model": "gpt-6.1-sol" },
  "answerer": { "harness": "opencode",    "model": "azure/gpt-6.1-mini" },
  "verifier": { "harness": "opencode",    "model": "azure/gpt-6.1", "timeoutSec": 900 },
  "review":   { "harness": "opencode",    "model": "azure/gpt-6.1" },
  "env": ["AZURE_API_KEY", "AZURE_RESOURCE_NAME"],
  "secretEnv": ["AZURE_API_KEY"],
  "language": "en"
}

A role without its own harness uses the agent's; a role without its own model uses that CLI's default model. So one login is enough. language (en or de) is the language of the simulated user's answers; the setup detects it from the ticket. env lists variable names passed into the containers by name. Values of names in e2e.secretEnv are removed from transcripts and logs; other e2e.env values are kept as they are, so list every key or token there.

Under .adw/e2e/<ticket>/, commit ticket.md, answers.json and acceptance.md; runs/ holds the per-run records and reports and is git-ignored (the command writes .adw/e2e/.gitignore). A run is compared with the newest earlier fully replayed run with the same base commit, ticket and harness. Before the first trial, one short call per answerer and judge harness and model checks that the model exists and the login works, so a misspelled model fails in seconds, not after the agent's trial. A run whose verifier or review fails (other than the verifier being skipped) is aborted: it gets no compare verdict and is never a baseline.

Trade-offs: no calibration, one repetition by default, and your first-time answers shape the result, so scores are less precise than the Harbor self-test. Variance between identical runs is large: compare medians over several repetitions, never single runs. When a judge shares the agent's harness and model, the report warns that it is self-judging.

Run in a container

The workflow ships a container runtime with Claude Code, Codex, OpenCode, Serena, Playwright/Chromium, Context7, Azure DevOps MCP, Azure CLI (with the azure-devops extension), Superpowers and ccusage. Answer yes to Set up the dev container? during init: it writes compose.ai-dev.yml (preset with the published image for the detected stack: Node, .NET or generic), a certificate overlay, the launchers ai-dev.sh / ai-dev.ps1 and AI-DEV.md with the logins for your coding agents and ticketing backend, then prints the exact next steps. It also asks whether to enable the Docker overlay (AGENT_DIND=1, root-equivalent) and company root certificates (AGENT_CA_DIR), and writes those to the git-ignored .env.ai-dev. These files are project-owned. Run the generator on the host; the image does not install or run it.

./ai-dev.sh claude --dangerously-skip-permissions   # PowerShell: .\ai-dev.ps1 …

Two derived images add app-facing runtimes (ai-dev-workflow-node, ai-dev-workflow-dotnet). The container assets live under docker/ and are hand-maintained, not generated. See docker/README.md for the run model, mounts, auth/persistence, UID/GID mapping, and how a consuming project extends the base.

To work on this repository itself in a container — tool stack only, without the generated agent-dev skill — use the repo-root compose.ai-dev.yml (it sets AGENT_TOOLSTACK_ONLY=1):

export PROJECT_ROOT="$(pwd)" HOST_UID="$(id -u)" HOST_GID="$(id -g)"
docker compose -f compose.ai-dev.yml run --rm ai-dev-workflow bash

See docker/README.md → Working on this repo in a container.

Behind a TLS-inspecting corporate proxy, set AGENT_CA_DIR and the proxy variables in the project's git-ignored .env.ai-dev; the launchers add the certificate overlay and the published images install the certificates at startup, so no per-company image build is needed. See docker/README.md → Corporate TLS inspection.

End-to-end self-test. node e2e/run.mjs run exercises the whole workflow in Claude Code, Codex and OpenCode and compares the result with the previous run — see docs/adw-e2e/README.md.

License

Apache-2.0

About

Contains an agentic coding development workflow for multiple harnesses

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages