---
title: "Agent-Native Code UI"
description: "Build and customize Agent-Native Code surfaces with the shared UI package, Desktop host bridge, and CLI run store."
---

# Agent-Native Code UI

> **Who is this for:** host authors building or customizing a coding-workspace
> surface (CLI, Desktop, or a browser template) on the shared Code UI package.

## Which coding doc do I want? {#which-doc}

| You want to…                                                               | Use                                    |
| -------------------------------------------------------------------------- | -------------------------------------- |
| Render a Claude-Code/Codex-style **coding workspace UI**                   | **Agent-Native Code UI** (this page)   |
| Run Claude Code / Codex / Pi **as the agent**, with their own loop + tools | [Harness Agents](/docs/harness-agents) |
| Swap the backend that runs the agent's **`run-code` tool**                 | [Adapters](/docs/sandbox-adapters)     |
| Wrap a CLI tool (`gh`, `ffmpeg`) for the agent to call                     | [Adapters](/docs/sandbox-adapters)     |

Agent-Native Code is the Agent-Native coding surface: a local Claude Code/Codex-style workspace for coding sessions, slash commands, migrations, audits, transcripts, run controls, and follow-ups. A bare `npx @agent-native/core@latest` command opens this workspace; `npx @agent-native/core@latest code` is the explicit subcommand for the same experience.

There are three layers:

- **CLI**: `npx @agent-native/core@latest` and `npx @agent-native/core@latest code` start, resume, inspect, and stop runs.
- **Desktop**: the left-sidebar Code tab adds native terminal launch, app webviews, and desktop deep links while using the same run model.
- **Shared UI**: `@agent-native/code-agents-ui` renders the reusable React surface.

<Diagram id="doc-block-130r10o" title="Three layers over one run store" summary={"CLI, Desktop, and the shared UI are different surfaces over the same file-backed run store and executor; hosts adapt it via the CodeAgentsHost contract."}>

```html
<div class="diagram-layers">
  <div class="diagram-row">
    <div class="diagram-card" data-rough>
      <span class="diagram-pill">CLI</span
      ><small class="diagram-muted">start · resume · status · stop</small>
    </div>
    <div class="diagram-card" data-rough>
      <span class="diagram-pill">Desktop</span
      ><small class="diagram-muted"
        >native terminal · webviews · deep links</small
      >
    </div>
    <div class="diagram-card" data-rough>
      <span class="diagram-pill accent">Shared UI</span
      ><small class="diagram-muted">@agent-native/code-agents-ui</small>
    </div>
  </div>
  <div class="diagram-arrow diagram-muted" aria-hidden="true">&darr;</div>
  <div class="diagram-panel center" data-rough>
    <span class="diagram-pill">CodeAgentsHost</span
    ><small class="diagram-muted">host contract</small>
  </div>
  <div class="diagram-arrow diagram-muted" aria-hidden="true">&darr;</div>
  <div class="diagram-box" data-rough>
    File-backed run store + executor<br /><small class="diagram-muted"
      >@agent-native/core/code-agents</small
    >
  </div>
</div>
```

```css
.diagram-layers {
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: center;
}
.diagram-layers .diagram-row {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  justify-content: center;
}
.diagram-layers .diagram-card {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 12px 16px;
}
.diagram-layers .diagram-arrow {
  font-size: 22px;
  line-height: 1;
}
.diagram-layers .center {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}
```

</Diagram>

The current split is intentionally converging: the standard agent sidebar and Agent Teams run on the core `run-manager` lifecycle, while Agent-Native Code uses local long-running sessions backed by the file-based Code run store and the shared background-run controller vocabulary.

The shared UI is host-driven. It does not know whether it is running in Electron, a browser template, or a future hosted shell. Hosts provide a `CodeAgentsHost` implementation.

