fallow 3.18.0 → 3.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,6 +11,7 @@ Complete command and flag specifications for all fallow CLI commands.
11
11
  - [`fix`: Auto-Remove Unused Code](#fix-auto-remove-unused-code)
12
12
  - [`list`: Project Introspection](#list-project-introspection)
13
13
  - [`init`: Config Generation](#init-config-generation)
14
+ - [`agent`: One-Pass Agent Onboarding](#agent-one-pass-agent-onboarding)
14
15
  - [`migrate`: Config Migration](#migrate-config-migration)
15
16
  - [`health`: Function Complexity and File Health Analysis](#health-function-complexity-and-file-health-analysis)
16
17
  - [`audit`: Changed-File Quality Gate](#audit-changed-file-quality-gate)
@@ -345,6 +346,73 @@ fallow hooks uninstall --target agent
345
346
 
346
347
  ---
347
348
 
349
+ ## `agent`: One-Pass Agent Onboarding
350
+
351
+ Wires fallow into the coding-agent harnesses a project uses. `install` detects Claude Code, Codex, and Cursor from the project (`.claude/`, `CLAUDE.md`, `.mcp.json`, `.codex/`, `.cursor/`; `AGENTS.md` is not a signal because every harness and fallow itself write it), the home directory, and the session environment (`CLAUDECODE`, `CODEX_THREAD_ID`, `CURSOR_AGENT`), or takes `--harness`. When nothing is detected only harness-neutral files are written (`AGENTS.md` and `.agents/skills/fallow`).
352
+
353
+ Steps per harness:
354
+
355
+ | Step | Claude Code | Codex | Cursor |
356
+ |---|---|---|---|
357
+ | `guide` | `AGENTS.md` task map; `CLAUDE.md` gains an `@AGENTS.md` import (created when absent, appended as a marked block otherwise) | `AGENTS.md` task map | `AGENTS.md` task map (Cursor reads it) |
358
+ | `skill` | `.claude/skills/fallow/` | `.agents/skills/fallow/` | `.agents/skills/fallow/` |
359
+ | `mcp` | `mcpServers.fallow` in `.mcp.json` (`--approve` also lists it in `.claude/settings.local.json`) | `[mcp_servers.fallow]` in `.codex/config.toml` (applies once the project is trusted; the `codex mcp add` next step works immediately) | `mcpServers.fallow` in `.cursor/mcp.json` |
360
+ | `hooks` | `.claude/settings.json` PreToolUse gate plus `.claude/hooks/fallow-gate.sh` | marked gate block in `AGENTS.md` | skipped (`unsupported_harness`) |
361
+
362
+ The skill is a small pointer to `node_modules/fallow/skills/fallow` when that copy exists (so it never drifts from the installed binary); otherwise the tree embedded in the binary is written. The MCP command is probed before anything is written: `npx --no fallow-mcp` for an npm-installed project, `fallow-mcp` from `PATH`, or the running multicall binary; when none exists the step is `skipped` with `mcp_entry_unavailable` rather than writing a config that cannot start.
363
+
364
+ Every file or block carries a `<!-- fallow:agent-install v1 ... -->` marker. Re-running is byte-stable. An existing skill named `fallow` without a marker is `refused` (`skill_name_taken`) unless `--force`. JSON and TOML cannot carry a marker, so a `fallow` MCP entry counts as fallow-managed only when its command is one fallow writes; any other entry is `refused` (`mcp_entry_foreign`) and never removed without `--force`. `--force` on an unparsable config file saves the old bytes as `<file>.fallow-bak` before rewriting. `uninstall` removes managed content, deletes a config file it emptied (and an emptied `.cursor/` or `.codex/` directory), and deletes `AGENTS.md` or `CLAUDE.md` only while the file still matches what fallow authored.
365
+
366
+ ### Flags
367
+
368
+ | Flag | Applies to | Description |
369
+ |---|---|---|
370
+ | `--harness <auto\|claude\|codex\|cursor>` | `install`, `uninstall` | Repeatable; default `auto` |
371
+ | `--without <guide\|skill\|mcp\|hooks>` | `install` | Skip a step; repeatable |
372
+ | `--dry-run` | `install`, `uninstall` | Print the plan without touching the filesystem |
373
+ | `--force` | `install`, `uninstall` | Replace or remove skills, hook scripts, or config files fallow did not write |
374
+ | `--approve` | `install` | Pre-approve the project MCP server for yourself in `.claude/settings.local.json`; refused when that file is tracked by git |
375
+ | `--user` | `install`, `uninstall` | Skill and MCP config under `$HOME` (`~/.claude/skills`, `~/.agents/skills`, `~/.codex/config.toml`, `~/.cursor/mcp.json`); the guide step is skipped, and Claude Code prints the `claude mcp add --scope user` command instead of editing `~/.claude.json` |
376
+ | `--gitignore-claude` | `install` | Append `.claude/` to `.gitignore` |
377
+
378
+ Root: the git toplevel of the current directory unless `--root` is passed explicitly, so a run from a monorepo package still writes where the harnesses read. The chosen root is the first line of output and `root` in JSON.
379
+
380
+ ### Output
381
+
382
+ Human output groups paths under "Shared with your team (commit these)" and "Local to you". JSON:
383
+
384
+ ```json
385
+ {
386
+ "kind": "agent-install",
387
+ "schema_version": 1,
388
+ "fallow_version": "3.19.0",
389
+ "root": "/abs/path",
390
+ "mode": "install",
391
+ "dry_run": false,
392
+ "harnesses": ["claude", "codex"],
393
+ "detected": true,
394
+ "evidence": [{"harness": "claude", "evidence": [".claude", "$CLAUDECODE"]}],
395
+ "steps": [
396
+ {"harness": null, "step": "guide", "status": "written", "scope": "shared", "path": "AGENTS.md"},
397
+ {"harness": "claude", "step": "mcp", "status": "skipped", "scope": "local", "path": ".claude/settings.local.json", "reason": "approval_not_requested"}
398
+ ],
399
+ "next_actions": [{"id": "codex-mcp-add", "command": "codex mcp add fallow -- npx --no fallow-mcp", "reason": "...", "mutating": true}]
400
+ }
401
+ ```
402
+
403
+ `status` values: `written`, `removed`, `unchanged`, `skipped`, `refused`, `failed`. Exit code 2 when any step is `refused` or `failed`; every other step still runs. `kind` is `agent-install`, `agent-uninstall`, or `agent-status`; `schema_version` is `1`; `agent status` reports `surfaces[]` with `installed`, `stale`, `absent`, or `foreign`. `next_actions` is deliberately not `next_steps`: entries flagged `mutating: true` write harness config when run, unlike the read-only `next_steps[]` of the analysis commands.
404
+
405
+ ### Examples
406
+
407
+ ```bash
408
+ fallow agent install --dry-run # show the plan for the detected harnesses
409
+ fallow agent install # wire everything detected
410
+ fallow agent install --harness claude --approve
411
+ fallow agent install --without hooks --format json --quiet
412
+ fallow agent status --format json
413
+ fallow agent uninstall --dry-run
414
+ ```
415
+
348
416
  ## `migrate`: Config Migration
349
417
 
350
418
  Migrates configuration from knip and/or jscpd to fallow. Auto-detects config files.
@@ -1779,7 +1847,7 @@ These are global flags with behavior specific to bare `fallow` combined mode.
1779
1847
  | `FALLOW_FORMAT` | Default output format. CLI `--format` overrides. |
1780
1848
  | `FALLOW_QUIET` | Set to `1` to suppress progress. CLI `--quiet` overrides. |
1781
1849
  | `FALLOW_BIN` | Path to fallow binary (used by the MCP server). |
1782
- | `FALLOW_TIMEOUT_SECS` | MCP server subprocess timeout in seconds (default: `120`). Increase for very large codebases. |
1850
+ | `FALLOW_TIMEOUT_SECS` | MCP server subprocess timeout in seconds (default: `120`; similar-code discovery and inspection default to `900`). Increase or reduce it to override either bound. |
1783
1851
  | `FALLOW_EXTENDS_TIMEOUT_SECS` | Timeout for fetching remote config inheritance in seconds (default: `5`). Do not raise this for untrusted sources. |
1784
1852
  | `FALLOW_CACHE_DIR` | Override the persistent extraction cache directory. Wins over `cache.dir`. Useful for read-only checkouts or CI cache volumes. `--no-cache` disables this knob. |
1785
1853
  | `FALLOW_CACHE_MAX_SIZE` | Maximum on-disk extraction cache (`.fallow/cache.bin`) size in megabytes (default: `256`). Triggers LRU eviction when crossed. Wins over `cache.maxSizeMb` config field. Intended for CI runners with disk quotas. `--no-cache` short-circuits this knob. |
@@ -486,7 +486,7 @@ The detector intentionally abstains when a Tailwind plugin or published CSS surf
486
486
 
487
487
  The same Tailwind v4 projects also get `css_analytics.token_consumers`, the reverse index: per `@theme` token, where it is consumed (a `consumer_count` plus a located `consumers[]` sample tagged `theme-var` / `css-var` / `utility` / `apply`), so you can read a token's blast radius before changing it. Treat `consumer_count` as a static lower bound: a computed class name such as `bg-${color}` is invisible to the scan, so a `0` here is the same "nothing fallow can see consumes this" population as `unused_theme_tokens`, not a deletion proof. `token_consumers` is descriptive context with no `actions[]`; drive any deletion off `unused_theme_tokens` and its verification command.
488
488
 
489
- `token_consumers` also covers CSS-in-JS token DEFINITIONS (StyleX `defineVars`, vanilla-extract `createTheme` / `createThemeContract` / `createGlobalTheme`, and PandaCSS `defineTokens`), disambiguated by the consumer `kind`: StyleX and vanilla-extract entries use `kind` `js-member`, `token` is the binding-qualified dotted access path (`vars.color.primary`), and `namespace` is the defining binding (`vars`); PandaCSS entries use the defining binding plus token path (`tokens.colors.brand`) and `token(...)` consumers are tagged `js-call`. The cross-file scan uses fallow's shared import resolver, so relative imports, tsconfig `paths` aliases, and workspace package imports can resolve to the token definition. Dynamic import strings, unresolved aliases, generated package state, and computed token access still keep `consumer_count` a lower bound, and unlike Tailwind there is no corroborating dead-token finding, so a CSS-in-JS `consumer_count` of `0` is a weaker signal. Gated on a declared CSS-in-JS library (`@stylexjs/stylex`, `@vanilla-extract/css`, or `@pandacss/dev`).
489
+ `token_consumers` also covers CSS-in-JS token DEFINITIONS (StyleX `defineVars` / `unstable_defineVarsNested`, vanilla-extract `createTheme` / `createThemeContract` / `createGlobalTheme`, and PandaCSS `defineTokens`). Member reads use `kind` `js-member`; StyleX `createTheme` / `unstable_createThemeNested` calls apply the complete resolved variable group and use `kind` `js-call`, including partial overrides and empty reset themes. `token` is the binding-qualified dotted access path (`vars.color.primary`) and `namespace` is the defining binding (`vars`). PandaCSS entries use the defining binding plus token path (`tokens.colors.brand`) and `token(...)` consumers are also tagged `js-call`. The cross-file scan uses fallow's shared import resolver, so direct named token-contract imports through relative paths, tsconfig `paths` aliases, and workspace packages can resolve to the token definition. Same-file StyleX reads are included. Dynamic import strings, unresolved aliases, generated package state, dynamic computed token access, and dynamic token-object structure still keep `consumer_count` a lower bound, and unlike Tailwind there is no corroborating dead-token finding, so a CSS-in-JS `consumer_count` of `0` is a weaker signal. Detection is gated on imports in the analyzed source files, including workspace packages whose root manifest does not declare the styling library. StyleX's built-in `@stylexjs/stylex` and `stylex` sources are recognized, with named aliases plus namespace/default imports supported for calls to the StyleX API itself. Barrel re-exports and default or namespace imports of token contracts conservatively abstain. Compiler-configured `importSources`, custom package aliases, CommonJS, and `stylex.env`-backed token structures are outside the current support boundary.
490
490
 
491
491
  ## CSS Health Candidates Are Advisory
492
492
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  The fallow MCP server (`fallow-mcp`) exposes fallow's analyses as agent tools. This is the full catalogue: each tool's kind, license, nearest CLI fallback, key params, plus the agent guidance the live tool schemas do not carry (CLI-fallback mapping, runtime-coverage confidence tiers, and `next_steps` dispatch). SKILL.md keeps only a short pointer; load this file when driving fallow through MCP.
4
4
 
5
- The `generated:mcp-tools` table below is regenerated from `fallow schema` by scripts/generate-agent-docs.mjs; edit the curated Description cells in place, never the identity columns.
5
+ The `generated:mcp-tools` and `generated:mcp-resources` tables below are regenerated from `fallow schema` by scripts/generate-agent-docs.mjs; edit the curated Description cells in place, never the identity columns.
6
6
 
7
7
  ## Tool catalogue
8
8
 
@@ -11,10 +11,12 @@ When using fallow via MCP (`fallow-mcp`), the following tools are available:
11
11
  <!-- generated:mcp-tools:start -->
12
12
  | Tool | Kind | License | CLI fallback | Key params | Description |
13
13
  |---|---|---|---|---|---|
14
- | `code_execute` | composition | free | - | `code`, `timeout_ms`, `max_output_bytes` | Bounded read-only Code Mode for composing multiple fallow analysis calls in one JavaScript snippet. The snippet receives `{ fallow, root }`, returns JSON-serializable data, and can call read-only helpers such as `fallow.projectInfo`, `fallow.audit`, `fallow.checkHealth`, and `fallow.run(tool, params)` for the same allowlist. Mutating fix tools are not exposed. The sandbox has no filesystem, network, imports, `eval`, `Function`, `process`, `require`, `Deno`, `Bun`, or shell access. Params: `code`, optional `root`, `timeout_ms` (capped at 30000), and `max_output_bytes` (capped at 4000000). |
14
+ | `code_execute` | composition | free | - | `code`, `timeout_ms`, `max_output_bytes` | Bounded read-only Code Mode for composing multiple fallow analysis calls in one JavaScript snippet. The snippet receives `{ fallow, root }`, returns JSON-serializable data, and can call read-only helpers such as `fallow.projectInfo`, `fallow.audit`, `fallow.checkHealth`, and `fallow.run(tool, params)` for the same allowlist. Similar-code is excluded because Code Mode is capped at 30 seconds; use standalone `find_similar_code` and `inspect_similar_code`, which have dedicated 15-minute timeouts. Mutating fix tools are not exposed. The sandbox has no filesystem, network, imports, `eval`, `Function`, `process`, `require`, `Deno`, `Bun`, or shell access. Params: `code`, optional `root`, `timeout_ms` (capped at 30000), and `max_output_bytes` (capped at 4000000). |
15
15
  | `analyze` | analysis | free | `fallow dead-code --format json --quiet` | `issue_types`, `production`, `workspace`, `baseline`, `group_by`, `file` | Full dead code analysis (unused files/exports/types/dependencies/members + circular dependencies + re-export cycles (barrel files that form a structural loop, silently breaking re-exports) + boundary violations + rule-pack policy violations (banned calls, imports, and catalogue-derived effects declared via the `rulePacks` config key) + stale suppressions). Private type leaks are an opt-in API hygiene check via `issue_types: ["private-type-leaks"]`. Set `boundary_violations: true` as a convenience alias for `issue_types: ["boundary-violations"]`. Set `group_by` to `"owner"`, `"directory"`, `"package"`, or `"section"` to partition results. The `section` mode reads GitLab CODEOWNERS `[Section]` headers and emits `owners` metadata per group |
16
16
  | `check_changed` | analysis | free | `fallow dead-code --changed-since <ref> --format json --quiet` | `since`, `baseline`, `fail_on_regression` | Incremental analysis of files changed since a git ref |
17
17
  | `security_candidates` | analysis | free | `fallow security --format json --quiet` | `gate`, `surface`, `changed_since`, `paths` | Unverified local security candidates, not confirmed vulnerabilities (`fallow security --format json`). Read `security_findings[]` for category, CWE, severity, evidence, trace, optional `reachability`, blind-spot counters, and optional `unresolved_callee_diagnostics` samples for dynamic callee follow-up. `severity` is a review-priority tier, not a verified vulnerability verdict. Each finding also carries an agent-actionable `candidate` (`source_kind`/`sink`/`boundary`), where URL-category sinks may include `url_shape` (`fixed-origin-dynamic-path` or `dynamic-origin`), an optional `taint_flow` source-to-sink triple, and a stable `finding_id` (equal to the SARIF fingerprint) for cross-run correlation; there is no `impact` field (deciding exploitability is the agent's job). Set `surface: true` to include top-level `attack_surface[]` entries with defensive-boundary prompts for a verifier. Set `gate` to `new` for changed-line candidates or `newly-reachable` for candidates that became reachable from entry points; `newly-reachable` requires `changed_since`. `reachability.untrusted_source_trace` is module-level import context only and does not prove value flow; `reachability.taint_confidence` tiers each reachable candidate as `arg-level` (sink argument traces to a same-module source read, strong) or `module-level` (only the module is import-reachable from a source, weak), so tier from this field instead of the evidence text. Verify trace, reachability context, severity, and evidence before editing code. Supports `root`, `config`, `workspace`, `paths`, `changed_since`, `changed_workspaces`, `surface`, `gate`, `no_cache`, and `threads`; `paths` forwards repeated `fallow security --file` filters for finding anchors, trace hops, untrusted-source reachability trace hops, and unresolved-callee diagnostics. See <https://docs.fallow.tools/cli/security-agent-verification> for the verifier packet and verdict recipe. Inherits `FALLOW_DIFF_FILE` from the server environment for line-level diff scoping; raise `FALLOW_TIMEOUT_SECS` for large repos. |
18
+ | `find_similar_code` | analysis | free | `fallow similar-code --format json --quiet` | `threshold`, `min_lines`, `top`, `changed_since`, `paths` | Find unverified semantically similar function candidates with the exact pinned local model. Discovery is read-only and never authorizes or performs model setup. Scoped output materializes the exact admitted files once in `generation.scope.paths` as provenance. Ask the user to run `fallow similar-code setup --local` when setup is missing. Cold local inference has a dedicated 15-minute subprocess window. |
19
+ | `inspect_similar_code` | trace | free | `fallow similar-code inspect <candidate-id> --candidates <report.json> --format json --quiet` | `candidate_id`, `snapshot` | Inspect one exact unverified candidate without rerunning provider retrieval or global ranking. Pass `candidate_id` plus a bounded typed snapshot containing the unchanged discovery `schema_version`, `generation`, selected `candidate`, `completion`, and `diagnostics`. Current source is re-extracted and both endpoint hashes must still match, so stale source fails closed. Keep candidate worthiness, behavioral equivalence, and refactor safety as separate verdicts, and abstain when evidence is incomplete. |
18
20
  | `inspect_target` | analysis | free | `fallow inspect --format json --quiet` | `target`, `production`, `include_churn` | Compose one evidence bundle for a file or exported symbol. File targets use `target: { type: "file", file }`; symbol targets use `target: { type: "symbol", file, export_name }`. Returns `kind: "inspect_target"`, normalized target identity, `trace_file`, optional `trace_export`, file-scoped dead-code actions, duplication groups filtered to the file, complexity findings filtered to the file, and security candidates scoped to the file. Set `include_churn: true` to add target-level git churn from the health hotspot subsystem. Churn is off by default, and unavailable git history or analysis failures remain explicit section states. Evidence sections carry `status` and `scope`; symbol targets warn when supporting evidence is file-scoped. Supports `root`, `config`, `production`, `workspace`, `include_churn`, `no_cache`, and `threads`; `production` applies to trace, dead-code, and health evidence only. Raise `FALLOW_TIMEOUT_SECS` for large repos. |
19
21
  | `guard` | introspection | free | `fallow guard <file> --format json --quiet` | `files` | Report the architecture rules that apply to given files before editing them: boundary zone, allowed import zones, forbidden calls, and rule-pack policies |
20
22
  | `find_dupes` | analysis | free | `fallow dupes --format json --quiet` | `mode`, `near`, `min_tokens`, `min_occurrences`, `top`, `threshold` | Code duplication detection. Set `near: true` for function-level clones with small structural edits. Set `changed_since` to scope to changed files since a git ref. Set `min_occurrences` (≥ 2, default 2) to hide pair-only clones and focus on widespread copy-paste. Each `clone_groups[]` entry carries a normalized `fingerprint` and `spread`; near groups also carry `similarity`. `stats.clone_groups_ignored` reports reviewed groups hidden by config, while `stats.near_candidates_skipped` signals bounded near comparisons that were skipped. Pass the fingerprint to `trace_clone` to inspect the group |
@@ -24,7 +26,7 @@ When using fallow via MCP (`fallow-mcp`), the following tools are available:
24
26
  | `get_blast_radius` | runtime-coverage | freemium | `fallow health --runtime-coverage <path> --format json --quiet` | `coverage`, `group_by` | Runtime-context slice for blast-radius review. Same params as `check_runtime_coverage`; read `runtime_coverage.blast_radius` for stable `fallow:blast:<hash>` IDs, caller counts, traffic-weighted caller reach, optional cloud deploy touch counts, and low/medium/high risk bands. |
25
27
  | `get_importance` | runtime-coverage | freemium | `fallow health --runtime-coverage <path> --format json --quiet` | `coverage`, `group_by` | Runtime-context slice for production-importance review. Same params as `check_runtime_coverage`; read `runtime_coverage.importance` for stable `fallow:importance:<hash>` IDs, invocations, cyclomatic complexity, owner count, 0-100 score, and templated reason. |
26
28
  | `get_cleanup_candidates` | runtime-coverage | freemium | `fallow health --runtime-coverage <path> --format json --quiet` | `coverage`, `group_by` | Runtime-context slice for cleanup review. Same params as `check_runtime_coverage`; read `runtime_coverage.findings` for `safe_to_delete`, `review_required`, `low_traffic`, and `coverage_unavailable`. |
27
- | `get_token_blast_radius` | analysis | free | `fallow health --css --format json --quiet` | - | Design-token blast radius for Tailwind v4 @theme tokens and CSS-in-JS token definitions (StyleX, vanilla-extract, PandaCSS): per token, a consumer_count (static lower bound) and a capped located consumers[] sample tagged theme-var/css-var/utility/apply (Tailwind), js-member (member access), or js-call (Panda token calls); descriptive context for sizing a token change, never a deletion gate |
29
+ | `get_token_blast_radius` | analysis | free | `fallow health --css --format json --quiet` | - | Design-token blast radius for Tailwind v4 @theme tokens and CSS-in-JS token definitions (StyleX, vanilla-extract, PandaCSS): per token, a consumer_count (static lower bound) and a capped located consumers[] sample tagged theme-var/css-var/utility/apply (Tailwind), js-member (member access), or js-call (StyleX theme-group and Panda token calls); descriptive context for sizing a token change, never a deletion gate |
28
30
  | `audit` | analysis | free | `fallow audit --format json --quiet` | `gate`, `base`, `css_deep`, `max_crap`, `coverage`, `runtime_coverage` | Combined dead-code + complexity + duplication + styling for changed files, returns verdict. Styling analytics are enabled by default; CSS and CSS-in-JS evidence can add `styling_findings`, `css_analytics`, and `styling_health` under the health sub-result. Set `gate` to `"new-only"` or `"all"`. Set `css_deep: false` to skip project-wide styling reachability while keeping local styling checks, or `css_deep: true` to force it back on when config disables it. Optional `runtime_coverage` (V8 dir / V8 JSON / Istanbul JSON) folds runtime findings into the same call; `min_invocations_hot` tunes the hot-path threshold (default 100). Runtime evidence appears under the audit `complexity` sub-result, including `coverage_intelligence` when combined evidence yields actionable recommendations. |
29
31
  | `decision_surface` | analysis | free | `fallow decision-surface --format json --quiet` | `base`, `max_decisions`, `workspace` | Surface the few consequential structural decisions a change embeds (coupling, public API, dependency), each as a judgment question with the routed expert; ranked, capped, and signal_id-anchored |
30
32
  | `fallow_explain` | introspection | free | `fallow explain <issue-type> --format json --quiet` | `issue_type` | Explain one issue type without running analysis. Required `issue_type`; returns rationale, examples, fix guidance, and docs URL |
@@ -46,6 +48,23 @@ When using fallow via MCP (`fallow-mcp`), the following tools are available:
46
48
  | `trace_clone` | trace | free | `fallow dupes --trace <file:line> --format json --quiet` | `file`, `line`, `fingerprint`, `near`, `min_occurrences` | Deep-dive a duplicate-code clone group (`fallow dupes --trace <spec> --format json`). Address by exactly one of: `file` + `line` (a source location), or `fingerprint` (a `dup:<id>` from a prior `find_dupes` `clone_groups[].fingerprint`, usually `dup:<8hex>` and widened only on rare report collisions). Returns the matched clone instance plus every clone group containing it; each traced group carries its `fingerprint`, an extract-function `suggestion` with estimated savings, and a best-effort `suggested_name` (omitted when no confident name). Supports `mode`, `near`, `min_tokens`, `min_lines`, `min_occurrences`, `threshold`, `skip_local`, `cross_language`, `ignore_imports`. Use the same `near` value as the originating `find_dupes` call. Use to consolidate duplication when you need exact sibling locations and a refactor target |
47
49
  <!-- generated:mcp-tools:end -->
48
50
 
51
+ ## Resource catalogue
52
+
53
+ Resources are the server's read-only reference channel: compile-time material an agent can list (`resources/list`, `resources/templates/list`) and read (`resources/read`) with no subprocess and no analysis run, cacheable by URI (your client reads them through its own resource tool). Each content item carries the server version in `_meta.fallow_version`; the payload itself is the plain document, so the schema resources are valid strict JSON Schema. Unknown URIs return a structured error whose `data` lists the known URIs (or the nearest issue types); the numeric code is `-32002` on protocol versions before 2026-07-28 and `-32602` from then on, so key on `data`. Every payload is JSON and carries `fallow_version`, so cache by URI and invalidate when the server version changes. The catalogue is static (no `subscribe`, no `listChanged`). Read `fallow://explain/{issue_type}` instead of calling `fallow_explain` when you only need the reference document; `issue_type` accepts the bare id (`unused-export`), the namespaced rule id (`security/sql-injection`), or the CLI filter spelling (`unused-exports`). An unknown URI or issue type returns a structured `resource_not_found` error listing the known URIs or the nearest issue types.
54
+
55
+ <!-- generated:mcp-resources:start -->
56
+ | Resource | Name | Kind | MIME | Description |
57
+ |---|---|---|---|---|
58
+ | `fallow://tools` | `tools` | static | `application/json` | MCP tool manifest: name, kind, one-line description, nearest CLI fallback, key params, license, and read-only flag for every tool |
59
+ | `fallow://issue-types` | `issue-types` | static | `application/json` | Every issue type with its command, category, config key, zero-config default severity, opt-in flag, fixable flag, docs URL, and explain resource URI |
60
+ | `fallow://explain` | `explain` | static | `application/json` | Index of every explainable issue type with its one-line summary and the fallow://explain/{issue_type} URI to read |
61
+ | `fallow://task-matrix` | `task-matrix` | static | `application/json` | Agent task-to-command matrix: which read-only fallow command to run before deleting, refactoring, committing, or scoping work |
62
+ | `fallow://schema/config` | `schema-config` | static | `application/json` | JSON Schema of the fallow config file (same document as fallow config-schema) |
63
+ | `fallow://schema/plugin` | `schema-plugin` | static | `application/json` | JSON Schema of a user-authored external plugin (same document as fallow plugin-schema) |
64
+ | `fallow://schema/rule-pack` | `schema-rule-pack` | static | `application/json` | JSON Schema of a declarative rule pack (same document as fallow rule-pack-schema) |
65
+ | `fallow://explain/{issue_type}` | `explain-issue-type` | template | `application/json` | Explain document for one issue type (same payload as fallow explain <issue-type> --format json): name, summary, rationale, example, fix guidance, docs URL |
66
+ <!-- generated:mcp-resources:end -->
67
+
49
68
  ## How type-aware proof relates to the root trace
50
69
 
51
70
  `trace_symbol` is the only tool that returns a checker-backed `semantic` block
@@ -80,7 +99,7 @@ ambiguity or reachable references.
80
99
 
81
100
  ## Shared params, JSON output, and next_steps
82
101
 
83
- Most tools accept `root`, `config`, `no_cache`, and `threads` params. Exceptions: `impact` takes only `root`; `code_execute` takes `code`, optional `root`, `timeout_ms`, and `max_output_bytes`. The MCP server subprocess timeout defaults to 120s, configurable via `FALLOW_TIMEOUT_SECS`.
102
+ Most tools accept `root`, `config`, `no_cache`, and `threads` params. Exceptions: `impact` takes only `root`; `code_execute` takes `code`, optional `root`, `timeout_ms`, and `max_output_bytes`. Similar-code file scope is named `paths` on both standalone MCP tools and forwards repeated CLI `--file` flags. MCP subprocesses default to 120 seconds, except similar-code discovery and inspection which default to 15 minutes for cold local inference. `FALLOW_TIMEOUT_SECS` overrides either default. Code Mode does not expose similar-code because its 30-second cap cannot satisfy that contract.
84
103
 
85
104
  All JSON responses include structured `actions` arrays on every finding (dead code, health, duplication), enabling programmatic fix application or suppression.
86
105
 
@@ -7,14 +7,15 @@ npm install @fallow-cli/fallow-node
7
7
  ```
8
8
 
9
9
  ```ts
10
- import { detectDeadCode, detectDuplication, computeHealth } from '@fallow-cli/fallow-node';
10
+ import { computeHealth, detectDeadCode, detectDuplication, detectSimilarCode } from '@fallow-cli/fallow-node';
11
11
 
12
12
  const deadCode = await detectDeadCode({ root: process.cwd(), explain: true });
13
13
  const dupes = await detectDuplication({ root: process.cwd(), mode: 'mild', minTokens: 30 });
14
+ const similarCode = await detectSimilarCode({ root: process.cwd(), files: ['src/services/api.ts'] });
14
15
  const health = await computeHealth({ root: process.cwd(), score: true, ownershipEmails: 'handle' });
15
16
  ```
16
17
 
17
- Seven async functions: `detectDeadCode`, `detectCircularDependencies`, `detectBoundaryViolations`, `detectDuplication`, `detectFeatureFlags`, `computeComplexity`, `computeHealth`. Each returns the same JSON envelope the CLI emits for `--format json`. Rejected promises throw a `FallowNodeError` with `message`, `exitCode`, and optional `code`, `help`, `context` fields that mirror the CLI's structured error surface.
18
+ Eight async functions: `detectDeadCode`, `detectCircularDependencies`, `detectBoundaryViolations`, `detectDuplication`, `detectSimilarCode`, `detectFeatureFlags`, `computeComplexity`, `computeHealth`. Each returns the same JSON envelope the CLI emits for `--format json`. `detectSimilarCode` returns a precisely typed `SimilarCodeReport`, including generation provenance, embedding semantics, effective `generation.scope.paths`, completion, skips, cache accounting, diagnostics, and read-only candidate actions. Treat the materialized scope as provenance and preserve the raw report when a candidate may be inspected later. The Node binding exposes discovery only. Use CLI `similar-code inspect --candidates <report.json>` or MCP `inspect_similar_code` with the exact typed candidate snapshot so global retrieval and ranking are not repeated. Its loader resolves and verifies the exact-version local companion; it never downloads the model or authorizes setup. Rejected promises throw a `FallowNodeError` with `message`, `exitCode`, and optional `code`, `help`, `context` fields that mirror the CLI's structured error surface.
18
19
 
19
20
  Enum-like fields take lowercase CLI-style literals (`"mild"`, `"cyclomatic"`, `"handle"`, `"low"`). Write-path commands (`fix`, `init`, `hooks install`, `hooks uninstall`, `license activate`, `coverage setup`) are not exposed; use the CLI for those.
20
21
 
@@ -0,0 +1,47 @@
1
+ # Semantic Similar-Code Workflow
2
+
3
+ Similar-code is an opt-in, local semantic discovery workflow. It complements deterministic `fallow dupes`; it does not replace clone detection, tests, or human judgment.
4
+
5
+ 1. Check readiness with `fallow similar-code status --format json --quiet`. If the pinned model is missing, ask the user to run `fallow similar-code setup --local`. Agents must not authorize setup or run it on the user's behalf.
6
+ 2. Run discovery once. Preserve its independent JSON envelope so inspection and review use the exact candidate set:
7
+
8
+ ```bash
9
+ fallow similar-code --file src/services/api.ts --format json --quiet > similar-code.json
10
+ ```
11
+
12
+ In Node, call `detectSimilarCode({ files: ["src/services/api.ts"] })`. Over MCP, call standalone `find_similar_code` with `paths: ["src/services/api.ts"]`. Do not use Code Mode for similar-code because its 30-second window cannot accommodate documented cold inference. The standalone MCP tools have a dedicated 15-minute timeout.
13
+ 3. Inspect a candidate before judging it. Hand off the original raw discovery document so inspect selects that exact candidate without rerunning global retrieval or ranking:
14
+
15
+ ```bash
16
+ fallow similar-code inspect sc_example --candidates similar-code.json \
17
+ --format json --quiet
18
+ ```
19
+
20
+ Over MCP, call standalone `inspect_similar_code` with `candidate_id` and a typed `snapshot` containing the unchanged discovery `schema_version`, `generation`, selected `candidate`, `completion`, and `diagnostics`. Treat `generation.scope.paths` as provenance, not as an argument list. Inspect re-extracts only the two snapshot endpoints, validates both current source hashes, and fails closed on stale source. Review source, callers, callees, tests, side effects, ownership, and missing evidence.
21
+ 4. Author a separate verdict document. Keep the three axes independent. `refactor_safe: true` requires `behaviorally_equivalent: true`, which requires `candidate_worthy: true`. Use `null` for an undecided axis, use `needs-human-review`, and abstain when evidence is incomplete.
22
+
23
+ ```json
24
+ {
25
+ "schema_version": "1",
26
+ "verdicts": [
27
+ {
28
+ "candidate_id": "sc_example",
29
+ "review_key": "scr_example",
30
+ "candidate_worthy": true,
31
+ "behaviorally_equivalent": false,
32
+ "refactor_safe": false,
33
+ "outcome": "related-but-distinct",
34
+ "rationale": "Both normalize input, but only one preserves empty values."
35
+ }
36
+ ]
37
+ }
38
+ ```
39
+
40
+ 5. Join raw candidates and verdicts without changing either input:
41
+
42
+ ```bash
43
+ fallow similar-code review --candidates similar-code.json --verdicts verdicts.json \
44
+ --require-verdict-for-each-candidate --format json --quiet
45
+ ```
46
+
47
+ Only `completion.status: "complete"` makes an empty candidate list conclusive for the admitted scope. Candidates remain advisory and unverified until the separate verdict flow supplies source-grounded judgment.