> Documentation version: main. [HTML page](https://lukewilliamboswell.github.io/roc-blueprint/architecture.html)

<a id="understand-the-architecture"></a>

# Understand the architecture

Blueprint gives repository-owned commands declared environments and, when
asked, a managed contract for producing artifacts. This chapter defines the
model: what each part owns, the vocabulary, the stages, and the invariants that
keep the model independent of any one package ecosystem. It describes the
design Blueprint is built towards; [What ships today](#status) says what ships.

<a id="goals"></a>

## Goals and non-goals

Many tools turn a description of an environment into a working one for a
single ecosystem, and tie the project’s intent to that ecosystem’s formats and
commands. Blueprint separates the two. Shared contracts state intent,
dependency authority and execution evidence; every ecosystem-specific concern
belongs to a replaceable provider.

**The protocol is the product; providers are adapters.**

The protocol is the Spec, the Lock, the provider contract and the versioned
reports and records. A provider implements part of it for one ecosystem, or
for Blueprint’s own store.

<a id="goals-2"></a>

### Goals

- Realise the same Blueprint through different package ecosystems, or through
  Blueprint’s own store, on Linux, macOS and Windows. A machine with no
  package ecosystem installed still gets declared downloads, Roc packages,
  expected host tools and tasks from the core alone.

- Pin dependencies in a reviewed Lock that only explicit resolution changes,
  and verify pinned content before use.

- Give an artifact an explicit build contract: declared files, inputs,
  dependencies, executor and output, with capabilities checked before
  effects.

- Explain what a build consumed and what changed, from typed evidence rather
  than from reports reconstructed after the fact.

- Keep planning pure, so that any host can import the core types and perform
  the effects itself.

- Present an environment to any consumer, a shell, CI, an editor, an agent or
  a container, from one activation.

<a id="non-goals"></a>

### Non-goals

- Owning compilation, packaging, validation or release logic. The
  repository’s scripts keep it.

- Discovering dependencies hidden in arbitrary commands. A build declares
  what it consumes.

- Translating package names between ecosystems, or choosing a provider
  automatically.

- A second artifact cache. Providers own caching and substitution.


- Sandboxing tasks or the evaluation of ` Blueprint.roc `. Only a managed-build
  executor enforces isolation, and only the guarantees it advertises.

- Pinning or versioning tools the machine already has. An expected tool is
  looked for by name.

- Running workflow steps in parallel.


<a id="purpose"></a>

## What Blueprint owns

A project keeps compilation, packaging and validation logic in its own scripts.
Blueprint describes how to run them: tools, pinned inputs, selected project
files, dependencies, outputs and ordered workflows. It does not discover
arbitrary script dependencies or decide a project’s release policy.

| Owner | Responsibility |
| --- | --- |
| Repository | Commands, compilation and packaging logic, validation and release policy. |
| Configuration | Explicit environments, tasks, builds, inputs, outputs and workflow order. |
| Pure core library | Types, semantic validation, dependency relationships, request planning and evidence comparison. |
| Host | Filesystem, network and process effects described by constrained plans. The CLI is one host. |
| Provider | Native resolution, recipe preparation, execution and cache behavior for the capabilities it supports. |
| Release automation | Reviewing and admitting published artifacts, publication and advisory decisions. |

A Task is a common runner around a command. A Build adds an explicit contract
for producing an artifact from declared inputs. Both may invoke the same script;
Blueprint does not take ownership of the script’s algorithm. A Workflow orders
these operations rather than inferring their dependencies from script contents.

<a id="provider-neutrality"></a>

### Provider neutrality is an enduring constraint

Shared contracts define capabilities and guarantees independently of native
formats. A provider owns package grammar, native recipes, process arguments,
store paths and metadata. A provider need not imitate another or offer every
capability. An unsupported capability fails before effects rather than
silently weakening isolation or a reproducibility check.

A provider plays one or more roles:

- **Resolver**: chooses and records pins for the sources it owns.


- **Realiser**: materialises environment tools from those pins.


- **Executor**: prepares and runs managed builds, and states the guarantees of a
  successful build.

- **Inspector**: projects its native authority into provider-qualified identities
  and inert metadata for reports.

Source resolution, environment tools and build execution are separate roles.
Sources name their resolver; builds select a named executor. Registering a
provider that nothing selects must not change a request. An unsupported
combination is refused explicitly; neutrality does not promise arbitrary
mixed-provider composition or portable ecosystem-specific package names.

Providers own their native caches and substitution. Blueprint supplies the
selected inputs and interprets typed results; it does not implement a second
artifact cache or infer a cache hit from a successful command.

<a id="terms"></a>

## Terms

<a id="terms-data"></a>

### Configuration and data

| Term | Definition |
| --- | --- |
| Blueprint | The authored ` Blueprint.roc ` configuration. |
| Spec | Its normalized, validated, versioned description of intent. |
| Source | A declared external content origin, with explicit resolver ownership. Its reference is text the owning provider validates; the core reads no provider grammar. |
| Component | A requested package within a source’s native package universe. |
| Execution system | The operating system, architecture and platform on which an operation executes. ` Systems ` and ` BLUEPRINT_TARGET ` select it. |
| Artifact target | The platform an artifact runs on, when it differs from the execution system. Cross-compilation settings belong to the script. |
| Lock | Committed dependency authority: exact pins, declared resolution intent and the trust record of every download. |
| Trust record | For each fetched program and system: the declared URLs, the hosts that actually served the bytes, the digest, how it was obtained (computed, published, both) and the witness it was read from. |
| Artifact | A produced or fetched file or tree. Its role is stated; a location alone does not identify its content. |
| Store | Disposable local materialization of pinned or produced content. |
| Host facts | Explicitly observed machine requirements that Blueprint does not supply or pin. |
| Environment | Selected tools, fetched programs, variables and expected host requirements for execution. |
| Task | Exact command argv executed in an environment, with repository-owned behavior and side effects. |
| Build | An artifact-producing command with declared files, inputs, dependencies, executor and output. |
| Workflow | An ordered sequence of tasks, builds and nested workflows. |
| Activation | Structured search-path and environment-variable operations for entering an environment. |
| Input snapshot | Captured selected project files and their executable bits, together with the selected pinned inputs and build settings. |
| Request plan | Validated operations, dependency relationships, capabilities and permitted preparation effects. |
| Prepared build | Captured inputs and the exact provider-native recipe with its build identity, ready for execution. |
| Build result | Prepared build identity, output locations and execution evidence established by the provider. |
| Report | A rendering of typed inspection or execution evidence, with a defined input and compatibility boundary. |

<a id="identities-digests-and-locations"></a>

### Identities, digests and locations

| Term | Comparison domain |
| --- | --- |
| ` content_identity ` | Pinned input content, compared together with its provider. Opaque to consumers outside that provider’s contract. |
| ` build_identity ` | A fully prepared executable build, compared together with its provider. Includes the provider’s selected inputs and recipe semantics. A changed build identity means the request changed, not that output bytes differ. |
| File digest | Exact original file bytes under a named hashing scheme; an archive’s hash includes compression and archive metadata. |
| Tree digest | Directory content under a named tree-hashing scheme. A Nix NAR hash and an archive SHA-256 are different measurements. |
| Output digest | Measured content of a produced artifact under a named scheme. |
| ` path ` | A location of content; it is not automatically a content checksum. |

Equal content identities do not imply equal builds: commands, selected files,
tools and options also matter. Equal build identities do not prove
deterministic execution. A checked rebuild provides evidence about repeated
execution; it does not prove determinism for every execution. Consumers do not
interpret opaque provider identities or compare them across providers.

<a id="terms-stages"></a>

### Stages

| Stage | Input | Responsibility |
| --- | --- | --- |
| Evaluate | Blueprint | Produce and validate the Spec without effects. |
| Resolve | Spec, previous Lock and source responses | Explicitly select dependency pins and record verification evidence. |
| Fetch | Lock | Obtain and verify the pinned bytes without changing authority. |
| Realise | Pinned inputs and declared environment | Materialize tools and activation data. |
| Plan | Spec, Lock, request and execution system | Validate relationships and capability requirements before effects. |
| Prepare | Validated build request and selected project files | Capture inputs and obtain the exact native build recipe and identity. |
| Execute | Prepared build or task plan | Run through the selected host or provider and validate results. |
| Activate | Realized environment | Describe environment operations as data. |
| Present | Typed data | Render human output, JSON or shell syntax for a consumer. |
| Inspect | Committed authority, and evidence explicitly supplied | Derive a read-only explanation without discovering hidden dependencies. |

Preparation may fetch pinned content and write caches. It does not resolve new
pins or start the requested build or dependency builds. A provider refuses
preparation that would require unsupported evaluation effects. Execution uses
the captured inputs and native recipe; it does not silently reevaluate a
changed working tree.

<a id="terms-roles"></a>

### Pure planning and effect execution

The core library and provider adapters return data and constrained steps. They
perform no I/O. A host performs the effects: the CLI is one host, and another
application may import the same core types and execute authorized operations
itself.

Executable steps are distinct from inspectable evidence. Parsing a saved
record never authorizes executing it. Human output and JSON are renderings of
the same typed result, never independently reconstructed models or raw
provider output.

<a id="layers"></a>

## Authority, execution and release evidence

The Lock is dependency authority, not a complete build description. A build
also consumes its command, selected project files, tool options and declared
dependency builds. Captured inputs can include untracked or task-generated
files; the Lock alone cannot reconstruct them.

Every download the Lock records carries its trust record, so a reviewer of
the lock diff sees where bytes came from and who vouched for their digest.
A host the lock did not name before, whether declared or reached by redirect,
is reported before the lock is written.

Successful-build evidence records what was prepared and obtained. It is
disposable operational state, not a replacement lock. A failed build, planning
or explanation never replaces the successful baseline. Missing or incompatible
evidence means unavailable, never unchanged.

An SBOM describes selected artifact composition. Neither a lock projection nor
an SBOM is a complete executable build graph. Release admission is repository
policy: obtaining a cached result does not authorize adopting newly published
bytes, and a producer keeps its own final build identity out of its recipe
inputs so that identity cannot depend on itself.

<a id="flow"></a>

## Environment flow

The diagram shows the environment path. Builds additionally consume captured
project inputs and preparation evidence, as described above. Read-only reports
inspect committed data and any execution evidence explicitly supplied to them.

**Data flow through the environment layers**

![Data flow through the environment layers](images/blueprint-flow.png)

<a id="stage-responsibilities"></a>

### Build and workflow execution

A request validates structure and capabilities before effects. A workflow
then executes in order and stops on failure. Each build captures its inputs
when it is reached, after earlier tasks may have changed files. A repeated
build step prepares again; the provider may reuse identical results through
its cache. Blueprint never reuses a result by build name across intervening
tasks.

Selected files and dependency identities let changes flow through the declared
graph. Explanations distinguish changed declarations, changed build identities
and measured output changes. A script that reads undeclared ambient inputs
receives no guarantee beyond the executor’s enforced contract.

<a id="commands-as-flows"></a>

### Commands use the same model

Tasks use the common runner. Builds, preparation and explanations use the same
request and prepared-build objects. JSON is presentation, not the
architecture’s integration mechanism. Explanation compares a request with
recorded evidence: the last successful local build, or any record explicitly
supplied for comparison.

<a id="invariants"></a>

## Invariants

<a id="inv-1"></a>

### Invariant 1: The core is provider neutral

A shared capability has one meaning. The Spec, the Lock and the core carry no
provider concept outside namespaced hints and opaque provider-validated text:
a reference, a package name and an executor’s settings are the owning
provider’s to read. Explicit source ownership and executor selection determine
routing; nothing ambient selects a provider.

<a id="inv-2"></a>

### Invariant 2: Every stage after Resolve is a pure function of named upstream facts

Only Resolve chooses pins. Every later stage is a function of the Spec, the
Lock, the execution system, the declared host facts and the captured project
inputs, and of nothing else: no environment variable, installed tool or file
that is not one of those. Two machines with the same upstream facts plan the
same steps, prepare the same build and produce the same activation.

<a id="inv-3"></a>

### Invariant 3: Authority and evidence are separate

Pins and their verification decisions belong in the reviewed Lock. Captured
build inputs, results and measured outputs are execution evidence. Neither
silently expands or rewrites the other.

<a id="inv-4"></a>

### Invariant 4: Pinned content is verified before every use

Fetched bytes are checked against the Lock, and a tree unpacked from them is
checked against its recorded digest, on every use. A damaged tree is rebuilt
from its verified archive without a network request. Nothing in the store is
exposed through a hard link, so no consumer can write into it. Native build
caches use the provider’s own integrity contract.

<a id="inv-5"></a>

### Invariant 5: Materialization is disposable

A cache may be deleted without losing committed authority. The Lock, the
configuration and the captured project inputs together rebuild everything.

<a id="inv-6"></a>

### Invariant 6: Host dependence is explicit

Expected tools are checked, not pinned. Tasks and configuration evaluation are
not sandboxed. An isolation or reproducibility claim names the capability an
executor enforces.

<a id="inv-7"></a>

### Invariant 7: Planning is pure and effects are constrained

Providers return typed plans. Hosts execute only granted operations.
Unsupported capabilities and invalid selected relationships fail before
effects.

<a id="inv-8"></a>

### Invariant 8: Activation is data, and rendering happens at the edge

An entered environment is an Activation value: search-path directories and
variables, each naming what supplies it. The core produces it for what it
realises, a provider for what it realises, and only a presenter turns it into
shell syntax, CI files or JSON. Presenters own escaping. Machine and human
presentations share one typed result; native process output is decoded first.

<a id="inv-9"></a>

### Invariant 9: Inspection declares what it reads

Lock inspection reads committed authority without a Store or project
evaluation. Build explanation reads committed authority and the execution
evidence it is given. Missing coverage is explicit; an inspector never invents
a complete graph from reports.

<a id="inv-10"></a>

### Invariant 10: One authoritative codec; JSON is interchange

The Spec, the Lock, build records and every other authoritative or locally
kept record are S-expressions with their own major and minor versions. JSON
is for interchange and presentation only: reports a program reads, the output
of a native tool the host decodes, and files written for another tool to
consume. Nothing authoritative is read from JSON. A package version, a wire
format and a compiler version are distinct. A format a consumer does not read
is refused by name, never converted at runtime.

<a id="coupling-test"></a>

## The coupling test

An ecosystem implementing an existing capability needs an adapter, not a new
shared meaning. A consumer uses typed plans, results and their renderings,
not dependencies reconstructed from unrelated reports. A new capability may
require versioned semantics or a constrained host effect; one provider’s
syntax alone is not a reason for either.

Review a change by asking whether repository logic remains in scripts, source
ownership is explicit, execution guarantees are accurate, identity comparisons
are well-defined, and a provider could implement the capability without
another provider’s native data.

<a id="status"></a>

## What ships today

- Nix is the only complete provider: resolver, realiser, executor and
  inspector. Its managed builds run sandboxed on x86\_64 Linux.

- A Guix package source is accepted as intent and refused by every request
  until a Guix provider exists.

- Core-managed downloads, Roc packages, expected host tools, tasks and
  workflows of tasks run on every supported system, including Windows,
  without any provider.

- ` blueprint env ` renders an environment’s Activation for a shell, for
  GitHub Actions or as JSON. No other presenter ships.

- Blueprint’s own store holds verified downloads; it is not yet an executor.


- Remote execution and comparison against arbitrary historical records are
  not implemented.

