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,253 @@
|
|
|
1
|
+
# runtime.md — Runtimes & Adapters
|
|
2
|
+
|
|
3
|
+
## Model Names & IDs
|
|
4
|
+
|
|
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
|
+
|
|
7
|
+
Sources to check:
|
|
8
|
+
- **Anthropic:** https://platform.claude.com/docs/en/about-claude/models/overview
|
|
9
|
+
- **OpenAI/Codex:** https://developers.openai.com/codex/models/
|
|
10
|
+
- **Claude Code CLI shorthand:** `sonnet`, `opus`, `haiku` resolve to the latest version of each model family
|
|
11
|
+
|
|
12
|
+
Current model IDs (as of 2026-02-17):
|
|
13
|
+
| Provider | Model | API/CLI ID |
|
|
14
|
+
|----------|-------|-----------|
|
|
15
|
+
| Anthropic | Claude Opus 4.6 | `claude-opus-4-6` (CLI shorthand: `opus`) |
|
|
16
|
+
| Anthropic | Claude Sonnet 4.6 | `claude-sonnet-4-6` (CLI shorthand: `sonnet`) |
|
|
17
|
+
| Anthropic | Claude Haiku 4.5 | `claude-haiku-4-5-20251001` (CLI shorthand: `haiku`) |
|
|
18
|
+
| OpenAI | GPT-5.3-Codex | `gpt-5.3-codex` |
|
|
19
|
+
| OpenAI | GPT-5.3-Codex-Spark | `gpt-5.3-codex-spark` |
|
|
20
|
+
| OpenAI | GPT-5-Codex-Mini | `gpt-5-codex-mini` |
|
|
21
|
+
|
|
22
|
+
## Runtime Adapter Interface
|
|
23
|
+
- The orchestrator consumes a provider-agnostic event stream (`EngineEvent`) from any adapter.
|
|
24
|
+
- Each runtime adapter implements `RuntimeAdapter.invoke()` and declares capabilities.
|
|
25
|
+
- The orchestrator routes to adapters based on context: message handling, forge drafting/auditing, cron execution.
|
|
26
|
+
|
|
27
|
+
See: `src/runtime/types.ts`
|
|
28
|
+
|
|
29
|
+
## Strategy Pattern (CLI Adapters)
|
|
30
|
+
|
|
31
|
+
All CLI-based runtime adapters share a universal factory (`src/runtime/cli-adapter.ts`) parameterized by a thin strategy object. New models only need ~40-80 lines of model-specific logic.
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
createCliRuntime(strategy, opts) → RuntimeAdapter
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The strategy provides: arg building, stdin formatting, output parsing, error handling.
|
|
38
|
+
The factory provides: subprocess tracking, process pool, stall detection, session scanning, JSONL parsing, image dedup, event queue.
|
|
39
|
+
|
|
40
|
+
| Strategy | File | Multi-turn | Notes |
|
|
41
|
+
|----------|------|------------|-------|
|
|
42
|
+
| Claude Code | `strategies/claude-strategy.ts` | process-pool | Default JSONL parsing, image support |
|
|
43
|
+
| 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 |
|
|
44
|
+
| Template | `strategies/template-strategy.ts` | — | Commented starting point for new models |
|
|
45
|
+
|
|
46
|
+
Thin wrappers (`claude-code-cli.ts`, `codex-cli.ts`) map legacy opts and re-export for backward compatibility. Shared utilities live in `cli-shared.ts` and `cli-output-parsers.ts`. Strategy types are in `cli-strategy.ts`.
|
|
47
|
+
|
|
48
|
+
Shutdown: `killAllSubprocesses()` from `cli-adapter.ts` kills all tracked subprocesses across all adapters.
|
|
49
|
+
|
|
50
|
+
## Claude Code CLI Runtime (Current)
|
|
51
|
+
- Adapter: `src/runtime/claude-code-cli.ts` (thin wrapper around `cli-adapter.ts` + `strategies/claude-strategy.ts`)
|
|
52
|
+
- Invocation shape (full):
|
|
53
|
+
```
|
|
54
|
+
claude -p --model <id|alias>
|
|
55
|
+
[--dangerously-skip-permissions] # when CLAUDE_DANGEROUSLY_SKIP_PERMISSIONS=1
|
|
56
|
+
[--strict-mcp-config] # when CLAUDE_STRICT_MCP_CONFIG=1
|
|
57
|
+
[--fallback-model <alias>] # when RUNTIME_FALLBACK_MODEL is set
|
|
58
|
+
[--max-budget-usd <number>] # when RUNTIME_MAX_BUDGET_USD is set
|
|
59
|
+
[--append-system-prompt <text>] # when CLAUDE_APPEND_SYSTEM_PROMPT is set
|
|
60
|
+
[--debug-file <path>] # when CLAUDE_DEBUG_FILE is set
|
|
61
|
+
[--session-id <uuid>] # when sessions are enabled
|
|
62
|
+
[--add-dir <dir> ...] # group CWD mode
|
|
63
|
+
[--output-format text|stream-json] # always passed
|
|
64
|
+
[--include-partial-messages] # when format is stream-json
|
|
65
|
+
[--tools <comma-list>] # configurable tool surface
|
|
66
|
+
-- <prompt> # POSIX terminator before prompt
|
|
67
|
+
```
|
|
68
|
+
- The `--` terminator prevents variadic flags (e.g. `--tools`, `--add-dir`) from consuming the positional prompt argument.
|
|
69
|
+
- Output modes:
|
|
70
|
+
- `CLAUDE_OUTPUT_FORMAT=stream-json` (preferred; DiscoClaw parses JSONL and streams text)
|
|
71
|
+
- `CLAUDE_OUTPUT_FORMAT=text` (fallback if your local CLI doesn't support stream-json)
|
|
72
|
+
|
|
73
|
+
## Tool Surface
|
|
74
|
+
- Default tools: `Bash, Read, Write, Edit, Glob, Grep, WebSearch, WebFetch` (8 tools).
|
|
75
|
+
- `Glob` + `Grep` are purpose-built for file search — faster than `find`/`grep` via Bash.
|
|
76
|
+
- `Write` enables proper file creation (previously required Bash echo/cat workarounds).
|
|
77
|
+
- Non-Claude adapters use a **capability gate** (`tools_fs`) to determine tool access:
|
|
78
|
+
- Codex CLI adapter: declares `tools_fs` — receives read-only tools (Read, Glob, Grep) in auditor role.
|
|
79
|
+
- OpenAI HTTP adapter: text-only (`streaming_text` only) — no tool execution.
|
|
80
|
+
- Future adapters (Gemini, etc.): declare capabilities as appropriate.
|
|
81
|
+
|
|
82
|
+
## Per-Workspace Permissions
|
|
83
|
+
- `workspace/PERMISSIONS.json` controls the tool surface per workspace.
|
|
84
|
+
- Loaded per-invocation from `src/workspace-permissions.ts`.
|
|
85
|
+
- If the file doesn't exist, falls back to the `RUNTIME_TOOLS` env var (fully backward compatible).
|
|
86
|
+
|
|
87
|
+
Tiers:
|
|
88
|
+
| Tier | Tools |
|
|
89
|
+
|------|-------|
|
|
90
|
+
| `readonly` | `Read, Glob, Grep, WebSearch, WebFetch` |
|
|
91
|
+
| `standard` | `Read, Edit, Glob, Grep, WebSearch, WebFetch` |
|
|
92
|
+
| `full` | `Bash, Read, Write, Edit, Glob, Grep, WebSearch, WebFetch` |
|
|
93
|
+
| `custom` | User-specified `tools` array in the JSON |
|
|
94
|
+
|
|
95
|
+
Note: `Write` is excluded from `standard` tier (non-destructive). Included in `full` alongside Bash.
|
|
96
|
+
|
|
97
|
+
Example: `{ "tier": "standard", "note": "Never modify files outside workspace." }`
|
|
98
|
+
|
|
99
|
+
The optional `note` field is injected into the prompt as a soft behavioral constraint.
|
|
100
|
+
Custom tier example: `{ "tier": "custom", "tools": ["Read", "Edit", "Bash"] }`
|
|
101
|
+
|
|
102
|
+
## Streaming & Reply Pacing (Discord)
|
|
103
|
+
|
|
104
|
+
Key settings for block streaming:
|
|
105
|
+
- `blockStreaming: true` — chunks output so user sees progress instead of silence then wall of text
|
|
106
|
+
- `blockStreamingCoalesce: {minChars:100, maxChars:600, idleMs:800}` — merges tiny fragments; 800ms idle = natural paragraph breaks
|
|
107
|
+
- `blockStreamingBreak: text_end` — flushes after each text block (between paragraphs, before/after tool calls)
|
|
108
|
+
- `toolStatusUpdates: true` — shows "Running tool..." during tool calls
|
|
109
|
+
- `reasoningStreaming: false` — reasoning tokens stay hidden for casual use
|
|
110
|
+
|
|
111
|
+
Tuning: too chattery? increase `minChars` or `idleMs`. Too slow? decrease `maxChars` or `idleMs`.
|
|
112
|
+
|
|
113
|
+
## Stream Stall Detection
|
|
114
|
+
|
|
115
|
+
Two-layer protection against hung Claude Code processes:
|
|
116
|
+
|
|
117
|
+
| Env Var | Default | Purpose |
|
|
118
|
+
|---------|---------|---------|
|
|
119
|
+
| `DISCOCLAW_STREAM_STALL_TIMEOUT_MS` | `120000` | Kill one-shot process if no stdout/stderr for this long. `0` disables. |
|
|
120
|
+
| `DISCOCLAW_STREAM_STALL_WARNING_MS` | `60000` | Show user-visible warning in Discord after this many ms of no events. `0` disables. |
|
|
121
|
+
|
|
122
|
+
**Runtime layer** (`src/runtime/cli-adapter.ts`): resets a timer on every stdout/stderr `data` event. On timeout, emits a `stream stall: no output for ${ms}ms` error and kills the process. Applies to both `text` and `stream-json` output formats.
|
|
123
|
+
|
|
124
|
+
**Discord layer** (`src/discord.ts`, `src/discord/reaction-handler.ts`): both message and reaction handlers track `lastEventAt` and `activeToolCount` in their streaming loops. When stall threshold is exceeded and no tools are active, appends a warning to `deltaText`. Enable `DISCOCLAW_SESSION_SCANNING=1` for tool-aware stall suppression (warnings suppressed during tool execution).
|
|
125
|
+
|
|
126
|
+
## Session Scanning & Tool-Aware Streaming
|
|
127
|
+
|
|
128
|
+
Two opt-in features for better Discord UX during tool-heavy invocations:
|
|
129
|
+
|
|
130
|
+
| Env Var | Default | Purpose |
|
|
131
|
+
|---------|---------|---------|
|
|
132
|
+
| `DISCOCLAW_SESSION_SCANNING` | `0` | Tail Claude Code's JSONL session log to emit `tool_start`/`tool_end` events |
|
|
133
|
+
| `DISCOCLAW_TOOL_AWARE_STREAMING` | `0` | Buffer text during tool execution, show activity indicators, stream final answer cleanly |
|
|
134
|
+
|
|
135
|
+
Both require `CLAUDE_OUTPUT_FORMAT=stream-json` for structured events.
|
|
136
|
+
|
|
137
|
+
## Resilience & Cost Controls
|
|
138
|
+
|
|
139
|
+
| Env Var | Default | Purpose |
|
|
140
|
+
|---------|---------|---------|
|
|
141
|
+
| `RUNTIME_FALLBACK_MODEL` | *(unset)* | Auto-fallback model when primary is overloaded (e.g. `sonnet`) |
|
|
142
|
+
| `RUNTIME_MAX_BUDGET_USD` | *(unset)* | Max USD per CLI process. One-shot = per invocation. Multi-turn = per session lifetime |
|
|
143
|
+
| `CLAUDE_APPEND_SYSTEM_PROMPT` | *(unset)* | Append text to Claude's system prompt (max 4000 chars) |
|
|
144
|
+
|
|
145
|
+
**Budget semantics:** For multi-turn sessions, budget accumulates across turns and cannot be reset mid-session. Recommend $5-10 for multi-turn.
|
|
146
|
+
|
|
147
|
+
**Append system prompt:** When set, workspace PA files (SOUL.md, IDENTITY.md, USER.md, TOOLS.md) are skipped from the context file list (their content is already in the system prompt). PA context modules (`.context/pa.md`, `.context/pa-safety.md`) and channel-specific context are unaffected. **Note:** Do not set this on first run before `workspace/BOOTSTRAP.md` has been consumed — the skip logic also bypasses BOOTSTRAP.md loading.
|
|
148
|
+
|
|
149
|
+
- **Session scanner** (`src/runtime/session-scanner.ts`): watches `~/.claude/projects/<escaped-cwd>/<session-id>.jsonl`, skips pre-existing content, degrades gracefully if the file never appears.
|
|
150
|
+
- **Tool-aware queue** (`src/discord/tool-aware-queue.ts`): state machine that suppresses narration text before tools, shows human-readable activity labels (from `src/runtime/tool-labels.ts`), and streams the final answer after all tool use completes.
|
|
151
|
+
- **Tool labels** (`src/runtime/tool-labels.ts`): maps tool names to labels like "Reading .../file.ts", "Running command...", etc.
|
|
152
|
+
|
|
153
|
+
## Multi-Turn (Long-Running Process)
|
|
154
|
+
|
|
155
|
+
Opt-in feature that keeps a long-running Claude Code subprocess alive per Discord session key using `--input-format stream-json`. Follow-up messages are pushed to the same process via stdin NDJSON, giving Claude Code native multi-turn context (tool results, file reads, edits persist across turns).
|
|
156
|
+
|
|
157
|
+
| Env Var | Default | Purpose |
|
|
158
|
+
|---------|---------|---------|
|
|
159
|
+
| `DISCOCLAW_MULTI_TURN` | `1` | Enable long-running process pool |
|
|
160
|
+
| `DISCOCLAW_MULTI_TURN_HANG_TIMEOUT_MS` | `60000` | Kill process if no stdout output for this long |
|
|
161
|
+
| `DISCOCLAW_MULTI_TURN_IDLE_TIMEOUT_MS` | `300000` | Kill idle process after 5 min of no messages |
|
|
162
|
+
| `DISCOCLAW_MULTI_TURN_MAX_PROCESSES` | `5` | Max concurrent long-running processes |
|
|
163
|
+
|
|
164
|
+
Key files:
|
|
165
|
+
- **Long-running process** (`src/runtime/long-running-process.ts`): manages a single subprocess with state machine (`idle` -> `busy` -> `idle` or `dead`), hang detection, idle timeout.
|
|
166
|
+
- **Process pool** (`src/runtime/process-pool.ts`): pool of `LongRunningProcess` instances keyed by session key, with LRU eviction.
|
|
167
|
+
|
|
168
|
+
Behavior:
|
|
169
|
+
- When enabled, `invoke()` tries the long-running process first for any call with a `sessionKey`.
|
|
170
|
+
- On hang detection or process crash, automatically falls back to the existing one-shot mode (unchanged).
|
|
171
|
+
- On shutdown, `killAllSubprocesses()` cleans up the pool.
|
|
172
|
+
|
|
173
|
+
Known limitations:
|
|
174
|
+
- GitHub issue #3187 reports that multi-turn stdin can hang after the first message. Mitigated by automatic hang detection + fallback.
|
|
175
|
+
- Prompt construction is unchanged (full context sent every turn). Optimizing to skip redundant context is a follow-up.
|
|
176
|
+
|
|
177
|
+
## Image Input (Discord → Claude)
|
|
178
|
+
|
|
179
|
+
When a Discord message or reaction target has image attachments (PNG, JPEG, WebP, GIF), they are downloaded and sent to Claude Code as base64-encoded image content blocks via `--input-format stream-json` stdin.
|
|
180
|
+
|
|
181
|
+
### How it works
|
|
182
|
+
|
|
183
|
+
1. **Filtering** — `resolveMediaType()` checks the attachment's `contentType` (lowercased) or falls back to file extension. Non-image attachments are surfaced as plain URLs in the prompt text.
|
|
184
|
+
2. **Validation** — Host allowlist (`cdn.discordapp.com`, `media.discordapp.net`), HTTPS-only, redirect rejection (`redirect: 'error'`), per-image and total size caps.
|
|
185
|
+
3. **Download** — `downloadAttachment()` fetches the image with a 10 s timeout, post-checks actual size, and returns base64.
|
|
186
|
+
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.
|
|
187
|
+
|
|
188
|
+
### Security controls
|
|
189
|
+
|
|
190
|
+
| Control | Detail |
|
|
191
|
+
|---------|--------|
|
|
192
|
+
| Host allowlist | Only Discord CDN hosts are permitted (SSRF protection) |
|
|
193
|
+
| HTTPS only | HTTP URLs are rejected |
|
|
194
|
+
| Redirect rejection | `fetch()` uses `redirect: 'error'` — no following redirects to internal hosts |
|
|
195
|
+
| Per-image size cap | 20 MB (`MAX_IMAGE_BYTES`), checked from metadata pre-download and from buffer post-download |
|
|
196
|
+
| Total size cap | 50 MB across all images in one message (`MAX_TOTAL_BYTES`) |
|
|
197
|
+
| Per-invocation cap | 10 images (`MAX_IMAGES_PER_INVOCATION`) |
|
|
198
|
+
| Download timeout | 10 s per image (`DOWNLOAD_TIMEOUT_MS`) |
|
|
199
|
+
| Filename sanitization | Control chars stripped, truncated to 100 chars in error messages |
|
|
200
|
+
|
|
201
|
+
### Key files
|
|
202
|
+
|
|
203
|
+
| File | Role |
|
|
204
|
+
|------|------|
|
|
205
|
+
| `src/discord/image-download.ts` | Download, validate, base64-encode Discord attachments |
|
|
206
|
+
| `src/runtime/claude-code-cli.ts` | Stdin pipe construction, `effectiveOutputFormat` override |
|
|
207
|
+
| `src/discord.ts` | Message handler: download images, pass to runtime, images only on initial turn |
|
|
208
|
+
| `src/discord/reaction-handler.ts` | Reaction handler: same download flow, also surfaces non-image attachment URLs |
|
|
209
|
+
|
|
210
|
+
### Follow-up depth gating
|
|
211
|
+
|
|
212
|
+
Images are only sent on the initial invocation (`followUpDepth === 0`). Auto-follow-up turns (triggered by query actions) are text-only — re-downloading images would waste time and bandwidth.
|
|
213
|
+
|
|
214
|
+
## Image Output (Claude → Discord)
|
|
215
|
+
|
|
216
|
+
Any `image` content block in Claude Code's stream-json output is automatically captured and delivered as a Discord file attachment. Claude models don't natively generate images — images only appear when an MCP tool returns image content blocks.
|
|
217
|
+
|
|
218
|
+
### How it works
|
|
219
|
+
|
|
220
|
+
1. **Extraction** — `extractImageFromUnknownEvent()` in `claude-code-cli.ts` recognizes direct `{ type: 'image', source: { type: 'base64', media_type, data } }` blocks and `content_block_start` wrappers. `extractResultContentBlocks()` handles result events containing mixed text + image arrays.
|
|
221
|
+
2. **Dedup** — `imageDedupeKey()` builds a key from media type + base64 length + 64-char prefix. Each consumer tracks a `Set<string>` of seen keys so duplicates (common with multi-turn mirrors) are dropped.
|
|
222
|
+
3. **Delivery** — `buildAttachments()` in `output-common.ts` converts each `ImageData` to a Discord `AttachmentBuilder` (named `image-1.png`, etc.). The three consumer paths — message (`discord.ts`), reaction (`reaction-handler.ts`), and cron (`executor.ts`) — all collect images into an `ImageData[]` during streaming and pass them to the shared send helpers.
|
|
223
|
+
|
|
224
|
+
### Key files
|
|
225
|
+
|
|
226
|
+
| File | Role |
|
|
227
|
+
|------|------|
|
|
228
|
+
| `src/runtime/types.ts` | `ImageData` type, `image_data` EngineEvent variant |
|
|
229
|
+
| `src/runtime/cli-output-parsers.ts` | Extraction, dedup key functions |
|
|
230
|
+
| `src/runtime/cli-adapter.ts` | Per-invocation image counting, dedup via strategy |
|
|
231
|
+
| `src/runtime/long-running-process.ts` | Multi-turn mirror: dedup + emit for long-running sessions |
|
|
232
|
+
| `src/discord/output-common.ts` | `buildAttachments()`, attachment slicing across message chunks |
|
|
233
|
+
| `src/discord.ts` | Message path consumer |
|
|
234
|
+
| `src/discord/reaction-handler.ts` | Reaction path consumer |
|
|
235
|
+
| `src/cron/executor.ts` | Cron path consumer |
|
|
236
|
+
|
|
237
|
+
### Limits
|
|
238
|
+
|
|
239
|
+
| Limit | Value | Source |
|
|
240
|
+
|-------|-------|--------|
|
|
241
|
+
| Max base64 size per image | 25 MB | `MAX_IMAGE_BASE64_LEN` |
|
|
242
|
+
| Max images per invocation | 10 | `MAX_IMAGES_PER_INVOCATION` |
|
|
243
|
+
| Max attachments per Discord message | 10 | Discord API limit |
|
|
244
|
+
|
|
245
|
+
### Enabling image generation
|
|
246
|
+
|
|
247
|
+
Since Claude can't generate images directly, you need an MCP server that wraps an external image API (DALL-E, Replicate, Stability, etc.).
|
|
248
|
+
|
|
249
|
+
1. **Set up an MCP server** that exposes a tool (e.g. `generate_image`) returning an `image` content block with `{ type: 'base64', media_type, data }`. Any MCP server that returns image content blocks will work — the pipeline is format-driven, not tool-name-driven.
|
|
250
|
+
2. **Register it** in the workspace `.mcp.json` so Claude Code loads it on invocation.
|
|
251
|
+
3. **Add workspace instructions** (in `workspace/SOUL.md` or system prompt) telling the bot it can generate images and when to use the tool.
|
|
252
|
+
|
|
253
|
+
The rest is automatic: the runtime adapter extracts the image blocks, deduplicates them, and the Discord layer attaches them to the reply.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# tasks.md — Task Tracking
|
|
2
|
+
|
|
3
|
+
Tasks are backed by an in-process `TaskStore` and synced to Discord forum threads.
|
|
4
|
+
|
|
5
|
+
Ground-zero post-hard-cut refactor tracker: `docs/tasks-ground-zero-post-hard-cut-plan.md`
|
|
6
|
+
Ground-zero task architecture refactor status: COMPLETE (FROZEN), verified on 2026-02-21.
|
|
7
|
+
|
|
8
|
+
## Data Model
|
|
9
|
+
|
|
10
|
+
Canonical type: `TaskData` in `src/tasks/types.ts`.
|
|
11
|
+
|
|
12
|
+
Statuses: `open` | `in_progress` | `blocked` | `closed`
|
|
13
|
+
|
|
14
|
+
## Task Store
|
|
15
|
+
|
|
16
|
+
Implementation: `src/tasks/store.ts`
|
|
17
|
+
|
|
18
|
+
Architecture contract: `src/tasks/architecture-contract.ts`
|
|
19
|
+
Mutation entrypoint service: `src/tasks/service.ts`
|
|
20
|
+
|
|
21
|
+
- Synchronous in-memory writes
|
|
22
|
+
- Event emission on mutations (`created`, `updated`, `closed`, `labeled`)
|
|
23
|
+
- Optional JSONL persistence (`tasks.jsonl`)
|
|
24
|
+
|
|
25
|
+
## Discord Sync
|
|
26
|
+
|
|
27
|
+
Canonical runtime sync implementation lives in `src/tasks/*`:
|
|
28
|
+
|
|
29
|
+
- `src/tasks/task-sync-engine.ts`
|
|
30
|
+
- `src/tasks/task-sync-pipeline.ts`
|
|
31
|
+
- `src/tasks/task-sync-apply-plan.ts`
|
|
32
|
+
- `src/tasks/task-sync-reconcile-plan.ts`
|
|
33
|
+
- `src/tasks/task-sync-apply-types.ts`
|
|
34
|
+
- `src/tasks/task-sync-phase-apply.ts`
|
|
35
|
+
- `src/tasks/task-sync-reconcile.ts`
|
|
36
|
+
- `src/tasks/sync-coordinator.ts`
|
|
37
|
+
- `src/tasks/sync-coordinator-metrics.ts`
|
|
38
|
+
- `src/tasks/sync-coordinator-retries.ts`
|
|
39
|
+
- `src/tasks/thread-helpers.ts`
|
|
40
|
+
- `src/tasks/thread-forum-ops.ts`
|
|
41
|
+
- `src/tasks/thread-lifecycle-ops.ts`
|
|
42
|
+
- `src/tasks/thread-ops.ts` (facade)
|
|
43
|
+
- `src/tasks/tag-map.ts`
|
|
44
|
+
- `src/tasks/thread-cache.ts`
|
|
45
|
+
- `src/tasks/forum-guard.ts`
|
|
46
|
+
|
|
47
|
+
Legacy runtime compatibility shims under `src/beads/` have been removed.
|
|
48
|
+
|
|
49
|
+
Primary action trigger is `taskSync` via `src/tasks/task-action-executor.ts`.
|
|
50
|
+
|
|
51
|
+
## Auto-Tagging
|
|
52
|
+
|
|
53
|
+
Auto-tagging runs through `src/tasks/auto-tag.ts` and is controlled by the tasks env surface:
|
|
54
|
+
|
|
55
|
+
- `DISCOCLAW_TASKS_AUTO_TAG`
|
|
56
|
+
- `DISCOCLAW_TASKS_AUTO_TAG_MODEL`
|
|
57
|
+
|
|
58
|
+
## Config Surface
|
|
59
|
+
|
|
60
|
+
Primary names:
|
|
61
|
+
|
|
62
|
+
- `DISCOCLAW_TASKS_ENABLED`
|
|
63
|
+
- `DISCOCLAW_TASKS_FORUM`
|
|
64
|
+
- `DISCOCLAW_TASKS_CWD`
|
|
65
|
+
- `DISCOCLAW_TASKS_TAG_MAP`
|
|
66
|
+
- `DISCOCLAW_TASKS_MENTION_USER`
|
|
67
|
+
- `DISCOCLAW_TASKS_SIDEBAR`
|
|
68
|
+
- `DISCOCLAW_TASKS_AUTO_TAG`
|
|
69
|
+
- `DISCOCLAW_TASKS_AUTO_TAG_MODEL`
|
|
70
|
+
- `DISCOCLAW_TASKS_SYNC_SKIP_PHASE5`
|
|
71
|
+
- `DISCOCLAW_TASKS_PREFIX`
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# tools.md — Tool Capabilities
|
|
2
|
+
|
|
3
|
+
Canonical reference for tools available to the discoclaw agent.
|
|
4
|
+
`agent-browser` is optional — it requires a separate `npm install -g @anthropic/agent-browser` and is not bundled with discoclaw.
|
|
5
|
+
|
|
6
|
+
## WebFetch / Browser Escalation Ladder
|
|
7
|
+
|
|
8
|
+
Use the lightest tool that works. Escalate only when a lighter level fails.
|
|
9
|
+
|
|
10
|
+
1. **WebFetch (read-only)** — Built-in. Fetches raw page content. No JS rendering, no interaction. Try this first for any URL.
|
|
11
|
+
2. **Playwright headless** — `agent-browser` launches a fresh, isolated browser with no saved state. Good for JS-rendered pages, simple form fills, screenshots. No extensions, no cookies from real sessions.
|
|
12
|
+
3. **Playwright headed** — Same as above but with a visible browser window. Useful for debugging or when a site blocks headless user agents.
|
|
13
|
+
4. **CDP headless (connect)** — Connects to an already-running Chrome instance via Chrome DevTools Protocol. Persistent state: logged-in sessions, cookies, extensions. Use when Playwright can't get past auth walls or bot detection.
|
|
14
|
+
5. **CDP headed (connect)** — Same as CDP headless but with a visible window. Use for initial login flows where you need to watch what's happening, then switch to CDP headless for ongoing automation.
|
|
15
|
+
|
|
16
|
+
Key distinction: Playwright = fresh/isolated (no persistent state). CDP = persistent (real browser session with real cookies and extensions).
|
|
17
|
+
|
|
18
|
+
## agent-browser Commands
|
|
19
|
+
|
|
20
|
+
These are `agent-browser`-specific commands, not generic browser automation.
|
|
21
|
+
|
|
22
|
+
| Command | Purpose |
|
|
23
|
+
|---------|---------|
|
|
24
|
+
| `navigate` | Go to a URL |
|
|
25
|
+
| `snapshot` | Get an accessibility snapshot of the current page |
|
|
26
|
+
| `interact` | Click, fill, select, check/uncheck elements |
|
|
27
|
+
| `keyboard` | Type text, press keys, keyboard shortcuts |
|
|
28
|
+
| `scroll` | Scroll the page or a specific element |
|
|
29
|
+
| `read` | Extract text content from elements |
|
|
30
|
+
| `wait` | Wait for elements, navigation, or a timeout |
|
|
31
|
+
| `capture` | Take a screenshot of the page or an element |
|
|
32
|
+
|
|
33
|
+
## Playwright Modes
|
|
34
|
+
|
|
35
|
+
- **Headless (default):** No visible browser window. Faster, works on servers without a display.
|
|
36
|
+
- **Headed:** Visible browser window. Requires a display (or Xvfb). Use when debugging or when headless is detected/blocked.
|
|
37
|
+
|
|
38
|
+
## CDP Connect
|
|
39
|
+
|
|
40
|
+
Use CDP when you need persistent browser state that Playwright can't provide.
|
|
41
|
+
|
|
42
|
+
**When to use:**
|
|
43
|
+
- Auth walls that require a real logged-in session
|
|
44
|
+
- Bot detection that blocks Playwright's browser fingerprint
|
|
45
|
+
- Sites that require specific extensions
|
|
46
|
+
- Reusing an existing session (e.g., already logged into a service)
|
|
47
|
+
|
|
48
|
+
**Setup — headed (for initial login):**
|
|
49
|
+
|
|
50
|
+
Launch Chrome with remote debugging enabled. The binary name varies by platform (`google-chrome`, `chromium`, `chrome`, `/Applications/Google Chrome.app/Contents/MacOS/Google Chrome`, etc.).
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-cdp-profile
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Use a dedicated profile directory (`--user-data-dir`) to avoid clobbering your daily browser profile.
|
|
57
|
+
|
|
58
|
+
**Setup — headless (for automation after login):**
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
google-chrome --headless --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-cdp-profile
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Workflow:**
|
|
65
|
+
1. Launch Chrome headed with `--remote-debugging-port=9222`
|
|
66
|
+
2. Log in manually or let the agent navigate the login flow
|
|
67
|
+
3. Verify the connection: `agent-browser` connects to `http://localhost:9222`
|
|
68
|
+
4. For ongoing automation, relaunch headless with the same `--user-data-dir`
|
|
69
|
+
5. Shut down Chrome when done — don't leave debug ports open
|
|
70
|
+
|
|
71
|
+
## Security Guardrails
|
|
72
|
+
|
|
73
|
+
- **CDP is ask-first.** Never connect to a real browser session without explicit user consent. CDP exposes the user's live cookies, passwords, and session tokens.
|
|
74
|
+
- **No browsing internal networks.** Don't navigate to `localhost`, `127.0.0.1`, `::1`, or RFC 1918 addresses (`10.*`, `172.16-31.*`, `192.168.*`) — except the CDP connect port itself (`localhost:9222`).
|
|
75
|
+
- **No saving auth state to tracked locations.** Cookies, tokens, screenshots with sensitive data, and browser profiles must not be saved anywhere that gets committed or pushed. Use `/tmp/` or the workspace's gitignored directories.
|
package/.env.example
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# ============================================================
|
|
2
|
+
# Discoclaw — Quick Start Configuration
|
|
3
|
+
# ============================================================
|
|
4
|
+
# Copy this file to .env and fill in the REQUIRED values.
|
|
5
|
+
# Primary guided setup: run `discoclaw init` (global install).
|
|
6
|
+
# From source: run `pnpm setup` for guided interactive configuration.
|
|
7
|
+
# For all ~90 options, see .env.example.full
|
|
8
|
+
# ============================================================
|
|
9
|
+
|
|
10
|
+
# ----------------------------------------------------------
|
|
11
|
+
# REQUIRED — the bot won't start without these
|
|
12
|
+
# ----------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
# Your Discord bot token (from https://discord.com/developers/applications)
|
|
15
|
+
# Important: Enable Message Content Intent in Developer Portal
|
|
16
|
+
# (Bot → Privileged Gateway Intents) or the bot receives empty messages.
|
|
17
|
+
DISCORD_TOKEN=
|
|
18
|
+
|
|
19
|
+
# Comma-separated Discord user IDs allowed to talk to the bot.
|
|
20
|
+
# Empty = nobody can use it (fail-closed).
|
|
21
|
+
DISCORD_ALLOW_USER_IDS=
|
|
22
|
+
|
|
23
|
+
# Tasks forum channel ID (required when DISCOCLAW_TASKS_ENABLED=1; default on).
|
|
24
|
+
DISCOCLAW_TASKS_FORUM=
|
|
25
|
+
|
|
26
|
+
# Automations forum channel ID (cron subsystem; required when DISCOCLAW_CRON_ENABLED=1; default on).
|
|
27
|
+
DISCOCLAW_CRON_FORUM=
|
|
28
|
+
|
|
29
|
+
# ----------------------------------------------------------
|
|
30
|
+
# CORE — most users will want to review these
|
|
31
|
+
# ----------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
# Guild (server) ID — used for task sync and system channel bootstrap.
|
|
34
|
+
DISCORD_GUILD_ID=
|
|
35
|
+
|
|
36
|
+
# Where the Claude CLI runs (its working directory).
|
|
37
|
+
# Default: ./workspace (or $DISCOCLAW_DATA_DIR/workspace if DATA_DIR is set)
|
|
38
|
+
#WORKSPACE_CWD=
|
|
39
|
+
|
|
40
|
+
# Primary runtime adapter: claude | gemini | codex | openai | openrouter
|
|
41
|
+
# Notes:
|
|
42
|
+
# - openai requires OPENAI_API_KEY
|
|
43
|
+
# - claude requires a working Claude CLI
|
|
44
|
+
# - gemini requires the Gemini CLI (GEMINI_BIN)
|
|
45
|
+
#PRIMARY_RUNTIME=claude
|
|
46
|
+
# If PRIMARY_RUNTIME=codex and you want full-access mode (no approvals/sandbox):
|
|
47
|
+
#CODEX_DANGEROUSLY_BYPASS_APPROVALS_AND_SANDBOX=1
|
|
48
|
+
# Optional: isolate Codex state/sessions from ~/.codex (helps avoid stale rollout DB issues):
|
|
49
|
+
#CODEX_HOME=/absolute/path/to/.codex-home-discoclaw
|
|
50
|
+
# Disable Codex session persistence/resume (workaround for session DB issues):
|
|
51
|
+
#CODEX_DISABLE_SESSIONS=1
|
|
52
|
+
|
|
53
|
+
# Model tier: fast | capable (provider-agnostic).
|
|
54
|
+
# Concrete model names (e.g. opus, sonnet, gpt-4o) are still accepted as passthrough.
|
|
55
|
+
#RUNTIME_MODEL=capable
|
|
56
|
+
|
|
57
|
+
# Output format for the Claude CLI. stream-json gives smoother streaming.
|
|
58
|
+
#CLAUDE_OUTPUT_FORMAT=stream-json
|
|
59
|
+
|
|
60
|
+
# Allow Claude to run without permission prompts. This is what makes
|
|
61
|
+
# headless/Discord operation possible — the Discord allowlist above
|
|
62
|
+
# is the security boundary instead.
|
|
63
|
+
#CLAUDE_DANGEROUSLY_SKIP_PERMISSIONS=1
|
|
64
|
+
|
|
65
|
+
# Gemini CLI adapter
|
|
66
|
+
# Path to the Gemini CLI binary (default: gemini).
|
|
67
|
+
#GEMINI_BIN=gemini
|
|
68
|
+
# Default model for the Gemini CLI adapter.
|
|
69
|
+
#GEMINI_MODEL=gemini-2.5-pro
|
|
70
|
+
|
|
71
|
+
# --- OpenRouter adapter ---
|
|
72
|
+
#OPENROUTER_API_KEY=
|
|
73
|
+
#OPENROUTER_BASE_URL=https://openrouter.ai/api/v1
|
|
74
|
+
#OPENROUTER_MODEL=anthropic/claude-sonnet-4
|
|
75
|
+
|
|
76
|
+
# Log level: trace | debug | info | warn | error | fatal
|
|
77
|
+
#LOG_LEVEL=info
|
|
78
|
+
|
|
79
|
+
# Override the default platform-detected restart command used by !restart and
|
|
80
|
+
# !update apply. Useful for custom setups (e.g. Docker, non-standard service
|
|
81
|
+
# managers, or running under a different user). If unset, the command is
|
|
82
|
+
# auto-selected: systemctl --user on Linux, launchctl on macOS.
|
|
83
|
+
#DC_RESTART_CMD=
|
|
84
|
+
|
|
85
|
+
# ----------------------------------------------------------
|
|
86
|
+
# For all ~90 options (subsystems, actions, memory, identity,
|
|
87
|
+
# observability, advanced/debug), see .env.example.full
|
|
88
|
+
# ----------------------------------------------------------
|