Skip to content

Latest commit

 

History

History
443 lines (340 loc) · 17.9 KB

File metadata and controls

443 lines (340 loc) · 17.9 KB

OpenClaw Platform Adapter

Maps Cursor-specific tool calls to OpenClaw equivalents for running Writ commands via OpenClaw agents.

Quick Reference

Cursor Tool OpenClaw Equivalent Notes
Task({ prompt }) sessions_spawn({ task: prompt }) Auto-announces completion
Task({ resume: id }) subagents({ action: "steer", target, message }) Steers existing sub-agent
AskQuestion({ questions }) message({ action: "send", buttons }) Telegram inline buttons
codebase_search exec({ command: "rg 'pattern' src/" }) ripgrep preferred
file_search exec({ command: "fd 'pattern'" }) or find fallback
todo_write Write({ path: ".writ/state/tracking.json" }) File-based tracking
read_file Read({ path }) Direct equivalent
run_terminal_cmd exec({ command }) Direct equivalent
list_dir exec({ command: "ls -la path/" }) Direct equivalent
readonly: true Add constraint to task prompt "Do NOT modify any files"

Detailed Mappings

1. Spawning Sub-Agents (Task → sessions_spawn)

Cursor:

Task({
  subagent_type: "generalPurpose",
  # model: adapter-resolved from model_tier=floor (ADR-024), never hardcoded
  description: "Create user story 1",
  prompt: "You are a User Story Generator agent..."
})

OpenClaw:

sessions_spawn({
  task: "You are a User Story Generator agent...",
  label: "cc-story-1"
})

Parallel spawning — launch multiple in one turn:

sessions_spawn({ task: "Create story 1...", label: "cc-story-1" })
sessions_spawn({ task: "Create story 2...", label: "cc-story-2" })
sessions_spawn({ task: "Create story 3...", label: "cc-story-3" })
sessions_spawn({ task: "Create story 4...", label: "cc-story-4" })

All run concurrently. Each auto-announces completion back to the requester chat.

Key differences:

  • No subagent_type: all OpenClaw sub-agents are general purpose
  • No tier vocabulary on the call: model_tier resolves to the optional model param per the table below
  • label is optional but recommended for identification
  • Completion is push-based: no polling needed

Tier resolution: agents declare model_tier: anchor | floor (ADR-024; contract text in system-instructions.md § Model Tiers), which OpenClaw resolves through the optional model param on sessions_spawn. The row below is marked (unverified): no OpenClaw install was available to observe a spawn, so it is written from the documented sessions_spawn primitive:

Origin source anchor floor escalation
(unverified) anchor.model from the session config, unknown when absent; anchor.effort = unknown; anchor.platform = openclaw omit model an operator-configured cheaper model of the same vendor, passed as model; else omit omit model

Degradation: an unrecognized model_tier warns and runs as anchor; when no cheaper same-vendor model is configured, floor runs with model omitted (the parent's model) and emits one degraded line. Never hard-fail the spawn.

2. Resuming / Steering Agents (resume → subagents steer)

Cursor:

Task({
  subagent_type: "generalPurpose",
  resume: "{coding_agent_id}",
  prompt: "The Review Agent found issues..."
})

OpenClaw:

subagents({
  action: "steer",
  target: "cc-coding-agent",    // label from spawn
  message: "The Review Agent found issues..."
})

Alternative — kill and respawn with context:

subagents({ action: "kill", target: "cc-coding-agent" })
sessions_spawn({
  task: "PREVIOUS CONTEXT: [coding agent output]\n\nREVIEW FEEDBACK: [review issues]\n\nFix the issues above...",
  label: "cc-coding-agent-v2"
})

When to use which:

  • steer — agent is still running, send new instructions mid-flight
  • kill + respawn — agent finished, need a fresh run with accumulated context (more reliable for the review loop)

3. Structured Questions (AskQuestion → message with buttons)

Cursor:

AskQuestion({
  title: "Feature Clarification - Round 1",
  questions: [
    {
      id: "user_type",
      prompt: "Who is the primary user?",
      options: [
        { id: "end_user", label: "End users/customers" },
        { id: "admin", label: "Administrators" },
        { id: "developer", label: "Developers" }
      ]
    }
  ]
})

OpenClaw (Telegram with inline buttons):

message({
  action: "send",
  message: "**Feature Clarification - Round 1**\n\nWho is the primary user of this feature?",
  buttons: [
    [
      { "text": "End users/customers", "callback_data": "user_type:end_user" },
      { "text": "Administrators", "callback_data": "user_type:admin" }
    ],
    [
      { "text": "Developers", "callback_data": "user_type:developer" }
    ]
  ]
})

Multi-question rounds — since Telegram buttons support one action per press, batch questions as sequential messages or combine into a single formatted message with numbered options:

message({
  action: "send",
  message: "**Round 1 — Core Understanding**\n\n1️⃣ **Primary user?**\n2️⃣ **Integration approach?**\n3️⃣ **Implementation priority?**\n\nReply with your choices (e.g., '1: End users, 2: Extends existing, 3: MVP')",
})

Fallback for non-button channels:

Just present numbered options as text:
1. End users/customers
2. Administrators
3. Developers

Reply with the number.

4. Code Search (codebase_search → exec with ripgrep)

Cursor:

codebase_search("authentication pattern")

OpenClaw:

exec({ command: "rg -l 'auth' src/ --type ts" })           // find files
exec({ command: "rg -n 'authenticate|authorize' src/" })     // find lines
exec({ command: "rg -C 3 'export.*Auth' src/" })             // with context

For broader searches:

exec({ command: "rg -l 'pattern' --type ts --type tsx" })    // by file type
exec({ command: "rg 'pattern' -g '!node_modules' -g '!dist'" })  // exclude dirs

5. File Search (file_search → exec with fd)

Cursor:

file_search("AuthService")

OpenClaw:

exec({ command: "fd AuthService" })                          // filename match
exec({ command: "fd -e ts -e tsx auth" })                    // by extension
exec({ command: "find . -name '*auth*' -not -path '*/node_modules/*'" })  // fallback

6. Progress Tracking (todo_write → file-based JSON)

Cursor:

todo_write({
  todos: [
    { id: "context-gathering", content: "Gather context", status: "completed" },
    { id: "coding-phase", content: "Launch coding agent", status: "in_progress" },
    { id: "review-phase", content: "Launch review agent", status: "pending" }
  ]
})

OpenClaw:

Write({
  path: ".writ/state/implement-story-2026-02-22.json",
  content: JSON.stringify({
    story: "story-1-feature-name",
    startedAt: "2026-02-22T17:40:00Z",
    phases: {
      "context-gathering": { status: "completed", completedAt: "..." },
      "coding-phase": { status: "in_progress", agentLabel: "cc-coding-agent" },
      "review-phase": { status: "pending" },
      "testing-phase": { status: "pending" },
      "documentation-phase": { status: "pending" }
    }
  }, null, 2)
})

Update progress — use Edit to patch specific fields, or Write to overwrite the whole state file.

7. Read-Only Agents

Cursor:

Task({
  subagent_type: "generalPurpose",
  readonly: true,
  prompt: "Review the implementation..."
})

OpenClaw:

sessions_spawn({
  task: "Review the implementation...\n\n⚠️ CONSTRAINT: You are in READ-ONLY mode. Do NOT create, modify, or delete any files. Use only Read and exec (for grep/find) tools. Your job is analysis and reporting only.",
  label: "cc-review-agent"
})

Skills

Skills are the third Writ primitive, peer to commands and agents: capability files that describe how to do one thing well. See ADR-009 for the verb/noun/tool framing and .writ/docs/skills.md for the user-facing explainer.

Install Path

.openclaw/skills/<name>/SKILL.md

Status note: OpenClaw is one of ADR-009's four target platforms but is not yet a --platform flag in install.sh. The path above is the install location the ADR names; install fanout to OpenClaw waits on a future OpenClaw install adapter (separate spec). Until then, OpenClaw users wire skills manually with the same <name>/SKILL.md layout.

Loading Mechanism

OpenClaw's session loader reads files from the project workspace on demand; there is no <agent_skills> ambient discovery channel as on Cursor. Skills load via explicit Read calls when a command or agent needs them.

Writ-authored skills set disable-model-invocation: true in frontmatter for cross-platform consistency, even though OpenClaw does not auto-invoke skills. The same SKILL.md then works on Cursor, Claude Code, and OpenClaw without per-platform frontmatter variants. Community skills installed by other means follow whatever invocation behavior their installer configured.

Invocation

Commands and agents that need a skill load it explicitly. In OpenClaw, the Read tool maps directly:

Read({ path: "skills/<name>/SKILL.md" })

For sub-agents spawned via sessions_spawn, the orchestrator includes the skill content (or an explicit Read instruction) in the spawn prompt. Sub-agents inherit context only through the prompt, not shared session state.

For commands and agents that declare required_skills: in their frontmatter (see Story 5 / system-instructions.md), the orchestrator pre-loads each named skill via Read before spawning the consumer session. The convention was resolved revisit-to-adopt on 2026-08-11 on the strength of a named future consumer, Phase 10 progressive disclosure (ADR-021). Phase 10 evaluated the mechanism and did not adopt it: an eager pre-load moves extracted bytes into the floor that every invocation pays, so a disclosed command costs more per invocation than the monolith it replaced. Phase 10 loads its skills with an inline Read skills/<name>/SKILL.md at the point of need. The convention therefore has no consumer; nothing in the product declares the field. The schema, this mechanism, and the graceful-degradation rule are unchanged and stay supported. The adoption carries a review trigger of 2026-11-11, aligned to ADR-021's own review: no consumer by then, deprecate; a consumer appears, record it and reset. See system-instructions.md → required_skills: frontmatter convention.

Authoring & Reference

Need Tool
Scaffold a new skill /new-skill <name> (boundary lint enforced at authoring time)
Lint an existing skill against the role convention /refresh-command → boundary check
Cross-platform format spec AgentSkills standard
Boundary rationale ADR-009
User-facing explainer .writ/docs/skills.md

Workflow Patterns

implement-story --full-pipeline Full Flow

Default /implement-story is coding + evaluator plus scripts. The six-agent hatch is --full-pipeline:

// Phase 1: Context gathering (orchestrator does this directly)
Read({ path: "user-stories/story-1-feature.md" })
Read({ path: "spec-lite.md" })
exec({ command: "rg -l 'relevant_pattern' src/" })
// Also grep .writ/knowledge/ and assemble optional knowledge_context

// Phase 2: Spawn coding agent
sessions_spawn({
  task: "[Full coding agent prompt with all context]",
  label: "cc-coding-agent"
})
// Wait for auto-announce completion, capture output

// Phase 3: Spawn review agent (read-only)
sessions_spawn({
  task: "[Review prompt with coding agent output]\n\n⚠️ READ-ONLY MODE...",
  label: "cc-review-agent"
})
// Parse REVIEW_RESULT from output

// If FAIL: respawn coding agent with feedback
sessions_spawn({
  task: "[Original context + review feedback]",
  label: "cc-coding-agent-v2"
})

// If PASS: spawn testing agent
sessions_spawn({
  task: "[Testing prompt with files to test]",
  label: "cc-testing-agent"
})

// Phase 5: Spawn documentation agent
sessions_spawn({
  task: "[Documentation prompt with implementation summary]",
  label: "cc-docs-agent"
})

// Phase 6: Update story status
Edit({ path: "user-stories/story-1-feature.md", ... })

Knowledge Loading

The .writ/knowledge/ scan stays in the orchestrator. Before spawning architecture, coding, or review sessions, OpenClaw implementations should extract story keywords, use rg against .writ/knowledge/, cap the assembled knowledge_context at about 2KB, and include it in each relevant sub-agent prompt. If no entries match, omit the block silently.

Preamble Convention

OpenClaw implementations install commands/_preamble.md with the command set. When a session loads a command file, the final ## References section points at _preamble.md and system-instructions.md; the session should read those links as standing instructions before translating generic tool names to OpenClaw calls.

Review Feedback Loop

max_iterations = 3
iteration = 0

while iteration < max_iterations:
  // Spawn review agent
  review_result = spawn review agent, wait for completion
  
  if PASS:
    break → continue to testing
  
  if FAIL:
    iteration++
    // Respawn coding agent with accumulated feedback
    spawn coding agent with: original context + all review feedback so far
    wait for completion

if iteration >= max_iterations:
  // Escalate to user
  message({ action: "send", message: "⚠️ Review loop exceeded 3 iterations..." })

State Persistence

For long-running implement-story workflows, persist state after each phase:

// .writ/state/implement-story-2026-02-22T174000.json
{
  "story": "story-1-feature-name",
  "spec": "2026-02-22-feature-name",
  "startedAt": "2026-02-22T17:40:00Z",
  "currentPhase": "review",
  "iteration": 1,
  "phases": {
    "coding": {
      "status": "completed",
      "agentLabel": "cc-coding-agent",
      "output": "Files created: ...",
      "filesModified": ["src/lib/feature.ts", "src/components/Feature.tsx"],
      "testsWritten": ["__tests__/lib/feature.test.ts"]
    },
    "review": {
      "status": "in_progress",
      "agentLabel": "cc-review-agent",
      "iteration": 1
    },
    "testing": { "status": "pending" },
    "documentation": { "status": "pending" }
  }
}

This enables recovery if the orchestrator session is interrupted.


Native Memory & the Writ Ledger

Native memory holds session preferences and trivia; the Writ ledger holds negotiated decisions, conventions, and lessons — the reviewable markdown layer that feeds native memory and any external index.

On OpenClaw there is no ambient persistent memory store. Native context is session state / file-based context: the per-session working state, for example the .writ/state/ JSON an /implement-story run persists between phases. Let that state hold ephemeral, in-flight session context. When a decision, convention, or lesson is negotiated and needs to survive past the session, write it to the ledger under .writ/decision-records/ or .writ/knowledge/.

Anti-pattern: negotiated decisions that live only in native memory are unreviewable and are lost on a reinstall, a new machine, or a teammate who never had your store. Write the decision, the convention, or the lesson to the ledger, and let native memory keep only the ephemeral trivia.

Three layers, one system of record: native memory (session prefs/trivia, per platform) → the Writ ledger (canonical, reviewable markdown in git) → an optional external index (GBrain, disposable). The gbrain-interop skill and .writ/docs/gbrain-recipe.md cover the external-index layer. Removing that index loses nothing; the ledger is the only copy.


Command Workflow Integrity

When a Writ command uses a discovery or planning phase, that phase serves the command; it does not replace the command's artifact creation steps.

Rule: After discovery completes, the command resumes its documented phases and produces its documented artifacts. After artifact creation, the command terminates with a next-step suggestion. Do not continue the session into implementation or offer to execute what was planned.

Common failure: After producing spec artifacts, the session offers implementation. Planning commands produce files, present a summary, and stop; the user decides what to run next.

Reference: System instructions → Prime Directive → Hard Constraints → "Never let Plan Mode absorb a command's workflow."


Gotchas

  1. Sub-agent output capture: sessions_spawn auto-announces completion. The orchestrator receives the result as a system message. Parse the output from there.

  2. No direct return values: Unlike Cursor's Task() which returns output inline, OpenClaw sub-agents deliver results asynchronously. Design your orchestration to handle this.

  3. Button limitations: Telegram inline buttons have a 64-byte callback_data limit. Keep IDs short. For complex multi-question forms, use sequential messages.

  4. Parallel spawn limit: OpenClaw does not enforce a hard limit on concurrent sub-agents. Watch API costs: 4 parallel story generators is fine; 20 gets expensive.

  5. File conflicts: When multiple sub-agents write files in the same workspace, ensure they write to different paths. The user-story-generator pattern (each agent writes its own story-N-*.md) is safe.

  6. Model for sub-agents: see the § 1 resolution table: floor passes an operator-configured cheaper same-vendor model, anchor omits the param. That row is marked (unverified).

Model-specific

Claude Fable 5.1 may serialize independent tool calls: issue independent reads, searches, and checks as one batched message, not one at a time (the only model-specific line this adapter carries — ADR-026; see ADR-024 for delegation).