Architecture¶
Validance's architecture is three layers, with strict boundaries between them. Each layer has a defined set of responsibilities and is prohibited from reaching into the layers above or below. This page describes each layer, what it owns, and the principle that determines what does and doesn't belong in the kernel.
┌──────────────────────────────────────────────────────────────────┐
│ LAYER 1 — SDK CONTRACT │
│ Pure declarations. ZERO side effects at construction. │
│ No database, no Docker, no file I/O. │
│ │
│ Open source · zero dependencies · serializable to JSON │
└──────────────────────────────────────────────────────────────────┘
▲
│ engine wraps SDK objects
│ via composition
│
┌──────────────────────────────────────────────────────────────────┐ ┌────────────────────────────┐
│ LAYER 2 — ENGINE │ │ REST API │
│ Orchestration · state · audit · policy enforcement. │ ◀── │ Language-agnostic │
│ Pure control plane. No Docker. No remote storage I/O. │ │ The only ingress │
└──────────────────────────────────────────────────────────────────┘ └────────────────────────────┘
▲
│ TaskSpec ↓ ↑ TaskResult
│ (in-process or HTTP)
│
┌──────────────────────────────────────────────────────────────────┐
│ LAYER 3 — WORKER │
│ Containerized execution · file staging · secret redaction. │
│ No database access. No audit emission. No policy decisions. │
└──────────────────────────────────────────────────────────────────┘
Layer 1 — SDK contract¶
The SDK is a pure declaration layer. A Task is a frozen dataclass describing a containerized unit of work; a Workflow is a frozen DAG of tasks. Constructing them performs no I/O, opens no database connection, touches no Docker socket. They are values, not handles.
This layer is the only public Python surface. It ships as validance-sdk on PyPI under Apache 2.0, with no dependencies beyond the Python standard library. The contract also serializes to JSON, which means workflows can be authored in any language that can produce a JSON object. Python is one option, not a requirement.
The SDK boundary is what makes workflow definitions independently reviewable: a workflow that imports only from validance cannot reach into engine internals, database handles, or Docker clients, by construction. A reviewer can audit a workflow without auditing the engine that runs it.
It also makes the contract layer future-portable. SDK objects are immutable values: they can be hashed for audit, shipped between engines, and reread by any future engine version that honors the same contract. A workflow definition serialized today will not silently change meaning tomorrow.
Layer 2 — Engine¶
The engine is the validated kernel. It has four responsibilities:
- Orchestration: traversing the workflow DAG, scheduling tasks, handling parallelism, propagating cancellation.
- State: persisting workflow and task execution records, resolving inter-task data references, tracking sessions across workflows.
- Audit: emitting cryptographically chained events for every state transition. Fail-closed: if the chain cannot be appended, the workflow stops.
- Policy enforcement: gating proposals against a closed-vocabulary catalog, applying approval rules, enforcing rate limits and learned policies.
The engine never executes containers, never touches remote storage, and never makes business decisions. Branching, looping, cross-workflow logic all live outside the kernel.
The engine ships as a licensed binary, not as source. This is what allows the kernel to be validated once as a frozen artifact: a customer revalidates configuration and deployment against a fixed validation package, instead of re-validating engine internals on every release.
Layer 3 — Worker¶
The worker is the execution plane. It receives a TaskSpec (a frozen description of one task to run), launches a container, stages files in and out by content hash, runs the command, captures the result, and returns a TaskResult. That is the entire interface.
The worker has no database connection, never emits audit events, and makes no policy decisions. It can run in-process with the engine or as a separate process behind an HTTP endpoint. When it runs separately, the boundary is physical: the engine has no Docker socket, the worker has no database credentials.
This separation is what makes execution pluggable. A Validance deployment can run workers in a Kubernetes cluster, on a fleet of edge devices, or beside the engine in a single container, without changing the engine.
REST API¶
The REST API is the only ingress. Every external action goes through HTTP: triggering a workflow, submitting a proposal, resolving an approval, querying audit, retrieving artifacts. There is no Python-only side door.
This is what makes Validance language-agnostic. Anything that can speak HTTP can orchestrate Validance workflows: a Go service, a TypeScript agent runtime, a bash script in a CI job, a cron job in a regulated lab. The full surface is documented at api.validance.io/docs.
Boundary discipline¶
The boundaries are not advisory. They are enforced at the import level: workflow definitions cannot import from the engine; the engine cannot reach the worker except through the worker interface; the worker cannot touch the database.
This is what makes the kernel validatable as a frozen artifact. A reviewer can verify that workflow code cannot bypass approval gates, that the worker cannot tamper with audit, and that the engine cannot leak secrets, all without re-validating every workflow change. The validation pattern this enables: customers validate their configuration and deployment against a fixed kernel, instead of re-validating engine internals on every release.
The kernel-caller split¶
The kernel executes; the caller orchestrates. Validance does not implement business workflows. It executes contracts. Branching, loops, retries with modified inputs, cross-workflow sequencing all live in the caller, which speaks to Validance over the REST API. The kernel guarantees how a contract executes; the caller owns what to execute and when. This split is what lets the engine remain a fixed validated artifact, while business logic stays flexible and replaceable. See Agent substrate for how this composition gates LLM-driven workflows.
Agent substrate¶
An LLM agent never executes anything directly in Validance. It proposes; the kernel decides whether to allow. The agent gets to be probabilistic; the execution layer stays deterministic. The composition that makes this work, in three clusters:
Bounded action. What an agent can propose, whether it's allowed, and what credentials it runs with.
- Catalog: a closed vocabulary of allowed actions. Arbitrary code execution is out of scope by construction.
- Approval gate: three tiers (auto-approve, human-confirm, always-deny) with fail-closed timeouts. Every decision is recorded in the audit chain.
- Learned policy: patterns auto-approved or denied from prior human decisions, with a 30-day TTL refreshed on use. Deny always wins. The gated experience improves with use but never silently expands.
- Secret store: tasks reference credentials by name, not by value. The engine resolves the name at execution time; the agent never sees the credential and the audit log never records it.
Resource discipline. What an action costs, and how often it can run.
- Rate limits: per-template execution caps, enforced before the proposal runs.
- Budgets: per-session token and cost ceilings. Overruns are treated as task failures and recorded as such.
State and continuity. How a multi-turn agent stays coherent across executions.
- Continuations: when an agent extends a plan, the new tasks become a new validated workflow linked to the prior one via
continued_from. The DAG of any single workflow stays immutable; the agent's trajectory is the chain of validated continuations. There is no runtime DAG mutation. - Persistent workers: long-lived containers for tasks that need warm context across agent turns.
- Sessions: a correlation handle that ties continuations together for audit and budget queries, not a stateful server-side context store.
- Streaming: token-by-token output via callback for LLM-driven tasks. The audit record captures the complete response, not fragments.
Every proposal, approval, denial, policy change, and execution lands in the same dual hash chain that anchors the rest of the kernel. The agent's full trajectory is independently verifiable.
For SDK usage, see the SDK reference. For the wire format, see api.validance.io/docs.