Problem
Skills invoke other skills and subagents in prose ("invoke the capture-event skill"). Nothing marks a genuine runtime invocation as distinct from a passing mention, and the invocation's rendered form is not adapted per harness. A skill's runtime dependency on another artifact can only be captured by hand-declaring it in dependencies: frontmatter, separately from the prose that performs the invocation, where the two can drift apart.
Context
{tool:NAME} tokens already solve the analogous problem for tools: they are rewritten at deploy time in the render chain (tool-name-rewriter.ts), failing the run on an unmapped name. The harness-static tokens {harness_id} and {harness_home_dir} are the closer precedent: they render from per-harness values held in the typed HarnessConfig table (harness.ts), not from the overlay's per-name map. resolveClosure (dependency-resolver.ts) computes the deploy closure from frontmatter edges and fails the run on an edge pointing at a missing artifact. This ticket is a prerequisite for the cross-artifact dependency audit (#879), whose audit emits these tokens.
Proposed solution
Introduce {skill:<slug>} and {subagent:<slug>} tokens (kebab-case slugs), rendered in the deploy render chain alongside {tool:NAME}, in both the skill and subagent transforms.
Render via a per-harness sigil held in HarnessConfig (the home of the comparable {harness_id} / {harness_home_dir} values), not the overlay's per-name map, since the slug is identical across harnesses:
{skill:<slug>} renders to the harness skill sigil plus the slug (Claude /, Rovo !).
{subagent:<slug>} renders to the harness subagent sigil plus the slug. That sigil is empty on both current harnesses, so it renders to the bare slug, which is how a subagent is dispatched on each; the field exists for uniformity and future harnesses.
Because the sigils live in the typed HarnessConfig record rather than the overlay, a harness with no configured rendering is a compile error, stronger than a deploy-time check.
Make resolveClosure union body tokens with dependencies: frontmatter, so a tokenized invocation is itself a dependency edge. Extract tokens from the include-expanded body, the same surface the render pass emits, so an invocation inside a shared _partials file becomes an edge for every skill that includes it. The resolver's existing missing-artifact check validates token targets, so a token naming a non-existent slug fails the run. An inline invocation is then expressed once, as the token; dependencies: remains for non-inline edges.
Scope the tokens to skills and subagents, the types that pass through the render pass. Rulebooks (whose bodies are embedded without that pass) and collections keep dependencies: / members:. A token in a standalone skill sub-document that no skill includes still renders but is not edge-validated; the convention is to place cross-artifact invocations in the main body or a partial. (#902 adds a lint to catch untokenized invocations.)
Acceptance criteria
Must have
Problem
Skills invoke other skills and subagents in prose ("invoke the
capture-eventskill"). Nothing marks a genuine runtime invocation as distinct from a passing mention, and the invocation's rendered form is not adapted per harness. A skill's runtime dependency on another artifact can only be captured by hand-declaring it independencies:frontmatter, separately from the prose that performs the invocation, where the two can drift apart.Context
{tool:NAME}tokens already solve the analogous problem for tools: they are rewritten at deploy time in the render chain (tool-name-rewriter.ts), failing the run on an unmapped name. The harness-static tokens{harness_id}and{harness_home_dir}are the closer precedent: they render from per-harness values held in the typedHarnessConfigtable (harness.ts), not from the overlay's per-name map.resolveClosure(dependency-resolver.ts) computes the deploy closure from frontmatter edges and fails the run on an edge pointing at a missing artifact. This ticket is a prerequisite for the cross-artifact dependency audit (#879), whose audit emits these tokens.Proposed solution
Introduce
{skill:<slug>}and{subagent:<slug>}tokens (kebab-case slugs), rendered in the deploy render chain alongside{tool:NAME}, in both the skill and subagent transforms.Render via a per-harness sigil held in
HarnessConfig(the home of the comparable{harness_id}/{harness_home_dir}values), not the overlay's per-name map, since the slug is identical across harnesses:{skill:<slug>}renders to the harness skill sigil plus the slug (Claude/, Rovo!).{subagent:<slug>}renders to the harness subagent sigil plus the slug. That sigil is empty on both current harnesses, so it renders to the bare slug, which is how a subagent is dispatched on each; the field exists for uniformity and future harnesses.Because the sigils live in the typed
HarnessConfigrecord rather than the overlay, a harness with no configured rendering is a compile error, stronger than a deploy-time check.Make
resolveClosureunion body tokens withdependencies:frontmatter, so a tokenized invocation is itself a dependency edge. Extract tokens from the include-expanded body, the same surface the render pass emits, so an invocation inside a shared_partialsfile becomes an edge for every skill that includes it. The resolver's existing missing-artifact check validates token targets, so a token naming a non-existent slug fails the run. An inline invocation is then expressed once, as the token;dependencies:remains for non-inline edges.Scope the tokens to skills and subagents, the types that pass through the render pass. Rulebooks (whose bodies are embedded without that pass) and collections keep
dependencies:/members:. A token in a standalone skill sub-document that no skill includes still renders but is not edge-validated; the convention is to place cross-artifact invocations in the main body or a partial. (#902 adds a lint to catch untokenized invocations.)Acceptance criteria
Must have
{skill:<slug>}and{subagent:<slug>}render to their harness-appropriate form in the deploy render chain, for both skills and subagents.HarnessConfigtable, so a harness missing a sigil fails to compile.resolveClosuretreats a body token as a dependency edge, unioned withdependencies:frontmatter, extracted from the include-expanded body.HarnessConfighome, and the auto-edge behavior are documented in authoring guidance.