Skip to main content

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: ?name partial 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 uses carrier.
  • Stable generic bounds use a single comma-separated clause: where T: Trait, U: Trait.
  • Effect operations use explicit effect declarations plus perform Effect.op(...); reusable unions use effect Name = A | B.
  • Error sets are checked contracts: throw expr must 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 keeps Int/Float as I64/F64 aliases; implementation catch-up is tracked separately.
  • The live structured-concurrency surface includes parallel_scope { ... }, spawn { ... }, postfix task.await, Channel.new[...], and select { ... 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 / select subset. Until richer cost-slot terms land, examples use explicit parameters such as n instead of projections like urls.len. The same active-docs target also uses Channel.new[...] and select { 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/:

License

MIT OR Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

spore_lang-0.0.2-py3-none-macosx_11_0_arm64.whl (1.1 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

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

Hashes for spore_lang-0.0.2-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 458b5304ceecfdc3b87820f6c8c1f8454828de429627ff291c8fbadf69272e26
MD5 a1961d7055a93633fa7d59434c81809b
BLAKE2b-256 4f80d29abaa343a8b6af166d54c846b79bd27c5bf2828d653caaee66b423cdcb

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page