SRBN Architecture¶
The Stabilized Recursive Barrier Network (SRBN) is the idea behind Perspt’s experimental autonomous coding agent. It comes from the Stability is All You Need paper series.
The idea is plain to state. A language model is good at proposing changes, but a proposal is only a guess. Left unchecked, a long run of guesses drifts: small mistakes pile up until the work is broken. SRBN refuses to trust a guess on its word. It measures every proposed change, keeps the change only when the measurement shows progress, and writes the kept result to a permanent record. Perspt’s coding agent implements this work via a reusable software-development-kit (SDK) platform (originally specified in the references section under PSP-8).
Theory vs. Implementation
This page describes both the SRBN paper series and how Perspt’s runtime implements it. Where a claim comes from the papers’ formal proofs, it is noted as a paper result. Where the developer team makes engineering choices that approximate or extend the theory, those are noted as implementation details. The theoretical framework is mature; empirical benchmarks on Perspt’s implementation have not yet been published.
Overview¶
The SRBN paper models coding tasks as a directed acyclic graph (DAG) of nodes with a sheaf structure that enforces consistency across shared boundaries. The system establishes the following concrete mechanics: each node owns a set of output files (ownership closure), runs a governed tool loop of typed tool calls against an isolated candidate, and must pass the measured acceptance gate on deterministic verifier evidence. Only then is the node’s winner promoted and committed to the Merkle ledger.
The runtime environment structures execution in two primary ways:
Quadratic energy. Acceptance is gated on the quadratic residual energy \(V(x) = \sum_{e} w_e \lVert r_e \rVert^2\) (see Lyapunov Energy below).
Mutable work graph. Rather than walking a precomputed topological order, a closed-loop scheduler re-evaluates a dependency-aware ready queue each round and may requeue, split, insert, or replan nodes as verifier evidence arrives. Each individual graph revision stays acyclic. Bounded parallelism shipped in v0.6.6: the multi-node dispatcher behind
--max-parallel-nodesruns ready nodes concurrently, and two nodes with conflicting file footprints never run at the same time.
The core concepts of the control system — ownership closure, typed tool calls, the verifier profiles, node classes, and the Merkle ledger — are described below.
![digraph srbn {
rankdir=TB;
compound=true;
node [shape=box, style="rounded,filled", fontname="Helvetica", fontsize=10];
subgraph cluster_models {
label="Model Roles";
style=dashed;
arch [label="Architect\n(Graph Planning)", fillcolor="#E8F5E9"];
act [label="Actuator\n(Governed Tool Calls)", fillcolor="#E3F2FD"];
exp [label="Explorer\n(Read-Only Exploration)", fillcolor="#FFF3E0"];
adj [label="Adjudicator\n(No-Tool Diff Review)", fillcolor="#F3E5F5"];
}
kernel [label="Admissibility Kernel\n(Deterministic)", fillcolor="#D1C4E9"];
cand [label="Candidate Overlay", fillcolor="#E0E0E0"];
subgraph cluster_barriers {
label="Deterministic Verifier Sensors";
style=dashed;
lsp [label="V_syn\n(LSP)", fillcolor="#FFECB3"];
tests [label="V_log\n(Tests)", fillcolor="#FFECB3"];
boot [label="V_boot\n(Build)", fillcolor="#FFECB3"];
struct [label="V_str\n(Contracts)", fillcolor="#FFECB3"];
sheaf [label="V_sheaf\n(Cross-Node)", fillcolor="#FFECB3"];
}
gate [label="Accept Gate\n(hard pass or descent)", fillcolor="#B3E5FC"];
subgraph cluster_output {
label="Output";
style=dashed;
ledger [label="Merkle Ledger\n(DuckDB)", fillcolor="#C8E6C9"];
}
arch -> act [label="work graph"];
exp -> act [label="evidence", style=dashed];
act -> kernel [label="typed proposals"];
kernel -> cand [label="admitted effects"];
cand -> lsp;
cand -> tests;
cand -> boot;
cand -> struct;
cand -> sheaf;
lsp -> gate;
tests -> gate;
boot -> gate;
struct -> gate;
sheaf -> gate;
adj -> gate [label="conjunctive review", style=dashed];
gate -> act [label="correction", style=dashed];
gate -> ledger [label="promote"];
}](../_images/graphviz-7bc18f13b75330339f2bdf988c5b8bab98249dac.png)
SRBN Architecture¶
The Control Loop¶
Bootstrap and the architect turn run once at the start; the remaining phases run per node inside the closed loop. The dispatcher re-evaluates the mutable work graph, fills free slots with ready nodes, and runs the governed tool loop for each. A node that fails its gate can open a bounded search forest and be re-attempted, so these phases are not a single topological pass:
# |
Phase |
Description |
|---|---|---|
1 |
Session Bootstrap |
Create the durable session, detect the domain package and language plugins, mint epoch-bound capabilities from the grant policy, and compile the prompt programs for the resolved routes and dialects. |
2 |
Architect Turn |
A governed, forced-tool-choice model turn restricted to the privileged
|
3 |
Work-Graph Dispatch |
Behind |
4 |
Governed Tool Loop |
Per node, model turns issue typed tool calls. Each call becomes a proposal; the deterministic admissibility kernel decides whether it may affect the candidate; admitted effects mutate an isolated candidate overlay; sandboxed deterministic verifiers re-measure the candidate. |
5 |
Accept Gate |
A candidate is accepted on a hard verifier pass, or on a measured energy descent of at least \(\rho_{\text{gate}}\) below the best accepted state. Non-descending candidates consume the shared rejection budget; the gate is evaluated on the re-measured candidate, never on the model’s account of it. |
6 |
Bounded Search (optional) |
On gate failure with budget remaining, a bounded search forest runs up to three isolated branches with distinct strategies against the accepted root. Every branch action reserves its cost before it runs, exact no-goods suppress repeats, and exactly one selected candidate is committed through the same gate. |
7 |
Staging & Integration |
Each node’s winner lands in a content-addressed staging root instead of the user workspace. When dispatch settles, the merged state passes one global integration gate; failure restores the prior staging root. |
8 |
Promotion |
The integrated winner is written to the user workspace through
journaled, descriptor-relative promotion and committed to the
hash-chained ledger, from which |
Lyapunov Energy¶
The stability of generated code is measured using a Lyapunov energy function, adapted from the paper’s sheaf-theoretic formulation into concrete verification barriers. The system evaluates a canonical quadratic residual energy: each sensor \(e\) emits a residual with a non-negative magnitude \(r_e(x)\), and the energy is a weighted sum of their squares.
Let \(\mathcal{E}\) be the set of active sensors monitoring the system. For a proposed state \(x\), the total Lyapunov energy \(V(x)\) is defined by the quadratic form:
where \(w_e > 0\) represents the positive weight assigned to the residual class of sensor \(e\).
The five component readouts \(V_{syn}\), \(V_{str}\), \(V_{log}\), \(V_{boot}\), and \(V_{sheaf}\) are derived rollups of this same energy, grouped by component type, such that the total is the sum of the rollups:
In this formulation, the rollups themselves carry the squared, weighted residual contributions:
There is no secondary \(\alpha/\beta/\gamma\) aggregation pass. The per-class weights \(w_e\) are fixed by the domain package’s energy model, leaving the core mathematical engine as a pure sum of pre-weighted squares.
Components¶
We enumerate the five component categories and the specific residual classes mapped to them from the perspt-coding domain package:
Component |
Mapped Residual Classes (Weights) |
Operational Semantics |
|---|---|---|
V_syn |
|
Captures syntax errors, build-time compilation failures, and LSP diagnostic warnings.
Compiler warnings or type-check diagnostics produce residuals of class |
V_str |
|
Measures structural contract adherence. If a required symbol defined by a node’s public
interface signature is absent from the generated output files, the |
V_log |
|
Evaluates behavioral outcomes. Unit test failures yield a |
V_boot |
|
Registers system infrastructure state. If a required sensor (e.g., an LSP server or
test runner) is degraded or unavailable, it raises a |
V_sheaf |
|
Evaluates global structural consistency across nodes. Cross-node import/dependency
mismatches or signature differences raise a |
Convergence Criterion¶
The system is considered stable if and only if the candidate achieves a
hard pass: every required verifier and every hard policy constraint
passes. A domain may additionally declare an analytic energy floor; a
candidate at or below the floor is checkpointed as a classified terminal
state but is never reported as verified success. If the state is not stable,
the accept-gate evaluates descent. The single runtime acceptance knob is
--rho-gate. A state \(x\) can be provisionally accepted during
convergence if:
where \(x_{\text{best}}\) is the best previously accepted state, and \(\rho_{\text{gate}}\) is the minimum descent gate (default \(0.50\)), ensuring non-trivial progress.
Spectral and Independence Diagnostics¶
The system supports an energy-slope constant \(\mu = 2\,\lambda_{\min}^{+}(A)\) — twice the algebraic connectivity (Fiedler value) of the verification graph built from the quadratic energy \(V(x)=x^{\top}Ax\). It measures how strongly the verifier ensemble drives the code toward consensus, and its sensitivity to a candidate verifier edge distinguishes an independent verifier (which raises the spectral gap) from a redundant one. A companion measure, \(\rho_{\text{eff}}\), captures effective verifier independence from observed miss correlations.
Note
mu and \(\rho_{\text{eff}}\) are diagnostics, not acceptance-gate
inputs — by design they are computed off the critical path and never block a
node. The independence statistics are live: independence::compute
folds the psp9_verdicts ledger into per-validator miss rates and
matched-stratum pair statistics, and \(\rho_{\text{eff}}\) is reported
only when every pair meets the matched-sample floor (a Hoeffding upper
confidence bound backs the certified value). perspt status and the
dashboard’s Governance page surface these figures. The spectral
eigensolver (spectral::VerificationGraph) remains an offline
perspt-sdk diagnostic.
Node Classes¶
The system utilizes three node classes that govern execution order and verification:
Class |
Description |
|---|---|
Interface |
Define exported signatures, schemas, and seals. Must be committed before dependent Implementation nodes can proceed. Produces an interface-seal digest. |
Implementation |
Operate on owned files using sealed interfaces from parent nodes. The bulk of code generation happens here. |
Integration |
Reconcile cross-owner boundaries after all dependent nodes converge. Used for multi-language projects or cross-module wiring. |
Ownership Closure¶
The ownership closure rule is a fundamental invariant of PSP-5:
Each output file appears in exactly one node’s
output_fileslist.
This prevents conflicting writes. In the current runtime the guarantee is enforced at dispatch through footprints: two nodes whose declared file footprints conflict never run concurrently, and each node attempt is seeded from the staging root rather than from unstaged sibling state.
Model Roles¶
The runtime uses one required and two optional model roles. Verification is not a model role: the verifiers are deterministic sandboxed sensors (compilers, test runners, linters), never a model call.
Role |
Purpose |
CLI Flag |
|---|---|---|
Actuator |
Proposes governed coding tool calls; the only role that can mutate
the candidate. Also serves the architect’s |
|
Explorer |
Optional cheaper read-only repository exploration. |
|
Adjudicator |
Optional no-tool conjunctive diff adjudication before promotion. |
|
Configure per-role routes via CLI:
perspt agent \
--actuator-model <provider::model> \
--explorer-model <provider::model> \
--adjudicator-model <provider::model> \
--fallback-model <provider::model> \
"Build a REST API"
--fallback-model is repeatable and defines the ordered sticky actuator
failover route. Persistent per-role routes live in the [models] table of
config.toml as fully qualified provider::model values, so identity,
calibration, and replay never depend on an ambient default provider. No
model name is hard-coded in the runtime.
PSP-10: Model-Conditioned Prompt Programs¶
PSP-10 replaces free-form prompt templates with compiled prompt programs: typed sections, deterministic composition per model route, and ledgered digests for every model call.
Typed Prompt Sections¶
Prompt text lives in versioned section files under
crates/perspt-core/prompts/<stage>/NN_name.md, one directory per stage
(session_bootstrap, graph_plan, repository_explore,
adjudicate, evidence_summarize), beside a committed
manifest.toml. The perspt-prompt-macros crate compiles every section
at build time from the owning crate’s build.rs: it parses the front
matter into a typed SectionSchema (id, version, role, priority, size
bound, declared variables), runs the codegen validation list, and emits typed section
structs into OUT_DIR. A malformed section fails cargo build with an
error naming the offending file — never a session.
Stage Composition and Digests¶
At runtime a StageComposition composes one stage’s rendered sections for
the resolved model route and dialect into a CompiledPromptProgram: the
ordered messages with per-message rendered hashes, any sections dropped by
deterministic budget fitting, the tool-spec hash, and a program_digest
computed over canonical bytes of the identity-bearing fields. One model call
binds a platform program (the universal envelope) and a domain program; the
pair forms a CompiledPromptInvocation with its own invocation digest.
Provenance¶
Every model call is ledgered: a prompt_program_compiled event records
each program’s sections and digest, and a prompt_program_invoked event
records the actor, turn, platform digest, domain digest, invocation digest,
and tool-spec hash. A session’s prompts are therefore reconstructible and
diffable after the fact. Validated replacement bundles may substitute
section bodies live only behind --allow-experimental-prompts; external
bodies obey exactly the validation rules the build does.
The perspt prompts CLI¶
perspt prompts list # every compiled section: id, version, stage, role, hash
perspt prompts render <stage> # compose one stage with fixture variables
perspt prompts lint --bundle <dir> # validate an external bundle directory
perspt prompts manifest <dir> # regenerate a library's manifest.toml
perspt prompts explain-session --db-path <db> <session-id>
# the programs a session actually compiled, with digests
perspt context explain-turn is the companion command for a session’s
recorded resident-context events (compactions and refusals).
Rejection Budget¶
There is no per-error-type retry table. The loop runs against a single
shared, non-replenishing rejection budget \(B\) (default 4,
--rejection-budget): non-descending candidates and recovery attempts
consume it, while accepted descents do not. Together with the descent gate
this yields the finite-decision bound
\(\lfloor V_0 / \rho_{\text{gate}} \rfloor + B + 1\) on gate decisions
per node. When the budget is exhausted, the gate issues a residual
certificate enumerating the remaining errors and the node terminates as a
classified failure rather than looping. In headless mode (--yes) the
session exits with a non-zero code when the outcome is not verified success.
Typed Tool Proposals¶
The Actuator does not emit artifact bundles. Every mutation is an individual
typed tool call: the call becomes an effect proposal, the deterministic
admissibility kernel checks it against the node’s capability (path patterns,
command patterns, effect kinds), and only an admitted effect executes —
against the isolated candidate overlay, never the user workspace. Proposed
commands additionally pass the deterministic sanitize_command and
workspace-bound guards plus the Starlark policy engine, and normally run inside
the process sandbox. Explicit native Windows reduced-isolation mode retains
those agent checks but runs child processes with host-user authority. The
candidate journals a pre-image of every file it
touches, so any attempt can be discarded without residue.
Plugin-Driven Verification¶
Language plugins determine the verification toolchain:
Plugin |
LSP Server |
Test Runner |
Init Command |
Required Binaries |
|---|---|---|---|---|
Rust |
|
|
|
|
Python |
|
|
|
|
JavaScript |
|
|
|
|
Go |
|
|
|
|
The plugin is selected automatically during the Detection phase based on existing project files or the task description. Multi-language projects activate multiple plugins simultaneously.
Degraded Verification¶
When a verification tool is unavailable (e.g., ty not installed), the SRBN
engine falls back to degraded mode:
Sensor fallback: If the primary LSP server is not found, try a secondary (e.g.,
pyrightinstead ofty). Emit aSensorFallbackevent.Degraded stages: If no LSP server is available at all, V_syn is set to 0.0 and the stage is marked degraded. Energy convergence proceeds without that component.
Stability blocked: If too many stages degrade, the node cannot converge and is escalated.
Merkle Ledger¶
All changes are recorded in a DuckDB-backed Merkle ledger:
Integrity - Each commit has a cryptographic hash chaining to its parent
Rollback - Roll back a session’s newest completed promotion via
perspt ledger --rollback(the argument is a session id prefix)Resume -
perspt resumecontinues an interrupted session from its newest durable checkpoint by folding the ledger (see Crash Resume)Audit - Complete trail of AI-generated changes with energy breakdowns
perspt ledger --recent # View recent commits
perspt ledger --rollback abc123
perspt ledger --stats # Session statistics
Isolation and Resume¶
Nothing speculative ever touches the user workspace. Three layers keep observed work separated from accepted work, and crash resume preserves the separation.
Key Invariant
Model-proposed work reaches the user workspace only through the accept gate, the staging root, and the global integration gate — in that order. Everything else is discarded without residue.
Candidate Overlays¶
Each node attempt runs in a CandidateWorkspace overlay. Admitted effects
mutate the overlay; every touched file’s pre-image is journaled; verifiers
measure the overlay, not the workspace. A rejected attempt is dropped
wholesale.
Test evidence follows an explicit policy. The ordinary evolving policy
measures the resulting implementation and resulting tests together, which is
necessary when a task intentionally changes a contract. A
backward-compatible run adds a regression view with recognized historical
test files restored. An external-oracle run adds a separately supplied
acceptance overlay that the actuator does not promote. These are additional
test-stage views of the same realized candidate, not alternate paths around
the syntax, build, or test requirements.
Search Forest Branches¶
A bounded search forest opens at most three branch identities, one branch attempt at a time. Every branch runs the ordinary governed loop in an isolated eager-copy workspace against the same immutable accepted root, and its internal states stay private to the forest. Exactly one selected candidate is committed through a single gate submission, and the committed decision must equal the preview or the forest fails closed. Exact no-goods learned from failed branches suppress equivalent later attempts, and every branch action reserves its cost against the declared limit vector before it runs.
Staging and the Integration Gate¶
With --max-parallel-nodes above 1, node winners land in a
content-addressed staging root instead of the user workspace. Disjoint
footprints are enforced at dispatch; the merged state must pass one global
integration gate before promotion, and a gate failure restores the prior
staging root. The integration gate uses the same session-bound test policy as
the node gates: resulting tests for ordinary evolving development, an
additional historical regression view for explicitly backward-compatible
work, or a separately protected external acceptance overlay.
Crash Resume¶
perspt resume folds the durable ledger rather than deserializing live
state. A single-node session re-enters its loop from the newest durable
candidate checkpoint with exactly the remaining budgets, its accepted
candidate rebuilt from content-addressed artifacts and a fresh capability
minted at the current authority epoch (a bumped epoch refuses the resume).
A multi-node session resumes through graph dispatch: the staging root is
rebuilt from the ledger and every winner still reaches the user workspace
only through the global integration gate.