Stand up a "dark factory" for your repo: issues in → reviewed, auto-merged PRs out.
gp-foundry lets you declare an autonomous agent pipeline as a directed graph and compile
it into a repo. You describe the crew and the flow in one harness.dot; a deterministic
compiler emits plain GitHub Actions workflows. There's no orchestrator to run — GitHub is
the executor (native events, per-job least-privilege, Environment approvals, secrets, cron).
The pipeline keeps itself moving: it's self-healing (rebases conflicts, re-drives stranded work, escalates to a human only when truly stuck) and self-improving (mines its own merged PRs and reviews for recurring lessons, then feeds them back to every agent). And it isn't code-specific — the same shape that ships a library can ship docs or marketing copy.
Most agent-pipeline systems ship an orchestrator — a long-running engine that walks the graph, holds state, and runs the agents. (StrongDM's Attractor is one well-articulated example; gp-foundry borrows its DOT-graph representation.) That buys rich control flow and fast hops, but it's a stateful service you have to deploy, secure, and trust.
gp-foundry takes the opposite bet: compile the graph away and let GitHub run it. No server — state lives in labels, PRs, reviews, and cron. Every transition is an artifact your team already knows how to read and override, and the compiler checks the topology (bounded loops, livelock detection) before anything runs.
The cost is real: everything round-trips through GitHub-observable events. Hops take minutes, not milliseconds; gates poll on cron; data between agents narrows to labels and comment markers; and GitHub's event model has sharp edges the runtime works around rather than owns.
So gp-foundry aims at one altitude — issue → PR → review → merge — where hops are slow anyway and auditability matters more than latency, and it covers that without running any infrastructure of its own. Need tight multi-agent choreography, dynamic subgraphs, or streaming state between nodes? Run an orchestrator — this isn't one.
The fastest path — don't install anything yourself. Paste this into your coding agent (Claude Code, Cursor, or any agent with shell access), inside the target repo:
Fetch https://unpkg.com/@thegpvc/gp-foundry/AGENTS.md and follow it to set up an autonomous delivery pipeline in this repository.
AGENTS.md walks the agent through the bring-up via npx — no global
install: scaffold, adapt the toolchain/scope/roles with you, run up, then hand off the two
secrets only a human can set. Claude Code agents get steered to the richer
Socratic skill instead.
npm i -g @thegpvc/gp-foundry
gp-foundry init # scaffold .github/harness.dot + config + roles + scope + policy
gp-foundry up # labels + vendor actions + build workflows + doctor
gh secret set CLAUDE_CODE_OAUTH_TOKEN # agent auth (paste the Claude Code OAuth token)
gh secret set AGENT_PAT # fine-grained PAT: Contents + Pull requests + Issues RW
git add .github && git commit -m "add agent harness" && git push
# then file an issue — the 🕵️ scout triages it and the factory takes it from theregp-foundry up is offline-safe: it skips the gh-dependent steps (labels, doctor's
repo checks) cleanly when there's no GitHub remote yet, and builds the workflows regardless.
| Secret | What it is | Scopes |
|---|---|---|
CLAUDE_CODE_OAUTH_TOKEN |
The coding agent's auth token — how each agent job authenticates to Claude Code. | n/a (agent credential) |
AGENT_PAT |
A fine-grained Personal Access Token used for the agents' git writes, PRs, and comments. Needed because pushes made with the built-in GITHUB_TOKEN do not trigger downstream workflows, so the pipeline couldn't cascade stage to stage. |
Contents · Pull requests · Issues · Actions — read/write, scoped to this repo |
(AGENT_PAT is the default auth.mode: pat. You can instead run under a GitHub App
(mode: app, set app_id_secret/app_key_secret) or the built-in token (mode: github-token, zero setup but no cascading) — see foundry.config.yaml.)
The package ships a Claude skill — a Socratic front door that interviews you about your repo and builds the harness for you, instead of you editing the spec files by hand:
gp-foundry skill # install into this repo (.claude/skills/gp-foundry/)
gp-foundry skill --user # or once, for every project (~/.claude/skills/)Then in Claude Code, type /gp-foundry — or just ask "set up an agent pipeline for
this repo". The skill runs a five-question interview (what does this repo produce? who
approves? what must agents never touch? what roles and handoffs? what cadence and
identity?), drafts harness.dot + roles + policy from your answers, shows you the graph,
and then drives the same gp-foundry CLI — it never hand-writes workflow YAML. It also
handles evolving an existing harness ("add a docs lane", "tighten the merge gate").
The CLI quickstart above and the skill produce the same thing; the skill is for people who'd
rather answer questions than read reference/node-types.md.
The default init scaffolds the software pack — an autonomous engineering team that
takes an issue from triage to merge, plus the lanes that keep the factory healthy.
| Role | What it does | |
|---|---|---|
| 🕵️ | scout | Triage an incoming issue; label it for a lane (build / plan). |
| 📋 | planner | For big/ambiguous issues, post a plan before any code is written (read-only). |
| 👷 | builder | Turn a labeled issue into a small, tested, shippable PR (the only code-writer). |
| ⚖️ | reviewer | Read the diff, run gates, post an approve / request-changes verdict. |
| 🔧 | fixer | Apply review feedback in a bounded retry loop with the reviewer. |
| 🧹 | janitor | Scheduled sweep: rebase PRs the gate flagged needs-rebase so they can merge. |
| 🧭 | supervisor | Scheduled sweep: re-drive stranded issues/PRs; escalate to needs-human after 2 nudges. |
| ♻️ | retro | Scheduled: mine merged PRs/reviews/CI for recurring lessons; write them to team memory. |
| 🔀 | merge_gate | Policy gate, not a persona — enforces merge policy (approval, CI green, size, protected paths); auto-merges or labels needs-rebase/needs-human. |
Roles are generic; a consumer repo supplies its stack (label strings, build/test commands,
size thresholds, merge policy) via config and the roles/*.md overlay, never baked into the
role's contract.
harness.dot ──▶ parse ──▶ validate ──▶ model-check ──▶ assemble ──▶ .github/workflows/*.yml
(topology) IR schema reachability fragments (GENERATED,
+ cycle bounds + wiring drift-checked)
- Nodes are roles. Each node has a
type(mechanical:analyst,issue-agent,producer,pr-review,pr-fix,merge-gate,human-gate,scheduled-agent, plusstart/exit) and arole="agents/roles/<name>.md"carrying the domain-specific job description. The type is the GitHub interaction; the role is the behavior. - Edges are transitions. Expressed only in GitHub-observable primitives
(
on="issues.opened",when="label=build",when="verdict=approve"), so the platform — not a bespoke engine — drives the loop. - Generated workflows are a build artifact. Every emitted
.yml(andHARNESS.md) carries a# GENERATED FROM harness.dot — DO NOT EDITheader and is drift-checked in CI. You evolve a harness by editing the spec and rebuilding in a PR, never by hand. - Content is runtime-loaded. Editing a prompt, role, or merge policy needs no rebuild;
only topology changes (
harness.dot) recompile.
The default graph gp-foundry init scaffolds (.github/harness.dot) — a complete dark
factory with self-healing and self-improving lanes:
digraph harness {
start [type=start]
scout [type=issue-agent, role="agents/roles/scout.md", context=issue]
planner [type=analyst, role="agents/roles/planner.md", context=issue, output=comment]
builder [type=producer, role="agents/roles/builder.md", context=issue]
reviewer [type=pr-review, role="agents/roles/reviewer.md", context="pr-diff"]
fixer [type=pr-fix, role="agents/roles/fixer.md", max_attempts=3]
merge_gate [type=merge-gate, policy="agents/policy/merge.yaml", schedule="*/30 * * * *"]
janitor [type=scheduled-agent, role="agents/roles/janitor.md", schedule="*/30 * * * *"]
supervisor [type=scheduled-agent, role="agents/roles/supervisor.md", schedule="17 * * * *"]
retro [type=scheduled-agent, role="agents/roles/retro.md", schedule="0 7 * * 1-5"]
needs_human [type=exit]
start -> scout [on="issues.opened"]
scout -> planner [when="label=plan"]
scout -> builder [when="label=build"]
planner -> builder [when="label=build"]
builder -> reviewer [on="pull_request.opened"]
reviewer -> merge_gate [when="verdict=approve"]
reviewer -> fixer [when="verdict=request_changes"]
fixer -> reviewer [on="push"] // retry loop…
fixer -> needs_human [when="attempts>=3"] // …with a bounded escape
}Every cycle must keep a bounded escape edge to an exit node; the model-checker rejects
unbounded loops at build time. Full vocabulary in
skill/reference/node-types.md.
Self-healing — stuck work gets re-driven or escalated, not left silently stranded:
- 🧹 janitor runs on a schedule and rebases every PR the merge gate flagged
needs-rebase, so conflicts don't strand mergeable work. - 🧭 supervisor runs on a schedule, re-drives stranded issues and PRs (no PR for a
build-labeled issue, idle PRs), and escalates toneeds-humanafter 2 nudges. - The merge gate posts a 🔀 audit comment explaining each decision and labels
needs-rebaseon conflicts rather than merging a broken state. - Agent failures are visibly red — no green no-ops. A failing job fails the run.
- The 🔧 fixer has a real attempt budget: it stamps a marker comment each attempt and,
at
max_attempts, labels the PRneeds-humanand stops instead of looping forever.
Self-improving — the factory learns from its own record:
- ♻️ retro mines merged PRs, reviews, and CI for lessons that recur (≥ 2 occurrences),
and writes evidence-cited notes to
.github/agents/memory/topics/. scope.yamlguidance makes every agent read that memory before working, so a lesson learned once shapes every subsequent run.
- Cost — every agent hop is a model call inside an Actions run: a busy factory spends
real tokens and CI minutes. Start with the scheduled lanes at modest cadence, watch
gp-foundry status, and cap intake (labels are your throttle). There are no built-in per-day budget caps yet. - Security — agents write with
AGENT_PAT; scope it to the one repo. On public repos, issue text is untrusted input to the agents: keepscope.yamlimmutable paths tight (.github/at minimum), keep the merge gate's protected paths on, and treat the human-gate as mandatory for anything irreversible. The reviewer is also an LLM — the gate's policy (CI green, size caps, protected paths) is the non-negotiable backstop. - Limits —
parallel/fan_insupport clean diamonds only (one fan-out event, ≥2 agent lanes, one join); staggered/non-diamond joins are a v2 concern. Merges are serialized one per gate sweep. Cross-workflow races (e.g. janitor and fixer pushing at once) resolve by retry, not transactions — the supervisor sweep is the safety net.
| Command | Use |
|---|---|
gp-foundry status |
Operator dashboard: work in flight per lane, agent PRs, stalled items, failed runs (last 24h). |
gp-foundry doctor |
Preflight: config validity, workflow drift, vendored actions, gh auth, labels, secrets, committed. |
gp-foundry build --check |
The CI drift gate — exit non-zero if the committed workflows are stale vs the graph. Add it to your CI. |
Where to make a change — three surfaces, only one of which recompiles:
| To change… | Edit | Rebuild? |
|---|---|---|
| An agent's behavior (job description, quality bar) | agents/roles/<name>.md |
No — runtime content |
| The merge policy (size gates, protected paths, approvals) | agents/policy/merge.yaml |
No — runtime content |
| The topology (add a role/lane, rewire handoffs, change a schedule) | .github/harness.dot |
Yes — gp-foundry build |
Roles and policy are runtime-loaded, so tuning them is a content edit with no regenerated
YAML. Changing the graph is the only thing that recompiles — do it in a PR, and commit the
spec change and the regenerated workflows together so build --check stays green.
runtime.mode controls how the generated workflows reference the runtime-core actions:
vendored(default) —gp-foundry vendor(andup) copy the actions into.github/actions/, and the workflows reference them by local path. Self-contained, no external dependency; upgrade by re-runningvendor.pinned— reference<owner_repo>/actions/<name>@<ref>centrally (set a SHA/tag). Smaller consumer repos, central upgrades — available once the actions repo is public.
| Path | Contents |
|---|---|
src/ |
the compiler — parser, IR types, validate, model-check, role & step handlers, CLI |
actions/ |
the runtime core (JS + composite actions the generated workflows call) |
roles/ |
generic role packs (software/, content/, docs/) — the job descriptions |
skill/ |
the packaged Claude skill: SKILL.md, reference/, and the scaffolding templates/ |
schema/ |
JSON Schema for foundry.config.yaml |
examples/ |
a complete reference harness — examples/starter/, exactly what init scaffolds |
docs/ |
design docs (docs/plans/) |
- docs/plans/ — dated design specs (start with the system design).
- skill/SKILL.md — the Socratic setup skill and its CLI, node-type, and role-pack references.
- Each runtime-core action documents its contract in
actions/<name>/.
npm ci
npm run typecheck # tsc --noEmit
npm test # vitest run
npm run build # bundle the CLI to dist/cli/index.cjs
npm run build:actions # bundle the runtime-core actions to actions/*/dist/
npm run check:dist # fail if bundled action dist drifts from sourceCI runs the above, plus actionlint + zizmor over this repo's workflows and every
generated example harness, and guards that no generated workflow uses a local action path or
splices ${{ github.event.* }} into a shell.