discoclaw 0.5.8 → 0.7.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/.context/README.md +3 -1
- package/.context/dev.md +3 -3
- package/.context/memory.md +2 -2
- package/.context/pa.md +20 -11
- package/.context/project.md +5 -1
- package/.context/runtime.md +37 -1
- package/.context/voice.md +3 -0
- package/.env.example +39 -1
- package/.env.example.full +118 -13
- package/README.md +50 -8
- package/dashboard/server.js +21 -0
- package/dist/cli/dashboard.js +444 -0
- package/dist/cli/dashboard.test.js +963 -0
- package/dist/cli/index.js +243 -56
- package/dist/cli/index.test.js +122 -0
- package/dist/cli/init-wizard.js +22 -0
- package/dist/cli/init-wizard.test.js +47 -0
- package/dist/cold-storage/chunker.js +140 -0
- package/dist/cold-storage/chunker.test.js +141 -0
- package/dist/cold-storage/embeddings.js +63 -0
- package/dist/cold-storage/embeddings.test.js +172 -0
- package/dist/cold-storage/index.js +59 -0
- package/dist/cold-storage/index.test.js +131 -0
- package/dist/cold-storage/openai-compat.js +62 -0
- package/dist/cold-storage/openai-compat.test.js +129 -0
- package/dist/cold-storage/prompt-section.js +64 -0
- package/dist/cold-storage/prompt-section.test.js +107 -0
- package/dist/cold-storage/store.js +246 -0
- package/dist/cold-storage/store.test.js +376 -0
- package/dist/cold-storage/types.js +8 -0
- package/dist/config.js +121 -7
- package/dist/config.test.js +257 -8
- package/dist/cron/executor.js +67 -2
- package/dist/cron/executor.test.js +159 -5
- package/dist/dashboard/api/snapshot.js +7 -0
- package/dist/dashboard/api/snapshot.test.js +152 -0
- package/dist/dashboard/options.js +53 -0
- package/dist/dashboard/options.test.js +44 -0
- package/dist/dashboard/page.js +1160 -0
- package/dist/dashboard/page.test.js +51 -0
- package/dist/dashboard/server-errors.js +20 -0
- package/dist/dashboard/server-errors.test.js +16 -0
- package/dist/dashboard/server.js +477 -0
- package/dist/dashboard/server.test.js +790 -0
- package/dist/dashboard/shipped-entrypoint.test.js +187 -0
- package/dist/discord/action-categories.js +5 -1
- package/dist/discord/actions-channels.js +73 -4
- package/dist/discord/actions-channels.test.js +1 -1
- package/dist/discord/actions-config.js +144 -67
- package/dist/discord/actions-config.test.js +93 -9
- package/dist/discord/actions-crons.js +11 -4
- package/dist/discord/actions-crons.test.js +28 -0
- package/dist/discord/actions-defer.js +21 -3
- package/dist/discord/actions-defer.test.js +271 -3
- package/dist/discord/actions-forge.js +214 -9
- package/dist/discord/actions-forge.test.js +195 -7
- package/dist/discord/actions-guild.js +104 -5
- package/dist/discord/actions-guild.test.js +71 -2
- package/dist/discord/actions-imagegen.js +1 -1
- package/dist/discord/actions-imagegen.test.js +39 -2
- package/dist/discord/actions-loop.js +434 -0
- package/dist/discord/actions-loop.test.js +302 -0
- package/dist/discord/actions-memory.js +38 -4
- package/dist/discord/actions-memory.test.js +88 -5
- package/dist/discord/actions-messaging.js +137 -4
- package/dist/discord/actions-messaging.test.js +112 -3
- package/dist/discord/actions-moderation.js +44 -1
- package/dist/discord/actions-plan.js +307 -108
- package/dist/discord/actions-plan.test.js +187 -11
- package/dist/discord/actions-poll.js +32 -1
- package/dist/discord/actions-spawn.js +152 -18
- package/dist/discord/actions-spawn.test.js +677 -10
- package/dist/discord/actions.js +313 -227
- package/dist/discord/actions.test.js +308 -5
- package/dist/discord/audit-handler.js +32 -2
- package/dist/discord/audit-handler.test.js +71 -0
- package/dist/discord/capsule.js +240 -0
- package/dist/discord/capsule.test.js +150 -0
- package/dist/discord/cold-storage-ingest.js +93 -0
- package/dist/discord/cold-storage-ingest.test.js +220 -0
- package/dist/discord/cron-prefetch.js +301 -0
- package/dist/discord/cron-prefetch.test.js +162 -0
- package/dist/discord/defer-scheduler.js +188 -6
- package/dist/discord/deferred-runner.js +92 -15
- package/dist/discord/deferred-runner.test.js +351 -4
- package/dist/discord/durable-consolidation.js +17 -13
- package/dist/discord/durable-memory.js +70 -2
- package/dist/discord/durable-memory.test.js +128 -1
- package/dist/discord/forge-audit-verdict.js +42 -6
- package/dist/discord/forge-auto-implement.js +3 -0
- package/dist/discord/forge-auto-implement.test.js +12 -0
- package/dist/discord/forge-commands.js +464 -200
- package/dist/discord/forge-commands.test.js +671 -7
- package/dist/discord/forge-plan-registry.js +36 -7
- package/dist/discord/forge-plan-registry.test.js +87 -12
- package/dist/discord/health-command.js +79 -2
- package/dist/discord/health-command.test.js +174 -1
- package/dist/discord/help-command.js +4 -0
- package/dist/discord/help-command.test.js +4 -0
- package/dist/discord/image-download.js +14 -2
- package/dist/discord/image-download.test.js +42 -0
- package/dist/discord/inflight-replies.js +37 -2
- package/dist/discord/inflight-replies.test.js +54 -1
- package/dist/discord/long-run-watchdog.js +398 -0
- package/dist/discord/long-run-watchdog.test.js +290 -0
- package/dist/discord/markdown-code-ranges.js +141 -0
- package/dist/discord/mcp-command.js +72 -0
- package/dist/discord/mcp-command.test.js +93 -0
- package/dist/discord/memory-commands.js +48 -6
- package/dist/discord/memory-commands.test.js +84 -1
- package/dist/discord/memory-timing.integration.test.js +413 -5
- package/dist/discord/message-coordinator.js +1427 -477
- package/dist/discord/message-coordinator.mcp-command.test.js +146 -0
- package/dist/discord/message-coordinator.onboarding.test.js +38 -0
- package/dist/discord/message-coordinator.plan-run.test.js +389 -13
- package/dist/discord/message-coordinator.reaction-action-ordering.test.js +73 -13
- package/dist/discord/message-coordinator.reaction-cleanup.test.js +86 -3
- package/dist/discord/message-coordinator.trace-command.test.js +208 -0
- package/dist/discord/message-history.js +13 -5
- package/dist/discord/message-history.test.js +17 -1
- package/dist/discord/models-command.js +8 -7
- package/dist/discord/models-command.test.js +2 -1
- package/dist/discord/output-common.js +11 -1
- package/dist/discord/output-common.test.js +13 -0
- package/dist/discord/output-utils.js +133 -8
- package/dist/discord/output-utils.test.js +34 -0
- package/dist/discord/phase-status-heartbeat.js +248 -0
- package/dist/discord/phase-status-heartbeat.test.js +126 -0
- package/dist/discord/plan-commands.js +261 -30
- package/dist/discord/plan-commands.test.js +386 -2
- package/dist/discord/plan-manager.js +733 -67
- package/dist/discord/plan-manager.test.js +1070 -64
- package/dist/discord/plan-parser.js +8 -1
- package/dist/discord/plan-parser.test.js +25 -0
- package/dist/discord/prompt-common.js +308 -28
- package/dist/discord/prompt-common.test.js +620 -10
- package/dist/discord/reaction-handler.js +278 -38
- package/dist/discord/reaction-handler.test.js +687 -40
- package/dist/discord/reaction-prompt-store.js +143 -0
- package/dist/discord/reaction-prompt-store.test.js +74 -0
- package/dist/discord/reaction-prompts.js +24 -23
- package/dist/discord/reaction-prompts.test.js +66 -3
- package/dist/discord/restart-command.js +1 -45
- package/dist/discord/runtime-event-text-adapter.js +152 -0
- package/dist/discord/runtime-event-text-adapter.test.js +241 -0
- package/dist/discord/runtime-signal-budget.js +172 -0
- package/dist/discord/runtime-signal-budget.test.js +68 -0
- package/dist/discord/runtime-utils.js +25 -3
- package/dist/discord/runtime-utils.test.js +59 -0
- package/dist/discord/shutdown-context.js +56 -0
- package/dist/discord/shutdown-context.test.js +385 -1
- package/dist/discord/spawn-registry.js +49 -0
- package/dist/discord/spawn-registry.test.js +90 -0
- package/dist/discord/status-channel.js +82 -1
- package/dist/discord/status-channel.test.js +213 -1
- package/dist/discord/status-command.js +8 -0
- package/dist/discord/status-command.test.js +18 -0
- package/dist/discord/streaming-progress.js +79 -5
- package/dist/discord/streaming-progress.test.js +379 -5
- package/dist/discord/summarizer-recency.test.js +217 -0
- package/dist/discord/summarizer.js +141 -8
- package/dist/discord/summarizer.test.js +63 -1
- package/dist/discord/tool-aware-queue.js +32 -6
- package/dist/discord/tool-aware-queue.test.js +67 -0
- package/dist/discord/trace-command.js +153 -0
- package/dist/discord/trace-command.test.js +131 -0
- package/dist/discord/user-errors.js +10 -50
- package/dist/discord/user-errors.test.js +38 -1
- package/dist/discord/verification-evidence.js +150 -0
- package/dist/discord/verification-evidence.test.js +311 -0
- package/dist/discord-followup.test.js +446 -13
- package/dist/discord.health-command.integration.test.js +92 -0
- package/dist/discord.js +1 -0
- package/dist/discord.prompt-context.test.js +181 -12
- package/dist/discord.render.test.js +107 -3
- package/dist/health/config-doctor.js +730 -0
- package/dist/health/config-doctor.test.js +319 -0
- package/dist/image/resize.js +47 -0
- package/dist/image/resize.test.js +145 -0
- package/dist/index.js +699 -166
- package/dist/index.post-connect.js +8 -0
- package/dist/index.runtime.js +35 -3
- package/dist/index.runtime.test.js +263 -0
- package/dist/instructions/system-defaults.js +57 -0
- package/dist/instructions/system-defaults.test.js +94 -0
- package/dist/instructions/tracked-tools.js +59 -0
- package/dist/instructions/tracked-tools.test.js +89 -0
- package/dist/mcp-detect.js +76 -9
- package/dist/mcp-detect.test.js +216 -19
- package/dist/model-config.js +167 -0
- package/dist/model-config.test.js +277 -0
- package/dist/observability/trace-store.js +119 -0
- package/dist/observability/trace-store.test.js +236 -0
- package/dist/pipeline/engine.js +21 -2
- package/dist/pipeline/engine.test.js +100 -3
- package/dist/runtime/anthropic-rest.js +172 -0
- package/dist/runtime/anthropic-rest.test.js +344 -0
- package/dist/runtime/claude-code-cli.test.js +114 -0
- package/dist/runtime/cli-adapter.js +692 -380
- package/dist/runtime/cli-adapter.test.js +401 -5
- package/dist/runtime/cli-shared.js +12 -1
- package/dist/runtime/cli-shared.test.js +17 -1
- package/dist/runtime/codex-cli.js +5 -1
- package/dist/runtime/codex-cli.test.js +700 -9
- package/dist/runtime/concurrency-limit.test.js +52 -0
- package/dist/runtime/gemini-cli.test.js +21 -3
- package/dist/runtime/gemini-rest.js +6 -8
- package/dist/runtime/gemini-rest.test.js +8 -3
- package/dist/runtime/global-supervisor.js +419 -0
- package/dist/runtime/global-supervisor.test.js +347 -0
- package/dist/runtime/long-running-process.js +271 -9
- package/dist/runtime/long-running-process.test.js +164 -6
- package/dist/runtime/model-smoke-helpers.js +2 -2
- package/dist/runtime/model-tiers.js +117 -13
- package/dist/runtime/model-tiers.test.js +96 -12
- package/dist/runtime/openai-compat.js +25 -10
- package/dist/runtime/openai-compat.test.js +116 -2
- package/dist/runtime/openai-tool-exec.js +1214 -13
- package/dist/runtime/openai-tool-exec.test.js +556 -1
- package/dist/runtime/openai-tool-schemas.js +211 -14
- package/dist/runtime/openai-tool-schemas.test.js +59 -4
- package/dist/runtime/process-pool.js +29 -5
- package/dist/runtime/process-pool.test.js +27 -0
- package/dist/runtime/runtime-failure.js +674 -0
- package/dist/runtime/runtime-failure.test.js +209 -0
- package/dist/runtime/session-scanner.js +24 -2
- package/dist/runtime/session-scanner.test.js +5 -1
- package/dist/runtime/strategies/claude-strategy.js +108 -7
- package/dist/runtime/strategies/codex-strategy.js +225 -14
- package/dist/runtime/tools/fs-glob.js +92 -7
- package/dist/runtime/tools/fs-glob.test.js +76 -1
- package/dist/runtime/tools/path-security.js +7 -0
- package/dist/runtime/types.js +2 -0
- package/dist/runtime-overrides.js +27 -11
- package/dist/runtime-overrides.test.js +23 -80
- package/dist/service-control.js +100 -0
- package/dist/service-control.test.js +104 -0
- package/dist/tasks/task-action-executor.test.js +31 -0
- package/dist/tasks/task-action-mutations.js +12 -5
- package/dist/tasks/task-action-thread-sync.js +5 -0
- package/dist/voice/stt-factory.js +3 -0
- package/dist/voice/stt-openai.js +2 -0
- package/dist/voice/tts-factory.js +3 -0
- package/dist/voice/tts-openai.js +1 -0
- package/dist/voice/voice-prompt-builder.js +36 -3
- package/dist/voice/voice-prompt-builder.test.js +60 -9
- package/dist/voice/voice-responder.js +31 -7
- package/dist/voice/voice-responder.test.js +10 -8
- package/dist/voice/voice-sanitize.js +47 -0
- package/dist/voice/voice-sanitize.test.js +30 -1
- package/dist/webhook/server.js +48 -74
- package/dist/webhook/server.test.js +96 -3
- package/dist/workspace-bootstrap.js +100 -13
- package/dist/workspace-bootstrap.test.js +283 -115
- package/dist/workspace-permissions.js +6 -4
- package/dist/workspace-permissions.test.js +9 -2
- package/docs/official-docs.md +123 -0
- package/package.json +12 -2
- package/templates/instructions/SYSTEM_DEFAULTS.md +102 -0
- package/templates/instructions/TOOLS.md +143 -0
- package/templates/mcp.json +7 -2
- package/templates/workspace/AGENTS.md +14 -205
- package/templates/workspace/DISCOCLAW.md +15 -0
- package/templates/workspace/MEMORY.md +1 -1
- package/templates/workspace/TOOLS.md +10 -496
package/.context/README.md
CHANGED
|
@@ -21,11 +21,12 @@ Core instructions live in `CLAUDE.md` at the repo root.
|
|
|
21
21
|
| **Voice system (STT/TTS, audio pipeline, actions)** | `voice.md` |
|
|
22
22
|
| **Forge/plan standing constraints** | `project.md` *(auto-loaded by forge)* |
|
|
23
23
|
| **Plan & Forge commands** | `plan-and-forge.md` *(in docs/, not .context/)* |
|
|
24
|
+
| **Engineering lessons / compound learnings** | `docs/compound-lessons.md` *(single checked-in durable artifact; lives in `docs/`, not `.context/`; human/developer reference, not auto-loaded into agent context)* |
|
|
24
25
|
|
|
25
26
|
## Context Hygiene (Strict)
|
|
26
27
|
- Read the minimum necessary modules for the task.
|
|
27
28
|
- Do not load modules "just in case."
|
|
28
|
-
- Some reference docs live in `docs/` rather than `.context/` — these are human/developer references and are **not** auto-loaded into agent context. The `.context/project.md` file remains the only `.context` module for plan/forge constraints.
|
|
29
|
+
- Some reference docs live in `docs/` rather than `.context/` — these are human/developer references and are **not** auto-loaded into agent context. The `.context/project.md` file remains the only `.context` module for plan/forge constraints, and `docs/compound-lessons.md` remains the single checked-in artifact for distilled engineering lessons.
|
|
29
30
|
|
|
30
31
|
## Quick Reference
|
|
31
32
|
- **pa.md** — PA behavioral rules, Discord formatting, memory, group chat etiquette, autonomy tiers
|
|
@@ -42,3 +43,4 @@ Core instructions live in `CLAUDE.md` at the repo root.
|
|
|
42
43
|
- **voice.md** — Voice subsystem: module map, audio data flow, key patterns (barge-in, allowlist gating), wiring sequence, dependencies, config reference
|
|
43
44
|
- **project.md** — Standing constraints auto-loaded by forge drafter and auditor
|
|
44
45
|
- **docs/plan-and-forge.md** — Canonical reference for `!plan` and `!forge` commands (lives in `docs/`, not `.context/` — human/developer reference, not auto-loaded into agent context)
|
|
46
|
+
- **docs/compound-lessons.md** — Single checked-in durable artifact for distilled engineering lessons from audits, forge runs, and repeated workflow failures
|
package/.context/dev.md
CHANGED
|
@@ -79,12 +79,12 @@ Two setup paths:
|
|
|
79
79
|
| Variable | Default | Description |
|
|
80
80
|
|----------|---------|-------------|
|
|
81
81
|
| `PRIMARY_RUNTIME` | `claude` | Runtime engine (`claude`, `openai`, `openrouter`, `gemini`, `codex`) |
|
|
82
|
-
| `RUNTIME_MODEL` | `capable` | Model tier (`fast`, `capable`) or concrete model name passed to the CLI |
|
|
82
|
+
| `RUNTIME_MODEL` | `capable` | **Deprecated — use `models.json` instead.** Model tier (`fast`, `capable`) or concrete model name passed to the CLI |
|
|
83
83
|
| `RUNTIME_TOOLS` | `Bash,Read,Write,Edit,Glob,Grep,WebSearch,WebFetch` | Comma-separated tool list |
|
|
84
84
|
| `RUNTIME_TIMEOUT_MS` | `1800000` | Per-invocation timeout in milliseconds |
|
|
85
85
|
| `RUNTIME_FALLBACK_MODEL` | *(unset)* | Auto-fallback model when primary is overloaded (e.g. `sonnet`) |
|
|
86
86
|
| `RUNTIME_MAX_BUDGET_USD` | *(unset)* | Max USD per CLI process; one-shot = per invocation, multi-turn = per session lifetime |
|
|
87
|
-
| `DISCOCLAW_FAST_MODEL` | `fast` | Default "fast" model tier alias used for summarization, auto-tag, and cron parsing |
|
|
87
|
+
| `DISCOCLAW_FAST_MODEL` | `fast` | **Deprecated — use `models.json` instead.** Default "fast" model tier alias used for summarization, auto-tag, and cron parsing |
|
|
88
88
|
| `DISCOCLAW_RUNTIME_SESSIONS` | `1` | Persist Claude session IDs across messages |
|
|
89
89
|
| `DISCOCLAW_SESSION_SCANNING` | `1` | Enable session ID scanning for resume detection |
|
|
90
90
|
| `DISCOCLAW_ACTION_FOLLOWUP_DEPTH` | `3` | Max depth for chained action follow-ups |
|
|
@@ -165,7 +165,7 @@ Two setup paths:
|
|
|
165
165
|
### Health/Status
|
|
166
166
|
| Variable | Default | Description |
|
|
167
167
|
|----------|---------|-------------|
|
|
168
|
-
| `DISCOCLAW_HEALTH_COMMANDS_ENABLED` | `1` | Enable `!health`
|
|
168
|
+
| `DISCOCLAW_HEALTH_COMMANDS_ENABLED` | `1` | Enable `!health` and `!doctor` commands (uptime, memory, runtime status, config doctor) |
|
|
169
169
|
| `DISCOCLAW_HEALTH_VERBOSE_ALLOWLIST` | *(empty — falls back to `DISCORD_ALLOW_USER_IDS`)* | Space/comma-separated user IDs that can request verbose health output |
|
|
170
170
|
|
|
171
171
|
### Plan & Forge
|
package/.context/memory.md
CHANGED
|
@@ -161,8 +161,8 @@ Bot: Sure — is this related to the auth middleware test you were debugging
|
|
|
161
161
|
`workspace/MEMORY.md` + `workspace/memory/YYYY-MM-DD.md`
|
|
162
162
|
|
|
163
163
|
Curated long-term notes and daily scratch logs. Loaded in DMs only. These hold
|
|
164
|
-
things too nuanced for structured durable items — decisions,
|
|
165
|
-
|
|
164
|
+
things too nuanced for structured durable items — decisions, project context,
|
|
165
|
+
relationship dynamics. Engineering lessons belong in `docs/compound-lessons.md`.
|
|
166
166
|
|
|
167
167
|
**What the user sees:**
|
|
168
168
|
- In DMs, the bot has deep context about ongoing projects and past decisions.
|
package/.context/pa.md
CHANGED
|
@@ -9,17 +9,20 @@ For architecture details, see `.context/architecture.md`.
|
|
|
9
9
|
|
|
10
10
|
## Workspace Files
|
|
11
11
|
|
|
12
|
-
| File | Purpose | Loaded |
|
|
13
|
-
|
|
14
|
-
| `SOUL.md` | Core personality and values | Every prompt |
|
|
15
|
-
| `IDENTITY.md` | Name and vibe | Every prompt |
|
|
16
|
-
| `USER.md` | Who you're helping | Every prompt |
|
|
17
|
-
| `
|
|
18
|
-
| `
|
|
19
|
-
| `
|
|
20
|
-
| `
|
|
12
|
+
| File | Purpose | Owner | Loaded |
|
|
13
|
+
|------|---------|-------|--------|
|
|
14
|
+
| `SOUL.md` | Core personality and values | User | Every prompt |
|
|
15
|
+
| `IDENTITY.md` | Name and vibe | User | Every prompt |
|
|
16
|
+
| `USER.md` | Who you're helping | User | Every prompt |
|
|
17
|
+
| `templates/instructions/SYSTEM_DEFAULTS.md` | Tracked default instructions (runtime-injected) | Discoclaw repo (tracked) | Every prompt |
|
|
18
|
+
| `AGENTS.md` | Personal rules and preferences | User (never overwritten) | Every prompt |
|
|
19
|
+
| `TOOLS.md` | Available tools and integrations | Discoclaw | Every prompt |
|
|
20
|
+
| `MEMORY.md` | Curated long-term memory | User | DM prompts |
|
|
21
|
+
| `BOOTSTRAP.md` | First-run onboarding (deleted after) | User | Once |
|
|
21
22
|
|
|
22
23
|
Templates live in `templates/workspace/` and are scaffolded on first run (copy-if-missing).
|
|
24
|
+
Tracked defaults come from `templates/instructions/SYSTEM_DEFAULTS.md` and are injected at runtime.
|
|
25
|
+
Legacy `workspace/DISCOCLAW.md` files are not authoritative.
|
|
23
26
|
|
|
24
27
|
## Operational Essentials
|
|
25
28
|
|
|
@@ -115,5 +118,11 @@ See `.context/memory.md` for full architecture, examples, and config reference.
|
|
|
115
118
|
|
|
116
119
|
## Customization
|
|
117
120
|
|
|
118
|
-
|
|
119
|
-
|
|
121
|
+
Instruction precedence is deterministic:
|
|
122
|
+
1. immutable security policy (`ROOT_POLICY`)
|
|
123
|
+
2. tracked defaults (`templates/instructions/SYSTEM_DEFAULTS.md`)
|
|
124
|
+
3. `workspace/AGENTS.md` overrides
|
|
125
|
+
4. memory/context sections
|
|
126
|
+
|
|
127
|
+
Customize behavior in `workspace/AGENTS.md` (user-owned, never overwritten).
|
|
128
|
+
Do not rely on `workspace/DISCOCLAW.md`; defaults are sourced from the tracked template and injected at runtime.
|
package/.context/project.md
CHANGED
|
@@ -20,6 +20,10 @@ Standing constraints for planning and auditing. These apply to all forge/plan op
|
|
|
20
20
|
- Keep changes minimal — don't over-engineer for hypothetical multi-user scenarios.
|
|
21
21
|
- Prefer wiring existing systems together over building new abstractions.
|
|
22
22
|
- Tests are required for new functionality.
|
|
23
|
+
- `docs/compound-lessons.md` is the single checked-in durable artifact for reusable engineering lessons. Raw findings can stay in plans, audits, postmortems, or task context, but distilled standing guidance belongs there.
|
|
24
|
+
- Forge drafter/auditor/reviser agents should consult `docs/compound-lessons.md` for known patterns and pitfalls before drafting, search for an existing matching lesson first, and update that entry instead of proposing a near-duplicate.
|
|
25
|
+
- Before drafting, consult the `## Lessons` section of `docs/compound-lessons.md` to avoid rediscovering known patterns. When a plan reveals a materially distinct reusable lesson from audits, postmortems, or task/workflow context, include a `docs/compound-lessons.md` update in `## Changes`.
|
|
26
|
+
- If a change closes a recurring workflow, review, or quality gap, the implementing engineer must either update `docs/compound-lessons.md` in the same change or explicitly record that no durable lesson was needed. Auditors and reviewers must verify that decision and the dedup check before approval.
|
|
23
27
|
|
|
24
28
|
## Plan Scope & Size Constraints
|
|
25
29
|
|
|
@@ -40,4 +44,4 @@ Plans that grow too large fail — they blow past token limits, cause audit/revi
|
|
|
40
44
|
### Auditor guidance
|
|
41
45
|
- Do NOT flag "underspecified implementation details" as medium/high. The plan describes intent and scope — the implementing agent fills in the details.
|
|
42
46
|
- DO flag: missing scope items, incorrect assumptions about existing code, safety/correctness issues, missing error handling for external boundaries.
|
|
43
|
-
- If a plan is too large or touches too many source modules, flag that as **high severity** with recommendation to split. Co-located test files, lockfile changes from dependency additions, and doc/inventory updates do not count toward the scope cap.
|
|
47
|
+
- If a plan is too large or touches too many source modules, flag that as **high severity** with recommendation to split. Co-located test files, lockfile changes from dependency additions, and doc/inventory updates do not count toward the scope cap.
|
package/.context/runtime.md
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
## Model Names & IDs
|
|
4
4
|
|
|
5
5
|
**Always research official documentation** when referencing model names, IDs, or parameters — never guess or rely on training data alone. Model names change frequently across providers.
|
|
6
|
+
For the complete maintainer docs index covering providers, SDKs, Discord, MCP, and dependency references, see `docs/official-docs.md`.
|
|
6
7
|
|
|
7
8
|
Sources to check:
|
|
8
9
|
- **Anthropic:** https://platform.claude.com/docs/en/about-claude/models/overview
|
|
@@ -45,7 +46,7 @@ The factory provides: subprocess tracking, process pool, stall detection, sessio
|
|
|
45
46
|
| Strategy | File | Multi-turn | Notes |
|
|
46
47
|
|----------|------|------------|-------|
|
|
47
48
|
| Claude Code | `strategies/claude-strategy.ts` | process-pool | Default JSONL parsing, image support |
|
|
48
|
-
| Codex CLI | `strategies/codex-strategy.ts` | session-resume | Custom JSONL (thread.started, item.completed), error sanitization; reasoning items surface in the Discord preview during streaming but are excluded from the final reply |
|
|
49
|
+
| Codex CLI | `strategies/codex-strategy.ts` | session-resume | Custom JSONL (thread.started, item.completed), error sanitization; reasoning items surface in the Discord preview during streaming but are excluded from the final reply; image support via `--image` temp files; if a resumed turn includes images, the adapter resets to a fresh session because `codex exec resume` cannot accept `--image`, notifies the user, and loses prior conversation context |
|
|
49
50
|
| Gemini CLI | `strategies/gemini-strategy.ts` | none (Phase 1) | Text-only output mode; no sessions; stdin fallback for large prompts |
|
|
50
51
|
| Template | `strategies/template-strategy.ts` | — | Commented starting point for new models |
|
|
51
52
|
|
|
@@ -102,6 +103,39 @@ Shutdown: `killAllSubprocesses()` from `cli-adapter.ts` kills all tracked subpro
|
|
|
102
103
|
- No tool execution, no fs tools
|
|
103
104
|
- No image input/output support
|
|
104
105
|
|
|
106
|
+
## Anthropic REST Runtime
|
|
107
|
+
|
|
108
|
+
Direct HTTP adapter for the Anthropic Messages API — no CLI subprocess, no cold-start. Designed for latency-sensitive paths like voice where the ~2-4 s CLI bootstrap is unacceptable.
|
|
109
|
+
|
|
110
|
+
- Adapter: `src/runtime/anthropic-rest.ts`
|
|
111
|
+
- Factory: `createAnthropicRestRuntime(opts)`
|
|
112
|
+
- Auth: `x-api-key` header (from `ANTHROPIC_API_KEY` env var)
|
|
113
|
+
- Streaming: SSE (`stream: true`) — emits `text_delta`, `usage`, `text_final`, `done` engine events
|
|
114
|
+
- Runtime ID: `claude_code` (same as CLI adapter so model tier resolution is compatible)
|
|
115
|
+
- Default model: `claude-sonnet-4-6` (set at registration time in `src/index.ts`)
|
|
116
|
+
- Capabilities: `streaming_text` only (no tools, no sessions)
|
|
117
|
+
- Conditional registration: only registered as `'anthropic'` in the runtime registry when `ANTHROPIC_API_KEY` is set
|
|
118
|
+
|
|
119
|
+
Env vars:
|
|
120
|
+
|
|
121
|
+
| Var | Default | Purpose |
|
|
122
|
+
|-----|---------|---------|
|
|
123
|
+
| `ANTHROPIC_API_KEY` | *(required)* | API key; also gates adapter registration |
|
|
124
|
+
|
|
125
|
+
Configurable via `AnthropicRestOpts`: `baseUrl` (default `https://api.anthropic.com`), `apiVersion` (default `2023-06-01`), `defaultMaxTokens` (default `1024`).
|
|
126
|
+
|
|
127
|
+
### Voice auto-wiring
|
|
128
|
+
|
|
129
|
+
When both `ANTHROPIC_API_KEY` and `DISCOCLAW_VOICE_ENABLED=1` are set, the startup path in `src/index.ts` auto-wires the Anthropic REST adapter as the voice runtime. `resolveVoiceRuntime()` checks `voiceModelRef.runtime` first, then falls back to the `'anthropic'` registry entry, then the primary CLI runtime. Model overrides are now configured in `models.json`; the voice runtime override is still in `runtime-overrides.json` (`voiceRuntime` key). The model can also be changed via the `!models` command.
|
|
130
|
+
|
|
131
|
+
### Key files
|
|
132
|
+
|
|
133
|
+
| File | Role |
|
|
134
|
+
|------|------|
|
|
135
|
+
| `src/runtime/anthropic-rest.ts` | Adapter: SSE streaming, abort/timeout, system prompt extraction |
|
|
136
|
+
| `src/runtime/anthropic-rest.test.ts` | Unit tests (mocked fetch, SSE parsing, error handling, abort) |
|
|
137
|
+
| `src/runtime/openai-compat.ts` | Provides `splitSystemPrompt()` used by the adapter |
|
|
138
|
+
|
|
105
139
|
## OpenRouter Adapter
|
|
106
140
|
|
|
107
141
|
- Implementation: reuses `src/runtime/openai-compat.ts` with `id: 'openrouter'` — no separate adapter file needed.
|
|
@@ -279,6 +313,8 @@ When a Discord message or reaction target has image attachments (PNG, JPEG, WebP
|
|
|
279
313
|
3. **Download** — `downloadAttachment()` fetches the image with a 10 s timeout, post-checks actual size, and returns base64.
|
|
280
314
|
4. **Delivery** — The runtime adapter writes a `stream-json` stdin message containing `[{ type: 'text', text: prompt }, { type: 'image', source: { type: 'base64', ... } }, ...]`. When images are present, `--output-format` is forced to `stream-json` regardless of the configured format.
|
|
281
315
|
|
|
316
|
+
**Codex delivery:** Codex CLI does not accept base64 image data via stdin — it requires file paths on disk via `--image <path>` flags. The Codex strategy writes each `ImageData` (base64) to a temp file before invocation and cleans up after. If images arrive on a resumed Codex turn, the adapter automatically falls back to a fresh session because `codex exec resume` does not support `--image`; the user sees a notification, and prior conversation context is lost. The full pipeline is: Discord attachment → base64 `ImageData` → temp file → `--image <path>` → cleanup.
|
|
317
|
+
|
|
282
318
|
### Security controls
|
|
283
319
|
|
|
284
320
|
| Control | Detail |
|
package/.context/voice.md
CHANGED
|
@@ -51,6 +51,8 @@ User speaks in Discord voice channel
|
|
|
51
51
|
|
|
52
52
|
- **Allowlist gating** — `AudioReceiver` only subscribes to users in `DISCORD_ALLOW_USER_IDS`. Empty allowlist = ignore everyone (fail-closed).
|
|
53
53
|
- **Dual-flag voice actions** — Voice action execution requires both `VOICE_ENABLED` and `DISCORD_ACTIONS_VOICE`. The `buildVoiceActionFlags()` function intersects a voice-specific allowlist (messaging, tasks, memory) with env config; all other action categories are hard-disabled.
|
|
54
|
+
- **Queued invocations** — `VoiceResponder` queues new transcriptions when a pipeline is already in-flight instead of aborting the active AI call. Only the most recent pending text is kept (coalesced). On completion the responder drains the queue, processing the next pending transcription. This eliminates the death-spiral where CLI cold-start latency caused cascading cancellations. Barge-in still stops *playback* immediately but never cancels the running AI request.
|
|
55
|
+
- **Fast invoke path** — When `ANTHROPIC_API_KEY` is set, voice auto-wires to the Anthropic REST adapter (`src/runtime/anthropic-rest.ts`) instead of the CLI subprocess path. Direct HTTP eliminates the ~2-4 s CLI cold-start, bringing first-token latency under 500 ms. The wiring happens at startup in `src/index.ts`; at invoke time `resolveVoiceRuntime()` picks the `'anthropic'` adapter from the registry. Model configuration is now in `models.json`; the voice runtime override is still in `runtime-overrides.json` (`voiceRuntime` key). The model can also be changed via the `!models` command.
|
|
54
56
|
- **Generation-based cancellation** — `VoiceResponder` increments a generation counter on each new transcription. If a newer transcription arrives mid-pipeline, the older one is silently abandoned.
|
|
55
57
|
- **Barge-in** — Gated on a non-empty STT transcription result, not the raw VAD `speaking.start` event. Echo from the bot's own TTS leaking through the user's mic produces empty transcriptions and is ignored. Only when `VoiceResponder.handleTranscription()` receives a non-empty transcript while the player is active does it stop playback and advance the generation counter. This eliminates false positives from echo without relying on a static grace-period timeout.
|
|
56
58
|
- **Conversation ring buffer** — `ConversationBuffer` maintains a per-guild 10-turn ring buffer of user/model exchanges that gets injected into the voice prompt as formatted conversation history. Turns are appended live during a session. On voice join, the buffer backfills from recent voice-log channel messages so context carries across disconnects. The buffer is cleared when the bot leaves the voice channel.
|
|
@@ -87,4 +89,5 @@ When `voiceEnabled=true`, the post-connect block in `src/index.ts` initializes t
|
|
|
87
89
|
| `DEEPGRAM_TTS_VOICE` | `aura-2-asteria-en` | Deepgram TTS voice name |
|
|
88
90
|
| `DEEPGRAM_TTS_SPEED` | `1.3` | Deepgram TTS playback speed (range 0.5–1.5) |
|
|
89
91
|
| `CARTESIA_API_KEY` | — | Required for cartesia TTS |
|
|
92
|
+
| `ANTHROPIC_API_KEY` | — | Enables the Anthropic REST adapter; when set and voice is enabled, voice auto-wires to the direct Messages API path (zero CLI cold-start). See `runtime.md § Anthropic REST Runtime`. |
|
|
90
93
|
| *(built-in)* | — | Telegraphic style instruction hardcoded into every voice AI invocation — front-loads the answer, strips preambles/markdown/filler, keeps responses short for TTS latency. Not an env var; not overridable by `DISCOCLAW_VOICE_SYSTEM_PROMPT`. |
|
package/.env.example
CHANGED
|
@@ -45,6 +45,24 @@ DISCORD_ALLOW_USER_IDS=
|
|
|
45
45
|
# Collected as a required field by `discoclaw init`.
|
|
46
46
|
DISCORD_GUILD_ID=
|
|
47
47
|
|
|
48
|
+
# Optional custom service name for multi-instance installs.
|
|
49
|
+
# Written automatically by `discoclaw install-daemon --service-name <name>`.
|
|
50
|
+
# `discoclaw dashboard`, `!restart`, and other service actions use this to target the correct unit.
|
|
51
|
+
# Leave unset to use the default service name: discoclaw
|
|
52
|
+
#DISCOCLAW_SERVICE_NAME=discoclaw
|
|
53
|
+
# Disable the local operator dashboard HTTP server inside the main discoclaw process.
|
|
54
|
+
# It is enabled by default and binds to 127.0.0.1. To allow access from a Tailscale
|
|
55
|
+
# phone/browser without SSH tunneling, set DISCOCLAW_DASHBOARD_TRUSTED_HOSTS to your
|
|
56
|
+
# tailnet IP or MagicDNS name.
|
|
57
|
+
#DISCOCLAW_DASHBOARD_ENABLED=0
|
|
58
|
+
# Dashboard port (default: 9401). Multi-instance setups on the same machine must use distinct ports.
|
|
59
|
+
#DISCOCLAW_DASHBOARD_PORT=9401
|
|
60
|
+
# Comma-separated Host header allowlist for non-loopback dashboard access.
|
|
61
|
+
# When set, the dashboard binds to 0.0.0.0 but still rejects all Host headers except
|
|
62
|
+
# loopback names plus the entries listed here.
|
|
63
|
+
# Example: phone.tailnet.ts.net,100.64.0.12
|
|
64
|
+
#DISCOCLAW_DASHBOARD_TRUSTED_HOSTS=
|
|
65
|
+
|
|
48
66
|
# Where the Claude CLI runs (its working directory).
|
|
49
67
|
# Default: ./workspace (or $DISCOCLAW_DATA_DIR/workspace if DATA_DIR is set)
|
|
50
68
|
#WORKSPACE_CWD=
|
|
@@ -59,12 +77,31 @@ DISCORD_GUILD_ID=
|
|
|
59
77
|
#CODEX_DANGEROUSLY_BYPASS_APPROVALS_AND_SANDBOX=1
|
|
60
78
|
# Optional: isolate Codex state/sessions from ~/.codex (helps avoid stale rollout DB issues):
|
|
61
79
|
#CODEX_HOME=/absolute/path/to/.codex-home-discoclaw
|
|
80
|
+
# Runtime launcher state hardening for CLI providers.
|
|
81
|
+
# When enabled, launcher state/path errors (e.g. Codex rollout-path corruption) trigger
|
|
82
|
+
# one automatic retry with CODEX_HOME set to a clean stable home.
|
|
83
|
+
# Set to 0 to disable this behavior.
|
|
84
|
+
#DISCOCLAW_CLI_LAUNCHER_STATE_HARDENING=1
|
|
85
|
+
# Optional stable home override used by the hardening retry above.
|
|
86
|
+
# Default: <discoclaw cwd>/.codex-home-discoclaw
|
|
87
|
+
#DISCOCLAW_CODEX_STABLE_HOME=/absolute/path/to/.codex-home-discoclaw
|
|
62
88
|
# Disable Codex session persistence/resume (workaround for session DB issues):
|
|
63
89
|
#CODEX_DISABLE_SESSIONS=1
|
|
64
|
-
|
|
90
|
+
# Emit Codex item lifecycle debug events in stream preview (item.started/item.completed + item.type):
|
|
91
|
+
#DISCOCLAW_CODEX_ITEM_TYPE_DEBUG=1
|
|
92
|
+
# Log each Discord preview line decision (allowed/suppressed + rendered line) to journald:
|
|
93
|
+
#DISCOCLAW_DEBUG_STREAM_PREVIEW_LINES=1
|
|
94
|
+
|
|
95
|
+
# [DEPRECATED] Model configuration has moved to models.json (managed via !models commands).
|
|
96
|
+
# RUNTIME_MODEL is still read as a fallback when models.json is missing, but new deployments
|
|
97
|
+
# should use `!models set chat <model>` instead. See docs for migration details.
|
|
65
98
|
# Model tier: fast | capable | deep (provider-agnostic).
|
|
66
99
|
# Concrete model names (e.g. opus, sonnet, gpt-4o) are still accepted as passthrough.
|
|
67
100
|
#RUNTIME_MODEL=capable
|
|
101
|
+
# [DEPRECATED] Plan execution has its own startup default now. When models.json is missing
|
|
102
|
+
# or reset, DISCOCLAW_PLAN_RUN_MODEL seeds the dedicated `plan-run` role independently.
|
|
103
|
+
# New deployments should use `!models set plan-run <model>` instead.
|
|
104
|
+
#DISCOCLAW_PLAN_RUN_MODEL=capable
|
|
68
105
|
|
|
69
106
|
# Output format for the Claude CLI. stream-json gives smoother streaming.
|
|
70
107
|
#CLAUDE_OUTPUT_FORMAT=stream-json
|
|
@@ -117,6 +154,7 @@ DISCORD_GUILD_ID=
|
|
|
117
154
|
# Only set this to override the auto-discovered channel.
|
|
118
155
|
#DISCOCLAW_VOICE_LOG_CHANNEL=
|
|
119
156
|
#DEEPGRAM_API_KEY=
|
|
157
|
+
#ANTHROPIC_API_KEY=
|
|
120
158
|
|
|
121
159
|
# ----------------------------------------------------------
|
|
122
160
|
# Secret management via Discord DM
|
package/.env.example.full
CHANGED
|
@@ -49,14 +49,30 @@ DISCORD_ALLOW_USER_IDS=
|
|
|
49
49
|
#PRIMARY_RUNTIME=claude
|
|
50
50
|
|
|
51
51
|
# --- Primary models ---
|
|
52
|
+
# [DEPRECATED] Model configuration has moved to models.json (managed via !models commands).
|
|
53
|
+
# RUNTIME_MODEL is still read as a fallback when models.json is missing, but new deployments
|
|
54
|
+
# should use `!models set chat <model>` instead. See docs for migration details.
|
|
52
55
|
# Model tier: fast | capable | deep (provider-agnostic).
|
|
53
56
|
# Concrete model names (e.g. opus, sonnet, gpt-4o) are still accepted as passthrough.
|
|
54
57
|
#RUNTIME_MODEL=capable
|
|
58
|
+
# [DEPRECATED] Plan execution has its own startup default now. When models.json is missing
|
|
59
|
+
# or reset, DISCOCLAW_PLAN_RUN_MODEL seeds the dedicated `plan-run` role independently.
|
|
60
|
+
# New deployments should use `!models set plan-run <model>` instead.
|
|
61
|
+
#DISCOCLAW_PLAN_RUN_MODEL=capable
|
|
55
62
|
|
|
56
63
|
# --- Fast-tier default ---
|
|
64
|
+
# [DEPRECATED] Model configuration has moved to models.json (managed via !models commands).
|
|
65
|
+
# DISCOCLAW_FAST_MODEL is still read as a fallback when models.json is missing, but new
|
|
66
|
+
# deployments should use `!models set fast <model>` instead.
|
|
57
67
|
# Sets the default model for all "small" tasks (summary, cron, cron auto-tag, task auto-tag).
|
|
58
68
|
# Valid tiers: fast | capable | deep. Individual overrides (DISCOCLAW_SUMMARY_MODEL, etc.) still win when set.
|
|
59
69
|
#DISCOCLAW_FAST_MODEL=fast
|
|
70
|
+
# [DEPRECATED] Fast-tier runtime selection has moved to models.json (managed via !models commands).
|
|
71
|
+
# Use `!models set fast <provider>/<model>` to route fast-tier through a different runtime —
|
|
72
|
+
# the provider prefix auto-selects the runtime adapter. DISCOCLAW_FAST_RUNTIME is still read
|
|
73
|
+
# as a fallback when models.json has no fast-tier entry, but new deployments should migrate.
|
|
74
|
+
# Valid values: claude | gemini | codex | openai | openrouter
|
|
75
|
+
#DISCOCLAW_FAST_RUNTIME=
|
|
60
76
|
|
|
61
77
|
# --- Tier model overrides ---
|
|
62
78
|
# Override the concrete model resolved for any runtime × tier combination.
|
|
@@ -177,6 +193,10 @@ DISCORD_GUILD_ID=
|
|
|
177
193
|
# Per-category flags (only active when master switch is 1):
|
|
178
194
|
#DISCOCLAW_DISCORD_ACTIONS_CHANNELS=1
|
|
179
195
|
#DISCOCLAW_DISCORD_ACTIONS_MESSAGING=1
|
|
196
|
+
# Comma-separated absolute directory paths allowed for the sendFile Discord action.
|
|
197
|
+
# Defaults to /tmp when unset. DISCOCLAW_DATA_DIR and WORKSPACE_CWD are always
|
|
198
|
+
# auto-included when configured. Symlinks are resolved via fs.realpath() before checking.
|
|
199
|
+
#DISCOCLAW_SENDFILE_ALLOWED_DIRS=/tmp
|
|
180
200
|
#DISCOCLAW_DISCORD_ACTIONS_GUILD=1
|
|
181
201
|
# Intentionally off — moderation actions require explicit opt-in.
|
|
182
202
|
#DISCOCLAW_DISCORD_ACTIONS_MODERATION=0
|
|
@@ -207,6 +227,17 @@ DISCOCLAW_DISCORD_ACTIONS_DEFER=1
|
|
|
207
227
|
# When depth reaches this limit, the defer action is disabled for that run (default: 4).
|
|
208
228
|
#DISCOCLAW_DISCORD_ACTIONS_DEFER_MAX_DEPTH=4
|
|
209
229
|
|
|
230
|
+
# Allow the AI to schedule repeating self-invocations with loopCreate/loopList/loopCancel.
|
|
231
|
+
# Loops are inspectable recurring jobs and should be preferred over chaining repeated defers.
|
|
232
|
+
# Default: on. Set to 0 to disable.
|
|
233
|
+
#DISCOCLAW_DISCORD_ACTIONS_LOOP=1
|
|
234
|
+
# Minimum interval (seconds) accepted for loopCreate (default: 60).
|
|
235
|
+
#DISCOCLAW_DISCORD_ACTIONS_LOOP_MIN_INTERVAL_SECONDS=60
|
|
236
|
+
# Maximum interval (seconds) accepted for loopCreate (default: 86400 / 24 h).
|
|
237
|
+
#DISCOCLAW_DISCORD_ACTIONS_LOOP_MAX_INTERVAL_SECONDS=86400
|
|
238
|
+
# Maximum number of active loops allowed at once (default: 5).
|
|
239
|
+
#DISCOCLAW_DISCORD_ACTIONS_LOOP_MAX_CONCURRENT=5
|
|
240
|
+
|
|
210
241
|
# Allow the AI to spawn parallel sub-agents in target channels.
|
|
211
242
|
# Each spawned agent is a fire-and-forget invocation that posts output to the specified channel.
|
|
212
243
|
# Spawned agents run at recursion depth 1 and cannot themselves spawn further agents.
|
|
@@ -255,6 +286,10 @@ DISCOCLAW_DISCORD_ACTIONS_DEFER=1
|
|
|
255
286
|
#DISCOCLAW_SUMMARY_MODEL=fast
|
|
256
287
|
#DISCOCLAW_SUMMARY_MAX_CHARS=2000
|
|
257
288
|
#DISCOCLAW_SUMMARY_EVERY_N_TURNS=5
|
|
289
|
+
# Estimated token threshold for one-pass summary recompression.
|
|
290
|
+
#DISCOCLAW_SUMMARY_MAX_TOKENS=1500
|
|
291
|
+
# Compression target ratio used when recompression runs (target = max_tokens * ratio).
|
|
292
|
+
#DISCOCLAW_SUMMARY_TARGET_RATIO=0.65
|
|
258
293
|
# Override storage directory for rolling summaries.
|
|
259
294
|
#DISCOCLAW_SUMMARY_DATA_DIR=
|
|
260
295
|
# Durable per-user facts/preferences (manual via !memory commands).
|
|
@@ -287,6 +322,34 @@ DISCOCLAW_DISCORD_ACTIONS_DEFER=1
|
|
|
287
322
|
# Character budget for recent conversation history in prompts (0 = disabled).
|
|
288
323
|
#DISCOCLAW_MESSAGE_HISTORY_BUDGET=3000
|
|
289
324
|
|
|
325
|
+
# ----------------------------------------------------------
|
|
326
|
+
# Cold storage — vector-indexed conversation history (off by default)
|
|
327
|
+
# ----------------------------------------------------------
|
|
328
|
+
# Master switch — enables SQLite + sqlite-vec backed long-term memory.
|
|
329
|
+
# When enabled, messages are chunked, embedded, and stored for semantic
|
|
330
|
+
# retrieval. Matching context is injected into prompts automatically.
|
|
331
|
+
#DISCOCLAW_COLD_STORAGE_ENABLED=0
|
|
332
|
+
# API key for the embedding provider. Falls back to OPENAI_API_KEY when unset.
|
|
333
|
+
# For the default "openai" provider, this is your OpenAI API key.
|
|
334
|
+
#COLD_STORAGE_API_KEY=
|
|
335
|
+
# Embedding provider: openai (default) or openai-compat (any OpenAI-compatible API).
|
|
336
|
+
#COLD_STORAGE_PROVIDER=openai
|
|
337
|
+
# Model name for embeddings (required for openai-compat; optional for openai).
|
|
338
|
+
#COLD_STORAGE_MODEL=
|
|
339
|
+
# Embedding dimensions (required for openai-compat; optional for openai).
|
|
340
|
+
#COLD_STORAGE_DIMENSIONS=
|
|
341
|
+
# Base URL for the embedding API (required for openai-compat; optional for openai).
|
|
342
|
+
#COLD_STORAGE_BASE_URL=
|
|
343
|
+
# Path to the SQLite database file. Default: <data-dir>/cold-storage.db
|
|
344
|
+
#COLD_STORAGE_DB_PATH=
|
|
345
|
+
# Max characters for the cold-storage prompt section injected into each prompt (default: 1500).
|
|
346
|
+
#DISCOCLAW_COLD_STORAGE_INJECT_MAX_CHARS=1500
|
|
347
|
+
# Max search results returned per query (default: 10).
|
|
348
|
+
#DISCOCLAW_COLD_STORAGE_SEARCH_LIMIT=10
|
|
349
|
+
# Comma-separated channel IDs to restrict cold-storage ingestion and retrieval.
|
|
350
|
+
# When set, only messages from these channels are stored/searched. Empty = all channels.
|
|
351
|
+
#COLD_STORAGE_CHANNEL_FILTER=
|
|
352
|
+
|
|
290
353
|
# ----------------------------------------------------------
|
|
291
354
|
# Bot identity
|
|
292
355
|
# ----------------------------------------------------------
|
|
@@ -359,12 +422,38 @@ DISCOCLAW_DISCORD_ACTIONS_DEFER=1
|
|
|
359
422
|
# Sets the systemd unit / launchd label name used by !restart and !update apply.
|
|
360
423
|
# Default: discoclaw. Ignored when DC_RESTART_CMD is set (that overrides the entire command).
|
|
361
424
|
#DISCOCLAW_SERVICE_NAME=discoclaw
|
|
425
|
+
# Disable the local operator dashboard HTTP server inside the main discoclaw process.
|
|
426
|
+
# It is enabled by default and bound to 127.0.0.1; see DISCOCLAW_DASHBOARD_TRUSTED_HOSTS
|
|
427
|
+
# for Tailscale/LAN access. When DISCOCLAW_DASHBOARD_TRUSTED_HOSTS is set, the server
|
|
428
|
+
# binds to 0.0.0.0 and accepts only loopback Host headers plus the trusted list.
|
|
429
|
+
#DISCOCLAW_DASHBOARD_ENABLED=0
|
|
430
|
+
# Operator dashboard port (default: 9401).
|
|
431
|
+
#DISCOCLAW_DASHBOARD_PORT=9401
|
|
432
|
+
# Comma-separated Host header allowlist for dashboard access over Tailscale or another
|
|
433
|
+
# trusted network path. Supports hostnames and IPv4 addresses only; IPv6 literals are
|
|
434
|
+
# rejected because Host parsing is ambiguous here. Example:
|
|
435
|
+
#DISCOCLAW_DASHBOARD_TRUSTED_HOSTS=phone.tailnet.ts.net,100.64.0.12
|
|
362
436
|
# Global cap on parallel runtime invocations across all Discord sessions (0 = unlimited).
|
|
363
437
|
#DISCOCLAW_MAX_CONCURRENT_INVOCATIONS=3
|
|
364
438
|
# Max depth for chained action follow-ups (e.g. defer → action → response). 0 = disabled.
|
|
365
439
|
#DISCOCLAW_ACTION_FOLLOWUP_DEPTH=3
|
|
366
440
|
# Timeout for runtime invocations (ms).
|
|
367
441
|
#RUNTIME_TIMEOUT_MS=1800000
|
|
442
|
+
# Global runtime supervisor wrapper (off by default; preserves legacy behavior).
|
|
443
|
+
# When enabled, all runtime invocations run through plan -> execute -> evaluate -> decide.
|
|
444
|
+
#DISCOCLAW_GLOBAL_SUPERVISOR_ENABLED=0
|
|
445
|
+
# Emit supervisor cycle audit JSON on stdout or stderr.
|
|
446
|
+
#DISCOCLAW_GLOBAL_SUPERVISOR_AUDIT_STREAM=stderr
|
|
447
|
+
# Max supervisor cycles before forced bail (must be >= 1).
|
|
448
|
+
#DISCOCLAW_GLOBAL_SUPERVISOR_MAX_CYCLES=3
|
|
449
|
+
# Max retries allowed across cycles (must be >= 0).
|
|
450
|
+
#DISCOCLAW_GLOBAL_SUPERVISOR_MAX_RETRIES=2
|
|
451
|
+
# Max escalation prompt level applied across retries (must be >= 0).
|
|
452
|
+
#DISCOCLAW_GLOBAL_SUPERVISOR_MAX_ESCALATION_LEVEL=2
|
|
453
|
+
# Hard cap on total streamed events across all cycles (must be >= 1).
|
|
454
|
+
#DISCOCLAW_GLOBAL_SUPERVISOR_MAX_TOTAL_EVENTS=5000
|
|
455
|
+
# Wall-time cap for the full supervisor loop (ms). 0 disables wall-time cap.
|
|
456
|
+
#DISCOCLAW_GLOBAL_SUPERVISOR_MAX_WALL_TIME_MS=0
|
|
368
457
|
# Multi-turn mode: persistent subprocess per session, keeping session context across messages (default: 1).
|
|
369
458
|
#DISCOCLAW_MULTI_TURN=1
|
|
370
459
|
# Timeout (ms) before a multi-turn process is considered hung and restarted.
|
|
@@ -377,18 +466,26 @@ DISCOCLAW_DISCORD_ACTIONS_DEFER=1
|
|
|
377
466
|
#DISCOCLAW_SESSION_SCANNING=1
|
|
378
467
|
# Parse tool-use events during streaming for better progress reporting and stall suppression.
|
|
379
468
|
#DISCOCLAW_TOOL_AWARE_STREAMING=1
|
|
380
|
-
#
|
|
381
|
-
#
|
|
382
|
-
#
|
|
383
|
-
#
|
|
469
|
+
# Render a denser "Thinking..." streaming preview tail (more lines + wider logs + richer tool signals).
|
|
470
|
+
# Helps previews update more visibly during long runs; action tags are still stripped from preview text.
|
|
471
|
+
#DISCOCLAW_STREAM_PREVIEW_RAW=0
|
|
472
|
+
# Stream stall detection: kill one-shot process if no stdout/stderr for this long (ms). 0 = disabled. (default: 1800000)
|
|
473
|
+
#DISCOCLAW_STREAM_STALL_TIMEOUT_MS=1800000
|
|
474
|
+
# Progress stall timeout: alert after this many ms with no progress event (ms). 0 = disabled. (default: 1800000)
|
|
475
|
+
#DISCOCLAW_PROGRESS_STALL_TIMEOUT_MS=1800000
|
|
384
476
|
# Stream stall warning: show user-visible warning in Discord after this many ms of no events. 0 = disabled. (default: 300000)
|
|
385
477
|
#DISCOCLAW_STREAM_STALL_WARNING_MS=60000
|
|
386
|
-
#
|
|
387
|
-
#
|
|
388
|
-
#
|
|
478
|
+
# Enable long-run watchdog follow-up status updates.
|
|
479
|
+
# Normal path: after the threshold delay, a deferred "Still running..." check-in is posted.
|
|
480
|
+
# Recovery path: lifecycle state is persisted and swept on startup so interrupted long-running
|
|
481
|
+
# runs still get a final status update after restart.
|
|
482
|
+
# Persistence-first lifecycle: run completion is persisted before attempting the final Discord
|
|
483
|
+
# post/edit, and finalPosted is set only after a successful post/edit. Crash boundaries may
|
|
484
|
+
# duplicate follow-up/final updates, but should not omit them. Set to 0 to disable watchdog
|
|
485
|
+
# follow-up posting entirely.
|
|
389
486
|
#DISCOCLAW_COMPLETION_NOTIFY=1
|
|
390
|
-
#
|
|
391
|
-
# considered
|
|
487
|
+
# Delay (ms) before the in-process "Still running..." follow-up timer fires. Fast runs shorter
|
|
488
|
+
# than this are considered non-long-running and do not post watchdog follow-ups. Default: 30000.
|
|
392
489
|
#DISCOCLAW_COMPLETION_NOTIFY_THRESHOLD_MS=30000
|
|
393
490
|
|
|
394
491
|
# ----------------------------------------------------------
|
|
@@ -405,6 +502,10 @@ DISCOCLAW_DISCORD_ACTIONS_DEFER=1
|
|
|
405
502
|
#PLAN_PHASE_TIMEOUT_MS=1800000
|
|
406
503
|
# Max audit-fix attempts per phase before marking failed.
|
|
407
504
|
#PLAN_PHASE_AUDIT_FIX_MAX=3
|
|
505
|
+
# Default heartbeat interval (ms) for command-path phase progress updates
|
|
506
|
+
# in `!plan run*` and `!forge`. Set to 0 to disable periodic heartbeats;
|
|
507
|
+
# phase starts/transitions and the single terminal outcome still post.
|
|
508
|
+
#PLAN_FORGE_HEARTBEAT_INTERVAL_MS=45000
|
|
408
509
|
# Max draft-audit-revise loops before CAP_REACHED.
|
|
409
510
|
#FORGE_MAX_AUDIT_ROUNDS=5
|
|
410
511
|
# Model overrides for forge roles (fall back to RUNTIME_MODEL).
|
|
@@ -434,7 +535,7 @@ DISCOCLAW_DISCORD_ACTIONS_DEFER=1
|
|
|
434
535
|
# Optional: isolate Codex state/sessions from ~/.codex (helps avoid stale rollout DB issues).
|
|
435
536
|
#CODEX_HOME=/absolute/path/to/.codex-home-discoclaw
|
|
436
537
|
# Default model for the Codex CLI adapter. Used when FORGE_AUDITOR_MODEL is not set.
|
|
437
|
-
#CODEX_MODEL=gpt-5.
|
|
538
|
+
#CODEX_MODEL=gpt-5.4
|
|
438
539
|
# WARNING: disables Codex approval prompts and sandbox protections (full-access mode).
|
|
439
540
|
# Equivalent to passing --dangerously-bypass-approvals-and-sandbox to codex exec.
|
|
440
541
|
#CODEX_DANGEROUSLY_BYPASS_APPROVALS_AND_SANDBOX=0
|
|
@@ -540,13 +641,17 @@ DISCOCLAW_DISCORD_ACTIONS_IMAGEGEN=0
|
|
|
540
641
|
# Leave unset to disable transcript mirroring.
|
|
541
642
|
#DISCOCLAW_VOICE_LOG_CHANNEL= # e.g. "voice-log" if using the default scaffold
|
|
542
643
|
# Model for voice AI responses: tier (fast | capable | deep) or concrete name (sonnet, opus, haiku).
|
|
543
|
-
# Independent of
|
|
544
|
-
# Switchable at runtime via
|
|
545
|
-
# Default: follows
|
|
644
|
+
# Independent of the chat model — allows tuning voice latency vs quality separately from chat.
|
|
645
|
+
# Switchable at runtime via `!models set voice <model>`.
|
|
646
|
+
# Default: follows the startup chat model unless overridden here.
|
|
546
647
|
#DISCOCLAW_VOICE_MODEL=sonnet
|
|
547
648
|
# Custom system prompt prepended to voice AI invocations. Max 4000 chars.
|
|
548
649
|
# Use this to set a conversational tone, brevity instructions, or persona for voice responses.
|
|
549
650
|
#DISCOCLAW_VOICE_SYSTEM_PROMPT=
|
|
651
|
+
# Anthropic API key for direct Messages API access (bypasses Claude CLI cold-start).
|
|
652
|
+
# When set and voice is enabled, voice invocations use the Anthropic REST adapter
|
|
653
|
+
# instead of the CLI subprocess, eliminating ~2-5s cold-start latency per response.
|
|
654
|
+
#ANTHROPIC_API_KEY=
|
|
550
655
|
# API key for Deepgram Nova-3 STT. Required when DISCOCLAW_STT_PROVIDER=deepgram.
|
|
551
656
|
#DEEPGRAM_API_KEY=
|
|
552
657
|
# Deepgram STT model for voice transcription (default: nova-3-conversationalai).
|
package/README.md
CHANGED
|
@@ -26,6 +26,7 @@ Your assistant carries context across every conversation, channel, and restart.
|
|
|
26
26
|
|
|
27
27
|
- **Durable facts** — `!memory remember prefers dark mode` persists across sessions and channels
|
|
28
28
|
- **Rolling summaries** — Compresses earlier conversation so context carries forward, even across restarts
|
|
29
|
+
- **Cold storage** — Semantic search over past conversations using vector embeddings + keyword search. Relevant history is automatically retrieved and injected into the prompt (see [docs/memory.md](docs/memory.md))
|
|
29
30
|
- **Per-channel context** — Each channel gets a markdown file shaping behavior (formal in #work, casual in #random)
|
|
30
31
|
- **Customizable identity** — Personality, name, and values defined in workspace files (`SOUL.md`, `IDENTITY.md`, etc.)
|
|
31
32
|
- **Group chat aware** — Knows when to speak up and when to stay quiet in shared channels
|
|
@@ -84,6 +85,24 @@ DiscoClaw orchestrates the flow between Discord and AI runtimes (Claude Code by
|
|
|
84
85
|
4. Streams the response back, chunked to fit Discord's message limits
|
|
85
86
|
5. Parses and executes any Discord actions the assistant emitted
|
|
86
87
|
|
|
88
|
+
### Instruction precedence
|
|
89
|
+
|
|
90
|
+
Prompt assembly has two layers, each with its own ordering contract.
|
|
91
|
+
|
|
92
|
+
**Preamble precedence** — the front of every prompt, in strict priority order:
|
|
93
|
+
|
|
94
|
+
1. **Immutable security policy** (hard-coded root rules)
|
|
95
|
+
2. **Tracked defaults** (runtime-injected from `templates/instructions/SYSTEM_DEFAULTS.md`)
|
|
96
|
+
3. **Tracked tools** (runtime-injected from `templates/instructions/TOOLS.md`)
|
|
97
|
+
4. **User rules override** (`workspace/AGENTS.md`)
|
|
98
|
+
5. **User tools override** (`workspace/TOOLS.md`, optional)
|
|
99
|
+
6. **Memory/context layers** (workspace identity files, channel context, durable/rolling memory, etc.)
|
|
100
|
+
|
|
101
|
+
**Post-preamble section ordering** — the sections between the preamble and the user message are arranged to exploit primacy bias (high-signal sections first) and recency bias (action schemas and constraints near the end, just before the user message). Low-signal data sections sit in the middle. See [`docs/prompt-ordering.md`](docs/prompt-ordering.md) for the canonical order and rationale.
|
|
102
|
+
|
|
103
|
+
`workspace/DISCOCLAW.md` is no longer a managed or authoritative instruction source.
|
|
104
|
+
If you still have a legacy copy, treat it as historical reference only.
|
|
105
|
+
|
|
87
106
|
### Message batching
|
|
88
107
|
|
|
89
108
|
When multiple messages arrive while the bot is thinking (i.e., an AI invocation is already active for that session), they're automatically combined into a single prompt rather than queued individually. This means rapid follow-up messages are processed together, giving the bot full context in one shot. Commands (`!`-prefixed messages) bypass batching and are always processed individually.
|
|
@@ -92,11 +111,13 @@ When multiple messages arrive while the bot is thinking (i.e., an AI invocation
|
|
|
92
111
|
|
|
93
112
|
Set `PRIMARY_RUNTIME=openrouter` to route requests through [OpenRouter](https://openrouter.ai), which provides access to models from Anthropic, OpenAI, Google, and others via a single API key — useful if you want to switch models without managing multiple provider accounts.
|
|
94
113
|
|
|
95
|
-
Required: `OPENROUTER_API_KEY`. Optional overrides: `OPENROUTER_BASE_URL` (default: `https://openrouter.ai/api/v1`) and `OPENROUTER_MODEL` (default: `anthropic/claude-sonnet-4`). See `.env.example` for the full reference.
|
|
114
|
+
Required: `OPENROUTER_API_KEY`. Optional overrides: `OPENROUTER_BASE_URL` (default: `https://openrouter.ai/api/v1`) and `OPENROUTER_MODEL` (default: `anthropic/claude-sonnet-4`). OpenRouter does not have a built-in `fast`/`capable`/`deep` tier map inside DiscoClaw, so if you want tier names or fast/voice auto-switching to resolve through OpenRouter, define the specific `DISCOCLAW_TIER_OPENROUTER_<TIER>` vars you need in `.env` and restart. A single unique entry such as `DISCOCLAW_TIER_OPENROUTER_FAST=openai/gpt-5-mini` is enough for that exact-string fast/voice reverse-mapping. See `.env.example` for the full reference.
|
|
96
115
|
|
|
97
116
|
## Model Overrides
|
|
98
117
|
|
|
99
|
-
The `!models` command lets you view and swap AI models per role at runtime — no restart needed,
|
|
118
|
+
The `!models` command lets you view and swap AI models per role at runtime — no restart needed. Per-role model values persist to `models.json` under the data dir, while fast/voice runtime overlays persist separately to `runtime-overrides.json`. Live runtime swaps like `!models set chat openrouter` are still live-only until the next restart, but they affect the main runtime path broadly, not just chat.
|
|
119
|
+
|
|
120
|
+
For the full operator guide to install-mode detection, persistent adapter switches, OpenRouter tier overrides, fast/voice runtime behavior, and `!models reset` semantics, see [docs/runtime-switching.md](docs/runtime-switching.md).
|
|
100
121
|
|
|
101
122
|
**Roles:** `chat`, `fast`, `forge-drafter`, `forge-auditor`, `summary`, `cron`, `cron-exec`, `voice`
|
|
102
123
|
|
|
@@ -104,17 +125,18 @@ The `!models` command lets you view and swap AI models per role at runtime — n
|
|
|
104
125
|
|---------|-------------|
|
|
105
126
|
| `!models` | Show current model assignments |
|
|
106
127
|
| `!models set <role> <model>` | Change the model for a role |
|
|
107
|
-
| `!models reset` | Revert all roles to
|
|
108
|
-
| `!models reset <role>` | Revert a specific role |
|
|
128
|
+
| `!models reset` | Revert all roles to startup defaults and clear overrides |
|
|
129
|
+
| `!models reset <role>` | Revert a specific role to its startup default |
|
|
109
130
|
|
|
110
131
|
**Examples:**
|
|
111
132
|
- `!models set chat claude-sonnet-4` — use Sonnet for chat
|
|
112
|
-
- `!models set chat openrouter` — switch
|
|
133
|
+
- `!models set chat openrouter` — live-switch the main runtime to OpenRouter until restart
|
|
113
134
|
- `!models set cron-exec haiku` — run crons on a cheaper model
|
|
135
|
+
- `!models set cron-exec default` — clear the cron-exec override and use the startup default again
|
|
114
136
|
- `!models set voice sonnet` — use a specific model for voice
|
|
115
|
-
- `!models reset` — clear all overrides
|
|
137
|
+
- `!models reset` — clear all overrides and revert to startup defaults
|
|
116
138
|
|
|
117
|
-
Setting
|
|
139
|
+
Setting `chat` to a runtime name (`openrouter`, `openai`, `gemini`, `codex`, `claude`) live-switches the main runtime path until restart; setting `voice` to a runtime name switches only voice. Exact model-string runtime auto-switching is only implemented for `fast` and `voice`.
|
|
118
140
|
|
|
119
141
|
## Secret Management
|
|
120
142
|
|
|
@@ -165,6 +187,15 @@ When using the Claude runtime, you can connect external tool servers via MCP. Pl
|
|
|
165
187
|
**Contributors (from source):**
|
|
166
188
|
- Everything above, plus **pnpm** — enable via Corepack (`corepack enable`) or install separately
|
|
167
189
|
|
|
190
|
+
### Model capability requirement
|
|
191
|
+
|
|
192
|
+
DiscoClaw assumes reliable structured output for several runtime paths (for example: Discord actions, cron JSON routing, and tool-call loops).
|
|
193
|
+
|
|
194
|
+
- For OpenAI-compatible and OpenRouter adapters, pick models that reliably support JSON-shaped output and function calling.
|
|
195
|
+
- "OpenAI-compatible" API shape alone is not a capability guarantee.
|
|
196
|
+
- If a model fails JSON/tool-call smoke tests, treat it as unsupported for DiscoClaw runtime use.
|
|
197
|
+
- Use the [model validation smoke test checklist](docs/configuration.md#model-validation-smoke-test-recommended) before adopting a new model.
|
|
198
|
+
|
|
168
199
|
<!-- source-of-truth: docs/discord-bot-setup.md -->
|
|
169
200
|
## Quick start
|
|
170
201
|
|
|
@@ -211,6 +242,7 @@ Full step-by-step guide: [docs/discord-bot-setup.md](docs/discord-bot-setup.md)
|
|
|
211
242
|
### Operations
|
|
212
243
|
|
|
213
244
|
- [Configuration reference](docs/configuration.md) — all environment variables indexed by category
|
|
245
|
+
- [Runtime/model switching](docs/runtime-switching.md) — operator guide for switching adapters, models, and defaults safely
|
|
214
246
|
- [Webhook exposure](docs/webhook-exposure.md) — tunnel/proxy setup and webhook security
|
|
215
247
|
- [Data migration](docs/data-migration.md) — migrating task data between formats
|
|
216
248
|
|
|
@@ -242,6 +274,14 @@ Full step-by-step guide: [docs/discord-bot-setup.md](docs/discord-bot-setup.md)
|
|
|
242
274
|
discoclaw install-daemon --service-name personal
|
|
243
275
|
```
|
|
244
276
|
|
|
277
|
+
4. **Open the local operator dashboard:**
|
|
278
|
+
```bash
|
|
279
|
+
discoclaw dashboard
|
|
280
|
+
```
|
|
281
|
+
By default this listens on `127.0.0.1`. To reach it from a phone over Tailscale,
|
|
282
|
+
set `DISCOCLAW_DASHBOARD_TRUSTED_HOSTS` to your tailnet IP or MagicDNS hostname.
|
|
283
|
+
See [docs/dashboard-tailscale.md](docs/dashboard-tailscale.md).
|
|
284
|
+
|
|
245
285
|
#### From source (contributors)
|
|
246
286
|
|
|
247
287
|
```bash
|
|
@@ -282,7 +322,9 @@ pnpm install
|
|
|
282
322
|
pnpm build
|
|
283
323
|
```
|
|
284
324
|
|
|
285
|
-
Run `pnpm preflight` — it flags configuration options from `.env.example` that aren't in your `.env` yet.
|
|
325
|
+
Run `pnpm preflight` — it flags configuration options from `.env.example` that aren't in your `.env` yet. You can also run `discoclaw doctor` to inspect config drift and related issues, `discoclaw doctor --fix` to apply safe remediations, or use `!doctor` / `!doctor fix` from Discord (`!health doctor` / `!health doctor fix` remain supported). Restart the service afterward for fixed config to take effect.
|
|
326
|
+
|
|
327
|
+
For a local operator console, run `discoclaw dashboard` in the project directory. It shows the active service target, current model assignments, runtime overrides, config doctor status, and quick actions for status/logs/restart. It binds to `127.0.0.1` by default; configure `DISCOCLAW_DASHBOARD_TRUSTED_HOSTS` to allow Tailscale access via a tailnet IP or MagicDNS hostname while keeping Host-header checks in place for all other names. See [docs/dashboard-tailscale.md](docs/dashboard-tailscale.md).
|
|
286
328
|
|
|
287
329
|
If running as a systemd service, restart it:
|
|
288
330
|
|