synwire-agent-skills 0.1.0

Agent skills runtime for Synwire following the agentskills.io specification
Documentation

synwire-agent-skills

Agent skills runtime for Synwire, implementing the agentskills.io specification for discoverable, composable agent capabilities.

Overview

A skill is a self-contained directory that an agent can discover and invoke. Skills provide natural-language instructions, optional runtime scripts, reference material, and static assets. Synwire extends the base spec with an optional runtime field to support scripted execution.

Directory layout

my-skill/
├── SKILL.md          — manifest (YAML frontmatter) + instruction body
├── scripts/          — optional runtime scripts (Lua, Rhai, WASM)
├── references/       — optional reference material (docs, specs)
└── assets/           — optional static assets (templates, configs)

SKILL.md format

SKILL.md begins with a YAML frontmatter block enclosed by --- delimiters, followed by free-form Markdown instructions.

Frontmatter fields

Field Required Constraints Description
name Yes 1–64 chars, [a-z0-9-] Unique skill identifier
description Yes 1–1024 chars Human-readable purpose
license No SPDX identifier e.g. MIT, Apache-2.0
compatibility No Semver expression e.g. >=0.1.0
allowed-tools No Space-separated tool names Tools this skill may invoke
runtime No See runtimes table Synwire extension — how to execute
metadata No key: value map Arbitrary metadata (author, version, tags)

Example

---
name: summarise-pr
description: "Fetch a GitHub PR, summarise the diff, and post a review comment."
license: MIT
compatibility: ">=0.1.0"
allowed-tools: read write grep semantic_search
runtime: lua
metadata:
  author: example
  version: "1.0.0"
---

## Instructions

Use this skill when asked to review a pull request. Steps:

1. Read the PR diff using the `read` tool.
2. Search for related tests with `semantic_search`.
3. Summarise changes and post a comment.

Name validation

  • Lowercase letters (a-z), digits (0-9), and hyphens (-) only
  • 1 to 64 characters
  • Must match the skill directory name

Runtimes

Runtime runtime field value Description
Lua lua Lua scripts via mlua (sandboxed)
Rhai rhai Rhai scripts (safe by default, no I/O)
WebAssembly wasm WASM modules via extism
Tool sequence tool-sequence Declarative JSON list of tool invocations
External external Script executed as a subprocess
None (omit) Instruction-only skill (no script execution)

Omitting runtime produces an instruction-only skill: the agent reads the SKILL.md body and follows it without any programmatic execution.

Discovery

Skills are discovered from two locations, in priority order:

Location Path Scope
Project-local .<product>/skills/ relative to project root Project
Global $DATA/<product>/skills/ All projects

Project-local skills take precedence over global skills with the same name. Skills are loaded at agent startup; the registry provides names and descriptions immediately (progressive disclosure). Full skill bodies are loaded only when a skill is activated.

use synwire_agent_skills::{loader::SkillLoader, registry::SkillRegistry};
use std::path::Path;

let loader = SkillLoader::new();

// Scan global skills directory
let global = loader.scan(Path::new("/home/user/.local/share/myapp/skills")).await?;
// Scan project-local directory
let local  = loader.scan(Path::new(".myapp/skills")).await?;

let mut registry = SkillRegistry::new();
for entry in local.into_iter().chain(global) {
    registry.register(entry);
}

// Progressive disclosure: only names + descriptions loaded
for (name, desc) in registry.list_names_and_descriptions() {
    println!("{name}: {desc}");
}

// Full body loaded on activation
let skill = registry.get("summarise-pr")?;

Progressive disclosure

Loading all skill bodies at startup would consume significant tokens. Instead, the registry loads:

  • At startup: name and description from frontmatter only
  • On activation: full SKILL.md body + scripts

This keeps agent context small — typically 50–200 tokens per skill at startup regardless of body length.

Writing a Lua skill

-- scripts/summarise_pr.lua
-- Context is provided as a global `ctx` table.

local diff = ctx.tool("fs.read", { path = ctx.args.pr_diff_path })
local results = ctx.tool("code.search_semantic", { query = "related tests" })

return "Summary: " .. diff:sub(1, 500) .. "\n\nRelated: " .. tostring(#results) .. " results"

Writing a Rhai skill

// scripts/check_style.rhai
let content = tool("fs.read", #{ path: args.file });
if content.contains("unwrap()") {
    return "Found unwrap() calls — consider handling errors explicitly.";
}
"No issues found."

Writing a tool-sequence skill

A JSON array of tool invocations executed in order. Outputs from earlier steps are available as $step_N:

[
  { "tool": "fs.glob",              "args": { "pattern": "**/*.rs" } },
  { "tool": "code.search_semantic","args": { "query": "error handling", "top_k": 5 } }
]

Installing skills

Global install

Copy the skill directory to $DATA/<product>/skills/:

cp -r my-skill ~/.local/share/myapp/skills/

Project-local install

Copy to .<product>/skills/ in your project root:

cp -r my-skill .myapp/skills/

From synwire-mcp-server

The MCP server auto-discovers skills from both locations on startup. No restart required after adding a skill — restart the MCP server to pick up new skills.

Feature flags

Feature Description
lua Enable Lua runtime via mlua
rhai Enable Rhai runtime
wasm Enable WebAssembly runtime via extism

All runtimes are optional to keep binary size small. Enable only the runtimes your skills require.

[dependencies]
synwire-agent-skills = { version = "0.1", features = ["lua", "rhai"] }