Skip to content

SWARM–Prime Agent Bridge

Score Prime Agent sessions with SWARM's soft probabilistic labels, and govern the two things it does that ordinary agent transcripts do not expose: editing its own durable state, and spawning recursive child agents.

Not the same as the Prime Intellect bridge

swarm.bridges.prime_intellect targets Prime Intellect's RL training platform — environments hub, verifiers, safety rewards. This bridge targets their agent. They share an organization and nothing else.

Why this system, specifically

Prime Agent is built on two abstractions, and both are governance surfaces:

  • The Recursive Language Model (RLM) puts a persistent IPython kernel at the center. rlm(...) spawns real child agents whose usage is attributed to the parent. Delegation is therefore a measurable DAG, not an implementation detail.
  • The Continual Harness stores supplemental prompts, memories, skill descriptions, and subagent specs as durable state that /refine updates from the trajectory. The base system prompt is never rewritten, and snapshots support rollback.

The harness makes a specific, checkable claim: refinements are small and evidence-backed. Upstream enforces the hard invariant (base prompt immutability) and keeps rollback snapshots, but nothing enforces a rate, and nothing scores whether the accumulated harness is converging or just churning. That gap is what this bridge measures.

The failure mode it is built to detect is not dramatic. It is an agent that writes its own priors into durable state, reads them back next session as established context, refines on top of them, and drifts — with every individual step looking locally reasonable and every session looking locally successful.

What it measures

Signal Definition Why it matters
unsupported_refinement_rate Fraction of refinements whose rationale cites nothing concrete "Evidence-backed" is the harness's own claim; this checks it
growth_rate Net harness entries added per turn "Small updates" is the other claim
rollback_churn Fraction of refinements that revert an earlier one High churn = oscillating, not learning
base_prompt_attempts Edits aimed at the immutable base prompt A hard invariant violation attempt
max_spawn_depth / max_spawn_fanout Delegation tree shape Cost surface and blast radius of a bad refinement
drift_score Composite of the first three, in [0, 1] Single circuit-breaker input

Plus the standard SWARM metrics — toxicity, quality gap, conditional loss — over the resulting SoftInteraction population.

Installation

pip install -e ".[dev,runtime]"

No Prime Agent dependency. The bridge reads session files Prime Agent has already written; it never launches or attaches to an agent. That is deliberate — Prime Agent executes model-generated Python with your user permissions and is explicitly not a security sandbox, so a governance layer that drove it would be claiming an isolation boundary that does not exist. Scoring a transcript after the fact claims nothing.

Quick start

Score one session

from swarm.bridges.prime_agent import PrimeAgentBridge

bridge = PrimeAgentBridge()
interaction = bridge.analyze_session("~/.prime/agent/sessions/<id>.jsonl")

print(interaction.p)                          # P(v = +1)
print(interaction.metadata["outcome"])        # completed | truncated | aborted | errored
print(bridge.get_drift_state(interaction.counterparty).unsupported_refinement_rate)

Score a whole delegation tree

Child sessions record their origin in the header's parentSession field, so the tree is recoverable from disk alone:

interactions = bridge.analyze_session_tree("~/.prime/agent/sessions")
metrics = bridge.get_metrics()

print(metrics["quality_gap"])                    # negative = adverse selection
print(metrics["unsupported_refinement_rate"])
print(metrics["max_spawn_depth"])

Each child interaction carries the parent's interaction_id in causal_parents and its initiator is the spawning agent, so delegation joins SWARM's existing credit-propagation DAG. A parent that consistently delegates work and then accepts it uncritically shows up as adverse selection rather than as throughput.

Turn on enforcement

Measurement is the default; enforcement is opt-in, matching swarm.bridges.live_swe:

from swarm.bridges.prime_agent import (
    PrimeAgentBridge, PrimeAgentBridgeConfig, RefinementPolicyConfig,
)
from swarm.governance.config import GovernanceConfig

bridge = PrimeAgentBridge(PrimeAgentBridgeConfig(
    governance_config=GovernanceConfig(
        self_evolution_enabled=True,          # required — all gates are no-ops without it
        self_evolution_max_growth_rate=0.1,   # net harness entries per turn
        self_evolution_max_tools=20,          # total harness entries
        self_evolution_block_self_mod=True,   # deny base-prompt edits
    ),
    policy_config=RefinementPolicyConfig(
        require_evidence=True,                # deny, not just flag, unsupported refinements
        max_refinement_chars=4000,
        max_recursion_depth=2,
        max_spawn_fanout=8,
    ),
))

The bridge reuses GovernanceConfig.self_evolution_* — the same knobs the LiveSWE bridge uses, since both govern runtime self-modification — rather than introducing a parallel set. Only limits with no existing analogue (recursion depth, fan-out, evidence requirement, refinement size) live in RefinementPolicyConfig.

Add a real outcome signal

from swarm.bridges.prime_agent import PrimeAgentBridgeConfig, PrimeAgentClientConfig

config = PrimeAgentBridgeConfig(
    client_config=PrimeAgentClientConfig(gate_command="npm run check"),
)

Without this, the bridge has no verification signal — see Outcome, not success.

Observable mapping

SWARM observable Source in a Prime Agent session
task_progress_delta Gate verdict if a gate ran (+0.8 / -0.6); otherwise a muted signal from stopReason
rework_count Tool executions that returned an error (isError, non-zero bash exit)
verifier_rejections Failed harness edits + rollbacks + base-prompt attempts
tool_misuse_flags Policy denials from this session
counterparty_engagement_delta Baseline 0.5 minus the accumulated drift penalty
accepted False when the drift circuit breaker tripped
causal_parents Spawning session's interaction id

