---
title: Architecture
description: A harness, not an agent — three layers, strict downward dependencies.
status: draft
sidebar:
  order: 1
---

Nori CLI is a harness: it never implements an agent. Every agent is an
external subprocess speaking the Agent Client Protocol, and the workspace is
organized so that rule is structural, not aspirational.

```
┌ layer 2 · frontends ────────────────────────────┐
│  nori-cli (the binary)      nori-tui (terminal) │
└───────────────────┬─────────────────────────────┘
┌ layer 1 · runtime ▼─────────────────────────────┐
│  nori-harness (sessions, transcripts, undo,     │
│  hooks)             nori-config (~/.nori/cli)   │
└───────────────────┬─────────────────────────────┘
┌ layer 0 · leaves  ▼─────────────────────────────┐
│  nori-acp-host      nori-protocol               │
│  mock-acp-agent (conformance testing)           │
└─────────────────────────────────────────────────┘
```

Rules that hold the shape: dependencies point strictly downward; the TUI
never talks to `nori-acp-host` directly (everything flows through harness
events); nothing below layer 2 knows a terminal exists; no cargo feature may
move a responsibility between crates.

## The ecosystem crates

Layer 0 is being groomed for crates.io:

- **nori-acp-host** — the host side of ACP as a standalone library: agent
  registry, subprocess spawning, JSON-RPC connection, permission plumbing.
- **nori-protocol** — the event vocabulary on top of the ACP schema.
- **mock-acp-agent** — a scriptable agent for conformance-testing hosts and
  agents.

The session transcript format is a stable, documented contract for
third-party tools (JSONL, one file per session under
`~/.nori/cli/transcripts/`).

## Fork heritage

The workspace began as a fork of OpenAI Codex. Crates prefixed `codex-*` are
inherited (sandboxing, login, protocol vocabulary, utilities) and get renamed
to `nori-*` as they're adopted; upstream syncing has ended, so inherited
crates shrink or disappear over time.
