shared/invoke.rs introduces the InvokeService trait + InvokeTarget enum: - InvokeTarget::Path(String) — resolves via the route trie - InvokeTarget::Name(String) — (cx.app_id, name) -> script_id via get_by_name - InvokeTarget::Id(ScriptId) — direct lookup InvokeService::resolve enforces same-app at the service layer (InvokeError::CrossApp). InvokeService::enqueue_async writes a v1.1.9 OutboxSourceKind::Invoke row for fire-and-forget composition. Errors: NotFound, CrossApp, DepthExceeded(u32), Forbidden, Rejected, Unavailable. NoopInvokeService surfaces all calls as Unavailable for harnesses that don't wire the service. ScriptRepository gains get_by_name(app_id, name) backed by the existing (app_id, name) uniqueness constraint. Postgres impl + in-memory mock + the picloud crate's PostgresScriptRepoHandle delegate added. Services::new gains invoke: Arc<dyn InvokeService> positionally after queue. with_noop_services wires NoopInvokeService. 12 test sites threaded through. picloud/lib.rs binds NoopInvokeService at this commit boundary — the real InvokeResolver lands in commit 8. Deviation from plan (flagged for HANDBACK §7): the plan called for moving ExecutorClient + ScriptIdentity from orchestrator-core to shared so the invoke bridge could call a re-entrant variant. Re-evaluated: the bridge lives in executor-core which can hold Arc<Engine> directly, making the trait move unnecessary. Engine::execute is sync, returns ExecResponse, and shares the engine instance + per-call SdkCallCx exactly as required. AST cache reuse across invokes is a v1.2 optimization (invokes recompile each call — ms-scale cost, acceptable). 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.