Maps Cursor-specific tool calls to OpenClaw equivalents for running Writ commands via OpenClaw agents.
| 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" |
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_tierresolves to the optionalmodelparam per the table below labelis 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.
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-flightkill + respawn— agent finished, need a fresh run with accumulated context (more reliable for the review loop)
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.
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
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
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.
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 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.
.openclaw/skills/<name>/SKILL.md
Status note: OpenClaw is one of ADR-009's four target platforms but is not yet a
--platformflag ininstall.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.mdlayout.
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.
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.
| 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 |
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", ... })
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.
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.
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..." })
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 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.
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."
-
Sub-agent output capture:
sessions_spawnauto-announces completion. The orchestrator receives the result as a system message. Parse the output from there. -
No direct return values: Unlike Cursor's
Task()which returns output inline, OpenClaw sub-agents deliver results asynchronously. Design your orchestration to handle this. -
Button limitations: Telegram inline buttons have a 64-byte callback_data limit. Keep IDs short. For complex multi-question forms, use sequential messages.
-
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.
-
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. -
Model for sub-agents: see the § 1 resolution table:
floorpasses an operator-configured cheaper same-vendormodel,anchoromits the param. That row is marked (unverified).
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).