Complete tutorial

Build prompt software, not prompt paste.

This tutorial takes you from a blank file to a portable Stim workflow with commands, agents, imports, subagents, orchestration, packages, targets, and optimization.

Lesson 01

Install Stim and understand the pipeline.

Stim is a compiler. A .stim file does not run at compile time. The compiler parses your source, resolves imports and task references, optionally optimizes the AST, renders natural-language markdown, then lets a target adapter shape the final file for Claude Code, ChatGPT, or Cursor.

Install the standalone binary, verify it, then keep source files in your project just like any other prompt asset.

curl -fsSL https://raw.githubusercontent.com/wess/stim/main/install.sh | sh
stim version

mkdir prompts
cd prompts
touch greet.stim

Lesson 02

Write a command for an interactive workflow.

A command becomes an interactive workflow. In Claude Code it installs as a slash command. The body is a sequence of statements that the target AI follows in order.

Start small: ask for context, wait for the user, then ask the next useful question. This is the core shape of a Stim command.

command greet {
  ask("What are you working on?")
  wait_for_response()

  ask("What outcome should this session produce?")
  wait_for_response()

  ask("I have the context. I will keep the work scoped to that outcome.")
}
stim install greet.stim

# Claude Code
/greet

Lesson 03

Create an agent persona that ports across tools.

An agent is a static persona. Metadata must come first. Body prose is written as bare string literals, one sentence or paragraph per line. Targets that do not support fields like tools or model warn and drop them instead of breaking the source.

agent reviewer {
  description "Reviews pull requests for security and correctness"
  tools [Read, Grep, Bash]
  model "sonnet"

  "You are a senior code reviewer."
  "Cite concrete file paths and line numbers for each finding."
  "Prioritize findings by severity: critical, high, medium, low."
  "Do not pad the review with praise or generic style advice."
}
stim install reviewer.stim
stim install reviewer.stim --target cursor
stim compile reviewer.stim --target chatgpt

Lesson 04

Use variables, arrays, and control flow.

Variables make prompts maintainable. Stim supports strings, booleans, and arrays of strings. Conditions and expressions are stored as prompt logic, not evaluated as JavaScript.

Keep each statement on its own line. The parser is line-based, so block openers end with { and closing braces sit alone.

command triage {
  areas = ["security", "performance", "correctness", "docs"]
  strict = true

  ask("Paste the change summary.")
  wait_for_response()

  for area in areas {
    if (confirm("Review " + area + "?")) {
      ask("Review the change for " + area + ".")
      wait_for_response()
    }
  }

  if (strict) {
    ask("List blockers first. Do not bury required fixes.")
  }
}

Lesson 05

Spawn subagents and run independent work in parallel.

Tasks describe subagent work. Use explore for codebase discovery, bash for command execution, plan for planning, and general when no specialized mode fits.

A parallel block may contain only task statements. It is for independent work that can happen at the same time.

command reviewpanel {
  parallel {
    task explore "map changed files" {
      ask("Inspect the diff and identify risky files.")
    }
    task explore "check tests" {
      ask("Find tests related to the changed behavior.")
    }
    task general "review behavior" {
      ask("Review for regressions and missing edge cases.")
    }
  }

  ask("Merge the findings, dedupe them, and report blockers first.")
}

Lesson 06

Split larger prompt systems with imports.

Imports bring variable definitions into scope before the declaration. Task file references inline another .stim file at compile time. Stim detects circular references, so shared prompt systems can grow without becoming fragile copy-paste chains.

// shared/standards.stim
severity = ["critical", "high", "medium", "low"]
reviewtone = "direct, concise, evidence-first"
import "shared/standards.stim"

command audit {
  ask("Use this severity order: " + severity.join(", "))
  ask("Use this tone: " + reviewtone)

  task("review/deep.stim")
}

Lesson 07

Turn repeatable orchestration into harnesses.

A harness is a reusable orchestration template. It declares param inputs at the top and is instantiated from a command with run. This keeps large review, planning, and verification workflows from becoming one-off monoliths.

harness reviewmatrix {
  param dimensions
  param passes = "2"

  fanout dim over dimensions {
    task explore "review dimension" {
      ask("Review the change for the current dimension.")
    }
  }

  gather "dedupe findings by file and line"
  loop until_dry rounds passes {
    task explore "verify findings" {
      ask("Re-check each remaining finding for evidence.")
    }
  }
  synthesize "write a final review with blockers first"
}
command deepreview {
  dimensions = ["security", "correctness", "performance"]

  run "reviewmatrix.stim" {
    dimensions = dimensions
    passes = "2"
  }
}

Lesson 08

Compile the same source for different AI tools.

Targets own output shape. Claude gets command and agent markdown with supported frontmatter. Cursor gets project-scoped rule files. ChatGPT gets markdown that can be pasted into a Custom GPT or saved as prompt material.

stim compile reviewer.stim --target claude
stim compile reviewer.stim --target cursor
stim compile reviewer.stim --target chatgpt

stim install reviewer.stim
stim install reviewer.stim --local
stim install reviewer.stim --target cursor

Lesson 09

Install and publish reusable prompt packages.

Packages are GitHub-hosted collections with a stim.yaml or stim.json manifest. Use them for team review agents, planning commands, git workflows, writing helpers, and any prompt kit worth sharing.

stim add github/wess/stim/packages/reviews
stim add github/wess/stim/packages/planning
stim add github/wess/stim/packages/gitflow
stim add github/wess/stim/packages/writing

stim update
stim remove github/wess/stim/packages/reviews
name: reviews
version: 1.0.0
commands: []
agents:
  - security.stim
  - quality.stim
  - docs.stim

Lesson 10

Use production patterns that keep prompts maintainable.

Treat Stim source like software. Keep files small, name the workflow by what the user invokes, factor shared values into imports, and turn repeatable orchestration into harnesses. Use stim tokens to compare size and --optimize when you want conservative AST cleanup.

The important constraint: do not document behavior Stim does not execute. Function calls other than the built-ins compile as instructions. Conditions are interpreted by the target AI. Stim's job is to make that instruction set structured, portable, and reviewable.

stim tokens deepreview.stim
stim tokens deepreview.stim --optimize

stim compile deepreview.stim --target claude --optimize
stim install deepreview.stim --local --optimize
Recommended project shape:

prompts/
  shared/
    standards.stim
  review/
    deep.stim
    matrix.stim
  commands/
    deepreview.stim
  agents/
    reviewer.stim

Lesson 11

Create files and use functions intentionally.

Stim has a small set of built-in functions that compile to instructions: ask, confirm, wait_for_response, and create_file. They do not perform filesystem work during compilation. They tell the target AI what to do when the command is invoked.

Unknown calls are passthrough instructions. That is useful for naming prompt concepts, but you should not document them as executable runtime functions.

command specwriter {
  ask("Describe the feature and the user outcome.")
  wait_for_response()

  ask("List constraints, non-goals, and release risks.")
  wait_for_response()

  create_file("SPEC.md", "Write a concise implementation spec from the gathered answers.")
  create_file("CHECKLIST.md", "Write acceptance checks and verification steps.")
}
command passthrough {
  ask("Gather the project context.")
  generate_release_notes()
  summarize_open_questions()
}

Lesson 12

Write for the parser Stim actually has.

Stim is intentionally line-based. One statement per line keeps source readable and avoids pretending the language is a general-purpose TypeScript parser. Block openers end with {, closing braces sit alone, and multi-line arrays are the main expression that can span lines.

Use // comments. Do not use # as a comment. Conditions are prompt expressions, not compiler-evaluated JavaScript.

command parserfriendly {
  questions = [
    "What changed?",
    "What could break?",
    "How should we verify it?",
  ]

  for question in questions {
    ask(question)
    wait_for_response()
  }
}
// Good
if (confirm("Continue?")) {
  ask("Proceeding")
}

// Avoid one-line blocks
if (confirm("Continue?")) { ask("Proceeding") }

Lesson 13

Add engine annotations when a command needs topology.

Commands can use annotations before any other statements. These annotations compile into engine-mode instructions such as topology, memory policy, and error handling. They belong on commands, not agents.

Use this when a command coordinates multiple phases and needs the target AI to keep structure visible.

command releaseaudit {
  @topology pipeline
  @memory session
  @on_error retry

  task explore "inspect release docs" {
    ask("Find install, versioning, and release workflow risks.")
  }

  task bash "verify binary" {
    ask("Build the binary and run the version command.")
  }

  synthesize "write blockers first, then adoption friction, then polish."
}

Lesson 14

Measure prompt size and optimize only when it helps.

stim tokens estimates prompt size. The --optimize flag enables conservative AST passes: constant folding, dead branch removal, empty block elimination, adjacent duplicate removal, unused assignment removal, and post-render whitespace normalization.

Optimization is opt-in. Without it, the compile pipeline stays straightforward and predictable.

stim tokens reviewpanel.stim
stim tokens reviewpanel.stim --optimize

stim compile reviewpanel.stim --target claude
stim compile reviewpanel.stim --target claude --optimize
command optimizedemo {
  enabled = true
  unused = "remove me"

  if (enabled) {
    ask("This branch remains.")
  } else {
    ask("This branch can be removed.")
  }
}

Lesson 15

Use editor support and a repeatable workflow.

Stim ships editor integrations for VS Code, Neovim, and Zed. The language server runs through stim --lsp, so syntax, completion, hover, symbols, and diagnostics share the same project understanding.

A practical workflow is simple: write small source files, compile locally, inspect the generated markdown, install locally for the project, then package reusable workflows once they prove useful.

stim compile prompts/commands/deepreview.stim --target claude
stim install prompts/commands/deepreview.stim --local
stim tokens prompts/commands/deepreview.stim

stim add github/wess/stim/packages/reviews --local
stim update
Editor docs:

plugins/vscode/README.md
plugins/neovim/README.md
plugins/zed/README.md

Next

Use the docs as your reference manual.

The tutorial gives you the workflow. The docs index gives you the exact syntax, target behavior, package format, plugin setup, and examples when you need precision.