Prefer the old long-form? See V1 archive.
Why
IC engineers and QAs split work across Jira, Confluence, service repos, automation repos, ad-hoc prompts. The workbench collapses that into one per-bundle harness:
- One or more Jira epics → PRD, eng-spec, TDD, ERD, ADRs, BDDs, test cases, test spec.
- PM / architect / staff-eng / UX / QA hats, no tool-switching.
- Dev + QA share drafts via git with explicit review + approval.
- Plan changes across multiple service repos in one ralph workspace-mode pass.
- Dispatch parallel autonomous ralph loops.
- Private, per-bundle, disposable. Not a long-running team OS.
Two-repo shape
| Repo | Role | Location |
|---|---|---|
ai-workbench |
Template, cloned per bundle. Ships skills, scripts, lifecycle aliases, config templates. | https://github.com/amit-t/ai-workbench |
ai-devkit |
Global CLI: init.wb, join.wb, wb.upgrade. |
https://github.com/amit-t/ai-devkit |
Never clone ai-workbench directly: init.wb stamps a private instance via gh repo create --template.
Workbench tree
wb-<label>/
├── CLAUDE.md # session start, plan-mode, role inference
├── AGENTS.md # shared agent constitution (Claude + Devin + Codex)
├── README.md # what this template does + how to use init.wb
├── .gitignore
├── .workbench-manifest.json # which paths are template-owned vs user-owned
├── .mcp.json.template # optional MCPs (Jira, Figma) — env-ref style
├── project.conf # filled in by init.wb (identity, epics, repos)
├── EPIC-PIPELINE.md # pipeline rollup — one H2 per epic
├── aliases.sh # wb.* commands sourced per workbench
├── .github/
│ └── CODEOWNERS # initiator + joiners appended
├── product/
│ ├── context-library/
│ │ └── epics/ # pulled Jira epic bodies (one MD per epic)
│ └── outputs/
│ └── prds/ # PRDs (lifecycle tracked in .workbench-state/)
├── design/
│ ├── context-library/
│ │ ├── figma-links.md
│ │ └── design-system-ref.md
│ └── outputs/
│ ├── wireframes/
│ ├── screens/
│ └── handoffs/
├── engineering/
│ ├── context-library/
│ └── outputs/
│ ├── specs/ # engineering spec
│ ├── tdd/ # technical design docs
│ ├── erd/ # entity/component diagrams
│ └── adrs/ # architecture decision records
├── qa/
│ ├── context-library/
│ └── outputs/
│ ├── bdd/ # Gherkin .feature files
│ ├── test-cases/ # structured test cases (MD or CSV)
│ ├── test-spec/ # QA equivalent of engineering spec
│ └── test-erd/ # test coverage model
├── ralph/
│ ├── workspace-plan.md # human-readable rollup of per-repo fix_plans
│ └── dispatch.log # parallel loop launch log (gitignored)
├── repos/ # gitignored — code repos cloned here
│ └── .gitkeep
├── .workbench-state/ # lifecycle state (shared via git)
│ ├── published.json # draft → published transitions
│ ├── approved.json # published → approved transitions (ralph gate)
│ └── rejected.json # reason-tracked rejections
├── steering/ # template-owned rule files (golden, role, artifact, topic)
├── steering.local/ # team-owned overlays (add / supersede / remove)
├── .claude/
│ └── settings.json # PostToolUse hook re-emits Layer 0 steering on update
├── scripts/
│ ├── lifecycle.py # unified publish/approve/reject CLI with flock
│ ├── sync-context.sh # workbench → repos/{x}/ai/, writes pr_footer.md
│ ├── ralph-context.sh # internal alias for sync-context.sh, used by ralph-plan
│ ├── ralph-plan.sh # wraps `ralph-plan --workspace` with per-repo fallback
│ ├── ralph-dispatch.sh # wraps `ralph --workspace --parallel N`
│ ├── ralph-enable-check.sh # preflight that `ralph enable --workspace` ran
│ ├── validate-artifact.py # blocks publish/approve when target_repos is missing
│ ├── artifact-schema.json # JSON schema used by validate-artifact.py
│ ├── steering-load.py # merge template + overlay rules for a scope
│ ├── steering-overlays.py # render add/supersede/remove footer for ralph PRs
│ ├── steering-lint.py # validate steering/ and steering.local/
│ ├── steering-post-tool-hook.sh # Claude Code PostToolUse hook for steering freshness
│ └── register-repo.sh # append a repo entry to project.conf
├── tests/ # template smoke tests
│ ├── README.md
│ └── smoke.sh
└── skills/ # symlinked into .claude/.agents/.devin at init
├── epic-intake/SKILL.md
├── prd-draft/SKILL.md
├── prd-review-panel/SKILL.md
├── bdd-gen/SKILL.md
├── test-cases-gen/SKILL.md
├── test-spec/SKILL.md
├── eng-spec/SKILL.md
├── tdd/SKILL.md
├── erd/SKILL.md
├── adr/SKILL.md
├── figma-pull/SKILL.md
├── ds-screen-gen/SKILL.md
├── design-draft/SKILL.md
├── design-review/SKILL.md
├── ralph-workspace-plan/SKILL.md
├── ralph-dispatch/SKILL.md
├── grill-me/SKILL.md
└── pmo-status/SKILL.md
project.conf (per-workbench manifest)
Committed shell file. Written by init.wb, extended by join.wb. Sourced by aliases and scripts.
#!/usr/bin/env bash
# Workbench configuration — written by init.wb, appended by join.wb
# --- Identity ---
WORKBENCH_LABEL="example"
WORKBENCH_REPO="https://github.com/<your-org>/wb-example"
WORKBENCH_TEMPLATE_UPSTREAM="https://github.com/<your-org>/ai-workbench"
WORKBENCH_CREATED_BY="<gh-user>"
WORKBENCH_CREATED_AT="2026-04-23"
# --- Epics in scope ---
EPICS=("EPIC-001" "EPIC-002")
# --- Managed code repos ---
# Each entry: name=<name>;url=<git_url>;role=<service|automation-tests|shared-lib|infra>;stack=<short>;added_by=<gh-user>
REPOS=(
"name=example-service;url=https://github.com/<your-org>/example-service;role=service;stack=node-nest;added_by=<gh-user>"
"name=example-automation-tests;url=https://github.com/<your-org>/example-automation-tests;role=automation-tests;stack=playwright;added_by=<qa-gh-user>"
)
.workbench-manifest.json (template vs user)
Only paths under template_owned are rewritten by wb.upgrade. Everything else (PRDs, specs, BDDs, test cases, repos, lifecycle state) is user_owned and untouched.
{
"version": 2,
"template_owned": [
"CLAUDE.md",
"AGENTS.md",
"README.md",
"aliases.sh",
".gitignore",
".workbench-manifest.json",
".mcp.json.template",
"project.conf.template",
"EPIC-PIPELINE.md.template",
".claude/settings.json",
".github/CODEOWNERS",
".github/workflows/**",
"scripts/**",
"skills/**",
"steering/**",
"tests/**"
],
"user_owned": [
"project.conf",
"EPIC-PIPELINE.md",
".mcp.json",
"product/**",
"design/**",
"engineering/**",
"qa/**",
"ralph/**",
"repos/**",
"steering.local/**",
".workbench-state/**"
]
}
Rules:
- Every tracked path lives in exactly one list.
wb.upgradeonly pullstemplate_owned.- Never hand-edit a
template_ownedpath. PR upstream toai-workbenchinstead.
Lifecycle
Every artifact flows draft → published → approved. Full state machine + downstream gates: Artifact lifecycle.
Version notifications
Meaningful wb.* commands (publish, approve, reject, sync-context, ralph-plan, ralph-dispatch, register-repo, steering*) fire a one-shot version check per 12h window. Newer upstream → banner; offline/rate-limited/missing gh → silent (fail-open). List aliases (wb.published, wb.approved, wb.rejected) skip the check. Details: Versioning + upgrades.
Security
- Workbench repos are private. Only CODEOWNERS push.
- MCP tokens stay in env vars per collaborator, never committed.
.mcp.json.templatecommitted;.mcp.jsongitignored.gh auth statusis checked before any GitHub-touching command. HTTPS or SSH (custom hostname alias) both work.- No force-push, no hook bypass, no branch-protection bypass.
Naming
- Repo name:
^wb-[a-z0-9][a-z0-9-]*$, max 60 chars. init.wbnormalises and rejects duplicates.- Fallback:
wb-<primary-epic-id-lowercased>-YYYYMMDD.