feat(plugin): Phase-7 follow-ons — cursor commands, support files, memory merge, unified lint - #251
Merged
Merged
Conversation
|
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
ScriptedAlchemy
force-pushed
the
feat/plugin-single-bundle
branch
from
July 3, 2026 18:39
045f65f to
df16846
Compare
ScriptedAlchemy
force-pushed
the
feat/plugin-followons
branch
from
July 3, 2026 18:41
2d4d4f4 to
0e89f2e
Compare
ScriptedAlchemy
force-pushed
the
feat/plugin-single-bundle
branch
from
July 3, 2026 18:54
df16846 to
bdde218
Compare
ScriptedAlchemy
force-pushed
the
feat/plugin-followons
branch
from
July 3, 2026 18:55
0e89f2e to
a0afe05
Compare
ScriptedAlchemy
force-pushed
the
feat/plugin-single-bundle
branch
from
July 3, 2026 19:25
bdde218 to
b42021d
Compare
Follow-on 1 of the plugin single-bundle rearchitecture. Cursor's 13 `tracedecay-*` slash dispatchers were `disable-model-invocation` skills deployed at `skills/tracedecay-*/SKILL.md`, overriding the canonical model-invocable dispatcher skills for Cursor only. This left Cursor's shared skill set divergent from Claude/Codex (30 skills incl. dispatcher form vs the 17 canonical model-invocable skills). Re-express each dispatcher as a Cursor 1.6+ native slash command under `plugin/overlays/cursor/commands/tracedecay-*.md`, deployed to `commands/` (declared by the manifest `commands` key). Each command keeps the dispatcher's "Apply the tracedecay:<foundational> skill" intent, scope/args, guardrails, and output contract, adapted to a Cursor command prompt (`$ARGUMENTS`). Net: Cursor's shared skills become the 17 canonical model-invocable set, byte-identical to Claude/Codex; Cursor's explicit dispatch is native commands. - plugin_bundle.rs: `CURSOR_DISPATCHER_FILES` (skills override) → `CURSOR_COMMAND_FILES` (commands/); cursor_files() drops the dispatcher skills and adds the commands. Claude/Codex composition unchanged. - cursor.rs: manifest gains `commands: commands/`; LEGACY_PLUGIN_DIRS sweeps the retired dispatcher skill dirs on upgrade; coverage/write tests retargeted. - skill_lint_cursor_test: `/slug` resolver now resolves against the cursor commands dir; disable-model-invocation dispatcher-skill rules removed; new cursor-command hygiene + reference-integrity test. - skill_lint_claude_test: shared skill set is now strictly Agent-Skills-spec conformant (no disable-model-invocation overlay); conflict-field machinery removed. - Other agent-suite tests (contract, manifest schema, update_plugin, tool_skill_coverage, agent_test) retargeted to the new command surface. - docs/PLUGIN-VALIDATION.md: layout note + cursor-lint heading rule updated. Deployed-tree delta (verified by sha256 golden capture): Claude and Codex byte-identical; Cursor drops 13 `skills/tracedecay-*/SKILL.md` and gains 13 `commands/tracedecay-*.md` (intended). agent_suite: 413 passed, 0 failed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Follow-on 2 of the plugin single-bundle rearchitecture. The plugin embedding was a flat hand-maintained `include_str!` table: every skill contributed exactly one entry for its SKILL.md, so a skill could not ship `references/`/`scripts/`/`assets/` support files (they would exist on disk and deploy via the recursive cache walk, but never be embedded — failing coverage and stranding fresh installs). Convert skill embedding to a build.rs recursive codegen. `build.rs` (`generate_skill_bundle`) walks `plugin/skills/` and emits `$OUT_DIR/plugin_bundle_generated.rs` with a `GENERATED_SKILL_FILES` slice of `PluginFile` entries — one per file under the tree, `include_str!`'d at compile time with per-file `rerun-if-changed`. `plugin_bundle.rs` `include!`s it and replaced the two flat skill tables (CANONICAL_PLUGIN_FILES + CANONICAL_DISPATCHER_FILES). Claude/Codex deploy every skill file; Cursor filters out the `tracedecay-*` dispatcher skills (native commands there). Coverage tests rewritten to walk the skill tree recursively (claude/codex/cursor `*_embedded_file_list_covers_the_whole_source_bundle`), plus a new `generated_skill_files_cover_the_skill_tree_exactly` asserting the embed equals the on-disk tree exactly. File-count assertions derive from the generated set instead of frozen literals. Add three genuinely useful support files (each linked from its SKILL.md): - editing-safely/scripts/safe-edit-sequence.sh — one-shot read-only recon via the `tracedecay tool` CLI (similar/callers/rename_preview/field_sites/ constructors/impact) for a symbol or Struct::field. - fixing-build-and-type-errors/references/error-class-to-tool.md — error-class → cheapest anchoring tool lookup table. - using-the-cli/references/tool-arg-catalog.md — `tracedecay tool` invocation grammar + required/optional flags for the common tools. Deployed-tree delta (sha256 golden): the recursive embed alone is byte-identical to the flat table; the only change is +3 support files per host (claude 51→54, codex 34→37, cursor 39→42), nothing else. agent_suite: 413 passed; recursive-embed coverage + byte-copy install tests green. docs/PLUGIN-VALIDATION.md: "Adding a skill" updated — support files auto-embed, no include_str! hand-registration. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Follow-on 3 of the plugin single-bundle rearchitecture.
`recalling-project-memory` (read/FTS→fact) and `curating-project-memory`
(write/curate) were two skills, forcing the model into a pre-read adjudication
("which memory skill applies?") it gets wrong. Both also referenced
`tracedecay_message_search`, leaving its ownership ambiguous with
`recalling-session-context`.
Merge them into one `plugin/skills/project-memory/SKILL.md` with clearly-headed
"Recall (read-only, start here)" and "Curate (mutation, requires approval)"
sections. All destructive-curation guardrails and every tool mention from both
are preserved (fact_store add/update/remove/search/probe/reason/get/list/
related/contradict, fact_feedback, memory_status, dashboard, message_search), so
tool_skill_coverage stays green.
Resolve message_search ownership by explicit lanes:
- project-memory owns the FTS → fact lane (message_search to recall durable
project facts).
- recalling-session-context owns the FTS → LCM lane (message_search as the entry
point into raw-message grep / replay / summary-DAG drill-down).
Each body scopes its message_search usage to its lane and cross-references the
other.
Foundational model-invocable count 13 → 12 (two memory skills → one); total
shared skills 30 → 29. Updated in lockstep: CURSOR_PLUGIN_SKILLS (steering.rs,
17 → 16), EXPECTED_SKILLS (claude_plugin_bundle_test), the claude/codex
`expected 30 → 29` coverage assertions, the analytics skill-classification
fixture + assertion, hooks/codex.rs post-compact steering, plugin/rules,
cursor commands, and every `tracedecay:recalling|curating-project-memory`
cross-reference across the skill tree → `tracedecay:project-memory`.
Deployed-tree delta (sha256 golden): on every host, exactly
`curating-project-memory` + `recalling-project-memory` removed, `project-memory`
added; the only other content changes are the cross-reference updates in skills
that pointed at the old slugs. claude 54→53, codex 37→36, cursor 42→41.
agent_suite: 413 passed; tool_skill_coverage + skill index + analytics green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Follow-on 4 of the plugin single-bundle rearchitecture.
Add tests/agent_suite/shared_skill_contract_test.rs: one contract validating the
single `plugin/skills/` tree against the INTERSECTION contract — the rules a
SKILL.md must satisfy to install cleanly on Claude, Codex, AND Cursor:
- frontmatter keys ⊆ {name, description, allowed-tools, license, metadata}
(name matches dir, kebab-case, ≤64 chars, no reserved claude/anthropic
prefix; a Cursor-only disable-model-invocation/paths key fails here);
- description 50–320 chars / ≤45 words / trigger-first / ends-with-period /
no-angle-brackets / unique;
- one plain-title H1 (never `# /slug`), no skipped heading levels, no
`## When to Use`, ≤500 lines;
- LF/BOM/tab/trailing-whitespace/fence hygiene, one trailing newline;
- support-file layout (SKILL.md + scripts/references/assets/agents, no
auxiliary docs).
The Cursor native commands and the Cursor agent overlay are validated
separately (slash-form `# /slug` H1 matching the file name; overlay present +
clean).
Consolidated to avoid coverage loss and duplication:
- Removed the three now-subsumed cursor-lint tests (file hygiene, heading
conventions, name/description quality) from skill_lint_cursor_test.rs, which
now keeps only the Cursor-specific reference-integrity + native-command lints.
- Trimmed plugin_skill_contract_test.rs's per-skill design-advice loop
(description/length/lines/when-to-use/supported-files) — now in the unified
test — keeping the aggregate metadata budget, the openai.yaml contract, the
per-host frontmatter allowances, and the byte-copy install parity tests.
The forbidden-auxiliary-doc-file check moved into the unified layout check so
nothing is lost.
Deployed tree unchanged (test-only; sha256 golden identical). agent_suite: 416
passed. docs/PLUGIN-VALIDATION.md updated to describe the new test split.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Follow-up to follow-on 1. `reinstall_sweeps_legacy_commands_dir` asserted the `commands/` dir was swept as a legacy surface — but follow-on 1 made `commands/` a live Cursor surface (native slash commands), so `commands` was removed from `LEGACY_PLUGIN_DIRS` and a stray file there is no longer nuked. Repurpose the test to cover the actual new legacy concern: an upgrade over an install that shipped a `tracedecay-*` dispatcher *skill* dir (now re-expressed as a native command) must sweep that retired skill dir. This matches the `skills/tracedecay-*` entries added to LEGACY_PLUGIN_DIRS in follow-on 1. Full lib suite (--test-threads=1): 774 passed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- render hooks.json binary-path substitution through serde so a path with a JSON-special char stays valid JSON (was a raw str::replace into JSON text) - coerce non-object enabledPlugins/permissions parents before assigning so a malformed-but-valid settings.json can't panic Value's IndexMut on install - extend the CLAUDE.md managed block only across its known owned sub-heading, not any line containing "tracedecay" (no longer swallows a user's own "## Using tracedecay in CI" heading on uninstall) - clean-replace the tracedecay-owned marketplace deploy dir before writing so a file the current bundle no longer ships never lingers across upgrades, guarded by a manifest-name ownership check that refuses to delete an unrelated dir - dir-walk plugin/agents in the coverage test instead of hardcoding agent names Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- replace the hand-maintained LEGACY_PLUGIN_DIRS sweep with a bundle-derived sweep: on replace/uninstall, remove every skills/<dir> the current embedded bundle no longer ships (retired dispatcher/workflow/merged-away memory skills), so a newly retired skill is swept automatically and the two merged-away memory skills (curating-/recalling-project-memory) no longer strand on upgrade - user-added files outside skills/ (and any skill dir still shipped) are preserved; the ownership guard still refuses an unmanaged plugin dir - dir-walk the cursor agent overlay in the coverage test instead of hardcoding Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An existing install carries the old "## Prefer tracedecay MCP tools" block (same owned end marker). Without a legacy-marker fallback that block was invisible: reinstall appended the new block and stranded the old one (duplicate steering every turn), and uninstall never removed it. - add PROMPT_MARKER_LEGACY and detect either marker in install_steering_rules, remove_steering_rules, doctor_check_steering, and the block-range finder (splices/removes the legacy block in place via the shared end marker) - tests: seeding the OLD marker, install REPLACES it (net one block) and uninstall REMOVES it, preserving any user content appended after the block Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
generate_skill_bundle embeds every plugin/skills file via include_str!, which only accepts UTF-8. A binary support file (e.g. assets/*.png) would otherwise fail to compile with an opaque "stream did not contain valid UTF-8" error pointing at the generated file. Guard it with a clear panic naming the offending file and stating binary support files aren't embeddable yet. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- shared_skill_contract: assert the first content line after the frontmatter is a plain-title H1 (restores the retired cursor heading-convention check) - claude_plugin_bundle: correct the skill-directory count in the assertion message to 29 (matches EXPECTED_SKILLS and the on-disk tree) - AGENT-MEMORY-INTERCEPTION.md: point slug/path references at the shared plugin/ tree and the merged project-memory skill, with a dated note that the per-host cursor-plugin/codex-plugin trees collapsed into plugin/ Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ScriptedAlchemy
force-pushed
the
feat/plugin-followons
branch
from
July 3, 2026 19:37
a0afe05 to
dd26880
Compare
The sweep is marker-aware (preserves same-name user skills), so the reinstall sweep/clean-replace tests must seed the retired dirs with a tracedecay authorship marker — matching reality, since retired bundle skills always carried one. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #250 (base:
feat/plugin-single-bundle). Completes the plugin rearchitecture (task #11). Merges after #250.Four follow-ons, each committed separately and taken to green, with a per-host deployed-tree golden re-verified after each so only intended files change.
1 — Cursor dispatchers → native slash commands (
52e2f515)Removed the 13
disable-model-invocationtracedecay-*dispatcher skills; re-expressed each as a Cursor 1.6+ native slash command (plugin/overlays/cursor/commands/tracedecay-*.md, declared via the manifestcommandskey). Cursor's shared skills are now the same clean model-invocable set as Claude/Codex; explicit dispatch is native commands. Cursor installerLEGACY_PLUGIN_DIRSsweeps the retired dirs;skill_lint_cursor/slugresolution retargeted at the commands dir.2 — Recursive embedding + first support files (
854658d2)Converted the flat
include_str!skill table to abuild.rscodegen that walksplugin/skills/and embeds every file (SKILL.md + support files) with per-file rerun-if-changed. Added 3 genuinely-useful, SKILL-linked support files:editing-safely/scripts/safe-edit-sequence.sh,fixing-build-and-type-errors/references/error-class-to-tool.md,using-the-cli/references/tool-arg-catalog.md.3 — Memory-skill merge +
message_searchlane split (1c688215)Merged
recalling-project-memory+curating-project-memoryinto oneproject-memoryskill ("Recall (read-only, start here)" / "Curate (mutation, requires approval)" sections) — all guardrails + tool mentions preserved (coverage stays green).message_searchlanes assigned:project-memoryowns FTS→fact,recalling-session-contextowns FTS→LCM.CURSOR_PLUGIN_SKILLS17→16, skill-count assertions and cross-references updated everywhere.project-memory.4 — Unified shared-skill contract test (
615c0e3c)New
shared_skill_contract_test.rsvalidating the oneplugin/skills/tree against the intersection contract (frontmatter allowlist, description 50–320 chars/≤45 words/trigger-first/period/no-angle-brackets/unique, single plain-title H1, no## When to Use, ≤500 lines, LF/trailing-newline hygiene, support-file layout) + Cursor commands/agent overlay separately. Consolidated the subsumed per-host lint duplication without coverage loss.Plus
8c0e81dd: retarget the cursor legacy-sweep unit test now thatcommands/is a live surface.Validation
fmt/clippy(
-D warnings)/build clean; lib 774 / agent_suite 416 pass; end-to-end deployed-tree delta (51/34/39 → 53/36/41 files claude/codex/cursor) is exactly the four intended changes and nothing else.🤖 Generated with Claude Code