Introduction
skillc is the development kit for Agent Skills — the open format for extending AI agent capabilities with specialized knowledge and workflows.
At a Glance
SKILL.md (source)
│
┌───────────────┴───────────────┐
│ │
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ skillc (optional) │ │ git push │
│ │ │ ↓ │
│ lint · build │ │ npx skills add │
│ stats · search │ │ ↓ │
│ ↓ │ │ Claude · Cursor │
│ local testing │ │ Codex · Copilot │
└─────────────────────┘ └─────────────────────┘
skillc helps authors validate and test skills locally. Consumers just run npx skills add — no compilation needed.
Who is this for?
| Audience | What skillc provides |
|---|---|
| Skill authors | Create, validate, and test skills before publishing |
| Power users | Track how agents use skills locally |
Core Commands
| Command | What it does |
|---|---|
init | Create a new skill or project structure |
lint | Validate structure, frontmatter, and links |
build | Compile for local testing and deploy to agents |
list | Show all managed skills |
outline | List sections across all files |
show | Retrieve specific section content |
open | Read a file |
search | Full-text search with FTS5 |
sources | Tree view of source files |
stats | Usage analytics |
sync | Merge local logs to global store |
mcp | Start MCP server for agent integration |
Common Options
| Command | Option | Description |
|---|---|---|
outline | --level <n> | Filter to headings ≤ level n (1-6) |
show | --max-lines | Truncate output to first n lines |
open | --max-lines | Truncate output to first n lines |
stats | --group-by | Aggregate by: sections, files, commands, projects, errors, search |
Two Interfaces
| Interface | For | Example |
|---|---|---|
CLI (skc) | Humans, scripts, CI | skc lint my-skill |
| MCP | AI agents directly | skc_lint tool |
Both expose the same functionality. MCP provides structured output for agent integration.
Key Concepts
Source vs. Compiled
| Source | Compiled | |
|---|---|---|
| What | Your SKILL.md with full content | Stub directing agents to gateway commands |
| For | Publishing to GitHub | Local development/testing |
| Publish? | Yes | No |
Always push source, never compiled output.
Skill Resolution
When you run skc <command> my-skill, skillc searches:
- Project:
.skillc/skills/my-skill/(from current directory upward) - Global:
~/.skillc/skills/my-skill/
Project-local skills take precedence.
Project Detection
skillc walks upward from your current directory looking for .skillc/:
~/projects/myapp/src/ ← you are here
~/projects/myapp/.skillc/ ← project root found
Run commands from anywhere within a project.
Workflow Guides
- Authoring — create and structure skills
- Validating — lint and check quality
- Testing — local testing with gateway commands
- Publishing — git-based distribution
- Analytics — track skill usage
Supported Agents
skillc deploys to these agent directories:
| Target | Directory |
|---|---|
claude | ~/.claude/skills/ |
codex | ~/.codex/skills/ |
copilot | ~/.github/skills/ |
cursor | ~/.cursor/skills/ |
gemini | ~/.gemini/skills/ |
kiro | ~/.kiro/skills/ |
opencode | ~/.opencode/skills/ |
trae | ~/.trae/skills/ |
Use skc build my-skill --target cursor to deploy to a specific agent.
Authoring Skills
This guide covers creating and structuring skills with skillc.
Initialize a project
Before creating skills, initialize skillc in your project:
skc init
This creates .skillc/skills/ where your skill sources live.
Create a new skill
skc init my-skill
This creates .skillc/skills/my-skill/SKILL.md with minimal frontmatter:
---
name: my-skill
description: A brief description of what this skill does
---
# my-skill
Your skill content here...
Skill structure
A skill is a directory containing at least SKILL.md. You can add additional markdown files for organization:
.skillc/skills/my-skill/
├── SKILL.md # Required: main entry point
├── examples/
│ └── usage.md # Optional: examples
├── reference/
│ └── api.md # Optional: reference docs
└── troubleshooting.md # Optional: troubleshooting
Frontmatter
Every SKILL.md must have YAML frontmatter with at least:
---
name: my-skill
description: A brief description
---
Optional fields:
---
name: my-skill
description: A brief description
version: 1.0.0
author: Your Name
tags: [rust, development]
---
Writing effective content
Keep it scannable
Agents read skills to find relevant information quickly. Use:
- Clear headings (H2 for major sections, H3 for subsections)
- Bullet points for lists
- Code blocks for examples
Use progressive disclosure
Put the most important information first. Detailed reference material can go in separate files.
Include activation triggers
Tell agents when to use this skill:
## When to use this skill
Use this skill when:
- Working with Rust projects
- Debugging lifetime errors
- Optimizing Rust performance
Global skills
To create a skill that’s available across all projects:
skc init my-skill --global
This creates the skill in ~/.skillc/skills/my-skill/.
Next steps
- Validate your skill with
skc lint - Test locally with gateway commands
- Publish when ready
Validating Skills
This guide covers using skc lint to validate skill quality before publishing.
Basic usage
skc lint my-skill
This checks your skill against quality rules and reports any issues.
What lint checks
See RFC-0008:C-REGISTRY for the full rule specification.
Meta rules (SKL0xx)
- SKL001: Skip compiled skills (internal)
Frontmatter rules (SKL1xx)
- SKL100: Frontmatter must be valid YAML
- SKL101:
namefield required - SKL102:
nameformat (lowercase, hyphens, digits only) - SKL103:
namelength (1-64 chars) - SKL104:
nameshould match directory name - SKL105:
descriptionfield required - SKL106:
descriptionmust be non-empty - SKL107:
descriptionlength (10-200 chars recommended) - SKL108: Include activation triggers
- SKL109: Only known frontmatter fields allowed
Structure rules (SKL2xx)
- SKL201: SKILL.md size warning (>500 lines)
- SKL202: Missing H1 heading
- SKL203: H1 should match skill name
- SKL204: First heading should be H1
- SKL205: No skipped heading levels
Link rules (SKL3xx)
- SKL301: Internal links must resolve
- SKL302: Anchor links must resolve
- SKL303: Links must not escape skill root
File rules (SKL4xx)
- SKL401: No orphan files (files not linked from SKILL.md)
Output formats
Text (default)
skc lint my-skill
my-skill: 2 errors, 1 warning
SKILL.md:1:1 error[SKL103]: missing required frontmatter field: description
SKILL.md:5:1 warning[SKL107]: skill should include activation triggers
examples/usage.md:12:1 error[SKL301]: broken link: ./nonexistent.md
JSON
skc lint my-skill --format json
{
"skill": "my-skill",
"diagnostics": [
{
"rule": "SKL103",
"severity": "error",
"file": "SKILL.md",
"line": 1,
"message": "missing required frontmatter field: description"
}
]
}
Fixing issues
Missing frontmatter fields
Add required fields to your SKILL.md:
---
name: my-skill
description: Helps with X by providing Y
---
Missing activation triggers
Add a section explaining when agents should use the skill:
## When to use this skill
Use this skill when:
- Condition A
- Condition B
Or use frontmatter:
---
name: my-skill
description: ...
activate when: working with Rust projects
---
Broken links
Check that all internal links point to existing files:
<!-- Bad -->
[See examples](./examples.md) <!-- file doesn't exist -->
<!-- Good -->
[See examples](./examples/usage.md) <!-- file exists -->
Lint all skills
To lint all skills in your project:
skc lint
Exit codes
0— No errors (warnings are OK)1— One or more errors found
Use exit codes in CI to block publishing of invalid skills.
Next steps
- Test locally with gateway commands
- Publish when validation passes
Testing Skills Locally
This guide covers testing skills with gateway commands before publishing.
Why test locally?
Before publishing, you want to verify:
- Agents can navigate your skill’s structure
- Content is accessible via gateway commands
- Search returns relevant results
Build for local testing
skc build my-skill
This compiles your skill and deploys it to the agent directory (e.g., ~/.claude/skills/).
Note: The compiled output is a stub that references gateway commands. This is for local testing only — you publish the source, not the compiled output.
Gateway commands
View structure
skc outline my-skill
Shows all sections in your skill:
# my-skill
## Installation
## Usage
### Basic usage
### Advanced options
## Troubleshooting
Read a section
skc show my-skill --section "Installation"
Displays the content of that section. This simulates how an agent would request specific content.
Open a file
skc open my-skill examples/usage.md
Opens a specific file from the skill. Use this for non-markdown files or when you need the entire file.
List source files
skc sources my-skill
Lists all files in the skill as a tree:
my-skill/
├── SKILL.md
├── examples/
│ └── usage.md
└── reference/
└── api.md
Use --format json for machine-readable output:
skc sources my-skill --format json
Search content
skc search my-skill "error handling"
Full-text search across all skill content:
examples/usage.md:45: ...proper error handling is crucial...
reference/api.md:112: ...the error handling middleware...
Test with an agent
After building, start a conversation with an agent that has access to ~/.claude/skills/ (or your target agent directory).
Ask the agent to use your skill and observe:
- Does it find the skill?
- Does it navigate to relevant sections?
- Does it understand the content?
Deploy to multiple agents
Test with different agents:
skc build my-skill --target claude,cursor,codex
Iterate
- Edit source files in
.skillc/skills/my-skill/ - Rebuild:
skc build my-skill - Test with gateway commands or agent
- Repeat
No need to restart agents — they read fresh content on each request.
Next steps
- Check usage analytics to see what agents access
- Publish when testing is complete
Publishing Skills
This guide covers publishing skills for distribution via the skills ecosystem.
What you publish
You publish source files, not compiled output.
Published (source): NOT published (compiled):
├── skills/ ├── SKILL.md (stub)
│ └── my-skill/ └── .skillc-meta/
│ ├── SKILL.md ├── manifest.json
│ └── examples/ └── index.tantivy/
The compilation step (skc build) is for local development and testing. Consumers download source directly and don’t need skillc.
Repository structure
The skills tool expects this structure:
your-repo/
└── skills/
└── my-skill/
├── SKILL.md
└── ...
Publishing workflow
Option 1: Dedicated skills repository
Make .skillc/ its own git repository:
cd .skillc
git init
git add skills/
git commit -m "Initial skill"
git remote add origin git@github.com:you/my-skills.git
git push -u origin main
The repo root becomes the published structure:
my-skills/ # repo root
└── skills/
└── my-skill/
Option 2: Monorepo with skills
If your project already has a skills/ directory, you can author directly there:
# Initialize skillc to use skills/ instead of .skillc/skills/
# (configure via .skillc/config.toml if needed)
Or maintain both and sync:
# Your project structure
project/
├── .skillc/
│ └── skills/my-skill/ # author here
├── skills/
│ └── my-skill/ # publish here (copy or symlink)
└── src/
Before publishing
Run through this checklist:
- Lint passes:
skc lint my-skillreports no errors - Content complete: All sections filled in
- Examples work: Code examples are tested
- Links valid: No broken internal links
Consumer experience
After you publish, consumers install with:
npx skills add github:you/my-skills
This downloads skills/my-skill/ to their agent directory. They don’t need skillc — the agent reads source files directly.
Versioning
Use git tags or branches for versioning:
git tag v1.0.0
git push --tags
Consumers can install specific versions:
npx skills add github:you/my-skills@v1.0.0
Multiple skills
One repository can contain multiple skills:
my-skills/
└── skills/
├── rust/
│ └── SKILL.md
├── cuda/
│ └── SKILL.md
└── typst/
└── SKILL.md
Consumers choose which to install:
npx skills add github:you/my-skills --skill rust
Next steps
- Track usage after publishing
- Share your skill on skills.sh
Usage Analytics
This guide covers tracking how agents use your skills locally.
Why analytics?
Understanding usage helps you:
- Identify which sections agents read most
- Find content that’s never accessed (candidates for removal)
- Optimize skill structure based on real patterns
How it works
When you use gateway commands (skc show, skc open, skc search), skillc logs each access:
- Timestamp
- Command used
- Skill and section accessed
- Working directory context
Logs are stored locally in .skillc-meta/logs.db within each skill’s runtime directory.
View statistics
skc stats my-skill
Example output:
my-skill usage statistics (last 30 days)
Total accesses: 47
Unique sections: 12
Top sections:
1. Installation (15 accesses)
2. Troubleshooting (12 accesses)
3. API Reference (8 accesses)
Unused sections:
- Contributing
- Changelog
Access by command:
show: 35
search: 8
open: 4
Filter by time
skc stats my-skill --since 7d # Last 7 days
skc stats my-skill --since 30d # Last 30 days
skc stats my-skill --since 2024-01-01
JSON output
For programmatic analysis:
skc stats my-skill --format json
{
"skill": "my-skill",
"period": {
"start": "2024-01-01T00:00:00Z",
"end": "2024-01-30T23:59:59Z"
},
"total_accesses": 47,
"sections": [
{ "name": "Installation", "count": 15 },
{ "name": "Troubleshooting", "count": 12 }
]
}
Sync local logs
If you work across multiple machines or projects, you may have fragmented logs. Sync them to a central location:
skc sync
This moves local fallback logs to the primary runtime location.
Privacy
- All analytics are local only — nothing is sent externally
- Logs contain access patterns, not content
- You control what to track and what to delete
Acting on analytics
High-traffic sections
If a section gets many hits:
- Ensure it’s well-written and complete
- Consider expanding with more detail
- Keep it near the top of your skill
Unused sections
If a section is never accessed:
- Is the heading discoverable? (Check
skc outline) - Is the content useful? Consider removing it
- Should it be merged with another section?
Search patterns
If certain queries appear often:
- Add a section that directly answers them
- Improve headings to match search terms
Next steps
- Use analytics to iterate on your skill structure
- Publish updates based on usage patterns
RFC-0000: skillc — A Development Kit for Skill Writers
Version: 0.1.0 | Status: normative | Phase: stable
1. Summary
[RFC-0000:C-VISION] Vision (Informative)
skillc is a development kit for Agent Skills — the open format for extending AI agent capabilities with specialized knowledge and workflows.
Agent Skills define what a skill is: a folder with a SKILL.md file containing metadata and instructions. skillc provides the how: tooling to author, validate, optimize, and instrument skills throughout their lifecycle.
Where the Agent Skills specification ends, skillc begins.
Since: v0.1.0
2. Motivation
[RFC-0000:C-PROBLEM] Problem Statement (Informative)
The Agent Skills format solves the consumption problem: a simple, portable way for agents to discover and load specialized knowledge. But skill authoring remains ad-hoc.
Today, skill writers:
- Write skills blind — No data on which sections agents actually read
- Guess at structure — No tooling to validate or optimize content organization
- Can’t iterate effectively — No feedback loop between publishing and agent usage
- Manage skills manually — No registry, no build pipeline, no version tracking
The Agent Skills spec recommends keeping SKILL.md under 500 lines and using progressive disclosure, but provides no tooling to enforce or automate these practices.
Skill writers need a development kit.
Since: v0.1.0
3. Scope
[RFC-0000:C-SCOPE] Scope (Informative)
skillc complements the Agent Skills ecosystem by providing:
- Scaffolding — Initialize properly-structured skill directories
- Validation — Check skills conform to the spec (extends
skills-ref validate) - Compilation — Generate optimized stubs that enforce size limits and progressive disclosure
- Instrumentation — Trace agent access to skill content (sections read, files opened)
- Analytics — Aggregate usage data to identify high-value vs. ignored content
- Registry — Track skills across source and runtime locations
skillc is a local CLI tool. It works with the existing Agent Skills format — no proprietary extensions, no lock-in.
Since: v0.1.0
[RFC-0000:C-NONGOALS] Non-Goals (Informative)
skillc does not:
- Define a new skill format — We build on Agent Skills, not compete with it
- Replace
skills-ref— We extend validation, not duplicate it - Host or distribute skills — Publishing is out of scope for v0
- Modify agent behavior — Agents consume skills normally; instrumentation is transparent
- Require infrastructure — No servers, no cloud, no accounts
Since: v0.1.0
4. Principles
[RFC-0000:C-PRINCIPLES] Design Principles (Informative)
1. Extend, don’t reinvent Agent Skills is an open standard with broad adoption. skillc adds tooling; it doesn’t fork the format.
2. Observability unlocks iteration You can’t improve what you can’t measure. Instrumented access is the foundation for data-driven skill refinement.
3. Progressive disclosure by default The spec recommends it; skillc enforces it. Compiled stubs expose structure without dumping content.
4. Local-first, zero infrastructure skillc runs on your machine. Skills are files. No accounts, no network, no vendor lock-in.
5. Minimal viable tooling Start with the smallest useful toolkit. Add capabilities only when clearly needed.
Since: v0.1.0
5. Compatibility Guarantees
[RFC-0000:C-COMPAT-FORMAT] Format Compatibility (Normative)
skillc MUST accept any directory that conforms to the Agent Skills specification.
skillc MUST NOT require proprietary extensions, additional metadata fields, or non-standard file structures to function.
Since: v0.1.0
[RFC-0000:C-COMPAT-OFFLINE] Offline Operation (Normative)
Core skillc functionality — authoring, validation, compilation, instrumentation, and analytics — MUST operate without network access.
Optional features MAY require network access, but MUST be explicitly opt-in and MUST NOT be required for basic skill development workflows.
skillc MUST NOT require accounts or authentication for core functionality.
Since: v0.1.0
[RFC-0000:C-COMPAT-PORTABLE] Portability (Normative)
Skill source directories managed by skillc MUST remain valid Agent Skills per the specification.
Compiled stubs MAY instruct agents to use skillc gateway commands for content access. Instrumented tracing is only available when agents access content through skillc.
skillc MAY provide options to include source references or mappings in compiled output, enabling fallback access when skillc is unavailable. The mechanism for source mapping is implementation-defined.
Since: v0.1.0
Changelog
v0.1.0 (2026-01-30)
Initial release
RFC-0001: Skill Compilation
Version: 0.2.1 | Status: normative | Phase: test
1. Summary
[RFC-0001:C-OVERVIEW] Overview (Informative)
Skill compilation transforms a skill source directory into a runtime-ready artifact.
The compiler reads an Agent Skills directory, extracts metadata and structure, and produces:
- A stub — a compact
SKILL.mdthat instructs agents to use gateway commands - A manifest — metadata for build tracking and change detection
Compilation enforces progressive disclosure: the stub exposes structure without content, directing agents to retrieve sections on-demand through skillc.
Since: v0.1.0
2. Specification
[RFC-0001:C-INPUT] Compilation Input (Normative)
The compiler MUST accept any directory that is a valid Agent Skill per RFC-0000:C-COMPAT-FORMAT.
The compiler MUST read the following from the source directory:
SKILL.md— extractnameanddescriptionfrom YAML frontmatter- All
.mdfiles — extract heading structure for outline generation - Directory structure — enumerate files for source listing
The compiler MUST fail with a clear error if:
SKILL.mdis missingSKILL.mdlacks requirednameordescriptionfrontmatter fields
Since: v0.1.0
[RFC-0001:C-OUTPUT] Compilation Output (Normative)
The compiler MUST produce the following outputs in the runtime directory:
SKILL.md— the compiled stub (see RFC-0001:C-STUB).skillc/manifest.json— build metadata (see RFC-0001:C-MANIFEST)
The compiler MUST create the runtime directory if it does not exist.
The compiler MUST NOT copy source content to the runtime directory. Only the stub, manifest, and log directories are permitted.
Since: v0.1.0
[RFC-0001:C-STUB] Stub Format (Normative)
The compiled stub MUST be a valid Agent Skills SKILL.md file.
The stub MUST include:
- YAML frontmatter with
nameanddescription(preserved from source) - A notice that agents should use gateway commands, not read sources directly
- A statement that agents SHOULD prefer MCP tools (
skc_outline,skc_show,skc_search, etc.) if the skillc MCP server is available, for better performance and structured output - Gateway command examples as CLI fallback:
skc outline,skc show --section,skc open,skc sources - A section listing per RFC-0001:C-SECTIONS
The stub MUST NOT include:
- Source content beyond headings
- Source file listings (use
skc sourcesinstead) - Implementation details or internal paths
- References to absolute filesystem paths
The stub format is designed to fit within agent context limits while providing enough structure for agents to navigate the skill.*
Since: v0.1.0
[RFC-0001:C-MANIFEST] Manifest Format (Normative)
The manifest MUST be a JSON file located at .skillc/manifest.json in the runtime directory.
The manifest MUST include:
skill— the skill nameversion— manifest schema version (integer)built_at— ISO 8601 timestamp of compilationsource_hash— content hash for change detection
The source hash MUST be computed as SHA-256 over the sorted list of (relative_path, file_hash) pairs from the source directory. This enables the compiler to detect when sources have changed since the last build.
The manifest MAY include additional fields for future extensibility.
Since: v0.1.0
[RFC-0001:C-ERRORS] Error Handling (Normative)
All compilation errors MUST exit with status 1 and print an error message to stderr.
Error codes: See RFC-0005:C-CODES for canonical error messages. This RFC uses:
| Condition | Error Code |
|---|---|
| Skill resolution failed | E001 or E010 |
| Missing frontmatter field | E011 |
| Path escapes skill root | E012 |
| Invalid CLI option | E100 |
Usage:
- E001/E010: Skill resolution failed per RFC-0007:C-RESOLUTION. See RFC-0005:C-CODES for when to use each.
- E011: SKILL.md exists but lacks required
nameordescriptionfrontmatter - E012: Symlink or path would escape the skill root directory
- E100: Unknown flag, missing required value, or other CLI parsing failure
Since: v0.1.0
[RFC-0001:C-SECTIONS] Section Listing Rules (Normative)
The stub section listing (“Top Sections”) MUST be generated according to these rules:
SKILL.md Sections
For the main SKILL.md file, the compiler MUST:
- Include all H1 headings at indent level 0
- Include H2 headings at indent level 1 (as children of the preceding H1)
- Exclude H3 and deeper headings (too detailed for stub)
- Limit to 15 entries; if more exist, append “… (N more)” indicator
The first H1 is NOT treated specially — it is included like any other H1.
Other Markdown Files
For all other .md files in the skill directory:
- Group all entries under a “References (query by title only)” label at indent level 0
- The hint “(query by title only)” clarifies that descriptions are for context only
- Use the first H1 heading from each file at indent level 1
- If a file has no H1 heading, use the relative file path as the label
- If the file has frontmatter with a
descriptionfield, append it inline after an em-dash:- Title — description - Description MUST be truncated to 120 characters with
…if longer - Limit to 15 entries; if more exist, append “… (N more)” indicator
- Files are listed in alphabetical order by path
The “References” section is only included if there are other .md files.
Reference File Frontmatter
Reference files MAY contain optional YAML frontmatter:
---
description: "Brief description of this reference document"
---
The description field:
- Is optional (no warning if absent)
- Should be concise (≤120 characters recommended)
- Is displayed inline in the stub after the title
- Is NOT part of the queryable section name
File Ordering
Files MUST be processed in this order:
SKILL.mdfirst (main document)- Other
.mdfiles in alphabetical order by path
Example Output
## Top Sections
- Rust CLI
- Default Flow
- Decision Tree
- Advanced Topics
- Performance
- References (query by title only)
- Clap Patterns — Advanced argument parsing examples
- Error Handling — anyhow vs thiserror patterns
- TUI Guide
In this example:
- “Rust CLI” and “Advanced Topics” are H1s from
SKILL.md - “Default Flow”, “Decision Tree”, “Performance” are H2s from
SKILL.md - “References (query by title only)” is the fixed grouping label with hint
- “Clap Patterns” and “Error Handling” have descriptions from their frontmatter
- “TUI Guide” has no description (frontmatter absent or no description field)
- When querying, use
skc show --section "Clap Patterns"(not the full line with description)
Since: v0.2.0
Since: v0.2.0
3. Constraints
[RFC-0001:C-CONSTRAINTS] Compilation Constraints (Normative)
The compiler MUST enforce the following constraints:
Stub size: The compiled stub MUST NOT exceed 100 lines. If the source skill is too large to summarize within this limit, the compiler MUST truncate sections and indicate truncation.
Section limit: The stub section listing MUST include at most 12 top-level headings. Additional headings MUST be omitted with an indication that more exist.
Command restrictions:
skc outline— Lists structure from.mdfiles onlyskc show— Retrieves sections from.mdfiles onlyskc open— Retrieves any file within the skill root (not restricted to.md)skc sources— Lists all files within the skill root
Path safety: The compiler MUST reject source directories containing symlinks that escape the skill root.
Since: v0.1.0
4. Compilation Output
[RFC-0001:C-DEPLOYMENT] Deployment Strategy (Normative)
The compiler MUST compile to a Single Source of Truth (SSOT) location and deploy to agent directories.
SSOT Locations
Compiled skills MUST be stored in one of these SSOT locations:
- Project-local SSOT:
.skillc/runtime/<skill-name>/ - Global SSOT:
~/.skillc/runtime/<skill-name>/
Agent Directories
Agent directories are where AI agents discover skills:
~/.claude/skills/<skill-name>/~/.cursor/skills/<skill-name>/
Agent directories contain links (or copies) pointing to the SSOT location.
Default Behavior (Local-First)
When compiling a project-local source (.skillc/skills/), the compiler MUST:
- Output to project-local SSOT (
.skillc/runtime/<skill-name>/) - Deploy to agent directory (
~/.claude/skills/<skill-name>/by default)
When compiling a global source (~/.skillc/skills/), the compiler MUST:
- Output to global SSOT (
~/.skillc/runtime/<skill-name>/) - Deploy to agent directory (
~/.claude/skills/<skill-name>/by default)
CLI Flags
| Flag | Default | Effect |
|---|---|---|
--global | false | Force SSOT to ~/.skillc/runtime/ regardless of source |
--target <agents> | claude | Which agent directories to deploy to (comma-separated) |
--copy | false | Force copy instead of symlink/junction |
--force | false | Overwrite existing skill during import |
Deployment Methods
The compiler MUST deploy from SSOT to agent directories using these methods:
- Unix: Create symlink (default)
- Windows: Create directory junction (no admin required)
- Fallback: Copy directory contents with warning
The --copy flag forces copy mode on all platforms.
Deployment Behavior
When deploying, the compiler MUST:
- Ensure the parent directory exists
- Remove any existing symlink/junction at the target path
- Create a symlink/junction pointing to the SSOT directory (or copy if
--copy) - Report each deployment with method used
The compiler MUST NOT overwrite an existing directory (non-symlink) without --force.
Since: v0.1.0
Changelog
v0.2.1 (2026-01-31)
Add reference file description support
v0.2.0 (2026-01-31)
Add C-SECTIONS
v0.1.0 (2026-01-30)
Initial release
RFC-0002: Gateway Protocol
Version: 0.2.1 | Status: normative | Phase: test
1. Summary
[RFC-0002:C-OVERVIEW] Overview (Informative)
The gateway is how agents access skill content on-demand. Rather than loading entire skills into context, agents use gateway commands to retrieve specific sections as needed.
Gateway commands operate on the source directory, not the compiled stub. This ensures agents always see current content without requiring a rebuild.
Every gateway access is logged per RFC-0007:C-LOGGING, enabling skill authors to understand which content agents actually use.
Gateway commands:
outline— List all sections in a skillshow— Retrieve section contentopen— Retrieve file contentsources— List source files (tree-style)
See RFC-0007:C-COMMANDS for the complete command registry with parameters and interface availability.
Since: v0.1.0
2. Specification
[RFC-0002:C-OUTLINE] Outline Command (Normative)
Syntax: skc outline <skill> [--level <n>]
The outline command MUST scan all .md files in the skill’s source directory and extract headings.
Options:
| Option | Description |
|---|---|
--level <n> | Maximum heading level to include (1-6, default: unlimited) |
When --level is provided, the command MUST only output headings with level ≤ n. For example, --level 2 shows only # and ## headings.
Output format: The command MUST output a structured list of headings with:
- Heading level (1-6)
- Heading text
- File path (relative to skill root)
Ordering: Headings MUST be listed in file order, with files sorted lexicographically by relative path (bytewise ASCII order). No special-case ordering is permitted.
Example output:
SKILL.md
# Skill Name
## Getting Started
## API Reference
### Authentication
### Endpoints
references/advanced.md
# Advanced Topics
## Performance
With --level 2:
SKILL.md
# Skill Name
## Getting Started
## API Reference
references/advanced.md
# Advanced Topics
## Performance
Since: v0.1.0
[RFC-0002:C-SHOW] Show Command (Normative)
Syntax: skc show <skill> --section "<heading>" [--file <path>] [--max-lines <n>]
The show command MUST locate the specified heading and return its content.
Options:
| Option | Description |
|---|---|
--file <path> | Limit search to specific file |
--max-lines <n> | Maximum lines to return (default: unlimited) |
When --max-lines is provided, the command MUST truncate output to the first n lines. If content is truncated, the command MUST append a line:
... (N more lines)
Index-based lookup: The command MUST use the pre-built headings index from RFC-0004:C-INDEX instead of parsing files at runtime. If the index is missing or stale, the command MUST exit with error E002 per RFC-0005:C-CODES.
Query normalization: Before matching, the query MUST be normalized:
- Trim leading/trailing whitespace
- If the query contains
—(em-dash with spaces), extract only the part before it
This allows queries copied from compiled stubs (which may include descriptions) to work correctly.
Heading matching:
- Matching MUST be case-insensitive
- If
--fileis provided, search only that file; otherwise search all indexed headings
Content extraction:
The command MUST read content from the source file using the start_line and end_line from the index. Lines are 1-based.
Multiple matches:
If multiple headings match, the command MUST return the first match and write a warning to stderr in the form:
warning: multiple matches for "<heading>"; showing first
The command MUST exit with status 0 in this case.
No match with suggestions: If no heading matches, the command MUST:
- Search for similar headings (case-insensitive prefix match or substring match)
- If suggestions found, include them in the error message:
error[E020]: section not found: '<query>' Did you mean one of these? - <suggestion1> (<file1>) - <suggestion2> (<file2>) - Limit suggestions to 5 entries
- Exit with non-zero status
Updated in v0.2.0: Added index-based lookup, query normalization (em-dash stripping), and suggestions on no match.
Since: v0.1.0
[RFC-0002:C-OPEN] Open Command (Normative)
Syntax: skc open <skill> <path> [--max-lines <n>]
The open command MUST return the contents of the specified file.
Options:
| Option | Description |
|---|---|
--max-lines <n> | Maximum lines to return (default: unlimited) |
When --max-lines is provided, the command MUST truncate output to the first n lines. If content is truncated, the command MUST append a line:
... (N more lines)
Path validation:
- The path MUST be relative to the skill source root
- The path MUST NOT contain
..sequences that escape the skill root - The path MUST refer to a file (not a directory)
Content:
The command MUST return the file contents as-is without transformation (except for --max-lines truncation).
File type:
The open command is NOT restricted to .md files. It can retrieve any file within the skill source directory. This enables retrieval of search results from non-.md files (e.g., .txt).
Path safety: The command MUST reject any path that would resolve outside the skill source directory after canonicalization. See RFC-0005:C-CODES for error E012.
No match: If the file does not exist, the command MUST exit with error E021 per RFC-0005:C-CODES.
Since: v0.1.0
[RFC-0002:C-ERRORS] Error Handling (Normative)
All gateway command errors MUST exit with status 1 and print an error message to stderr.
Error codes: See RFC-0005:C-CODES for canonical error messages. Gateway commands use:
| Condition | Error Code |
|---|---|
| Skill resolution failed | E001 or E010 |
| Path escapes skill root | E012 |
| Section not found | E020 |
| File not found | E021 |
| Directory not found | E022 |
| Invalid CLI option | E100 |
Usage:
- E001/E010: Skill resolution failed per RFC-0007:C-RESOLUTION. See RFC-0005:C-CODES for when to use each.
- E012:
skc openpath orskc sources --dirpath would escape the skill root after canonicalization - E020:
skc show --sectionfinds no matching heading - E021:
skc opentarget file does not exist - E022:
skc sources --dirtarget directory does not exist - E100: Unknown flag, missing required value, or other CLI parsing failure
Since: v0.1.0
[RFC-0002:C-SOURCES] Sources Command (Normative)
Syntax: skc sources <skill> [options]
The sources command MUST list all files in the skill’s source directory in a tree-style format.
Options:
| Option | Description |
|---|---|
--depth <n> | Maximum tree depth to display (default: unlimited) |
--dir <path> | Scope listing to a subdirectory |
--limit <n> | Maximum entries to display (default: 100) |
--pattern <glob> | Filter files by glob pattern (e.g., *.md) |
--format <fmt> | Output format: text (default) or json |
Output format:
The command MUST output a tree-style directory listing:
- Files are listed with their relative paths
- Directories that are not expanded MUST show a file count suffix:
dirname/ (N files) - When
--limitis exceeded, output MUST end with a truncation indicator:... (N more)
Ordering: Entries MUST be sorted lexicographically by relative path (bytewise ASCII order), with directories listed before files at each level.
Example output:
$ skc sources cuda --depth 2
cuda/
├── SKILL.md
├── references/
│ ├── compilation.md
│ ├── cuda-driver-docs/ (156 files)
│ ├── cuda-runtime-docs/ (89 files)
│ ├── debugging-tools.md
│ └── ... (8 more)
Scoped listing:
When --dir is provided, the command MUST:
- Validate that the path exists within the skill root
- Display the subtree rooted at that directory
- Apply
--depthrelative to the specified directory
Path safety:
The command MUST reject any --dir path that would resolve outside the skill source directory after canonicalization. See RFC-0005:C-CODES for error E012.
Since: v0.1.0
Changelog
v0.2.1 (2026-01-31)
Add missing –format support for skc sources
v0.2.0 (2026-01-31)
C-SHOW updated with em-dash stripping and suggestions
v0.1.0 (2026-01-30)
Initial release
RFC-0003: Usage Analytics
Version: 0.1.0 | Status: normative | Phase: test
1. Summary
[RFC-0003:C-OVERVIEW] Overview (Informative)
Usage analytics enables skill authors to understand how agents interact with their skills.
The analytics system is designed as a data layer with multiple front-end consumers:
- CLI commands for quick insights
- JSON output for scripts and automation
- Future: web API and dashboard
Analytics queries the access logs created by RFC-0007:C-LOGGING and aggregates usage data.
Commands:
skc stats <skill>— Show usage summaryskc stats <skill> --group-by <type>— Run specific aggregationskc stats <skill> --format json— Machine-readable output
Since: v0.1.0
2. Specification
[RFC-0003:C-QUERIES] Query Types (Normative)
The analytics system MUST support the following query types:
summary — Overview statistics
Returns total access count, unique sections accessed, unique files accessed, error count, and date range of data.
sections — Section access breakdown
Returns a list of sections ordered by access count (descending). Ties MUST be ordered by file path, then section heading, both ascending. Each entry includes the section heading text, file path, and access count.
files — File access breakdown
Returns a list of files ordered by access count (descending). Ties MUST be ordered by file path ascending. Each entry includes the file path and access count.
commands — Command type breakdown
Returns access counts grouped by command type. All logged commands appear as keys. Known command types include: outline, show, open, search, build, stats. Additional command types (from future versions) MUST be included as extra keys.
projects — Project/CWD breakdown
Returns access counts grouped by calling directory (CWD). Each entry includes the directory path and access count.
errors — Failed lookups
Returns a list of failed access attempts. Each entry includes the requested target, command type, error message, and count.
search — Search query breakdown
Returns a list of search queries ordered by frequency (descending). Ties MUST be ordered by query text ascending. Each entry includes the query string and count. This enables understanding which search terms agents use most frequently.
The default query type MUST be summary.
Since: v0.1.0
[RFC-0003:C-FILTERS] Query Filters (Normative)
All queries MUST support the following filters:
Time range filters:
--since <datetime>— Include only accesses on or after this timestamp--until <datetime>— Include only accesses on or before this timestamp
Timestamps MUST be parsed as RFC 3339 format (YYYY-MM-DDTHH:MM:SSZ) or date-only format (YYYY-MM-DD, interpreted as start of day UTC).
Logged access timestamps MUST be stored in UTC.
If no time filters are provided, all available data MUST be included.
Project filter:
--project <path>— Include only accesses where CWD matches or is a subdirectory of the given path
The path MUST be matched as a prefix after canonicalization. Canonicalization MUST resolve . and .. path segments and MUST resolve symlinks to their real paths. Matching MUST use the canonicalized absolute paths for both the filter and the logged CWD. For example, --project /Users/me/webapp matches CWDs like /Users/me/webapp, /Users/me/webapp/src, etc.
Multiple --project flags MAY be provided; accesses matching ANY of the paths MUST be included (OR logic).
Filter application:
Filters MUST be applied before aggregation. The response schema MUST include the applied filters in the filters field.
Since: v0.1.0
[RFC-0003:C-SCHEMA] Response Schema (Normative)
All analytics responses MUST conform to a JSON schema for interoperability with multiple front-ends.
Root response structure:
{
"skill": "<skill-name>",
"skill_path": "<absolute-source-path>",
"query": "<query-type>",
"filters": {
"since": "<datetime-or-null>",
"until": "<datetime-or-null>",
"projects": ["<path>", ...]
},
"period": {
"start": "<earliest-access-timestamp>",
"end": "<latest-access-timestamp>"
},
"data": { ... }
}
Query-specific data structures:
summary:
{
"total_accesses": 150,
"unique_sections": 8,
"unique_files": 3,
"error_count": 5
}
sections:
[
{"section": "Getting Started", "file": "SKILL.md", "count": 42},
{"section": "API Reference", "file": "SKILL.md", "count": 35}
]
files:
[
{"file": "SKILL.md", "count": 100},
{"file": "docs/advanced.md", "count": 25}
]
commands:
{
"outline": 50,
"show": 80,
"open": 20,
"search": 45,
"build": 10
}
projects:
[
{"project": "/Users/me/webapp", "count": 75},
{"project": "/Users/me/cli-tool", "count": 25}
]
errors:
[
{"target": "NonExistentSection", "command": "show", "error": "Section not found", "count": 5}
]
search:
[
{"query": "authentication", "count": 25},
{"query": "error handling", "count": 18},
{"query": "api", "count": 12}
]
The JSON output MUST be valid JSON. Field order is not significant.
Since: v0.1.0
[RFC-0003:C-CLI] CLI Commands (Normative)
Syntax: skc stats <skill> [options]
The stats command MUST query the access log for the specified skill and display usage analytics.
Options:
--group-by <type> — Aggregation dimension (default: summary)
Valid values: summary, sections, files, commands, projects, errors
--format <format> — Output format (default: text)
Valid values: text, json
--since <datetime> — Filter: include accesses on or after this time
--until <datetime> — Filter: include accesses on or before this time
--project <path> — Filter: include accesses from this project directory (may be repeated)
Skill resolution:
The <skill> argument MUST be resolved using the same logic as RFC-0007:C-RESOLUTION.
Log database location:
The command MUST read from .skillc-meta/logs.db in the resolved runtime directory (per RFC-0007:C-LOGGING).
No data:
If the log database does not exist or contains no matching records, the command MUST return an empty result (not an error). For summary, this means all counts are zero.
Text output:
When --format text (default), the command MUST produce human-readable output suitable for terminal display. The exact format is implementation-defined but MUST convey the same information as the JSON schema.
Exit codes:
- 0: Success (including empty results)
- 1: Error. See RFC-0003:C-ERRORS for error codes (E001/E010 for skill resolution, E030/E031 for invalid query/filter, E100 for invalid options).
Since: v0.1.0
[RFC-0003:C-ERRORS] Error Handling (Normative)
All analytics command errors MUST exit with status 1 and print an error message to stderr.
Error codes: See RFC-0005:C-CODES for canonical error messages. This RFC uses:
| Condition | Error Code |
|---|---|
| Skill resolution failed | E001 or E010 |
| Invalid query type | E030 |
| Invalid filter | E031 |
| Invalid CLI option | E100 |
Usage:
- E001/E010: Skill resolution failed per RFC-0007:C-RESOLUTION. See RFC-0005:C-CODES for when to use each.
- E030:
--queryvalue is not one of:summary,sections,files,commands,projects,errors - E031:
--since,--until, or--projectvalue is malformed - E100: Unknown flag, missing required value, or other CLI parsing failure
Note: Empty results (no matching log entries) are NOT errors. The command MUST return an empty result set with exit code 0.
Since: v0.1.0
Changelog
v0.1.0 (2026-01-30)
Initial release
RFC-0004: Search Protocol
Version: 0.2.0 | Status: normative | Phase: test
1. Summary
[RFC-0004:C-OVERVIEW] Overview (Informative)
Search enables agents to find content within skills using full-text queries.
The search system builds an index during compilation and supports BM25-ranked queries with snippet extraction. Rather than requiring agents to know exact section headings, search allows natural language queries like “how to configure authentication” to find relevant content.
Design principles:
- Progressive disclosure — Search returns section references; agents use
showto retrieve content - Offline-first — Uses SQLite FTS5, no external dependencies
- Extensible formats — File format support is added incrementally
- Observable — All searches are logged for analytics
Commands:
skc search <skill> <query>— Find matching sections
Since: v0.1.0
2. Specification
[RFC-0004:C-FORMATS] Supported Formats (Normative)
The search index MUST support the following file formats:
v0.1.0:
.md— Markdown files, segmented by headings. Each section (heading + content until next heading of equal or higher level) becomes a searchable document. Thesectionfield contains the heading text..txt— Plain text files, indexed as a single document. Thesectionfield MUST be an empty string ("").
Retrieval:
Search results from any indexed format can be retrieved using skc open <skill> <path>. The open command is not restricted to .md files (see RFC-0002:C-OPEN).
Additional formats MAY be added in future versions. The implementation MUST silently skip unsupported file types without error.
Planned (future versions):
.csv— Each row as a searchable document.json,.yaml,.toml— Flattened key-value pairs- Code files (
.py,.js,.ts,.rs) — Plain text with comment weighting
Since: v0.1.0
[RFC-0004:C-INDEX] Index Storage (Normative)
The search index MUST be stored as a SQLite FTS5 database in the skill’s runtime directory.
Index file naming: To avoid collisions when multiple source directories share a runtime store, the index file MUST be named using a hash of the source path:
.skillc-meta/search-<hash16>.db
Where <hash16> is the first 16 characters (64 bits) of the SHA-256 hash of the canonicalized source directory path.
Tokenizer preference: The current tokenizer preference is determined at runtime:
- Attempt
porter unicode61 - If unavailable, fall back to
unicode61
This preference is used for both index creation (build) and checking (search).
Corrupt index definition: An index is corrupt if any of:
- The database file cannot be opened as a SQLite database
- The
index_metatable does not exist - Any required key is missing (
skill_path,source_hash,schema_version,tokenizer) - Any required key value cannot be parsed (e.g., non-integer
schema_version)
Any read or parse failure during index access MUST be treated as corruption. Implementations MUST NOT attempt to distinguish transient errors from permanent corruption; all failures map to the same handling (E002 for search, delete+rebuild for build).
Index file selection (search): When searching, the implementation MUST follow these steps in order:
- Compute the expected filename
search-<hash16>.db - If file does not exist: exit with error E002 (missing)
- Open the database and read required keys from
index_meta; if corrupt (per definition above): exit with error E002 - If
skill_pathdoes not match current source path: exit with error E003 (collision) - Check staleness conditions (see below): if stale, exit with error E002
- Proceed with search
E002 conditions (search): E002 (“unusable”) is the umbrella error covering three distinct failure modes:
- Missing: file does not exist (step 2)
- Corrupt: any read/parse failure (step 3)
- Stale: metadata mismatch (step 5) — a subset of “unusable”
All three require skc build to fix.
See RFC-0005:C-CODES for canonical error messages.
Staleness conditions (search-only): “Stale” is a subset of “unusable” that applies when the index can be read but its metadata does not match the current skill state.
After confirming no collision (step 4), the index is stale if any of:
source_hashdoes not match current manifest hashschema_version< current schema version (currently2)tokenizerdoes not match current tokenizer preference
These three fields are the only staleness conditions. Missing file and corrupt index are handled earlier (steps 2-3). The skill_path field is used for collision detection (step 4), not staleness.
If stale, skc search MUST exit with error E002.
Index lifecycle (build):
When skc build runs:
- Compute the expected filename
search-<hash16>.db - If file does not exist: proceed to step 6 to create new index
- Open the database and read required keys from
index_meta; if any read/parse failure: delete file, proceed to step 6 to create new index - If
skill_pathdoes NOT match current source path: exit with error E003 (collision). Stop. - Compare
source_hash,schema_version, andtokenizer:- If all match: skip rebuild. Done.
- Else: delete existing file, proceed to step 6 to create new index.
- Create new index with current tokenizer preference
Build does not error on unusable indexes; it rebuilds them. Corrupt indexes are deleted without collision detection since skill_path cannot be reliably read.
Build behavior summary:
- Missing: create new index (step 2 → 6)
- Corrupt: delete and rebuild without collision check (step 3 → 6)
- Collision (
skill_pathmismatch): error E003 (step 4) - Up-to-date (all metadata matches): skip rebuild (step 5)
- Stale (metadata differs): rebuild (step 5 → 6)
No automatic cleanup:
The implementation MUST NOT delete other search-*.db files. Multiple skills may share a runtime directory.
Runtime directory resolution: The runtime directory MUST be resolved using the same logic as RFC-0007:C-RESOLUTION.
Index schema: The database MUST contain a virtual table using FTS5 for full-text search:
CREATE VIRTUAL TABLE sections USING fts5(
file,
section,
content,
tokenize='porter unicode61'
);
The database MUST contain a headings table for section lookup by RFC-0002:C-SHOW:
CREATE TABLE headings (
id INTEGER PRIMARY KEY,
file TEXT NOT NULL,
text TEXT NOT NULL,
level INTEGER NOT NULL,
start_line INTEGER NOT NULL,
end_line INTEGER NOT NULL
);
CREATE INDEX idx_headings_text ON headings(text COLLATE NOCASE);
Fields:
file— relative path from skill roottext— heading text (without#prefix)level— heading level (1-6)start_line— 1-based line number of headingend_line— 1-based line number of next heading (or EOF+1)
The database MUST also contain a metadata table:
CREATE TABLE index_meta (
key TEXT PRIMARY KEY,
value TEXT
);
Required metadata keys:
source_hash— Hash from RFC-0001:C-MANIFESTskill_path— Canonicalized absolute path to source directoryschema_version— Integer (currently2)indexed_at— RFC 3339 UTC timestamptokenizer—porterorunicode61
Schema migration:
No in-place migration. User must run skc build.
Updated in v0.2.0: Added headings table for index-based section lookup. Bumped schema_version to 2.
Since: v0.1.0
[RFC-0004:C-SEARCH] Search Command (Normative)
Syntax: skc search <skill> <query> [options]
The search command MUST query the FTS5 index and return ranked results.
Options:
--limit N— Maximum results (default: 10)--format <text|json>— Output format (default: text)
Ranking: Results MUST be ranked using BM25. Scores MUST be negated for display (FTS5 returns negative).
Snippet extraction:
Snippet parameters (FTS5 snippet() function):
- Column:
content(index 2) - Start marker:
[MATCH] - End marker:
[/MATCH] - Ellipsis:
... - Token limit:
32
Output format guarantees:
JSON is canonical (Normative). Use JSON for machine parsing.
JSON output (--format json):
{
"query": "<original-query>",
"results": [
{
"file": "<relative-path>",
"section": "<heading-or-identifier>",
"snippet": "...text with [MATCH]term[/MATCH]...",
"score": <float>
}
]
}
Text output (--format text) — Informative only:
Human-readable, NOT a stable contract. Do NOT parse.
<file>#<section> (score: <score>)
<snippet>
No results:
Return empty result set, exit 0. JSON: {"query": "...", "results": []}.
Skill resolution: Per RFC-0007:C-RESOLUTION.
Error handling: All errors exit with status 1. See RFC-0005:C-CODES for canonical error messages.
| Condition | Error Code |
|---|---|
| Skill resolution failed | E001 or E010 |
| Index unusable | E002 |
| Index hash collision | E003 |
| Empty query | E004 |
| Invalid CLI option | E100 |
Note: “Index unusable” (E002) covers three cases: missing file, corrupt index, or stale metadata. See RFC-0004:C-INDEX for details.
Since: v0.1.0
[RFC-0004:C-LOGGING] Search Logging (Normative)
Search commands MUST be logged per RFC-0007:C-LOGGING.
Command name: search
Args format:
{
"query": "<search-query>",
"result_count": <number-of-results-returned>
}
Error field:
If the search fails (e.g., stale index), the error message MUST be recorded in the error field.
Analytics extension (future):
The stats command (per RFC-0003) SHOULD be extended to support a searches query type that aggregates:
- Query strings and their frequency
- Average result counts
- Zero-result query patterns
This extension is NOT part of v0.1.0. Until implemented, --query searches is not a valid query type and will result in error E030 per RFC-0005:C-CODES.
Since: v0.1.0
[RFC-0004:C-QUERY-SYNTAX] Query Syntax (Normative)
Query semantics:
The <query> argument is treated as a bag-of-words query with implicit AND. Each word in the query must appear somewhere in the document for a match; word order and adjacency are NOT required.
Example: Query configure authentication matches documents containing both words anywhere in the content, regardless of order or proximity.
Tokenizer-dependent matching:
Query matching behavior depends on the tokenizer used to build the index (recorded in index_meta.tokenizer):
porter: Terms are stemmed. Queryconfiguringmatches indexedconfigure.unicode61: No stemming. Queryconfiguringdoes NOT matchconfigure.
FTS5 handles tokenizer selection internally based on how the index was created. The implementation does not need to branch on tokenizer type; FTS5 applies the correct tokenizer automatically. However, the recorded tokenizer value is useful for debugging, diagnostics, and user understanding of matching behavior.
Query tokenization: To construct a bag-of-words AND query, the implementation MUST:
- Split the query on ASCII whitespace only (space U+0020, tab U+0009, newline U+000A, carriage return U+000D)
- Remove empty tokens
- For each non-empty token:
a. Escape internal
"by doubling ("→"") b. Wrap in double quotes to make it a literal FTS5 term - Join all quoted tokens with spaces (implicit AND in FTS5)
Unicode whitespace limitation: Non-ASCII whitespace characters (e.g., non-breaking space U+00A0, ideographic space U+3000) are NOT treated as token separators. They are included as part of the token. This is a known limitation. Users should use ASCII spaces in queries.
Example: User input configure authentication becomes FTS5 query "configure" "authentication".
Example with quotes: User input my "special" app becomes FTS5 query "my" """special""" "app".
Why this works: Each quoted token is passed to FTS5 as a single-term phrase. FTS5 applies its internal tokenizer (matching the index) to each term, handling Unicode normalization and stemming as appropriate. Multiple quoted terms joined by spaces create an implicit AND query.
Note on punctuation:
Punctuation attached to words (e.g., hello, or (world)) is passed to FTS5 as-is. FTS5’s tokenizer will strip it during matching.
Shell quoting: The query is passed as a single shell argument. Users MUST quote multi-word queries:
skc search my-skill "configure authentication" # Correct
skc search my-skill configure authentication # Wrong: two positional args
Empty query: If the query is empty or contains only ASCII whitespace, the command MUST exit with error E004. See RFC-0005:C-CODES for the canonical message.
Future extension:
--raw— Pass raw FTS5 syntax for advanced users--phrase— Require adjacency (true phrase matching)
These flags are NOT part of v0.1.0.
Since: v0.1.0
[RFC-0004:C-ERRORS] Error Messages (Normative)
All search-related errors MUST exit with status 1 and print an error message to stderr.
Error codes: See RFC-0005:C-CODES for canonical error messages. This RFC uses:
| Condition | Error Code |
|---|---|
| Skill resolution failed | E001 or E010 |
| Index unusable | E002 |
| Index hash collision | E003 |
| Empty query | E004 |
| Invalid CLI option | E100 |
Usage:
- E001/E010: Skill resolution failed per RFC-0007:C-RESOLUTION. See RFC-0005:C-CODES for when to use each.
- E002: Index unusable (missing, corrupt, or stale). See RFC-0004:C-INDEX for details.
- E003: Index filename exists but
skill_pathdoes not match (hash collision) - E004: Query is empty or contains only whitespace
- E100: Unknown flag, missing required value, or other CLI parsing failure
Collision handling: Hash collisions are rare but possible. When detected, the user MUST manually delete the conflicting index file. The error message includes the filename pattern to delete. Automatic deletion is not performed because it could destroy another skill’s valid index.
Corrupt index handling:
An index is corrupt if the database cannot be opened, index_meta table is missing, required keys are missing, or key values cannot be parsed. See RFC-0004:C-INDEX for the full definition. During search, corruption maps to E002. During build, corrupt files are deleted and rebuilt without collision detection (since skill_path cannot be verified).
Since: v0.1.0
Changelog
v0.2.0 (2026-01-31)
C-INDEX updated with headings table, schema version bumped to 2
v0.1.0 (2026-01-30)
Initial release
RFC-0005: Error Code Registry
Version: 0.1.0 | Status: normative | Phase: test
1. Summary
2. Specification
[RFC-0005:C-CODES] Error Code Table (Normative)
Error Codes
Canonical error code table:
| Code | Message Template | Semantics |
|---|---|---|
| E001 | error[E001]: skill '<skill>' not found | Skill resolution failed (no matching directory in any store) |
| E002 | error[E002]: search index unusable; run 'skc build <skill>' to rebuild | Index is missing, corrupt, or stale |
| E003 | error[E003]: index hash collision; delete .skillc-meta/search-<hash16>.db and rebuild | Index filename exists but belongs to different skill |
| E004 | error[E004]: empty query | Search query is empty or whitespace-only |
| E010 | error[E010]: not a valid skill: '<path>' (missing SKILL.md) | Directory exists but lacks SKILL.md |
| E011 | error[E011]: missing frontmatter field '<field>' in SKILL.md | SKILL.md lacks required name or description field entirely |
| E012 | error[E012]: path escapes skill root: '<path>' | Symlink or path traversal would escape skill directory |
| E020 | error[E020]: section not found: '<section>' | Gateway show command found no matching heading |
| E021 | error[E021]: file not found: '<path>' | Gateway open command target does not exist |
| E022 | error[E022]: directory not found: '<path>' | Gateway sources –dir target does not exist |
| E030 | error[E030]: invalid query type: '<type>' | Stats command received unknown query type |
| E031 | error[E031]: invalid filter: '<message>' | Stats command received malformed filter value |
| E040 | error[E040]: no local logs found | Sync command found no fallback logs to sync |
| E041 | error[E041]: sync destination not writable: '<path>' | Sync command cannot write to primary runtime directory |
| E042 | error[E042]: sync source not readable: '<path>' | Sync command cannot read from fallback log database |
| E050 | error[E050]: skill '<skill>' already exists | Init command target already has SKILL.md |
| E100 | error[E100]: invalid option: '<message>' | CLI parsing failed (unknown flag, missing value, etc.) |
| E300 | error[E300]: <rule-id> <rule-name>: <message> | Lint rule violation with error severity (see RFC-0008) |
| E999 | error[E999]: <message> | Internal error (IO, database, parsing, or other unexpected failures) |
Warning Codes
Canonical warning code table:
| Code | Message Template | Semantics |
|---|---|---|
| W001 | warning[W001]: multiple matches for '<section>'; showing first | Gateway show found multiple headings matching query |
| W002 | warning[W002]: logging disabled; run 'skc sync' after session to merge logs | Access logging failed, using fallback or disabled |
| W003 | warning[W003]: stale local logs for '<skill>'; run 'skc sync' to upload | Local fallback logs exist and are older than threshold |
| W300 | warning[W300]: <rule-id> <rule-name>: <message> | Lint rule violation with warning severity (see RFC-0008) |
Warning behavior:
- Warnings are printed to stderr but do NOT cause command failure
- Commands that emit warnings still exit with code 0
- Multiple warnings may be emitted per command invocation
Resolution error hierarchy
When resolving a skill per RFC-0007:C-RESOLUTION:
- E010: A directory was found (at the given path OR in project/global stores) but it lacks SKILL.md
- E001: No directory was found at the path AND no match in project/global stores
E010 is a more specific form of resolution failure. Use E010 when a directory exists but isn’t a valid skill; use E001 when no directory is found at all.
Lint diagnostics
Lint diagnostics (E300, W300) use a structured format that includes the rule ID from RFC-0008:C-REGISTRY:
<severity>[<code>]: <rule-id> <rule-name>: <message>
Examples:
error[E300]: SKL102 name-format: name contains invalid characterswarning[W300]: SKL108 description-triggers: missing activation triggerwarning[W300]: SKL401 no-orphans: orphaned file 'old-draft.md'
The rule ID (SKLxxx) provides semantic detail; the diagnostic code (E300/W300) indicates severity. This separation allows adding new lint rules without modifying this RFC.
Unified codes
The following codes are used across multiple RFCs:
- E001/E010 (Skill resolution): All commands that resolve skills via RFC-0007:C-RESOLUTION MUST use E001 or E010 when resolution fails.
- E002–E004 (Index/query): Errors for index state and query validation. Currently used by search; future commands with similar semantics should reuse these.
- E012 (Path escape): Any command that validates paths MUST use E012 when a path would escape the skill root.
- E040–E042 (Sync): Errors specific to the sync command for log synchronization.
- E050 (Skill exists): Init command cannot overwrite existing skill.
- E100 (Invalid option): All commands MUST use E100 for flag/option parsing failures.
- E300/W300 (Lint): Skill authoring validation per RFC-0008. Rule IDs (SKLxxx) provide specifics.
- E999 (Internal): Unexpected failures (IO errors, database errors, parsing errors). These indicate bugs or environmental issues, not user errors.
- W001 (Multiple matches): Gateway commands that find multiple matches.
- W002 (Logging disabled): Access logging encountered errors.
- W003 (Stale logs): Local fallback logs need syncing.
Message format
All diagnostic messages MUST include the code in brackets:
- Errors:
error[EXXX]: <message> - Warnings:
warning[WXXX]: <message>
This format enables:
- Machine parsing of diagnostic codes
- Easy searching in documentation
- Consistent user experience across commands
Placeholder substitution:
<skill>— The skill name/path provided by the user<path>— File or directory path<hash16>— First 16 characters of SHA-256 hash<field>— Frontmatter field name<section>— Section heading text<type>— Query type string<message>— Contextual error details<rule-id>— Lint rule identifier (e.g., SKL102)<rule-name>— Lint rule name (e.g., name-format)
Exit behavior
- Errors: Exit with status 1
- Warnings: Do not affect exit status (exit 0 if no errors)
Implementations MUST NOT use different exit codes for different error types.
Adding new codes
New diagnostic codes MUST be added to this table via RFC amendment. Feature RFCs MUST NOT define new codes inline; they MUST reference this RFC and propose additions here.
Exception: Lint rules (SKLxxx) are defined in RFC-0008 and use E300/W300 as their diagnostic codes. Adding new lint rules does not require amending this RFC.
Reserved ranges:
Error codes:
- E001–E010: Unified errors (skill resolution, index state, query validation, path safety)
- E011–E019: Compilation errors (RFC-0001)
- E020–E029: Gateway errors (RFC-0002)
- E030–E039: Analytics errors (RFC-0003)
- E040–E049: Sync errors (RFC-0007)
- E050–E059: Scaffolding errors (RFC-0006)
- E100–E199: CLI parsing errors (all commands)
- E200–E299: Reserved for network/remote errors
- E300: Lint errors (RFC-0008) — rule IDs provide specifics
- E999: Internal/unexpected errors
Warning codes:
- W001–W009: Gateway warnings
- W010–W019: Logging warnings
- W020–W029: Reserved for future use
- W300: Lint warnings (RFC-0008) — rule IDs provide specifics
Since: v0.1.0
[RFC-0005:C-USAGE] Usage by Feature RFCs (Normative)
Feature RFC requirements:
Feature RFCs that define error behavior MUST:
- Reference this RFC — Use
[RFC-0005](../rfc/RFC-0005.md)or[RFC-0005:C-CODES](../rfc/RFC-0005.md#rfc-0005c-codes)when discussing error codes - Use canonical codes — Only use error codes defined in RFC-0005:C-CODES
- Document applicability — Specify which codes apply to which commands/conditions
- Not redefine messages — Use the exact message templates from this RFC
Example usage in feature RFCs:
**Error handling:**
See [RFC-0005:C-CODES](../rfc/RFC-0005.md#rfc-0005c-codes) for canonical error messages.
| Condition | Error Code |
|-----------|------------|
| Skill not found | E001 |
| Index unusable | E002 |
Proposing new codes:
To add a new error code:
- Submit an amendment to this RFC
- Include: code, message template, semantics, and reserved range justification
- Update the canonical table in RFC-0005:C-CODES
Deprecating codes:
Deprecated codes MUST remain in the table with a (deprecated) suffix in the Semantics column. They MUST NOT be removed to maintain backward compatibility.
Since: v0.1.0
3. Motivation
[RFC-0005:C-OVERVIEW] Overview (Normative)
This RFC defines the canonical diagnostic code registry for skillc. All error and warning codes used across the CLI are defined here.
Purpose:
- Single source of truth for diagnostic semantics
- Consistent messages across commands
- Feature RFCs reference this registry instead of defining their own codes
Scope: This RFC defines diagnostic codes and message templates. Per-command handling (which codes apply, when they’re raised) remains in feature RFCs.
Diagnostic levels:
- Errors (
error[EXXX]): Fatal conditions that prevent command completion. Exit code 1. - Warnings (
warning[WXXX]): Non-fatal conditions where command succeeds but with degraded behavior. Exit code 0.
Design principles:
- Exit code 1 for errors, 0 for warnings
- All diagnostics printed to stderr
- Human-readable messages with codes for documentation/search
Since: v0.1.0
Changelog
v0.1.0 (2026-01-30)
Initial release
RFC-0006: Scaffolding
Version: 0.1.0 | Status: normative | Phase: test
1. Summary
[RFC-0006:C-OVERVIEW] Overview (Informative)
Scaffolding provides commands to initialize skillc projects and create new skills.
The init command creates the necessary directory structure for skillc to manage skills locally within a project, or creates new skill templates.
Design principles:
- Project-local first — Skills are created within the current project by default
- Minimal templates — Generated files contain only required structure
- Idempotent initialization — Running
initmultiple times is safe
Since: v0.1.0
2. Specification
[RFC-0006:C-INIT] Initialization Command (Normative)
The skc init command scaffolds skillc project and skill structures.
Project Initialization
skc init
When invoked without arguments, skillc MUST:
- Create
.skillc/directory in the current working directory if it does not exist - Create
.skillc/skills/subdirectory for project-local skill sources - Print confirmation message to stdout
If .skillc/ already exists, the command MUST succeed without error (idempotent).
Skill Creation
skc init <name>
skc init <name> --global
When invoked with a skill name, skillc MUST:
- Determine the target directory:
- Without
--global:.skillc/skills/<name>/(project-local) - With
--global:~/.skillc/skills/<name>/(global source store)
- Without
- Create the target directory if it does not exist
- Create
SKILL.mdwith minimal frontmatter:
---
name: <name>
description: "TODO: Add skill description"
---
# <Name>
Where <name> is the skill name as provided (lowercase), and <Name> is title-cased.
The description MUST be non-empty to satisfy RFC-0001:C-INPUT requirements. Users should replace the placeholder with a meaningful description.
Error Conditions
The command MUST fail with an error if:
SKILL.mdalready exists in the target directory (prevents accidental overwrite)- The target directory cannot be created (permissions, disk full, etc.)
Rationale:
Scaffolding eliminates the need to manually create skill directories and remember frontmatter format. The minimal template ensures valid Agent Skills format from the start. Project-local skills support the common workflow of developing skills alongside application code.
Since: v0.1.0
Changelog
v0.1.0 (2026-01-30)
Initial release
RFC-0007: CLI Reference
Version: 0.1.0 | Status: normative | Phase: test
1. Summary
[RFC-0007:C-OVERVIEW] Overview (Informative)
RFC-0007 is the single source of truth for skillc’s command-line interface.
This RFC specifies:
- Command Registry — All commands, their parameters, and interface availability (CLI vs MCP)
- Skill Resolution — How skill names/paths are resolved to source directories
- Access Logging — How command invocations are logged for analytics
- Sync Command — How fallback logs are merged to primary locations
- MCP Interface — The Model Context Protocol server for agent integration
Relationship to other RFCs:
- RFC-0001 — Skill Compilation (
buildcommand behavioral spec) - RFC-0002 — Gateway Protocol (
outline,show,open,sourcesbehavioral specs) - RFC-0003 — Usage Analytics (
statscommand behavioral spec) - RFC-0004 — Search Protocol (
searchcommand behavioral spec) - RFC-0005 — Error Code Registry (canonical error codes)
- RFC-0006 — Scaffolding (
initcommand behavioral spec)
Each feature RFC owns the behavioral specification for its commands. RFC-0007 provides the cross-cutting infrastructure that all commands share.
Since: v0.1.0
2. Specification
[RFC-0007:C-COMMANDS] Command Registry (Normative)
This clause defines all skillc commands, their parameters, and interface availability.
Interface Legend:
- CLI: Command-line interface (
skc <command>) - MCP: Model Context Protocol tool (
skc_<command>)
Command Registry
| Command | CLI | MCP | Description |
|---|---|---|---|
init | ✓ | ✓ | Initialize project or create skill |
list | ✓ | ✓ | List all skillc-managed skills |
build | ✓ | ✓ | Compile skill to runtime format |
lint | ✓ | ✓ | Validate skill authoring quality |
outline | ✓ | ✓ | List all sections in a skill |
show | ✓ | ✓ | Retrieve section content |
open | ✓ | ✓ | Retrieve file content |
sources | ✓ | ✓ | List source files (tree-style) |
search | ✓ | ✓ | Search skill content |
stats | ✓ | ✓ | Usage analytics |
sync | ✓ | — | Merge fallback logs to primary (CLI-only) |
mcp | ✓ | — | Start MCP server (CLI-only) |
Parameter Definitions
init
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | no | — | Skill name to create |
--global | boolean | no | false | Create in global source store |
list
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
--scope | string | no | all | Filter: project, global, or all |
--status | string | no | all | Filter: normal, not-built, obsolete, or all |
--limit | number | no | unlimited | Maximum skills to return |
--pattern | string | no | — | Filter by skill name (glob pattern) |
--check-obsolete | boolean | no | false | Enable obsolete runtime detection |
See RFC-0007:C-LIST for full specification.
build
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
skill | string | yes | — | Skill name or path |
--global | boolean | no | false | Force SSOT to global (~/.skillc/runtime/) |
--target | string[] | no | claude | Target agents to deploy to (comma-separated) |
--copy | boolean | no | false | Force copy instead of symlink/junction |
--force | boolean | no | false | Overwrite existing skill during import |
Behavior:
- Skill name: Looks up skill in project source store (
.skillc/skills/) then global (~/.skillc/skills/) - Path: Imports skill to source store first, then builds (requires
--forceto overwrite existing)
Compiles to SSOT location (.skillc/runtime/ for local sources, ~/.skillc/runtime/ for global) and deploys to agent directories via symlink. See RFC-0001:C-DEPLOYMENT.
lint
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
skill | string | yes | — | Skill name or path |
--force | boolean | no | false | Lint even if skill is compiled |
outline
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
skill | string | yes | — | Skill name or path |
level | number | no | unlimited | Maximum heading level (1-6) |
show
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
skill | string | yes | — | Skill name or path |
section | string | yes | — | Section heading to retrieve |
file | string | no | — | Limit search to specific file |
max_lines | number | no | unlimited | Maximum lines to return |
open
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
skill | string | yes | — | Skill name or path |
path | string | yes | — | Relative path within skill |
max_lines | number | no | unlimited | Maximum lines to return |
sources
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
skill | string | yes | — | Skill name or path |
depth | number | no | unlimited | Maximum tree depth |
dir | string | no | — | Scope to subdirectory |
limit | number | no | 100 | Maximum entries |
pattern | string | no | — | Glob pattern filter |
search
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
skill | string | yes | — | Skill name or path |
query | string | yes | — | Search query |
limit | number | no | 10 | Maximum results |
stats
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
skill | string | yes | — | Skill name or path |
group_by | string | no | summary | Aggregation dimension: summary, files, sections, commands, projects, errors, search |
since | string | no | — | Include accesses on or after (ISO 8601) |
until | string | no | — | Include accesses on or before (ISO 8601) |
project | string[] | no | — | Filter by project directory |
sync (CLI-only)
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
skill | string | no | — | Specific skill to sync |
project | string | no | CWD | Project directory |
dry_run | boolean | no | false | Preview without writing |
Rationale for CLI-only commands:
- sync: MCP servers run outside the sandbox and write directly to primary runtime locations. No fallback logs are created, so there is nothing to sync. See RFC-0007:C-LOGGING for fallback mechanism.
- mcp: Starts the MCP server itself; not callable from within MCP.
MCP Tool Naming
MCP tools use snake_case with skc_ prefix:
| CLI Command | MCP Tool |
|---|---|
skc init | skc_init |
skc list | skc_list |
skc build | skc_build |
skc lint | skc_lint |
skc outline | skc_outline |
skc show | skc_show |
skc open | skc_open |
skc sources | skc_sources |
skc search | skc_search |
skc stats | skc_stats |
Since: v0.1.0
[RFC-0007:C-RESOLUTION] Skill Resolution (Normative)
All commands that operate on skills accept a <skill> argument that identifies the target skill.
Source directory resolution (first match wins):
- If
<skill>resolves to a valid directory path containingSKILL.md, use it directly (CWD-relative or absolute). This means a local path takes precedence over a global skill with the same name. - If project config exists (
.skillc/config.tomlrelative to CWD), check project source store using<skill>as a name - Check global source store (
~/.skillc/skills/<skill>/) using<skill>as a name - Resolution failed. Exit with error per RFC-0005:C-CODES:
- If a directory was found at any step but it lacks
SKILL.md: emit E010 - Otherwise (no directory found at all): emit E001
- If a directory was found at any step but it lacks
Runtime directory resolution (for logging):
Derive <skill-name> from the resolved source directory’s basename.
Resolve the runtime store using the same config precedence as storage layout (project config, then global config, then defaults).
The runtime directory is <runtime-store>/<skill-name>/.
If multiple source directories share the same basename within the same runtime store, they will share a log database; skill_path in the log distinguishes entries.
Since: v0.1.0
[RFC-0007:C-LOGGING] Access Logging (Normative)
All commands that resolve skills MUST log access events for usage analytics.
Log storage:
Logs MUST be stored in a SQLite database at .skillc-meta/logs.db in the resolved runtime directory.
Schema:
The database MUST contain an access_log table with at minimum:
id— Auto-incrementing primary keytimestamp— RFC 3339 UTC timestamp (YYYY-MM-DDTHH:MM:SSZ)run_id— Session identifiercommand— Command name (theskcsubcommand, e.g.,outline,show,open,search,build,stats)skill— Skill name (directory basename)skill_path— Canonicalized absolute path to the resolved skill source directorycwd— Canonicalized absolute path of the current working directory when command was invokedargs— JSON-encoded command argumentserror— Error message if command failed (NULL on success)
Canonicalization MUST resolve . and .. path segments and MUST resolve symlinks to their real paths.
Run ID generation:
If SKC_RUN_ID environment variable is set, use its value. Otherwise, generate a run ID in the format YYYYMMDDTHHMMSSZ-<rand4> where <rand4> is 4 random hex characters.
Initialization:
The command MUST attempt to create the runtime directory, .skillc-meta/ subdirectory, database, and schema if they do not exist.
Fallback logging (EAFP):
The command MUST first attempt to write to the primary runtime directory. If the INSERT fails with a read-only error (e.g., sandboxed filesystem), the command MUST fall back to <cwd>/.skillc/logs/<skill-name>/.skillc-meta/logs.db. The fallback directory and database MUST be created if they do not exist.
If both primary and fallback locations fail, the command MUST emit a warning to stderr:
warning: logging disabled; run 'skc sync' after session to merge logs
Stale fallback warning:
If fallback logs exist for the current skill and the database file’s mtime is older than 1 hour, the command SHOULD emit a warning to stderr:
warning: stale local logs for '<skill>'; run 'skc sync' to upload
This warning SHOULD be emitted at most once per command invocation (not per skill if multiple skills are accessed).
The command MUST continue execution regardless of logging success.
Since: v0.1.0
[RFC-0007:C-SYNC] Sync Command (Normative)
Syntax: skc sync [<skill>] [options]
The sync command MUST move log entries from project-local fallback databases to the primary runtime log, then delete the local fallback.
Source discovery:
Scan <cwd>/.skillc/logs/ for skill subdirectories containing .skillc-meta/logs.db. If <skill> is provided, sync only that skill’s logs.
Destination:
The primary runtime directory per RFC-0007:C-RESOLUTION. For global skills, this is typically ~/.skillc/runtime/<skill>/.skillc-meta/logs.db.
Behavior:
- For each discovered skill, copy all entries to the destination database
- Skip entries that already exist (idempotent safety check)
- After successful copy, delete the local fallback database directory
- If destination is not writable (e.g., sandbox still active), emit error E041 and skip that skill
Partial failure: If sync succeeds for skill A but fails for skill B, delete A’s local logs and report B’s error. Each skill is independent.
Options:
| Option | Description |
|---|---|
--project <path> | Sync from specified project directory instead of CWD |
--dry-run | Show what would be synced without writing or deleting |
Output:
Synced 47 entries for 'rust' (local logs removed)
Synced 12 entries for 'cuda' (local logs removed)
With --dry-run:
Would sync 47 entries for 'rust'
Would sync 12 entries for 'cuda'
If no local logs exist:
No local logs to sync
Exit codes:
- 0: Success (including “nothing to sync”)
- 1: Error (partial or complete failure). See RFC-0005:C-CODES for error codes E040–E042.
Since: v0.1.0
[RFC-0007:C-LIST] List Command (Normative)
Syntax: skc list [options]
The list command MUST enumerate all skillc-managed skills from source stores.
Discovery
The command MUST discover skills from these locations in order:
- Project-local source store: Recursive-up search for
.skillc/skills/directories - Global source store:
~/.skillc/skills/
A valid skill is a directory containing a SKILL.md file with valid frontmatter.
Status Detection
Default (Fast Mode)
Without --check-obsolete, status detection is fast:
| Status | Condition |
|---|---|
normal | Runtime directory exists with valid manifest.json |
not-built | No runtime directory or no manifest.json |
With –check-obsolete (Hash Comparison)
When --check-obsolete is provided, the command performs expensive source hash comparison:
| Status | Condition |
|---|---|
normal | Runtime exists and source hash matches manifest |
not-built | No runtime directory or no manifest.json |
obsolete | Runtime exists but source hash differs from manifest |
Output Format
Text Output (CLI default)
$ skc list
SKILL SCOPE STATUS
my-skill project normal
cuda global not-built
When --verbose is provided, include paths:
$ skc list --verbose
SKILL SCOPE STATUS SOURCE
my-skill project normal .skillc/skills/my-skill
cuda global not-built ~/.skillc/skills/cuda
JSON Output (MCP default)
{
"skills": [
{
"name": "my-skill",
"scope": "project",
"status": "normal",
"source_path": "/path/to/.skillc/skills/my-skill",
"runtime_path": "/path/to/.skillc/runtime/my-skill"
}
],
"total": 1,
"filtered": 1
}
Filtering
| Option | Type | Default | Description |
|---|---|---|---|
--scope | project|global|all | all | Filter by skill scope |
--status | normal|not-built|obsolete|all | all | Filter by build status |
--limit | number | unlimited | Maximum skills to return |
--pattern | string | — | Filter by skill name (glob pattern) |
--check-obsolete | boolean | false | Enable hash comparison for obsolete detection |
Ordering
Skills MUST be ordered by:
- Scope: project before global
- Name: alphabetical within scope
Error Handling
- If no skills are found, output an empty list (not an error)
- If a skill directory exists but
SKILL.mdis invalid, skip with warning
Since: v0.1.0
3. MCP Interface
[RFC-0007:C-MCP-OVERVIEW] MCP Interface Overview (Informative)
The MCP (Model Context Protocol) interface provides structured access to skillc functionality for AI agents. Per ADR-0003, MCP is the recommended interface for agents because:
- No sandbox restrictions: MCP servers run outside the IDE sandbox, enabling writes to global directories
- Structured I/O: JSON input/output eliminates text parsing errors
- Native integration: MCP is the designed protocol for agent tools
- Reduced latency: No shell process spawn per command
The MCP interface mirrors CLI functionality. Each CLI command has a corresponding MCP tool with equivalent behavior but structured data exchange.
Architecture:
Human users: Terminal → skc CLI → skillc core
AI agents: MCP client → skillc MCP server → skillc core
Since: v0.1.0
[RFC-0007:C-MCP-SERVER] MCP Server (Normative)
Syntax: skc mcp
The MCP server command MUST start a long-running process that speaks the MCP protocol over stdio.
Protocol:
The server MUST implement the MCP stdio transport:
- Read JSON-RPC messages from stdin
- Write JSON-RPC messages to stdout
- Diagnostic output (if any) MUST go to stderr
Server info:
The server MUST respond to initialize with:
name:"skillc"version: The skillc version string
Tool discovery:
The server MUST respond to tools/list with the MCP-enabled tools defined in RFC-0007:C-COMMANDS.
Configuration:
The MCP server is configured in the agent’s MCP settings:
{
"mcpServers": {
"skillc": {
"command": "skc",
"args": ["mcp"]
}
}
}
Logging:
All tool invocations MUST be logged per RFC-0007:C-LOGGING. Since the MCP server runs outside the sandbox, logging SHOULD write directly to the primary runtime location (no fallback needed).
Since: v0.1.0
Changelog
v0.1.0 (2026-01-30)
Initial release
RFC-0008: Skill Authoring Standard
Version: 0.2.1 | Status: normative | Phase: test
1. Summary
[RFC-0008:C-OVERVIEW] Overview (Informative)
This RFC defines the skill authoring standard as a set of configurable lint rules that skc lint applies to skill directories.
Design:
- Each rule has a unique identifier (SKLxxx)
- Rules are grouped by category (frontmatter, structure, links, files)
- Rules produce diagnostic output per RFC-0005
- Rules will be configurable in a future version (see RFC-0008:C-EXTENSIONS)
Rule categories:
- SKL1xx: Frontmatter validation rules
- SKL2xx: Structure and content rules
- SKL3xx: Link validation rules
- SKL4xx: File organization rules
Relationship to other RFCs:
- RFC-0001 defines compilation requirements; this RFC extends with quality validation
- RFC-0005 defines diagnostic output format; rules map to diagnostic codes
Since: v0.1.0
2. Specification
[RFC-0008:C-REGISTRY] Rule Registry (Normative)
This clause defines all lint rules. Each rule has an ID, name, default severity, and description.
Frontmatter Definition
SKILL.md frontmatter is a YAML block delimited by --- lines:
- The file MUST begin with a line containing exactly
--- - The frontmatter ends at the next line containing exactly
--- - Content between the delimiters is parsed as YAML
Frontmatter validation is handled by rule SKL100.
Rule Summary
| Rule ID | Name | Default | Category |
|---|---|---|---|
| SKL001 | skip-compiled | n/a | Meta |
| SKL100 | frontmatter-valid | error | Frontmatter |
| SKL101 | name-required | error | Frontmatter |
| SKL102 | name-format | error | Frontmatter |
| SKL103 | name-length | error | Frontmatter |
| SKL104 | name-match-dir | warning | Frontmatter |
| SKL105 | description-required | error | Frontmatter |
| SKL106 | description-nonempty | error | Frontmatter |
| SKL107 | description-length | warning | Frontmatter |
| SKL108 | description-triggers | warning | Frontmatter |
| SKL109 | frontmatter-known | warning | Frontmatter |
| SKL201 | skill-size | warning | Structure |
| SKL202 | heading-h1 | warning | Structure |
| SKL203 | heading-match-name | warning | Structure |
| SKL204 | heading-first-h1 | warning | Structure |
| SKL205 | heading-hierarchy | warning | Structure |
| SKL301 | link-file-exists | error | Links |
| SKL302 | link-anchor-exists | warning | Links |
| SKL303 | link-no-escape | error | Links |
| SKL401 | no-orphans | warning | Files |
Meta Rules (SKL0xx)
SKL001: skip-compiled
Skip linting for compiled skills (detected by .skillc-meta/manifest.json).
Default behavior: enabled (compiled skills are skipped)
When a compiled skill is detected and this rule is enabled:
- The linter prints:
info: skipping compiled skill '<name>' - Exits with code 0 (success)
When --force is used, this rule is disabled and:
- The linter emits:
warning[W300]: SKL001 skip-compiled: linting compiled skill; results may not be meaningful - Applies all other rules normally
Configurability: Unlike other rules, SKL001 is controlled by --force, not by rule configuration. Future versions MAY allow disabling it via config.
Rationale: Compiled skills are derived artifacts. Their generated stub differs from source content.
Frontmatter Rules (SKL1xx)
SKL100: frontmatter-valid
SKILL.md MUST have valid frontmatter delimiters and parseable YAML.
Default severity: error
Requirements:
- File MUST begin with a line containing exactly
--- - A second
---line MUST appear to close the frontmatter - Content between delimiters MUST be valid YAML
Error messages:
- Missing opening delimiter:
missing frontmatter: file does not start with --- - Missing closing delimiter:
missing frontmatter: no closing --- found - YAML parse error:
invalid frontmatter YAML: <parse-error>
SKL101: name-required
The name field MUST be present in SKILL.md frontmatter.
Default severity: error
SKL102: name-format
The name field MUST contain only lowercase ASCII letters (a-z), digits (0-9), and hyphens (-). It MUST NOT start or end with a hyphen.
Default severity: error
Valid: my-skill, skill123, a
Invalid: My-Skill (uppercase), -skill (leading hyphen), skill_name (underscore)
SKL103: name-length
The name field MUST be 1-64 characters in length.
Default severity: error
SKL104: name-match-dir
The name field SHOULD match the skill directory name.
Default severity: warning
SKL105: description-required
The description field MUST be present in SKILL.md frontmatter.
Default severity: error
SKL106: description-nonempty
The description field MUST NOT be empty or whitespace-only.
Default severity: error
SKL107: description-length
The description field SHOULD be at most 1024 characters.
Default severity: warning
SKL108: description-triggers
The description field SHOULD include activation triggers.
Default severity: warning
Detection: The rule checks for presence of any of these English patterns (case-insensitive):
use whenwhen to useuse fortriggers ontriggers:activate when
Note: This rule is designed for English-language skills. Non-English skills may disable this rule via configuration (future).
SKL109: frontmatter-known
Frontmatter fields SHOULD be from the known set.
Default severity: warning
Known fields:
name(required)description(required)allowed-tools(optional, implementation-defined behavior)
Unknown fields trigger a warning. This helps catch typos and misunderstandings of the schema.
Note on allowed-tools: This field is recognized by some agent implementations to restrict available tools. Its format and semantics are implementation-defined. Future versions MAY add validation rules for this field.
Structure Rules (SKL2xx)
SKL201: skill-size
SKILL.md SHOULD be at most 500 lines.
Default severity: warning
SKL202: heading-h1
SKILL.md SHOULD contain at least one H1 (#) heading.
Default severity: warning
SKL203: heading-match-name
The first H1 heading in SKILL.md SHOULD match or contain the skill name.
Default severity: warning
Matching: Case-insensitive comparison. The heading may contain additional text (e.g., heading “My Skill Guide” matches name “my-skill” if “my-skill” appears as a substring after normalizing hyphens to spaces).
SKL204: heading-first-h1
The first heading in each markdown file SHOULD be an H1 (#).
Default severity: warning
Scope: Applies to all .md files in the skill directory.
Rationale: The first heading establishes the document title. Starting with H2 or lower suggests missing context.
Since: v0.2.0
SKL205: heading-hierarchy
Headings SHOULD NOT skip levels when going deeper.
Default severity: warning
Scope: Applies to all .md files in the skill directory.
Requirements:
- When increasing heading depth, levels MUST NOT be skipped (H2→H4 is invalid; H2→H3 is valid)
- Decreasing depth is always allowed (H3→H2, H4→H1 are valid)
Examples:
- Valid:
# Title→## Section→### Subsection→## Another Section - Invalid:
# Title→### Subsection(skipped H2) - Invalid:
## Section→#### Deep(skipped H3)
Rationale: Skipped heading levels break document outline semantics and can cause accessibility issues.
Since: v0.2.0
Link Rules (SKL3xx)
SKL301: link-file-exists
Internal markdown file links MUST resolve to existing files within the skill directory.
Default severity: error
Scope: Relative links like [text](path/to/file.md). Absolute paths and external URLs are not checked.
SKL302: link-anchor-exists
Internal markdown anchor links SHOULD resolve to existing headings.
Default severity: warning
Anchor normalization: GitHub-style slugging for ASCII:
- Convert to lowercase
- Remove characters except
a-z,0-9, spaces, hyphens - Replace spaces with hyphens
- Collapse consecutive hyphens
Non-ASCII characters are removed. For duplicate headings, anchors are suffixed: #heading, #heading-1.
SKL303: link-no-escape
Links MUST NOT escape the skill root directory via .. traversal.
Default severity: error
File Rules (SKL4xx)
SKL401: no-orphans
Markdown files in the skill directory SHOULD be reachable from SKILL.md via link traversal.
Default severity: warning
Definition: A file is orphaned if it is not SKILL.md and is not reachable via links starting from SKILL.md (transitive closure).
Exceptions: Not considered orphaned:
- Files in hidden directories (starting with
.) - Common non-content files:
LICENSE.md,CHANGELOG.md,CONTRIBUTING.md,README.md
Since: v0.1.0
[RFC-0008:C-SCOPE] Lint Scope (Normative)
This clause defines what files the linter scans.
File Scanning
The linter scans all .md files in the skill directory, excluding:
- Files in directories starting with
.(e.g.,.git/,.skillc-meta/,.github/) - Files whose names start with
.
This is consistent with RFC-0001 compilation behavior.
Compiled Skill Detection
Compiled skill handling is defined by rule SKL001 in RFC-0008:C-REGISTRY.
Detection: A skill is compiled if .skillc-meta/manifest.json exists.
SKILL.md Requirement
The linter requires SKILL.md to exist. If missing, the linter exits with E010 per RFC-0005:C-CODES.
Frontmatter Requirement
Frontmatter validation is handled by rule SKL100 in RFC-0008:C-REGISTRY. Invalid frontmatter produces E300 (lint error), not E010.
Since: v0.1.0
[RFC-0008:C-DIAGNOSTICS] Diagnostic Output (Normative)
This clause defines how lint rules produce diagnostic output.
Output Format
All lint diagnostics use the format defined in RFC-0005:C-CODES:
<severity>[<code>]: <rule-id> <rule-name>: <message>
Components:
<severity>:errororwarning<code>:E300for errors,W300for warnings<rule-id>: The rule identifier (e.g.,SKL102)<rule-name>: The rule name (e.g.,name-format)<message>: Human-readable description of the violation
Examples:
error[E300]: SKL102 name-format: name 'My-Skill' contains uppercase characters
error[E300]: SKL301 link-file-exists: link target not found: 'references/missing.md'
warning[W300]: SKL104 name-match-dir: name 'foo' does not match directory 'bar'
warning[W300]: SKL401 no-orphans: orphaned file: 'old-notes.md'
Rule Severity Mapping
Each rule has a default severity (error or warning) defined in RFC-0008:C-REGISTRY.
| Default Severity | Diagnostic Code |
|---|---|
| error | E300 |
| warning | W300 |
Exit Behavior
- If any rule with error severity is violated: exit with status 1
- If only warning-severity rules are violated: exit with status 0
- If no violations: exit with status 0
Machine-Readable Output
Future versions MAY support structured output formats (JSON, SARIF) for tooling integration. See RFC-0008:C-EXTENSIONS.
Since: v0.1.0
[RFC-0008:C-REFERENCE-FRONTMATTER] Reference File Frontmatter (Informative)
Non-SKILL.md markdown files (reference documents) MAY contain optional YAML frontmatter.
Frontmatter Format
Reference files MAY begin with a YAML frontmatter block:
---
description: "Brief description of this reference document"
---
# Reference Title
Content here...
Supported Fields
| Field | Required | Description |
|---|---|---|
description | No | Brief description displayed in compiled stub |
Field Constraints
description:
- Optional (no lint warning if absent)
- Should be ≤120 characters for optimal display
- Longer descriptions are truncated with
…in the stub - Used by the compiler per RFC-0001:C-SECTIONS
Differences from SKILL.md Frontmatter
Reference file frontmatter differs from SKILL.md frontmatter:
| Aspect | SKILL.md | Reference files |
|---|---|---|
| Required | Yes | No |
name field | Required | Not used |
description field | Required | Optional |
| Linting | Full validation | No validation |
Example
A reference file references/clap-patterns.md:
---
description: "Advanced clap argument parsing patterns"
---
# Clap Patterns
## Value Enums
...
This description appears in the compiled stub:
- References
- Clap Patterns — Advanced clap argument parsing patterns
Since: v0.2.0
3. Extensions
[RFC-0008:C-EXTENSIONS] Future Extensions (Informative)
This clause describes planned future extensions. These are NOT part of v0.2.0.
Configurable Rules (Future)
A future version MAY support rule configuration via .skilllint.toml:
# Example future configuration (not implemented)
[rules]
SKL107 = "off" # Disable description length check
SKL201 = { max-lines = 300 } # Custom threshold
SKL108 = "error" # Upgrade warning to error
Design considerations:
- Configuration file location: skill root or global
~/.config/skillc/ - Per-rule enable/disable
- Severity override (error ↔ warning ↔ off)
- Rule-specific parameters (thresholds, patterns)
Inline Directives (Future)
A future version MAY support inline directives to suppress warnings:
<!-- skilllint-disable SKL201 -->
[large content here]
<!-- skilllint-enable SKL201 -->
Or single-line suppression:
[very long line] <!-- skilllint-disable-line SKL... -->
Structured Output (Future)
A future version MAY support machine-readable output:
--format=json— JSON array of violations--format=sarif— SARIF format for IDE integration
Additional Rules (Future)
Potential future rules:
- SKL110:
allowed-tools-known— warn on unrecognized tool names - SKL206:
code-block-language— code blocks should have language tags - SKL207:
line-length— lines should not exceed threshold
Note: These extensions are documented for planning. They are out of scope for v0.2.0.
Since: v0.1.0
Changelog
v0.2.1 (2026-01-31)
Add C-REFERENCE-FRONTMATTER for optional description in reference files
v0.2.0 (2026-01-31)
Normalize SKL204, SKL205
v0.1.0 (2026-01-30)
Initial release
RFC-0009: Configuration
Version: 0.2.0 | Status: normative | Phase: test
1. Summary
[RFC-0009:C-OVERVIEW] Overview (Informative)
skillc supports optional configuration files at two levels:
- Global:
~/.skillc/config.toml— user-wide preferences - Project:
.skillc/config.toml— project-specific overrides
Configuration is minimal by design. Most behavior is convention-based with CLI overrides for per-invocation choices. Config files are reserved for true preferences that rarely change but need project-level control.
v0.1.0 Scope:
- Tokenizer preference for search indexing (ASCII vs CJK)
Future Extensions (planned):
- Lint rule enable/disable per RFC-0008
Since: v0.1.0
2. Specification
[RFC-0009:C-FILES] Configuration Files (Normative)
File Locations
skillc MUST check for configuration files in these locations:
| Scope | Path | Purpose |
|---|---|---|
| Global | ~/.skillc/config.toml | User-wide preferences |
| Project | .skillc/config.toml | Project-specific overrides |
File Format
Configuration files MUST use TOML format.
Configuration files MAY be empty or omit any section. Missing values use defaults per RFC-0009:C-RESOLUTION.
Schema
# Schema version (optional, default: 1)
version = 1
[search]
# Tokenizer for search indexing: "ascii" (default) or "cjk"
tokenizer = "ascii"
# Reserved for future use
# [lint]
# rules = { ... }
Version Handling
The version field is OPTIONAL. If omitted, version 1 is assumed.
Compatibility rules:
- Version 1 is the only supported version in v0.1.0
- If
versionis present and greater than the supported version, skillc MUST emit a warning and proceed using only recognized fields - If
versionis present and not a positive integer, skillc MUST emit an error and ignore the entire config file (proceed as if it does not exist)
Unknown Keys
Unknown keys and sections MUST be ignored with a warning. This enables forward compatibility when older skillc versions read configs written for newer versions.
Since: v0.1.0
[RFC-0009:C-RESOLUTION] Resolution Order (Normative)
When resolving a configuration value, skillc MUST apply this precedence order (highest first):
- CLI flags — explicit per-invocation override
- Environment variables — process-level override (see below)
- Project config —
.skillc/config.tomlin current directory or ancestors - Global config —
~/.skillc/config.toml - Built-in defaults — hardcoded fallback values
Project Config Discovery
skillc MUST search for .skillc/config.toml starting from the current working directory and walking up to filesystem root. The first config file found is used.
If no project config is found, only global config and defaults apply.
Merging Behavior
Resolution is per-key, not per-file. For each setting:
- If project config specifies a value, use it
- Otherwise, if global config specifies a value, use it
- Otherwise, use the built-in default
Settings not specified in a config file do not override lower-precedence values.
Environment Variables (v0.1.0)
Only the following environment variables are defined in v0.1.0:
| Variable | Overrides | Valid Values |
|---|---|---|
SKILLC_TOKENIZER | [search].tokenizer | ascii, cjk |
If an environment variable is set to an invalid value, skillc MUST emit a warning and ignore the variable (fall through to next precedence level).
Additional environment variables MAY be added in future versions.
Since: v0.1.0
[RFC-0009:C-TOKENIZER] Tokenizer Setting (Normative)
The [search].tokenizer setting controls how text is tokenized for the search index per RFC-0004:C-INDEX.
Values
| Value | Behavior | Use Case |
|---|---|---|
ascii | Split on whitespace and punctuation | English and space-delimited languages (default) |
cjk | Character-level tokenization with ASCII fallback | Chinese, Japanese, Korean content |
Default
If not specified, the tokenizer MUST default to ascii.
Effect on Index
Changing the tokenizer setting invalidates existing search indexes. The search command MUST detect tokenizer mismatch and prompt for rebuild per RFC-0004:C-INDEX.
Since: v0.1.0
[RFC-0009:C-ENV-OVERRIDE] Environment Variable Override (Normative)
The SKILLC_HOME environment variable, if set, MUST override the default home directory detection for all global paths.
When SKILLC_HOME is set to a path (e.g., /custom/home):
global_skillc_dir()MUST return$SKILLC_HOME/.skillc/(e.g.,/custom/home/.skillc/)- All derived paths (global source store, global runtime, etc.) MUST use this base
find_project_root()MUST exclude$SKILLC_HOMEfrom project root detection
When SKILLC_HOME is not set:
- The implementation MUST fall back to
dirs::home_dir()behavior
Rationale: This enables:
- Cross-platform test isolation (HOME env var only works on Unix)
- Custom installation locations
- Portable/relocatable installations
Since: v0.2.0
Changelog
v0.2.0 (2026-01-31)
Add SKILLC_HOME override
v0.1.0 (2026-01-30)
Initial release
ADR-0001: Storage Layout
Status: accepted | Date: 2026-01-26
References: RFC-0001
Context
skillc needs to store skill-related files in two locations:
- Source files — where skill authors write and edit content
- Runtime files — where agents discover and consume compiled skills
These locations must be:
- Predictable (so skillc can find them without configuration)
- Non-conflicting (source and runtime are separate concerns)
- Compatible with existing Agent Skills tooling (Claude Code, Cursor, etc.)
The runtime location is particularly constrained: agents look for skills in specific directories based on their host environment.
Decision
We adopt a two-tier configuration system:
Global configuration: ~/.skillc/config.toml
- Default source store:
~/.skillc/src/ - Default runtime store:
~/.claude/skills/ - Registry:
~/.skillc/registry.json
Project configuration: ./.skillc/config.toml (in project root)
- Overrides global defaults when present
- Typical runtime store:
./.claude/skills/or./.skills/ - Enables project-local skills versioned with the repository
Resolution order (highest priority first):
- Project source store (
./.skillc/skills/) - Global source store (
~/.skillc/skills/)
Note: CLI flags and environment variables for overriding source/runtime directories were removed in v0.1.0 to simplify the design. Direct paths can be imported via skc build <path> which copies to the appropriate source store.
Registry scope:
- Global registry tracks globally-installed skills
- Project skills are discovered by scanning project config, not stored in global registry
This mirrors Claude Code’s model of global vs project-local skills.
Consequences
Positive:
- Matches mental model of global vs project-local (like Claude Code)
- Project skills can be version-controlled with the repository
- Flexible for different agent environments via config
- Clear precedence rules prevent confusion
Negative:
- Two config files to potentially manage
- Project detection logic needed (find
.skillc/config.tomlupward) - Registry now only covers global skills; project skills discovered differently
Trade-offs accepted:
- Complexity of layered config is justified by flexibility gained
- Project skills not in global registry is intentional (they belong to the project)
ADR-0002: Multi-Target Build Output
Status: accepted | Date: 2026-01-29
References: ADR-0001, RFC-0001
Context
Context
The current build system writes compiled skills directly to ~/.claude/skills/, which has several problems:
Problem Statement
-
Data destruction risk: If a user has hand-crafted skills in
~/.claude/skills/rust/, runningskc build rustoverwrites them without warning or backup. -
Single-target limitation: The build output is hardcoded to Claude’s skill directory. Other AI coding assistants (Cursor, Kiro, OpenCode, Copilot, etc.) have their own skill directories.
-
No canonical source location: Skills can be built from anywhere, making it hard to track what skills exist and where their sources are.
Constraints
- ADR-0001 defines a layered configuration system with global and project-level overrides
- RFC-0001 specifies compilation output format (SKILL.md + manifest)
- Backward compatibility with existing users who expect
skc buildto “just work”
Options Considered
- Keep current design — Accept data loss risk, single-target only
- Add backup before overwrite — Reduces risk but doesn’t solve multi-target
- Separate source from target — skillc manages source, deploys to targets
Decision
Decision
We adopt a source/target separation model:
Source Resolution (where to find skill source)
Resolution order (highest priority first):
./.skillc/skills/<skill>/— Project-local source (recursive-up search)~/.skillc/skills/<skill>/— Global source
Note: Direct paths can be provided to skc build, which imports them to the appropriate source store before building. Use --force to overwrite existing skills during import.
Target Selection (where to write compiled output)
The --target <platform> flag selects the output directory:
skc build rust # --target defaults to "claude"
skc build rust --target cursor # Output to cursor skill dir
skc build rust --target kiro # Output to kiro skill dir
Target Registry
Target paths are configured in ~/.skillc/config.toml:
[targets]
claude = "~/.claude/skills"
cursor = "~/.cursor/skills"
# Additional targets can be added by user
Built-in defaults are provided for known platforms. Users can override or add custom targets.
Implementation Notes
- The
--targetflag defaults toclaudefor backward compatibility - Unknown target names are errors (must be configured first)
- Build output structure remains unchanged per RFC-0001:C-OUTPUT
Consequences
Consequences
Positive
- No data destruction: skillc never overwrites user’s hand-crafted skills; it writes to its own source directory
- Multi-platform support: Same skill source can be deployed to multiple AI assistants
- Canonical source location:
~/.skillc/skills/becomes the single source of truth for skillc-managed skills - Extensible: New platforms can be added via config without code changes
Negative
- Migration required: Existing users must move skills to
~/.skillc/skills/or useskc build <path>to import - Additional config: Target registry adds configuration surface area
- Two-step mental model: Users must understand source vs target distinction
Trade-offs Accepted
- Complexity of source resolution order is justified by flexibility gained
- Default to
claudetarget maintains backward compatibility for most users - Requiring explicit target configuration for new platforms is safer than guessing paths
Alternatives Considered
- Keep current design: Accept data loss risk and single-target limitation. Rejected because it violates user trust.
- Backup before overwrite: Create backup of existing skills before writing. Partial solution - doesn’t address multi-target need.
ADR-0003: MCP as Primary Agent Interface
Status: accepted | Date: 2026-01-29
References: RFC-0002, RFC-0003, RFC-0004
Context
Context
AI coding agents interact with skillc through the CLI via the Shell tool. This architecture has fundamental limitations:
Problem Statement
-
Sandbox restrictions: Many AI IDEs (Cursor, Claude Desktop) sandbox Shell tool execution. This blocks writes to global directories like
~/.claude/skills/<skill>/.skillc-meta/logs.db. -
Workaround complexity: RFC-0007:C-LOGGING specifies a fallback mechanism (write locally, then
skc sync), but this requires manual user intervention and adds cognitive overhead. -
Interface mismatch: CLI is designed for humans (text parsing, exit codes). Agents benefit from structured data (JSON) and native tool integration.
-
Performance overhead: Each CLI invocation spawns a shell process, adding latency.
Constraints
- CLI must remain for human users and automation scripts
- MCP is the standard agent integration protocol
- Existing CLI behavior must not regress
Options Considered
- Keep CLI-only: Accept sandbox limitations, rely on fallback + sync
- MCP for logging only: Add MCP server just for log writes
- Full MCP interface: Expose all skillc operations as MCP tools
Decision
Decision
We adopt MCP as the primary agent interface:
Architecture
Human users: Terminal → skc CLI → skillc core
AI agents: MCP client → skillc MCP server → skillc core
The MCP server exposes tools that mirror CLI commands:
| MCP Tool | CLI Equivalent | Description |
|---|---|---|
skc_outline | skc outline <skill> | List skill sections |
skc_show | skc show <skill> [section] | Display skill content |
skc_open | skc open <skill> | Open skill in editor |
skc_search | skc search <query> | Search across skills |
skc_stats | skc stats [options] | Usage analytics |
skc_build | skc build <skill> | Compile skill |
skc_sync | skc sync | Sync local logs |
skc_sources | skc sources <skill> | List source files |
Key Design Points
- MCP server runs outside sandbox: No filesystem restrictions
- Structured I/O: JSON input/output instead of text parsing
- Same core logic: CLI and MCP share implementation
- Logging works naturally: MCP server writes directly to global db
Deployment
The MCP server is registered in the agent’s MCP configuration:
{
"mcpServers": {
"skillc": {
"command": "skc",
"args": ["mcp"]
}
}
}
Consequences
Consequences
Positive
- No sandbox issues: MCP server has full filesystem access
- Native agent integration: MCP is the designed protocol for agent tools
- Structured data: JSON eliminates text parsing errors
- Reduced latency: No shell spawn overhead per command
- Simplified logging: No fallback + sync dance needed for agents
Negative
- Two interfaces to maintain: CLI and MCP must stay in sync
- MCP server complexity: New component to build and test
- Setup required: Users must configure MCP server in their IDE
- CLI fallback still needed: For humans and non-MCP environments
Trade-offs Accepted
- Implementation cost of MCP server is justified by UX improvement
- Keeping CLI + MCP means more code, but serves distinct user populations
- RFC-0007:C-LOGGING fallback mechanism remains for CLI users in sandboxed environments
Alternatives Considered
- Keep CLI-only: Accept sandbox limitations. Rejected because it degrades agent UX and requires manual sync.
- MCP for logging only: Partial solution. Rejected because other operations also benefit from MCP.
Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
[0.2.1] - 2026-02-07
Fixed
- Index-based section extraction now correctlyignores headings inside code blocks (WI-2026-02-02-001)
[0.2.0] - 2026-01-31
Added
- SKL204 heading-first-h1 lint rule per RFC-0008:C-REGISTRY (WI-2026-01-31-003)
- SKL205 heading-hierarchy lint rule per RFC-0008:C-REGISTRY (WI-2026-01-31-003)
- Parse optional description from reference file frontmatter (WI-2026-01-31-004)
- Display description inline with em-dash in stub References section (WI-2026-01-31-004)
- Truncate descriptions longer than 120 chars with ellipsis (WI-2026-01-31-004)
- Headings table added to search index database (WI-2026-01-31-005)
- skc show uses index-based lookup instead of runtime parsing (WI-2026-01-31-005)
- Em-dash suffix stripping for section queries (WI-2026-01-31-005)
- Suggestions on section not found (WI-2026-01-31-005)
Changed
- Stub section listing per RFC-0001:C-SECTIONS - SKILL.md shows H1 and H2 only, other files show H1/filename with optional description (WI-2026-01-31-003)
- RFC-0004 C-INDEX updated with headings table schema (WI-2026-01-31-005)
- RFC-0002 C-SHOW updated with lookup behavior (WI-2026-01-31-005)
[0.1.1] - 2026-01-31
Added
SKILLC_HOMEenv var overrides home directory detection (WI-2026-01-31-001)
Fixed
- MCP lint/build use resolve_skill() (WI-2026-01-31-002)
[0.1.0] - 2026-01-30
Added
- RFC-0000 defines skillc vision aligned with Agent Skills ecosystem (WI-2026-01-25-001)
- RFC-0000 includes normative compatibility guarantees (format, offline, portability) (WI-2026-01-25-001)
- RFC-0001 specifies stub output format (WI-2026-01-25-002)
- RFC-0001 specifies manifest structure (WI-2026-01-25-002)
- RFC-0001 defines compilation constraints (WI-2026-01-25-002)
- Compiler accepts valid Agent Skills directory (WI-2026-01-26-001)
- Compiler produces stub SKILL.md per RFC-0001:C-STUB (WI-2026-01-26-001)
- Compiler produces manifest.json per RFC-0001:C-MANIFEST (WI-2026-01-26-001)
skc buildCLI command works (WI-2026-01-26-001)- Implement
skc outlinecommand per RFC-0002:C-OUTLINE (WI-2026-01-26-002) - Implement
skc showcommand per RFC-0002:C-SHOW (WI-2026-01-26-002) - Implement
skc opencommand per RFC-0002:C-OPEN (WI-2026-01-26-002) - Implement access logging per RFC-0007:C-LOGGING (WI-2026-01-26-002)
- Implement skill resolution per RFC-0007:C-RESOLUTION (WI-2026-01-26-002)
- Implement stats analytics queries per RFC-0003 (WI-2026-01-26-003)
- Support filters and JSON output schema (WI-2026-01-26-003)
- CLI integration test harness with snapshots (WI-2026-01-27-001)
- Integration coverage for gateway and stats commands (WI-2026-01-27-001)
- Draft RFC-0004 Search Protocol (WI-2026-01-28-001)
- Create RFC-0005 Error Code Registry (WI-2026-01-28-002)
- Define canonical error code table (WI-2026-01-28-002)
- Migrate RFC-0004 C-ERRORS to reference RFC-0005 (WI-2026-01-28-002)
- Build centralized error code registry in
error.rs(WI-2026-01-29-001) - Migrate all commands to use canonical error messages per RFC-0005:C-CODES (WI-2026-01-29-001)
- Implement
skc searchcommand with FTS5 index (WI-2026-01-29-003) - Build search index during
skc buildper RFC-0004:C-INDEX (WI-2026-01-29-003) - Support .md and .txt file formats per RFC-0004:C-FORMATS (WI-2026-01-29-003)
- E999 added to RFC-0005 for internal errors (WI-2026-01-29-007)
- SKC_VERBOSE/-v flag for debug output (WI-2026-01-29-008)
- CLI examples in –help output (WI-2026-01-29-008)
- CONTRIBUTING.md documentation (WI-2026-01-29-008)
- Pass verbose flag through to library functions (WI-2026-01-29-009)
- Verbose output shows resolved paths for skill resolution (WI-2026-01-29-009)
- Verbose output shows timing information for operations (WI-2026-01-29-009)
skc sourcescommand with tree-style output (WI-2026-01-29-011)--depth,--dir,--limit,--patternoptions (WI-2026-01-29-011)- Amend RFC-0007:C-LOGGING with fallback logging for sandboxed environments (WI-2026-01-29-012)
- Add RFC-0007:C-SYNC clause for sync command (WI-2026-01-29-012)
- Implement fallback logging to workspace when primary fails (WI-2026-01-29-012)
- Implement
skc synccommand to merge local logs to global (WI-2026-01-29-012) - Stale fallback warning when local logs >1 hour old (WI-2026-01-29-014)
- ADR-0002 Multi-Target Build Output drafted and accepted (WI-2026-01-29-017)
- ADR-0003 MCP as Primary Agent Interface drafted and accepted (WI-2026-01-29-017)
- C-MCP-OVERVIEW clause for MCP interface overview (WI-2026-01-29-019)
- C-MCP-SERVER clause for server specification (WI-2026-01-29-019)
- C-MCP-TOOLS clause for tool specifications (WI-2026-01-29-019)
--targetflag for build command (default: claude) (WI-2026-01-29-020)- Target registry in config with built-in defaults (WI-2026-01-29-020)
skc mcpcommand for MCP server (WI-2026-01-29-021)- MCP tools: skc_outline, skc_show, skc_open, skc_sources, skc_search, skc_stats, skc_build, skc_sync (WI-2026-01-29-021)
- Add missing optional params to MCP tools (WI-2026-01-29-022)
- Create RFC-0007 CLI Reference (WI-2026-01-29-023)
- Add C-INIT to RFC-0006 for init command (WI-2026-01-29-023)
skc initcreates.skillc/project structure (WI-2026-01-29-024)skc init <name>creates project-local skill (WI-2026-01-29-024)skc init <name> --globalcreates global skill (WI-2026-01-29-024)- RFC-0005 amended with warning code specification (WI-2026-01-29-026)
- Warning codes W001-W003 defined for existing warnings (WI-2026-01-29-026)
- Warning infrastructure in error.rs (WI-2026-01-29-026)
- Implement
skc lintcommand per RFC-0008 (WI-2026-01-29-027) - Implement SKL1xx frontmatter rules (WI-2026-01-29-027)
- Implement SKL2xx structure rules (WI-2026-01-29-027)
- Implement SKL3xx link rules (WI-2026-01-29-027)
- Implement SKL4xx file rules (WI-2026-01-29-027)
- Implement
skc_initMCP tool (WI-2026-01-30-001) - Implement
skc_lintMCP tool (WI-2026-01-30-001) - Local source compiles to .skillc/runtime/ (SSOT) and symlinks to agent directory (WI-2026-01-30-005)
- –global flag compiles to ~/.skillc/runtime/ (global SSOT) (WI-2026-01-30-005)
- –target flag specifies which agents to deploy to (default: claude) (WI-2026-01-30-005)
- –copy flag forces copy instead of symlink/junction (WI-2026-01-30-005)
- Cross-platform support: symlink (Unix), junction/copy fallback (Windows) (WI-2026-01-30-005)
- Unit tests for deploy.rs and integration tests for build command (WI-2026-01-30-005)
- Config file parsing for global and project configs (WI-2026-01-30-006)
- Tokenizer preference setting (ascii/cjk) (WI-2026-01-30-006)
- Import flow for direct paths (copy to .skillc/skills/) (WI-2026-01-30-007)
- –force flag for overwriting during import (WI-2026-01-30-007)
- Recursive-up project detection for skill lookup (WI-2026-01-30-007)
- Enhanced build output showing Source/Runtime/Deploy with scope labels (WI-2026-01-30-007)
- CLI list command with text output (WI-2026-01-30-008)
- MCP skc_list tool with JSON output (WI-2026-01-30-008)
- Skill discovery from project and global source stores (WI-2026-01-30-008)
- Status detection (normal, not-built, stale) (WI-2026-01-30-008)
- Filtering by scope, status, limit, pattern (WI-2026-01-30-008)
- Short flags for common options (-g, -f, -o, -t, -l, -p) (WI-2026-01-30-009)
- Colored output using comfy-table (WI-2026-01-30-009)
- Document list command in README (WI-2026-01-30-011)
- Integration tests for lint command (WI-2026-01-30-012)
- Integration tests for list command (WI-2026-01-30-012)
skc stats --group-by searchreturns search query breakdown (WI-2026-01-30-013)skc outline --level <n>filters headings by level (WI-2026-01-30-013)skc show --max-lines <n>limits output lines (WI-2026-01-30-013)skc open --max-lines <n>limits output lines (WI-2026-01-30-013)
Changed
- Error messages include error codes (e.g., error[E001]: …) (WI-2026-01-29-007)
- Sync always deletes local logs after successful upload (remove –purge option) (WI-2026-01-29-014)
- Partial failure handling - delete what synced successfully (WI-2026-01-29-014)
- RFC-0001:C-STUB updated to include MCP preference statement (WI-2026-01-29-018)
- C-OVERVIEW updated to mention MCP (WI-2026-01-29-019)
- Source resolution uses
~/.skillc/skills/instead of~/.skillc/src/(WI-2026-01-29-020) - Move C-COMMANDS from RFC-0002 to RFC-0007 (WI-2026-01-29-023)
- Move C-MCP-OVERVIEW from RFC-0002 to RFC-0007 (WI-2026-01-29-023)
- Move C-MCP-SERVER from RFC-0002 to RFC-0007 (WI-2026-01-29-023)
- Move C-RESOLUTION from RFC-0002 to RFC-0007 (WI-2026-01-29-023)
- Move C-LOGGING from RFC-0002 to RFC-0007 (WI-2026-01-29-023)
- Move C-SYNC from RFC-0002 to RFC-0007 (WI-2026-01-29-023)
- Remove –source-dir and –runtime-dir CLI flags (WI-2026-01-30-007)
- Remove SKILLC_SOURCE and SKILLC_RUNTIME env var support (WI-2026-01-30-007)
- Remove RFC references from CLI help text (WI-2026-01-30-009)
- Replace regex link extraction with pulldown-cmark AST (WI-2026-01-30-010)
Removed
- Remove skc_sync from MCP (CLI-only per RFC) (WI-2026-01-29-022)
Fixed
- Resolver checks runtime store as fallback (WI-2026-01-29-005)
- Error message for invalid project path should be descriptive (WI-2026-01-29-006)
- InvalidPath error shows descriptive message (WI-2026-01-29-007)
- Clippy collapsible if warning in tests/common/mod.rs (WI-2026-01-29-008)
- Source hash is deterministic across rebuilds (excludes .git/.jj directories) (WI-2026-01-29-010)
- Init creates non-empty description per RFC-0001 (WI-2026-01-29-025)
- Compiler rejects symlinks escaping skill root per RFC-0001 (WI-2026-01-29-025)
- Enforce 100-line stub size limit per RFC-0001:C-CONSTRAINTS (WI-2026-01-30-002)
- Complete staleness check per RFC-0004:C-INDEX (WI-2026-01-30-002)
- Status filter documentation (stale -> obsolete) (WI-2026-01-30-009)
- Linter SKL301 no longer flags links inside code blocks (WI-2026-01-30-010)
- Linter SKL301 no longer flags links inside inline code (WI-2026-01-30-010)
- Correct storage path from ~/.skillc/src/ to ~/.skillc/skills/ (WI-2026-01-30-011)
Security
- Add cargo-deny configuration for dependency auditing (WI-2026-01-29-008)