The ALGAL process VM

For a one-binary hands-on tour with a passive HTML workbench and actual SIGKILL proofs, start with the native workbench.

ALGAL can run a bounded graph as a durable named process. A process records its manifest, inputs, generation budget, checkpoint, and wake capabilities. Each CLI invocation can exit; a later invocation verifies the checkpoint and continues from its recorded effects. The durable state lives in the store, not in a resident model conversation.

This is an application VM for typed agent programs. It does not emulate a CPU, isolate an operating system, or turn a shell executor into a sandbox. The host still owns admission, credentials, tools, and storage.

Run the end-to-end demonstration

sh
bun scripts/vm-demo.ts

# Cross-runtime handoff, using an already built native executable:
bun scripts/vm-demo.ts --native ./target/debug/algal

# Retain the stores, receipts, invocation logs, and a JSON report:
bun scripts/vm-demo.ts --native ./target/debug/algal --keep --out vm-report.json

The demo script starts a new OS process for every CLI command. It creates its own temporary stores and removes them after completion unless --keep is set. There are no network actions or paid model calls.

The release-review manifest implements a release report approval workflow:

mermaid
flowchart LR
    E[Release evidence] --> D[Bounded recommendation]
    D --> P[Record proposal in mailbox]
    P --> W[Wait for approval mailbox]
    W --> C[Match release and require approval]
    C -->|approved| A[Publish to local mailbox]
    C -->|denied or mismatched| F[Complete without publication]

A digest-linked wait organism takes both the receive capability and the proposal's delivery ID. That dependency makes the proposal precede the wait; it does not rely on incidental scheduling order. The model cell sees only evidence. It receives no approval or publication capability, and its output cannot itself approve the release. The host sends the approval message. The final effect publishes a message to a local mailbox, not a production release.

Measured behavior

A successful report checks the following results rather than printing hard-coded success messages:

ObservationProcess VMFresh-run baseline
Decision adapter invocations across two actors and their restarts24
Additional decisions during resume02
Proposal messages per actor11
Approved / denied publication count1 / 01 / 0
Idle scheduler ticks and decision calls0 / 0Not measured
Completed actor receipt generations verified offline4Not measured

The baseline runs the same manifest and evidence from entry after the wake, without its execution checkpoint. It retains the same idempotent mailbox driver, so this comparison isolates repeated decision work. This is a naive restart baseline, not a comparison against another durable workflow engine. The adapter executes as a real subprocess and appends one log entry per request, but returns a deterministic fixture response. Command adapters are non-cacheable: this reuses a process checkpoint without enabling cross-run effect memoization. Two avoided fixture invocations demonstrate replay behavior; they are not model-quality, token, latency, energy, or dollar measurements.

Two main actors share a manifest and evidence but have separate mailbox capabilities: approving one leaves the other suspended, and denying the second prevents publication. A separate scenario starts two process names with byte-identical arguments, including shared capabilities. Both create a distinct proposal; a single approval is consumed by exactly one actor. This checks that process identity scopes effect idempotency while mailbox messages still have one consumer.

The script sends each approval twice with the same explicit idempotency key. It checks that the two sends return one delivery ID and that no second message remains after consumption. It also compares the recorded recommendation and proposal cells before and after resume, verifies every completed actor receipt generation, and checks that verification did not invoke the adapter.

With --native, TypeScript creates and suspends one actor, then Rust resumes it; Rust creates and suspends the other, then TypeScript resumes it. Both runtimes verify both completed actor histories from the same filesystem store. The identical-argument pair also starts in different runtimes and shares the native scheduler, adding a third handoff while checking scoped write identity. No network transport, cross-machine capability migration, or distributed coordination is implied by this handoff.

CLI and lifecycle

sh
bun cli.ts process create review workflow.algal.json \
  --args review.args.json --modules examples/vm --max-generations 4 --dir .algal
bun cli.ts process tick review --executor-cmd 'your-adapter' --dir .algal
bun cli.ts process inspect review --dir .algal
bun cli.ts process schedule --max-ticks 8 --executor-cmd 'your-adapter' --dir .algal
bun cli.ts process list --dir .algal
bun cli.ts process verify review --dir .algal