```ts
import { CodeAgentsApp, type CodeAgentsHost } from "@agent-native/code-agents-ui";
import "@agent-native/code-agents-ui/styles.css";

const host: CodeAgentsHost = {
  listRuns: (goalId) => listRunsSomehow(goalId),
  listCodePacks: () => listCodePacksSomehow(),
  createRun: (request) => createRunSomehow(request),
  subscribeTranscript: (request, callback) =>
    subscribeToTranscriptSomehow(request, callback),
  readTranscript: (request) => readTranscriptSomehow(request),
  appendFollowUp: (request) => appendFollowUpSomehow(request),
  updateRun: (request) => updateRunSomehow(request),
  retryRun: (request) => retryRunSomehow(request),
  rerunRun: (request) => rerunRunSomehow(request),
  controlRun: (goalId, runId, command, permissionMode) =>
    controlRunSomehow({ goalId, runId, command, permissionMode }),
};

export function CodeSurface() {
  return <CodeAgentsApp apps={[]} host={host} />;
}
```

Hosts can mix run sources in the same list. Local Agent-Native Code sessions
can appear next to Agent Teams or other background-run adapters as long as each
entry normalizes to `CodeAgentRun`. When a host supplies `sourceLabel`,
`source`, or `kind`, the hub renders a small source label such as "Local Code"
or "Agent Teams" in the run list and selected-session header. Omit those fields
for a single-source surface; the empty state and base layout stay unchanged.

## Desktop Host

Desktop uses the shared UI but keeps privileged capabilities in Electron:

- opening a native terminal
- rendering optional app-backed surfaces with `AppWebview`
- handling `agentnative://open?...` links
- tracking local run processes
- recording steering vs queued follow-ups for active runs
- retrying and re-running native Code sessions, including `/migrate` and `/audit`
- stopping a process it started

That separation matters. The UI can be reused by templates, but native process control should stay in Desktop or CLI.

## Codex CLI Auth {#codex-cli-auth}

Agent-Native Code can use a local Codex CLI login instead of an OpenAI API key.
Install the Codex CLI on your `PATH`, sign in once, then restart Desktop or the
Code UI if it was already open:

```bash
npm install -g @openai/codex@latest
codex login
codex login status
```

Desktop and the CLI read `codex login status` and run `codex exec`, so they
reuse whatever ChatGPT subscription or API-key auth your installed Codex CLI
reports. This is separate from the `@ai-sdk/harness-codex` package used by
[Harness Agents](/docs/harness-agents); the harness adapter can copy local
Codex CLI auth into a trusted sandbox only when `codexCliAuth: true` is
explicitly enabled.

## Browser Host

The old hidden `code` template has been removed. To build a browser-hosted Code surface, create a normal app and mount the shared UI package with a host implementation:

```bash
npx @agent-native/core@latest create my-code-ui --template chat
cd my-code-ui
pnpm add @agent-native/code-agents-ui
pnpm install
pnpm dev
```

Your host can wrap the local run store through normal actions. These are
host-owned actions you would define yourself — they are not shipped framework
actions — mapping each `CodeAgentsHost` method onto the run store, for example:

- a "list runs" action backing `listRuns`
- a "list code packs" action backing `listCodePacks`
- a "create run" action backing `createRun`
- a "read transcript" action backing `readTranscript`
- an "append follow-up" action backing `appendFollowUp`
- an "update run" action backing `updateRun`
- a "control run" action backing `controlRun`

Each one calls `@agent-native/core/code-agents`, which exposes the same
file-backed run store and executor used by the CLI.

## CLI Run Controls

The top-level CLI behaves like Claude Code or Codex:

```bash
npx @agent-native/core@latest
npx @agent-native/core@latest "fix the failing auth tests"
npx @agent-native/core@latest code
```

Use `npx @agent-native/core@latest code` when you want the explicit namespace. Built-in slash
goals and project commands can run inside the interactive workspace or directly
from the shell:

```bash
npx @agent-native/core@latest code /migrate ./legacy-app --emit ./migration-dossier
npx @agent-native/core@latest code /audit --url https://example.com
npx @agent-native/core@latest code /release-check
```

Here `/migrate` and `/audit` are built-in goals (the built-in goals are
`task`, `migrate`, and `audit`). `/release-check` is shown as an example of a
project command — defined in `.agents/commands/`, not a built-in goal. Project
commands come from `.agents/commands/*.md`; project skills come from
`.agents/skills/*/SKILL.md`. The control commands operate on the same run
records that the Desktop Code tab and shared UI display:

