lazyclaw 4.3.0 → 5.0.0

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.
Files changed (54) hide show
  1. package/README.ko.md +44 -0
  2. package/README.md +172 -508
  3. package/channels/handoff.mjs +41 -0
  4. package/channels/loader.mjs +124 -0
  5. package/channels/threads.mjs +116 -0
  6. package/cli.mjs +398 -6
  7. package/daemon.mjs +13 -0
  8. package/mas/agent_turn.mjs +28 -0
  9. package/mas/confidence.mjs +108 -0
  10. package/mas/index_db.mjs +242 -0
  11. package/mas/nudge.mjs +97 -0
  12. package/mas/prompt_stack.mjs +80 -0
  13. package/mas/skill_synth.mjs +124 -25
  14. package/mas/tool_runner.mjs +10 -61
  15. package/mas/tools/browser.mjs +77 -0
  16. package/mas/tools/clarify.mjs +36 -0
  17. package/mas/tools/coding.mjs +109 -0
  18. package/mas/tools/delegation.mjs +53 -0
  19. package/mas/tools/edit.mjs +36 -0
  20. package/mas/tools/git.mjs +110 -0
  21. package/mas/tools/ha.mjs +34 -0
  22. package/mas/tools/learning.mjs +168 -0
  23. package/mas/tools/media.mjs +105 -0
  24. package/mas/tools/os.mjs +152 -0
  25. package/mas/tools/patch.mjs +91 -0
  26. package/mas/tools/recall.mjs +103 -0
  27. package/mas/tools/registry.mjs +93 -0
  28. package/mas/tools/scheduling.mjs +62 -0
  29. package/mas/tools/web.mjs +137 -0
  30. package/mas/toolsets.mjs +64 -0
  31. package/mas/trajectory_export.mjs +169 -0
  32. package/mas/trajectory_store.mjs +179 -0
  33. package/mas/user_modeler.mjs +108 -0
  34. package/package.json +20 -3
  35. package/providers/codex_cli.mjs +200 -0
  36. package/providers/gemini_cli.mjs +179 -0
  37. package/providers/registry.mjs +61 -1
  38. package/sandbox/base.mjs +82 -0
  39. package/sandbox/confiners/bubblewrap.mjs +21 -0
  40. package/sandbox/confiners/firejail.mjs +16 -0
  41. package/sandbox/confiners/landlock.mjs +14 -0
  42. package/sandbox/confiners/seatbelt.mjs +28 -0
  43. package/sandbox/daytona.mjs +37 -0
  44. package/sandbox/docker.mjs +91 -0
  45. package/sandbox/index.mjs +67 -0
  46. package/sandbox/local.mjs +59 -0
  47. package/sandbox/modal.mjs +53 -0
  48. package/sandbox/singularity.mjs +39 -0
  49. package/sandbox/ssh.mjs +56 -0
  50. package/sandbox.mjs +11 -127
  51. package/scripts/hermes-import.mjs +111 -0
  52. package/scripts/migrate-v5.mjs +342 -0
  53. package/scripts/openclaw-import.mjs +71 -0
  54. package/sessions.mjs +20 -1
package/README.md CHANGED
@@ -1,582 +1,246 @@
1
- # 🦞 lazyclaw
1
+ # lazyclaw
2
2
 
