GitHub - sshwarts/skillscript: Skillscript — a small declarative language for authoring agent workflows. Runtime, compiler, and CLI.
Pangram verdict · v3.3
We believe that this document is fully AI-generated
AI likelihood · overall
AIArticle text · 1,730 words · 5 segments analyzed
*A language for agents to write themselves in.*
skillscript.ai • docs
TL;DR — npm install -g skillscript-runtime && skillfile init && skillfile dashboard. See Quickstart.
Contents
The problem The frame Why a new language Why not just have the agent write a Skill? Three kinds of skill
Waking agents Local models as tools for the frontier Composition: skills calling skills Static vs dynamic skills
What you get The bet Quickstart
A canonical autonomous skill
Connector model Configuration & security knobs CLI MCP server surface Examples Architecture and deep documentation Status Contributing License
The problem AI agents are mostly transient. Every routine task is re-derived from prose reasoning. The agent that summarized a thread yesterday will summarize one tomorrow by reasoning from scratch about how to summarize threads, burning frontier inference on a procedure with a known shape, a known output format, and known failure modes. The waste compounds in three directions: cost (every routine operation runs through the most expensive reasoning layer in the system), latency (every operation pays the full inference cost), and drift (the same task produces slightly different results each invocation because nothing crystallizes). The deeper problem is that agents have no substrate to write themselves down in. Agents are partly defined by what they can do and what they can do is currently held entirely in a soft, transient form of reasoning at inference time. There's no hard form. No place for an agent to crystallize a learned procedure into something cheap to execute, cheap to inspect, and cheap to improve. Most agent infrastructure projects today focus on memory — episodic recall, retrieval-augmented context, conversation summarization. Those projects answer "what does the agent know." They don't answer "what can the agent do" in any persistent, executable, inspectable form. Skillscript intends to answer the second question. The frame Agents are code, and skillscript is the language they write themselves in. Not memory in the recall sense. Not prompt templates. Not configuration. Code, in the strict sense of named, typed, composable, executable artifacts that constitute capability. A skillscript skill is a declarative recipe, a small program with a dependency DAG of typed operations — that an agent authors once and the runtime fires many times.
Where typical agent code is procedural (Python scripts, TypeScript handlers), skillscript is orchestration-only: it composes calls into tools, models, and data stores through swappable connector contracts. Computation lives in tools; coordination lives in skills. # Skill: hello # Status: Approved # Description: The canonical first-run example. # Vars: WHO=world
Hello, ${WHO}! Welcome to Skillscript.
That's a complete, runnable skill — and the body text is the output. No target, no boilerplate, no emit() ceremony: the runtime renders the body against the skill's variables and publishes it. The same shape scales to multi-stage DAGs that classify inputs, dispatch to LLMs, query data stores, branch on conditions, and orchestrate sub-agents, all in the same declarative grammar. Why a new language The obvious alternative is "let the agent write Python." Python is Turing-complete, has mature tooling, and models write it well. For one-shot exploratory work or where computation matters, Python is the right tool, and we're not proposing anyone stop using it for that. But agent-authored persistent automation has a different shape:
An agent (not a human) writes the code. The code runs autonomously — cron-fired, event-triggered — with no human in the loop at execution time. The work is dispatch-shaped: call a tool, classify a result, branch, call another tool. Not algorithmic computation. The code needs to be auditable by humans at human tempo even though it's authored at agent tempo.
For this shape, Python's strengths invert into liabilities:
Turing completeness becomes a liability. An agent-authored script can do anything including things the agent didn't realize were dangerous. subprocess.run, arbitrary network calls, file writes. None of these are gated. The blast radius of a buggy agent-authored script is the whole host. Mature tooling doesn't help when the author isn't human. Debuggers and REPLs are for human iteration. Agents don't iterate that way. Direct execution magnifies failure. When an agent ships a broken Python script to production cron, there's no validation layer. The script fails silently at 3am and the human discovers it the next day. The package ecosystem becomes an unbounded attack surface. Agents that can pip install anything can install anything — including supply-chain-compromised packages.
The package ecosystem assumes human review before adoption; agent adoption breaks that assumption.
Skillscript deliberately constrains expressiveness. It's not Turing complete. It can't eval, can't subprocess, can't import arbitrary code. The constraint is the safety story — enforced at the language level, not as an aspiration. In exchange:
Sandboxed grammar. The language can only do what configured connectors permit. Declarative legibility. Skills are DAGs of typed dispatches. A human reading a skill sees exactly which tools get called, which data writes happen, which model prompts fire. The same source produces the same audit diagram every time. Connector-mediated capability. Skills don't import packages, they invoke connectors, gated artifacts with curated tool surfaces. Python doesn't disappear from the system; it moves out of the agent's hands and into the connector implementations adopters write deliberately. The safety boundary moves to the connector edge. Static validation before admission. A skill that fails the linter can't enter the library. Structural issues, missing dependencies, undeclared variables, mutation paths without confirmation gates are caught at authorship time, not at 3am. Signed approval before effect. In secured mode, only skills carrying a valid operator signature perform effectful ops — an unapproved or tampered skill is inert no matter how it's dispatched (CLI, cron, /event, MCP, composition). Approval is an Ed25519 signature applied operator-side and verified on every execution; the runtime never holds the signing key. Asymmetric cost. Routine work (classify, dispatch, transform) costs local-model tokens. The frontier model is reserved for the small fraction of work that actually needs frontier judgment.
Why not just have the agent write a Skill? Skills (Anthropic/OpenAI) are the existing convention for giving agents named, reusable capabilities, hand-authored markdown that loads instructions into the model's context. They work, and skillscript is complementary to them, not competing. The problem with hand-authoring is that both authoring populations produce badly-shaped artifacts when working in prose:
Agents authoring markdown produce artifacts shaped for humans, not agents — verbose explanations, hedging language, redundant context-setting, prose where structure would do. The result is expensive to load, noisy to parse, and hard to maintain. Humans authoring markdown produce the opposite failure modes.
Either ultra-terse and missing context, or kitchen-sink comprehensive in ways that bury the actual procedure under hedges and edge cases.
Making this a programming problem disciplines both populations into the right shape. The grammar doesn't permit rambling. The compiler emits structure, not prose-pretending-to-be-structure. A skillscript skill compiles into an artifact of the same shape as a hand-authored Skill — # Skill: <name> header, instructional markdown body — and that artifact can be loaded into an agent's context the same way. Skillscript is what you author in; the compiled Skill is what runs. Mature deployments use both: Skills as agent-facing capability descriptions, skillscript as the higher-leverage authoring layer underneath. Three kinds of skill Every skillscript skill is one of three shapes, determined by the relationship to a frontier agent:
Kind Output goes to Use case
Headless a downstream system or human, consumed asynchronously Cron-fired monitors, batch processors, autonomous workflows
Augmenting a frontier agent's reasoning context, immediately at session start or wake Session-start briefings, alerts, prepared context
Template a frontier agent's execution loop, as a prompt the agent runs itself Reusable recipes the agent fetches and follows
The kinds compose. A Headless monitor fires on cron, evaluates a condition, and routes into an Augmenting skill that wakes an agent with context, which itself references a Template skill for the agent to execute. The three kinds describe the skill's role (who consumes the output). Orthogonal to that is how the result ships. The default is the body-text output template: any non-op text in the skill body is rendered against the skill's final variables and published as its canonical output — no ceremony, as in the hello skill above. For what the template can't express, three delivery ops are first-class — emit() for incremental/per-item output, $ data_write for data handoff, file_write for files — and they coexist with the template (which owns canonical output; emit lines are additional). See the Language Reference §1 for the full taxonomy.
The canonical use for emit is per-item output inside a loop, where there's no single template to render — one line per iteration: # Vars: TICKETS=[...]
process: foreach T in ${TICKETS}: emit(text="${T.id}: ${T.urgency}")
default: process
Local models as tools for the frontier Most agent systems treat local models as substitutes for frontier inference. Call them instead of the frontier when latency or cost matters. Skillscript treats them as something different: delegation targets the frontier orchestrates. The frontier composes the workflow; each LLM dispatch is the frontier handing off a bounded sub-task (classify a message, extract a field, judge whether two strings refer to the same thing, summarize a chunk, format a response) to a local or smaller model and consuming the result. In skillscript, this isn't a separate "local-model interplay" pattern adopters bolt on — it's just MCP dispatch through a connector named whatever your substrate calls it. $ llm prompt="..." -> RESULT (one shop wires llm pointing at Ollama; another wires openai_chat against the OpenAI API; another wires claude_messages against Anthropic) lives next to any other $ tool args -> RESULT in the skill body, with the same op-level discipline, the same trace surface, the same lint coverage. The language has no built-in LLM keyword — adopters wire their substrate. The cost shape that follows: routine work runs at local-model cost (free at scale, fast, private to the host); the frontier model intervenes only at orchestration boundaries and ambiguous cases. Customer data flowing through bounded sub-tasks never reaches an external API when the wired connector is local. The local-model layer becomes the privacy boundary, not a separate add-on. Composition: skills calling skills A skill can invoke another skill via execute_skill(...): Extracted: ${RESULT.final_vars.VALUE|trim}
parent: execute_skill(name="extract-json-number", JSON_BLOB="${RAW}", FIELD_PATH="total_count") -> RESULT
default: parent
The child skill runs to completion against the runtime's wired connectors, returns its full execution record (final vars, transcript, outputs), and binds to the parent's named variable. Field access on the bound result (${RESULT.final_vars.X}) lets the parent reach into whatever the child produced.