Context name: AgentboxIntegration (BC20 — provisional, pending BC catalogue update)
Date: 2026-04-23
Author: VisionClaw platform team
Related: PRD-004 (agentbox ↔ VisionClaw integration), ADR-058 (MAD→agentbox migration), ADR-005 (agentbox pluggable adapters), docs/ddd-bead-provenance-context.md (BC — Bead Provenance), ADR-056 (JSS parity migration), ADR-057 (Contributor Enablement Platform)
Define the bounded context that mediates between VisionClaw's Rust substrate and the agentbox execution container. This context is an Anti-Corruption Layer: its job is to translate between the external agentbox adapter protocol (stable, generic, owned by the agentbox product) and VisionClaw's internal aggregates (evolving, domain-specific, owned by VisionClaw).
Without this context, every VisionClaw actor that wants to spawn an agent or record a receipt would couple itself to agentbox's wire format. With it, agentbox can evolve independently in its own repo and VisionClaw can evolve its domain model without breaking the agent pipeline.
| Term | Meaning in this context |
|---|---|
| AgentExecutionRequest | A VisionClaw-side command asking agentbox to spawn an agent with a role, prompt, and user context |
| AgentExecutionReceipt | The bead an agent records when it performs work; one epic per brief, one child per role response |
| AdapterEndpoint | A VisionClaw service that implements one of the five agentbox adapter contracts (beads, pods, memory, events, orchestrator) |
| FederationSession | A resolved configuration binding a running agentbox instance to a specific set of VisionClaw AdapterEndpoints for its lifetime |
| SpawnChannel | The stdio or HTTP contract over which VisionClaw actors drive agent lifecycle inside agentbox |
| AgentEventStream | The JSONL event stream from agentbox (spawn, tool-use, progress, completion) consumed by VisionClaw actors |
| LocalFallbackProbe | A diagnostic check confirming that an agentbox in federated mode is not silently using its local fallbacks when VisionClaw AdapterEndpoints are expected. Mechanism: each external AdapterEndpoint must respond to a GET /probe/origin (or MCP/stdio equivalent) with a signed token containing {endpoint_id, issued_at, session_id_nonce}, signed with the endpoint's registered Ed25519 key. The local fallbacks have no such key, cannot produce a valid signature, and probe failure is treated as session quarantine (see §4.1 invariant) |
Status: aspirational design — not implemented as of 2026-06-12 (no
AgentExecutionRequestHandler,AdapterEndpointRegistry, orFederationSessiontypes exist insrc/).
graph TD
subgraph VC["VisionClaw Rust substrate"]
BP["BeadProvenance (BC)<br/>(ddd-bead-...)"]
CONTRIB["Contributor (BC18)<br/>(ADR-057)"]
SKILLS["Skills (BC19)"]
subgraph BC20["AgentboxIntegration (BC20 - this context)"]
AERH["AgentExecutionRequestHandler"]
AER["AdapterEndpointRegistry"]
FS["FederationSession aggregate"]
AESP["AgentEventStreamProjector"]
ACA["AntiCorruptionAdapters<br/>(beads, pods, memory, events, orchestrator)<br/>translate agentbox wire to VC domain"]
end
end
subgraph AB["agentbox (sibling container, ADR-005 adapters)"]
end
BP --> BC20
CONTRIB --> BC20
SKILLS --> BC20
BC20 -->|"docker-compose-internal DNS"| AB
Root entity. Represents one running agentbox instance and its resolved adapter bindings.
pub struct FederationSession {
id: FederationSessionId, // UUID v7 — time-ordered
agentbox_image_hash: ImageHash, // sha256 from Nix build — invariant per session
manifest_checksum: ManifestHash, // sha256 of agentbox.toml
adapter_bindings: AdapterBindings, // one AdapterEndpoint per slot
started_at: DateTime<Utc>,
health: SessionHealth, // Healthy | Degraded | Failed
active_executions: Vec<AgentExecutionId>,
}Invariants:
adapter_bindingsMUST NOT include anyLocalbinding whenmode = "client". A LocalFallbackProbe failure triggers session quarantine (the session transitions toFailed, outstanding executions are cancelled with reasonFederationIntegrityViolation, and theLocalFallbackProbeFailedevent is raised).manifest_checksumMUST match the agentbox container's reported manifest hash at boot. Mismatch = reject session start.- Once started,
adapter_bindingsare immutable — changing them requires a new session. - Version compatibility is verified via the
/v1/metahandshake (see §4.1a) BEFORE the session transitions to Healthy.
Domain events emitted:
FederationSessionStarted { session_id, manifest_checksum, adapter_bindings }FederationSessionHealthDegraded { session_id, reason, affected_slots }LocalFallbackProbeFailed { session_id, slot, expected_endpoint, actual_signature_result }AdapterContractVersionMismatch { session_id, slot, agentbox_version, visionclaw_range }FederationSessionStopped { session_id, reason }
On session start, FederationSessionLifecycleService executes this sequence before emitting FederationSessionStarted:
- Pull agentbox meta. Call
GET http://<agentbox>:9090/v1/meta. Response shape:{ "image_hash": "sha256:...", "manifest_checksum": "sha256:...", "federation_mode": "client", "adapter_contract_versions": { "beads": "1.2.0", "pods": "1.0.1", "memory": "2.0.0", "events": "1.1.0", "orchestrator": "1.0.0" } } - Verify federation mode.
federation_modeMUST equal"client". Otherwise abort withFederationMisconfigured. - Compare adapter contract versions against
AdapterEndpointRegistry.compat_ranges. For each slot, the agentbox-declared version MUST intersect the VisionClaw-declared SemVer range. Otherwise emitAdapterContractVersionMismatchand abort. - Run LocalFallbackProbe for every slot. For each slot, call the registered endpoint's
GET /probe/origin, verify the Ed25519 signature against the endpoint's registered public key, and confirmendpoint_idmatches the registry entry. Any failure emitsLocalFallbackProbeFailedand aborts. - Emit
FederationSessionStartedwith the resolved bindings and the full handshake record (for audit replay).
The handshake runs on every session start; no caching. Total p95 budget: 2 seconds across all five slots. Timeouts abort session start rather than fall through to partial startup.
Root entity. One unit of agent work requested by a VisionClaw actor.
pub struct AgentExecution {
id: AgentExecutionId,
session: FederationSessionId,
requester: ActorRef, // which VC actor asked
role: RoleSlug, // architect, dev, ciso, ...
prompt: PromptPayload,
user_context: UserContext, // pubkey + display name (NIP-98 identity)
brief_ref: Option<BriefRef>, // if this is part of a Briefing workflow
bead_ref: Option<BeadRef>, // the child bead created for this execution
status: ExecutionStatus, // Spawning | Running | Completed | Failed
events: Vec<AgentEvent>, // lifecycle projection
}Invariants:
- An
AgentExecutionbelongs to exactly oneFederationSession. bead_refMUST be populated if the session'sadapters.beads != Off.eventsappend-only; projection from agentbox's AgentEventStream; last event MUST be terminal (Completed or Failed) before the execution is archived.
Domain events emitted:
AgentExecutionRequested { execution_id, session, role, user_context }AgentExecutionSpawned { execution_id, pid_or_token, started_at }AgentExecutionToolUsed { execution_id, tool, input_ref, output_ref }AgentExecutionCompleted { execution_id, outcome, artefact_refs }AgentExecutionFailed { execution_id, reason }
Aggregate of value objects. Not an entity — a read-model that records which VisionClaw sibling containers implement which agentbox adapter slot.
pub struct AdapterEndpoint {
slot: AdapterSlot, // Beads | Pods | Memory | Events | Orchestrator
protocol: AdapterProtocol, // Http | Stdio | Mcp
address: EndpointAddress, // e.g. "http://beads-actor:7001"
health: EndpointHealth,
contract_version: SemVer, // adapter contract version it implements
}Invariants:
- For every slot, at least one endpoint is Healthy before
FederationSessionStartedcan emit. contract_versionmust be compatible with the agentbox version agentbox reports. Incompatibility = rejected session start.
The ACL is the heart of this context. It owns five translator modules, one per adapter slot:
| ACL module | Maps agentbox wire → VC domain |
|---|---|
beads_acl |
agentbox bd-CLI-shaped JSON ↔ BeadProvenance aggregate commands/events |
pods_acl |
Solid-protocol LDP containers ↔ VisionClaw pod artefact URIs (LDP-compatible but often with extra VC metadata) |
memory_acl |
Generic vector query/store ↔ VisionClaw's memory namespace layout (personal-context, project-state, patterns, etc.) |
events_acl |
agentbox JSONL event schema ↔ VisionClaw's Contributor Stratum event bus schema (kinds, partition keys, retention) |
orchestrator_acl |
agentbox stdio spawn protocol ↔ VisionClaw's actor spawn command/reply pattern |
ACL rules:
- No VisionClaw domain type ever appears in agentbox's repo. Agentbox's adapter interface is generic by design.
- No agentbox wire type ever leaks into VisionClaw domain code outside this context. Callers see VC-typed commands only.
- ACL modules version their translations. When agentbox's adapter contract changes, the ACL translator is bumped; VC domain events do not change.
- Translation must be total — every agentbox payload must either map to a VC domain event or be classified as a known-and-ignorable signal. Unknown payloads raise
UnmappedAgentboxPayloadfor triage.
Upstream. beads_acl is the ONLY code path that invokes BeadProvenance commands on behalf of an agentbox execution. When adapters.beads = "external", agentbox POSTs to the VisionClaw beads-actor endpoint; the actor accepts a narrow command-shape that beads_acl translates into rich CreateEpic / CreateChild / ClaimBead commands honouring the context's invariants.
Upstream. ContributorStudioSupervisor is the most common requester of AgentExecutionRequested. It passes a GuidanceSession context that this context projects into agentbox's UserContext + role-specific prompt.
Upstream. Skills are discovered + installed on the agentbox side (skills are content-addressed Nix inputs per agentbox PRD-001 §5). VisionClaw's SkillRegistrySupervisor signals which skill is currently active per session; the session's adapter bindings may narrow or extend based on skill requirements (e.g. a skill needing ontology tools requires skills.ontology = true in the manifest).
Downstream. When adapters.events = "external" AND the VC event bus fans out to Nostr, each AgentExecutionCompleted produces a NIP-33 addressable replaceable event that the Contributor Stratum's publicTypeIndex can reference.
A FederationSession's health is NOT a boolean AND of its five adapter endpoints. Per-slot degrade policies determine whether partial failures are survivable.
pub enum SessionHealth { Healthy, Degraded, Failed }
pub enum SlotDegradePolicy {
Required, // any non-Healthy → session Failed
TolerateDegrade, // Degraded allowed, Unhealthy → Failed
TolerateOutage, // Unhealthy allowed (best-effort slot), session remains Degraded
}
// Default policy per slot:
beads: Required // every agent execution must be receipt-tracked
pods: TolerateDegrade // read can be stale, write failure blocks session
memory: TolerateDegrade // retrieval can be partial, store failure blocks session
events: TolerateOutage // event loss is visible in metrics; does not block execution
orchestrator: Required // can't spawn agents without it — session failsRule:
SessionHealth = Healthyiff all slots meet or exceed their policy's threshold AND none areFailed.SessionHealth = Degradediff at least one slot is Degraded under aTolerateDegradepolicy OR Unhealthy underTolerateOutage, AND no slot is Failed underRequired.SessionHealth = Failediff any slot violates its policy.
FederationSessionHealthDegraded events carry affected_slots so downstream consumers know which capability is impaired. AdapterHealthMonitor re-evaluates the composition every 10 s; transitions trigger event emission (no spamming on steady-state).
| Service | Responsibility |
|---|---|
FederationSessionLifecycleService |
Start/stop sessions; probes LocalFallbackProbe on boot; quarantines degraded sessions |
AgentExecutionCoordinator |
Accepts AgentExecutionRequested commands; resolves session; delegates to orchestrator_acl |
AgentEventStreamProjector |
Consumes agentbox JSONL stream; translates via events_acl; emits VC domain events |
AdapterHealthMonitor |
Periodic health checks against all registered AdapterEndpoints; publishes AdapterEndpointHealthChanged; computes composed SessionHealth per §7a |
MADDeprecationMigrator |
One-shot service: reads MAD state (beads via MAD's BeadsService, briefs from team/ filesystem) and replays into VC's BC aggregates before MAD is stopped |
- No agentbox-side business logic. Anything the Briefing role-table (architect/dev/ciso/...) decides is configuration in
agentbox/config/briefing-roles.toml. Policy about who may trigger which role, rate limits, NIP-26 delegation caps — all live in VC's Policy Engine (ADR-045). - Adapter contract versioning is monotonic. Agentbox publishes adapter contract versions per slot; VC's
AdapterEndpointdeclares the range it supports. Agentbox upgrades that would break older VC endpoints must ship a compat shim; VC upgrades that require newer contracts block on agentbox PR. - Standalone mode is not a VisionClaw concern. When agentbox runs in
federation.mode = "standalone", this context is inert. There is no code path that inspects standalone-mode behaviour.
- Event bus substrate for VC↔agentbox events. Options: NATS, Redis streams, direct HTTP long-poll, WebSocket. Preference leans to NATS because it's already used elsewhere in VC actors, but not yet decided. Tracking in a follow-up ADR once the first implementation lands.
- MAD state replay atomicity. The
MADDeprecationMigratorhas to replay ~months of BeadsService state intoBeadProvenance. If it fails mid-way, is the partial replay kept or rolled back? Current lean: keep, since beads are append-only and idempotent; a retry converges. Verify with BeadProvenance owners before cutover. - Contract test location. Adapter contract tests live in agentbox's repo. VC-side ACL tests live in VC. A shared contract-test fixture repo could reduce duplication but adds release coordination. Defer until the second VC-shaped consumer of agentbox appears.
- Bead / Epic / Child / Claim — see
docs/ddd-bead-provenance-context.md - ContributorStudioSupervisor, GuidanceSession, ShareIntent — see ADR-057 and the BC18 aggregate in
src/domain/contributor/ - SkillPackage, SkillEvalSuite — see BC19 in
src/domain/skills/ - Policy Engine — see ADR-045
- publicTypeIndex / NIP-26 delegation — see ADR-029
- adapter contract — see agentbox ADR-005