[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6N0NQMRPDM6TNT4PPPHSJ9F":3,"skill-same:01M6N0NQMRPDM6TNT4PPPHSJ9F":91},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":39,"linkOnly":40,"markdownContent":41,"markdownBody":42,"frontMatter":43,"refName":63,"commitSha":64,"skillDirectory":65,"forksCount":66,"repositoryHtmlUrl":67,"repositoryHomepageUrl":6,"ownerHtmlUrl":68,"ownerBlogUrl":69,"ownerDescription":70,"updatedAt":71,"install":72,"resources":84},"01M6N0NQMRPDM6TNT4PPPHSJ9F","functional-area-resolver",null,"Compress an agent's routing file (RESOLVER.md or AGENTS.md) by converting\ngranular skill-per-row tables into functional-area dispatchers. Each area\nlists sub-skills in a \"(dispatcher for: ...)\" clause. The LLM reads one\narea entry and routes to the correct sub-skill. Proven via held-out\nA\u002FB eval: dispatcher pattern outperforms naive pipe-table compression.","garrytan\u002Fgbrain","garrytan","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F19957?v=4","01M6DJCCDDG53MTYYRTXAXFG17","Garry Tan","01M6MZQZCEN3RRMD33E1X9ZZR9",32847,"MIT","https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Fskills\u002Ffunctional-area-resolver\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"functional area resolver","resolver","functional","pipe","down","reduce","for","my","tables","pattern","dispatcher","context","edit","write","read","eval","table","compress","correct","Budget","2026-11-10 10:12:30",false,"---\nname: functional-area-resolver\nversion: 1.0.0\nprompt_version: 1\ndescription: |\n  Compress an agent's routing file (RESOLVER.md or AGENTS.md) by converting\n  granular skill-per-row tables into functional-area dispatchers. Each area\n  lists sub-skills in a \"(dispatcher for: ...)\" clause. The LLM reads one\n  area entry and routes to the correct sub-skill. Proven via held-out\n  A\u002FB eval: dispatcher pattern outperforms naive pipe-table compression.\ntriggers:\n  - \"compress agents.md\"\n  - \"compress my resolver\"\n  - \"resolver too big\"\n  - \"resolver.md too big\"\n  - \"agents.md too large\"\n  - \"shrink routing table\"\n  - \"slim down agents.md\"\n  - \"functional area resolver\"\n  - \"functional area dispatcher\"\n  - \"context-health agents\"\n  - \"context-health resolver\"\n  - \"reduce context budget\"\ntools:\n  - exec\n  - read\n  - write\n  - edit\nmutating: true\n# This skill names other skills (perplexity-research, brain-publish,\n# etc.) in its dispatcher prose; the v0.36.x brain-first regex matches\n# the word `perplexity` but the skill never actually calls external\n# APIs. It rewrites local routing tables. Declarative opt-out.\nbrain_first: exempt\n---\n\n# Functional-Area Resolver — Pattern for Compressing Routing Tables\n\n## Problem\n\nRouting files (RESOLVER.md, AGENTS.md) grow as skills are added. Each skill\ngets its own row (trigger -> skill path). At ~200+ skills this hits 25-30KB,\neating context budget that should go to actual work.\n\n## Solution: Functional-Area Dispatchers\n\nReplace N rows per area with **one entry per functional area**. Each entry\nlists all sub-skills it can dispatch to in a `(dispatcher for: ...)` clause.\n\n### Before (270 rows, 25KB)\n```\n- Creating\u002Fenriching a person or company page -> `enrich`\n- Fix broken citations in brain pages -> `citation-fixer`\n- Publish\u002Fshare a brain page as link -> `brain-publish`\n- Generate PDF from brain page -> `brain-pdf`\n- Read a book through lens of a problem -> `strategic-reading`\n- Personalized book analysis -> `book-mirror`\n- Brain integrity -> `brain-librarian`\n...\n```\n\n### After (13 rows, 13KB)\n```\n- **Brain & knowledge**: create\u002Fenrich\u002Fsearch\u002Fexport brain pages, filing,\n  citations, publishing, book analysis, strategic reading, concept synthesis,\n  archive mining -> `brain-ops` (dispatcher for: enrich, query, brain-pdf,\n  brain-publish, brain-export, brain-librarian, citation-fixer, book-mirror,\n  strategic-reading, concept-synthesis, archive-crawler, ...)\n```\n\n## Why It Works\n\nThe LLM doesn't need one row per sub-skill. It needs:\n1. **Area recognition** — \"this is about brain pages\" -> Brain & Knowledge\n2. **Sub-skill visibility** — the `(dispatcher for: ...)` list shows what's available\n3. **The skill file itself** — once the LLM reads `brain-ops\u002FSKILL.md`, it has full routing detail\n\nThis is a **two-layer dispatch**: routing file routes to the area, the area\nskill routes to the specific sub-skill. Each layer does one job well.\n\n## A\u002FB Eval Results\n\nThree resolver architectures tested across three Anthropic frontier models\n(Opus 4.7, Sonnet 4.6, Haiku 4.5) on real production AGENTS.md content,\n20 hand-authored training fixtures + 5 held-out blind fixtures, n=3 seeded\nrepeats per (fixture, variant). Two scoring rules: **STRICT** (predicted\nslug exactly equals expected) and **LENIENT** (predicted is in the same\ndispatcher area as expected). Both matter:\n\n- STRICT measures: \"does the LLM return the exact slug?\"\n- LENIENT measures: \"does the LLM land in the right area, even if it picks a\n  more-specific sub-skill from `(dispatcher for: ...)`?\" This is closer to\n  production behavior — an agent that lands in `gmail` for an email intent\n  succeeds even if the resolver entry said `executive-assistant`.\n\n### Training corpus (n=20, 3 seeds × 3 variants × 3 models, LENIENT)\n\n| Variant | Opus 4.7 | Sonnet 4.6 | Haiku 4.5 | Size |\n|---|---|---|---|---|\n| baseline (270 bullet rows) | 81.7% ± 7.2% | 86.7% ± 7.2% | 73.3% ± 7.2% | 25KB |\n| **functional-areas** (this pattern) | **98.3% ± 7.2%** | **100% ± 0%** | **88.3% ± 7.2%** | **13KB** |\n| resolver-of-resolvers (no dispatcher clause) | 63.3% ± 14.3% | 41.7% ± 7.2% | 65.0% ± 12.4% | 10KB |\n\n### Held-out blind corpus (n=5, 3 seeds, LENIENT)\n\n| Variant | Opus 4.7 | Sonnet 4.6 | Haiku 4.5 |\n|---|---|---|---|\n| baseline | 100% ± 0% | 100% ± 0% | 100% ± 0% |\n| **functional-areas** | **100% ± 0%** | **100% ± 0%** | **100% ± 0%** |\n| resolver-of-resolvers | 100% ± 0% | **73.3% ± 28.7%** | 100% ± 0% |\n\n### What the data shows\n\n1. **Functional-areas BEATS baseline on training across all three models** (+13 to +17pp) at 48% the size. Held-out is saturated at 100% for both — within margin of error.\n\n2. **The `(dispatcher for: ...)` clause is the load-bearing signal.** resolver-of-resolvers strips that clause and collapses to 41.7% on Sonnet — the catastrophic failure case the original PR predicted, now observed.\n\n3. **The pattern works because the LLM can drill into the dispatcher list.** Most \"STRICT failures\" are the LLM picking a more-specific sub-skill (`gmail` instead of `executive-assistant`). That's the pattern working as designed. STRICT scoring under-counts; LENIENT scoring reflects production agent behavior.\n\n4. **The pattern's value scales with model tier.** Compression gain (functional-areas vs baseline, training, LENIENT) is +17pp on Opus, +13pp on Sonnet, +15pp on Haiku. Sonnet shows the cleanest separation between functional-areas and resolver-of-resolvers (100% vs 41.7%) — model capacity affects how much the dispatcher signal matters.\n\n### Reproduce\n\n```bash\ncd evals\u002Ffunctional-area-resolver\nnode harness.mjs --model opus    # ~225 LLM calls, ~$1.70 at Opus pricing\nnode harness.mjs --model sonnet  # ~$1.00\nnode harness.mjs --model haiku   # ~$0.30\nnode rescore.mjs baseline-runs\u002F2026-05-11-opus-4-7.jsonl  # zero-cost re-score\n```\n\nReceipts (model, prompt_template_hash, fixtures_hash, harness_sha, ts):\n`evals\u002Ffunctional-area-resolver\u002Fbaseline-runs\u002F2026-05-11-{opus-4-7,sonnet-4-6,haiku-4-5}.jsonl`.\n\n### Methodology caveats\n\n- **Production prompt matters.** With a naive \"return the skill slug\" prompt\n  (no instruction about `(dispatcher for: ...)`), every compression variant\n  collapses to ~30-60% on Opus. The dispatcher-aware prompt is in\n  `evals\u002Ffunctional-area-resolver\u002Fharness-runner.ts:PROMPT_TEMPLATE`. Use it\n  as the template for your agent's harness; without it, compression breaks.\n- **Training corpus and variants were authored by the same release.** Held-out\n  corpus was written before the variants and never adjusted; this mitigates\n  but does not eliminate overfitting.\n- **Confidence intervals via t-distribution across n=3 seeded repeats.** Hold the\n  n=3 lower-bound: high CIs mean the underlying sample is noisy.\n- **Single-vendor result.** All three models are Anthropic. Cross-vendor\n  verification (Gemini, GPT) is a v0.33.x follow-up.\n- **Held-out blind set is small (n=5).** Saturated at 100% across most cells —\n  the harness can't distinguish between \"100%\" and \"95% with one nondeterministic\n  miss.\" Expanding to ≥20 is a v0.33.x follow-up.\n\n### Prior work and citations\n\nThe pattern is a **static-prompt analog of hierarchical agent routing**, a\n2024-2025 research direction:\n\n- **AnyTool** ([arXiv:2402.04253](https:\u002F\u002Farxiv.org\u002Fabs\u002F2402.04253)) showed\n  meta-agent → category-agent → tool-agent hierarchy on 16K APIs beats flat\n  retrieval by +35.4pp. The `(dispatcher for: ...)` clause is the\n  meta-agent's view collapsed into a single LLM pass.\n- **RAG-MCP** ([arXiv:2505.03275](https:\u002F\u002Farxiv.org\u002Fhtml\u002F2505.03275v1))\n  reports 49.2% prompt-token reduction at 3.2× accuracy gain via\n  embedding-based pre-retrieval. The token-reduction story matches ours\n  (48% smaller), via a different mechanism (RAG vs static dispatcher).\n- **Anthropic Agent Skills**\n  ([engineering blog](https:\u002F\u002Fwww.anthropic.com\u002Fengineering\u002Fequipping-agents-for-the-real-world-with-agent-skills))\n  promotes progressive disclosure: frontmatter (~80 tokens) always loaded,\n  SKILL.md body loaded on match. This skill applies the same principle at\n  the routing-table level, not the per-skill body level.\n\nThe 2025-2026 literature has no published benchmark for **static-prompt\nhierarchical routing** (every published hierarchical scheme resolves the\nhierarchy at runtime via a second LLM call). Our finding — that the\nhierarchy can be inlined into a single-LLM-pass dispatcher list and retain\nrouting accuracy — is the open contribution. See\n`evals\u002Ffunctional-area-resolver\u002FREADME.md` for methodology details.\n\n## How To Compress\n\n### Step 1: Preconditions\n\nRefuse to compress if either gate fails:\n- Source routing file is under 12KB (compression overhead exceeds benefit).\n- `git status` shows uncommitted changes to the routing file (the\n  compressor's edit would entangle with whatever the user was doing).\n\nIf a user wants to override either gate, they ask explicitly with `--force`.\n\n### Step 2: When to compress which file\n\nGBrain workspaces often have TWO routing files merged at runtime (per\n`src\u002Fcore\u002Fcheck-resolvable.ts` v0.31.7): `skills\u002FRESOLVER.md` and a sibling\n`..\u002FAGENTS.md`. Choose which to compress:\n\n- Only one is fat (>12KB): compress that one; leave the small one alone.\n- Both are fat: compress them separately, in order: AGENTS.md first\n  (usually the larger one in OpenClaw-style deployments), then RESOLVER.md.\n- Only the small one is fat (rare): same rule — compress it.\n\nIf the deployment uses only one routing file, this section is a no-op —\ncompress that one.\n\n### Step 3: Identify functional areas\n\nGroup skills by domain. Typical areas (adjust per deployment):\n\n- **Brain & Knowledge** — brain-ops as dispatcher\n- **Content Ingestion** — ingest as dispatcher\n- **Calendar & Scheduling** — google-calendar as dispatcher\n- **Email & Comms** — executive-assistant as dispatcher\n- **Research & Investigation** — perplexity-research as dispatcher\n- **X\u002FTwitter & Social** — x-ingest as dispatcher\n- **Places & Travel** — checkin as dispatcher\n- **Product & Building** — acp-coding as dispatcher\n- **Infrastructure** — healthcheck as dispatcher\n- **Tasks & Logistics** — daily-task-manager as dispatcher\n- **People & Contacts** — google-contacts as dispatcher\n\n### Step 4: Build the area entry format\n\nEach area entry follows this template:\n\n```\n- **{Area Name}**: {comma-separated trigger phrases} -> `{dispatcher-skill}`\n  (dispatcher for: {comma-separated sub-skill names})\n```\n\nRules:\n- Trigger phrases should be broad enough to catch intent (\"brain pages, enrich,\n  search, filing, citations, book analysis\")\n- Sub-skill list should be comprehensive — this is how the LLM knows what's available\n- The dispatcher skill file should have its own internal routing table\n\n### Step 5: Keep always-on entries separate\n\nGates and always-on entries (acknowledge, multi-user, entity-detector, etc.)\nstay as individual rows — they're checked on every message, not dispatched.\n\n### Step 6 (MANDATORY): Verify routing accuracy\n\nRun two gates before committing the compressed file. Do NOT commit if either\nfails.\n\n**Gate 1: Structural verification.** Confirms your `routing-eval.jsonl`\nfixtures still resolve to the right skills under the compressed routing file.\nRun from the workspace whose routing file you just edited:\n\n```bash\ngbrain routing-eval --json\n```\n\nIf accuracy on your fixtures drops below 95%, revert and tune the area\nentries before re-running.\n\n**Gate 2: LLM A\u002FB verification on YOUR edited file.** Confirms a frontier\nLLM can still drill into the dispatcher list and reach sub-skills under\nyour specific compression. Requires a gbrain repo checkout because the\nharness lives there. Copy your edited routing file into the harness's\nvariants directory, then invoke the harness with `--variants` pointing\nat it:\n\n```bash\n# In your agent workspace, identify the routing file you just compressed.\nEDITED=\u002Fpath\u002Fto\u002Fyour\u002FAGENTS.md       # or skills\u002FRESOLVER.md, whichever you edited\n\n# In your gbrain repo checkout:\ncd \u002Fpath\u002Fto\u002Fgbrain\u002Fevals\u002Ffunctional-area-resolver\nTMP=$(mktemp -d)\u002Fvariants && mkdir -p \"$TMP\"\ncp \"$EDITED\" \"$TMP\u002Fmy-edit.md\"\n\n# Without --yes the harness prints its cost estimate and exits (no model calls).\nANTHROPIC_API_KEY=... node harness.mjs --variants-dir \"$TMP\" --variants my-edit \\\n                                       --model opus --parallel 3\n\n# Only after the user approves that estimate:\nANTHROPIC_API_KEY=... node harness.mjs --variants-dir \"$TMP\" --variants my-edit \\\n                                       --model opus --parallel 3 --yes\n```\n\nGate 2 makes paid model calls. Show the user the estimate the first command\nprints and get their agreement before you add `--yes`; `--yes` only skips\nthe harness's own prompt, it is not the user's approval.\n\nThe harness uses gbrain's bundled fixture set, so this verifies \"did the LLM\nland in the right sub-skill for routing intents the gbrain-bundled fixtures\ncover\" — a regression check on shared skills, not a full re-eval of YOUR\nfixture set. For full eval coverage, mirror this skill's\n`fixtures.jsonl` + `fixtures-held-out.jsonl` setup with intents specific\nto your skills.\n\nIf the lenient (same-area) score on your variant drops below 95%, revert the\ncompression and tune. Common causes:\n- A sub-skill was omitted from the `(dispatcher for: ...)` list.\n- Trigger phrases for an area are too narrow (LLM can't recognize intent).\n- Areas were collapsed too aggressively (too few areas — see Anti-Patterns).\n- ASCII `->` vs Unicode `→` mismatch — the harness now accepts both, but\n  earlier versions only matched Unicode. Pin gbrain to v0.32.3.0+.\n\nCommon false negatives on the harness eval (NOT bugs in your compression):\n- The gbrain-bundled fixtures target skill names like `enrich`, `query`,\n  `gmail`, `executive-assistant`. If your routing file doesn't expose\n  those skills at all, expect strict-scoring failures on those fixtures.\n  Lenient scoring stays accurate for any sub-skill present in your\n  `(dispatcher for: ...)` lists.\n\n### Step 7: Review the diff before committing\n\nShow the user the proposed edit (or the actual git diff) and wait for\nexplicit approval before staging. Same convention as `skills\u002Fbook-mirror\u002FSKILL.md`.\n\n## Contract\n\nThis skill guarantees:\n\n- Routing matches the canonical triggers in the frontmatter.\n- Compression is only performed when the preconditions in Step 1 pass (file ≥12KB AND clean working tree, or `--force`).\n- The mandatory verification gate in Step 6 fires on the user's edited file, not on sample variants. The user runs `gbrain routing-eval --json` AND the gbrain-repo harness (`node harness.mjs --variants-dir \u003Ctmp> --variants my-edit`) before committing the compressed file.\n- Privacy contract preserved: no fork-specific filesystem path literals (server-side brain home, OpenClaw fork home) leak into the compressed output.\n\nThe full behavior contract is documented in the body sections above; this section exists for the conformance test.\n\n## Output Format\n\nThe compressed routing file follows the area-entry template documented in Step 4 (\"Build the area entry format\"). Each entry: `- **{Area Name}**: {trigger phrases} -> \\`{dispatcher-skill}\\` (dispatcher for: {sub-skill list})`. The dispatcher arrow may be either ASCII `->` (default in this template) or Unicode `→` (used in some production deployments); the gbrain harness accepts both.\n\n## When it fails\n\nFollow the [agent operator protocol](..\u002Fconventions\u002Fagent-operator-protocol.md) for any gbrain error `code`, exit code, `[AGENT]` block or notice block. Specific to this skill:\n\n- Either verification gate fails (structural or LLM A\u002FB): refuse to compress and report the failing gate; never ship a smaller resolver that routes worse.\n- The A\u002FB harness lacks a provider key or hits a cost cap: say the LLM gate did not run and keep the original resolver.\n\n## Anti-Patterns\n\n- **Resolver-of-resolvers with pipe tables.** Tested and failed (see eval\n  table). The LLM picks area names from the table instead of drilling into\n  sub-skills.\n\n- **Removing sub-skill names.** Without the `(dispatcher for: ...)` list,\n  the LLM can't route to specific sub-skills. The list is the routing signal.\n\n- **Too few areas.** Collapsing to \u003C5 areas makes each area too broad.\n  12-15 areas is the sweet spot.\n\n- **Too many areas.** Defeats the purpose. If you have 50 areas, just keep\n  individual rows.\n\n## Maintenance\n\nWhen adding a new skill:\n1. Identify its functional area.\n2. Add the skill name to that area's `(dispatcher for: ...)` list.\n3. Update the area's skill file with routing detail.\n4. Run the routing eval (Step 6) to verify.\n\nWhen adding a new functional area:\n1. Create the dispatcher skill with internal routing.\n2. Add the area entry to the routing file.\n3. Run the routing eval (Step 6) to verify.\n\n## Changelog\n\n### v1.0.0 — 2026-05-11\n- Initial version. Pattern shipped in gbrain v0.32.3.0 with a held-out A\u002FB\n  eval (see `evals\u002Ffunctional-area-resolver\u002F`).\n- Skill renamed from `compress-agents-md` to `functional-area-resolver`\n  pre-release; the contribution is the pattern, not the filename.\n","# Functional-Area Resolver — Pattern for Compressing Routing Tables\n\n## Problem\n\nRouting files (RESOLVER.md, AGENTS.md) grow as skills are added. Each skill\ngets its own row (trigger -> skill path). At ~200+ skills this hits 25-30KB,\neating context budget that should go to actual work.\n\n## Solution: Functional-Area Dispatchers\n\nReplace N rows per area with **one entry per functional area**. Each entry\nlists all sub-skills it can dispatch to in a `(dispatcher for: ...)` clause.\n\n### Before (270 rows, 25KB)\n```\n- Creating\u002Fenriching a person or company page -> `enrich`\n- Fix broken citations in brain pages -> `citation-fixer`\n- Publish\u002Fshare a brain page as link -> `brain-publish`\n- Generate PDF from brain page -> `brain-pdf`\n- Read a book through lens of a problem -> `strategic-reading`\n- Personalized book analysis -> `book-mirror`\n- Brain integrity -> `brain-librarian`\n...\n```\n\n### After (13 rows, 13KB)\n```\n- **Brain & knowledge**: create\u002Fenrich\u002Fsearch\u002Fexport brain pages, filing,\n  citations, publishing, book analysis, strategic reading, concept synthesis,\n  archive mining -> `brain-ops` (dispatcher for: enrich, query, brain-pdf,\n  brain-publish, brain-export, brain-librarian, citation-fixer, book-mirror,\n  strategic-reading, concept-synthesis, archive-crawler, ...)\n```\n\n## Why It Works\n\nThe LLM doesn't need one row per sub-skill. It needs:\n1. **Area recognition** — \"this is about brain pages\" -> Brain & Knowledge\n2. **Sub-skill visibility** — the `(dispatcher for: ...)` list shows what's available\n3. **The skill file itself** — once the LLM reads `brain-ops\u002FSKILL.md`, it has full routing detail\n\nThis is a **two-layer dispatch**: routing file routes to the area, the area\nskill routes to the specific sub-skill. Each layer does one job well.\n\n## A\u002FB Eval Results\n\nThree resolver architectures tested across three Anthropic frontier models\n(Opus 4.7, Sonnet 4.6, Haiku 4.5) on real production AGENTS.md content,\n20 hand-authored training fixtures + 5 held-out blind fixtures, n=3 seeded\nrepeats per (fixture, variant). Two scoring rules: **STRICT** (predicted\nslug exactly equals expected) and **LENIENT** (predicted is in the same\ndispatcher area as expected). Both matter:\n\n- STRICT measures: \"does the LLM return the exact slug?\"\n- LENIENT measures: \"does the LLM land in the right area, even if it picks a\n  more-specific sub-skill from `(dispatcher for: ...)`?\" This is closer to\n  production behavior — an agent that lands in `gmail` for an email intent\n  succeeds even if the resolver entry said `executive-assistant`.\n\n### Training corpus (n=20, 3 seeds × 3 variants × 3 models, LENIENT)\n\n| Variant | Opus 4.7 | Sonnet 4.6 | Haiku 4.5 | Size |\n|---|---|---|---|---|\n| baseline (270 bullet rows) | 81.7% ± 7.2% | 86.7% ± 7.2% | 73.3% ± 7.2% | 25KB |\n| **functional-areas** (this pattern) | **98.3% ± 7.2%** | **100% ± 0%** | **88.3% ± 7.2%** | **13KB** |\n| resolver-of-resolvers (no dispatcher clause) | 63.3% ± 14.3% | 41.7% ± 7.2% | 65.0% ± 12.4% | 10KB |\n\n### Held-out blind corpus (n=5, 3 seeds, LENIENT)\n\n| Variant | Opus 4.7 | Sonnet 4.6 | Haiku 4.5 |\n|---|---|---|---|\n| baseline | 100% ± 0% | 100% ± 0% | 100% ± 0% |\n| **functional-areas** | **100% ± 0%** | **100% ± 0%** | **100% ± 0%** |\n| resolver-of-resolvers | 100% ± 0% | **73.3% ± 28.7%** | 100% ± 0% |\n\n### What the data shows\n\n1. **Functional-areas BEATS baseline on training across all three models** (+13 to +17pp) at 48% the size. Held-out is saturated at 100% for both — within margin of error.\n\n2. **The `(dispatcher for: ...)` clause is the load-bearing signal.** resolver-of-resolvers strips that clause and collapses to 41.7% on Sonnet — the catastrophic failure case the original PR predicted, now observed.\n\n3. **The pattern works because the LLM can drill into the dispatcher list.** Most \"STRICT failures\" are the LLM picking a more-specific sub-skill (`gmail` instead of `executive-assistant`). That's the pattern working as designed. STRICT scoring under-counts; LENIENT scoring reflects production agent behavior.\n\n4. **The pattern's value scales with model tier.** Compression gain (functional-areas vs baseline, training, LENIENT) is +17pp on Opus, +13pp on Sonnet, +15pp on Haiku. Sonnet shows the cleanest separation between functional-areas and resolver-of-resolvers (100% vs 41.7%) — model capacity affects how much the dispatcher signal matters.\n\n### Reproduce\n\n```bash\ncd evals\u002Ffunctional-area-resolver\nnode harness.mjs --model opus    # ~225 LLM calls, ~$1.70 at Opus pricing\nnode harness.mjs --model sonnet  # ~$1.00\nnode harness.mjs --model haiku   # ~$0.30\nnode rescore.mjs baseline-runs\u002F2026-05-11-opus-4-7.jsonl  # zero-cost re-score\n```\n\nReceipts (model, prompt_template_hash, fixtures_hash, harness_sha, ts):\n`evals\u002Ffunctional-area-resolver\u002Fbaseline-runs\u002F2026-05-11-{opus-4-7,sonnet-4-6,haiku-4-5}.jsonl`.\n\n### Methodology caveats\n\n- **Production prompt matters.** With a naive \"return the skill slug\" prompt\n  (no instruction about `(dispatcher for: ...)`), every compression variant\n  collapses to ~30-60% on Opus. The dispatcher-aware prompt is in\n  `evals\u002Ffunctional-area-resolver\u002Fharness-runner.ts:PROMPT_TEMPLATE`. Use it\n  as the template for your agent's harness; without it, compression breaks.\n- **Training corpus and variants were authored by the same release.** Held-out\n  corpus was written before the variants and never adjusted; this mitigates\n  but does not eliminate overfitting.\n- **Confidence intervals via t-distribution across n=3 seeded repeats.** Hold the\n  n=3 lower-bound: high CIs mean the underlying sample is noisy.\n- **Single-vendor result.** All three models are Anthropic. Cross-vendor\n  verification (Gemini, GPT) is a v0.33.x follow-up.\n- **Held-out blind set is small (n=5).** Saturated at 100% across most cells —\n  the harness can't distinguish between \"100%\" and \"95% with one nondeterministic\n  miss.\" Expanding to ≥20 is a v0.33.x follow-up.\n\n### Prior work and citations\n\nThe pattern is a **static-prompt analog of hierarchical agent routing**, a\n2024-2025 research direction:\n\n- **AnyTool** ([arXiv:2402.04253](https:\u002F\u002Farxiv.org\u002Fabs\u002F2402.04253)) showed\n  meta-agent → category-agent → tool-agent hierarchy on 16K APIs beats flat\n  retrieval by +35.4pp. The `(dispatcher for: ...)` clause is the\n  meta-agent's view collapsed into a single LLM pass.\n- **RAG-MCP** ([arXiv:2505.03275](https:\u002F\u002Farxiv.org\u002Fhtml\u002F2505.03275v1))\n  reports 49.2% prompt-token reduction at 3.2× accuracy gain via\n  embedding-based pre-retrieval. The token-reduction story matches ours\n  (48% smaller), via a different mechanism (RAG vs static dispatcher).\n- **Anthropic Agent Skills**\n  ([engineering blog](https:\u002F\u002Fwww.anthropic.com\u002Fengineering\u002Fequipping-agents-for-the-real-world-with-agent-skills))\n  promotes progressive disclosure: frontmatter (~80 tokens) always loaded,\n  SKILL.md body loaded on match. This skill applies the same principle at\n  the routing-table level, not the per-skill body level.\n\nThe 2025-2026 literature has no published benchmark for **static-prompt\nhierarchical routing** (every published hierarchical scheme resolves the\nhierarchy at runtime via a second LLM call). Our finding — that the\nhierarchy can be inlined into a single-LLM-pass dispatcher list and retain\nrouting accuracy — is the open contribution. See\n`evals\u002Ffunctional-area-resolver\u002FREADME.md` for methodology details.\n\n## How To Compress\n\n### Step 1: Preconditions\n\nRefuse to compress if either gate fails:\n- Source routing file is under 12KB (compression overhead exceeds benefit).\n- `git status` shows uncommitted changes to the routing file (the\n  compressor's edit would entangle with whatever the user was doing).\n\nIf a user wants to override either gate, they ask explicitly with `--force`.\n\n### Step 2: When to compress which file\n\nGBrain workspaces often have TWO routing files merged at runtime (per\n`src\u002Fcore\u002Fcheck-resolvable.ts` v0.31.7): `skills\u002FRESOLVER.md` and a sibling\n`..\u002FAGENTS.md`. Choose which to compress:\n\n- Only one is fat (>12KB): compress that one; leave the small one alone.\n- Both are fat: compress them separately, in order: AGENTS.md first\n  (usually the larger one in OpenClaw-style deployments), then RESOLVER.md.\n- Only the small one is fat (rare): same rule — compress it.\n\nIf the deployment uses only one routing file, this section is a no-op —\ncompress that one.\n\n### Step 3: Identify functional areas\n\nGroup skills by domain. Typical areas (adjust per deployment):\n\n- **Brain & Knowledge** — brain-ops as dispatcher\n- **Content Ingestion** — ingest as dispatcher\n- **Calendar & Scheduling** — google-calendar as dispatcher\n- **Email & Comms** — executive-assistant as dispatcher\n- **Research & Investigation** — perplexity-research as dispatcher\n- **X\u002FTwitter & Social** — x-ingest as dispatcher\n- **Places & Travel** — checkin as dispatcher\n- **Product & Building** — acp-coding as dispatcher\n- **Infrastructure** — healthcheck as dispatcher\n- **Tasks & Logistics** — daily-task-manager as dispatcher\n- **People & Contacts** — google-contacts as dispatcher\n\n### Step 4: Build the area entry format\n\nEach area entry follows this template:\n\n```\n- **{Area Name}**: {comma-separated trigger phrases} -> `{dispatcher-skill}`\n  (dispatcher for: {comma-separated sub-skill names})\n```\n\nRules:\n- Trigger phrases should be broad enough to catch intent (\"brain pages, enrich,\n  search, filing, citations, book analysis\")\n- Sub-skill list should be comprehensive — this is how the LLM knows what's available\n- The dispatcher skill file should have its own internal routing table\n\n### Step 5: Keep always-on entries separate\n\nGates and always-on entries (acknowledge, multi-user, entity-detector, etc.)\nstay as individual rows — they're checked on every message, not dispatched.\n\n### Step 6 (MANDATORY): Verify routing accuracy\n\nRun two gates before committing the compressed file. Do NOT commit if either\nfails.\n\n**Gate 1: Structural verification.** Confirms your `routing-eval.jsonl`\nfixtures still resolve to the right skills under the compressed routing file.\nRun from the workspace whose routing file you just edited:\n\n```bash\ngbrain routing-eval --json\n```\n\nIf accuracy on your fixtures drops below 95%, revert and tune the area\nentries before re-running.\n\n**Gate 2: LLM A\u002FB verification on YOUR edited file.** Confirms a frontier\nLLM can still drill into the dispatcher list and reach sub-skills under\nyour specific compression. Requires a gbrain repo checkout because the\nharness lives there. Copy your edited routing file into the harness's\nvariants directory, then invoke the harness with `--variants` pointing\nat it:\n\n```bash\n# In your agent workspace, identify the routing file you just compressed.\nEDITED=\u002Fpath\u002Fto\u002Fyour\u002FAGENTS.md       # or skills\u002FRESOLVER.md, whichever you edited\n\n# In your gbrain repo checkout:\ncd \u002Fpath\u002Fto\u002Fgbrain\u002Fevals\u002Ffunctional-area-resolver\nTMP=$(mktemp -d)\u002Fvariants && mkdir -p \"$TMP\"\ncp \"$EDITED\" \"$TMP\u002Fmy-edit.md\"\n\n# Without --yes the harness prints its cost estimate and exits (no model calls).\nANTHROPIC_API_KEY=... node harness.mjs --variants-dir \"$TMP\" --variants my-edit \\\n                                       --model opus --parallel 3\n\n# Only after the user approves that estimate:\nANTHROPIC_API_KEY=... node harness.mjs --variants-dir \"$TMP\" --variants my-edit \\\n                                       --model opus --parallel 3 --yes\n```\n\nGate 2 makes paid model calls. Show the user the estimate the first command\nprints and get their agreement before you add `--yes`; `--yes` only skips\nthe harness's own prompt, it is not the user's approval.\n\nThe harness uses gbrain's bundled fixture set, so this verifies \"did the LLM\nland in the right sub-skill for routing intents the gbrain-bundled fixtures\ncover\" — a regression check on shared skills, not a full re-eval of YOUR\nfixture set. For full eval coverage, mirror this skill's\n`fixtures.jsonl` + `fixtures-held-out.jsonl` setup with intents specific\nto your skills.\n\nIf the lenient (same-area) score on your variant drops below 95%, revert the\ncompression and tune. Common causes:\n- A sub-skill was omitted from the `(dispatcher for: ...)` list.\n- Trigger phrases for an area are too narrow (LLM can't recognize intent).\n- Areas were collapsed too aggressively (too few areas — see Anti-Patterns).\n- ASCII `->` vs Unicode `→` mismatch — the harness now accepts both, but\n  earlier versions only matched Unicode. Pin gbrain to v0.32.3.0+.\n\nCommon false negatives on the harness eval (NOT bugs in your compression):\n- The gbrain-bundled fixtures target skill names like `enrich`, `query`,\n  `gmail`, `executive-assistant`. If your routing file doesn't expose\n  those skills at all, expect strict-scoring failures on those fixtures.\n  Lenient scoring stays accurate for any sub-skill present in your\n  `(dispatcher for: ...)` lists.\n\n### Step 7: Review the diff before committing\n\nShow the user the proposed edit (or the actual git diff) and wait for\nexplicit approval before staging. Same convention as `skills\u002Fbook-mirror\u002FSKILL.md`.\n\n## Contract\n\nThis skill guarantees:\n\n- Routing matches the canonical triggers in the frontmatter.\n- Compression is only performed when the preconditions in Step 1 pass (file ≥12KB AND clean working tree, or `--force`).\n- The mandatory verification gate in Step 6 fires on the user's edited file, not on sample variants. The user runs `gbrain routing-eval --json` AND the gbrain-repo harness (`node harness.mjs --variants-dir \u003Ctmp> --variants my-edit`) before committing the compressed file.\n- Privacy contract preserved: no fork-specific filesystem path literals (server-side brain home, OpenClaw fork home) leak into the compressed output.\n\nThe full behavior contract is documented in the body sections above; this section exists for the conformance test.\n\n## Output Format\n\nThe compressed routing file follows the area-entry template documented in Step 4 (\"Build the area entry format\"). Each entry: `- **{Area Name}**: {trigger phrases} -> \\`{dispatcher-skill}\\` (dispatcher for: {sub-skill list})`. The dispatcher arrow may be either ASCII `->` (default in this template) or Unicode `→` (used in some production deployments); the gbrain harness accepts both.\n\n## When it fails\n\nFollow the [agent operator protocol](..\u002Fconventions\u002Fagent-operator-protocol.md) for any gbrain error `code`, exit code, `[AGENT]` block or notice block. Specific to this skill:\n\n- Either verification gate fails (structural or LLM A\u002FB): refuse to compress and report the failing gate; never ship a smaller resolver that routes worse.\n- The A\u002FB harness lacks a provider key or hits a cost cap: say the LLM gate did not run and keep the original resolver.\n\n## Anti-Patterns\n\n- **Resolver-of-resolvers with pipe tables.** Tested and failed (see eval\n  table). The LLM picks area names from the table instead of drilling into\n  sub-skills.\n\n- **Removing sub-skill names.** Without the `(dispatcher for: ...)` list,\n  the LLM can't route to specific sub-skills. The list is the routing signal.\n\n- **Too few areas.** Collapsing to \u003C5 areas makes each area too broad.\n  12-15 areas is the sweet spot.\n\n- **Too many areas.** Defeats the purpose. If you have 50 areas, just keep\n  individual rows.\n\n## Maintenance\n\nWhen adding a new skill:\n1. Identify its functional area.\n2. Add the skill name to that area's `(dispatcher for: ...)` list.\n3. Update the area's skill file with routing detail.\n4. Run the routing eval (Step 6) to verify.\n\nWhen adding a new functional area:\n1. Create the dispatcher skill with internal routing.\n2. Add the area entry to the routing file.\n3. Run the routing eval (Step 6) to verify.\n\n## Changelog\n\n### v1.0.0 — 2026-05-11\n- Initial version. Pattern shipped in gbrain v0.32.3.0 with a held-out A\u002FB\n  eval (see `evals\u002Ffunctional-area-resolver\u002F`).\n- Skill renamed from `compress-agents-md` to `functional-area-resolver`\n  pre-release; the contribution is the pattern, not the filename.\n",{"name":5,"tools":44,"version":46,"mutating":47,"triggers":48,"brain_first":60,"description":61,"prompt_version":62},[45,33,32,31],"exec","1.0.0",true,[49,50,51,52,53,54,55,19,56,57,58,59],"compress agents.md","compress my resolver","resolver too big","resolver.md too big","agents.md too large","shrink routing table","slim down agents.md","functional area dispatcher","context-health agents","context-health resolver","reduce context budget","exempt","Compress an agent's routing file (RESOLVER.md or AGENTS.md) by converting\ngranular skill-per-row tables into functional-area dispatchers. Each area\nlists sub-skills in a \"(dispatcher for: ...)\" clause. The LLM reads one\narea entry and routes to the correct sub-skill. Proven via held-out\nA\u002FB eval: dispatcher pattern outperforms naive pipe-table compression.\n",1,"master","074ec301549ded4930f04d2c3b22d709a6c095cc","skills\u002Ffunctional-area-resolver",4902,"https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain","https:\u002F\u002Fgithub.com\u002Fgarrytan","https:\u002F\u002Fblog.garrytan.com","Writes software, dreams. ","2026-11-14 04:11:30",{"source":8,"skillName":5,"commands":73,"prompt":83,"zipAvailable":47},[74,77,80],{"tool":75,"command":76},"npx","npx skills add garrytan\u002Fgbrain --skill functional-area-resolver",{"tool":78,"command":79},"bunx","bunx skills add garrytan\u002Fgbrain --skill functional-area-resolver",{"tool":81,"command":82},"pnpm","pnpm dlx skills add garrytan\u002Fgbrain --skill functional-area-resolver","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Fskills\u002Ffunctional-area-resolver\u002FSKILL.md",[85],{"path":86,"resourceType":87,"resourceTypeDesc":88,"sizeBytes":89,"sourceHtmlUrl":90},"routing-eval.jsonl","OTHER","其他",2297,"https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Fskills\u002Ffunctional-area-resolver\u002Frouting-eval.jsonl",[92,105,111,132,158,171],{"skillNo":93,"name":94,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":95,"categories":96,"keywords":97,"publishedAt":39},"01M6N109FNGH1PK49T734PZXGB","query-helper","https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Ftest\u002Ffixtures\u002Fskill-catalog\u002Fskills\u002Fquery-helper\u002FSKILL.md",[],[98,99,100,101,102,103,104],"query helper","helper","query","search","page","find","false",{"skillNo":106,"name":107,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":108,"categories":109,"keywords":110,"publishedAt":39},"01M6N108A23GW6NGQEQ0E7GV0A","broken","https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Ftest\u002Ffixtures\u002Fskill-catalog\u002Fskills\u002Fbroken\u002FSKILL.md",[],[107],{"skillNo":112,"name":113,"nameZh":6,"description":114,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":115,"categories":116,"keywords":117,"publishedAt":39},"01M6N105E88C5K2H03H0CC79G1","brain-ops","Read, enrich, and write brain pages with source attribution.","https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Ftest\u002Ffixtures\u002Fskill-catalog\u002Fskills\u002Fbrain-ops\u002FSKILL.md",[],[118,119,120,121,122,102,33,32,123,124,100,125,126,127,128,129,130,131,101],"brain ops","brain","ops","true","attribution","up","look","pages","people","with","enrich","web","path","source",{"skillNo":133,"name":134,"nameZh":6,"description":135,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":136,"categories":137,"keywords":143,"publishedAt":39},"01M6N102GRMF22TVCNT6RK5MRD","meeting-prep","Build a briefing before you meet someone, from their recent threads, open loops and what they care about.","https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Ftest\u002Ffixtures\u002Fskill-catalog-query\u002Fskills\u002Fmeeting-prep\u002FSKILL.md",[138],{"categoryNo":139,"categoryName":140,"taxonomyType":141,"taxonomyTypeDesc":142},"01JBSEEDCAT000000000000034","行政与办公人员","PROFESSION","适用职业",[144,145,146,147,148,101,149,150,151,100,104,152,153,154,155,156,25,157],"meeting","prep","meeting prep","me","prepare","brief","open","build","loops","about","you","briefing","threads","Meet",{"skillNo":159,"name":160,"nameZh":6,"description":161,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":162,"categories":163,"keywords":164,"publishedAt":39},"01M6N1005QK7REHX5KGMNR5PF0","inbox-zero","Triage the inbox into replies, delegations and archives.","https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Ftest\u002Ffixtures\u002Fskill-catalog-query\u002Fskills\u002Finbox-zero\u002FSKILL.md",[],[165,166,167,101,168,104,169,26,170],"inbox zero","ZeRO","inbox","clear","replies","triage",{"skillNo":172,"name":173,"nameZh":6,"description":174,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":175,"categories":176,"keywords":177,"publishedAt":39},"01M6N0ZXQ8RRRW71PNV61T57GP","deal-memo","Draft an investment memo from the deal pages and the founder history already in the brain.","https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Ftest\u002Ffixtures\u002Fskill-catalog-query\u002Fskills\u002Fdeal-memo\u002FSKILL.md",[],[178,179,180,125,119,181,182,32,183,121,101,184],"deal memo","deal","memo","draft","investment","history","founder"]