Agent Skills › nekocode/filetree-skill

nekocode/filetree-skill

GitHub

定义 /filetree:init 和 /filetree:update 命令共享的规则,包括摘要风格、语言统一策略及更新时的 UNCHANGED 优化机制。

1 skills 148

Install All Skills

npx skills add nekocode/filetree-skill --all -g -y
More Options

List skills in collection

npx skills add nekocode/filetree-skill --list

Skills in Collection (1)

定义 /filetree:init 和 /filetree:update 命令共享的规则,包括摘要风格、语言统一策略及更新时的 UNCHANGED 优化机制。
运行 /filetree:init 或 /filetree:update 命令时加载
skills/filetree/SKILL.md
npx skills add nekocode/filetree-skill --skill filetree -g -y
SKILL.md
Frontmatter
{
    "name": "filetree",
    "license": "MIT",
    "description": "Use when running \/filetree:init or \/filetree:update — the shared rules those commands load before generating or syncing FILETREE.md. Not invoked directly.\n"
}

Filetree Skill — Shared Rules

Cross-cutting rules used by /filetree:init and /filetree:update. The commands themselves contain step-by-step flows; this file holds rules that apply across modes so they're maintained in one place.

/filetree:lint is read-only script invocation and does not need these rules.


Summary style

One line, max 25 words, describes what the file is FOR (its role / purpose). Not what it implements internally.

  • Good: "JWT auth middleware; parses token from request header and injects user_id into context"
  • Bad: "Defines AuthMiddleware class with init and call methods"
  • Bad: "Handles auth" (too vague)

Present tense. No marketing words. For the language to write summaries in, see "Summary language" below — never pick per-file.


Summary language

One run, ONE language. Every summary in the manifest — and the command's own narration — uses it. Without a single anchor, parallel sub-agents each guess and the manifest ends up mixing Chinese and English.

The command resolves the canonical language ONCE, up front, by this priority:

  1. config.language from the todo output (set when .filetree.json pins language). When present it is authoritative — skip the rest of the chain.
  2. Else the dominant natural language of CLAUDE.md / AGENTS.md (the agent contract — most authoritative).
  3. Else README (any localized variant).
  4. Else (/filetree:update only) the dominant language of existing manifest entries.
  5. Else English.

Then it passes that one language verbatim into EVERY sub-agent prompt ("Write all summaries in "). Sub-agents never re-detect; they run in parallel and would diverge if left to choose.


UNCHANGED bias (for /filetree:update ONLY)

Scope. This entire section applies to /filetree:update only. During /filetree:init the manifest starts empty, so there is no old summary to keep — UNCHANGED has nothing to refresh and apply will drop it. In init, every file gets a real summary. Do not apply this bias to init sub-tasks.

Why this matters. Hash changes trigger the LLM, but most code changes (typos, refactors, comments, small additions) don't change a file's purpose. Outputting "UNCHANGED" lets cmd_apply refresh just the hash and keep the existing summary — the manifest itself carries the memory of "I already reviewed this version". In a healthy update run, 80%+ of changed items should resolve to UNCHANGED. Writing a fresh 25-word summary when the old one still fits wastes ~100x more tokens than a 4-byte "UNCHANGED" reply.

Decision rule. You have: old summary, old hash, new hash, and the file's new content (prefer reading the git diff over the full file — diff is far denser per token and is all you need for purpose-level judgement). If the diff comes back EMPTY (the change was already committed, so working tree == HEAD), fall back to reading the file — the hash moved, so judging purpose from a blank diff would falsely yield UNCHANGED.

Output "UNCHANGED" if the old summary still describes the file's PURPOSE. Refactors, renames, bug fixes, test additions, formatting, comment changes, small additions — these almost always leave the purpose intact.

