CLI and reference compiler for the Spore language.
Project description
Spore (孢子)
A general-purpose programming language optimized for Agent-human intent interaction.
Spore is a compiled language where function signatures are "gravity centers" — complete specifications carrying type, error, required effect, and cost information. The compiler serves as a documentation assistant, and the hole system enables Agent-driven collaborative development.
Key Features
- Hole System:
?namepartial functions as first-class collaboration protocol with Agents - Effect System: IO effects gated by required effects, verified at compile time
- Cost Model: 4-dimension cost analysis (compute, alloc, io, parallel) with compile-time budgets
- Content-Addressed: Dual hash (sig + impl) for modules — no semver, pure hash addressing
- Effect Handlers: All IO through Platform-provided effect handlers, application code stays pure
- Structured Concurrency: Task trees with cancellation propagation, channels for communication
- Expression-Based: Everything is an expression, no loops (recursion + higher-order functions)
Canonical Surface Syntax
- Modules come only from file paths; there is no
module ...header. - Effect checks live on function signatures and package/Platform boundaries only; source files have no module-level
usescarrier. - Stable generic bounds use a single comma-separated clause:
where T: Trait, U: Trait. - Effect operations use explicit
effectdeclarations plusperform Effect.op(...); reusable unions useeffect Name = A | B. - Error sets are checked contracts:
throw exprmust match the current! E1 | E2, calling a throwing function requires compatible caller errors, and?is propagation sugar. - Current implementation primitives are
I32/I64/U32/U64/F32/F64/Bool/Str/(). The locked surface also keepsInt/FloatasI64/F64aliases; implementation catch-up is tracked separately. - The live structured-concurrency surface includes
parallel_scope { ... },spawn { ... }, postfixtask.await,Channel.new[...], andselect { ... timeout(...) => ... }.
Quick Start
cargo build # build the compiler
cargo run --bin spore -- new hello-app # create a new application project
cd hello-app && ../target/debug/spore run src/main.sp # run the application from this checkout
cargo test --all # run all compiler tests
For single-file exploration:
cargo run --bin spore -- run examples/demo.sp # run standalone file (no Platform)
cargo run --bin spore -- check examples/demo.sp # type-check standalone file
cargo run --bin spore -- test examples/demo.sp # validate spec examples in file
If spore is installed on your PATH, you can replace the explicit Cargo or
target/debug/spore invocations above with bare spore ....
Examples
Hello World (Application Project)
The canonical way to write Spore programs is as a project with a Platform contract:
spore new hello-app
This generates src/main.sp with a Platform-aware entry point:
import basic_cli.stdout
fn main() -> () uses [Console] {
println("Hello from hello-app!")
return
}
Applications declare fn main() -> () and require effects that are handled by the Platform.
The basic-cli Platform handles effect operations like Console for terminal IO.
Standalone File Mode
For quick experiments, you can run single .sp files without a project:
fn demo() -> I32 {
let x = 42;
x * 2
}
fn main() -> () {
println(to_string(demo()))
return
}
Standalone mode does not participate in a package-backed Platform contract.
It still runs through legacy built-in CLI behavior today (e.g., bare println works),
but completion values have no default CLI host semantics: spore run does not print
them automatically and does not treat them as process exit codes.
Compatibility paths like fn main() -> I32 still compile, but the CLI canon is
explicit output plus fn main() -> ().
Real applications should prefer spore new / project mode with an explicit Platform effect boundary.
See examples/demo.sp for a standalone example file.
Structs and Pattern Matching
struct Point { x: I32, y: I32 }
type Shape {
Circle(I32),
Rect(I32, I32),
}
fn area(s: Shape) -> I32 {
match s {
Circle(r) => r * r * 3,
Rect(w, h) => w * h,
}
}
Lambdas, Pipes, and Higher-Order Functions
fn apply(f: (I32) -> I32, x: I32) -> I32 { f(x) }
fn compute() -> I32 {
let double = |x: I32| x * 2;
apply(double, 21)
}
Required Effects, Costs, and Error Sets
These annotations are part of the function signature — the compiler verifies
required effects, cost budgets, checked error contracts, and explicit effect
surfaces at call boundaries. throw expr must be covered by the current
function's ! E1 | E2, calling a throwing function requires a compatible
caller signature, and ? is sugar for
that propagation rule.
The parser accepts where, uses, cost, and spec clauses in any order.
Documentation examples use the canonical order: where, uses, cost, spec,
and stable where syntax is a single comma-separated clause such as
where T: Trait, U: Trait. Active cost syntax is the fixed-order vector
cost [compute, alloc, io, parallel]; each slot currently uses the minimal
subset only: integer constants, parameter variables, or linear O(n) terms.
Old scalar cost <= expr, log/max/min, and richer algebraic terms are
deferred.
effect NetConnect {
fn fetch(url: Str) -> Str ! NetError | Timeout
}
fn fetch(url: Str) -> Str ! NetError | Timeout
uses [NetConnect]
cost [1, 0, 1, 0]
{
perform NetConnect.fetch(url)
}
Parallel Fetch
fn fetch_all(urls: List[Str], n: I32) -> List[Str] ! NetError | Timeout
uses [NetConnect, Spawn]
cost [O(n), O(n), n, n]
{
parallel_scope {
urls |> map(|url| spawn { fetch(url) })
|> map(|task| task.await?)
}
}
This is part of the live structured-concurrency surface: the parser, typechecker, and interpreter all cover the current
parallel_scope/spawn/await/selectsubset. Until richer cost-slot terms land, examples use explicit parameters such asninstead of projections likeurls.len. The same active-docs target also usesChannel.new[...]andselect { msg from rx => ..., timeout(5.seconds) => ... }.
Traits and Implementations
trait Display[T] {
fn show(self: T) -> Str
}
impl Display for Point {
fn show(self: Point) -> Str { "point" }
}
Architecture
sporec (stateless compiler CLI / product)
└── sporec-driver Host-side compiler driver crate
├── sporec-parser Source text -> AST
├── sporec-typeck Type checking, effect & cost analysis
│ ├── hir HIR with pipe desugaring
│ ├── effect sets Effect-set algebra (∪/∩/hierarchy)
│ ├── cost 4D cost vectors + cost checker
│ ├── hole Hole dependency graph + topological ordering
│ ├── sig_hash BLAKE3 256-bit signature hashing
│ ├── incremental Incremental compilation DB
│ ├── module Module registry + import resolution
│ ├── concurrency Structured concurrency analysis
│ └── platform Platform system (cli/web/embedded)
└── sporec-codegen Tree-walk interpreter (PoC) / Cranelift (planned)
spore (stateful codebase manager — handles IO / project workflow)
├── File watching, incremental compilation
├── Package management (content-addressed)
├── Platform management
└── LSP server (spore-lsp)
Project Status
Compiler infrastructure implemented. Parser is feature-complete for the syntax spec. Type checker covers unification, pattern exhaustiveness, trait conformance, error set checking, cost analysis, and the current structured-concurrency subset. Interpreter is a PoC tree-walking evaluator with enum constructors, 30+ builtin functions (list/string/math/IO), method-style dispatch, try-operator support, and the current structured-concurrency runtime.
See docs/DESIGN.md for the canonical in-repo design document. Topic-level normative proposals live in the sibling spore-evolution repo under seps/.
Packaging
The spore CLI is packaged from crates/spore via maturin so it can be built and published as a PyPI binary package.
just package-cli # build a wheel into dist/
just package-cli-sdist # build a source distribution into dist/
Development
Local hooks
just pre-commit-install # install pre-commit + commit-msg hooks via prek
just pre-commit # run the configured hooks on all files
In this repository, the local Spore hooks intentionally focus on the canonical example surface under examples/. The reusable published hooks below are for arbitrary .sp files in downstream repos.
Reusable hooks
With the root pyproject.toml in place, the repository can also expose reusable pre-commit hooks for .sp files:
repos:
- repo: https://github.com/spore-lang/spore
rev: <tag-or-sha>
hooks:
- id: spore-format
- id: spore-check
Until a dedicated thin mirror repo exists, installing these hooks from the source repo still builds Spore from source, so consumers need a working Rust toolchain.
Documentation
Canonical design docs
| Document | Description |
|---|---|
| docs/DESIGN.md | Primary in-repo design document, syntax authority, and durable design summary |
| docs/specs/README.md | Redirect for the retired per-topic spec drafts |
| docs/research/README.md | Redirect for the retired research drafts |
SEP mapping
Detailed topic proposals now live in spore-evolution/seps/:
SEP-0001-core-syntax.mdSEP-0002-type-system.mdSEP-0003-effect-system.mdSEP-0004-cost-analysis.mdSEP-0005-hole-system.mdSEP-0006-compiler-architecture.mdSEP-0007-concurrency-model.mdSEP-0008-module-package-system.mdSEP-0009-standard-library.md
License
MIT OR Apache-2.0
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file spore_lang-0.0.2-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: spore_lang-0.0.2-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.1 MB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
458b5304ceecfdc3b87820f6c8c1f8454828de429627ff291c8fbadf69272e26
|
|
| MD5 |
a1961d7055a93633fa7d59434c81809b
|
|
| BLAKE2b-256 |
4f80d29abaa343a8b6af166d54c846b79bd27c5bf2828d653caaee66b423cdcb
|