System architecture
ash is an independently buildable Rust workspace and release unit. The A3S
umbrella repository pins proven revisions as its crates/ash Git submodule; it
does not turn ash into a member of the root Cargo package.
Data flow
Why Rust
- One native binary covers six operating-system and architecture targets.
- Ownership and types express request lifetime, cancellation, transactions, and one-time permits.
- Tokio handles many I/O waits while Rayon maps splittable CPU work to a fixed multicore pool.
Send + Syncboundaries let a long-lived Harness share immutable state and schedulers safely.
Dual execution planes
Tokio I/O
Owns stdio RPC, child processes, pipes, deadlines, cancellation, update downloads, and bounded file I/O. Programs launch through executable + argv by default, never through an implicit Bash, PowerShell, or CMD layer.
Cancellation is more than sending a signal. Unix terminates and waits for the
owned process group; Windows terminates and waits for the Job Object to become
empty. exec then joins stdin, stdout, and stderr tasks before encoding the final
cancelled response.
Stdout and stderr drain concurrently in 16 KiB chunks. Each stream stays in memory through 4 MiB; after that, every original byte moves to a session-private temporary file while only a bounded head/tail sample remains for projection. The prefix and each later chunk are charged before disk write. Streams that need references commit together, so failure publishes no partial alias. Rayon hashes the complete spool through a fixed 4 MiB buffer instead of occupying a Tokio I/O worker.
Disk references support byte-range reads. Consumers that need a complete value still enforce independent 8, 64, or 128 MiB ceilings. A lease prevents early unlink; after release or session shutdown, the final lease cleans up its spool files.
Crash-orphan recovery needs no resident daemon. When a later process first creates a result store, it reclaims only an ash spool whose exact marker is at least one hour old, whose lock can be acquired exclusively, and whose entries are all recognized regular files. Active, recent, malformed, symlinked, or foreign-content roots remain untouched; deletion is file-by-file, not recursive.
Rayon CPU
Owns search preparation, hashing, diffs, reduction, and other splittable work. A fixed work-stealing pool uses available host cores without creating a pool per request.
After process pipes drain, UTF-8 projection also enters this fixed pool:
consecutive repeated lines collapse into ×N, and repeated K-line blocks into
×N#K. Unsuccessful native exits then retain fixed diagnostic windows and replace only
byte-saving gaps with ⋯N before the output budget is applied. Classification,
candidate, and verification work may run concurrently; results merge in stable
source order. Timeout or cancellation finalization uses the same bounded pool
without letting an already-cancelled request permit suppress typed termination
evidence.
Hierarchical governor
Host, session, request, and action share budgets. A wide graph cannot multiply each node's nested parallelism. Budgets cover concurrency, deadlines, bytes read, output records, and retained evidence.
Deterministic boundary
Workers may finish in any order. Responses are first merged by protocol-defined stable keys, then projected, truncated, and encoded. Identical input, capability, and filesystem state must produce byte-identical canonical ASON.
See the full repository architecture for component ownership and failure boundaries.