Use for any task involving the Spore language, including writing, reviewing, debugging, or reasoning about Spore code, `.spore` files, `.sp` files, holes, and Spore program architecture.
Spore is a language where programmer intent is explicit, verifiable, and collaborative. Every function signature is a complete specification — types, errors, cost budget, and capabilities — so humans and AI agents can collaborate through typed holes without ambiguity.
Spore is built around one idea: programmer intent should be explicit, verifiable, and collaborative.
A function signature is a complete specification of intent — types, errors, cost budget, and required capabilities. The body can be a hole; the intent is already fully expressed.
fn fetch(url: String) -> String ! [NetError, Timeout]
cost ≤ 1000
uses [NetRead]
{
?todo
}
A program with holes compiles successfully. Holes are how humans and Agents collaborate:
The compiler generates a self-contained HoleReport (JSON) for each hole: expected type, bindings, capabilities, cost budget, and candidate functions. No additional context is needed.
| Language | Idea | How it shows up in Spore |
|---|---|---|
| Agda | Holes | typed placeholders with compiler-provided context |
| Idris | Elaboration | Compiler infers details the programmer omits |
| Unison | Content-addressing | Modules identified by hash, not name+version |
| Elm | Error messages | Human-friendly diagnostics with repair hints |
| Roc | Managed effects | All IO through platform-provided effect handlers |
Follow these steps when building any Spore program. This is the workflow Spore's tooling is designed to support.
Write function signatures and types first. Use holes everywhere the implementation is not yet decided.
struct Order { id: Int, items: List[Item], total: Int }
fn calculate_total(items: List[Item]) -> Int cost ≤ O(n) { ?total_logic }
fn validate_order(order: Order) -> Order ! [ValidationError] { ?validation }
fn process_payment(order: Order) -> Receipt ! [PaymentError] uses [NetWrite] { ?payment }
Run spore check — the compiler validates signatures, capabilities, and cost budgets even with holes.
Run spore holes <file> to get the dependency graph and fill order. Start with leaf holes (no dependencies on other holes).
Use spore watch for incremental re-checking on every save.
Zero holes = complete, fully verified program.
A Spore project follows a conventional layout managed by spore.toml:
my-app/
├── spore.toml # project manifest
├── src/
│ ├── main.sp # default entry module (application)
│ └── billing/
│ ├── invoice.sp # module: billing.invoice
│ └── types.sp # module: billing.types
└── .gitignore
Cross-file imports use dot-separated module paths:
import billing.invoice
import billing.types
The compiler resolves modules from the src/ directory and detects circular dependencies at compile time.
At the project layer, an entry selects a source path/module. The selected
entry module then provides a startup function that must satisfy the
configured Platform's startup contract.
# Compile and execute
spore run <file> # compile and execute (tree-walk interpreter)
spore run --json <file> # output result as JSON
# Type-checking
spore check <file...> # type-check one or more files
spore check --verbose <file> # show inferred types, costs, capabilities
spore check --json <file> # output diagnostics as JSON
spore check --deny-warnings <file> # treat warnings as errors
# Formatting
spore format <file> # format source in-place (alias: spore fmt)
spore format --check <file> # check if file is formatted (exit 1 if not)
spore format --diff <file> # show formatting diff without writing
# Hole reports
spore holes <file> # JSON hole report (types, bindings, candidates, DAG)
# Building
spore build <file> # compile without executing (interpreter mode)
# Watch mode
spore watch <file> # re-check on file changes
spore watch --json <file> # NDJSON events for IDE/Agent consumption
# Project scaffolding (PR #26 — may not yet be on main)
spore new <name> # create new project directory
spore new <name> --type package # project types: application (default), package, platform
spore init # initialize project in current directory
spore init --type package # specify project type
# Version / help
spore --version # print version
spore help # show usage
# Development (building the compiler itself)
cargo build # build the compiler
cargo test --all # run all tests
perform / handleSpore supports algebraic effects via perform and handle. Effects are dispatched at runtime and checked at compile time via the uses clause.
Multi-file compilation resolves import billing.invoice to src/billing/invoice.sp. The module dependency graph is validated for circular imports.
The spore-lsp binary provides IDE integration:
Cost budgets declared in signatures are verified by the compiler. Functions whose cost cannot be determined structurally receive a warning. The @unbounded annotation opts out of cost checking (contagious to callers).
When filling a ?name hole:
uses clause).errors_to_handle.List: len, head, tail, append, prepend, reverse, range, contains.
Higher-order: map, filter, fold, each.
String: string_length, split, trim, to_upper, to_lower, starts_with, ends_with, replace.
Math: abs, min, max, to_string.
IO: print, println, read_line.
Operators: +, -, *, /, %, ==, !=, <, <=, >, >=, &&, ||, !, |>, ?.
spawn/await/parallel_scope parse but do not execute.