Output a new summary string only if:

  • A major new feature has been added that meaningfully expands purpose
  • A previously central concern has been removed
  • The file has been substantially rewritten for a different goal
  • The old summary is in the wrong language (not the run's canonical language — see "Summary language"). Rewrite it in the target language even if the purpose is unchanged; this is how a legacy mixed-language manifest converges — gradually, as each file's hash changes and re-enters the work plan. Language mismatch ALWAYS overrides the UNCHANGED bias.

When in doubt (and the language already matches), output UNCHANGED.

Rationalizations — every one resolves to UNCHANGED

The pressure to "be thorough" pushes toward rewriting. Each excuse below is a trap; the right answer is UNCHANGED.

Excuse Reality
"The diff is large, so I should rewrite" Diff size ≠ purpose change. A 500-line refactor with the same role is UNCHANGED.
"Let me polish the old summary while I'm here" Polishing burns ~100x the tokens of UNCHANGED and isn't an exception. Only purpose change or wrong language qualifies.
"It's slightly more accurate now" "Slightly better wording" is not "purpose changed". UNCHANGED.
"I'm not sure the purpose changed" Not sure = it didn't. UNCHANGED.
"New function added, must re-describe" A helper added to the same role doesn't expand purpose. UNCHANGED.

Red flags — STOP, you're about to waste tokens

  • About to write a summary that says the same thing as old_summary in new words
  • Justifying a rewrite by how much the code changed rather than whether the role changed
  • "Improving" or "tidying" a summary whose language already matches
  • Reading the full file when the git diff already answers the purpose question

All of these mean: output "UNCHANGED".


Symlinks

Some added / changed items carry a symlink_target field. For those: do not Read the file — a Read follows the link to the target's content (wasteful, and fails on a broken link). Write exactly symlink → <target> using the supplied symlink_target; do not infer a role you can't see. The script already hashes symlinks correctly from the link string.


Processing the work plan (todo --split)

Always run todo --split (the script chunks the LLM work and writes it to files, so you never count, truncate, or hand-split). Output:

{ "stats": {...}, "removed": [...], "renamed": [...],
  "manifest_exists": true,
  "config": {"manifest_path": "FILETREE.md", "language": null},
  "split_dir": "/tmp/filetree_XXXX",
  "batches": [{"file": ".../batch_00.json", "count": 25}, ...] }

The config block reflects .filetree.json (the script is the only config parser — never re-read the file yourself). manifest_path is where the manifest lives (may be renamed / relocated); language pins the summary language (see "Summary language" priority 0). exclude / include filtering is already applied inside the script, so the work plan only lists files that belong in the manifest. manifest_exists is whether the manifest file is already on disk — /filetree:update uses it to detect a not-yet-initialized repo (a present-but-empty manifest also reads total_in_manifest: 0, so the boolean is the reliable signal).

Each batch_NN.json is a JSON array of todo items (added + changed). Drive it purely off batches:

  • 0 batches → no LLM work; no part files exist to glob, so apply the empty payload via stdin (it still syncs removed/renamed from repo state):
    echo '{"updates": []}' | python3 .../filetree.py apply
    
  • 1 or more batches → spawn one claude-haiku-4-5 sub-agent per batch (good enough, ~10x cheaper) — always, even for a single batch. The main session never Reads a file or writes a summary itself; that work stays out of its context. Each sub-agent: Read SKILL.md, Read its assigned batch_NN.json, then write <split_dir>/part_NN.json. Sub-agents run in parallel and never see each other's batch.

Part-file shape (no hand-merging, no hashes)

Each part_NN.json carries ONLY summaries — hash is computed from disk, removed/renamed are recomputed from repo state, so neither belongs here:

{"updates": [{"path": "...", "summary": "..." | "UNCHANGED"}]}

Apply all parts in one call (the shell expands the glob, the script merges):

python3 .../filetree.py apply <split_dir>/part_*.json

Coverage gate — evidence from apply, never a hand-rolled diff

Before claiming the manifest is synced, run this gate on apply's return:

  1. READ missing_from_manifest — any indexable file still without an entry (a dropped sub-agent output, a forgotten file). This is the completion gate.
  2. READ the fixable anomaly keys: skipped_unchanged_new (a wrong UNCHANGED), skipped_missing_path (a hallucinated path).
  3. If 1 or 2 are non-empty → spawn one more claude-haiku-4-5 sub-agent to summarize those files. Pass it the split_dir, the exact paths to fix, and an output filename that does NOT collide with the existing part_NN.json (use part_fixup_NN.json, NN incrementing each retry). It writes <split_dir>/part_fixup_NN.json; then re-run apply <split_dir>/part_*.json — the glob still catches the fixup part, and apply merges and dedups by path. Keep this fixup off the main session too — same as the batch work. Loop until both clear.
  4. IGNORE skipped_excluded — real files the config keeps out, nothing to fix. Do NOT gate on applied == received: a legitimate skipped_excluded makes applied < received hold forever, which would loop here.
  5. ONLY THEN report — straight from apply's return.

Never hand-roll a coverage diff (concatenating batch lists, comparing counts): it is redundant and error-prone. The script's keys are the only evidence.

trang chủ - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-07-08 20:38
浙ICP备14020137号-1 $bản đồ khách truy cập$