moldig
v0.1.2
Published
CleanMyMac for your AI setup: scan, review and clean the skills, MCP servers, context files, memories and cache that AI coding harnesses leave across your projects.
Maintainers
Readme
moldig
CleanMyMac for your AI setup. Six AI coding harnesses — Claude Code, Codex, Cursor, Gemini CLI, Copilot and OpenCode — each keep their own configuration and their own state on your machine, spread across every project you have ever opened: context files you wrote, skills installed through several installers into a dozen harness directories at once, MCP servers configured in five different files, memory files a harness writes for itself, and hundreds of megabytes of harness cache. moldig reads all of it in one read-only pass and shows you what is there, what one session in the project you are standing in costs you in tokens, and what is worth removing.
npx moldig # the interactive experience
npx moldig scan # what every harness left on this machine
npx moldig audit # the headline number and the findings
npx moldig clean # the explicit form of the trusted Clean ritual
npx moldig purge # Delete state left by missing Projects
npx moldig update # update recognised Skills, plugins and Docker MCP imagesRequires Node.js 22.18 or newer. macOS, Linux and Windows.
Status at this version. All six adapters,
scan,audit, the focused Clean ritual, missing-Projectpurgeand machine-wideupdateare here, including unattended filtered Clean. moldig always names the harnesses it read and never claims to have changed anything it did not.
Install
npx moldig # no install
npm install -g moldig # or keep it around
brew install guillermolg00/tap/moldig # once the tap existsThe published package is a bundle of the engine, the commands and the interactive experience
with one runtime dependency, trash — its native helpers cannot be bundled — and
everything else inlined. The engine is published separately as
@moldig/core.
What it finds
Eight kinds of thing, each one entity per real thing on disk, whichever harnesses reach it:
| | |
|---|---|
| Context files | CLAUDE.md, AGENTS.md, GEMINI.md, Cursor rules — which harness loads which, fully, on demand or never |
| Skills | one row per real directory, with every placement that reaches it, its origin and whether it drifted from it |
| MCP servers | every entry in every configuration file, with duplicates and exposed secrets |
| Memory files | what a harness wrote about a project for itself, its size in tokens, and (Claude Code) which facts were never read |
| Agent definitions | the sub-agent configurations a harness can spawn |
| Plugins | installed bundles that provide skills, agent definitions, MCP servers or hooks as one unit |
| Settings files | settings, MCP configuration, lock files, plugin registries, policy files, credential stores |
| Harness cache | transcripts, tool results, shell snapshots, rotating backups, plugin and marketplace clones, databases — grouped by the unit the harness itself documents as sweepable |
Around them: the projects every harness has worked in (including the ones whose directory is gone), the breadcrumbs that prove it, and the edges between everything — which harness loads what, which skill duplicates which, what a lock file lists, what nothing resolves.
The audit files what it thinks you should look at into eight categories: duplicate, orphan, bloat, drift, shadow memory, autogenerated, harness cache, exposure.
Commands
moldig [roots…] — the interactive experience
moldig # every project on this machine
moldig ~/Work # only the projects under ~/WorkInside a Project, the first screen is one narrow Plan containing only that Project's old,
documented-sweepable Harness cache; outside every Project, it contains the same safe cache across
the scanned Roots. Enter is the confirmation, while space can exclude a group or item and tab
enters Inventory. Human-owned Context files, Skills, Agent definitions, plugins, MCP servers,
Memory, kept cache and Live state never enter this trusted Clean Plan.
Inventory contains the Finding categories and existing surgical views. From there, u opens the
machine-wide Update Plan. moldig purge separately opens one compact missing-Project list: toggle
Projects with space, use a for all/none, then Delete their complete Harness records after two
confirmations.
After any run, moldig scans and audits again before it returns.
Keys: ↑↓ j k to navigate (PgUp/PgDn, Home/End jump), enter to choose or open,
space to select removable Harness state, a cleanup group or one missing Project, a for every
removable row or every missing Project in the current view, d for an explicit Delete, u for
Update (or Update all from Inventory), o to open the path in your editor, g for the graph, /
to filter, r for Finding categories, p for Projects, s for
the selection, esc to go back, ? for shortcuts and q to leave. Where the terminal supports
OSC 8, paths are clickable links.
q gives the terminal back and leaves one quiet summary line on the primary screen (a completed
run keeps its recovery details). Outside a terminal — a pipe, a CI log, TERM=dumb — moldig
prints the audit plus that same summary and exits 0 without interacting. moldig --json prints
the same document as
audit --json, terminal or not; it takes no --fail-on, so it always exits 0. Use
moldig audit when you want an exit code that means something.
Exit codes: 0 you left with nothing failed · 1 at least one row of a run failed · 2 a
usage or environment error.
moldig scan [roots…]
The read-only pass, and nothing else: no detectors, no read signal, no headline.
Harnesses
Harness Presence Version Projects Warnings
Claude Code installed 2.1.245 2 1
…
Totals
42 entities · 36 files · 31.4 KB
harness cache 4.8 KB · memory files 5.3 KB · 1 604 tokens on diskOne row per harness with its presence, its version where the harness writes it down, and its
counts per kind; the projects with what a session there loads and what their harness cache
weighs; the totals; and the split of projects into present, gone and unreachable. With --json
it prints the index document (schemaVersion: 0) on stdout and nothing else.
Exit codes: 0 the scan completed — warnings never change it · 2 a usage or environment
error.
moldig audit [roots…]
Scan, then the read signal and the eight detectors.
Headline number
project-a — the Project the working directory is in
Claude Code
every session pays 100 + project-a adds 265 = 365 tokens/session
Categories
Category Findings Severity
duplicate 2 low
orphan 1 medium
…
Findings
Severity Category Finding Impact
medium orphan gone: directory gone; 2 breadcrumbs, 2 memory… 720 B
…The headline number counts only what you control — context files, their imports, the loaded
slice of memory files, skill descriptions — never the harness's own system prompt or tool
schemas. No prices anywhere. With --json it prints the index document plus findings[] and
headline.
| Flag | |
|---|---|
| --fail-on low\|medium\|high\|never | exit 1 on a finding at this severity or above (default low) |
| --category <c> | duplicate, orphan, bloat, drift, shadow-memory, autogenerated, harness-cache, exposure; repeatable |
| --severity low\|medium\|high | keep that severity and above |
| --no-read-signal | skip the memory read signal; never-read facts stay unknown |
--category and --severity restrict the printed table, the JSON findings[] and what
--fail-on looks at — the document reports what you asked for. The headline and the index parts
are never filtered.
Exit codes: 0 nothing at or above --fail-on · 1 something is · 2 a usage or environment
error. In CI:
npx moldig audit --fail-on high # fails the build on, say, a secret in a git-tracked .mcp.jsonmoldig clean [roots…]
The named form of the same focused/global trusted Clean Plan described above. In a terminal, Enter
moves the reviewed cache to the OS Trash without a second prompt. Unattended it needs both
--yes and a filter, so a scheduled run can never remove more than it was told to, and it only
ever reaches what the audit preselected; without them it prints why and exits 2.
| Flag | |
|---|---|
| --yes | run unattended; a filter is required with it |
| --category harness-cache | the only category an unattended clean reaches in v1 |
| --older-than <days> | keep only units older than this |
| --harness <id> | keep only units of these harnesses |
| --dry-run | print the plan and stop; nothing is moved, and no manifest and no backup are written |
npx moldig clean --dry-run # what a run would do, and nothing else
npx moldig clean --yes --older-than 60 # unattended, and never more than it was told
npx moldig clean --dry-run --json | jq .rows # the plan as the run-manifest documentAn unattended clean can only ever narrow what the audit preselected: harness cache the harness itself documents as safe to sweep, past that harness's own retention, with no live session on it. Nothing widens that set. Memory files are never in it without an explicit selection, and human-owned items are never part of a Clean at all — inspect those from Inventory instead.
Exit codes: 0 every attempted row ended moved, edited or delegated · 1 at least one row
failed · 2 it refused to run, or a usage or environment error.
moldig purge [roots…]
Requires a terminal. Every missing Project starts selected as one aggregate Delete target. Files go to the OS Trash; store entries are backed up before precise edits; Live state remains. The Plan asks twice, continues after row failures, re-scans, and then returns a recovery-aware Result.
Only [roots…], --no-git, help and version flags are accepted. Exit codes: 0 every attempted
row succeeded · 1 a row failed · 2 no terminal, usage or environment error.
moldig update [roots…]
Requires a terminal and opens one Update Plan over the complete scanned Index. Vercel Skills are grouped by lock scope and updated once per scope. Locally modified or divergent Skills stay; a plugin containing one stays too. Plugin-owned MCP servers follow their parent plugin. Remote servers and ephemeral npx/uvx launchers are shown as managed elsewhere or on launch, not falsely updated. Docker MCP images are pulled once per trusted Docker command, context and platform target. Launcher version pins, Docker digests, direct binaries and ambiguous launchers stay with a reason and item labels.
Enter continues to one confirmation. Every updater runs as preserved argv + cwd without a shell;
failures do not stop later batches. moldig then re-scans and returns to Inventory. Only [roots…],
--no-git, help and version flags are accepted. Exit codes: 0 every updater succeeded · 1 an
updater failed · 2 no terminal, usage or environment error.
Shared flags
| Flag | |
|---|---|
| [roots…] | limit the scan to the projects under these directories; a root that is not an existing directory is a usage error |
| --harness <id> | claude-code, codex, cursor, gemini-cli, copilot, opencode; repeatable |
| --no-git | never spawn git; git-tracked status stays unknown |
| --json | the machine-readable document on stdout and nothing else |
| --pretty | indent the JSON; implies --json |
| --help, -h | the page for moldig or for a command (moldig scan --help) |
| --version, -V | the version |
Exit codes
| | |
|---|---|
| 0 | the scan completed, or no finding reached --fail-on, or every attempted row succeeded |
| 1 | a finding reached --fail-on, or a row of a run failed |
| 2 | a usage or environment error (an unknown flag, an unknown harness id, a root that is not a directory, a platform moldig does not run on, Node older than 22.18), clean refusing to run, or purge/update without a terminal |
Output contract
With --json, stdout carries the JSON document and nothing else: no banner, no progress, no
ANSI. Warnings are emitted twice — one line on stderr as warning <code>: <message>, and the
same records in warnings[]. The seven codes are parse-error, stat-deadline,
sqlite-unreadable, tokenizer-fallback, unsupported-shape, git-missing and
read-signal-skipped. A usage error prints one line and the usage synopsis on stderr.
NO_COLOR, FORCE_COLOR and TERM=dumb are honoured; there is no --no-color flag. No file
contents, no transcript text and no secret value ever reaches any output.
The six harnesses
Every adapter reads its harness's user scope, and the projects the breadcrumbs name.
| Harness | Id | User scope | In a project |
|---|---|---|---|
| Claude Code | claude-code | ~/.claude/ and ~/.claude.json — CLAUDE_CONFIG_DIR moves both | CLAUDE.md, CLAUDE.local.md, .claude/, .mcp.json |
| Codex | codex | ~/.codex/ (CODEX_HOME), its config.toml, sessions, memories and databases (CODEX_SQLITE_HOME) | AGENTS.md, .codex/ |
| Cursor | cursor | ~/.cursor/ (CURSOR_CONFIG_DIR) and Cursor's application-support directory | .cursor/, .cursorrules, AGENTS.md |
| Gemini CLI | gemini-cli | ~/.gemini/, plus the system settings files GEMINI_CLI_SYSTEM_DEFAULTS_PATH and GEMINI_CLI_SYSTEM_SETTINGS_PATH name | GEMINI.md, .gemini/ |
| Copilot | copilot | ~/.copilot/ (COPILOT_HOME) and VS Code's application-support directory, stable and Insiders | .github/copilot-instructions.md, .github/{instructions,skills,agents,prompts}/, .github/mcp.json, .vscode/mcp.json, AGENTS.md |
| OpenCode | opencode | the XDG config, data, cache and state directories (~/.config/opencode and friends), plus $OPENCODE_CONFIG | opencode.json, opencode.jsonc, .opencode/, AGENTS.md |
On top of those, the stores several harnesses share — ~/.agents/, .agents/skills,
skills-lock.json, .skill-lock.json — are always read, because the skills in them belong to
no single harness. --harness never turns them off, and it never changes what an entity is:
restricting the scan removes readers, never the thing they read.
A harness that left no trace on the machine is not listed. A harness's version is read only
where the harness writes it down; binaries are never run and PATH is never probed.
What moldig promises
- The scan is read-only. It never runs a harness, a sub-agent or an MCP server. The only
process it spawns is
git, to learn what a repository tracks —--no-gitturns even that off. It creates no configuration file, no cache and no data directory of its own. - Credential stores are never opened. They are listed by name and size so the megabytes are honest, and that is all. MCP configuration files are parsed for key names and sanitised endpoints; no secret value reaches the screen or the JSON.
- Harness databases are opened read-only (
?immutable=1, falling back to?mode=ro), never written and never copied — not even a-walsidecar is left beside a database that had none. A database that opens neither way becomes a warning, not a guess. - Every removal is recoverable. Files, directories and links go to the system trash. A configuration or lock file is copied to a backup before an entry is edited, and the backup path is printed. What moldig does not understand it never rewrites: it delegates to the harness's own command. On a network, read-only, dropped-mount or unclassifiable volume nothing is removed and the row says why.
- Every run is recorded. A clean, delete or update run writes a run manifest listing each target, where it went and how it ended, and prints its path.
- Nothing is ever written inside a repository. No backups, no manifests, no cache files. moldig never dirties your git status, and every suggested action on a git-tracked item carries a warning because your collaborators may rely on it.
- Scan, audit and every removal stay offline. Only a confirmed Update hands preserved argv to recognised installers or Docker, whose normal network access is previewed before it runs.
- No telemetry, no account, no daemon, no update check, no configuration file. The first run
is
npx moldigand nothing else.
Where moldig keeps its own files
Run manifests and backups — the only things moldig ever writes — live outside every repository, under:
| | |
|---|---|
| macOS, Linux | $XDG_DATA_HOME/moldig, default ~/.local/share/moldig |
| Windows | %LOCALAPPDATA%\moldig, default <home>\AppData\Local\moldig |
runs/<run id>.json for the manifests, backups/<run id>/ for the backups. Nothing is created
until a run actually writes something; a scan or an audit creates nothing at all. There is no
restore command: the trash and the backups are the recovery path, and both are yours.
Screenshots
Coming with the first tagged release.
Something not right?
Open a ticket at github.com/guillermolg00/moldig/issues.
Include the command you ran, what moldig --version prints, your operating system and your
Node version. moldig scan --json --pretty is useful to attach — it carries no file contents
and no secret values — but read it first: it does carry the absolute paths of your machine.
Development
bun install
bun run check # typecheck, lint, format
bun run test # Vitest on Node — never `bun test`
bun run build
node packages/cli/dist/cli.mjsFixture trees of the six harnesses live under fixtures/<harness>/<case>/, with the contract in
fixtures/README.md. Commits are conventional. The vocabulary every user-visible string uses is
in CONTEXT.md.
github.com/guillermolg00/moldig · MIT © Guillermo López