```bash
npx @agent-native/core@latest code list
npx @agent-native/core@latest code status --last
npx @agent-native/core@latest code attach --last
npx @agent-native/core@latest code logs --last
npx @agent-native/core@latest code resume --last
npx @agent-native/core@latest code stop --last
npx @agent-native/core@latest code ui
```

`resume` appends context and continues a run, `status` reports the latest run
state, `stop` asks the active controller to halt work, and `ui` opens the local
Code surface. These are run controls, not a separate implementation path. If a
high-risk command pauses for approval, `approve --last` runs that one pending
command and then points you back to resume the session.

Run modes make editing policy explicit per session:

| Mode          | CLI flag | Behavior                                                                                                 |
| ------------- | -------- | -------------------------------------------------------------------------------------------------------- |
| **Plan mode** | `--plan` | Inspect, plan, and explain without writing files or running mutations.                                   |
| **Auto mode** | `--auto` | Edit files, run checks, and pause only for genuinely destructive file, git, publish, or data operations. |

Auto mode is the default for local Agent-Native Code sessions. Use Plan mode for
assessment, architecture, review, or any task where you want a proposal before
edits.

For cross-surface lists, dashboards, or monitoring panes, prefer the shared
background-run exports from `@agent-native/core/code-agents` over reading Code
run files directly. They normalize local Code sessions into the same vocabulary
used by hosted background work: run id, status, cwd, needs-input,
needs-approval, transcript events, and artifact root.

Hosted Agent Teams are also exposed from the agent chat route for browser
hosts that need a Code hub-compatible list without direct server imports:
`GET /_agent-native/agent-chat/runs/list?goalId=agent-team` returns
`{ status: "ok", goalId, runs }`, where each run includes `kind`,
`source`, `sourceLabel`, `status`, `title`, timestamps, and task metadata.
`GET /_agent-native/agent-chat/runs/:id/background-events` returns the
shared background transcript events for an Agent Teams run.

Adapter-backed hosts may also attach source metadata:

```ts
{
  id: run.id,
  goalId: "task",
  title: run.title,
  source: "agent-teams",
  sourceLabel: "Agent Teams",
  kind: "background-run",
  status: run.status,
  createdAt: run.createdAt,
  updatedAt: run.updatedAt,
}
```

## Run Store

Local Agent-Native Code runs are stored at:

```text
~/.agent-native/code-agents
```

Set `AGENT_NATIVE_CODE_AGENTS_HOME` to isolate a template or test run store.

```bash
AGENT_NATIVE_CODE_AGENTS_HOME=./data/code-agents pnpm dev
```

## Host Contract

`CodeAgentsHost` has a small required core; everything else is an optional
method a host can skip:

| Method                                                | Purpose                                                |
| ----------------------------------------------------- | ------------------------------------------------------ |
| `listRuns(goalId?)`                                   | List sessions for the selected goal                    |
| `listCodePacks?()`                                    | List `.agents/commands` and `.agents/skills`           |
| `createRun(request)`                                  | Start a new run                                        |
| `subscribeTranscript?(request, callback)`             | Push transcript updates to the shared conversation     |
| `readTranscript(request)`                             | Poll transcript events as a compatibility fallback     |
| `appendFollowUp(request)`                             | Add a follow-up, either steering active work or queued |
| `updateRun(request)`                                  | Update mode or run metadata                            |
| `retryRun?(request)`                                  | Retry the selected run in place                        |
| `rerunRun?(request)`                                  | Start a new run from a previous prompt                 |
| `controlRun(goalId, runId, command, permissionMode?)` | Resume, approve, refresh, or stop                      |
| `openTerminal?(request)`                              | Optional native terminal hook                          |

Browser hosts should return a graceful `openTerminal` error instead of trying to emulate native terminal launch.

Desktop also implements further optional methods for native-only affordances —
project picking (`listProjects`, `selectProject`, `chooseProject`), model
listing, computer-setup actions, Codex login, and remote-connector
pairing/status. A browser host can omit all of them; the shared UI hides the
corresponding controls when a method isn't implemented. See
`CodeAgentsHost` in `@agent-native/code-agents-ui` for the full, current list.

## Shared Composer

Agent-Native Code uses the same `AgentComposerFrame` + `PromptComposer` /
`TiptapComposer` stack exported from `@agent-native/core/client/composer` as the
framework agent sidebar. Do not fork a separate
textarea, coding-tool picker, upload picker, voice button, model picker, or Enter-to-submit
implementation for Code-like surfaces. If a host needs one extra control, pass
it through the shared composer extension points so the sidebar, Code UI, and
Brain chat keep the same interaction model and visual field.

Brain's Ask route uses `AgentChatSurface`, which is already backed by the
standard sidebar composer. Code uses `PromptComposer` directly because the host
owns run creation, transcripts, and follow-up delivery.

## Shared Coding Tools

The sidebar development agent and Agent-Native Code both use the same minimal
coding-tool profile: `bash`, `read`, `edit`, and `write`. `bash` is the default
for listing/searching files, running tests, and invoking project CLIs; `read`
shows line-numbered file slices; `edit` applies exact text replacements; and
`write` is reserved for new files or intentional full rewrites. Older aliases
such as `shell`, `read-file`, `write-file`, `list-files`, and `search-files`
are compatibility-only and are not part of the default advertised surface.

Code-specific UI belongs around the composer, not inside a forked chatfield. The
shared Code UI may add slots for:

- Auto / Plan mode controls.
- The selected cwd, project picker, and run metadata.
- Host-only affordances such as opening a terminal.

Everything else stays in the shared composer: attachments, references, slash and
skill insertion, pasted-text handling, voice dictation, drafts, keyboard
shortcuts, and submission semantics.

The user-facing transcript should stay conversational. Code hosts normalize raw
transcript/status/tool events into the shared conversation renderer: assistant
text coalesces into one turn, low-signal lifecycle noise stays out of the main
surface, and tool activity renders as compact inline summaries with details
available when needed.

## Slash Commands

Agent-Native Code treats migration as a capability, not a separate app category. `/migrate` can be a built-in goal, a project command, or a custom instruction pack on top of the same host contract.

### Migrating to Agent-Native with `/migrate` {#migrate}

`/migrate` is the built-in goal for moving an existing app, URL, or described product into Agent-Native. It is a slash goal in the Code workspace — not a separate template to scaffold and not a one-off product — so it shares the same session store, transcript, run controls, and Desktop hub as every other Code session, and you can resume, attach to, inspect, and stop it the same way.

<Diagram id="doc-block-1lox5dw" title="/migrate is a Code session, not a separate app" summary={"A path, URL, or description goes in; the run shares the same store, transcript, and controls as every other Code session, and can emit a portable dossier."}>

```html
<div class="diagram-migrate">
  <div class="diagram-col">
    <div class="diagram-pill">./local-app</div>
    <div class="diagram-pill">https://example.com</div>
    <div class="diagram-pill">--describe \"...\"</div>
  </div>
  <div class="diagram-arrow diagram-muted" aria-hidden="true">&rarr;</div>
  <div class="diagram-panel center" data-rough>
    <span class="diagram-pill accent">/migrate goal</span
    ><small class="diagram-muted">same store · transcript · run controls</small>
  </div>
  <div class="diagram-arrow diagram-muted" aria-hidden="true">&rarr;</div>
  <div class="diagram-col">
    <div class="diagram-box" data-rough>Migrated app</div>
    <div class="diagram-pill ok">--emit dossier</div>
  </div>
</div>
```

```css
.diagram-migrate {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.diagram-migrate .diagram-col {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.diagram-migrate .diagram-arrow {
  font-size: 22px;
  line-height: 1;
}
.diagram-migrate .center {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}
```

</Diagram>

