Skip to content

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 Result envelope
  • 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:

  1. structured JSON is the source of truth
  2. prose and rich rendering are views over that truth
  3. every shell should consume the same Result / manifest() / events() surfaces
  4. 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.md as a primary entry point, not an afterthought
  • new features should expose structured state through Result, manifest(), and events() rather than only through UI affordances