ADR-0003: Preserve a Machine-First Contract
- Status: Accepted
- Date: 2026-05-19
Context
runex is driven by multiple possible shells:
- CLI
- human-facing product UI
- autonomous agents
- background watchers
These consumers need the same truth surface. If each consumer gets its own derived contract, the system splits into multiple semantic worlds:
- one hidden in app views
- one inferred by agents
- one encoded in CLI behavior
The project already exposes a unified interface:
- one
Resultenvelope - one
manifest()introspection surface - one closed event vocabulary
- one resumable event stream
The question is whether this should remain the primary contract, or be treated as an implementation detail beneath more shell-specific APIs.
Decision
We preserve runex's external contract as machine-first.
That means:
- structured JSON is the source of truth
- prose and rich rendering are views over that truth
- every shell should consume the same
Result/manifest()/events()surfaces - no consumer should have to scrape source code, UI text, or human prose to understand what exists or what happened
The preferred framing is:
the contract is first for machines, then rendered for humans
This is not an anti-UI decision. It is a decision that the UI is a shell over the same contract the agent sees.
Why
runex's value depends on one shared semantic world.
If the contract stops being machine-first, the most likely failures are:
- product shells invent hidden semantics not visible to agents
- agents reconstruct behavior from prose or brittle conventions
- CLI and UI diverge in what they expose
- eventful observability becomes optional rather than guaranteed
A machine-first contract prevents that drift by making introspection and observation first-class runtime responsibilities.
Alternatives Considered
1. Human-first UI, machine support added later
Rejected.
Reason:
- it produces a product-specific semantic center
- agent support becomes a reverse-engineering problem
- the system risks split-brain truth between UI and runtime
2. Separate app API and agent API
Rejected.
Reason:
- two contracts inevitably drift
- the same business event would need parallel representations
- architecture discipline gets weaker with every shell-specific surface
3. Rich CLI output as the primary interface
Rejected.
Reason:
- text output is for humans, not durable consumers
- agents should never need to parse prose to operate the system
- rendering should be downstream of structured data, not its substitute
Consequences
Positive
- keeps agents and UI shells on one truth model
- makes
manifest()the durable introspection center - makes the event stream a first-class operational surface
- simplifies product shells: they render and orchestrate rather than invent domain semantics
Negative / Tradeoffs
- some user-facing product flows may feel less "native" at first because they are built on a stricter contract
- the runtime must carry the burden of high-quality structured errors and event semantics
We accept this cost because contract discipline is category-defining for the system.
Implications
- future desktop apps should be designed as shells over the runtime contract
- docs should continue treating
agent-contract.mdas a primary entry point, not an afterthought - new features should expose structured state through
Result,manifest(), andevents()rather than only through UI affordances