Skip to content

Spec proposal: declared agent skills on components #60

@rawwerks

Description

@rawwerks

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:

  1. 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.
  2. 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:

  1. The project's ./skills/ directory.
  2. ~/.claude/skills/.
  3. ~/.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

  1. Implicit detection — scan ### Execution for skill mentions. Rejected:
    too magical, and brittle against rephrasing or templating.
  2. 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.
  3. 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.
  4. 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

  1. 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?
  2. Should the section header be ### Skills or ### Harness Skills?
  3. 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.)
  4. Should the search order include a user-configurable path list, or is
    ./skills/ + ~/.claude/skills/ + ~/.codex/skills/ enough?
  5. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions