Skip to content

starhaven-io/midden

Repository files navigation

midden

CI License: AGPL-3.0-only

A CLI tool that resolves, audits, and garbage-collects the heap of state Claude Code accumulates.

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. ~/.claude.json is 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. Claude Code writes a lot of state across many files — ~/.claude.json's projects map appended to on every visit and never pruned, settings layered across user/project/local/managed scopes with non-obvious precedence, ephemeral worktrees with adjective-scientist names, memory files (CLAUDE.md) loading from many locations simultaneously — and almost nothing in the loop removes any of it. midden surfaces what's actually active for a given 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.

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 report-only for doctor. Writes always require an explicit flag and always create a timestamped backup first. Use --json for machine-readable output.

# 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

# 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

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.

Secret-looking keys (*_token, *_api_key, password, credential, …) are masked to abcd*** by default. 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 KB (69.9 KB -> 49.8 KB).

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. midden never guesses from value contents. --worktrees-only restricts to entries under a .claude/worktrees/ path.

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 KB (Claude Code never prunes it)
stale-worktree Info no Ephemeral worktree dir untouched for >30 days
secret-in-committed-settings Error no Suspect key holding a string value in committed settings.json
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
mcp-server-unreachable Warn no MCP server defined with no command or url
mcp-server-disabled Info no MCP server defined but disabled: true

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)
--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 (prune --apply, doctor --fix) while a claude process is running

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

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

Contributing

Commits must follow Conventional Commits format and include a DCO sign-off (git commit -s).

Acknowledgements

Built with Claude Code.

License

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

Copyright (C) 2026 Patrick Linnane

About

Audit Claude Code's config sprawl. Clean up the midden left behind.

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Packages

 
 
 

Contributors