Install
openclaw skills install @threelanestudios/paneOperate Pane through its local Gateway: create notes, tasks, and projects via chat sessions; manage AI sessions.
openclaw skills install @threelanestudios/paneOperate a locally running Pane app through its Gateway HTTP API: create/manage notes, tasks, projects, and folders conversationally via chat sessions; manage sessions directly.
Requires PANE_GATEWAY_URL and PANE_GATEWAY_TOKEN already provisioned (see
Setup). Every authenticated call uses exec + curl — the gateway needs a
custom Authorization: Bearer header and a self-signed TLS cert by default,
so web_fetch is not a good fit here.
Pane is a local-first desktop workspace (macOS/Linux) where you and your AI share notes, tasks, and projects — one place for conversations, documents, and boards. Pane is a paid app — pricing at paneapp.ai. This skill requires a running, paired Pane Gateway.
The gateway URL points to the user's own local Pane Gateway process; the token is user-supplied at pairing time. This skill sends no data to any third party.
Pairing exchanges a 6-digit code (shown in the Pane app / gateway logs, 5-min expiry) for a 90-day bearer token. This skill assumes a human has already paired and exported the env vars — it does not walk through pairing interactively, since the code is time-limited and shown in the Pane UI, not to this agent.
If the user asks you to pair for them and gives you a live code immediately, fetch the gateway's cert first (see TLS handling below), then pair:
curl -sS "$PANE_GATEWAY_URL/v1/health" | jq -r '.tls_cert_pem' > /tmp/pane-gateway.pem
CACERT=/tmp/pane-gateway.pem
curl -sS --cacert "$CACERT" \
-X POST "$PANE_GATEWAY_URL/pair" \
-H "Content-Type: application/json" \
-d '{"code":"123456"}'
Response: {"token": "...", "expires_at": "...", "tenant_id": "default", "gateway_version": "..."}.
Save token as PANE_GATEWAY_TOKEN. Never print/log the token in full in chat
transcripts — treat it as a secret.
Pane Gateway uses a self-signed cert by default (GATEWAY_TLS_MODE=selfsigned).
Two options, in order of preference:
1. Pin the cert (recommended). Fetch the cert once via the unauthenticated health check, save it, and pass it to every subsequent call:
curl -sS "$PANE_GATEWAY_URL/v1/health" | jq -r '.tls_cert_pem' > /tmp/pane-gateway.pem
curl -sS --cacert /tmp/pane-gateway.pem "$PANE_GATEWAY_URL/v1/health"
2. Skip verification (dev only). If PANE_GATEWAY_INSECURE_TLS=1 is set,
use -k/--insecure. Do not default to this silently — only use it when the
env var is explicitly set, and mention to the user that verification is
skipped.
if [ "$PANE_GATEWAY_INSECURE_TLS" = "1" ]; then
curl -sS -k "$PANE_GATEWAY_URL/v1/health"
else
curl -sS --cacert /tmp/pane-gateway.pem "$PANE_GATEWAY_URL/v1/health"
fi
The rest of this doc uses --cacert "$CACERT" in examples; substitute -k
per the above when PANE_GATEWAY_INSECURE_TLS=1.
The Pane Gateway does NOT expose direct REST endpoints for note, task, project, or folder CRUD. Those operations only exist as Tauri-internal commands used by Pane's in-app AI assistant. The way an external agent creates/edits notes, tasks, projects, and folders is by messaging through a Pane chat session — Pane's own in-app AI reads the message, decides which tool(s) to call, and executes them app-side.
Flow:
POST /v1/sessionsPOST /v1/sessions/:id/messagescreate_note, edit_note, append_to_note,
create_project, create_folder, set_status, search_notes, etc.GET /v1/sessions/:id/messages (poll) or
GET /v1/sessions/:id/messages/stream (SSE, real-time)Write your message like you're talking to a capable assistant that already
knows Pane's data model — be specific about title, project, and any status/due
date, the same way you'd phrase it to a human assistant. Don't try to call
create_note etc. yourself; there is no such REST endpoint.
CACERT=/tmp/pane-gateway.pem
# 1. Create a session (oc_agent_id is the OpenClaw agent Pane should route to
# — usually "main" unless the user has a specific Pane-side agent in mind)
SESSION=$(curl -sS --cacert "$CACERT" \
-X POST "$PANE_GATEWAY_URL/v1/sessions" \
-H "Authorization: Bearer $PANE_GATEWAY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"oc_agent_id":"main","title":"Agent task"}')
SESSION_ID=$(echo "$SESSION" | jq -r '.session_id')
# 2. Send a message describing the desired note
curl -sS --cacert "$CACERT" \
-X POST "$PANE_GATEWAY_URL/v1/sessions/$SESSION_ID/messages" \
-H "Authorization: Bearer $PANE_GATEWAY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"content":"Create a note called '\''Meeting Notes'\'' in the Work project with today'\''s agenda: 1. Budget review 2. Q3 roadmap"}'
# 3. Poll for the response (Pane's assistant needs a moment to run tools)
sleep 3
curl -sS --cacert "$CACERT" \
"$PANE_GATEWAY_URL/v1/sessions/$SESSION_ID/messages?limit=10" \
-H "Authorization: Bearer $PANE_GATEWAY_TOKEN" | jq '.messages'
The assistant's reply in messages confirms what it did (e.g. "Created
'Meeting Notes' in Work"). If the reply is ambiguous or reports failure,
re-phrase the request with more specific project/folder names — Pane's
assistant resolves project_id/folder_id/note_id by name or UUID, so
typos or ambiguous names ("the work project" when two projects contain
"work") can misfire.
Phrase requests around these operations (Pane's in-app AI executes them):
cabinet/todo/in_progress/review/done), due date, initial content,
priority (low/medium/high/urgent).Do not attempt to construct direct REST calls like POST /v1/notes — they
do not exist. If unsure whether Pane executed an action, ask it to confirm
("search for the note you just created") in a follow-up message on the same
session.
When a request in a Pane session implies multi-step or long-running work, do not complete it in one turn and do not wait to be prompted between steps. Instead:
openclaw cron add --at "+90s" --message "<next step instruction>" --session "session:<this session's key>" --no-deliver --delete-after-run
## Runtime section of your system prompt (session=agent:<agentId>:openai-user:pane-<sessionId>). Use it exactly.--announce, any delivery mode, or --session isolated. The Pane transcript is the delivery: Pane polls this session and shows your reply automatically.exec only to run openclaw cron add, and never touch files or databases to do the user's task. The curl operations elsewhere in this skill are for agents operating Pane from outside a session.All authenticated routes require Authorization: Bearer $PANE_GATEWAY_TOKEN.
/v1/health and /pair are unauthenticated (health returns a reduced
payload without auth).
curl -sS --cacert "$CACERT" "$PANE_GATEWAY_URL/v1/health"
# Authenticated (fuller response incl. oc_connection_status):
curl -sS --cacert "$CACERT" "$PANE_GATEWAY_URL/v1/health" \
-H "Authorization: Bearer $PANE_GATEWAY_TOKEN"
curl -sS --cacert "$CACERT" "$PANE_GATEWAY_URL/v1/agents" \
-H "Authorization: Bearer $PANE_GATEWAY_TOKEN"
curl -sS --cacert "$CACERT" "$PANE_GATEWAY_URL/v1/models" \
-H "Authorization: Bearer $PANE_GATEWAY_TOKEN"
# Force refresh (bypass 30s cache):
curl -sS --cacert "$CACERT" "$PANE_GATEWAY_URL/v1/models?refresh=1" \
-H "Authorization: Bearer $PANE_GATEWAY_TOKEN"
# Create
curl -sS --cacert "$CACERT" -X POST "$PANE_GATEWAY_URL/v1/sessions" \
-H "Authorization: Bearer $PANE_GATEWAY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"oc_agent_id":"main","title":"My session","context_hint":"optional hint"}'
# List
curl -sS --cacert "$CACERT" "$PANE_GATEWAY_URL/v1/sessions" \
-H "Authorization: Bearer $PANE_GATEWAY_TOKEN"
# Send a message (idempotency_key auto-generated if omitted; pass your own to
# safely retry a POST without risking a duplicate send)
curl -sS --cacert "$CACERT" \
-X POST "$PANE_GATEWAY_URL/v1/sessions/$SESSION_ID/messages" \
-H "Authorization: Bearer $PANE_GATEWAY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"content":"Hello Pane","idempotency_key":"'"$(uuidgen)"'"}'
# Read messages (paginated: before/since cursors, limit up to 200, default 50)
curl -sS --cacert "$CACERT" \
"$PANE_GATEWAY_URL/v1/sessions/$SESSION_ID/messages?limit=50" \
-H "Authorization: Bearer $PANE_GATEWAY_TOKEN"
# Abort an in-flight generation
curl -sS --cacert "$CACERT" -X POST "$PANE_GATEWAY_URL/v1/sessions/$SESSION_ID/abort" \
-H "Authorization: Bearer $PANE_GATEWAY_TOKEN"
Message content is capped at 1 MiB. Message bodies from GET messages are
opaque JSON objects passed through from OpenClaw — inspect with jq rather
than assuming a fixed schema; look for role/content-style fields.
GET /v1/sessions/:id/messages/stream returns text/event-stream. Use curl's
-N (no-buffer) flag to consume it live:
curl -sS -N --cacert "$CACERT" \
"$PANE_GATEWAY_URL/v1/sessions/$SESSION_ID/messages/stream" \
-H "Authorization: Bearer $PANE_GATEWAY_TOKEN"
To resume after a disconnect, pass Last-Event-ID: <sequence> to replay
buffered events (falls back to a replay.gap event if the buffer has already
rolled past that sequence). This is a real HTTP SSE stream, not WebSocket —
run it as a background exec process if you need to consume it alongside
other work; do not attempt to open a WebSocket connection to the gateway
(clients never connect via WS — only the gateway's internal
Gateway→OpenClaw link uses WS).
POST /v1/chat/completions proxies straight to OpenClaw's OpenAI-compatible
chat endpoint (8 MiB body limit, supports "stream": true/false). Prefer
the session endpoints above for anything that should show up in Pane's UI —
use this only when you need a raw one-off completion outside of a Pane
session.
curl -sS --cacert "$CACERT" -X POST "$PANE_GATEWAY_URL/v1/chat/completions" \
-H "Authorization: Bearer $PANE_GATEWAY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"model":"openclaw","messages":[{"role":"user","content":"hi"}],"stream":false}'
See references/gateway-api.md for the full endpoint reference including
request/response field details.
POST /v1/notes — they
return 404 (fallback handler).exec+curl over plain HTTP/SSE.| Symptom | Likely cause | Fix |
|---|---|---|
curl: (60) SSL certificate problem | Self-signed cert, not pinned | Fetch tls_cert_pem from /v1/health and use --cacert, or set PANE_GATEWAY_INSECURE_TLS=1 and use -k |
401 {"error":"unauthorized",...} | Missing/expired/invalid Authorization header | Confirm Bearer $PANE_GATEWAY_TOKEN is set; token expires 90 days after pairing — re-pair if expired |
curl: (7) Failed to connect | Gateway not running, or wrong port | Confirm PANE_GATEWAY_URL matches the running gateway (default port per Pane docs); check the Pane app is open |
404 {"error":"not_found","message":"Unknown endpoint"} on any /v1/notes, /v1/tasks, /v1/projects path | Those routes don't exist | Use the conversational session flow instead |
413/{"error":"payload_too_large",...} | Message >1 MiB or chat body >8 MiB | Shorten the payload |
| Session message sent but nothing seems to happen | Pane's assistant runs async; you polled too soon | Wait 2-5s (or use the SSE stream) before reading messages |
| Assistant's reply says it couldn't find the project/note | Ambiguous or misspelled name in your message | Re-phrase with the exact project/folder/note title, or search_notes first via a session message |
Idempotent retry returns the same message_id unexpectedly | Working as intended — same idempotency_key reused | Generate a new idempotency_key (e.g. uuidgen) for a genuinely new message |
| Scheduled step never appeared in Pane | --session "session:<key>" was not used (or --session isolated was used), or a delivery mode was set | Verify --session "session:<key>" was used (not --session isolated) and no delivery mode; confirm the key matches the ## Runtime line |
npm i -g clawhub
clawhub login
clawhub whoami
clawhub skill publish ./pane \
--slug pane \
--name "Pane" \
--version 1.0.0 \
--changelog "Initial release: conversational note/task/project ops via chat sessions, session/chat/sync REST operations"
Org-scoped publish target: @ThreeLaneStudios/pane. See PUBLISHING.md for
the full command reference.