# AGENTS.md

Guidance for coding agents and contributors working in this repository. Keep
changes small, tested, and consistent with the patterns already present.
`CLAUDE.md` is a symlink to this file so project guidance has one source of
truth.

## Project overview

Decant is a local-first Bun and TypeScript application that turns Claude Code,
Codex, Gemini CLI, and GitHub Copilot CLI JSONL session logs, OpenCode's
SQLite session store, Cursor CLI's per-chat SQLite stores, Copilot Chat in
VS Code's chat session files, and imported ATIF trajectory files into a
normalized, full-text-searchable SQLite archive. The `decant` CLI owns
parsing, ingest, reads, reports, distillation, recommendations, watch mode, and
the React UI served by `decant serve`.

Start with these files and guides:

- `src/cli.ts` and `src/cli/` handle command composition, output, and exit-code
  policy.
- `src/sources/` contains source parsers and the primary extension point.
- `src/db.ts`, `src/schema.sql`, and `src/schema-manifest.ts` manage storage
  and schema.
- `src/server.ts` and `src/ui/` serve the local API and web UI.
- `docs/architecture.md` maps module boundaries and data flow.
- `docs/analytics-methodology.md` details metric definitions.
- `docs/data-lifecycle.md` describes sync and local state.
- `docs/sources.md` lists each source's default location, overrides, and
  user-facing caveats.
- `docs/api/openapi.yaml` defines the local API contract.
- `docs/distribution.md` covers npm, installer, Homebrew, Docker, and source
  builds.
- `docs/adding-a-source.md` provides the parser contribution checklist.
- `docs/contribution-triage.md` is the procedure for triaging outside pull
  requests.

## Setup and commands

Run commands from the repository root. Bun 1.3 or newer is required. Docker is
only needed when validating the container image.

- `bun run dev` performs a frozen dependency install, startup sync, local UI,
  and source watcher.
- `bun run src/cli.ts --help` runs the CLI from source.
- `bun test` runs the test suite.
- `bunx tsc --noEmit` runs the type check.
- `bunx biome check .` runs the formatting and lint check.
- `just check` runs the full local gate, including the native distribution
  staging smoke. It needs network access because the smoke packs and installs
  the npm launcher packages.

The default archive is `~/.decant/decant.db`. Override it with `DECANT_DB` or
`--db`. Set `DECANT_NO_SYNC` or pass `--no-sync` whenever a command points at a
scratch archive, or automatic sync may populate it from the real Claude Code,
Codex, Gemini CLI, OpenCode, Cursor CLI, GitHub Copilot CLI, and VS Code
directories.

## Definition of done

A change is ready when:

- `bun test` passes.
- `bunx tsc --noEmit` passes.
- `bunx biome check .` passes.
- New behavior has focused tests. Do not weaken or delete tests to make a
  change pass.
- Distribution changes get a native binary smoke test. Docker changes also get
  a local `docker build` and `docker run --help` smoke when Docker is
  available.
- User-visible command, route, configuration, or metric changes update their
  corresponding public docs.

## Project invariants

1. **Core modules stay print-free.** Parsing, ingest, query, stats, distill,
   recommendations, and database helpers return data or structured errors.
   Human-readable CLI output and exit codes belong in `src/cli.ts` and `src/cli/`.
2. **One process owns SQLite.** The CLI process opens the archive directly. WAL
   mode allows reads and ingest to coexist, so do not add another process that
   opens the database behind a separate contract.
3. **Runtime stays local-first.** Do not add outbound network calls, hosted
   service dependencies, or LLM calls. The only runtime networking is the local
   UI and API served by `decant serve`, bound to loopback by default. The one
   exception lives in `src/update.ts`, a once-a-day npm registry version check
   that stays off until the user turns it on, and the release downloads
   `decant update` makes when the user runs it. Neither sends archive data.
4. **Costs reflect current pricing.** `estimateCost` in `src/cost.ts` is applied
   when a session is written. Every sync reconciles stored session and activity
   costs with current rates, preserving transcripts and user state.
