docs: expand Claude contractor design
This commit is contained in:
436
docs/claude/ARCHITECTURE.md
Normal file
436
docs/claude/ARCHITECTURE.md
Normal file
@@ -0,0 +1,436 @@
|
||||
# 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
|
||||
307
docs/claude/CLI.md
Normal file
307
docs/claude/CLI.md
Normal file
@@ -0,0 +1,307 @@
|
||||
# Contractor Agents CLI Design
|
||||
|
||||
## Purpose
|
||||
|
||||
Define the plugin-owned CLI surface for managing contractor-backed OpenClaw agents.
|
||||
|
||||
Phase 1 supports Claude only. Gemini remains reserved in the command shape but is not implemented yet.
|
||||
|
||||
## Command root
|
||||
|
||||
```bash
|
||||
openclaw contractor-agents
|
||||
```
|
||||
|
||||
This should be implemented as a plugin-owned CLI root, not as a patch to `openclaw agents add`.
|
||||
|
||||
## Why a separate command root
|
||||
|
||||
Current OpenClaw plugin docs show support for plugin CLI registration, but do not document support for extending existing core commands with new flags.
|
||||
|
||||
Relevant doc statements:
|
||||
|
||||
> "Common registration methods: ... `registerCommand` / `registerCli` | CLI commands"
|
||||
|
||||
> "For plugin-owned root CLI commands, prefer `api.registerCli(..., { descriptors: [...] })` ..."
|
||||
|
||||
This suggests the supported extension seam is plugin-owned CLI trees.
|
||||
|
||||
Sources:
|
||||
- https://docs.openclaw.ai/tools/plugin
|
||||
- https://docs.openclaw.ai/plugins/sdk-entrypoints
|
||||
|
||||
## Phase 1 command
|
||||
|
||||
```bash
|
||||
openclaw contractor-agents add --agent-id <agent-id> --workspace <workspace> --contractor <claude|gemini>
|
||||
```
|
||||
|
||||
Phase 1 restrictions:
|
||||
|
||||
- `--contractor` must currently be `claude`
|
||||
- `gemini` is accepted only as a reserved future value if desired, but should currently fail with a clear not-yet-implemented message unless you intentionally decide to reject it at parsing time
|
||||
|
||||
## Arguments
|
||||
|
||||
### Required
|
||||
|
||||
- `--agent-id <agent-id>`
|
||||
- `--workspace <workspace>`
|
||||
- `--contractor <claude|gemini>`
|
||||
|
||||
### Optional, possible later
|
||||
|
||||
Not required for first implementation, but likely useful later:
|
||||
|
||||
- `--bridge-model <model-id>`
|
||||
- `--backend <acp-backend>`
|
||||
- `--mode <persistent|oneshot>`
|
||||
- `--json`
|
||||
- `--non-interactive`
|
||||
|
||||
For now, phase 1 can hardcode the bridge model and runtime defaults.
|
||||
|
||||
## Behavior of `add`
|
||||
|
||||
For:
|
||||
|
||||
```bash
|
||||
openclaw contractor-agents add --agent-id my-agent --workspace /path/to/ws --contractor claude
|
||||
```
|
||||
|
||||
The CLI should do the following.
|
||||
|
||||
### Step 1, validate inputs
|
||||
|
||||
- ensure `agent-id` is provided
|
||||
- ensure workspace exists or is creatable, based on your desired policy
|
||||
- ensure contractor kind is supported
|
||||
- ensure target agent does not already exist unless overwrite behavior is explicitly added later
|
||||
|
||||
### Step 2, create the base OpenClaw agent
|
||||
|
||||
Run the equivalent of:
|
||||
|
||||
```bash
|
||||
openclaw agents add <agent-id> --workspace <workspace> --model contractor-claude-bridge --non-interactive
|
||||
```
|
||||
|
||||
Important note:
|
||||
|
||||
Earlier review of `openclaw agents add` docs showed these supported options:
|
||||
|
||||
> `--workspace <dir>`
|
||||
> `--model <id>`
|
||||
> `--agent-dir <dir>`
|
||||
> `--bind <channel[:accountId]>`
|
||||
> `--non-interactive`
|
||||
> `--json`
|
||||
|
||||
Source:
|
||||
- https://docs.openclaw.ai/cli/agents
|
||||
|
||||
This means the contractor CLI can compose the existing agent creation flow rather than replacing it.
|
||||
|
||||
### Step 3, mark the agent as a contractor-backed agent
|
||||
|
||||
After agent creation, write contractor metadata so runtime selection and session bridging can identify this agent as contractor-managed.
|
||||
|
||||
Proposed config direction:
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
list: [
|
||||
{
|
||||
id: "my-agent",
|
||||
model: "contractor-claude-bridge",
|
||||
runtime: {
|
||||
type: "contractor",
|
||||
contractor: {
|
||||
kind: "claude",
|
||||
backend: "acp",
|
||||
mode: "persistent"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Exact schema is still TBD, but the CLI should be the mechanism that writes this state.
|
||||
|
||||
### Step 4, initialize contractor runtime state
|
||||
|
||||
Prepare runtime state for the agent, including a place to store session mappings.
|
||||
|
||||
Suggested path:
|
||||
|
||||
```text
|
||||
<workspace>/.openclaw/contractor-agent/
|
||||
```
|
||||
|
||||
Suggested initial files:
|
||||
|
||||
```text
|
||||
session-map.json
|
||||
runtime.json
|
||||
```
|
||||
|
||||
## Session mapping responsibility
|
||||
|
||||
The CLI does not create Claude sessions immediately unless you explicitly want eager setup.
|
||||
|
||||
Recommended phase 1 behavior:
|
||||
|
||||
- create agent metadata
|
||||
- create runtime state directory
|
||||
- initialize empty mapping file
|
||||
- defer real Claude session creation to first actual agent turn
|
||||
|
||||
This keeps `add` lightweight and avoids unused contractor sessions.
|
||||
|
||||
## Suggested future commands
|
||||
|
||||
These are not required immediately, but the command tree should reserve room for them.
|
||||
|
||||
### Status
|
||||
|
||||
```bash
|
||||
openclaw contractor-agents status --agent-id <agent-id>
|
||||
```
|
||||
|
||||
Show:
|
||||
- contractor kind
|
||||
- bridge model id
|
||||
- runtime backend
|
||||
- session mapping count
|
||||
- recent activity
|
||||
|
||||
### List sessions
|
||||
|
||||
```bash
|
||||
openclaw contractor-agents sessions --agent-id <agent-id>
|
||||
```
|
||||
|
||||
Show session mappings for the given contractor-backed agent.
|
||||
|
||||
### Reset mapping
|
||||
|
||||
```bash
|
||||
openclaw contractor-agents reset-session --agent-id <agent-id> --openclaw-session <session-key>
|
||||
```
|
||||
|
||||
Drop a specific OpenClaw-to-Claude mapping so the next message recreates the Claude session.
|
||||
|
||||
### Disable
|
||||
|
||||
```bash
|
||||
openclaw contractor-agents disable --agent-id <agent-id>
|
||||
```
|
||||
|
||||
Either:
|
||||
- remove contractor metadata but keep agent
|
||||
- or mark the contractor runtime disabled
|
||||
|
||||
Semantics TBD.
|
||||
|
||||
## JSON output
|
||||
|
||||
I recommend all subcommands eventually support `--json` so this can be scripted.
|
||||
|
||||
Example success response shape:
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"agentId": "my-agent",
|
||||
"workspace": "/path/to/ws",
|
||||
"contractor": "claude",
|
||||
"model": "contractor-claude-bridge",
|
||||
"runtimeStateDir": "/path/to/ws/.openclaw/contractor-agent"
|
||||
}
|
||||
```
|
||||
|
||||
## Failure cases
|
||||
|
||||
The CLI should fail clearly for:
|
||||
|
||||
- unsupported contractor kind
|
||||
- agent already exists
|
||||
- workspace invalid or inaccessible
|
||||
- bridge model plugin not available
|
||||
- failure in underlying `openclaw agents add`
|
||||
- failure writing contractor metadata
|
||||
|
||||
If the agent is created successfully but metadata writing fails, the CLI should either:
|
||||
|
||||
- roll back the created agent if safe and simple
|
||||
- or return a partial-failure error with explicit cleanup instructions
|
||||
|
||||
Phase 1 recommendation: prefer explicit rollback if implementation is reliable.
|
||||
|
||||
## Interaction with the bridge model
|
||||
|
||||
The CLI should not directly run Claude Code or create a Claude contractor session by default.
|
||||
|
||||
Its main job is to provision an agent whose primary model is the contractor bridge model:
|
||||
|
||||
- `contractor-claude-bridge`
|
||||
|
||||
That model then handles runtime dispatch during actual conversation turns.
|
||||
|
||||
## Implementation notes
|
||||
|
||||
The plugin should register a root command owned by the plugin.
|
||||
|
||||
Relevant doc statements:
|
||||
|
||||
> "For plugin-owned root CLI commands, prefer `api.registerCli(..., { descriptors: [...] })` when you want the command to stay lazy-loaded without disappearing from the root CLI parse tree."
|
||||
|
||||
Source:
|
||||
- https://docs.openclaw.ai/plugins/sdk-entrypoints
|
||||
|
||||
So the intended shape is:
|
||||
|
||||
- plugin registers `contractor-agents`
|
||||
- plugin owns parsing and handling of its subcommands
|
||||
- plugin composes `openclaw agents add` behavior internally or via shared config/runtime helpers
|
||||
|
||||
## Open questions
|
||||
|
||||
1. Should the CLI shell out to `openclaw agents add` or use a lower-level config/runtime helper directly?
|
||||
2. Where should contractor metadata live, `agents.list[].runtime`, plugin config, or both?
|
||||
3. Should `gemini` be rejected now or accepted with a not implemented error?
|
||||
4. Should add create the workspace if it does not exist?
|
||||
5. Should agent creation be rolled back if contractor metadata writing fails?
|
||||
|
||||
## References
|
||||
|
||||
### Plugin CLI support
|
||||
|
||||
> "Common registration methods: ... `registerCommand` / `registerCli` | CLI commands"
|
||||
|
||||
Source:
|
||||
- https://docs.openclaw.ai/tools/plugin
|
||||
|
||||
### Plugin-owned CLI descriptors
|
||||
|
||||
> "For plugin-owned root CLI commands, prefer `api.registerCli(..., { descriptors: [...] })` ..."
|
||||
|
||||
Source:
|
||||
- https://docs.openclaw.ai/plugins/sdk-entrypoints
|
||||
|
||||
### Existing agent creation command
|
||||
|
||||
> `agents add [name]`
|
||||
|
||||
> `--workspace <dir>`
|
||||
> `--model <id>`
|
||||
> `--agent-dir <dir>`
|
||||
> `--bind <channel[:accountId]>`
|
||||
> `--non-interactive`
|
||||
> `--json`
|
||||
|
||||
Source:
|
||||
- https://docs.openclaw.ai/cli/agents
|
||||
530
docs/claude/IMPLEMENTATION.md
Normal file
530
docs/claude/IMPLEMENTATION.md
Normal file
@@ -0,0 +1,530 @@
|
||||
# Claude Contractor Implementation Plan
|
||||
|
||||
## Purpose
|
||||
|
||||
Turn the architecture decisions into an implementation-oriented plan for phase 1.
|
||||
|
||||
This document is intentionally practical. It focuses on file structure, core modules, interfaces, and build order for the Claude-only phase.
|
||||
|
||||
## Phase 1 implementation goal
|
||||
|
||||
Deliver a working Claude-backed contractor agent in OpenClaw that can:
|
||||
|
||||
1. be provisioned through `openclaw contractor-agents add`
|
||||
2. use `contractor-claude-bridge` as its primary model
|
||||
3. map an OpenClaw session to a Claude Code session
|
||||
4. forward the latest user message into Claude Code
|
||||
5. return Claude output through normal OpenClaw response flow
|
||||
|
||||
Gemini is out of scope for this phase.
|
||||
|
||||
## Proposed repository structure
|
||||
|
||||
```text
|
||||
ContractorAgent/
|
||||
├── docs/
|
||||
│ ├── claude/
|
||||
│ │ ├── PLAN.md
|
||||
│ │ ├── MODEL.md
|
||||
│ │ ├── CLI.md
|
||||
│ │ ├── ARCHITECTURE.md
|
||||
│ │ └── IMPLEMENTATION.md
|
||||
│ └── gemini/
|
||||
│ └── .gitkeep
|
||||
├── src/
|
||||
│ ├── index.ts
|
||||
│ ├── config/
|
||||
│ │ ├── schema.ts
|
||||
│ │ └── contractor-config.ts
|
||||
│ ├── cli/
|
||||
│ │ ├── register-cli.ts
|
||||
│ │ ├── contractor-agents-add.ts
|
||||
│ │ └── contractor-agents-status.ts
|
||||
│ ├── model/
|
||||
│ │ ├── register-bridge-model.ts
|
||||
│ │ ├── contractor-claude-bridge.ts
|
||||
│ │ ├── input-filter.ts
|
||||
│ │ └── response-normalizer.ts
|
||||
│ ├── contractor/
|
||||
│ │ ├── metadata-resolver.ts
|
||||
│ │ ├── runtime-state.ts
|
||||
│ │ ├── session-map-store.ts
|
||||
│ │ ├── bootstrap.ts
|
||||
│ │ └── recovery.ts
|
||||
│ ├── claude/
|
||||
│ │ ├── acp-adapter.ts
|
||||
│ │ ├── claude-session.ts
|
||||
│ │ └── claude-types.ts
|
||||
│ ├── openclaw/
|
||||
│ │ ├── agent-config-writer.ts
|
||||
│ │ ├── agents-add-runner.ts
|
||||
│ │ └── session-context.ts
|
||||
│ └── types/
|
||||
│ ├── contractor.ts
|
||||
│ ├── session-map.ts
|
||||
│ └── model.ts
|
||||
├── package.json
|
||||
├── openclaw.plugin.json
|
||||
└── tsconfig.json
|
||||
```
|
||||
|
||||
Not every file needs to exist on day 1, but this is a good target shape.
|
||||
|
||||
## Module responsibilities
|
||||
|
||||
## 1. `src/index.ts`
|
||||
|
||||
Plugin entry point.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- export the OpenClaw plugin entry
|
||||
- register the bridge model
|
||||
- register plugin-owned CLI commands
|
||||
- register any supporting services needed by the plugin
|
||||
|
||||
Expected shape:
|
||||
|
||||
```ts
|
||||
export default definePluginEntry({
|
||||
id: "contractor-agent",
|
||||
name: "Contractor Agent",
|
||||
description: "Claude-backed contractor agents for OpenClaw",
|
||||
register(api) {
|
||||
// register bridge model
|
||||
// register CLI
|
||||
// register helpers/services if needed
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
## 2. `src/model/register-bridge-model.ts`
|
||||
|
||||
Registers the custom model id used by contractor-backed agents.
|
||||
|
||||
Primary concern:
|
||||
|
||||
- expose `contractor-claude-bridge` to OpenClaw as a valid model selection target
|
||||
|
||||
This is the key seam that makes contractor-backed agents look normal to OpenClaw.
|
||||
|
||||
## 3. `src/model/contractor-claude-bridge.ts`
|
||||
|
||||
Core bridge model implementation.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- receive the model request from OpenClaw
|
||||
- identify agent id and session key
|
||||
- resolve contractor metadata
|
||||
- resolve or create Claude session mapping
|
||||
- filter input
|
||||
- call Claude adapter
|
||||
- normalize result
|
||||
- return OpenClaw-compatible model output
|
||||
|
||||
This file is the heart of the system.
|
||||
|
||||
## 4. `src/model/input-filter.ts`
|
||||
|
||||
Convert raw OpenClaw model input into the payload actually sent to Claude.
|
||||
|
||||
Possible exports:
|
||||
|
||||
```ts
|
||||
export function extractLatestActionableMessage(...)
|
||||
export function buildClaudeTurnPayload(...)
|
||||
```
|
||||
|
||||
This module should be pure and testable.
|
||||
|
||||
## 5. `src/model/response-normalizer.ts`
|
||||
|
||||
Convert Claude-side output into OpenClaw-compatible model response data.
|
||||
|
||||
Possible exports:
|
||||
|
||||
```ts
|
||||
export function normalizeClaudeResponse(...)
|
||||
export function normalizeClaudeError(...)
|
||||
```
|
||||
|
||||
This should also be mostly pure and testable.
|
||||
|
||||
## 6. `src/contractor/metadata-resolver.ts`
|
||||
|
||||
Read agent config and decide whether the current agent is a contractor-backed Claude agent.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- inspect agent config
|
||||
- return structured contractor runtime metadata
|
||||
- reject unsupported or misconfigured contractor setups
|
||||
|
||||
Possible export:
|
||||
|
||||
```ts
|
||||
export function resolveContractorAgentMetadata(...): ContractorAgentMetadata
|
||||
```
|
||||
|
||||
## 7. `src/contractor/session-map-store.ts`
|
||||
|
||||
Read and write the OpenClaw session to Claude session mapping file.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- find by OpenClaw session key
|
||||
- insert new mapping
|
||||
- update timestamps
|
||||
- replace mapping on reset/recovery
|
||||
- mark mapping orphaned
|
||||
|
||||
Possible interface:
|
||||
|
||||
```ts
|
||||
export interface SessionMapStore {
|
||||
get(openclawSessionKey: string): Promise<SessionMapEntry | null>
|
||||
put(entry: SessionMapEntry): Promise<void>
|
||||
markOrphaned(openclawSessionKey: string): Promise<void>
|
||||
remove(openclawSessionKey: string): Promise<void>
|
||||
list(agentId: string): Promise<SessionMapEntry[]>
|
||||
}
|
||||
```
|
||||
|
||||
## 8. `src/contractor/runtime-state.ts`
|
||||
|
||||
Resolve and initialize plugin runtime state directories.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- compute state directory from workspace
|
||||
- ensure directories exist
|
||||
- provide path helpers for session-map and related files
|
||||
|
||||
Possible exports:
|
||||
|
||||
```ts
|
||||
export function getContractorStateDir(workspace: string): string
|
||||
export function getSessionMapPath(workspace: string): string
|
||||
export async function ensureContractorStateDir(workspace: string): Promise<void>
|
||||
```
|
||||
|
||||
## 9. `src/contractor/bootstrap.ts`
|
||||
|
||||
Create the initial contractor bootstrap payload for new Claude sessions.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- generate initial instruction text
|
||||
- include workspace metadata
|
||||
- include contractor role expectations
|
||||
- avoid repeating per-turn content
|
||||
|
||||
Possible export:
|
||||
|
||||
```ts
|
||||
export function buildClaudeBootstrap(...): string
|
||||
```
|
||||
|
||||
## 10. `src/contractor/recovery.ts`
|
||||
|
||||
Handle missing or invalid Claude sessions.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- mark mappings orphaned
|
||||
- trigger fresh Claude session creation
|
||||
- optionally build a minimal recovery summary
|
||||
|
||||
Possible export:
|
||||
|
||||
```ts
|
||||
export async function recoverClaudeSession(...)
|
||||
```
|
||||
|
||||
## 11. `src/claude/acp-adapter.ts`
|
||||
|
||||
Claude runtime adapter used by the bridge model.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- create Claude session
|
||||
- resume Claude session
|
||||
- send message to Claude
|
||||
- close Claude session if needed
|
||||
|
||||
Possible interface:
|
||||
|
||||
```ts
|
||||
export interface ClaudeAcpAdapter {
|
||||
createSession(input: CreateClaudeSessionInput): Promise<CreateClaudeSessionResult>
|
||||
sendMessage(input: SendClaudeMessageInput): Promise<SendClaudeMessageResult>
|
||||
closeSession?(sessionId: string): Promise<void>
|
||||
}
|
||||
```
|
||||
|
||||
This should hide ACP/runtime-specific details from the bridge model.
|
||||
|
||||
## 12. `src/openclaw/agents-add-runner.ts`
|
||||
|
||||
Encapsulate the logic for creating base OpenClaw agents from the contractor CLI.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- run or emulate `openclaw agents add <agent-id> --workspace <workspace> --model contractor-claude-bridge --non-interactive`
|
||||
- translate failures into contractor CLI errors
|
||||
|
||||
Possible export:
|
||||
|
||||
```ts
|
||||
export async function createBaseAgent(...): Promise<void>
|
||||
```
|
||||
|
||||
## 13. `src/openclaw/agent-config-writer.ts`
|
||||
|
||||
Write contractor metadata into OpenClaw config after the base agent is created.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- update target agent config entry
|
||||
- write contractor runtime stanza
|
||||
- preserve unrelated config
|
||||
|
||||
Possible export:
|
||||
|
||||
```ts
|
||||
export async function markAgentAsClaudeContractor(...): Promise<void>
|
||||
```
|
||||
|
||||
## 14. `src/cli/register-cli.ts`
|
||||
|
||||
Register the plugin-owned CLI root.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- register `openclaw contractor-agents`
|
||||
- attach subcommands such as `add`, later `status`, `sessions`, `reset-session`
|
||||
|
||||
## 15. `src/cli/contractor-agents-add.ts`
|
||||
|
||||
Implementation of the phase 1 provisioning flow.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- parse args
|
||||
- validate contractor kind
|
||||
- create base agent
|
||||
- write contractor metadata
|
||||
- initialize runtime state directory
|
||||
- initialize empty session map
|
||||
- return human-readable or JSON result
|
||||
|
||||
## Primary types
|
||||
|
||||
## `src/types/contractor.ts`
|
||||
|
||||
```ts
|
||||
export type ContractorKind = "claude" | "gemini"
|
||||
|
||||
export type ContractorAgentMetadata = {
|
||||
agentId: string
|
||||
contractor: "claude"
|
||||
bridgeModel: string
|
||||
workspace: string
|
||||
backend: "acp"
|
||||
mode: "persistent" | "oneshot"
|
||||
}
|
||||
```
|
||||
|
||||
## `src/types/session-map.ts`
|
||||
|
||||
```ts
|
||||
export type SessionMapState = "active" | "closed" | "orphaned"
|
||||
|
||||
export type SessionMapEntry = {
|
||||
openclawSessionKey: string
|
||||
agentId: string
|
||||
contractor: "claude"
|
||||
claudeSessionId: string
|
||||
workspace: string
|
||||
createdAt: string
|
||||
lastActivityAt: string
|
||||
state: SessionMapState
|
||||
}
|
||||
|
||||
export type SessionMapFile = {
|
||||
version: 1
|
||||
sessions: SessionMapEntry[]
|
||||
}
|
||||
```
|
||||
|
||||
## `src/types/model.ts`
|
||||
|
||||
```ts
|
||||
export type ContractorBridgeModelRequest = {
|
||||
agentId: string
|
||||
openclawSessionKey: string
|
||||
workspace: string
|
||||
latestUserMessage: string
|
||||
rawInput: unknown
|
||||
}
|
||||
```
|
||||
|
||||
Exact fields depend on how OpenClaw provider/model requests are exposed in runtime.
|
||||
|
||||
## Suggested implementation order
|
||||
|
||||
## Milestone 1, project skeleton
|
||||
|
||||
Create:
|
||||
|
||||
- package metadata
|
||||
- plugin manifest
|
||||
- `src/index.ts`
|
||||
- empty docs-backed source tree
|
||||
|
||||
Success condition:
|
||||
- plugin package structure exists
|
||||
- build can run
|
||||
|
||||
## Milestone 2, CLI provisioning path
|
||||
|
||||
Implement:
|
||||
|
||||
- `register-cli.ts`
|
||||
- `contractor-agents-add.ts`
|
||||
- `agents-add-runner.ts`
|
||||
- `agent-config-writer.ts`
|
||||
- `runtime-state.ts`
|
||||
- empty `session-map-store.ts`
|
||||
|
||||
Success condition:
|
||||
- `openclaw contractor-agents add ... --contractor claude` provisions a contractor-marked agent successfully
|
||||
|
||||
## Milestone 3, bridge model registration
|
||||
|
||||
Implement:
|
||||
|
||||
- `register-bridge-model.ts`
|
||||
- minimal `contractor-claude-bridge.ts`
|
||||
|
||||
Success condition:
|
||||
- OpenClaw recognizes `contractor-claude-bridge` as a valid model id
|
||||
|
||||
## Milestone 4, session mapping and Claude dispatch
|
||||
|
||||
Implement:
|
||||
|
||||
- session-map CRUD
|
||||
- metadata resolver
|
||||
- initial ACP adapter
|
||||
- input filter
|
||||
- response normalizer
|
||||
|
||||
Success condition:
|
||||
- a contractor-backed agent can receive a real turn and return a Claude-generated response
|
||||
|
||||
## Milestone 5, bootstrap and recovery
|
||||
|
||||
Implement:
|
||||
|
||||
- `bootstrap.ts`
|
||||
- `recovery.ts`
|
||||
- reset semantics
|
||||
|
||||
Success condition:
|
||||
- first-turn session creation and broken-session recovery are both handled predictably
|
||||
|
||||
## Testing strategy
|
||||
|
||||
## Unit-test first
|
||||
|
||||
Best candidates for unit tests:
|
||||
|
||||
- metadata resolver
|
||||
- input filter
|
||||
- response normalizer
|
||||
- session-map-store read/write/update behavior
|
||||
- bootstrap payload builder
|
||||
|
||||
## Integration-test later
|
||||
|
||||
Integration targets:
|
||||
|
||||
- contractor CLI add flow
|
||||
- bridge model request path
|
||||
- session creation and reuse
|
||||
- reset and orphan recovery
|
||||
|
||||
## Failure handling rules
|
||||
|
||||
The implementation should clearly separate:
|
||||
|
||||
### Provisioning failures
|
||||
|
||||
Examples:
|
||||
- invalid workspace
|
||||
- base agent creation failed
|
||||
- contractor metadata write failed
|
||||
|
||||
Recommended behavior:
|
||||
- fail loudly
|
||||
- roll back base agent creation if practical and safe
|
||||
|
||||
### Runtime failures
|
||||
|
||||
Examples:
|
||||
- Claude session missing
|
||||
- ACP adapter unavailable
|
||||
- response normalization failed
|
||||
|
||||
Recommended behavior:
|
||||
- mark runtime mapping state explicitly
|
||||
- recover when safe
|
||||
- surface user-visible error when recovery is not possible
|
||||
|
||||
## Minimum viable internal contracts
|
||||
|
||||
To prevent overdesign, phase 1 only needs a few stable internal boundaries:
|
||||
|
||||
1. bridge model -> metadata resolver
|
||||
2. bridge model -> session map store
|
||||
3. bridge model -> Claude ACP adapter
|
||||
4. contractor CLI -> base agent creator
|
||||
5. contractor CLI -> agent config writer
|
||||
|
||||
If these boundaries are clean, later Gemini support can reuse most of the same architecture.
|
||||
|
||||
## Design choices to keep intentionally simple in phase 1
|
||||
|
||||
- single contractor kind implemented, Claude
|
||||
- JSON file-backed session map
|
||||
- no aggressive streaming support initially
|
||||
- no large-scale tool bridge yet
|
||||
- no complicated migration logic yet
|
||||
|
||||
## Things to avoid early
|
||||
|
||||
- overabstracting for Gemini before Claude works
|
||||
- mixing static config with dynamic session map state
|
||||
- rebuilding full OpenClaw context every turn
|
||||
- making the bridge model pretend to be a normal stateless LLM provider
|
||||
|
||||
## Open questions to resolve during implementation
|
||||
|
||||
1. What exact OpenClaw plugin/provider registration API should the bridge model use?
|
||||
2. How should the plugin call underlying agent creation, shelling out to CLI vs internal config mutation?
|
||||
3. What exact payload does OpenClaw pass to a custom model implementation?
|
||||
4. What exact continuation identifier should be stored for Claude sessions?
|
||||
5. How should Claude tool requests later be bridged into OpenClaw-hosted tool execution?
|
||||
|
||||
## Immediate next coding step
|
||||
|
||||
If starting implementation now, I would begin with:
|
||||
|
||||
1. plugin manifest and `src/index.ts`
|
||||
2. CLI registration for `contractor-agents add`
|
||||
3. base agent creation + contractor metadata write
|
||||
4. empty state dir and empty session map initialization
|
||||
|
||||
That gets provisioning working before the runtime bridge itself is added.
|
||||
238
docs/claude/MODEL.md
Normal file
238
docs/claude/MODEL.md
Normal file
@@ -0,0 +1,238 @@
|
||||
# Claude Bridge Model Design
|
||||
|
||||
## Purpose
|
||||
|
||||
Define how Claude-backed contractor agents integrate into OpenClaw using a custom model seam.
|
||||
|
||||
This document is specific to the Claude phase of ContractorAgent.
|
||||
|
||||
## Why this must be a custom model
|
||||
|
||||
OpenClaw expects every agent to have a primary model. For contractor-backed agents, the actual reasoning engine is not a normal OpenClaw LLM provider call, but a Claude Code session managed outside the usual stateless completion flow.
|
||||
|
||||
Therefore the contractor integration should present itself to OpenClaw as a custom model id, while internally acting as a stateful bridge to Claude Code.
|
||||
|
||||
Recommended model id for phase 1:
|
||||
|
||||
- `contractor-claude-bridge`
|
||||
|
||||
## Mental model
|
||||
|
||||
From OpenClaw's perspective:
|
||||
|
||||
- the agent has a normal primary model
|
||||
- a model request is issued for each turn
|
||||
- the model returns assistant output
|
||||
|
||||
From the plugin's perspective:
|
||||
|
||||
- the model request is actually a routing event
|
||||
- the request identifies the OpenClaw session and agent
|
||||
- the plugin resolves a mapped Claude Code session
|
||||
- the plugin forwards only the newest actionable turn to Claude Code
|
||||
- the plugin returns Claude's output as the model response
|
||||
|
||||
So this is a pseudo-model backend with sessionful behavior.
|
||||
|
||||
## Responsibilities of the bridge model
|
||||
|
||||
The bridge model should:
|
||||
|
||||
1. accept model requests for contractor-backed agents
|
||||
2. identify the current OpenClaw session and contractor agent id
|
||||
3. resolve or create the mapped Claude Code session
|
||||
4. filter OpenClaw-managed envelope/context
|
||||
5. forward only the latest actionable message plus minimal metadata
|
||||
6. collect Claude Code output
|
||||
7. normalize that output into an OpenClaw model response
|
||||
8. persist session mapping metadata
|
||||
|
||||
The bridge model should not:
|
||||
|
||||
- act like a generic stateless LLM provider
|
||||
- replay full OpenClaw session history every turn unless recovery is required
|
||||
- try to mirror all Claude internal state into OpenClaw session files
|
||||
|
||||
## Model lifecycle
|
||||
|
||||
### First turn in an OpenClaw session
|
||||
|
||||
1. OpenClaw selects `contractor-claude-bridge` as the agent's primary model
|
||||
2. bridge model receives the turn input
|
||||
3. plugin extracts:
|
||||
- agent id
|
||||
- OpenClaw session key
|
||||
- workspace
|
||||
- latest user message
|
||||
4. no session mapping exists yet
|
||||
5. plugin creates a Claude Code session through ACP/runtime integration
|
||||
6. plugin injects initial contractor instructions and minimal OpenClaw metadata
|
||||
7. plugin sends the latest user message
|
||||
8. Claude responds
|
||||
9. plugin stores the new mapping and returns assistant output to OpenClaw
|
||||
|
||||
### Later turns
|
||||
|
||||
1. bridge model receives next turn
|
||||
2. plugin resolves existing mapping
|
||||
3. plugin resumes or continues the Claude Code session
|
||||
4. plugin forwards latest user message only
|
||||
5. Claude responds
|
||||
6. plugin returns normalized response and updates mapping timestamps
|
||||
|
||||
### Reset or new session
|
||||
|
||||
Reset semantics should be explicit.
|
||||
|
||||
Recommended behavior:
|
||||
|
||||
- OpenClaw `/new` or reset-equivalent for this agent should create a fresh Claude session transcript
|
||||
- keep the OpenClaw agent identity and routing stable
|
||||
- replace the existing mapping for the OpenClaw session key
|
||||
- reinject initial contractor instructions
|
||||
|
||||
## Session mapping contract
|
||||
|
||||
Bridge model depends on a persistent mapping store.
|
||||
|
||||
Suggested record shape:
|
||||
|
||||
```ts
|
||||
type ContractorSessionMapEntry = {
|
||||
openclawSessionKey: string
|
||||
agentId: string
|
||||
contractor: "claude"
|
||||
claudeSessionId: string
|
||||
workspace: string
|
||||
createdAt: string
|
||||
lastActivityAt: string
|
||||
state: "active" | "closed" | "orphaned"
|
||||
}
|
||||
```
|
||||
|
||||
## Input filtering
|
||||
|
||||
The bridge model must not blindly forward the entire model input payload to Claude Code.
|
||||
|
||||
Instead it should derive a contractor payload with:
|
||||
|
||||
- latest user-visible message
|
||||
- minimal agent metadata
|
||||
- minimal workspace metadata
|
||||
- optional turn metadata needed for reply formatting or approvals
|
||||
|
||||
It should ignore or strip:
|
||||
|
||||
- repeated long-form system envelope generated by OpenClaw
|
||||
- redundant chat history already owned by Claude session memory
|
||||
- internal bookkeeping not useful to Claude Code
|
||||
|
||||
This keeps Claude as the owner of live context.
|
||||
|
||||
## Initial contractor instructions
|
||||
|
||||
When creating a fresh Claude session, inject a stable bootstrap payload that includes:
|
||||
|
||||
- identity of the contractor role inside OpenClaw
|
||||
- workspace path
|
||||
- allowed interaction style with OpenClaw
|
||||
- tool/skill access strategy
|
||||
- output expectations for OpenClaw replies
|
||||
- rule that session continuity lives primarily in Claude Code session state
|
||||
|
||||
This injection should happen on session creation and hard resets, not every turn.
|
||||
|
||||
## Output normalization
|
||||
|
||||
Claude output must be normalized before returning to OpenClaw.
|
||||
|
||||
Normalization should handle:
|
||||
|
||||
- plain assistant text
|
||||
- tool-use related status text
|
||||
- multi-part responses if Claude adapter streams or chunks
|
||||
- failures or blocked actions
|
||||
- explicit clarification requests
|
||||
|
||||
The custom model should emit output in a way OpenClaw can treat as a normal assistant response.
|
||||
|
||||
## Session file interaction
|
||||
|
||||
The current working assumption is:
|
||||
|
||||
- OpenClaw session files remain the system of record for visible conversation state
|
||||
- Claude session state remains the system of record for internal live reasoning context
|
||||
|
||||
Therefore the bridge model should inject Claude responses back into OpenClaw's normal session response path, rather than bypassing it.
|
||||
|
||||
This means the plugin should preserve OpenClaw's normal transcript behavior while avoiding full upstream context replay.
|
||||
|
||||
## Recovery behavior
|
||||
|
||||
### Missing Claude session
|
||||
|
||||
If the mapped Claude session is missing or invalid:
|
||||
|
||||
1. mark mapping as `orphaned`
|
||||
2. create a fresh Claude session
|
||||
3. inject bootstrap context
|
||||
4. optionally summarize minimal recent OpenClaw-visible context for recovery
|
||||
5. store replacement mapping
|
||||
|
||||
This should be treated as degraded recovery, not the normal path.
|
||||
|
||||
### Mapping corruption
|
||||
|
||||
If mapping storage cannot be read:
|
||||
|
||||
- fail closed for the turn if data integrity is uncertain
|
||||
- or create a new Claude session only when policy allows and user impact is acceptable
|
||||
|
||||
## Why not use a normal provider model directly
|
||||
|
||||
Because a normal provider model implies:
|
||||
|
||||
- stateless prompt in
|
||||
- stateless completion out
|
||||
- OpenClaw-owned context reconstruction each turn
|
||||
|
||||
That is the opposite of the intended contractor design.
|
||||
|
||||
The custom model seam is useful precisely because it lets OpenClaw keep the agent abstraction while delegating real session continuity to Claude Code.
|
||||
|
||||
## Open questions
|
||||
|
||||
1. Which provider/plugin registration seam is best for the bridge model id?
|
||||
2. What exact request shape does the plugin receive for a model turn in OpenClaw runtime?
|
||||
3. Where should bootstrap instructions be stored, generated text, template file, or config?
|
||||
4. How should streaming behavior be represented if Claude session output arrives incrementally?
|
||||
5. How should tool requests from Claude be surfaced back into OpenClaw tool execution?
|
||||
|
||||
## References
|
||||
|
||||
### OpenClaw plugin capability
|
||||
|
||||
> "Plugins extend OpenClaw with new capabilities: channels, model providers, ... agent tools, or any combination."
|
||||
|
||||
Source:
|
||||
- https://docs.openclaw.ai/plugins/building-plugins
|
||||
|
||||
### Plugin entry model
|
||||
|
||||
> "For provider plugins, tool plugins, hook plugins, and anything that is not a messaging channel."
|
||||
|
||||
Source:
|
||||
- https://docs.openclaw.ai/plugins/sdk-entrypoints
|
||||
|
||||
### Claude Code 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
|
||||
@@ -23,6 +23,16 @@ Desired properties:
|
||||
|
||||
Use a session proxy runtime rather than replaying full OpenClaw-managed context into Claude Code on every turn.
|
||||
|
||||
Important implementation note: in OpenClaw this should be delivered as a **custom model**.
|
||||
|
||||
Reason:
|
||||
|
||||
- OpenClaw expects each agent to have a primary model
|
||||
- for this special contractor agent, the real primary intelligence is provided by Claude Code
|
||||
- therefore the most natural integration seam is a custom model that accepts OpenClaw messages, routes them into the mapped Claude Code session, and then injects Claude's response back into OpenClaw session state
|
||||
|
||||
So although the architecture is conceptually a session proxy runtime, the concrete integration form inside OpenClaw should be a **bridge model** or **pseudo-model backend** for Claude-backed agents.
|
||||
|
||||
Core idea:
|
||||
|
||||
- map each OpenClaw session to a Claude Code session
|
||||
@@ -30,6 +40,7 @@ Core idea:
|
||||
- resume or continue that Claude session
|
||||
- forward only the newest actionable message plus minimal metadata
|
||||
- avoid rebuilding full prompt history on every turn
|
||||
- return the Claude response through the custom model seam so it becomes part of normal OpenClaw agent flow
|
||||
|
||||
This reduces:
|
||||
|
||||
@@ -137,6 +148,26 @@ This supports the idea that OpenClaw skills and tooling may be adapted into Clau
|
||||
Source:
|
||||
- https://code.claude.com/docs/en/plugins-reference
|
||||
|
||||
## Bridge Model Direction
|
||||
|
||||
The contractor-agent implementation should expose one or more plugin-provided custom model ids for OpenClaw agents to use as their primary model.
|
||||
|
||||
For Claude phase 1, the working assumption is a model id in the shape of:
|
||||
|
||||
- `contractor-claude-bridge`
|
||||
|
||||
Behavior of this bridge model:
|
||||
|
||||
1. receive the agent turn from OpenClaw
|
||||
2. identify the current OpenClaw session key and target contractor agent
|
||||
3. resolve or create the mapped Claude Code session
|
||||
4. filter OpenClaw-managed envelope/context so only the latest actionable message and minimal metadata are forwarded
|
||||
5. send the turn to Claude Code through the chosen ACP/session continuation path
|
||||
6. capture Claude's response
|
||||
7. inject the response back into OpenClaw through the model response path and session file flow
|
||||
|
||||
This approach fits OpenClaw's requirement that every agent has a primary model while still allowing Claude Code to act as the true reasoning engine for contractor-backed agents.
|
||||
|
||||
## Initial CLI Plan
|
||||
|
||||
Introduce a plugin-owned command:
|
||||
|
||||
Reference in New Issue
Block a user