Skip to content

feat(discovery): buildSkillMd renderer for /skill.md agent surface#5

Merged
vvillait88 merged 5 commits into
mainfrom
feat/skill-md-discovery
May 2, 2026
Merged

feat(discovery): buildSkillMd renderer for /skill.md agent surface#5
vvillait88 merged 5 commits into
mainfrom
feat/skill-md-discovery

Conversation

@vvillait88
Copy link
Copy Markdown
Contributor

Summary

  • New discovery builder `buildSkillMd` in `@agent-score/commerce/discovery` that emits a Claude-Skill-compatible manifest (YAML frontmatter + markdown body) for an agent-commerce merchant.
  • Renders strictly agent-facing data: rails accepted, compatible clients per rail, identity requirements as outcomes, shipping policy, endpoints, triggers, support links. No internal posture (`failOpen`, mount-strategy, KYC vendor, defense parameters, idempotency construction) leaks into the surface.
  • Per-rail compatible-clients table sources from the same SDK constant (`compatibleClientsByRails`, extracted from `challenge/agent_instructions.ts`) that drives the live 402 body's `compatible_clients` field — single source of truth across surfaces.
  • Bump to 1.2.0 (additive surface, no breaking changes).

Test plan

  • 30 unit tests covering every section, optional fields, output hygiene, and the no-internal-disclosure boundary
  • `bun run lint` clean
  • `bun run typecheck` clean
  • Coverage: branches 90.27% (over 90% threshold)
  • CI green

vvillait88 and others added 3 commits May 2, 2026 09:30
Adds a new discovery builder that emits a Claude-Skill-compatible manifest
(YAML frontmatter + markdown body) describing the merchant's agent-facing
contract: payment rails, compatible clients per rail, identity requirements
as outcomes, shipping policy, endpoints, triggers, support links.

Renders strictly agent-facing data — no failOpen, no mount-strategy names,
no KYC vendor names, no defense parameters, no idempotency construction
shape. Internal posture stays in merchant runtime config.

Compatible-clients-per-rail table sources from the same SDK constant
(compatibleClientsByRails, extracted from challenge/agent_instructions.ts)
that drives the live 402 body's compatible_clients field, so updating a
smoke-verified client in one place propagates to skill.md, the 402 body,
and any future surface that consumes it.

Bump to 1.2.0 (additive surface, no breaking changes).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add /skill.md to defaultDiscoveryPaths so the existing noindex
  middleware and discovery-path predicate auto-recognize the new
  surface.
- Update README + CLAUDE.md to mention buildSkillMd alongside the
  other discovery builders.
- Update robots_tag tests to assert /skill.md is in the default set.

Keeps node + python parity (python-commerce ships the same change).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Addresses spec violations + cross-language parity issues from end-to-end
review against https://agentskills.io/specification:

P0 — spec violations:
- description / license / compatibility / allowed-tools / metadata-values now
  emitted as YAML double-quoted scalars. Fixes the colon / quote / newline
  parse failure the spec explicitly warns about.
- metadata.version emitted as quoted string ("1") not int (1). Spec requires
  metadata values to be strings.

P1 — validation + exports:
- Validate name against the spec regex (1-64 chars, lowercase alphanumeric +
  hyphens, no leading / trailing / consecutive hyphens). Throws with a clear
  agentskills.io-spec message on bad input.
- Validate description length ≤1024 + non-empty.
- Validate compatibility length ≤500.
- Re-export RailKey + compatibleClientsByRails from src/discovery so callers
  don't have to reach into challenge/.

P2 — additional spec fields:
- Surface optional license, compatibility, allowed-tools frontmatter fields.
- Move homepage from top-level to metadata.homepage (top-level non-spec
  fields belong under metadata per spec).

P3 — edge cases:
- Drop compatibleClients overrides for rails not in acceptedRails (silent
  filter).
- Escape pipe characters in markdown table cells (file labels, file URLs,
  endpoint paths, endpoint descriptions) so embedded `|` doesn't break rows.
- Add /SKILL.md (uppercase) to defaultDiscoveryPaths so the canonical-cased
  alias inherits the noindex exemption.

Tests: 38 cases covering spec-violation regression + edge cases + escape
behavior + the new validation throw paths. Coverage 90.36% (over 90%).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread src/discovery/skill_md.ts Fixed
vvillait88 and others added 2 commits May 2, 2026 10:27
End-to-end review flagged version: 0 as potential parity drift between
node (?? nullish coalescing) and python (str()). Verified both pass 0
through unchanged; this test locks the contract so a future refactor to
|| (falsy) wouldn't silently change emission.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CodeQL flagged the markdown-cell sanitizer as incomplete escaping: prior
implementation escaped \`|\` but not \`\\\`, so an input like \`a\\|b\` rendered
as \`a\\\\|b\` which markdown reads as literal-backslash + cell-terminator —
breaking the row.

Fix matches the spec'd two-pass escape (backslash first, then pipe), same
order quoteYaml uses. Test asserts \`a\\|b\` round-trips as \`a\\\\\\|b\`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vvillait88 vvillait88 merged commit cd90a83 into main May 2, 2026
6 checks passed
@vvillait88 vvillait88 deleted the feat/skill-md-discovery branch May 2, 2026 17:32
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