Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,49 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Fixed
- **bob commit-lifecycle deadlock (mark/seal split).** Sealing the run inside
a pre-commit gate released the ACTIVE marker *before* the commit landed, so
a require-run policy blocked the very commit the gate had just validated
(and a failed commit left the run wrongly closed). The gate now splits the
lifecycle: `bob gate --mark-pass` (pre-commit) validates and records
`gate-pass.json` but keeps ACTIVE; the new `bob seal` (post-commit)
releases ACTIVE only when a gate pass is recorded, stamping the landed
commit hash. New `bob hook-install` writes all three hooks (pre-commit,
pre-merge-commit, post-commit); `AGENT_ULTRA_REQUIRE_RUN=1` makes the
pipeline mandatory for hook-level commits. `--complete-on-pass` remains
for closures outside a commit. `run_bob(..., seal_on_pass=False)` selects
the git-workflow lifecycle from Python. Regression test drives the full
cycle through real git: proven commit lands, post-commit seals, an
unproven follow-up commit is blocked. **If you had wired `bob gate
--complete-on-pass` into a pre-commit hook, replace it: run
`agent-ultra bob hook-install` to regenerate the hooks.**

### Added
- **bob** (`agent_ultra.bob`) — the 10-step enforced build pipeline
(SPEC → RED → GREEN → REFACTOR → CODE-QUALITY → SECURITY-FANOUT → WORKFLOW
→ ULTRA → QUIZ → COMMIT) composing ultracode fan-out, the adversarial
panel, the broker's risk tiers, and signed receipts into one loop. Each
gated step leaves a hash-chained (`prev_sha256`), HMAC-signed step receipt
written from real execution: RED/GREEN receipts come from the pytest
runner's actual output (`writer="system"`); the two fan-out steps are
cross-checked against ultracode's own checksummed run receipts; ULTRA is
proven by the panel execution receipt (a self-review is not a panel); a
`passed` quiz needs a captured operator response. The commit/report gate
re-runs pytest live, re-hashes covered files (staleness), demands coverage
for staged files, and fail-closes on anything it cannot verify — a
skipped, fabricated, edited, re-ordered, or hand-authored step blocks.
Mock mode (`--mock`, no API key) swaps only the model content for a
bundled sample task; pytest, ultracode, the panel, and the gate all really
execute. CLI: `agent-ultra bob run|gate|status` (alias: `agent-ultra
build`); Python: `run_bob` / `gate_check` / `assert_bob_done`. `doctor`
and `demo` prove the pass AND three blocked-fraud scenarios; see
[docs/bob-the-builder.md](docs/bob-the-builder.md). Each cross-checked
artifact (the ultracode run receipt's file bytes, the panel receipt's
task/artifact hashes) is bound into the signed chain, and model-authored
file paths are validated against workspace escape; the docs state the
trust boundary honestly (no host middleware, unlike the private reference).
29 offline tests.
- **ultracode** (`agent_ultra.ultracode`) — deterministic multi-agent workflow
engine. Workflows are plain Python modules (`META` + `async def run(wf)`) that
fan work across bounded agents via `wf.agent` (one model call, optional
Expand Down
50 changes: 49 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,12 @@ $ agent-ultra doctor
[PASS] panel demo: 3 findings, 3 accepted, decision produced
[PASS] ULTRA demo: build->test->panel->fix loop->proof artifacts
[PASS] ultracode: fan-out -> journal -> resume (cached) -> valid receipt
[PASS] bob: 10-step pipeline gate passes; skipped/faked steps block
[PASS] receipts bus: HMAC authenticity, forgery rejected, audit chain
[PASS] verifier: refute-first default, engine re-check, refuted!=gate
[PASS] secret hygiene: redaction active, no secrets in artifacts
[PASS] worker layer: router (default) available
Result: 12 pass, 1 warn, 0 fail
Result: 13 pass, 1 warn, 0 fail

$ agent-ultra demo
[ok] panel: 3 findings, 3 accepted -> Fix the empty-token acceptance before shipping...
Expand All @@ -85,6 +86,7 @@ $ agent-ultra demo
[ok] receipts: genuine authentic, forgery rejected, audit chain ok=True
[ok] verifier: no-evidence refuted, re-check confirmed (cannot satisfy a gate)
[ok] ultracode: 4 agents fan out -> COMPLETE -> receipt valid=True -> resume replays 4 cached (0 calls)
[ok] bob: 10-step pipeline gate passed=True; skipped step blocks=True, fake fan-out blocks=True, doctored panel blocks=True
DEMO PASSED — the full loop works on this machine.

$ agent-ultra --mock panel "Is this auth service safe?" --lenses security,correctness,failure-modes
Expand Down Expand Up @@ -147,13 +149,58 @@ Commands: `ultracode run <workflow>` · `list` · `status` · `resume <run_id>`.
Bundled workflows: **smoke** (fan-out + pipeline) and **review** (finders →
skeptic votes → synthesis). Full guide: [docs/ultracode.md](docs/ultracode.md).

## bob — the 10-step enforced build pipeline

**bob** composes the whole kit into one enforced build loop (alias:
`agent-ultra build`):

```
SPEC -> RED -> GREEN -> REFACTOR -> CODE-QUALITY -> SECURITY-FANOUT
-> WORKFLOW -> ULTRA -> QUIZ -> COMMIT
```

Every gated step leaves a **hash-chained, HMAC-signed receipt** written from
real execution — the pytest runner's actual output (RED/GREEN), ultracode's
checksummed run receipts (the two fan-out steps), the panel's execution
receipt (ULTRA). The commit gate re-derives what it can (a live pytest
re-run, file staleness hashes) and cross-checks the rest. You cannot *claim*
a step ran:

- a **skipped step** blocks (missing receipt + broken chain),
- a **fabricated fan-out** blocks (no ultracode run receipt backs the claim),
- a **doctored panel receipt** blocks (its checksum no longer matches),
- an **edited or hand-authored receipt** blocks (integrity/HMAC fail).

```console
$ agent-ultra bob run "add a slugify helper" --mock # offline, no key
bob run 20260708T154002Z — add a slugify helper [mock: sample task, no key]
[step01_spec] slugify(text) lowercases the input, replaces runs of non-al...
[step02_red] RED: 4 failing / 4 collected
[step03_green] GREEN: 4 passing
[step04_refactor] no edits (hashes re-pinned)
[step05_codequality] checklist recorded
[step06_security] 4 agents, 4 finding(s)
[step07_workflow] 5 agents over 5 dimensions
[step08_panel] decision: Fix the empty-token acceptance before shipping...
[step09_quiz] outcome=skipped (3 questions)

gate PASSED — receipt chain validates (9 receipts).
```

Mock mode swaps only the *model content* for a bundled sample task — pytest,
ultracode, the panel, and the gate all really execute, which is what makes
the no-key demo honest. Commands: `bob run <task>` · `bob gate`
(pre-commit chokepoint; `--complete-on-pass` seals the run) · `bob status`.
Full guide: [docs/bob-the-builder.md](docs/bob-the-builder.md).

## What's in the box

| module | what it does |
|--------|--------------|
| **panel** | Adversarial review: parallel critic *lenses* → steelman → judge cross-exam → synthesis. Verdicts: `real_now` / `real_later` / `theoretical` / `wrong`. Panel agents are roles, not models — one healthy route runs a whole panel. |
| **ultra_loop** | build → test → panel → classify → fix → re-test → re-panel → **ship gate**. Red tests stop before the panel; low-context panels are refused; only proof-gated work ships. |
| **ultracode** | Deterministic multi-agent workflows: `META` + `async run(wf)` scripts fan work across bounded agents (`parallel`/`pipeline`) under hard budgets, with a resumable journal, a checksummed receipt, and a terminal-safe status card. Fan-out → journal → resume → receipt → status. |
| **bob** | The 10-step enforced build pipeline (SPEC→RED→GREEN→…→COMMIT). Each gated step leaves a hash-chained, HMAC-signed receipt from real execution; the commit gate re-runs tests live and cross-checks ultracode/panel receipts. Skipped, faked, or edited steps block. |
| **broker** | Every model-authored command classified SAFE / ELEVATED / DANGEROUS, ledgered, and executed only if its tier allows. DANGEROUS with no approval path is **denied by default**. |
| **proof** | "Done" requires recorded evidence. Accepted findings become gates; `assert_shippable()` raises on unsupported completion claims. |
| **evidence** | Bounded source gathering with secret redaction; low-context detection. |
Expand Down Expand Up @@ -248,6 +295,7 @@ Full guide: [docs/adapter-guide.md](docs/adapter-guide.md).

[architecture](docs/architecture.md) · [panel](docs/panel.md) ·
[ULTRA loop](docs/ultra-loop.md) · [ultracode](docs/ultracode.md) ·
[bob pipeline](docs/bob-the-builder.md) ·
[command broker](docs/command-broker.md) ·
[proof gates](docs/proof-gates.md) · [adapter guide](docs/adapter-guide.md) ·
[security](docs/security.md) · [troubleshooting](docs/troubleshooting.md) ·
Expand Down
176 changes: 176 additions & 0 deletions docs/bob-the-builder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
# bob — the 10-step enforced build pipeline

`bob` composes the kit's pieces — ultracode fan-out, the adversarial panel,
the command broker's risk tiers, and signed receipts — into one enforced
build loop. The doctrine:

```
real execution -> receipt -> gate validates the chain -> commit/report
```

Ten steps, six of them gated. You cannot claim a step ran: the gate
re-derives what it can and cross-checks the rest, and every receipt is
hash-chained and HMAC-signed, so skipping, faking, editing, re-ordering, or
hand-authoring a step blocks the commit.

## The pipeline

| # | step | receipt | how it's enforced |
|---|------|---------|-------------------|
| 1 | SPEC | agent | one-paragraph spec recorded (judgment step) |
| 2 | RED | **system** | written by the pytest runner from actual output; needs ≥1 FAILED, 0 collection ERRORs |
| 3 | GREEN | **system** | all tests pass; every RED test id must appear in the GREEN run |
| 4 | REFACTOR | agent | judgment step; edited files re-pin their hashes |
| 5 | CODE-QUALITY | agent | judgment step; checklist recorded |
| 6 | SECURITY-FANOUT | **engine** | cross-checked: points at an ultracode run whose own checksummed receipt must re-verify, with ≥1 real agent call |
| 7 | WORKFLOW | **engine** | same cross-check + non-empty review dimensions |
| 8 | ULTRA | **engine** | the panel writes its execution receipt from real model calls — a self-review is not a panel |
| 9 | QUIZ | agent | `passed` requires a captured operator response; otherwise the honest outcome is `skipped` |
| 10 | COMMIT | gate | `gate-pass.json` written by the gate itself; ACTIVE marker released |

`writer` records who produced each receipt's evidence. The gate trusts
nothing it cannot re-derive (live pytest re-run, file staleness hashes) or
cross-check (ultracode receipts, the panel execution receipt).

## Quick start (no API key)

```bash
agent-ultra bob run "add a slugify helper" --mock
```

Mock mode swaps only the MODEL CONTENT (spec text, tests, implementation)
for a bundled sample task. Everything else is real: pytest runs RED and
GREEN as subprocesses, ultracode fans out on the mock route and writes its
checksummed receipts, the panel executes and writes its execution receipt,
and the gate validates the whole chain (including a live pytest re-run).
`agent-ultra build run ...` is the same command under its alias.

On a real endpoint (after `agent-ultra init` + key env var), drop `--mock`:
the spec, tests, and implementation come from your configured model. If the
model's tests don't genuinely fail at RED or its implementation doesn't
genuinely pass at GREEN, the run ends **blocked** — the pipeline never
pretends.

## The receipt chain

Receipts live in `<workspace>/.agent-ultra/bob/runs/<run_id>/`, one JSON per
step, each carrying:

- `receipt_sha256` — integrity: the body was not edited after writing;
- `receipt_hmac` — authenticity: written by something holding the
per-install key (created at first use under the agent-ultra home, never
inside the workspace);
- `prev_sha256` — the sha256 of the receipt before it. Editing or replacing
ANY earlier receipt breaks every later one;
- `files` — sha256 of every file the step covered. A covered file that
changes afterward is **stale** and blocks until the owning step re-runs;
- `mock` — set on mock-route evidence. The gate only accepts mock receipts
with `--allow-mock` (demo mode), never by default.

## The gate (commit/report chokepoint)

```bash
agent-ultra bob gate # validate the active run's chain
agent-ultra bob gate --mark-pass # validate + record the pass, keep ACTIVE
agent-ultra bob seal # release ACTIVE (needs a recorded pass)
agent-ultra bob gate --complete-on-pass # mark + seal in one step (no commit involved)
agent-ultra bob status # which steps have receipts
```

The gate fail-closes: a check it cannot perform (missing receipt, unreadable
artifact, unverifiable chain) is a failure, not a warning. On block, the
errors name exactly which step to redo. Staged files that appear in no
receipt also block (`*.md`, `.agent-ultra/*`, and `.gitignore` are exempt).

### Commit lifecycle: mark at pre-commit, seal at post-commit

Sealing inside pre-commit is a deadlock: the pass would release ACTIVE
*before* the commit lands, so any require-run policy then blocks the very
commit the gate just validated (and if the commit fails, the run is wrongly
closed). The split lifecycle avoids it:

1. **pre-commit** — `bob gate --hook --mark-pass`: validates the chain; on
pass it writes `gate-pass.json` but **keeps ACTIVE**.
2. the commit lands.
3. **post-commit** — `bob seal --if-passed`: releases ACTIVE and stamps the
landed commit hash into `gate-pass.json`. `seal` refuses when no gate
pass is recorded — a run can never be sealed unproven.

Install all three hooks (pre-commit, pre-merge-commit — git fires that one
for merge commits — and post-commit) in one command:

```bash
agent-ultra bob hook-install
```

With no active run the gate exits 0 immediately (non-interference). To make
the pipeline mandatory — every commit needs an active, proven run — export
`AGENT_ULTRA_REQUIRE_RUN=1` in the agent's environment: hook-mode gates then
block commits that have no run at all.

`--complete-on-pass` remains for closures that happen *outside* a commit
(the mock demo's report path, an operator retiring a run manually).

From Python, `assert_bob_done(workspace)` raises `BobProofError` when a run
is active and unproven — wire it in front of your agent's completion claims:

```python
from agent_ultra.bob import assert_bob_done, BobProofError
assert_bob_done(".") # raises unless the receipt chain validates
```

`assert_bob_done` passes `staged_files=[]` (at claim time nothing is staged),
so it validates the receipt chain but does **not** run the staged-file
coverage check — that lives in the `agent-ultra bob gate` pre-commit path,
which reads git's staged list. Install both: `assert_bob_done` guards
completion claims, the pre-commit hook guards the commit itself and catches
any staged file that no receipt covers.

## Trust boundary (read this)

bob resists the failure modes an agent actually falls into: **skipping** the
expensive steps, **claiming** a step ran without running it, **borrowing** a
prior run's fan-out or panel, and **editing** a receipt after the fact. It
enforces those by re-deriving what it can (a live pytest re-run) and binding
every cross-checked artifact — the ultracode run's receipt bytes and the
panel receipt's task/artifact hashes — into an HMAC-signed, hash-chained
receipt. Change any pinned artifact and the signed chain breaks.

What bob does **not** claim: to stop a fully adversarial process that has
arbitrary code execution *and* the per-install signing key. The key lives at
`<agent-ultra home>/bob.key`, readable by the same process the gate runs in,
so an attacker willing to genuinely fabricate every artifact end-to-end (run
the real fan-out over decoy code, forge matching signed receipts) can pass.
The private reference implementation closes this by writing the delegation
and clarify logs **host-side**, outside the agent's reach; the public port
has no host middleware, so its guarantee is "honest work is cheap, faking it
convincingly is not," not "unforgeable." Treat the gate as a strong
tripwire against lazy or accidental skipping, not a cryptographic proof
against a determined local adversary.

## What the proofs look like

`agent-ultra doctor` and `agent-ultra demo` both run the pipeline offline
and then attack it three ways; all three must block:

1. **skipped step** — a gated receipt is removed → missing receipt + broken
chain;
2. **fabricated fan-out** — a re-signed step-6 receipt names an invented
ultracode run → no run receipt on disk backs the claim;
3. **doctored panel receipt** — one field changed in the panel's execution
receipt → its checksum no longer matches.

The offline test suite (`pytest -q`) additionally proves: unsigned receipts
are forgeries, a wrong key fails closed, re-ordered/removed receipts break
linkage, `passed` quiz outcomes need an operator response, stale files
block, and the live re-run catches a state that fails its own tests.

## Troubleshooting

| symptom | fix |
|---------|-----|
| `gate BLOCKED ... receipt missing` | That step never ran (or its receipt was deleted). Re-run the step; the chain rebuilds from there. |
| `stale: <file> changed after its last covering receipt` | Re-run the step that owns the file (usually GREEN) so hashes re-pin. |
| `authenticity FAIL` on every receipt | The per-install key changed (e.g. new `AGENT_ULTRA_HOME`). Finish runs with the key that started them. |
| `receipt is marked mock` | You gated a demo run without `--allow-mock`. Mock evidence never satisfies a real gate. |
| blocked at RED on a real route | The model's tests didn't fail cleanly (or errored on import). Inspect the run dir's `step02_red.json` `output_tail`. |
Loading
Loading