Skip to content

feat(spec): declared ### Skills section with fail-closed compile resolution#62

Merged
rawwerks merged 5 commits into
mainfrom
spec/skills-section
May 7, 2026
Merged

feat(spec): declared ### Skills section with fail-closed compile resolution#62
rawwerks merged 5 commits into
mainfrom
spec/skills-section

Conversation

@rawwerks
Copy link
Copy Markdown
Contributor

@rawwerks rawwerks commented May 4, 2026

Implements the spec from #60 with the maintainer's review applied verbatim.

Maintainer's decisions from #60 (applied)

Question Decision Where
### Skills canonical section Yes skills/open-prose/contract-markdown.md (Canonical Sections + Skills H2)
skills: frontmatter form Dropped — section only, one place n/a
Section header name ### Skills (not ### Harness Skills) spec
Search order ./skills, ~/.claude/skills, ~/.codex/skills, ~/.agents/skills tools/cli/src/skills/declared.ts (DECLARED_SKILL_SEARCH_DIRECTORIES)
~/.agents/skills added Yes (everyone-except-claude convention) same
Fail behavior Fail closed on prose compile tools/cli/src/commands/compile.ts (preflightDeclaredSkillsForCompile)
BYO harness invariant Confirmed — OpenProse never installs skills spec
Scope Minimal. One example/test. this PR

What changed (8 files, +823)

  • Specskills/open-prose/contract-markdown.md gains a ### Skills row in the Canonical Sections table and a short ## Skills H2 covering colon naming, search order, the BYO invariant, and fail-closed semantics.
  • Implementationtools/cli/src/skills/declared.ts (new). Pure TS: parseDeclaredSkills, resolveDeclaredSkill, resolveDeclaredSkillsForFile, preflightDeclaredSkillsInRoot, DeclaredSkillsUnresolvedError. No I/O beyond readFile / readdir / stat.
  • Wiringtools/cli/src/commands/compile.ts pre-checks declared skills before forwarding the compile prompt; throws CompileValidationError with a skill_unresolved heading and per-skill detail lines listing the searched paths. Pre-forward, so unresolved skills do not burn agent tokens. Gated behind the existing skillPreflight option for test parity.
  • Exampleskills/open-prose/examples/declared-skills/ shows the document-skills:pdf canonical pattern from the issue.
  • Tests — 19 new (TDD):
    • 18 in tools/cli/tests/skills/declared.test.ts covering parser, resolver, directory walker, error formatter, and edge cases (case-insensitive header, dedupe, backticked names, hidden-dir skipping).
    • 1 in tools/cli/tests/cli/cli.test.ts asserting prose compile rejects with CompileValidationError before the harness is invoked when a declared skill is missing.
  • Changelog[Unreleased] entry references Spec proposal: declared agent skills on components #60.

Total test count: 158 → 177 (all green, typecheck clean).

Test plan

  • npx vitest run — 177 / 177 pass
  • npx tsc -p tsconfig.json --noEmit — clean
  • Manual: a .prose.md declaring document-skills:pdf against an empty HOME triggers skill_unresolved with searched paths, harness uninvoked

Notes

