12 KiB
Claude Contractor Architecture
Purpose
Describe the phase 1 architecture for integrating Claude Code into OpenClaw as a contractor-backed agent.
This document assumes the phase 1 decisions already made:
- Claude only, Gemini deferred
- plugin-owned CLI root:
openclaw contractor-agents ... - contractor-backed agents use a custom primary model
- that custom model bridges OpenClaw turns into Claude Code sessions
High-level architecture
User / Channel
↓
OpenClaw routing + agent selection
↓
Agent primary model = contractor-claude-bridge
↓
ContractorAgent plugin
├─ contractor metadata resolver
├─ session map store
├─ Claude ACP adapter
├─ input filter / context reducer
└─ response normalizer
↓
Claude Code session
Core architectural principle
OpenClaw remains the outer control plane. Claude Code remains the live reasoning runtime.
That means:
OpenClaw owns
- agent registration
- workspace ownership
- routing and channel bindings
- visible transcript/session files
- permissions and approvals
- plugin loading and bridge model selection
Claude Code owns
- live session continuity
- evolving reasoning context for a contractor task
- internal coding workflow and execution trajectory
The plugin exists to bridge those two worlds without forcing both systems to maintain full independent copies of the same conversation state.
Main components
1. Contractor metadata resolver
This component determines whether the current agent is a contractor-backed Claude agent and, if so, what runtime settings apply.
Expected inputs:
- OpenClaw agent id
- agent config entry
- plugin config defaults
Expected outputs:
- whether contractor runtime is enabled
- contractor kind, currently
claude - bridge model id
- backend type, likely ACP
- runtime mode, likely persistent
- workspace path
Proposed config direction
{
agents: {
list: [
{
id: "contractor-dev",
workspace: "/workspace/contractor-dev",
model: "contractor-claude-bridge",
runtime: {
type: "contractor",
contractor: {
kind: "claude",
backend: "acp",
mode: "persistent"
}
}
}
]
}
}
The exact config location can still evolve, but the architecture assumes there is a stable way to resolve contractor runtime settings from agent identity.
2. Bridge model
The bridge model is the primary execution seam inside OpenClaw.
Suggested model id:
contractor-claude-bridge
Why it exists
OpenClaw expects a primary model for each agent. The bridge model satisfies that contract while redirecting actual reasoning work to Claude Code.
What it does
- receive the agent turn as a model request
- identify the target OpenClaw agent and session
- resolve contractor metadata
- call the session map store
- call the Claude ACP adapter
- normalize Claude output into an OpenClaw model response
What it does not do
- behave like a normal stateless LLM provider
- replay the full OpenClaw prompt envelope every turn
- replace OpenClaw routing or channel delivery
3. Session map store
This component persists the mapping between OpenClaw sessions and Claude sessions.
Suggested location:
<agent-workspace>/.openclaw/contractor-agent/session-map.json
Suggested record shape:
type SessionMapEntry = {
openclawSessionKey: string
agentId: string
contractor: "claude"
claudeSessionId: string
workspace: string
createdAt: string
lastActivityAt: string
state: "active" | "closed" | "orphaned"
}
Responsibilities
- lookup mapping by OpenClaw session key
- create mapping after first successful Claude session creation
- update timestamps and state
- mark sessions orphaned on recoverable failures
- remove or replace mappings during reset flows
Non-responsibilities
- storing full conversation text
- storing OpenClaw config
- being the canonical transcript source
4. Input filter and context reducer
This is one of the most important parts of the architecture.
The bridge model should not forward full OpenClaw-managed input blindly to Claude Code. Instead it should convert the incoming turn into a contractor payload.
Contractor payload should include
- latest user message
- OpenClaw session key
- agent id
- workspace path
- minimal runtime hints needed by Claude
Contractor payload should exclude or heavily reduce
- repeated OpenClaw prompt wrappers
- large historical message dumps already represented in Claude session state
- redundant policy text already injected at Claude session creation
Why this matters
Without this reducer, the system drifts into dual-context management:
- OpenClaw reconstructs context every turn
- Claude maintains its own session context
- both copies diverge over time
The reducer prevents that by making Claude the primary owner of live context after bootstrap.
5. Claude ACP adapter
This component talks to Claude Code through the chosen ACP/runtime path.
Architecture assumption for phase 1:
- Claude Code is hosted through OpenClaw-compatible ACP infrastructure
- the plugin uses persistent Claude sessions whenever possible
Responsibilities
- create new Claude sessions
- resume existing Claude sessions
- send new user messages to Claude
- collect Claude output
- surface recoverable failures to the bridge model
Expected operations
createSession(...)resumeSession(...)sendMessage(...)closeSession(...)healthCheck(...)
Exact API shape depends on implementation details and available runtime hooks.
6. Response normalizer
Claude output may not match the exact shape OpenClaw expects from a model provider. The normalizer converts it into the response format used by the bridge model.
Responsibilities
- convert plain assistant text
- preserve useful structured output if present
- flatten multi-part response payloads where needed
- translate adapter/runtime failures into OpenClaw-visible model errors
Desired outcome
From OpenClaw's point of view, the result should feel like a normal model completion even though it came from a stateful Claude session.
Turn lifecycle
A. Agent provisioning lifecycle
Triggered by:
openclaw contractor-agents add --agent-id <agent-id> --workspace <workspace> --contractor claude
Flow:
- create OpenClaw agent with model
contractor-claude-bridge - write contractor runtime metadata to agent config
- create contractor state directory
- initialize empty session map store
No Claude session is required at provisioning time.
B. First conversation turn
- OpenClaw routes message to contractor-backed agent
- OpenClaw invokes primary model
contractor-claude-bridge - bridge model resolves agent metadata
- bridge model checks session map for current OpenClaw session
- no mapping found
- bridge model asks Claude ACP adapter to create a new Claude session
- plugin injects bootstrap instructions and minimal OpenClaw metadata
- plugin sends latest user message
- Claude replies
- plugin stores mapping and returns normalized output to OpenClaw
C. Later conversation turns
- OpenClaw invokes
contractor-claude-bridge - metadata resolver confirms contractor-backed Claude agent
- session map returns mapped Claude session id
- input reducer extracts newest actionable message
- Claude ACP adapter resumes session and sends message
- Claude replies
- response normalizer emits OpenClaw model response
- session map timestamp is updated
D. Reset flow
If the user resets the session:
- plugin invalidates or replaces mapping for the OpenClaw session key
- next turn creates a fresh Claude session
- bootstrap instructions are injected again
Recommended behavior:
- keep OpenClaw agent and workspace stable
- replace only contractor session continuity
E. Recovery flow
If Claude session is missing or unusable:
- mark mapping as
orphaned - create a new Claude session
- inject bootstrap instructions
- optionally pass a minimal recovery summary derived from recent OpenClaw-visible context
- replace mapping
This should be treated as a degraded fallback path, not the normal operating path.
Bootstrap strategy
Bootstrap text should be injected when a Claude session is first created.
It should include:
- contractor role inside OpenClaw
- workspace root
- expectations for message style back to OpenClaw
- constraints around approvals and tools
- guidance on using session continuity instead of expecting full replay every turn
It should not be re-injected every turn.
Storage design
Static config
Static agent configuration belongs in OpenClaw config and is managed by the contractor CLI.
Examples:
- agent id
- workspace
- bridge model id
- contractor kind
- contractor runtime defaults
Dynamic state
Dynamic session mapping belongs in plugin runtime state under the agent workspace.
Examples:
- OpenClaw session key to Claude session id mapping
- session state flags
- timestamps
This separation keeps declarative config and runtime state from bleeding into each other.
Why not mirror full Claude state into OpenClaw session files
Because doing so would:
- create duplicated context systems
- encourage replay-based turn handling
- increase token cost and failure complexity
- still fail to capture Claude's real internal runtime state perfectly
Instead:
- OpenClaw transcript remains the visible conversation record
- Claude session remains the live cognitive state for the contractor runtime
Approval and tool interaction
Phase 1 should keep this conservative.
Recommended initial stance:
- start with limited or no complex tool bridging beyond what is required for basic operation
- preserve OpenClaw as the place where approvals and policy are enforced
- design later tool bridging so Claude requests are translated into OpenClaw-hosted tool execution rather than bypassing OpenClaw directly
Key risks
Risk 1, poor boundary between model and runtime
If the bridge model tries to imitate a normal provider too literally, implementation gets awkward. It must be treated as a stateful pseudo-model.
Risk 2, session mapping drift
If mappings are lost or stale, the user may silently lose Claude-side continuity. Recovery behavior must be explicit.
Risk 3, over-forwarding context
If too much OpenClaw-managed prompt content is forwarded each turn, the design collapses back into dual-context management.
Risk 4, under-specified reset semantics
Reset, new, and recovery must be clearly defined or the plugin will become unpredictable.
Phase 1 implementation priorities
- Register bridge model id
- Implement contractor metadata resolver
- Implement contractor CLI add flow
- Implement session map store
- Implement create/resume/send behavior in Claude ACP adapter
- Implement response normalization
- Add reset and recovery semantics
References
OpenClaw Claude via ACP
"ACP sessions let OpenClaw run external coding harnesses (for example ... Claude Code ...) through an ACP backend plugin."
"For Claude Code through ACP, the stack is:
- OpenClaw ACP session control plane
- bundled
acpxruntime plugin- Claude ACP adapter
- Claude-side runtime/session machinery"
Source:
OpenClaw plugin extensibility
"Plugins extend OpenClaw with new capabilities: channels, model providers, ... agent tools, or any combination."
Source:
Plugin entry contract
"For provider plugins, tool plugins, hook plugins, and anything that is not a messaging channel."
Source:
Plugin CLI surface
"For plugin-owned root CLI commands, prefer
api.registerCli(..., { descriptors: [...] })..."
Source: