feat(docs): update README and add CLI reference and MagicForm integration documentation
This commit is contained in:
parent
ac6e77d7c9
commit
12cab29449
3 changed files with 677 additions and 20 deletions
|
|
@ -3,17 +3,19 @@
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> This project is a temporary solution and will be refactored in the future to provide a complete web service. Therefore, the APIs in this directory are not stable.
|
> This project is a temporary solution and will be refactored in the future to provide a complete web service. Therefore, the APIs in this directory are not stable.
|
||||||
|
|
||||||
A standalone launcher for PicoClaw, providing visual JSON editing and OAuth provider authentication management.
|
A standalone launcher for PicoClaw, providing visual JSON editing, OAuth provider authentication management, and gateway process control.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- 📝 **Config Editor** — Sidebar-based settings UI with model management, channel configuration forms, and a raw JSON editor
|
- 📝 **Config Editor** — Sidebar-based settings UI with model management, channel configuration forms, and a raw JSON editor
|
||||||
- 🤖 **Model Management** — Model card grid with availability status (grayed out without API key), primary model selection, add/edit/delete with required/optional field separation
|
- 🤖 **Model Management** — Model card grid with availability status (grayed out without API key), primary model selection, add/edit/delete with required/optional field separation
|
||||||
- 📡 **Channel Configuration** — Form-based settings for 12 channel types (Telegram, Discord, Slack, WeCom, DingTalk, Feishu, LINE, WhatsApp, QQ, OneBot, MaixCAM, etc.) with documentation links
|
- 📡 **Channel Configuration** — Form-based settings for 12+ channel types (Telegram, Discord, Slack, WeCom, DingTalk, Feishu, LINE, WhatsApp, QQ, OneBot, MaixCAM, MagicForm, etc.) with documentation links
|
||||||
- 🔐 **Provider Auth** — Login to OpenAI (Device Code), Anthropic (API Token), Google Antigravity (Browser OAuth)
|
- 🔐 **Provider Auth** — Login to OpenAI (Device Code), Anthropic (API Token), Google Antigravity (Browser OAuth with PKCE)
|
||||||
|
- 🚀 **Gateway Process Control** — Start, stop, and monitor the `picoclaw gateway` process with live log streaming
|
||||||
- 🌐 **Embedded Frontend** — Compiles to a single binary with no external dependencies
|
- 🌐 **Embedded Frontend** — Compiles to a single binary with no external dependencies
|
||||||
- 🌍 **i18n** — Chinese/English language switching with browser auto-detection
|
- 🌍 **i18n** — Chinese/English language switching with browser auto-detection
|
||||||
- 🎨 **Theme** — Light / Dark / System theme toggle with localStorage persistence
|
- 🎨 **Theme** — Light / Dark / System theme toggle with localStorage persistence
|
||||||
|
- 🔒 **Security Headers** — `X-Content-Type-Options`, `X-Frame-Options`, and `Content-Security-Policy` on all responses
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
|
|
@ -31,12 +33,12 @@ go build -o picoclaw-launcher ./cmd/picoclaw-launcher/
|
||||||
./picoclaw-launcher -public
|
./picoclaw-launcher -public
|
||||||
```
|
```
|
||||||
|
|
||||||
Open `http://localhost:18800` in your browser.
|
The launcher automatically opens `http://localhost:18800` in your default browser on startup.
|
||||||
|
|
||||||
## CLI Options
|
## CLI Options
|
||||||
|
|
||||||
```
|
```
|
||||||
Usage: picoclaw-config [options] [config.json]
|
Usage: picoclaw-launcher [options] [config.json]
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
config.json Path to the configuration file (default: ~/.picoclaw/config.json)
|
config.json Path to the configuration file (default: ~/.picoclaw/config.json)
|
||||||
|
|
@ -45,10 +47,14 @@ Options:
|
||||||
-public Listen on all interfaces (0.0.0.0), allowing access from other devices
|
-public Listen on all interfaces (0.0.0.0), allowing access from other devices
|
||||||
```
|
```
|
||||||
|
|
||||||
|
When `-public` is set, the startup banner also prints the local network IP address for LAN access.
|
||||||
|
|
||||||
## API Reference
|
## API Reference
|
||||||
|
|
||||||
Base URL: `http://localhost:18800`
|
Base URL: `http://localhost:18800`
|
||||||
|
|
||||||
|
Default port: `18800`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Static Files
|
### Static Files
|
||||||
|
|
@ -70,7 +76,7 @@ Reads the current configuration file.
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"config": { ... },
|
"config": { ... },
|
||||||
"path": "/Users/xiao/.picoclaw/config.json"
|
"path": "/home/user/.picoclaw/config.json"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -78,7 +84,7 @@ Reads the current configuration file.
|
||||||
|
|
||||||
#### PUT /api/config
|
#### PUT /api/config
|
||||||
|
|
||||||
Saves the configuration. The request body must be a complete Config JSON object.
|
Saves the configuration. The request body must be a complete Config JSON object (max 1 MB).
|
||||||
|
|
||||||
**Request Body** — `application/json`
|
**Request Body** — `application/json`
|
||||||
|
|
||||||
|
|
@ -122,6 +128,13 @@ Returns the authentication status of all providers and any in-progress device co
|
||||||
"status": "active",
|
"status": "active",
|
||||||
"account_id": "user-xxx",
|
"account_id": "user-xxx",
|
||||||
"expires_at": "2026-03-01T00:00:00Z"
|
"expires_at": "2026-03-01T00:00:00Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"provider": "google-antigravity",
|
||||||
|
"auth_method": "oauth",
|
||||||
|
"status": "active",
|
||||||
|
"email": "user@example.com",
|
||||||
|
"project_id": "projects/123/locations/global/codeAssistModels/default"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"pending_device": {
|
"pending_device": {
|
||||||
|
|
@ -135,7 +148,7 @@ Returns the authentication status of all providers and any in-progress device co
|
||||||
|
|
||||||
`status` values: `active` | `expired` | `needs_refresh`
|
`status` values: `active` | `expired` | `needs_refresh`
|
||||||
|
|
||||||
`pending_device` is only present when a device code login is in progress.
|
`pending_device` is only present when a device code login is in progress. Once completed, it shows `status: "success"` and is cleared on the next poll.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -149,11 +162,11 @@ Initiates a provider login.
|
||||||
{ "provider": "openai" }
|
{ "provider": "openai" }
|
||||||
```
|
```
|
||||||
|
|
||||||
Supported `provider` values: `openai` | `anthropic` | `google-antigravity`
|
Supported `provider` values: `openai` | `anthropic` | `google-antigravity` (alias: `antigravity`)
|
||||||
|
|
||||||
##### OpenAI (Device Code Flow)
|
##### OpenAI (Device Code Flow)
|
||||||
|
|
||||||
Returns device code info. The server polls for completion in the background.
|
Returns device code info. The server polls for completion in the background (15-minute timeout).
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
|
@ -164,7 +177,7 @@ Returns device code info. The server polls for completion in the background.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The user opens `device_url` in a browser and enters `user_code`. Once authenticated, `GET /api/auth/status` will show `pending_device.status` as `success`.
|
The user opens `device_url` in a browser and enters `user_code`. Once authenticated, `GET /api/auth/status` will show `pending_device.status` as `success`. If a device code flow is already in progress, the existing session is returned.
|
||||||
|
|
||||||
##### Anthropic (API Token)
|
##### Anthropic (API Token)
|
||||||
|
|
||||||
|
|
@ -180,7 +193,9 @@ Requires a `token` field in the request:
|
||||||
{ "status": "success", "message": "Anthropic token saved" }
|
{ "status": "success", "message": "Anthropic token saved" }
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Google Antigravity (Browser OAuth)
|
The token is saved to the auth credential store and the config is updated to set `auth_method: "token"` on any Anthropic model entry.
|
||||||
|
|
||||||
|
##### Google Antigravity (Browser OAuth with PKCE)
|
||||||
|
|
||||||
Returns an authorization URL for the frontend to open in a new tab:
|
Returns an authorization URL for the frontend to open in a new tab:
|
||||||
|
|
||||||
|
|
@ -192,7 +207,7 @@ Returns an authorization URL for the frontend to open in a new tab:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
After authentication, Google redirects to `GET /auth/callback`, which saves the credentials and redirects back to the picoclaw-config UI.
|
After authentication, Google redirects to `GET /auth/callback`, which exchanges the authorization code for tokens using PKCE, fetches the user's email and Cloud Code Assist project ID, saves the credentials, and redirects back to the launcher UI at `/#auth`. OAuth sessions expire after 10 minutes if not completed.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -206,7 +221,7 @@ Logs out from a provider.
|
||||||
{ "provider": "openai" }
|
{ "provider": "openai" }
|
||||||
```
|
```
|
||||||
|
|
||||||
Omit or leave `provider` empty to log out from all providers.
|
Omit or leave `provider` empty to log out from all providers. Clears both the auth credential store and `auth_method` fields in the config file.
|
||||||
|
|
||||||
**Response** `200 OK`
|
**Response** `200 OK`
|
||||||
|
|
||||||
|
|
@ -224,14 +239,21 @@ OAuth browser callback endpoint (used by Google Antigravity). Called by the OAut
|
||||||
- `state` — OAuth state for CSRF validation
|
- `state` — OAuth state for CSRF validation
|
||||||
- `code` — Authorization code
|
- `code` — Authorization code
|
||||||
|
|
||||||
On success, redirects to `/#auth`.
|
On success, redirects to `/#auth`. On failure, displays an error page.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Process API
|
### Process API
|
||||||
|
|
||||||
#### GET /api/process/status
|
#### GET /api/process/status
|
||||||
|
|
||||||
Gets the running status of the `picoclaw gateway` process.
|
Gets the running status of the `picoclaw gateway` process by probing its health endpoint.
|
||||||
|
|
||||||
|
The gateway address is read from the config file (`gateway.host` and `gateway.port`, default `127.0.0.1:18790`).
|
||||||
|
|
||||||
|
**Query Parameters** (optional, for incremental log streaming):
|
||||||
|
- `log_offset` — Last received log line index (0-based)
|
||||||
|
- `log_run_id` — Run ID from previous response (detects gateway restarts)
|
||||||
|
|
||||||
**Response** `200 OK` (Running)
|
**Response** `200 OK` (Running)
|
||||||
|
|
||||||
|
|
@ -239,7 +261,11 @@ Gets the running status of the `picoclaw gateway` process.
|
||||||
{
|
{
|
||||||
"process_status": "running",
|
"process_status": "running",
|
||||||
"status": "ok",
|
"status": "ok",
|
||||||
"uptime": "1.010814s"
|
"uptime": "1.010814s",
|
||||||
|
"logs": ["[INFO] Gateway started on :18790", "..."],
|
||||||
|
"log_total": 42,
|
||||||
|
"log_run_id": 1,
|
||||||
|
"log_source": "launcher"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -248,15 +274,23 @@ Gets the running status of the `picoclaw gateway` process.
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"process_status": "stopped",
|
"process_status": "stopped",
|
||||||
"error": "Get \"http://localhost:18790/health\": dial tcp [::1]:18790: connect: connection refused"
|
"error": "Get \"http://localhost:18790/health\": dial tcp [::1]:18790: connect: connection refused",
|
||||||
|
"logs": [],
|
||||||
|
"log_total": 0,
|
||||||
|
"log_run_id": 0,
|
||||||
|
"log_source": "none"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`log_source` values: `launcher` (logs captured from a process started by the launcher) | `none` (no log source available, e.g. gateway started externally or never launched)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### POST /api/process/start
|
#### POST /api/process/start
|
||||||
|
|
||||||
Starts the `picoclaw gateway` process in the background.
|
Starts the `picoclaw gateway` process in the background. The launcher looks for the `picoclaw` binary first in the same directory as itself, then falls back to `$PATH`.
|
||||||
|
|
||||||
|
Stdout and stderr from the gateway process are captured into a ring buffer (200 lines) and can be streamed via `GET /api/process/status`.
|
||||||
|
|
||||||
**Response** `200 OK`
|
**Response** `200 OK`
|
||||||
|
|
||||||
|
|
@ -273,6 +307,8 @@ Starts the `picoclaw gateway` process in the background.
|
||||||
|
|
||||||
Stops the running `picoclaw gateway` process.
|
Stops the running `picoclaw gateway` process.
|
||||||
|
|
||||||
|
On Linux/macOS, uses `pkill -f "picoclaw gateway"`. On Windows, uses PowerShell to find and stop matching processes.
|
||||||
|
|
||||||
**Response** `200 OK`
|
**Response** `200 OK`
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|
@ -286,5 +322,5 @@ Stops the running `picoclaw gateway` process.
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go test -v ./cmd/picoclaw-launcher/
|
go test -v ./cmd/picoclaw-launcher/...
|
||||||
```
|
```
|
||||||
|
|
|
||||||
367
docs/cli.md
Normal file
367
docs/cli.md
Normal file
|
|
@ -0,0 +1,367 @@
|
||||||
|
# PicoClaw CLI Reference
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go install github.com/nuestra-ai/picoclaw/cmd/picoclaw@latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## Global Config
|
||||||
|
|
||||||
|
Create `~/.picoclaw/config.json` (or set `PICOCLAW_CONFIG` env var):
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
{
|
||||||
|
"model_list": [
|
||||||
|
{
|
||||||
|
"model_name": "main",
|
||||||
|
"model": "anthropic/claude-sonnet-4.6",
|
||||||
|
"api_key": "sk-ant-...",
|
||||||
|
"api_base": "https://api.anthropic.com/v1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"agents": {
|
||||||
|
"defaults": {
|
||||||
|
"model_name": "main",
|
||||||
|
"max_tokens": 4096,
|
||||||
|
"max_tool_iterations": 20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The global config is the base. Per-workspace configs overlay it (see [Workspace Config](#workspace-config)).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Subcommands
|
||||||
|
|
||||||
|
| Command | Alias | Description |
|
||||||
|
|---------|-------|-------------|
|
||||||
|
| `picoclaw agent` | | Interact with the agent (interactive REPL or one-shot) |
|
||||||
|
| `picoclaw gateway` | `g` | Start the HTTP gateway server |
|
||||||
|
| `picoclaw auth` | | Manage authentication (login, logout, status, models) |
|
||||||
|
| `picoclaw cron` | `c` | Manage scheduled tasks |
|
||||||
|
| `picoclaw skills` | | Manage skills (list, install, remove, search) |
|
||||||
|
| `picoclaw status` | | Show current status |
|
||||||
|
| `picoclaw migrate` | | Migrate config/workspace from another installation |
|
||||||
|
| `picoclaw onboard` | | Interactive first-run setup |
|
||||||
|
| `picoclaw version` | | Print version |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## picoclaw agent
|
||||||
|
|
||||||
|
Interact with the agent directly. Without `-m`, starts an interactive REPL. With `-m`, sends a single message and exits.
|
||||||
|
|
||||||
|
### Flags
|
||||||
|
|
||||||
|
| Flag | Short | Default | Description |
|
||||||
|
|------|-------|---------|-------------|
|
||||||
|
| `--message` | `-m` | | Single message (non-interactive). Omit for interactive REPL. |
|
||||||
|
| `--session` | `-s` | `""` (→ `agent:main:cli:default`) | Session key for conversation isolation (e.g. `stackId:conversationId`). |
|
||||||
|
| `--model` | | | Override model name from config. |
|
||||||
|
| `--workspace` | | | Override agent workspace directory. |
|
||||||
|
| `--config-dir` | | | Directory containing `config.json` (model/agent/tool overrides) and bootstrap files (`AGENTS.md`, `IDENTITY.md`, `SOUL.md`, `USER.md`). |
|
||||||
|
| `--tools` | | | Comma-separated tool allowlist (e.g. `read_file,web_fetch`). Only these tools are enabled. |
|
||||||
|
| `--skills` | | | Comma-separated skill filter (e.g. `summarize,translate`). Only these skills are loaded. |
|
||||||
|
| `--debug` | `-d` | `false` | Enable debug logging. |
|
||||||
|
|
||||||
|
### Config Precedence (highest wins)
|
||||||
|
|
||||||
|
```
|
||||||
|
CLI flags (--model, --tools, --skills, --workspace)
|
||||||
|
> config-dir/config.json
|
||||||
|
> ~/.picoclaw/config.json
|
||||||
|
> defaults
|
||||||
|
```
|
||||||
|
|
||||||
|
### Session Key Formatting
|
||||||
|
|
||||||
|
The `--session` value is automatically prefixed:
|
||||||
|
|
||||||
|
| Input | Resulting key |
|
||||||
|
|-------|--------------|
|
||||||
|
| _(empty)_ | `agent:main:cli:default` |
|
||||||
|
| `s1:c1` | `agent:main:cli:s1:c1` |
|
||||||
|
| `my-project` | `agent:main:cli:my-project` |
|
||||||
|
| `agent:custom:key` | `agent:custom:key` (used as-is) |
|
||||||
|
|
||||||
|
Session files are stored at `{workspace}/sessions/{sanitized_key}.json`.
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Interactive mode with default session
|
||||||
|
picoclaw agent
|
||||||
|
|
||||||
|
# One-shot message
|
||||||
|
picoclaw agent -m "Hello, world"
|
||||||
|
|
||||||
|
# With workspace isolation
|
||||||
|
picoclaw agent -m "Summarize the report" \
|
||||||
|
-s tenant1:conv42 \
|
||||||
|
--workspace /data/workspaces/tenant1/conv42 \
|
||||||
|
--config-dir /data/workspaces/tenant1/config
|
||||||
|
|
||||||
|
# Restricted tools, custom model
|
||||||
|
picoclaw agent -m "Search the web for recent news" \
|
||||||
|
--tools web,web_fetch \
|
||||||
|
--model gpt-5.2
|
||||||
|
|
||||||
|
# Debug mode to see session key, model, and iteration details
|
||||||
|
picoclaw agent -d -m "Hello" -s test
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## picoclaw gateway
|
||||||
|
|
||||||
|
Start the HTTP gateway server. Channels (Telegram, Discord, MagicForm, etc.) receive messages via webhooks and respond asynchronously.
|
||||||
|
|
||||||
|
| Flag | Short | Default | Description |
|
||||||
|
|------|-------|---------|-------------|
|
||||||
|
| `--debug` | `-d` | `false` | Enable debug logging. |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
picoclaw gateway
|
||||||
|
# or with debug logging:
|
||||||
|
picoclaw gateway -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Listens on `{gateway.host}:{gateway.port}` from the config (default `127.0.0.1:18790`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## picoclaw auth
|
||||||
|
|
||||||
|
Manage provider authentication.
|
||||||
|
|
||||||
|
### picoclaw auth login
|
||||||
|
|
||||||
|
```bash
|
||||||
|
picoclaw auth login -p <provider>
|
||||||
|
```
|
||||||
|
|
||||||
|
| Flag | Short | Default | Description |
|
||||||
|
|------|-------|---------|-------------|
|
||||||
|
| `--provider` | `-p` | _(required)_ | Provider: `openai`, `anthropic`, `google-antigravity` |
|
||||||
|
| `--device-code` | | `false` | Use device code flow for headless environments (OpenAI) |
|
||||||
|
| `--setup-token` | | `false` | Use setup-token flow for Anthropic (from `claude setup-token`) |
|
||||||
|
|
||||||
|
**Anthropic login** prompts to choose between:
|
||||||
|
1. **Setup token** (recommended) — paste a token from `claude setup-token`
|
||||||
|
2. **API key** — paste an `sk-ant-...` key from console.anthropic.com
|
||||||
|
|
||||||
|
Use `--setup-token` to skip the prompt and go directly to option 1.
|
||||||
|
|
||||||
|
**OpenAI login** uses browser-based OAuth by default, or `--device-code` for headless environments.
|
||||||
|
|
||||||
|
**Google Antigravity login** uses browser-based OAuth with PKCE. Also fetches user email and Cloud Code Assist project ID.
|
||||||
|
|
||||||
|
### picoclaw auth logout
|
||||||
|
|
||||||
|
```bash
|
||||||
|
picoclaw auth logout [-p <provider>]
|
||||||
|
```
|
||||||
|
|
||||||
|
| Flag | Short | Default | Description |
|
||||||
|
|------|-------|---------|-------------|
|
||||||
|
| `--provider` | `-p` | `""` (all) | Provider to logout from. Empty = logout from all. |
|
||||||
|
|
||||||
|
### picoclaw auth status
|
||||||
|
|
||||||
|
```bash
|
||||||
|
picoclaw auth status
|
||||||
|
```
|
||||||
|
|
||||||
|
Shows all authenticated providers with method, status, account info, and expiry. For Anthropic OAuth credentials, also displays 5-hour and 7-day usage percentages.
|
||||||
|
|
||||||
|
### picoclaw auth models
|
||||||
|
|
||||||
|
```bash
|
||||||
|
picoclaw auth models
|
||||||
|
```
|
||||||
|
|
||||||
|
Lists available models for Google Antigravity (requires prior login). Shows model ID, display name, and quota status.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## picoclaw cron
|
||||||
|
|
||||||
|
Manage scheduled tasks.
|
||||||
|
|
||||||
|
### picoclaw cron list
|
||||||
|
|
||||||
|
```bash
|
||||||
|
picoclaw cron list
|
||||||
|
```
|
||||||
|
|
||||||
|
### picoclaw cron add
|
||||||
|
|
||||||
|
```bash
|
||||||
|
picoclaw cron add -n <name> -m <message> (--every <seconds> | --cron <expr>)
|
||||||
|
```
|
||||||
|
|
||||||
|
| Flag | Short | Default | Description |
|
||||||
|
|------|-------|---------|-------------|
|
||||||
|
| `--name` | `-n` | _(required)_ | Job name |
|
||||||
|
| `--message` | `-m` | _(required)_ | Message for the agent |
|
||||||
|
| `--every` | `-e` | | Run every N seconds |
|
||||||
|
| `--cron` | `-c` | | Cron expression (e.g. `0 9 * * *`) |
|
||||||
|
| `--deliver` | `-d` | `false` | Deliver response to a channel |
|
||||||
|
| `--channel` | | | Channel for delivery |
|
||||||
|
| `--to` | | | Recipient for delivery |
|
||||||
|
|
||||||
|
`--every` and `--cron` are mutually exclusive; one is required.
|
||||||
|
|
||||||
|
### picoclaw cron remove / enable / disable
|
||||||
|
|
||||||
|
```bash
|
||||||
|
picoclaw cron remove <job-id>
|
||||||
|
picoclaw cron enable <job-id>
|
||||||
|
picoclaw cron disable <job-id>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## picoclaw skills
|
||||||
|
|
||||||
|
Manage skills (install, remove, list, search).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
picoclaw skills list # List installed skills
|
||||||
|
picoclaw skills list-builtin # List built-in skills
|
||||||
|
picoclaw skills install <url> # Install from URL or local path
|
||||||
|
picoclaw skills install-builtin # Install built-in skills to workspace
|
||||||
|
picoclaw skills remove <name> # Remove an installed skill
|
||||||
|
picoclaw skills search <query> # Search skill registries
|
||||||
|
picoclaw skills show <name> # Show skill details
|
||||||
|
```
|
||||||
|
|
||||||
|
The `install` command also supports `--registry <name> <slug>` to install from a named registry.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## picoclaw migrate
|
||||||
|
|
||||||
|
Migrate config and workspace from another installation (e.g. OpenClaw).
|
||||||
|
|
||||||
|
| Flag | Default | Description |
|
||||||
|
|------|---------|-------------|
|
||||||
|
| `--from` | `openclaw` | Source to migrate from |
|
||||||
|
| `--dry-run` | `false` | Preview changes without applying |
|
||||||
|
| `--refresh` | `false` | Re-run migration (overwrite existing) |
|
||||||
|
| `--config-only` | `false` | Migrate config only |
|
||||||
|
| `--workspace-only` | `false` | Migrate workspace only |
|
||||||
|
| `--force` | `false` | Overwrite existing files |
|
||||||
|
| `--source-home` | | Custom source home directory |
|
||||||
|
| `--target-home` | | Custom target home directory |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Workspace Config
|
||||||
|
|
||||||
|
A workspace-level `config.json` (placed in the config directory) overlays the global config. Only these fields are honored:
|
||||||
|
|
||||||
|
| Field | Behavior | Required? |
|
||||||
|
|-------|----------|-----------|
|
||||||
|
| `model_list` | Replaces global model_list | Yes, if using a different API key |
|
||||||
|
| `agents.defaults` | Merges non-zero fields (model_name, max_tokens, temperature, etc.) | No |
|
||||||
|
| `agents.list` | Replaces global agents list | No |
|
||||||
|
| `tools` | Merges only keys present in the file (unmentioned tools are not affected) | No |
|
||||||
|
| `session` | Merges non-zero fields (dm_scope, identity_links) | No |
|
||||||
|
| `bindings` | Replaces global bindings | No |
|
||||||
|
|
||||||
|
**Not honored** (infrastructure-level): `gateway`, `heartbeat`, `devices`, `providers`, `channels`.
|
||||||
|
|
||||||
|
Example `config.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"model_list": [
|
||||||
|
{
|
||||||
|
"model_name": "main",
|
||||||
|
"model": "anthropic/claude-sonnet-4.6",
|
||||||
|
"api_key": "sk-ant-tenant-key",
|
||||||
|
"api_base": "https://api.anthropic.com/v1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"agents": {
|
||||||
|
"defaults": {
|
||||||
|
"model_name": "main",
|
||||||
|
"max_tokens": 4096,
|
||||||
|
"temperature": 0.7
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tools": {
|
||||||
|
"exec": { "enabled": false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Directory Layout
|
||||||
|
|
||||||
|
PicoClaw uses the following workspace directory structure for per-tenant/per-conversation isolation:
|
||||||
|
|
||||||
|
```
|
||||||
|
{workspace_root}/
|
||||||
|
{stackId}/
|
||||||
|
config/ # configDir -- shared per-stack
|
||||||
|
config.json # API key, model, agent settings
|
||||||
|
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)
|
||||||
|
```
|
||||||
|
|
||||||
|
The config directory contains shared settings (API keys, bootstrap files) for all conversations in a stack. Each conversation gets its own workspace directory with isolated sessions and memory.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tool Names Reference
|
||||||
|
|
||||||
|
For `--tools` (CLI) or `allowedTools` (webhook API):
|
||||||
|
|
||||||
|
| Tool name | Description |
|
||||||
|
|-----------|-------------|
|
||||||
|
| `read_file` | Read files from workspace |
|
||||||
|
| `write_file` | Write files to workspace |
|
||||||
|
| `edit_file` | Edit files in workspace |
|
||||||
|
| `append_file` | Append to files in workspace |
|
||||||
|
| `list_dir` | List directory contents |
|
||||||
|
| `exec` | Execute shell commands |
|
||||||
|
| `spawn` | Spawn background processes |
|
||||||
|
| `cron` | Schedule recurring tasks |
|
||||||
|
| `web` | Web search (DuckDuckGo, Brave, etc.) |
|
||||||
|
| `web_fetch` | Fetch and parse web pages |
|
||||||
|
| `skills` | Run installed skills |
|
||||||
|
| `find_skills` | Search skill registries |
|
||||||
|
| `install_skill` | Install skills from registry |
|
||||||
|
| `subagent` | Spawn sub-agents |
|
||||||
|
| `message` | Send messages to channels |
|
||||||
|
| `mcp` | Model Context Protocol tools |
|
||||||
|
| `i2c` | I2C hardware bus (Linux only) |
|
||||||
|
| `spi` | SPI hardware bus (Linux only) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
**Workspace config ignored**
|
||||||
|
- Verify `config.json` exists in the `--config-dir` path.
|
||||||
|
- Check that the JSON is valid (`picoclaw agent -d` shows parse errors).
|
||||||
|
- Only allowed fields are merged. `gateway`, `heartbeat`, `devices`, `providers` are ignored.
|
||||||
|
|
||||||
|
**Tools unexpectedly disabled**
|
||||||
|
- Workspace `config.json` only affects tools explicitly mentioned. If you set `{"tools": {"exec": {"enabled": false}}}`, only `exec` is disabled; all other tools keep their global config values.
|
||||||
|
|
||||||
|
**Session not persisting**
|
||||||
|
- Ensure the same `--workspace` path is used for the same conversation.
|
||||||
|
- Sessions are stored at `{workspace}/sessions/`. Different workspace paths = different sessions.
|
||||||
254
docs/magicform-integration.md
Normal file
254
docs/magicform-integration.md
Normal file
|
|
@ -0,0 +1,254 @@
|
||||||
|
# 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](cli.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pre-requisites
|
||||||
|
|
||||||
|
1. **Install PicoClaw** — see [cli.md § Install](cli.md#install)
|
||||||
|
2. **Global config** — see [cli.md § Global Config](cli.md#global-config)
|
||||||
|
|
||||||
|
### Directory layout
|
||||||
|
|
||||||
|
MagicForm pre-provisions directories on disk before calling PicoClaw (see [cli.md § Directory Layout](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](cli.md#workspace-config) for merge rules and example.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Gateway Mode
|
||||||
|
|
||||||
|
### Channel config
|
||||||
|
|
||||||
|
Add to `~/.picoclaw/config.json`:
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
{
|
||||||
|
"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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"status": "ok", "channel": "magicform"}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Webhook: send a message
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /hooks/magicform
|
||||||
|
Authorization: Bearer your-shared-secret
|
||||||
|
Content-Type: application/json
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Request body
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"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](cli.md#tool-names-reference). |
|
||||||
|
| `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
|
||||||
|
```
|
||||||
|
|
||||||
|
```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](cli.md#picoclaw-agent) for full flag reference.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 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 `POST` requests. Ensure you are not sending a `GET` or other method.
|
||||||
|
|
||||||
|
**Webhook returns 401 Unauthorized**
|
||||||
|
- Check that the `Authorization: Bearer {token}` header matches the `token` in the MagicForm channel config. Token comparison uses constant-time comparison.
|
||||||
|
|
||||||
|
**Webhook returns 400 "workspace path escapes workspace_root"**
|
||||||
|
- The `workspace` or `configDir` path in the payload resolves outside `workspace_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_root` in the MagicForm channel config.
|
||||||
|
|
||||||
|
**Callback not received**
|
||||||
|
- Check that `callbackUrl` in the payload or `backend_url` in 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 `workspace` path is sent for the same conversation.
|
||||||
|
- Sessions are stored at `{workspace}/sessions/`. Different workspace paths = different sessions.
|
||||||
Loading…
Add table
Reference in a new issue