docs(architecture): canonical agent-harness layered runtime + correct §6/§10 of ergon spec (BRO-1001)#1190
Conversation
… §6/§10 of ergon spec (BRO-1001)
The framing in `2026-05-05-ergon-v0.1.md` §6 (Composition with arcan)
and §10 (Migration plan) was structurally wrong. Both sections assumed
ergon would replace `arcan-harness` as a parallel session-level
runtime via an `AgentKind` trait abstraction. Reality:
1. `arcan-harness` is a ~300 LOC tool/sandbox utility crate, not the
agent harness. The actual agent harness is a 7-layer runtime stack
distributed across ~25 crates (kernel contract, substrate primitives,
port traits, tick engine, session orchestration, daemons).
2. Ergon's `Workflow::execute()` is one async fn — it cannot replace
the long-horizon tick engine (`aios_runtime::KernelRuntime`) without
losing per-tick journal traceability that autonomic / EGRI /
branching depend on.
Corrected framing: ergon supplies one shape of *tick body*
(workflow-bodied ticks) alongside the existing direct-call tick body.
Both compose with KernelRuntime; both produce per-tick events; neither
replaces anything.
## What this PR ships
**No code changes.** Documentation only:
- **NEW** `docs/architecture/agent-harness.md` — canonical 7-layer
runtime architecture. Maps every layer L0–L6 to its owning crates,
walks bottom-up dependency chain + top-down execution trace, defines
the two scopes of the agent loop (outer/session vs inner/tick),
enumerates built vs pending. This is the doc any future spec should
reference when it talks about "the harness."
- **NEW** `docs/superpowers/specs/2026-05-08-bro-1001-ergon-tick-body.md`
— corrected BRO-1001 design. 13 sections covering: scope (in/out),
the layered position, public API (TickBodyCtx, run_workflow_as_tick,
WorkflowRegistry), lifecycle, the small TickKind extension to
aios-runtime, definition of done, open questions, validation
criteria, composition trajectory, versioning, ordered impl plan.
- **MODIFIED** `docs/superpowers/specs/2026-05-05-ergon-v0.1.md`:
added a top-level correction note pointing to the architecture doc +
the new BRO-1001 spec. §6 and §10 marked SUPERSEDED inline with
links to the new doc. §§0-5, 7-9, 11-13 valid as written.
- **MODIFIED** `crates/ergon/ergon/CLAUDE.md` with the corrected
positioning ("ergon is one shape of tick body, not a parallel
session runtime"). Replaced the spec's old layer-numbering with the
canonical layer diagram.
- **MODIFIED** `CHANGELOG.md` — Changed entry documenting the
correction.
## What does NOT change
- ergon trait surface (workflow / step / hook / model / runtime / stream)
- ergon-life-hooks (4 auto-hooks + adapter traits)
- ergon-life-sinks (Lago / Vigil / Lifegw)
All of these are correct as shipped. They're precisely what a tick-body
adapter needs. What changes is the *framing* of how they're integrated.
## Why this is a doc-only PR
The course correction was caught BEFORE shipping the wrong adapter.
ergon (the trait crate) and ergon-life-* (the hooks + sinks) shipped to
main correctly under their original framing — they're substrate-free
trait crates that happen to be useful for either framing. The
mismatched framing was only in the spec text + the not-yet-written
adapter design.
By correcting the docs first, BRO-1001 will be scaffolded against the
right design. No retracted code, no rewritten history.
## Validation
- `cargo check -p ergon -p ergon-life-hooks` — clean (no code change)
- All previous ergon test counts unchanged (#1170 pending merge with
ergon-life-sinks; this PR independent)
- Markdown only; no compile/lint targets
Linear: BRO-1001 — description will be updated to point at the new
spec after this PR merges. Tracker: BRO-994.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThis PR introduces a canonical 7-layer agent harness architecture document, specifies the arcan-ergon tick-body adapter API and lifecycle (BRO-1001), corrects prior ergon v0.1 spec assumptions with supersession markers, updates ergon crate documentation, and records architecture clarifications and new crate additions in the changelog. ChangesErgON Architecture and Adapter Design
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
crates/ergon/ergon/CLAUDE.md (1)
22-30: ⚡ Quick winAdd language identifier to fenced code block.
The code block showing the harness stack position should specify a language identifier for proper rendering and tooling support.
📝 Proposed fix
-``` +```text L5 — Session orchestration (arcand::ConsciousnessActor) L4 — Tick engine (aios_runtime::KernelRuntime)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/ergon/ergon/CLAUDE.md` around lines 22 - 30, The fenced code block that lists the harness stack position lacks a language identifier; update the opening fence to include a plain text language (e.g., change ``` to ```text) so the block renders correctly and tooling highlights it as plain text—apply this change to the code block containing the lines starting with "L5 — Session orchestration (arcand::ConsciousnessActor)" and ending with "L0 — Kernel contract (aios-protocol)".
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@crates/ergon/ergon/CLAUDE.md`:
- Around line 22-30: The fenced code block that lists the harness stack position
lacks a language identifier; update the opening fence to include a plain text
language (e.g., change ``` to ```text) so the block renders correctly and
tooling highlights it as plain text—apply this change to the code block
containing the lines starting with "L5 — Session orchestration
(arcand::ConsciousnessActor)" and ending with "L0 — Kernel contract
(aios-protocol)".
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 4369fa69-8eb1-4379-a264-0230f4d2ea9f
📒 Files selected for processing (5)
CHANGELOG.mdcrates/ergon/ergon/CLAUDE.mddocs/architecture/agent-harness.mddocs/superpowers/specs/2026-05-05-ergon-v0.1.mddocs/superpowers/specs/2026-05-08-bro-1001-ergon-tick-body.md
… composition note
Two additions to the architecture + BRO-1001 spec to finalize the
scoping for nous metacognition as workflows:
## docs/architecture/agent-harness.md
New section "Where evaluators live (nous metacognition)" between "The
two scopes of the agent loop" and "Bottom-up dependency chain". Covers:
- **Scope A (inline scoring)** — `NousScoreHook` already shipped in
`ergon-life-hooks`. Per-turn observation, observe-only failure
semantics, no workflow ceremony needed.
- **Scope B (block-level evaluation)** — `ergon::Workflow` impls in
`apps/<judge-name>/`. Multi-step LLM reasoning that produces typed
verdicts. The bookkeeping-judge (BRO-1003) is the canonical first
example.
- **Decision rule** — does the evaluator need the autonomous loop?
If yes, workflow. If no, direct `NousEvaluator` impl in
`nous-heuristics` / `nous-judge`.
- **Verify-mode composition** — once BRO-1001 + BRO-1003 ship, the
kernel's `Verify` mode can dispatch to evaluator workflows
directly via a future `TickKind::VerifyWorkflow` variant. Deferred,
but architecturally clean.
- **Optional `WorkflowAsNousEvaluator` adapter** — ~50 LOC bridge
if/when an existing workflow needs to be addressable through
nous-routing. Cheap, written when needed.
- **Three architectural wins** when evaluators run as workflows:
per-tick traceability, composability via sub-workflows, automatic
substrate inheritance (anima / autonomic / lago / vigil / Spec E).
## docs/superpowers/specs/2026-05-08-bro-1001-ergon-tick-body.md
New §6.1 "Composition with OperatingMode::Verify (forward-compatible
note)". Documents that the `TickKind` enum is `#[non_exhaustive]` and
intentionally allows future variants like `VerifyWorkflow` and
`RecoverWorkflow` without committing to them in v0.1. Anchors the
forward-compatibility for future agents reading the spec so they
understand the design is anticipating evaluator-workflow dispatch.
## Linear
Created BRO-1038 — "Ergon §12.7b — arcand wiring for workflow-bodied
ticks (BRO-1001 follow-up)". Documents the daemon-side integration
that follows the kernel-side BRO-1001:
- `AgentKindConfig { Direct, PinnedWorkflow{name} }` on
`SessionManifest`
- arcand consciousness reads it, sets `tick_input.kind` accordingly
- Behind `--feature workflow-ticks` (disabled by default in v0.1)
- ~1-2 days work; small because BRO-1001 carries the heavy lifting
## What's now finalized for v0.1 scope
- BRO-1001 (kernel-side) — arcan-ergon adapter + TickKind enum
- BRO-1038 (daemon-side) — arcand wiring with feature flag
- BRO-1003 — bookkeeping-judge as first real evaluator workflow
- BRO-1004 — CI gates + final docs
After these four ship, the "evaluators as workflows" architecture is
proven end-to-end. Verify-mode dispatch becomes the natural next
composition.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…k body (BRO-1001) (#1192) * feat(arcan-ergon): kernel-side adapter running ergon::Workflow as tick body (BRO-1001) New `arcan-ergon` crate at `crates/arcan/arcan-ergon/` that runs an `ergon::Workflow` as the body of one `aios_runtime::KernelRuntime` tick. Closes BRO-1001's "ergon tick-body adapter" deliverable per the corrected architectural framing in `docs/superpowers/specs/2026-05-08-bro-1001-ergon-tick-body.md` (§6, §10 of the original ergon spec are SUPERSEDED — see PR #1190). Kernel side (aios-runtime): - `TickKind` enum on `TickInput` — `Direct` (default, kernel-owned single model call) vs `Workflow { name, input }` (delegated). - `WorkflowTickDispatcher` trait + `WorkflowTickInvocation<'a>` + `WorkflowTickOutcome` types so workflow runners (arcan-ergon today, future shapes later) plug in without forcing the kernel to take on substrate dependencies. - `KernelRuntime::with_workflow_dispatcher` builder method; dispatch logic in `execute_turn` after the `Perceive`/`Deliberate`/`StateEstimated` boundary. - Existing `TickInput` call sites updated to `kind: TickKind::Direct` for behavior parity. arcan-ergon modules: - `dispatcher` — `ErgonWorkflowDispatcher` implements `WorkflowTickDispatcher` against a `WorkflowRegistry`. - `registry` — type-erased boxed-executor registry keyed by name (`BoxedWorkflowExecutor::run_json` does the JSON boundary). - `provider` — `ModelProviderAdapter` wraps `ModelProviderPort` as `ergon::Provider`, translating the kernel's flat shape and synthesizing `StreamEvent` sequences from the directives. - `tools` — `ToolHarnessAdapter` wraps `ToolHarnessPort` as `ergon::ToolRegistry`. No capability evaluation here — that lives on the dedicated capability hook to avoid double-firing. - `runtime_handle` — `ModeRuntimeHandle` exposes per-tick `OperatingMode` as `ergon::RuntimeHandle`. - `hooks` — `KernelCapabilityResolver` (real `PolicyGatePort`-backed adapter for `CapabilityResolver`, with `ToolCapabilityMap` declaring per-tool caps and fail-closed on unknown tools), plus `NoopBudgetGate` / `NoopResponseScorer` / `NoopSoulAttester` permissive stand-ins for the other three adapter traits — real autonomic / nous / anima impls land in follow-up. - `runner::run_workflow_as_tick` — composes a fully-built `ergon::StepCtx` from a `WorkflowTickInvocation`, drives the workflow body, returns `WorkflowTickOutcome` with JSON output + emitted-event count. arcan binary now installs an `ErgonWorkflowDispatcher` (with an empty registry by default) on the kernel runtime at startup. Adopting daemons override the registry to register their concrete `ergon::Workflow` impls before the runtime starts serving. Tests: 16 unit + 4 end-to-end integration tests (`tests/workflow_tick_e2e.rs`) verifying the workflow tick path against a real `KernelRuntime` over file-backed event storage: workflow runs, JSON output ends up in an `ergon.workflow_output` `Custom` event in the journal, direct ticks still work alongside the dispatcher, unknown workflows surface clear errors. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(arcan-ergon): address CodeRabbit feedback on PR #1192 (BRO-1001) Five actionable items + two nitpicks from CodeRabbit's review: 1. **Workflow tick lifecycle parity** (`aios-runtime/src/lib.rs`): the workflow branch was returning early after dispatch, skipping the standard terminal lifecycle (StepFinished + RunFinished) and bubbling dispatch failures out as bare anyhow errors. Now mirrors the Direct path: emits StepStarted before dispatch, then on success appends ergon.workflow_output + StepFinished + RunFinished and runs Commit/Reflect/Sleep finalize; on failure appends RunErrored, increments error_streak / uncertainty / error_budget, drops the runtime into Recover mode, and still finalizes the tick so the journal is coherent. The integration test `unknown_workflow_routes_to_run_errored_and_recover_mode` (renamed + rewritten from `unknown_workflow_yields_error`) asserts the new shape: tick returns Ok, mode=Recover, error_streak >= 1, and an `RunErrored` event in the journal mentioning the workflow name. 2. **Workspace.members alphabetization** (`Cargo.toml`): `crates/arcan/arcan-ergon` was wedged between arcan-commands and arcan-console. Moved to the alphabetically correct slot after arcan-core. 3. **TickInput doc accuracy** (`aios-runtime/src/lib.rs`): the doc-comment referenced `Default::default()` and a `direct()` helper that don't exist. Removed the misleading sentence — the field is just a normal struct field today and call sites set `kind: TickKind::Direct` explicitly. 4. **Provider Message id collision** (`arcan-ergon/src/provider.rs`): `ModelDirective::Message` was emitting `StreamEvent::TextStart` / `TextDelta` / `TextEnd` with a constant `id="message"`, so a completion with multiple Message directives would fail downstream sink pairing. Now uses a directive-local `message_idx` counter so each Message gets a unique `message-N` id. 5. **Test assertion hardening** (`tests/workflow_tick_e2e.rs::workflow_tick_emits_output_event`): was using `if let Some && let Custom` chain that would silently pass if the event went missing or its kind changed. Now uses `.expect()` + `let-else` so a regression fails the test loudly. Nitpicks: - **`requires_approval` test** (`arcan-ergon/src/hooks.rs`): added `approval_required_tool_fails_until_flow_lands` — exercises the BRO-1001 fail-closed path when `PolicyGateDecision.requires_approval` is non-empty (the kernel approval flow isn't bridged into ergon hooks yet; this regression-tests the temporary fail-closed behavior so a future bridge implementation can update the test deliberately). - **`WorkflowRunInputs` re-export** (`arcan-ergon/src/lib.rs`): now re-exported at the crate root alongside `run_workflow_as_tick` so callers can construct `ErgonWorkflowDispatcher::new(registry, inputs)` purely through `arcan_ergon::*` without reaching into the `runner` module. Test counts: 17 unit (was 16) + 4 e2e (4) all green. Workspace: cargo clippy --all-targets -- -D warnings clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Course correction PR. No code changes. Documents what the agent harness actually is, and corrects two sections of the original ergon spec (§6 + §10) that assumed an architecture that doesn't exist in arcan.
What was wrong
`docs/superpowers/specs/2026-05-05-ergon-v0.1.md` §6 and §10 framed ergon as a parallel session-level runtime that would replace `arcan-harness` over time via an `AgentKind` trait abstraction.
That's wrong on two counts:
Corrected framing
Ergon supplies one shape of tick body alongside the existing direct-call tick body. Both compose with `aios_runtime::KernelRuntime`. Both produce per-tick events. Neither replaces anything.
What this PR ships
Documentation only:
NEW `docs/architecture/agent-harness.md` — canonical 7-layer runtime architecture. Maps every layer (L0 kernel contract → L6 process daemons) to its owning crates, walks bottom-up dependency chain + top-down execution trace, defines the two scopes of the agent loop (outer/session vs inner/tick), enumerates built vs pending. This is the doc any future spec should reference when it talks about "the harness."
NEW `docs/superpowers/specs/2026-05-08-bro-1001-ergon-tick-body.md` — corrected BRO-1001 design. 13 sections covering: scope, layered position, public API (`TickBodyCtx`, `run_workflow_as_tick`, `WorkflowRegistry`), lifecycle, the small `TickKind` extension to aios-runtime, DoD, open questions, validation criteria, composition trajectory, versioning, ordered impl plan.
MODIFIED `docs/superpowers/specs/2026-05-05-ergon-v0.1.md` — added top-level correction note pointing to the architecture doc + new BRO-1001 spec. §6 + §10 marked SUPERSEDED inline. §§0-5, 7-9, 11-13 valid as written.
MODIFIED `crates/ergon/ergon/CLAUDE.md` — corrected positioning ("ergon is one shape of tick body, not a parallel session runtime") + canonical layer diagram.
MODIFIED `CHANGELOG.md` — Changed entry documenting the correction.
What does NOT change
The ergon trait surface (Workflow, Step, StepCtx, Hook, model wire types, runtime ports, stream sinks), ergon-life-hooks (4 auto-hooks + adapter traits), ergon-life-sinks (Lago / Vigil / Lifegw). All correct as shipped. They're precisely what a tick-body adapter needs.
Why this is a doc-only PR
The course correction was caught before shipping the wrong adapter (BRO-1001 wasn't scaffolded yet). The trait crates already on main are substrate-free and framing-agnostic. The mismatched framing existed only in the spec text + the not-yet-written adapter design. By correcting the docs first, BRO-1001 will be scaffolded against the right design — no retracted code.
Test plan
What's next after merge
🤖 Generated with Claude Code
Summary by CodeRabbit