[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M71BP02S49HHD4R5X6N12C9Q":3,"skill-same:01M71BP02S49HHD4R5X6N12C9Q":74},{"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":51,"commitSha":52,"skillDirectory":53,"forksCount":54,"repositoryHtmlUrl":55,"repositoryHomepageUrl":56,"ownerHtmlUrl":57,"ownerBlogUrl":6,"ownerDescription":58,"updatedAt":59,"install":60,"resources":73},"01M71BP02S49HHD4R5X6N12C9Q","unikit-rules-registry",null,"Orchestrate the remote rules registry — the shared registry (often connected as a local folder or git repo) that the project's rules are published to and pulled from. Three modes, picked from the user's wording: create scaffolds a new local rules registry (\"create a local rules registry\", \"init a rules registry\"); update migrates\u002Fpromotes local knowledge-base rules from .unikit\u002Fmemory\u002F into the remote registry with automatic semver bumps (\"migrate local rules to the remote registry\", \"promote my rules to the registry\", \"push local rules\", \"publish local rules\", \"update the rules registry\"); sync pulls registry updates back into memory (\"sync the rules registry\", \"pull registry updates\"). Pass \"--module \u003Cid>\" to scope to one knowledge-base module. This skill ONLY orchestrates the CLI (`unikit-ai rules *`) — it never edits .unikit.json or .unikit\u002Fmemory\u002F sources directly.","NintendaDev\u002Funikit-ai","NintendaDev","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F181320258?v=4","01M71BFH8JJ6EBGRXBWRZK894Y","Dmitrii Vasilev","01M71BFH9T4K66TTBFNV1ZWFN5",22,"MIT","https:\u002F\u002Fgithub.com\u002FNintendaDev\u002Funikit-ai\u002Fblob\u002Fmain\u002Fskills\u002Funikit-rules-registry\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"Rules","unikit rules registry","registry","three","as","knowledge-base","semver","automatic","ai rules","git","write","read","update","create","migrate","remote","knowledge","local","project","shared","2026-11-10 10:12:30",false,"---\nname: unikit-rules-registry\ndescription: >-\n  Orchestrate the remote rules registry — the shared registry (often connected as a local\n  folder or git repo) that the project's rules are published to and pulled from. Three modes,\n  picked from the user's wording: create scaffolds a new local rules registry (\"create a local\n  rules registry\", \"init a rules registry\"); update migrates\u002Fpromotes local knowledge-base\n  rules from .unikit\u002Fmemory\u002F into the remote registry with automatic semver bumps (\"migrate\n  local rules to the remote registry\", \"promote my rules to the registry\", \"push local rules\",\n  \"publish local rules\", \"update the rules registry\"); sync pulls registry updates back into\n  memory (\"sync the rules registry\", \"pull registry updates\"). Pass \"--module \u003Cid>\" to scope\n  to one knowledge-base module. This skill ONLY orchestrates the CLI (`unikit-ai rules *`) —\n  it never edits .unikit.json or .unikit\u002Fmemory\u002F sources directly.\nargument-hint: \"[create | update | sync] [--module \u003Cid>]\"\nallowed-tools:\n  - Read\n  - Write\n  - Bash\n  - Glob\n  - AskUserQuestion\n---\n\n# UniKit Rules Registry — External Registry Orchestrator\n\nManage the external rules registry lifecycle from the project side. This skill owns three modes:\n\n- **create** — scaffold a new local registry repository, seed it with rules currently in `.unikit\u002Fmemory\u002F`, and optionally switch the project to use it.\n- **update** — diff `.unikit\u002Fmemory\u002F` against the currently configured **local** registry and push changes back (new rules, content updates with automatic semver bumps, stale deletions).\n- **sync** — pull registry-side updates into `.unikit\u002Fmemory\u002F` via `unikit-ai rules sync` (direction: registry → memory).\n\nDirection matters:\n- `create` and `update` flow **memory → registry**.\n- `sync` flows **registry → memory**.\n\nThe skill is **module-agnostic**: the knowledge base is partitioned into top-level\nmodules (`.unikit\u002Fmemory\u002F\u003Cmodule>\u002F\u003Ctier>`), and this skill iterates over the\nmodules registered in `.unikit\u002Fsystem\u002Fmodules.yml`. It never hardcodes a module\nid, a tier name, or a registry layout — those come from `modules.yml`.\n\n**User questions.** Right before your first question to the user, not earlier, read `.unikit\u002Fsystem\u002Fuser-questions.md` once and ask every question as it says, with the question tool of your agent (`AskUserQuestion`). If the file cannot be read, print `WARN [questions] user-questions contract missing — asking with the question tool` and still ask with that tool, the recommended option first.\n\n## Boundaries\n\n**This skill MUST NOT:**\n- Write to `.unikit.json` directly via the `Write`\u002F`Edit` tools. All config mutations go through CLI commands: `unikit-ai rules registry set` \u002F `rules registry reset` in create mode, and `unikit-ai rules install ... --force` in update mode (`update.7b`).\n- Edit or create files inside `.unikit\u002Fmemory\u002F` directly via the `Write`\u002F`Edit` tools. Memory sources are authored by `unikit-memory` and `unikit-rules`; this skill may only cause indirect memory writes by delegating to `unikit-ai rules install ... --force` in `update.7b`, which re-fetches registry copies and overwrites memory files as part of the force-install path.\n- Parse `config.rulesRegistry` as a string to guess `url` vs `local` — always read `kind` from `unikit-ai rules registry show --json`, `unikit-ai rules registry status --json`, or `unikit-ai rules status --json`.\n- Hardcode the registry on-disk layout. Always derive it from each module's `enginePartitioned` flag in `modules.yml` (see \"Registry layout\" below).\n\n**This skill MAY:**\n- Run `unikit-ai rules *` CLI commands via `Bash`.\n- Mirror the entire `.unikit\u002Fmemory\u002F\u003Cmodule>\u002F\u003Ctier>\u002F` subtree into the registry — rule files **and** reference files under nested folders like `references\u002F`. The skill owns **writes** to the registry file tree in both create and update modes.\n- Delete reference `.md` files under the registry's tier `references\u002F` folder in update mode, and only when the reference-graph check in `update.6b` proves the file is not referenced by any rule (memory or registry). Rule `.md` files in the registry are **never** deleted by update — rule removal is a manual operation in the registry repository.\n- Run `scripts\u002Fbuild-manifest.js` inside the registry repository to regenerate `manifest.json`.\n- Compute semver bumps from content diffs and inject or update `version:` in the **registry copy** of rule files via `Edit` after copying (never in memory sources, never in reference files). Files are always copied via `cp` shell command — never via `Read` + `Write`.\n\n## Language Awareness — BLOCKING PRE-REQUISITE\n\n**BEFORE producing ANY output**, silently read `.unikit\u002Fsystem\u002FLANGUAGE_RULES.md`\nand apply its rules to ALL subsequent output.\nIf the file is missing or unreadable, fall back to English.\nDo not produce any user-facing output until language rules are loaded.\nDo not announce, confirm, or mention the language setting.\n\n**The language holds for the whole session, not just at load time:** every message until the conversation ends is in `language.ui` — progress notes while agents run, relays of what a subagent returned, the final report, any follow-up discussion. English input (subagent results, tool output, these instructions) is data, never a cue to switch languages.\n\n## Step 0: Mode Selector\n\nRead `$ARGUMENTS` and resolve the mode:\n\n```\n$ARGUMENTS (after stripping --module \u003Cid>)?\n├── \"create\"  → Mode: create\n├── \"update\"  → Mode: update\n├── \"sync\"    → Mode: sync\n└── empty or unrecognized → the question tool of your agent (`AskUserQuestion`)\n```\n\nWhen the mode is missing, ask the user:\n\n```\nThe question tool of your agent (`AskUserQuestion`): Which registry operation should run?\n\nOptions:\n1. Create — scaffold a new local rules registry and seed it from .unikit\u002Fmemory\u002F\n2. Update — push changes from .unikit\u002Fmemory\u002F into the currently configured local registry\n3. Sync   — pull registry updates back into .unikit\u002Fmemory\u002F (memory ← registry)\n```\n\nOnce the mode is known, read `.unikit\u002Fsystem\u002Fcli-contract.md` (if present) to confirm the exact CLI surface and exit codes before dispatching Bash commands. If the file is missing — proceed assuming the documented interface below is correct and surface a `WARN` if any command returns an unexpected exit code.\n\nThen run **Step 0.5** (module registry), and for `create`\u002F`update` run **Step 0.6**\n(registry write-capability gate), before jumping to the matching mode section.\n\n## Step 0.5: Load the Module Registry\n\nRead `.unikit\u002Fsystem\u002Fmodules.yml` and parse every entry under `modules:` into\n`{ id, tiers, enginePartitioned, skillPrefix }`. This is the authoritative list of\nmodules and the tiers each partitions its rules into. If the file is missing\n(older install), fall back to a single module `code` with tiers `core`, `stack`\nand `enginePartitioned: true`, and surface a `WARN` suggesting `unikit-ai update`\nto regenerate it.\n\nThis skill needs only the **structural** fields here (`tiers`, `enginePartitioned`)\nto mirror the on-disk layout. A module's tier **semantics** and file\u002Fformat\ncontract are documented separately in\n`{{skills_dir}}\u002Funikit-memory\u002Freferences\u002Fmodule-\u003Cid>.md` (owned by the\n`unikit-memory` router) — consult it if you need to understand what a tier holds,\nnever to derive registry paths.\n\n**Resolve the target modules** (the policy mirrors `--engine`):\n\n1. **Explicit `--module \u003Cid>`** in `$ARGUMENTS` → validate against the parsed ids.\n   Valid → operate on that single module; strip the flag. Invalid → ask via\n   the question tool of your agent (`AskUserQuestion`) (options = registered module ids), then use the chosen id.\n   Print the module ids with their one-line domain summaries to the screen as plain\n   markdown first.\n2. **No flag, neutral operation** (a plain create\u002Fupdate\u002Fsync) → operate on **all**\n   registered modules (read from `modules.yml`).\n3. **Context narrows to one module ambiguously** (e.g. the prompt clearly targets\n   one module but another is plausible) → ask via the question tool of your agent (`AskUserQuestion`) (options =\n   registered module ids + \"all modules\"). Never guess.\n   Print the module ids with their one-line domain summaries to the screen as plain\n   markdown first.\n\nEverywhere below, \"for each module\" means \"for each resolved target module\", and\n\"for each tier\" means \"for each tier of that module from `modules.yml`\".\n\n**Registry layout** (schema:2, derived per module from `enginePartitioned`):\n\n- Engine-partitioned module (e.g. `code`): `\u003CregistryPath>\u002F\u003Cmodule>\u002F\u003Cengine>\u002F\u003Ctier>`\n- Non-engine module (e.g. a future `gamedesign`): `\u003CregistryPath>\u002F\u003Cmodule>\u002F\u003Ctier>`\n\nThe tier's reference subfolder is `\u003Cthat tier path>\u002Freferences\u002F`. Memory sources\nalways live at `.unikit\u002Fmemory\u002F\u003Cmodule>\u002F\u003Ctier>\u002F`. Never hardcode these — assemble\nthem from the module id, its `enginePartitioned` flag, the resolved engine, and the\ntier.\n\n\u003C!-- unikit:extension-point:bootstrap -->\n\n## Step 0.6: Registry Write-Capability Gate (create \u002F update only)\n\nWrite modes must confirm the target registry is reachable, on the latest schema,\nand writable **before** seeding or pushing. `sync` skips this gate entirely — it is\nregistry → memory and relies on its own `rules sync` exit codes (2\u002F5).\n\nRun against the target registry (the configured registry for `update`; for\n`create`, run it after `create.2` against the scaffold target path):\n\n```bash\nunikit-ai rules registry status --json\n```\n\nThe JSON has six facts: `{ target, kind, schema, isLatestSchema, readable, writable }`.\nExit codes: `0` (reachable, schema ≤ latest), `2` (unreachable), `5` (unsupported\nschema > latest). Branch on the result:\n\n| Condition | Verdict | Action |\n|-----------|---------|--------|\n| exit 2 \u002F `schema == null` | unreachable | Report `registry unreachable` and **stop**. A write mode cannot proceed against a registry it cannot read. |\n| exit 5 \u002F `readable == false` (schema > latest) | unsupported schema | Report `registry schema is newer than this CLI — upgrade unikit-ai`, then **stop**. |\n| `kind == \"local\"` and `isLatestSchema == false` | local, behind latest schema | Offer to migrate: the question tool of your agent (`AskUserQuestion`) → run `unikit-ai rules registry migrate \u003Ctarget>` on yes, then **re-run `rules registry status --json`** and re-evaluate. On no → **stop** (writing schema:2 layout into a schema:1 registry would corrupt it). |\n| `kind == \"remote\"` and `isLatestSchema == false` | outdated remote | `migrate` cannot write a remote registry. Report that the user must clone the registry, run `rules registry migrate` on the clone, open a PR upstream, then point the project at a writable copy. **Stop.** |\n| `kind == \"remote\"` and `isLatestSchema == true` | remote, read-only via CLI | A write mode needs a local registry. For `update`, this duplicates the `update.1` guard — report `update requires a local registry` and **stop**. (create scaffolds a fresh local target, so this row should not occur there.) |\n| `kind == \"local\"` and `isLatestSchema == true` (`writable == true`) | up to date and writable | Proceed to the mode body. |\n\nOnly continue into the create-seed \u002F update-diff steps when the gate resolves to\n**writable** (`kind == \"local\"` and `isLatestSchema == true`).\n\n---\n\n## Mode: create\n\nScaffold a new local registry and seed it with the rules currently installed in `.unikit\u002Fmemory\u002F`.\n\n### create.1: Ask for target path\n\n```\nThe question tool of your agent (`AskUserQuestion`): Where should the new rules registry be created?\n\nOptions:\n1. Project subfolder — .\u002Frules-registry\n2. Custom path — I will ask next (relative or absolute)\n3. Cancel\n```\n\n- Option 1 → `pathArg = \".\u002Frules-registry\"`. Pass this verbatim to the CLI in `create.2`. `rulesRegistryInitCommand` in `src\u002Fcli\u002Fcommands\u002Frules.ts` resolves it against `process.cwd()` and auto-creates the target directory via `fs.ensureDir`.\n- Option 2 → ask for the path in a message of your own, with no options. Trim the input; if the result is empty, ask again the same way. Then compute the absolute path via `path.resolve(\u003Ccwd>, \u003Ctrimmed-input>)` **for display only** and ask a second question with the question tool of your agent (`AskUserQuestion`) of this shape:\n  - Question: `Target directory will be: \u003Cresolved-absolute-path>. Proceed?`\n  - Options: `Yes, proceed` \u002F `No, enter a different path` \u002F `Cancel`\n  - Yes → use the original (pre-resolve) input string as `pathArg` in `create.2`.\n  - No → loop back to the text-input prompt.\n  - Cancel → stop the skill.\n- Option 3 → stop the skill.\n\nDo **not** pre-check path existence, expand `~`, normalize the path, or reject relative paths on the skill side. `rulesRegistryInitCommand` is the single authority on path validation: it calls `path.resolve(cwd, pathArg)` itself, auto-creates missing directories via `fs.ensureDir`, and signals problems through exit codes 3 (INVALID_ARGS), 6 (REGISTRY_ALREADY_INITIALIZED), and 7 (PATH_OCCUPIED) — all handled in `create.2` below.\n\n### create.2: Scaffold the registry\n\nRun:\n\n```bash\nunikit-ai rules registry init \u003Ctarget-path>\n```\n\nExit-code handling:\n\n| Exit | Meaning | Action |\n|------|---------|--------|\n| 0 | Scaffold OK | Continue to create.2b |\n| 3 | INVALID_ARGS (relative path, etc.) | Report stderr and stop |\n| 5 | VALIDATION_FAILED (build-manifest.js failed) | Report stderr and stop |\n| 6 | REGISTRY_ALREADY_INITIALIZED | Ask with the question tool of your agent (`AskUserQuestion`): `Reuse the existing scaffold and continue` (Recommended) · `Stop` → reuse proceeds to create.2b, stop ends the skill |\n| 7 | PATH_OCCUPIED | Report `target path is not empty and is not a registry`, stop |\n| other | Unexpected | Report stderr and stop |\n\n### create.2b: Write-capability gate on the scaffold\n\n`registry init` creates a fresh schema:2 scaffold, but on the **reuse** path (exit 6)\nthe existing directory may be a schema:1 registry. Run the **Step 0.6** gate against\n`\u003Ctarget-path>` now. A freshly-initialized target resolves to writable immediately;\na reused schema:1 target routes through the migrate offer. Only continue to\n`create.3` when the gate resolves to writable.\n\n### create.3: Resolve current engine\n\n```bash\nunikit-ai rules status --json\n```\n\nParse the JSON and read `.engine`. Never open `.unikit.json` directly — the CLI is the source of truth.\n\nIf the CLI exits non-zero (project not initialized), stop the skill with an ERROR referencing `unikit-ai init`.\n\n### create.4: Seed registry with memory rules\n\nFor each **module** (Step 0.5) and each **tier** of that module:\n\n1. Use `Glob: .unikit\u002Fmemory\u002F\u003Cmodule>\u002F\u003Ctier>\u002F**\u002F*` to enumerate the **entire subtree** — not just top-level `*.md`. This captures nested folders like `references\u002F` that hold reference files referenced by rule headers (quickrefs, catalogs, indexes).\n2. For every file discovered:\n   - Compute `relPath` relative to `.unikit\u002Fmemory\u002F\u003Cmodule>\u002F\u003Ctier>\u002F`.\n   - Target path = `\u003Ctier-registry-path>\u002F\u003CrelPath>`, where `\u003Ctier-registry-path>` is the schema:2 layout from Step 0.5 (`\u003Ctarget-path>\u002F\u003Cmodule>\u002F\u003Cengine>\u002F\u003Ctier>` for engine-partitioned modules, `\u003Ctarget-path>\u002F\u003Cmodule>\u002F\u003Ctier>` otherwise).\n   - **Classify the file:**\n     - **Top-level rule file** (`relPath` contains no `\u002F`, extension `.md`) → copy via shell, then inject version into the **registry copy only** if absent:\n       1. `Bash: mkdir -p \"$(dirname \"\u003Ctarget>\")\" && cp \"\u003Csrc>\" \"\u003Ctarget>\"`\n       2. `Bash: grep -q \"^version:\" \"\u003Ctarget>\"` — if exit 1 (not found), use `Edit` to insert `version: 1.0.0` into the frontmatter of `\u003Ctarget>`. The source in `.unikit\u002Fmemory\u002F` stays untouched.\n     - **Reference file** (anything under a subdirectory, or non-`.md` extension) → copy via shell verbatim. Never touch frontmatter — reference files are plain docs and must travel with their parent rule as-is:\n       1. `Bash: mkdir -p \"$(dirname \"\u003Ctarget>\")\" && cp \"\u003Csrc>\" \"\u003Ctarget>\"`\n3. If the tier directory yields zero files, continue silently.\n\nTrack per-module\u002Fper-tier totals: `rulesCopied` (top-level rule files) and `referencesCopied` (everything else). These feed the final table in `create.7`.\n\nWhy recursive: rule files reference reference files via `> **References**:` headers. A seed that copies only `*.md` at the top level would publish rules pointing at paths that do not exist in the registry. Mirroring the full tree keeps the references intact.\n\n### create.5: Regenerate registry manifest\n\n```bash\nnode \u003Ctarget-path>\u002Fscripts\u002Fbuild-manifest.js\n```\n\n- On non-zero exit: print stderr, stop the skill, and advise the user to inspect the rule files — the most common cause is missing `> **Load when**:` blocks or invalid frontmatter.\n- On success: continue.\n\n### create.6: Offer to switch the project registry\n\nThe scaffold mirrors `.unikit\u002Fmemory\u002F` bit-for-bit on disk — content-wise the new registry agrees with memory. But the **state metadata** in `.unikit.json.rules.installed` still points at the old provenance: every rule entry is tagged with its original `source` (`installer` \u002F `registry`) and `origin` (`official` \u002F old primary). Flipping `rulesRegistry` alone does not rewrite those tags, so the project would still look like it is \"using the old registry\" on the next `rules status --json`.\n\nTo make the switch complete, the skill pairs `registry set` with a follow-up `rules sync --replace --prune`. `--replace` bypasses the `source !== 'registry'` guard in `syncRulesState` so installer-sourced rules get walked; the sync loop rewrites `source`, `version`, `installed_hash`, and `origin` (via `HybridRegistry.getResolvedOrigin()`) against the new primary registry. `--prune` removes obsolete stack rules that are not in the new manifest. The HARD GUARD in `syncRulesState` still prevents discovery of previously-uninstalled rules — only already-installed entries get reclassified.\n\n```\nThe question tool of your agent (`AskUserQuestion`): Switch the current project to this new registry now?\n\nOptions:\n1. Yes — point .unikit.json at the new registry and reclassify installed rules as primary\n2. No — keep the current registry\n```\n\nMapping to CLI commands (order matters — `registry set` must succeed before `sync` runs):\n\n| Choice | Commands |\n|--------|----------|\n| 1 | `unikit-ai rules registry set \u003Ctarget-path>` then `unikit-ai rules sync --replace --prune` |\n| 2 | (skip — do not touch `.unikit.json`) |\n\nExit-code handling:\n\n- `rules registry set` exit 3 (INVALID_ARGS) or 5 (VALIDATION_FAILED) → report stderr and stop the skill. Do **not** run `rules sync`; the URL has not been written.\n- `rules sync --replace --prune` exit 2 (NETWORK — local path disappeared between the two commands) or 5 (VALIDATION_FAILED — registry manifest broken) → report stderr and warn the user that `.unikit.json.rulesRegistry` has already been rewritten to the new path, but rule metadata is still on the old provenance. Instruct them to fix the registry and re-run `unikit-ai rules sync --replace --prune` manually. Do not attempt to roll back `registry set` automatically.\n- Both commands exit 0 → continue to `create.7`.\n\nStream stdout\u002Fstderr of both commands to the user so the per-rule event log from `syncRulesState` is visible.\n\n### create.7: Report\n\nProduce a **compact** final report — no prose paragraphs, no step-by-step narrative, no CLI echoes. Just one table of the rules that were transferred, followed by two direction reminders. Anything longer than a dozen lines means you are over-reporting.\n\nTable format (add a `Module` column when more than one module was seeded; omit it when only `code` ran):\n\n```\n| Module | Tier  | Rule              | Version |\n|--------|-------|-------------------|---------|\n| code   | core  | folders-structure | 1.0.0   |\n| code   | core  | code-style        | 1.0.0   |\n| code   | stack | aspid-mvvm        | 1.0.0   |\n| code   | stack | node-canvas       | 1.0.0   |\n```\n\n- One row per top-level rule file copied (the files counted by `rulesCopied`).\n- Do not list reference files individually — mention them only as a single trailing line: `+ N reference files under references\u002F` (omit the line if `referencesCopied == 0`).\n- Version column shows the version that ended up in the registry copy (either the existing frontmatter value or the injected `1.0.0`).\n\nAfter the table, print exactly these two reminders (adapt to the configured language):\n\n- `\u002Funikit-rules-registry update` — push later local edits from `.unikit\u002Fmemory\u002F` into this registry.\n- `\u002Funikit-rules-registry sync` — pull registry-side updates back into `.unikit\u002Fmemory\u002F` (opposite direction).\n\nIf the project was switched to the new registry in `create.6`, add exactly two lines after the reminders:\n\n- `✅ rules registry set: \u003Ctarget-path>`\n- `✅ rules sync --replace --prune: N rules reclassified as primary`\n\n`N` is the number of rules touched by the sync — count the `phase2:updating` events from the `syncRulesState` event log (every such event flips one rule's `source`\u002F`origin` to the new primary). If the switch was declined, add nothing.\n\n---\n\n## Mode: update\n\nPush changes from `.unikit\u002Fmemory\u002F` into the currently configured **local** registry and regenerate its manifest.\n\n### update.1: Verify registry kind\n\n```bash\nunikit-ai rules registry show --json\n```\n\nParse JSON fields `configured`, `url`, `kind`.\n\n- `kind` is not `\"local\"` → ERROR: `update requires a local registry — run \u002Funikit-rules-registry create first`. Stop.\n- `configured` is `false` → ERROR: `no registry configured`. Stop.\n- Otherwise: `registryPath = \u003Curl>`.\n\n### update.1b: Write-capability gate\n\nRun the **Step 0.6** gate against `registryPath`. If the registry is local but\nbehind the latest schema, this routes through the `rules registry migrate` offer —\ncritical, because writing schema:2 layout (`\u003Cmodule>\u002F\u003Cengine>\u002F\u003Ctier>`) into a\nschema:1 registry (`\u003Cengine>\u002F\u003Ctier>`) would corrupt the layout and break\n`build-manifest.js`. Only continue to `update.2` when the gate resolves to writable.\n\n### update.2: Resolve engine\n\n```bash\nunikit-ai rules status --json\n```\n\nRead `.engine`. Abort on non-zero exit.\n\n### update.3: Diff memory vs registry\n\nFor each **module** (Step 0.5) and each **tier** of that module:\n\n1. `Glob: .unikit\u002Fmemory\u002F\u003Cmodule>\u002F\u003Ctier>\u002F**\u002F*` — walk the full subtree so reference files under `references\u002F` (and any other nested folders) are diffed alongside their parent rules.\n2. For every file `src` found in memory, compute `relPath` relative to `.unikit\u002Fmemory\u002F\u003Cmodule>\u002F\u003Ctier>\u002F` and classify it:\n   - **Rule file** if `relPath` has no `\u002F` and ends with `.md` (top-level markdown).\n   - **Reference file** otherwise (nested file, or non-`.md`). Reference files carry no `version:` frontmatter — they travel with their parent rule as plain content.\n3. For every `src`:\n   - target = `\u003Ctier-registry-path>\u002F\u003CrelPath>` (schema:2 layout from Step 0.5)\n   - If target does not exist → mark as **add**.\n   - Else run `Bash: diff -q --strip-trailing-cr \"\u003Csrc>\" \"\u003Ctarget>\"`:\n     - exit 0 → identical, **skip**.\n     - exit 1 → differs, continue to bump classification (rule files only) or mark as **reference-update** (reference files).\n     - other exit → report and stop.\n4. Walk the registry side the same way: `Glob: \u003Ctier-registry-path>\u002F**\u002F*`. Any file present in the registry but not in memory becomes a **delete** candidate (handled in update.5). Tag each orphan as rule vs reference file so the prompt can display them in two groups.\n\n**Why recursive:** rule files reference reference files via `> **References**:` headers. If `update` diffs only top-level `*.md`, edits to reference docs (quickrefs, full catalogs) silently stay behind and the registry drifts out of sync with the project's actual knowledge base. Walking the subtree is the simplest way to guarantee every referenced file reaches the registry.\n\n### update.4: Classify bumps for `differs` rule files\n\nReference files (`reference-update` from update.3) have no frontmatter version to bump — skip this step for them and handle them directly in update.6.\n\nFor every `differs` **rule file**, run `Bash: diff -u --strip-trailing-cr \"\u003Csrc>\" \"\u003Ctarget>\"`. Parse the output:\n\n- `added = number of lines starting with \"+\" excluding the \"+++\" header`\n- `removed = number of lines starting with \"-\" excluding the \"---\" header`\n- `oldTotal = wc -l of \u003Ctarget>` (used for the `removed > 30% oldTotal` rule)\n\nApply the heuristic **in order** — the first matching row wins:\n\n| Condition | Bump |\n|-----------|------|\n| `removed > 0.3 * oldTotal` | **major** |\n| `removed == 0` AND `added \u003C= 5` | **patch** |\n| `removed == 0` AND `added > 5` | **minor** |\n| `removed \u003C= 3` AND `added \u003C= 10` | **patch** |\n| `removed > 3` AND `added > removed` | **minor** |\n| otherwise | **patch** |\n\nCompute the new version:\n\n- Read the current `version:` from the target file's frontmatter (if missing, assume `1.0.0`).\n- Apply the bump:\n  - `patch` → `x.y.(z+1)`\n  - `minor` → `x.(y+1).0`\n  - `major` → `(x+1).0.0`\n- This heuristic is fully automatic — do **not** ask the user to approve each bump.\n\n### update.5: Collect orphan rule files (informational)\n\nUpdate is **strictly push-only** for rule files — it never removes them from the registry. For every rule `.md` file present in the registry and missing from memory (i.e. top-level `*.md` under `\u003Ctier-registry-path>` with no counterpart in `.unikit\u002Fmemory\u002F\u003Cmodule>\u002F\u003Ctier>\u002F`), append `{ module, tier, filename }` to an `orphanRuleFiles` list. That list is consumed purely by `update.8` as a WARN block — no prompt, no delete, no cascade.\n\nDo **not** walk reference files under `references\u002F` here. Reference file reconciliation is a separate concern handled in `update.6b` via the real `rule → references` graph; orphan detection at the file level would miss shared reference files and produce false positives.\n\nIf `orphanRuleFiles` is empty after the walk, the WARN block is skipped entirely in `update.8`.\n\n### update.6: Apply changes\n\nFor each **rule file** `add`:\n- Copy via shell, then inject version into the **registry copy only** if absent:\n  1. `Bash: mkdir -p \"$(dirname \"\u003Ctarget>\")\" && cp \"\u003Csrc>\" \"\u003Ctarget>\"`\n  2. `Bash: grep -q \"^version:\" \"\u003Ctarget>\"` — if exit 1 (not found), use `Edit` to insert `version: 1.0.0` into the frontmatter of `\u003Ctarget>`. The source in `.unikit\u002Fmemory\u002F` stays untouched.\n\nFor each **rule file** `differs`:\n- Copy via shell, then replace the version in the **registry copy**:\n  1. `Bash: cp \"\u003Csrc>\" \"\u003Ctarget>\"`\n  2. Use `Edit` to replace the `version:` line in `\u003Ctarget>` with the bumped version from update.4 (insert if absent). The source in `.unikit\u002Fmemory\u002F` stays untouched.\n\nFor each **reference file** `add` or `reference-update`:\n- Copy via shell verbatim. Do not inject or alter any frontmatter — reference files are plain docs and must reach the registry byte-identical to the memory source (modulo the path):\n  1. `Bash: mkdir -p \"$(dirname \"\u003Ctarget>\")\" && cp \"\u003Csrc>\" \"\u003Ctarget>\"`\n\nTrack `touchedRuleFiles = [...]` — every rule file classified as `add` or `differs` in this step, stored as `{ module, tier, ruleId }` (ruleId = filename without `.md`). This list is consumed by `update.7b` to drive the post-write `rules install --force` batch. Reference files are **not** tracked — `installOneRule` re-fetches a parent rule's declared references automatically during force install.\n\nThere is **no `delete` branch** in this step — update never removes rule files from the registry (see `## Boundaries`). Companion deletions happen separately in `update.6b` via the reference-graph check; that step runs after all writes here so it sees the final set of registry files.\n\nAll writes happen inside the registry tree only — never touch memory sources.\n\n### update.6b: Reference file cleanup (reference-graph based)\n\nReconcile reference files in the registry against the real `rule → references` graph. Remove any reference `.md` under a tier's `references\u002F` folder that no rule (in memory or in the registry) references anymore. The algorithm covers four scenarios:\n\n| Scenario | `referencedByAnyone`? | Action |\n|----------|----------------------|--------|\n| Parent rule dropped a ref, nobody else holds it | No | Delete |\n| Shared — another memory rule still references it | Yes | Keep (protected) |\n| Orphan parent rule in registry still references it | Yes | Keep (protected) |\n| Zombie — no rule references it anywhere | No | Delete |\n\nRun the algorithm **per module + per tier** — each `\u003Cmodule>\u002F\u003Ctier>` is an independent namespace and never shares reference filenames across the divide.\n\nFor each module + tier:\n\n1. Initialise `referencedByAnyone` as an empty `Set\u003Cstring>` of reference filenames.\n2. Walk `\u003Ctier-registry-path>\u002F*.md` (top-level rule files only — do not recurse into `references\u002F` here). For every rule file found:\n   - Let `ruleId = basename without .md`.\n   - If `.unikit\u002Fmemory\u002F\u003Cmodule>\u002F\u003Ctier>\u002F\u003CruleId>.md` exists → `parseTarget = memory` (memory wins for rules present in both).\n   - Else → `parseTarget = registry` (orphan parent rule — protect its own references using the on-disk registry header).\n   - Read the chosen file, locate the `> **References**:` header line, and extract every reference filename with the regex `references\\\u002F([^\\s,)]+\\.md)\u002Fg`. This is the exact regex used by `rules-registry\u002Fscripts\u002Fbuild-manifest.js` — stay byte-for-byte aligned so `update.6b` and the manifest rebuild in `update.7` never disagree about what is referenced.\n   - Add every extracted filename to `referencedByAnyone`.\n3. Enumerate physical reference files: `Glob: \u003Ctier-registry-path>\u002Freferences\u002F*.md` → `physical` (set of filenames only, strip paths).\n4. Compute `safeToDelete = physical \\ referencedByAnyone` (set difference by filename).\n5. For every filename in `safeToDelete`:\n   - `Bash: rm \"\u003Ctier-registry-path>\u002Freferences\u002F\u003Cfilename>\"` (single-file delete, never recursive, never glob).\n   - Append `{ module, tier, filename }` to a top-level `deletedReferences` list consumed by `update.8`.\n\nDocumented edge cases (**not** special-cased — the algorithm handles them naturally):\n\n- **Memory rule without a `> **References**:` header.** The regex returns an empty set for that rule. If nobody else references its former reference files, they become part of `safeToDelete`. This is the user's explicit intent — removing the header is the signal.\n- **Header contains a dangling filename** (names a file that does not physically exist). The filename still joins `referencedByAnyone`, so the delete check stays consistent with manifest generation. Nothing is fabricated — this step only deletes.\n- **Two rules in the same tier with identical references** — the set union on `referencedByAnyone` handles this: a shared file is recorded once and protected by both rules.\n\nThis step runs **before** `update.7` — the manifest rebuild must see the final physical layout of `references\u002F`, otherwise it would list reference filenames that no longer exist on disk.\n\n### update.7: Regenerate registry manifest\n\n```bash\nnode \u003CregistryPath>\u002Fscripts\u002Fbuild-manifest.js\n```\n\nOn non-zero exit: print stderr, stop the skill. The most common cause is a rule missing `> **Load when**:` or invalid frontmatter; the user must fix the rule source in `.unikit\u002Fmemory\u002F` (via `\u002Funikit-memory`) before re-running `\u002Funikit-rules-registry update`.\n\n### update.7b: Reconcile project state after registry bumps\n\n`update.6` wrote new and bumped rule files into the registry, but `.unikit.json.rules.installed[...]` still points at the pre-update `version` and `installed_hash` for every touched rule. Without reconciliation:\n\n- `unikit-ai rules status` will lie about installed versions.\n- The next `unikit-ai rules sync` (Safe mode) will mark disk files as `locally-modified` and **skip** the version update, so the drift never heals on its own.\n\nForce-install every touched rule in a single variadic CLI call. Reference files are **not** listed — `installOneRule` re-fetches a parent rule's declared references automatically during force install.\n\n1. Collect `installTargets = [ruleId for each entry in touchedRuleFiles]`, deduplicated. Read the list tracked in `update.6`.\n2. If `installTargets` is empty → **skip this step entirely**. No rule file changed in this run, so there is nothing to reconcile.\n3. Otherwise run one variadic invocation:\n\n   ```bash\n   unikit-ai rules install \u003Cid1> \u003Cid2> ... --force\n   ```\n\n   Stream stdout\u002Fstderr to the user so the per-rule report (`✓ installed …`, `↻ already installed …`, `✗ failed …`) surfaces as events occur.\n\n4. Exit-code handling:\n\n   | Exit | Meaning | Action |\n   |------|---------|--------|\n   | 0 | At least one rule installed (aggregated report may still contain `failed` rows) | Parse the report, forward any failures into `update.8` as a WARN block, continue |\n   | 2 | NETWORK — registry chain unreachable | Report stderr and stop the skill |\n   | 4 | NOT_FOUND — every rule failed | Capture the aggregated report, continue to `update.8` and surface as a WARN block; **do not** roll back `update.6` writes |\n   | 5 | VALIDATION_FAILED — registry manifest broken | Report stderr and stop the skill |\n   | other | Unexpected | Report stderr and stop the skill |\n\n   Do **not** attempt to roll back the writes `update.6` already made to the registry. The registry-side update has already succeeded; partial install failures are recoverable by re-running `unikit-ai rules install \u003Cid> --force` manually against specific ids once the root cause is fixed.\n\n`installOneRule` with `force=true` covers all three state branches deterministically:\n\n- **Existing entry with `source: registry` and stale version** → in-place update of `source`, `version`, `installed_hash`, `origin`.\n- **Existing entry with `source: local`** → transition to `source: registry, version: \u003Cfrom registry>` (first-time publication path). This is how a rule that was previously authored locally and just pushed to the registry in this run becomes \"owned\" by the registry in `.unikit.json`.\n- **No existing entry** → push a new entry with `source: registry, version: \u003Cfrom registry>`.\n\nA free bonus: `rulesInstallCommand` always regenerates `RULES_INDEX.md` at the end of its invocation, so the skill does not need a separate index refresh after this step.\n\n### update.8: Report\n\nProduce a **compact** final report — same style as `create.7`. No prose paragraphs, no step-by-step narrative, no CLI echoes. One table of rule changes, optional tallies, optional WARN blocks, one direction reminder. Anything longer than a dozen lines (plus WARN blocks, which can grow if the situation warrants) means you are over-reporting.\n\nTable format (add a `Module` column when more than one module was pushed; omit it when only `code` ran):\n\n```\n| Action | Module | Tier  | Rule        | Version       |\n|--------|--------|-------|-------------|---------------|\n| add    | code   | stack | aspid-mvvm  | 1.0.0         |\n| update | code   | stack | node-canvas | 1.2.0 → 1.3.0 |\n| skip   | code   | core  | code-style  | 1.1.0         |\n```\n\n- One row per top-level rule file touched. Rows are grouped by action in the order: `add`, `update`, `skip`. Omit the `skip` rows entirely if every unchanged rule would otherwise bloat the table — keep them only when useful for verification.\n- There is **no `delete` row for rule files** — update is strictly push-only for `.md` rule files (see `## Boundaries`). A rule that only exists in the registry surfaces in the orphan WARN block below, never as a table row.\n- `Version` column: for `add` and `skip` shows the current registry version; for `update` shows `old → new`.\n- Do not list reference files in the main table. Add a single trailing line directly under the table: `+ N reference files: X added · Y updated · Z deleted · W unchanged` (omit the line if all four counts are zero). `Z` comes from the `deletedReferences` list populated in `update.6b`.\n- If `Z > 0`, print a separate deletion table directly under the tally line:\n\n  ```\n  | Action | Module | Tier  | File                         |\n  |--------|--------|-------|------------------------------|\n  | delete | code   | stack | aspid-mvvm-binders-full.md   |\n  | delete | code   | core  | old-reference.md             |\n  ```\n\n  Rows come from `deletedReferences`, sorted by `module`, then `tier`, then `filename`. Do not inline the list on one line — the table is both the primary signal and the full record.\n\nIf `update.5` collected any entries into `orphanRuleFiles`, print one WARN block before the final two lines. Skip the block entirely when the list is empty:\n\n```\n⚠️ WARN: registry contains orphan rule files not mirrored in .unikit\u002Fmemory\u002F:\n  - code\u002Fstack\u002Flegacy-rule.md\n  - code\u002Fcore\u002Fretired-guidelines.md\nupdate is push-only; rule deletion must be done in the registry repo directly\n(rm + scripts\u002Fbuild-manifest.js + commit).\n```\n\nIf `update.7b` surfaced any `failed` rows in the `rules install --force` report (either partial failures on exit 0 or total failure on exit 4), print a second WARN block directly after the orphan block:\n\n```\n⚠️ WARN: state reconcile partially failed — the registry was updated but these rules\nstayed on their pre-update versions in .unikit.json:\n  - stack\u002Faspid-mvvm — \u003Creason from the install report>\nRe-run `unikit-ai rules install \u003Cid>... --force` manually after fixing the cause.\n```\n\nAfter the table, the reference files tally, and any WARN blocks, print exactly these two lines (adapt to the configured language):\n\n- `✅ manifest: ok` or `❌ manifest: failed — \u003Cone-line reason>`\n- `\u002Funikit-rules-registry sync` — pull registry-side updates back into `.unikit\u002Fmemory\u002F` (opposite direction of this run).\n\n---\n\n## Mode: sync\n\nPull registry-side updates back into `.unikit\u002Fmemory\u002F` by delegating to `unikit-ai rules sync`. Direction is registry → memory (the opposite of `update`).\n\nThis mode does **not** run the Step 0.6 write-capability gate — it does not write the\nregistry. `rules sync` carries its own reachability\u002Fvalidation exit codes (2\u002F5),\nwhich `sync.2` handles. `rules sync` reconciles the whole project and does **not**\naccept `--module`; a resolved `--module \u003Cid>` does not narrow the CLI call in this\nversion (it only documents intent for the report).\n\n### sync.1: Ask about the sync intensity\n\nThe CLI exposes two composable flags that used to live behind the single `--force`:\n\n- `--replace` — overwrite rules already in state (same-version refresh AND local modifications).\n- `--prune` — remove obsolete stack rules that vanished from the manifest.\n\nThe question below maps each user choice to a concrete flag combination.\n\n```\nThe question tool of your agent (`AskUserQuestion`): How should the sync run?\n\nOptions:\n1. Safe — update rules already marked source: registry whose version changed (no rewrite of local modifications, no prune)\n2. Replace — also overwrite rules that are up-to-date but locally modified (no prune)\n3. Mirror — full parity with the registry: replace AND prune obsolete stack rules (equivalent to the legacy `--force`)\n```\n\n### sync.2: Run the CLI\n\n| Choice | Command |\n|--------|---------|\n| Safe    | `unikit-ai rules sync` |\n| Replace | `unikit-ai rules sync --replace` |\n| Mirror  | `unikit-ai rules sync --replace --prune` |\n\n`rules sync` does not accept `--module` — do not append it. The command reconciles\nevery module's rules in one pass.\n\nStream stdout\u002Fstderr to the user so the per-rule event log from `syncRulesState` is visible.\n\nHandle exit codes:\n\n- 0 → success, continue to sync.3.\n- 2 → registry unreachable, report stderr, stop.\n- 5 → registry validation failed, report stderr, stop.\n- other non-zero → report and stop.\n\n### sync.3: Report\n\nProduce a **compact** final report — same style as `create.7` and `update.8`. No prose paragraphs, no CLI echoes. Parse the per-rule event log from `syncRulesState` into a single table of what happened in memory, followed by one direction reminder.\n\nTable format (add a `Module` column when more than one module synced; omit it when only `code` ran):\n\n```\n| Action | Module | Tier  | Rule        | Version       |\n|--------|--------|-------|-------------|---------------|\n| add    | code   | stack | aspid-mvvm  | 1.0.0         |\n| update | code   | stack | node-canvas | 1.2.0 → 1.3.0 |\n| delete | code   | stack | odin        | —             |\n```\n\n- One row per rule touched in `.unikit\u002Fmemory\u002F`. Group by action in the order: `add`, `update`, `delete`. Do not include `skip` rows — on sync they are noise.\n- `Version` column: for `add` shows the installed version; for `update` shows `old → new`; for `delete` shows `—`.\n- If the registry ships reference files under `references\u002F`, add a single trailing line: `+ N reference files refreshed` (omit if zero).\n- If `RULES_INDEX.md` was regenerated, print one line: `✅ RULES_INDEX.md: regenerated`.\n\nAfter the table, print exactly one reminder (adapt to the configured language):\n\n- `\u002Funikit-rules-registry update` — push local edits from `.unikit\u002Fmemory\u002F` back into the registry (opposite direction of this run).\n\n---\n\n## Access Rules\n\n**Writable** (this skill may create and edit these, strictly inside the registry target path):\n- `\u003Cregistry-path>\u002F\u003Cmodule>\u002F\u003Cengine>\u002F\u003Ctier>\u002F**` (engine-partitioned modules) or `\u003Cregistry-path>\u002F\u003Cmodule>\u002F\u003Ctier>\u002F**` (non-engine modules) — rule files and any nested reference files (e.g. `references\u002F*.md`)\n- `\u003Cregistry-path>\u002Fmanifest.json` (only as a side effect of running `build-manifest.js`)\n\n**Deletable** (update mode only, under the conditions below):\n- A tier's `references\u002F*.md` — reference files. Only when the reference-graph check in `update.6b` proves the file is not referenced by any rule in memory or in the registry (shared-reference protection).\n- Rule `.md` files in the registry are **never** deleted by update — rule removal is a manual operation in the registry repository.\n\n**Read-only** (this skill MUST NEVER modify these files directly via Write\u002FEdit):\n- `.unikit\u002Fmemory\u002F**` — owned by `unikit-memory`. Mutated only indirectly when `unikit-ai rules install --force` re-fetches registry copies in `update.7b`.\n- `.unikit.json` — mutated only via `unikit-ai rules registry set` \u002F `unikit-ai rules registry reset` \u002F `unikit-ai rules install --force`.\n- `.unikit\u002Fsystem\u002Fcli-contract.md` — regenerated by the build pipeline\n- `.unikit\u002Fsystem\u002Fmodules.yml` — module registry snapshot, regenerated by the build pipeline\n- `.unikit\u002Fconfig.yaml` — project settings\n\nEach mode ends at its own per-mode report (`create.7`, `update.8`, `sync.3`). Do not add a second summary on top of them, and never auto-invoke another skill.\n","# UniKit Rules Registry — External Registry Orchestrator\n\nManage the external rules registry lifecycle from the project side. This skill owns three modes:\n\n- **create** — scaffold a new local registry repository, seed it with rules currently in `.unikit\u002Fmemory\u002F`, and optionally switch the project to use it.\n- **update** — diff `.unikit\u002Fmemory\u002F` against the currently configured **local** registry and push changes back (new rules, content updates with automatic semver bumps, stale deletions).\n- **sync** — pull registry-side updates into `.unikit\u002Fmemory\u002F` via `unikit-ai rules sync` (direction: registry → memory).\n\nDirection matters:\n- `create` and `update` flow **memory → registry**.\n- `sync` flows **registry → memory**.\n\nThe skill is **module-agnostic**: the knowledge base is partitioned into top-level\nmodules (`.unikit\u002Fmemory\u002F\u003Cmodule>\u002F\u003Ctier>`), and this skill iterates over the\nmodules registered in `.unikit\u002Fsystem\u002Fmodules.yml`. It never hardcodes a module\nid, a tier name, or a registry layout — those come from `modules.yml`.\n\n**User questions.** Right before your first question to the user, not earlier, read `.unikit\u002Fsystem\u002Fuser-questions.md` once and ask every question as it says, with the question tool of your agent (`AskUserQuestion`). If the file cannot be read, print `WARN [questions] user-questions contract missing — asking with the question tool` and still ask with that tool, the recommended option first.\n\n## Boundaries\n\n**This skill MUST NOT:**\n- Write to `.unikit.json` directly via the `Write`\u002F`Edit` tools. All config mutations go through CLI commands: `unikit-ai rules registry set` \u002F `rules registry reset` in create mode, and `unikit-ai rules install ... --force` in update mode (`update.7b`).\n- Edit or create files inside `.unikit\u002Fmemory\u002F` directly via the `Write`\u002F`Edit` tools. Memory sources are authored by `unikit-memory` and `unikit-rules`; this skill may only cause indirect memory writes by delegating to `unikit-ai rules install ... --force` in `update.7b`, which re-fetches registry copies and overwrites memory files as part of the force-install path.\n- Parse `config.rulesRegistry` as a string to guess `url` vs `local` — always read `kind` from `unikit-ai rules registry show --json`, `unikit-ai rules registry status --json`, or `unikit-ai rules status --json`.\n- Hardcode the registry on-disk layout. Always derive it from each module's `enginePartitioned` flag in `modules.yml` (see \"Registry layout\" below).\n\n**This skill MAY:**\n- Run `unikit-ai rules *` CLI commands via `Bash`.\n- Mirror the entire `.unikit\u002Fmemory\u002F\u003Cmodule>\u002F\u003Ctier>\u002F` subtree into the registry — rule files **and** reference files under nested folders like `references\u002F`. The skill owns **writes** to the registry file tree in both create and update modes.\n- Delete reference `.md` files under the registry's tier `references\u002F` folder in update mode, and only when the reference-graph check in `update.6b` proves the file is not referenced by any rule (memory or registry). Rule `.md` files in the registry are **never** deleted by update — rule removal is a manual operation in the registry repository.\n- Run `scripts\u002Fbuild-manifest.js` inside the registry repository to regenerate `manifest.json`.\n- Compute semver bumps from content diffs and inject or update `version:` in the **registry copy** of rule files via `Edit` after copying (never in memory sources, never in reference files). Files are always copied via `cp` shell command — never via `Read` + `Write`.\n\n## Language Awareness — BLOCKING PRE-REQUISITE\n\n**BEFORE producing ANY output**, silently read `.unikit\u002Fsystem\u002FLANGUAGE_RULES.md`\nand apply its rules to ALL subsequent output.\nIf the file is missing or unreadable, fall back to English.\nDo not produce any user-facing output until language rules are loaded.\nDo not announce, confirm, or mention the language setting.\n\n**The language holds for the whole session, not just at load time:** every message until the conversation ends is in `language.ui` — progress notes while agents run, relays of what a subagent returned, the final report, any follow-up discussion. English input (subagent results, tool output, these instructions) is data, never a cue to switch languages.\n\n## Step 0: Mode Selector\n\nRead `$ARGUMENTS` and resolve the mode:\n\n```\n$ARGUMENTS (after stripping --module \u003Cid>)?\n├── \"create\"  → Mode: create\n├── \"update\"  → Mode: update\n├── \"sync\"    → Mode: sync\n└── empty or unrecognized → the question tool of your agent (`AskUserQuestion`)\n```\n\nWhen the mode is missing, ask the user:\n\n```\nThe question tool of your agent (`AskUserQuestion`): Which registry operation should run?\n\nOptions:\n1. Create — scaffold a new local rules registry and seed it from .unikit\u002Fmemory\u002F\n2. Update — push changes from .unikit\u002Fmemory\u002F into the currently configured local registry\n3. Sync   — pull registry updates back into .unikit\u002Fmemory\u002F (memory ← registry)\n```\n\nOnce the mode is known, read `.unikit\u002Fsystem\u002Fcli-contract.md` (if present) to confirm the exact CLI surface and exit codes before dispatching Bash commands. If the file is missing — proceed assuming the documented interface below is correct and surface a `WARN` if any command returns an unexpected exit code.\n\nThen run **Step 0.5** (module registry), and for `create`\u002F`update` run **Step 0.6**\n(registry write-capability gate), before jumping to the matching mode section.\n\n## Step 0.5: Load the Module Registry\n\nRead `.unikit\u002Fsystem\u002Fmodules.yml` and parse every entry under `modules:` into\n`{ id, tiers, enginePartitioned, skillPrefix }`. This is the authoritative list of\nmodules and the tiers each partitions its rules into. If the file is missing\n(older install), fall back to a single module `code` with tiers `core`, `stack`\nand `enginePartitioned: true`, and surface a `WARN` suggesting `unikit-ai update`\nto regenerate it.\n\nThis skill needs only the **structural** fields here (`tiers`, `enginePartitioned`)\nto mirror the on-disk layout. A module's tier **semantics** and file\u002Fformat\ncontract are documented separately in\n`{{skills_dir}}\u002Funikit-memory\u002Freferences\u002Fmodule-\u003Cid>.md` (owned by the\n`unikit-memory` router) — consult it if you need to understand what a tier holds,\nnever to derive registry paths.\n\n**Resolve the target modules** (the policy mirrors `--engine`):\n\n1. **Explicit `--module \u003Cid>`** in `$ARGUMENTS` → validate against the parsed ids.\n   Valid → operate on that single module; strip the flag. Invalid → ask via\n   the question tool of your agent (`AskUserQuestion`) (options = registered module ids), then use the chosen id.\n   Print the module ids with their one-line domain summaries to the screen as plain\n   markdown first.\n2. **No flag, neutral operation** (a plain create\u002Fupdate\u002Fsync) → operate on **all**\n   registered modules (read from `modules.yml`).\n3. **Context narrows to one module ambiguously** (e.g. the prompt clearly targets\n   one module but another is plausible) → ask via the question tool of your agent (`AskUserQuestion`) (options =\n   registered module ids + \"all modules\"). Never guess.\n   Print the module ids with their one-line domain summaries to the screen as plain\n   markdown first.\n\nEverywhere below, \"for each module\" means \"for each resolved target module\", and\n\"for each tier\" means \"for each tier of that module from `modules.yml`\".\n\n**Registry layout** (schema:2, derived per module from `enginePartitioned`):\n\n- Engine-partitioned module (e.g. `code`): `\u003CregistryPath>\u002F\u003Cmodule>\u002F\u003Cengine>\u002F\u003Ctier>`\n- Non-engine module (e.g. a future `gamedesign`): `\u003CregistryPath>\u002F\u003Cmodule>\u002F\u003Ctier>`\n\nThe tier's reference subfolder is `\u003Cthat tier path>\u002Freferences\u002F`. Memory sources\nalways live at `.unikit\u002Fmemory\u002F\u003Cmodule>\u002F\u003Ctier>\u002F`. Never hardcode these — assemble\nthem from the module id, its `enginePartitioned` flag, the resolved engine, and the\ntier.\n\n\u003C!-- unikit:extension-point:bootstrap -->\n\n## Step 0.6: Registry Write-Capability Gate (create \u002F update only)\n\nWrite modes must confirm the target registry is reachable, on the latest schema,\nand writable **before** seeding or pushing. `sync` skips this gate entirely — it is\nregistry → memory and relies on its own `rules sync` exit codes (2\u002F5).\n\nRun against the target registry (the configured registry for `update`; for\n`create`, run it after `create.2` against the scaffold target path):\n\n```bash\nunikit-ai rules registry status --json\n```\n\nThe JSON has six facts: `{ target, kind, schema, isLatestSchema, readable, writable }`.\nExit codes: `0` (reachable, schema ≤ latest), `2` (unreachable), `5` (unsupported\nschema > latest). Branch on the result:\n\n| Condition | Verdict | Action |\n|-----------|---------|--------|\n| exit 2 \u002F `schema == null` | unreachable | Report `registry unreachable` and **stop**. A write mode cannot proceed against a registry it cannot read. |\n| exit 5 \u002F `readable == false` (schema > latest) | unsupported schema | Report `registry schema is newer than this CLI — upgrade unikit-ai`, then **stop**. |\n| `kind == \"local\"` and `isLatestSchema == false` | local, behind latest schema | Offer to migrate: the question tool of your agent (`AskUserQuestion`) → run `unikit-ai rules registry migrate \u003Ctarget>` on yes, then **re-run `rules registry status --json`** and re-evaluate. On no → **stop** (writing schema:2 layout into a schema:1 registry would corrupt it). |\n| `kind == \"remote\"` and `isLatestSchema == false` | outdated remote | `migrate` cannot write a remote registry. Report that the user must clone the registry, run `rules registry migrate` on the clone, open a PR upstream, then point the project at a writable copy. **Stop.** |\n| `kind == \"remote\"` and `isLatestSchema == true` | remote, read-only via CLI | A write mode needs a local registry. For `update`, this duplicates the `update.1` guard — report `update requires a local registry` and **stop**. (create scaffolds a fresh local target, so this row should not occur there.) |\n| `kind == \"local\"` and `isLatestSchema == true` (`writable == true`) | up to date and writable | Proceed to the mode body. |\n\nOnly continue into the create-seed \u002F update-diff steps when the gate resolves to\n**writable** (`kind == \"local\"` and `isLatestSchema == true`).\n\n---\n\n## Mode: create\n\nScaffold a new local registry and seed it with the rules currently installed in `.unikit\u002Fmemory\u002F`.\n\n### create.1: Ask for target path\n\n```\nThe question tool of your agent (`AskUserQuestion`): Where should the new rules registry be created?\n\nOptions:\n1. Project subfolder — .\u002Frules-registry\n2. Custom path — I will ask next (relative or absolute)\n3. Cancel\n```\n\n- Option 1 → `pathArg = \".\u002Frules-registry\"`. Pass this verbatim to the CLI in `create.2`. `rulesRegistryInitCommand` in `src\u002Fcli\u002Fcommands\u002Frules.ts` resolves it against `process.cwd()` and auto-creates the target directory via `fs.ensureDir`.\n- Option 2 → ask for the path in a message of your own, with no options. Trim the input; if the result is empty, ask again the same way. Then compute the absolute path via `path.resolve(\u003Ccwd>, \u003Ctrimmed-input>)` **for display only** and ask a second question with the question tool of your agent (`AskUserQuestion`) of this shape:\n  - Question: `Target directory will be: \u003Cresolved-absolute-path>. Proceed?`\n  - Options: `Yes, proceed` \u002F `No, enter a different path` \u002F `Cancel`\n  - Yes → use the original (pre-resolve) input string as `pathArg` in `create.2`.\n  - No → loop back to the text-input prompt.\n  - Cancel → stop the skill.\n- Option 3 → stop the skill.\n\nDo **not** pre-check path existence, expand `~`, normalize the path, or reject relative paths on the skill side. `rulesRegistryInitCommand` is the single authority on path validation: it calls `path.resolve(cwd, pathArg)` itself, auto-creates missing directories via `fs.ensureDir`, and signals problems through exit codes 3 (INVALID_ARGS), 6 (REGISTRY_ALREADY_INITIALIZED), and 7 (PATH_OCCUPIED) — all handled in `create.2` below.\n\n### create.2: Scaffold the registry\n\nRun:\n\n```bash\nunikit-ai rules registry init \u003Ctarget-path>\n```\n\nExit-code handling:\n\n| Exit | Meaning | Action |\n|------|---------|--------|\n| 0 | Scaffold OK | Continue to create.2b |\n| 3 | INVALID_ARGS (relative path, etc.) | Report stderr and stop |\n| 5 | VALIDATION_FAILED (build-manifest.js failed) | Report stderr and stop |\n| 6 | REGISTRY_ALREADY_INITIALIZED | Ask with the question tool of your agent (`AskUserQuestion`): `Reuse the existing scaffold and continue` (Recommended) · `Stop` → reuse proceeds to create.2b, stop ends the skill |\n| 7 | PATH_OCCUPIED | Report `target path is not empty and is not a registry`, stop |\n| other | Unexpected | Report stderr and stop |\n\n### create.2b: Write-capability gate on the scaffold\n\n`registry init` creates a fresh schema:2 scaffold, but on the **reuse** path (exit 6)\nthe existing directory may be a schema:1 registry. Run the **Step 0.6** gate against\n`\u003Ctarget-path>` now. A freshly-initialized target resolves to writable immediately;\na reused schema:1 target routes through the migrate offer. Only continue to\n`create.3` when the gate resolves to writable.\n\n### create.3: Resolve current engine\n\n```bash\nunikit-ai rules status --json\n```\n\nParse the JSON and read `.engine`. Never open `.unikit.json` directly — the CLI is the source of truth.\n\nIf the CLI exits non-zero (project not initialized), stop the skill with an ERROR referencing `unikit-ai init`.\n\n### create.4: Seed registry with memory rules\n\nFor each **module** (Step 0.5) and each **tier** of that module:\n\n1. Use `Glob: .unikit\u002Fmemory\u002F\u003Cmodule>\u002F\u003Ctier>\u002F**\u002F*` to enumerate the **entire subtree** — not just top-level `*.md`. This captures nested folders like `references\u002F` that hold reference files referenced by rule headers (quickrefs, catalogs, indexes).\n2. For every file discovered:\n   - Compute `relPath` relative to `.unikit\u002Fmemory\u002F\u003Cmodule>\u002F\u003Ctier>\u002F`.\n   - Target path = `\u003Ctier-registry-path>\u002F\u003CrelPath>`, where `\u003Ctier-registry-path>` is the schema:2 layout from Step 0.5 (`\u003Ctarget-path>\u002F\u003Cmodule>\u002F\u003Cengine>\u002F\u003Ctier>` for engine-partitioned modules, `\u003Ctarget-path>\u002F\u003Cmodule>\u002F\u003Ctier>` otherwise).\n   - **Classify the file:**\n     - **Top-level rule file** (`relPath` contains no `\u002F`, extension `.md`) → copy via shell, then inject version into the **registry copy only** if absent:\n       1. `Bash: mkdir -p \"$(dirname \"\u003Ctarget>\")\" && cp \"\u003Csrc>\" \"\u003Ctarget>\"`\n       2. `Bash: grep -q \"^version:\" \"\u003Ctarget>\"` — if exit 1 (not found), use `Edit` to insert `version: 1.0.0` into the frontmatter of `\u003Ctarget>`. The source in `.unikit\u002Fmemory\u002F` stays untouched.\n     - **Reference file** (anything under a subdirectory, or non-`.md` extension) → copy via shell verbatim. Never touch frontmatter — reference files are plain docs and must travel with their parent rule as-is:\n       1. `Bash: mkdir -p \"$(dirname \"\u003Ctarget>\")\" && cp \"\u003Csrc>\" \"\u003Ctarget>\"`\n3. If the tier directory yields zero files, continue silently.\n\nTrack per-module\u002Fper-tier totals: `rulesCopied` (top-level rule files) and `referencesCopied` (everything else). These feed the final table in `create.7`.\n\nWhy recursive: rule files reference reference files via `> **References**:` headers. A seed that copies only `*.md` at the top level would publish rules pointing at paths that do not exist in the registry. Mirroring the full tree keeps the references intact.\n\n### create.5: Regenerate registry manifest\n\n```bash\nnode \u003Ctarget-path>\u002Fscripts\u002Fbuild-manifest.js\n```\n\n- On non-zero exit: print stderr, stop the skill, and advise the user to inspect the rule files — the most common cause is missing `> **Load when**:` blocks or invalid frontmatter.\n- On success: continue.\n\n### create.6: Offer to switch the project registry\n\nThe scaffold mirrors `.unikit\u002Fmemory\u002F` bit-for-bit on disk — content-wise the new registry agrees with memory. But the **state metadata** in `.unikit.json.rules.installed` still points at the old provenance: every rule entry is tagged with its original `source` (`installer` \u002F `registry`) and `origin` (`official` \u002F old primary). Flipping `rulesRegistry` alone does not rewrite those tags, so the project would still look like it is \"using the old registry\" on the next `rules status --json`.\n\nTo make the switch complete, the skill pairs `registry set` with a follow-up `rules sync --replace --prune`. `--replace` bypasses the `source !== 'registry'` guard in `syncRulesState` so installer-sourced rules get walked; the sync loop rewrites `source`, `version`, `installed_hash`, and `origin` (via `HybridRegistry.getResolvedOrigin()`) against the new primary registry. `--prune` removes obsolete stack rules that are not in the new manifest. The HARD GUARD in `syncRulesState` still prevents discovery of previously-uninstalled rules — only already-installed entries get reclassified.\n\n```\nThe question tool of your agent (`AskUserQuestion`): Switch the current project to this new registry now?\n\nOptions:\n1. Yes — point .unikit.json at the new registry and reclassify installed rules as primary\n2. No — keep the current registry\n```\n\nMapping to CLI commands (order matters — `registry set` must succeed before `sync` runs):\n\n| Choice | Commands |\n|--------|----------|\n| 1 | `unikit-ai rules registry set \u003Ctarget-path>` then `unikit-ai rules sync --replace --prune` |\n| 2 | (skip — do not touch `.unikit.json`) |\n\nExit-code handling:\n\n- `rules registry set` exit 3 (INVALID_ARGS) or 5 (VALIDATION_FAILED) → report stderr and stop the skill. Do **not** run `rules sync`; the URL has not been written.\n- `rules sync --replace --prune` exit 2 (NETWORK — local path disappeared between the two commands) or 5 (VALIDATION_FAILED — registry manifest broken) → report stderr and warn the user that `.unikit.json.rulesRegistry` has already been rewritten to the new path, but rule metadata is still on the old provenance. Instruct them to fix the registry and re-run `unikit-ai rules sync --replace --prune` manually. Do not attempt to roll back `registry set` automatically.\n- Both commands exit 0 → continue to `create.7`.\n\nStream stdout\u002Fstderr of both commands to the user so the per-rule event log from `syncRulesState` is visible.\n\n### create.7: Report\n\nProduce a **compact** final report — no prose paragraphs, no step-by-step narrative, no CLI echoes. Just one table of the rules that were transferred, followed by two direction reminders. Anything longer than a dozen lines means you are over-reporting.\n\nTable format (add a `Module` column when more than one module was seeded; omit it when only `code` ran):\n\n```\n| Module | Tier  | Rule              | Version |\n|--------|-------|-------------------|---------|\n| code   | core  | folders-structure | 1.0.0   |\n| code   | core  | code-style        | 1.0.0   |\n| code   | stack | aspid-mvvm        | 1.0.0   |\n| code   | stack | node-canvas       | 1.0.0   |\n```\n\n- One row per top-level rule file copied (the files counted by `rulesCopied`).\n- Do not list reference files individually — mention them only as a single trailing line: `+ N reference files under references\u002F` (omit the line if `referencesCopied == 0`).\n- Version column shows the version that ended up in the registry copy (either the existing frontmatter value or the injected `1.0.0`).\n\nAfter the table, print exactly these two reminders (adapt to the configured language):\n\n- `\u002Funikit-rules-registry update` — push later local edits from `.unikit\u002Fmemory\u002F` into this registry.\n- `\u002Funikit-rules-registry sync` — pull registry-side updates back into `.unikit\u002Fmemory\u002F` (opposite direction).\n\nIf the project was switched to the new registry in `create.6`, add exactly two lines after the reminders:\n\n- `✅ rules registry set: \u003Ctarget-path>`\n- `✅ rules sync --replace --prune: N rules reclassified as primary`\n\n`N` is the number of rules touched by the sync — count the `phase2:updating` events from the `syncRulesState` event log (every such event flips one rule's `source`\u002F`origin` to the new primary). If the switch was declined, add nothing.\n\n---\n\n## Mode: update\n\nPush changes from `.unikit\u002Fmemory\u002F` into the currently configured **local** registry and regenerate its manifest.\n\n### update.1: Verify registry kind\n\n```bash\nunikit-ai rules registry show --json\n```\n\nParse JSON fields `configured`, `url`, `kind`.\n\n- `kind` is not `\"local\"` → ERROR: `update requires a local registry — run \u002Funikit-rules-registry create first`. Stop.\n- `configured` is `false` → ERROR: `no registry configured`. Stop.\n- Otherwise: `registryPath = \u003Curl>`.\n\n### update.1b: Write-capability gate\n\nRun the **Step 0.6** gate against `registryPath`. If the registry is local but\nbehind the latest schema, this routes through the `rules registry migrate` offer —\ncritical, because writing schema:2 layout (`\u003Cmodule>\u002F\u003Cengine>\u002F\u003Ctier>`) into a\nschema:1 registry (`\u003Cengine>\u002F\u003Ctier>`) would corrupt the layout and break\n`build-manifest.js`. Only continue to `update.2` when the gate resolves to writable.\n\n### update.2: Resolve engine\n\n```bash\nunikit-ai rules status --json\n```\n\nRead `.engine`. Abort on non-zero exit.\n\n### update.3: Diff memory vs registry\n\nFor each **module** (Step 0.5) and each **tier** of that module:\n\n1. `Glob: .unikit\u002Fmemory\u002F\u003Cmodule>\u002F\u003Ctier>\u002F**\u002F*` — walk the full subtree so reference files under `references\u002F` (and any other nested folders) are diffed alongside their parent rules.\n2. For every file `src` found in memory, compute `relPath` relative to `.unikit\u002Fmemory\u002F\u003Cmodule>\u002F\u003Ctier>\u002F` and classify it:\n   - **Rule file** if `relPath` has no `\u002F` and ends with `.md` (top-level markdown).\n   - **Reference file** otherwise (nested file, or non-`.md`). Reference files carry no `version:` frontmatter — they travel with their parent rule as plain content.\n3. For every `src`:\n   - target = `\u003Ctier-registry-path>\u002F\u003CrelPath>` (schema:2 layout from Step 0.5)\n   - If target does not exist → mark as **add**.\n   - Else run `Bash: diff -q --strip-trailing-cr \"\u003Csrc>\" \"\u003Ctarget>\"`:\n     - exit 0 → identical, **skip**.\n     - exit 1 → differs, continue to bump classification (rule files only) or mark as **reference-update** (reference files).\n     - other exit → report and stop.\n4. Walk the registry side the same way: `Glob: \u003Ctier-registry-path>\u002F**\u002F*`. Any file present in the registry but not in memory becomes a **delete** candidate (handled in update.5). Tag each orphan as rule vs reference file so the prompt can display them in two groups.\n\n**Why recursive:** rule files reference reference files via `> **References**:` headers. If `update` diffs only top-level `*.md`, edits to reference docs (quickrefs, full catalogs) silently stay behind and the registry drifts out of sync with the project's actual knowledge base. Walking the subtree is the simplest way to guarantee every referenced file reaches the registry.\n\n### update.4: Classify bumps for `differs` rule files\n\nReference files (`reference-update` from update.3) have no frontmatter version to bump — skip this step for them and handle them directly in update.6.\n\nFor every `differs` **rule file**, run `Bash: diff -u --strip-trailing-cr \"\u003Csrc>\" \"\u003Ctarget>\"`. Parse the output:\n\n- `added = number of lines starting with \"+\" excluding the \"+++\" header`\n- `removed = number of lines starting with \"-\" excluding the \"---\" header`\n- `oldTotal = wc -l of \u003Ctarget>` (used for the `removed > 30% oldTotal` rule)\n\nApply the heuristic **in order** — the first matching row wins:\n\n| Condition | Bump |\n|-----------|------|\n| `removed > 0.3 * oldTotal` | **major** |\n| `removed == 0` AND `added \u003C= 5` | **patch** |\n| `removed == 0` AND `added > 5` | **minor** |\n| `removed \u003C= 3` AND `added \u003C= 10` | **patch** |\n| `removed > 3` AND `added > removed` | **minor** |\n| otherwise | **patch** |\n\nCompute the new version:\n\n- Read the current `version:` from the target file's frontmatter (if missing, assume `1.0.0`).\n- Apply the bump:\n  - `patch` → `x.y.(z+1)`\n  - `minor` → `x.(y+1).0`\n  - `major` → `(x+1).0.0`\n- This heuristic is fully automatic — do **not** ask the user to approve each bump.\n\n### update.5: Collect orphan rule files (informational)\n\nUpdate is **strictly push-only** for rule files — it never removes them from the registry. For every rule `.md` file present in the registry and missing from memory (i.e. top-level `*.md` under `\u003Ctier-registry-path>` with no counterpart in `.unikit\u002Fmemory\u002F\u003Cmodule>\u002F\u003Ctier>\u002F`), append `{ module, tier, filename }` to an `orphanRuleFiles` list. That list is consumed purely by `update.8` as a WARN block — no prompt, no delete, no cascade.\n\nDo **not** walk reference files under `references\u002F` here. Reference file reconciliation is a separate concern handled in `update.6b` via the real `rule → references` graph; orphan detection at the file level would miss shared reference files and produce false positives.\n\nIf `orphanRuleFiles` is empty after the walk, the WARN block is skipped entirely in `update.8`.\n\n### update.6: Apply changes\n\nFor each **rule file** `add`:\n- Copy via shell, then inject version into the **registry copy only** if absent:\n  1. `Bash: mkdir -p \"$(dirname \"\u003Ctarget>\")\" && cp \"\u003Csrc>\" \"\u003Ctarget>\"`\n  2. `Bash: grep -q \"^version:\" \"\u003Ctarget>\"` — if exit 1 (not found), use `Edit` to insert `version: 1.0.0` into the frontmatter of `\u003Ctarget>`. The source in `.unikit\u002Fmemory\u002F` stays untouched.\n\nFor each **rule file** `differs`:\n- Copy via shell, then replace the version in the **registry copy**:\n  1. `Bash: cp \"\u003Csrc>\" \"\u003Ctarget>\"`\n  2. Use `Edit` to replace the `version:` line in `\u003Ctarget>` with the bumped version from update.4 (insert if absent). The source in `.unikit\u002Fmemory\u002F` stays untouched.\n\nFor each **reference file** `add` or `reference-update`:\n- Copy via shell verbatim. Do not inject or alter any frontmatter — reference files are plain docs and must reach the registry byte-identical to the memory source (modulo the path):\n  1. `Bash: mkdir -p \"$(dirname \"\u003Ctarget>\")\" && cp \"\u003Csrc>\" \"\u003Ctarget>\"`\n\nTrack `touchedRuleFiles = [...]` — every rule file classified as `add` or `differs` in this step, stored as `{ module, tier, ruleId }` (ruleId = filename without `.md`). This list is consumed by `update.7b` to drive the post-write `rules install --force` batch. Reference files are **not** tracked — `installOneRule` re-fetches a parent rule's declared references automatically during force install.\n\nThere is **no `delete` branch** in this step — update never removes rule files from the registry (see `## Boundaries`). Companion deletions happen separately in `update.6b` via the reference-graph check; that step runs after all writes here so it sees the final set of registry files.\n\nAll writes happen inside the registry tree only — never touch memory sources.\n\n### update.6b: Reference file cleanup (reference-graph based)\n\nReconcile reference files in the registry against the real `rule → references` graph. Remove any reference `.md` under a tier's `references\u002F` folder that no rule (in memory or in the registry) references anymore. The algorithm covers four scenarios:\n\n| Scenario | `referencedByAnyone`? | Action |\n|----------|----------------------|--------|\n| Parent rule dropped a ref, nobody else holds it | No | Delete |\n| Shared — another memory rule still references it | Yes | Keep (protected) |\n| Orphan parent rule in registry still references it | Yes | Keep (protected) |\n| Zombie — no rule references it anywhere | No | Delete |\n\nRun the algorithm **per module + per tier** — each `\u003Cmodule>\u002F\u003Ctier>` is an independent namespace and never shares reference filenames across the divide.\n\nFor each module + tier:\n\n1. Initialise `referencedByAnyone` as an empty `Set\u003Cstring>` of reference filenames.\n2. Walk `\u003Ctier-registry-path>\u002F*.md` (top-level rule files only — do not recurse into `references\u002F` here). For every rule file found:\n   - Let `ruleId = basename without .md`.\n   - If `.unikit\u002Fmemory\u002F\u003Cmodule>\u002F\u003Ctier>\u002F\u003CruleId>.md` exists → `parseTarget = memory` (memory wins for rules present in both).\n   - Else → `parseTarget = registry` (orphan parent rule — protect its own references using the on-disk registry header).\n   - Read the chosen file, locate the `> **References**:` header line, and extract every reference filename with the regex `references\\\u002F([^\\s,)]+\\.md)\u002Fg`. This is the exact regex used by `rules-registry\u002Fscripts\u002Fbuild-manifest.js` — stay byte-for-byte aligned so `update.6b` and the manifest rebuild in `update.7` never disagree about what is referenced.\n   - Add every extracted filename to `referencedByAnyone`.\n3. Enumerate physical reference files: `Glob: \u003Ctier-registry-path>\u002Freferences\u002F*.md` → `physical` (set of filenames only, strip paths).\n4. Compute `safeToDelete = physical \\ referencedByAnyone` (set difference by filename).\n5. For every filename in `safeToDelete`:\n   - `Bash: rm \"\u003Ctier-registry-path>\u002Freferences\u002F\u003Cfilename>\"` (single-file delete, never recursive, never glob).\n   - Append `{ module, tier, filename }` to a top-level `deletedReferences` list consumed by `update.8`.\n\nDocumented edge cases (**not** special-cased — the algorithm handles them naturally):\n\n- **Memory rule without a `> **References**:` header.** The regex returns an empty set for that rule. If nobody else references its former reference files, they become part of `safeToDelete`. This is the user's explicit intent — removing the header is the signal.\n- **Header contains a dangling filename** (names a file that does not physically exist). The filename still joins `referencedByAnyone`, so the delete check stays consistent with manifest generation. Nothing is fabricated — this step only deletes.\n- **Two rules in the same tier with identical references** — the set union on `referencedByAnyone` handles this: a shared file is recorded once and protected by both rules.\n\nThis step runs **before** `update.7` — the manifest rebuild must see the final physical layout of `references\u002F`, otherwise it would list reference filenames that no longer exist on disk.\n\n### update.7: Regenerate registry manifest\n\n```bash\nnode \u003CregistryPath>\u002Fscripts\u002Fbuild-manifest.js\n```\n\nOn non-zero exit: print stderr, stop the skill. The most common cause is a rule missing `> **Load when**:` or invalid frontmatter; the user must fix the rule source in `.unikit\u002Fmemory\u002F` (via `\u002Funikit-memory`) before re-running `\u002Funikit-rules-registry update`.\n\n### update.7b: Reconcile project state after registry bumps\n\n`update.6` wrote new and bumped rule files into the registry, but `.unikit.json.rules.installed[...]` still points at the pre-update `version` and `installed_hash` for every touched rule. Without reconciliation:\n\n- `unikit-ai rules status` will lie about installed versions.\n- The next `unikit-ai rules sync` (Safe mode) will mark disk files as `locally-modified` and **skip** the version update, so the drift never heals on its own.\n\nForce-install every touched rule in a single variadic CLI call. Reference files are **not** listed — `installOneRule` re-fetches a parent rule's declared references automatically during force install.\n\n1. Collect `installTargets = [ruleId for each entry in touchedRuleFiles]`, deduplicated. Read the list tracked in `update.6`.\n2. If `installTargets` is empty → **skip this step entirely**. No rule file changed in this run, so there is nothing to reconcile.\n3. Otherwise run one variadic invocation:\n\n   ```bash\n   unikit-ai rules install \u003Cid1> \u003Cid2> ... --force\n   ```\n\n   Stream stdout\u002Fstderr to the user so the per-rule report (`✓ installed …`, `↻ already installed …`, `✗ failed …`) surfaces as events occur.\n\n4. Exit-code handling:\n\n   | Exit | Meaning | Action |\n   |------|---------|--------|\n   | 0 | At least one rule installed (aggregated report may still contain `failed` rows) | Parse the report, forward any failures into `update.8` as a WARN block, continue |\n   | 2 | NETWORK — registry chain unreachable | Report stderr and stop the skill |\n   | 4 | NOT_FOUND — every rule failed | Capture the aggregated report, continue to `update.8` and surface as a WARN block; **do not** roll back `update.6` writes |\n   | 5 | VALIDATION_FAILED — registry manifest broken | Report stderr and stop the skill |\n   | other | Unexpected | Report stderr and stop the skill |\n\n   Do **not** attempt to roll back the writes `update.6` already made to the registry. The registry-side update has already succeeded; partial install failures are recoverable by re-running `unikit-ai rules install \u003Cid> --force` manually against specific ids once the root cause is fixed.\n\n`installOneRule` with `force=true` covers all three state branches deterministically:\n\n- **Existing entry with `source: registry` and stale version** → in-place update of `source`, `version`, `installed_hash`, `origin`.\n- **Existing entry with `source: local`** → transition to `source: registry, version: \u003Cfrom registry>` (first-time publication path). This is how a rule that was previously authored locally and just pushed to the registry in this run becomes \"owned\" by the registry in `.unikit.json`.\n- **No existing entry** → push a new entry with `source: registry, version: \u003Cfrom registry>`.\n\nA free bonus: `rulesInstallCommand` always regenerates `RULES_INDEX.md` at the end of its invocation, so the skill does not need a separate index refresh after this step.\n\n### update.8: Report\n\nProduce a **compact** final report — same style as `create.7`. No prose paragraphs, no step-by-step narrative, no CLI echoes. One table of rule changes, optional tallies, optional WARN blocks, one direction reminder. Anything longer than a dozen lines (plus WARN blocks, which can grow if the situation warrants) means you are over-reporting.\n\nTable format (add a `Module` column when more than one module was pushed; omit it when only `code` ran):\n\n```\n| Action | Module | Tier  | Rule        | Version       |\n|--------|--------|-------|-------------|---------------|\n| add    | code   | stack | aspid-mvvm  | 1.0.0         |\n| update | code   | stack | node-canvas | 1.2.0 → 1.3.0 |\n| skip   | code   | core  | code-style  | 1.1.0         |\n```\n\n- One row per top-level rule file touched. Rows are grouped by action in the order: `add`, `update`, `skip`. Omit the `skip` rows entirely if every unchanged rule would otherwise bloat the table — keep them only when useful for verification.\n- There is **no `delete` row for rule files** — update is strictly push-only for `.md` rule files (see `## Boundaries`). A rule that only exists in the registry surfaces in the orphan WARN block below, never as a table row.\n- `Version` column: for `add` and `skip` shows the current registry version; for `update` shows `old → new`.\n- Do not list reference files in the main table. Add a single trailing line directly under the table: `+ N reference files: X added · Y updated · Z deleted · W unchanged` (omit the line if all four counts are zero). `Z` comes from the `deletedReferences` list populated in `update.6b`.\n- If `Z > 0`, print a separate deletion table directly under the tally line:\n\n  ```\n  | Action | Module | Tier  | File                         |\n  |--------|--------|-------|------------------------------|\n  | delete | code   | stack | aspid-mvvm-binders-full.md   |\n  | delete | code   | core  | old-reference.md             |\n  ```\n\n  Rows come from `deletedReferences`, sorted by `module`, then `tier`, then `filename`. Do not inline the list on one line — the table is both the primary signal and the full record.\n\nIf `update.5` collected any entries into `orphanRuleFiles`, print one WARN block before the final two lines. Skip the block entirely when the list is empty:\n\n```\n⚠️ WARN: registry contains orphan rule files not mirrored in .unikit\u002Fmemory\u002F:\n  - code\u002Fstack\u002Flegacy-rule.md\n  - code\u002Fcore\u002Fretired-guidelines.md\nupdate is push-only; rule deletion must be done in the registry repo directly\n(rm + scripts\u002Fbuild-manifest.js + commit).\n```\n\nIf `update.7b` surfaced any `failed` rows in the `rules install --force` report (either partial failures on exit 0 or total failure on exit 4), print a second WARN block directly after the orphan block:\n\n```\n⚠️ WARN: state reconcile partially failed — the registry was updated but these rules\nstayed on their pre-update versions in .unikit.json:\n  - stack\u002Faspid-mvvm — \u003Creason from the install report>\nRe-run `unikit-ai rules install \u003Cid>... --force` manually after fixing the cause.\n```\n\nAfter the table, the reference files tally, and any WARN blocks, print exactly these two lines (adapt to the configured language):\n\n- `✅ manifest: ok` or `❌ manifest: failed — \u003Cone-line reason>`\n- `\u002Funikit-rules-registry sync` — pull registry-side updates back into `.unikit\u002Fmemory\u002F` (opposite direction of this run).\n\n---\n\n## Mode: sync\n\nPull registry-side updates back into `.unikit\u002Fmemory\u002F` by delegating to `unikit-ai rules sync`. Direction is registry → memory (the opposite of `update`).\n\nThis mode does **not** run the Step 0.6 write-capability gate — it does not write the\nregistry. `rules sync` carries its own reachability\u002Fvalidation exit codes (2\u002F5),\nwhich `sync.2` handles. `rules sync` reconciles the whole project and does **not**\naccept `--module`; a resolved `--module \u003Cid>` does not narrow the CLI call in this\nversion (it only documents intent for the report).\n\n### sync.1: Ask about the sync intensity\n\nThe CLI exposes two composable flags that used to live behind the single `--force`:\n\n- `--replace` — overwrite rules already in state (same-version refresh AND local modifications).\n- `--prune` — remove obsolete stack rules that vanished from the manifest.\n\nThe question below maps each user choice to a concrete flag combination.\n\n```\nThe question tool of your agent (`AskUserQuestion`): How should the sync run?\n\nOptions:\n1. Safe — update rules already marked source: registry whose version changed (no rewrite of local modifications, no prune)\n2. Replace — also overwrite rules that are up-to-date but locally modified (no prune)\n3. Mirror — full parity with the registry: replace AND prune obsolete stack rules (equivalent to the legacy `--force`)\n```\n\n### sync.2: Run the CLI\n\n| Choice | Command |\n|--------|---------|\n| Safe    | `unikit-ai rules sync` |\n| Replace | `unikit-ai rules sync --replace` |\n| Mirror  | `unikit-ai rules sync --replace --prune` |\n\n`rules sync` does not accept `--module` — do not append it. The command reconciles\nevery module's rules in one pass.\n\nStream stdout\u002Fstderr to the user so the per-rule event log from `syncRulesState` is visible.\n\nHandle exit codes:\n\n- 0 → success, continue to sync.3.\n- 2 → registry unreachable, report stderr, stop.\n- 5 → registry validation failed, report stderr, stop.\n- other non-zero → report and stop.\n\n### sync.3: Report\n\nProduce a **compact** final report — same style as `create.7` and `update.8`. No prose paragraphs, no CLI echoes. Parse the per-rule event log from `syncRulesState` into a single table of what happened in memory, followed by one direction reminder.\n\nTable format (add a `Module` column when more than one module synced; omit it when only `code` ran):\n\n```\n| Action | Module | Tier  | Rule        | Version       |\n|--------|--------|-------|-------------|---------------|\n| add    | code   | stack | aspid-mvvm  | 1.0.0         |\n| update | code   | stack | node-canvas | 1.2.0 → 1.3.0 |\n| delete | code   | stack | odin        | —             |\n```\n\n- One row per rule touched in `.unikit\u002Fmemory\u002F`. Group by action in the order: `add`, `update`, `delete`. Do not include `skip` rows — on sync they are noise.\n- `Version` column: for `add` shows the installed version; for `update` shows `old → new`; for `delete` shows `—`.\n- If the registry ships reference files under `references\u002F`, add a single trailing line: `+ N reference files refreshed` (omit if zero).\n- If `RULES_INDEX.md` was regenerated, print one line: `✅ RULES_INDEX.md: regenerated`.\n\nAfter the table, print exactly one reminder (adapt to the configured language):\n\n- `\u002Funikit-rules-registry update` — push local edits from `.unikit\u002Fmemory\u002F` back into the registry (opposite direction of this run).\n\n---\n\n## Access Rules\n\n**Writable** (this skill may create and edit these, strictly inside the registry target path):\n- `\u003Cregistry-path>\u002F\u003Cmodule>\u002F\u003Cengine>\u002F\u003Ctier>\u002F**` (engine-partitioned modules) or `\u003Cregistry-path>\u002F\u003Cmodule>\u002F\u003Ctier>\u002F**` (non-engine modules) — rule files and any nested reference files (e.g. `references\u002F*.md`)\n- `\u003Cregistry-path>\u002Fmanifest.json` (only as a side effect of running `build-manifest.js`)\n\n**Deletable** (update mode only, under the conditions below):\n- A tier's `references\u002F*.md` — reference files. Only when the reference-graph check in `update.6b` proves the file is not referenced by any rule in memory or in the registry (shared-reference protection).\n- Rule `.md` files in the registry are **never** deleted by update — rule removal is a manual operation in the registry repository.\n\n**Read-only** (this skill MUST NEVER modify these files directly via Write\u002FEdit):\n- `.unikit\u002Fmemory\u002F**` — owned by `unikit-memory`. Mutated only indirectly when `unikit-ai rules install --force` re-fetches registry copies in `update.7b`.\n- `.unikit.json` — mutated only via `unikit-ai rules registry set` \u002F `unikit-ai rules registry reset` \u002F `unikit-ai rules install --force`.\n- `.unikit\u002Fsystem\u002Fcli-contract.md` — regenerated by the build pipeline\n- `.unikit\u002Fsystem\u002Fmodules.yml` — module registry snapshot, regenerated by the build pipeline\n- `.unikit\u002Fconfig.yaml` — project settings\n\nEach mode ends at its own per-mode report (`create.7`, `update.8`, `sync.3`). Do not add a second summary on top of them, and never auto-invoke another skill.\n",{"name":5,"description":7,"allowed-tools":44,"argument-hint":50},[45,46,47,48,49],"Read","Write","Bash","Glob","AskUserQuestion","[create | update | sync] [--module \u003Cid>]","main","ae3c6dfffd26d9b45b9d96d71ba2c122c50b67ae","skills\u002Funikit-rules-registry",1,"https:\u002F\u002Fgithub.com\u002FNintendaDev\u002Funikit-ai","https:\u002F\u002Funikit.nintenda.dev","https:\u002F\u002Fgithub.com\u002FNintendaDev","Unity Developer. Building games and UniKit AI","2026-11-08 15:05:51",{"source":8,"skillName":5,"commands":61,"prompt":71,"zipAvailable":72},[62,65,68],{"tool":63,"command":64},"npx","npx skills add NintendaDev\u002Funikit-ai --skill unikit-rules-registry",{"tool":66,"command":67},"bunx","bunx skills add NintendaDev\u002Funikit-ai --skill unikit-rules-registry",{"tool":69,"command":70},"pnpm","pnpm dlx skills add NintendaDev\u002Funikit-ai --skill unikit-rules-registry","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FNintendaDev\u002Funikit-ai\u002Fblob\u002Fmain\u002Fskills\u002Funikit-rules-registry\u002FSKILL.md",true,[],[75,101,126,148,168,191],{"skillNo":76,"name":77,"nameZh":6,"description":78,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":79,"categories":80,"keywords":86,"publishedAt":39},"01M71BQ00EXGX51PPCDY7VG334","unikit","Initialize the UniKit framework in a project. Scans the current project to detect the engine and real tech stack, then generates the base framework documents that give AI agents context about the project — the resolved project description, the architecture doc, AGENTS.md, and the user-editable .unikit\u002Fconfig.yaml. This is the one-time, whole-project setup run before any other unikit skill. Use whenever the user wants to initialize, set up, or onboard the framework, e.g. \"initialize unikit\", \"init the framework\", \"set up unikit\", \"set up the project\", \"configure AI context\", \"scan my project and set it up\", \"bootstrap the project\". It also actualizes the config of a project already set up — say \"update the config\", \"add missing settings\", \"actualize configuration\", \"fix my config\". On a set-up project it offers the actions to choose from.","https:\u002F\u002Fgithub.com\u002FNintendaDev\u002Funikit-ai\u002Fblob\u002Fmain\u002Fskills\u002Funikit\u002FSKILL.md",[81],{"categoryNo":82,"categoryName":83,"taxonomyType":84,"taxonomyTypeDesc":85},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[77,37,87,88,89,90,91,92,93,31,30,29,94,95,28,96,97,98,99,100],"time","actions","fix","documents","architecture","stack","run","config","edit","context","initialize","tech","scan","use",{"skillNo":102,"name":103,"nameZh":6,"description":104,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":105,"categories":106,"keywords":111,"publishedAt":39},"01M71BPRTMKW7FRAZZBN44NW5Q","unikit-verify","Verify a completed implementation against the plan in .unikit\u002Fcode\u002Fplans\u002F. Checks that every task was implemented, nothing was forgotten, the code compiles, the recorded test run still matches the code, and {{engine_name}} conventions are followed. Use after \u002Funikit-implement completes, or when the user says \"verify\", \"check the work\", \"did we miss anything\". For code review use \u002Funikit-review instead.","https:\u002F\u002Fgithub.com\u002FNintendaDev\u002Funikit-ai\u002Fblob\u002Fmain\u002Fskills\u002Funikit-verify\u002FSKILL.md",[107,110],{"categoryNo":108,"categoryName":109,"taxonomyType":84,"taxonomyTypeDesc":85},"01JBSEEDCAT000000000000007","代码审查",{"categoryNo":82,"categoryName":83,"taxonomyType":84,"taxonomyTypeDesc":85},[112,113,114,115,116,117,93,30,29,95,28,118,119,100,120,121,122,123,124,125],"unikit verify","verify","powershell","code review","phase","plan","for","system","implement","check","engine","research","name","quality",{"skillNo":127,"name":128,"nameZh":6,"description":129,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":130,"categories":131,"keywords":132,"publishedAt":39},"01M71BPM35M5ETPA4E7EKQYRWD","unikit-todo","Manage the project's TODO list in .unikit\u002FTODO.md — capture work to remember for later, not to do right now. Use it to add a deferred item, mark a todo complete, or show the list. The point is to park tasks you don't want to act on in the moment but don't want to forget. Trigger on \"add a todo\", \"add this to the todo list\", \"put X on the todo list\", \"remind me to...\", \"don't forget to...\", \"note this for later\", \"we should do this later\", \"mark this todo done\", \"what's on the todo list\", \"what's left to do\". This is only for parking reminders — to actually plan or do the work now, use \u002Funikit-plan, \u002Funikit-implement, or \u002Funikit-execute.","https:\u002F\u002Fgithub.com\u002FNintendaDev\u002Funikit-ai\u002Fblob\u002Fmain\u002Fskills\u002Funikit-todo\u002FSKILL.md",[],[133,134,135,136,37,137,138,139,140,141,142,143,117,144,145,146,30,29,95,147],"unikit todo","todo","remind","show","todo list","only","now","you","done","tasks","work","me","reminders","later","act",{"skillNo":149,"name":150,"nameZh":6,"description":151,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":152,"categories":153,"keywords":155,"publishedAt":39},"01M71BPEQDVD7DTGFQBQJQ7JKY","unikit-skills-context","Customize how a built-in unikit skill behaves in this specific project by writing workflow overrides into its skill-context file. These are per-skill workflow rules (e.g. \"\u002Funikit-review should also flag TODO comments\", \"\u002Funikit-implement should run tests after each task\"), not coding conventions. Use when the user wants to change, customize, or override how a particular unikit skill works in this project — \"customize the review skill\", \"make \u002Funikit-fix always add logging here\", \"the implement skill should do X differently\", \"add a skill rule for \u002Funikit-commit\". Use \"validate\" to find stale overrides against updated base skills. For a general coding convention (not tied to one skill) use \u002Funikit-rules; to derive rules from past mistakes use \u002Funikit-evolve.","https:\u002F\u002Fgithub.com\u002FNintendaDev\u002Funikit-ai\u002Fblob\u002Fmain\u002Fskills\u002Funikit-skills-context\u002FSKILL.md",[154],{"categoryNo":82,"categoryName":83,"taxonomyType":84,"taxonomyTypeDesc":85},[156,96,37,89,157,158,159,160,161,162,163,164,134,165,166,93,167,30,29,95],"unikit skills context","coding conventions","writing","when","workflow","commit","review","general coding","text","change","how","past",{"skillNo":169,"name":170,"nameZh":6,"description":171,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":172,"categories":173,"keywords":181,"publishedAt":39},"01M71BP7K5KEGJV4ASRKPG1DM8","unikit-rules","Add a short, project-specific rule, convention, or override to .unikit\u002FRULES.md — the quick-capture inbox for this project's rules (common rules always load; topic files in .unikit\u002Frules\u002F load when the work matches), automatically loaded by \u002Funikit-implement (later promotable via \u002Funikit-memory migrate-rules). Works only with a rule typed as a prompt — it does NOT read files, folders, URLs, or PDFs. Cross-checks the knowledge base (RULES_INDEX.md) to avoid duplicating core\u002Fstack entries. Use for one-line conventions and corrections: \"add a rule\", \"remember this\", \"convention\", \"always do X\", \"never use Y\", \"from now on do Z\", or when the user corrects agent behavior and wants it remembered; also \"split the rules into topics\" (optimise), \"clean up the rules\" (prune), \"shorten RULES.md\" (compact), by keyword or in plain words. If the user points to a source (file, folder, URL, PDF, article, book) or wants to research\u002Fdocument framework usage, use \u002Funikit-memory; for architecture decisions use ARCHITECTURE.md.","https:\u002F\u002Fgithub.com\u002FNintendaDev\u002Funikit-ai\u002Fblob\u002Fmain\u002Fskills\u002Funikit-rules\u002FSKILL.md",[174,177,180],{"categoryNo":175,"categoryName":176,"taxonomyType":84,"taxonomyTypeDesc":85},"01JBSEEDCAT000000000000002","文档处理",{"categoryNo":178,"categoryName":179,"taxonomyType":84,"taxonomyTypeDesc":85},"01JBSEEDCAT000000000000021","资料检索与研究",{"categoryNo":82,"categoryName":83,"taxonomyType":84,"taxonomyTypeDesc":85},[19,182,183,184,37,185,35,186,187,33,91,188,164,189,92,146,30,29,95,190],"unikit rules","quick","PDF","clean","files","URL","batch","knowledge base","prune",{"skillNo":192,"name":193,"nameZh":6,"description":194,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":195,"categories":196,"keywords":202,"publishedAt":39},"01M71BNWH4SE1W3E5Y50Z1KX6K","unikit-roadmap","Create or update a strategic project roadmap with major milestones. Generates .unikit\u002FROADMAP.md — a high-level checklist of project goals. Use when user says \"roadmap\", \"project plan\", \"milestones\", \"what to build next\", \"strategic goals\", or wants to see big-picture progress. Also use when the user asks to check which milestones are done or wants to plan the overall project direction.","https:\u002F\u002Fgithub.com\u002FNintendaDev\u002Funikit-ai\u002Fblob\u002Fmain\u002Fskills\u002Funikit-roadmap\u002FSKILL.md",[197],{"categoryNo":198,"categoryName":199,"taxonomyType":200,"taxonomyTypeDesc":201},"01JBSEEDCAT000000000000031","产品经理","PROFESSION","适用职业",[203,204,205,206,37,207,159,141,47,32,117,208,209,210,31,30,29,95,28,211],"unikit roadmap","roadmap","which","direction","milestones","progress","next","project plan","vision"]