35 added, 355 removed. Audit A to A.
# codemem
- ## Public repository safety
-
- Assume this repository is public and everything you write (code, docs, tests, and commit messages)
- will be published.
-
- - Never add proprietary/internal references (private domains/hostnames, internal project codenames,
- employee emails, vendor/customer confidential identifiers, etc.).
- - Never add secrets (API keys, tokens, passwords, private keys), even as examples. Use obvious
- placeholders instead.
- - Keep local artifacts out of git (`.venv/`, `.tmp/`, `*.sqlite`, logs, caches).
- - If you discover sensitive content already tracked or in git history: stop and propose a
- remediation plan (remove from tree + consider history rewrite).
-
- If you are about to run commands, default to the TypeScript toolchain (`pnpm ...`).
- Use `uv run ...` only when you are explicitly working on the legacy Python backend
- (`codemem/`, `tests/`, pytest/ruff, or Python release metadata).
-
- ## Execution Contract
-
- - Treat work as incomplete until the requested change is implemented, the smallest relevant validation has run, and any remaining gaps are called out explicitly as blocked or deferred.
- - Do not stop at analysis, a partial fix, or "here's what I would do" unless the user explicitly asked for plan-only work.
- - Before acting, check prerequisites first: read the file you will change, inspect nearby tests/docs when behavior or public usage changes, and resolve dependency outputs from earlier steps before continuing.
- - If a lookup/search result is empty or suspiciously narrow, try at least one fallback query or adjacent source before concluding that nothing relevant exists.
- - Before finalizing, verify: requirements are met, claims are grounded in repo/tool output, requested format is satisfied, and the smallest relevant test/lint/build/doc check has passed.
- - For substantial work, send short progress updates at phase changes only: what changed or was learned, and the next step. Do not narrate routine tool calls.
- - For commits, pushes, issue updates, server restarts, or maintenance commands, briefly state the intended action first, then confirm the outcome and validation afterward.
-
- ## Releases
-
- Release checklist:
-
- 1. Create a release branch + PR (no direct pushes to `main`)
- 2. Update version:
- - `packages/core/package.json`
- - `packages/cli/package.json`
- - `packages/opencode-plugin/package.json`
- - `packages/mcp-server/package.json`
- - `packages/viewer-server/package.json`
- - `packages/core/src/index.ts`
- - `packages/core/src/index.test.ts`
- - `packages/cli/.opencode/plugins/codemem.js`
- - `packages/opencode-plugin/.opencode/plugins/codemem.js`
- - `.claude-plugin/marketplace.json` (metadata version and codemem plugin entry version; MCP args are unpinned)
- - `plugins/claude/.claude-plugin/plugin.json` (metadata version only; MCP args are unpinned)
- 3. Regenerate lockfiles/artifacts and commit the results:
- - JS: run `pnpm install` and commit lockfile/artifact changes when applicable
- - Viewer UI bundle/assets: built via `pnpm build`
- 4. Ensure JS installs use the public npm registry (avoid private registries/mirrors)
- - Keep `.opencode/.npmrc` with `registry=https://registry.npmjs.org/`
- 5. Wait for CI to pass, then squash-merge the PR
- 6. After the release PR merges, switch to updated `main` and verify `HEAD` is the merged release commit
- - Run `git checkout main`
- - Run `git pull --rebase`
- - Run `git status --short --branch` and confirm the worktree is clean
- - Run `git show --stat --summary HEAD` and confirm the release version/artifact changes are present on `main`
- 7. Tag the merge commit on `main` as `vX.Y.Z` and push the tag
- - Never tag the release branch commit directly
- - Never create/push the release tag while checked out on `release/*`
- - Never assume the release branch tip and merged `main` commit are interchangeable; verify before tagging
- - The `Release` workflow triggers on `v*` tags and publishes the GitHub Release artifacts.
- 8. Do not immediately bump `main` to the next unreleased version with the current shared versioning model
- - `main` also carries live marketplace/plugin metadata and pinned CLI version references
- - A post-release bump on `main` can point live install paths at a package version that is not published yet
- - Keep next-version bumps in a later release-prep branch/PR unless versioning is explicitly decoupled first
-
- ## Stack
-
- - Node: >=24
- - Package manager: pnpm (workspace at root)
- - Build: Vite 8 (library mode, Rolldown-powered)
- - Tests: vitest
- - Lint/format: biome
- - Packages: `packages/core`, `packages/mcp-server`, `packages/viewer-server`, `packages/cli`
- - Storage: SQLite (path configurable)
-
- ### Legacy Python (reference-only)
-
- - Python backend code remains in `codemem/` and `tests/` for migration/reference work.
- - Use `uv run ...` only when explicitly touching legacy Python surfaces.
-
- **Publish model:** root `package.json` is workspace-only (`private: true`).
- The published CLI package is `codemem` from `packages/cli`.
- The published OpenCode plugin package is `@codemem/opencode-plugin` from `packages/opencode-plugin`.
-
- ## Quick Commands
-
- ### TypeScript default workflow
-
- - Install JS deps: `pnpm install`
- - Build all TS packages: `pnpm build`
- - Run tests: `pnpm run test`
- - Lint: `pnpm run lint`
- - Typecheck: `pnpm run tsc`
- - Run TS CLI from source: `pnpm run codemem --help`
-
- ### Legacy Python setup (only when required)
- - Install dev deps + create venv: `uv sync`
- - Run commands via the venv (no activate): `uv run codemem --help`
- - Activate (fish): `source .venv/bin/activate.fish`
- - Activate (bash/zsh): `source .venv/bin/activate`
-
- ### Legacy Python build / install
- - Editable install (if you want `codemem` on PATH): `uv pip install -e .`
- - No-install run from this repo: `uv run codemem stats`
- - One-off run via uvx: `uvx --from . codemem stats`
-
- ### TypeScript runtime commands (preferred)
-
- - CLI help: `pnpm run codemem --help`
- - Viewer help: `pnpm run codemem serve --help`
- - Serve viewer (start): `pnpm run codemem serve start`
- - Serve viewer (background): `pnpm run codemem serve --background`
- - Serve viewer (restart): `pnpm run codemem serve restart`
- - MCP server: `pnpm run codemem mcp`
- - Claude hook ingest (stdin JSON): `pnpm run codemem claude-hook-ingest`
- - Stats: `pnpm run codemem stats`
- - Raw-event backlog: `pnpm run codemem db raw-events-status`
-
- ### Legacy Python runtime commands (only when explicitly required)
-
- - CLI help: `uv run codemem --help`
- - Viewer help: `uv run codemem serve --help`
- - Serve viewer: `uv run codemem serve`
- - Serve viewer (background): `uv run codemem serve --background`
- - Serve viewer (restart): `uv run codemem serve --restart`
- - MCP server: `uv run codemem mcp`
- - Ingest (stdin JSON): `uv run codemem ingest`
- - Stats: `uv run codemem stats`
-
- ### Tests (pytest)
- - Run all tests: `uv run pytest`
- - Run a single file: `uv run pytest tests/test_store.py`
- - Run a single test: `uv run pytest tests/test_store.py::test_store_roundtrip`
- - Run by substring match: `uv run pytest -k "roundtrip and store"`
-
- - `uv run pytest tests/test_store.py::test_deactivate_low_signal_observations`
-
- - Pytest default opts are in `pyproject.toml` (`addopts = "-q"`).
-
- ### Lint / Format (ruff)
- - Lint: `uv run ruff check codemem tests`
- - Format (check only): `uv run ruff format --check codemem tests`
- - Auto-fix lint + format: `uv run ruff check --fix codemem tests` then `uv run ruff format codemem tests`
-
- Ruff config (from `pyproject.toml`):
- - line length: 100
- - target: py311
- - lint selects: E, W, F, I, UP, B, SIM
- - ignores: E501 (formatter), B008 (Typer default args)
-
- ### Coverage (optional)
- - `uv run pytest --cov=codemem --cov-report=term`
-
- ## Frontend Development
-
- Viewer UI is in `packages/ui` and served by `packages/viewer-server`.
-
- ### Viewer UI
-
- - Source: `packages/ui/src/`
- - Dev loop: edit UI files, run `pnpm build`, then restart viewer if needed
-
- ### OpenCode plugin
-
- - Source: `packages/opencode-plugin/.opencode/plugins/codemem.js`
- - Rules:
- - ESM only (`import`/`export`)
- - must never crash OpenCode (no uncaught exceptions)
- - avoid blocking hooks; defer heavy work to background CLI calls
-
- ## Repo Map
- - `packages/core/src/`: core store/search/ingest/sync logic
- - `packages/viewer-server/src/`: viewer API server
- - `packages/ui/src/`: viewer frontend
- - `packages/mcp-server/src/`: MCP server tools
- - `packages/cli/src/`: CLI commands
- - `packages/opencode-plugin/.opencode/plugins/codemem.js`: OpenCode plugin entrypoint
- - `codemem/`, `tests/`: legacy Python backend/tests (reference only)
-
- ## Runtime Commands
- - CLI entrypoint: `codemem`
- - MCP server: `codemem mcp` (or `codemem-mcp`)
- - Claude hook ingest (stdin JSON): `codemem claude-hook-ingest`
- - Viewer: `codemem serve start|stop|restart` (or `codemem serve --background`)
- - Export/Import: `codemem export-memories`, `codemem import-memories`
- - Store maintenance: `codemem db prune-memories` (use `--dry-run` first)
-
- ## Environment Variables
-
- - `CODEMEM_DB`: sqlite path (example: `~/.codemem/mem.sqlite`)
- - `CODEMEM_PLUGIN_LOG`: set to `1` to enable plugin logging
-
- ## CLI Design
- - Follow `docs/cli-design-conventions.md` for all CLI command additions and modifications
- - Key rules: max 2 nesting levels, positional args for primary nouns, flags for config/modifiers, `--json` on all data-returning commands, structured error output, no uncaught throws from action handlers
- - Shared flags (`--db-path`, `--config`, `--json`) should use option-builder helpers, not copy-paste
-
- ## Code Style
-
- ### Python
- - Version: Python >=3.11,<3.15 (see `pyproject.toml`)
- - Always use `from __future__ import annotations` (project convention; most files already do)
- - Formatting: let `ruff format` do the wrapping; don't fight it
- - Imports:
- - Let ruff/isort order imports
- - Prefer relative imports within `codemem` (as existing code does)
- - Types:
- - Prefer built-in generics (`list[str]`, `dict[str, Any]`) and `collections.abc` (`Iterable`, `Sequence`)
- - Use `Path` for filesystem paths; accept `Path | str` at public boundaries and normalize early
- - Use `TypedDict` for "event-like" dict payloads when shape matters
- - Naming:
- - `snake_case` for functions/vars, `PascalCase` for classes, `UPPER_SNAKE_CASE` for constants
- - Private helpers start with `_`; keep module surfaces small and explicit
- - Error handling:
- - Validate at boundaries (env vars, config, CLI inputs, network payloads)
- - Avoid bare `except:`; log exceptions with context (`logger.warning(..., exc_info=exc)` or `logger.exception(...)`)
- - CLI: prefer user-friendly messages + non-zero exits (Typer patterns)
- - Keep failure paths safe/deterministic (no partial DB writes without intent)
-
- ### JavaScript (OpenCode plugin)
- - ESM modules (`import`/`export`)
- - The plugin must never crash OpenCode:
- - Guard risky code paths; swallow/record errors where needed
- - Avoid blocking work in hooks; defer heavy work to background CLI calls
- - Keep helper functions small and testable; prefer pure transformations
-
- ## Memory Quality
- - Don't store raw tool logs as memories
- - Filter low-signal tool events (`read`, `edit`, `glob`, `grep`, etc.)
- - Prefer typed memory kinds: `discovery`, `change`, `feature`, `bugfix`, `refactor`, `decision`, `exploration`
- - Use `exploration` for attempts/experiments that were tried but not shipped (preserves "why not")
- - Session summaries/observations are OFF by default; only enable via config
-
- ## Configuration
- - Default config file: `~/.config/codemem/config.json`
- - Env vars override config values when present
- - Default DB path is configurable; `CODEMEM_DB=~/.codemem/mem.sqlite` is a common override
- - Avoid hardcoding user paths in code; use config/env and normalize with `Path(...).expanduser()`
-
- ## Testing Guidance
- - Prefer fast unit tests in `packages/**` via vitest (avoid network; mock external calls)
- - Use targeted test runs for touched files, then broader runs as needed
- - Legacy Python tests in `tests/` are for reference/migration surfaces
-
- ## Plugin / Viewer Notes
- - Plugin must be defensive: no uncaught exceptions in hooks; avoid blocking work
- - Viewer UI comes from `packages/ui` and `packages/viewer-server`; restart viewer to see runtime changes
- - Docs:
- - `docs/architecture.md` (data flow, flush strategy)
- - `docs/user-guide.md` (viewer usage, troubleshooting)
-
- ## Quick Debug Checklist
- - Plugin logging: `CODEMEM_PLUGIN_LOG=1` then check `~/.codemem/plugin.log`
- - Missing sessions: confirm plugin + viewer use the same DB path (`CODEMEM_DB`)
- - Flush/backlog issues: look for viewer logs and `codemem db raw-events-status` output
-
- ## When Changing Behavior
- - If you change plugin behavior, update `README.md` (and relevant docs under `docs/`)
- - If you change memory kinds, also update:
- - `packages/core/src/store.ts` (kind handling and persistence)
- - `packages/mcp-server/src/index.ts` (`memory_schema` tool)
- - `packages/ui/src/tabs/feed.ts` (UI kind presentation)
- - relevant vitest coverage in `packages/**`
-
- ## PR Hygiene
-
- - Always use `.github/PULL_REQUEST_TEMPLATE.md` for every PR.
- - Replace all template placeholder text before requesting review.
- - Complete all checklist sections accurately:
- - Type of Change
- - Testing
- - Checklist
- - Apply this to every PR in a stack (base PR and each follow-up PR).
- - Keep PR titles/bodies and commit messages free of private inspiration references or other non-public context.
-
- ## Releases
- - Release versions are prepared on a release branch + PR, then tagged only after that PR is merged to `main`.
- - Before tagging:
- - `git checkout main`
- - `git pull --rebase`
- - verify the merged release commit is at `HEAD`
- - verify the worktree is clean
- - Tag from `main` only: `git tag vX.Y.Z` then `git push origin vX.Y.Z`
- - Do not tag from `release/*` branches.
- - Do not immediately bump `main` to the next unreleased version with the current shared marketplace/package versioning model.
-
- ## Do / Don't
- - Do keep changes small and deterministic; prefer adding tests when behavior changes
- - Do validate inputs at boundaries; keep DB writes intentional
- - Don't add new heavy dependencies without a clear need
- - Don't let the plugin throw uncaught exceptions or block OpenCode hooks
-
- <!-- BEGIN BEADS INTEGRATION -->
- ## Issue Tracking with bd (beads)
-
- **IMPORTANT**: This project uses **bd (beads)** for ALL issue tracking. Do NOT use markdown TODOs, task lists, or other tracking methods.
-
- ### Why bd?
-
- - Dependency-aware: Track blockers and relationships between issues
- - Git-friendly: Dolt-powered version control with native sync
- - Agent-optimized: JSON output, ready work detection, discovered-from links
- - Prevents duplicate tracking systems and confusion
-
- ### Quick Start
-
- **Check for ready work:**
-
- ```bash
- bd ready --json
- ```
-
- **Create new issues:**
-
- ```bash
- bd create "Issue title" --description="Detailed context" -t bug|feature|task -p 0-4 --json
- bd create "Issue title" --description="What this issue is about" -p 1 --deps discovered-from:bd-123 --json
- ```
-
- **Claim and update:**
-
- ```bash
- bd update <id> --claim --json
- bd update bd-42 --priority 1 --json
- ```
-
- **Complete work:**
+ - Public repo: never add secrets, internal hostnames, private identifiers, or local artifact paths. Keep `.tmp/`, `.venv/`, `*.sqlite`, `packages/*/dist/`, `packages/viewer-server/static/`, and `.opencode/package-lock.json` out of git.
+ - Default to the TypeScript toolchain: this repo is a pnpm workspace on Node 24 / pnpm 10.33.0. Use `uv ...` only when explicitly touching the legacy Python code in `codemem/` or `tests/`.
- ```bash
- bd close bd-42 --reason "Completed" --json
- ```
+ ## What runs where
- ### Issue Types
+ - CLI entrypoint: `packages/cli/src/index.ts` (`pnpm run codemem ...`).
+ - Shared store/search/sync logic and exported version: `packages/core/src/index.ts`.
+ - Viewer HTTP API + SPA host: `packages/viewer-server/src/index.ts`.
+ - Viewer UI source: `packages/ui/src/`.
+ - OpenCode plugin source of truth: `packages/opencode-plugin/.opencode/plugins/codemem.js`.
+ - `packages/cli/.opencode/plugins/codemem.js` and repo-root `.opencode/plugins/codemem.js` are wrappers/re-exports, not the main implementation.
+ - `packages/cloudflare-coordinator-worker/` is its own worker package with separate tests.
- - `bug` - Something broken
- - `feature` - New functionality
- - `task` - Work item (tests, docs, refactoring)
- - `epic` - Large feature with subtasks
- - `chore` - Maintenance (dependencies, tooling)
+ ## Commands worth using
- ### Priorities
+ - Install: `pnpm install`
+ - Full local gate / CI order: `pnpm run tsc && pnpm run lint && pnpm run test` (`pnpm run check`)
+ - Build everything: `pnpm run build`
+ - Run CLI from source: `pnpm run codemem --help`
+ - Run one vitest file: `pnpm exec vitest run packages/cli/src/commands/serve.test.ts`
+ - Run one package script: `pnpm --filter codemem test`, `pnpm --filter @codemem/ui build`, `pnpm --filter @codemem/cloudflare-coordinator-worker test:worker`
+ - E2E smoke: `CODEMEM_E2E_BUILD=1 CODEMEM_E2E_JSON=1 pnpm run e2e:smoke -- --json` (artifacts land in `.tmp/e2e-artifacts`)
- - `0` - Critical (security, data loss, broken builds)
- - `1` - High (major features, important bugs)
- - `2` - Medium (default, nice-to-have)
- - `3` - Low (polish, optimization)
- - `4` - Backlog (future ideas)
+ ## Gotchas agents usually miss
- ## Issue Tracking
+ - `pnpm run lint` only checks files included by `biome.json` (mostly `packages/**` TS/TSX/JS/JSON and root TS config). Docs like `AGENTS.md` are outside Biome.
+ - `pnpm run test` is workspace vitest; root `vitest.config.ts` points at `packages/*/vite.config.ts`.
+ - The viewer server throws if `packages/viewer-server/static/index.html` is missing. If you change UI or viewer assets, run `pnpm build` or at least `pnpm --filter @codemem/ui build`.
+ - `packages/viewer-server/static/` is generated and ignored. Do not hand-edit it. UI build stages assets there, but most non-`app.js` assets still come from `codemem/viewer_static/`.
+ - Plugin smoke tests rely on nested `.opencode` runtime deps. CI installs `@opencode-ai/plugin` inside `packages/cli/.opencode` and `packages/opencode-plugin/.opencode` before running smoke tests.
+ - CLI work should follow `docs/cli-design-conventions.md`: max 2 nesting levels, noun-based groups, shared `--db-path` / `--config` / `--json` helpers, and no uncaught throws from command handlers.
+ - The repo still contains legacy Python and old static assets. For TS work, trust `package.json`, package scripts, and CI over old Python-era docs/checklists.
+ - `.github/PULL_REQUEST_TEMPLATE.md` is TS-first now; use `pnpm run tsc`, `pnpm run lint`, and `pnpm run test` unless you are actually changing legacy Python.
- This project uses **bd (beads)** for issue tracking.
- Run `bd prime` for workflow context, or install hooks (`bd hooks install`) for auto-injection.
+ ## Workflow rules specific to this repo
- **Quick reference:**
- - `bd ready` - Find unblocked work
- - `bd create "Title" --type task --priority 2` - Create issue
- - `bd close <id>` - Complete work
- - `bd dolt push` - Push beads to remote
+ - Use `bd` for issue tracking, not markdown TODOs: `bd ready --json`, `bd create ... --json`, `bd close ... --json`.
+ - If you change plugin behavior, update `README.md` and any affected docs under `docs/`.
+ - If you change memory kinds or their presentation, update all three surfaces together: `packages/core/src/store.ts`, `packages/mcp-server/src/index.ts`, and `packages/ui/src/tabs/feed.ts`.
- **Agent rules:**
- - Use `bd` for task tracking; do not create markdown TODO lists
- - Prefer `--json` for programmatic commands
- - Link discovered follow-up work with `discovered-from` when relevant
+ ## Release traps
- For full workflow details: `bd prime`
+ - Release tags trigger publishing. Tag only the merged `main` commit, not a `release/*` branch tip.
+ - Version alignment is scripted in `scripts/release-version.mjs`; tag safety is enforced by `pnpm run release:preflight-tag` / `scripts/release-tag-preflight.sh`.
+ - Releases publish to the public npm registry; keep `.opencode/.npmrc` pointed at `https://registry.npmjs.org/`.