# GUIDE — The agent harness as a surface

**Status:** law — v1, 2026-08-03
**Applies to:** every MCP tool response — Claude Code, Claude desktop, and any other client
**Parent:** [`GUIDE.interface-principles.md`](GUIDE.interface-principles.md)
**Visual reference:** [`../mcp/`](../mcp/) · **Mechanism:**
`relay-platform/docs/DESIGN-NOTE.mcp-rich-display.md` · **Contract:** `SPEC.mcp.md`

The harness is where a large share of real Relay usage happens. It is the **adjacent priority
interface** to mobile, not an API with nice strings — and it is designed, not emitted.

It has no pixels and it still has hierarchy, rhythm, and restraint. The same governing principle
holds: **display weight is proportional to information value.**

---

## Two readers, always

Every response is read twice:

1. **The agent** — needs to know what happened and what it can do next.
2. **The person over its shoulder** — needs to recognise the result without decoding it.

A response that serves only the first is a state dump. One that serves only the second is prose
the agent can't act on. Compose for both.

---

## The rules

### 1. Answer, then evidence

Lead with what happened. Detail comes after, and only what's needed.

> ✅ "Sent — Code `HAVVPX`, claimable once, expires in 7 days."
> ❌ A JSON object with 40 fields, three of which matter.

### 2. Cost less context than you save

**A response that blows the context window is a defect, not a big result.** This is the harness's
version of "content below the fold": an orientation call that costs more than it returns teaches
agents to skip it, and an agent that skips orientation guesses.

Rules:

- Lists return **counts plus a top slice**, never everything.
- Bulk data offers a **handle** — an id, a link, a follow-up call — not the payload.
- Depth is **opt-in** via a parameter, not the default.
- If a response routinely exceeds a few thousand tokens, redesign the shape.

*(Recorded as EXP-001: `relay_context`, the documented once-per-session bootstrap, returned ~98k
characters — large enough that the client spilled it to a file instead of into context.)*

### 3. Never make anyone decode an identifier

Every id appears **with its name**. `pc_9b8b6183e706` alone is a failure; *"Relay Experience
(`pc_9b8b6183e706`)"* is fine. If the reader has to make a second call to find out what the first
one returned, the first was underspecified.

### 4. Verbs mean one thing

Relay has two opposite directions and they are never blurred:

| Direction | Verb | Never |
|---|---|---|
| Pull context **in** | claim / receive / relay in | "handoff" |
| Give context **away** | handoff / send / package | "claim" |

A tool's name, its description, and what it does must agree. Ambiguity here is not a copy problem;
it causes wrong writes.

### 5. Gates where the stakes justify them

Two-step confirmation is protection, and it is spent by overuse — a gate that fires on
low-stakes calls trains agents and users to confirm reflexively, which disarms it for the call
that mattered.

- Gate: irreversible, outward-facing, or destructive writes.
- Don't gate: reads, drafts, and anything trivially undone.
- A gate always says **what will happen**, not just "confirm?".

### 6. Failures and empties are answers too

- An error names the next thing to try — never a bare code or a traceback.
- An empty result says *empty*, and says what would change it. "No relays match `tag:mobile`" beats
  `[]`.
- Never return success shaped like failure, or the reverse.

### 7. Progressive display, honest fallback

Rich display is an enhancement, never a dependency. The plain-text tier must carry the full
meaning on its own — a client that can't render cards is a supported client, not a degraded one.
Mechanism and per-harness config live in `relay-platform`; **what's worth showing** is decided
here.

---

## Composition

Even in plain text, structure carries meaning:

- **One idea per line.** A wall of prose is as unreadable as a wall of JSON.
- **Codes always mono and letter-spaced** — same law as the UI.
- **Time relative and honest** — "seen 7h ago", not a raw timestamp.
- **A card is framed and consistent**, so the reader recognises the shape before reading it.
- **Never more than one call to action** in a response. If there are three next steps, name the
  one that's most likely and offer the rest as options.

---

## What the harness must never do

- Dump raw database rows, internal ids without names, or full object graphs
- Instruct the user to do something the client can't do (the harness twin of hover-only
  affordances)
- Return a nudge or prompt as though it were the result of what was asked
- Bury an error inside a successful-looking response
- Repeat the same card unchanged on every call in a session

---

## Checklist

- [ ] Answer first, evidence second
- [ ] Response cost proportionate to value; lists are counts + slice
- [ ] Every id accompanied by a name
- [ ] Verb direction unambiguous
- [ ] Gates only where stakes justify, and they say what will happen
- [ ] Errors and empties name the next step
- [ ] Plain tier carries full meaning
- [ ] Codes mono; time relative

---

## Framework note

Every rule here except the claim/handoff vocabulary is generic MCP-surface design —
`framework-candidate`, and directly relevant to **Launchpad Phase 3 — Integration Surface**, which
takes the MCP scaffolding into core. Any product built on Launchpad will ship tools with the same
two readers and the same context budget.
