bajaclaw 0.14.3 → 0.14.5
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 +44 -44
- package/bin/bajaclaw.js +1 -1
- package/bin/create-bajaclaw.js +1 -1
- package/dist/agent.js +2 -2
- package/dist/api/server.js +7 -7
- package/dist/channels/gateway.d.ts +2 -2
- package/dist/channels/gateway.js +4 -4
- package/dist/claude.js +8 -8
- package/dist/cli.js +15 -15
- package/dist/commands/channel.js +2 -2
- package/dist/commands/chat.js +10 -10
- package/dist/commands/compact.js +2 -2
- package/dist/commands/daemon.js +5 -5
- package/dist/commands/dashboard.d.ts +1 -1
- package/dist/commands/dashboard.js +12 -12
- package/dist/commands/effort.js +4 -4
- package/dist/commands/guide.js +3 -3
- package/dist/commands/health.js +1 -1
- package/dist/commands/init.js +3 -3
- package/dist/commands/persona.js +1 -1
- package/dist/commands/port.js +1 -1
- package/dist/commands/setup.js +6 -6
- package/dist/commands/skill.js +8 -8
- package/dist/commands/subagent.js +1 -1
- package/dist/commands/uninstall.js +1 -1
- package/dist/concurrency.js +2 -2
- package/dist/delegation.js +2 -2
- package/dist/logger.js +1 -1
- package/dist/mcp/consumer.js +1 -1
- package/dist/memory/compact.js +1 -1
- package/dist/memory/recall.js +1 -1
- package/dist/model-picker.js +4 -4
- package/dist/persona.js +2 -2
- package/dist/prompt.js +1 -1
- package/dist/skills/auto-skiller.js +2 -2
- package/dist/skills/loader.d.ts +1 -1
- package/dist/skills/loader.js +1 -1
- package/dist/skills/matcher.js +1 -1
- package/dist/skills/porter.js +1 -1
- package/package.json +3 -3
- package/scripts/postinstall.js +4 -4
- package/scripts/run-tests.js +28 -0
- package/skills/configure-effort/SKILL.md +2 -2
- package/skills/configure-model/SKILL.md +3 -3
- package/skills/configure-tools/SKILL.md +6 -6
- package/skills/daily-briefing/SKILL.md +4 -4
- package/skills/delegate-to-subagent/SKILL.md +4 -4
- package/skills/setup-api/SKILL.md +10 -10
- package/skills/setup-compaction/SKILL.md +6 -6
- package/skills/setup-daemon/SKILL.md +1 -1
- package/skills/setup-dashboard/SKILL.md +2 -2
- package/skills/setup-discord/SKILL.md +9 -9
- package/skills/setup-heartbeat/SKILL.md +4 -4
- package/skills/setup-mcp-port/SKILL.md +2 -2
- package/skills/setup-memory-sync/SKILL.md +2 -2
- package/skills/setup-profile/SKILL.md +2 -2
- package/skills/setup-subagent/SKILL.md +1 -1
- package/skills/setup-telegram/SKILL.md +10 -10
- package/skills/setup-uninstall/SKILL.md +6 -6
- package/skills/web-research/SKILL.md +2 -2
- package/templates/code/AGENT.md +2 -2
- package/templates/code/SOUL.md +5 -2
- package/templates/custom/AGENT.md +1 -1
- package/templates/custom/SOUL.md +5 -2
- package/templates/outreach/AGENT.md +2 -2
- package/templates/outreach/SOUL.md +5 -2
- package/templates/research/AGENT.md +2 -2
- package/templates/research/SOUL.md +5 -2
- package/templates/social/AGENT.md +2 -2
- package/templates/social/SOUL.md +5 -2
- package/templates/support/AGENT.md +1 -1
- package/templates/support/SOUL.md +5 -2
package/README.md
CHANGED
|
@@ -7,17 +7,17 @@
|
|
|
7
7
|
██╔══██╗██╔══██║██ ██║██╔══██║ ██║ ██║ ██╔══██║██║███╗██║
|
|
8
8
|
██████╔╝██║ ██║╚█████╔╝██║ ██║ ╚██████╗███████╗██║ ██║╚███╔███╔╝
|
|
9
9
|
╚═════╝ ╚═╝ ╚═╝ ╚════╝ ╚═╝ ╚═╝ ╚═════╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝
|
|
10
|
-
autonomous agents on your terms · MIT · v0.14.
|
|
10
|
+
autonomous agents on your terms · MIT · v0.14.5
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
**BajaClaw is a long-running agent runtime for the `claude` CLI.** It turns
|
|
14
14
|
the one-shot `claude -p` command into an always-on, scheduled, memory-backed,
|
|
15
|
-
skill-matching autonomous agent
|
|
15
|
+
skill-matching autonomous agent - with a local dashboard, multiple profiles,
|
|
16
16
|
OS-native scheduling, and first-class MCP integration.
|
|
17
17
|
|
|
18
18
|
You install it once. It sets itself up. You run `bajaclaw start`. It goes.
|
|
19
19
|
|
|
20
|
-
> The name is a tribute to Baja Blast
|
|
20
|
+
> The name is a tribute to Baja Blast - the author's favorite soda. The
|
|
21
21
|
> dashboard ships in that same tropical-lime teal on purpose.
|
|
22
22
|
|
|
23
23
|
---
|
|
@@ -36,7 +36,7 @@ That's it. The post-install runs `bajaclaw setup` automatically, which:
|
|
|
36
36
|
- Runs the health check and tells you if anything's off
|
|
37
37
|
|
|
38
38
|
**Requirements**: Node 20+ and the `claude` CLI backend on your `PATH`.
|
|
39
|
-
BajaClaw drives the backend as a subprocess
|
|
39
|
+
BajaClaw drives the backend as a subprocess - whatever login/subscription
|
|
40
40
|
that CLI uses is what BajaClaw uses. BajaClaw itself never sees credentials.
|
|
41
41
|
|
|
42
42
|
First run, end-to-end:
|
|
@@ -82,7 +82,7 @@ A BajaClaw **cycle** is one pass of the 13-step loop in
|
|
|
82
82
|
|
|
83
83
|
You can run a cycle manually (`bajaclaw start`), schedule it (`bajaclaw
|
|
84
84
|
daemon install`), or trigger it externally (`bajaclaw trigger <event>`).
|
|
85
|
-
Cycles are idempotent
|
|
85
|
+
Cycles are idempotent - safe to re-run.
|
|
86
86
|
|
|
87
87
|
---
|
|
88
88
|
|
|
@@ -101,9 +101,9 @@ You can invoke it from a Claude Code session the same way you invoke any
|
|
|
101
101
|
other agent. The BajaClaw profile is the durable side; the Claude Code
|
|
102
102
|
descriptor is the handle.
|
|
103
103
|
|
|
104
|
-
### Claude Code skills
|
|
104
|
+
### Claude Code skills - compatible format, **isolated scope**
|
|
105
105
|
|
|
106
|
-
A BajaClaw skill is a `SKILL.md` file with YAML frontmatter
|
|
106
|
+
A BajaClaw skill is a `SKILL.md` file with YAML frontmatter - byte-for-byte
|
|
107
107
|
the same shape Claude Code uses. But BajaClaw reads only BajaClaw-owned
|
|
108
108
|
directories:
|
|
109
109
|
|
|
@@ -114,7 +114,7 @@ directories:
|
|
|
114
114
|
| 3 | `~/.bajaclaw/skills/` |
|
|
115
115
|
| 4 | `<repo>/skills/` (built-ins) |
|
|
116
116
|
|
|
117
|
-
`~/.claude/skills/` is **not** read automatically
|
|
117
|
+
`~/.claude/skills/` is **not** read automatically - that keeps the two
|
|
118
118
|
agents from stepping on each other's skill libraries.
|
|
119
119
|
|
|
120
120
|
**Porting skills from Claude Code is a one-liner:**
|
|
@@ -137,7 +137,7 @@ Skills`. See [`docs/skills.md`](docs/skills.md).
|
|
|
137
137
|
### Self-knowledge (built-in guides)
|
|
138
138
|
|
|
139
139
|
BajaClaw knows how to configure itself. Ship 13 built-in skills describe
|
|
140
|
-
the procedure for every integration
|
|
140
|
+
the procedure for every integration - ask your agent in plain language:
|
|
141
141
|
|
|
142
142
|
> "Help me set up Telegram."
|
|
143
143
|
> "Walk me through connecting Discord."
|
|
@@ -171,7 +171,7 @@ Procedure / Pitfalls / Verification sections into
|
|
|
171
171
|
`~/.bajaclaw/skills/auto/<name>/` for review.
|
|
172
172
|
|
|
173
173
|
This is BajaClaw's take on the "create a skill after a complex task"
|
|
174
|
-
behavior from agents like Hermes
|
|
174
|
+
behavior from agents like Hermes - capture procedures the first time you
|
|
175
175
|
solve them so repeats are faster.
|
|
176
176
|
|
|
177
177
|
Candidates live in `auto/` until you promote them:
|
|
@@ -187,7 +187,7 @@ Tune the trigger in the profile's `config.json`:
|
|
|
187
187
|
{ "autoSkill": { "enabled": true, "minToolUses": 5, "maxPerDay": 10 } }
|
|
188
188
|
```
|
|
189
189
|
|
|
190
|
-
### MCP
|
|
190
|
+
### MCP - isolated by default
|
|
191
191
|
|
|
192
192
|
BajaClaw uses its own MCP config. The desktop CLI's `mcpServers` is **not**
|
|
193
193
|
inherited by default. Merge order per cycle (highest wins):
|
|
@@ -195,7 +195,7 @@ inherited by default. Merge order per cycle (highest wins):
|
|
|
195
195
|
1. `<profile>/agent-mcp-config.json`
|
|
196
196
|
2. `<profile>/mcp-config.json`
|
|
197
197
|
3. `~/.bajaclaw/mcp-config.json` (user-global BajaClaw)
|
|
198
|
-
4. Desktop CLI config
|
|
198
|
+
4. Desktop CLI config - **only if `mergeDesktopMcp: true`** in the profile
|
|
199
199
|
|
|
200
200
|
Port servers from Claude Code on demand:
|
|
201
201
|
|
|
@@ -212,7 +212,7 @@ desktop MCP list on every cycle (pre-0.4 behavior).
|
|
|
212
212
|
BajaClaw's own MCP entry (`bajaclaw`) is skipped automatically during port
|
|
213
213
|
to avoid self-references.
|
|
214
214
|
|
|
215
|
-
### MCP
|
|
215
|
+
### MCP - expose
|
|
216
216
|
|
|
217
217
|
BajaClaw is itself an MCP server. `bajaclaw setup` auto-registers it so your
|
|
218
218
|
desktop MCP client (Claude Desktop and anything else that reads that config)
|
|
@@ -220,10 +220,10 @@ can query BajaClaw's state directly.
|
|
|
220
220
|
|
|
221
221
|
**Resources:**
|
|
222
222
|
|
|
223
|
-
- `bajaclaw://profiles`
|
|
223
|
+
- `bajaclaw://profiles` - list of profiles
|
|
224
224
|
- `bajaclaw://profile/<n>/agents`
|
|
225
|
-
- `bajaclaw://profile/<n>/memories`
|
|
226
|
-
- `bajaclaw://profile/<n>/cycles`
|
|
225
|
+
- `bajaclaw://profile/<n>/memories` - FTS5-searchable
|
|
226
|
+
- `bajaclaw://profile/<n>/cycles` - recent cycle history
|
|
227
227
|
- `bajaclaw://profile/<n>/schedules`
|
|
228
228
|
|
|
229
229
|
**Tools:**
|
|
@@ -234,7 +234,7 @@ can query BajaClaw's state directly.
|
|
|
234
234
|
- `bajaclaw_skill_list({ profile })`
|
|
235
235
|
|
|
236
236
|
Which means: from any MCP client, you can ask "what does BajaClaw remember
|
|
237
|
-
about X?" or "queue a task for the default agent"
|
|
237
|
+
about X?" or "queue a task for the default agent" - without leaving your
|
|
238
238
|
current session.
|
|
239
239
|
|
|
240
240
|
Run it manually with `bajaclaw mcp serve --stdio` or as HTTP SSE with
|
|
@@ -249,7 +249,7 @@ Set `memorySync: true` in the profile config and BajaClaw will:
|
|
|
249
249
|
- Write a digest to `~/.claude/memory/bajaclaw-<profile>.md` after each
|
|
250
250
|
cycle, so Claude Code sessions can see what BajaClaw has been learning
|
|
251
251
|
|
|
252
|
-
Disabled by default
|
|
252
|
+
Disabled by default - memory sharing is deliberate, not automatic. See
|
|
253
253
|
[`docs/memory.md`](docs/memory.md).
|
|
254
254
|
|
|
255
255
|
### Sub-agent delegation
|
|
@@ -257,7 +257,7 @@ Disabled by default — memory sharing is deliberate, not automatic. See
|
|
|
257
257
|
For heavy coding work, an agent using the `code` template plans and then
|
|
258
258
|
delegates to a dedicated Claude Code sub-session via `delegateCoding` in
|
|
259
259
|
[`src/delegation.ts`](src/delegation.ts). The orchestrator never writes code
|
|
260
|
-
itself
|
|
260
|
+
itself - that keeps its transcript reviewable before any code exists. See
|
|
261
261
|
[`docs/integration.md`](docs/integration.md).
|
|
262
262
|
|
|
263
263
|
---
|
|
@@ -267,12 +267,12 @@ itself — that keeps its transcript reviewable before any code exists. See
|
|
|
267
267
|
```
|
|
268
268
|
bajaclaw start # runs a cycle against the default profile
|
|
269
269
|
bajaclaw start --dry-run # shows the assembled prompt + exact argv
|
|
270
|
-
bajaclaw dashboard # http://localhost:7337
|
|
270
|
+
bajaclaw dashboard # http://localhost:7337 - live cycle feed, memories
|
|
271
271
|
bajaclaw daemon install # schedule a 15-minute heartbeat via your OS
|
|
272
272
|
bajaclaw daemon start # supervisor loop with exponential backoff
|
|
273
273
|
```
|
|
274
274
|
|
|
275
|
-
The default profile has **full tool access**
|
|
275
|
+
The default profile has **full tool access** - Read, Write, Edit, Bash,
|
|
276
276
|
Grep, Glob, WebSearch, WebFetch, plus every MCP tool you've configured. It's
|
|
277
277
|
a real autonomous agent, not a sandboxed assistant.
|
|
278
278
|
|
|
@@ -313,7 +313,7 @@ BAJACLAW_PROFILE=triage bajaclaw daemon start
|
|
|
313
313
|
|
|
314
314
|
| template | shape |
|
|
315
315
|
|---|---|
|
|
316
|
-
| `custom` | blank slate, full tools
|
|
316
|
+
| `custom` | blank slate, full tools - the default |
|
|
317
317
|
| `research` | research + synthesis + artifacts; full tools |
|
|
318
318
|
| `outreach` | email prospecting + drafting |
|
|
319
319
|
| `support` | inbox triage + reply drafts |
|
|
@@ -333,7 +333,7 @@ classifies the task and routes it to the cheapest capable model:
|
|
|
333
333
|
| **Sonnet** | normal work, answers, summaries | 5 memories, 2 skills, 8 turns |
|
|
334
334
|
| **Opus** | planning, coding, refactoring, deep research, reflection | 7 memories, 3 skills, 14 turns |
|
|
335
335
|
|
|
336
|
-
The classifier is a heuristic
|
|
336
|
+
The classifier is a heuristic - zero extra backend calls for routing.
|
|
337
337
|
Post-cycle memory extract + auto-skill synthesis are **skipped**
|
|
338
338
|
entirely for Haiku cycles. This keeps cheap tasks cheap.
|
|
339
339
|
|
|
@@ -353,8 +353,8 @@ bajaclaw serve --api-key $(openssl rand -hex 32) # with auth
|
|
|
353
353
|
bajaclaw serve --host 0.0.0.0 --api-key <key> # bind all (auth required)
|
|
354
354
|
```
|
|
355
355
|
|
|
356
|
-
Anything that speaks the OpenAI chat API
|
|
357
|
-
`openai` SDKs, curl, LangChain, LlamaIndex
|
|
356
|
+
Anything that speaks the OpenAI chat API - Cursor, Open WebUI, LibreChat,
|
|
357
|
+
`openai` SDKs, curl, LangChain, LlamaIndex - can drive BajaClaw as an LLM.
|
|
358
358
|
The request's `model` field is a profile name; each request is one full
|
|
359
359
|
cycle (memory recall, skill matching, MCP inheritance, backend call,
|
|
360
360
|
post-cycle extract).
|
|
@@ -415,14 +415,14 @@ the notice with `BAJACLAW_NO_UPDATE_NOTICE=1`.
|
|
|
415
415
|
```
|
|
416
416
|
bajaclaw setup # idempotent bootstrap; safe to re-run
|
|
417
417
|
bajaclaw setup --profile foo # use a different default profile name
|
|
418
|
-
bajaclaw uninstall # dry-run
|
|
418
|
+
bajaclaw uninstall # dry-run - shows what would be removed
|
|
419
419
|
bajaclaw uninstall --yes # actually tear everything down
|
|
420
420
|
bajaclaw uninstall --yes --keep-data # remove integrations, keep ~/.bajaclaw/
|
|
421
421
|
```
|
|
422
422
|
|
|
423
423
|
`setup` is the re-run button. If the MCP registration gets knocked out of
|
|
424
424
|
the desktop config, or the agent descriptor is missing, or you moved your
|
|
425
|
-
home directory
|
|
425
|
+
home directory - `bajaclaw setup` fixes it all without touching existing
|
|
426
426
|
data.
|
|
427
427
|
|
|
428
428
|
`uninstall` tears down everything BajaClaw has created:
|
|
@@ -435,7 +435,7 @@ data.
|
|
|
435
435
|
- Removes `~/.claude/memory/bajaclaw-*.md` sync files
|
|
436
436
|
- Removes `~/.bajaclaw/` entirely (unless `--keep-data`)
|
|
437
437
|
|
|
438
|
-
It does **not** `npm uninstall` itself
|
|
438
|
+
It does **not** `npm uninstall` itself - that's one command you still run by
|
|
439
439
|
hand, printed at the end of the teardown.
|
|
440
440
|
|
|
441
441
|
---
|
|
@@ -483,7 +483,7 @@ Memories`. After the cycle finishes, a 1-turn Haiku call reads the
|
|
|
483
483
|
Those facts become FTS-indexed rows with `source=cycle` and
|
|
484
484
|
`source_cycle_id=<id>`. Next cycle, they're eligible for recall again.
|
|
485
485
|
|
|
486
|
-
Kinds are a soft taxonomy
|
|
486
|
+
Kinds are a soft taxonomy - BajaClaw doesn't enforce them: `fact`,
|
|
487
487
|
`decision`, `preference`, `todo`, `reference`, `claude-code`, `imported`.
|
|
488
488
|
|
|
489
489
|
Full detail: [`docs/memory.md`](docs/memory.md).
|
|
@@ -493,7 +493,7 @@ Full detail: [`docs/memory.md`](docs/memory.md).
|
|
|
493
493
|
## Channels (optional)
|
|
494
494
|
|
|
495
495
|
BajaClaw ships optional adapters for **Telegram** and **Discord** bots.
|
|
496
|
-
They're `optionalDependencies`
|
|
496
|
+
They're `optionalDependencies` - not installed unless you use them.
|
|
497
497
|
|
|
498
498
|
```
|
|
499
499
|
bajaclaw channel add default telegram --token <BOT_TOKEN>
|
|
@@ -519,7 +519,7 @@ bajaclaw dashboard
|
|
|
519
519
|
Single HTML file served at `http://localhost:7337` (port in `config.json`).
|
|
520
520
|
Dark theme, vanilla JS, Tailwind CDN. Live cycle feed, FTS-searchable
|
|
521
521
|
memory browser, schedule editor, inbox/tasks list. Reads directly from the
|
|
522
|
-
SQLite DB
|
|
522
|
+
SQLite DB - no extra service.
|
|
523
523
|
|
|
524
524
|
---
|
|
525
525
|
|
|
@@ -627,20 +627,20 @@ Deeper in [`docs/architecture.md`](docs/architecture.md).
|
|
|
627
627
|
|
|
628
628
|
## Docs
|
|
629
629
|
|
|
630
|
-
- [`architecture.md`](docs/architecture.md)
|
|
631
|
-
- [`integration.md`](docs/integration.md)
|
|
632
|
-
- [`commands.md`](docs/commands.md)
|
|
633
|
-
- [`agents.md`](docs/agents.md)
|
|
634
|
-
- [`skills.md`](docs/skills.md)
|
|
635
|
-
- [`memory.md`](docs/memory.md)
|
|
636
|
-
- [`heartbeat.md`](docs/heartbeat.md)
|
|
630
|
+
- [`architecture.md`](docs/architecture.md) - module map, cycle, on-disk layout
|
|
631
|
+
- [`integration.md`](docs/integration.md) - Claude Code + MCP seams in detail
|
|
632
|
+
- [`commands.md`](docs/commands.md) - full command reference
|
|
633
|
+
- [`agents.md`](docs/agents.md) - profiles, templates, AGENT.md / SOUL.md / HEARTBEAT.md
|
|
634
|
+
- [`skills.md`](docs/skills.md) - scoping, matching, self-generated skills
|
|
635
|
+
- [`memory.md`](docs/memory.md) - FTS5 recall + extract, cross-tool sync
|
|
636
|
+
- [`heartbeat.md`](docs/heartbeat.md) - scheduling + supervisor
|
|
637
637
|
- [`channels.md`](docs/channels.md)
|
|
638
|
-
- [`api.md`](docs/api.md)
|
|
639
|
-
- [`security.md`](docs/security.md)
|
|
640
|
-
- [`fair-use.md`](docs/fair-use.md)
|
|
641
|
-
- [`troubleshooting.md`](docs/troubleshooting.md)
|
|
642
|
-
- [`faq.md`](docs/faq.md)
|
|
643
|
-
- [`contributing.md`](docs/contributing.md)
|
|
638
|
+
- [`api.md`](docs/api.md) - OpenAI-compatible HTTP endpoint - Telegram + Discord
|
|
639
|
+
- [`security.md`](docs/security.md) - threat model + mitigations
|
|
640
|
+
- [`fair-use.md`](docs/fair-use.md) - how BajaClaw stays a thin wrapper
|
|
641
|
+
- [`troubleshooting.md`](docs/troubleshooting.md) - common fixes
|
|
642
|
+
- [`faq.md`](docs/faq.md) - frequently asked
|
|
643
|
+
- [`contributing.md`](docs/contributing.md) - dev setup, style, release
|
|
644
644
|
|
|
645
645
|
---
|
|
646
646
|
|
package/bin/bajaclaw.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// Thin launcher
|
|
2
|
+
// Thin launcher - resolves tsx and invokes src/cli.ts, or dist/cli.js if built.
|
|
3
3
|
import { spawnSync } from "node:child_process";
|
|
4
4
|
import { existsSync } from "node:fs";
|
|
5
5
|
import { dirname, join } from "node:path";
|
package/bin/create-bajaclaw.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// npx create-bajaclaw [name]
|
|
2
|
+
// npx create-bajaclaw [name] - bootstrap BajaClaw.
|
|
3
3
|
// With no args: runs `bajaclaw setup` to create the default profile.
|
|
4
4
|
// With a name: runs `bajaclaw init <name>` to scaffold that specific profile.
|
|
5
5
|
import { spawnSync } from "node:child_process";
|
package/dist/agent.js
CHANGED
|
@@ -163,7 +163,7 @@ async function runCycleInner(input) {
|
|
|
163
163
|
}
|
|
164
164
|
recordSuccess(db);
|
|
165
165
|
// Store up to 8k chars of the response. Needed for conversational
|
|
166
|
-
// history on channel-sourced cycles
|
|
166
|
+
// history on channel-sourced cycles - the old 300-char cap made
|
|
167
167
|
// every prior turn look like a stub. 8k ≈ 2k tokens; beyond that
|
|
168
168
|
// we rely on memory extraction to preserve context.
|
|
169
169
|
db.prepare("UPDATE cycles SET finished_at=?, status=?, response_preview=?, cost_usd=?, input_tokens=?, output_tokens=?, turns=? WHERE id=?").run(finished, "ok", result.text.slice(0, 8000), result.costUsd ?? null, result.inputTokens ?? null, result.outputTokens ?? null, result.turns ?? null, cycleId);
|
|
@@ -171,7 +171,7 @@ async function runCycleInner(input) {
|
|
|
171
171
|
db.prepare("UPDATE tasks SET status='done', cycle_id=? WHERE id=?").run(cycleId, popped.id);
|
|
172
172
|
}
|
|
173
173
|
// Post-cycle memory extraction + auto-skill synthesis. Both are extra
|
|
174
|
-
// backend calls
|
|
174
|
+
// backend calls - skip them on cheap (Haiku) cycles and on trivially
|
|
175
175
|
// short responses to keep token usage tight.
|
|
176
176
|
const shouldDoPostWork = !result.dryRun && result.text.length >= 120 && picked.tier !== "haiku";
|
|
177
177
|
if (shouldDoPostWork) {
|
package/dist/api/server.js
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
//
|
|
3
3
|
// Endpoints:
|
|
4
4
|
// GET /health
|
|
5
|
-
// GET /v1/models
|
|
6
|
-
// POST /v1/chat/completions
|
|
7
|
-
// POST /v1/bajaclaw/cycle
|
|
8
|
-
// POST /v1/bajaclaw/tasks
|
|
5
|
+
// GET /v1/models - lists exposed profiles as models
|
|
6
|
+
// POST /v1/chat/completions - OpenAI chat (stream + non-stream)
|
|
7
|
+
// POST /v1/bajaclaw/cycle - native: { profile, task } -> full CycleOutput
|
|
8
|
+
// POST /v1/bajaclaw/tasks - native: enqueue without waiting
|
|
9
9
|
//
|
|
10
10
|
// Auth: if config.api.apiKey is set, require `Authorization: Bearer <key>`.
|
|
11
11
|
// Bind: defaults to 127.0.0.1 unless config.api.host is explicit.
|
|
@@ -139,18 +139,18 @@ function listProfilesAsModels(exposed) {
|
|
|
139
139
|
const names = filter ? all.filter((n) => filter.has(n)) : all;
|
|
140
140
|
const now = Math.floor(Date.now() / 1000);
|
|
141
141
|
const out = [];
|
|
142
|
-
// Bare profile names
|
|
142
|
+
// Bare profile names - use each profile's configured model.
|
|
143
143
|
for (const id of names) {
|
|
144
144
|
out.push({ id, object: "model", created: now, owned_by: "bajaclaw" });
|
|
145
145
|
}
|
|
146
|
-
// profile:model virtual entries
|
|
146
|
+
// profile:model virtual entries - pick any model per request without
|
|
147
147
|
// touching profile config.
|
|
148
148
|
for (const id of names) {
|
|
149
149
|
for (const m of KNOWN_MODELS) {
|
|
150
150
|
out.push({ id: `${id}:${m.id}`, object: "model", created: now, owned_by: "bajaclaw" });
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
|
-
// Bare model-id shortcuts
|
|
153
|
+
// Bare model-id shortcuts - apply to the default profile.
|
|
154
154
|
if (names.includes("default")) {
|
|
155
155
|
for (const m of KNOWN_MODELS) {
|
|
156
156
|
out.push({ id: m.id, object: "model", created: now, owned_by: "bajaclaw" });
|
|
@@ -5,14 +5,14 @@ export declare function startAllGateways(profile: string): Promise<void>;
|
|
|
5
5
|
/** Backwards-compatible entry point: starts adapters, then blocks. */
|
|
6
6
|
export declare function runGateway(profile: string): Promise<void>;
|
|
7
7
|
/** Send an agent reply back to whatever channel originated a task.
|
|
8
|
-
* `source` is formatted as "telegram:<id>" or "discord:<id>"
|
|
8
|
+
* `source` is formatted as "telegram:<id>" or "discord:<id>" - the
|
|
9
9
|
* same string written into tasks.source by the inbound handlers.
|
|
10
10
|
* Also ends any typing indicator associated with that source. */
|
|
11
11
|
export declare function replyToSource(profile: string, source: string, text: string): Promise<void>;
|
|
12
12
|
/** Show the platform's "typing…" indicator for the given source. The
|
|
13
13
|
* adapter internally refreshes on the platform's cadence (Telegram
|
|
14
14
|
* indicator lasts ~5s, Discord ~10s) until `endTyping(source)` is
|
|
15
|
-
* called. Safe to call multiple times
|
|
15
|
+
* called. Safe to call multiple times - a second call replaces the
|
|
16
16
|
* first. No-ops if the adapter isn't loaded. */
|
|
17
17
|
export declare function beginTyping(profile: string, source: string): void;
|
|
18
18
|
export declare function endTyping(source: string): void;
|
package/dist/channels/gateway.js
CHANGED
|
@@ -54,7 +54,7 @@ export async function runGateway(profile) {
|
|
|
54
54
|
await new Promise(() => { });
|
|
55
55
|
}
|
|
56
56
|
/** Send an agent reply back to whatever channel originated a task.
|
|
57
|
-
* `source` is formatted as "telegram:<id>" or "discord:<id>"
|
|
57
|
+
* `source` is formatted as "telegram:<id>" or "discord:<id>" - the
|
|
58
58
|
* same string written into tasks.source by the inbound handlers.
|
|
59
59
|
* Also ends any typing indicator associated with that source. */
|
|
60
60
|
export async function replyToSource(profile, source, text) {
|
|
@@ -74,7 +74,7 @@ export async function replyToSource(profile, source, text) {
|
|
|
74
74
|
/** Show the platform's "typing…" indicator for the given source. The
|
|
75
75
|
* adapter internally refreshes on the platform's cadence (Telegram
|
|
76
76
|
* indicator lasts ~5s, Discord ~10s) until `endTyping(source)` is
|
|
77
|
-
* called. Safe to call multiple times
|
|
77
|
+
* called. Safe to call multiple times - a second call replaces the
|
|
78
78
|
* first. No-ops if the adapter isn't loaded. */
|
|
79
79
|
export function beginTyping(profile, source) {
|
|
80
80
|
const colon = source.indexOf(":");
|
|
@@ -94,7 +94,7 @@ export function beginTyping(profile, source) {
|
|
|
94
94
|
const stop = a.startTyping(id);
|
|
95
95
|
activeTyping.set(source, stop);
|
|
96
96
|
}
|
|
97
|
-
catch { /* ignore
|
|
97
|
+
catch { /* ignore - typing is best-effort */ }
|
|
98
98
|
}
|
|
99
99
|
export function endTyping(source) {
|
|
100
100
|
const stop = activeTyping.get(source);
|
|
@@ -149,7 +149,7 @@ async function startTelegram(profile, c, log) {
|
|
|
149
149
|
startTyping: (chatId) => {
|
|
150
150
|
// Telegram's typing indicator auto-clears after 5s, so re-send
|
|
151
151
|
// every 4s until stopped. `sendChatAction` errors are swallowed
|
|
152
|
-
//
|
|
152
|
+
// - they'd be noise (bot blocked, etc.) and the agent still has
|
|
153
153
|
// a reply path via the eventual send.
|
|
154
154
|
const send = () => {
|
|
155
155
|
bot.sendChatAction(Number(chatId), "typing").catch(() => undefined);
|
package/dist/claude.js
CHANGED
|
@@ -57,7 +57,7 @@ export function buildCommand(prompt, opts) {
|
|
|
57
57
|
// --effort is the real knob for "how much runway does the agent get".
|
|
58
58
|
// Levels: low < medium < high < xhigh < max. Higher = more turns
|
|
59
59
|
// + more tokens + higher cost. claude's internal turn budget is
|
|
60
|
-
// tied to this level
|
|
60
|
+
// tied to this level - there is no `--max-turns` flag.
|
|
61
61
|
if (opts.effort)
|
|
62
62
|
args.push("--effort", opts.effort);
|
|
63
63
|
if (opts.allowedTools?.length)
|
|
@@ -69,7 +69,7 @@ export function buildCommand(prompt, opts) {
|
|
|
69
69
|
if (opts.systemPrompt)
|
|
70
70
|
args.push("--system-prompt", opts.systemPrompt);
|
|
71
71
|
// Beta flags. `context1M: true` is shorthand for adding the
|
|
72
|
-
// `context-1m-2025-08-07` beta. API-key-only
|
|
72
|
+
// `context-1m-2025-08-07` beta. API-key-only - the CLI warns and
|
|
73
73
|
// falls back to 200k for subscription auth.
|
|
74
74
|
const betas = [...(opts.betas ?? [])];
|
|
75
75
|
if (opts.context1M && !betas.includes("context-1m-2025-08-07")) {
|
|
@@ -78,7 +78,7 @@ export function buildCommand(prompt, opts) {
|
|
|
78
78
|
if (betas.length > 0)
|
|
79
79
|
args.push("--betas", ...betas);
|
|
80
80
|
// Per-cycle cost ceiling. Safer than a turn cap because agent
|
|
81
|
-
// complexity varies wildly
|
|
81
|
+
// complexity varies wildly - this caps the actual spend, not a
|
|
82
82
|
// proxy for it.
|
|
83
83
|
if (opts.maxBudgetUsd !== undefined) {
|
|
84
84
|
args.push("--max-budget-usd", String(opts.maxBudgetUsd));
|
|
@@ -128,7 +128,7 @@ export async function runOnce(prompt, opts = {}) {
|
|
|
128
128
|
// Explicitly close stdin. Without this, the claude CLI waits 3s
|
|
129
129
|
// for piped input before proceeding (and treats the wait as a
|
|
130
130
|
// warning that contaminates stdout). Closing stdin tells it
|
|
131
|
-
// "the prompt on -p is complete
|
|
131
|
+
// "the prompt on -p is complete - don't wait for more".
|
|
132
132
|
stdin: "ignore",
|
|
133
133
|
});
|
|
134
134
|
return parseResult(r.stdout, r.stderr, r.exitCode ?? 0, start, jsonSupported, ["claude", ...cmd]);
|
|
@@ -163,12 +163,12 @@ function parseResult(stdout, stderr, exitCode, start, jsonMode, command) {
|
|
|
163
163
|
command,
|
|
164
164
|
};
|
|
165
165
|
// True when the JSON result block explicitly reported success. When
|
|
166
|
-
// it's set, trust the JSON over a non-zero exit code
|
|
166
|
+
// it's set, trust the JSON over a non-zero exit code - claude can
|
|
167
167
|
// exit non-zero if a child process it spawned (e.g. a long-running
|
|
168
168
|
// dashboard server) leaves stdout/stderr pipes open past the
|
|
169
169
|
// parent's timeout, even though the turn itself completed cleanly.
|
|
170
170
|
let jsonReportedSuccess = false;
|
|
171
|
-
// Try JSON parse regardless of exit code
|
|
171
|
+
// Try JSON parse regardless of exit code - claude sometimes emits
|
|
172
172
|
// useful error detail in JSON even when exiting non-zero.
|
|
173
173
|
if (jsonMode) {
|
|
174
174
|
try {
|
|
@@ -251,7 +251,7 @@ function parseResult(stdout, stderr, exitCode, start, jsonMode, command) {
|
|
|
251
251
|
}
|
|
252
252
|
if (exitCode !== 0 && !base.error && !jsonReportedSuccess) {
|
|
253
253
|
// Prefer stderr, then stdout first-line fallback. Never echo the
|
|
254
|
-
// entire stdout into the error field
|
|
254
|
+
// entire stdout into the error field - it may be a multi-KB JSON.
|
|
255
255
|
const trimmedStderr = stderr.trim();
|
|
256
256
|
if (trimmedStderr)
|
|
257
257
|
base.error = trimmedStderr.slice(0, 400);
|
|
@@ -263,7 +263,7 @@ function parseResult(stdout, stderr, exitCode, start, jsonMode, command) {
|
|
|
263
263
|
// If we determined an error from JSON but exit was 0, still mark not-ok.
|
|
264
264
|
if (base.error && base.ok)
|
|
265
265
|
base.ok = false;
|
|
266
|
-
// Conversely: JSON explicitly said success. Honor that
|
|
266
|
+
// Conversely: JSON explicitly said success. Honor that - ignore a
|
|
267
267
|
// non-zero exit caused by lingering child processes.
|
|
268
268
|
if (jsonReportedSuccess) {
|
|
269
269
|
base.ok = true;
|
package/dist/cli.js
CHANGED
|
@@ -35,7 +35,7 @@ function defaultProfile(explicit) {
|
|
|
35
35
|
return explicit ?? process.env.BAJACLAW_PROFILE ?? DEFAULT_PROFILE_NAME;
|
|
36
36
|
}
|
|
37
37
|
const program = new Command();
|
|
38
|
-
program.name(pkg.name).description("BajaClaw
|
|
38
|
+
program.name(pkg.name).description("BajaClaw - autonomous agents on your terms").version(pkg.version);
|
|
39
39
|
program
|
|
40
40
|
.command("init [name]")
|
|
41
41
|
.description("Scaffold a new agent profile")
|
|
@@ -53,7 +53,7 @@ program
|
|
|
53
53
|
});
|
|
54
54
|
program
|
|
55
55
|
.command("chat [profile]")
|
|
56
|
-
.description("Interactive chat REPL
|
|
56
|
+
.description("Interactive chat REPL - converse with the agent turn-by-turn")
|
|
57
57
|
.option("--model <id>", "model or alias (auto|haiku|sonnet|opus|<full-id>)")
|
|
58
58
|
.action(async (p, opts) => {
|
|
59
59
|
const target = defaultProfile(p);
|
|
@@ -188,7 +188,7 @@ program.command("update").description("Check for and install a newer version")
|
|
|
188
188
|
.option("--check", "only check; don't install")
|
|
189
189
|
.option("--yes", "apply without confirmation")
|
|
190
190
|
.action(async (opts) => runUpdate({ check: !!opts.check, yes: !!opts.yes }));
|
|
191
|
-
// Setup
|
|
191
|
+
// Setup - idempotent first-run bootstrap. Safe to rerun. Interactive
|
|
192
192
|
// persona wizard on a TTY the first time; non-interactive otherwise.
|
|
193
193
|
program.command("setup").description("Idempotent first-run bootstrap (profile, MCP register, persona wizard, health check)")
|
|
194
194
|
.option("--profile <name>", "profile name (default: 'default')")
|
|
@@ -207,7 +207,7 @@ program.command("setup").description("Idempotent first-run bootstrap (profile, M
|
|
|
207
207
|
interactive: !!opts.interactive,
|
|
208
208
|
nonInteractive: !!opts.nonInteractive,
|
|
209
209
|
}));
|
|
210
|
-
// Compact
|
|
210
|
+
// Compact - run memory compaction (or show what would run)
|
|
211
211
|
program.command("compact [profile]")
|
|
212
212
|
.description("Compact memory (summarize old entries, prune stale cycle rows)")
|
|
213
213
|
.option("--dry-run", "show trigger state and policy without running")
|
|
@@ -242,7 +242,7 @@ program.command("compact [profile]")
|
|
|
242
242
|
set: Object.keys(set).length > 0 ? set : undefined,
|
|
243
243
|
});
|
|
244
244
|
});
|
|
245
|
-
// Persona
|
|
245
|
+
// Persona - view or re-run the wizard
|
|
246
246
|
program.command("persona [profile]")
|
|
247
247
|
.description("Show or edit the agent's persona (name, tone, user name, focus)")
|
|
248
248
|
.option("--edit", "re-run the interactive wizard")
|
|
@@ -270,30 +270,30 @@ subCmd.command("create <name>")
|
|
|
270
270
|
subCmd.command("list [parent]")
|
|
271
271
|
.description("List sub-agents under a parent (or the whole tree if omitted)")
|
|
272
272
|
.action(async (p) => subagent.cmdList(p));
|
|
273
|
-
// Delegate
|
|
273
|
+
// Delegate - orchestrators call this via Bash to hand off a task
|
|
274
274
|
program.command("delegate <subagent> <task>")
|
|
275
275
|
.description("Run one cycle on a sub-agent and stream its response text to stdout")
|
|
276
276
|
.option("--json", "output full CycleOutput JSON instead of just text")
|
|
277
277
|
.action(async (sub, task, opts) => subagent.cmdDelegate(sub, task, { json: !!opts.json }));
|
|
278
|
-
// Uninstall
|
|
278
|
+
// Uninstall - full teardown.
|
|
279
279
|
program.command("uninstall").description("Remove all BajaClaw state (profiles, scheduler, MCP, memory sync)")
|
|
280
280
|
.option("--yes", "actually perform the teardown")
|
|
281
281
|
.option("--keep-data", "keep ~/.bajaclaw/ data; only remove integrations")
|
|
282
282
|
.action(async (opts) => runUninstall({ yes: !!opts.yes, keepData: !!opts.keepData }));
|
|
283
|
-
// Model
|
|
283
|
+
// Model - show or set per profile
|
|
284
284
|
program.command("model [value] [profile]")
|
|
285
285
|
.description("Show or set the model for a profile (no value: lists known models)")
|
|
286
286
|
.action(async (value, p) => runModel(value, { profile: p }));
|
|
287
|
-
// Effort
|
|
287
|
+
// Effort - show or set per profile
|
|
288
288
|
program.command("effort [value] [profile]")
|
|
289
289
|
.description("Show or set the effort level (low/medium/high) for a profile")
|
|
290
290
|
.action(async (value, p) => runEffort(value, { profile: p }));
|
|
291
|
-
// Guide
|
|
291
|
+
// Guide - print a self-setup walkthrough
|
|
292
292
|
program.command("guide [topic]")
|
|
293
293
|
.description("Print a self-setup walkthrough, or list available guides")
|
|
294
294
|
.option("--profile <name>", "profile to use for skill lookup")
|
|
295
295
|
.action(async (topic, opts) => runGuide(topic, { profile: opts.profile }));
|
|
296
|
-
// Serve
|
|
296
|
+
// Serve - OpenAI-compatible HTTP endpoint
|
|
297
297
|
program.command("serve")
|
|
298
298
|
.description("Serve BajaClaw over an OpenAI-compatible HTTP API")
|
|
299
299
|
.option("--host <host>", "bind host (default 127.0.0.1)")
|
|
@@ -312,7 +312,7 @@ program.command("serve")
|
|
|
312
312
|
program.command("banner").description("Print the ASCII banner").action(() => {
|
|
313
313
|
printBanner(pkg.version, { force: true });
|
|
314
314
|
});
|
|
315
|
-
// Welcome
|
|
315
|
+
// Welcome - first-run greeting; also callable anytime
|
|
316
316
|
program.command("welcome").description("Print the welcome banner + next steps")
|
|
317
317
|
.action(async () => {
|
|
318
318
|
await printWelcome({ force: true });
|
|
@@ -341,7 +341,7 @@ async function printWelcome(opts = {}) {
|
|
|
341
341
|
}
|
|
342
342
|
catch { /* health check optional */ }
|
|
343
343
|
console.log(chalk.bold("Start chatting:"));
|
|
344
|
-
console.log(` ${chalk.cyan("bajaclaw chat")} ${chalk.dim("# interactive REPL
|
|
344
|
+
console.log(` ${chalk.cyan("bajaclaw chat")} ${chalk.dim("# interactive REPL - talk to your agent")}`);
|
|
345
345
|
console.log("");
|
|
346
346
|
console.log(chalk.bold("First-time setup:"));
|
|
347
347
|
console.log(` ${chalk.cyan("bajaclaw setup --interactive")} ${chalk.dim("# name your agent, set tone, topics, don'ts")}`);
|
|
@@ -368,7 +368,7 @@ async function maybeShowWelcome() {
|
|
|
368
368
|
return;
|
|
369
369
|
// Only show when stdout is a TTY. npm captures postinstall output,
|
|
370
370
|
// so firing the welcome during `npm install` prints to the void and
|
|
371
|
-
// then marks done
|
|
371
|
+
// then marks done - defeating the point. Non-TTY: silent no-op, don't
|
|
372
372
|
// even mark done, so the next interactive run still gets the welcome.
|
|
373
373
|
if (!process.stdout.isTTY)
|
|
374
374
|
return;
|
|
@@ -392,7 +392,7 @@ program.hook("postAction", async () => {
|
|
|
392
392
|
return;
|
|
393
393
|
await maybeNoticeAtExit();
|
|
394
394
|
});
|
|
395
|
-
// Run the first-run welcome before command dispatch. Non-blocking
|
|
395
|
+
// Run the first-run welcome before command dispatch. Non-blocking -
|
|
396
396
|
// a failure here should never prevent the user's command from running.
|
|
397
397
|
await maybeShowWelcome().catch(() => { });
|
|
398
398
|
// Await the parse so long-running interactive commands (like `chat`)
|
package/dist/commands/channel.js
CHANGED
|
@@ -4,7 +4,7 @@ export async function cmdAdd(profile, kind, token, channelId, userId) {
|
|
|
4
4
|
const cfg = loadConfig(profile);
|
|
5
5
|
// For telegram: `--channel-id` is the user's numeric Telegram id
|
|
6
6
|
// (the same thing @userinfobot returns). It lives in the allowlist,
|
|
7
|
-
// not channelId
|
|
7
|
+
// not channelId - telegram adapters route replies by chat id from
|
|
8
8
|
// the inbound message, not a pre-set channel.
|
|
9
9
|
// For discord: `--channel-id` is the discord channel id; `--user-id`
|
|
10
10
|
// is the sender to allow. Without a user id, no allowlist is
|
|
@@ -25,7 +25,7 @@ export async function cmdAdd(profile, kind, token, channelId, userId) {
|
|
|
25
25
|
saveConfig(cfg);
|
|
26
26
|
console.log(chalk.green(`✓ added ${kind} channel to ${profile}`));
|
|
27
27
|
if (kind === "telegram" && entry.allowlist?.length === 0) {
|
|
28
|
-
console.log(chalk.yellow(" note: no user id provided
|
|
28
|
+
console.log(chalk.yellow(" note: no user id provided - allowlist is empty (any user can message)"));
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
export async function cmdRemove(profile, kind) {
|