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.
Files changed (393) hide show
  1. package/.context/README.md +42 -0
  2. package/.context/architecture.md +58 -0
  3. package/.context/bot-setup.md +24 -0
  4. package/.context/dev.md +230 -0
  5. package/.context/discord.md +144 -0
  6. package/.context/memory.md +257 -0
  7. package/.context/ops.md +59 -0
  8. package/.context/pa-safety.md +47 -0
  9. package/.context/pa.md +118 -0
  10. package/.context/project.md +43 -0
  11. package/.context/runtime.md +253 -0
  12. package/.context/tasks.md +71 -0
  13. package/.context/tools.md +75 -0
  14. package/.env.example +88 -0
  15. package/.env.example.full +378 -0
  16. package/LICENSE +21 -0
  17. package/README.md +220 -0
  18. package/dist/beads/auto-tag.js +2 -0
  19. package/dist/beads/auto-tag.test.js +62 -0
  20. package/dist/beads/bd-cli.js +9 -0
  21. package/dist/beads/bd-cli.test.js +495 -0
  22. package/dist/beads/bead-hooks-cli.js +149 -0
  23. package/dist/beads/bead-sync-cli.js +5 -0
  24. package/dist/beads/bead-sync-cli.test.js +72 -0
  25. package/dist/beads/bead-sync-coordinator.js +4 -0
  26. package/dist/beads/bead-sync-coordinator.test.js +239 -0
  27. package/dist/beads/bead-sync-watcher.js +2 -0
  28. package/dist/beads/bead-sync-watcher.test.js +96 -0
  29. package/dist/beads/bead-sync.js +7 -0
  30. package/dist/beads/bead-sync.test.js +876 -0
  31. package/dist/beads/bead-thread-cache.js +8 -0
  32. package/dist/beads/bead-thread-cache.test.js +91 -0
  33. package/dist/beads/discord-sync.js +18 -0
  34. package/dist/beads/discord-sync.test.js +782 -0
  35. package/dist/beads/find-bead-by-thread.test.js +36 -0
  36. package/dist/beads/forum-guard.js +2 -0
  37. package/dist/beads/forum-guard.test.js +204 -0
  38. package/dist/beads/initialize.js +3 -0
  39. package/dist/beads/initialize.test.js +304 -0
  40. package/dist/beads/types.js +10 -0
  41. package/dist/cli/daemon-installer.js +225 -0
  42. package/dist/cli/daemon-installer.test.js +289 -0
  43. package/dist/cli/index.js +42 -0
  44. package/dist/cli/init-wizard.js +374 -0
  45. package/dist/cli/init-wizard.test.js +191 -0
  46. package/dist/config.js +385 -0
  47. package/dist/config.test.js +589 -0
  48. package/dist/cron/auto-tag.js +100 -0
  49. package/dist/cron/auto-tag.test.js +91 -0
  50. package/dist/cron/cadence.js +74 -0
  51. package/dist/cron/cadence.test.js +53 -0
  52. package/dist/cron/cron-sync-coordinator.js +66 -0
  53. package/dist/cron/cron-sync-coordinator.test.js +118 -0
  54. package/dist/cron/cron-sync.js +165 -0
  55. package/dist/cron/cron-sync.test.js +228 -0
  56. package/dist/cron/cron-tag-map-watcher.js +128 -0
  57. package/dist/cron/cron-tag-map-watcher.test.js +155 -0
  58. package/dist/cron/default-timezone.js +23 -0
  59. package/dist/cron/default-timezone.test.js +30 -0
  60. package/dist/cron/discord-sync.js +205 -0
  61. package/dist/cron/discord-sync.test.js +353 -0
  62. package/dist/cron/executor.js +303 -0
  63. package/dist/cron/executor.test.js +614 -0
  64. package/dist/cron/forum-sync.js +347 -0
  65. package/dist/cron/forum-sync.test.js +539 -0
  66. package/dist/cron/job-lock.js +164 -0
  67. package/dist/cron/job-lock.test.js +178 -0
  68. package/dist/cron/parser.js +68 -0
  69. package/dist/cron/parser.test.js +115 -0
  70. package/dist/cron/run-control.js +24 -0
  71. package/dist/cron/run-control.test.js +27 -0
  72. package/dist/cron/run-stats.js +265 -0
  73. package/dist/cron/run-stats.test.js +160 -0
  74. package/dist/cron/scheduler.js +97 -0
  75. package/dist/cron/scheduler.test.js +112 -0
  76. package/dist/cron/tag-map.js +47 -0
  77. package/dist/cron/tag-map.test.js +64 -0
  78. package/dist/cron/types.js +1 -0
  79. package/dist/discoclaw-plan-format.test.js +137 -0
  80. package/dist/discoclaw-recipe-format.test.js +137 -0
  81. package/dist/discord/abort-registry.js +70 -0
  82. package/dist/discord/action-categories.js +36 -0
  83. package/dist/discord/action-types.js +1 -0
  84. package/dist/discord/action-utils.js +58 -0
  85. package/dist/discord/action-utils.test.js +58 -0
  86. package/dist/discord/actions-beads.js +1 -0
  87. package/dist/discord/actions-beads.test.js +372 -0
  88. package/dist/discord/actions-bot-profile.js +107 -0
  89. package/dist/discord/actions-bot-profile.test.js +138 -0
  90. package/dist/discord/actions-channels.js +427 -0
  91. package/dist/discord/actions-channels.test.js +697 -0
  92. package/dist/discord/actions-config.js +173 -0
  93. package/dist/discord/actions-config.test.js +322 -0
  94. package/dist/discord/actions-crons.js +586 -0
  95. package/dist/discord/actions-crons.test.js +499 -0
  96. package/dist/discord/actions-defer.js +60 -0
  97. package/dist/discord/actions-defer.test.js +134 -0
  98. package/dist/discord/actions-forge.js +134 -0
  99. package/dist/discord/actions-forge.test.js +206 -0
  100. package/dist/discord/actions-guild.js +301 -0
  101. package/dist/discord/actions-guild.test.js +386 -0
  102. package/dist/discord/actions-memory.js +106 -0
  103. package/dist/discord/actions-memory.test.js +248 -0
  104. package/dist/discord/actions-messaging.js +401 -0
  105. package/dist/discord/actions-messaging.test.js +738 -0
  106. package/dist/discord/actions-moderation.js +65 -0
  107. package/dist/discord/actions-moderation.test.js +88 -0
  108. package/dist/discord/actions-plan.js +445 -0
  109. package/dist/discord/actions-plan.test.js +610 -0
  110. package/dist/discord/actions-poll.js +38 -0
  111. package/dist/discord/actions-poll.test.js +93 -0
  112. package/dist/discord/actions-tasks.js +3 -0
  113. package/dist/discord/actions-tasks.test.js +418 -0
  114. package/dist/discord/actions.js +600 -0
  115. package/dist/discord/actions.test.js +522 -0
  116. package/dist/discord/allowed-mentions.js +3 -0
  117. package/dist/discord/allowed-mentions.test.js +17 -0
  118. package/dist/discord/allowlist.js +29 -0
  119. package/dist/discord/allowlist.test.js +24 -0
  120. package/dist/discord/audit-handler.js +191 -0
  121. package/dist/discord/audit-handler.test.js +361 -0
  122. package/dist/discord/bot.js +141 -0
  123. package/dist/discord/channel-context.js +181 -0
  124. package/dist/discord/defer-scheduler.js +45 -0
  125. package/dist/discord/destructive-confirmation.js +128 -0
  126. package/dist/discord/destructive-confirmation.test.js +49 -0
  127. package/dist/discord/discord-plan-auto-implement.test.js +18 -0
  128. package/dist/discord/durable-memory.js +145 -0
  129. package/dist/discord/durable-memory.test.js +281 -0
  130. package/dist/discord/durable-write-queue.js +4 -0
  131. package/dist/discord/file-download.js +308 -0
  132. package/dist/discord/file-download.test.js +303 -0
  133. package/dist/discord/forge-audit-verdict.js +140 -0
  134. package/dist/discord/forge-auto-implement.js +80 -0
  135. package/dist/discord/forge-auto-implement.test.js +110 -0
  136. package/dist/discord/forge-commands.js +698 -0
  137. package/dist/discord/forge-commands.test.js +1606 -0
  138. package/dist/discord/forge-plan-registry.js +68 -0
  139. package/dist/discord/forge-plan-registry.test.js +127 -0
  140. package/dist/discord/forum-count-sync.js +130 -0
  141. package/dist/discord/forum-count-sync.test.js +200 -0
  142. package/dist/discord/health-command.js +98 -0
  143. package/dist/discord/health-command.test.js +195 -0
  144. package/dist/discord/help-command.js +22 -0
  145. package/dist/discord/help-command.test.js +49 -0
  146. package/dist/discord/image-download.js +201 -0
  147. package/dist/discord/image-download.test.js +499 -0
  148. package/dist/discord/inflight-replies.js +228 -0
  149. package/dist/discord/inflight-replies.test.js +295 -0
  150. package/dist/discord/json-extract.js +110 -0
  151. package/dist/discord/keyed-queue.js +22 -0
  152. package/dist/discord/memory-commands.js +85 -0
  153. package/dist/discord/memory-commands.test.js +159 -0
  154. package/dist/discord/memory-timing.integration.test.js +159 -0
  155. package/dist/discord/message-coordinator.js +2347 -0
  156. package/dist/discord/message-coordinator.onboarding.test.js +183 -0
  157. package/dist/discord/message-coordinator.plan-run.test.js +264 -0
  158. package/dist/discord/message-history.js +53 -0
  159. package/dist/discord/message-history.test.js +95 -0
  160. package/dist/discord/models-command.js +59 -0
  161. package/dist/discord/models-command.test.js +150 -0
  162. package/dist/discord/nickname.test.js +76 -0
  163. package/dist/discord/onboarding-completion.js +55 -0
  164. package/dist/discord/onboarding-completion.test.js +176 -0
  165. package/dist/discord/output-common.js +178 -0
  166. package/dist/discord/output-common.test.js +198 -0
  167. package/dist/discord/output-utils.js +156 -0
  168. package/dist/discord/parse-identity-name.test.js +129 -0
  169. package/dist/discord/plan-commands.js +612 -0
  170. package/dist/discord/plan-commands.test.js +1622 -0
  171. package/dist/discord/plan-manager.js +1491 -0
  172. package/dist/discord/plan-manager.test.js +2380 -0
  173. package/dist/discord/plan-parser.js +110 -0
  174. package/dist/discord/plan-parser.test.js +63 -0
  175. package/dist/discord/plan-run-phase-start.js +20 -0
  176. package/dist/discord/plan-run-phase-start.test.js +29 -0
  177. package/dist/discord/platform-message.js +45 -0
  178. package/dist/discord/platform-message.test.js +110 -0
  179. package/dist/discord/prompt-common.js +240 -0
  180. package/dist/discord/prompt-common.test.js +423 -0
  181. package/dist/discord/reaction-handler.js +691 -0
  182. package/dist/discord/reaction-handler.test.js +1574 -0
  183. package/dist/discord/reaction-prompts.js +118 -0
  184. package/dist/discord/reaction-prompts.test.js +253 -0
  185. package/dist/discord/reply-reference.js +66 -0
  186. package/dist/discord/reply-reference.test.js +125 -0
  187. package/dist/discord/restart-command.js +143 -0
  188. package/dist/discord/restart-command.test.js +196 -0
  189. package/dist/discord/runtime-utils.js +43 -0
  190. package/dist/discord/runtime-utils.test.js +112 -0
  191. package/dist/discord/session-key.js +7 -0
  192. package/dist/discord/session-key.test.js +13 -0
  193. package/dist/discord/shortterm-memory.js +166 -0
  194. package/dist/discord/shortterm-memory.test.js +345 -0
  195. package/dist/discord/shutdown-context.js +122 -0
  196. package/dist/discord/shutdown-context.test.js +279 -0
  197. package/dist/discord/startup-profile.test.js +214 -0
  198. package/dist/discord/status-channel.js +190 -0
  199. package/dist/discord/status-channel.test.js +282 -0
  200. package/dist/discord/status-command.js +206 -0
  201. package/dist/discord/status-command.test.js +341 -0
  202. package/dist/discord/streaming-progress.js +107 -0
  203. package/dist/discord/streaming-progress.test.js +93 -0
  204. package/dist/discord/summarizer.js +89 -0
  205. package/dist/discord/summarizer.test.js +245 -0
  206. package/dist/discord/system-bootstrap.js +396 -0
  207. package/dist/discord/system-bootstrap.test.js +724 -0
  208. package/dist/discord/thread-context.js +169 -0
  209. package/dist/discord/thread-context.test.js +386 -0
  210. package/dist/discord/tool-aware-queue.js +116 -0
  211. package/dist/discord/tool-aware-queue.test.js +180 -0
  212. package/dist/discord/update-command.js +127 -0
  213. package/dist/discord/update-command.test.js +275 -0
  214. package/dist/discord/user-errors.js +40 -0
  215. package/dist/discord/user-errors.test.js +31 -0
  216. package/dist/discord/user-turn-to-durable.js +111 -0
  217. package/dist/discord/user-turn-to-durable.test.js +273 -0
  218. package/dist/discord-followup.test.js +677 -0
  219. package/dist/discord.channel-context.test.js +95 -0
  220. package/dist/discord.fail-closed.test.js +199 -0
  221. package/dist/discord.health-command.integration.test.js +140 -0
  222. package/dist/discord.js +190 -0
  223. package/dist/discord.prompt-context.test.js +1431 -0
  224. package/dist/discord.render.test.js +621 -0
  225. package/dist/discord.status-wiring.test.js +187 -0
  226. package/dist/engine/claudeCli.js +137 -0
  227. package/dist/engine/types.js +1 -0
  228. package/dist/group-queue.js +25 -0
  229. package/dist/health/credential-check.js +175 -0
  230. package/dist/health/credential-check.test.js +401 -0
  231. package/dist/health/startup-healing.js +139 -0
  232. package/dist/health/startup-healing.test.js +298 -0
  233. package/dist/identity.js +36 -0
  234. package/dist/index.js +1378 -0
  235. package/dist/logging/logger-like.js +1 -0
  236. package/dist/observability/memory-sampler.js +51 -0
  237. package/dist/observability/memory-sampler.test.js +93 -0
  238. package/dist/observability/metrics.js +88 -0
  239. package/dist/observability/metrics.test.js +42 -0
  240. package/dist/onboarding/onboarding-flow.js +246 -0
  241. package/dist/onboarding/onboarding-flow.test.js +238 -0
  242. package/dist/onboarding/onboarding-writer.js +102 -0
  243. package/dist/onboarding/onboarding-writer.test.js +143 -0
  244. package/dist/pidlock.js +187 -0
  245. package/dist/pidlock.test.js +128 -0
  246. package/dist/pipeline/engine.js +206 -0
  247. package/dist/pipeline/engine.test.js +771 -0
  248. package/dist/root-policy.js +21 -0
  249. package/dist/root-policy.test.js +55 -0
  250. package/dist/runtime/claude-code-cli.js +35 -0
  251. package/dist/runtime/claude-code-cli.test.js +1199 -0
  252. package/dist/runtime/cli-adapter.js +584 -0
  253. package/dist/runtime/cli-output-parsers.js +108 -0
  254. package/dist/runtime/cli-shared.js +96 -0
  255. package/dist/runtime/cli-shared.test.js +104 -0
  256. package/dist/runtime/cli-strategy.js +6 -0
  257. package/dist/runtime/codex-cli.js +16 -0
  258. package/dist/runtime/codex-cli.test.js +862 -0
  259. package/dist/runtime/concurrency-limit.js +80 -0
  260. package/dist/runtime/concurrency-limit.test.js +137 -0
  261. package/dist/runtime/gemini-cli.js +16 -0
  262. package/dist/runtime/gemini-cli.test.js +413 -0
  263. package/dist/runtime/long-running-process.js +415 -0
  264. package/dist/runtime/long-running-process.test.js +318 -0
  265. package/dist/runtime/model-smoke-helpers.js +160 -0
  266. package/dist/runtime/model-smoke.test.js +194 -0
  267. package/dist/runtime/model-tiers.js +33 -0
  268. package/dist/runtime/model-tiers.test.js +65 -0
  269. package/dist/runtime/openai-auth.js +151 -0
  270. package/dist/runtime/openai-auth.test.js +361 -0
  271. package/dist/runtime/openai-compat.js +178 -0
  272. package/dist/runtime/openai-compat.test.js +449 -0
  273. package/dist/runtime/process-pool.js +93 -0
  274. package/dist/runtime/process-pool.test.js +148 -0
  275. package/dist/runtime/registry.js +15 -0
  276. package/dist/runtime/registry.test.js +47 -0
  277. package/dist/runtime/session-scanner.js +186 -0
  278. package/dist/runtime/session-scanner.test.js +257 -0
  279. package/dist/runtime/strategies/claude-strategy.js +193 -0
  280. package/dist/runtime/strategies/codex-strategy.js +161 -0
  281. package/dist/runtime/strategies/gemini-strategy.js +64 -0
  282. package/dist/runtime/strategies/template-strategy.js +85 -0
  283. package/dist/runtime/tool-capabilities.js +27 -0
  284. package/dist/runtime/tool-capabilities.test.js +24 -0
  285. package/dist/runtime/tool-labels.js +48 -0
  286. package/dist/runtime/types.js +2 -0
  287. package/dist/sessionManager.js +47 -0
  288. package/dist/sessions.js +18 -0
  289. package/dist/tasks/architecture-contract.js +33 -0
  290. package/dist/tasks/architecture-contract.test.js +90 -0
  291. package/dist/tasks/auto-tag.js +50 -0
  292. package/dist/tasks/auto-tag.test.js +64 -0
  293. package/dist/tasks/bd-cli.js +164 -0
  294. package/dist/tasks/bd-cli.test.js +359 -0
  295. package/dist/tasks/bead-sync.js +1 -0
  296. package/dist/tasks/context-summary.js +27 -0
  297. package/dist/tasks/discord-sync.js +3 -0
  298. package/dist/tasks/discord-sync.test.js +685 -0
  299. package/dist/tasks/discord-types.js +4 -0
  300. package/dist/tasks/find-task-by-thread.test.js +36 -0
  301. package/dist/tasks/forum-guard.js +81 -0
  302. package/dist/tasks/forum-guard.test.js +192 -0
  303. package/dist/tasks/initialize.js +77 -0
  304. package/dist/tasks/initialize.test.js +263 -0
  305. package/dist/tasks/logger-types.js +1 -0
  306. package/dist/tasks/metrics-types.js +3 -0
  307. package/dist/tasks/migrate.js +33 -0
  308. package/dist/tasks/migrate.test.js +156 -0
  309. package/dist/tasks/path-defaults.js +67 -0
  310. package/dist/tasks/path-defaults.test.js +73 -0
  311. package/dist/tasks/runtime-types.js +1 -0
  312. package/dist/tasks/service.js +33 -0
  313. package/dist/tasks/service.test.js +51 -0
  314. package/dist/tasks/store.js +238 -0
  315. package/dist/tasks/store.test.js +417 -0
  316. package/dist/tasks/sync-context.js +1 -0
  317. package/dist/tasks/sync-contract.js +24 -0
  318. package/dist/tasks/sync-contract.test.js +25 -0
  319. package/dist/tasks/sync-coordinator-metrics.js +41 -0
  320. package/dist/tasks/sync-coordinator-retries.js +71 -0
  321. package/dist/tasks/sync-coordinator.js +96 -0
  322. package/dist/tasks/sync-coordinator.test.js +501 -0
  323. package/dist/tasks/sync-types.js +1 -0
  324. package/dist/tasks/sync-watcher.js +27 -0
  325. package/dist/tasks/sync-watcher.test.js +92 -0
  326. package/dist/tasks/tag-map.js +36 -0
  327. package/dist/tasks/tag-map.test.js +54 -0
  328. package/dist/tasks/task-action-contract.js +16 -0
  329. package/dist/tasks/task-action-contract.test.js +16 -0
  330. package/dist/tasks/task-action-executor.js +18 -0
  331. package/dist/tasks/task-action-executor.test.js +420 -0
  332. package/dist/tasks/task-action-mutation-helpers.js +17 -0
  333. package/dist/tasks/task-action-mutations.js +151 -0
  334. package/dist/tasks/task-action-prompt.js +62 -0
  335. package/dist/tasks/task-action-read-ops.js +73 -0
  336. package/dist/tasks/task-action-runner-types.js +1 -0
  337. package/dist/tasks/task-action-thread-sync.js +82 -0
  338. package/dist/tasks/task-actions.js +3 -0
  339. package/dist/tasks/task-cli.js +227 -0
  340. package/dist/tasks/task-context.js +1 -0
  341. package/dist/tasks/task-lifecycle.js +46 -0
  342. package/dist/tasks/task-lifecycle.test.js +35 -0
  343. package/dist/tasks/task-sync-apply-plan.js +95 -0
  344. package/dist/tasks/task-sync-apply-types.js +12 -0
  345. package/dist/tasks/task-sync-apply.js +319 -0
  346. package/dist/tasks/task-sync-cli.js +89 -0
  347. package/dist/tasks/task-sync-cli.test.js +70 -0
  348. package/dist/tasks/task-sync-engine.js +88 -0
  349. package/dist/tasks/task-sync-engine.test.js +934 -0
  350. package/dist/tasks/task-sync-phase-apply.js +171 -0
  351. package/dist/tasks/task-sync-pipeline.js +2 -0
  352. package/dist/tasks/task-sync-pipeline.test.js +265 -0
  353. package/dist/tasks/task-sync-reconcile-plan.js +182 -0
  354. package/dist/tasks/task-sync-reconcile.js +144 -0
  355. package/dist/tasks/task-sync.js +56 -0
  356. package/dist/tasks/task-sync.test.js +86 -0
  357. package/dist/tasks/thread-cache.js +42 -0
  358. package/dist/tasks/thread-cache.test.js +89 -0
  359. package/dist/tasks/thread-contracts.test.js +711 -0
  360. package/dist/tasks/thread-forum-ops.js +68 -0
  361. package/dist/tasks/thread-helpers.js +86 -0
  362. package/dist/tasks/thread-helpers.test.js +33 -0
  363. package/dist/tasks/thread-lifecycle-ops.js +144 -0
  364. package/dist/tasks/thread-ops-shared.js +21 -0
  365. package/dist/tasks/thread-ops.js +2 -0
  366. package/dist/tasks/types.js +20 -0
  367. package/dist/tasks/types.test.js +60 -0
  368. package/dist/test-setup.js +11 -0
  369. package/dist/test-setup.test.js +42 -0
  370. package/dist/transport/types.js +1 -0
  371. package/dist/validate.js +41 -0
  372. package/dist/validate.test.js +94 -0
  373. package/dist/version.js +15 -0
  374. package/dist/version.test.js +31 -0
  375. package/dist/webhook/server.js +199 -0
  376. package/dist/webhook/server.test.js +460 -0
  377. package/dist/workspace-bootstrap.js +135 -0
  378. package/dist/workspace-bootstrap.test.js +514 -0
  379. package/dist/workspace-permissions.js +134 -0
  380. package/dist/workspace-permissions.test.js +181 -0
  381. package/package.json +74 -0
  382. package/scripts/cron/cron-tag-map.json +9 -0
  383. package/scripts/tasks/tag-map.json +10 -0
  384. package/systemd/discoclaw.service +19 -0
  385. package/templates/recipes/integration.discoclaw-recipe.md +171 -0
  386. package/templates/workspace/AGENTS.md +217 -0
  387. package/templates/workspace/BOOTSTRAP.md +1 -0
  388. package/templates/workspace/HEARTBEAT.md +10 -0
  389. package/templates/workspace/IDENTITY.md +16 -0
  390. package/templates/workspace/MEMORY.md +24 -0
  391. package/templates/workspace/SOUL.md +52 -0
  392. package/templates/workspace/TOOLS.md +304 -0
  393. 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.
@@ -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.