OpenMarlin
Use this skill when a user explicitly wants to use OpenMarlin from inside OpenClaw.
This skill covers four main jobs:
- account registration and API key bootstrap
- native execution requests through
/v1/executions - asynchronous long-running jobs through
/v1/tasks - billing, balance, and
402 Payment Requiredrecovery
When To Activate
Activate this skill for requests such as:
- "use openmarlin to answer this"
- "ask openmarlin to summarize this page"
- "use openmarlin to find today's USD/CNY exchange rate"
- "use openmarlin to execute this task"
- "use openmarlin to generate a video"
- "use openmarlin to submit an async video task"
- "register OpenMarlin"
- "check OpenMarlin balance"
When routing the request:
- treat "use openmarlin ..." as an OpenMarlin intent, not generic chat
- prefer
/v1/executionsfor normal tasks such as answering, searching, summarizing, extracting, or translating - prefer
/v1/tasksfor video generation and other artifact-oriented jobs even when the user did not explicitly say "async" - treat requests mentioning video, rendering, long-running generation, or
background execution as
/v1/tasksby default unless the user explicitly asks for synchronous execution - do not reject activation just because the user did not provide an exact model ref in the first sentence
Core Constraints
- Keep the flow OpenClaw-first by default.
- Do not collect passwords, magic links, MFA secrets, or raw credentials in chat.
- Prefer the
deviceauth flow unless the deployment specifically requiresworkos_callback. - Treat browser use as a narrow external step for identity or Stripe checkout, not the main control plane.
- After browser handoff begins, keep polling the registration session in
OpenClaw until it becomes
completedorexpired. - Treat browser callback or landing pages as user-facing only. Machine-readable registration state must come from the registration session.
- Treat
OPENMARLIN_SERVER_URLas the only trusted API origin and keep it as a bare origin without/v1. - Do not use
https://openmarlin.aiasOPENMARLIN_SERVER_URL; that is the browser-facing website. Usehttps://api.openmarlin.aiunless the user is targeting a custom deployment. - Use server-provided
handoff.authorization_urldirectly. Do not reconstruct WorkOS or browser URLs locally. - Store platform API keys in OpenClaw auth-profile storage when available, not in ordinary skill config.
- Treat
OPENMARLIN_PLATFORM_API_KEYas a temporary override for debugging, not the preferred steady-state storage path. - If no platform key is available yet, start registration/bootstrap instead of telling the user to manually provide an API key.
- When balance information is incomplete, label local billing state as last-known or estimated instead of pretending it is authoritative.
Installation
This skill is distributed as a directory, not as a standalone Markdown file.
If you install it manually, copy both SKILL.md and the sibling scripts/
directory.
Required files:
SKILL.mdscripts/registration_session.pyscripts/platform_request.pyscripts/billing.pyscripts/openclaw_billing_state.pyscripts/openclaw_platform_auth.pyscripts/openclaw_skill_config.py
Runtime expectations:
python3is available inPATHOPENMARLIN_SERVER_URLdefaults tohttps://api.openmarlin.aiOPENMARLIN_SERVER_URLmust be a bare origin, not a URL ending in/v1
First Run
For a new user, the shortest safe path is:
- Confirm
OPENMARLIN_SERVER_URLif you need to override the default. - Start registration with
python3 scripts/registration_session.py create. - Complete external auth in the browser if the server returns a handoff URL.
- Poll the registration session with
watchuntil it becomescompleted. - Bootstrap and store the first workspace API key with
bootstrap --store. - Optionally call
python3 scripts/platform_request.py models. - Send the first execution request.
After setup, the most common next actions are:
- send a routed execution request
- submit a long-running task and poll for completion
- inspect available models
- recover from a
402 Payment Requiredresponse - inspect balance or recent billing activity
- fetch the caller's referral code and invite link
Request Model
Registration
Registration flows are built on:
POST /v1/registration/sessionsGET /v1/registration/sessions/:sessionIdPOST /v1/registration/sessions/:sessionId/api-keys
Registration session states:
pending_external_authcompletedexpired
When a session completes, OpenClaw should continue from the machine-readable registration session state, not from browser callback output.
Executions
Native execution uses:
POST /v1/executions
Execution requests may include:
instructionkind = agent_runstreamprovider_idlabelsagent_idsession_keytimeout_msmodelmetadata
Execution routing rules:
- with neither
modelnorprovider_id, let the server choose both - with only
model, use an exact full ref and let the server choose a provider - with only
provider_id, let the server choose an eligible model on that provider - with both
modelandprovider_id, the server enforces both constraints
If model is provided, it must be an exact full ref such as
openai-codex/gpt-5.4.
If you provide both provider_id and model, first confirm from
python3 scripts/platform_request.py models that the provider advertises that
same exact model ref.
Tasks
Long-running jobs use:
POST /v1/tasksGET /v1/tasks/:taskId
Task requests do not use the same routing shape as /v1/executions.
Task requests use:
kind = videoinput.promptrequiredinput.media_urlsoptionalinput.media_idsoptionalinput.duration_msoptionalinput.aspect_ratiooptionalmetadataoptional
Task requests do not accept:
instructionprovider_idlabelsmodelstream
Prefer /v1/tasks when:
- generation may take many minutes
- stream output is absent or not useful
- the real result is expected to arrive later as artifact metadata such as an
artifact_url - the request is for video generation, unless the user explicitly insists on a synchronous execution path
- when using
/v1/tasksfrom inside OpenClaw, default to submitting with watch-and-wait behavior instead of stopping after returning atask_id
Task states:
queuedrunningsucceededfailed
Billing
Billing and recovery flows use:
GET /v1/balanceGET /v1/usage-eventsGET /v1/ledgerPOST /v1/topup/sessionsGET /v1/topup/sessions/:sessionId
Structured balance failures may return:
error_code = insufficient_balancemessageworkspace_idcurrent_balance.amount / unitrequired_balance.amount / unit
Treat that 402 shape as workflow input, not a generic transport failure.
Common Commands
Registration
Create a registration session:
python3 scripts/registration_session.py create
Create a callback-style session when the deployment requires it:
python3 scripts/registration_session.py create --auth-flow workos_callback
Check or poll a registration session:
python3 scripts/registration_session.py status --session-id <session-id>
python3 scripts/registration_session.py watch --session-id <session-id>
Bootstrap and store the first API key:
python3 scripts/registration_session.py bootstrap \
--session-id <session-id> \
--store
Executions
List currently available exact models:
python3 scripts/platform_request.py models
Let the server choose model and provider automatically:
python3 scripts/platform_request.py executions \
--body-json '{"instruction":"say hello"}'
Use an exact model ref with automatic provider routing:
python3 scripts/platform_request.py executions \
--body-json '{"instruction":"say hello","model":"openai-codex/gpt-5.4"}'
Use an explicit provider override:
python3 scripts/platform_request.py executions \
--provider node-a \
--body-json '{"instruction":"say hello"}'
Send a dry run:
python3 scripts/platform_request.py executions \
--dry-run \
--server-url https://your-server.example.com \
--api-key claw_wsk_placeholder \
--body-json '{"instruction":"say hello"}'
Use streaming execution:
python3 scripts/platform_request.py executions \
--body-json '{"instruction":"say hello","stream":true}'
Tasks
Submit a long-running job:
python3 scripts/platform_request.py tasks-submit \
--watch \
--body-json '{"kind":"video","input":{"prompt":"Generate a short plane video."}}'
Fetch the current task state:
python3 scripts/platform_request.py tasks-status --task-id <task-id>
Poll until the task succeeds or fails:
python3 scripts/platform_request.py tasks-watch --task-id <task-id>
Billing
Explain a structured 402 response:
python3 scripts/billing.py explain-402 \
--response-json '{"error_code":"insufficient_balance","message":"Workspace balance is insufficient for this request.","workspace_id":"ws_123","current_balance":{"amount":0,"unit":"credits"},"required_balance":{"amount":1,"unit":"credits"}}'
Create a top-up session from the 402 shortfall:
python3 scripts/billing.py create-topup \
--response-json '{"error_code":"insufficient_balance","message":"Workspace balance is insufficient for this request.","workspace_id":"ws_123","current_balance":{"amount":0,"unit":"credits"},"required_balance":{"amount":1,"unit":"credits"}}'
Check top-up progress:
python3 scripts/billing.py status --session-id <topup-session-id>
python3 scripts/billing.py watch --session-id <topup-session-id>
Show current balance:
python3 scripts/billing.py balance --workspace-id <workspace-id>
Show recent billing activity:
python3 scripts/billing.py activity
Fetch the caller's referral code, invite link, and attribution summary:
python3 scripts/billing.py referral-link
Operational Guidance
Routing Failures
Translate common routing errors into plain language:
provider_unavailable: the selected provider is not currently connectedprovider_label_mismatch: the selected provider does not satisfy the requested routing hintsexecution_provider_not_found: no eligible execution provider matched the current requestexecution_provider_ambiguous: more than one execution provider matched and the server needs narrower labels or an explicit provider overrideexecution_kind_not_available: the selected provider does not support the requested execution kindtask_executor_not_found: no configured task executor matched the current long-running task requestinvalid_routing_labels: labels were malformed
When these happen:
- restate the provider and labels you actually sent
- suggest retrying with different labels, a different provider, or automatic routing
- do not invent hidden labels or undocumented routing fields
For /v1/tasks specifically:
- do not suggest provider overrides, labels, or model routing as a recovery path
- suggest validating
kind = videoand theinputpayload shape instead
For long-running jobs:
- prefer
tasks-submit --watchover asking the user to manually follow up withtasks-watch - for video-generation requests, treat
tasks-submit --watchas the default completion path unless the user explicitly asks for fire-and-forget behavior - when repeating the exact same video submission shortly after a task was
already attempted, prefer reusing the recent
idempotency_keyso the server returns the original task instead of creating a second/v1/tasksrequest - keep refreshing local task state while watching so long-running tasks remain inside that short reuse window
- acknowledge acceptance as soon as a
task_idis returned - keep polling until the task reaches a terminal state or times out; do not require the user to ask again just to continue watching the same task
- surface final
outputandmetadatawhen the task reachessucceeded
Balance And Recovery
When the server returns a structured 402 insufficient_balance response:
- show the current balance, required balance, and shortfall explicitly
- explain that this is a recoverable billing state
- keep the recovery flow inside OpenClaw until the required Stripe checkout step
- prefer authoritative
GET /v1/balancereads when available - keep local billing snapshots only as supporting context
When guiding a top-up flow:
- create the top-up session inside OpenClaw
- show the difference between
pending_payment,credit_applied, andpayment_failed - tell the user that opening the Stripe
checkout_urlis the only required external billing step - refresh balance after credit lands
Credential Handling
The returned secret from API key bootstrap is the steady-state platform
credential for OpenClaw.
- prefer OpenClaw auth profiles over plain repo files or ordinary config
- store the key in the default OpenClaw auth profile when
--storeis used - avoid echoing raw secrets unless the active command explicitly returns them
- when reporting success, show where the key was stored or loaded from
- never ask the user to paste a platform API key into chat as the normal registration path
- if
openmarlin.aiappears blocked by browser or Cloudflare protection, verify that helpers are targetinghttps://api.openmarlin.aibefore suggesting manual browser actions
微信扫一扫