Skip to content

Repository files navigation

midden

CI License: AGPL-3.0-only

A CLI tool that resolves, audits, visualizes, and cleans the heap of context and state Codex and Claude Code accumulate.

The name: midden, an archaeological term for a refuse heap — kitchen scraps, broken pottery, lost things — that tells you what life was like in the layer below. Agent memory and ~/.claude.json are exactly that.

Why

For installing skills, managing MCP server lists, or browsing the marketplace, plenty of tools already exist. Use those.

midden picks up where they leave off. Coding agents accumulate generated memories, layered repository instructions, session evidence, project mappings, local settings, and ephemeral worktrees, while almost nothing in the loop makes that state legible or removes it. midden surfaces what's actually active for a directory with provenance, flags what's stale or leaking, and prunes the state nothing else cleans up.

Installation

Homebrew

brew install starhaven-io/tap/midden

crates.io

cargo install midden

From releases

Download a prebuilt binary from GitHub Releases. There is no committed CHANGELOG — release notes live on the GitHub Releases page. Binaries are available for:

  • Linux amd64, glibc — x86_64-unknown-linux-gnu
  • Linux arm64, glibc — aarch64-unknown-linux-gnu
  • Linux amd64, musl (static) — x86_64-unknown-linux-musl
  • Linux arm64, musl (static) — aarch64-unknown-linux-musl
  • macOS Apple Silicon — aarch64-apple-darwin

The gnu builds link against the system glibc. They are built on Ubuntu 24.04, so they require glibc 2.39 or newer (Ubuntu 24.04+, Debian 13+, Fedora 40+). On older releases — Ubuntu 22.04, Debian 12, RHEL 9 and the like — use the statically linked musl builds instead. The musl builds carry no glibc requirement and also run on musl-based distributions such as Alpine, as well as minimal or distroless containers.

From git (unreleased HEAD)

To try unreleased changes from main:

cargo install --git https://github.com/starhaven-io/midden

Usage

All commands default to safe modes: dry-run for prune, read-only for show and memory inventory, and report-only for doctor. Writes always require an explicit flag, create a timestamped backup first, and replace the file atomically, preserving its file mode. Use --json for machine-readable output.

# Compare Codex and Claude memory sources for this repo
midden memory show

# Inspect only one provider
midden memory show --provider codex

# Include unrelated and unassociated memory sources
midden memory show --all

# Show what's actually active for a directory with provenance
midden show

# Target a specific repo
midden show /path/to/repo

# Hygiene + audit lint
midden doctor

# Auto-resolve safe findings (orphaned projects, etc.)
midden doctor --fix

# Garbage-collect dead `projects` entries (dry-run)
midden prune

# Apply the prune
midden prune --apply

# Also report orphaned transcript artifacts under ~/.claude/projects/
midden prune --transcripts

# Remove dead project entries and orphaned transcript artifacts
midden prune --transcripts --apply

# Only consider ephemeral worktree entries
midden prune --worktrees-only --apply

# Override the safety gate when claude is running
midden prune --apply --force

# Unmask secret-looking values in output (dangerous)
midden show --show-secrets

# Generate shell completions
midden completions zsh

Memory show

memory show resolves Codex and Claude Code through one normalized, read-only inventory while preserving each provider's native loading behavior:

$ midden memory show .
memory for /Users/me/myproject

codex  memory enabled  management read-only
  instructions
    [repository; loaded] /Users/me/myproject/AGENTS.md (2.4 KiB)
  retained memory
    [global; loaded] /Users/me/.codex/memories/memory_summary.md (1.1 KiB)

claude  memory enabled  management read-only
  instructions
    [repository; loaded] /Users/me/myproject/CLAUDE.md (31 B)
    [repository; loaded] /Users/me/myproject/AGENTS.md (2.4 KiB)
      imported by /Users/me/myproject/CLAUDE.md
  retained memory
    [repository; loaded] /Users/me/.claude/projects/example/memory/MEMORY.md (3.2 KiB)

provider coverage
  codex: 1 instruction, 1 retained memory
  claude: 2 instructions, 1 retained memory

Codex discovery follows AGENTS.override.md, AGENTS.md, configured fallback names, and the combined instruction byte limit. It inventories the generated summary, durable-memory index, and evidence stores under the configured Codex home without recursively reading rollout history.

Claude discovery includes managed, user, ancestor, project, local, imported, and path-scoped instruction sources. It associates per-repository auto-memory with the target from transcript cwd evidence rather than decoding Claude's lossy project-directory slugs, and reports MEMORY.md as startup context with topic files available on demand.

