discoclaw 0.1.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 +42 -0
- package/.context/architecture.md +58 -0
- package/.context/bot-setup.md +24 -0
- package/.context/dev.md +230 -0
- package/.context/discord.md +144 -0
- package/.context/memory.md +257 -0
- package/.context/ops.md +59 -0
- package/.context/pa-safety.md +47 -0
- package/.context/pa.md +118 -0
- package/.context/project.md +43 -0
- package/.context/runtime.md +253 -0
- package/.context/tasks.md +71 -0
- package/.context/tools.md +75 -0
- package/.env.example +88 -0
- package/.env.example.full +378 -0
- package/LICENSE +21 -0
- package/README.md +220 -0
- package/dist/beads/auto-tag.js +2 -0
- package/dist/beads/auto-tag.test.js +62 -0
- package/dist/beads/bd-cli.js +9 -0
- package/dist/beads/bd-cli.test.js +495 -0
- package/dist/beads/bead-hooks-cli.js +149 -0
- package/dist/beads/bead-sync-cli.js +5 -0
- package/dist/beads/bead-sync-cli.test.js +72 -0
- package/dist/beads/bead-sync-coordinator.js +4 -0
- package/dist/beads/bead-sync-coordinator.test.js +239 -0
- package/dist/beads/bead-sync-watcher.js +2 -0
- package/dist/beads/bead-sync-watcher.test.js +96 -0
- package/dist/beads/bead-sync.js +7 -0
- package/dist/beads/bead-sync.test.js +876 -0
- package/dist/beads/bead-thread-cache.js +8 -0
- package/dist/beads/bead-thread-cache.test.js +91 -0
- package/dist/beads/discord-sync.js +18 -0
- package/dist/beads/discord-sync.test.js +782 -0
- package/dist/beads/find-bead-by-thread.test.js +36 -0
- package/dist/beads/forum-guard.js +2 -0
- package/dist/beads/forum-guard.test.js +204 -0
- package/dist/beads/initialize.js +3 -0
- package/dist/beads/initialize.test.js +304 -0
- package/dist/beads/types.js +10 -0
- package/dist/cli/daemon-installer.js +225 -0
- package/dist/cli/daemon-installer.test.js +289 -0
- package/dist/cli/index.js +42 -0
- package/dist/cli/init-wizard.js +374 -0
- package/dist/cli/init-wizard.test.js +191 -0
- package/dist/config.js +385 -0
- package/dist/config.test.js +589 -0
- package/dist/cron/auto-tag.js +100 -0
- package/dist/cron/auto-tag.test.js +91 -0
- package/dist/cron/cadence.js +74 -0
- package/dist/cron/cadence.test.js +53 -0
- package/dist/cron/cron-sync-coordinator.js +66 -0
- package/dist/cron/cron-sync-coordinator.test.js +118 -0
- package/dist/cron/cron-sync.js +165 -0
- package/dist/cron/cron-sync.test.js +228 -0
- package/dist/cron/cron-tag-map-watcher.js +128 -0
- package/dist/cron/cron-tag-map-watcher.test.js +155 -0
- package/dist/cron/default-timezone.js +23 -0
- package/dist/cron/default-timezone.test.js +30 -0
- package/dist/cron/discord-sync.js +205 -0
- package/dist/cron/discord-sync.test.js +353 -0
- package/dist/cron/executor.js +303 -0
- package/dist/cron/executor.test.js +614 -0
- package/dist/cron/forum-sync.js +347 -0
- package/dist/cron/forum-sync.test.js +539 -0
- package/dist/cron/job-lock.js +164 -0
- package/dist/cron/job-lock.test.js +178 -0
- package/dist/cron/parser.js +68 -0
- package/dist/cron/parser.test.js +115 -0
- package/dist/cron/run-control.js +24 -0
- package/dist/cron/run-control.test.js +27 -0
- package/dist/cron/run-stats.js +265 -0
- package/dist/cron/run-stats.test.js +160 -0
- package/dist/cron/scheduler.js +97 -0
- package/dist/cron/scheduler.test.js +112 -0
- package/dist/cron/tag-map.js +47 -0
- package/dist/cron/tag-map.test.js +64 -0
- package/dist/cron/types.js +1 -0
- package/dist/discoclaw-plan-format.test.js +137 -0
- package/dist/discoclaw-recipe-format.test.js +137 -0
- package/dist/discord/abort-registry.js +70 -0
- package/dist/discord/action-categories.js +36 -0
- package/dist/discord/action-types.js +1 -0
- package/dist/discord/action-utils.js +58 -0
- package/dist/discord/action-utils.test.js +58 -0
- package/dist/discord/actions-beads.js +1 -0
- package/dist/discord/actions-beads.test.js +372 -0
- package/dist/discord/actions-bot-profile.js +107 -0
- package/dist/discord/actions-bot-profile.test.js +138 -0
- package/dist/discord/actions-channels.js +427 -0
- package/dist/discord/actions-channels.test.js +697 -0
- package/dist/discord/actions-config.js +173 -0
- package/dist/discord/actions-config.test.js +322 -0
- package/dist/discord/actions-crons.js +586 -0
- package/dist/discord/actions-crons.test.js +499 -0
- package/dist/discord/actions-defer.js +60 -0
- package/dist/discord/actions-defer.test.js +134 -0
- package/dist/discord/actions-forge.js +134 -0
- package/dist/discord/actions-forge.test.js +206 -0
- package/dist/discord/actions-guild.js +301 -0
- package/dist/discord/actions-guild.test.js +386 -0
- package/dist/discord/actions-memory.js +106 -0
- package/dist/discord/actions-memory.test.js +248 -0
- package/dist/discord/actions-messaging.js +401 -0
- package/dist/discord/actions-messaging.test.js +738 -0
- package/dist/discord/actions-moderation.js +65 -0
- package/dist/discord/actions-moderation.test.js +88 -0
- package/dist/discord/actions-plan.js +445 -0
- package/dist/discord/actions-plan.test.js +610 -0
- package/dist/discord/actions-poll.js +38 -0
- package/dist/discord/actions-poll.test.js +93 -0
- package/dist/discord/actions-tasks.js +3 -0
- package/dist/discord/actions-tasks.test.js +418 -0
- package/dist/discord/actions.js +600 -0
- package/dist/discord/actions.test.js +522 -0
- package/dist/discord/allowed-mentions.js +3 -0
- package/dist/discord/allowed-mentions.test.js +17 -0
- package/dist/discord/allowlist.js +29 -0
- package/dist/discord/allowlist.test.js +24 -0
- package/dist/discord/audit-handler.js +191 -0
- package/dist/discord/audit-handler.test.js +361 -0
- package/dist/discord/bot.js +141 -0
- package/dist/discord/channel-context.js +181 -0
- package/dist/discord/defer-scheduler.js +45 -0
- package/dist/discord/destructive-confirmation.js +128 -0
- package/dist/discord/destructive-confirmation.test.js +49 -0
- package/dist/discord/discord-plan-auto-implement.test.js +18 -0
- package/dist/discord/durable-memory.js +145 -0
- package/dist/discord/durable-memory.test.js +281 -0
- package/dist/discord/durable-write-queue.js +4 -0
- package/dist/discord/file-download.js +308 -0
- package/dist/discord/file-download.test.js +303 -0
- package/dist/discord/forge-audit-verdict.js +140 -0
- package/dist/discord/forge-auto-implement.js +80 -0
- package/dist/discord/forge-auto-implement.test.js +110 -0
- package/dist/discord/forge-commands.js +698 -0
- package/dist/discord/forge-commands.test.js +1606 -0
- package/dist/discord/forge-plan-registry.js +68 -0
- package/dist/discord/forge-plan-registry.test.js +127 -0
- package/dist/discord/forum-count-sync.js +130 -0
- package/dist/discord/forum-count-sync.test.js +200 -0
- package/dist/discord/health-command.js +98 -0
- package/dist/discord/health-command.test.js +195 -0
- package/dist/discord/help-command.js +22 -0
- package/dist/discord/help-command.test.js +49 -0
- package/dist/discord/image-download.js +201 -0
- package/dist/discord/image-download.test.js +499 -0
- package/dist/discord/inflight-replies.js +228 -0
- package/dist/discord/inflight-replies.test.js +295 -0
- package/dist/discord/json-extract.js +110 -0
- package/dist/discord/keyed-queue.js +22 -0
- package/dist/discord/memory-commands.js +85 -0
- package/dist/discord/memory-commands.test.js +159 -0
- package/dist/discord/memory-timing.integration.test.js +159 -0
- package/dist/discord/message-coordinator.js +2347 -0
- package/dist/discord/message-coordinator.onboarding.test.js +183 -0
- package/dist/discord/message-coordinator.plan-run.test.js +264 -0
- package/dist/discord/message-history.js +53 -0
- package/dist/discord/message-history.test.js +95 -0
- package/dist/discord/models-command.js +59 -0
- package/dist/discord/models-command.test.js +150 -0
- package/dist/discord/nickname.test.js +76 -0
- package/dist/discord/onboarding-completion.js +55 -0
- package/dist/discord/onboarding-completion.test.js +176 -0
- package/dist/discord/output-common.js +178 -0
- package/dist/discord/output-common.test.js +198 -0
- package/dist/discord/output-utils.js +156 -0
- package/dist/discord/parse-identity-name.test.js +129 -0
- package/dist/discord/plan-commands.js +612 -0
- package/dist/discord/plan-commands.test.js +1622 -0
- package/dist/discord/plan-manager.js +1491 -0
- package/dist/discord/plan-manager.test.js +2380 -0
- package/dist/discord/plan-parser.js +110 -0
- package/dist/discord/plan-parser.test.js +63 -0
- package/dist/discord/plan-run-phase-start.js +20 -0
- package/dist/discord/plan-run-phase-start.test.js +29 -0
- package/dist/discord/platform-message.js +45 -0
- package/dist/discord/platform-message.test.js +110 -0
- package/dist/discord/prompt-common.js +240 -0
- package/dist/discord/prompt-common.test.js +423 -0
- package/dist/discord/reaction-handler.js +691 -0
- package/dist/discord/reaction-handler.test.js +1574 -0
- package/dist/discord/reaction-prompts.js +118 -0
- package/dist/discord/reaction-prompts.test.js +253 -0
- package/dist/discord/reply-reference.js +66 -0
- package/dist/discord/reply-reference.test.js +125 -0
- package/dist/discord/restart-command.js +143 -0
- package/dist/discord/restart-command.test.js +196 -0
- package/dist/discord/runtime-utils.js +43 -0
- package/dist/discord/runtime-utils.test.js +112 -0
- package/dist/discord/session-key.js +7 -0
- package/dist/discord/session-key.test.js +13 -0
- package/dist/discord/shortterm-memory.js +166 -0
- package/dist/discord/shortterm-memory.test.js +345 -0
- package/dist/discord/shutdown-context.js +122 -0
- package/dist/discord/shutdown-context.test.js +279 -0
- package/dist/discord/startup-profile.test.js +214 -0
- package/dist/discord/status-channel.js +190 -0
- package/dist/discord/status-channel.test.js +282 -0
- package/dist/discord/status-command.js +206 -0
- package/dist/discord/status-command.test.js +341 -0
- package/dist/discord/streaming-progress.js +107 -0
- package/dist/discord/streaming-progress.test.js +93 -0
- package/dist/discord/summarizer.js +89 -0
- package/dist/discord/summarizer.test.js +245 -0
- package/dist/discord/system-bootstrap.js +396 -0
- package/dist/discord/system-bootstrap.test.js +724 -0
- package/dist/discord/thread-context.js +169 -0
- package/dist/discord/thread-context.test.js +386 -0
- package/dist/discord/tool-aware-queue.js +116 -0
- package/dist/discord/tool-aware-queue.test.js +180 -0
- package/dist/discord/update-command.js +127 -0
- package/dist/discord/update-command.test.js +275 -0
- package/dist/discord/user-errors.js +40 -0
- package/dist/discord/user-errors.test.js +31 -0
- package/dist/discord/user-turn-to-durable.js +111 -0
- package/dist/discord/user-turn-to-durable.test.js +273 -0
- package/dist/discord-followup.test.js +677 -0
- package/dist/discord.channel-context.test.js +95 -0
- package/dist/discord.fail-closed.test.js +199 -0
- package/dist/discord.health-command.integration.test.js +140 -0
- package/dist/discord.js +190 -0
- package/dist/discord.prompt-context.test.js +1431 -0
- package/dist/discord.render.test.js +621 -0
- package/dist/discord.status-wiring.test.js +187 -0
- package/dist/engine/claudeCli.js +137 -0
- package/dist/engine/types.js +1 -0
- package/dist/group-queue.js +25 -0
- package/dist/health/credential-check.js +175 -0
- package/dist/health/credential-check.test.js +401 -0
- package/dist/health/startup-healing.js +139 -0
- package/dist/health/startup-healing.test.js +298 -0
- package/dist/identity.js +36 -0
- package/dist/index.js +1378 -0
- package/dist/logging/logger-like.js +1 -0
- package/dist/observability/memory-sampler.js +51 -0
- package/dist/observability/memory-sampler.test.js +93 -0
- package/dist/observability/metrics.js +88 -0
- package/dist/observability/metrics.test.js +42 -0
- package/dist/onboarding/onboarding-flow.js +246 -0
- package/dist/onboarding/onboarding-flow.test.js +238 -0
- package/dist/onboarding/onboarding-writer.js +102 -0
- package/dist/onboarding/onboarding-writer.test.js +143 -0
- package/dist/pidlock.js +187 -0
- package/dist/pidlock.test.js +128 -0
- package/dist/pipeline/engine.js +206 -0
- package/dist/pipeline/engine.test.js +771 -0
- package/dist/root-policy.js +21 -0
- package/dist/root-policy.test.js +55 -0
- package/dist/runtime/claude-code-cli.js +35 -0
- package/dist/runtime/claude-code-cli.test.js +1199 -0
- package/dist/runtime/cli-adapter.js +584 -0
- package/dist/runtime/cli-output-parsers.js +108 -0
- package/dist/runtime/cli-shared.js +96 -0
- package/dist/runtime/cli-shared.test.js +104 -0
- package/dist/runtime/cli-strategy.js +6 -0
- package/dist/runtime/codex-cli.js +16 -0
- package/dist/runtime/codex-cli.test.js +862 -0
- package/dist/runtime/concurrency-limit.js +80 -0
- package/dist/runtime/concurrency-limit.test.js +137 -0
- package/dist/runtime/gemini-cli.js +16 -0
- package/dist/runtime/gemini-cli.test.js +413 -0
- package/dist/runtime/long-running-process.js +415 -0
- package/dist/runtime/long-running-process.test.js +318 -0
- package/dist/runtime/model-smoke-helpers.js +160 -0
- package/dist/runtime/model-smoke.test.js +194 -0
- package/dist/runtime/model-tiers.js +33 -0
- package/dist/runtime/model-tiers.test.js +65 -0
- package/dist/runtime/openai-auth.js +151 -0
- package/dist/runtime/openai-auth.test.js +361 -0
- package/dist/runtime/openai-compat.js +178 -0
- package/dist/runtime/openai-compat.test.js +449 -0
- package/dist/runtime/process-pool.js +93 -0
- package/dist/runtime/process-pool.test.js +148 -0
- package/dist/runtime/registry.js +15 -0
- package/dist/runtime/registry.test.js +47 -0
- package/dist/runtime/session-scanner.js +186 -0
- package/dist/runtime/session-scanner.test.js +257 -0
- package/dist/runtime/strategies/claude-strategy.js +193 -0
- package/dist/runtime/strategies/codex-strategy.js +161 -0
- package/dist/runtime/strategies/gemini-strategy.js +64 -0
- package/dist/runtime/strategies/template-strategy.js +85 -0
- package/dist/runtime/tool-capabilities.js +27 -0
- package/dist/runtime/tool-capabilities.test.js +24 -0
- package/dist/runtime/tool-labels.js +48 -0
- package/dist/runtime/types.js +2 -0
- package/dist/sessionManager.js +47 -0
- package/dist/sessions.js +18 -0
- package/dist/tasks/architecture-contract.js +33 -0
- package/dist/tasks/architecture-contract.test.js +90 -0
- package/dist/tasks/auto-tag.js +50 -0
- package/dist/tasks/auto-tag.test.js +64 -0
- package/dist/tasks/bd-cli.js +164 -0
- package/dist/tasks/bd-cli.test.js +359 -0
- package/dist/tasks/bead-sync.js +1 -0
- package/dist/tasks/context-summary.js +27 -0
- package/dist/tasks/discord-sync.js +3 -0
- package/dist/tasks/discord-sync.test.js +685 -0
- package/dist/tasks/discord-types.js +4 -0
- package/dist/tasks/find-task-by-thread.test.js +36 -0
- package/dist/tasks/forum-guard.js +81 -0
- package/dist/tasks/forum-guard.test.js +192 -0
- package/dist/tasks/initialize.js +77 -0
- package/dist/tasks/initialize.test.js +263 -0
- package/dist/tasks/logger-types.js +1 -0
- package/dist/tasks/metrics-types.js +3 -0
- package/dist/tasks/migrate.js +33 -0
- package/dist/tasks/migrate.test.js +156 -0
- package/dist/tasks/path-defaults.js +67 -0
- package/dist/tasks/path-defaults.test.js +73 -0
- package/dist/tasks/runtime-types.js +1 -0
- package/dist/tasks/service.js +33 -0
- package/dist/tasks/service.test.js +51 -0
- package/dist/tasks/store.js +238 -0
- package/dist/tasks/store.test.js +417 -0
- package/dist/tasks/sync-context.js +1 -0
- package/dist/tasks/sync-contract.js +24 -0
- package/dist/tasks/sync-contract.test.js +25 -0
- package/dist/tasks/sync-coordinator-metrics.js +41 -0
- package/dist/tasks/sync-coordinator-retries.js +71 -0
- package/dist/tasks/sync-coordinator.js +96 -0
- package/dist/tasks/sync-coordinator.test.js +501 -0
- package/dist/tasks/sync-types.js +1 -0
- package/dist/tasks/sync-watcher.js +27 -0
- package/dist/tasks/sync-watcher.test.js +92 -0
- package/dist/tasks/tag-map.js +36 -0
- package/dist/tasks/tag-map.test.js +54 -0
- package/dist/tasks/task-action-contract.js +16 -0
- package/dist/tasks/task-action-contract.test.js +16 -0
- package/dist/tasks/task-action-executor.js +18 -0
- package/dist/tasks/task-action-executor.test.js +420 -0
- package/dist/tasks/task-action-mutation-helpers.js +17 -0
- package/dist/tasks/task-action-mutations.js +151 -0
- package/dist/tasks/task-action-prompt.js +62 -0
- package/dist/tasks/task-action-read-ops.js +73 -0
- package/dist/tasks/task-action-runner-types.js +1 -0
- package/dist/tasks/task-action-thread-sync.js +82 -0
- package/dist/tasks/task-actions.js +3 -0
- package/dist/tasks/task-cli.js +227 -0
- package/dist/tasks/task-context.js +1 -0
- package/dist/tasks/task-lifecycle.js +46 -0
- package/dist/tasks/task-lifecycle.test.js +35 -0
- package/dist/tasks/task-sync-apply-plan.js +95 -0
- package/dist/tasks/task-sync-apply-types.js +12 -0
- package/dist/tasks/task-sync-apply.js +319 -0
- package/dist/tasks/task-sync-cli.js +89 -0
- package/dist/tasks/task-sync-cli.test.js +70 -0
- package/dist/tasks/task-sync-engine.js +88 -0
- package/dist/tasks/task-sync-engine.test.js +934 -0
- package/dist/tasks/task-sync-phase-apply.js +171 -0
- package/dist/tasks/task-sync-pipeline.js +2 -0
- package/dist/tasks/task-sync-pipeline.test.js +265 -0
- package/dist/tasks/task-sync-reconcile-plan.js +182 -0
- package/dist/tasks/task-sync-reconcile.js +144 -0
- package/dist/tasks/task-sync.js +56 -0
- package/dist/tasks/task-sync.test.js +86 -0
- package/dist/tasks/thread-cache.js +42 -0
- package/dist/tasks/thread-cache.test.js +89 -0
- package/dist/tasks/thread-contracts.test.js +711 -0
- package/dist/tasks/thread-forum-ops.js +68 -0
- package/dist/tasks/thread-helpers.js +86 -0
- package/dist/tasks/thread-helpers.test.js +33 -0
- package/dist/tasks/thread-lifecycle-ops.js +144 -0
- package/dist/tasks/thread-ops-shared.js +21 -0
- package/dist/tasks/thread-ops.js +2 -0
- package/dist/tasks/types.js +20 -0
- package/dist/tasks/types.test.js +60 -0
- package/dist/test-setup.js +11 -0
- package/dist/test-setup.test.js +42 -0
- package/dist/transport/types.js +1 -0
- package/dist/validate.js +41 -0
- package/dist/validate.test.js +94 -0
- package/dist/version.js +15 -0
- package/dist/version.test.js +31 -0
- package/dist/webhook/server.js +199 -0
- package/dist/webhook/server.test.js +460 -0
- package/dist/workspace-bootstrap.js +135 -0
- package/dist/workspace-bootstrap.test.js +514 -0
- package/dist/workspace-permissions.js +134 -0
- package/dist/workspace-permissions.test.js +181 -0
- package/package.json +74 -0
- package/scripts/cron/cron-tag-map.json +9 -0
- package/scripts/tasks/tag-map.json +10 -0
- package/systemd/discoclaw.service +19 -0
- package/templates/recipes/integration.discoclaw-recipe.md +171 -0
- package/templates/workspace/AGENTS.md +217 -0
- package/templates/workspace/BOOTSTRAP.md +1 -0
- package/templates/workspace/HEARTBEAT.md +10 -0
- package/templates/workspace/IDENTITY.md +16 -0
- package/templates/workspace/MEMORY.md +24 -0
- package/templates/workspace/SOUL.md +52 -0
- package/templates/workspace/TOOLS.md +304 -0
- package/templates/workspace/USER.md +37 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Context Modules
|
|
2
|
+
|
|
3
|
+
Modular context files loaded on-demand based on the task at hand.
|
|
4
|
+
Core instructions live in `CLAUDE.md` at the repo root.
|
|
5
|
+
|
|
6
|
+
## Loading Patterns
|
|
7
|
+
|
|
8
|
+
| When doing... | Read this first |
|
|
9
|
+
|---------------|-----------------|
|
|
10
|
+
| **PA behavior / formatting / memory** | `pa.md` |
|
|
11
|
+
| **PA safety / injection defense** | `pa-safety.md` |
|
|
12
|
+
| **Discord behavior + routing** | `discord.md` |
|
|
13
|
+
| **Discord bot setup (invite + env)** | `bot-setup.md` |
|
|
14
|
+
| **Development / build / test** | `dev.md` |
|
|
15
|
+
| **Runtime adapters (Claude CLI, OpenAI/Gemini later)** | `runtime.md` |
|
|
16
|
+
| **Ops / systemd service** | `ops.md` |
|
|
17
|
+
| **Memory system** | `memory.md` |
|
|
18
|
+
| **Task tracking / bd CLI** | `tasks.md` |
|
|
19
|
+
| **Architecture / system overview** | `architecture.md` |
|
|
20
|
+
| **Tool capabilities / browser automation** | `tools.md` |
|
|
21
|
+
| **Forge/plan standing constraints** | `project.md` *(auto-loaded by forge)* |
|
|
22
|
+
| **Plan & Forge commands** | `plan-and-forge.md` *(in docs/, not .context/)* |
|
|
23
|
+
|
|
24
|
+
## Context Hygiene (Strict)
|
|
25
|
+
- Read the minimum necessary modules for the task.
|
|
26
|
+
- Do not load modules "just in case."
|
|
27
|
+
- 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.
|
|
28
|
+
|
|
29
|
+
## Quick Reference
|
|
30
|
+
- **pa.md** — PA behavioral rules, Discord formatting, memory, group chat etiquette, autonomy tiers
|
|
31
|
+
- **pa-safety.md** — Indirect prompt injection defense, golden rules, red flags
|
|
32
|
+
- **dev.md** — Commands, env, local dev loops, build/test
|
|
33
|
+
- **discord.md** — Allowlist gating, session keys, threading rules, output constraints
|
|
34
|
+
- **runtime.md** — Runtime adapter interface, Claude CLI flags, capability routing
|
|
35
|
+
- **ops.md** — systemd service notes, logs, restart workflow
|
|
36
|
+
- **memory.md** — Memory layers, user-facing examples, config reference, concurrency
|
|
37
|
+
- **tasks.md** — Task tracker: data model, bd CLI, hooks, Discord sync, auto-tagging
|
|
38
|
+
- **architecture.md** — System overview, data flow, directory layout, key concepts
|
|
39
|
+
- **bot-setup.md** — One-time bot creation and invite guide
|
|
40
|
+
- **tools.md** — Available tools: browser automation (agent-browser), escalation ladder, CDP connect, security guardrails
|
|
41
|
+
- **project.md** — Standing constraints auto-loaded by forge drafter and auditor
|
|
42
|
+
- **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)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
DiscoClaw is a personal AI orchestrator that coordinates between Discord, AI runtimes
|
|
4
|
+
(Claude Code, OpenAI, Codex), and local system resources — managing conversation state,
|
|
5
|
+
task routing, scheduling, and tool access. It emphasizes small, explicit, auditable code.
|
|
6
|
+
|
|
7
|
+
## Data Flow
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Discord message
|
|
11
|
+
→ allowlist gate (DISCORD_ALLOW_USER_IDS)
|
|
12
|
+
→ session lookup/create (keyed by user+channel)
|
|
13
|
+
→ context assembly (PA files + PA modules + channel context + durable memory)
|
|
14
|
+
→ runtime adapter invocation (streaming)
|
|
15
|
+
→ streaming response → Discord message edits (chunked, code-block-aware)
|
|
16
|
+
→ optional: parse & execute discord actions from response
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Directory Layout
|
|
20
|
+
|
|
21
|
+
| Path | Purpose |
|
|
22
|
+
|------|---------|
|
|
23
|
+
| `src/index.ts` | Entry point — config, wiring, bot startup |
|
|
24
|
+
| `src/discord.ts` | Discord client, message handler, prompt assembly |
|
|
25
|
+
| `src/discord/` | Discord subsystems: actions, allowlist, channel context, memory, output |
|
|
26
|
+
| `src/runtime/` | Runtime adapters (Claude CLI), concurrency, process pool |
|
|
27
|
+
| `src/tasks/` | In-process task data model + store + migration helpers |
|
|
28
|
+
| `src/beads/` | Retired legacy shim namespace (runtime shims removed in hard-cut) |
|
|
29
|
+
| `src/cron/` | Cron scheduler, executor, forum sync, run stats |
|
|
30
|
+
| `src/observability/` | Metrics registry |
|
|
31
|
+
| `src/sessions.ts` | Session manager (maps session keys to runtime session IDs) |
|
|
32
|
+
| `content/discord/channels/` | Per-channel context files |
|
|
33
|
+
| `workspace/` | Identity files (SOUL.md, IDENTITY.md, USER.md) — gitignored |
|
|
34
|
+
| `.context/` | Developer context modules (you are here) |
|
|
35
|
+
|
|
36
|
+
## Key Concepts
|
|
37
|
+
|
|
38
|
+
- **Channel context** — per-channel `.md` files injected into the prompt. PA modules
|
|
39
|
+
apply to all channels; channel-specific files add overrides.
|
|
40
|
+
- **PA context modules** — `.context/pa.md` and `.context/pa-safety.md`, loaded for
|
|
41
|
+
every invocation. Fail-closed: missing modules crash the bot at startup.
|
|
42
|
+
- **Session keys** — `user:channel` composites that map to runtime sessions, giving
|
|
43
|
+
each user+channel pair its own conversation continuity.
|
|
44
|
+
- **Runtime adapters** — pluggable interface (`src/runtime/types.ts`) that wraps an AI
|
|
45
|
+
CLI/API. The orchestrator routes to the appropriate adapter based on context (message
|
|
46
|
+
handling, forge drafting, auditing). Available: Claude Code CLI, OpenAI HTTP, Codex CLI.
|
|
47
|
+
- **Discord actions** — structured JSON actions the AI can emit in its response
|
|
48
|
+
(send messages, create channels, manage tasks, etc.), parsed and executed post-response.
|
|
49
|
+
- **Tasks** — built-in task tracker backed by in-process `TaskStore`, synced to Discord forum threads.
|
|
50
|
+
- **Cron** — forum-based scheduled tasks. Each forum thread defines a job;
|
|
51
|
+
archive to pause, unarchive to resume. Enabled by default.
|
|
52
|
+
|
|
53
|
+
## Entry Points
|
|
54
|
+
|
|
55
|
+
- `src/index.ts` — loads config, wires up runtime adapters + session manager + channel
|
|
56
|
+
context, starts the orchestrator.
|
|
57
|
+
- `src/discord.ts` — Discord interface layer: event handlers, context assembly, prompt
|
|
58
|
+
routing, response streaming.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# bot-setup.md — Discord Bot Setup (Agent Context)
|
|
2
|
+
|
|
3
|
+
> For the full human-facing setup guide, see `docs/discord-bot-setup.md`. This file is a brief reference for Claude when helping with bot setup tasks.
|
|
4
|
+
|
|
5
|
+
## Quick reference
|
|
6
|
+
|
|
7
|
+
1. **Developer Portal** → create application → Bot → enable **Message Content Intent** → copy token to `.env` (`DISCORD_TOKEN`).
|
|
8
|
+
2. **OAuth2 → URL Generator** → scope `bot` → pick permissions (see permission profiles in `docs/discord-bot-setup.md`) → invite to server.
|
|
9
|
+
3. **Configure `.env`**:
|
|
10
|
+
- *Global install:* `discoclaw init` — wizard creates `.env` with `DISCORD_TOKEN`, `DISCORD_ALLOW_USER_IDS`, and `DISCORD_CHANNEL_IDS`.
|
|
11
|
+
- *From source:* `pnpm setup` for guided configuration, or copy `.env.example` → `.env` and set `DISCORD_TOKEN`, `DISCORD_ALLOW_USER_IDS` (fail-closed if empty), `DISCORD_CHANNEL_IDS` (recommended).
|
|
12
|
+
4. **Validate**:
|
|
13
|
+
- *Global install:* `discoclaw install-daemon` to register the systemd service, then DM the bot to confirm it responds.
|
|
14
|
+
- *From source:* `pnpm dev`, DM the bot, post in allowed/disallowed channels.
|
|
15
|
+
|
|
16
|
+
## Getting IDs
|
|
17
|
+
|
|
18
|
+
Discord client: Settings → Advanced → Developer Mode, then right-click a user/channel → Copy ID.
|
|
19
|
+
|
|
20
|
+
## Common issues
|
|
21
|
+
|
|
22
|
+
- **Bot ignores guild messages**: Message Content Intent not enabled in Developer Portal.
|
|
23
|
+
- **"Missing Permissions"**: Bot role is below the target role in Server Settings → Roles. Drag it higher.
|
|
24
|
+
- **Private threads**: Bot must be explicitly added to private threads regardless of permissions.
|
package/.context/dev.md
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# dev.md — Development
|
|
2
|
+
|
|
3
|
+
## Install / Build / Run
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
cd /path/to/discoclaw
|
|
7
|
+
pnpm i
|
|
8
|
+
pnpm build
|
|
9
|
+
pnpm dev
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
**Optional tools:** Install [`agent-browser`](https://github.com/anthropics/agent-browser) if browser automation is needed. It must be on `PATH` for Claude CLI to launch it. After installing, run `agent-browser install` to fetch a bundled Chromium (or set `AGENT_BROWSER_EXECUTABLE_PATH` to use a system browser).
|
|
13
|
+
|
|
14
|
+
## One-Off: Sync Discord Content
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm sync:discord-context
|
|
18
|
+
pnpm sync:discord-context -- --rewrite-index
|
|
19
|
+
pnpm sync:discord-context -- --add-channel 123456789012345678:my-channel
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Environment
|
|
23
|
+
|
|
24
|
+
Two setup paths:
|
|
25
|
+
|
|
26
|
+
- **Global install (end users):** Run `discoclaw init` — interactive wizard creates and configures `.env`.
|
|
27
|
+
- **From source (contributors):** Run `pnpm setup` for guided configuration, or copy `.env.example` → `.env` for essentials only. For all ~90 options, use `.env.example.full`. See those files for inline comments.
|
|
28
|
+
|
|
29
|
+
### Discord
|
|
30
|
+
| Variable | Default | Description |
|
|
31
|
+
|----------|---------|-------------|
|
|
32
|
+
| `DISCORD_TOKEN` | **(required)** | Bot token |
|
|
33
|
+
| `DISCORD_ALLOW_USER_IDS` | **(required)** | Comma/space-separated Discord user IDs; fail-closed if empty |
|
|
34
|
+
| `DISCORD_CHANNEL_IDS` | *(empty — all channels)* | Restrict the bot to specific guild channel IDs (DMs still allowed) |
|
|
35
|
+
| `DISCORD_REQUIRE_CHANNEL_CONTEXT` | `1` | Require a per-channel context file before responding |
|
|
36
|
+
| `DISCORD_AUTO_INDEX_CHANNEL_CONTEXT` | `1` | Auto-create stub context files for new channels |
|
|
37
|
+
| `DISCORD_AUTO_JOIN_THREADS` | `0` | Best-effort auto-join threads so the bot can respond inside them |
|
|
38
|
+
| `DISCOCLAW_DISCORD_ACTIONS` | `0` | Master switch for Discord server actions |
|
|
39
|
+
| `DISCOCLAW_DISCORD_ACTIONS_CHANNELS` | `1` | Channel management (create/edit/delete/list/info, categoryCreate) |
|
|
40
|
+
| `DISCOCLAW_DISCORD_ACTIONS_MESSAGING` | `0` | Messaging (send/edit/delete/read messages, react, threads, pins) |
|
|
41
|
+
| `DISCOCLAW_DISCORD_ACTIONS_GUILD` | `0` | Guild info (memberInfo, roleInfo, roleAdd/Remove, events, search) |
|
|
42
|
+
| `DISCOCLAW_DISCORD_ACTIONS_MODERATION` | `0` | Moderation (timeout, kick, ban) |
|
|
43
|
+
| `DISCOCLAW_DISCORD_ACTIONS_POLLS` | `0` | Poll creation |
|
|
44
|
+
| `DISCOCLAW_DISCORD_ACTIONS_TASKS` | `1` | Task tracking (create/update/close/show/list/sync) |
|
|
45
|
+
|
|
46
|
+
### Claude CLI
|
|
47
|
+
| Variable | Default | Description |
|
|
48
|
+
|----------|---------|-------------|
|
|
49
|
+
| `CLAUDE_BIN` | `claude` | Path/name of the Claude CLI binary |
|
|
50
|
+
| `CLAUDE_DANGEROUSLY_SKIP_PERMISSIONS` | `0` | Pass `--dangerously-skip-permissions` to the CLI |
|
|
51
|
+
| `CLAUDE_OUTPUT_FORMAT` | `text` | `text` or `stream-json` (preferred for smoother streaming) |
|
|
52
|
+
| `CLAUDE_ECHO_STDIO` | `0` | Forward raw CLI stdout/stderr lines into Discord output |
|
|
53
|
+
| `CLAUDE_DEBUG_FILE` | *(empty)* | Write Claude CLI debug logs to this file path |
|
|
54
|
+
| `CLAUDE_STRICT_MCP_CONFIG` | `1` | Pass `--strict-mcp-config` to skip slow MCP plugin init |
|
|
55
|
+
|
|
56
|
+
### App
|
|
57
|
+
| Variable | Default | Description |
|
|
58
|
+
|----------|---------|-------------|
|
|
59
|
+
| `DISCOCLAW_DATA_DIR` | *(empty)* | Optional data root; sets default `WORKSPACE_CWD` to `$DISCOCLAW_DATA_DIR/workspace` |
|
|
60
|
+
| `DISCOCLAW_CONTENT_DIR` | *(empty)* | Channel-context content dir (per-channel files only; PA modules always load from `.context/` in repo root); defaults to `$DISCOCLAW_DATA_DIR/content` |
|
|
61
|
+
| `WORKSPACE_CWD` | `./workspace` | Runtime working directory (overrides the data-dir default) |
|
|
62
|
+
| `GROUPS_DIR` | `./groups` | Base directory for per-session working dirs |
|
|
63
|
+
| `USE_GROUP_DIR_CWD` | `0` | Enable nanoclaw-style group CWD per session |
|
|
64
|
+
| `LOG_LEVEL` | `info` | Pino log level |
|
|
65
|
+
| `DISCOCLAW_DEBUG_RUNTIME` | `0` | Dump resolved runtime config at startup (debugging systemd env issues) |
|
|
66
|
+
|
|
67
|
+
### Runtime Invocation
|
|
68
|
+
| Variable | Default | Description |
|
|
69
|
+
|----------|---------|-------------|
|
|
70
|
+
| `RUNTIME_MODEL` | `capable` | Model tier (`fast`, `capable`) or concrete model name passed to the CLI |
|
|
71
|
+
| `RUNTIME_TOOLS` | `Bash,Read,Write,Edit,Glob,Grep,WebSearch,WebFetch` | Comma-separated tool list |
|
|
72
|
+
| `RUNTIME_TIMEOUT_MS` | `600000` | Per-invocation timeout in milliseconds |
|
|
73
|
+
| `DISCOCLAW_RUNTIME_SESSIONS` | `1` | Persist Claude session IDs across messages |
|
|
74
|
+
| `DISCOCLAW_MESSAGE_HISTORY_BUDGET` | `3000` | Char budget for recent conversation history in prompts (0 = disabled) |
|
|
75
|
+
| `DISCOCLAW_SUMMARY_ENABLED` | `1` | Enable rolling conversation summaries |
|
|
76
|
+
| `DISCOCLAW_SUMMARY_MODEL` | `fast` | Model tier or concrete name for summarization |
|
|
77
|
+
| `DISCOCLAW_SUMMARY_MAX_CHARS` | `2000` | Max chars for the rolling summary text |
|
|
78
|
+
| `DISCOCLAW_SUMMARY_EVERY_N_TURNS` | `5` | Re-summarize every N messages per session |
|
|
79
|
+
| `DISCOCLAW_DURABLE_MEMORY_ENABLED` | `1` | Enable durable per-user memory (persistent facts/preferences) |
|
|
80
|
+
| `DISCOCLAW_DURABLE_INJECT_MAX_CHARS` | `2000` | Max chars for durable memory injected into prompts |
|
|
81
|
+
| `DISCOCLAW_DURABLE_MAX_ITEMS` | `200` | Max durable items per user |
|
|
82
|
+
| `DISCOCLAW_MEMORY_COMMANDS_ENABLED` | `1` | Enable `!memory` commands (show/remember/forget/reset) |
|
|
83
|
+
| `DISCOCLAW_STATUS_CHANNEL` | *(empty — disabled)* | Channel name or ID for status messages (bot online/offline, errors) |
|
|
84
|
+
| `RUNTIME_FALLBACK_MODEL` | *(unset)* | Auto-fallback model when primary is overloaded (e.g. `sonnet`) |
|
|
85
|
+
| `RUNTIME_MAX_BUDGET_USD` | *(unset)* | Max USD per CLI process; one-shot = per invocation, multi-turn = per session lifetime |
|
|
86
|
+
| `CLAUDE_APPEND_SYSTEM_PROMPT` | *(unset)* | Append to system prompt (max 4000 chars); skips workspace PA file reads when set |
|
|
87
|
+
| `DISCOCLAW_CRON_ENABLED` | `1` | Master switch for the cron subsystem (forum-based scheduled tasks) |
|
|
88
|
+
| `DISCOCLAW_CRON_FORUM` | **(required when enabled)** | Automations forum channel ID (snowflake) for cron/automation definitions |
|
|
89
|
+
| `DISCOCLAW_CRON_MODEL` | `fast` | Model tier or concrete name for parsing cron definitions |
|
|
90
|
+
|
|
91
|
+
### Browser Automation
|
|
92
|
+
| Variable | Default | Description |
|
|
93
|
+
|----------|---------|-------------|
|
|
94
|
+
| `AGENT_BROWSER_EXECUTABLE_PATH` | *(empty)* | Path to the browser binary for `agent-browser` (e.g. Chromium). If unset, agent-browser uses its bundled default. |
|
|
95
|
+
|
|
96
|
+
### Tasks (Task Tracking)
|
|
97
|
+
| Variable | Default | Description |
|
|
98
|
+
|----------|---------|-------------|
|
|
99
|
+
| `DISCOCLAW_TASKS_ENABLED` | `1` | Master switch — loads tasks subsystem |
|
|
100
|
+
| `DISCOCLAW_TASKS_FORUM` | **(required when enabled)** | Forum channel ID (snowflake) for task threads |
|
|
101
|
+
| `DISCOCLAW_TASKS_CWD` | `<WORKSPACE_CWD>` | Tasks workspace override (legacy import/migration path) |
|
|
102
|
+
| `DISCOCLAW_TASKS_TAG_MAP` | `data/tasks/tag-map.json` | Path to task forum tag map |
|
|
103
|
+
| `DISCOCLAW_TASKS_MENTION_USER` | *(empty)* | User ID to @mention in new task threads |
|
|
104
|
+
| `DISCOCLAW_TASKS_SIDEBAR` | `0` | When `1` + `MENTION_USER` set, persists @mention in open task starters for sidebar visibility |
|
|
105
|
+
| `DISCOCLAW_TASKS_AUTO_TAG` | `1` | Enable AI auto-tagging |
|
|
106
|
+
| `DISCOCLAW_TASKS_AUTO_TAG_MODEL` | `fast` | Model tier or concrete name for auto-tagging |
|
|
107
|
+
| `DISCOCLAW_TASKS_SYNC_SKIP_PHASE5` | `0` | Disable phase-5 reconciliation during sync |
|
|
108
|
+
| `DISCOCLAW_TASKS_PREFIX` | `ws` | Prefix for generated task IDs (e.g. `ws-001`) |
|
|
109
|
+
|
|
110
|
+
## Debugging
|
|
111
|
+
|
|
112
|
+
### Where logs go
|
|
113
|
+
|
|
114
|
+
| Mode | Log destination |
|
|
115
|
+
|------|----------------|
|
|
116
|
+
| `pnpm dev` | stdout/stderr in your terminal |
|
|
117
|
+
| systemd service | journalctl (`journalctl --user -u discoclaw.service`) |
|
|
118
|
+
|
|
119
|
+
DiscoClaw uses Pino for structured JSON logging. All app logs go to stdout.
|
|
120
|
+
|
|
121
|
+
### Quick commands
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# Local dev — logs stream to terminal automatically
|
|
125
|
+
pnpm dev
|
|
126
|
+
|
|
127
|
+
# Production — tail live logs
|
|
128
|
+
journalctl --user -u discoclaw.service -f
|
|
129
|
+
|
|
130
|
+
# Production — last 50 lines
|
|
131
|
+
journalctl --user -u discoclaw.service -n 50
|
|
132
|
+
|
|
133
|
+
# Production — logs since last boot
|
|
134
|
+
journalctl --user -u discoclaw.service -b
|
|
135
|
+
|
|
136
|
+
# Production — logs from the last 10 minutes
|
|
137
|
+
journalctl --user -u discoclaw.service --since "10 min ago"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Increasing verbosity
|
|
141
|
+
|
|
142
|
+
Set `LOG_LEVEL` in `.env` to get more detail. Levels: `fatal`, `error`, `warn`, `info`, `debug`, `trace`.
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
LOG_LEVEL=debug pnpm dev
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Claude CLI debug output
|
|
149
|
+
|
|
150
|
+
To capture raw Claude CLI stdin/stdout for diagnosing runtime issues:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
# Write CLI debug logs to a file
|
|
154
|
+
CLAUDE_DEBUG_FILE=/tmp/claude-debug.log pnpm dev
|
|
155
|
+
|
|
156
|
+
# Echo raw CLI output into Discord (noisy, useful for live debugging)
|
|
157
|
+
CLAUDE_ECHO_STDIO=1 pnpm dev
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Startup / env issues
|
|
161
|
+
|
|
162
|
+
If the bot starts but behaves unexpectedly (wrong model, missing tools, wrong CWD):
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
# Dump resolved runtime config at startup
|
|
166
|
+
DISCOCLAW_DEBUG_RUNTIME=1 pnpm dev
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
This is especially useful for systemd, where env loading can differ from your shell.
|
|
170
|
+
|
|
171
|
+
### What to look for
|
|
172
|
+
|
|
173
|
+
- **Bot not responding:** Check allowlist (`DISCORD_ALLOW_USER_IDS`), channel restrictions (`DISCORD_CHANNEL_IDS`), and channel context requirement (`DISCORD_REQUIRE_CHANNEL_CONTEXT`).
|
|
174
|
+
- **Claude CLI errors:** Look for `runtime` or `spawn` in logs. Use `CLAUDE_DEBUG_FILE` to capture full CLI output.
|
|
175
|
+
- **Timeout issues:** Look for `timeout` in logs. Adjust `RUNTIME_TIMEOUT_MS` if needed.
|
|
176
|
+
- **PID lock conflicts:** Look for `pidlock` in logs. See ops.md for stale lock handling.
|
|
177
|
+
|
|
178
|
+
## Task Auto-Sync
|
|
179
|
+
|
|
180
|
+
When the bot is running, task changes trigger Discord sync immediately via in-process events:
|
|
181
|
+
|
|
182
|
+
- **Startup sync:** On boot, a fire-and-forget full sync runs to catch any drift that occurred while the bot was down.
|
|
183
|
+
- **Synchronous events:** The in-process task store emits events on every write (`created`, `updated`, `closed`, `labeled`). Discord sync subscribers handle each event immediately — no file watcher, no debounce, no subprocess spawning.
|
|
184
|
+
- **Coordinator:** All sync paths (event-driven, startup, manual `taskSync` action) share a `TaskSyncCoordinator` that prevents concurrent syncs and invalidates the thread cache. Auto-triggered syncs are silent; only manual sync posts to the status channel.
|
|
185
|
+
|
|
186
|
+
No extra env vars are needed — auto-sync activates whenever `DISCOCLAW_TASKS_ENABLED=1` and a guild is available.
|
|
187
|
+
|
|
188
|
+
## Smoke Tests
|
|
189
|
+
|
|
190
|
+
The smoke-test suite validates each configured model tier end-to-end — verifying API keys, tier mappings, system prompts, and binary availability — before real users encounter a broken model path.
|
|
191
|
+
|
|
192
|
+
It exercises `RuntimeAdapter.invoke()` → `EngineEvent` pipeline with a curated set of prompt categories (basic Q&A, tool use, streaming). Tests are **opt-in** and skipped by default in CI unless `SMOKE_TEST_TIERS` is set.
|
|
193
|
+
|
|
194
|
+
### Environment variables
|
|
195
|
+
|
|
196
|
+
| Variable | Default | Description |
|
|
197
|
+
|----------|---------|-------------|
|
|
198
|
+
| `SMOKE_TEST_TIERS` | *(unset — skips smoke tests)* | Comma-separated list of tier names (`fast`, `capable`) or literal model IDs to test for Claude Code (e.g. `fast,capable` or `claude-haiku-4-5-20251001`) |
|
|
199
|
+
| `GEMINI_SMOKE_TEST_TIERS` | *(unset — skips Gemini smoke tests)* | Comma-separated tier names or model IDs for Gemini smoke tests (requires `GEMINI_API_KEY`) |
|
|
200
|
+
| `OPENAI_SMOKE_TEST_TIERS` | *(unset — skips OpenAI smoke tests)* | Comma-separated tier names or model IDs for OpenAI smoke tests (requires `OPENAI_API_KEY`) |
|
|
201
|
+
| `CODEX_SMOKE_TEST_TIERS` | *(unset — skips Codex smoke tests)* | Comma-separated tier names or model IDs for Codex smoke tests (requires `codex` binary on `PATH`) |
|
|
202
|
+
| `SMOKE_TEST_TIMEOUT_MS` | `60000` | Per-invocation timeout for each smoke-test prompt, in milliseconds (applies to all providers) |
|
|
203
|
+
|
|
204
|
+
### Usage
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
# Run Claude Code smoke tests against the fast and capable tiers
|
|
208
|
+
SMOKE_TEST_TIERS=fast,capable pnpm test
|
|
209
|
+
|
|
210
|
+
# Run against a specific Claude model ID
|
|
211
|
+
SMOKE_TEST_TIERS=claude-sonnet-4-6 pnpm test
|
|
212
|
+
|
|
213
|
+
# Run Gemini smoke tests for the fast tier
|
|
214
|
+
GEMINI_SMOKE_TEST_TIERS=fast pnpm test
|
|
215
|
+
|
|
216
|
+
# Run OpenAI smoke tests (requires OPENAI_API_KEY)
|
|
217
|
+
OPENAI_SMOKE_TEST_TIERS=fast pnpm test
|
|
218
|
+
|
|
219
|
+
# Run Codex smoke tests (requires codex binary on PATH)
|
|
220
|
+
CODEX_SMOKE_TEST_TIERS=fast pnpm test
|
|
221
|
+
|
|
222
|
+
# Adjust timeout (e.g. slower network)
|
|
223
|
+
SMOKE_TEST_TIERS=fast SMOKE_TEST_TIMEOUT_MS=120000 pnpm test
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
The suite uses your real `.env` — the same config that runs the bot is sufficient. No separate test credentials are needed.
|
|
227
|
+
|
|
228
|
+
## Notes
|
|
229
|
+
- Runtime invocation defaults are configurable via env (`RUNTIME_MODEL`, `RUNTIME_TOOLS`, `RUNTIME_TIMEOUT_MS`).
|
|
230
|
+
- If `pnpm dev` fails with "Missing DISCORD_TOKEN", your `.env` isn't loaded or the var is unset.
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# discord.md — Discord Behavior & Routing
|
|
2
|
+
|
|
3
|
+
## Access Control
|
|
4
|
+
- `DISCORD_ALLOW_USER_IDS` is the primary gate.
|
|
5
|
+
- Fail closed: if the allowlist is empty, DiscoClaw responds to nobody.
|
|
6
|
+
- Optional: `DISCORD_CHANNEL_IDS` restricts the bot to specific guild channels (DMs are still allowed).
|
|
7
|
+
|
|
8
|
+
## Base PA Context
|
|
9
|
+
|
|
10
|
+
Base PA behavioral and safety context is loaded from `.context/pa.md` and `.context/pa-safety.md`
|
|
11
|
+
in the repo root. These are required — the bot refuses to start if either is missing.
|
|
12
|
+
|
|
13
|
+
## Channel Context (Token-Efficient)
|
|
14
|
+
DiscoClaw inlines per-channel context files into the runtime prompt.
|
|
15
|
+
|
|
16
|
+
Layout (under `$DISCOCLAW_CONTENT_DIR` or `$DISCOCLAW_DATA_DIR/content`):
|
|
17
|
+
- `discord/DISCORD.md` (index: channel -> id -> context file)
|
|
18
|
+
- `discord/channels/*.md` (per-channel context modules)
|
|
19
|
+
- `discord/channels/_default.md` (fallback for unknown channels)
|
|
20
|
+
- `discord/channels/dm.md` (DM fallback)
|
|
21
|
+
|
|
22
|
+
Behavior:
|
|
23
|
+
- For each message, DiscoClaw tells the runtime to `Read` the relevant channel context file before responding.
|
|
24
|
+
- For threads, the parent channel context applies.
|
|
25
|
+
|
|
26
|
+
Strict mode:
|
|
27
|
+
- `DISCORD_REQUIRE_CHANNEL_CONTEXT=1` (default): the bot requires a per-channel context file.
|
|
28
|
+
- `DISCORD_AUTO_INDEX_CHANNEL_CONTEXT=1` (default): when a message arrives for a new channel, DiscoClaw appends it to `discord/DISCORD.md` and creates a blank stub file.
|
|
29
|
+
|
|
30
|
+
Thread auto-join:
|
|
31
|
+
- `DISCORD_AUTO_JOIN_THREADS=0` (default): best-effort auto-join threads so the bot can respond inside them. Private threads still require adding the bot manually.
|
|
32
|
+
|
|
33
|
+
## Conversation History & Memory
|
|
34
|
+
When `DISCOCLAW_MESSAGE_HISTORY_BUDGET` > 0 (default: `3000`), DiscoClaw fetches recent messages from the Discord channel and includes them in the prompt as conversation context. This allows Claude to maintain conversational context across messages without relying on CLI session persistence. The char budget caps the total history size; messages are selected newest-first so the most relevant context is preserved. Bot responses are truncated when necessary to fit the budget.
|
|
35
|
+
|
|
36
|
+
### Rolling Summaries
|
|
37
|
+
When `DISCOCLAW_SUMMARY_ENABLED=1` (default), DiscoClaw maintains a rolling conversation summary per session key, generated by Haiku every N turns (`DISCOCLAW_SUMMARY_EVERY_N_TURNS`, default 5). The summary is a compressed narrative of earlier conversation — decisions, preferences, current focus — kept under `DISCOCLAW_SUMMARY_MAX_CHARS` characters.
|
|
38
|
+
|
|
39
|
+
Summaries are stored on disk at `data/memory/rolling/<safe-session-key>.json` and injected into the prompt between context files and recent conversation as a "Conversation memory" section. When recent messages and the summary conflict, the recent messages take precedence (the summary is lossy). Summary generation is best-effort: failures are logged and do not block responding.
|
|
40
|
+
|
|
41
|
+
### Durable Memory
|
|
42
|
+
When `DISCOCLAW_DURABLE_MEMORY_ENABLED=1` (default), DiscoClaw maintains persistent per-user memory that survives across channels and sessions. Items are stored at `data/memory/durable/<user-id>.json` and include facts, preferences, projects, and other user-specific notes.
|
|
43
|
+
|
|
44
|
+
Active durable items are injected into the prompt between context files and conversation memory, sorted by most recently updated, capped by `DISCOCLAW_DURABLE_INJECT_MAX_CHARS` (default 2000). Each user can store up to `DISCOCLAW_DURABLE_MAX_ITEMS` (default 200) items.
|
|
45
|
+
|
|
46
|
+
When `DISCOCLAW_MEMORY_COMMANDS_ENABLED=1` (default), users can manage their durable memory via commands:
|
|
47
|
+
- `!memory` or `!memory show` — display active durable items and rolling summary
|
|
48
|
+
- `!memory remember <text>` — store a new fact
|
|
49
|
+
- `!memory forget <text>` — deprecate matching items (requires 60% text-length match)
|
|
50
|
+
- `!memory reset rolling` — clear the rolling summary for the current session
|
|
51
|
+
|
|
52
|
+
Memory commands are intercepted before runtime invocation and do not consume API tokens.
|
|
53
|
+
|
|
54
|
+
## Session Keys
|
|
55
|
+
- DM: `discord:dm:<authorId>`
|
|
56
|
+
- Thread: `discord:thread:<threadId>` (if the incoming channel is a thread)
|
|
57
|
+
- Channel: `discord:channel:<channelId>`
|
|
58
|
+
|
|
59
|
+
These session keys map to persisted UUIDs via `data/sessions.json`.
|
|
60
|
+
|
|
61
|
+
## Concurrency (Single Flight)
|
|
62
|
+
- DiscoClaw serializes processing per session key to avoid interleaving tool runs/context.
|
|
63
|
+
- Implementation: `src/group-queue.ts`
|
|
64
|
+
|
|
65
|
+
## Output Constraints
|
|
66
|
+
- Discord has a ~2000 char limit per message.
|
|
67
|
+
- DiscoClaw chunks long replies and attempts to keep fenced code blocks renderable across splits.
|
|
68
|
+
|
|
69
|
+
## Discord Actions
|
|
70
|
+
When `DISCOCLAW_DISCORD_ACTIONS=1` (master switch), Claude can perform Discord server actions by emitting `<discord-action>` blocks in its response. After the runtime completes, DiscoClaw parses these blocks, executes them via discord.js, strips the blocks from the displayed message, and appends results.
|
|
71
|
+
|
|
72
|
+
Each action category has its own flag (only active when the master switch is `1`):
|
|
73
|
+
|
|
74
|
+
| Flag | Default | Actions |
|
|
75
|
+
|------|---------|---------|
|
|
76
|
+
| `DISCOCLAW_DISCORD_ACTIONS_CHANNELS` | `1` | channelCreate, channelEdit, channelDelete, channelList, channelInfo, categoryCreate, threadListArchived |
|
|
77
|
+
| `DISCOCLAW_DISCORD_ACTIONS_MESSAGING` | `0` | sendMessage, react, readMessages, fetchMessage, editMessage, deleteMessage, threadCreate, pinMessage, unpinMessage, listPins |
|
|
78
|
+
| `DISCOCLAW_DISCORD_ACTIONS_GUILD` | `0` | memberInfo, roleInfo, roleAdd, roleRemove, searchMessages, eventList, eventCreate |
|
|
79
|
+
| `DISCOCLAW_DISCORD_ACTIONS_MODERATION` | `0` | timeout, kick, ban |
|
|
80
|
+
| `DISCOCLAW_DISCORD_ACTIONS_POLLS` | `0` | poll |
|
|
81
|
+
| `DISCOCLAW_DISCORD_ACTIONS_TASKS` | `1` | taskCreate, taskUpdate, taskClose, taskShow, taskList, taskSync |
|
|
82
|
+
|
|
83
|
+
Auto-follow-up: When query actions (channelList, channelInfo, threadListArchived, readMessages, fetchMessage, listPins, memberInfo, roleInfo, searchMessages, eventList, taskList, taskShow) succeed, DiscoClaw automatically re-invokes Claude with the results. This allows Claude to reason about query results without requiring the user to send a follow-up message. Controlled by `DISCOCLAW_ACTION_FOLLOWUP_DEPTH` (default `3`, `0` disables). Mutation-only responses do not trigger follow-ups. Trivially short follow-up responses (<50 chars with no actions) are suppressed.
|
|
84
|
+
|
|
85
|
+
Requirements:
|
|
86
|
+
- The bot needs appropriate permissions in the server (Manage Channels, Manage Roles, Moderate Members, etc.) depending on the actions used. These are server-level role permissions, not Developer Portal settings.
|
|
87
|
+
- Only works in guild channels (not DMs).
|
|
88
|
+
- Master switch defaults to off (`0`). Only allowlisted users can trigger actions.
|
|
89
|
+
- Destructive actions (delete, kick, ban, timeout) prompt Claude to confirm with the user first.
|
|
90
|
+
- If actions fail with "Missing Permissions", the bot's role lacks the required permission.
|
|
91
|
+
|
|
92
|
+
## Status Channel
|
|
93
|
+
When `DISCOCLAW_STATUS_CHANNEL` is set to a channel name or ID, DiscoClaw posts plain-text status messages on key events:
|
|
94
|
+
- **Bot Online** — posted after the `ready` event fires
|
|
95
|
+
- **Bot Offline** — posted on SIGTERM/SIGINT (best-effort)
|
|
96
|
+
- **Runtime Error** — runtime invocation failed or timed out
|
|
97
|
+
- **Handler Failure** — uncaught exception in message processing
|
|
98
|
+
- **Action Failed** — a Discord action returned `{ ok: false }`
|
|
99
|
+
|
|
100
|
+
Fail-open: if the channel is not found or the env var is unset, the bot works normally with no status posts. Errors posting to the status channel are caught and logged, never crashing the bot.
|
|
101
|
+
|
|
102
|
+
Implementation: `src/discord/status-channel.ts`
|
|
103
|
+
|
|
104
|
+
## Cron (Scheduled Tasks)
|
|
105
|
+
When `DISCOCLAW_CRON_ENABLED=1` (default), `DISCOCLAW_CRON_FORUM` must be set to the "automations" forum channel ID (snowflake). DiscoClaw runs a forum-based cron subsystem. Each forum thread is a cron job: the thread name is the job name, and the starter message is a natural-language definition that gets parsed by AI into a schedule, timezone, target channel, and prompt.
|
|
106
|
+
|
|
107
|
+
Creating a cron: create a thread in the forum. The starter message should describe the schedule, target channel, and what to do (e.g., "Every weekday at 7am Pacific, check the weather for Portland OR and post a brief summary to #general."). The bot reacts with a checkmark and replies with the parsed schedule.
|
|
108
|
+
|
|
109
|
+
Managing crons:
|
|
110
|
+
- **Disable:** Archive the thread. The bot stops scheduling.
|
|
111
|
+
- **Enable:** Unarchive the thread. The bot re-parses and resumes.
|
|
112
|
+
- **Edit:** Edit the starter message. The bot re-parses on the next `messageUpdate`.
|
|
113
|
+
- **Delete:** Delete the thread. The bot removes the job.
|
|
114
|
+
|
|
115
|
+
Archive vs delete: archiving a thread is reversible (sets the archived flag; thread still exists and can be unarchived). Deleting a thread is permanent (thread and its messages are gone). The `cronDelete` action archives the thread — it does not delete it — so history is preserved and the cron can be restored by unarchiving.
|
|
116
|
+
|
|
117
|
+
Cron responses are posted to the target channel only (threads stay clean as config). Discord actions are supported in cron responses if the master switch is enabled. Failures are posted to the status channel.
|
|
118
|
+
|
|
119
|
+
Overlap protection: if a previous run for the same job is still active, the next tick is skipped.
|
|
120
|
+
|
|
121
|
+
Implementation: `src/cron/`
|
|
122
|
+
|
|
123
|
+
## Tasks (Task Tracking)
|
|
124
|
+
DiscoClaw includes a task tracker backed by in-process `TaskStore` data and synced to Discord forum threads.
|
|
125
|
+
|
|
126
|
+
- Data model/store: `src/tasks/types.ts`, `src/tasks/store.ts`
|
|
127
|
+
- Discord task action path: `src/tasks/task-action-executor.ts` (dispatch), `src/tasks/task-action-mutations.ts` (create/update/close), `src/tasks/task-action-thread-sync.ts` (thread lifecycle helpers), `src/tasks/task-action-mutation-helpers.ts` (shared mutation helpers), `src/tasks/task-action-read-ops.ts` (show/list/sync/reload), `src/tasks/task-action-contract.ts` (request types)
|
|
128
|
+
- Canonical sync modules: `src/tasks/task-sync-engine.ts`, `src/tasks/task-sync-pipeline.ts` (facade), `src/tasks/task-sync-apply-plan.ts`, `src/tasks/task-sync-reconcile-plan.ts`, `src/tasks/task-sync-apply-types.ts`, `src/tasks/task-sync-phase-apply.ts`, `src/tasks/task-sync-reconcile.ts`, `src/tasks/sync-coordinator.ts`, `src/tasks/sync-coordinator-metrics.ts`, `src/tasks/sync-coordinator-retries.ts`, `src/tasks/thread-helpers.ts`, `src/tasks/thread-forum-ops.ts`, `src/tasks/thread-lifecycle-ops.ts`, `src/tasks/thread-ops.ts` (facade), `src/tasks/tag-map.ts`
|
|
129
|
+
- Runtime shim status: `src/beads/*` compatibility modules removed in hard-cut phase
|
|
130
|
+
|
|
131
|
+
Auto-sync is event-driven from the in-process store and runs a startup reconciliation pass.
|
|
132
|
+
Auto-triggered syncs are silent; explicit `taskSync` can post status output.
|
|
133
|
+
|
|
134
|
+
Primary env surface is `DISCOCLAW_TASKS_*`.
|
|
135
|
+
|
|
136
|
+
## Discord API Quirks
|
|
137
|
+
|
|
138
|
+
**Thread name + archive in one call:** When updating a thread's name AND archiving it in a single PATCH request, the name updates but the archive flag doesn't stick. Do them as separate API calls with a short delay between.
|
|
139
|
+
|
|
140
|
+
## Group CWD Mode
|
|
141
|
+
If `USE_GROUP_DIR_CWD=1`:
|
|
142
|
+
- CWD becomes `groups/<sessionKey>/` for that Discord context.
|
|
143
|
+
- The main workspace (`WORKSPACE_CWD`) is added via `--add-dir` so tools can still read/write it.
|
|
144
|
+
- DiscoClaw bootstraps `groups/<sessionKey>/CLAUDE.md` on first use.
|