```bash
npx @agent-native/core@latest code /migrate ./my-next-app --out ../migrated-app
npx @agent-native/core@latest code /migrate https://example.com --describe "marketing site plus dashboard"
npx @agent-native/core@latest code /migrate --describe "A Rails admin app with reports and CSV imports" --emit
npx @agent-native/core@latest migrate ./my-next-app --out ../migrated-app   # shortcut into the same goal
```

Local source paths are read-only; generated output must live outside the source tree. Use `--emit <dir>` to write a portable migration dossier (`AGENTS.md`, `MIGRATION_PLAYBOOK.md`, assessment, and an `ir.json` inventory when available) and hand it to another coding agent instead of opening the internal run surface. `/migrate` reuses the framework's normal credentials system — there is no migration-specific key store. The `@agent-native/migrate` package exposes a reusable engine (`createMigrationRun`, `discoverMigration`, `planMigration`, source/target adapters) for custom workflows.

<Callout id="doc-block-mig8ban" tone="info">
  The legacy hidden `migration` detail app has been removed. Use the Code
  workspace, the Desktop Code tab, or an emitted dossier as the supported
  surfaces.
</Callout>

Project-specific commands live in:

```text
.agents/commands/*.md
```

Use these for team workflows such as release checks, migration variants, framework upgrades, or audits.

Project skills live in:

```text
.agents/skills/*/SKILL.md
```

When the host implements `listCodePacks`, the shared UI shows project commands and skills in the rail. Command rows insert `/<command>`, and skill rows insert a focused “Use the `<skill>` skill…” prompt so the rail stays actionable. The built-in slash goals `/migrate` and `/audit` stay reserved for the global Agent-Native Code controls, as do run-control names such as `status` and `resume` — those are subcommands invoked without a slash (`npx @agent-native/core@latest code status`, `npx @agent-native/core@latest code resume`), not slash goals.

Do not create a separate slash-command registry for a new Code host. Project
commands and skills are discovered from `.agents/commands/*.md` and
`.agents/skills/*/SKILL.md`; the UI should render those packs and insert prompts
through the shared composer.

## Background Agent Run-Manager

Background coding-agent work should reuse the same run-manager foundation as the
rest of Agent-Native:

- Use the Code run store/executor for local Code sessions.
- Use the shared background-run adapter/foundation when a surface needs to list,
  inspect, or bridge local Code sessions alongside other background work.
- Use core `run-manager` for hosted agent runs so streams, aborts, heartbeats,
  resumability, soft timeouts, and stuck-run cleanup behave consistently.
- Use `agent-teams` / `spawnTask()` when the UI is delegating work to a
  background sub-agent from a normal app chat.

Do not add a parallel background-agent runner just because a new surface needs a
different layout. Build a host adapter or UI slot on top of the shared
run-manager foundation instead.

## Follow-Ups

Follow-ups on active runs support two delivery modes:

- Pressing Enter or clicking send records an immediate steering prompt that the
  active runner applies at the next safe continuation point.
- Pressing Cmd+Enter on macOS or Ctrl+Enter elsewhere queues the prompt to run
  after the current turn finishes.

Inactive runs keep the compatible behavior: the follow-up is appended and the run resumes immediately.

That gives Code the same user-facing two-way messaging shape as Agent Teams:
the user can keep talking to active work, but execution only consumes that
message at a safe continuation point. If a runner cannot steer immediately, it
must persist the follow-up as queued work rather than dropping or racing it.

## Remote Dispatch

Desktop can expose the local Code Agent runner to a deployed Dispatch relay so a
phone or Telegram chat can start, monitor, and continue sessions while the
computer is awake.

The connection is outbound-only from Desktop:

1. Desktop pairs with Dispatch and stores a device token locally.
2. Desktop long-polls `/_agent-native/integrations/remote/poll`.
3. Mobile Sessions and Telegram `/code` enqueue commands in the relay database.
4. Desktop claims commands, drives the local run store, and posts results and
   transcript events back to Dispatch.
5. Mobile reads `hosts`, `runs`, and `transcript` from Dispatch; it never talks
   directly to the desktop.

<Diagram id="doc-block-1egkjzi" title="Remote Dispatch is outbound-only" summary={"Mobile never talks to the desktop directly. Desktop long-polls Dispatch, claims commands, drives the local run store, and mirrors results back."}>

