mirror of
https://github.com/openclaw/lobster.git
synced 2026-08-14 00:48:09 +00:00
docs: rename Clawdbot/Moltbot references to OpenClaw
This commit is contained in:
@@ -1,20 +1,20 @@
|
|||||||
# Lobster
|
# Lobster
|
||||||
|
|
||||||
A Moltbot-native workflow shell: typed (JSON-first) pipelines, jobs, and approval gates.
|
An OpenClaw-native workflow shell: typed (JSON-first) pipelines, jobs, and approval gates.
|
||||||
|
|
||||||
|
|
||||||
## Example of lobster at work
|
## Example of Lobster at work
|
||||||
Moltbot or any other AI agent can use `lobster` as a workflow engine and not construct a query every time - thus saving tokens, providing room for determinism, and resumability.
|
OpenClaw (or any other AI agent) can use `lobster` as a workflow engine and avoid re-planning every step — saving tokens while improving determinism and resumability.
|
||||||
|
|
||||||
### Watching a PR that hasn't had changes
|
### Watching a PR that hasn't had changes
|
||||||
```
|
```
|
||||||
node bin/lobster.js "workflows.run --name github.pr.monitor --args-json '{\"repo\":\"moltbot/moltbot\",\"pr\":1152}'"
|
node bin/lobster.js "workflows.run --name github.pr.monitor --args-json '{\"repo\":\"openclaw/openclaw\",\"pr\":1152}'"
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"kind": "github.pr.monitor",
|
"kind": "github.pr.monitor",
|
||||||
"repo": "moltbot/moltbot",
|
"repo": "openclaw/openclaw",
|
||||||
"prNumber": 1152,
|
"prNumber": 1152,
|
||||||
"key": "github.pr:moltbot/moltbot#1152",
|
"key": "github.pr:openclaw/openclaw#1152",
|
||||||
"changed": false,
|
"changed": false,
|
||||||
"summary": {
|
"summary": {
|
||||||
"changedFields": [],
|
"changedFields": [],
|
||||||
@@ -36,7 +36,7 @@ node bin/lobster.js "workflows.run --name github.pr.monitor --args-json '{\"repo
|
|||||||
"state": "OPEN",
|
"state": "OPEN",
|
||||||
"title": "feat: Add optional lobster plugin tool (typed workflows, approvals/resume)",
|
"title": "feat: Add optional lobster plugin tool (typed workflows, approvals/resume)",
|
||||||
"updatedAt": "2026-01-18T20:16:56Z",
|
"updatedAt": "2026-01-18T20:16:56Z",
|
||||||
"url": "https://github.com/moltbot/moltbot/pull/1152"
|
"url": "https://github.com/openclaw/openclaw/pull/1152"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -44,13 +44,13 @@ node bin/lobster.js "workflows.run --name github.pr.monitor --args-json '{\"repo
|
|||||||
### And a PR that has a state change (in this case an approved PR)
|
### And a PR that has a state change (in this case an approved PR)
|
||||||
|
|
||||||
```
|
```
|
||||||
node bin/lobster.js "workflows.run --name github.pr.monitor --args-json '{\"repo\":\"moltbot/moltbot\",\"pr\":1200}'"
|
node bin/lobster.js "workflows.run --name github.pr.monitor --args-json '{\"repo\":\"openclaw/openclaw\",\"pr\":1200}'"
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"kind": "github.pr.monitor",
|
"kind": "github.pr.monitor",
|
||||||
"repo": "moltbot/moltbot",
|
"repo": "openclaw/openclaw",
|
||||||
"prNumber": 1200,
|
"prNumber": 1200,
|
||||||
"key": "github.pr:moltbot/moltbot#1200",
|
"key": "github.pr:openclaw/openclaw#1200",
|
||||||
"changed": true,
|
"changed": true,
|
||||||
"summary": {
|
"summary": {
|
||||||
"changedFields": [
|
"changedFields": [
|
||||||
@@ -76,7 +76,7 @@ node bin/lobster.js "workflows.run --name github.pr.monitor --args-json '{\"repo
|
|||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
"from": null,
|
"from": null,
|
||||||
"to": "https://github.com/moltbot/moltbot/pull/1200"
|
"to": "https://github.com/openclaw/openclaw/pull/1200"
|
||||||
},
|
},
|
||||||
"state": {
|
"state": {
|
||||||
"from": null,
|
"from": null,
|
||||||
@@ -124,7 +124,7 @@ node bin/lobster.js "workflows.run --name github.pr.monitor --args-json '{\"repo
|
|||||||
"state": "MERGED",
|
"state": "MERGED",
|
||||||
"title": "feat(tui): add syntax highlighting for code blocks",
|
"title": "feat(tui): add syntax highlighting for code blocks",
|
||||||
"updatedAt": "2026-01-19T05:06:09Z",
|
"updatedAt": "2026-01-19T05:06:09Z",
|
||||||
"url": "https://github.com/moltbot/moltbot/pull/1200"
|
"url": "https://github.com/openclaw/openclaw/pull/1200"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -136,7 +136,7 @@ node bin/lobster.js "workflows.run --name github.pr.monitor --args-json '{\"repo
|
|||||||
- Typed pipelines (objects/arrays), not text pipes.
|
- Typed pipelines (objects/arrays), not text pipes.
|
||||||
- Local-first execution.
|
- Local-first execution.
|
||||||
- No new auth surface: Lobster must not own OAuth/tokens.
|
- No new auth surface: Lobster must not own OAuth/tokens.
|
||||||
- Composable macros that Moltbot can invoke in one step to save tokens.
|
- Composable macros that OpenClaw (or any agent) can invoke in one step to save tokens.
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
|
|
||||||
@@ -159,11 +159,11 @@ From this folder:
|
|||||||
- `exec --stdin raw|json|jsonl`: feed pipeline input into subprocess stdin
|
- `exec --stdin raw|json|jsonl`: feed pipeline input into subprocess stdin
|
||||||
- `where`, `pick`, `head`: data shaping
|
- `where`, `pick`, `head`: data shaping
|
||||||
- `json`, `table`: renderers
|
- `json`, `table`: renderers
|
||||||
- `approve`: approval gate (TTY prompt or `--emit` for Moltbot integration)
|
- `approve`: approval gate (TTY prompt or `--emit` for OpenClaw integration)
|
||||||
|
|
||||||
## Next steps
|
## Next steps
|
||||||
|
|
||||||
- Moltbot integration: ship as an optional Moltbot plugin tool.
|
- OpenClaw integration: ship as an optional OpenClaw plugin tool.
|
||||||
|
|
||||||
## Workflow files
|
## Workflow files
|
||||||
|
|
||||||
|
|||||||
@@ -2,26 +2,26 @@
|
|||||||
|
|
||||||
## One-liner
|
## One-liner
|
||||||
|
|
||||||
**Lobster is safe automation for Clawdbot — workflows that ask before acting.**
|
**Lobster is safe automation for OpenClaw — workflows that ask before acting.**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## What is Lobster?
|
## What is Lobster?
|
||||||
|
|
||||||
Lobster is a workflow runtime for Clawdbot. It lets you define multi-step automations that:
|
Lobster is a workflow runtime for OpenClaw. It lets you define multi-step automations that:
|
||||||
|
|
||||||
- Run deterministically (no LLM re-planning each step)
|
- Run deterministically (no LLM re-planning each step)
|
||||||
- Halt at checkpoints and ask for approval before side effects
|
- Halt at checkpoints and ask for approval before side effects
|
||||||
- Resume exactly where they left off
|
- Resume exactly where they left off
|
||||||
- Remember what they've already processed
|
- Remember what they've already processed
|
||||||
|
|
||||||
Think of it as **IFTTT/Zapier for Clawdbot, but with human checkpoints**.
|
Think of it as **IFTTT/Zapier for OpenClaw, but with human checkpoints**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## The Problem Lobster Solves
|
## The Problem Lobster Solves
|
||||||
|
|
||||||
### Today's workflow in Clawdbot
|
### Today's workflow in OpenClaw
|
||||||
|
|
||||||
```
|
```
|
||||||
User: "Check my email, draft replies to anything urgent, and send them"
|
User: "Check my email, draft replies to anything urgent, and send them"
|
||||||
@@ -46,7 +46,7 @@ What happens:
|
|||||||
### With Lobster
|
### With Lobster
|
||||||
|
|
||||||
```
|
```
|
||||||
Clawdbot calls: lobster.run("email.triage")
|
OpenClaw calls: lobster.run("email.triage")
|
||||||
|
|
||||||
What happens:
|
What happens:
|
||||||
1. Lobster fetches emails (deterministic)
|
1. Lobster fetches emails (deterministic)
|
||||||
@@ -63,7 +63,7 @@ Tomorrow: Lobster remembers cursor, only processes new emails
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Why Lobster Makes Clawdbot Better
|
## Why Lobster Makes OpenClaw Better
|
||||||
|
|
||||||
| Without Lobster | With Lobster |
|
| Without Lobster | With Lobster |
|
||||||
|-----------------|--------------|
|
|-----------------|--------------|
|
||||||
@@ -85,7 +85,7 @@ Workflows can persist state: "last processed email ID", "last PR SHA seen", etc.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## How Lobster Fits with Clawdbot
|
## How Lobster Fits with OpenClaw
|
||||||
|
|
||||||
```
|
```
|
||||||
┌─────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────┐
|
||||||
@@ -95,7 +95,7 @@ Workflows can persist state: "last processed email ID", "last PR SHA seen", etc.
|
|||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
┌─────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────┐
|
||||||
│ Clawdbot │
|
│ OpenClaw │
|
||||||
│ - Understands intent │
|
│ - Understands intent │
|
||||||
│ - Chooses appropriate tool/workflow │
|
│ - Chooses appropriate tool/workflow │
|
||||||
│ - Presents results and approval prompts │
|
│ - Presents results and approval prompts │
|
||||||
@@ -105,15 +105,15 @@ Workflows can persist state: "last processed email ID", "last PR SHA seen", etc.
|
|||||||
┌─────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────┐
|
||||||
│ Lobster │
|
│ Lobster │
|
||||||
│ - Executes deterministic pipeline │
|
│ - Executes deterministic pipeline │
|
||||||
│ - Calls Clawdbot tools (gmail, trello, etc) │
|
│ - Calls OpenClaw tools (gmail, trello, etc) │
|
||||||
│ - Halts at approval checkpoints │
|
│ - Halts at approval checkpoints │
|
||||||
│ - Returns structured result + resume token │
|
│ - Returns structured result + resume token │
|
||||||
└─────────────────────────────────────────────────┘
|
└─────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
**Key insight:** Lobster doesn't replace Clawdbot. It's the execution layer that makes Clawdbot's automations safe and efficient.
|
**Key insight:** Lobster doesn't replace OpenClaw. It's the execution layer that makes OpenClaw's automations safe and efficient.
|
||||||
|
|
||||||
- **Clawdbot** = the brain (understands what you want)
|
- **OpenClaw** = the brain (understands what you want)
|
||||||
- **Lobster** = the hands (executes workflows safely)
|
- **Lobster** = the hands (executes workflows safely)
|
||||||
- **Tools/Skills** = the capabilities (gmail, trello, github, etc.)
|
- **Tools/Skills** = the capabilities (gmail, trello, github, etc.)
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ Workflows can persist state: "last processed email ID", "last PR SHA seen", etc.
|
|||||||
|
|
||||||
## Who Should Use Lobster?
|
## Who Should Use Lobster?
|
||||||
|
|
||||||
### Average Clawdbot users (invisible benefit)
|
### Average OpenClaw users (invisible benefit)
|
||||||
They don't need to know Lobster exists. They just notice:
|
They don't need to know Lobster exists. They just notice:
|
||||||
- "Set up daily email triage" works better
|
- "Set up daily email triage" works better
|
||||||
- Automations ask before sending/posting
|
- Automations ask before sending/posting
|
||||||
@@ -133,7 +133,7 @@ They can:
|
|||||||
- Write new workflows for their specific needs
|
- Write new workflows for their specific needs
|
||||||
- Share workflows with the community
|
- Share workflows with the community
|
||||||
|
|
||||||
### The Clawdbot ecosystem
|
### The OpenClaw ecosystem
|
||||||
- Workflow recipes become a new category of shareable assets
|
- Workflow recipes become a new category of shareable assets
|
||||||
- Skills stay simple (just expose APIs)
|
- Skills stay simple (just expose APIs)
|
||||||
- Lobster handles the orchestration layer
|
- Lobster handles the orchestration layer
|
||||||
@@ -151,21 +151,21 @@ They can:
|
|||||||
| Temporal | But 80/20 version for personal workflows |
|
| Temporal | But 80/20 version for personal workflows |
|
||||||
|
|
||||||
**Best analogy for most people:**
|
**Best analogy for most people:**
|
||||||
> "Lobster is Zapier for Clawdbot, except it asks you before doing anything irreversible."
|
> "Lobster is Zapier for OpenClaw, except it asks you before doing anything irreversible."
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Why Not Build This Into Clawdbot Core?
|
## Why Not Build This Into OpenClaw Core?
|
||||||
|
|
||||||
It could be. But the plugin architecture is intentional:
|
It could be. But the plugin architecture is intentional:
|
||||||
|
|
||||||
1. **Core stays small** — Clawdbot is already complex
|
1. **Core stays small** — OpenClaw is already complex
|
||||||
2. **Faster iteration** — Lobster can evolve without core releases
|
2. **Faster iteration** — Lobster can evolve without core releases
|
||||||
3. **Opt-in** — Not everyone needs workflow automation
|
3. **Opt-in** — Not everyone needs workflow automation
|
||||||
4. **Community** — Easier to contribute workflows than core changes
|
4. **Community** — Easier to contribute workflows than core changes
|
||||||
5. **Ecosystem proof** — If plugins work for Lobster, they work for other capabilities
|
5. **Ecosystem proof** — If plugins work for Lobster, they work for other capabilities
|
||||||
|
|
||||||
Pete (Clawdbot creator) explicitly built the plugin boundary to enable this pattern. Lobster is the first proof that it works.
|
OpenClaw explicitly provides a plugin boundary to enable this pattern. Lobster is the first proof that it works.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -221,9 +221,9 @@ Other automation tools either:
|
|||||||
- Don't integrate with your AI assistant
|
- Don't integrate with your AI assistant
|
||||||
|
|
||||||
Lobster is:
|
Lobster is:
|
||||||
- Native to Clawdbot (uses the same tools you already have)
|
- Native to OpenClaw (uses the same tools you already have)
|
||||||
- Safe by default (approvals are a language primitive)
|
- Safe by default (approvals are a language primitive)
|
||||||
- Invisible when you want (Clawdbot uses it automatically)
|
- Invisible when you want (OpenClaw uses it automatically)
|
||||||
- Customizable when you need (write your own workflows)
|
- Customizable when you need (write your own workflows)
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -232,8 +232,8 @@ Lobster is:
|
|||||||
|
|
||||||
- **Not a terminal replacement** — You don't switch your shell to Lobster
|
- **Not a terminal replacement** — You don't switch your shell to Lobster
|
||||||
- **Not a general programming language** — It's for workflows, not apps
|
- **Not a general programming language** — It's for workflows, not apps
|
||||||
- **Not trying to replace Clawdbot** — It makes Clawdbot better
|
- **Not trying to replace OpenClaw** — It makes OpenClaw better
|
||||||
- **Not managing your secrets** — Clawdbot handles auth, Lobster orchestrates
|
- **Not managing your secrets** — OpenClaw handles auth, Lobster orchestrates
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -241,9 +241,9 @@ Lobster is:
|
|||||||
|
|
||||||
| Question | Answer |
|
| Question | Answer |
|
||||||
|----------|--------|
|
|----------|--------|
|
||||||
| What is it? | Workflow runtime for Clawdbot |
|
| What is it? | Workflow runtime for OpenClaw |
|
||||||
| One-liner? | Safe automation — workflows that ask before acting |
|
| One-liner? | Safe automation — workflows that ask before acting |
|
||||||
| Why use it? | Cheaper, safer, stateful automations |
|
| Why use it? | Cheaper, safer, stateful automations |
|
||||||
| Who uses it? | Everyone (invisibly) or power users (directly) |
|
| Who uses it? | Everyone (invisibly) or power users (directly) |
|
||||||
| Why not in core? | Plugin architecture — core stays small, capabilities are extensions |
|
| Why not in core? | Plugin architecture — core stays small, capabilities are extensions |
|
||||||
| Best analogy? | Zapier for Clawdbot, but with approval checkpoints |
|
| Best analogy? | Zapier for OpenClaw, but with approval checkpoints |
|
||||||
|
|||||||
+4
-4
@@ -43,16 +43,16 @@
|
|||||||
"approval",
|
"approval",
|
||||||
"pipeline",
|
"pipeline",
|
||||||
"lobster",
|
"lobster",
|
||||||
"clawdbot"
|
"openclaw"
|
||||||
],
|
],
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/clawdbot/lobster.git"
|
"url": "git+https://github.com/openclaw/lobster.git"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/clawdbot/lobster/issues"
|
"url": "https://github.com/openclaw/lobster/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/clawdbot/lobster#readme",
|
"homepage": "https://github.com/openclaw/lobster#readme",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ajv": "^8.17.1",
|
"ajv": "^8.17.1",
|
||||||
|
|||||||
+1
-1
@@ -449,7 +449,7 @@ function writeToolEnvelope(payload) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function helpText() {
|
function helpText() {
|
||||||
return `lobster — Clawdbot-native typed shell\n\n` +
|
return `lobster — OpenClaw-native typed shell\n\n` +
|
||||||
`Usage:\n` +
|
`Usage:\n` +
|
||||||
` lobster '<pipeline>'\n` +
|
` lobster '<pipeline>'\n` +
|
||||||
` lobster run --mode tool '<pipeline>'\n` +
|
` lobster run --mode tool '<pipeline>'\n` +
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export const commandsListCommand: LobsterCommand = {
|
|||||||
`Usage:\n` +
|
`Usage:\n` +
|
||||||
` commands.list\n\n` +
|
` commands.list\n\n` +
|
||||||
`Notes:\n` +
|
`Notes:\n` +
|
||||||
` - Intended for agents (e.g. Clawdbot) to discover available pipeline stages dynamically.\n` +
|
` - Intended for agents (e.g. OpenClaw) to discover available pipeline stages dynamically.\n` +
|
||||||
` - Output includes name/description plus optional metadata (argsSchema/examples/sideEffects) when provided by commands.\n`
|
` - Output includes name/description plus optional metadata (argsSchema/examples/sideEffects) when provided by commands.\n`
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
export const clawdInvokeCommand = {
|
export const clawdInvokeCommand = {
|
||||||
name: 'clawd.invoke',
|
name: 'clawd.invoke',
|
||||||
meta: {
|
meta: {
|
||||||
description: 'Call a local Clawdbot tool endpoint',
|
description: 'Call a local OpenClaw tool endpoint',
|
||||||
argsSchema: {
|
argsSchema: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
url: { type: 'string', description: 'Clawdbot control URL (or CLAWD_URL)' },
|
url: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'OpenClaw control URL (or OPENCLAW_URL / CLAWD_URL)',
|
||||||
|
},
|
||||||
token: { type: 'string', description: 'Bearer token (or CLAWD_TOKEN)' },
|
token: { type: 'string', description: 'Bearer token (or CLAWD_TOKEN)' },
|
||||||
tool: { type: 'string', description: 'Tool name (e.g. message, cron, github, etc.)' },
|
tool: { type: 'string', description: 'Tool name (e.g. message, cron, github, etc.)' },
|
||||||
action: { type: 'string', description: 'Tool action' },
|
action: { type: 'string', description: 'Tool action' },
|
||||||
@@ -21,14 +24,16 @@ export const clawdInvokeCommand = {
|
|||||||
sideEffects: ['calls_clawd_tool'],
|
sideEffects: ['calls_clawd_tool'],
|
||||||
},
|
},
|
||||||
help() {
|
help() {
|
||||||
return `clawd.invoke — call a local Clawdbot tool endpoint\n\n` +
|
return `clawd.invoke — call a local OpenClaw tool endpoint\n\n` +
|
||||||
`Usage:\n` +
|
`Usage:\n` +
|
||||||
` clawd.invoke --tool message --action send --args-json '{"provider":"telegram","to":"...","message":"..."}'\n` +
|
` clawd.invoke --tool message --action send --args-json '{"provider":"telegram","to":"...","message":"..."}'\n` +
|
||||||
` clawd.invoke --tool message --action send --args-json '{...}' --dry-run\n` +
|
` clawd.invoke --tool message --action send --args-json '{...}' --dry-run\n` +
|
||||||
` ... | clawd.invoke --tool message --action send --each --item-key message --args-json '{"provider":"telegram","to":"..."}'\n\n` +
|
` ... | clawd.invoke --tool message --action send --each --item-key message --args-json '{"provider":"telegram","to":"..."}'\n\n` +
|
||||||
`Config:\n` +
|
`Config:\n` +
|
||||||
` - Uses CLAWD_URL env var by default (or pass --url).\n` +
|
` - Uses OPENCLAW_URL env var by default (or pass --url).\n` +
|
||||||
` - Optional Bearer token via CLAWD_TOKEN env var (or pass --token).\n` +
|
` - Backward compatible: CLAWD_URL is also supported.\n` +
|
||||||
|
` - Optional Bearer token via OPENCLAW_TOKEN env var (or pass --token).\n` +
|
||||||
|
` - Backward compatible: CLAWD_TOKEN is also supported.\n` +
|
||||||
` - Optional attribution via --session-key <sessionKey>.\n\n` +
|
` - Optional attribution via --session-key <sessionKey>.\n\n` +
|
||||||
`Notes:\n` +
|
`Notes:\n` +
|
||||||
` - This is a thin transport bridge. Lobster should not own OAuth/secrets.\n`;
|
` - This is a thin transport bridge. Lobster should not own OAuth/secrets.\n`;
|
||||||
@@ -37,14 +42,14 @@ export const clawdInvokeCommand = {
|
|||||||
const each = Boolean(args.each);
|
const each = Boolean(args.each);
|
||||||
const itemKey = String(args.itemKey ?? args['item-key'] ?? 'item');
|
const itemKey = String(args.itemKey ?? args['item-key'] ?? 'item');
|
||||||
|
|
||||||
const url = String(args.url ?? ctx.env.CLAWD_URL ?? '').trim();
|
const url = String(args.url ?? ctx.env.OPENCLAW_URL ?? ctx.env.CLAWD_URL ?? '').trim();
|
||||||
if (!url) throw new Error('clawd.invoke requires --url or CLAWD_URL');
|
if (!url) throw new Error('clawd.invoke requires --url or OPENCLAW_URL');
|
||||||
|
|
||||||
const tool = args.tool;
|
const tool = args.tool;
|
||||||
const action = args.action;
|
const action = args.action;
|
||||||
if (!tool || !action) throw new Error('clawd.invoke requires --tool and --action');
|
if (!tool || !action) throw new Error('clawd.invoke requires --tool and --action');
|
||||||
|
|
||||||
const token = String(args.token ?? ctx.env.CLAWD_TOKEN ?? '').trim();
|
const token = String(args.token ?? ctx.env.OPENCLAW_TOKEN ?? ctx.env.CLAWD_TOKEN ?? '').trim();
|
||||||
|
|
||||||
let toolArgs = {};
|
let toolArgs = {};
|
||||||
if (args['args-json']) {
|
if (args['args-json']) {
|
||||||
|
|||||||
@@ -233,7 +233,7 @@ export const emailTriageCommand = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const model = String(args.model ?? '').trim();
|
const model = String(args.model ?? '').trim();
|
||||||
// Model is optional when running under Clawdbot (llm_task.invoke will use Clawdbot defaults).
|
// Model is optional when running under OpenClaw (llm_task.invoke will use OpenClaw defaults).
|
||||||
|
|
||||||
if (!ctx?.registry) throw new Error('email.triage (LLM mode) requires ctx.registry');
|
if (!ctx?.registry) throw new Error('email.triage (LLM mode) requires ctx.registry');
|
||||||
const llmCmd = ctx.registry.get('llm_task.invoke');
|
const llmCmd = ctx.registry.get('llm_task.invoke');
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const payloadSchema = {
|
|||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
prompt: { type: 'string', minLength: 1 },
|
prompt: { type: 'string', minLength: 1 },
|
||||||
// In direct mode, the remote likely requires model; in CLAWD mode, Clawdbot can default.
|
// In direct mode, the remote likely requires model; in OPENCLAW mode, OpenClaw can default.
|
||||||
model: { type: 'string', minLength: 1 },
|
model: { type: 'string', minLength: 1 },
|
||||||
artifacts: { type: 'array', items: artifactSchema },
|
artifacts: { type: 'array', items: artifactSchema },
|
||||||
artifactHashes: { type: 'array', items: { type: 'string', minLength: 10 } },
|
artifactHashes: { type: 'array', items: { type: 'string', minLength: 10 } },
|
||||||
@@ -151,7 +151,7 @@ type Transport = 'clawd';
|
|||||||
export const llmTaskInvokeCommand = {
|
export const llmTaskInvokeCommand = {
|
||||||
name: 'llm_task.invoke',
|
name: 'llm_task.invoke',
|
||||||
meta: {
|
meta: {
|
||||||
description: 'Call Clawdbot llm-task tool with typed payloads and caching',
|
description: 'Call OpenClaw llm-task tool with typed payloads and caching',
|
||||||
argsSchema: {
|
argsSchema: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
@@ -160,7 +160,11 @@ export const llmTaskInvokeCommand = {
|
|||||||
description: 'Bearer token (or CLAWD_TOKEN). Optional if unauthenticated.',
|
description: 'Bearer token (or CLAWD_TOKEN). Optional if unauthenticated.',
|
||||||
},
|
},
|
||||||
prompt: { type: 'string', description: 'Primary prompt / instructions' },
|
prompt: { type: 'string', description: 'Primary prompt / instructions' },
|
||||||
model: { type: 'string', description: 'Model identifier (optional; Clawdbot default will be used if omitted in CLAWD mode)' },
|
model: {
|
||||||
|
type: 'string',
|
||||||
|
description:
|
||||||
|
'Model identifier (optional; OpenClaw default will be used if omitted in OPENCLAW mode)',
|
||||||
|
},
|
||||||
'artifacts-json': { type: 'string', description: 'JSON array of artifacts to send' },
|
'artifacts-json': { type: 'string', description: 'JSON array of artifacts to send' },
|
||||||
'metadata-json': { type: 'string', description: 'JSON object of metadata to include' },
|
'metadata-json': { type: 'string', description: 'JSON object of metadata to include' },
|
||||||
'output-schema': { type: 'string', description: 'JSON schema LLM output must satisfy' },
|
'output-schema': { type: 'string', description: 'JSON schema LLM output must satisfy' },
|
||||||
@@ -179,15 +183,17 @@ export const llmTaskInvokeCommand = {
|
|||||||
},
|
},
|
||||||
help() {
|
help() {
|
||||||
return (
|
return (
|
||||||
`llm_task.invoke — call Clawdbot llm-task tool with caching and schema validation\n\n` +
|
`llm_task.invoke — call OpenClaw llm-task tool with caching and schema validation\n\n` +
|
||||||
`Usage:\n` +
|
`Usage:\n` +
|
||||||
` llm_task.invoke --prompt 'Write summary'\n` +
|
` llm_task.invoke --prompt 'Write summary'\n` +
|
||||||
` llm_task.invoke --model claude-3-sonnet --prompt 'Write summary'\n` +
|
` llm_task.invoke --model claude-3-sonnet --prompt 'Write summary'\n` +
|
||||||
` cat artifacts.json | llm_task.invoke --prompt 'Score each item'\n` +
|
` cat artifacts.json | llm_task.invoke --prompt 'Score each item'\n` +
|
||||||
` ... | llm_task.invoke --prompt 'Plan next steps' --output-schema '{"type":"object"}'\n\n` +
|
` ... | llm_task.invoke --prompt 'Plan next steps' --output-schema '{"type":"object"}'\n\n` +
|
||||||
`Config:\n` +
|
`Config:\n` +
|
||||||
` - Requires CLAWD_URL (Clawdbot gateway).\n` +
|
` - Requires OPENCLAW_URL (OpenClaw gateway).\n` +
|
||||||
` - Optional CLAWD_TOKEN for auth.\n\n` +
|
` - Backward compatible: CLAWD_URL is also supported.\n` +
|
||||||
|
` - Optional OPENCLAW_TOKEN for auth.\n` +
|
||||||
|
` - Backward compatible: CLAWD_TOKEN is also supported.\n\n` +
|
||||||
`Features:\n` +
|
`Features:\n` +
|
||||||
` - Typed payload validation before invoking tool.\n` +
|
` - Typed payload validation before invoking tool.\n` +
|
||||||
` - Run-state + file cache so resumes do not re-call the LLM.\n` +
|
` - Run-state + file cache so resumes do not re-call the LLM.\n` +
|
||||||
@@ -197,17 +203,17 @@ export const llmTaskInvokeCommand = {
|
|||||||
async run({ input, args, ctx }) {
|
async run({ input, args, ctx }) {
|
||||||
const env = ctx.env ?? process.env;
|
const env = ctx.env ?? process.env;
|
||||||
|
|
||||||
const clawdUrl = String(env.CLAWD_URL ?? '').trim();
|
const clawdUrl = String(env.OPENCLAW_URL ?? env.CLAWD_URL ?? '').trim();
|
||||||
const transport: Transport = 'clawd';
|
const transport: Transport = 'clawd';
|
||||||
if (!clawdUrl) {
|
if (!clawdUrl) {
|
||||||
throw new Error('llm_task.invoke requires CLAWD_URL (run via Clawdbot gateway)');
|
throw new Error('llm_task.invoke requires OPENCLAW_URL (run via OpenClaw gateway)');
|
||||||
}
|
}
|
||||||
|
|
||||||
const prompt = extractPrompt(args);
|
const prompt = extractPrompt(args);
|
||||||
if (!prompt) throw new Error('llm_task.invoke requires --prompt or positional text');
|
if (!prompt) throw new Error('llm_task.invoke requires --prompt or positional text');
|
||||||
|
|
||||||
const model = String(args.model ?? env.LLM_TASK_MODEL ?? '').trim();
|
const model = String(args.model ?? env.LLM_TASK_MODEL ?? '').trim();
|
||||||
// Model is optional in Clawdbot mode (Clawdbot llm-task tool can use its default model).
|
// Model is optional in OpenClaw mode (OpenClaw llm-task tool can use its default model).
|
||||||
|
|
||||||
const schemaVersion = args['schema-version']
|
const schemaVersion = args['schema-version']
|
||||||
? String(args['schema-version']).trim()
|
? String(args['schema-version']).trim()
|
||||||
@@ -279,7 +285,7 @@ export const llmTaskInvokeCommand = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const endpoint = buildClawdEndpoint(clawdUrl);
|
const endpoint = buildClawdEndpoint(clawdUrl);
|
||||||
const token = String(args.token ?? env.CLAWD_TOKEN ?? '').trim();
|
const token = String(args.token ?? env.OPENCLAW_TOKEN ?? env.CLAWD_TOKEN ?? '').trim();
|
||||||
|
|
||||||
const validator = userOutputSchema ? ajv.compile(userOutputSchema) : null;
|
const validator = userOutputSchema ? ajv.compile(userOutputSchema) : null;
|
||||||
|
|
||||||
@@ -425,7 +431,7 @@ function computeCacheKey({
|
|||||||
}) {
|
}) {
|
||||||
const payload = {
|
const payload = {
|
||||||
prompt,
|
prompt,
|
||||||
// If model is omitted (Clawdbot default), keep caching stable but explicit.
|
// If model is omitted (OpenClaw default), keep caching stable but explicit.
|
||||||
model: model || 'clawd-default',
|
model: model || 'clawd-default',
|
||||||
schemaVersion,
|
schemaVersion,
|
||||||
artifactHashes,
|
artifactHashes,
|
||||||
@@ -464,7 +470,7 @@ async function invokeRemoteViaClawd({ endpoint, token, payload }: { endpoint: UR
|
|||||||
throw new Error('Response was not JSON');
|
throw new Error('Response was not JSON');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clawdbot tool router envelope: { ok, result, error }
|
// OpenClaw tool router envelope: { ok, result, error }
|
||||||
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed) && 'ok' in parsed) {
|
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed) && 'ok' in parsed) {
|
||||||
if (parsed.ok !== true) {
|
if (parsed.ok !== true) {
|
||||||
const msg = parsed?.error?.message ?? 'Unknown error';
|
const msg = parsed?.error?.message ?? 'Unknown error';
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export const workflowsListCommand = {
|
|||||||
sideEffects: [],
|
sideEffects: [],
|
||||||
},
|
},
|
||||||
help() {
|
help() {
|
||||||
return `workflows.list — list available Lobster workflows\n\nUsage:\n workflows.list\n\nNotes:\n - Intended for Clawdbot to discover workflows dynamically.\n`;
|
return `workflows.list — list available Lobster workflows\n\nUsage:\n workflows.list\n\nNotes:\n - Intended for OpenClaw to discover workflows dynamically.\n`;
|
||||||
},
|
},
|
||||||
async run({ input }) {
|
async run({ input }) {
|
||||||
// Drain input.
|
// Drain input.
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export const workflowsRunCommand = {
|
|||||||
sideEffects: [],
|
sideEffects: [],
|
||||||
},
|
},
|
||||||
help() {
|
help() {
|
||||||
return `workflows.run — run a named Lobster workflow\n\nUsage:\n workflows.run --name <workflow> [--args-json '{...}']\n\nExample:\n workflows.run --name github.pr.monitor.notify --args-json '{"repo":"clawdbot/clawdbot","pr":1152}'\n`;
|
return `workflows.run — run a named Lobster workflow\n\nUsage:\n workflows.run --name <workflow> [--args-json '{...}']\n\nExample:\n workflows.run --name github.pr.monitor.notify --args-json '{"repo":"openclaw/openclaw","pr":1152}'\n`;
|
||||||
},
|
},
|
||||||
async run({ input, args, ctx }) {
|
async run({ input, args, ctx }) {
|
||||||
// Drain input.
|
// Drain input.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* Recipe entrypoints.
|
* Recipe entrypoints.
|
||||||
*
|
*
|
||||||
* Core Lobster intentionally keeps only Clawdbot-first recipes here.
|
* Core Lobster intentionally keeps only OpenClaw-first recipes here.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export * from "./github/index.js";
|
export * from "./github/index.js";
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export const workflowRegistry = {
|
|||||||
argsSchema: {
|
argsSchema: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
repo: { type: 'string', description: 'owner/repo (e.g. clawdbot/clawdbot)' },
|
repo: { type: 'string', description: 'owner/repo (e.g. openclaw/openclaw)' },
|
||||||
pr: { type: 'number', description: 'Pull request number' },
|
pr: { type: 'number', description: 'Pull request number' },
|
||||||
key: { type: 'string', description: 'Optional state key override.' },
|
key: { type: 'string', description: 'Optional state key override.' },
|
||||||
changesOnly: { type: 'boolean', description: 'If true, suppress output when unchanged.' },
|
changesOnly: { type: 'boolean', description: 'If true, suppress output when unchanged.' },
|
||||||
@@ -15,7 +15,7 @@ export const workflowRegistry = {
|
|||||||
},
|
},
|
||||||
examples: [
|
examples: [
|
||||||
{
|
{
|
||||||
args: { repo: 'clawdbot/clawdbot', pr: 1152 },
|
args: { repo: 'openclaw/openclaw', pr: 1152 },
|
||||||
description: 'Monitor a PR and report when it changes.',
|
description: 'Monitor a PR and report when it changes.',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -27,7 +27,7 @@ export const workflowRegistry = {
|
|||||||
argsSchema: {
|
argsSchema: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
repo: { type: 'string', description: 'owner/repo (e.g. clawdbot/clawdbot)' },
|
repo: { type: 'string', description: 'owner/repo (e.g. openclaw/openclaw)' },
|
||||||
pr: { type: 'number', description: 'Pull request number' },
|
pr: { type: 'number', description: 'Pull request number' },
|
||||||
key: { type: 'string', description: 'Optional state key override.' },
|
key: { type: 'string', description: 'Optional state key override.' },
|
||||||
},
|
},
|
||||||
@@ -35,7 +35,7 @@ export const workflowRegistry = {
|
|||||||
},
|
},
|
||||||
examples: [
|
examples: [
|
||||||
{
|
{
|
||||||
args: { repo: 'clawdbot/clawdbot', pr: 1152 },
|
args: { repo: 'openclaw/openclaw', pr: 1152 },
|
||||||
description: 'Emit "PR updated" message only when changed.',
|
description: 'Emit "PR updated" message only when changed.',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ test("email.triage --llm uses llm_task.invoke to draft replies (and can emit dra
|
|||||||
bodyLog.push(parsed);
|
bodyLog.push(parsed);
|
||||||
|
|
||||||
res.writeHead(200, { "content-type": "application/json" });
|
res.writeHead(200, { "content-type": "application/json" });
|
||||||
// Clawdbot tool router envelope -> llm-task tool envelope
|
// OpenClaw tool router envelope -> llm-task tool envelope
|
||||||
res.end(
|
res.end(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
ok: true,
|
ok: true,
|
||||||
|
|||||||
@@ -308,7 +308,7 @@ test('llm_task.invoke uses CLAWD_URL (/tools/invoke) without requiring --url/--m
|
|||||||
const parsed = JSON.parse(buf || '{}');
|
const parsed = JSON.parse(buf || '{}');
|
||||||
bodyLog.push(parsed);
|
bodyLog.push(parsed);
|
||||||
|
|
||||||
// This is the Clawdbot tool router envelope.
|
// This is the OpenClaw tool router envelope.
|
||||||
res.writeHead(200, { 'content-type': 'application/json' });
|
res.writeHead(200, { 'content-type': 'application/json' });
|
||||||
res.end(
|
res.end(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
|||||||
Reference in New Issue
Block a user