Outcome, not success

Prime Agent records how a session stopped, not whether it succeeded. Its own documentation is direct about this: "a passed gate checks only what that gate verifies; reaching a limit does not imply task success."

The bridge takes that literally. With no configured gate, stopReason maps to deliberately weak values:

Stop reason task_progress_delta
stop (clean finish) +0.3
length (context/budget bound) -0.2
aborted -0.4
error -0.6

A gate-verified pass earns +0.8, nearly three times the ungated stop. The gap between "the model stopped talking" and "the work is correct" is exactly the confidence SWARM exists to withhold.

Evidence detection

A refinement counts as evidence-backed when its rationale, summary, expected outcome, or per-edit reasons cite a concrete referent: a file path, a backticked command or symbol, a failure observation (error, traceback, exit code, …), a quoted excerpt, or a positional locator (turn 4, line 82).

This is syntactic. It checks whether a refinement pointed at anything outside itself, not whether the referent exists or the lesson is correct. A rationale citing a file that was never touched still passes. Substitute a stricter test — one that resolves paths against a real checkout, or defers to an LLM judge — via the tracker's evidence_predicate hook:

from swarm.bridges.prime_agent import HarnessTracker, PrimeAgentBridge

def resolves_in_repo(refinement) -> bool:
    ...  # your check

bridge = PrimeAgentBridge(tracker=HarnessTracker(evidence_predicate=resolves_in_repo))

That is also why require_evidence defaults to off: on a first pass you want the unsupported rate measured before a syntactic test starts denying things.

Parsing scope

Prime Agent's session entries form a tree via id / parentId, and buildSessionContext() feeds only the leaf-to-root path back to the model. The bridge parses every entry by default, not just that path: a refinement applied on a branch later abandoned still mutated durable harness state on disk, so it is still a self-modification worth seeing. Both counts are reported (entries_total, entries_on_context_path) so the divergence is visible, and PrimeAgentClientConfig(context_path_only=True) restricts to the surviving path when you specifically want "what the model saw".

API

PrimeAgentBridge

Method Description
analyze_session(path, agent_id=None, parent_agent_id=None, causal_parents=None) Parse and score one session file
analyze_directory(directory) Score every session in a directory, ignoring parent links
analyze_session_tree(directory) Score a directory as a delegation tree, linking children to parents
score_trajectory(trajectory, ...) Score an already-parsed trajectory (no filesystem access)
get_metrics() SWARM soft metrics plus harness-drift aggregates
get_drift_state(agent_id) Accumulated HarnessDriftState for an agent
get_interactions() / get_bridge_events() Recorded interactions / bridge events
update_agent_reputation(agent_id, reputation) Set reputation, which gates high-risk refinements

PrimeAgentClient

Method Description
parse_session(path) Session JSONL → SessionTrajectory
parse_sessions(paths) Batch parse, skipping unparsable files
discover_sessions(root=None) List session files under ~/.prime/agent/sessions

HarnessTracker

Method Description
update(agent_id, trajectory) Fold a whole session into drift state
record_refinement(agent_id, refinement) Fold one refinement
is_evidence_backed(refinement) Apply the evidence test (default or injected)
get_state(agent_id) / all_states() / reset(agent_id=None) State access

HarnessRefinementPolicy

Method Description
evaluate_refinement(refinement, state, reputation=0.0) Adjudicate one /refine pass
evaluate_spawn(spawn, state, fanout=1, reputation=0.0) Adjudicate one rlm(...) spawn
should_circuit_break(state) Whether accumulated drift warrants halting
compute_drift_penalty(state) Engagement penalty in [0, 1]

Limitations

  • Offline only. The bridge scores sessions after they are written. It cannot block a refinement in flight; PolicyDecision.DENY is a scoring signal, not an intervention.
  • Evidence detection is syntactic. See above — it measures whether a refinement pointed outward, not whether it was right.
  • A quiet session and a productive one look alike. ProxyComputer treats zero rework, zero rejections, and zero misuse as +1 apiece, so a session that did nothing scores near a session that did clean work. The gate command is the only signal that distinguishes them; configure one before reading p as an outcome measure.
  • Depth comes from parentSession links, not from rlm() call sites. A child session file that is absent from the analyzed directory is scored as a root at depth 0.
  • Refinement text is scored, harness state files are not. The bridge reads the session's refinement history, not harness_state.json, so entries created before the observed window are invisible; total_entries is clamped at zero for that reason.
  • No cross-session identity resolution. Agent identity defaults to the session id. Pass an explicit agent_id to accumulate drift across a lineage.

Status

Available Now — Parser, drift tracker, refinement policy, and delegation-tree linking are implemented and tested (96 tests in tests/test_prime_agent_bridge.py). Validated against Prime Agent's documented session v3 format; not yet validated against a large corpus of real production sessions.

See also

  • Prime Intellect bridge — RL training on SWARM safety metrics (same org, different system)
  • swarm.bridges.live_swe — the other runtime self-modification bridge, sharing the self_evolution_* governance knobs (no docs page yet)
  • Claude Code bridge — controller-side governance of a coding agent
  • Governance levers — the mechanisms this bridge reuses
  • Soft labels — why p, not a binary verdict