Add Custom Skills
Create your own skills to teach Zeph new capabilities. A skill is a single SKILL.md file inside a named directory.
Skill Structure
.zeph/skills/
└── my-skill/
└── SKILL.md
SKILL.md Format
Two parts: a YAML header and a markdown body.
---
name: my-skill
description: Short description of what this skill does.
---
# My Skill
Instructions and examples go here. This content is injected verbatim
into the LLM context when the skill is matched.
Header Fields
| Field | Required | Description |
|---|---|---|
name | Yes | Unique identifier (1-64 chars, lowercase, hyphens allowed) |
description | Yes | Used for embedding-based matching against user queries |
compatibility | No | Runtime requirements (e.g., “requires curl”) |
allowed-tools | No | Space-separated tool names this skill can use |
x-requires-secrets | No | Comma-separated secret names the skill needs (see below) |
Secret-Gated Skills
If a skill requires API credentials or tokens, declare them with x-requires-secrets:
---
name: github-api
description: GitHub API integration — search repos, create issues, review PRs.
x-requires-secrets: github-token, github-org
---
Secret names use lowercase with hyphens. They map to vault keys with the ZEPH_SECRET_ prefix:
x-requires-secrets name | Vault key | Env var injected |
|---|---|---|
github-token | ZEPH_SECRET_GITHUB_TOKEN | GITHUB_TOKEN |
github-org | ZEPH_SECRET_GITHUB_ORG | GITHUB_ORG |
Activation gate: if any declared secret is missing from the vault, the skill is excluded from the prompt. It will not be matched or suggested until the secret is provided.
Scoped injection: when the skill is active, its secrets are injected as environment variables into shell commands the skill executes. Only the secrets declared by the active skill are exposed — not all vault secrets.
Store secrets with the vault CLI:
zeph vault set ZEPH_SECRET_GITHUB_TOKEN ghp_yourtokenhere
zeph vault set ZEPH_SECRET_GITHUB_ORG my-org
See Vault — Custom Secrets for full details.
Channel Allowlist
Restrict a skill to specific I/O channels with x-channels. When set, the skill is excluded from matching on channels not in the list:
---
name: deploy-prod
description: Production deployment via kubectl.
x-channels: cli
---
This skill only activates in CLI mode — it is invisible in Telegram or TUI. Omit x-channels to allow all channels. Multiple channels are comma-separated: x-channels: cli, tui.
Name Rules
Lowercase letters, numbers, and hyphens only. No leading, trailing, or consecutive hyphens. Must match the directory name.
Skill Resources
Add reference files alongside SKILL.md:
.zeph/skills/
└── system-info/
├── SKILL.md
└── references/
├── linux.md
├── macos.md
└── windows.md
Resources in scripts/, references/, and assets/ are loaded lazily on first skill activation (not at startup). OS-specific files (linux.md, macos.md, windows.md) are filtered by platform automatically.
Local file references in the skill body (e.g., [see config](references/config.md)) are validated at load time. Broken links and path traversal attempts (../../../etc/passwd) are rejected.
Configuration
[skills]
paths = [".zeph/skills", "/home/user/my-skills"]
max_active_skills = 5
Skills from multiple paths are scanned. If a skill with the same name appears in multiple paths, the first one found takes priority.
Testing Your Skill
- Place the skill directory under
.zeph/skills/ - Start Zeph — the skill is loaded automatically
- Send a message that should match your skill’s description
- Run
/skillsto verify it was selected
Changes to SKILL.md are hot-reloaded without restart (500ms debounce).
Installing External Skills
Use zeph skill install to add skills from git repositories or local paths:
# From a git URL — clones the repo into ~/.config/zeph/skills/
zeph skill install https://github.com/user/zeph-skill-example.git
# From a local path — copies the skill directory
zeph skill install /path/to/my-skill
Installed skills are placed in ~/.config/zeph/skills/ and automatically discovered at startup. They start at the quarantined trust level (restricted tool access). To grant full access:
zeph skill verify my-skill # check BLAKE3 integrity
zeph skill trust my-skill trusted # promote trust level
In an active session, use /skill install <url|path> and /skill remove <name> — changes are hot-reloaded without restart.
See Skill Trust Levels for the full security model.
Plugin Packages
For distributing and managing multiple related skills, utilities, and configurations together, Zeph supports plugin packages. A plugin is a directory containing a plugin.toml manifest that bundles:
- Multiple skill directories
- MCP server entries
- Configuration overlays (tighten-only: you can only restrict, not expand permissions)
Plugin Structure
my-plugin/
├── plugin.toml # Manifest file
├── skills/
│ ├── skill-one/
│ │ └── SKILL.md
│ └── skill-two/
│ └── SKILL.md
└── config/
└── overlay.toml # Optional config tightening rules
plugin.toml Format
[plugin]
name = "my-plugin"
version = "1.0.0"
description = "My plugin description"
# Skills bundled with this plugin (relative paths from plugin root)
[[plugin.skills]]
name = "skill-one"
path = "skills/skill-one"
[[plugin.skills]]
name = "skill-two"
path = "skills/skill-two"
# MCP servers managed by this plugin (optional)
[[plugin.mcp_servers]]
id = "my-mcp-server"
command = "python"
args = ["-m", "my_mcp_module"]
# Configuration overlay — restrictive only (default: empty)
[plugin.config_overlay]
# Union of blocked patterns:
tools.blocked_commands = ["dangerous_pattern"]
# Intersection of allowed patterns (if base is empty, stays empty):
# tools.allowed_commands = ["safe_pattern"]
# Maximum for numeric fields:
# skills.disambiguation_threshold = 0.1
Installing Plugins
Use zeph plugin add to install a plugin from a local path:
# From local directory
zeph plugin add /path/to/my-plugin
# List installed plugins
zeph plugin list
# Show the active plugin overlay (which plugins are active/skipped and why)
zeph plugin list --overlay
# Remove a plugin
zeph plugin remove my-plugin
Plugins are installed to ~/.local/share/zeph/plugins/<name>/ (XDG standard location). All bundled skills are automatically discovered and hot-reloaded without restart.
In TUI mode, use the /plugins commands:
/plugins list # Show installed plugins
/plugins list --overlay # Show the active plugin overlay
/plugins overlay # Show the active plugin overlay (alias)
/plugins add <path> # Install a plugin
/plugins remove <name> # Remove a plugin
Plugin Integrity Check
When you install a plugin, Zeph records a sha256 digest of its .plugin.toml manifest in ~/.local/share/zeph/.plugin-integrity.toml. At startup and when hot-reloading, Zeph verifies this digest to detect if a plugin manifest has been modified outside of Zeph’s control.
If a manifest is tampered with:
- The plugin is skipped with an “integrity mismatch” reason
- You can see the skipped plugin and reason with
zeph plugin list --overlayor/plugins overlay - To re-protect the plugin, reinstall it:
zeph plugin remove my-plugin && zeph plugin add /path/to/my-plugin
This provides basic tampering detection. The integrity check is not cryptographically signed, and concurrent installs may race (last writer wins).
Hot-Reload Behavior
Plugin config overlays — restrictions on tool access and embedding thresholds — are applied immediately when a plugin is installed or when you reload config mid-session. However, different overlay fields hot-reload differently:
Hot-reloads live (no restart needed):
tools.blocked_commands— shell commands blocked by the agent are updated atomically on the next execution
Require agent restart:
tools.allowed_commands— restrictions on allowed paths are applied at executor setup time. Zeph emits a RESTART REQUIRED warning when you change this setting
You do not need to restart Zeph when modifying blocked_commands — the agent picks up the new blocklist immediately. If you modify allowed_commands, you must restart Zeph for the change to take effect.
Plugin Security
- Path traversal defense: skill paths in the manifest are canonicalized and must resolve within the plugin root directory
- Config overlay validation: only
tools.blocked_commands,tools.allowed_commands, andskills.disambiguation_thresholdare permitted; other keys are rejected - Trust escalation filter: bundled skills are assigned the
Trustedtrust level automatically at startup, bypassing the defaultquarantinedlevel that external skills receive
See Skill Trust Levels for how trust levels control tool access.
Agent-Invocable Skills
Skills are typically matched to user queries automatically via semantic embedding. With the invoke_skill tool, the agent can explicitly fetch and execute any registered skill by name at runtime. This is useful for:
- Skills that should only run when explicitly requested
- Composing multiple skills in a single response
- Overriding the default embedding-based matching
Using invoke_skill in the LLM Response
When the agent needs to reference or use a skill, it calls the invoke_skill tool:
I'll use the "git-workflow" skill to help you:
<invoke_skill>
{
"skill_name": "git-workflow",
"args": "--verbose"
}
</invoke_skill>
The tool returns the skill body with security-aware sanitization:
- Blocked skills: refused with an error message
- Trusted skills: body returned as-is
- Quarantined skills: body wrapped with a quarantine warning
CLI Usage
Invoke skills from the command line:
zeph skill invoke git-workflow --verbose
zeph skill invoke deploy-prod --environment staging
Catalog
The agent sees an invoke_skill catalog during context assembly that lists all available skills with their names and descriptions. Use /skills in TUI or CLI to see the full registry.
Generate a Skill from a Description
Instead of writing SKILL.md manually, use /skill create with a natural language description:
/skill create "A skill that manages systemd services — start, stop, restart, status"
Zeph generates a complete SKILL.md with frontmatter, instructions, and examples. The skill is saved to your skills directory and hot-reloaded immediately. Duplicate detection prevents creating skills that overlap with existing ones.
Generated skills are scored on correctness, reusability, and specificity before being written to disk. A separate critic LLM evaluates the skill and filters out low-quality generations.
Skill Evaluation Configuration
Control how generated skills are evaluated:
[skills.evaluation]
enabled = true # enable external critic (default: true)
correctness_weight = 0.50 # importance of correctness (0.0-1.0)
reusability_weight = 0.25 # importance of broad applicability
specificity_weight = 0.25 # importance of precise instruction
pass_threshold = 0.60 # minimum score to accept (0.0-1.0)
When a generated skill scores below pass_threshold, it is rejected and the generation process is retried. If enabled = false, all generated skills are accepted without evaluation (fail-open).
Evaluation is disabled by default for generated skills from --init to keep initial setup fast; enable it in your config if you want quality gates on all subsequent /skill create commands.
See NL Skill Generation for details on generation from descriptions and GitHub repository mining.
Next Steps
- Skills — how embedding-based matching works
- Self-Learning Skills — automatic skill evolution
- NL Skill Generation — generate skills from descriptions or repos
- Skill Trust Levels — security model for imported skills