Four new test binaries, DB-gated via the established pool_or_skip()
pattern (returns Some(pool) when DATABASE_URL is set; prints a skip
notice and returns None otherwise — so plain `cargo test` stays green
locally while CI runs them).
crates/picloud/tests/queue_e2e.rs (4 tests):
- queue_receive_acks_on_success: enqueue → consumer fires → KV
marker observable → queue row deleted (ack worked)
- queue_receive_dead_letters_after_max_attempts: throwing handler
retries 3× via the dispatcher's compute_backoff path → dead_letters
row written, queue row deleted
- queue_one_consumer_per_queue_rejected: second trigger create for the
same (app_id, queue_name) returns 4xx with the documented "already
has a consumer trigger" message (advisory-lock guard works)
- queue_visibility_timeout_reclaim: insert message with stale claim
(claimed_at = NOW() - 60s, visibility_timeout = 5s); either the
dispatcher re-claims after reclaim runs, or the claim clears
crates/picloud/tests/invoke_e2e.rs (4 tests):
- invoke_by_name_same_app_returns_value: callee returns body.x+1;
caller invokes by name and writes the result to KV (42 round-trips)
- invoke_cross_app_rejects: callee in app_B, caller in app_A; error
string contains "different app" or "CrossApp"
- invoke_depth_limit_exceeds_cleanly: recursive script throws with
"depth" in the message at the bound (Limits::trigger_depth_max=8)
- invoke_async_enqueues_outbox_row: invoke_async returns execution_id,
dispatcher fires the OutboxSourceKind::Invoke arm, callee marker
appears
crates/picloud/tests/retry_e2e.rs (3 tests):
- retry_run_eventually_succeeds_inside_http_handler: counter mutates
across 3 retries through a real HTTP route, returns 3
- retry_run_surfaces_last_error_after_max_attempts: max_attempts=2,
always throws — caller's try/catch surfaces "boom"
- retry_on_codes_filters_unmatched_errors: counter == 1 after a
throw NOT in the codes list (immediate surface, no retry)
crates/manager-core/tests/migration_queue_messages.rs (4 tests):
- queue_messages_table_exists_with_expected_columns: shape +
nullability of every column
- queue_trigger_details_table_exists: shape
- queue_widens_trigger_kind_and_outbox_source_kind: triggers.kind
CHECK admits 'queue'; outbox.source_kind admits 'invoke'
- queue_messages_dispatch_index_is_partial: idx_queue_messages_dispatch
has WHERE claim_token IS NULL (guards against future migrations
accidentally dropping the partial)
All 15 tests pass clean skip when DATABASE_URL is unset. Workspace unit
suite remains at 432 passing (306 manager-core + 74 executor-core + 34
shared + 18 orchestrator-core).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PiCloud
A lightweight, self-hosted, event-driven serverless compute platform. Upload a Rhai script, get an HTTP endpoint. Designed to run on a single modest server with no idle CPU cost, and to scale out to a small cluster when you need it.
Status: Phase 1 — MVP scaffolding in progress.
The authoritative design lives in
serverless_cloud_blueprint.md.
Why
Existing serverless platforms are either cloud-locked, heavyweight, or both. PiCloud aims for the opposite end of the spectrum: one binary, one database, one reverse proxy — running on hardware you already own.
Architecture (one paragraph)
PiCloud splits into three logical services — manager (control plane: scripts, schedules, dashboard), orchestrator (per-node event ingress and dispatch), and executor (per-node Rhai sandbox) — each backed by a *-core Rust library. In MVP they run in a single process; in cluster mode they run as three binaries with one manager and one orchestrator + executor per node. Caddy fronts everything; PostgreSQL is the single source of truth.
See CLAUDE.md for working notes and serverless_cloud_blueprint.md for the full design.
Quick Start
Coming as scaffolding lands. For now:
# Rust toolchain (pinned via rust-toolchain.toml)
cargo check --workspace
# Run the all-in-one MVP binary (once main.rs is wired up)
cargo run -p picloud
Repository Layout
crates/
shared/ cross-cutting types
executor-core/ Rhai engine + sandbox
orchestrator-core/ event ingress, dispatch
manager-core/ control plane
picloud/ MVP all-in-one binary
picloud-{manager,orchestrator,executor}/ cluster-mode binaries (skeleton)
dashboard/ SvelteKit
caddy/ Caddyfile
docker/ Dockerfiles
docs/
git-workflow.md Trunk-based workflow
Contributing
See docs/git-workflow.md for the branching and commit conventions. TL;DR: trunk-based, short-lived branches, Conventional Commits, no force-pushing main.
License
TBD.