8.7 KiB
MagicForm Integration Spec
MagicForm delegates agentic tasks to PicoClaw via webhooks. PicoClaw processes the request asynchronously and POSTs the result back to a callback URL.
For general PicoClaw installation, CLI usage, and config reference, see cli.md.
Pre-requisites
- Install PicoClaw — see cli.md § Install
- Global config — see cli.md § Global Config
Directory layout
MagicForm pre-provisions directories on disk before calling PicoClaw (see cli.md § Directory Layout for the general structure):
{workspace_root}/
{stackId}/
config/ # configDir -- shared per-stack
config.json # API key, model, agent settings for this stack
AGENTS.md # Agent instructions (optional)
IDENTITY.md # Agent identity (optional)
SOUL.md # Agent personality (optional)
USER.md # User context (optional)
{conversationId}/ # workspace -- per-conversation
sessions/ # Conversation history (managed by PicoClaw)
memory/ # Persistent agent memory (managed by PicoClaw)
skills/ # Workspace-local skills (optional)
Workspace config
Per-stack config overlays are placed in the config directory. See cli.md § Workspace Config for merge rules and example.
Gateway Mode
Channel config
Add to ~/.picoclaw/config.json:
{
"gateway": {
"host": "0.0.0.0",
"port": 18790
},
"channels": {
"magicform": {
"enabled": true,
"token": "your-shared-secret",
"backend_url": "https://api.magicform.example.com",
"webhook_path": "/hooks/magicform",
"workspace_root": "/data/workspaces",
"allow_from": []
}
}
}
| Field | Description | Default |
|---|---|---|
token |
Bearer token for webhook auth. Empty = allow all (dev only). | "" |
backend_url |
Fallback callback URL base (used when payload omits callbackUrl). |
"" |
webhook_path |
HTTP path for the webhook endpoint. | /hooks/magicform |
workspace_root |
Root directory for workspace/configDir path validation. Required for path security. | "" |
allow_from |
Sender ID allowlist. Empty = allow all. Accepts strings and numbers (e.g. ["user1", 12345]). |
[] |
All fields can be set via environment variables:
PICOCLAW_CHANNELS_MAGICFORM_ENABLED=true
PICOCLAW_CHANNELS_MAGICFORM_TOKEN=your-shared-secret
PICOCLAW_CHANNELS_MAGICFORM_BACKEND_URL=https://api.magicform.example.com
PICOCLAW_CHANNELS_MAGICFORM_WEBHOOK_PATH=/hooks/magicform
PICOCLAW_CHANNELS_MAGICFORM_WORKSPACE_ROOT=/data/workspaces
PICOCLAW_CHANNELS_MAGICFORM_ALLOW_FROM=sender1,sender2
Start the gateway
picoclaw gateway
# or with debug logging:
picoclaw gateway -d
Listens on {host}:{port} (default 127.0.0.1:18790).
Health check
GET /health/magicform
Response:
{"status": "ok", "channel": "magicform"}
Webhook: send a message
POST /hooks/magicform
Authorization: Bearer your-shared-secret
Content-Type: application/json
Request body
{
"stackId": "s1",
"conversationId": "c1",
"userId": "user-123",
"message": "Summarize the latest sales report",
"workspace": "s1/c1",
"configDir": "s1/config",
"callbackUrl": "https://api.magicform.example.com/claw-agent/callback",
"allowedTools": ["read_file", "web_fetch"],
"allowedSkills": ["summarize"]
}
| Field | Type | Required | Description |
|---|---|---|---|
stackId |
string | Yes | Tenant/stack identifier. |
conversationId |
string | Yes | Conversation identifier. |
userId |
string | No | Sender identifier (defaults to "anonymous"). |
message |
string | Yes | The user's message. |
workspace |
string | No | Agent working directory, relative to workspace_root. |
configDir |
string | No | Config directory, relative to workspace_root. Contains config.json and bootstrap files. |
callbackUrl |
string | No | Where to POST the response. Falls back to backend_url + "/claw-agent/callback". |
allowedTools |
string[] | No | Tool allowlist. Empty = all tools enabled. See cli.md § Tool Names. |
allowedSkills |
string[] | No | Skill filter. Empty = all skills loaded. |
Path security: workspace and configDir must be relative paths that resolve under workspace_root. Traversal attempts (e.g. ../../etc) are rejected with 400 Bad Request.
Request size limit: Webhook payloads are limited to 1 MB. Larger requests receive 413 Request Entity Too Large.
Method: Only POST is accepted. Other methods receive 405 Method Not Allowed.
Response
Returns 200 OK immediately. Processing happens asynchronously.
Callback: receive the result
PicoClaw POSTs the result to the callback URL:
POST {callbackUrl}
Authorization: Bearer your-shared-secret
Content-Type: application/json
{
"stackId": "s1",
"conversationId": "c1",
"response": "Here is the summary of the latest sales report...",
"type": "final"
}
| Field | Type | Description |
|---|---|---|
stackId |
string | Echoed from request. |
conversationId |
string | Echoed from request. |
response |
string | The agent's response text. |
type |
string | Always "final". |
Session isolation
Each request gets a unique session key: agent:main:magicform:{stackId}:{conversationId}.
Sessions are stored at {workspace}/sessions/. Different conversations within the same stack share the config directory (API keys, bootstrap files) but have separate workspace directories, sessions, and memory.
Processing flow
MagicForm PicoClaw Gateway
| |
|-- POST /hooks/magicform ----------->|
|<------------ 200 OK ---------------|
| |
| resolveWorkspace(workspace)
| resolveWorkspace(configDir)
| publish InboundMessage to bus
| |
| Agent loop:
| create temp sessions + context
| copyBootstrapFiles(configDir -> workspace)
| loadWorkspaceConfig(configDir)
| mergeWorkspaceConfig into cloned global cfg
| createProvider (per-request)
| apply tool/skill filters
| run LLM iterations
| |
|<-- POST callbackUrl (result) -------|
Testing with CLI
You can test the same workspace/config setup without the gateway using picoclaw agent. See cli.md § picoclaw agent for full flag reference.
# One-shot with tenant isolation (same paths MagicForm would use)
picoclaw agent -m "Summarize the report" \
-s s1:c1 \
--workspace /data/workspaces/s1/c1 \
--config-dir /data/workspaces/s1/config
# Restricted tools, matching a webhook allowedTools filter
picoclaw agent -m "Search the web for recent news" \
--tools web,web_fetch
# Debug mode to see session key, model, and iteration details
picoclaw agent -d -m "Hello" -s test
Troubleshooting
Webhook returns 405 Method Not Allowed
- The endpoint only accepts
POSTrequests. Ensure you are not sending aGETor other method.
Webhook returns 401 Unauthorized
- Check that the
Authorization: Bearer {token}header matches thetokenin the MagicForm channel config. Token comparison uses constant-time comparison.
Webhook returns 400 "workspace path escapes workspace_root"
- The
workspaceorconfigDirpath in the payload resolves outsideworkspace_root. Ensure paths are relative (e.g.s1/c1, not/data/workspaces/s1/c1).
Webhook returns 413 Request Entity Too Large
- The request payload exceeds the 1 MB limit. Reduce the message size.
Webhook returns 400 "workspace_root not configured"
- Set
workspace_rootin the MagicForm channel config.
Callback not received
- Check that
callbackUrlin the payload orbackend_urlin config is reachable from PicoClaw. - Check PicoClaw logs for callback errors.
- Request contexts expire after 10 minutes.
Session not persisting across requests
- Ensure the same
workspacepath is sent for the same conversation. - Sessions are stored at
{workspace}/sessions/. Different workspace paths = different sessions.