Skill Examples
Complete, real-world examples of building skills for Nebo. Each example includes the full directory structure, complete SKILL.md content, any bundled scripts, and an explanation of design decisions. For the format specification, see SKILL.md Reference. For an overview of the skill system, see Skills Overview.
Progressive Skill Complexity
Skills range from a single SKILL.md file to multi-file directories with scripts, references, and plugin dependencies. The examples below progress from minimal to fully featured, showing what each level of complexity unlocks.
Simple: Commit Message Writer
The simplest possible skill -- a single SKILL.md file with only the two required frontmatter fields. No scripts, no references, no Nebo extensions. This skill works identically on Nebo, Claude Code, OpenAI Codex, and any Agent Skills-compatible platform.
Directory structure:
commit-message/ └── SKILL.md
SKILL.md:
---
name: commit-message
description: Write conventional commit messages from staged git changes.
Use when the user asks to write a commit message, describe their
changes, or prepare a commit.
---
# Commit Message Writer
Write commit messages following the Conventional Commits specification.
## Process
1. Run `git diff --staged` to see what changed
2. Identify the type: feat, fix, refactor, docs, test, chore, ci, perf
3. Identify the scope (the module or area affected)
4. Write a concise subject line (imperative mood, no period, under 72 chars)
5. If the change is non-trivial, add a body explaining WHY, not WHAT
## Format
```
<type>(<scope>): <subject>
<body>
```
## Rules
- Subject line: imperative mood ("add" not "added" or "adds")
- No period at the end of the subject
- Separate subject from body with a blank line
- Body wraps at 72 characters
- Use "BREAKING CHANGE:" footer for breaking changes
- If multiple things changed, consider whether it should be multiple commits
## Examples
- `feat(auth): add OAuth2 PKCE flow for mobile clients`
- `fix(parser): handle escaped quotes in CSV fields`
- `refactor(api): extract middleware into composable functions`
- `docs(readme): add deployment instructions for ARM64`Intermediate: API Documentation Generator
An intermediate skill that uses Nebo extensions (triggers, capabilities, priority) and bundles reference files for on-demand loading. Still no scripts, but the progressive disclosure pattern is visible -- the references directory keeps the SKILL.md body concise while providing deep detail when needed.
Directory structure:
api-docs-generator/
├── SKILL.md
└── references/
├── openapi-patterns.md
└── markdown-api-style.mdSKILL.md:
--- name: api-docs-generator description: Generate API documentation from source code. Use when the user asks to document an API, create endpoint docs, generate OpenAPI specs, or write API reference pages. triggers: - document this api - generate api docs - write endpoint documentation - openapi spec capabilities: [storage] priority: 5 version: 1.0.0 --- # API Documentation Generator You generate clear, accurate API documentation from source code. ## Process 1. Read the source files the user points to 2. Identify endpoints, methods, request/response types, and auth requirements 3. Generate documentation in the requested format (Markdown or OpenAPI) 4. Save output to the specified location ## Output Formats ### Markdown For each endpoint, document: - HTTP method and path - Description (one sentence) - Auth requirements - Request parameters (path, query, body) with types - Response schema with example - Error codes ### OpenAPI 3.1 Generate a valid OpenAPI spec with: - Info block (title, version, description) - Paths with operations - Components/schemas for shared types - Security schemes ## Style Guide - For Markdown formatting conventions, read `references/markdown-api-style.md` - For OpenAPI structural patterns, read `references/openapi-patterns.md` ## Rules - Always include example request/response pairs - Document error responses, not just success - Use the actual types from the source code -- never invent fields - Group endpoints by resource, not by HTTP method
triggers field adds phrase-matching that boosts this skill in discovery ranking beyond the description — it does not activate the skill; the agent's routing decides which skills to use. The capabilities: [storage] declaration tells the platform this skill needs file system access. The priority: 5 ranks this skill ahead of generic documentation skills. On non-Nebo platforms, these fields are silently ignored.Advanced: Database Migration Manager
A fully-featured skill with scripts, references, examples, plugin dependencies, template variables, and all Nebo extensions. This represents the upper end of skill complexity.
Directory structure:
db-migration-manager/
├── SKILL.md
├── scripts/
│ ├── validate_migration.py
│ └── generate_rollback.py
├── references/
│ ├── postgres-patterns.md
│ ├── mysql-patterns.md
│ └── safety-checklist.md
└── examples/
├── add-column.sql
├── create-index.sql
└── rename-table.sqlSKILL.md:
---
name: db-migration-manager
description: Create, validate, and manage database migrations for
PostgreSQL and MySQL. Use when the user needs to write migration
files, alter tables, add indexes, or manage schema changes safely.
triggers:
- write a migration
- database migration
- alter table
- add column
- schema change
capabilities: [python, storage]
priority: 10
max_turns: 5
version: 2.1.0
platform: [macos, linux]
plugins:
- name: dbtools
version: ">=1.0.0"
optional: true
metadata:
category: databases
difficulty: intermediate
---
# Database Migration Manager
You create safe, reversible database migrations. Every migration MUST
have a corresponding rollback. Never write a migration that cannot be
undone.
## Process
1. Understand the schema change the user wants
2. Check the current schema state
3. Write the UP migration
4. Write the DOWN (rollback) migration
5. Validate: `python scripts/validate_migration.py <file>`
6. Generate rollback verification: `python scripts/generate_rollback.py <file>`
7. Save both files to ${NEBO_DATA_DIR}/migrations/
## Safety Rules
- Never use `DROP TABLE` without explicit user confirmation
- Always use `IF EXISTS` / `IF NOT EXISTS` guards
- Large table ALTERs must use online DDL (pt-online-schema-change or
pg_repack) -- read `references/safety-checklist.md`
- Add indexes CONCURRENTLY on PostgreSQL
- Test rollback before marking migration as ready
## Database-Specific Patterns
- PostgreSQL: read `references/postgres-patterns.md`
- MySQL: read `references/mysql-patterns.md`
## File Naming
```
YYYYMMDDHHMMSS_description.sql
```
Example: `20260115143022_add_user_preferences_table.sql`
## Example Migrations
See the `examples/` directory for common patterns:
- `examples/add-column.sql` -- adding a nullable column with default
- `examples/create-index.sql` -- concurrent index creation
- `examples/rename-table.sql` -- safe table rename with view alias
## Plugin Integration
If the dbtools plugin is installed, use it for schema inspection:
```bash
${plugin.DBTOOLS_BIN} schema inspect --format json
```
If dbtools is not available, fall back to raw SQL:
```sql
SELECT column_name, data_type FROM information_schema.columns
WHERE table_name = '<table>';
```scripts/validate_migration.py:
#!/usr/bin/env python3
"""Validate a SQL migration file for common safety issues."""
import sys
import re
DANGEROUS_PATTERNS = [
(r'\bDROP\s+TABLE\b(?!.*\bIF\s+EXISTS\b)', 'DROP TABLE without IF EXISTS'),
(r'\bTRUNCATE\b', 'TRUNCATE is not reversible'),
(r'\bDROP\s+COLUMN\b(?!.*\bIF\s+EXISTS\b)', 'DROP COLUMN without IF EXISTS'),
(r'\bALTER\s+TABLE\b.*\bRENAME\b(?!.*\bIF\s+EXISTS\b)', 'RENAME without guard'),
(r'\bCREATE\s+INDEX\b(?!.*\bCONCURRENTLY\b)(?!.*\bIF\s+NOT\s+EXISTS\b)',
'CREATE INDEX without CONCURRENTLY (PostgreSQL) or IF NOT EXISTS'),
]
def validate(filepath):
with open(filepath) as f:
sql = f.read()
issues = []
for pattern, message in DANGEROUS_PATTERNS:
if re.search(pattern, sql, re.IGNORECASE):
issues.append(message)
if issues:
print(f"WARNINGS in {filepath}:")
for issue in issues:
print(f" - {issue}")
sys.exit(1)
else:
print(f"OK: {filepath} passed validation")
if __name__ == '__main__':
if len(sys.argv) != 2:
print("Usage: validate_migration.py <file.sql>")
sys.exit(1)
validate(sys.argv[1])scripts/generate_rollback.py:
#!/usr/bin/env python3
"""Generate a rollback verification script from a migration."""
import sys
import re
def generate_rollback_check(filepath):
with open(filepath) as f:
sql = f.read()
checks = []
# Find CREATE TABLE statements
for match in re.finditer(r'CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?(\w+)',
sql, re.IGNORECASE):
table = match.group(1)
checks.append(f"SELECT EXISTS (SELECT FROM pg_tables "
f"WHERE tablename = '{table}');")
# Find ADD COLUMN statements
for match in re.finditer(r'ADD\s+COLUMN\s+(?:IF\s+NOT\s+EXISTS\s+)?(\w+)',
sql, re.IGNORECASE):
col = match.group(1)
checks.append(f"-- Verify column '{col}' exists after migration")
if checks:
print("-- Rollback verification queries:")
for check in checks:
print(check)
else:
print("-- No automated checks generated. Review manually.")
if __name__ == '__main__':
if len(sys.argv) != 2:
print("Usage: generate_rollback.py <file.sql>")
sys.exit(1)
generate_rollback_check(sys.argv[1])plugins: [dbtools] as optional, so it works without the plugin but gains schema inspection when it is installed. The max_turns: 5 limit prevents runaway migration generation. The platform: [macos, linux] filter excludes Windows where the Python scripts may not be available. Reference files keep database-specific patterns out of the main body, keeping SKILL.md well under the 500-line guideline.Complete Example: Briefing Writer
A focused skill designed for use within a single workflow activity -- narrow, single-purpose, and domain-specific. This is the ideal shape for most skills: one SKILL.md with clear frontmatter, a well-defined process, and opinionated guidelines.
Directory structure:
briefing-writer/ └── SKILL.md
SKILL.md:
--- name: briefing-writer description: Synthesize information from calendar, email, and other sources into a concise morning briefing. Use when a workflow activity needs to produce a daily summary. triggers: - write a briefing - morning summary - daily brief capabilities: [storage] priority: 10 max_turns: 3 --- # Briefing Writer You synthesize information from multiple sources into a concise morning briefing. Lead with the single most important thing. ## Process 1. Gather today's calendar events, pending messages, and overdue items 2. Flag any conflicts (overlapping times) and anything starting within 60 minutes 3. Synthesize into the format below ## What "important" means - Time-sensitive beats interesting - If two things compete, pick the one with a deadline - Never surface something just because it's new ## Format 1. One sentence: the most important thing today 2. Calendar: what's on the schedule, conflicts, prep needed 3. Weather: only if it affects plans 4. Everything else: only if it matters
max_turns: 3 prevents open-ended iteration). The description clearly states both what it does and when it should trigger. The format section gives the agent a concrete template to follow rather than vague guidance.Complete Example: Excel Processor with Scripts
A more complex skill that bundles executable scripts and reference documentation. The scripts handle tasks the agent cannot do natively (formula recalculation), while the references provide deep technical detail without bloating the SKILL.md body.
Directory structure:
xlsx-processor/
├── SKILL.md
├── scripts/
│ └── recalc.py
└── references/
└── formula-guide.mdSKILL.md:
--- name: xlsx-processor description: Create, edit, and analyze Excel spreadsheet files. Use when the user wants to open, modify, or create .xlsx files, add formulas, format cells, or work with tabular data. capabilities: [python, storage] --- # Excel Processing Create and edit Excel files using openpyxl for formulas/formatting or pandas for data analysis. ## Workflow 1. Choose tool: pandas for data, openpyxl for formulas/formatting 2. Create or load the workbook 3. Modify: add data, formulas, formatting 4. Save to file 5. Recalculate formulas: `python scripts/recalc.py output.xlsx` 6. Verify and fix any errors from the recalc output ## References - For formula construction rules, see `references/formula-guide.md`
scripts/recalc.py:
#!/usr/bin/env python3
"""Recalculate all formulas in an Excel workbook.
openpyxl does not evaluate formulas -- this script opens the workbook
with formulas flagged for recalculation so Excel or LibreOffice will
recompute them on next open. It also validates formula syntax.
"""
import sys
from openpyxl import load_workbook
from openpyxl.utils import get_column_letter
def recalc(filepath):
wb = load_workbook(filepath)
errors = []
for ws in wb.worksheets:
for row in ws.iter_rows():
for cell in row:
if isinstance(cell.value, str) and cell.value.startswith('='):
# Flag cell for recalculation
try:
# Basic syntax validation
formula = cell.value[1:]
if formula.count('(') != formula.count(')'):
col = get_column_letter(cell.column)
errors.append(
f"{ws.title}!{col}{cell.row}: "
f"unbalanced parentheses in {cell.value}"
)
except Exception as e:
errors.append(f"{ws.title}: {e}")
# Force recalculation flag
wb.calculation.calcMode = 'auto'
wb.save(filepath)
if errors:
print("Formula issues found:")
for err in errors:
print(f" - {err}")
sys.exit(1)
else:
print(f"OK: {filepath} formulas validated and flagged for recalc")
if __name__ == '__main__':
if len(sys.argv) != 2:
print("Usage: recalc.py <file.xlsx>")
sys.exit(1)
recalc(sys.argv[1])references/formula-guide.md (excerpt):
# Excel Formula Construction Guide ## Cell References - Relative: `A1`, `B2` (shifts when copied) - Absolute: `$A$1`, `$B$2` (fixed when copied) - Mixed: `$A1`, `A$1` (one axis fixed) ## Common Functions | Function | Usage | Example | |----------|-------|---------| | SUM | Sum a range | `=SUM(A1:A10)` | | VLOOKUP | Vertical lookup | `=VLOOKUP(A1, B:C, 2, FALSE)` | | IF | Conditional | `=IF(A1>100, "High", "Low")` | | COUNTIF | Conditional count | `=COUNTIF(A:A, ">0")` | | INDEX/MATCH | Flexible lookup | `=INDEX(B:B, MATCH(A1, C:C, 0))` | ## Rules - Always use FALSE for exact match in VLOOKUP - Prefer INDEX/MATCH over VLOOKUP for flexibility - Use named ranges for readability in complex formulas - Wrap division in IFERROR to handle divide-by-zero
references/ and is only loaded when the agent needs formula construction rules. The recalc script runs as a subprocess -- it is never loaded into the agent's context window.Complete Example: Google Calendar Skill
A skill that depends on the gws plugin for Google Workspace integration. This shows how skills compose with plugins -- the skill provides the knowledge and workflow, while the plugin provides the executable tooling.
Directory structure:
gws-calendar/
├── SKILL.md
└── references/
└── recurring-events.mdSKILL.md:
---
name: gws-calendar
description: Manage Google Calendar events -- create, update, delete,
and query calendar events. Use when the user asks about their
schedule, wants to book a meeting, check availability, or manage
calendar events.
triggers:
- check my calendar
- schedule a meeting
- what's on my schedule
- book a time
- find a free slot
capabilities: [storage]
priority: 15
plugins:
- name: gws
version: ">=1.2.0"
optional: false
---
# Google Calendar
Manage calendar events using the Google Workspace CLI.
## Commands
List today's events:
```bash
${plugin.GWS_BIN} calendar list --date today
```
List events for a specific date:
```bash
${plugin.GWS_BIN} calendar list --date 2026-03-15
```
Create an event:
```bash
${plugin.GWS_BIN} calendar create \
--title "Team standup" \
--start "2026-03-15T09:00:00" \
--end "2026-03-15T09:30:00" \
--attendees "alice@co.com,bob@co.com"
```
Delete an event:
```bash
${plugin.GWS_BIN} calendar delete --id <event-id>
```
Check availability:
```bash
${plugin.GWS_BIN} calendar freebusy \
--emails "alice@co.com,bob@co.com" \
--date 2026-03-15
```
## Rules
- Always confirm before creating or deleting events
- Show the user what will be created before executing
- For recurring events, read `references/recurring-events.md`
- Default meeting duration is 30 minutes unless specified
- Use the user's timezone (from system settings)
## Output
After creating an event, show:
1. Event title, date, and time
2. Attendees
3. Calendar linkplugins field declares a required dependency on gws >=1.2.0. If the plugin is not installed or doesn't meet the version range, this skill is dropped during dependency verification. The ${plugin.GWS_BIN} template variable is resolved at runtime to the actual binary path.Complete Example: Code Review Checklist
A skill that uses the persistent data directory to store review history across sessions. This demonstrates template variables, the data directory pattern, and how skills can maintain state.
Directory structure:
code-review/
├── SKILL.md
├── scripts/
│ └── save_review.py
└── examples/
└── sample-review.jsonSKILL.md:
---
name: code-review
description: Perform structured code reviews with a consistent
checklist. Use when the user asks to review code, check a pull
request, or audit code quality.
triggers:
- review this code
- code review
- check this pr
- audit this file
capabilities: [python, storage]
priority: 8
max_turns: 10
version: 1.2.0
---
# Code Review
Perform structured code reviews using a consistent checklist.
Reviews are saved to ${NEBO_DATA_DIR}/reviews/ for history.
## Checklist
For every review, check each category:
### Correctness
- [ ] Logic handles edge cases (null, empty, boundary values)
- [ ] Error handling is present and appropriate
- [ ] Resource cleanup (files, connections, locks) is guaranteed
### Security
- [ ] No hardcoded secrets or credentials
- [ ] Input is validated and sanitized
- [ ] SQL queries use parameterized statements
- [ ] Auth checks are present on protected endpoints
### Performance
- [ ] No N+1 query patterns
- [ ] Large collections are paginated
- [ ] Expensive operations are cached or batched
### Maintainability
- [ ] Functions are under 50 lines
- [ ] Naming is clear and consistent
- [ ] No dead code or commented-out blocks
- [ ] Tests cover the critical path
## Output Format
```
## Review: [filename or PR title]
**Verdict:** APPROVE | REQUEST CHANGES | COMMENT
### Findings
1. [Category] [Severity: high/medium/low] Description
- File: path/to/file.go:42
- Suggestion: ...
### Summary
[1-2 sentences on overall code quality]
```
## Saving Reviews
After completing a review, save it:
```bash
python scripts/save_review.py \
--output ${NEBO_DATA_DIR}/reviews/ \
--title "Review of auth module"
```
Previous reviews: `ls ${NEBO_DATA_DIR}/reviews/`scripts/save_review.py:
#!/usr/bin/env python3
"""Save a code review to the persistent data directory."""
import sys
import json
import os
from datetime import datetime
def save_review(output_dir, title, content=""):
os.makedirs(output_dir, exist_ok=True)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
slug = title.lower().replace(" ", "-")[:50]
filename = f"{timestamp}_{slug}.json"
filepath = os.path.join(output_dir, filename)
review = {
"title": title,
"timestamp": datetime.now().isoformat(),
"content": content or sys.stdin.read()
}
with open(filepath, 'w') as f:
json.dump(review, f, indent=2)
print(f"Review saved: {filepath}")
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--output', required=True)
parser.add_argument('--title', required=True)
args = parser.parse_args()
save_review(args.output, args.title)${NEBO_DATA_DIR} variable resolves to <data_dir>/appdata/skills/code-review/ (the Nebo data directory is platform-native — ~/Library/Application Support/Nebo/ on macOS, %APPDATA%\Nebo\ on Windows, ~/.local/share/nebo/ on Linux), which is physically separate from the skill's code directory. Review history survives skill upgrades, reinstalls, and Nebo updates. The skill's code lives in ${NEBO_SKILL_DIR} and is replaceable; the data in ${NEBO_DATA_DIR} is permanent.When to Use What: Skill vs Plugin vs Agent
Nebo has three artifact types for extending agent capabilities. Choosing the right one depends on what you are building.
| Criteria | Skill | Plugin | Agent |
|---|---|---|---|
| What it is | Knowledge + instructions (markdown) | Native binary tool (executable) | Persona that bundles skills/plugins |
| Primary file | SKILL.md | PLUGIN.md + binary | AGENT.md |
| Runs code | Optional scripts (Python/TS) | Yes -- native binary, spawned per call | No -- delegates to skills and plugins |
| Review required | No | Yes (binary security review) | No |
| Developer account | Not required | Required | Not required |
| Cross-platform portable | Yes (Agent Skills standard) | Nebo only | Nebo only |
| Install code prefix | SKIL-XXXX | PLUG-XXXX | AGNT-XXXX |
| Best for | Teaching the agent how to do something | Connecting to external services/APIs | Creating specialized AI personas |
Decision guide
- Use a Skill when you want to teach the agent a process, give it domain knowledge, or standardize how it handles a type of request. Examples: writing conventions, code review checklists, documentation templates.
- Use a Plugin when you need to connect to an external service that requires a native binary -- API integrations, database connections, file format processing. The plugin provides the tool; skills bundled with the plugin teach the agent how to use it.
- Use an Agent when you want to create a distinct persona with its own identity, memory, and curated set of skills/plugins. Agents are the composition layer -- they combine skills and plugins into a coherent role.
Key Design Points
Summary of principles that make skills effective.
1. Narrow and focused
Each skill should do one thing well. A skill that tries to handle "all writing tasks" will be mediocre at everything. A skill that handles "conventional commit messages" can be excellent at that one thing. Split broad capabilities into multiple skills.
2. Knowledge + actions
The SKILL.md body teaches the agent what to know. Bundled scripts give it tools to act. The body should never contain implementation code -- it should describe processes, rules, and guidelines. Executable code belongs in scripts/.
3. Portable by default
The two required fields (name and description) are universal across the Agent Skills ecosystem. Nebo-specific extensions are silently ignored by other platforms. Write skills that work everywhere, then layer on Nebo extensions for enhanced behavior.
4. Progressive disclosure
The three-level loading system keeps context lean:
- Level 1 -- Metadata: Always loaded (~100 words). This is the name and description that determine whether the skill triggers.
- Level 2 -- SKILL.md body: Loaded on trigger (<500 lines ideal). The complete instructions the agent uses to execute.
- Level 3 -- Bundled resources: Loaded on demand. Scripts run as subprocesses. References are read only when the body points to them.
5. Platform capabilities
Declare what infrastructure the skill needs (storage, python, vision, network). The platform checks these against user-granted permissions before activating the skill. See Platform Capabilities for the full list.
6. Description drives discovery
The description field is the most important part of a skill. It is the primary signal the agent's routing uses to decide when the skill is relevant. Write it to include both what the skill does and when to use it. A description that says "Manage files" is too vague; a description that says "Create, edit, and analyze Excel spreadsheet files. Use when the user wants to open, modify, or create .xlsx files" is precise.
7. Be opinionated
Good skills make decisions so the agent does not have to. Define what "important" means. Specify the output format. Set rules about what to never do. The more concrete and opinionated the skill, the more consistent the agent's behavior will be.
Quick Reference: Skill Anatomy
my-skill/
├── SKILL.md # Required: frontmatter (name, description) + instructions
├── scripts/ # Optional: executables the agent can run
│ ├── process.py # - Python scripts (requires capabilities: [python])
│ └── transform.ts # - TypeScript scripts (requires capabilities: [typescript])
├── references/ # Optional: detailed docs loaded on demand
│ ├── deep-dive.md # - Referenced from SKILL.md body
│ └── api-reference.md # - Never loaded unless explicitly read
├── assets/ # Optional: static resources
│ ├── template.html # - Templates, images, fonts
│ └── config.json # - Default configurations
├── examples/ # Optional: sample data
│ ├── input.json # - Example inputs for the agent
│ └── output.json # - Expected outputs for verification
├── agents/ # Optional: subagent prompts
│ └── specialist.md # - Delegated to for specific subtasks
└── core/ # Optional: library code
└── utils/ # - Shared Python/TS modules| Component | When loaded | Into context? | Purpose |
|---|---|---|---|
| Frontmatter | Always | Yes (~100 words) | Trigger matching |
| SKILL.md body | On trigger | Yes (<500 lines) | Instructions and knowledge |
| References | On demand | Yes (when read) | Deep-dive documentation |
| Scripts | On execution | No (subprocess) | Executable actions |
| Assets | On access | No (file read) | Templates, static files |
| Examples | On access | Yes (when read) | Sample inputs/outputs |