ADL (Agent Definition Language) is a YAML format for declaring agent types and multi-step workflows. Place files in ~/.nui/agents/ to make them selectable in the nui UI under Installed agents.
Echo-specific docker/remote walkthroughs (with runnable harness servers) live in the nui harness-examples directory.
Each agent requires an id (stable identifier used by the CLI and sessions) and a name (display label). The UI shows the name with the description below it.
The nui executor runs multi-step pipelines in sequential topological order (no parallel fan-out). Omit steps for single-step agents; use steps when the agent has more than one step or a HITL gate step.
| File | Complexity | Demonstrates |
|---|---|---|
01-hello-world.yaml |
Trivial | Single step, default harness |
02-sequential-research-write.yaml |
Basic | dependsOn, named outputs, per-step systemPrompt |
03-docker-code-runner.yaml |
Basic | Docker harness |
04-remote-agent.yaml |
Basic | Remote harness |
06-devcontainer-agent.yaml |
Basic | Devcontainer harness |
05-parallel-research-fan-out.yaml |
Intermediate | Fan-in via dependsOn (steps still run sequentially) |
09-multi-harness-pipeline.yaml |
Advanced | Per-step harness/model override |
11-complex-research-pipeline.yaml |
Complex | Multi-harness pipeline with MCP and verification |
12-codex-sandbox-variants.yaml |
Basic | codex: none / bubblewrap / docker |
13-opencode-sandbox-variants.yaml |
Basic | opencode: none / bubblewrap / docker |
14-ai-assets-mcp.yaml |
Basic | aiAssets.mcpServers (HTTP + stdio) |
15-env-vars.yaml |
Basic | Global env + harness.env |
16-ai-assets-skills.yaml |
Basic | aiAssets.skills (path, ref, content, git) |
17-auto-scheduled-agent.yaml |
Basic | promptMode: auto agent for Customize → Schedules |
18-tool-approvals.yaml |
Basic | Top-level toolApprovals with harness.permissions: interactive |
19-hitl-workflow-gate.yaml |
Intermediate | Workflow step type: hitl orchestration gate |
20-evals.yaml |
Basic | evals test cases for nui agent eval run |
21-orchestrator-sub-agents.yaml |
Intermediate | subAgents orchestrator routing to registry agents |
22-allowed-harnesses.yaml |
Basic | allowedHarnesses — session/CLI override among CLI harnesses |
23-api-harness.yaml |
Basic | harness.type: api with provider / model |
Builtin and connector types supported by the nui executor:
| Type | How it runs |
|---|---|
claude-code |
claude CLI subprocess |
pi |
pi --mode rpc subprocess |
codex |
codex exec subprocess |
opencode |
opencode serve + opencode run |
api |
In-process LLM HTTP client (provider, model, optional baseUrl / apiKeyEnv) |
docker |
HTTP/SSE in user-managed Docker container |
devcontainer |
nui-managed devcontainer sandbox (innerHarness CLI via devcontainer exec) |
remote |
HTTP/SSE at configured host:port |
ext:<extension>/<harness-id> |
Installed extension harness (stdio/tcp/http) |
harness:
type: claude-code
allowedHarnesses:
- claude-code
- pi
- codex
- opencodeOmitted means any CLI harness is allowed. When set, the list is a whitelist (single entry pins). Example: nui run -a portable-coder --harness pi. Per-step steps[].harness is never overridden.
harness:
type: api
provider: anthropic # anthropic | openai | gemini | ollama | openrouter
model: claude-sonnet-4-20250514
# baseUrl: https://... # optional
# apiKeyEnv: MY_API_KEY # optional; default per provider
# disableTools: true # optional; omit tools from LLM requestsRuns in-process inside nui (no CLI subprocess). See 23-api-harness.yaml.
harness:
type: claude-code
model: claude-sonnet-4-6
steps:
- name: plan
harness:
type: claude-code
model: claude-opus-4-8MCP servers are declared under aiAssets.mcpServers. Each entry requires name. Use url + type for HTTP/SSE servers, or command + args + type for stdio servers.
aiAssets:
mcpServers:
- name: test-mcp-server
url: http://localhost:3000/mcp
type: http
- name: local-tool
command: npx
args: ["-y", "some-mcp-package"]
type: stdionui provisions these into ~/.nui/sessions/<session-id>/ and sets the harness config-dir env var (CLAUDE_CONFIG_DIR, CODEX_HOME, PI_CODING_AGENT_DIR, or OPENCODE_CONFIG_DIR) before each run.
Per-step overrides merge with top-level aiAssets by name (step entries override same name):
steps:
- name: doc-search
aiAssets:
mcpServers:
- name: internal-docs
url: http://localhost:3040
type: httpsystemPrompt: |
You are a helpful assistant.
aiAssets:
skills:
- name: code-review
path: ./skills/code-review
- name: commit-helper
ref: commit-helper
- name: greeting
content: |
---
name: greeting
description: Brief greeting skill
---
Keep responses to one sentence.Legacy top-level skill: still works (mapped to a single aiAssets.skills entry).
Install catalog skills ahead of time:
nui skills add ./skills/code-review
nui skills add https://github.com/example/agent-skills/tree/main/skills/shared-style
nui skills add --git https://github.com/example/agent-skills.git --path skills/shared-style
nui skills listsystemPrompt is written as harness-native markdown (CLAUDE.md, AGENTS.md, etc.). Skills are copied into the session harness skills directory (full directory tree, not just SKILL.md).
aiAssets:
rules:
- ref: ext:corp-pack/corp-guidelines
mentionProviders:
- ref: ext:corp-pack/corp-refsRules materialize into harness-specific rule files. Mention providers power @-mention autocomplete when opted in via ADL.
Quick-start pills above the chat input:
promptSuggestions:
- title: Review code
prompt: Review the current changes and suggest improvements.
icon: sparklesWorkflow steps with type: hitl pause the DAG for human approval, questions, or review:
steps:
- name: draft
outputs:
- name: summary
type: text
- name: review-gate
type: hitl
dependsOn: [draft]
hitl:
kind: approval
title: Approve summary
message: Review the draft before publishing.
actions:
- id: approve
label: Approve
- id: reject
label: Reject
display:
- from: draft.summary
channels: [nui-ui]See 19-hitl-workflow-gate.yaml for a full example.
Global env applies to every harness subprocess. harness.env overrides global keys for that harness (and per-step harness overrides).
env:
ANTHROPIC_BASE_URL: https://api.anthropic.com
harness:
type: claude-code
model: claude-sonnet-4-6
env:
ANTHROPIC_API_KEY: your-api-keypromptMode: user (default) waits for the user to type a message. promptMode: auto hides the input and runs on session open with a launch prompt, ADL defaultPrompt, or the built-in phrase "Follow your system instructions and run.".
When harness.permissions: interactive (Claude Code or Codex), nui routes native tool permission requests through the UI. Top-level toolApprovals controls which tools auto-approve vs prompt:
| Policy | Behavior |
|---|---|
default |
Prompt for every tool |
all |
Auto-approve all tools |
allowlist |
Auto-approve only listed tools |
denylist |
Prompt only for listed tools |
Tool names include native harness tools (Bash, Write) and MCP tools (mcp__server-name__tool-name). Glob patterns such as mcp__corp__* are supported. Selective policies are enforced for Claude Code in v1; Codex supports binary bypass only.
Session overrides: agentConfig.toolApprovalPolicy and agentConfig.toolApprovalTools.
harness:
permissions: interactive
toolApprovals:
policy: denylist
tools: [Bash, Write, Edit]promptMode: auto
defaultPrompt: Follow your system instructions and run.Define test cases on an agent to verify behavior with nui agent eval run -a <agent-id>:
evals:
- name: polite-greeting
description: Agent introduces itself politely
input: |
Hello, who are you?
expect:
type: contains # contains | exact | regex | llm | none
value: assistant
tags: [smoke]
timeout: 120 # seconds (optional; default 120, 300 for devcontainer)
workingDir: ./fixtures # optional per-case override
disabled: falseMulti-turn evals use messages instead of input (must end with a user turn). Graders: contains, exact, regex, llm (criteria rubric), or none (informational). Use hitl.mode: off and non-interactive tool approvals for unattended eval runs.
See 20-evals.yaml for a full example.
Each step's collected text is stored under declared outputs names (or an implicit default when omitted). Reference downstream with from: stepName.outputName:
steps:
- name: research
outputs:
- name: brief
type: text
- name: write
dependsOn: [research]
inputs:
- from: research.brief
as: researchBriefEach user chat turn re-runs all pipeline steps from the beginning.
Applies to claude-code, pi, codex, and opencode:
harness:
type: codex
sandbox: none # host subprocess (default)
harness:
type: codex
sandbox: bubblewrap # Linux only; bwrap wrapper
harness:
type: codex
sandbox: docker
image: nui-codex:latest # builtin image, port 8090See design.md for the full schema and executor status.