```html
<div class="diagram-remote">
  <div class="diagram-node" data-rough>
    Mobile / Telegram<br /><small class="diagram-muted">/code · sessions</small>
  </div>
  <div class="diagram-arrow diagram-muted" aria-hidden="true">&rarr;</div>
  <div class="diagram-box" data-rough>
    Dispatch relay<br /><small class="diagram-muted"
      >hosts · runs · transcript</small
    >
  </div>
  <div class="diagram-arrow diagram-muted" aria-hidden="true">&larr;</div>
  <div class="diagram-node" data-rough>
    Desktop<br /><small class="diagram-muted"
      >long-polls · claims · drives run store</small
    >
  </div>
</div>
```

```css
.diagram-remote {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.diagram-remote .diagram-arrow {
  font-size: 22px;
  line-height: 1;
}
```

</Diagram>

The canonical remote relay endpoints are:

<Endpoint id="doc-block-27ghbf" title="Desktop claims queued work" method="POST" path="/_agent-native/integrations/remote/poll" summary="Desktop long-polls the relay to claim enqueued commands" auth="Desktop device token" responses={[
  {
    "status": "200",
    "description": "Claimed commands for this host (may be empty after the long-poll window)."
  }
]}>

Outbound-only from a paired Desktop host. Desktop authenticates with its device token and claims work that mobile or Telegram enqueued.

</Endpoint>

| Method     | Route                                                    | Caller          | Purpose                                     |
| ---------- | -------------------------------------------------------- | --------------- | ------------------------------------------- |
| `POST`     | `/_agent-native/integrations/remote/register`            | Desktop session | Pair a desktop host and return a token once |
| `GET`      | `/_agent-native/integrations/remote/hosts`               | Mobile/session  | List paired hosts                           |
| `DELETE`   | `/_agent-native/integrations/remote/devices/:id`         | Mobile/session  | Revoke a paired host                        |
| `POST`     | `/_agent-native/integrations/remote/devices/:id/revoke`  | Mobile/session  | Revoke a paired host                        |
| `POST/GET` | `/_agent-native/integrations/remote/poll`                | Desktop token   | Claim work                                  |
| `POST`     | `/_agent-native/integrations/remote/result`              | Desktop token   | Complete or fail work                       |
| `POST`     | `/_agent-native/integrations/remote/run-events`          | Desktop token   | Mirror transcript events                    |
| `GET`      | `/_agent-native/integrations/remote/runs`                | Mobile/session  | List sessions                               |
| `GET`      | `/_agent-native/integrations/remote/runs/:id`            | Mobile/session  | Read session summary                        |
| `GET`      | `/_agent-native/integrations/remote/runs/:id/transcript` | Mobile/session  | Read mirrored transcript                    |
| `POST`     | `/_agent-native/integrations/remote/push/register`       | Mobile/session  | Register Expo/mobile push token             |

Telegram uses the same relay through Dispatch. Supported commands are:

```text
/code <prompt>
/code list
/code status <run>
/code continue <run> <text>
/code approve <id>
/code deny <id>
/code stop <run>
```

## Styling

Import the package stylesheet:

```ts
import "@agent-native/code-agents-ui/styles.css";
```

The stylesheet uses the same shadcn-style HSL custom properties as the templates and Desktop shell. Prefer changing tokens or small class overrides in the host app before forking the shared UI.

## Limits

The browser template is local-first. It can start and resume runs while its local Node server is alive. For native process lifecycle, terminal launch, and app webviews, use Desktop.

## What's next

- [**Harness Agents**](/docs/harness-agents) — run Claude Code, Codex, or Pi
  as the agent instead of the built-in Code loop.
- [**Adapters**](/docs/sandbox-adapters) — swap the sandbox or CLI backend
  behind the agent's `run-code` tool.
- [**Agent Teams**](/docs/agent-teams) — the same run-manager foundation for
  delegating work to background sub-agents.
- [**Durable Background Runs**](/docs/durable-background-runs) — the hosted
  execution model behind long-running work.
