Spec proposal: declared agent skills on components
Filing this as a spec proposal first per maintainer guidance — no implementation,
just use case and proposed syntax for debate.
Use case
OpenProse runs .prose.md components inside an agent harness (Claude Code, Codex,
etc.) that brings its own tools and skills. Today, a component cannot tell the
runtime which harness skills it depends on. That has two costs:
- Silent drift. A component authored against
document-skills:pdf will run
on a machine where that skill is absent and the agent will quietly improvise —
sometimes succeeding, sometimes producing wrong output, with no diagnostic.
- Unreviewable contracts. A reviewer reading a
.prose.md cannot see at a
glance which agent capabilities the component leans on, even though those are
load-bearing.
Concrete example: an invoice-extractor system whose ### Execution calls a
PDF-parsing skill works on the author's box and fails on a teammate's box because
document-skills:pdf is not installed. The author wants to declare the
dependency so the runtime can fail closed at preflight with a named, actionable
diagnostic.
This is the same shape as ### Requires / ### Ensures for typed I/O ports —
just for harness capabilities instead of data flow.
Ideal syntax
Two equivalent forms, both additive to the existing spec.
Frontmatter form
---
name: invoice-extractor
kind: system
skills:
- document-skills:pdf
---
Section form
### Skills
- document-skills:pdf
- document-skills:xlsx
The two are merged (deduped by declared name) into the component's skills
field on the IR. Either alone is sufficient; using both is allowed and useful
when a sub-service adds a skill the parent system did not need.
Naming
Skill names use the colon form that already matches plugin marketplace
conventions and /skill invocations:
namespace:name # e.g. document-skills:pdf
A bare leaf (pdf) is accepted with a deterministic Levenshtein fuzzy match
against installed skills, and emits an informational diagnostic nudging the
author to pin the canonical name. Never silent.
Scope
- System-level declarations apply to every sub-service inside the system.
- Service-level declarations are additive, not exclusive — declaring
skills: on a ## sub-service does not remove the system-level skills, it
adds to them.
BYO harness invariant
OpenProse never installs, modifies, or removes harness skills. BYO harness is
sacred. Preflight only verifies that declared skills are present and fails
closed (skill_unresolved) when one is missing, naming the skill and the search
paths it looked in. Installing the skill is the user's responsibility.
Search order:
- The project's
./skills/ directory.
~/.claude/skills/.
~/.codex/skills/.
Resolved canonical names are pinned into the IR so subsequent runs of the same
IR are reproducible across machines.
Where it slots into the existing spec
This is purely additive to skills/open-prose/contract-markdown.md:
- One new row in the Frontmatter table:
skills (optional).
- One new row in the Canonical Sections table:
### Skills (service, system).
- A short "Skill Declaration" subsection covering colon form, fuzzy fallback,
scope, and the BYO invariant.
No existing sections change. No runtime semantics change for components that
don't declare skills.
Alternatives considered
- Implicit detection — scan
### Execution for skill mentions. Rejected:
too magical, and brittle against rephrasing or templating.
- Out-of-band manifest (e.g., a
prose.skills.json next to the file).
Rejected: separates the contract from the dependency, defeating the
"single reviewable file" property of .prose.md.
- Reuse
### Runtime for skills. Rejected: Runtime is for VM/model/thinking
hints; mixing harness capability declarations there would muddy a section that
is already load-bearing.
- Hard-fail on bare leaf names instead of fuzzy match. Defensible, but
reduces ergonomics for the common case where there is exactly one installed
skill matching the leaf. Diagnostic + pin-on-resolve seems like the better
default; happy to flip this if the maintainer prefers strict.
Open questions for debate
- Is
skills: the right key, or should it be harness-skills: to make the
"this is about the agent harness, not OpenProse internals" framing explicit?
- Should the section header be
### Skills or ### Harness Skills?
- Is the frontmatter form alone sufficient, or is the section form worth it
for prose-readability? (The section form lets authors write a short
justification line under each skill.)
- Should the search order include a user-configurable path list, or is
./skills/ + ~/.claude/skills/ + ~/.codex/skills/ enough?
- Should
skill_unresolved block prose run outright, or default to a warning
with a --strict flag? My instinct is fail-closed by default.
What this issue is asking for
Agreement (or counter-proposal) on:
- The use case
- The two-form syntax (frontmatter + section)
- The colon naming convention and fuzzy fallback policy
- The BYO harness invariant and search order
Once the spec is settled, I'll send a small doc-only PR adding just the spec
text to skills/open-prose/contract-markdown.md plus a single assertion test,
and we can debate implementation separately.
Spec proposal: declared agent skills on components
Filing this as a spec proposal first per maintainer guidance — no implementation,
just use case and proposed syntax for debate.
Use case
OpenProse runs
.prose.mdcomponents inside an agent harness (Claude Code, Codex,etc.) that brings its own tools and skills. Today, a component cannot tell the
runtime which harness skills it depends on. That has two costs:
document-skills:pdfwill runon a machine where that skill is absent and the agent will quietly improvise —
sometimes succeeding, sometimes producing wrong output, with no diagnostic.
.prose.mdcannot see at aglance which agent capabilities the component leans on, even though those are
load-bearing.
Concrete example: an
invoice-extractorsystem whose### Executioncalls aPDF-parsing skill works on the author's box and fails on a teammate's box because
document-skills:pdfis not installed. The author wants to declare thedependency so the runtime can fail closed at preflight with a named, actionable
diagnostic.
This is the same shape as
### Requires/### Ensuresfor typed I/O ports —just for harness capabilities instead of data flow.
Ideal syntax
Two equivalent forms, both additive to the existing spec.
Frontmatter form
Section form
The two are merged (deduped by declared name) into the component's
skillsfield on the IR. Either alone is sufficient; using both is allowed and useful
when a sub-service adds a skill the parent system did not need.
Naming
Skill names use the colon form that already matches plugin marketplace
conventions and
/skillinvocations:A bare leaf (
pdf) is accepted with a deterministic Levenshtein fuzzy matchagainst installed skills, and emits an informational diagnostic nudging the
author to pin the canonical name. Never silent.
Scope
skills:on a## sub-servicedoes not remove the system-level skills, itadds to them.
BYO harness invariant
OpenProse never installs, modifies, or removes harness skills. BYO harness is
sacred. Preflight only verifies that declared skills are present and fails
closed (
skill_unresolved) when one is missing, naming the skill and the searchpaths it looked in. Installing the skill is the user's responsibility.
Search order:
./skills/directory.~/.claude/skills/.~/.codex/skills/.Resolved canonical names are pinned into the IR so subsequent runs of the same
IR are reproducible across machines.
Where it slots into the existing spec
This is purely additive to
skills/open-prose/contract-markdown.md:skills(optional).### Skills(service, system).scope, and the BYO invariant.
No existing sections change. No runtime semantics change for components that
don't declare skills.
Alternatives considered
### Executionfor skill mentions. Rejected:too magical, and brittle against rephrasing or templating.
prose.skills.jsonnext to the file).Rejected: separates the contract from the dependency, defeating the
"single reviewable file" property of
.prose.md.### Runtimefor skills. Rejected:Runtimeis for VM/model/thinkinghints; mixing harness capability declarations there would muddy a section that
is already load-bearing.
reduces ergonomics for the common case where there is exactly one installed
skill matching the leaf. Diagnostic + pin-on-resolve seems like the better
default; happy to flip this if the maintainer prefers strict.
Open questions for debate
skills:the right key, or should it beharness-skills:to make the"this is about the agent harness, not OpenProse internals" framing explicit?
### Skillsor### Harness Skills?for prose-readability? (The section form lets authors write a short
justification line under each skill.)
./skills/+~/.claude/skills/+~/.codex/skills/enough?skill_unresolvedblockprose runoutright, or default to a warningwith a
--strictflag? My instinct is fail-closed by default.What this issue is asking for
Agreement (or counter-proposal) on:
Once the spec is settled, I'll send a small doc-only PR adding just the spec
text to
skills/open-prose/contract-markdown.mdplus a single assertion test,and we can debate implementation separately.