Quick start¶
This walkthrough takes you from an empty (or existing) project to a graph the engine can drive. It assumes you have the ubc CLI installed and an AI coding assistant available — GitHub Copilot or Claude Code.
Note
The ubc agent command is experimental and hidden: it works, but it does
not appear in ubc --help and its behaviour may change between releases.
Run ubc agent --help to see the subcommands.
Start a new project¶
ubc agent install bootstraps a project into the loop from a named profile
(the default profile, vmodel, is the V-model described in the
overview):
ubc agent install # scaffold the default `vmodel` profile
ubc agent install --profile vmodel
In one non-destructive pass this:
writes the
[workflow]process model and the need-type/link ontology intoubproject.toml(existing files are never clobbered without--overwrite);installs the profile’s AI-asset bundle into the host integration directories — authoring and review skills plus a driver command under
.claude/, and a custom agent at.github/agents/workflow-author.agent.md;records every file it owns in an install manifest at
.pharaoh/agent/install-manifest, so a later update can tell your edits from the profile’s.
Tip
Commit .pharaoh/ to version control. It holds ubc’s per-project agent
state — the install manifest above, and (once you start reviewing) the review
verdicts under .pharaoh/verdicts/. Both are durable, shared records, so commit
the folder like any other source. A leading-dot directory is easy to overlook, but
leaving it untracked — or gitignoring it — loses your team’s review history and makes
ubc agent update and ubc agent doctor report the install as missing. Nothing
rebuildable lives there: the build cache is the separate .ub_cache/ directory,
which should stay gitignored.
Before you spend any tokens driving the loop, run the pre-flight check:
ubc agent doctor # config validity + required-tool probes, as JSON
doctor fails closed on a misconfiguration (an invalid [workflow], a missing
diagram renderer, a mis-wired code-trace gate) so you catch setup problems before
the first authoring run.
Drive the loop¶
Ask the engine what to do next, author that one artefact, then confirm it closed
its obligation. Repeat until next reports done.
$ ubc agent next # no --id: infer the active stream from your git diff
It names at most one stage as JSON. Here the engine picked the reqs stage and
resolved its route for the login stream it inferred from your working tree:
{
"ok": true,
"stage": {
"id": "reqs",
"produces": "req",
"skill": "draft-requirement",
"review": "review-requirement",
"route": {
"scope": "stream",
"granularity": "per-root",
"path": "specs/{stream}/requirements.rst",
"feature": "login",
"id_prefix": "REQ_",
"resolved_path": "specs/login/requirements.rst"
},
"gates_to_pass": ["trace"],
"gate": {
"link": "traces_to",
"up_type": "user_story",
"min": 1,
"direction": "both"
},
"id_prefix": "REQ_",
"verdicts_dir": "/work/acme/.pharaoh/verdicts"
}
}
So the next step is concrete: author req needs (ids prefixed REQ_) with the
draft-requirement skill at the resolved_path, and the gate still to close is the
trace link up to the story. The overview
breaks this payload down field by field.
There are three ways to author the stage the engine names:
- With your AI assistant (recommended).
In Copilot or Claude Code, invoke the driver — the installed
drive-workflowskill (or the/ubc-agent-nextcommand). It runsubc agent next, reads the recommendedskill, and authors the artefact at the reported route with the trace links the stage requires. The result is left uncommitted for you to review.- Headless, engine-driven.
ubc agent runassembles a prompt (the recommended skill + the anchor need’s context briefing + the resolved route) and executes it through the configured runner, then rebuilds and reports what was produced. Use--id <NEED_ID>to pick a stream on a clean tree:ubc agent run --id US_LOGIN # author the next stage for this stream
- By hand.
Nothing stops you writing the
.rstdirective (or the one-line code marker) yourself. The engine only cares about the resulting graph.
After each step, confirm the gap closed and watch the heartbeat:
ubc agent gaps --scope US_LOGIN # structural gaps for one stream (exits non-zero if any)
ubc agent status # one row per stage: done / ready / blocked
When every stage is done, the feature is finished only once the combined gate
is green:
ubc agent release-check --with-verdicts
Onboard an existing project¶
If you already have a Sphinx-Needs graph, --detect (brownfield mode) derives a
drivable [workflow] from the graph you already have — the links your needs
actually use, the schema, and your declared [needs.links] — instead of the blank
profile defaults:
ubc agent install --detect
Each structural edge it finds becomes a trace gate; what it cannot infer from the structure alone it raises as an open question carrying the evidence — whether a metadata-only type is a real stage or just a label, which parent types a fan-in should gate on, or whether a low-coverage backward edge is a genuine gap or noise. Preview the proposal as JSON without writing anything:
ubc agent install --detect --plan
Apply your choices with --answers <file> (an id-to-choice map); the recommended
default resolves every question, so answering always converges. The derived
[workflow] is appended to your project’s ubproject.toml — a provenance marker
keeps re-runs idempotent, and an existing config is never clobbered. --detect exits
non-zero on a project with no introspectable graph, so build your needs first.
Tip
The pharaoh-onboard skill completes this for you: an AI runs the plan, answers each open question from the structural signal, spot-checks a suspiciously empty result, and iterates to a clean, drivable workflow — onboarding interactively instead of hand-answering each question.
From there the loop is identical: ubc agent next points at whatever your graph is
missing (an arch with no test, a requirement with no parent) rather than starting
from an empty tree.
Keeping the profile in sync¶
When a new ubCode release ships an updated profile, reconcile your project against it with:
ubc agent update
For each file the manifest records as install-owned it does a three-way compare
(current preset vs. recorded baseline vs. on-disk): an unedited file is updated
in place, while a file you edited is preserved and reported as a conflict
rather than blindly overwritten. Pass --overwrite to resolve conflicts
preset-wins.