create admits the manifest closure and fixes the name, arguments, and maximum generation count. It starts at ready, generation zero. tick records dispatch intent before entering the executor; a normal result becomes suspended, complete, failed, or stuck. Every attempted generation consumes one of the declared slots, including an unsuccessful explicit wake.

schedule makes one bounded pass in name order. It runs ready processes and resumes suspended processes only when a recorded receive capability has a pending mailbox message. It skips completed processes and waiting processes with no message. It is a command that returns, not a resident background daemon. An explicit tick can retry a suspended process without a ready wake and thus consume another generation; normal polling should use schedule.

create, tick, and inspect return {digest, process}. digest addresses the complete process record in values/. The record contains a previous link through earlier state and dispatch intent. Its receipt addresses the complete receipt JSON in runs/; this storage digest includes the receipt's own intrinsic digest field, so the two digests have different meanings. verify checks the record chain and replays all completed receipt generations offline, returning {ok, generations, receipts, digest}. No live executor is needed for verification.

Verify a process away from its original host

sh
algal process export review --dir .algal > review.evidence.json
# Copy just review.evidence.json to another machine with Algal installed:
algal process verify-evidence review.evidence.json

# Demonstrate this with a crash-recovered repair and both runtimes:
bun scripts/process-evidence-demo.ts --native ./target/debug/algal

Export packages the fixed process head, immutable history, replay dependencies, and tool signatures into one bounded JSON file. The recipient can check every completed generation with Bun or the standalone native binary. Verification requires no original store, live adapter, credentials, or host configuration, and creates no runnable process. The report includes the head digest, document digest, retained status, and generation/receipt counts.

The demonstration repairs a failing scheduler through a deterministic durable adapter, recovers after killing the caller, then exports the completed process. It moves the original store, adapter and ledger away, runs fresh verifier processes in an empty directory, rejects removed or forged history, and checks that no host state was created or changed. Both runtimes verify both exports.

For custom tools, pass --tools tools.json during export; only signatures are read. verify-evidence rejects host flags. Evidence preserves recorded prompts, outputs, and capability strings, so review it before sharing. Replay establishes internal consistency, not provider truth; an independently trusted digest is needed to identify whose history was supplied. Host patch attachments, provider ledgers, and execution custody are outside this format. See the portable evidence contract.

Failure boundary and current limits

A process that stops after dispatch intent and before recording its result remains uncertain. Automatic scheduling does not retry it. Opt-in ordered journals now support explicit same-intent recovery: completed effects replay, unknown reads may be repeated within a budget, and unknown writes stop for reconciliation. Both runtimes use an OS-released SQLite lease while retaining legacy lock evidence. See the recovery contract and run bun scripts/recovery-demo.ts --native ./target/debug/algal.

The PR shepherd is a practical host application: it collects live exact-revision GitHub evidence, suspends on pending CI, and wakes from a durable timer or deduplicated event. It produces review or repair packets with no model calls in the waiting/readiness path. It currently performs read-only GitHub work. The Bun coding-job host supports explicit reconciliation through a qualified durable operation adapter; existing xcb v1 jobs do not expose that operation lookup. Provider qualification and native host parity remain separate.

Mailbox duplicate suppression applies to the supported durable mailbox operations and their idempotency keys. Host tools must implement their own idempotency and recovery semantics. ALGAL cannot guarantee exactly-once arbitrary external effects across a crash. Command executors may exercise the host process's full authority; cwd, ACP routing, type checking, and receipt hashing do not provide OS isolation.

The supervisor bounds limit the process count to 1,024, the generation count to 64, arguments at 250,000 canonical bytes, and each receipt at 16,000,000 canonical bytes. Per-run graph and mailbox bounds also apply. These are admission and execution limits, not a store-wide disk quota. There is no distributed consensus, network mailbox delivery, automatic capability transfer, or high-availability service in this implementation.

Receipts establish consistency between recorded inputs, effects, and graph execution under the admitted runtime. They do not attest that a provider was contacted, establish the truth of model output, or authenticate an approver beyond the host's control of the mailbox capability and storage.

Coding work with independent validation

The repair workflow is a second practical VM application: suspend until a host-owned coding job settles, then validate its retained patch with fixed commands. The foreground job never automatically relaunches after an uncertain result. The VM records check outcomes and both runtimes verify the history offline. Native installation and supported targets are documented in the distribution guide.