3
- [![npm](https://img.shields.io/npm/v/lazyclaw.svg)](https://www.npmjs.com/package/lazyclaw)
4
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
5
- [![Node](https://img.shields.io/badge/node-%E2%89%A518-blue.svg)](https://nodejs.org/)
6
-
7
- **A lazy, elegant terminal CLI for Claude / OpenAI / Gemini / Ollama.**
8
-
9
- One Node CLI that talks to every major LLM provider, runs multi-step workflows as a DAG, exposes a local HTTP gateway, and ships with the niceties you actually want at the prompt: an ASCII banner on launch, Cursor-style slash-command ghost autocomplete (right-arrow accepts), persistent chat sessions, and cost rate cards.
10
-
11
- > Standalone CLI. A companion dashboard, [LazyClaude](https://github.com/cmblir/LazyClaude), wraps the same providers in a web UI — but `lazyclaw` needs nothing from it: `npm i -g lazyclaw` and go.
12
-
13
- Every subcommand at a glance — `lazyclaw --help`:
14
-
15
- <img src="docs/screenshots/help.png" alt="lazyclaw --help — full subcommand reference" width="760">
16
-
17
- ---
18
-
19
- ## Install
20
-
21
- ```bash
22
- npm install -g lazyclaw
23
- lazyclaw version
24
- ```
25
-
26
- Requires **Node 18+**. Works on macOS / Linux / WSL. Windows native PowerShell mostly works but the ghost-text + ANSI banner are TTY-gated and may fall back to plain prompts.
27
-
28
- ## First run
29
-
30
- ```bash
31
- lazyclaw onboard # arrow-key picker; defaults to claude-cli (no key)
32
- lazyclaw status # current provider/model + masked key
33
- lazyclaw doctor # validate config + provider registry
34
- ```
35
-
36
- `onboard` writes `~/.lazyclaw/config.json`. Move it with `LAZYCLAW_CONFIG_DIR=/elsewhere`. For automation: `--non-interactive --provider X --model Y [--api-key Z]`.
37
-
38
- <img src="docs/screenshots/onboard.png" alt="lazyclaw onboard --non-interactive — writes config.json, prints JSON result" width="760">
39
-
40
- <img src="docs/screenshots/doctor.png" alt="lazyclaw doctor — config + provider registry health check" width="760">
41
-
42
- ### Subscription mode (no API key)
43
-
44
- If you already have **Claude Code** installed and signed in (Pro / Max / Team subscription), pick the **`claude-cli`** provider during onboard. lazyclaw shells out to the local `claude` binary, so requests bill against your existing subscription quota instead of pay-per-token API credit. No `sk-ant-` key needed.
45
-
46
- ```bash
47
- lazyclaw onboard --non-interactive --provider claude-cli --model claude-opus-4-7
48
- lazyclaw status
49
- # → { provider: "claude-cli", model: "claude-opus-4-7", hasApiKey: false }
50
- ```
51
-
52
- Same flow for `ollama` (local models, also keyless).
53
-
54
- ### Pay-per-token mode (API key)
55
-
56
- Pick `anthropic` / `openai` / `gemini` and supply the matching key:
57
-
58
- ```bash
59
- lazyclaw onboard --non-interactive --provider openai \
60
- --model gpt-4.1 --api-key sk-...
61
- ```
62
-
63
- `onboard` only prompts for an api-key when the picked provider's `requiresApiKey` is true (the picker labels each row `[subscription]` / `[api key]` / `[no key]` so the choice is explicit).
64
-
65
- ### Built-in OpenAI-compatible vendors
66
-
67
- Eight popular OpenAI-compatible services ship as first-class providers — pick one in the setup picker (no `+ Add custom` walkthrough needed) or set the matching environment variable and they Just Work:
68
-
69
- | Provider | Models include | Env var |
70
- |---|---|---|
71
- | `nim` | `meta/llama-3.1-405b-instruct`, `nvidia/llama-3.1-nemotron-70b-instruct`, `deepseek-ai/deepseek-r1`, `mistralai/mixtral-8x22b-instruct-v0.1` | `NVIDIA_API_KEY` (or `NIM_API_KEY`) |
72
- | `openrouter` | `anthropic/claude-3.5-sonnet`, `openai/gpt-4o`, `meta-llama/llama-3.1-405b-instruct`, `deepseek/deepseek-r1` | `OPENROUTER_API_KEY` |
73
- | `groq` | `llama-3.3-70b-versatile`, `mixtral-8x7b-32768`, `deepseek-r1-distill-llama-70b` | `GROQ_API_KEY` |
74
- | `together` | `meta-llama/Llama-3.3-70B-Instruct-Turbo`, `Qwen/Qwen2.5-72B-Instruct-Turbo`, `deepseek-ai/DeepSeek-V3` | `TOGETHER_API_KEY` |
75
- | `xai` | `grok-2-latest`, `grok-2-vision-1212` | `XAI_API_KEY` (or `GROK_API_KEY`) |
76
- | `deepseek` | `deepseek-chat`, `deepseek-reasoner` | `DEEPSEEK_API_KEY` |
77
- | `mistral` | `mistral-large-latest`, `codestral-latest`, `pixtral-large-latest` | `MISTRAL_API_KEY` |
78
- | `fireworks` | `accounts/fireworks/models/llama-v3p3-70b-instruct`, `…/deepseek-r1` | `FIREWORKS_API_KEY` |
79
-
80
- ```bash
81
- # NVIDIA NIM via env var — no `lazyclaw onboard` needed
82
- export NVIDIA_API_KEY=nvapi-...
83
- lazyclaw chat --provider nim --model meta/llama-3.1-405b-instruct
84
-
85
- # Or commit the choice to ~/.lazyclaw/config.json
86
- lazyclaw onboard --non-interactive --provider nim \
87
- --model nvidia/llama-3.1-nemotron-70b-instruct --api-key nvapi-...
88
- ```
89
-
90
- Need a vendor that's **not** built-in? `+ Add a custom OpenAI-compatible endpoint…` inside the setup picker (or `lazyclaw providers add <name> --base-url <url>`) still works for vLLM / LM Studio / private gateways / anything else that speaks the OpenAI v1 wire format.
91
-
92
- ### `orchestrator` — multi-agent dispatch as a provider
93
-
94
- `orchestrator` is a synthetic provider that composes the others. A chat message hitting `PROVIDERS.orchestrator` triggers a three-phase pipeline instead of a single 1:1 call:
95
-
96
- 1. **PLAN** — the *planner* provider decomposes the request into 2–5 parallel subtasks (JSON-only system prompt; fences / prose tolerated).
97
- 2. **EXECUTE** — each subtask is dispatched round-robin across the *workers*. Replies stream inline so you watch progress in real time.
98
- 3. **SYNTHESIS** — the planner re-enters with every worker's output and writes the final user-facing answer.
99
-
100
- Configure in `~/.lazyclaw/config.json`:
101
-
102
- ```json
103
- {
104
- "provider": "orchestrator",
105
- "orchestrator": {
106
- "planner": "claude-cli:claude-opus-4-7",
107
- "workers": [
108
- "claude-cli:claude-sonnet-4-6",
109
- "openai:gpt-4o",
110
- "gemini:gemini-2.5-pro",
111
- "nim:meta/llama-3.1-405b-instruct"
112
- ],
113
- "maxSubtasks": 5
114
- }
115
- }
116
- ```
117
-
118
- Then `lazyclaw chat` (or any other entry point that ends up calling a provider — `lazyclaw agent`, the daemon's `POST /agent` / `POST /chat`, the dashboard chat tab) routes through the orchestrator. Each worker's api-key is resolved through the same chain a direct chat would use (`authProfiles` → `customProviders` → built-in env var → legacy `cfg['api-key']`).
119
-
120
- Defaults fall back gracefully: `planner` defaults to `cfg.provider`/`cfg.model`, `workers` defaults to `[planner]` (single-agent chain, still benefits from plan + synthesis structure). Self-recursion (`planner: "orchestrator"`) is rejected up front.
121
-
122
- You can skip the JSON entirely and configure via `lazyclaw onboard` / `lazyclaw setup` (the picker lands on the orchestrator and walks you through a planner + workers wizard) **or** via the dedicated CLI:
123
-
124
- ```bash
125
- lazyclaw orchestrator status
126
- lazyclaw orchestrator set-planner claude-cli:claude-opus-4-7
127
- lazyclaw orchestrator workers add openai:gpt-4o
128
- lazyclaw orchestrator workers add gemini:gemini-2.5-pro
129
- lazyclaw orchestrator workers set claude-cli:claude-sonnet-4-6,nim:meta/llama-3.1-405b-instruct # bulk replace
130
- lazyclaw orchestrator set-max-subtasks 5
131
- lazyclaw orchestrator clear # wipe cfg.orchestrator
132
- lazyclaw config set provider orchestrator # route chats through it
133
- ```
3
+ <img src="docs/assets/sleepy-sloth-source.png" alt="lazyclaw sloth" width="120" align="right">
134
4
 
135
- ## Launcher (no-arg `lazyclaw`)
5
+ **A terminal agent whose learning loop runs free on your Claude Pro subscription.**
136
6
 
137
- Running `lazyclaw` with no subcommand drops into an arrow-key launcher with every subcommand laid out as a menu. Navigation:
7
+ Chat with any provider. Train the skill bank, user model, and reflection pass on `claude-cli` $0. One SQLite + FTS5 store remembers every session. Hand the same conversation off between TUI, Slack, Discord, Telegram, Matrix, Email, and Voice.
138
8
 
139
- | Key | What it does |
140
- |---|---|
141
- | `↑` / `↓` / `Home` / `End` / `PgUp` / `PgDn` | Move the selection |
142
- | `Enter` | Run the highlighted item |
143
- | `q` / `Esc` / `Ctrl-C` | Leave lazyclaw |
144
- | `/` | Open an inline slash-command prompt |
145
-
146
- Slash commands at the launcher (typed after `/`):
147
-
148
- | Slash | What it does |
149
- |---|---|
150
- | `/exit` / `/quit` | Leave lazyclaw |
151
- | `/help` | List launcher slash commands inline |
152
- | `/version` | Print version + node + platform |
153
-
154
- The slash buffer lives just below the menu — backspace edits it, deleting past `/` returns to menu mode, and `Esc` cancels slash mode without leaving lazyclaw.
155
-
156
- ## Interactive chat
9
+ [![npm](https://img.shields.io/npm/v/lazyclaw.svg)](https://www.npmjs.com/package/lazyclaw)
10
+ [![Node](https://img.shields.io/badge/node-%E2%89%A518-blue.svg)](https://nodejs.org/)
11
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
157
12
 
158
13
  ```bash
159
- lazyclaw chat # banner + active provider/model + REPL
160
- lazyclaw chat --pick # arrow-key picker before the prompt
161
- lazyclaw chat --session daily # persist turns to ~/.lazyclaw/sessions/daily.jsonl
162
- lazyclaw chat --skill review,style # compose named skills as the system prompt
163
- ```
164
-
165
- What you see on launch (TTY only):
166
-
167
- ```text
168
- ╭──────────────────────────────╮
169
- │ _ │
170
- │ | |__ _ _____ _ _ │
171
- │ | / _` |_ / || | '_| │
172
- │ |_\__,_/__\_, |_| │
173
- │ LazyClaw |__/ 3.99.11 │
174
- ╰──────────────────────────────╯
175
-
176
- provider · anthropic
177
- model · claude-opus-4-7
178
- slash · /help · /model · /provider · /exit
179
- hint · → to accept the suggested command, Tab to cycle
180
-
181
-
14
+ npx lazyclaw onboard # 15 seconds to a working CLI
182
15
  ```
183
16
 
184
- Slash commands inside the REPL:
17
+ <img src="docs/screenshots/help.png" alt="lazyclaw subcommand reference" width="820">
185
18
 
186
- | Slash | What it does |
187
- |---|---|
188
- | `/help` | List slash commands |
189
- | `/status` | Print provider + model + masked key |
190
- | `/provider` | Open the family / provider / model arrow picker |
191
- | `/provider X` | Switch active provider directly by name |
192
- | `/model` | Open the per-provider model picker (type-filter + live `/v1/models` fetch) |
193
- | `/model X` | Switch model directly. Accepts unified `provider/model` form |
194
- | `/skill a,b` | Replace the system prompt with a composition of named skills |
195
- | `/loop "<prompt>" [--max N] [--until "<regex>"]` | Repeat one prompt N times (default 3, cap 50). `--until` short-circuits when the regex matches. Ctrl-C aborts the loop. |
196
- | `/loop "..." --use-memory --recall "<query>"` | Inject `~/.lazyclaw/memory/core.md` and the top-3 matching episodic/recent fragments into the system slot per iteration |
197
- | `/goal` | List active goals |
198
- | `/goal <name>` | Switch the chat to the goal's session (subsequent turns persist to `goal:<name>.jsonl`) |
199
- | `/goal add <name> [--desc "..."] [--cron "<spec>"]` | Register a persistent goal; `--cron` schedules `lazyclaw goal tick <name>` |
200
- | `/goal close <name> [done\|abandoned]` | Close the goal and uninstall its cron entry |
201
- | `/memory [core\|recent\|episodic [topic]]` | Show layered memory contents |
202
- | `/dream` | Consolidate `recent.jsonl` into per-topic `episodic/<topic>.md` files |
203
- | `/agent` / `/agent list` | List registered multi-agent agents |
204
- | `/agent show <name>` | Print the agent's JSON record |
205
- | `/agent add <name> [role text…]` | Register an agent with the default tool whitelist `[bash, read, write, grep]` |
206
- | `/agent remove <name>` | Delete the agent's record |
207
- | `/team` / `/team list` | List teams + lead + members + Slack channel |
208
- | `/team add <name> --agents a,b,c [--lead a] [--channel #x]` | Create a team |
209
- | `/team remove <name>` | Delete the team |
210
- | `/usage` | Message count + chars + cumulative token totals |
211
- | `/new` / `/reset` | Wipe history and start over |
212
- | `/exit` | Leave the chat REPL (returns to the launcher when chat was opened from it) |
213
-
214
- **Cursor-style ghost autocomplete**: type `/` and the longest matching slash command appears in dim grey after the cursor. **`→`** accepts; **`Tab`** cycles. **Ctrl-C** during a streaming reply aborts that turn (not the whole process); **Ctrl-C** at an empty prompt exits.
215
-
216
- ## One-shot (no REPL)
19
+ *한국어: [README.ko.md](./README.ko.md)*
217
20
 
218
- ```bash
219
- lazyclaw agent "summarize: $(cat file.md)"
220
- lazyclaw agent - < prompt.txt # stdin
221
- lazyclaw agent "..." --provider openai --model gpt-4.1
222
- lazyclaw agent "..." --skill review # compose system prompt
223
- lazyclaw agent "..." --usage # token counts on stderr
224
- lazyclaw agent "..." --cost # USD when rates configured
225
- ```
226
-
227
- ## Loops and goals (durable agents)
21
+ ---
228
22
 
229
- ```bash
230
- # Repeat one prompt N times against the active provider. Foreground
231
- # blocks the terminal; --detach forks a worker and prints {loopId,
232
- # pid, statePath}. Worker state under ~/.lazyclaw/loops/<id>/.
233
- lazyclaw loop "fix the failing tests" --max 5 --until "DONE"
234
- lazyclaw loop "ship checklist" --max 10 --detach --session daily
235
- lazyclaw loops list
236
- lazyclaw loops show <loopId>
237
- lazyclaw loops tail <loopId>
238
- lazyclaw loops kill <loopId> # SIGTERM; repeat within 5s for SIGKILL
239
-
240
- # Goals: persistent objectives with optional cron schedule + channel fan-out.
241
- lazyclaw goal add ship-v4 --desc "Ship v4" --cron "0 9 * * 1-5"
242
- lazyclaw goal list
243
- lazyclaw goal tick ship-v4 --force
244
- lazyclaw goal channel add ship-v4 slack:#deploys
245
- lazyclaw goal close ship-v4 done # also uninstalls the cron entry
246
-
247
- # Memory: ~/.lazyclaw/memory/{core.md,recent.jsonl,episodic/*.md}
248
- lazyclaw memory show core
249
- lazyclaw memory show recent
250
- lazyclaw memory dream # consolidate recent → episodic files
251
- lazyclaw memory edit core # open $EDITOR
252
- ```
23
+ ## Why lazyclaw
253
24
 
254
- For Slack fan-out, set `SLACK_BOT_TOKEN` (xoxb-...) in `~/.lazyclaw/.env`.
255
- Tokens never appear in goal records or logs. Socket Mode inbound also
256
- needs `SLACK_APP_TOKEN` (xapp-...) and `SLACK_SIGNING_SECRET`.
25
+ Four things no other terminal agent CLI does together:
257
26
 
258
- ## Multi-agent Slack teams (v4.1)
27
+ 1. **Split chat and trainer providers.** Pay-per-token for chat, $0 subscription for the learning loop. Or vice versa.
28
+ 2. **Recall across every CLI.** One FTS5 index over sessions, skills, trajectories, and memory.
29
+ 3. **Cross-channel handoff.** `/handoff slack <channel-id>` moves the live conversation; context follows.
30
+ 4. **Six sandbox backends, one API.** `local` / `docker` / `ssh` / `singularity` / `modal` / `daytona`.
259
31
 
260
- Drive a small team of named agents through a single Slack thread. The
261
- lead agent receives the user's request, decides who else on the team
262
- should weigh in, `@mentions` them, and the router runs each mentioned
263
- agent in turn through the full tool-use loop (bash / read / write /
264
- grep) before handing control back. The thread terminates when the lead
265
- emits the literal marker `[[TASK_DONE]]` or the per-task iteration
266
- budget runs out. Each agent's reply is mirrored into the Slack thread
267
- under its own persona (`chat:write.customize` makes the username + icon
268
- match the agent in Slack's UI).
32
+ ## Known limitations (v5.1 roadmap)
269
33
 
270
- ```bash
271
- # 1) Register agents — system prompt + provider + per-agent tool whitelist
272
- lazyclaw agent add planner --role "Project planner" --provider anthropic --model claude-opus-4-7
273
- lazyclaw agent add backend --role "Backend engineer" --provider anthropic --model claude-opus-4-7
274
- lazyclaw agent add frontend --role "Frontend engineer" --provider openai --model gpt-4.1
275
- lazyclaw agent list
276
-
277
- # 2) Group them into a team that talks in a specific Slack channel
278
- lazyclaw team add shop --agents planner,backend,frontend --lead planner --channel '#shop'
279
-
280
- # 3) Open a task — posts a root message into the team's channel, returns
281
- # the task id and the Slack thread_ts.
282
- lazyclaw task start --team shop --title "ship checkout flow" --description "MVP scope"
283
-
284
- # 4) Drive one user turn through the mention router. The lead replies,
285
- # @mentions teammates, they run tool-use loops, hand back to the lead.
286
- lazyclaw task tick t_20260518_xxxxxx "go" --max-turns 12
287
-
288
- # 5) Inspect the conversation (text, markdown, or raw JSON)
289
- lazyclaw task transcript t_20260518_xxxxxx --format md > thread.md
290
- lazyclaw task show t_20260518_xxxxxx
291
- lazyclaw task done t_20260518_xxxxxx # or `abandon` — also posts a closing message
292
-
293
- # 6) Agent memory carries lessons forward across tasks (v4.2). The
294
- # router auto-fires a ≤6-bullet reflection per participating agent
295
- # when a task transitions to done. Manual control:
296
- lazyclaw agent memory show planner
297
- lazyclaw agent memory edit planner # opens $EDITOR
298
- lazyclaw agent memory clear planner
299
- lazyclaw agent reflect planner --task t_20260518_xxxxxx
300
- # Flip auto reflection off per agent: edit ~/.lazyclaw/agents/<name>.json
301
- # and set "memoryWrite": "off" (other values: "auto" default, "manual").
302
- ```
34
+ Calibrate expectations before reading the rest:
303
35
 
304
- ### Self-improving skills (v4.3)
36
+ - `recall` is callable from inside chat today; the top-level `lazyclaw recall ...` CLI shape ships in v5.1.
37
+ - `lazyclaw sandbox` exposes `list | test | add | use`; the `sandbox run --backend ...` shape lands in v5.1.
38
+ - `codex-cli` and `gemini-cli` provider modules are tracked but not yet registered in the main runtime.
39
+ - E2E matrix ships with 32 of 48 flows marked `test.skip` pending v5.1 wiring; the min-green-set is documented in `tests/e2e/phaseH-e2e-matrix.spec.ts`.
305
40
 
306
- Reflection writes free-text *lessons* to an agent's memory. A **skill**
307
- goes further: it distils a finished task into a reusable, structured
308
- `SKILL.md` (`## When to Use` / `## Procedure` / `## Pitfalls` /
309
- `## Verification`) that any future agent can load. This is the Hermes
310
- self-improving-skill pattern — synthesise once, recall forever.
41
+ ## Install
311
42
 
312
43
  ```bash
313
- # Synthesise a skill from a finished task. Mirrors `agent reflect`:
314
- # one LLM call over the transcript → a SKILL.md installed into
315
- # ~/.lazyclaw/skills/<name>.md (frontmatter created_by: agent).
316
- lazyclaw agent skill-synth planner --task t_20260518_xxxxxx
317
- lazyclaw agent skill-synth planner --task t_20260518_xxxxxx --dry-run # print, don't write
318
-
319
- # Opt an agent into AUTOMATIC synthesis on task done (default is manual):
320
- lazyclaw agent add researcher --skill-write auto # auto | manual (default) | off
321
- ```
44
+ # Try it (no install)
45
+ npx lazyclaw onboard && lazyclaw chat
322
46
 
323
- **Recall is progressive-disclosure.** Every agent turn gets a compact
324
- *index* of installed skills (name + one-line summary) injected into its
325
- system prompt — cheap, a line per skill. The agent pulls a full skill
326
- body on demand with the built-in read-only **`skill_view`** tool, so
327
- skill bodies never bloat the prompt until they're actually needed.
328
- `skill_view` ships in the default tool whitelist, so newly-created
329
- agents recall skills out of the box; older agents pick it up via
330
- `lazyclaw agent edit <name> --tools bash,read,write,grep,skill_view`.
331
-
332
- `skill-synth` defaults to `manual` (you run the command, or pass
333
- `--dry-run` to review first) because a synthesised skill feeds every
334
- future agent's prompt — keep it opt-in until you trust an agent's
335
- output. Flip the trigger any time with
336
- `lazyclaw agent edit <name> --skill-write auto|manual|off`.
337
-
338
- Auto-synthesis is defended for the cases where it runs unattended:
339
- secret-shaped tokens (`sk-…`, `ghp_…`, `AKIA…`, bearer tokens,
340
- `*_KEY=…`, PEM blocks) are redacted from both the transcript sent to
341
- the model and the saved skill; synthesised bodies are size-capped and
342
- the `[[TASK_DONE]]` marker is neutralised; and a synthesised skill
343
- **never overwrites a human-authored skill** — on a name collision it
344
- takes the next free `name-N` slug, only ever overwriting (and
345
- version-bumping) its own prior output. Skill bodies are framed to the
346
- model as untrusted reference, not instructions.
347
-
348
- Slack inbound (a user pings `@lazyclaw` in a channel, the bot replies)
349
- runs through the Socket Mode listener:
47
+ # Keep it
48
+ npm install -g lazyclaw
350
49
 
351
- ```bash
352
- lazyclaw slack listen # foreground; connects, reacts with :eyes:, replies in thread
50
+ # Hack on it
51
+ git clone https://github.com/cmblir/lazyclaw && cd lazyclaw
52
+ npm install && npm link
353
53
  ```
354
54
 
355
- ### Telegram — zero-install mobile control (v4.3)
356
-
357
- Control lazyclaw from your phone with no app to install and no public
358
- URL: the Telegram listener long-polls the Bot API (works behind NAT),
359
- pipes each inbound message through the active provider, and replies in
360
- the same chat. Push notifications are handled by Telegram itself.
361
-
362
55
  ```bash
363
- # 1) Create a bot with @BotFather, then store its token:
364
- echo 'TELEGRAM_BOT_TOKEN=123456:ABC...' >> ~/.lazyclaw/.env
365
-
366
- # 2) (recommended) restrict who can drive it — your Telegram numeric user id:
367
- lazyclaw pairing add 987654321
368
-
369
- # 3) Listen. Foreground; Ctrl-C to stop. An empty pairing allowlist
370
- # means "reply to anyone who messages the bot".
371
- lazyclaw telegram listen --provider anthropic --model claude-opus-4-7
56
+ lazyclaw version
57
+ # → { "version": "5.0.0", "nodeVersion": "v20.11.0", "platform": "darwin" }
372
58
  ```
373
59
 
374
- The `pairing` allowlist doubles as the Telegram sender allowlist, so
375
- only paired ids get a reply.
376
-
377
- ### Matrix + generic inbound (v4.3)
378
-
379
- The same pattern extends to **Matrix** over the client-server `/sync`
380
- long-poll (no SDK):
381
-
382
- ```bash
383
- printf 'MATRIX_HOMESERVER=https://matrix.org\nMATRIX_ACCESS_TOKEN=...\nMATRIX_USER_ID=@you:matrix.org\n' >> ~/.lazyclaw/.env
384
- lazyclaw matrix listen # pairing allowlist = @user:server ids
385
- ```
60
+ Requires **Node 18+**. macOS / Linux / WSL are first-class. Native PowerShell runs but ghost-text and the ANSI banner fall back to plain prompts.
386
61
 
387
- For any platform lazyclaw doesn't natively speak (Discord DMs, WhatsApp,
388
- Signal, Email — each needs a heavy SDK or external binary), run your own
389
- relay and forward messages to the **generic inbound webhook** on the
390
- daemon — no extra dependency in lazyclaw:
62
+ ## First run
391
63
 
392
64
  ```bash
393
- curl -s localhost:<port>/inbound -H 'content-type: application/json' \
394
- -d '{"text":"hi from anywhere","senderId":"123","threadId":"discord:42"}'
395
- # → { "reply": "...", "threadId": "discord:42" }
65
+ lazyclaw onboard # arrow-key picker; defaults to claude-cli (no key)
66
+ # writes ~/.lazyclaw/config.json
396
67
  ```
397
68
 
398
- `/inbound` runs the active provider and is auth-token-gated; when a
399
- `pairing` allowlist exists, `senderId` must be on it. Native adapters
400
- (Telegram, Matrix, Slack) all implement the same `channels/base.mjs`
401
- contract, so an SDK-backed channel can be dropped in later behind an
402
- explicit dependency review.
403
-
404
- The CLI is mirrored by daemon HTTP routes (`GET/POST/PATCH/DELETE
405
- /agents|teams|tasks`, `GET /tasks/<id>/transcript`) and by the
406
- browser dashboard's Agents / Teams / Tasks tabs:
69
+ <img src="docs/screenshots/onboard.png" alt="lazyclaw onboard --non-interactive" width="720">
407
70
 
408
71
  ```bash
409
- lazyclaw dashboard # opens http://127.0.0.1:<port>/ in the default browser
72
+ lazyclaw status # { provider, model, hasApiKey }
73
+ lazyclaw doctor # validates config + provider registry + index.db
410
74
  ```
411
75
 
412
- Slack app prerequisites bot token scopes `app_mentions:read`,
413
- `chat:write`, `chat:write.customize`, `im:history`, `im:read`,
414
- `im:write`, `channels:history`, `reactions:write`; Socket Mode enabled;
415
- app token scope `connections:write`; invite the bot into every team
416
- channel. Tokens live exclusively in `~/.lazyclaw/.env` and never appear
417
- in agent/team/task records or logs.
76
+ Move the config dir with `LAZYCLAW_CONFIG_DIR=/elsewhere`. For automation, add `--non-interactive --provider X --model Y [--api-key Z]`.
418
77
 
419
- For the full data model + phase plan, see `docs/multi-agent.md`.
78
+ ## The trainer split $0 learning on your Claude Pro subscription
420
79
 
421
- ## Providers / sessions / skills
80
+ v5 separates two provider slots in your config: `provider` (chat — the hot path) and `trainer.provider` (skill synthesis, user-model updates, reflection — bursty, cheap). They are wired independently, so a Pro/Max subscription can power the learning loop while chat runs through any provider, paid or local. lazyclaw is the **only** terminal agent CLI that splits these two roles.
422
81
 
423
- ```bash
424
- lazyclaw providers list # all registered providers
425
- lazyclaw providers info anthropic
426
- lazyclaw providers test anthropic # 1-token reachability probe
427
-
428
- lazyclaw sessions list # persisted chats
429
- lazyclaw sessions show daily
430
- lazyclaw sessions search "deploy"
431
- lazyclaw sessions export daily > daily.md
432
- lazyclaw sessions clear daily
433
-
434
- lazyclaw skills list # markdown skill bundles
435
- lazyclaw skills show review
436
- lazyclaw skills install ./my-skill.md
437
- lazyclaw skills remove review
438
-
439
- lazyclaw skills classify deploy-flow # active | stale (30d) | archived (90d)
440
- lazyclaw skills curate # archive agent skills unused >90d → skills/.archive/
82
+ ```jsonc
83
+ // ~/.lazyclaw/config.json
84
+ {
85
+ "provider": "openai", // chat: pay-per-token
86
+ "model": "gpt-4.1",
87
+ "trainer": {
88
+ "provider": "claude-cli", // trainer: $0 on Pro/Max
89
+ "model": "claude-haiku-4-5",
90
+ "schedule": "nightly",
91
+ "budget": { "maxCallsPerDay": 200, "usdPerDay": 0.50 }
92
+ }
93
+ }
441
94
  ```
442
95
 
443
- `skills curate` is the lifecycle sweep for self-improving skills:
444
- agent-authored skills that haven't been recalled (`skill_view`) in 90
445
- days move to `skills/.archive/` (recoverable); human-authored skills are
446
- never touched. Pair it with a `HEARTBEAT.md` routine (see
447
- `lazyclaw workspace init`, which now scaffolds AGENTS / SOUL / TOOLS /
448
- **HEARTBEAT**) and `lazyclaw cron` to run it on a schedule.
96
+ The canonical default is `trainer.provider = "auto"` — resolves to `claude-cli` when a Pro/Max session is detected, else mirrors the chat provider.
449
97
 
450
- <img src="docs/screenshots/providers.png" alt="lazyclaw providers info anthropic — model list + capabilities" width="760">
98
+ **Three configs covering the common cases:**
451
99
 
452
- ## Workflows (DAG / sequential / persistent)
100
+ | Setup | `provider` | `trainer.provider` | Cost |
101
+ |---|---|---|---|
102
+ | Subscription only | `claude-cli` | `claude-cli` | $0 |
103
+ | Hybrid (recommended) | `openai` / any | `claude-cli` | chat-only |
104
+ | Pure API | `openai` / any | `openai` / any | both metered |
453
105
 
454
- ```bash
455
- lazyclaw run my-job ./flow.mjs # sequential, resumable
456
- lazyclaw run my-job ./flow.mjs --parallel --concurrency 4 # in-memory DAG
457
- lazyclaw run my-job ./flow.mjs --parallel-persistent # DAG + checkpoints
458
- lazyclaw resume my-job ./flow.mjs # resume a stalled run
459
-
460
- lazyclaw inspect # list every session
461
- lazyclaw inspect my-job --summary
462
- lazyclaw inspect my-job --critical-path ./flow.mjs # bottleneck finder
463
- lazyclaw inspect my-job --slowest 5
464
- ```
106
+ Full JSONC examples and the `auto` resolution rules: [docs/trainer-recipes.md](./docs/trainer-recipes.md).
465
107
 
466
- State at `./.workflow-state/<id>/` (override with `LAZYCLAW_WORKFLOW_STATE_DIR=...`).
108
+ ## Provider matrix
467
109
 
468
- ## Local HTTP gateway
110
+ | Chat provider | Trainer provider | Auth |
111
+ |---|---|---|
112
+ | `claude-cli` | `claude-cli` | subscription (Pro/Max) |
113
+ | `anthropic` | `anthropic` | API key |
114
+ | `openai` | `openai` | API key |
115
+ | `gemini` | `gemini` | API key |
116
+ | `ollama` | `ollama` | local (no key) |
117
+ | `nim` / `openrouter` / `groq` / `together` / `xai` / `deepseek` / `mistral` / `fireworks` | — | API key (OpenAI-compatible) |
469
118
 
470
- ```bash
471
- lazyclaw daemon # bind a free port; prints { port, url }
472
- lazyclaw daemon --port 19600
473
- lazyclaw daemon --auth-token $(openssl rand -hex 16)
474
- lazyclaw daemon --rate-limit 60 --log info # 60 req/min/IP, JSON access logs
475
- lazyclaw daemon --once # serve a single request, then exit
476
- ```
119
+ Plus two meta-providers, usable in either slot:
120
+ - `orchestrator` composes any of the above into a multi-agent pipeline ([docs/multi-agent.md](./docs/multi-agent.md))
121
+ - `custom` any OpenAI-compatible v1 endpoint with your own base URL + key
477
122
 
478
- ### Device gatewaycompanion nodes (v4.3)
123
+ <img src="docs/screenshots/providers.png" alt="lazyclaw providers info model list + capabilities" width="720">
479
124
 
480
- A companion node (a future mobile/menu-bar app, or just `curl`)
481
- authenticates to the daemon with per-device Ed25519 keys, gated by
482
- explicit operator approval — the OpenClaw gateway model, realised over
483
- HTTP + SSE (no extra dependency). The daemon stays loopback-bound;
484
- expose it remotely only behind a tunnel (Tailscale / Cloudflare) + TLS,
485
- and set `--auth-token` for the non-gateway routes.
125
+ ## What it ships
486
126
 
487
- Handshake (all under `/gateway/`, which has its own device-auth so it
488
- sits outside the daemon's shared `--auth-token` gate):
127
+ ### Around 50 tools plus MCP
128
+ A unified registry covers fs, exec, web, os, coding, git (5 read + 2 sensitive), scheduling, delegation, media, ha, clarify, browser, and learning groups. Sensitive tools route through an approval hook. Bring external servers in over stdio MCP.
489
129
 
490
- 1. `POST /gateway/connect/challenge` `{ nonce, ts }` (single-use, time-boxed).
491
- 2. `POST /gateway/connect` with `{ payload, signature, publicKey, nonce }`
492
- — the node signs the canonical payload with its Ed25519 key. The
493
- gateway verifies the signature, **binds the key to the claimed device
494
- id**, enforces nonce single-use (anti-replay) and freshness. An
495
- unapproved device gets `403 { status: 'pending', requestId }`; an
496
- approved one gets its rotated bearer `token`.
497
- 3. Operator approves out-of-band:
130
+ ### Channels that hand off
131
+ First-class channels for Slack, Discord, Telegram, Matrix, Email, and Voice. Signal and WhatsApp ship as full implementations with external runtime dependencies (`signal-cli` for Signal; `whatsapp-web.js` browser automation with QR-on-first-run for WhatsApp). Move a live conversation between any two with `/handoff <target> <externalId>` — no other agent CLI does cross-channel handoff.
498
132
 
499
133
  ```bash
500
- lazyclaw nodes pending # list pending pairing requests
501
- lazyclaw nodes approve <requestId> # mint + rotate the device token (never printed)
502
- lazyclaw nodes devices # approved devices (token masked)
503
- lazyclaw nodes revoke <deviceId> # drop a device's approval + token
134
+ lazyclaw channels install @lazyclaw/channel-discord
135
+ # inside Slack: /handoff discord <channel-id>
136
+ # inside Discord: /handoff tui <thread-id>
504
137
  ```
505
138
 
506
- 4. The node reconnects receives its `token`, then calls authenticated
507
- routes with `Authorization: Bearer <token>` + `x-device-id: <id>`:
508
- `GET /gateway/whoami` and `GET /gateway/events` (an SSE push stream).
139
+ Slack is built-in and does not need `channels install`. The plugin loader expects `@lazyclaw/channel-<name>` npm package names.
509
140
 
510
- **Remote tool-call approval (SSE event producer).** A trusted local
511
- caller requests human approval for a sensitive action; the paired device
512
- approves it from anywhere:
513
-
514
- ```text
515
- POST /exec/request {tool,args,summary} ← auth-token-gated (local/operator)
516
- → broadcasts `exec.approval.requested` over /gateway/events
517
- → device POSTs /gateway/exec/resolve {id, decision:"approve"} (device-authed)
518
- → the request long-poll resolves { approved, by } (or denied on timeout)
519
- ```
141
+ ### Personas that compose
142
+ Swap personality per channel without losing session memory. Layers compose top-down: global SOUL → workspace SOUL → active personality → agent role → user model (USER.md) → skill bank → memory core → recent trajectory tail. See [docs/persona-cookbook.md](./docs/persona-cookbook.md).
520
143
 
521
- The MAS tool-use loop accepts an `approve` hook (`runTaskTurn` →
522
- `runAgentTurn` `runTool`) that gates the sensitive tools (`bash`,
523
- `write`) on exactly this decision; read-only tools run ungated. Pending
524
- approvals are bounded and the summary shown to the device is redacted.
144
+ ### Loops and scheduled goals
145
+ Durable foreground or `--detach` loops; cron-scheduled goals with channel fan-out. State lives in `~/.lazyclaw/loops/<id>/` and survives restart. See [docs/loop-goal-preflight.md](./docs/loop-goal-preflight.md).
525
146
 
526
- Tokens are stored owner-only (`0600`) under
527
- `~/.lazyclaw/gateway/devices.json`, compared in constant time, and
528
- rotated on every re-approval.
147
+ ### A TUI that ghosts the right answer
148
+ Ink-based UI with two-column splash, sloth ASCII banner, Cursor-style ghost autocomplete (`→` accepts, `Tab` cycles), interrupt-and-redirect REPL, multiline editor, and a fixed 4-line footer with live cost rate cards.
529
149
 
530
- ## Cost rate cards
150
+ ## Command reference
531
151
 
532
- ```bash
533
- lazyclaw rates list
534
- lazyclaw rates set anthropic/claude-opus-4-7 \
535
- --in 15 --out 75 --cache-read 1.5 --cache-create 18.75
536
- lazyclaw rates copy anthropic/claude-opus-4-7 anthropic/claude-opus-4-6
537
- lazyclaw rates delete openai/gpt-3.5-turbo
538
- lazyclaw rates validate
539
- ```
152
+ | Command | Purpose |
153
+ |---|---|
154
+ | `lazyclaw` | Interactive menu; type a slash command or pick a subcommand |
155
+ | `lazyclaw onboard` | Arrow-key setup; writes `~/.lazyclaw/config.json` |
156
+ | `lazyclaw status` | Print active provider / model / masked key |
157
+ | `lazyclaw doctor` | Validate config, provider registry, FTS5 index |
158
+ | `lazyclaw chat` | Interactive REPL with ghost autocomplete + slash commands |
159
+ | `lazyclaw agent "<prompt>"` | One-shot generate; supports stdin |
160
+ | `lazyclaw run \| resume \| inspect` | DAG / sequential / persistent workflow jobs (`--dir <state-dir>`) |
161
+ | `lazyclaw config get\|set\|list\|edit\|validate` | Dotted-key config access |
162
+ | `lazyclaw sandbox list\|test\|add\|use` | Manage sandbox backends |
163
+ | `lazyclaw channels install\|list\|remove` | Channel plugin lifecycle (`@lazyclaw/channel-<name>`) |
164
+ | `lazyclaw trajectories export --format ...` | Export to atropos / axolotl / openai-ft / jsonl |
165
+ | `lazyclaw personality use\|list\|show` | Activate / inspect personas |
166
+ | `lazyclaw migrate v5` | v4 → v5 with backup |
167
+ | `lazyclaw version` / `lazyclaw help` | Version + subcommand help |
168
+
169
+ In-REPL slash commands include `/help`, `/status`, `/provider`, `/model`, `/skill`, `/loop`, `/goal`, `/memory`, `/agent`, `/team`, `/handoff`, `/personality`, `/exit`. Depth lives in `lazyclaw <cmd> --help` and the docs below.
170
+
171
+ ## Migrating from v4
172
+
173
+ > [!IMPORTANT]
174
+ > `lazyclaw migrate v5` backs up your existing `~/.lazyclaw/` to `backup-v4-<ts>/` before rewriting anything. Don't skip the backup — the SQLite schema and skill frontmatter both change shape.
175
+
176
+ - **What changed**: split `trainer` provider block, new `~/.lazyclaw/index.db` (SQLite + FTS5), per-day JSONL trajectory sink, persona file directory, kebab-case provider IDs (`claude-cli`, `gemini-cli`, ...), additive SKILL.md frontmatter (`group`, `trained_by`, `confidence`, `cross_cli_tested`).
177
+ - **Migrate**:
178
+ ```bash
179
+ npm install -g lazyclaw@5
180
+ lazyclaw migrate v5
181
+ ```
182
+ - **Rollback**: restore `~/.lazyclaw/backup-v4-<ts>/` and `npm install -g lazyclaw@4`.
183
+
184
+ Full guide: [docs/migration-v4-to-v5.md](./docs/migration-v4-to-v5.md).
185
+
186
+ ## CLI vs Channels — quick reference
187
+
188
+ | Capability | TUI | Slack / Discord / Telegram |
189
+ |---|---|---|
190
+ | Start a chat | `lazyclaw chat` | `@lazyclaw <message>` |
191
+ | Hand off to another surface | `/handoff slack <channel-id>` | `/handoff tui <thread-id>` |
192
+ | Recall across history | `/recall "<query>"` inside chat (top-level CLI v5.1) | `/recall "<query>"` inside chat |
193
+ | Switch persona | `/personality use terse` | `/personality use terse` |
194
+ | Switch model | `/model <name>` | `/model <name>` |
195
+ | Show status | `lazyclaw status` | `@lazyclaw status` |
540
196
 
541
- `/usage` and `--cost` use these to compute USD totals locally no provider call.
197
+ Channel plugins implement a shared `channels/base.mjs` contract, so the surface you address them through is interchangeable.
542
198
 
543
- ## Config + bundles
199
+ ## Configuration
544
200
 
545
- ```bash
546
- lazyclaw config path # → ~/.lazyclaw/config.json
547
- lazyclaw config get provider
548
- lazyclaw config set provider openai
549
- lazyclaw config list
550
- lazyclaw config edit # opens $EDITOR
551
- lazyclaw config validate
552
-
553
- lazyclaw export > backup.json # config + skills (+ optional sessions)
554
- lazyclaw import --from backup.json
201
+ ```jsonc
202
+ // ~/.lazyclaw/config.json
203
+ {
204
+ "provider": "claude-cli",
205
+ "model": "claude-opus-4-7",
206
+ "trainer": {
207
+ "provider": "auto", // "auto" | claude-cli | anthropic | openai | gemini | ollama
208
+ "model": "claude-haiku-4-5",
209
+ "schedule": "nightly",
210
+ "budget": { "maxCallsPerDay": 200, "usdPerDay": 0.50 }
211
+ },
212
+ "sandbox": { "backend": "local" }, // local | docker | ssh | singularity | modal | daytona
213
+ "channels": { "slack": { "enabled": true } },
214
+ "persona": { "active": "default" },
215
+ "orchestra": { "learning": { "crossCliDampenFactor": 0.85 } }
216
+ }
555
217
  ```
556
218
 
557
- ## Shell completion
219
+ Override the config directory with `LAZYCLAW_CONFIG_DIR=/path`. Workflow state moves with `LAZYCLAW_WORKFLOW_STATE_DIR=/path`. Channel tokens live exclusively in `~/.lazyclaw/.env`. Full schema in `lazyclaw config --help` and the docs.
558
220
 
559
- ```bash
560
- lazyclaw completion bash >> ~/.bashrc
561
- lazyclaw completion zsh >> ~/.zshrc
562
- ```
221
+ ## Security and privacy
563
222
 
564
- ## File locations
223
+ > [!WARNING]
224
+ > **`~/.lazyclaw/config.json` is trusted code.** Values resolved with `$(...)` execute at config load. Treat the file like a shell rc — never paste an untrusted snippet without reading it first.
565
225
 
566
- | Path | Purpose |
567
- |---|---|
568
- | `~/.lazyclaw/config.json` | provider, model, api-key, skills, rates |
569
- | `~/.lazyclaw/sessions/*.jsonl` | persisted chat sessions |
570
- | `~/.lazyclaw/skills/*.md` | installed skill bundles |
571
- | `./.workflow-state/<id>/` | per-session workflow checkpoints (cwd-relative) |
226
+ - **Trainer transcripts stay local.** Skill synthesis and user-model writes go through your configured trainer provider only; there is no hosted lazyclaw service.
227
+ - **Sandbox backends enforce different blast radii.** `local` runs as you; `docker` / `singularity` / `daytona` isolate; `ssh` / `modal` move execution off-host. Pick per task.
228
+ - **Secrets are redacted** from trajectories and synthesised skills (`sk-...`, `ghp_...`, `AKIA...`, bearer tokens, `*_KEY=...`, PEM blocks). Channel tokens live in `~/.lazyclaw/.env` and are never logged.
572
229
 
573
- `LAZYCLAW_CONFIG_DIR=...` moves the first three; `LAZYCLAW_WORKFLOW_STATE_DIR=...` moves the last.
230
+ ## Documentation
574
231
 
575
- ---
232
+ - [docs/migration-v4-to-v5.md](./docs/migration-v4-to-v5.md) — full v4 → v5 walkthrough + rollback
233
+ - [docs/trainer-recipes.md](./docs/trainer-recipes.md) — $0, hybrid, offline, and `auto` trainer configs
234
+ - [docs/persona-cookbook.md](./docs/persona-cookbook.md) — layered persona compose stack + skin import
235
+ - [docs/multi-agent.md](./docs/multi-agent.md) — orchestrator pipeline + Slack team data model
236
+ - [docs/loop-goal-preflight.md](./docs/loop-goal-preflight.md) — durable loops and cron-scheduled goals
237
+ - [docs/agent-memory.md](./docs/agent-memory.md) — per-agent memory, reflection, and skill synthesis
238
+ - [CHANGELOG.md](./CHANGELOG.md) — release notes (Keep a Changelog)
239
+ - [README.ko.md](./README.ko.md) — Korean companion
576
240
 
577
- ## Issues / contributing
241
+ ## Community
578
242
 
579
- Source lives in [cmblir/lazyclaw](https://github.com/cmblir/lazyclaw). Issues and PRs welcome.
243
+ Source and issues: [cmblir/lazyclaw](https://github.com/cmblir/lazyclaw). PRs welcome.
580
244
 
581
245
  ## License
582
246