mixdog 0.7.8 → 0.7.12

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 (63) hide show
  1. package/.claude-plugin/marketplace.json +5 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +40 -0
  4. package/README.md +198 -251
  5. package/bin/statusline-launcher.mjs +5 -1
  6. package/bin/statusline-lib.mjs +14 -6
  7. package/bin/statusline.mjs +14 -6
  8. package/hooks/lib/settings-loader.cjs +4 -3
  9. package/hooks/pre-tool-subagent.cjs +7 -2
  10. package/hooks/session-start.cjs +52 -24
  11. package/lib/mixdog-debug.cjs +163 -0
  12. package/native/prebuilt/linux-aarch64/mixdog-shim +0 -0
  13. package/native/prebuilt/linux-x86_64/mixdog-shim +0 -0
  14. package/native/prebuilt/macos-aarch64/mixdog-shim +0 -0
  15. package/native/prebuilt/macos-x86_64/mixdog-shim +0 -0
  16. package/native/prebuilt/windows-x86_64/mixdog-shim.exe +0 -0
  17. package/package.json +1 -1
  18. package/scripts/builtin-utils-smoke.mjs +14 -8
  19. package/scripts/bump.mjs +80 -0
  20. package/scripts/doctor.mjs +8 -3
  21. package/scripts/mutation-io-smoke.mjs +17 -1
  22. package/scripts/openai-oauth-catalog-smoke.mjs +53 -0
  23. package/scripts/permission-eval-smoke.mjs +18 -1
  24. package/scripts/statusline-launcher-smoke.mjs +2 -2
  25. package/scripts/webhook-selfheal-smoke.mjs +1 -3
  26. package/server-main.mjs +57 -3
  27. package/setup/config-merge.mjs +0 -1
  28. package/setup/install.mjs +241 -51
  29. package/setup/mixdog-cli.mjs +30 -3
  30. package/setup/setup-server.mjs +21 -33
  31. package/setup/setup.html +46 -11
  32. package/setup/tui.mjs +35 -316
  33. package/src/agent/orchestrator/config.mjs +0 -1
  34. package/src/agent/orchestrator/providers/anthropic-oauth.mjs +2 -5
  35. package/src/agent/orchestrator/providers/anthropic.mjs +243 -86
  36. package/src/agent/orchestrator/providers/gemini.mjs +386 -31
  37. package/src/agent/orchestrator/providers/grok-oauth.mjs +2 -5
  38. package/src/agent/orchestrator/providers/model-catalog.mjs +146 -13
  39. package/src/agent/orchestrator/providers/openai-compat-stream.mjs +366 -0
  40. package/src/agent/orchestrator/providers/openai-compat.mjs +74 -30
  41. package/src/agent/orchestrator/providers/openai-oauth-ws.mjs +2 -1
  42. package/src/agent/orchestrator/providers/openai-oauth.mjs +66 -13
  43. package/src/agent/orchestrator/providers/openai-ws.mjs +23 -0
  44. package/src/agent/orchestrator/session/manager.mjs +18 -4
  45. package/src/agent/orchestrator/stall-policy.mjs +6 -0
  46. package/src/agent/orchestrator/tools/builtin/native-edit-runner.mjs +29 -8
  47. package/src/agent/orchestrator/tools/graph-manifest.json +11 -11
  48. package/src/agent/orchestrator/tools/patch-manifest.json +11 -11
  49. package/src/channels/index.mjs +27 -8
  50. package/src/channels/lib/event-queue.mjs +24 -1
  51. package/src/channels/lib/hook-pipe-server.mjs +21 -8
  52. package/src/channels/lib/webhook.mjs +142 -20
  53. package/src/memory/lib/memory-cycle1.mjs +7 -3
  54. package/src/memory/lib/memory-recall-store.mjs +27 -10
  55. package/src/search/lib/backends/openai-oauth.mjs +6 -2
  56. package/src/search/lib/cache.mjs +55 -7
  57. package/src/shared/config.mjs +1 -1
  58. package/src/shared/llm/cost.mjs +2 -2
  59. package/src/shared/open-url.mjs +37 -0
  60. package/src/shared/seed.mjs +20 -3
  61. package/src/shared/user-data-guard.mjs +3 -1
  62. package/scripts/test-config-rmw-restore.mjs +0 -122
  63. package/setup/wizard.mjs +0 -696
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
4
4
   [![Runtime: bun](https://img.shields.io/badge/runtime-bun-black.svg)](https://bun.sh)
5
-  ![Version: 0.7.1](https://img.shields.io/badge/version-0.7.1-blue.svg)
5
+  [![npm](https://img.shields.io/npm/v/mixdog.svg)](https://www.npmjs.com/package/mixdog)
6
6
 
7
7
  All-in-one agent plugin for the Claude Code CLI — autonomous sub-agents,
8
8
  continuous memory, multi-provider routing, and syntax-aware code tools,
@@ -13,134 +13,102 @@ behind a single MCP server. Zero telemetry; all state under
13
13
  - **Continuous memory** — conversations, decisions, and work persist across sessions; a prebuilt Postgres + pgvector runtime is auto-downloaded and supervised, with no database to install
14
14
  - **Lower cost** — session-spanning prompt cache with per-provider / per-role token tracking
15
15
  - **Natural-language search** — web search and URL scraping in one tool
16
- - **Syntax-aware code tools** — AST-based symbol / reference / caller lookup, keyword→symbol search via `code_graph` `search`, and precise edits
16
+ - **Syntax-aware code tools** — AST-based symbol / reference / caller lookup, keyword→symbol search via `code_graph`, and precise edits
17
17
  - **Channels & automation** — Discord front-end, cron schedules, and inbound webhooks
18
18
 
19
- ## Contents
19
+ ## Quickstart
20
20
 
21
- - [Why mixdog](#why-mixdog)
22
- - [Install](#install) · [Quick start](#quick-start)
23
- - [Modules & tools](#modules--tools)
24
- - [Skills & commands](#skills--commands)
25
- - [Providers](#providers)
26
- - [Channels & automation](#channels--automation)
27
- - [Configuration](#configuration)
28
- - [Architecture & hooks](#architecture--hooks)
29
- - [Safety](#safety) · [Windows support](#windows-support)
30
- - [Contributing](#contributing) · [License](#license)
21
+ ```bash
22
+ npm i -g mixdog # install the `mixdog` command
23
+ mixdog # launch Claude Code — the first run walks you through setup (Claude·Codex·Grok login + plugin registration), then opens it
24
+ mixdog --dangerously-skip-permissions # launch with full permissions
25
+ ```
31
26
 
32
- ## Why mixdog
27
+ `npm i -g mixdog` adds the `mixdog` command to your PATH; `mixdog` then launches
28
+ Claude Code with mixdog pre-loaded. The first `mixdog` run walks you through
29
+ setup (logins + plugin registration) and launches the moment it finishes — no
30
+ second run needed. Any extra Claude flags pass straight through; the `claude`
31
+ CLI must be on your PATH. (If `mixdog` isn't recognized right after install,
32
+ open a new terminal and run it again.)
33
33
 
34
- Claude Code is powerful, but out of the box it forgets everything between
35
- sessions, treats every request as a fresh context, and has no built-in way
36
- to delegate to cheaper or specialised models. Cost runs high, answers
37
- drift, and long-lived projects lose the thread.
34
+ Anthropic OAuth (the Claude Code login) is the default provider, so
35
+ `bridge` / `recall` / `explore` / `memory` work immediately no API keys
36
+ required. Configure providers, presets, and role bindings in the in-browser
37
+ config UI open it any time with `/mixdog:config`. (The config server is
38
+ pre-warmed in the background each session, so the window opens instantly.)
38
39
 
39
- mixdog replaces that pattern with a single MCP server that bundles four
40
- cooperating modules — **agent**, **memory**, **search**, and **channels** —
41
- so your Claude Code session gains persistent memory, multi-provider
42
- sub-agents, web lookup, and an optional Discord front-end,
43
- all behind one install.
40
+ **Or install from inside Claude Code:**
44
41
 
45
- The goal is deployment-grade: plain ESM, zero build step for runtime
46
- code, documented local state, and every configuration surface readable
47
- as JSON you can diff.
48
-
49
- ## Install
42
+ ```
43
+ /plugin marketplace add trib-plugin/mixdog
44
+ /plugin install mixdog@trib-plugin
45
+ ```
50
46
 
51
- **From npm (terminal):**
47
+ <details>
48
+ <summary>Other entry points & what first boot does</summary>
52
49
 
53
50
  ```bash
54
- npx mixdog # register plugin + run the setup wizard
55
- mixdog install # same install + wizard (explicit subcommand)
56
- mixdog install --dry-run # preview install steps (no writes, prompts, or installs)
57
- npm i -g mixdog # then launch Claude Code with mixdog pre-loaded:
58
- mixdog # no args → same setup wizard as `npx mixdog`
59
- mixdog --version # other args (e.g. `setup`) → claude --dangerously-load-development-channels plugin:mixdog@trib-plugin …
60
- mixdog --dangerously-skip-permissions # extra Claude flags pass through
51
+ npx mixdog # one-off run without a global install (leaves no persistent `mixdog` command)
52
+ mixdog install # (re)run setup only: detect Claude CLI, register plugin, OAuth login, prewarm deps
53
+ mixdog install --dry-run # preview the steps (no writes, prompts, or installs)
54
+ mixdog install --demo # preview in an isolated sandbox (no writes to your real config)
61
55
  ```
62
56
 
63
- With no arguments, or with `install` (optional `--dry-run`), `mixdog` runs the
64
- install flow. Any other arguments start Claude Code with mixdog pre-loaded; the
65
- `claude` CLI must be on your PATH.
57
+ Claude Code clones the repo as a marketplace, runs `bun install --frozen-lockfile`,
58
+ and registers the MCP server in `.mcp.json`. On first boot, `scripts/bootstrap.mjs`
59
+ locates bun (system PATH plugin-local → `npm install --no-save bun` fallback),
60
+ installs runtime deps into the shared data dir, and seeds defaults under
61
+ `~/.claude/plugins/data/mixdog-trib-plugin/`. The memory runtime (a prebuilt
62
+ Postgres + pgvector build) is downloaded and checksum-verified once, then reused.
63
+ First boot takes 10–15 extra seconds if bun wasn't pre-installed, plus the
64
+ one-time runtime download; later boots are unaffected.
65
+
66
+ First boot also reconfigures two Claude Code surfaces, originals preserved for
67
+ restore: the built-in `autoMemoryEnabled` and `awaySummaryEnabled` settings are
68
+ turned off in `~/.claude/settings.json` (mixdog's continuous memory and recap
69
+ replace both), and rules persistence takes over `~/.claude/CLAUDE.md` (see
70
+ Configuration). Prior values are snapshotted under
71
+ `~/.claude/backups/mixdog-user-data/install-restore/`, and
72
+ `node scripts/uninstall.mjs` restores them (see UNINSTALL.md for full teardown).
73
+
74
+ To enable Discord / voice / schedule / webhook channels, launch with the
75
+ development channel flag (see Channels & automation) and set the Discord token
76
+ and channel IDs in the config UI.
77
+
78
+ </details>
66
79
 
67
- **Inside Claude Code (slash commands):**
80
+ ## Why mixdog
68
81
 
69
- ```
70
- /plugin marketplace add trib-plugin/mixdog
71
- /plugin install mixdog@trib-plugin
72
- ```
82
+ Claude Code is powerful, but out of the box it forgets everything between
83
+ sessions, treats every request as a fresh context, and has no built-in way
84
+ to delegate to cheaper or specialised models. Cost runs high, answers drift,
85
+ and long-lived projects lose the thread.
73
86
 
74
- Claude Code will register the repository as a marketplace, clone it,
75
- run `bun install --frozen-lockfile`, and register the MCP server declared in
76
- `.mcp.json`. bun is auto-installed on first launch if missing (node + npm
77
- provided by Claude Code). To skip the first-boot install step, install bun
78
- manually: https://bun.sh
79
-
80
- First-launch flow: `scripts/bootstrap.mjs` (node, no deps) locates bun via
81
- system PATH, falls back to plugin-local `node_modules/.bin/bun`, and finally
82
- runs `npm install --no-save bun` if neither is present. node + npm are
83
- provided by Claude Code, so the npm fallback works on a clean machine.
84
-
85
- ## Quick start
86
-
87
- 1. **Install.**
88
- ```
89
- /plugin marketplace add trib-plugin/mixdog
90
- /plugin install mixdog@trib-plugin
91
- ```
92
-
93
- 2. **Restart Claude Code.** The node bootstrap layer locates or installs
94
- bun, then bun installs runtime dependencies into a shared data
95
- directory and seeds working defaults under
96
- `~/.claude/plugins/data/mixdog-trib-plugin/`. On first boot the memory
97
- runtime (a prebuilt Postgres + pgvector build) is also downloaded and
98
- checksum-verified once, then reused on every later boot. First boot
99
- takes 10-15 extra seconds if bun was not pre-installed, plus the
100
- one-time runtime download; subsequent boots are unaffected.
101
-
102
- First boot also reconfigures two Claude Code surfaces, with the
103
- originals preserved for restore: the built-in `autoMemoryEnabled` and
104
- `awaySummaryEnabled` settings are turned off in `~/.claude/settings.json`
105
- (mixdog's continuous memory and recap replace both), and rules
106
- persistence takes over `~/.claude/CLAUDE.md` (see **Configuration**).
107
- Prior values and the original file are snapshotted under
108
- `~/.claude/backups/mixdog-user-data/install-restore/`, and
109
- `node scripts/uninstall.mjs` restores them (`CLAUDE.md` + the two
110
- settings keys; see UNINSTALL.md for the full manual teardown).
111
-
112
- 3. **That's it.** Anthropic OAuth (the Claude Code login) is the default
113
- provider, so `bridge` / `recall` / `explore` / `memory` work immediately —
114
- no API keys required.
115
-
116
- 4. **Config UI.** On first launch the config UI opens automatically at
117
- `http://localhost:3458` for providers, presets, and role bindings.
118
- You can re-open it any time with `/mixdog:config`.
119
-
120
- 5. **Optional external web search.** Add a Firecrawl / Tavily / Exa key in
121
- the config UI (or edit the `search` section of `mixdog-config.json`
122
- directly in the data directory). xAI search uses the Agent xAI key (set
123
- in the config UI / keychain), not a separate search key.
124
-
125
- 6. **Optional channels.** To enable Discord / voice / schedule / webhook
126
- channels, restart Claude Code with the development channel flag
127
- (see **Channels & automation** below), then set the Discord bot token and
128
- channel IDs in the config UI — the token is stored in the OS keychain,
129
- not a file — and enable channels.
87
+ mixdog replaces that pattern with a single MCP server that bundles four
88
+ cooperating modules **agent**, **memory**, **search**, and **channels** so
89
+ your Claude Code session gains persistent memory, multi-provider sub-agents,
90
+ web lookup, and an optional Discord front-end, all behind one install. The goal
91
+ is deployment-grade: plain ESM, zero build step for runtime code, documented
92
+ local state, and every configuration surface readable as JSON you can diff.
130
93
 
131
94
  ## Modules & tools
132
95
 
133
- mixdog is one MCP server composing four user-facing modules. Code and
134
- filesystem tools are shared across all of them.
96
+ One MCP server composes four user-facing modules, plus code and filesystem
97
+ tools shared across all of them:
98
+
99
+ - **agent** — a session orchestrator with a single `bridge` entry point: delegated sub-agent sessions, role → preset bindings, multi-provider routing, and session-spanning cache / cost handling.
100
+ - **memory** — native Postgres + `pgvector` + `pg_trgm` hybrid store; a prebuilt runtime is fetched and supervised automatically. A three-cycle pipeline scores, dedupes, and promotes durable knowledge to core memory.
101
+ - **search** — one natural-language entry point routing across providers, scraping URLs through a Readability + Puppeteer pipeline, formatted for model consumption.
102
+ - **channels** — Discord, cron schedules, inbound webhooks, voice STT, and a heartbeat status surface (requires the channel flag).
103
+
104
+ <details>
105
+ <summary>Full tool reference</summary>
135
106
 
136
107
  ### agent
137
108
 
138
- A session orchestrator with a single `bridge` entry point: delegated
139
- sub-agent sessions, role preset bindings (`user-workflow.json`),
140
- multi-provider routing, and session-spanning cache / cost handling.
141
- Sessions run as long-lived loops with trim / compress, a stream
142
- watchdog, and background job tracking. A `<final-answer>` tag protocol
143
- separates a worker's final reply from its internal deliberation.
109
+ Sessions run as long-lived loops with trim / compress, a stream watchdog, and
110
+ background job tracking. A `<final-answer>` tag protocol separates a worker's
111
+ final reply from its internal deliberation.
144
112
 
145
113
  | Tool | Purpose |
146
114
  | --- | --- |
@@ -151,17 +119,12 @@ separates a worker's final reply from its internal deliberation.
151
119
 
152
120
  ### memory
153
121
 
154
- Native PostgreSQL with `pgvector` and `pg_trgm` backs a hybrid FTS +
155
- vector store; a prebuilt runtime is fetched from the release manifest on
156
- first boot, checksum-verified, and supervised automatically there is no
157
- separate database to install or configure. Every conversation chunk is
158
- scored, deduped, and if durable promoted to core memory. A three-cycle
159
- pipeline keeps it compact: cycle 1 extracts and scores chunks, cycle 2 is a
160
- unified curator gate that holds the active set to a cap (~100 entries), and
161
- cycle 3 reviews user-curated core memory. Keep/discard decisions follow a
162
- 3-layer framework — L1 relationship/communication, L2 behavior rules, L3
163
- current project map — so only durable standing knowledge survives. SessionStart
164
- injects durable context plus a recent recap.
122
+ Every conversation chunk is scored, deduped, and if durable promoted to core
123
+ memory. Cycle 1 extracts and scores chunks, cycle 2 is a unified curator gate
124
+ that holds the active set to a cap (~100 entries), and cycle 3 reviews
125
+ user-curated core memory. Keep/discard decisions follow a 3-layer framework
126
+ (L1 relationship/communication, L2 behavior rules, L3 current project map).
127
+ SessionStart injects durable context plus a recent recap.
165
128
 
166
129
  | Tool | Purpose |
167
130
  | --- | --- |
@@ -170,11 +133,6 @@ injects durable context plus a recent recap.
170
133
 
171
134
  ### search
172
135
 
173
- One natural-language entry point routes across multiple search
174
- providers and scrapes URLs through a Readability + Puppeteer pipeline.
175
- Results are cached and formatted for model
176
- consumption, not browser consumption.
177
-
178
136
  | Tool | Purpose |
179
137
  | --- | --- |
180
138
  | `search` | Web SERP search (string or array of queries) |
@@ -182,10 +140,8 @@ consumption, not browser consumption.
182
140
 
183
141
  ### channels
184
142
 
185
- Discord, cron schedules, inbound webhooks, voice STT, and a heartbeat
186
- status surface. Inbound chat / webhook events drive a turn, schedules
187
- fire on cadence, and the status feed keeps long-running sessions
188
- observable. (Requires the channel flag — see **Channels & automation**.)
143
+ Inbound chat / webhook events drive a turn, schedules fire on cadence, and the
144
+ status feed keeps long-running sessions observable.
189
145
 
190
146
  | Tool | Purpose |
191
147
  | --- | --- |
@@ -196,16 +152,13 @@ observable. (Requires the channel flag — see **Channels & automation**.)
196
152
  ### Code & filesystem tools
197
153
 
198
154
  Shared across all modules — AST navigation (`@ast-grep/cli`) plus
199
- content-addressed edits with a session read-dedup cache, so navigation
200
- stays syntax-correct without dumping whole files into context. Tool
201
- results are compressed before they hit the model (head/tail truncation,
202
- ANSI / repeated-line dedup, file-grouped grep output). The `Module` column
203
- matches the `module` tag in `tools.json`. `apply_patch` accepts unified and
204
- V4A hunks with order-independent matching, so multi-hunk patches apply
205
- regardless of the order the hunks are listed. `read` decodes UTF-8 and
206
- UTF-16 (LE/BE, with or without BOM). `bash` auto-backgrounds a foreground
207
- command that outlives 30s into a tracked job and streams live progress over
208
- MCP, so long commands never block the session.
155
+ content-addressed edits with a session read-dedup cache, so navigation stays
156
+ syntax-correct without dumping whole files into context. Tool results are
157
+ compressed before they hit the model (head/tail truncation, ANSI / repeated-line
158
+ dedup, file-grouped grep output). `apply_patch` accepts unified and V4A hunks
159
+ with order-independent matching. `read` decodes UTF-8 and UTF-16 (LE/BE, with or
160
+ without BOM). `bash` auto-backgrounds a foreground command that outlives 30s into
161
+ a tracked job and streams live progress over MCP.
209
162
 
210
163
  | Tool | Module | Purpose |
211
164
  | --- | --- | --- |
@@ -218,9 +171,19 @@ MCP, so long commands never block the session.
218
171
  | `inject_input` | `host_input` | Inject input into the host Claude Code session (Windows only) |
219
172
  | `cwd` | `cwd` | Get / set / list the session working directory for relative-path resolution |
220
173
 
174
+ </details>
175
+
221
176
  ## Skills & commands
222
177
 
223
- **Skills** (auto-triggered by intent; Claude Code also surfaces them by name):
178
+ **Skills** are auto-triggered by intent (Claude Code also surfaces them by name):
179
+ `setup` (onboarding & config), `schedule-add`, `webhook-add`, `retro-skill-proposer`.
180
+
181
+ **Commands:** `/mixdog:setup` (prerequisites + config UI), `/mixdog:doctor`
182
+ (health diagnostics), `/mixdog:config` (open the in-browser settings UI — **the
183
+ primary way to change any configuration**).
184
+
185
+ <details>
186
+ <summary>Details</summary>
224
187
 
225
188
  | Skill | Use |
226
189
  | --- | --- |
@@ -229,30 +192,42 @@ MCP, so long commands never block the session.
229
192
  | `setup` | Onboarding and config editing (channels, presets, roles, memory) |
230
193
  | `retro-skill-proposer` | Propose a reusable skill draft after a session |
231
194
 
232
- **Commands** (`/mixdog:<name>`):
233
-
234
195
  | Command | Purpose |
235
196
  | --- | --- |
236
197
  | `/mixdog:setup` | Check prerequisites and open the config UI |
237
198
  | `/mixdog:doctor` | Health diagnostics (versions, runtime, cache, deps, log count/size, Postgres `pgdata` size, hook-pipe reachability) |
238
- | `/mixdog:config` | Open the in-browser config page directly |
199
+ | `/mixdog:config` | Open the in-browser settings UI the primary way to change configuration (providers, presets, roles, channels, memory) |
239
200
 
240
201
  **Hidden maintenance roles** (under `agents/`, not user-invoked):
241
202
  `scheduler-task`, `webhook-handler`, `maintenance`, `memory-classification`.
242
- Any public roles (worker, reviewer, debugger, etc.) are defined locally in
203
+ Public roles (worker, reviewer, debugger, etc.) are defined locally in
243
204
  `user-workflow.json`, not bundled.
244
205
 
206
+ </details>
207
+
245
208
  ## Providers
246
209
 
247
- Anthropic (direct or OAuth), OpenAI (direct or OAuth), Google Gemini,
248
- and any OpenAI-compatible endpoint (LM Studio, Ollama, vLLM, LiteLLM)
249
- are first-class providers. Switch a role to a cheaper or faster model by
250
- editing one line in `user-workflow.json`. A shared-prefix cache strategy
251
- propagates Anthropic and OpenAI prompt caching across every role in a
252
- session, and token usage is logged per provider and per role so you can
253
- see where cost lands before the bill arrives.
210
+ Anthropic (direct or OAuth), OpenAI (direct or OAuth), Google Gemini, and any
211
+ OpenAI-compatible endpoint (LM Studio, Ollama, vLLM, LiteLLM) are first-class
212
+ providers. Switch a role to a cheaper or faster model by editing one line in
213
+ `user-workflow.json`. A shared-prefix cache strategy propagates Anthropic and
214
+ OpenAI prompt caching across every role in a session, and token usage is logged
215
+ per provider and per role so you can see where cost lands before the bill arrives.
254
216
 
255
- ## Channels & automation
217
+ ## Safety
218
+
219
+ - **Zero telemetry.** No outbound calls beyond the providers you configure and the search endpoints you opt into.
220
+ - **Protected paths.** Destructive shell patterns (recursive root deletes, force pushes, disk formatting) are hard-blocked, unconditionally, with no override flag.
221
+ - **Approval gates & tool scope.** Out-of-workspace writes by sub-agents require confirmation; system paths are hard-denied; each role has an explicit tool preset (`readonly` / `full` / custom).
222
+ - **Untrusted inbound data.** Webhook payloads are fenced as untrusted data, never executed as instructions.
223
+ - **Fail-open hooks.** Permission hooks are a guard layer, not a sandbox: if the daemon or hook pipe is down, decisions default to allow (`/mixdog:doctor` warns explicitly).
224
+
225
+ Full local-state, secret, and network model: [SECURITY.md](SECURITY.md) and
226
+ [DATA-FLOW.md](DATA-FLOW.md). To restore the pre-install `CLAUDE.md` and Claude
227
+ Code settings, run `node scripts/uninstall.mjs` ([UNINSTALL.md](UNINSTALL.md)).
228
+
229
+ <details>
230
+ <summary>Channels & automation</summary>
256
231
 
257
232
  Channel-driven features require launching Claude Code with the channel flag.
258
233
  mixdog is not in Anthropic's curated channel allowlist, so `--channels` is
@@ -264,139 +239,111 @@ claude --dangerously-load-development-channels plugin:mixdog@trib-plugin
264
239
 
265
240
  This activates the Discord backend, voice STT, schedule runner, and webhook
266
241
  receiver. Without the flag the plugin still works for direct tools (`recall`,
267
- `memory`, `bridge`, `explore`, `search`, `bash`, etc.) — channel inbound
268
- events are silently disabled.
242
+ `memory`, `bridge`, `explore`, `search`, `bash`, etc.) — channel inbound events
243
+ are silently disabled.
269
244
 
270
245
  **Schedules and webhooks** each live as a per-entry directory under the data
271
246
  directory (`schedules/<name>/`, `webhooks/<name>/`), holding `config.json`
272
- (cron `time` / `secret` / optional `channel` / `model`) and `instructions.md`
273
- (what to do on fire / delivery). Routing is decided purely by **channel
274
- presence**:
247
+ (cron `time` / `secret` / optional `channel` / `model`) and `instructions.md`.
248
+ Routing is decided purely by **channel presence**:
275
249
 
276
- - **No `channel`** → the delivery is **injected into the current (Lead)
277
- session**, which handles it with full context.
278
- - **`channel` set** → it is **dispatched directly to that Discord channel** by
279
- a standalone handler (which then requires a `model` preset).
250
+ - **No `channel`** → injected into the current (Lead) session, which handles it with full context.
251
+ - **`channel` set** → dispatched directly to that Discord channel by a standalone handler (which then requires a `model` preset).
280
252
 
281
253
  When a handler has nothing to report (no code change, non-default branch,
282
- docs-only, dedup), it emits `[meta:silent]` as the first line — the
283
- notification is then dropped entirely (no session turn, no channel post).
254
+ docs-only, dedup), it emits `[meta:silent]` as the first line — the notification
255
+ is dropped entirely (no session turn, no channel post).
284
256
 
285
- Outbound notifications respect a shared quiet-hours window (timezone-aware,
286
- with weekend and holiday handling); each channel system can opt out of
287
- quieting via its own `respectQuiet` flag in the config UI's DND tab.
257
+ Outbound notifications respect a shared quiet-hours window (timezone-aware, with
258
+ weekend and holiday handling); each channel can opt out via its `respectQuiet`
259
+ flag in the config UI's DND tab.
288
260
 
289
261
  To switch to plain `--channels`, either submit mixdog to
290
262
  `claude-plugins-official` (Anthropic curates the allowlist), or add
291
263
  `{marketplace: "trib-plugin", plugin: "mixdog"}` to your organization's
292
264
  `allowedChannelPlugins` managed setting (Team / Enterprise).
293
265
 
294
- ## Configuration
266
+ </details>
267
+
268
+ <details>
269
+ <summary>Configuration</summary>
295
270
 
296
271
  All user-editable config lives in the plugin data directory
297
- (`~/.claude/plugins/data/mixdog-trib-plugin/`), NOT in the repository.
298
- The easiest way to edit it is `/mixdog:config` this opens the in-browser
299
- UI. Editing the JSON files directly is also fully supported.
300
-
301
- New installs default to `CLAUDE.md` mode: mixdog persists its rules block
302
- into `~/.claude/CLAUDE.md`. On the first takeover of an existing file, the
303
- original is backed up once to
304
- `~/.claude/backups/mixdog-user-data/install-restore/claude-md-original.md`
305
- and the file is replaced with the marker-delimited managed block; if that
306
- backup cannot be written, mixdog appends the block instead and leaves your
307
- content in place. If you prefer ephemeral injection, switch to SessionStart
308
- hook mode in the config UI — that mode never writes to `~/.claude/CLAUDE.md`.
272
+ (`~/.claude/plugins/data/mixdog-trib-plugin/`), NOT in the repository. The
273
+ easiest way to edit it is `/mixdog:config` (the in-browser UI); editing the JSON
274
+ files directly is also fully supported.
275
+
276
+ New installs default to `CLAUDE.md` mode: mixdog persists its rules block into
277
+ `~/.claude/CLAUDE.md`. On the first takeover of an existing file, the original is
278
+ backed up once to
279
+ `~/.claude/backups/mixdog-user-data/install-restore/claude-md-original.md` and
280
+ the file is replaced with the marker-delimited managed block; if that backup
281
+ can't be written, mixdog appends the block instead and leaves your content in
282
+ place. Prefer ephemeral injection? Switch to SessionStart hook mode in the config
283
+ UI — that mode never writes to `~/.claude/CLAUDE.md`.
309
284
 
310
285
  First install also disables Claude Code's built-in `autoMemoryEnabled` and
311
- `awaySummaryEnabled` in `~/.claude/settings.json` mixdog's memory and
312
- recap replace both after snapshotting the prior values to
286
+ `awaySummaryEnabled` in `~/.claude/settings.json` (mixdog's memory and recap
287
+ replace both) after snapshotting the prior values to
313
288
  `install-restore/claude-settings-original.json`. Run
314
- `node scripts/uninstall.mjs` to restore the original file and settings.
315
-
316
- The following files are managed in the data directory:
289
+ `node scripts/uninstall.mjs` to restore.
317
290
 
318
291
  | File | How it gets there | Purpose |
319
292
  | --- | --- | --- |
320
- | `mixdog-config.json` | Auto-seeded on first boot | All user-configurable settings under named sections (`channels`, `memory`, `agent`, `search`, plus UI-managed extras). See `src/shared/seed.mjs` for the default structure. |
293
+ | `mixdog-config.json` | Auto-seeded on first boot | All user-configurable settings under named sections (`channels`, `memory`, `agent`, `search`, plus UI-managed extras). See `src/shared/seed.mjs`. |
321
294
  | `user-workflow.json` | Seeded by the setup server when missing | Role → preset bindings for delegated agents |
322
- | `user-workflow.md` | Auto-generated on first launch | Human-readable workflow description derived from `user-workflow.json`; used by the Lead as a role reference |
295
+ | `user-workflow.md` | Auto-generated on first launch | Human-readable workflow description derived from `user-workflow.json` |
323
296
  | `schedules/<name>/` | Created via config UI or `schedule-add` | Per-schedule `config.json` + `instructions.md` |
324
297
  | `webhooks/<name>/` | Created via config UI or `webhook-add` | Per-webhook `config.json` + `instructions.md` |
325
298
 
326
- Seed defaults and templates live under `defaults/`
327
- (`mixdog-config.template.json`, `user-workflow.json`) useful as a
328
- reference or for diffing after manual edits.
329
-
330
- **Discord setup (optional).** Set the Discord bot token in the config UI
331
- (`/mixdog:config`) — it is stored in the OS keychain, not a file — and add
332
- your channel IDs there, then enable channels.
333
-
334
- ## Architecture & hooks
335
-
336
- The MCP server starts via `scripts/bootstrap.mjs scripts/run-mcp.mjs`
337
- (stdio supervisor) `→ server.mjs` (thin client or shared daemon) `→
338
- server-main.mjs`. Hooks are declared in `hooks/hooks.json` and routed through
339
- a native shim + CJS files. SessionStart is split into three parts — `rules`
340
- (workflow / rules injection + first-boot setup), `core` (durable memory
341
- context), and `recap` (recent-session recap); PreToolUse / PostToolUse enforce
342
- permission gates, sandbox checks, and status updates. Session state is
343
- journalled every turn, so a mid-session crash resumes cleanly on next boot.
344
- SessionStart also installs a version-independent status line: a stable launcher
345
- is copied into the data directory and registered in `~/.claude/settings.json`
346
- (tagged `"source": "mixdog-auto"`), so the status line survives plugin version
347
- bumps and self-heals without a restart. A genuine user-configured `statusLine`
348
- is left untouched.
299
+ Seed defaults and templates live under `defaults/`. **Discord setup (optional):**
300
+ set the bot token in the config UI (stored in the OS keychain, not a file) and
301
+ add channel IDs there, then enable channels.
302
+
303
+ </details>
304
+
305
+ <details>
306
+ <summary>Architecture & hooks</summary>
307
+
308
+ The MCP server starts via `scripts/bootstrap.mjs → scripts/run-mcp.mjs` (stdio
309
+ supervisor) `→ server.mjs` (thin client or shared daemon) `→ server-main.mjs`.
310
+ Hooks are declared in `hooks/hooks.json` and routed through a native shim + CJS
311
+ files. SessionStart is split into three parts — `rules` (workflow / rules
312
+ injection + first-boot setup), `core` (durable memory context), and `recap`
313
+ (recent-session recap); PreToolUse / PostToolUse enforce permission gates,
314
+ sandbox checks, and status updates. Session state is journalled every turn, so a
315
+ mid-session crash resumes cleanly on next boot. SessionStart also installs a
316
+ version-independent status line (a stable launcher tagged
317
+ `"source": "mixdog-auto"` in `~/.claude/settings.json`) that survives version
318
+ bumps and self-heals; a genuine user-configured `statusLine` is left untouched.
319
+
349
320
  See [ARCHITECTURE.md](ARCHITECTURE.md) and [DATA-FLOW.md](DATA-FLOW.md).
350
321
 
351
- ## Safety
322
+ </details>
323
+
324
+ <details>
325
+ <summary>Windows support</summary>
326
+
327
+ mixdog is developed on Windows and tested on Windows + Linux. All scripts use
328
+ forward slashes or `path.join`, line endings are normalised to LF via
329
+ `.gitattributes` (except `.cmd` / `.bat` / `.ps1`, which stay CRLF), and Node
330
+ child-process calls resolve binaries through `process.platform`-aware shims.
352
331
 
353
- - **Protected paths.** The MCP server hard-blocks destructive shell
354
- patterns (recursive root deletes, force pushes, disk formatting)
355
- these are unconditional, with no override flag.
356
- - **Approval gates.** Out-of-workspace filesystem writes by sub-agents
357
- require a confirmation prompt, and system paths are hard-denied.
358
- - **Tool scope.** Each role has an explicit tool preset
359
- (`readonly` / `full` / custom) — there is no ambient access.
360
- - **Untrusted inbound data.** Webhook payloads are fenced as untrusted
361
- data and never executed as instructions.
362
- - **No background exfiltration.** The plugin makes no outbound calls
363
- beyond the providers you configure and the search endpoints you
364
- opt into.
365
- - **Fail-open hooks.** Permission hooks are a guard layer, not a
366
- sandbox: if the mixdog daemon or its hook pipe is down, hook
367
- decisions default to allow. `/mixdog:doctor` warns explicitly when
368
- the hook pipe is unreachable. See the "Fail-open Hook Model" section
369
- in [SECURITY.md](SECURITY.md).
370
-
371
- For the full local state, secret, and network model, see
372
- [SECURITY.md](SECURITY.md) and [DATA-FLOW.md](DATA-FLOW.md). To restore the
373
- pre-install `CLAUDE.md` and Claude Code settings, run
374
- `node scripts/uninstall.mjs`; for full removal, see
375
- [UNINSTALL.md](UNINSTALL.md).
376
-
377
- ## Windows support
378
-
379
- mixdog is developed on Windows and tested on Windows + Linux.
380
- All scripts use forward slashes or `path.join`, line endings are
381
- normalised to LF via `.gitattributes` (except `.cmd` / `.bat` /
382
- `.ps1`, which stay CRLF), and Node child-process calls resolve
383
- binaries through `process.platform`-aware shims.
384
-
385
- The prebuilt memory runtime ships for Windows (`win32-x64`), Linux
386
- (`linux-x64`), and macOS on both Apple Silicon (`darwin-arm64`) and Intel
387
- (`darwin-x64`); the optional voice helper publishes verified assets for the
388
- same platforms. `linux-arm64` is not yet built.
332
+ The prebuilt memory runtime ships for Windows (`win32-x64`), Linux (`linux-x64`),
333
+ and macOS on Apple Silicon (`darwin-arm64`) and Intel (`darwin-x64`); the optional
334
+ voice helper publishes verified assets for the same platforms. `linux-arm64` is
335
+ not yet built.
389
336
 
390
337
  The `bash` MCP tool is OS-native: Windows runs commands through PowerShell
391
- (`pwsh.exe` when available, otherwise Windows PowerShell), while macOS/Linux
392
- use `/bin/sh`. No extra Windows shell runtime is required or auto-installed.
338
+ (`pwsh.exe` when available, otherwise Windows PowerShell), while macOS/Linux use
339
+ `/bin/sh`. No extra Windows shell runtime is required or auto-installed.
393
340
 
394
- ## Contributing
341
+ </details>
395
342
 
396
- Architecture notes live in [ARCHITECTURE.md](ARCHITECTURE.md). Contributor
397
- setup and PR expectations live in [CONTRIBUTING.md](CONTRIBUTING.md).
343
+ ## Contributing
398
344
 
399
- Before opening a PR, run:
345
+ Architecture notes live in [ARCHITECTURE.md](ARCHITECTURE.md); contributor setup
346
+ and PR expectations in [CONTRIBUTING.md](CONTRIBUTING.md). Before opening a PR, run:
400
347
 
401
348
  ```sh
402
349
  bun run ci
@@ -21,6 +21,10 @@ function failSoft() {
21
21
  process.exit(0);
22
22
  }
23
23
 
24
+ function claudeConfigDir() {
25
+ return process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), '.claude');
26
+ }
27
+
24
28
  async function main() {
25
29
  // CC stdin JSON (may be empty). Never block the tick on a read error.
26
30
  let stdinBuf = Buffer.alloc(0);
@@ -29,7 +33,7 @@ async function main() {
29
33
  // Resolve the ACTIVE install from the manifest — manifest-canonical, no
30
34
  // version pin. Any failure here → fail-soft.
31
35
  const manifestPath = path.join(
32
- os.homedir(), '.claude', 'plugins', 'installed_plugins.json'
36
+ claudeConfigDir(), 'plugins', 'installed_plugins.json'
33
37
  );
34
38
  let installPath = '';
35
39
  try {