Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions .github/workflows/ci-static-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,6 @@ concurrency:
cancel-in-progress: true

jobs:
actionlint:
name: actionlint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: rhysd/actionlint@v1.7.12

prek:
name: prek
runs-on: ubuntu-latest
Expand Down
86 changes: 15 additions & 71 deletions .github/workflows/ci-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,91 +39,35 @@ jobs:
steps:
- uses: actions/checkout@v6

- uses: actions/checkout@v6
with:
repository: spore-lang/spore
ref: d96212aa5a4cfe24759c21d8690642adfd357018
path: _spore
- uses: astral-sh/setup-uv@v6

- uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable

- uses: Swatinem/rust-cache@v2
with:
workspaces: _spore
toolchain: 1.95

- name: Build spore compiler
run: cargo build --release --manifest-path _spore/Cargo.toml --bin spore
- name: Install spore CLI
run: uv tool install spore-lang==0.0.3

- name: Format Spore files
run: |
# `src/host.sp` is a legacy compatibility shim; validate package-backed behavior
# via the example and platform modules rather than standalone file-mode checks.
# Standalone file examples
find examples -maxdepth 1 -name '*.sp' -type f | sort | xargs _spore/target/release/spore format
# Project-mode examples (format their src files)
if [ -d examples/hello-app/src ]; then
find examples/hello-app/src -name '*.sp' -type f | sort | xargs _spore/target/release/spore format
fi
# Platform API modules
find src/basic_cli -name '*.sp' -type f | sort | xargs _spore/target/release/spore format
# Check tests if they exist
if [ -d tests ]; then
find tests -name '*.sp' -type f | sort | xargs _spore/target/release/spore format
fi
git diff --exit-code
run: spore format --check

- name: Check Spore files
run: |
# `src/host.sp` is a legacy compatibility shim; validate package-backed behavior
# via the example and platform modules rather than standalone file-mode checks.
# Standalone file examples
find examples -maxdepth 1 -name '*.sp' -type f | sort | xargs -n 1 _spore/target/release/spore check
# Platform API modules
find src/basic_cli -name '*.sp' -type f | sort | xargs -n 1 _spore/target/release/spore check
# Project-mode examples: validate with spore check
if [ -d examples/hello-app ]; then
echo "✓ Checking project-mode example examples/hello-app/src/main.sp"
_spore/target/release/spore check examples/hello-app/src/main.sp
fi
# Check tests if they exist
if [ -d tests ]; then
find tests -name '*.sp' -type f | sort | xargs -n 1 _spore/target/release/spore check
fi
find src/basic_cli -name '*.sp' -type f | sort | xargs -n 1 spore check
spore check examples/hello-app/src/main.sp

- name: Build Spore files
run: |
# `src/host.sp` is a legacy compatibility shim; validate package-backed behavior
# via the example and platform modules rather than standalone file-mode builds.
# Standalone file examples
find examples -maxdepth 1 -name '*.sp' -type f | sort | xargs -n 1 _spore/target/release/spore build
# Platform API modules
find src/basic_cli -name '*.sp' -type f | sort | xargs -n 1 _spore/target/release/spore build
# Project-mode examples: validate with spore build
if [ -d examples/hello-app ]; then
echo "✓ Building project-mode example examples/hello-app/src/main.sp"
_spore/target/release/spore build examples/hello-app/src/main.sp
fi
# Check tests if they exist
if [ -d tests ]; then
find tests -name '*.sp' -type f | sort | xargs -n 1 _spore/target/release/spore build
fi

- name: Run standalone hello example
run: _spore/target/release/spore run examples/hello.sp
find src/basic_cli -name '*.sp' -type f | sort | xargs -n 1 spore build
spore build examples/hello-app/src/main.sp

- name: Run project-mode hello-app example
run: |
if [ -d examples/hello-app ]; then
echo "✓ Running project-mode example examples/hello-app/src/main.sp"
_spore/target/release/spore run examples/hello-app/src/main.sp
fi
(
cd examples/hello-app
echo "✓ Running project-mode example (default entry)"
spore run src/main.sp
)

- name: Run Spore spec tests
run: |
if [ ! -d tests ]; then
echo "No Spore spec tests yet; skipping spore test."
exit 0
fi
find tests -name '*.sp' -type f | sort | xargs -r -n 1 _spore/target/release/spore test
run: spore test
Comment thread
zrr1999 marked this conversation as resolved.
4 changes: 4 additions & 0 deletions .learnings/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Project Learnings

## Gotchas
- [Spore CI should target project-mode files explicitly](gotchas/spore-ci-project-mode.md) — spore, ci, project-mode
27 changes: 27 additions & 0 deletions .learnings/gotchas/spore-ci-project-mode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
title: "Spore CI should target project-mode files explicitly"
category: gotchas
tags: [spore, ci, project-mode, basic-cli]
created: 2026-04-28
context: "basic-cli CI needed to validate a package-backed example with the shipped compiler"
---

