Files
ContractorAgent/docs/claude/ARCHITECTURE.md

437 lines
12 KiB
Markdown

# 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
```text
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
```json5
{
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:
```text
<agent-workspace>/.openclaw/contractor-agent/session-map.json
```
Suggested record shape:
```ts
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:
```bash
openclaw contractor-agents add --agent-id <agent-id> --workspace <workspace> --contractor claude
```
Flow:
1. create OpenClaw agent with model `contractor-claude-bridge`
2. write contractor runtime metadata to agent config
3. create contractor state directory
4. initialize empty session map store
No Claude session is required at provisioning time.
## B. First conversation turn
1. OpenClaw routes message to contractor-backed agent
2. OpenClaw invokes primary model `contractor-claude-bridge`
3. bridge model resolves agent metadata
4. bridge model checks session map for current OpenClaw session
5. no mapping found
6. bridge model asks Claude ACP adapter to create a new Claude session
7. plugin injects bootstrap instructions and minimal OpenClaw metadata
8. plugin sends latest user message
9. Claude replies
10. plugin stores mapping and returns normalized output to OpenClaw
## C. Later conversation turns
1. OpenClaw invokes `contractor-claude-bridge`
2. metadata resolver confirms contractor-backed Claude agent
3. session map returns mapped Claude session id
4. input reducer extracts newest actionable message
5. Claude ACP adapter resumes session and sends message
6. Claude replies
7. response normalizer emits OpenClaw model response
8. session map timestamp is updated
## D. Reset flow
If the user resets the session:
1. plugin invalidates or replaces mapping for the OpenClaw session key
2. next turn creates a fresh Claude session
3. 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:
1. mark mapping as `orphaned`
2. create a new Claude session
3. inject bootstrap instructions
4. optionally pass a minimal recovery summary derived from recent OpenClaw-visible context
5. 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
1. Register bridge model id
2. Implement contractor metadata resolver
3. Implement contractor CLI add flow
4. Implement session map store
5. Implement create/resume/send behavior in Claude ACP adapter
6. Implement response normalization
7. 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:
> 1. OpenClaw ACP session control plane
> 2. bundled `acpx` runtime plugin
> 3. Claude ACP adapter
> 4. Claude-side runtime/session machinery"
Source:
- https://docs.openclaw.ai/tools/acp-agents
### OpenClaw plugin extensibility
> "Plugins extend OpenClaw with new capabilities: channels, model providers, ... agent tools, or any combination."
Source:
- https://docs.openclaw.ai/plugins/building-plugins
### Plugin entry contract
> "For provider plugins, tool plugins, hook plugins, and anything that is not a messaging channel."
Source:
- https://docs.openclaw.ai/plugins/sdk-entrypoints
### Plugin CLI surface
> "For plugin-owned root CLI commands, prefer `api.registerCli(..., { descriptors: [...] })` ..."
Source:
- https://docs.openclaw.ai/plugins/sdk-entrypoints