Branched off origin/main this time (last attempt was anchored to the abandoned rfc/reactive-openprose branch — that PR (#59) is closed). No frontmatter form, per maintainer feedback that frontmatter stays structural. prose run enforcement was deliberately deferred — once prose compile is fail-closed, a successful compile guarantees declared skills resolved at compile time, and runtime enforcement can be a follow-up if needed.

Closes #60.

Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com

Comment thread skills/open-prose/contract-markdown.md Outdated
Rules:

- `### Skills` is the only place to declare harness-skill dependencies. The
declaration is not duplicated in frontmatter — frontmatter stays structural
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we can remove lines like this.

Common claude/codex failure pattern: I often see design decisions creep into implementation. They proposed adding it to the front-matter, we said no, and then they propagate a description of that decision into the actual implementation when it would be better to just not say it at all.

I see this all the time.

Comment thread skills/open-prose/contract-markdown.md Outdated
3. `~/.codex/skills/`.
4. `~/.agents/skills/`.
- If a declared skill cannot be resolved in any of those paths, both `prose
compile` and `prose run` fail closed with a `skill_unresolved` diagnostic
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Here it says prose run fails, but in the PR description it says we deferred that decision and that prose run will not fail.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think it's fine to do it just in the prose compile step, but I'm curious why it came to the decision to defer it for prose run to make sure I'm not missing anything.

@@ -0,0 +1,226 @@
import { readdir, readFile, stat } from "node:fs/promises";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think we want the logic for "searching for skills that are required" to be a harness responsibility.

It should be a compiler/program-level responsibility.

Keep in mind the goal for prose is to still be harness-agnostic, and if we put this logic here instead of in the compiler (in markdown), then running a Prose-with-Skills program on a different harness will not behave as we expect.

rawwerks and others added 2 commits May 4, 2026 19:36
…lution

Implements the spec from issue #60. Components declare required harness
skills via a `### Skills` section (colon form, e.g. `document-skills:pdf`).
`prose compile` resolves declared skills against ./skills/, ~/.claude/skills/,
~/.codex/skills/, and ~/.agents/skills/, and fails closed with
`skill_unresolved` before forwarding to the agent harness when any are
missing.

- Spec: skills/open-prose/contract-markdown.md gains a ### Skills row in
  the Canonical Sections table and a ## Skills H2 covering colon naming,
  search order, the BYO-harness invariant, and fail-closed semantics.
- Implementation: tools/cli/src/skills/declared.ts (parser + resolver +
  directory walker + DeclaredSkillsUnresolvedError). Pure functions; no
  I/O beyond readFile / readdir / stat.
- Wiring: tools/cli/src/commands/compile.ts pre-checks declared skills
  before forwarding the compile prompt; fails closed with
  CompileValidationError when any are unresolved. Gated behind the
  existing skillPreflight option for test parity.
- Example: skills/open-prose/examples/declared-skills/ shows the
  document-skills:pdf canonical pattern.
- Tests: 19 new (18 in declared.test.ts covering parser/resolver/walker/
  error formatter; 1 in cli.test.ts asserting compile fails closed before
  the harness is invoked when a declared skill is missing).
- BYO harness: OpenProse never installs harness skills; resolution failure
  is the user's signal to install the named skill themselves.

Resolves #60.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…r review

Address review feedback on #62:

- contract-markdown.md: drop the "not duplicated in frontmatter" clause —
  the rejected alternative shouldn't propagate into the spec.
- contract-markdown.md: fail-closed clause now mentions only `prose compile`;
  `prose run` enforcement is deferred per the PR description.
- compiler/index.prose.md: add a `skills_resolver` agent that owns the
  search-path order, scope aggregation, BYO invariant, and fail-closed
  semantics. Skill resolution is now a compiler/program-level
  responsibility, not a harness responsibility, so other harnesses running
  the compiler get the same behavior.
- skills/declared.ts: add a header comment pointing at the program-level
  spec; this module is the harness implementation of `skills_resolver`.
- examples/declared-skills/README.md: update wording to reference the
  compiler agent.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@rawwerks rawwerks force-pushed the spec/skills-section branch from eac2424 to d4ff12a Compare May 4, 2026 23:47
@rawwerks
Copy link
Copy Markdown
Contributor Author

rawwerks commented May 6, 2026

Dan, yes, the review comments on #62 were addressed in d4ff12a:

  • contract-markdown.md: removed the rejected frontmatter-alternative wording. The spec now just describes the accepted ### Skills section without carrying forward the “not duplicated in frontmatter” decision text.
  • contract-markdown.md: corrected the fail-closed wording to say prose compile only. prose run enforcement remains deferred, matching the PR description.
  • compiler/index.prose.md: moved the behavior into the compiler/program contract via the skills_resolver agent. That agent owns the search order, scope aggregation, BYO invariant, and skill_unresolved diagnostics. The CLI TypeScript remains the current harness implementation of that compiler step, but the semantics now live in the compiler program so other harnesses can implement the same behavior.

@rawwerks rawwerks merged commit 9856ac5 into main May 7, 2026
24 checks passed
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.

Spec proposal: declared agent skills on components

2 participants