## Problem

The current `spore` CLI validates package-backed examples reliably when given the explicit entry file, but bare directory invocations and standalone file assumptions can fail depending on current compiler surface and imports.

## Solution

Use explicit file targets for project-mode checks:

```bash
spore check examples/hello-app/src/main.sp
spore build examples/hello-app/src/main.sp
cd examples/hello-app && spore run src/main.sp
```

## Key points

- Keep CI focused on the canonical package-backed entry file.
- Treat standalone `.sp` examples as separate from project-mode validation.
- Re-run `spore format --check`, `spore check`, and `spore build` against explicit files when compiler behavior is in flux.
23 changes: 10 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# basic-cli

Basic CLI platform for [Spore](https://github.com/spore-lang/spore) — provides file I/O, process execution, environment variables, and standard I/O capabilities.
Basic CLI platform for [Spore](https://github.com/spore-lang/spore) — provides file I/O, process execution, environment variables, and standard I/O effects.

## Overview

In Spore, a **platform** bridges the pure, capability-tracked language with real-world side effects. `basic-cli` is the standard platform for command-line applications.
In Spore, a **platform** bridges the pure, effect-tracked language with real-world side effects. `basic-cli` is the standard platform for command-line applications.

```
Your Spore App (pure, capability-checked)
Your Spore App (pure, effect-checked)
↕ (effect dispatch)
basic-cli Platform API (.sp modules)
↕ (foreign fn)
Expand All @@ -18,7 +18,7 @@ Operating System

## Modules

| Module | Capabilities | Description |
| Module | Effects | Description |
|--------|-------------|-------------|
| `basic_cli.stdout` | `uses [Console]` | Standard output |
| `basic_cli.stdin` | `uses [Console]` | Standard input |
Expand Down Expand Up @@ -46,9 +46,6 @@ default-entry = "app"
[entries.app]
path = "main.sp"

[capabilities]
allow = ["Compute"]

[dependencies]
basic-cli = { path = "../.." }
```
Expand Down Expand Up @@ -100,19 +97,19 @@ basic-cli/

The current Platform contract MVP is intentionally split across two artifacts:

1. `spore.toml` `[platform]` metadata names the contract module, the startup contract symbol, the adapter function, and the handled capabilities.
1. `spore.toml` `[platform]` metadata names the contract module, the startup contract symbol, the adapter function, and the handled effects.
2. `src/platform_contract.sp` owns the startup contract itself:
- a hole-backed `main` function carries the authoritative startup signature
- `main_for_host` is the Platform-owned adapter that receives the application startup function

Applications targeting `basic-cli` must implement the same startup function name/signature in their entry module. The current compiler already resolves the package's `[platform]` metadata and `src/platform_contract.sp` to validate that startup shape. Runtime support is currently specialized to package-backed `basic-cli`: imported `basic_cli.*` foreign functions route through the built-in basic-cli host profile, while generic `handles` enforcement and startup `spec` stacking are still follow-up work.
Applications targeting `basic-cli` must implement the same startup function name/signature in their entry module. The current compiler already resolves the package's `[platform]` metadata and `src/platform_contract.sp` to validate that startup shape. Runtime support is currently specialized to package-backed `basic-cli`: imported `basic_cli.*` foreign functions route through the built-in basic-cli host profile, while generic handled-effects enforcement and startup `spec` stacking are still follow-up work.

`src/host.sp` remains as a compatibility copy of the adapter for older references; current manifest-backed projects use `src/platform_contract.sp`.

## Tutorial Contract

- `examples/hello-app/` is the **canonical project-mode example** — it is formatted, checked, built, and run in CI.
- `examples/hello.sp` is a minimal standalone file for quick experiments (also validated in CI).
- `examples/hello.sp` is a minimal standalone file for quick experiments.
- `src/basic_cli/` is the API surface for the platform modules themselves.
- `src/platform_contract.sp` is the package-owned startup contract surface.
- Only add `tests/` when the repo has real Spore-side regression coverage worth running with `spore test`.
Expand All @@ -125,9 +122,9 @@ If you want to add a new tutorial/example, treat this as the bar:

## Design Philosophy

Following Spore's [SEP-0003 (Effect Capability System)](https://github.com/spore-lang/spore-evolution/blob/main/seps/SEP-0003-effect-capability-system.md):
Following Spore's [SEP-0003 (Effect System)](https://github.com/spore-lang/spore-evolution/blob/main/seps/SEP-0003-effect-system.md):

- **Capability-gated**: Every I/O function declares its required capabilities via `uses [Cap]`
- **Effect-gated**: Every I/O function declares its required effects via `uses [Effect]`
- **Cost-annotated**: Platform functions can carry `cost [c, a, i, p]` budgets where meaningful
- **Error-typed**: Functions declare error sets via `! ErrorType`
- **Pure by default**: The platform boundary is the only place side effects occur
Expand All @@ -138,7 +135,7 @@ Following Spore's [SEP-0003 (Effect Capability System)](https://github.com/spore

The canonical example is the **package-backed project-mode** `examples/hello-app/` application. It already validates and runs with `[project].platform = "basic-cli"`, an in-repo path dependency, and `import basic_cli.stdout`.

The standalone file example (`examples/hello.sp`) stays around for quick experiments. The main remaining platform gaps are generic `handles` enforcement, startup `spec` stacking, and lifting the runtime from its current explicit `basic-cli` host profile to a more general package-backed mechanism.
The standalone file example (`examples/hello.sp`) stays around for quick experiments. The main remaining platform gaps are generic handled-effects enforcement, startup `spec` stacking, and lifting the runtime from its current explicit `basic-cli` host profile to a more general package-backed mechanism.

## License

Expand Down
3 changes: 0 additions & 3 deletions examples/hello-app/spore.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,5 @@ default-entry = "app"
[entries.app]
path = "main.sp"

[capabilities]
allow = ["Compute"]

[dependencies]
basic-cli = { path = "../.." }
14 changes: 7 additions & 7 deletions examples/hello-app/src/main.sp
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/// Canonical package-backed application example for basic-cli.
///
/// This mirrors the formatted `spore new` scaffold: import the
/// platform module explicitly and call `println` directly from the
/// imported basic-cli surface.
/// Application entry point matching the platform contract.
// Canonical package-backed application example for basic-cli.
//
// This mirrors the formatted `spore new` scaffold: import the
// platform module explicitly and call `println` from the imported
// basic-cli surface.
import basic_cli.stdout as stdout

/// Application entry point matching the platform contract.
fn main() -> () uses [Console] {
println("Hello from a project-mode Spore application!")
println("Hello from a project-mode Spore application!");
return
}
7 changes: 7 additions & 0 deletions prek.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ hooks = [
{ id = "tombi-lint" },
]

[[repos]]
repo = "https://github.com/rhysd/actionlint"
rev = "v1.7.12"
hooks = [
{ id = "actionlint" },
]

[[repos]]
repo = "https://github.com/crate-ci/typos"
rev = "v1.33.1"
Expand Down
5 changes: 1 addition & 4 deletions spore.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ spore-version = ">=0.1.0"
contract-module = "platform_contract"
startup-contract = "main"
adapter-function = "main_for_host"
handles = ["Console", "FileRead", "FileWrite", "Env", "Spawn", "Exit"]

[capabilities]
allow = ["Compute"]
handled-effects = ["Console", "FileRead", "FileWrite", "Env", "Spawn", "Exit"]

[dependencies]
2 changes: 1 addition & 1 deletion src/basic_cli/cmd.sp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// basic-cli platform — Process execution
///
/// Run external commands with capability tracking.
/// Run external commands with effect tracking.

/// Run a command and capture its stdout as a string.
/// Returns the full stdout output on success.
Expand Down
2 changes: 1 addition & 1 deletion src/basic_cli/file.sp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// basic-cli platform — File system operations
///
/// Provides capability-gated file read and write operations.
/// Provides effect-gated file read and write operations.

/// Read the entire contents of a file as a string.
pub foreign fn file_read(path: Str) -> Str ! IoError uses [FileRead]
Expand Down
2 changes: 1 addition & 1 deletion src/basic_cli/stdout.sp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// basic-cli platform — Standard output operations
///
/// Provides capability-gated access to stdout/stderr.
/// Provides effect-gated access to stdout/stderr.

/// Print a string to stdout without trailing newline.
pub foreign fn print(s: Str) -> () ! IoError uses [Console]
Expand Down
2 changes: 1 addition & 1 deletion src/host.sp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
/// Manifest-backed projects resolve `main_for_host` from `platform_contract.sp`;
/// keep this shim in sync for older references.
pub fn main_for_host(app_main: () -> ()) -> () {
app_main()
app_main();
return
}
6 changes: 2 additions & 4 deletions src/platform_contract.sp
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@
/// Applications targeting this Platform must implement the same `main`
/// signature in their entry module. Any `spec` items attached here will stack
/// with the application's own `main` spec and both must hold.
pub fn main() -> () {
?platform_startup_contract
}
pub fn main() -> () { ?platform_startup_contract }

/// Platform-owned startup adapter.
pub fn main_for_host(app_main: () -> ()) -> () {
app_main()
app_main();
return
}
Loading