5. **Schema constants are the source of truth.** Use `LATEST_SCHEMA_VERSION` in
   `src/db.ts` rather than copying the current number into documentation.
   Unsupported older archives are rebuild-only. A migration is frozen once
   committed because someone may already have opened an archive with that
   branch, so put later schema adjustments in a new migration. Bump
   `INGEST_PIPELINE_REVISION` whenever unchanged sources must be re-derived so
   the next sync backfills them once and later syncs stay idempotent.
6. **Parsers are the extension point.** A new source requires
   `src/sources/<tool>.ts`, hand-written synthetic fixtures, parser tests,
   ingest/query coverage, and reviewed golden updates. Follow
   `docs/adding-a-source.md`.
7. **Serve routes are a documented local API.**
   `docs/api/openapi.yaml` is the source contract and `/api/openapi.json` is its
   runtime representation. Keep the implementation, OpenAPI document, route
   guide, and contract tests in sync.

## Security and privacy

- Never commit secrets, API keys, tokens, `.env` files, private keys, real
  transcripts, exports from real sessions, or personal archive databases.
- `~/.claude`, `~/.codex`, `~/.copilot`, VS Code's `User` directory, and the
  other source directories
  contain private content. Fixtures must be written from scratch, and
  `test/golden/` must be generated only from those synthetic fixtures.
- Keep source parsing resilient, meaning malformed records should become
  diagnostics, not crashes or leaked transcript content.
- Non-loopback serving must require explicit trusted-peer configuration. Treat
  `Host` and browser-origin checks as defense in depth, not authentication.

## Conventions

- Use surrounding code style, narrow changes, and focused tests.
- Use Conventional Commit prefixes such as `feat:`, `fix:`, `docs:`, `test:`,
  and `chore:`. Sign commits when the environment supports it.
- Comments explain why a constraint exists, not what the code already says.
- Branch from `main`, open a pull request, and keep CI green.
- Do not edit unrelated user changes in a dirty worktree.

## Pull requests

- Open a pull request only when the developer asks for one.
- Fill in every heading of `.github/PULL_REQUEST_TEMPLATE.md`, including the
  schema and privacy checkboxes. Do not replace it with your own layout.
- Verification lists the focused commands or manual checks you ran and what
  they showed. "Tests pass" alone is not evidence.
- Upload screenshots and recordings with the pull request
  (`gh pr edit <n> --body-file <file> --attach <image>`). Never commit PR-only
  assets.
- End the description with the model and harness that wrote the change.
- `bun run scripts/pr-policy.ts` runs the same policy checks as CI: committed
  migrations unchanged, docs updated alongside rate and route-manifest
  changes, and a pattern scan of fixtures for real-looking home paths, emails,
  and credentials. Passing the scan does not prove a fixture is synthetic.
- When babysitting a pull request, wait for check and review events instead of
  polling. Check each bot finding against the source, fix the real ones, and
  answer false positives with a reason.

## Documentation expectations

Keep the public repository useful to users and outside contributors. Prefer
current behavior and durable constraints over migration history, private
runbooks, project-specific agent setup, or stale release notes. The README is
the product entry point, and detailed operational behavior belongs in `docs/`.
The skills in `.claude/skills/` are the one exception to the agent-setup rule:
each stays a thin pointer to the doc that owns its procedure, so update the doc
first and the skill only when a path or rule it names changes.

When changing:

- metrics or classification, update `docs/analytics-methodology.md`.
- archive state, sync, or migration behavior, update
  `docs/data-lifecycle.md`.
- a route, update `docs/api/openapi.yaml`, `docs/api/routes.md`, and contract
  tests.
- install or packaging behavior, update `docs/distribution.md` and the npm
  package README.
- model rates, update `docs/pricing.md` with dated first-party sources.

## When stuck

If a test fails in a way you cannot resolve, the plan appears wrong, or a
change would alter schema or route semantics beyond the request, stop and
report the exact failure before guessing.
