@plateforme-ai/lobster 2026.6.13 → 2026.6.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,353 +1,360 @@
1
- # 🦞 Lobster
2
-
3
- ![Lobster banner](docs/assets/readme-banner.jpg)
4
-
5
- An OpenClaw-native workflow shell: typed (JSON-first) pipelines, jobs, and approval gates.
6
-
7
-
8
- ## Example of Lobster at work
9
- 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.
10
-
11
- ### Watching a PR that hasn't had changes
12
- ```
13
- node bin/lobster.js "workflows.run --name github.pr.monitor --args-json '{\"repo\":\"openclaw/openclaw\",\"pr\":1152}'"
14
- [
15
- {
16
- "kind": "github.pr.monitor",
17
- "repo": "openclaw/openclaw",
18
- "prNumber": 1152,
19
- "key": "github.pr:openclaw/openclaw#1152",
20
- "changed": false,
21
- "summary": {
22
- "changedFields": [],
23
- "changes": {}
24
- },
25
- "prSnapshot": {
26
- "author": {
27
- "id": "MDQ6VXNlcjE0MzY4NTM=",
28
- "is_bot": false,
29
- "login": "vignesh07",
30
- "name": "Vignesh"
31
- },
32
- "baseRefName": "main",
33
- "headRefName": "feat/lobster-plugin",
34
- "isDraft": false,
35
- "mergeable": "MERGEABLE",
36
- "number": 1152,
37
- "reviewDecision": "",
38
- "state": "OPEN",
39
- "title": "feat: Add optional lobster plugin tool (typed workflows, approvals/resume)",
40
- "updatedAt": "2026-01-18T20:16:56Z",
41
- "url": "https://github.com/openclaw/openclaw/pull/1152"
42
- }
43
- }
44
- ]
45
- ```
46
- ### And a PR that has a state change (in this case an approved PR)
47
-
48
- ```
49
- node bin/lobster.js "workflows.run --name github.pr.monitor --args-json '{\"repo\":\"openclaw/openclaw\",\"pr\":1200}'"
50
- [
51
- {
52
- "kind": "github.pr.monitor",
53
- "repo": "openclaw/openclaw",
54
- "prNumber": 1200,
55
- "key": "github.pr:openclaw/openclaw#1200",
56
- "changed": true,
57
- "summary": {
58
- "changedFields": [
59
- "number",
60
- "title",
61
- "url",
62
- "state",
63
- "isDraft",
64
- "mergeable",
65
- "reviewDecision",
66
- "updatedAt",
67
- "baseRefName",
68
- "headRefName"
69
- ],
70
- "changes": {
71
- "number": {
72
- "from": null,
73
- "to": 1200
74
- },
75
- "title": {
76
- "from": null,
77
- "to": "feat(tui): add syntax highlighting for code blocks"
78
- },
79
- "url": {
80
- "from": null,
81
- "to": "https://github.com/openclaw/openclaw/pull/1200"
82
- },
83
- "state": {
84
- "from": null,
85
- "to": "MERGED"
86
- },
87
- "isDraft": {
88
- "from": null,
89
- "to": false
90
- },
91
- "mergeable": {
92
- "from": null,
93
- "to": "UNKNOWN"
94
- },
95
- "reviewDecision": {
96
- "from": null,
97
- "to": ""
98
- },
99
- "updatedAt": {
100
- "from": null,
101
- "to": "2026-01-19T05:06:09Z"
102
- },
103
- "baseRefName": {
104
- "from": null,
105
- "to": "main"
106
- },
107
- "headRefName": {
108
- "from": null,
109
- "to": "feat/tui-syntax-highlighting"
110
- }
111
- }
112
- },
113
- "prSnapshot": {
114
- "author": {
115
- "id": "MDQ6VXNlcjE0MzY4NTM=",
116
- "is_bot": false,
117
- "login": "vignesh07",
118
- "name": "Vignesh"
119
- },
120
- "baseRefName": "main",
121
- "headRefName": "feat/tui-syntax-highlighting",
122
- "isDraft": false,
123
- "mergeable": "UNKNOWN",
124
- "number": 1200,
125
- "reviewDecision": "",
126
- "state": "MERGED",
127
- "title": "feat(tui): add syntax highlighting for code blocks",
128
- "updatedAt": "2026-01-19T05:06:09Z",
129
- "url": "https://github.com/openclaw/openclaw/pull/1200"
130
- }
131
- }
132
- ]
133
- ```
134
-
135
- ## Goals
136
-
137
-
138
- - Typed pipelines (objects/arrays), not text pipes.
139
- - Local-first execution.
140
- - No new auth surface: Lobster must not own OAuth/tokens.
141
- - Composable macros that OpenClaw (or any agent) can invoke in one step to save tokens.
142
-
143
- ## Quick start
144
-
145
- From this folder:
146
-
147
- - `pnpm install`
148
- - `pnpm test`
149
- - `pnpm lint`
150
- - `node ./bin/lobster.js --help`
151
- - `node ./bin/lobster.js doctor`
152
- - `node ./bin/lobster.js "exec --json --shell 'echo [1,2,3]' | where '0>=0' | json"`
153
-
154
- ### Notes
155
-
156
- - `pnpm test` runs `tsc` and then executes tests against `dist/`.
157
- - `bin/lobster.js` prefers the compiled entrypoint in `dist/` when present.
158
- ## Commands
159
-
160
- - `exec`: run OS commands
161
- - `exec --stdin raw|json|jsonl`: feed pipeline input into subprocess stdin
162
- - `where`, `pick`, `head`: data shaping
163
- - `json`, `table`: renderers
164
- - `approve`: approval gate (TTY prompt or `--emit` for OpenClaw integration)
165
-
166
- ## Next steps
167
-
168
- - OpenClaw integration: ship as an optional OpenClaw plugin tool.
169
-
170
- ## Workflow files
171
-
172
- Lobster workflow files are meant to read like small scripts:
173
-
174
- - `run:` or `command:` for deterministic shell/CLI steps
175
- - `pipeline:` for native Lobster stages like `llm.invoke`
176
- - `approval:` for hard workflow gates between steps
177
- - `stdin: $step.stdout` or `stdin: $step.json` to pass data forward
178
-
179
- ```
180
- lobster run path/to/workflow.lobster
181
- lobster run --file path/to/workflow.lobster --args-json '{"tag":"family"}'
182
- ```
183
-
184
- Example file:
185
-
186
- ```yaml
187
- name: jacket-advice
188
- args:
189
- location:
190
- default: Phoenix
191
- steps:
192
- - id: fetch
193
- run: weather --json ${location}
194
-
195
- - id: confirm
196
- approval: Want jacket advice from the LLM?
197
- stdin: $fetch.json
198
-
199
- - id: advice
200
- pipeline: >
201
- llm.invoke --prompt "Given this weather data, should I wear a jacket?
202
- Be concise and return JSON."
203
- stdin: $fetch.json
204
- when: $confirm.approved
205
- ```
206
-
207
- Notes:
208
-
209
- - `run:` and `command:` are equivalent; `run:` is the preferred spelling for new files.
210
- - `pipeline:` shares the same args/env/results model as shell steps, so later steps can still reference `$step.stdout` or `$step.json`.
211
- - If you need a human checkpoint before an LLM call, use a dedicated `approval:` step in the workflow file rather than `approve` inside the nested pipeline.
212
- - `cwd`, `env`, `stdin`, `when`, and `condition` work for both shell and pipeline steps.
213
- - Use `retry`, `timeout_ms`, and `on_error` per step to control transient-failure behavior and recovery.
214
- - Approval steps can optionally enforce identity constraints:
215
- - `approval.required_approver` (or `requiredApprover`) requires an exact approver id.
216
- - `approval.require_different_approver` (or `requireDifferentApprover`) requires approver id to differ from initiator.
217
- - `approval.initiated_by` (or `initiatedBy`) sets the initiator id for comparison.
218
- - `LOBSTER_APPROVAL_INITIATED_BY` can provide a default initiator id at run time.
219
- - `LOBSTER_APPROVAL_APPROVED_BY` is used at resume/approval time for identity checks.
220
-
221
- ### Command-level input requests
222
-
223
- Pipeline commands can call `ctx.requestInput({ prompt, responseSchema, defaults, subject, suspendedState })` to pause in tool mode, workflows, or the SDK and resume the same command after a structured response. CLI/tool resume tokens store only a state key; the persisted state validates the suspended request metadata before returning the submitted response to the command. SDK same-command resumes store the command frame in the configured SDK state directory.
224
-
225
- Commands are re-run on resume, so they must be idempotent until `requestInput` returns. Array-backed command input is snapshotted with bounds for replay; lazy stream input is not buffered and requires a compact JSON `suspendedState` supplied by the command. On resume, call `ctx.requestInput.getSuspendedState()` before reading lazy input to restore that command-owned continuation state.
226
-
227
- ## Visualizing workflows
228
-
229
- Use `lobster graph` to inspect workflow structure before execution.
230
-
231
- ```bash
232
- lobster graph --file path/to/workflow.lobster
233
- lobster graph --file path/to/workflow.lobster --format mermaid
234
- lobster graph --file path/to/workflow.lobster --format dot
235
- lobster graph --file path/to/workflow.lobster --format ascii
236
- lobster graph --file path/to/workflow.lobster --args-json '{"location":"Seattle"}'
237
- ```
238
-
239
- What gets visualized:
240
-
241
- - each workflow step as a node (`run`, `pipeline`, `approval`, etc.)
242
- - data-flow edges from `stdin: $step.stdout` / `$step.json` references
243
- - conditional dependencies from `when:` / `condition:` expressions
244
- - approval gates as diamond-shaped nodes in `mermaid` and `dot` output
245
-
246
- Format notes:
247
-
248
- - `mermaid` (default): emits `flowchart TD` text for GitHub/Markdown rendering
249
- - `dot`: emits Graphviz DOT syntax
250
- - `ascii`: emits a terminal-friendly node/edge list
251
-
252
- ## Calling LLMs from workflows
253
-
254
- Use `llm.invoke` from a native `pipeline:` step for model-backed work:
255
-
256
- ```bash
257
- llm.invoke --prompt 'Summarize this diff'
258
- llm.invoke --provider openclaw --prompt 'Summarize this diff'
259
- llm.invoke --provider pi --prompt 'Summarize this diff'
260
- ```
261
-
262
- Provider resolution order:
263
-
264
- - `--provider`
265
- - `LOBSTER_LLM_PROVIDER`
266
- - auto-detect from environment
267
-
268
- Built-in providers today:
269
-
270
- - `openclaw` via `OPENCLAW_URL` / `OPENCLAW_TOKEN`
271
- - `pi` via `LOBSTER_PI_LLM_ADAPTER_URL` (typically supplied by the Pi extension)
272
- - `http` via `LOBSTER_LLM_ADAPTER_URL`
273
-
274
- Workflow `_meta.cost` and `cost_limit` use a static pricing table plus optional overrides from `LOBSTER_LLM_PRICING_JSON`, for example `{"my-model":{"input":1.0,"output":2.0}}` in USD per million tokens. Unknown or missing model IDs still record token counts with zero estimated cost, but Lobster warns on stderr so stale or missing pricing does not fail silently.
275
-
276
- `llm_task.invoke` remains available as a backward-compatible alias for the OpenClaw provider.
277
-
278
- ### `pipeline:` vs `run:` for LLM calls
279
-
280
- - Use `pipeline:` for `llm.invoke` and `llm_task.invoke` (they are Lobster pipeline stages, not shell executables).
281
- - Use `run:` only for real binaries in your shell (for example `openclaw.invoke`).
282
-
283
- Example (`stdin` from a prior step is passed to the LLM as artifacts):
284
-
285
- ```yaml
286
- steps:
287
- - id: make_words
288
- run: echo "One two three four five six"
289
-
290
- - id: count_words
291
- pipeline: llm_task.invoke --prompt "How many words have been pasted below?"
292
- stdin: $make_words.stdout
293
- ```
294
-
295
- ## Calling OpenClaw tools from workflows
296
-
297
- Shell `run:` steps execute in your system shell, so OpenClaw tool calls there must be real executables.
298
-
299
- If you install Lobster via npm/pnpm, it installs a small shim executable named:
300
-
301
- - `openclaw.invoke` (preferred)
302
- - `clawd.invoke` (alias)
303
-
304
- These shims forward to the Lobster pipeline command of the same name.
305
-
306
- ### Example: invoke llm-task
307
-
308
- Prereqs:
309
-
310
- - `OPENCLAW_URL` points at a running OpenClaw gateway
311
- - optionally `OPENCLAW_TOKEN` if auth is enabled
312
-
313
- ```bash
314
- export OPENCLAW_URL=http://127.0.0.1:18789
315
- # export OPENCLAW_TOKEN=...
316
- ```
317
-
318
- In a workflow:
319
-
320
- ```yaml
321
- name: hello-world
322
- steps:
323
- - id: greeting
324
- run: >
325
- openclaw.invoke --tool llm-task --action json --args-json '{"prompt":"Hello"}'
326
- ```
327
-
328
- ### Passing data between steps (no temp files)
329
-
330
- Use `stdin: $stepId.stdout` to pipe output from one step into the next.
331
-
332
- ## Args and shell-safety
333
-
334
- `${arg}` substitution is a raw string replace into the shell command text.
335
-
336
- For anything that may contain quotes, `$`, backticks, or newlines, prefer env vars:
337
-
338
- - every resolved workflow arg is exposed as `LOBSTER_ARG_<NAME>` (uppercased, non-alnum → `_`)
339
- - the full args object is also available as `LOBSTER_ARGS_JSON`
340
-
341
- Example:
342
-
343
- ```yaml
344
- args:
345
- text:
346
- default: ""
347
- steps:
348
- - id: safe
349
- env:
350
- TEXT: "$LOBSTER_ARG_TEXT"
351
- command: |
352
- jq -n --arg text "$TEXT" '{"result": $text}'
353
- ```
1
+ # 🦞 Lobster
2
+
3
+ ![Lobster banner](docs/assets/readme-banner.jpg)
4
+
5
+ An OpenClaw-native workflow shell: typed (JSON-first) pipelines, jobs, and approval gates.
6
+
7
+ | Source | Version |
8
+ |--------|---------|
9
+ | forked | [![forked version](https://img.shields.io/npm/v/%40clawdbot%2Flobster?label=npm)](https://www.npmjs.com/package/@plateforme-ai/lobster) |
10
+ | synced | [![synced version](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fplateforme-ai%2Flobster%2Fmain%2Fpackage.json&query=%24.version&label=npm&prefix=v)](https://github.com/plateforme-ai/lobster/tree/main) |
11
+ | release | [![patched version](https://img.shields.io/npm/v/%40plateforme-ai%2Flobster?label=npm)](https://www.npmjs.com/package/@plateforme-ai/lobster) |
12
+
13
+ Forked from [https://github.com/openclaw/lobster](https://github.com/openclaw/lobster)
14
+
15
+ ## Example of Lobster at work
16
+ 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.
17
+
18
+ ### Watching a PR that hasn't had changes
19
+ ```
20
+ node bin/lobster.js "workflows.run --name github.pr.monitor --args-json '{\"repo\":\"openclaw/openclaw\",\"pr\":1152}'"
21
+ [
22
+ {
23
+ "kind": "github.pr.monitor",
24
+ "repo": "openclaw/openclaw",
25
+ "prNumber": 1152,
26
+ "key": "github.pr:openclaw/openclaw#1152",
27
+ "changed": false,
28
+ "summary": {
29
+ "changedFields": [],
30
+ "changes": {}
31
+ },
32
+ "prSnapshot": {
33
+ "author": {
34
+ "id": "MDQ6VXNlcjE0MzY4NTM=",
35
+ "is_bot": false,
36
+ "login": "vignesh07",
37
+ "name": "Vignesh"
38
+ },
39
+ "baseRefName": "main",
40
+ "headRefName": "feat/lobster-plugin",
41
+ "isDraft": false,
42
+ "mergeable": "MERGEABLE",
43
+ "number": 1152,
44
+ "reviewDecision": "",
45
+ "state": "OPEN",
46
+ "title": "feat: Add optional lobster plugin tool (typed workflows, approvals/resume)",
47
+ "updatedAt": "2026-01-18T20:16:56Z",
48
+ "url": "https://github.com/openclaw/openclaw/pull/1152"
49
+ }
50
+ }
51
+ ]
52
+ ```
53
+ ### And a PR that has a state change (in this case an approved PR)
54
+
55
+ ```
56
+ node bin/lobster.js "workflows.run --name github.pr.monitor --args-json '{\"repo\":\"openclaw/openclaw\",\"pr\":1200}'"
57
+ [
58
+ {
59
+ "kind": "github.pr.monitor",
60
+ "repo": "openclaw/openclaw",
61
+ "prNumber": 1200,
62
+ "key": "github.pr:openclaw/openclaw#1200",
63
+ "changed": true,
64
+ "summary": {
65
+ "changedFields": [
66
+ "number",
67
+ "title",
68
+ "url",
69
+ "state",
70
+ "isDraft",
71
+ "mergeable",
72
+ "reviewDecision",
73
+ "updatedAt",
74
+ "baseRefName",
75
+ "headRefName"
76
+ ],
77
+ "changes": {
78
+ "number": {
79
+ "from": null,
80
+ "to": 1200
81
+ },
82
+ "title": {
83
+ "from": null,
84
+ "to": "feat(tui): add syntax highlighting for code blocks"
85
+ },
86
+ "url": {
87
+ "from": null,
88
+ "to": "https://github.com/openclaw/openclaw/pull/1200"
89
+ },
90
+ "state": {
91
+ "from": null,
92
+ "to": "MERGED"
93
+ },
94
+ "isDraft": {
95
+ "from": null,
96
+ "to": false
97
+ },
98
+ "mergeable": {
99
+ "from": null,
100
+ "to": "UNKNOWN"
101
+ },
102
+ "reviewDecision": {
103
+ "from": null,
104
+ "to": ""
105
+ },
106
+ "updatedAt": {
107
+ "from": null,
108
+ "to": "2026-01-19T05:06:09Z"
109
+ },
110
+ "baseRefName": {
111
+ "from": null,
112
+ "to": "main"
113
+ },
114
+ "headRefName": {
115
+ "from": null,
116
+ "to": "feat/tui-syntax-highlighting"
117
+ }
118
+ }
119
+ },
120
+ "prSnapshot": {
121
+ "author": {
122
+ "id": "MDQ6VXNlcjE0MzY4NTM=",
123
+ "is_bot": false,
124
+ "login": "vignesh07",
125
+ "name": "Vignesh"
126
+ },
127
+ "baseRefName": "main",
128
+ "headRefName": "feat/tui-syntax-highlighting",
129
+ "isDraft": false,
130
+ "mergeable": "UNKNOWN",
131
+ "number": 1200,
132
+ "reviewDecision": "",
133
+ "state": "MERGED",
134
+ "title": "feat(tui): add syntax highlighting for code blocks",
135
+ "updatedAt": "2026-01-19T05:06:09Z",
136
+ "url": "https://github.com/openclaw/openclaw/pull/1200"
137
+ }
138
+ }
139
+ ]
140
+ ```
141
+
142
+ ## Goals
143
+
144
+
145
+ - Typed pipelines (objects/arrays), not text pipes.
146
+ - Local-first execution.
147
+ - No new auth surface: Lobster must not own OAuth/tokens.
148
+ - Composable macros that OpenClaw (or any agent) can invoke in one step to save tokens.
149
+
150
+ ## Quick start
151
+
152
+ From this folder:
153
+
154
+ - `pnpm install`
155
+ - `pnpm test`
156
+ - `pnpm lint`
157
+ - `node ./bin/lobster.js --help`
158
+ - `node ./bin/lobster.js doctor`
159
+ - `node ./bin/lobster.js "exec --json --shell 'echo [1,2,3]' | where '0>=0' | json"`
160
+
161
+ ### Notes
162
+
163
+ - `pnpm test` runs `tsc` and then executes tests against `dist/`.
164
+ - `bin/lobster.js` prefers the compiled entrypoint in `dist/` when present.
165
+ ## Commands
166
+
167
+ - `exec`: run OS commands
168
+ - `exec --stdin raw|json|jsonl`: feed pipeline input into subprocess stdin
169
+ - `where`, `pick`, `head`: data shaping
170
+ - `json`, `table`: renderers
171
+ - `approve`: approval gate (TTY prompt or `--emit` for OpenClaw integration)
172
+
173
+ ## Next steps
174
+
175
+ - OpenClaw integration: ship as an optional OpenClaw plugin tool.
176
+
177
+ ## Workflow files
178
+
179
+ Lobster workflow files are meant to read like small scripts:
180
+
181
+ - `run:` or `command:` for deterministic shell/CLI steps
182
+ - `pipeline:` for native Lobster stages like `llm.invoke`
183
+ - `approval:` for hard workflow gates between steps
184
+ - `stdin: $step.stdout` or `stdin: $step.json` to pass data forward
185
+
186
+ ```
187
+ lobster run path/to/workflow.lobster
188
+ lobster run --file path/to/workflow.lobster --args-json '{"tag":"family"}'
189
+ ```
190
+
191
+ Example file:
192
+
193
+ ```yaml
194
+ name: jacket-advice
195
+ args:
196
+ location:
197
+ default: Phoenix
198
+ steps:
199
+ - id: fetch
200
+ run: weather --json ${location}
201
+
202
+ - id: confirm
203
+ approval: Want jacket advice from the LLM?
204
+ stdin: $fetch.json
205
+
206
+ - id: advice
207
+ pipeline: >
208
+ llm.invoke --prompt "Given this weather data, should I wear a jacket?
209
+ Be concise and return JSON."
210
+ stdin: $fetch.json
211
+ when: $confirm.approved
212
+ ```
213
+
214
+ Notes:
215
+
216
+ - `run:` and `command:` are equivalent; `run:` is the preferred spelling for new files.
217
+ - `pipeline:` shares the same args/env/results model as shell steps, so later steps can still reference `$step.stdout` or `$step.json`.
218
+ - If you need a human checkpoint before an LLM call, use a dedicated `approval:` step in the workflow file rather than `approve` inside the nested pipeline.
219
+ - `cwd`, `env`, `stdin`, `when`, and `condition` work for both shell and pipeline steps.
220
+ - Use `retry`, `timeout_ms`, and `on_error` per step to control transient-failure behavior and recovery.
221
+ - Approval steps can optionally enforce identity constraints:
222
+ - `approval.required_approver` (or `requiredApprover`) requires an exact approver id.
223
+ - `approval.require_different_approver` (or `requireDifferentApprover`) requires approver id to differ from initiator.
224
+ - `approval.initiated_by` (or `initiatedBy`) sets the initiator id for comparison.
225
+ - `LOBSTER_APPROVAL_INITIATED_BY` can provide a default initiator id at run time.
226
+ - `LOBSTER_APPROVAL_APPROVED_BY` is used at resume/approval time for identity checks.
227
+
228
+ ### Command-level input requests
229
+
230
+ Pipeline commands can call `ctx.requestInput({ prompt, responseSchema, defaults, subject, suspendedState })` to pause in tool mode, workflows, or the SDK and resume the same command after a structured response. CLI/tool resume tokens store only a state key; the persisted state validates the suspended request metadata before returning the submitted response to the command. SDK same-command resumes store the command frame in the configured SDK state directory.
231
+
232
+ Commands are re-run on resume, so they must be idempotent until `requestInput` returns. Array-backed command input is snapshotted with bounds for replay; lazy stream input is not buffered and requires a compact JSON `suspendedState` supplied by the command. On resume, call `ctx.requestInput.getSuspendedState()` before reading lazy input to restore that command-owned continuation state.
233
+
234
+ ## Visualizing workflows
235
+
236
+ Use `lobster graph` to inspect workflow structure before execution.
237
+
238
+ ```bash
239
+ lobster graph --file path/to/workflow.lobster
240
+ lobster graph --file path/to/workflow.lobster --format mermaid
241
+ lobster graph --file path/to/workflow.lobster --format dot
242
+ lobster graph --file path/to/workflow.lobster --format ascii
243
+ lobster graph --file path/to/workflow.lobster --args-json '{"location":"Seattle"}'
244
+ ```
245
+
246
+ What gets visualized:
247
+
248
+ - each workflow step as a node (`run`, `pipeline`, `approval`, etc.)
249
+ - data-flow edges from `stdin: $step.stdout` / `$step.json` references
250
+ - conditional dependencies from `when:` / `condition:` expressions
251
+ - approval gates as diamond-shaped nodes in `mermaid` and `dot` output
252
+
253
+ Format notes:
254
+
255
+ - `mermaid` (default): emits `flowchart TD` text for GitHub/Markdown rendering
256
+ - `dot`: emits Graphviz DOT syntax
257
+ - `ascii`: emits a terminal-friendly node/edge list
258
+
259
+ ## Calling LLMs from workflows
260
+
261
+ Use `llm.invoke` from a native `pipeline:` step for model-backed work:
262
+
263
+ ```bash
264
+ llm.invoke --prompt 'Summarize this diff'
265
+ llm.invoke --provider openclaw --prompt 'Summarize this diff'
266
+ llm.invoke --provider pi --prompt 'Summarize this diff'
267
+ ```
268
+
269
+ Provider resolution order:
270
+
271
+ - `--provider`
272
+ - `LOBSTER_LLM_PROVIDER`
273
+ - auto-detect from environment
274
+
275
+ Built-in providers today:
276
+
277
+ - `openclaw` via `OPENCLAW_URL` / `OPENCLAW_TOKEN`
278
+ - `pi` via `LOBSTER_PI_LLM_ADAPTER_URL` (typically supplied by the Pi extension)
279
+ - `http` via `LOBSTER_LLM_ADAPTER_URL`
280
+
281
+ Workflow `_meta.cost` and `cost_limit` use a static pricing table plus optional overrides from `LOBSTER_LLM_PRICING_JSON`, for example `{"my-model":{"input":1.0,"output":2.0}}` in USD per million tokens. Unknown or missing model IDs still record token counts with zero estimated cost, but Lobster warns on stderr so stale or missing pricing does not fail silently.
282
+
283
+ `llm_task.invoke` remains available as a backward-compatible alias for the OpenClaw provider.
284
+
285
+ ### `pipeline:` vs `run:` for LLM calls
286
+
287
+ - Use `pipeline:` for `llm.invoke` and `llm_task.invoke` (they are Lobster pipeline stages, not shell executables).
288
+ - Use `run:` only for real binaries in your shell (for example `openclaw.invoke`).
289
+
290
+ Example (`stdin` from a prior step is passed to the LLM as artifacts):
291
+
292
+ ```yaml
293
+ steps:
294
+ - id: make_words
295
+ run: echo "One two three four five six"
296
+
297
+ - id: count_words
298
+ pipeline: llm_task.invoke --prompt "How many words have been pasted below?"
299
+ stdin: $make_words.stdout
300
+ ```
301
+
302
+ ## Calling OpenClaw tools from workflows
303
+
304
+ Shell `run:` steps execute in your system shell, so OpenClaw tool calls there must be real executables.
305
+
306
+ If you install Lobster via npm/pnpm, it installs a small shim executable named:
307
+
308
+ - `openclaw.invoke` (preferred)
309
+ - `clawd.invoke` (alias)
310
+
311
+ These shims forward to the Lobster pipeline command of the same name.
312
+
313
+ ### Example: invoke llm-task
314
+
315
+ Prereqs:
316
+
317
+ - `OPENCLAW_URL` points at a running OpenClaw gateway
318
+ - optionally `OPENCLAW_TOKEN` if auth is enabled
319
+
320
+ ```bash
321
+ export OPENCLAW_URL=http://127.0.0.1:18789
322
+ # export OPENCLAW_TOKEN=...
323
+ ```
324
+
325
+ In a workflow:
326
+
327
+ ```yaml
328
+ name: hello-world
329
+ steps:
330
+ - id: greeting
331
+ run: >
332
+ openclaw.invoke --tool llm-task --action json --args-json '{"prompt":"Hello"}'
333
+ ```
334
+
335
+ ### Passing data between steps (no temp files)
336
+
337
+ Use `stdin: $stepId.stdout` to pipe output from one step into the next.
338
+
339
+ ## Args and shell-safety
340
+
341
+ `${arg}` substitution is a raw string replace into the shell command text.
342
+
343
+ For anything that may contain quotes, `$`, backticks, or newlines, prefer env vars:
344
+
345
+ - every resolved workflow arg is exposed as `LOBSTER_ARG_<NAME>` (uppercased, non-alnum → `_`)
346
+ - the full args object is also available as `LOBSTER_ARGS_JSON`
347
+
348
+ Example:
349
+
350
+ ```yaml
351
+ args:
352
+ text:
353
+ default: ""
354
+ steps:
355
+ - id: safe
356
+ env:
357
+ TEXT: "$LOBSTER_ARG_TEXT"
358
+ command: |
359
+ jq -n --arg text "$TEXT" '{"result": $text}'
360
+ ```