Files
ContractorAgent/docs/claude/ARCHITECTURE.md

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:

  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:

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: