CLAUDE.md · diff

git:20260327.6081e19 to git:20260328.9e12a79

5 added, 288 removed. Audit B to A.

- # Myco — Collective Agent Intelligence
-
- Claude Code plugin that captures session knowledge (events, observations, summaries) into a SQLite-backed intelligence graph and serves it back via MCP tools.
-
- ## Dogfooding
-
- We develop Myco using Myco. The plugin is loaded from the local working directory, not installed from the marketplace:
-
- ```sh
- claude --plugin-dir .
- ```
-
- This sets `${CLAUDE_PLUGIN_ROOT}` to the repo root. The vault lives at `~/.myco/vaults/myco/` (configured in `.env` and `.claude/settings.json`).
-
- **Implications for development:**
-
- - After changing hook or daemon code, you MUST run `make build` and then `myco-dev restart` for the daemon. Hooks pick up new code on next invocation; the daemon does not.
- - The MCP server reloads on `/reload-plugins`, but a full session restart may be needed for connection changes.
- - Session data from your development sessions is real vault data. Be careful with destructive vault operations — you'll lose your own session history.
-
- **How end users install Myco (not how we run it):**
-
- ```sh
- curl -fsSL https://myco.sh/install.sh | sh # Installs Node package globally
- cd your-project
- myco init # Interactive wizard: embedding provider, model, plugin registration
- ```
-
- `myco init` runs an interactive wizard that guides users through embedding provider selection (Ollama, OpenRouter, OpenAI, or skip), model selection, vault creation, and symbiont plugin registration. Use `myco doctor` to verify setup health.
-
- **Dev binary setup:**
-
- ```sh
- make dev-link # Creates myco-dev symlink, sets MYCO_CMD=myco-dev in settings.json
- make dev-unlink # Removes myco-dev, clears MYCO_CMD
- ```
-
- After changing hook or daemon code, run `make build` — the wrapper script picks up the new build automatically.
-
- ## Non-Goals
-
- - This is NOT a general-purpose knowledge base or note-taking app. Do not add external REST APIs or public-facing web services. The local dashboard is the configuration and operations interface.
- - This is NOT a framework. Do not add plugin systems, extensibility hooks, or abstraction layers for hypothetical consumers.
- - Do not add dependencies on cloud services. All intelligence runs locally (Ollama, LM Studio) or via lightweight API (Anthropic).
-
- ## Architecture
-
- ```
- src/
- agent/ # Intelligence pipeline: wave-based DAG executor, task definitions, orchestrator, provider abstraction
- capture/ # Event buffering (EventBuffer) and buffer-based turn fallback
- config/ # Vault config loading and Zod schema
- context/ # Context injection for UserPromptSubmit hook
- daemon/ # Long-lived HTTP daemon: batch processing, session lifecycle, plan watching, digest
- hooks/ # Claude Code hook entry points (thin — delegate to daemon)
- index/ # SQLite FTS5 + sqlite-vec vector search
- intelligence/ # LLM backend abstraction (Ollama, LM Studio, Anthropic)
- mcp/ # MCP server + tool handlers
- prompts/ # LLM prompt templates (extraction, summary, title, classification)
- symbionts/ # Symbiont adapters (Claude Code, Cursor) for transcript discovery, parsing, and plugin registration
- vault/ # Reader, writer, Zod schemas for database records
- tests/ # Mirrors src/ structure: tests/<module>.test.ts
- hooks/ # Hook registration shell scripts (invoke dist/src/hooks/*.js)
- skills/ # Skill markdown files (subdirectory per skill)
- .claude-plugin/ # Claude Code plugin manifest + marketplace catalog
- .cursor-plugin/ # Cursor plugin manifest + marketplace catalog
- .github/ # VS Code Copilot agent plugin manifest (also CI workflows)
- .mcp.json # MCP server config for VS Code (servers format)
- ui/ # React + Tailwind dashboard (Vite build → dist/ui/)
- src/
- components/ # UI components (ui/, topology/, config/, operations/)
- hooks/ # React hooks (use-daemon, use-config, use-power-query, etc.)
- layout/ # Layout with sidebar navigation
- lib/ # Utilities (api, cn, constants)
- pages/ # Dashboard, Configuration, Operations, Logs
- providers/ # Theme, Font, Power providers
- ```
-
- ### Dashboard
-
- The daemon serves a React SPA at `http://localhost:<port>/` for configuration management and operational triggers.
-
- **Development:** `cd ui && MYCO_DAEMON_PORT=<port> npx vite dev` — Vite dev server proxies API calls to the daemon.
-
- **Build:** `make build` runs both `tsup` (backend) and `vite build` (frontend). Output: `dist/ui/`.
-
- **API routes** are thin handlers in `src/daemon/api/` that delegate to shared services in `src/services/`. The CLI and API use the same code paths — no logic duplication.
-
- ### Module Boundaries
-
- - **Hooks MUST be thin.** Hook entry points in `src/hooks/` MUST delegate to the daemon via `DaemonClient`. Hooks MUST NOT contain business logic, LLM calls, or complex processing. If the daemon is unreachable, hooks spawn it via `client.ensureRunning()` and buffer events to disk for later processing.
- - **The daemon is the authority.** All event processing, session recording, spore extraction, and embedding happen in the daemon (`src/daemon/main.ts`). Hooks send events; the daemon decides what to do with them.
- - **MCP server config MUST be in `plugin.json`.** The `mcpServers` field in `.claude-plugin/plugin.json` is the only way to register MCP servers for plugins loaded via `--plugin-dir`. Do NOT use standalone `.mcp.json` for plugin MCP servers.
- - **Digest is a daemon task.** The digest engine runs inside the daemon process alongside batch processing and plan watching. It is NOT a hook or MCP server — it produces digest extracts that are served by hooks and MCP tools at query time.
- - **Agent phases execute in parallel waves.** The executor topologically sorts phases by their `dependsOn` fields into waves using Kahn's algorithm. Phases in the same wave run in parallel via `Promise.allSettled()`. Each phase gets isolated provider env via `buildPhaseEnv()`, passed to the SDK's `env` option — no `process.env` mutation.
- - **All periodic/polling work MUST use the PowerManager.** Do not use `setInterval` or `setTimeout` for recurring daemon jobs. Register jobs with `powerManager.register()` so they respect the activity-based power states (active → idle → sleep → deep_sleep). The PowerManager is the single authority for when background work executes.
-
- ## Data Preservation
-
- **Every write path MUST be additive. Never overwrite or delete accumulated session data.**
-
- This is Myco's core contract. Violations:
-
- - Session records are rebuilt from the agent's authoritative transcript on each stop event. The transcript file (e.g., Claude's `.jsonl`) is the source of truth — all turns are re-parsed and the conversation section is regenerated in full. Data preservation is guaranteed by the transcript being append-only, not by the session record's write logic.
- - The degraded stop path (`src/hooks/stop.ts`) MUST NOT write a session file if one already exists. It returns early; the daemon handles it when it's back.
- - Buffer files (`buffer/<session-id>.jsonl`) MUST NOT be deleted on session unregister. Session reload (SessionEnd → SessionStart) reuses the same session ID. Buffers are cleaned up by age (>24h) on daemon startup only.
- - `observation_type` in spore frontmatter accepts any string (`z.string()`). The LLM prompt guides types; the schema MUST NOT reject unexpected values.
-
- ## Session ID Is the Source of Truth
-
- Do not tie state management to hook lifecycle events (SessionEnd, SessionStart). The agent will reload, resume, and trigger these hooks unpredictably. Session ID is the durable identifier — key all persistent state to it. Clean up based on age/staleness, never based on lifecycle transitions.
-
- React to the **content** of hook payloads, not the event type.
-
- ## Idempotence by Default
-
- Every write operation MUST be safe to run twice with the same input. No "first-time" vs "subsequent" branching that produces different structures — the output MUST be identical regardless of how many times the operation runs.
-
- Concrete requirements:
-
- - `writeSpore`, `writeArtifact`, `writeSession`, `writePlan`, `writeTeamMember` MUST produce the same file content given the same input, whether or not the file already exists.
- - Startup tasks (migration, buffer cleanup, index rebuild) MUST be idempotent. Running the daemon startup sequence twice in a row MUST NOT move, duplicate, or corrupt data.
- - `indexNote` and `indexAndEmbed` MUST upsert, not insert. Re-indexing an already-indexed note MUST NOT create duplicates.
-
- If an operation cannot be made idempotent, it MUST be guarded by an explicit check (e.g., "skip if already migrated") and that guard MUST be documented in the code.
-
- ## No Magic Literals
-
- Numeric and string constants MUST NOT appear inline in logic. Extract them as named constants at module scope or in a shared constants file.
-
- This applies to:
-
- - **Truncation limits:** Every `.slice(0, N)` MUST reference a named constant (e.g., `EMBEDDING_INPUT_LIMIT`, `PROMPT_PREVIEW_CHARS`, `CANDIDATE_CONTENT_PREVIEW`). The constant name documents the intent; the number alone does not.
- - **Timeouts and thresholds:** Durations (e.g., `24 * 60 * 60 * 1000` for buffer cleanup), retry counts, similarity thresholds — all MUST be named constants.
- - **Token estimates:** The `chars / 4` heuristic MUST use a named constant (`CHARS_PER_TOKEN = 4`) so it can be found and updated in one place.
- - **Config defaults:** Zod `.default()` values are acceptable as-is — the schema IS the documentation. But defaults used outside Zod schemas (e.g., fallback values in constructors) MUST be named constants.
-
- Exceptions: array indices (`[0]`), string operations (`.slice(0, 10)` for ISO date prefix), and loop bounds derived from data (`i < items.length`) are not magic literals.
-
- ## Naming Conventions
-
- - **Spore files:** `spores/{normalized_type}/{observation_type}-{session_id_last_6}-{timestamp}.md` (e.g., `spores/gotcha/gotcha-ac5220-1773416089650.md`). The subdirectory name normalizes underscores to hyphens (`bug_fix` → `bug-fix/`).
- - **Session files:** `sessions/{YYYY-MM-DD}/session-{session_id}.md`
- - **Imports:** Use `@myco/*` path aliases mapping to `src/*`
- - **Tests:** `tests/<module>.test.ts` mirroring `src/<module>.ts`
-
- ## Glossary
-
- | Term | Definition |
- |------|-----------|
- | **Digest** | Continuous reasoning process that synthesizes vault knowledge into pre-computed context extracts. Runs as a daemon task on an adaptive timer. |
- | **Extract** | Tiered context representation at a specific token budget (1500/3000/5000/10000). Stored in `digest_extracts` table. |
- | **Substrate** | New or updated database records not yet digested. Input to a digest cycle. |
- | **Trace** | Append-only audit chain of digest cycles. Stored in `agent_runs` and `agent_reports` tables. |
- | **Metabolism** | Adaptive processing rate of the digest system. Active → cooling → dormant. |
- | **Dormancy** | Digest timer suspended when no new substrate arrives for an extended period. |
- | **Activation** | Return from dormancy to active metabolism, triggered by new session events. |
- | **Spore** | Discrete observation extracted from session activity (gotcha, decision, discovery, trade-off, bug fix). Stored in `spores` table. |
- | **Wisdom** | Higher-order observation synthesized from 3+ related spores. Stored as spore with `observation_type: 'wisdom'` and `properties.consolidated_from`. |
- | **Lineage edge** | Automatic graph connection created by daemon on insert: FROM_SESSION, EXTRACTED_FROM, HAS_BATCH, DERIVED_FROM. No LLM needed. |
- | **Semantic edge** | Intelligence graph connection created by agent: RELATES_TO, SUPERSEDED_BY, REFERENCES, DEPENDS_ON, AFFECTS. LLM-driven. |
- | **Graph edge** | Stored in `graph_edges` table. Supports cross-type references between session, batch, spore, and entity nodes. |
- | **Symbiont** | External coding agent that Myco integrates with (Claude Code, Cursor). Named for the mycorrhizal symbiotic relationship. Declared via YAML manifests in `src/symbionts/manifests/`. |
- | **Wave** | Group of phases whose dependencies are all satisfied, executing in parallel via `Promise.allSettled()`. The executor computes waves from the phase `dependsOn` DAG using topological sort. |
- | **Phase dependency** | DAG edge between phases declared via `dependsOn` in task YAML. Phases depend on named predecessors; the executor resolves these into execution waves. |
-
- ## Vault Structure
-
- ```
- ~/.myco/vaults/<vault-name>/
- myco.yaml # Vault configuration
- daemon.json # Running daemon PID/port
- index.db # SQLite FTS5 index
- vectors.db # sqlite-vec vector embeddings
- buffer/ # Per-session JSONL event buffers (ephemeral)
- sessions/ # Session notes by date
- spores/ # Observation notes (subdirectories by type: gotcha/, decision/, etc.)
- plans/ # Plan notes
- artifacts/ # Artifact references
- attachments/ # Images extracted from session transcripts
- team/ # Team member notes
- digest/ # Pre-computed context extracts and digest trace
- logs/ # Daemon logs
- ```
-
- ## Quality Gates
-
- Before committing:
-
- ```sh
- make check
- ```
-
- This runs `make lint` (tsc --noEmit) then `make test` (vitest run). Both MUST pass.
-
- To build (which also runs check first):
-
- ```sh
- make build
- ```
-
- ### Available Make targets
-
- | Target | What it does |
- |--------|-------------|
- | `make build` | Runs `check`, then `npm run build` (tsup bundle) |
- | `make check` | Runs `lint` + `test` — the pre-commit gate |
- | `make lint` | `tsc --noEmit` — type checking only, strict mode |
- | `make test` | `vitest run` — all tests |
- | `make watch` | `tsc --watch` for development |
- | `make clean` | Remove `dist/` |
- | `make install` | `npm install` |
-
- - `make check` MUST pass with zero errors before committing.
- - Do NOT skip or disable tests to make the build pass.
-
- ## Golden Paths
-
- ### Add a new MCP tool
-
- 1. Create handler in `src/mcp/tools/<tool-name>.ts`
- 2. Add tool definition to `TOOL_DEFINITIONS` array in `src/mcp/server.ts`
- 3. Add case to the `CallToolRequestSchema` switch in `src/mcp/server.ts`
- 4. Add tests in `tests/mcp/tools/<tool-name>.test.ts`
-
- ### Add a new hook
-
- 1. Create entry point in `src/hooks/<hook-name>.ts` — keep it thin, export `main()`
- 2. Create entry wrapper in `src/entries/<hook-name>.ts` that imports and calls `main()`
- 3. Add hook name to the `HOOK_DISPATCH` map in `src/cli.ts`
- 4. Add hook entry to `hooks/hooks.json` using `${CLAUDE_PLUGIN_ROOT}/bin/myco-run hook <hook-name>` command
- 5. The hook SHOULD send events to the daemon via `DaemonClient`; only fall back to local processing if the daemon is unreachable
-
- ### Add a new daemon route
-
- 1. Add `server.registerRoute()` call in `src/daemon/main.ts`
- 2. Follow the pattern: validate input → process → write to vault → index → embed
- 3. Embedding is fire-and-forget (`.then()/.catch()`) — never block the response on embedding
-
- ### Add a new API route (dashboard)
-
- 1. Create handler in `src/daemon/api/<name>.ts` — thin handler that delegates to shared services
- 2. If the operation needs shared logic with the CLI, put it in `src/services/vault-ops.ts`
- 3. Register route in `src/daemon/main.ts` (use `server.registerRoute()` with the new `RouteRequest`/`RouteResponse` types)
- 4. Add tests in `tests/daemon/api/<name>.test.ts`
- 5. Add the UI in `ui/src/pages/` or `ui/src/components/` as needed
-
- ### Test the vault and embeddings
-
- Use the CLI: `myco <command>` (or `myco-dev` in dogfooding mode)
-
- - `stats` — vault health, index counts, daemon status
- - `search <query>` — semantic search (primary) + FTS (fallback)
- - `vectors <query>` — raw similarity scores for threshold tuning
- - `rebuild` — reindex all records (FTS + vectors)
- - `restart` — kill and respawn the daemon with current code
-
- ### Modify digest behavior
-
- 1. Prompt templates in `src/prompts/digest-*.md` — change what the LLM focuses on per tier
- 2. Substrate formatting in `src/daemon/digest.ts` `formatSubstrate()` — change how notes are presented to the LLM
- 3. Metabolism timing in `src/daemon/digest.ts` `Metabolism` class — change active/cooldown/dormancy intervals
- 4. Config in `src/config/schema.ts` `DigestSchema` — change defaults or add new options
-
- ### Configure a task to use a local model
-
- 1. Add to `myco.yaml`:
- ```yaml
- agent:
- tasks:
- title-summary:
- provider:
- type: ollama
- model: llama3.2
- base_url: http://localhost:11434
- ```
- 2. Or use the dashboard: Configuration → Agent Tasks → select task → Provider Config
- 3. Run `myco verify` to test provider connectivity
-
- Provider priority: phase YAML `provider` > `myco.yaml` `agent.tasks` > task execution `provider` > default Anthropic.
-
- ### Restart daemon after code changes
-
- The daemon persists across sessions. After modifying daemon code, you MUST restart it:
+ # Myco — Claude Code Instructions
- ```sh
- myco restart # or myco-dev restart in dogfooding mode
- ```
+ > **Source of truth:** Read and follow [`AGENTS.md`](AGENTS.md) — it is the authoritative specification for this project's architecture, conventions, golden paths, and quality gates.
+ >
+ > If anything in this file conflicts with `AGENTS.md`, **`AGENTS.md` wins**.
- Or manually: kill the PID in `~/.myco/vaults/myco/daemon.json`, then let the next session-start hook spawn a fresh one.
+ This file contains only Claude Code-specific instructions that supplement `AGENTS.md`.
## Agent Teams
Use Claude Code agent teams for parallelizable work where teammates need to communicate with each other. See [docs/agent-teams.md](docs/agent-teams.md) for the full reference.
### When to use agent teams
- **User explicitly requests it** — always honor a direct request to create an agent team.
- **Cross-layer implementation** — changes spanning frontend, backend, and tests where each layer can be owned independently.
- **Competing hypothesis debugging** — multiple theories to investigate in parallel, especially when adversarial debate would surface the root cause faster.
- **Parallel review** — reviewing a PR or codebase from multiple lenses (security, performance, coverage) simultaneously.
- **Independent module development** — building 3+ modules with no shared files, where parallel execution saves significant time.
### When NOT to use agent teams
- **Sequential or dependent work** — tasks that must happen in order. Use a single session.
- **Same-file edits** — two teammates editing the same file causes overwrites. Use a single session or subagents.
- **Simple focused tasks** — when only the result matters and no inter-worker discussion is needed. Use subagents.
- **Token-constrained work** — each teammate is a separate Claude instance. Use subagents for lower cost.
### Rules for agent team usage
- **3-5 teammates** is the default. Scale up only when the work genuinely benefits.
- **5-6 tasks per teammate** keeps everyone productive without excessive context switching.
- **File ownership must be exclusive** — break work so each teammate owns a different set of files. Never assign two teammates to the same file.
- **Spawn prompts must include full context** — teammates do NOT inherit the lead's conversation history. Include all task-specific details in the spawn prompt.
- **Require plan approval for risky changes** — use plan mode for teammates touching critical paths (auth, data, config).
- **The lead delegates, not implements** — if the lead starts doing work itself, tell it to wait for teammates.
- **Only the lead cleans up** — teammates must not run cleanup. Shut down all teammates before the lead cleans up the team.