Skip to content

feat(plugin): Phase-7 follow-ons — cursor commands, support files, memory merge, unified lint - #251

Merged
ScriptedAlchemy merged 11 commits into
masterfrom
feat/plugin-followons
Jul 3, 2026
Merged

feat(plugin): Phase-7 follow-ons — cursor commands, support files, memory merge, unified lint#251
ScriptedAlchemy merged 11 commits into
masterfrom
feat/plugin-followons

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

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-invocation tracedecay-* dispatcher skills; re-expressed each as a Cursor 1.6+ native slash command (plugin/overlays/cursor/commands/tracedecay-*.md, declared via the manifest commands key). Cursor's shared skills are now the same clean model-invocable set as Claude/Codex; explicit dispatch is native commands. Cursor installer LEGACY_PLUGIN_DIRS sweeps the retired dirs; skill_lint_cursor /slug resolution retargeted at the commands dir.

  • Delta: Claude/Codex unchanged; Cursor −13 dispatcher skills, +13 commands (intended).

2 — Recursive embedding + first support files (854658d2)

Converted the flat include_str! skill table to a build.rs codegen that walks plugin/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.

  • Delta: recursive embed is byte-identical to the flat table; only change is +3 support files per host.

3 — Memory-skill merge + message_search lane split (1c688215)

Merged recalling-project-memory + curating-project-memory into one project-memory skill ("Recall (read-only, start here)" / "Curate (mutation, requires approval)" sections) — all guardrails + tool mentions preserved (coverage stays green). message_search lanes assigned: project-memory owns FTS→fact, recalling-session-context owns FTS→LCM. CURSOR_PLUGIN_SKILLS 17→16, skill-count assertions and cross-references updated everywhere.

  • Delta (all hosts): −2 memory skills, +project-memory.

4 — Unified shared-skill contract test (615c0e3c)

New shared_skill_contract_test.rs validating the one plugin/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 that commands/ 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

@changeset-bot

changeset-bot Bot commented Jul 3, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 53905b2

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@ScriptedAlchemy
ScriptedAlchemy force-pushed the feat/plugin-single-bundle branch from 045f65f to df16846 Compare July 3, 2026 18:39
@ScriptedAlchemy
ScriptedAlchemy force-pushed the feat/plugin-followons branch from 2d4d4f4 to 0e89f2e Compare July 3, 2026 18:41
@ScriptedAlchemy
ScriptedAlchemy force-pushed the feat/plugin-single-bundle branch from df16846 to bdde218 Compare July 3, 2026 18:54
@ScriptedAlchemy
ScriptedAlchemy force-pushed the feat/plugin-followons branch from 0e89f2e to a0afe05 Compare July 3, 2026 18:55
@ScriptedAlchemy
ScriptedAlchemy force-pushed the feat/plugin-single-bundle branch from bdde218 to b42021d Compare July 3, 2026 19:25
ScriptedAlchemy and others added 10 commits July 3, 2026 19:25
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
ScriptedAlchemy force-pushed the feat/plugin-followons branch from a0afe05 to dd26880 Compare July 3, 2026 19:37
@ScriptedAlchemy
ScriptedAlchemy changed the base branch from feat/plugin-single-bundle to master July 3, 2026 19:43
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>
@ScriptedAlchemy
ScriptedAlchemy merged commit 237ee50 into master Jul 3, 2026
16 checks passed
@ScriptedAlchemy
ScriptedAlchemy deleted the feat/plugin-followons branch July 4, 2026 01:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant