Skip to content

feat(runtime-api): serve a skill's body so a client can activate it - #6869

Merged
Hmbown merged 1 commit into
codewhale-hq:wave/0.10.1-nextfrom
gaord:feat/skill-detail-route
Oct 6, 2026
Merged

Hmbown merged 1 commit into
codewhale-hq:wave/0.10.1-nextfrom
gaord:feat/skill-detail-route

Conversation

@gaord

@gaord gaord commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

What

GET /v1/skills/{name} returns one skill's SKILL.md body plus the routing metadata around it (source, invocation, aliases, bundled_tier, enabled).

Why

A skill is its body, and no route served it. /skill <name> works in the TUI because the body is already in the process; a client outside it — the VS Code GUI — could list skills and toggle them but not activate one, so the same /skill <name> meant "switch this on" there and "apply this now" in the terminal. This is the read that closes that gap without moving activation into the engine: the client composes the same instruction the TUI composes.

Details

  • Discovery is the listing's own walk, so a name the listing shows resolves here; an alias resolves to the canonical body.
  • Plugin skills serve from the content-bound snapshot: authority re-verified per request (PluginActivationCapability::Skills), workspace checked, and no mutable on-disk path in the response.
  • A native skill whose SKILL.md has since been deleted answers 404 rather than serving the instructions it cached at discovery.
  • GET /v1/skills rows gain invocation, aliases and bundled_tier, so a picker or autocomplete needs no second request per row. Both routes build their row through one helper, so the listing and the detail cannot drift; the curated tier is reported only where is_bundled is true.
  • Advertised as capabilities.skill_detail on GET /v1/runtime/info. Clients should feature-detect rather than probe: a 404 here means "no such skill" and cannot be told from "no such route". (GET /v1/skills/install does answer 405, but that only proves the install route.)

Trust boundary

This route hands a skill body to a client, so it is worth a maintainer's eye: it reuses the existing authority checks (plugin receipt/trust/enablement, workspace containment) and adds no new surface, and it never returns a plugin's mutable path. Flagging it rather than assuming, per CONTRIBUTING.

Tests

  • skill_detail_returns_body_and_routing_metadata — body, invocation, aliases, path, and alias lookup
  • skill_detail_404s_for_unknown_skill
  • skill_list_rows_carry_routing_metadata
  • listed_tier_belongs_to_the_bundled_copy_only — fails against the previous tier logic (it reported tools for a non-bundled copy)
  • runtime_info_advertises_skill_detail_capability
  • the existing auth test now also covers GET /v1/skills/{name} (401 without a token)

Verified on this branch: rustfmt --check clean on the touched files; cargo clippy -p codewhale-protocol -p codewhale-tui --all-features --locked -- -D warnings -A clippy::uninlined_format_args -A clippy::too_many_arguments -A clippy::unnecessary_map_or -A clippy::collapsible_if -A clippy::assertions_on_constants clean; runtime_api::tests::skill* 23/23 green; and an end-to-end run of the built binary over HTTP (detail + alias, 404, 401, list metadata, audit, capability flags).

No CHANGELOG entry, per CONTRIBUTING.

No-Issue: Expose the existing reviewed skill body through the authenticated Runtime API.

`GET /v1/skills/{name}` returns one skill's `SKILL.md` body with the routing
metadata around it: `source`, `invocation`, `aliases`, `bundled_tier`,
`enabled`. The TUI's own `/skill <name>` composes its activation instruction
from a body it already holds in process; a client outside that process — the VS
Code GUI — has only the listing, which stops at the description. This is the
read that closes the gap, over the same discovery walk the listing uses, so a
name the listing shows resolves here.

Plugin bodies stay content-bound to their reviewed snapshot (authority and
workspace re-checked, no mutable path returned); a native skill whose file has
since been deleted answers 404 rather than serving the stale instructions.

`GET /v1/skills` rows now carry `invocation`, `aliases` and `bundled_tier` too,
so a picker or an autocomplete needs no second request per row. The curated
tier is reported only where `is_bundled` is true, so the two fields cannot
disagree. Both routes build their row through one helper for that reason.

Advertised as `capabilities.skill_detail` on `GET /v1/runtime/info`, which is
the source a client should use rather than probing: a 404 from this path means
"no such skill" and is indistinguishable from "no such route".
@gaord
gaord requested a review from Hmbown as a code owner October 5, 2026 15:47
@Hmbown Hmbown added this to the v0.10.2 milestone Oct 5, 2026

@Hmbown Hmbown left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes thank you!!! this is so wonderful

@Hmbown
Hmbown changed the base branch from main to wave/0.10.1-next October 6, 2026 05:30
@Hmbown
Hmbown merged commit 50868f6 into codewhale-hq:wave/0.10.1-next Oct 6, 2026
26 of 28 checks passed
Hmbown pushed a commit that referenced this pull request Oct 6, 2026
Reconcile the complete contributions from #6832 (@aboimpinto), #6867
(@hodeswildsmith455-boop), and #6805 (@LIghtJUNction) with the current
Engine, provider identities, reviewed-plugin policy, and task lifecycle.
Original contributor histories are recorded by subsequent resolved merges.

Fix the already integrated contributor cases: snapshot corruption is an
explicit unavailable/error result (#6817), malformed locales cannot select
an incidental script (#6860), image metadata uses the exact uploaded bytes
and respects available decoders (#6858), automation deletion waits for
actual scheduler reconciliation (#6864), and blocking trust/skill reads stay
off the async executor (#6869). Preserve #6857's compaction regression.

Extend #6872's human-wait lifecycle guard to approval/elevation cards;
retire only the matching ended parent request and refresh activity only
after a delivered decision. Enforce configured finite approval deadlines in
the Engine, including deadline/cancellation races and durable receipts.

Serialize Native Windows ACL admission/retirement across Core processes
with a logon-scoped kernel mutex, preserving exact SID/object validation.
Add an actual child-process lock test; serialize DSH host tests in the
existing extension-host lane. Windows execution proof remains hosted CI.

Reconcile the vendored computer-use plugin with canonical main a656f67455fc
while preserving Core's 0.12.1 embedding contract. Canonical b47/a656 tree
passed Ubuntu/macOS/Windows source and package gates, including 28/28
Windows-focused tests and the controlled desktop fixture; this is separate
from the new Engine head's CI verdict.

Partial adaptation of the discovery-cache priority portion from PR #6393
by @AdityaVG13 (original ac33dd4). Preserve the best match under count
and byte limits without importing the unfinished echolocation/fork design;
the broader draft remains open.

Validation:
- npm test: 1286 passed, 0 failed, 7 skipped; web 767/767.
- npm run check:web: lint, typecheck and production build passed.
- Affected Rust selection: 801/803 initially passed; the two fixture/lifecycle
  expectation failures were corrected and each passed a focused rerun.
- Additional focused Rust: approval 28/28, discovery cache 11/11,
  OrcaRouter synthetic catalog 3/3, and 33/33 lifecycle/API/routing checks.
- Final CI-repair selection: 37/39 initially passed; the BMP feature-proxy
  and feature-registry summary failures were corrected; both corrected tests passed (2/2, 0 failures).
- Qualified Clippy: six packages, all targets/all features, passed with
  the CI style allowances. Portable no-default-feature check passed;
  portable policy verifier 6/6 passed; formatting and diff checks passed.
- Runtime contract: 55 measured metrics passed after explicit remeasurement;
  all 21 structural identities were unchanged. Twelve byte/token-estimate
  budgets account for bounded child-wait disclosure and contributor locale
  descriptions; no runtime field/prompt was removed to lower the budget.
- Persistence budget was not qualified locally: the checker requires a
  clean tree and this shared checkout retains an unrelated operator file.
  Clean hosted CI, fresh stamped build and real DeepSeek TUI acceptance
  remain required before the integration PR can merge to main.

Refs #6872, #6843, #6795.

Co-authored-by: Paulo Aboim Pinto <paulo.aboim.pinto@gmail.com>
Co-authored-by: hodeswildsmith455-boop <hodeswildsmith455-boop@users.noreply.github.com>
Co-authored-by: LIghtJUNction <lightjunction.me@gmail.com>
Co-authored-by: AdityaVG13 <adityavgcode@gmail.com>
Signed-off-by: CodeWhale Bot <bot@codewhale.net>
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.

2 participants