The default provider is all. --provider codex or --provider claude filters the same schema to one adapter. --all additionally includes unrelated and unassociated sources for forensic work. Memory content is not printed; JSON output contains source metadata, loading state, association, capabilities, and warnings.

Show

Resolve every configuration surface for a target directory with provenance:

$ midden show .
resolved for /Users/me/myproject

settings
  permissions.defaultMode = "bypass"
    [user shadowed] /Users/me/.claude/settings.json = "ask"
    [project] /Users/me/myproject/.claude/settings.json = "bypass"
  permissions.deny = ["Bash(rm:*)", "Read(./.env)"]
    [user merged] /Users/me/.claude/settings.json = ["Bash(rm:*)"]
    [project merged] /Users/me/myproject/.claude/settings.json = ["Read(./.env)"]

CLAUDE.md
  [user] /Users/me/.claude/CLAUDE.md (8421 bytes)
  [project] /Users/me/myproject/CLAUDE.md (10442 bytes)

hooks
  PreToolUse
    [local] Bash (command): bash -c '… DCO sign-off check …'
      /Users/me/myproject/.claude/settings.local.json

mcp servers
  [user] github -> https://api.githubcopilot.com/mcp
    /Users/me/.claude.json
  [project] astro-docs -> https://mcp.docs.astro.build/mcp
    /Users/me/myproject/.mcp.json

Settings precedence is Managed → Local → Project → User. Scalars from a higher scope override; arrays concat and deduplicate across scopes. show tags every value with its source and marks contributions shadowed by a higher scope. CLAUDE.md files do not follow precedence — all applicable files load simultaneously, so midden lists every contributor and runs a heuristic contradiction-detection pass instead of picking a winner.

MCP servers are gathered from all four scopes: user (~/.claude.json), local (the per-project entry inside ~/.claude.json — where claude mcp add writes by default), project (.mcp.json), and managed (.claude/managed-mcp.json).

Secrets are masked to abcd*** by default — both by key name (*_token, *_api_key, password, credential, …) and by value shape under innocent keys: known token prefixes (sk-, ghp_, xoxb-, AWS key ids, JWTs, private-key blocks), user:pass URLs, credential-named query parameters, and Bearer tokens inside hook commands. Pass --show-secrets to unmask.

Doctor

Hygiene + audit lint over the layered state, emitting structured Findings:

$ midden doctor
warn [missing-credential-deny] no deny rule covers .env, secrets — Claude could read credentials here
  at /Users/me/.claude/settings.json:permissions.deny
  fix: add e.g. "Read(./.env)", "Read(./.env.*)", "Read(./secrets/**)" to permissions.deny in ~/.claude/settings.json to cover every project

warn [orphaned-project] worktree directory no longer exists: /Users/me/Developer/foo/.claude/worktrees/witty-curie (auto-fixable)
  at /Users/me/.claude.json:projects./Users/me/Developer/foo/.claude/worktrees/witty-curie
  fix: remove this entry with `midden prune --apply`

0 error, 2 warn, 0 info — 1 auto-fixable

Run with --fix to apply auto-fixable findings. As with prune, this writes a timestamped backup first and refuses to write while a claude process is running (override with --force).

Prune

Garbage-collect dead projects entries from ~/.claude.json (dry-run by default):

$ midden prune
43 project entries total; 24 orphaned (13 worktree, 11 other):

  - /Users/me/Developer/Brewy
  - /Users/me/Developer/Brewy/.claude/worktrees/competent-fermat   [worktree]
  - /Users/me/Developer/macOSdb
  …

would shrink .claude.json by ~20.0 KiB (69.9 KiB -> 49.8 KiB).

dry run. re-run with --apply to remove these entries.
quit all Claude Code sessions first; it rewrites this file live.

An entry is a removal candidate only if its directory is provably absent from disk — a path that merely fails to stat (permission denied, an unreachable mount) is kept, and midden never guesses from value contents. --worktrees-only restricts to entries under a .claude/worktrees/ path. If nearly all entries resolve missing — usually a sign you are on a different machine or an unmounted volume rather than that they are all dead — prune --apply refuses unless you pass --force.

Pass --transcripts to also inspect ~/.claude/projects/, where Claude Code stores per-project session transcripts. These directories are named with lossy path slugs, so midden never decodes the directory name. Instead it reads only the head of each *.jsonl transcript and uses the first cwd field it can derive. A transcript directory is skipped if its transcripts disagree, no cwd can be derived, or it has no *.jsonl files.

When a derived cwd is provably absent, prune --transcripts reports the session artifacts it would remove: *.jsonl files and bare UUID-named session artifact directories. memory/ is durable user data and is never deleted. If only memory/ remains, the transcript project directory is kept and reported as memory preserved; unknown entries are left in place and reported as partially cleaned. Unlike .claude.json rewrites, transcript deletion does not create .bak copies, because copying hundreds of MB of append-only logs would make cleanup impractical; the same dry-run, running-claude, mass-deletion, and --force gates still apply.

prune --transcripts also reports the largest kept transcript directories. Those are not removal candidates today because their project directories still exist, but the inventory shows where live Claude Code history is consuming disk so retention-policy work can be deliberate rather than guesswork.

What doctor checks

ID Severity Auto-fixable What it catches
orphaned-project Warn yes projects entry whose directory no longer exists
claude-json-bloat Info no ~/.claude.json over 512 KiB (Claude Code never prunes it)
orphaned-transcript Warn no Transcript directory whose derived cwd no longer exists
claude-transcript-storage Info no Kept transcript history under ~/.claude/projects/ exceeds 64 MiB
stale-worktree Info no Ephemeral worktree dir untouched for >30 days
config-path-inaccessible Warn no Config/worktree path could not be inspected because of permissions or filesystem errors
malformed-json-config Warn no Settings or MCP JSON could not be parsed, so key-aware checks were skipped
secret-in-malformed-config Error no Token-shaped secret appears in malformed committed JSON
secret-in-committed-settings Error no Suspect secret in a settings.json that git doesn't ignore — by key name or value shape (masked by default)
secret-in-committed-mcp Error no Suspect secret in a .mcp.json / managed-mcp.json that git doesn't ignore — by key name or value shape; pure ${VAR} references are exempt
local-settings-tracked Warn no settings.local.json tracked by git (meant to stay machine-local)
local-settings-not-ignored Warn no settings.local.json not gitignored — one git add from being committed
missing-credential-deny Warn no No permissions.deny covers .env or secrets/ paths
skill-missing-skill-md Warn no Skill directory missing its SKILL.md
empty-config-file Warn no Slash command or subagent markdown file is empty
missing-frontmatter Warn no Subagent markdown file missing the required --- YAML frontmatter (slash commands don't need it)
mcp-server-unreachable Warn no MCP server defined with no command or url (any scope, including local)
mcp-server-plaintext-http Warn no MCP server uses plaintext http:// or ws:// for a non-local URL (localhost, *.localhost, loopback, 0.0.0.0, and [::] are local)
mcp-server-disabled Info no MCP server defined but disabled — disabled: true, or listed in the project's disabledMcpjsonServers
stale-mcp-approval Info no enabledMcpjsonServers/disabledMcpjsonServers names a server .mcp.json no longer defines

Configuration

midden does not yet have a config file — all behavior is controlled by CLI flags. Settings precedence and CLAUDE.md merge rules come from Claude Code itself, not midden.

Flag Purpose
--config <PATH> Override the path to ~/.claude.json (for testing)
--claude-home <PATH> Override the path to ~/.claude/ (for testing)
--codex-home <PATH> Override $CODEX_HOME / ~/.codex/ (for testing)
--json Emit machine-readable JSON instead of styled text
--color auto|always|never Control color output
--show-secrets Unmask secret-looking values in show / doctor output
--force Allow writes while a claude process is running, and override the mass-deletion guard

Exit codes

Code Meaning
0 Clean — no findings, or successful apply
1 Findings present (doctor with errors)
2 Error — bad input, missing file, write blocked by running claude

When output is piped and the reader exits early (midden show | head), midden dies of SIGPIPE like any other Unix filter — shells report that as 141, never as a panic.

Building

A justfile provides common tasks:

just build          # Build the project
just build-release  # Build in release mode
just test           # Run tests
just clippy         # Run clippy
just fmt            # Format code
just typos          # Check for typos
just deny           # cargo-deny: license + advisory + source checks
just lychee         # Check README links
just audit          # Audit GitHub Actions workflows (zizmor)
just check          # Run all checks
just install-hooks  # Install git hooks: pre-push check + DCO sign-off (once per clone)

Contributing

Commits must follow Conventional Commits format and include a DCO sign-off (git commit -s). Run just install-hooks once per clone to enable the git hooks (a pre-push just check and DCO sign-off enforcement).

License

This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0-only).

Copyright (C) 2026 Patrick Linnane

About

Resolve, audit, visualize, and clean coding-agent context and state.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages