Examples

Real, runnable skills — from the canonical first run to event-driven autonomy. Every one of these is in the bundle and compiles clean. All of these skillscripts were written by an agent. Read top to bottom and the language builds up under you.

Start here — the shape of the language

hello-world

The canonical first run. The body text is the skill — no substrate, no compute. If this executes, your install is healthy.

# Skill: hello-world
# Status: Approved
# Description: The canonical first run — pure declarative output, no substrate.
# Vars: WHO=world

Hello, ${WHO}!
Your install is healthy. Try data-store-roundtrip next to verify substrate wiring.

data-store-roundtrip

Write a record, read it back. The smallest possible proof that your memory substrate is wired correctly.

Uses: data store

# Skill: data-store-roundtrip
# Status: Approved
# Description: Round-trip the memory store — write a record, read it back by full-text search.

wrote record '${W.id}'; read back ${R.items|length} item(s)

run:
    $set MARKER = "probe-${NOW}"
    $ data_write content="${MARKER} probe record" tags=["probe"] -> W
    $ data_read mode="fts" query="${MARKER}" limit=5 -> R

default: run

skill-store-roundtrip

Skills that write skills. A generated skill lands as Draft — a human approves it before it can ever run.

Uses: skill store

# Skill: skill-store-roundtrip
# Status: Approved
# Description: Skills that write skills (the Lisp-shape). In-skill writes land as Draft;
#   a human promotes before the child can run.

wrote skill '${W.name}' as Status: ${W.status}; read back ${R.source|length} bytes

run:
    $ skill_write name="hello-child" source="# Skill: hello-child\n# Status: Approved\nrun:\n    emit(text=\"hello from a generated skill\")\ndefault: run\n" overwrite=true -> W
    $ skill_read name="hello-child" -> R

default: run

email-a-document

Send a document by email using a sealed credential. The API key is declared once (# Requires: secret.AGENTMAIL_KEY) and placed only at the curl sink as {{secret.AGENTMAIL_KEY}} — the skill can use the key but can never read, bind, or print it, and it never appears in the execution trace. file_read(encoding="base64") turns the file into an inline attachment; the operator's filesystem allowlist gates which paths it can reach. Capability without access — act through a credential without ever holding it.

Uses: shell (curl), sealed secret

# Skill: email-a-document
# Requires: secret.AGENTMAIL_KEY
# Vars: TO, SUBJECT, BODY, FILENAME, CONTENT_TYPE, DOC_PATH
# Returns: RESULT

send:
    file_read(path="${DOC_PATH}", encoding="base64") -> B64
    shell(argv=["curl","-s","-X","POST","https://api.agentmail.to/v0/inboxes/you%40agentmail.to/messages/send","-H","Authorization: Bearer {{secret.AGENTMAIL_KEY}}","-H","Content-Type: application/json","-d","{\"to\":[${TO|json}],\"subject\":${SUBJECT|json},\"text\":${BODY|json},\"attachments\":[{\"filename\":${FILENAME|json},\"content_type\":${CONTENT_TYPE|json},\"content\":${B64|json}}]}"]) -> RESULT (fallback: "{\"error\":\"send failed\"}")
    emit(text="Sent to ${TO} with ${FILENAME}")

default: send

speak_attention

A containerized agent reaching the outside world — safely. The runtime is sandboxed, so the only way out is an operator-allowlisted shell binary; here that's macOS `say`. The agent can speak aloud on the host, and nothing beyond the allowlist is reachable. (Perry's own attention-grabber.)

Uses: shell (macOS say)

# Skill: speak_attention
# Status: Approved
# Autonomous: true
# Description: Speak text aloud on the host in Perry's voice via the macOS `say` command.
# Vars: TEXT=

speak:
    if not ${TEXT}:
        emit(text="speak_attention: no text given")
    else:
        shell(argv=["say", "-v", "Jamie", "${TEXT}"]) -> R
        emit(text="spoke: ${TEXT}")

default: speak

Real work — retrieval, compute, branching

doc-qa-with-citations

Retrieval-augmented answer with inline citations. Rerank the doc set, then a local LLM (called by the script via $ llm) answers using only the passages, citing every claim.

Uses: local model, data store

# Skill: doc-qa-with-citations
# Status: Approved
# Description: RAG with citations — rerank retrieval, then answer using only the passages.
# Vars: QUESTION, K=6
# Output: text

${RESPONSE}

answer:
    $ data_read mode=rerank query="${QUESTION}" limit=${K} -> HITS (fallback: [])
    $ llm prompt="Answer using ONLY the supplied passages. Cite each claim as [id:<record-id>]. Question: ${QUESTION}. Passages: ${HITS|json}" maxTokens=900 -> RESPONSE

default: answer

queue-length-monitor

Count and threshold — no model in the loop. The |length filter is deterministic and free; frontier inference never wakes up.

Uses: shell (cat)

# Skill: queue-length-monitor
# Status: Approved
# Description: Count items in a queue and alert when over threshold — no model needed.
#   Requires `cat` on the operator's shell allowlist.
# Vars: QUEUE_PATH=/var/queue/pending.json, THRESHOLD=10
# Triggers: cron: */5 * * * *

fetch:
    shell(command="cat ${QUEUE_PATH}") -> ITEMS (fallback: "[]")

evaluate:
    needs: fetch
    if ${ITEMS|length} > ${THRESHOLD}:
        emit(text="Queue backlog: ${ITEMS|length} items (threshold ${THRESHOLD}). Action required.")
    else:
        emit(text="Queue healthy: ${ITEMS|length} items (under ${THRESHOLD}).")

default: evaluate

classify-support-ticket

Multi-step classification and branching, all on a local LLM (the script calls $ llm) — a category pass plus an independent severity check, then route: page, tag, or draft a reply.

Uses: local model, data store

# Skill: classify-support-ticket
# Status: Approved
# Autonomous: true
# Description: Read a support ticket and route it — sev-1 pages ops, billing is tagged
#   for finance, everything else gets a draft reply queued for review.
# Vars: TICKET_TEXT, TICKET_ID
# Output: agent: ops-oncall

classify:
    $ llm prompt="Categorize this ticket. Reply EXACTLY one of: 'sev-1', 'billing', 'general'.\n\nTicket: ${TICKET_TEXT}" maxTokens=10 -> CATEGORY

severity_check:
    needs: classify
    $ llm prompt="Does this ticket describe a production sev-1 (outage, data loss, security)? Reply ONLY 'yes' or 'no'.\n\nTicket: ${TICKET_TEXT}" maxTokens=10 -> IS_SEV1

route:
    needs: severity_check
    if ${CATEGORY|contains:"sev-1"}:
        emit(text="PAGE: sev-1 ticket ${TICKET_ID}")
        $ data_write content="sev-1 ${TICKET_ID}: ${TICKET_TEXT}" tags=["support","sev-1","page"]
    elif ${IS_SEV1|contains:"yes"}:
        emit(text="PAGE: classifier said ${CATEGORY|trim} but severity-check flagged sev-1: ${TICKET_ID}")
        $ data_write content="sev-1 escalation ${TICKET_ID}" tags=["support","sev-1","disagreement"]
    elif ${CATEGORY|contains:"billing"}:
        emit(text="Tagged for finance review: ${TICKET_ID}")
        $ data_write content="billing ${TICKET_ID}: ${TICKET_TEXT}" tags=["support","billing"]
    else:
        $ llm prompt="Draft a polite two-sentence acknowledgment. No greeting or sign-off.\n\n${TICKET_TEXT}" maxTokens=150 -> DRAFT
        $ data_write content="draft ${TICKET_ID}: ${DRAFT|trim}" tags=["support","draft"]

default: route

Autonomous & event-driven

service-health-watch

Cron-polled health checks. Probe endpoints every five minutes; a local LLM (called via $ llm) judges ok-vs-degraded, and on degradation the script writes a signal record and alerts. The poll counterpart to the pushed alert below.

Uses: local model, data store, shell (curl)

# Skill: service-health-watch
# Status: Approved
# Autonomous: true
# Description: Every 5 minutes, probe service endpoints; on degradation write a signal
#   record and alert. Polls on cron — contrast with the pushed site-distress-relay.
#   Requires `curl` on the operator's shell allowlist.
# Vars: SERVICES=[auth-api, ledger-api, search-api], LATENCY_BUDGET_MS=400
# Triggers: cron: */5 * * * *
# Output: none

probe:
    foreach SVC in ${SERVICES}:
        shell(command="curl -s -o /dev/null -w \"%{http_code} %{time_total}\" https://status.internal/${SVC|url}") -> RAW
        $ llm prompt="From '${RAW|trim}' (http_code time_seconds) and budget ${LATENCY_BUDGET_MS} ms, answer ok or degraded only." -> STATUS
        if ${STATUS|contains:"degraded"}:
            $ data_write content="degradation: ${SVC} at ${NOW}: ${RAW|trim}" tags=["ops","degraded:${SVC}"] -> ACK
            emit(text="${SVC} degraded — wrote signal ${ACK.id}")
        else:
            emit(text="${SVC} ok")

default: probe

feedback-sentiment-scan

Nightly scan that classifies a day of customer feedback via a local LLM (the script calls $ llm per item), surfacing only the frustrated and blocking entries to the support lead.

Uses: local model, data store

# Skill: feedback-sentiment-scan
# Status: Approved
# Description: Nightly, scan the last day of feedback, classify sentiment with the local
#   model, and surface the frustrated/blocking ones to the support lead.
# Triggers: cron: 0 3 * * *
# Vars: SCAN_LIMIT=50
# Output: agent: support-lead

scan:
    $ data_read mode=fts query="customer feedback" limit=${SCAN_LIMIT} -> FEEDBACK
    emit(text="Sentiment scan for ${NOW}:")
    foreach F in ${FEEDBACK.items}:
        $ llm prompt="Classify sentiment in ONE word: 'frustrated','blocking','satisfied','neutral'.\n\n${F.summary}\n${F.detail}" maxTokens=10 -> VERDICT
        if ${VERDICT|contains:"frustrated"}:
            emit(text="- FRUSTRATED [${F.id|trim}] ${F.summary}")
        elif ${VERDICT|contains:"blocking"}:
            emit(text="- BLOCKING [${F.id|trim}] ${F.summary}")

default: scan

youtrack-morning-sweep

A real third-party tool, wired in. Pull your open issues through a remote MCP connector, with dotted access on the JSON response.

Uses: YouTrack MCP

# Skill: youtrack-morning-sweep
# Status: Approved
# Description: Pull your open YouTrack issues via a configured RemoteMcpConnector, with
#   dotted access on the parsed JSON. Requires a `youtrack` connector in connectors.json.

fetch_me:
    $ youtrack.get_current_user -> ME

fetch_issues: fetch_me
    $ youtrack.search_issues query="for: me" limit=5 -> RAW

report: fetch_issues
    emit(text="Morning sweep for ${ME.login}:")
    emit(text="Open issues assigned: ${RAW.issuesPage|length}")
    foreach I in ${RAW.issuesPage}:
        emit(text="- ${I.id}: ${I.summary}")

default: report

morning-brief

Fan-in composition. Calendar, mailbox, and overnight notes gathered in parallel via needs:, then composed into one brief by a local LLM (the script calls $ llm), with an error fallback.

Uses: local model, calendar MCP, data store

# Skill: morning-brief
# Status: Approved
# Description: At 7am, compose a brief from calendar + mailbox + overnight notes (three
#   sources fanned in via needs:), with a target-level else: fallback. Requires a `calendar`
#   connector; model=qwen is a representative LocalModel alias.
# Vars: AGENT, BRIEF_HORIZON_HOURS=24
# Triggers: cron: 0 7 * * *
# Output: agent: ${AGENT}

${BRIEF}

calendar:
    $ calendar.list_events horizon_hours=${BRIEF_HORIZON_HOURS} -> EVENTS

mailbox:
    $ data_read mode=fts query="messages for ${AGENT}" limit=10 -> MAIL

overnight:
    $ data_read mode=rerank query="overnight notes and writes" limit=15 -> NOTES

compose: needs: calendar, mailbox, overnight
    $ llm prompt="Compose a concise morning brief. Calendar: ${EVENTS|json}. Mailbox: ${MAIL|json}. Overnight: ${NOTES|json}. Three sections, six bullets max each." model=qwen maxTokens=1200 -> BRIEF
else:
    $set BRIEF = "Morning brief unavailable — a source failed (${ERROR_CONTEXT.message})."

default: compose

brand-monitor

Persistent state across runs — remember what you've already seen. Search the web for mentions of your project, keep only the genuine hits (a local model drops name-collisions), page-verify each, then dedup against a running log in the data store so only FIRST-TIME mentions surface. Each new one is appended to the log, which doubles as your mention history: read prior state, filter, append new. (The actual mention-tracker behind Perry's morning brief.)

Uses: DuckDuckGo MCP, local model, data store

# Skill: brand-monitor
# Status: Approved
# Description: Track NEW web mentions of your project. Search, let a local model keep only
#   genuine hits (vs name-collisions), page-verify each, then dedup against a running log in
#   the data store so only first-time mentions surface — appending each new one to the log,
#   which doubles as your mention history. The read-filter-append pattern for "remember what
#   you've already seen." Swap BRAND / QUERY for your own project.
# Vars: BRAND="skillscript", QUERY="skillscript declarative agent skill language"
# Returns: REPORT, NEW

scan:
    $set REPORT = "brand-monitor: no result this run."
    # Load the seen-log. $ data_read returns an envelope {items:[...]}, so iterate .items.
    $ data_read mode=fts query="${BRAND} mention seen" domain_tags=["brand-mention"] limit=200 -> SEEN_RAW
    $set SEEN = ""
    foreach S in ${SEEN_RAW.items}:
        $append SEEN <" ${S.detail}">
    # Search, then a local model keeps only genuine mentions (drops name-collisions).
    $ ddg.search query="${QUERY}" max_results=10 -> R
    $ llm prompt="Select ONLY results genuinely about the project '${BRAND}' (a real writeup or reference to it), excluding unrelated tools that merely share the name. Output ONLY a raw JSON array; each element {\"title\":\"...\",\"url\":\"...\"}. If none qualify, output []. Results:\n\n${R}" -> CANDIDATES
    $ json_parse ${CANDIDATES} -> G
    $set ITEMS = ""
    $set NEW = []
    foreach IT in ${G}:
        if not ${IT.url|contains:"github.com"}:
            # Dedup: skip anything already in the log; page-verify the rest.
            if not ${SEEN|contains:"${IT.url}"}:
                $ ddg.fetch_content url="${IT.url}" timeout=8 -> PAGE (fallback: "")
                if ${PAGE|contains:"${BRAND}"}:
                    $append NEW ${IT.url}
                    $append ITEMS <"\n- ${IT.title} — ${IT.url}">
                    # Append the new mention — the log is a 30-day rolling window.
                    $ data_write content="${BRAND} mention (seen) | ${IT.url} | ${IT.title} | first-seen ${NOW}" tags=["brand-mention", "${BRAND}"] approved="log new verified mention" -> REC
    $set REPORT = "New ${BRAND} mentions this run: ${NEW|length} (log holds ${SEEN_RAW.items|length} prior).${ITEMS}"
else:
    $set REPORT = "brand-monitor: search or parse failed this run."

${REPORT}

default: scan

site-distress-relay + restart-server

Event-triggered, and it acts. A monitor pushes a distress event — no polling, no loop — and the payload arrives as Vars. A hard-down runs restart-server once via execute_skill and reports back. Push delivery, skill-to-skill composition, and auditable autonomy (one restart, then a human decides) in one example.

Uses: shell (service restart), event trigger

site-distress-relay — the event-triggered parent

# Skill: site-distress-relay
# Status: Approved
# Description: A monitor fires this when a site goes down or degrades. The event carries
#   the site + state as Vars — the skill never polls. On a hard-down it runs restart-server
#   ONCE, reports the result, and leaves the escalation call to the human.
# Vars: SITE, STATE, DETAIL=""
# Triggers: event: site-distress
# Output: agent: on-call

Site alert: ${SITE} is ${STATE}.
${DETAIL}

${OUTCOME}

assess:
    if ${STATE|contains:"down"}:
        execute_skill(name="restart-server", inputs={"TARGET": "${SITE}"}) -> RESTART (fallback: "restart-server unavailable — page a human now.")
        $set OUTCOME = "Ran restart-server once: ${RESTART.outputs.text}. Confirm 200; if not, page a human — do not loop restarts."
    elif ${STATE|contains:"degraded"}:
        $set OUTCOME = "No action — single degraded sample. If it worsens to down, the monitor fires this again."
    else:
        $set OUTCOME = "Unrecognized state — surface to a human and wait."

default: assess

restart-server — the skill it calls

# Skill: restart-server
# Status: Approved
# Description: Restart one service via an allowlisted wrapper. Uses shell(argv=[...]) so the
#   target is passed as a single argument, never interpolated into a command string.
# Vars: TARGET
# Returns: RESULT

run:
    shell(argv=["svc-restart", "${TARGET}"]) -> RESULT (fallback: "restart wrapper not available")
    emit(text="restart issued for ${TARGET}: ${RESULT|trim}")

default: run

← Back home