Manifest
Every skill requires a deployment manifest — a YAML file that declares its identity, permissions, and configuration.
Minimal example
id: my-skill
path: skills/my-company.my-skill.skill
permissions:
fs: { enabled: false }
invoke_policy:
can_invoke: []
can_be_invoked_by: ["*"]
mcp:
mapping: per_method
Top-level fields
| Field | Required | Description |
|---|---|---|
id | yes | Unique skill instance ID ([a-zA-Z][a-zA-Z0-9-]*, no dots) |
path | yes | Path to the signed .skill package |
description | no | Override the annotation description |
permissions | yes | Permission block (deny-by-default) |
invoke_policy | no | Inter-skill invocation policy |
mcp | no | MCP exposure settings |
env | no | Environment variables available via env_get |
The id is used as the MCP tool prefix — e.g., skill fs-skill with method read becomes tool fs-skill/read.
The path is relative to the working directory where luminarys is started.
Permissions
All permissions are deny-by-default. Only include sections for capabilities the skill actually needs.
File system (fs)
permissions:
fs:
enabled: true
dirs:
- "/data:rw"
- "/config:ro"
- "/data/projects/*/src:rw"
| Mode | Description |
|---|---|
ro | Read-only access |
rw | Read and write access |
Glob patterns: * matches a single directory level, ** matches everything recursively.
HTTP (http)
permissions:
http:
enabled: true
allowlist:
- "https://api.example.com/**"
- "https://*.internal.company.com/**"
Wildcard patterns: * matches a single segment, ** matches everything.
TCP (tcp)
permissions:
tcp:
enabled: true
allowlist:
- "redis.internal:6379"
- "10.0.0.*:*"
Same wildcard syntax as HTTP. An empty allowlist with enabled: true allows internal IPs only.
Shell (shell)
permissions:
shell:
enabled: true
allowlist:
- "git **"
- "go build **"
- "ps **"
allowed_dirs:
- "/data/project"
Pattern syntax: ** matches all remaining arguments. Shell operators (&&, ||, ;, |, >) are always blocked.
File transfer (file_transfer)
permissions:
file_transfer:
enabled: true
allowed_nodes: ["master"]
local_dirs: ["/data/shared:ro"]
| Field | Description |
|---|---|
allowed_nodes | Node IDs allowed for transfer (["*"] = all) |
local_dirs | Local directories accessible for transfer (with :ro/:rw mode) |
Invoke policy
Controls inter-skill invocation.
invoke_policy:
can_invoke: ["fs-skill", "web-skill"]
can_be_invoked_by: ["*"]
Both the caller's can_invoke and the target's can_be_invoked_by must allow the call. Use ["*"] to allow all, or list specific skill IDs.
MCP configuration
mcp:
mapping: per_method
| Field | Default | Description |
|---|---|---|
mapping | per_method | per_method — each method is a separate tool. per_skill — one tool per skill. |
disabled | false | Hide the skill from MCP entirely (still callable by other skills) |
hidden_methods | [] | Hide specific methods from MCP tool listings |
Environment variables
env:
API_KEY: "${API_KEY}"
DB_HOST: "postgres.internal"
Values are read via env_get("API_KEY") in skill code. These are isolated to the skill — not system environment variables. Use ${VAR} syntax to load values from the host environment or .env files.
Complete example
id: go-toolchain
path: skills/ai.luminarys.as.go-toolchain.skill
permissions:
fs:
enabled: true
dirs: ["/data/shared:rw"]
shell:
enabled: true
allowlist: ["go **", "gofmt **", "ps **", "kill **", "./**"]
allowed_dirs: ["/data/shared"]
invoke_policy:
can_invoke: []
can_be_invoked_by: ["*"]
mcp:
mapping: per_method
env:
GOPATH: "/tmp/go"