mixdog 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +31 -0
- package/.claude-plugin/plugin.json +20 -0
- package/.gitattributes +34 -0
- package/.mcp.json +14 -0
- package/ARCHITECTURE.md +77 -0
- package/CHANGELOG.md +7 -0
- package/CONTRIBUTING.md +45 -0
- package/DATA-FLOW.md +79 -0
- package/LICENSE +21 -0
- package/README.md +389 -0
- package/SECURITY.md +138 -0
- package/UNINSTALL.md +112 -0
- package/agents/maintenance.md +5 -0
- package/agents/memory-classification.md +30 -0
- package/agents/scheduler-task.md +18 -0
- package/agents/webhook-handler.md +27 -0
- package/agents/worker.md +24 -0
- package/bin/bridge +133 -0
- package/bin/statusline-launcher.mjs +78 -0
- package/bin/statusline-lib.mjs +550 -0
- package/bin/statusline.mjs +607 -0
- package/bun.lock +802 -0
- package/commands/config.md +16 -0
- package/commands/doctor.md +13 -0
- package/commands/setup.md +17 -0
- package/defaults/cycle3-review-prompt.md +90 -0
- package/defaults/hidden-roles.json +65 -0
- package/defaults/memory-chunk-prompt.md +63 -0
- package/defaults/memory-promote-prompt.md +135 -0
- package/defaults/mixdog-config.template.json +27 -0
- package/defaults/user-workflow.json +8 -0
- package/defaults/user-workflow.md +12 -0
- package/hooks/hooks.json +73 -0
- package/hooks/lib/active-instance.cjs +77 -0
- package/hooks/lib/permission-evaluator.cjs +411 -0
- package/hooks/lib/permission-route.cjs +63 -0
- package/hooks/lib/permission-rules.cjs +170 -0
- package/hooks/lib/settings-loader.cjs +116 -0
- package/hooks/post-tool-use.cjs +84 -0
- package/hooks/pre-mcp-sandbox.cjs +158 -0
- package/hooks/pre-tool-subagent.cjs +253 -0
- package/hooks/session-start.cjs +1372 -0
- package/hooks/turn-timer.cjs +82 -0
- package/lib/claude-md-writer.cjs +386 -0
- package/lib/config-cjs.cjs +61 -0
- package/lib/hook-pipe-path.cjs +10 -0
- package/lib/keychain-cjs.cjs +263 -0
- package/lib/plugin-paths.cjs +61 -0
- package/lib/rules-builder.cjs +241 -0
- package/lib/text-utils.cjs +61 -0
- package/native/README.md +117 -0
- package/native/prebuilt/linux-aarch64/mixdog-shim +0 -0
- package/native/prebuilt/linux-x86_64/mixdog-shim +0 -0
- package/native/prebuilt/macos-aarch64/mixdog-shim +0 -0
- package/native/prebuilt/macos-x86_64/mixdog-shim +0 -0
- package/native/prebuilt/windows-x86_64/mixdog-shim.exe +0 -0
- package/package.json +107 -0
- package/prompts/code-review.txt +16 -0
- package/prompts/security-audit.txt +17 -0
- package/rules/bridge/00-common.md +39 -0
- package/rules/bridge/20-skip-protocol.md +18 -0
- package/rules/bridge/30-explorer.md +33 -0
- package/rules/bridge/40-cycle1-agent.md +52 -0
- package/rules/bridge/41-cycle2-agent.md +62 -0
- package/rules/bridge/42-cycle3-agent.md +44 -0
- package/rules/lead/00-tool-lead.md +61 -0
- package/rules/lead/01-general.md +23 -0
- package/rules/lead/02-channels.md +49 -0
- package/rules/lead/03-team.md +27 -0
- package/rules/lead/04-workflow.md +20 -0
- package/rules/shared/00-language.md +14 -0
- package/rules/shared/01-tool.md +138 -0
- package/scripts/bootstrap.mjs +184 -0
- package/scripts/bridge-unify-smoke.mjs +308 -0
- package/scripts/build-runtime-linux.sh +348 -0
- package/scripts/build-runtime-macos.sh +217 -0
- package/scripts/build-runtime-windows.ps1 +242 -0
- package/scripts/builtin-utils-smoke.mjs +392 -0
- package/scripts/check-json.mjs +45 -0
- package/scripts/check-syntax-changed.mjs +102 -0
- package/scripts/check-syntax.mjs +58 -0
- package/scripts/code-graph-batch.test.mjs +33 -0
- package/scripts/config-preserve-smoke.mjs +180 -0
- package/scripts/doctor.mjs +484 -0
- package/scripts/edit-normalize-fuzz.mjs +130 -0
- package/scripts/edit-normalize-smoke.mjs +401 -0
- package/scripts/edit-operation-smoke.mjs +369 -0
- package/scripts/edit2-smoke.mjs +63 -0
- package/scripts/fuzzy-e2e.mjs +28 -0
- package/scripts/fuzzy-smoke.mjs +26 -0
- package/scripts/generate-runtime-manifest.mjs +166 -0
- package/scripts/guard-smoke.mjs +66 -0
- package/scripts/hidden-role-schema-smoke.mjs +162 -0
- package/scripts/hook-routing-smoke.mjs +29 -0
- package/scripts/inject-input.ps1 +204 -0
- package/scripts/io-complex-smoke.mjs +667 -0
- package/scripts/io-explore-bench.mjs +424 -0
- package/scripts/io-guardrails-smoke.mjs +205 -0
- package/scripts/io-mini-bench-baseline.json +11 -0
- package/scripts/io-mini-bench.mjs +216 -0
- package/scripts/io-route-harness.mjs +933 -0
- package/scripts/io-telemetry-report.mjs +691 -0
- package/scripts/mutation-bench.mjs +564 -0
- package/scripts/mutation-io-smoke.mjs +1081 -0
- package/scripts/native-patch-bridge-smoke.mjs +288 -0
- package/scripts/native-patch-smoke.mjs +304 -0
- package/scripts/patch-interior-context-smoke.mjs +49 -0
- package/scripts/patch-newline-utf8-smoke.mjs +157 -0
- package/scripts/perf-hook-smoke.mjs +71 -0
- package/scripts/permission-eval-smoke.mjs +426 -0
- package/scripts/prep-patch.mjs +53 -0
- package/scripts/prep-shim.mjs +96 -0
- package/scripts/provider-cache-smoke.mjs +687 -0
- package/scripts/report-runtime-health.mjs +132 -0
- package/scripts/run-mcp.mjs +1547 -0
- package/scripts/salvage-v4a-shatter.test.mjs +58 -0
- package/scripts/scoped-cache-io-smoke.mjs +103 -0
- package/scripts/shell-policy-round3-smoke.mjs +46 -0
- package/scripts/smoke-runtime-negative.ps1 +100 -0
- package/scripts/smoke-runtime-negative.sh +95 -0
- package/scripts/stall-policy-smoke.mjs +50 -0
- package/scripts/start-memory-worker.mjs +23 -0
- package/scripts/statusline-launcher-smoke.mjs +82 -0
- package/scripts/stress-atomic-write.mjs +1028 -0
- package/scripts/test-config-rmw-restore.mjs +122 -0
- package/scripts/test-fault-inject.mjs +164 -0
- package/scripts/test-large-file.mjs +174 -0
- package/scripts/tool-edge-smoke.mjs +209 -0
- package/scripts/uninstall.mjs +201 -0
- package/scripts/webhook-selfheal-smoke.mjs +29 -0
- package/scripts/write-overwrite-guard-smoke.mjs +56 -0
- package/server-main.mjs +3055 -0
- package/server.mjs +468 -0
- package/setup/config-merge.mjs +254 -0
- package/setup/install.mjs +120 -0
- package/setup/launch-core.mjs +507 -0
- package/setup/launch.mjs +101 -0
- package/setup/setup-server.mjs +3206 -0
- package/setup/setup.html +3693 -0
- package/skills/retro-skill-proposer/SKILL.md +92 -0
- package/skills/schedule-add/SKILL.md +77 -0
- package/skills/setup/SKILL.md +346 -0
- package/skills/webhook-add/SKILL.md +81 -0
- package/src/agent/bridge-stall-watchdog.mjs +337 -0
- package/src/agent/index.mjs +2138 -0
- package/src/agent/orchestrator/activity-bus.mjs +38 -0
- package/src/agent/orchestrator/ai-wrapped-dispatch.mjs +1010 -0
- package/src/agent/orchestrator/bridge-retry.mjs +220 -0
- package/src/agent/orchestrator/bridge-trace.mjs +583 -0
- package/src/agent/orchestrator/cache-mtime.mjs +58 -0
- package/src/agent/orchestrator/config.mjs +358 -0
- package/src/agent/orchestrator/context/collect.mjs +651 -0
- package/src/agent/orchestrator/dispatch-persist.mjs +549 -0
- package/src/agent/orchestrator/drain-registry.mjs +50 -0
- package/src/agent/orchestrator/explore-validator.mjs +8 -0
- package/src/agent/orchestrator/internal-roles.mjs +118 -0
- package/src/agent/orchestrator/internal-tools.mjs +88 -0
- package/src/agent/orchestrator/jobs.mjs +116 -0
- package/src/agent/orchestrator/mcp/client.mjs +364 -0
- package/src/agent/orchestrator/providers/anthropic-betas.mjs +21 -0
- package/src/agent/orchestrator/providers/anthropic-oauth.mjs +1745 -0
- package/src/agent/orchestrator/providers/anthropic.mjs +437 -0
- package/src/agent/orchestrator/providers/gemini.mjs +1175 -0
- package/src/agent/orchestrator/providers/grok-oauth.mjs +782 -0
- package/src/agent/orchestrator/providers/model-catalog.mjs +241 -0
- package/src/agent/orchestrator/providers/openai-compat.mjs +1467 -0
- package/src/agent/orchestrator/providers/openai-oauth-ws.mjs +1890 -0
- package/src/agent/orchestrator/providers/openai-oauth.mjs +1307 -0
- package/src/agent/orchestrator/providers/openai-ws.mjs +104 -0
- package/src/agent/orchestrator/providers/registry.mjs +192 -0
- package/src/agent/orchestrator/providers/retry-classifier.mjs +325 -0
- package/src/agent/orchestrator/session/abort-lookup.mjs +13 -0
- package/src/agent/orchestrator/session/cache/post-edit-marks.mjs +42 -0
- package/src/agent/orchestrator/session/cache/prefetch-cache.mjs +142 -0
- package/src/agent/orchestrator/session/cache/read-cache.mjs +319 -0
- package/src/agent/orchestrator/session/cache/scoped-cache-outcome.mjs +11 -0
- package/src/agent/orchestrator/session/cache/scoped-cache.mjs +361 -0
- package/src/agent/orchestrator/session/cache/util.mjs +49 -0
- package/src/agent/orchestrator/session/loop.mjs +1478 -0
- package/src/agent/orchestrator/session/manager.mjs +1975 -0
- package/src/agent/orchestrator/session/read-dedup.mjs +6 -0
- package/src/agent/orchestrator/session/result-classification.mjs +65 -0
- package/src/agent/orchestrator/session/save-session-worker.mjs +18 -0
- package/src/agent/orchestrator/session/store.mjs +624 -0
- package/src/agent/orchestrator/session/stream-watchdog.mjs +130 -0
- package/src/agent/orchestrator/session/tool-result-offload.mjs +166 -0
- package/src/agent/orchestrator/session/trim.mjs +491 -0
- package/src/agent/orchestrator/smart-bridge/CACHE-SHARD.md +115 -0
- package/src/agent/orchestrator/smart-bridge/bridge-llm.mjs +327 -0
- package/src/agent/orchestrator/smart-bridge/cache-obs.mjs +150 -0
- package/src/agent/orchestrator/smart-bridge/cache-strategy.mjs +228 -0
- package/src/agent/orchestrator/smart-bridge/index.mjs +215 -0
- package/src/agent/orchestrator/smart-bridge/profiles.mjs +37 -0
- package/src/agent/orchestrator/smart-bridge/registry.mjs +348 -0
- package/src/agent/orchestrator/smart-bridge/session-builder.mjs +116 -0
- package/src/agent/orchestrator/stall-policy.mjs +195 -0
- package/src/agent/orchestrator/tool-loop-guard.mjs +75 -0
- package/src/agent/orchestrator/tools/bash-policy-scan.mjs +77 -0
- package/src/agent/orchestrator/tools/bash-session.mjs +721 -0
- package/src/agent/orchestrator/tools/builtin/advisory-lock.mjs +171 -0
- package/src/agent/orchestrator/tools/builtin/arg-guard.mjs +455 -0
- package/src/agent/orchestrator/tools/builtin/atomic-write.mjs +236 -0
- package/src/agent/orchestrator/tools/builtin/bash-tool.mjs +480 -0
- package/src/agent/orchestrator/tools/builtin/binary-file.mjs +76 -0
- package/src/agent/orchestrator/tools/builtin/builtin-tools.mjs +256 -0
- package/src/agent/orchestrator/tools/builtin/cache-layers.mjs +386 -0
- package/src/agent/orchestrator/tools/builtin/cwd-utils.mjs +37 -0
- package/src/agent/orchestrator/tools/builtin/device-paths.mjs +154 -0
- package/src/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +292 -0
- package/src/agent/orchestrator/tools/builtin/diff-utils.mjs +109 -0
- package/src/agent/orchestrator/tools/builtin/edit-base-guard.mjs +58 -0
- package/src/agent/orchestrator/tools/builtin/edit-byte-plan.mjs +240 -0
- package/src/agent/orchestrator/tools/builtin/edit-byte-utils.mjs +113 -0
- package/src/agent/orchestrator/tools/builtin/edit-commit.mjs +74 -0
- package/src/agent/orchestrator/tools/builtin/edit-context-utils.mjs +242 -0
- package/src/agent/orchestrator/tools/builtin/edit-diagnostics.mjs +211 -0
- package/src/agent/orchestrator/tools/builtin/edit-engine.mjs +1364 -0
- package/src/agent/orchestrator/tools/builtin/edit-failure-context.mjs +126 -0
- package/src/agent/orchestrator/tools/builtin/edit-hint.mjs +141 -0
- package/src/agent/orchestrator/tools/builtin/edit-match-utils.mjs +194 -0
- package/src/agent/orchestrator/tools/builtin/edit-partial-write.mjs +60 -0
- package/src/agent/orchestrator/tools/builtin/edit-stale-refresh.mjs +168 -0
- package/src/agent/orchestrator/tools/builtin/edit-tool.mjs +173 -0
- package/src/agent/orchestrator/tools/builtin/edit-utf8-guard.mjs +48 -0
- package/src/agent/orchestrator/tools/builtin/fs-reachability.mjs +48 -0
- package/src/agent/orchestrator/tools/builtin/fuzzy-match.mjs +99 -0
- package/src/agent/orchestrator/tools/builtin/glob-walk.mjs +170 -0
- package/src/agent/orchestrator/tools/builtin/grep-formatting.mjs +113 -0
- package/src/agent/orchestrator/tools/builtin/hash-utils.mjs +6 -0
- package/src/agent/orchestrator/tools/builtin/list-formatting.mjs +7 -0
- package/src/agent/orchestrator/tools/builtin/list-tool.mjs +593 -0
- package/src/agent/orchestrator/tools/builtin/native-edit-runner.mjs +89 -0
- package/src/agent/orchestrator/tools/builtin/notebook-edit-tool.mjs +300 -0
- package/src/agent/orchestrator/tools/builtin/open-config-tool.mjs +26 -0
- package/src/agent/orchestrator/tools/builtin/path-diagnostics.mjs +152 -0
- package/src/agent/orchestrator/tools/builtin/path-locks.mjs +35 -0
- package/src/agent/orchestrator/tools/builtin/path-utils.mjs +201 -0
- package/src/agent/orchestrator/tools/builtin/read-args.mjs +103 -0
- package/src/agent/orchestrator/tools/builtin/read-batch.mjs +172 -0
- package/src/agent/orchestrator/tools/builtin/read-constants.mjs +40 -0
- package/src/agent/orchestrator/tools/builtin/read-formatting.mjs +118 -0
- package/src/agent/orchestrator/tools/builtin/read-image-resize.mjs +189 -0
- package/src/agent/orchestrator/tools/builtin/read-image.mjs +88 -0
- package/src/agent/orchestrator/tools/builtin/read-lines.mjs +12 -0
- package/src/agent/orchestrator/tools/builtin/read-mode-tool.mjs +455 -0
- package/src/agent/orchestrator/tools/builtin/read-open.mjs +190 -0
- package/src/agent/orchestrator/tools/builtin/read-range-index.mjs +271 -0
- package/src/agent/orchestrator/tools/builtin/read-ranges.mjs +26 -0
- package/src/agent/orchestrator/tools/builtin/read-single-tool.mjs +728 -0
- package/src/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +173 -0
- package/src/agent/orchestrator/tools/builtin/read-special-files.mjs +268 -0
- package/src/agent/orchestrator/tools/builtin/read-streaming.mjs +602 -0
- package/src/agent/orchestrator/tools/builtin/read-tool.mjs +530 -0
- package/src/agent/orchestrator/tools/builtin/read-windows.mjs +107 -0
- package/src/agent/orchestrator/tools/builtin/rename-tool.mjs +196 -0
- package/src/agent/orchestrator/tools/builtin/rg-runner.mjs +422 -0
- package/src/agent/orchestrator/tools/builtin/search-builders.mjs +158 -0
- package/src/agent/orchestrator/tools/builtin/search-tool.mjs +869 -0
- package/src/agent/orchestrator/tools/builtin/shell-analysis.mjs +653 -0
- package/src/agent/orchestrator/tools/builtin/shell-jobs.mjs +936 -0
- package/src/agent/orchestrator/tools/builtin/shell-output.mjs +36 -0
- package/src/agent/orchestrator/tools/builtin/shell-runtime.mjs +214 -0
- package/src/agent/orchestrator/tools/builtin/snapshot-helpers.mjs +143 -0
- package/src/agent/orchestrator/tools/builtin/snapshot-store.mjs +206 -0
- package/src/agent/orchestrator/tools/builtin/snapshot-validation.mjs +98 -0
- package/src/agent/orchestrator/tools/builtin/text-stats.mjs +69 -0
- package/src/agent/orchestrator/tools/builtin/windows-roots.mjs +23 -0
- package/src/agent/orchestrator/tools/builtin/write-tool.mjs +401 -0
- package/src/agent/orchestrator/tools/builtin.mjs +500 -0
- package/src/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +39 -0
- package/src/agent/orchestrator/tools/code-graph-tool-defs.mjs +24 -0
- package/src/agent/orchestrator/tools/code-graph.mjs +4095 -0
- package/src/agent/orchestrator/tools/cwd-tool.mjs +298 -0
- package/src/agent/orchestrator/tools/destructive-warning.mjs +323 -0
- package/src/agent/orchestrator/tools/edit-normalize.mjs +603 -0
- package/src/agent/orchestrator/tools/env-scrub.mjs +100 -0
- package/src/agent/orchestrator/tools/graph-binary-fetcher.mjs +144 -0
- package/src/agent/orchestrator/tools/graph-manifest.json +26 -0
- package/src/agent/orchestrator/tools/host-input.mjs +204 -0
- package/src/agent/orchestrator/tools/mutation-content-cache.mjs +67 -0
- package/src/agent/orchestrator/tools/mutation-planner.mjs +75 -0
- package/src/agent/orchestrator/tools/next-call-utils.mjs +48 -0
- package/src/agent/orchestrator/tools/patch-binary-fetcher.mjs +133 -0
- package/src/agent/orchestrator/tools/patch-manifest.json +26 -0
- package/src/agent/orchestrator/tools/patch-tool-defs.mjs +20 -0
- package/src/agent/orchestrator/tools/patch.mjs +2754 -0
- package/src/agent/orchestrator/tools/progress-message.mjs +118 -0
- package/src/agent/orchestrator/tools/result-compression.mjs +279 -0
- package/src/agent/orchestrator/tools/shell-command.mjs +865 -0
- package/src/agent/orchestrator/tools/shell-exec-policy.mjs +89 -0
- package/src/agent/orchestrator/tools/shell-policy-danger-target.mjs +27 -0
- package/src/agent/orchestrator/tools/shell-policy-imports.mjs +7 -0
- package/src/agent/orchestrator/tools/shell-policy.mjs +345 -0
- package/src/agent/orchestrator/tools/shell-snapshot.mjs +313 -0
- package/src/agent/orchestrator/workflow-store.mjs +93 -0
- package/src/agent/tool-defs.mjs +103 -0
- package/src/channels/backends/discord.mjs +784 -0
- package/src/channels/data/voice-runtime-manifest.json +138 -0
- package/src/channels/index.mjs +3229 -0
- package/src/channels/lib/cli-worker-host.mjs +12 -0
- package/src/channels/lib/config-lock.mjs +13 -0
- package/src/channels/lib/config.mjs +292 -0
- package/src/channels/lib/drop-trace.mjs +71 -0
- package/src/channels/lib/event-pipeline.mjs +81 -0
- package/src/channels/lib/event-queue.mjs +345 -0
- package/src/channels/lib/executor.mjs +168 -0
- package/src/channels/lib/format.mjs +188 -0
- package/src/channels/lib/holidays.mjs +138 -0
- package/src/channels/lib/hook-pipe-server.mjs +802 -0
- package/src/channels/lib/interaction-workflows.mjs +184 -0
- package/src/channels/lib/memory-client.mjs +149 -0
- package/src/channels/lib/output-forwarder.mjs +765 -0
- package/src/channels/lib/runtime-paths.mjs +479 -0
- package/src/channels/lib/scheduler.mjs +723 -0
- package/src/channels/lib/session-control.mjs +36 -0
- package/src/channels/lib/session-discovery.mjs +103 -0
- package/src/channels/lib/settings.mjs +11 -0
- package/src/channels/lib/state-file.mjs +68 -0
- package/src/channels/lib/status-snapshot.mjs +219 -0
- package/src/channels/lib/tool-format.mjs +140 -0
- package/src/channels/lib/transcript-discovery.mjs +195 -0
- package/src/channels/lib/voice-runtime-fetcher.mjs +734 -0
- package/src/channels/lib/webhook.mjs +1179 -0
- package/src/channels/lib/whisper-server.mjs +477 -0
- package/src/channels/tool-defs.mjs +170 -0
- package/src/daemon/host.mjs +118 -0
- package/src/daemon/mcp-transport.mjs +47 -0
- package/src/daemon/session.mjs +100 -0
- package/src/daemon/thin-client.mjs +71 -0
- package/src/daemon/transport.mjs +163 -0
- package/src/memory/data/runtime-manifest.json +40 -0
- package/src/memory/index.mjs +3305 -0
- package/src/memory/lib/agent-ipc.mjs +93 -0
- package/src/memory/lib/bridge-trace-queries.mjs +120 -0
- package/src/memory/lib/core-memory-store.mjs +330 -0
- package/src/memory/lib/embedding-provider.mjs +269 -0
- package/src/memory/lib/embedding-worker.mjs +323 -0
- package/src/memory/lib/llm-worker-host.mjs +17 -0
- package/src/memory/lib/memory-cycle.mjs +11 -0
- package/src/memory/lib/memory-cycle1.mjs +641 -0
- package/src/memory/lib/memory-cycle2.mjs +1284 -0
- package/src/memory/lib/memory-cycle3.mjs +540 -0
- package/src/memory/lib/memory-embed.mjs +299 -0
- package/src/memory/lib/memory-extraction.mjs +5 -0
- package/src/memory/lib/memory-maintenance-store.mjs +32 -0
- package/src/memory/lib/memory-ops-policy.mjs +190 -0
- package/src/memory/lib/memory-recall-id-patch.mjs +15 -0
- package/src/memory/lib/memory-recall-read-query.mjs +7 -0
- package/src/memory/lib/memory-recall-scope-filter.mjs +63 -0
- package/src/memory/lib/memory-recall-store.mjs +621 -0
- package/src/memory/lib/memory-retrievers.mjs +112 -0
- package/src/memory/lib/memory-score.mjs +71 -0
- package/src/memory/lib/memory-text-utils.mjs +58 -0
- package/src/memory/lib/memory.mjs +412 -0
- package/src/memory/lib/model-profile.mjs +85 -0
- package/src/memory/lib/pg/adapter.mjs +308 -0
- package/src/memory/lib/pg/process.mjs +360 -0
- package/src/memory/lib/pg/supervisor.mjs +396 -0
- package/src/memory/lib/project-id-resolver.mjs +86 -0
- package/src/memory/lib/runtime-fetcher.mjs +442 -0
- package/src/memory/lib/trace-store.mjs +728 -0
- package/src/memory/tool-defs.mjs +79 -0
- package/src/search/index.mjs +1173 -0
- package/src/search/lib/backends/anthropic-oauth.mjs +98 -0
- package/src/search/lib/backends/exa.mjs +50 -0
- package/src/search/lib/backends/firecrawl.mjs +61 -0
- package/src/search/lib/backends/gemini-api.mjs +83 -0
- package/src/search/lib/backends/grok-oauth.mjs +86 -0
- package/src/search/lib/backends/index.mjs +150 -0
- package/src/search/lib/backends/openai-api.mjs +144 -0
- package/src/search/lib/backends/openai-oauth.mjs +98 -0
- package/src/search/lib/backends/openai-web-search.mjs +76 -0
- package/src/search/lib/backends/tavily.mjs +55 -0
- package/src/search/lib/backends/xai-api.mjs +113 -0
- package/src/search/lib/cache.mjs +131 -0
- package/src/search/lib/config.mjs +192 -0
- package/src/search/lib/formatter.mjs +115 -0
- package/src/search/lib/provider-usage.mjs +67 -0
- package/src/search/lib/providers.mjs +47 -0
- package/src/search/lib/search-intent.mjs +109 -0
- package/src/search/lib/setup-handler.mjs +261 -0
- package/src/search/lib/state.mjs +201 -0
- package/src/search/lib/web-tools.mjs +1207 -0
- package/src/search/tool-defs.mjs +83 -0
- package/src/setup/defender-exclusion.mjs +183 -0
- package/src/shared/abort-controller.mjs +15 -0
- package/src/shared/atomic-file.mjs +420 -0
- package/src/shared/config.mjs +350 -0
- package/src/shared/daemon-recycle.mjs +108 -0
- package/src/shared/disable-claude-builtins.mjs +88 -0
- package/src/shared/err-text.mjs +12 -0
- package/src/shared/llm/cost.mjs +66 -0
- package/src/shared/llm/http-agent.mjs +123 -0
- package/src/shared/llm/index.mjs +41 -0
- package/src/shared/llm/pid-cleanup.mjs +27 -0
- package/src/shared/llm/usage-log.mjs +47 -0
- package/src/shared/plugin-paths.mjs +58 -0
- package/src/shared/schedules-store.mjs +70 -0
- package/src/shared/seed.mjs +119 -0
- package/src/shared/user-cwd.mjs +213 -0
- package/src/shared/user-data-guard.mjs +238 -0
- package/src/status/aggregator.mjs +584 -0
- package/src/status/server.mjs +413 -0
- package/tools.json +1653 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: retro-skill-proposer
|
|
3
|
+
description: Use ONLY during the Retro phase of a Plan/Execute/Verify/Ship/Retro workflow to evaluate whether the completed session produced a reusable pattern worth saving as a skill draft. Never triggers during other phases. Skip if session was trivial or no distinctive pattern emerged. User-approval gated — never saves without explicit OK.
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Retro Skill Proposer
|
|
8
|
+
|
|
9
|
+
## When to invoke
|
|
10
|
+
|
|
11
|
+
Only at the Retro phase of the `Plan -> Execute -> Verify -> Ship -> Retro` workflow. Never during Plan/Execute/Verify/Ship. If the session did not follow this workflow at all (pure Q&A, quick lookup, etc.), do not invoke.
|
|
12
|
+
|
|
13
|
+
Skip entirely when any of:
|
|
14
|
+
- Fewer than 5 tool calls in session
|
|
15
|
+
- Pure reading / research with no state change
|
|
16
|
+
- No distinctive pattern emerged
|
|
17
|
+
- An existing skill already covers the pattern (check `~/.claude/skills/`, `~/.claude/skills/auto/`, `~/.claude/skills/auto-drafts/`, plugin bundled skills)
|
|
18
|
+
|
|
19
|
+
## Trigger conditions (ANY ONE is sufficient)
|
|
20
|
+
|
|
21
|
+
1. **Complex success** — a 5+ tool call workflow completed successfully
|
|
22
|
+
2. **Error recovery** — got past an error and found a working path
|
|
23
|
+
3. **User correction** — user revealed a better approach mid-session
|
|
24
|
+
4. **Novel sequence** — a non-obvious reusable tool chain worth remembering
|
|
25
|
+
|
|
26
|
+
## Procedure
|
|
27
|
+
|
|
28
|
+
1. **Silent scan** — review the current session's tool calls, decisions, user corrections. Do NOT narrate this step.
|
|
29
|
+
2. **Match conditions** — evaluate against the four trigger conditions above.
|
|
30
|
+
3. **Dedup check** — compare the candidate pattern against existing skills in:
|
|
31
|
+
- `~/.claude/skills/` (user global)
|
|
32
|
+
- `~/.claude/skills/auto/` (auto-generated, promoted)
|
|
33
|
+
- `~/.claude/skills/auto-drafts/` (auto-generated, pending)
|
|
34
|
+
- plugin bundled skills
|
|
35
|
+
4. **Propose** — if eligible and non-duplicate, write a concise proposal in the user's configured language:
|
|
36
|
+
- Skill name (slug form)
|
|
37
|
+
- Which trigger condition matched
|
|
38
|
+
- When to invoke the skill
|
|
39
|
+
- Procedure (step by step)
|
|
40
|
+
- Verification method
|
|
41
|
+
- Why this is worth saving (1-2 sentences)
|
|
42
|
+
5. **Wait for user approval** — the user MUST explicitly say "save" or equivalent. Silence or ambiguity means skip.
|
|
43
|
+
6. **On approval** — use the `write` tool to create:
|
|
44
|
+
- `~/.claude/skills/auto-drafts/{name}/SKILL.md` with proper frontmatter (name, description, version: 0.1.0)
|
|
45
|
+
- Include the full procedure in markdown body
|
|
46
|
+
7. **On skip or rejection** — leave no trace, no explanation needed. Continue the Retro normally.
|
|
47
|
+
|
|
48
|
+
## Non-goals
|
|
49
|
+
|
|
50
|
+
- Do NOT propose for every session
|
|
51
|
+
- Do NOT save without explicit user approval
|
|
52
|
+
- Do NOT duplicate existing skills
|
|
53
|
+
- Do NOT modify CLAUDE.md or bridge common instructions
|
|
54
|
+
- Do NOT propose during Plan/Execute/Verify/Ship phases
|
|
55
|
+
- Do NOT force-inject the skill into future sessions — saved drafts sit dormant until the LLM naturally picks them up via Progressive Disclosure
|
|
56
|
+
|
|
57
|
+
## SKILL.md frontmatter template for the draft
|
|
58
|
+
|
|
59
|
+
```yaml
|
|
60
|
+
---
|
|
61
|
+
name: <slug-form-name>
|
|
62
|
+
description: <one-line trigger description; keep under 200 chars; lead with "Use when..."; be specific about conditions so the LLM can match accurately>
|
|
63
|
+
version: 0.1.0
|
|
64
|
+
source: retro-skill-proposer
|
|
65
|
+
session: <current session id or date>
|
|
66
|
+
---
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Proposal output format (to the user, in their configured language)
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
Proposed skill: {name}
|
|
73
|
+
Trigger: {which of the 4 conditions matched}
|
|
74
|
+
When to use: {when to invoke this skill}
|
|
75
|
+
|
|
76
|
+
Procedure:
|
|
77
|
+
1. ...
|
|
78
|
+
2. ...
|
|
79
|
+
3. ...
|
|
80
|
+
|
|
81
|
+
Verification: {how to confirm the skill worked}
|
|
82
|
+
|
|
83
|
+
Why it is worth saving: {1-2 sentences}
|
|
84
|
+
|
|
85
|
+
On approval, save to ~/.claude/skills/auto-drafts/{name}/SKILL.md.
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Verification
|
|
89
|
+
|
|
90
|
+
After saving, confirm the file exists at the expected path and the frontmatter parses cleanly. Do not auto-test the skill — it sits as a draft until:
|
|
91
|
+
- A batch run promotes it to `auto/` after frequency validation, OR
|
|
92
|
+
- The user manually moves it to `~/.claude/skills/`
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: schedule-add
|
|
3
|
+
description: Invoke when the user's intent is to register a new recurring/cron-style task in mixdog so the scheduler fires it on a future cadence. Writes a new entry under `${CLAUDE_PLUGIN_DATA}/schedules/<name>/` and reloads the channels config. Do not invoke for one-shot in-session reminders (use `/loop`) or for inspecting existing schedules.
|
|
4
|
+
version: 0.3.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# schedule-add
|
|
8
|
+
|
|
9
|
+
Register a new schedule item in mixdog.
|
|
10
|
+
|
|
11
|
+
## When to invoke
|
|
12
|
+
|
|
13
|
+
User intent: register a new recurring task in the mixdog scheduler. The trigger is the intent, not specific phrasing — invoke whenever the user is asking for a future-cadence task that should persist across sessions.
|
|
14
|
+
|
|
15
|
+
Skip if the user only wants a one-shot run within the current session (use `/loop` for that), or asks to *list* existing schedules (just read the directory directly).
|
|
16
|
+
|
|
17
|
+
## Routing model (channel presence — no `type`)
|
|
18
|
+
|
|
19
|
+
A schedule with **no `channel`** is injected into the current (Lead) session when it fires — the session handles it with full context, like a webhook. A schedule **with a `channel`** is dispatched directly to that Discord channel by a standalone LLM (so it needs a `model`). Channel presence is the only switch; there is no `type` field. `src/channels/lib/config.mjs` buckets entries by `!!channel`.
|
|
20
|
+
|
|
21
|
+
A channel-direct schedule that fires with nothing worth posting can suppress its own notification: emit `[meta:silent]` as the **first line** of the response and the turn/post is skipped (Discord still gets the body for audit). Mention this in `instructions.md` when the task is a conditional "only ping if X". See `rules/bridge/20-skip-protocol.md`.
|
|
22
|
+
|
|
23
|
+
## Storage contract
|
|
24
|
+
|
|
25
|
+
The on-disk schema MUST match what `setup-server` (POST /schedules) writes, because the scheduler reader (`src/channels/lib/scheduler.mjs`) and the setup UI consume the same `config.json` shape. Drift silently disables the entry: `scheduler.mjs` skips cron registration when `time` is absent.
|
|
26
|
+
|
|
27
|
+
## Required fields
|
|
28
|
+
|
|
29
|
+
Collect from the user message; ask only for the truly missing ones in plain text (no AskUserQuestion).
|
|
30
|
+
|
|
31
|
+
| Field | Required | Default | Notes |
|
|
32
|
+
|---|---|---|---|
|
|
33
|
+
| `name` | yes | — | slug `[a-z0-9-]+`, becomes directory name |
|
|
34
|
+
| `time` | yes | — | 5- or 6-field cron expression ONLY (e.g. `0 9 * * *`). Legacy formats (`HH:MM`, `every<N>m`, `hourly`, `daily`) are rejected by the scheduler — translate them: daily 09:00 = `0 9 * * *`; every 15 min = `*/15 * * * *`; weekday 18:00 = `0 18 * * 1-5` |
|
|
35
|
+
| `timezone` | no | `Asia/Seoul` | IANA name; used by node-cron and the DND / holiday guards |
|
|
36
|
+
| `days` | no | `daily` | `daily` / `weekday` / `weekend` |
|
|
37
|
+
| `channel` | no | — (inject to current session) | set to a Discord channel label to dispatch DIRECT to that channel instead of injecting |
|
|
38
|
+
| `model` | conditional | — | REQUIRED when `channel` is set (direct dispatch runs a standalone LLM preset, e.g. `haiku`). Omit when injecting — the session handles it, no preset needed. |
|
|
39
|
+
| `enabled` | no | `true` | omit unless the user explicitly wants the entry pre-disabled (reader filters `enabled !== false`) |
|
|
40
|
+
| `instructions` | yes | — | what the schedule should do when it fires (markdown body) |
|
|
41
|
+
|
|
42
|
+
## Procedure
|
|
43
|
+
|
|
44
|
+
1. Parse the user's request. Extract whatever is unambiguous (name, time, channel, instructions). For missing required fields ask in one short message; do NOT proceed with partial data.
|
|
45
|
+
2. Validate:
|
|
46
|
+
- `name` matches `^[a-z0-9][a-z0-9-]*$`, length ≤ 64
|
|
47
|
+
- `time` is a valid 5- or 6-field cron expression. Legacy formats (`HH:MM`, `every<N>m`, `hourly`, `daily`) are NOT accepted — convert the user's phrasing to cron before writing
|
|
48
|
+
- if `channel` is set, `model` MUST also be set (direct dispatch has no preset fallback)
|
|
49
|
+
- target directory `${CLAUDE_PLUGIN_DATA}/schedules/<name>/` does NOT already exist (if it does, ask user whether to overwrite or rename)
|
|
50
|
+
3. Create directory + write two files atomically (tmp + rename):
|
|
51
|
+
- `config.json` — omit fields that equal their default; NEVER write `type`:
|
|
52
|
+
```json
|
|
53
|
+
// inject into current session (no channel)
|
|
54
|
+
{ "time": "0 9 * * *" }
|
|
55
|
+
|
|
56
|
+
// direct to a channel (channel + model required)
|
|
57
|
+
{ "time": "0 9 * * *", "channel": "main", "model": "haiku" }
|
|
58
|
+
```
|
|
59
|
+
- `instructions.md`: the user-provided body as-is.
|
|
60
|
+
4. Call `mcp__plugin_mixdog_mixdog__reload_config` to re-register schedules.
|
|
61
|
+
5. Call `mcp__plugin_mixdog_mixdog__schedule_status` and confirm the new entry appears.
|
|
62
|
+
6. Report back to the user in their configured language with: name, next fire (local time), and where it goes (current session vs which channel). One short paragraph; no bullet padding.
|
|
63
|
+
|
|
64
|
+
## Failure handling
|
|
65
|
+
|
|
66
|
+
- File write error → report path:error, do not retry blindly.
|
|
67
|
+
- `reload_config` error → file is written but not live; tell user to restart Claude Code or rerun.
|
|
68
|
+
- `schedule_status` missing the new entry → `time` expression rejected; show the raw status response.
|
|
69
|
+
|
|
70
|
+
## Anti-patterns
|
|
71
|
+
|
|
72
|
+
- Do not invent a `time` value when the cadence the user gave is ambiguous — ask for a specific time.
|
|
73
|
+
- Do not write a legacy `time` format (`HH:MM` / `every<N>m` / `hourly` / `daily`) — the scheduler rejects it and the entry never registers; always convert to a cron expression.
|
|
74
|
+
- Do not auto-overwrite an existing schedule with the same name without explicit confirmation.
|
|
75
|
+
- Do not skip the `reload_config` + `schedule_status` round trip; without it the user has no proof of registration.
|
|
76
|
+
- Do not write a `type` / `cron` / `mode` / `role` key. Routing is decided purely by `channel` presence; the scheduler reader does not consume those keys. Use `time` (+ optional `channel`/`model`) only.
|
|
77
|
+
- Do not set `channel` without `model` — direct dispatch is rejected with no LLM preset.
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: setup
|
|
3
|
+
description: Invoke for ANY mixdog setup or config task — onboarding a fresh install AND editing existing config. Covers agent providers/models, bridge role→preset mapping (changing worker/reviewer/tester/debugger models), agent.presets, channels/Discord, memory, search, webhook/ngrok, quiet hours, DM access, address form (user title), launch flag, and secrets. Trigger on intents like "mixdog config", "edit/change settings", "set up", "세팅"/"설정 수정", "호칭 변경" (change how the assistant addresses the user), "조용시간"/quiet hours, DM access, "change worker (or any role) model", "add a preset", "switch provider", or first-time "what goes where". Also handles uninstall/restore intents ("remove mixdog", "restore pre-install state", "원상복구") — route those to `node scripts/uninstall.mjs` and UNINSTALL.md.
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# setup
|
|
8
|
+
|
|
9
|
+
Guided onboarding for a fresh mixdog install **and** a reference for editing existing user config.
|
|
10
|
+
|
|
11
|
+
## Which file do I edit? (decide FIRST — do not guess paths)
|
|
12
|
+
|
|
13
|
+
| You want to change… | Edit this | Never edit |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| Any setting value (channels, memory, agent presets, search, capabilities, cwd) | `${DATA}/mixdog-config.json` | `defaults/*.template.json`, anything under `<plugin>/cache/` |
|
|
16
|
+
| Which model a role uses | `${DATA}/user-workflow.json` (`roles[].preset`) | `defaults/user-workflow.json` |
|
|
17
|
+
| A secret (bot token, API key, authtoken) | OS keychain / `MIXDOG_*` env | any JSON file |
|
|
18
|
+
| Skill text / prompts / plugin code | the marketplace **source** (`<plugin>/marketplaces/trib-plugin/`; dev installs: the source repo, then sync) | the `cache/` copy — it is overwritten on update/sync |
|
|
19
|
+
|
|
20
|
+
`${DATA}` = `~/.claude/plugins/data/mixdog-trib-plugin/`. Rule of thumb:
|
|
21
|
+
**user config → `${DATA}`; code/templates → marketplace source; `cache/` and
|
|
22
|
+
`defaults/` are never the edit target.**
|
|
23
|
+
|
|
24
|
+
## Key facts
|
|
25
|
+
|
|
26
|
+
- The default agent provider is **Anthropic OAuth** — it reuses Claude Code's
|
|
27
|
+
own login (`~/.claude/.credentials.json`). A fresh user needs **no** Anthropic
|
|
28
|
+
API key. Direct provider API keys (OpenAI, Gemini, Anthropic, etc.) are
|
|
29
|
+
optional and only needed if the user wants a non-default provider.
|
|
30
|
+
- OpenAI OAuth is also available: it logs in and writes `openai-oauth.json` in
|
|
31
|
+
the plugin data dir, or reuses an existing `~/.codex/auth.json`.
|
|
32
|
+
- All settings live in a **single unified config** at
|
|
33
|
+
`${CLAUDE_PLUGIN_DATA}/mixdog-config.json` with sections
|
|
34
|
+
`channels`, `memory`, `agent`, and `search`. There are no separate
|
|
35
|
+
`search-config.json` or `bot.json` files anymore. (Anthropic OAuth reuses
|
|
36
|
+
Claude Code's credentials, so there is no Anthropic token file to create; an
|
|
37
|
+
`anthropic-oauth-models.json` cache may appear automatically and is not user
|
|
38
|
+
config.)
|
|
39
|
+
- **Secrets are never written into the JSON.** Discord bot token,
|
|
40
|
+
agent/search provider API keys, and the webhook authtoken live in the **OS
|
|
41
|
+
keychain** (or `MIXDOG_*` env vars). The config file holds only non-secret
|
|
42
|
+
settings.
|
|
43
|
+
- **First install reconfigures Claude Code** (originals preserved): the
|
|
44
|
+
built-in `autoMemoryEnabled` / `awaySummaryEnabled` settings are turned off
|
|
45
|
+
in `~/.claude/settings.json` (mixdog memory/recap replace them), and
|
|
46
|
+
`~/.claude/CLAUDE.md` is backed up once, then taken over by the managed
|
|
47
|
+
rules block. Snapshots live under
|
|
48
|
+
`~/.claude/backups/mixdog-user-data/install-restore/`;
|
|
49
|
+
`node scripts/uninstall.mjs` restores both.
|
|
50
|
+
|
|
51
|
+
## Config structure & editing
|
|
52
|
+
|
|
53
|
+
- Config lives under the plugin data dir `~/.claude/plugins/data/mixdog-trib-plugin/` (the `CLAUDE_PLUGIN_DATA` env var overrides it). Two files matter:
|
|
54
|
+
- **user-workflow.json** — `roles[] {name, preset, permission}` maps each bridge role to a preset (the active role set is whatever this file defines — e.g. worker / reviewer / debugger / tester). This sets which model each role uses. To change a role's model, set its `preset` to one of the preset names below (takes effect LIVE — bridge dispatch re-reads this file on every spawn; only the Lead's injected `# Roles` list waits for the next SessionStart).
|
|
55
|
+
- **mixdog-config.json → `agent.presets[] {id, name, type, provider, model, tools, effort?, fast?, xaiCacheMaxInFlight?}`** defines each preset, e.g. opus-high → claude-opus-4-8 / high, composer-2.5 → grok-composer-2.5-fast, gpt-5.5-xhigh → gpt-5.5 / xhigh. `type` is `"bridge"` and `tools` is `"full"` for normal worker presets; `xaiCacheMaxInFlight` is a grok-oauth-only tuning knob. `agent.default` is the fallback preset for any role without its own mapping. To offer a new model, add a preset here first, then point a role at it in user-workflow.json.
|
|
56
|
+
- Edit via the Setup UI (Custom Workflow for role→preset, Agent presets for presets) or edit the JSON files directly (reloads next session). These are user data — no rebuild needed.
|
|
57
|
+
|
|
58
|
+
## Agent providers — supported list & onboarding
|
|
59
|
+
|
|
60
|
+
A preset's `provider` field selects the backend. Authoritative allow-list:
|
|
61
|
+
`initProviders()` in `src/agent/orchestrator/providers/registry.mjs`; the
|
|
62
|
+
openai-compatible ids + base URLs come from `OPENAI_COMPAT_PRESETS` in
|
|
63
|
+
`providers/openai-compat.mjs`. Any other id throws `unknown enabled provider`.
|
|
64
|
+
|
|
65
|
+
### Supported providers
|
|
66
|
+
|
|
67
|
+
| `provider` | Kind | Auth | Default base URL |
|
|
68
|
+
|---|---|---|---|
|
|
69
|
+
| `anthropic-oauth` | first-class | OAuth — reuses Claude Code login (default, no key) | — |
|
|
70
|
+
| `anthropic` | first-class | API key | — |
|
|
71
|
+
| `openai-oauth` | first-class (Codex) | OAuth (`openai-oauth.json` / `~/.codex/auth.json`) | — |
|
|
72
|
+
| `openai` | first-class | API key | — |
|
|
73
|
+
| `gemini` | first-class | API key | — |
|
|
74
|
+
| `grok-oauth` | first-class (Grok/xAI) | OAuth | — |
|
|
75
|
+
| `deepseek` | openai-compat | API key | `https://api.deepseek.com` |
|
|
76
|
+
| `xai` | openai-compat | API key | `https://api.x.ai/v1` |
|
|
77
|
+
| `nvidia` | openai-compat | API key | `https://integrate.api.nvidia.com/v1` |
|
|
78
|
+
| `ollama` | openai-compat (local) | none | `http://localhost:11434/v1` |
|
|
79
|
+
| `lmstudio` | openai-compat (local) | none | `http://localhost:1234/v1` |
|
|
80
|
+
|
|
81
|
+
### Where an API key goes (never in JSON)
|
|
82
|
+
|
|
83
|
+
Key-bearing providers (`openai`, `anthropic`, `gemini`, `deepseek`, `xai`,
|
|
84
|
+
`nvidia`) resolve their key in this precedence (`getAgentApiKey`):
|
|
85
|
+
`<PROVIDER>_API_KEY` env → `MIXDOG_AGENT_<PROVIDER>_APIKEY` env → OS keychain
|
|
86
|
+
account `agent.<provider>.apiKey` → alias env (`GROK_API_KEY` for `xai`).
|
|
87
|
+
|
|
88
|
+
Keychain is the canonical store — a provider key placed in `mixdog-config.json`
|
|
89
|
+
is ignored. On Windows the secret is a DPAPI file at
|
|
90
|
+
`${DATA}/secrets/agent.<provider>.apiKey.dpapi`; macOS/Linux use the OS keychain.
|
|
91
|
+
Store it via the Setup UI agent-key field (moves it to keychain, strips from
|
|
92
|
+
JSON), via `saveSecret('agent.<provider>.apiKey', key)`, or by exporting the
|
|
93
|
+
standard `<PROVIDER>_API_KEY` env. `ollama` / `lmstudio` are local and need no key.
|
|
94
|
+
|
|
95
|
+
### End-to-end: add a provider + model + role (e.g. DeepSeek as a worker)
|
|
96
|
+
|
|
97
|
+
1. **Validate + store the key.** Confirm it works (`GET <baseURL>/models` → 200),
|
|
98
|
+
then save it to keychain `agent.deepseek.apiKey` (or export `DEEPSEEK_API_KEY`).
|
|
99
|
+
2. **Enable the provider** (optional — auto-enabled once the key is present): add
|
|
100
|
+
`agent.providers.deepseek = { "enabled": true, "baseURL": "https://api.deepseek.com" }`
|
|
101
|
+
to `mixdog-config.json`.
|
|
102
|
+
3. **Register a preset** in `agent.presets[]`:
|
|
103
|
+
`{ "id": "deepseek-v4-pro", "name": "DEEPSEEK V4 PRO", "type": "bridge", "provider": "deepseek", "model": "deepseek-v4-pro", "tools": "full" }`
|
|
104
|
+
— use the provider's real model id (e.g. `deepseek-v4-pro`, `deepseek-v4-flash`).
|
|
105
|
+
4. **Map a role → preset** in `user-workflow.json`: repoint an existing role's
|
|
106
|
+
`preset`, or add `{ "name": "deepseek-worker", "preset": "deepseek-v4-pro", "permission": "full" }`.
|
|
107
|
+
For maintenance slots (explore / cycle* / scheduler / webhook) set
|
|
108
|
+
`agent.maintenance.<slot>` to a preset id instead.
|
|
109
|
+
|
|
110
|
+
**Effect timing:** new presets / providers / `agent.maintenance.*` and API keys
|
|
111
|
+
apply **next session** (daemon reload); a role→preset change in
|
|
112
|
+
`user-workflow.json` is **live** (re-read per bridge spawn). Ad-hoc one-off
|
|
113
|
+
override: `bridge spawn role=<any> preset=<id>`.
|
|
114
|
+
|
|
115
|
+
## File locations — defaults vs user data
|
|
116
|
+
|
|
117
|
+
`<plugin>` = `~/.claude/plugins/`. `<ver>` = the installed mixdog version
|
|
118
|
+
directory (check `<plugin>/cache/trib-plugin/mixdog/` for the actual value).
|
|
119
|
+
`${CLAUDE_PLUGIN_DATA}` (`${DATA}`) defaults to
|
|
120
|
+
`<plugin>/data/mixdog-trib-plugin/` and can be overridden by the env var.
|
|
121
|
+
|
|
122
|
+
| Layer | Path | What it is | Edit here? |
|
|
123
|
+
|---|---|---|---|
|
|
124
|
+
| **Defaults (seed)** | source `<plugin>/marketplaces/trib-plugin/defaults/` · active `<plugin>/cache/trib-plugin/mixdog/<ver>/defaults/` | shipped templates copied into user data on first run | no — read-only |
|
|
125
|
+
| **User config (live)** | `${DATA}/` = `<plugin>/data/mixdog-trib-plugin/` | the real config you actually edit | **yes** |
|
|
126
|
+
| **Secrets** | OS keychain · `MIXDOG_*` env · `${DATA}/secrets/` | tokens & API keys | yes — never inside config JSON |
|
|
127
|
+
| **Plugin / skill code** | active `<plugin>/cache/trib-plugin/mixdog/<ver>/` · source `<plugin>/marketplaces/trib-plugin/` | skill md, builtin tools, prompts | source-of-truth = marketplace |
|
|
128
|
+
|
|
129
|
+
**Default file → live file** (edit the live one):
|
|
130
|
+
|
|
131
|
+
| Purpose | Default (seed, do not edit) | Live (edit this) |
|
|
132
|
+
|---|---|---|
|
|
133
|
+
| Unified config | `defaults/mixdog-config.template.json` | `${DATA}/mixdog-config.json` |
|
|
134
|
+
| Role → preset | `defaults/user-workflow.json` | `${DATA}/user-workflow.json` |
|
|
135
|
+
| Hidden/internal roles | `defaults/hidden-roles.json` (loaded directly from plugin root, not seeded) | — |
|
|
136
|
+
| Per-role extra brief (optional) | — | `${DATA}/roles/<role>.md` |
|
|
137
|
+
| Prompt templates | `defaults/*-prompt.md`, `defaults/user-workflow.md` | seeded into `${DATA}` runtime |
|
|
138
|
+
|
|
139
|
+
**Precedence:** on first launch the `defaults/` seeds (incl.
|
|
140
|
+
`mixdog-config.template.json`) are copied into `${DATA}`. After that **`${DATA}`
|
|
141
|
+
wins** — editing a file under `defaults/` does NOT change an already-initialized
|
|
142
|
+
install. To change settings, edit the live file under `${DATA}`. A live file
|
|
143
|
+
that is deleted is **not** auto-recreated once the install is initialized — the
|
|
144
|
+
seed guard (`shouldSeedMissingUserData`) refuses it, drops a
|
|
145
|
+
`RECOVERY-REQUIRED.txt`, and asks you to restore from the `${DATA}` backup (or
|
|
146
|
+
intentionally reset the init marker). Only a never-initialized install seeds
|
|
147
|
+
`mixdog-config.json` from `defaults/`. Everything else
|
|
148
|
+
under `${DATA}` (logs, `pgdata/`, `sessions/`, `channels/`, `webhooks/`,
|
|
149
|
+
`*-oauth*.json`, model caches) is runtime state, not user config — leave it
|
|
150
|
+
alone.
|
|
151
|
+
|
|
152
|
+
## Config map — where every setting lives
|
|
153
|
+
|
|
154
|
+
Single source of truth is `${CLAUDE_PLUGIN_DATA}/mixdog-config.json` unless the
|
|
155
|
+
row names another file. `${DATA}` = `~/.claude/plugins/data/mixdog-trib-plugin/`.
|
|
156
|
+
**Effect** = when the change is picked up: `reload_config` (channels hot-reload
|
|
157
|
+
now) · `SessionStart` (next session inject) · `restart` (relaunch Claude Code /
|
|
158
|
+
dev full-restart) · `relaunch+flag` (relaunch with the channels flag).
|
|
159
|
+
|
|
160
|
+
**Channels / Discord**
|
|
161
|
+
|
|
162
|
+
| Setting | Key path | Example | Secret | Effect |
|
|
163
|
+
|---|---|---|---|---|
|
|
164
|
+
| Discord application id | `channels.discord.applicationId` | `"1485…"` | no | `reload_config` |
|
|
165
|
+
| Channel backend | `channels.backend` | `"discord"` | no | restart |
|
|
166
|
+
| Discord bot token | OS keychain / `MIXDOG_DISCORD_TOKEN` env | — | **yes** | restart |
|
|
167
|
+
| Main channel | `channels.channelsConfig.main.channelId` + `channels.mainChannel` | `"1485…"` | no | `reload_config` |
|
|
168
|
+
| Per-channel access | `channels.access.channels.<id>.{requireMention,allowFrom}` | `false` / `[]` | no | `reload_config` |
|
|
169
|
+
| DM policy | `channels.access.dmPolicy` (`allowlist` \| `disabled`) | `"allowlist"` | no | `reload_config` |
|
|
170
|
+
| Mention patterns | `channels.access.mentionPatterns[]` | `[]` | no | `reload_config` |
|
|
171
|
+
| Prompt injection | `channels.promptInjection.{mode,targetPath}` | `"claude_md"` / `"~/.claude/CLAUDE.md"` | no | restart |
|
|
172
|
+
| Quiet hours | `channels.quiet.{schedule,holidays}` | `"23:00-09:00"` / `"KR"` | no | `reload_config` |
|
|
173
|
+
| Quiet exceptions | `channels.schedules.respectQuiet` / `channels.webhook.respectQuiet` | `false` | no | `reload_config` |
|
|
174
|
+
| Webhook | `channels.webhook.{enabled,ngrokDomain}` | `true` / `"…ngrok-free.dev"` | no | `reload_config` |
|
|
175
|
+
| Webhook authtoken | keychain / env | — | **yes** | restart |
|
|
176
|
+
| `NGROK_BIN` | env var · Windows `HKCU\Environment\NGROK_BIN` | `…\ngrok.exe` | no | webhook restart (win) / relaunch (posix) |
|
|
177
|
+
|
|
178
|
+
**Memory**
|
|
179
|
+
|
|
180
|
+
| Setting | Key path | Example | Secret | Effect |
|
|
181
|
+
|---|---|---|---|---|
|
|
182
|
+
| Enable | `memory.enabled` | `true` | no | restart |
|
|
183
|
+
| Module gate | `modules.memory.enabled` | `true` | no | restart |
|
|
184
|
+
| Address form | `memory.user.title` | `"길동님"` | no | `SessionStart` |
|
|
185
|
+
| Cycle intervals | `memory.cycle1.interval` / `memory.cycle2.interval` | `"10m"` / `"1h"` | no | restart |
|
|
186
|
+
|
|
187
|
+
> `memory.enabled: false` only pauses the periodic cycle scheduler.
|
|
188
|
+
> `modules.memory.enabled: false` (Setup UI → General → Modules) is the real
|
|
189
|
+
> off switch: it stops the memory worker, hides the `recall` / `memory` tools,
|
|
190
|
+
> and skips the channels worker that depends on them.
|
|
191
|
+
|
|
192
|
+
**Agent / models**
|
|
193
|
+
|
|
194
|
+
| Setting | File · key path | Example | Secret | Effect |
|
|
195
|
+
|---|---|---|---|---|
|
|
196
|
+
| Preset definitions | `agent.presets[] {id,provider,model,effort,fast,name}` | see file | no | next session |
|
|
197
|
+
| Default preset | `agent.default` | `"opus-high"` | no | next session |
|
|
198
|
+
| Maintenance presets | `agent.maintenance.{explore,cycle1,cycle2,cycle3,scheduler,webhook}` (unset keys fall back to the built-in `haiku` default) | `"haiku"` (all) | no | restart |
|
|
199
|
+
| Role → preset | **user-workflow.json** `roles[].preset` (must equal a `presets[].id`) | `"composer-2.5"` | no | `SessionStart` (`# Roles`) |
|
|
200
|
+
| Anthropic access | reuses Claude Code login `~/.claude/.credentials.json` | — | OAuth | — (default; no key) |
|
|
201
|
+
| OpenAI OAuth | `${DATA}/openai-oauth.json` or `~/.codex/auth.json` | — | OAuth | restart |
|
|
202
|
+
| Grok / xAI OAuth | `grok-oauth` login token (keychain) | — | OAuth | restart |
|
|
203
|
+
| Direct provider API key | keychain / `MIXDOG_*` env | — | **yes** | restart |
|
|
204
|
+
|
|
205
|
+
**Search**
|
|
206
|
+
|
|
207
|
+
| Setting | Key path | Example | Secret | Effect |
|
|
208
|
+
|---|---|---|---|---|
|
|
209
|
+
| Enable | `search.enabled` | `true` | no | restart |
|
|
210
|
+
| Provider | `search.provider` | `"grok-oauth"` | no | restart |
|
|
211
|
+
| Raw-search keys | `search.rawSearch.credentials.<firecrawl\|tavily\|exa>.apiKey` (prefer keychain) | `""` | **sensitive** | restart |
|
|
212
|
+
| xAI search key | uses the **Agent xAI key** (config UI / keychain), not a raw-search key | — | **sensitive** | restart |
|
|
213
|
+
| Result / timeout limits | `search.rawSearch.maxResults` · `search.requestTimeoutMs` | `10` / `120000` | no | restart |
|
|
214
|
+
| Crawl bounds | `search.crawl.{maxPages,maxDepth,sameDomainOnly}` | `10` / `2` / `true` | no | restart |
|
|
215
|
+
| Per-provider model opts | `search.modelOptions.<provider>.{effort,fast}` | `"medium"` / `true` | no | restart |
|
|
216
|
+
|
|
217
|
+
**Misc**
|
|
218
|
+
|
|
219
|
+
| Setting | File · key path | Example | Secret | Effect |
|
|
220
|
+
|---|---|---|---|---|
|
|
221
|
+
| Home dir access | `capabilities.homeAccess` | `true` | no | restart |
|
|
222
|
+
| Commit identity emails | `cwd.identityEmails[]` | `["dev@…","…@gmail.com"]` | no | restart |
|
|
223
|
+
| Extra repo-scan roots | `cwd.extraRoots[]` | `[]` | no | restart |
|
|
224
|
+
| Channels launch flag | CLI `claude --dangerously-load-development-channels plugin:mixdog@trib-plugin` | — | no | relaunch+flag |
|
|
225
|
+
|
|
226
|
+
> The `search.rawSearch.credentials.*.apiKey` slots are a write-side input
|
|
227
|
+
> only: a value placed there is moved into the OS keychain on Setup save and
|
|
228
|
+
> stripped from the JSON. Runtime key lookup reads `MIXDOG_*` env and the
|
|
229
|
+
> keychain — a plaintext key left in the JSON is ignored.
|
|
230
|
+
|
|
231
|
+
## Procedure (onboarding — fill what's missing)
|
|
232
|
+
|
|
233
|
+
1. Read `${CLAUDE_PLUGIN_DATA}/mixdog-config.json` and list what's missing or
|
|
234
|
+
empty across its sections:
|
|
235
|
+
- `channels` — Discord application/channel wiring.
|
|
236
|
+
- `memory` — `memory.user.title` is the address form the assistant uses for
|
|
237
|
+
the user.
|
|
238
|
+
- `agent` — provider selection (default: Anthropic OAuth; no key required).
|
|
239
|
+
- `search` — search provider selection (optional).
|
|
240
|
+
- `NGROK_BIN` env var (only when webhook public exposure is wanted).
|
|
241
|
+
For secrets, check whether they are *present* (keychain/env), not their
|
|
242
|
+
values — never read or echo a secret.
|
|
243
|
+
2. Pick one missing item. For a secret, tell the user where to get the value
|
|
244
|
+
(provider console URL + the exact field to copy) and wait for them to paste
|
|
245
|
+
it. For agent access, remind them the default already works via Claude Code
|
|
246
|
+
login — a key is only needed for a different provider.
|
|
247
|
+
- `memory.user.title`: ask for the exact address form they want
|
|
248
|
+
(e.g., "길동님", "Alex"); do not ask for or store a separate first/last
|
|
249
|
+
name. The builder injects only this title.
|
|
250
|
+
3. Persist the value:
|
|
251
|
+
- **Non-secret settings** → write to the right section of
|
|
252
|
+
`mixdog-config.json`.
|
|
253
|
+
- **Secrets** (Discord token, agent/search API keys, webhook authtoken) →
|
|
254
|
+
store in the OS keychain. Never write them into the JSON, never echo them
|
|
255
|
+
back, never pass them through tool args / logs.
|
|
256
|
+
- **OAuth** → no key to store: Anthropic uses Claude Code's `~/.claude`
|
|
257
|
+
credentials; OpenAI OAuth runs its login flow (`openai-oauth.json`) or
|
|
258
|
+
reuses `~/.codex/auth.json`.
|
|
259
|
+
4. After a `channels`-related change (schedules / webhooks / events), call
|
|
260
|
+
`reload_config` to re-register them. Note this is **channels-focused** —
|
|
261
|
+
it does not hot-reload agent/search providers.
|
|
262
|
+
5. Loop to the next missing item.
|
|
263
|
+
6. When nothing critical is missing, confirm with one short line and stop.
|
|
264
|
+
|
|
265
|
+
## Procedure (editing existing config)
|
|
266
|
+
|
|
267
|
+
1. Identify what the user wants to change (preset for a role, new preset,
|
|
268
|
+
channels, memory title, search provider, etc.).
|
|
269
|
+
2. Use **Config structure & editing** above to pick the correct file/section.
|
|
270
|
+
3. Apply **one field per turn** unless the user explicitly batches related
|
|
271
|
+
edits.
|
|
272
|
+
4. For role model changes: confirm the target `agent.presets` id exists (or
|
|
273
|
+
add the preset first), then update `user-workflow.json` `roles[].preset`.
|
|
274
|
+
Remind that `# Roles` in the system prompt updates on the next SessionStart.
|
|
275
|
+
5. After `channels`-related edits, call `reload_config`.
|
|
276
|
+
|
|
277
|
+
## Launching with channels
|
|
278
|
+
|
|
279
|
+
Discord channels are gated behind a launch flag. Remind the user that mixdog
|
|
280
|
+
channels only come up when Claude Code is started with:
|
|
281
|
+
|
|
282
|
+
```sh
|
|
283
|
+
claude --dangerously-load-development-channels plugin:mixdog@trib-plugin
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Without that flag the channel runtime stays disabled regardless of config.
|
|
287
|
+
|
|
288
|
+
## NGROK_BIN auto-detection
|
|
289
|
+
|
|
290
|
+
Only runs when the user wants ngrok-backed public webhook URLs and
|
|
291
|
+
`process.env.NGROK_BIN` is unset or points at a missing file. The plugin's
|
|
292
|
+
`resolveNgrokBin()` reads `NGROK_BIN` from the environment, and on Windows also
|
|
293
|
+
from the `HKCU\Environment` registry — there is no PATH heuristic, so the
|
|
294
|
+
assistant must locate the binary deterministically and persist the chosen path.
|
|
295
|
+
|
|
296
|
+
1. Probe these candidate paths in order. Use the first that exists:
|
|
297
|
+
- Windows winget: `%LOCALAPPDATA%\Microsoft\WinGet\Packages\Ngrok.Ngrok_Microsoft.Winget.Source_8wekyb3d8bbwe\ngrok.exe`
|
|
298
|
+
- Windows scoop: `%USERPROFILE%\scoop\apps\ngrok\current\ngrok.exe`
|
|
299
|
+
- Windows chocolatey: `C:\ProgramData\chocolatey\bin\ngrok.exe`
|
|
300
|
+
- POSIX homebrew (Apple silicon): `/opt/homebrew/bin/ngrok`
|
|
301
|
+
- POSIX homebrew (Intel): `/usr/local/bin/ngrok`
|
|
302
|
+
- POSIX apt / generic: `/usr/bin/ngrok`
|
|
303
|
+
2. If none match, ask the user for an absolute path or for an install command
|
|
304
|
+
(`winget install Ngrok.Ngrok`, `brew install ngrok/ngrok/ngrok`, etc.) —
|
|
305
|
+
never auto-install.
|
|
306
|
+
3. Show the discovered path to the user verbatim and ask for explicit
|
|
307
|
+
confirmation before writing.
|
|
308
|
+
4. Persist the chosen path:
|
|
309
|
+
- Windows: `setx NGROK_BIN "<path>"` (permanent, takes effect in new shells).
|
|
310
|
+
- POSIX: append `export NGROK_BIN="<path>"` to the user's shell rc
|
|
311
|
+
(`~/.bashrc` / `~/.zshrc`).
|
|
312
|
+
5. After persist:
|
|
313
|
+
- **Windows**: `setx` writes `HKCU\Environment\NGROK_BIN`, which
|
|
314
|
+
`resolveNgrokBin()` reads at start time, so a webhook (re)start picks it up
|
|
315
|
+
without relaunching Claude Code.
|
|
316
|
+
- **POSIX**: the exported var only reaches a new shell, so the user must
|
|
317
|
+
relaunch Claude Code (with the channels flag) for it to take effect.
|
|
318
|
+
|
|
319
|
+
## Common errors & symptoms
|
|
320
|
+
|
|
321
|
+
| Symptom | Likely cause | Check / fix |
|
|
322
|
+
|---|---|---|
|
|
323
|
+
| Bot offline, no channels, total silence | launch flag missing | start with `--dangerously-load-development-channels plugin:mixdog@trib-plugin` |
|
|
324
|
+
| Bot online but never replies in a channel | not invited, or `requireMention:true` with no mention | invite bot to server · `channels.access.channels.<id>.requireMention` |
|
|
325
|
+
| DMs ignored | sender not in `channels.access.allowFrom` | add the user ID to `channels.access.allowFrom` |
|
|
326
|
+
| Role still uses old model after edit | a worker spawned BEFORE the edit keeps its bound preset (a `send` reuses it); the Lead's injected `# Roles` list also lags to SessionStart | spawn a FRESH worker — a new dispatch re-reads `user-workflow.json` live; relaunch only refreshes the Lead's `# Roles` display |
|
|
327
|
+
| Role falls back to default / "preset not found" | `roles[].preset` has no matching `agent.presets[].id` | reconcile ids across user-workflow.json ↔ mixdog-config.json |
|
|
328
|
+
| `reload_config` ran but model/search unchanged | reload is **channels-only** | relaunch for agent / memory / search changes |
|
|
329
|
+
| Webhook public URL dead / 404 | `NGROK_BIN` unset or `channels.webhook.ngrokDomain` mismatch | env / `HKCU\Environment` + `channels.webhook` |
|
|
330
|
+
| Search fails or returns empty | `search.enabled:false`, missing provider key, or expired OAuth | `search.provider` + credentials / keychain |
|
|
331
|
+
| "token missing" / secret not found | keychain empty or `MIXDOG_*` env unset | re-store the secret in the keychain |
|
|
332
|
+
| Address form (title) unchanged | same session | wait for next SessionStart (rules re-inject — CLAUDE.md or hook mode) |
|
|
333
|
+
| 401 / OAuth expired | login lapsed | re-login (Anthropic = Claude Code login · OpenAI = codex auth · grok) |
|
|
334
|
+
| Config edits silently ignored | invalid JSON broke the parse | validate `mixdog-config.json` syntax |
|
|
335
|
+
| Quiet at night | `channels.quiet.schedule` active | `channels.quiet` (`respectQuiet` per surface) |
|
|
336
|
+
|
|
337
|
+
## Notes
|
|
338
|
+
|
|
339
|
+
- One field per turn — do not batch unrelated prompts.
|
|
340
|
+
- If a value looks malformed (wrong prefix, wrong length), say so and re-ask
|
|
341
|
+
instead of storing it.
|
|
342
|
+
- For the Discord bot token: also remind the user to invite the bot to the
|
|
343
|
+
target server before testing.
|
|
344
|
+
- Never overwrite an existing non-empty secret without explicit confirmation.
|
|
345
|
+
- NGROK_BIN is skipped entirely when the user does not need public webhook URLs
|
|
346
|
+
(local-only routing works without ngrok).
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: webhook-add
|
|
3
|
+
description: Invoke when the user's intent is to register a new inbound webhook listener in mixdog so an external service can deliver events to a channel. Writes a new entry under `${CLAUDE_PLUGIN_DATA}/webhooks/<name>/`, generates a secret if not given, reloads config, and returns the inbound URL + secret to paste into the source service. Do not invoke for inspecting deliveries of an existing webhook.
|
|
4
|
+
version: 0.3.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# webhook-add
|
|
8
|
+
|
|
9
|
+
Register a new webhook listener in mixdog.
|
|
10
|
+
|
|
11
|
+
## When to invoke
|
|
12
|
+
|
|
13
|
+
User intent: stand up a new inbound webhook endpoint so an external service (GitHub, generic HTTP source, etc.) can deliver events into mixdog. The trigger is the intent, not specific phrasing.
|
|
14
|
+
|
|
15
|
+
Skip if the user is asking to *inspect* deliveries of an existing webhook (read `deliveries.jsonl` directly).
|
|
16
|
+
|
|
17
|
+
## Routing model (channel presence — no `mode`)
|
|
18
|
+
|
|
19
|
+
A webhook with **no `channel`** is injected into the current (Lead) session on delivery — the session handles it with full context. A webhook **with a `channel`** is dispatched to the hidden `webhook-handler` role, which reports the result to that Discord channel (so it needs a `model`). Channel presence is the only switch; there is no `mode` field.
|
|
20
|
+
|
|
21
|
+
**Skip protocol (channel-direct only):** for a channel webhook, `instructions.md` can tell the handler to emit `[meta:silent]` as the FIRST line when a delivery has nothing worth reporting (dedup, docs-only, non-default branch, etc.) — that drops the notification entirely (no channel post). Use only for true skips, never to suppress an actionable finding.
|
|
22
|
+
|
|
23
|
+
## Storage contract
|
|
24
|
+
|
|
25
|
+
Writes to `${CLAUDE_PLUGIN_DATA}/webhooks/<name>/{config.json, instructions.md}`. `role` is always the hidden `webhook-handler` (the reader defaults it; setup-server also forces it) — do NOT write a `role` key.
|
|
26
|
+
|
|
27
|
+
## Required fields
|
|
28
|
+
|
|
29
|
+
Collect from the user message; ask only for the truly missing ones in plain text (no AskUserQuestion).
|
|
30
|
+
|
|
31
|
+
| Field | Required | Default | Notes |
|
|
32
|
+
|---|---|---|---|
|
|
33
|
+
| `name` | yes | — | slug `[a-z0-9-]+`, becomes directory name |
|
|
34
|
+
| `parser` | no | `github` | `github` (HMAC SHA256 + GitHub event headers) or `generic` (raw JSON body) |
|
|
35
|
+
| `secret` | no | auto | hex string ≥ 32 bytes; auto-generate via `crypto.randomBytes(24).toString('hex')` if absent. Required in practice — an instructions.md endpoint with no secret is rejected (fail-closed). |
|
|
36
|
+
| `channel` | no | — (inject to current session) | set to a Discord channel label to dispatch DIRECT to that channel instead of injecting |
|
|
37
|
+
| `model` | conditional | — | REQUIRED when `channel` is set (direct dispatch runs the webhook-handler with this preset, e.g. `haiku`). Omit when injecting — the session handles it. |
|
|
38
|
+
| `instructions` | yes | — | what should happen on inbound delivery (markdown body) |
|
|
39
|
+
|
|
40
|
+
## Procedure
|
|
41
|
+
|
|
42
|
+
1. Parse the user's request. Extract name, parser, channel, and instructions if stated. For missing required fields ask in one short message; do NOT proceed with partial data.
|
|
43
|
+
2. Validate:
|
|
44
|
+
- `name` matches `^[a-z0-9][a-z0-9-]*$`, length ≤ 64
|
|
45
|
+
- `parser` ∈ {`github`, `generic`}
|
|
46
|
+
- if `channel` is set, `model` MUST also be set (direct dispatch has no preset fallback)
|
|
47
|
+
- target directory `${CLAUDE_PLUGIN_DATA}/webhooks/<name>/` does NOT already exist
|
|
48
|
+
3. If `secret` not provided, generate a 48-char hex string via `bash` (`openssl rand -hex 24` or Node `crypto.randomBytes(24).toString('hex')`).
|
|
49
|
+
4. Create directory + write two files atomically (tmp + rename):
|
|
50
|
+
- `config.json` — omit defaults; NEVER write `mode` or `role`:
|
|
51
|
+
```json
|
|
52
|
+
// inject into current session (no channel)
|
|
53
|
+
{ "secret": "<hex>", "parser": "github" }
|
|
54
|
+
|
|
55
|
+
// direct to a channel (channel + model required)
|
|
56
|
+
{ "secret": "<hex>", "parser": "github", "channel": "main", "model": "haiku" }
|
|
57
|
+
```
|
|
58
|
+
- `instructions.md`: the user-provided body.
|
|
59
|
+
5. Call `mcp__plugin_mixdog_mixdog__reload_config` to register the new endpoint.
|
|
60
|
+
6. Resolve the inbound URL: form `<base>/webhook/<name>` (singular `webhook`, NOT `webhooks`). The `<base>` is the webhook server's public domain (channels config `webhook.ngrokDomain`; legacy `webhook.domain` is a fallback only — e.g. an ngrok URL). If it cannot be resolved, return the relative `/webhook/<name>` path and tell the user to prepend their tunnel/public URL.
|
|
61
|
+
7. Report back in the user's configured language with:
|
|
62
|
+
- inbound URL (to paste into the source service)
|
|
63
|
+
- secret (so the user can paste it into the source service's webhook secret field)
|
|
64
|
+
- parser, and where output goes (current session vs which channel)
|
|
65
|
+
- reminder: rotate the secret if it is ever shown in a shared channel
|
|
66
|
+
- for a GitHub source: in the repo's **Settings → Webhooks → Add webhook**, set Payload URL = the inbound URL, Content type = `application/json`, Secret = the generated secret, and "Which events" = **Just the push event** (matches the `github` parser default).
|
|
67
|
+
|
|
68
|
+
## Failure handling
|
|
69
|
+
|
|
70
|
+
- File write error → report path:error, do not retry blindly.
|
|
71
|
+
- `reload_config` error → file is written but not live; tell user to restart Claude Code or rerun.
|
|
72
|
+
- URL resolution miss → still return the secret + relative `/webhook/<name>` path; user can build the full URL.
|
|
73
|
+
|
|
74
|
+
## Anti-patterns
|
|
75
|
+
|
|
76
|
+
- Do not show the secret in tool args / external logs. Once the user has copied it, treat it as sensitive.
|
|
77
|
+
- Do not auto-overwrite an existing webhook with the same name without explicit confirmation — losing the secret invalidates the source-side configuration.
|
|
78
|
+
- Do not skip `reload_config`; without it the new endpoint will not respond.
|
|
79
|
+
- Do not write a `mode` / `role` key. Routing is decided purely by `channel` presence; `role` is always the hidden `webhook-handler`.
|
|
80
|
+
- Do not set `channel` without `model` — direct dispatch is rejected with no preset.
|
|
81
|
+
- Do not use `/webhooks/<name>` (plural) for the inbound URL — the live route is `/webhook/<name>` (singular).
|