{"slug": "glean-run-an-ai-skill-only-over-what-changed-since-it-last-ran", "title": "Glean: Run an AI skill only over what changed since it last ran", "summary": "Glean, a new Rust-based developer tool, lets AI skills and MCP servers track which files they have already processed and only operate on files changed since the last run, using content hashing and per-consumer baselines stored in .git/glean/. The tool, installable via cargo and available as a Claude Code plugin, scales with the diff and supports commands like list, mark, status, reset, run, and mcp, with features like NUL-separated paths and JSON output.", "body_md": "`glean`\n\nrecords which files a tool has already processed, so the next run only sees what changed since. A skill on a loop scopes itself to new edits instead of re-sweeping the whole diff every tick.\n\n**Per-consumer baselines.** Each skill or tool tracks its own position, so parallel passes share a tree without redoing each other's work.**Content-hashed.** A file is changed when its bytes differ from the baseline — surviving rebases, branch switches, and rewrites that only bump mtimes.**Scales with the diff.** The candidate set is the uncommitted working set, so a monorepo with three edits costs three reads.**Out of history.** Baselines live in`.git/glean/`\n\n, never committed, separate per worktree.\n\nA single Rust binary. The `/glean`\n\nskill and the MCP server both resolve it by name on `PATH`\n\n:\n\n```\ncargo install --path . --root ~/.local   # → ~/.local/bin/glean\nglean list   [--as <consumer>] [-z] [-q] [--json]        files changed since this consumer's last mark\nglean mark   [--as <consumer>] [--stdin] [-z] [paths…]   record files as processed (no paths = the whole changed set)\nglean status [--as <consumer>] [--json]                  counts; with no --as, summarize every consumer\nglean reset  [--as <consumer>] [--all]                   forget a baseline to force a full re-sweep\nglean run    [--as <consumer>] [--each] -- <cmd>…        run <cmd> on the changed files, mark on success\nglean mcp                                                serve the change-set as MCP tools over stdio\n```\n\nA *consumer* is one skill or tool with its own baseline. `--as`\n\nnames it; it defaults to `default`\n\n.\n\n``` bash\n$ glean list --as slop        # what has changed since slop last ran?\nsrc/auth.rs\nsrc/db.rs\n\n# ... slop processes those two files ...\n\n$ glean mark --as slop src/auth.rs src/db.rs   # record them as done\n\n$ glean list --as slop         # nothing new since\n$\n```\n\n`-z`\n\nwrites NUL-separated paths, safe for paths with spaces or newlines; `--json`\n\nwrites a JSON array. `-q`\n\nprints nothing and exits 0 if anything changed, 1 if not. `mark --stdin`\n\nreads paths from stdin:\n\n```\nglean list -z --as slop | glean mark --stdin -z --as slop\n```\n\nConsumers are independent. When a file changes, every consumer that has not seen those exact bytes picks it up, including files the other passes edited:\n\n```\nglean list --as slop        # code smells\nglean list --as simplify    # structure\nglean list --as check       # type checking\n```\n\nglean ships as a Claude Code plugin — the `/glean`\n\nskill and the `glean`\n\nMCP server:\n\n```\n/plugin marketplace add amalucelli/glean\n/plugin install glean@glean\n```\n\nBoth call the `glean`\n\nbinary by name, so install that too. Without the plugin, copy the skill where Claude Code looks for it:\n\n```\ncp -r skills/glean ~/.claude/skills/\n```\n\n`/glean <skill>`\n\nscopes `<skill>`\n\nto what changed since it last ran, invokes it, and marks the result. Point a loop at it:\n\n```\n/loop 2m /glean slop         # slop only new edits, every 2 minutes\n/loop 5m /glean simplify     # works with built-in skills too\n```\n\nIt runs in a forked subagent, so the loop's main context grows by one line per tick rather than by every file the pass reads. Run the skill directly to watch or steer it. The wrapped skill must accept file paths as arguments. Forking from a plugin needs Claude Code v2.1.101+; older versions run it inline.\n\n`glean run`\n\npackages list → run → mark into one command:\n\n```\ntool <args> <files>   →   glean run --as tool -- tool <args>\n```\n\nIt snapshots the changed set, runs the command on it, and marks those files only if the command succeeds — a failing pass leaves its files for the next tick. `run`\n\nexits with the command's status. In CI, cache `.git/glean/`\n\nbetween runs and a step only re-checks files that changed since they last passed.\n\n**Formatters** rewrite in place, so batch (the default) fits: glean records the formatted bytes as the new baseline.\n\n```\nglean run --as gofmt -- gofmt -w\n```\n\n**Linters** report per file, so use `--each`\n\n: the command runs once per file and only passing files are marked. A file with errors returns each tick until it is fixed, instead of pinning the whole batch.\n\n```\nglean run --each --as eslint -- eslint\n```\n\nOutside Claude Code that is a plain shell loop:\n\n```\nwhile true; do\n  glean run --each --as eslint -- eslint\n  sleep 300\ndone\n```\n\nWhole-project tools that cannot take file paths (`cargo clippy`\n\n, `tsc`\n\n) do not fit `run`\n\n. Gate them on `-q`\n\ninstead:\n\n```\nglean list -q --as clippy && cargo clippy && glean mark --as clippy\n```\n\n`glean mcp`\n\nserves the change-set over stdio. The plugin registers it automatically; for another client, run `glean mcp`\n\nas the server command.\n\n`glean_list`\n\n— paths changed since a consumer last marked them.`glean_mark`\n\n— record paths as processed; omit`paths`\n\nto mark the whole changed set.`glean_status`\n\n— tracked and changed counts per consumer.\n\n`run`\n\nis not exposed: the MCP surface reads and advances the cursor, it does not execute commands.\n\n- The candidate set is\n`git diff HEAD`\n\nplus`git ls-files --others`\n\n— staged, unstaged, and untracked. - Baselines are stored at\n`.git/glean/<consumer>.json`\n\n. Git does not track its own directory, so the state stays out of history and out of glean's view of the tree. - Each consumer is the sole writer of its own file, so consumers need no locking.\n- Lockfiles and binary files are excluded from\n`list`\n\n. `core.fsmonitor`\n\nand`core.untrackedCache`\n\nspeed up large trees.\n\nThere is no base flag. For committed work the file set (`git diff <ref>`\n\n) is static and swept once, so a cursor adds nothing — scope that with git, or with the skill's own branch mode.\n\nMIT. See [LICENSE](/amalucelli/glean/blob/main/LICENSE).", "url": "https://wpnews.pro/news/glean-run-an-ai-skill-only-over-what-changed-since-it-last-ran", "canonical_source": "https://github.com/amalucelli/glean", "published_at": "2026-08-31 02:39:48+00:00", "updated_at": "2026-08-31 02:52:41.350067+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools"], "entities": ["Glean", "Claude Code", "MCP"], "alternates": {"html": "https://wpnews.pro/news/glean-run-an-ai-skill-only-over-what-changed-since-it-last-ran", "markdown": "https://wpnews.pro/news/glean-run-an-ai-skill-only-over-what-changed-since-it-last-ran.md", "text": "https://wpnews.pro/news/glean-run-an-ai-skill-only-over-what-changed-since-it-last-ran.txt", "jsonld": "https://wpnews.pro/news/glean-run-an-ai-skill-only-over-what-changed-since-it-last-ran.jsonld"}}