@inetafrica/open-claudia 2.14.8 → 3.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.
- package/.env.example +30 -4
- package/CHANGELOG.md +21 -0
- package/README.md +87 -66
- package/bin/agent.js +44 -18
- package/bin/cli.js +30 -28
- package/bin/dream.js +5 -11
- package/bin/loopback-client.js +29 -5
- package/bin/schedule.js +19 -5
- package/bin/tool.js +23 -5
- package/bot-agent.js +5 -2350
- package/bot.js +105 -7
- package/channels/telegram/adapter.js +6 -1
- package/channels/voice/adapter.js +1 -0
- package/channels/voice/manage.js +43 -5
- package/config-dir.js +3 -11
- package/core/actions.js +149 -40
- package/core/approvals.js +136 -29
- package/core/auth-flow.js +103 -19
- package/core/config-dir.js +19 -0
- package/core/config.js +127 -69
- package/core/doctor.js +111 -57
- package/core/dream.js +219 -62
- package/core/enforcer.js +0 -0
- package/core/entities.js +2 -1
- package/core/fsutil.js +55 -0
- package/core/handlers.js +503 -217
- package/core/ideas.js +2 -1
- package/core/identity.js +8 -11
- package/core/io.js +24 -3
- package/core/jobs.js +589 -72
- package/core/lessons.js +3 -2
- package/core/loopback.js +45 -8
- package/core/memory-mutation-queue.js +241 -0
- package/core/migration-backup.js +1060 -0
- package/core/pack-review.js +295 -88
- package/core/packs.js +4 -3
- package/core/persona.js +2 -1
- package/core/process-tree.js +19 -2
- package/core/provider-migration.js +39 -0
- package/core/provider-status.js +80 -0
- package/core/providers/claude-events.js +117 -0
- package/core/providers/claude-hook.js +114 -0
- package/core/providers/claude.js +296 -0
- package/core/providers/codex-events.js +121 -0
- package/core/providers/codex-hook.js +280 -0
- package/core/providers/codex.js +286 -0
- package/core/providers/contract.js +153 -0
- package/core/providers/env.js +148 -0
- package/core/providers/events.js +170 -0
- package/core/providers/hook-command.js +22 -0
- package/core/providers/index.js +240 -0
- package/core/providers/utility-policy.js +269 -0
- package/core/recall/classic.js +2 -2
- package/core/recall/discoverer.js +71 -22
- package/core/recall/metrics.js +27 -1
- package/core/recall/tuning.js +4 -1
- package/core/recall/warm-walker.js +151 -108
- package/core/recall-filter.js +86 -61
- package/core/router.js +79 -7
- package/core/run-context.js +185 -0
- package/core/runner.js +1415 -1282
- package/core/scheduler.js +515 -210
- package/core/side-chat.js +346 -0
- package/core/state.js +1096 -95
- package/core/subagent.js +72 -98
- package/core/system-prompt.js +462 -279
- package/core/tool-guard.js +73 -39
- package/core/tools.js +22 -5
- package/core/transcripts.js +30 -1
- package/core/usage-log.js +19 -4
- package/core/utility-agent.js +654 -0
- package/core/web-auth.js +29 -13
- package/core/web-sessions.js +78 -0
- package/docs/CHANNEL_DESIGN.md +181 -0
- package/docs/MULTI_CHANNEL_PLAN.md +254 -0
- package/docs/PROVIDER_MIGRATION.md +67 -0
- package/health.js +50 -39
- package/package.json +51 -4
- package/setup.js +198 -38
- package/soul.md +39 -0
- package/test-ability-extraction.js +5 -0
- package/test-approval-async.js +63 -4
- package/test-cursor-removal.js +334 -0
- package/test-delivery-contract.js +88 -0
- package/test-enforcer.js +70 -27
- package/test-fixtures/current-provider-parity.json +132 -0
- package/test-fixtures/fake-agent-cli.js +477 -0
- package/test-fixtures/migrations/claude-only/jobs.json +3 -0
- package/test-fixtures/migrations/claude-only/sessions.json +5 -0
- package/test-fixtures/migrations/claude-only/state.json +5 -0
- package/test-fixtures/migrations/cursor-selected/crons.json +3 -0
- package/test-fixtures/migrations/cursor-selected/jobs.json +3 -0
- package/test-fixtures/migrations/cursor-selected/sessions.json +5 -0
- package/test-fixtures/migrations/cursor-selected/state.json +6 -0
- package/test-fixtures/migrations/dual-provider/jobs.json +3 -0
- package/test-fixtures/migrations/dual-provider/sessions.json +7 -0
- package/test-fixtures/migrations/dual-provider/state.json +10 -0
- package/test-fixtures/migrations/malformed-partial/jobs.json +1 -0
- package/test-fixtures/migrations/malformed-partial/sessions.json +1 -0
- package/test-fixtures/migrations/malformed-partial/sessions.json.bak +3 -0
- package/test-fixtures/migrations/malformed-partial/state.json +1 -0
- package/test-fixtures/migrations/malformed-partial/state.json.bak +5 -0
- package/test-fixtures/migrations/missing-project/jobs.json +3 -0
- package/test-fixtures/migrations/missing-project/sessions.json +3 -0
- package/test-fixtures/migrations/missing-project/state.json +4 -0
- package/test-fixtures/migrations/multi-user/jobs.json +4 -0
- package/test-fixtures/migrations/multi-user/sessions.json +4 -0
- package/test-fixtures/migrations/multi-user/state.json +6 -0
- package/test-fixtures/provider-event-samples.json +17 -0
- package/test-learning-e2e.js +5 -0
- package/test-memory-mutation-queue.js +191 -0
- package/test-provider-boot-matrix.js +399 -0
- package/test-provider-bootstrap.js +158 -0
- package/test-provider-capabilities.js +232 -0
- package/test-provider-claude.js +206 -0
- package/test-provider-codex.js +228 -0
- package/test-provider-compaction.js +371 -0
- package/test-provider-core-prompt.js +264 -0
- package/test-provider-coupling-audit.js +90 -0
- package/test-provider-dream.js +312 -0
- package/test-provider-enforcer.js +252 -0
- package/test-provider-env-isolation.js +150 -0
- package/test-provider-events.js +141 -0
- package/test-provider-fixture.js +332 -0
- package/test-provider-gateway.js +508 -0
- package/test-provider-language.js +89 -0
- package/test-provider-migration-backup.js +424 -0
- package/test-provider-pack-review.js +436 -0
- package/test-provider-parity-e2e.js +537 -0
- package/test-provider-prompt-parity.js +89 -0
- package/test-provider-recall.js +271 -0
- package/test-provider-registry.js +251 -0
- package/test-provider-resume-parity.js +41 -0
- package/test-provider-run-lifecycle.js +349 -0
- package/test-provider-runner.js +271 -0
- package/test-provider-scheduler.js +689 -0
- package/test-provider-session-commands.js +185 -0
- package/test-provider-session-history.js +205 -0
- package/test-provider-side-chat.js +337 -0
- package/test-provider-state-migration.js +316 -0
- package/test-provider-stream-decoder.js +69 -0
- package/test-provider-subagent.js +228 -0
- package/test-provider-tool-hooks.js +360 -0
- package/test-recall-discoverer.js +1 -0
- package/test-recall-engine.js +3 -3
- package/test-recall-evolution.js +18 -0
- package/test-run-lock.js +63 -0
- package/test-runner-watchdog-static.js +16 -8
- package/test-single-runtime.js +35 -0
- package/test-telegram-poll-recovery.js +56 -0
- package/test-tool-guard.js +56 -0
- package/test-tools.js +19 -0
- package/test-unified-identity.js +3 -1
- package/test-usage-accounting.js +92 -20
- package/test-utility-provider-policy.js +486 -0
- package/test-web-sessions.js +74 -0
- package/web.js +159 -45
package/.env.example
CHANGED
|
@@ -15,11 +15,35 @@ KAZEE_OWNER_USER_ID=
|
|
|
15
15
|
KAZEE_DEBUG_EVENTS=
|
|
16
16
|
|
|
17
17
|
WORKSPACE=/path/to/your/workspace
|
|
18
|
-
|
|
18
|
+
# Both provider paths are optional. Leave blank to discover the CLI on PATH.
|
|
19
|
+
CLAUDE_PATH=
|
|
20
|
+
CODEX_PATH=
|
|
21
|
+
# Optional explicit foreground/global default. When blank, Open Claudia picks
|
|
22
|
+
# the first available compatible provider deterministically (Claude, then Codex).
|
|
23
|
+
DEFAULT_PROVIDER=
|
|
19
24
|
# Default Claude Code model when users haven't selected one with /model.
|
|
20
25
|
CLAUDE_MODEL=claude-fable-5
|
|
21
|
-
|
|
22
|
-
|
|
26
|
+
CODEX_MODEL=
|
|
27
|
+
# Background intelligence uses the active provider by default. Per-purpose
|
|
28
|
+
# overrides and fallbacks are opt-in; fallbacks never retarget foreground turns.
|
|
29
|
+
UTILITY_PROVIDER=active
|
|
30
|
+
PROVIDER_FALLBACKS=
|
|
31
|
+
DREAM_PROVIDER=
|
|
32
|
+
MEMORY_PROVIDER=
|
|
33
|
+
RECALL_PROVIDER=
|
|
34
|
+
ENFORCER_PROVIDER=
|
|
35
|
+
SUBAGENT_PROVIDER=
|
|
36
|
+
# Exact per-provider model overrides for utility work (optional).
|
|
37
|
+
DREAM_MODEL_CLAUDE=
|
|
38
|
+
DREAM_MODEL_CODEX=
|
|
39
|
+
PACK_REVIEW_MODEL_CLAUDE=
|
|
40
|
+
PACK_REVIEW_MODEL_CODEX=
|
|
41
|
+
RECALL_MODEL_CLAUDE=
|
|
42
|
+
RECALL_MODEL_CODEX=
|
|
43
|
+
ENFORCER_MODEL_CLAUDE=
|
|
44
|
+
ENFORCER_MODEL_CODEX=
|
|
45
|
+
SUBAGENT_MODEL_CLAUDE=
|
|
46
|
+
SUBAGENT_MODEL_CODEX=
|
|
23
47
|
AUTO_COMPACT_TOKENS=280000
|
|
24
48
|
# Inactivity watchdog: kill a heavy turn's child if it emits no output for
|
|
25
49
|
# this many ms, so a hung tool call can't wedge the bot. Default 600000 (10min).
|
|
@@ -32,8 +56,10 @@ USAGE_ALERT_COOLDOWN_MS=1800000
|
|
|
32
56
|
MEMORY_RECALL_MAX_CHARS=9000
|
|
33
57
|
# Default recall engine when a chat hasn't picked one with /engine: classic | discoverer
|
|
34
58
|
RECALL_ENGINE=classic
|
|
35
|
-
# Dream
|
|
59
|
+
# Dream utility tier is mapped by the selected provider: low | medium | high (default).
|
|
36
60
|
DREAM_TIER=high
|
|
61
|
+
# Independent external-person guardrail fails closed. Every total provider
|
|
62
|
+
# failure holds the action for owner approval.
|
|
37
63
|
PROJECT_TRANSCRIPTS=true
|
|
38
64
|
TRANSCRIPT_MAX_ENTRY_CHARS=12000
|
|
39
65
|
TRANSCRIPTS_DIR=
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v3.0.0 — provider parity and Cursor removal
|
|
4
|
+
|
|
5
|
+
- **The runtime is now a provider-agnostic coding-agent harness.** Claude Code and OpenAI Codex implement one registry contract for prompts, immutable run admission, normalized events, native sessions, capability reporting, utility work, and pre-tool safety policy. Setup, web configuration, status, and doctor work with either, both, or neither provider installed; only model turns require a compatible authenticated provider.
|
|
6
|
+
- **Active Cursor Agent runtime support has been removed.** Open Claudia now runs model turns through the registered Claude Code and OpenAI Codex providers only. The command, model/backend buttons, executable discovery, auth/doctor branches, configuration key, active session pointer, and runtime parser/invocation path are gone. Buttons from an older message return a removal notice and direct the user to `/backend`; they never switch to another provider silently.
|
|
7
|
+
- **Cursor data is archived, not rewritten.** The verified provider-migration snapshot retains the byte-for-byte original state, session, job, and legacy cron files. Cursor selections, settings, session pointers/history, and pinned jobs move only into non-selectable/disabled archive records; no native session ID or model is reassigned to Claude or Codex.
|
|
8
|
+
- **Migration activation is proven, not asserted.** Startup snapshots the allowlisted originals, migrates state, sessions, and jobs before the scheduler/router/adapters load, and records each live output's schema, size, path, and SHA-256. A partial, stale, or legacy output cannot satisfy provider-removal readiness; rerunning startup safely completes an interrupted component.
|
|
9
|
+
- **Rollback requires the matching older runtime.** Stop every bot/scheduler process, validate and restore the snapshot described in `docs/PROVIDER_MIGRATION.md`, then restart a pre-removal Open Claudia release that still understands the restored schema. Do not run old and new schedulers against the same restored files.
|
|
10
|
+
- **Authenticated release validation passed locally on 2026-07-10.** Claude Code 2.1.158 and Codex CLI 0.144.0 each passed a fresh turn, resumed turn, read-only plan, harmless tool command, utility JSON output, and prompt-context sentinel through the Open Claudia adapters. Claude-only and Codex-only startup/status probes also passed with the opposite executable absent. These were isolated existing-auth checks only: no login, credential change, publish, deploy, or production action was performed.
|
|
11
|
+
- **Real-CLI validation tightened three compatibility edges.** Claude `structured_output` is now the authoritative terminal value for schema-constrained utility work even when the CLI also streams presentation text. Codex hook trust uses a strict inline `projects` table accepted by the current CLI while user configuration remains ignored, and the supported model tiers no longer select deprecated `o4-mini` for utility work.
|
|
12
|
+
- **Breaking-release recommendation accepted — released as `v3.0.0` (2026-07-10).** Removing an active provider and changing configuration/session schemas are breaking changes; package metadata and the git tag are v3.0.0.
|
|
13
|
+
- **Post-review hardening (2026-07-10).** stdin EPIPE from a fast-exiting provider child no longer crashes the bot — it surfaces as a stderr diagnostic and the exit code decides the run. Crons/wakeups archived by the provider migration are announced once at boot and listed in `open-claudia cron-list` and `/cron`. Healthy provider status is cached for 30 seconds so per-message admission stops respawning CLI probes; disappearance detection stays instant and unhealthy states always re-probe. `/doctor` now runs the real-binary Codex tool-hook enforcement probe behind an explicit opt-in, so boot/health/setup never spawn a model turn. Merged main's Telegram polling recovery fix.
|
|
14
|
+
|
|
15
|
+
## v2.15.0
|
|
16
|
+
- **Production-hardening pass (P0). Two root causes, closed at the source.** A deep-dive audit traced the reliability and safety gaps to two patterns: (1) **overloaded return contracts** where a falsy value meant both "no id" and "failed", so callers guessed — the exact shape behind v2.14.8's Kazee double-send; and (2) **unsafe shared state under concurrency**, amplified because the owner's Telegram + Kazee turns now share ONE in-memory state object *and* load-modify-write the same JSON files under unified identity. This release fixes both, plus the credential-exposure and crash-durability gaps found alongside them. No new deps, no new required env, no schema change.
|
|
17
|
+
- **One explicit delivery contract, so no caller guesses.** Adapters historically overloaded `send()`'s return: a message id on success, a bare `true` for an idless success (server fast-ack), or a falsy value on failure. `core/io.send()` now collapses every adapter's raw return through `normalizeSendResult` into `{ ok, messageId, editable }` — `messageId` is always a string or null, so `typeof`/edit-target checks are uniform across transports. The runner's final-delivery guard is now `if (!sent.ok)` (an idless success no longer reads as failure → no phantom re-send), and the streaming-preview path keeps the real string id when editable or a truthy sentinel otherwise, so `canEditStatus()` still declines to edit an unaddressable bubble. The loopback approval-prompt send routes through the same normalizer. New `test-delivery-contract.js`.
|
|
18
|
+
- **Crash-safe atomic writes for every durable JSON store.** `state.json`, `sessions.json`, and `identities.json` were each written with a bare `fs.writeFileSync(JSON.stringify(...))` — a crash or a full disk mid-write left a truncated file that fails to parse, and the loaders swallowed the parse error and returned `{}`, i.e. **silent total data loss** (every session pointer, per-user setting, and identity link gone). New `core/fsutil.js` provides `atomicWriteFileSync` (write to a temp file, `fsync`, then `rename` — atomic on POSIX — keeping a `.bak` sibling) and `readJsonWithFallback` (try the file, then its `.bak`, then the default). Every loader/writer in `core/state.js` and `core/identity.js` now uses them, and a failed write logs instead of vanishing. An interrupted flush now falls back to the last good file rather than wiping state.
|
|
19
|
+
- **A synchronous single-flight run-lock closes the double-spawn race.** The turn guard was `if (state.runningProcess)`, but `runningProcess` isn't set until *after* the pre-spawn awaits (recall, auto-compaction, auth preflight). Two turns for one canonical user — the owner's Telegram and Kazee messages sharing one state object — could both pass the check during that window and both spawn, racing the shared state and JSON files. New `state.acquireRunLock()` arms `state.preparingRun` **synchronously** (no `await` between test and set), so the second turn queues cleanly; the lock is released if a run bails before spawning (auth preflight) so a never-spawned turn can't wedge the next one. New `test-run-lock.js` proves the single-flight property on a shared state object.
|
|
20
|
+
- **Dashboard credential exposure closed on three fronts.** (1) `GET /api/config` returned the **raw `.env`** — every bot token, model API key, and the web control token in plaintext — to anyone holding a dashboard session; it now passes through `maskEnv`, which masks any secret-looking key to a 4-char tail (the config UI only ever edits the non-secret `SAFE_KEYS`, and masked values can't round-trip back in). (2) The session cookie was a **static `sha256(password)`** — identical for every login, unexpiring, and impossible to revoke short of a password change; replaced by `core/web-sessions.js`, which mints a random 256-bit token per login, tracks it server-side with a 24h expiry, validates the cookie against that store, and supports individual `revoke` + `revokeAll` (a password change now drops every outstanding session, then re-issues one for the caller). Sessions persist via the atomic writer, so a login survives a restart/upgrade. (3) The bot's own control-plane secrets (`TELEGRAM_BOT_TOKEN`, `KAZEE_BOT_TOKEN`, `BOT_CONTROL_TOKEN`) are now **stripped from the ambient subprocess env** (`botSubprocessEnv`) — the model CLI is authed by its own token/key and `open-claudia` CLIs re-read `.env` from disk, so nothing legitimately needs them, and a prompt-injected agent dumping its environment can no longer read them. New `test-web-sessions.js` (token lifecycle, targeted + mass revoke, expiry sweep, prototype-pollution-key rejection, disk persistence).
|
|
21
|
+
- **Crashes and shutdowns no longer lose state or die silently.** In-memory per-user state (settings, session pointers, usage, compaction timestamps) was only ever flushed opportunistically — a `SIGTERM` (every deploy/restart) or an uncaught exception dropped whatever hadn't been saved. A new best-effort synchronous `persist()` (→ `saveState()`, made crash-safe by the atomic writer above) now runs in `gracefulShutdown` and in the `uncaughtException` handler before exit. And `notifyError` — the last-ditch crash notifier — now **redacts secrets** before sending (`core/redact`), hardens the raw Telegram POST (`req.on("error")` guard so the notifier can't itself throw; correct `Content-Length` via `Buffer.byteLength`), and adds a second path that relays to the owner's **primary channel** via a live adapter, so a Kazee-only owner is reached too (skipped when the raw Telegram ping already covers a Telegram-primary owner — no double-notify).
|
|
22
|
+
- **Agent-space / OpenClaw:** no new deps, no new env, no schema change; Docker image builds identically. All changes are correctness/safety hardening — inert-by-default and back-compatible, with one **visible behaviour change on upgrade**: because the dashboard session model changed, any existing dashboard cookie is invalidated once, so a logged-in browser is asked to log in again after this upgrade (expected, one-time). Three new hermetic tests (`test-run-lock.js`, `test-web-sessions.js`, `test-delivery-contract.js`) wired into `npm test`; full suite green.
|
|
23
|
+
|
|
3
24
|
## v2.14.8
|
|
4
25
|
- **Kazee replies no longer post twice.** On a successful send, the Kazee adapter's `send()` returned the created message's id so the runner can edit its streaming preview in place — but it read only `res.message._id`, then fell back to the ActionHero envelope's numeric `messageId`, then `res._id`. chat-central serves the new message's id under `message.id` on some routes (the adapter's own reply-to fetch already handles `m._id || m.id`), so when only `.id` was present `send()` returned `null`. The final-delivery path in `core/runner.js` reads that return as "did the send fail?": `const sent = await send(firstChunk, { replyTo }); if (!sent) await send(firstChunk);`. A successful-but-idless send therefore looked like a failure and the reply was posted a second time — once as a reply-quote, once as a plain bubble (exactly the pair seen in-chat). `send()` now returns `message._id || message.id` (or the top-level equivalents) and **never** the numeric envelope `messageId` — that counter is a per-request id, not a chat message id, and using it also made later `PUT /message/<counter>` edits 500.
|
|
5
26
|
- **A streaming preview minted on one channel is never edited on another.** Under unified identity the owner's Telegram and Kazee turns share ONE per-canonical state object, and `statusMessageId` (the id of the live "typing…/preview" bubble) sat on it untagged. A Telegram message id (e.g. `24991`) could then be edited under the Kazee adapter → `PUT /message/24991` → *"Cast to ObjectId failed"* 500, a frozen preview, and a duplicate final send. `statusMessageId` now carries the channel it was minted on (`statusMessageChannel`, `core/state.js`); every edit-in-place site in `core/runner.js` (streaming tick + final delivery + the external-hold notice) only edits when the channel matches, otherwise it discards the stale id and sends fresh on the correct channel. Telegram-only deployments are unaffected (single channel → always matches).
|
package/README.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# Open Claudia
|
|
2
2
|
|
|
3
|
-
Your always-on
|
|
3
|
+
Your always-on, provider-agnostic coding-agent harness — Claude Code and OpenAI Codex via Telegram or Kazee Chat.
|
|
4
4
|
|
|
5
|
-
Send text, voice notes, screenshots, and files from your phone.
|
|
5
|
+
Send text, voice notes, screenshots, and files from your phone. Open Claudia runs the selected coding-agent provider on your projects, remembers what it learned, and reports back.
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
### Channels &
|
|
9
|
+
### Channels & providers
|
|
10
10
|
- **Multi-channel** — run the same bot on Telegram, Kazee Chat, or both at once (`CHANNELS=telegram,kazee`). Each channel renders keyboards, files, voice notes, and edits natively
|
|
11
|
-
- **Multi-
|
|
12
|
-
- **Multi-user / team mode** — one bot serves multiple authorized users in parallel, each with their own conversations, settings, model,
|
|
11
|
+
- **Multi-provider** — switch between Claude Code and OpenAI Codex on the fly (`/claude`, `/codex`); each keeps its own project-scoped session state
|
|
12
|
+
- **Multi-user / team mode** — one bot serves multiple authorized users in parallel, each with their own conversations, settings, model, provider, and usage counters
|
|
13
13
|
- **Multi-project sessions** — switch between workspace projects; per-project conversation history auto-resumes
|
|
14
14
|
|
|
15
15
|
### Memory & long-term context
|
|
@@ -44,7 +44,7 @@ Send text, voice notes, screenshots, and files from your phone. Your chosen AI a
|
|
|
44
44
|
### Operations
|
|
45
45
|
- **Encrypted vault** — store API keys and credentials securely
|
|
46
46
|
- **Customizable soul** — define your assistant's personality and knowledge
|
|
47
|
-
- **
|
|
47
|
+
- **Capability-driven settings** — model, effort, read-only mode, budget, and worktree controls appear only when the selected provider supports them
|
|
48
48
|
- **Token economy** — byte-stable system prompt for maximum Anthropic prompt-cache hits; dynamic state rides each message instead
|
|
49
49
|
- **Web UI** — optional browser UI for setup and config (`open-claudia start --web`)
|
|
50
50
|
- **Auto-updates** — checks npm every 5 minutes, upgrade with `/upgrade`
|
|
@@ -56,16 +56,16 @@ Send text, voice notes, screenshots, and files from your phone. Your chosen AI a
|
|
|
56
56
|
|
|
57
57
|
- [Node.js](https://nodejs.org/) 18+ (22.5+ recommended — its built-in SQLite powers transcript/pack/entity search; on older Node those features quietly disable themselves)
|
|
58
58
|
- A Telegram bot token (from [@BotFather](https://t.me/BotFather)) and/or a Kazee Chat bot
|
|
59
|
-
- At least one authenticated
|
|
59
|
+
- At least one authenticated coding-agent provider on the host machine for model turns (setup, doctor, status, and web configuration also work with none installed)
|
|
60
60
|
- (Optional) [whisper.cpp](https://github.com/ggerganov/whisper.cpp) + ffmpeg for voice notes
|
|
61
61
|
|
|
62
62
|
## Quick Start
|
|
63
63
|
|
|
64
|
-
### 1. Install and authenticate
|
|
64
|
+
### 1. Install and authenticate coding-agent providers
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
For model-bearing turns, authenticate **at least one** of these on the machine where Open Claudia will run.
|
|
67
67
|
|
|
68
|
-
**Claude Code** (required):
|
|
68
|
+
**Claude Code** (optional — at least one provider is required for model turns):
|
|
69
69
|
|
|
70
70
|
```bash
|
|
71
71
|
npm install -g @anthropic-ai/claude-code
|
|
@@ -73,16 +73,7 @@ claude # Opens browser to log in
|
|
|
73
73
|
claude --version # Verify it works
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
**
|
|
77
|
-
|
|
78
|
-
```bash
|
|
79
|
-
# Install from Cursor IDE: Settings > General > Agent CLI
|
|
80
|
-
# Or download from https://docs.cursor.com/agent
|
|
81
|
-
agent login # Opens browser to authenticate
|
|
82
|
-
agent status # Verify: should show your email and plan
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
**OpenAI Codex** (optional — enables `/codex` backend):
|
|
76
|
+
**OpenAI Codex** (optional — at least one provider is required for model turns):
|
|
86
77
|
|
|
87
78
|
```bash
|
|
88
79
|
npm install -g @openai/codex
|
|
@@ -92,7 +83,7 @@ codex login # Opens browser to authenticate
|
|
|
92
83
|
codex --version # Verify it works
|
|
93
84
|
```
|
|
94
85
|
|
|
95
|
-
Docker images include the Codex CLI. Direct npm installs still need optional
|
|
86
|
+
Docker images include the Codex CLI. Direct npm installs still need optional provider CLIs installed on the host.
|
|
96
87
|
|
|
97
88
|
> **Important**: Claude Code can use macOS Keychain when you log in interactively, but a launchd/background bot may not be able to read that Keychain session. Open Claudia supports `CLAUDE_CODE_OAUTH_TOKEN` for non-interactive Claude runs. Prefer `/setup_token` then `/use_oauth_token` if chat shows Claude auth/keychain errors.
|
|
98
89
|
|
|
@@ -110,8 +101,8 @@ open-claudia setup
|
|
|
110
101
|
|
|
111
102
|
The setup wizard will:
|
|
112
103
|
|
|
113
|
-
1. Detect Claude
|
|
114
|
-
2.
|
|
104
|
+
1. Detect the Claude and Codex CLIs, plus ffmpeg and whisper, on your system
|
|
105
|
+
2. Report provider authentication status
|
|
115
106
|
3. Ask for your Telegram bot token and verify it
|
|
116
107
|
4. Generate a verification code — send it to your bot to prove your identity
|
|
117
108
|
5. Set your workspace path (default: `~/.open-claudia/Workspace`)
|
|
@@ -142,16 +133,15 @@ If installed as a background service, the bot starts automatically on login and
|
|
|
142
133
|
|
|
143
134
|
## Chat Commands
|
|
144
135
|
|
|
145
|
-
###
|
|
136
|
+
### Provider switching
|
|
146
137
|
|
|
147
138
|
| Command | Description |
|
|
148
139
|
|---------|-------------|
|
|
149
|
-
| `/claude` | Switch to Claude Code
|
|
150
|
-
| `/
|
|
151
|
-
| `/
|
|
152
|
-
| `/backend` | Show current backend with picker |
|
|
140
|
+
| `/claude` | Switch to the Claude Code provider |
|
|
141
|
+
| `/codex` | Switch to the OpenAI Codex provider |
|
|
142
|
+
| `/backend` | Show the current provider with picker |
|
|
153
143
|
|
|
154
|
-
Each
|
|
144
|
+
Each provider keeps its own persistent project session. Switching doesn't lose your place — you can go back and forth freely.
|
|
155
145
|
|
|
156
146
|
### Session management
|
|
157
147
|
|
|
@@ -171,14 +161,14 @@ When you select a project, the last conversation is automatically resumed. Tap "
|
|
|
171
161
|
|
|
172
162
|
| Command | Description |
|
|
173
163
|
|---------|-------------|
|
|
174
|
-
| `/model [<model>]` | Switch model
|
|
175
|
-
| `/effort [
|
|
176
|
-
| `/budget [$N]` | Set max spend for next task
|
|
177
|
-
| `/plan` | Toggle
|
|
178
|
-
| `/ask` | Toggle
|
|
179
|
-
| `/worktree` | Toggle isolated git branch |
|
|
164
|
+
| `/model [<model>]` | Switch model for the selected provider |
|
|
165
|
+
| `/effort [<value>]` | Set a provider-supported effort level |
|
|
166
|
+
| `/budget [$N]` | Set max spend for the next task when supported (Claude Code) |
|
|
167
|
+
| `/plan` | Toggle read-only planning — Claude permission mode / Codex read-only sandbox |
|
|
168
|
+
| `/ask` | Toggle read-only Q&A through the selected provider's read-only mode |
|
|
169
|
+
| `/worktree` | Toggle a provider-managed isolated git branch when supported (Claude Code) |
|
|
180
170
|
| `/mode` | Switch between direct and agent bot modes |
|
|
181
|
-
| `/status` | Show current session,
|
|
171
|
+
| `/status` | Show current session, provider, capabilities, recall engine, and settings |
|
|
182
172
|
| `/usage` | Token usage and cost for this session |
|
|
183
173
|
| `/doctor` / `/requirements` | Check Node, CLI binaries/versions/auth, voice stack, and writable paths |
|
|
184
174
|
|
|
@@ -259,7 +249,7 @@ Available only when the bot runs as an AgentSpace-provisioned pod (the broker cr
|
|
|
259
249
|
|
|
260
250
|
## Memory & Long-Term Context
|
|
261
251
|
|
|
262
|
-
Open Claudia layers three memory systems on top of
|
|
252
|
+
Open Claudia layers three memory systems on top of provider-native sessions:
|
|
263
253
|
|
|
264
254
|
**Context packs** (`~/.open-claudia/packs/<dir>/PACK.md`) are living per-topic documents with four sections: *Stance* (how to think about the topic — your preferences and hard rules), *Procedure* (verified how-to steps), *State* (where work stands now), and *Journal* (a dated one-line log of past sessions). Incoming messages are matched against packs (FTS5, field-weighted so a stray word can't drag a pack in) and hits are injected into the agent's context — mention a project anywhere and the assistant picks up its train of thought, decisions, and history without you re-explaining. After every substantial turn, a background reviewer on a cheap model updates the relevant pack (or creates one for a genuinely new topic). Every change is announced in chat.
|
|
265
255
|
|
|
@@ -267,7 +257,7 @@ Open Claudia layers three memory systems on top of the backend's native sessions
|
|
|
267
257
|
|
|
268
258
|
**Recall engines** — how packs and entities get matched and surfaced is pluggable per chat via `/engine` (or the `RECALL_ENGINE` env default). **classic** (the default) is keyword FTS plus a relevance judge with headline injection — stable and unchanged. **discoverer** (opt-in) adds a typed-edge graph over the same corpus (`parent`/`governed-by`/`related` edges with weights in `recall-graph.db`) and runs: a pre-gate that skips recall on trivial turns → FTS seeding → spreading activation across the graph (1–2 hops — auto-pulls cross-cutting concerns the query never named) → a walker that reads each candidate and returns the genuinely-relevant set with one-line why-bullets (fail-open to keyword seeds, so it never recalls worse than classic). Edges form structurally from pack `parent` frontmatter and `[[links]]`, and strengthen via Hebbian co-use when the agent opens packs together (📖); weights decay over time. Inspect with `open-claudia recall-stats` and `open-claudia recall graph [--sync]`, or flip on `/recall` to watch — per turn — which packs/entities surfaced and why, right in the chat. Switch back any time with `/engine classic`.
|
|
269
259
|
|
|
270
|
-
**Dream consolidation** — while the per-turn reviewer takes quick notes, *dream* is the slow overnight pass (default 4am,
|
|
260
|
+
**Dream consolidation** — while the per-turn reviewer takes quick notes, *dream* is the slow overnight pass (default 4am, through the configured provider's high model tier): it merges packs that drifted into the same topic, builds parent/sub pack trees with umbrella summaries, tightens descriptions and tags so the router matches with less noise, dedupes entities, cross-links notes, and tends the recall graph (structural sync, weight decay, orphan prune). The pass is *evidence-grounded*: per-turn recall telemetry (what surfaced, what got kept, what the agent actually opened) feeds the prompt, so archive/merge calls rest on usage numbers rather than vibes. Most nights run as cheap *deltas* — full pack bodies only for what changed since the last dream plus graph neighbours and pre-computed merge candidates; a full-corpus sweep runs every `DREAM_FULL_SWEEP_DAYS` (30). Deterministic phases run even if the model call fails: journal backfill dedupe, weakening of graph nodes that keep arriving but never get kept, co-rescue edge reinforcement, episodic index tending, and a memory-health report (rescue rate, noise, latency, spend) in the morning chat summary. Dream may also tune one bounded recall knob per night (`recall-tuning.json`) — every change is checked against the next window's health and auto-rolled-back if rescue drops or noise rises; env pins always win. Anything merged away is backed up under `~/.open-claudia/backup/dream-<stamp>/` first, and each report and morning summary records the provider/model used. Configure with `DREAM_CRON`, `DREAM_TIER`, `DREAM_PROVIDER`, or a provider-specific `DREAM_MODEL_CLAUDE` / `DREAM_MODEL_CODEX`; disable with `DREAM=off`.
|
|
271
261
|
|
|
272
262
|
**Personality** — your `soul.md` holds identity and hard rules; `~/.open-claudia/persona.md` holds the voice on top — tone, quirks, emoji habits. It feeds into the system prompt and the dream pass may evolve it gently (bounded, backed up, announced). Edit it directly any time.
|
|
273
263
|
|
|
@@ -332,22 +322,41 @@ open-claudia send-to --person "<name>" "<message>"
|
|
|
332
322
|
open-claudia recent --person "<name>" [--limit 20] # read recent activity from another chat
|
|
333
323
|
```
|
|
334
324
|
|
|
335
|
-
|
|
325
|
+
Replies and write/destructive actions for external people pass through an independent, read-only relationship guard. The guard can use Claude or Codex (`ENFORCER_PROVIDER`) and fails closed: malformed output, timeout, or total provider failure holds the action for owner approval. A fallback is used only when explicitly listed in `PROVIDER_FALLBACKS`; audit records identify the provider/model that judged the action without storing the mandate or proposed content.
|
|
326
|
+
|
|
327
|
+
## Provider Comparison
|
|
328
|
+
|
|
329
|
+
| | Claude Code | OpenAI Codex |
|
|
330
|
+
|---|---|---|
|
|
331
|
+
| Binary | `claude` | `codex` |
|
|
332
|
+
| Session flag | `--resume <id>` | `exec resume <id>` |
|
|
333
|
+
| Auth | `claude auth` | `codex login` |
|
|
334
|
+
| Plan mode | Yes (`--permission-mode plan`) | Yes (read-only sandbox) |
|
|
335
|
+
| Budget control | Yes (`--max-budget-usd`) | No |
|
|
336
|
+
| Effort levels | Native (`low` through `max`) | Native (`minimal` through `xhigh`) |
|
|
337
|
+
| Worktree | Yes (`--worktree`) | No |
|
|
338
|
+
| Model switching | Yes | Yes (`--model`) |
|
|
339
|
+
| Partial text streaming | Yes | No; normalized progress and final events only |
|
|
340
|
+
|
|
341
|
+
Both providers output structured events which Open Claudia normalizes for progress, usage, tools, sessions, and terminal results.
|
|
342
|
+
|
|
343
|
+
Unsupported optional controls return a provider-specific explanation and do not change saved settings. Mandatory safety controls are different: Open Claudia configures each provider's native pre-tool hook, and refuses unrestricted execution if that policy cannot initialize.
|
|
344
|
+
|
|
345
|
+
## Utility provider policy
|
|
336
346
|
|
|
337
|
-
|
|
338
|
-
|---|---|---|---|
|
|
339
|
-
| Binary | `claude` | `agent` | `codex` |
|
|
340
|
-
| Session flag | `--resume <id>` | `--resume <id>` | `exec resume <id>` |
|
|
341
|
-
| Auth | `claude auth` | `agent login` | `codex login` |
|
|
342
|
-
| Plan mode | Yes (`--permission-mode plan`) | Yes (`--mode plan`) | Yes (`--sandbox read-only`) |
|
|
343
|
-
| Ask mode | No | Yes (`--mode ask`) | No |
|
|
344
|
-
| Budget control | Yes (`--max-budget-usd`) | No | No |
|
|
345
|
-
| Effort levels | Yes | No | Via config.toml |
|
|
346
|
-
| Worktree | Yes (`--worktree`) | Yes (`--worktree`) | No |
|
|
347
|
-
| Model switching | Yes | Yes | Yes (`--model`) |
|
|
348
|
-
| Dangerously skip permissions | Yes | Yes (`--trust`) | Yes (`--dangerously-bypass-approvals-and-sandbox`) |
|
|
347
|
+
Background intelligence—sub-agents, recall, memory review, dream/introspection, and the external-person enforcer—uses one provider-selection policy. A per-purpose override is checked first, then `UTILITY_PROVIDER` (default `active`), the active foreground provider when a chat exists, and `DEFAULT_PROVIDER` for global jobs. Providers translate the neutral `low`, `medium`, and `high` tiers to their own models; exact per-provider model overrides remain available.
|
|
349
348
|
|
|
350
|
-
|
|
349
|
+
Foreground turns never silently fall back to a different provider. Utility work uses `PROVIDER_FALLBACKS` only when the operator explicitly supplies an ordered list, starts a fresh provider session, and records the provider/model used. The relationship enforcer may try that configured list, but total failure always fails closed and asks the owner to decide.
|
|
350
|
+
|
|
351
|
+
## Provider session semantics
|
|
352
|
+
|
|
353
|
+
Conversation identity is the tuple of canonical user, project, provider, and native session ID. Claude Code and Codex histories and active pointers stay separate: switching providers restores only that provider's project session and never passes one provider's native session ID to another. Session-history entries are provider-tagged; ambiguous legacy records remain visible but non-selectable.
|
|
354
|
+
|
|
355
|
+
Model, effort, budget, permission mode, and worktree settings are stored per provider. `/new` clears only the selected project/provider pointer, while `/end` closes the project selection without deleting history. Compaction and scheduled jobs capture an immutable provider/session tuple; an explicitly configured scheduled fallback starts fresh from a provider-neutral archived brief.
|
|
356
|
+
|
|
357
|
+
## Provider migration and rollback
|
|
358
|
+
|
|
359
|
+
Upgrades from a release with the removed third provider snapshot `state.json`, `sessions.json`, `jobs.json`, legacy cron sources, and their relevant backups before activating provider-aware schemas. Removed-provider selections, histories, and jobs become non-selectable or disabled archives; they are never reassigned to Claude Code or Codex. See [Provider migration snapshots and rollback](docs/PROVIDER_MIGRATION.md) before upgrading or restoring an older runtime.
|
|
351
360
|
|
|
352
361
|
## Sending Files
|
|
353
362
|
|
|
@@ -379,16 +388,19 @@ Voice notes are transcribed locally — nothing sent to external services. On ma
|
|
|
379
388
|
|
|
380
389
|
```
|
|
381
390
|
Phone (Telegram / Kazee) --> Bot (Node.js) --> Claude Code CLI --> Your codebase
|
|
382
|
-
--> Cursor Agent CLI -->
|
|
383
391
|
--> OpenAI Codex CLI -->
|
|
384
392
|
<-- <-- <--
|
|
385
393
|
```
|
|
386
394
|
|
|
387
|
-
The bot spawns the
|
|
395
|
+
The bot spawns the selected provider CLI in headless mode for each message, normalizing its JSONL output back to the chat. It maintains provider-native context through the provider adapter and passes the same Open Claudia prompt/context contract to either CLI.
|
|
388
396
|
|
|
389
397
|
The appended system prompt is byte-stable within a session to maximize Anthropic prompt-cache hits; per-turn state (vault status, pending tasks, matched packs/entities) rides the user message instead, where it is always uncached anyway.
|
|
390
398
|
|
|
391
|
-
Open Claudia does not summarize one
|
|
399
|
+
Open Claudia does not summarize one provider's native session into another during switches; instead it records a redacted project transcript outside the repo and injects a small pointer telling fresh/switched sessions to search it only if needed.
|
|
400
|
+
|
|
401
|
+
### Provider credential boundary
|
|
402
|
+
|
|
403
|
+
Native Claude and Codex child processes receive allowlisted process variables plus explicitly configured `AGENT_ENV_PASSTHROUGH` entries. Open Claudia removes control-plane, keyring, and all provider credential keys before adding back only the selected provider's credentials and auth/config root. This is environment isolation, not OS containment: a native same-UID process retains whatever filesystem access that operating-system user has, including access to readable CLI auth stores and configuration files.
|
|
392
404
|
|
|
393
405
|
## Configuration Files
|
|
394
406
|
|
|
@@ -408,7 +420,7 @@ All stored in `~/.open-claudia/`:
|
|
|
408
420
|
| `packs/` | Context packs (living topic documents) + FTS index |
|
|
409
421
|
| `entities/` | Entity notes (people/places/projects) + FTS index |
|
|
410
422
|
| `sessions.json` | Per-project conversation history |
|
|
411
|
-
| `state.json` | Current
|
|
423
|
+
| `state.json` | Current provider/project state and provider-scoped settings (survives restarts) |
|
|
412
424
|
| `transcripts/` | Redacted project-scoped JSONL transcripts + FTS index |
|
|
413
425
|
| `briefs/` | Archived full compaction briefs |
|
|
414
426
|
| `audit.log` | Relay/intro/auth audit trail |
|
|
@@ -426,10 +438,13 @@ All stored in `~/.open-claudia/`:
|
|
|
426
438
|
| `CHANNELS` | No | Channels to start: `telegram`, `kazee`, or `telegram,kazee` (default `telegram`) |
|
|
427
439
|
| `KAZEE_URL` / `KAZEE_BOT_TOKEN` / `KAZEE_BOT_USER_ID` / `KAZEE_OWNER_USER_ID` | Kazee only | Kazee Chat connection |
|
|
428
440
|
| `WORKSPACE` | Yes | Path to your projects directory |
|
|
429
|
-
| `CLAUDE_PATH` |
|
|
430
|
-
| `
|
|
441
|
+
| `CLAUDE_PATH` / `CODEX_PATH` | No | Optional paths to provider CLIs (auto-detected if in PATH) |
|
|
442
|
+
| `DEFAULT_PROVIDER` | No | Foreground default (`claude` or `codex`); blank deterministically chooses the first compatible provider |
|
|
443
|
+
| `UTILITY_PROVIDER` | No | Utility default (`active`, `claude`, or `codex`); defaults to the active foreground provider |
|
|
444
|
+
| `MEMORY_PROVIDER` / `RECALL_PROVIDER` / `SUBAGENT_PROVIDER` | No | Optional per-purpose utility-provider overrides |
|
|
431
445
|
| `CLAUDE_CODE_OAUTH_TOKEN` | No | OAuth token for non-interactive Claude runs (set via `/use_oauth_token`) |
|
|
432
|
-
| `
|
|
446
|
+
| `AGENT_ENV_PASSTHROUGH` | No | Comma-separated project environment keys to pass to provider children; reserved provider/control/keyring keys are always filtered and re-added only by the selected provider |
|
|
447
|
+
| `CLAUDE_MODEL` / `CODEX_MODEL` | No | Optional default model for the matching provider |
|
|
433
448
|
| `AUTO_COMPACT_TOKENS` | No | Auto-compact threshold in tokens (also settable via `/compactwindow`) |
|
|
434
449
|
| `USAGE_ALERT_CONTEXT_TOKENS` | No | Alert when one completed turn's context tokens exceed this ceiling (default `120000`, `off` disables) |
|
|
435
450
|
| `USAGE_ALERT_RATE_MULTIPLIER` | No | Alert when the latest context-token rate exceeds the recent baseline by this multiple (default `1.75`, `off` disables) |
|
|
@@ -450,9 +465,13 @@ All stored in `~/.open-claudia/`:
|
|
|
450
465
|
| `PACK_MATCH_THRESHOLD` / `ENTITY_MATCH_THRESHOLD` | No | Router match score thresholds (default `2`) |
|
|
451
466
|
| `DREAM` | No | `off` disables the nightly memory consolidation pass (default on) |
|
|
452
467
|
| `DREAM_CRON` | No | Schedule for the dream pass (default `0 4 * * *`) |
|
|
453
|
-
| `
|
|
454
|
-
| `
|
|
468
|
+
| `DREAM_PROVIDER` | No | Provider for dream and introspection (`claude` or `codex`); otherwise scheduled work resolves through `DEFAULT_PROVIDER` |
|
|
469
|
+
| `DREAM_MODEL_CLAUDE` / `DREAM_MODEL_CODEX` | No | Exact per-provider dream model override; legacy `DREAM_MODEL` remains a Claude-only compatibility alias |
|
|
470
|
+
| `DREAM_TIER` | No | Provider-owned model tier for the dream pass: `low`, `medium`, or `high` (default) |
|
|
455
471
|
| `DREAM_FULL_SWEEP_DAYS` | No | Days between full-corpus dream sweeps; other nights are cheap deltas over recently-touched packs (default `30`) |
|
|
472
|
+
| `ENFORCER_PROVIDER` | No | Provider for the independent external-person guard (`claude` or `codex`) |
|
|
473
|
+
| `ENFORCER_MODEL_CLAUDE` / `ENFORCER_MODEL_CODEX` | No | Exact per-provider guard model override; legacy `ENFORCER_MODEL` remains a Claude-only compatibility alias |
|
|
474
|
+
| `PROVIDER_FALLBACKS` | No | Explicit ordered utility fallback list (for example `codex`); the enforcer never invents an unconfigured fallback |
|
|
456
475
|
| `PERSONA_FILE` | No | Override the persona file location |
|
|
457
476
|
| `WEB_UI` / `WEB_PORT` / `WEB_PASSWORD` | No | Web UI toggle, port, and password |
|
|
458
477
|
| `WHISPER_CLI` / `WHISPER_MODEL` | No | whisper.cpp binary and model for voice notes |
|
|
@@ -467,13 +486,13 @@ All stored in `~/.open-claudia/`:
|
|
|
467
486
|
Set up during `open-claudia setup`, or manually:
|
|
468
487
|
|
|
469
488
|
```bash
|
|
470
|
-
# The setup wizard
|
|
489
|
+
# The setup wizard retains the legacy-compatible service id com.claude-telegram-bot
|
|
471
490
|
# To manage:
|
|
472
|
-
launchctl load ~/Library/LaunchAgents/com.
|
|
473
|
-
launchctl unload ~/Library/LaunchAgents/com.
|
|
491
|
+
launchctl load ~/Library/LaunchAgents/com.claude-telegram-bot.plist
|
|
492
|
+
launchctl unload ~/Library/LaunchAgents/com.claude-telegram-bot.plist
|
|
474
493
|
```
|
|
475
494
|
|
|
476
|
-
**Important**: If
|
|
495
|
+
**Important**: If a provider CLI is installed in a non-standard location, make sure that path is included in the launchd plist's `PATH` environment variable or configure its explicit path.
|
|
477
496
|
|
|
478
497
|
### Linux (systemd)
|
|
479
498
|
|
|
@@ -485,11 +504,13 @@ sudo systemctl start claude-telegram-bot
|
|
|
485
504
|
sudo systemctl status claude-telegram-bot
|
|
486
505
|
```
|
|
487
506
|
|
|
507
|
+
The systemd unit name is retained as a legacy service identifier so upgrades manage the existing unit instead of installing a duplicate; it does not select the coding-agent provider.
|
|
508
|
+
|
|
488
509
|
## Auto-Updates
|
|
489
510
|
|
|
490
511
|
The bot checks npm for new versions every 5 minutes. When an update is available, you get a chat notification. Send `/upgrade` to update — the bot installs the new version, restarts, runs a doctor check, and notifies you it's back.
|
|
491
512
|
|
|
492
|
-
For direct npm installs, `/upgrade` updates Open Claudia itself and does not install optional
|
|
513
|
+
For direct npm installs, `/upgrade` updates Open Claudia itself and does not install optional provider CLIs such as Codex. Container deployments should roll out a new Docker image when bundled CLI tools change.
|
|
493
514
|
|
|
494
515
|
## Cron Jobs
|
|
495
516
|
|
package/bin/agent.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
// open-claudia agent "<prompt>" [--role "<role>"] [--json] [--cwd <dir>]
|
|
2
|
-
// Spawn a fresh
|
|
1
|
+
// open-claudia agent "<prompt>" [--role "<role>"] [--provider active|claude|codex] [--json] [--cwd <dir>]
|
|
2
|
+
// Spawn a fresh provider-isolated sub-agent for focused research.
|
|
3
3
|
// No session resume; the parent agent captures stdout and decides what
|
|
4
4
|
// to do with the result.
|
|
5
5
|
|
|
6
6
|
const path = require("path");
|
|
7
7
|
|
|
8
8
|
const HELP = `
|
|
9
|
-
Spawn a fresh
|
|
9
|
+
Spawn a fresh Open Claudia sub-agent. Output goes to stdout.
|
|
10
10
|
|
|
11
|
-
open-claudia agent "<prompt>" [--role "<role>"] [--cwd <dir>] [--json] [--timeout <s>]
|
|
11
|
+
open-claudia agent "<prompt>" [--role "<role>"] [--provider active|claude|codex] [--cwd <dir>] [--json] [--timeout <s>]
|
|
12
12
|
|
|
13
13
|
The sub-agent has read-only research tools (Read, Glob, Grep, Bash for read-only
|
|
14
14
|
commands) but no access to your chat session or the send-* CLIs.
|
|
@@ -18,6 +18,7 @@ function takeFlag(args, name) {
|
|
|
18
18
|
const idx = args.indexOf(`--${name}`);
|
|
19
19
|
if (idx < 0) return null;
|
|
20
20
|
const v = args[idx + 1];
|
|
21
|
+
if (v == null || String(v).startsWith("--")) throw new Error(`--${name} requires a value`);
|
|
21
22
|
args.splice(idx, 2);
|
|
22
23
|
return v;
|
|
23
24
|
}
|
|
@@ -29,32 +30,57 @@ function hasFlag(args, name) {
|
|
|
29
30
|
return true;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
console.log(HELP); process.exit(args[0] === "--help" || args[0] === "help" ? 0 : 2);
|
|
35
|
-
}
|
|
36
|
-
const rest = args.slice();
|
|
33
|
+
function parseAgentArgs(input) {
|
|
34
|
+
const rest = input.slice();
|
|
37
35
|
const role = takeFlag(rest, "role");
|
|
36
|
+
const provider = takeFlag(rest, "provider");
|
|
37
|
+
if (provider !== null && !new Set(["active", "claude", "codex"]).has(provider)) {
|
|
38
|
+
throw new Error("--provider must be active, claude, or codex");
|
|
39
|
+
}
|
|
38
40
|
const cwd = takeFlag(rest, "cwd") || process.cwd();
|
|
39
41
|
const timeoutS = takeFlag(rest, "timeout");
|
|
40
42
|
const json = hasFlag(rest, "json");
|
|
43
|
+
if (rest.some((value) => value.startsWith("--"))) {
|
|
44
|
+
throw new Error(`Unknown agent option: ${rest.find((value) => value.startsWith("--"))}`);
|
|
45
|
+
}
|
|
41
46
|
const prompt = rest.join(" ").trim();
|
|
42
|
-
if (!prompt)
|
|
47
|
+
if (!prompt) throw new Error("Missing prompt.");
|
|
48
|
+
let timeoutMs;
|
|
49
|
+
if (timeoutS != null) {
|
|
50
|
+
const seconds = Number(timeoutS);
|
|
51
|
+
if (!Number.isFinite(seconds) || seconds <= 0) throw new Error("--timeout must be a positive number of seconds");
|
|
52
|
+
timeoutMs = seconds * 1000;
|
|
53
|
+
}
|
|
54
|
+
return { prompt, role, provider, cwd, timeoutMs, json };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function run(args) {
|
|
58
|
+
if (args.length === 0 || args[0] === "--help" || args[0] === "help") {
|
|
59
|
+
console.log(HELP); process.exit(args[0] === "--help" || args[0] === "help" ? 0 : 2);
|
|
60
|
+
}
|
|
61
|
+
let parsed;
|
|
62
|
+
try { parsed = parseAgentArgs(args); }
|
|
63
|
+
catch (error) { console.error(error.message); process.exit(2); return; }
|
|
43
64
|
|
|
44
|
-
const {
|
|
65
|
+
const { spawnUtilityAgent } = require(path.join(__dirname, "..", "core", "utility-agent"));
|
|
66
|
+
const { buildSubagentSystemPrompt } = require(path.join(__dirname, "..", "core", "subagent"));
|
|
45
67
|
const channelId = process.env.OC_CHANNEL_ID || null;
|
|
46
68
|
try {
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
69
|
+
const request = {
|
|
70
|
+
purpose: "subagent",
|
|
71
|
+
tier: "medium",
|
|
72
|
+
cwd: parsed.cwd,
|
|
73
|
+
systemPrompt: buildSubagentSystemPrompt(parsed.role),
|
|
74
|
+
readOnly: true,
|
|
50
75
|
channelId,
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
76
|
+
timeoutMs: parsed.timeoutMs,
|
|
77
|
+
};
|
|
78
|
+
if (parsed.provider !== null) request.provider = parsed.provider;
|
|
79
|
+
const res = await spawnUtilityAgent(parsed.prompt, request);
|
|
54
80
|
if (res.text) process.stdout.write(res.text + (res.text.endsWith("\n") ? "" : "\n"));
|
|
55
81
|
if (res.truncated) process.stderr.write("(output truncated to 64KB)\n");
|
|
56
82
|
process.exit(0);
|
|
57
83
|
} catch (e) { console.error(`agent failed: ${e.message}`); process.exit(1); }
|
|
58
84
|
}
|
|
59
85
|
|
|
60
|
-
module.exports = { run, HELP };
|
|
86
|
+
module.exports = { run, HELP, parseAgentArgs };
|