Decant#
Your coding agent sessions contain a lot of useful information. What tokens got
spent on, how full the context window got, which files an agent worked with, and
what a run cost. Decant gives you insight into what's on disk, right now.
Built by Dosu for developers who want their agents to learn
from real work.
It reads the JSONL logs Claude Code and Codex already write
(~/.claude/projects/*.jsonl, ~/.codex/sessions/rollout-*.jsonl), normalizes
both formats into one WAL + FTS5 SQLite archive, and gives you full-text search,
token economics, context-window occupancy, and phase breakdowns from a CLI or a
local web UI. Your transcripts never leave your machine.
![]()
Features#
- One archive for Claude Code and Codex sessions.
- Full-text search across messages and tool calls.
- Usage, estimated cost, tool, MCP, file-hotspot, and
activity analytics. - Deterministic
distillartifacts from real command history: scripts, replays,
and skill/AGENTS snippets. - Persisted recommendations with implemented-state tracking.
- Local React UI served by the same Bun process:
decant serve. - Watch mode with native filesystem events plus a periodic sweep.
- Scriptable JSON output, shell completions, and stable exit codes.
Quick Start#
Run Decant with npx—no Bun install or global package required:
npx @dosu/decant@latest
That starts the local web UI at http://127.0.0.1:3000, prints the link, and
opens your browser (skipped when it can't — the printed link always works). The
first run syncs the Claude Code and Codex logs already on your machine, then
keeps watching them for changes. decant serve is the same thing with flags:
--port, --host, --no-open, and friends. npx downloads the launcher and
matching native binary for this run without installing a persistent decant
command.
Use the same package for one-off CLI commands:
npx @dosu/decant@latest sync
npx @dosu/decant@latest ls
npx @dosu/decant@latest search "auth bug"
For a persistent installation:
npm install --global @dosu/decant@latest
decant
Install it with Homebrew:
brew install dosu-ai/dosu/decant
decant
Install it without Node, straight from the release assets:
curl -fsSL https://raw.githubusercontent.com/dosu-ai/decant/main/install.sh | sh
decant
Run the GHCR image:
docker run --rm \
-p 127.0.0.1:3000:3000 \
-v decant-data:/var/lib/decant \
-v "$HOME/.claude/projects:/sources/claude:ro" \
-v "$HOME/.codex:/sources/codex:ro" \
ghcr.io/dosu-ai/decant:latest
To run from source instead, install Bun 1.3+ and use bun run dev. It performs
a frozen dependency install, starts decant serve, runs the startup sync, and
keeps watching your source logs. See Install Matrix for the
full set of options.
Keep the 127.0.0.1: host prefix on the Docker port publish. Publishing as
-p 3000:3000 exposes the archive port on every host interface. The container
binds 0.0.0.0 only inside its own network namespace so Docker's host loopback
publish can reach it.
The API is unauthenticated, so the peer's source address is the boundary. The
image ships no peer allowlist. It sets DECANT_TRUST_DEFAULT_GATEWAY=1, which
trusts exactly one address: the container's own bridge gateway, which is where
Docker's port publisher forwards -p traffic from. It does that only when
Decant can prove the default route is a container veth to an on-link gateway
inside 172.16.0.0/12. A sibling container on the same bridge keeps its own
source address and gets 403 forbidden remote.
Shapes that cannot be proven trust nobody beyond loopback and need one env var:
--network host, macvlan/ipvlan, multi-homed hosts, and bridges outside
172.16.0.0/12 (Podman's 10.88.0.0/16, a custom --subnet, Kubernetes). If
the UI answers 403 forbidden remote, set DECANT_TRUSTED_PEERS to the exact
address requests arrive from, for example
-e DECANT_TRUSTED_PEERS=192.168.65.1. That replaces the gateway default
entirely; DECANT_TRUST_DEFAULT_GATEWAY=0 turns it off without naming a peer.
CLI#
decant sync
decant ls
decant show 1
decant search "auth bug"
decant stats --by model
decant files --group ext
decant tool stats
decant mcp stats
decant distill script
decant distill replay 1
decant distill skill --kind agents
decant recommendations ls
decant export 1 > session.md
decant export 1 --as trajectory > session.trajectory.json
decant completion zsh
All read commands support --json. Use --db /path/to/decant.db or
DECANT_DB for an alternate archive. Use decant sync --path /path/to/log-or-dir
to ingest only specific source files or a temporary source tree, including raw
Claude stream-json logs; pass --path more than once to ingest multiple paths.
Configuration#
DECANT_DB: archive path, default~/.decant/decant.db.DECANT_CLAUDE_DIR: Claude projects directory, default
~/.claude/projects.DECANT_CODEX_DIR: Codex home directory, default~/.codex.DECANT_CONFIG_DIR: settings directory, default~/.config/decant.DECANT_LOG_LEVEL: minimum structured operational log level written as JSON
Lines to stderr. Defaults toinfo; acceptstrace,debug,info,warn
(orwarning),error,fatal, andoff(orsilent).DECANT_NO_SYNC: set to any value to skip the sync-on-read that read commands
perform, and to rundecant servewithout its source watcher so it serves the
archive as-is and ingests nothing. The--no-syncflag does the same. The
"Sync now" button andPOST /api/syncstill work; this only suppresses the
syncing Decant starts on its own.DECANT_NO_OPEN: set to any value to never auto-open a browser from
decant serve; the--no-openflag does the same per run.BROWSER: opener command used instead of the platform default (openon
macOS,xdg-openon Linux). A bare command name or path, no arguments;
BROWSER=nonedisables opening. The URL is always printed either way, and
auto-open is skipped in CI or when stdout is not a terminal.DECANT_TRUSTED_PEERS: comma-separated peer IPs or IPv4 CIDRs allowed through
the local API guard whenserveis bound to a non-loopback host. Unset by
default. Keep it as narrow as the deployment allows: every listed address, and
every address inside a listed CIDR, reads and writes the whole archive without
a credential.DECANT_TRUST_DEFAULT_GATEWAY: set to1to trust this container's own
bridge gateway, resolved once at startup from/proc/net/routeand
/sys/class/net. Off by default and off for any other value, including0.
The derived peer is a single address, and only when the default route is a
container veth pointing at an on-link gateway inside172.16.0.0/12; every
other shape resolves to no peers. The container image turns this on so the
documenteddocker runrecipe works without a peer CIDR.
Precedence is replace, not merge: --trusted-peer wins over
DECANT_TRUSTED_PEERS, which wins over DECANT_TRUST_DEFAULT_GATEWAY. Setting
either peer source, including DECANT_TRUSTED_PEERS= with an empty value,
means no gateway is derived.
decant serve binds 127.0.0.1:3000 by default. Override with
--host/--port. There is no authentication, so bind loopback unless you
deliberately want other hosts in: the Host header check is not an access
control for non-browser clients, which can send Host: localhost freely.
Archives older than schema v8 are rebuild-only. v8 through v21 archives migrate
forward to v22 on open. Schema v22 tracks the ingest-pipeline revision for every
source: when parser or enrichment behavior advances, the next decant sync
transactionally re-ingests each unchanged stale source once, and later syncs
skip it again. Existing archives therefore backfill new derived data without a
manual rebuild. Older archives should be deleted and rebuilt with decant sync.
Source logs remain the source of truth, so nothing is lost by rebuilding.
Integrating with Decant#
decant serve exposes a documented local API at
http://127.0.0.1:3000/api. It has no authentication on the default loopback
listener, so any local process can read or mutate the archive. Keep the listener
on loopback unless you have deliberately configured the trusted-peer boundary
described under Configuration.
The source OpenAPI 3.1 contract is
docs/api/openapi.yaml. A running server exposes the
same contract as JSON at http://127.0.0.1:3000/api/openapi.json.
For example, read the archive summary:
curl --fail --silent --show-error \
http://127.0.0.1:3000/api/stats/summary
See docs/api/routes.md for local access-control semantics,
write-request requirements, and Server-Sent Event names.
How It Works#
~/.claude + ~/.codex
|
v
Bun + TypeScript Decant process
parse -> enrich -> ingest + economics vectors -> SQLite WAL + FTS5
|
+--> CLI reads / JSON
+--> local React UI + JSON routes + SSE
There is no background daemon or separate service process. The old
Rust/Phoenix/Swift implementation is preserved in the signed pre-typescript
tag.
The local API contract lives in
docs/api/openapi.yaml, with operational semantics in
docs/api/routes.md.
The architecture guide maps the modules and data flow;
analytics methodology defines the reported
units; API recipes show reproducible local queries; and
archive lifecycle explains sync, visibility, deletion,
and rebuild behavior.
Operational log fields and privacy rules live in docs/logging.md.
Distribution notes live in docs/distribution.md, and the
tag-driven release pipeline is documented in
docs/releasing.md.
Install Matrix#
Ordered from the most streamlined to the most manual. Everything except "build
from source" is available from v0.1.0, once the Release workflow has
published a version. See docs/distribution.md for build
details and per-artifact verification.
-
npx / npm — zero persistent install, or a global one:
npx @dosu/decant@latest npm install --global @dosu/decant@latest # persistent, then use `decant` -
Homebrew — via the
dosu-ai/dosutap:brew install dosu-ai/dosu/decantOr with the tap and short names:
brew tap dosu-ai/dosu brew trust dosu-ai/dosu # Homebrew 6.0+ only — skip on older versions brew install decant -
Install script — for machines without Node:
curl -fsSL https://raw.githubusercontent.com/dosu-ai/decant/main/install.sh | shDetects your platform, downloads the matching release tarball, verifies it
againstSHA256SUMS, and installs to${DECANT_INSTALL_DIR:-~/.local/bin}.
Pin a version withDECANT_VERSION, skip thePATHedit with
DECANT_NO_MODIFY_PATH=1, or pointDECANT_BASE_URLat a mirror — see
docs/distribution.md for the full knob list. -
Docker — the
ghcr.io/dosu-ai/decantimage, per thedocker runrecipe
in Quick Start. Keep the127.0.0.1:host prefix on the port
publish. -
Build from source — the contributor path, and the only one that works
before v0.1.0:bun run dev
macOS, tarball downloads only. v0.1.0 binaries are ad-hoc signed but not
notarized, so a tarball downloaded through a browser carries
com.apple.quarantine and Gatekeeper blocks the first run. Clear it with
xattr -d com.apple.quarantine ./decant. brew install, npx @dosu/decant, and the
install script are unaffected, because none of them set the quarantine
attribute. Integrity comes from SLSA build provenance (published with each
release as an offline-verifiable decant-<version>.sigstore.json bundle),
SHA256SUMS, and the gh attestation verify check install.sh runs.
Upgrading. npx @dosu/decant@latest always resolves the newest published
version. For a persistent install, run npm i -g @dosu/decant@latest,
brew upgrade decant, re-run the install script, or
docker pull ghcr.io/dosu-ai/decant:latest. A source checkout reports
git describe --tags --always --dirty from decant --version (for example,
v0.1.0-8-ge9a0c00-dirty); a non-Git unstamped build falls back to dev.
Released artifacts carry their injected release version.
Development#
Run the local UI and watcher:
bun run dev
Run quality gates:
bun test
bunx tsc --noEmit
bunx biome check .
just check
Build distribution artifacts:
bun run scripts/build-binaries.ts --target native
bun run scripts/build-npm.ts --target native --no-build
docker build --platform linux/amd64 -t decant:local .
See AGENTS.md for the full command list, conventions, and project
invariants.
Security and Privacy#
Decant is local-first and offline at runtime. It reads files already on disk and
makes no outbound runtime network calls. Do not commit real session data,
personal archives, tokens, keys, or .env files. To report a vulnerability, see
SECURITY.md.
About Dosu#
Decant is built and maintained by Dosu, Knowledge
Infrastructure for Agents. Dosu makes agents faster, cheaper, and more effective
across every run.
Decant is the measurement end of that. It shows you what your agents actually
spent, read, and touched, from logs already on your disk. It is Apache 2.0 and
runs entirely on your own machine. See
Security and Privacy.
License#
Licensed under the Apache License 2.0.