Skip to content

Latest commit

 

History

History
136 lines (96 loc) · 7.91 KB

File metadata and controls

136 lines (96 loc) · 7.91 KB

Agent Instructions

Project Perspective

Agent Skill is a personal variant of the upstream Agent Skills specification: frontmatter-free, XML-mixed Markdown wrapped in a single <skill> element with three fixed-order section tags (<purpose> → <guidelines> → <implementation>). Metadata lives on the root tag as XML attributes instead of YAML frontmatter.

This repository ships two artifacts:

  1. The specification (SPECIFICATION.md) - authoritative for format requirements.
  2. A reference parser (src/, published as @neabyte/agent-skill) - a text-to-data function with no runtime dependencies and no filesystem I/O.

Keep the format small. Every new requirement adds work for every implementation and every skill author. Prefer progressive disclosure: keep details in their natural source (spec, README, parser) instead of duplicating rules here.

Authority and Boundaries

SPECIFICATION.md is authoritative for format requirements. Explanatory documentation, examples, tests, and the reference parser do not add requirements to the format. When these surfaces disagree, surface the discrepancy and resolve it at the spec level rather than treating existing parser behavior as normative.

Preserve the distinction between:

  • The format - what a valid SKILL.md must contain.
  • Author choices - content inside <purpose>, <guidelines>, <implementation>.
  • Client / tooling choices - how a parser or agent consumes the parsed result.

The reference parser under src/ is small on purpose. It exposes one class Skill with one static method Skill.parse(source: string): SkillResult[]. Refactors that keep behavior identical while improving readability, error messages, or type inference are welcome. Feature additions belong in a Discussion before code.

Why This Format for Tooling

For agents and CLI tooling that need to load, index, or dispatch skills at runtime, this variant aims to reduce integration cost by removing common sources of friction:

  • No frontmatter to handle. No YAML parser, no dual-format edge cases (frontmatter vs. body drift), no --- fence detection. A skill is one XML-mixed Markdown document from start to finish.
  • Metadata and prompt live together. Root attributes on <skill> (name, self-invoked, license, version, compatibility, plus custom kebab-case keys) sit inside the same element as the body, so metadata is less likely to drift out of sync with the prompt. Renaming a skill means editing one attribute in the same file the model reads.
  • Fixed section order. <purpose> → <guidelines> → <implementation> is required by the spec and enforced by the parser. Downstream tooling can index sections positionally without heuristics.
  • Word-count guidance (recommended 9-13 words for <purpose> body, 6-9 words for hint attributes; not enforced by the parser) keeps discovery-time payloads small when fanning out across many skills.
  • Progressive disclosure. Root attributes + <purpose> are usually enough to decide whether to activate a skill; the full body loads on activation; assets/, references/, scripts/ load on demand.
  • No runtime dependencies, no filesystem access. The parser is a synchronous string-in / object-out function, so it should run without changes on current versions of Node, Deno, and Bun, and inside sandboxed agent runtimes.

If you are building an agent framework, IDE extension, or CLI orchestrator that needs to enumerate skills and route model calls to the right one, this format is intended to let you do it with a single regex-and-slice pass over each SKILL.md.

Install and Quick Parse

Install for a Project

npm install @neabyte/agent-skill

Deno / Bun / browsers can import directly from a CDN without installing:

import Skill from 'https://esm.sh/@neabyte/agent-skill'
// or
import Skill from 'https://cdn.jsdelivr.net/npm/@neabyte/agent-skill/dist/index.mjs'

One-Liner Parse via node --eval or deno eval

For CLI integration, ad-hoc validation, or shell pipelines, the parser can be driven inline without a project scaffold. The examples below read from stdin end-to-end.

Node (>=24) - validate a SKILL.md from stdin and print JSON:

cat path/to/SKILL.md | node --input-type=module --eval "
import Skill from '@neabyte/agent-skill'
const chunks = []
for await (const c of process.stdin) chunks.push(c)
const src = Buffer.concat(chunks).toString('utf8')
console.log(JSON.stringify(Skill.parse(src), null, 2))
"

Deno - same flow, no install step required:

cat path/to/SKILL.md | deno eval "
import Skill from 'npm:@neabyte/agent-skill'
const src = new TextDecoder().decode(await new Response(Deno.stdin.readable).arrayBuffer())
console.log(JSON.stringify(Skill.parse(src), null, 2))
"

Bun - one command, no build step:

cat path/to/SKILL.md | bun -e "
import Skill from '@neabyte/agent-skill'
const src = await Bun.stdin.text()
console.log(JSON.stringify(Skill.parse(src), null, 2))
"

Extract only root attributes (fast discovery pass):

cat path/to/SKILL.md | deno eval "
import Skill from 'npm:@neabyte/agent-skill'
const src = new TextDecoder().decode(await new Response(Deno.stdin.readable).arrayBuffer())
for (const entry of Skill.parse(src)) console.log(entry.skill)
"

Exit non-zero on invalid skill (CI gate):

node --input-type=module --eval "
import Skill from '@neabyte/agent-skill'
import { readFileSync } from 'node:fs'
try { Skill.parse(readFileSync(process.argv[1], 'utf8')); process.exit(0) }
catch (e) { console.error(e.message); process.exit(1) }
" path/to/SKILL.md

These snippets are usually enough to wire the parser into a Makefile, pre-commit hook, GitHub Action, or agent bootstrap script without adding a permanent dependency on a build system.

Integration Guidance

When embedding the parser inside a larger tool:

  • Cache parse results by file mtime and size so Skill.parse runs only once per revision instead of on every model call, since a single regex-and-slice pass is already the discovery-time cost.
  • Route requests on skill.name first and then on self-invoked, remembering that a skill declared with self-invoked="false" must run only when the user explicitly names it.
  • Treat every root attribute besides name, self-invoked, license, compatibility, and version as an opaque kebab-case string owned by tooling, and refrain from enforcing schemas that the specification does not define.
  • Preserve the whitespace inside <purpose>, <guidelines>, and <implementation> exactly as parsed, because the parser only trims one leading and one trailing newline and any further reflow will corrupt the prompt.
  • Match errors on the tag name embedded in each SyntaxError message (missing <tag> element, unclosed <tag> element, or nested <skill> element) rather than the full string when rendering user-facing diagnostics.
  • Assume the parser is synchronous and side-effect free, which means it is safe to invoke inside a worker, an eval sandbox, or a hot request handler without additional isolation.

Documentation

README.md covers user-facing usage. SPECIFICATION.md is the format contract. CONTRIBUTING.md owns contribution scope, disclosure policy for AI-assisted contributions, and the local development commands (deno task check, deno task test, npm run build). Read CONTRIBUTING.md before opening a PR or Discussion.

Contributions

Follow CONTRIBUTING.md. Highlights:

  • Small, focused PRs. One logical change per PR.
  • Verify locally with deno task check and deno task test before opening a PR.
  • Disclose AI assistance in the PR or issue description (trivial fixes exempt).
  • Out of scope right now: community skill submissions, frontmatter support, sweeping architectural rewrites.