undomap

DOCS · SHEET 05 OF 06

Reference

Finding kinds

kindzonewhen
ignoredVEgitignored, not regenerable (or regenerable-looking but listed under permanent)
untrackedVEuntracked, not regenerable
no-gitVEoutside every git work tree (dir/, or * for loose files)
symlink-escapeVEa link inside the map whose target is outside it and writable by you; bytes are the target's
no-remoteVErepo with commits and no remote: .git is the only copy
regenerableAEknown build output by name, or by marker: pyvenv.cfg, CACHEDIR.TAG, ELF/Mach-O/PE headers
dirtyAEtracked file with uncommitted changes
unpushedAEcommits on local branches not on any remote
snapshotAEwould be VE, but a snapshot probe covers it
backed-upAEwould be VE, but .undomap.json says it's backed up
cloudAEwould be VE, but it's in a sync folder whose version history undomap could verify (see cloud sync)
trackedXclean tracked files, one aggregate per repo

Cloud sync

A sync client copies a delete to the cloud within seconds, so the real undo is the provider's version history and deleted-files bin. undomap only counts it when it can show the history covers the path. The probe is read-only and can't fail the map.

ProviderDetected fromHistoryKnown gaps (stay Zone VE)
Dropbox~/.dropbox/info.json (or %APPDATA%/%LOCALAPPDATA%\Dropbox\info.json) paths; weaker: a .dropbox marker above the map, ~/Dropbox*versions and deleted files, 30+ days by plancom.dropbox.ignored / com.apple.fileprovider.ignore#P on the path or a folder above it; rules.dropboxignore; desktop.ini, .DS_Store, ~$…, .~…, ~…tmp
OneDrive%OneDrive%, %OneDriveConsumer%, %OneDriveCommercial%, ~/Library/CloudStorage/OneDrive-*; weaker: ~/OneDrive*version history and recycle bin, 30 days (93 for work)files over 250 GB; .tmp, desktop.ini, .DS_Store, ~$…, .lock, CON/NUL/…, _vti_, " * : < > ? |
Google Drive~/Library/CloudStorage/GoogleDrive-*, G:\My Drive-style virtual drives; weaker: legacy ~/Google Drivefile versions for 30 days or 100 versions, trash for 30 daysfiles over 5 TB; .tmp, desktop.ini, .DS_Store, ~$…
iCloud Drive~/Library/Mobile Documents (macOS), ~/iCloudDrive (Windows)Recently Deleted keeps deleted files 30 days; no older versions of overwritten filesalways: an overwrite is permanent. Also *.nosync, *.tmp, files over 50 GB

The demotion rule. A path moves to Zone AE (kind: "cloud") only when all of these hold:

  1. the client's own config (Dropbox info.json, the OneDrive environment variables, the ~/Library/CloudStorage folder the client creates) points at a folder containing it;
  2. the client is running right now (ps / tasklist), so the folder isn't a stale copy;
  3. no known gap applies to the path or any folder above it, and its largest file is under the provider's per-file limit;
  4. for Dropbox, the ignore attribute could be read and isn't set, and rules.dropboxignore doesn't match.

iCloud Drive never demotes: it keeps deletes but not overwrites, and an agent overwriting a file is as final as deleting it. Anything undomap can't confirm (client not running, a folder name or .dropbox marker with no client config, attributes it can't read) stays in Zone VE with possible cloud versioning, unverified in the reason, the probe line, and one cloud sync line under the report with the cheapest way to check. A snapshot or backedUp still wins over all of this.

What it can't see. A paused sync, a full quota, or a subfolder inside a place that's marked ignored (undomap checks the place itself and the folders above it). If the client shows errors, treat cloud Zone AE as Zone VE. iCloud's Desktop & Documents sync isn't detected, which only errs towards Zone VE.

JSON

{
  "tool": "undomap", "version": "0.1.0", "root": "/home/me/app", "scannedAt": "…", "durationMs": 41,
  "repos": [{ "path": ".", "remote": "origin", "unpushed": 2, "branch": "main" }],
  "probes": [{ "name": "git", "status": "ok", "detail": "2.47.3", "counts": true }, …],
  "totals": { "VE": { "bytes": 1300000000, "places": 4, "files": 3155 }, "AE": {…}, "X": {…} },
  "findings": [{ "zone": "VE", "kind": "ignored", "path": "textures_sorted/", "bytes": 1300000000,
                 "files": 3112, "capped": false, "why": "gitignored", "secret": false,
                 "forcedBy": "textures_sorted/",   // only when a .undomap.json "permanent" pattern matched
                 "cloud": { "provider": "Dropbox", "status": "unverified", "note": "Dropbox app not running" },
                 "fix": { "say": "…", "run": "…", "cost": "minutes" } }, …],
  "skipped": [{ "path": "private/", "reason": "EACCES" }],
  "exitCode": 1, "thresholdBytes": 0,
  "reach": {                                   // only with --reach
    "credentials": [{ "path": ".env", "type": "dotenv", "where": "tree" },
                    { "path": "/home/me/.aws/credentials", "type": "AWS credentials", "where": "home" },
                    { "path": "GITHUB_TOKEN", "type": "token-like name", "where": "env" }],
    "credentialsCapped": false,
    "network": { "status": "open", "detail": "eth0 has an address (no connection attempted)" },
    "writable": [{ "path": "/home/me", "why": "your home folder" }],
    "legs": 3, "trifecta": true,
    "fix": { "say": "break one leg: …", "run": "env -u GITHUB_TOKEN "$SHELL"", "cost": "minutes" }
  }
}

cloud is present for a path inside a sync folder: status is covered (graded AE), unverified, partial (iCloud: deletes only) or gap (the provider skips it); note says why. forcedBy is present when a permanent pattern from .undomap.json matched the path (see precedence); why then says the config forced it. Paths are relative to root, use POSIX separators, and directories end in /. capped: true means sizing stopped at 250,000 entries for that place, so bytes is a lower bound (shown with a +). Remote URLs are never printed, only remote names, because URLs can carry tokens.

reach (only with --reach): where is tree (path relative to root), home (absolute) or env (the variable name: never its value). network.status is open, closed (loopback only, or the Codex sandbox's network-disabled flag) or unknown (loopback plus a proxy, as sandboxes with an allowlist set up). legs counts the three conditions; trifecta is all three.

MCP tools

toolargsreturns
map_reportpath?, reach? (false)Markdown report + compact JSON; with reach, the credential reach section too
list_permanentpath?, limit? (25)JSON: summary, permanent[] with path, bytes, why, forcedBy, cloud, fix, run; more

Both are annotated readOnlyHint: true, destructiveHint: false.

Next sheet: FAQ