6.9 KiB
AIRI Coding CLI + Chafa Architecture
Purpose
Define a narrow architecture for a terminal-facing AIRI coding CLI that can
optionally render an animated avatar through chafa, without coupling terminal
presentation to the computer-use-mcp runtime.
This document is a boundary and contract proposal. It is not an implementation plan for a full CLI in this PR.
Current Status
As of 2026-04-26, the main branch does not expose a stable coding runner event stream. A CLI that renders real progress needs a runner contract first. Starting with terminal animation before that contract exists would produce presentation without reliable runtime state.
The correct dependency order is:
- Define a coding runner event contract.
- Emit deterministic runner events from the coding runner.
- Build a text-first CLI that consumes those events.
- Add optional
chafaavatar rendering as a display adapter.
Confirmed Decisions
- Future CLI package location:
packages/airi-cli. - First integration channel: in-process runner callback.
- JSONL over stdin/file remains a follow-up adapter for replay, fixtures, and tooling interoperability.
chafais optional presentation only.
Hard Boundaries
- No
chafadependency belongs inservices/computer-use-mcpcore runtime. computer-use-mcpmust remain headless-safe and CI-safe.- The CLI consumes runner events; it must not own planning, tool execution, or runtime policy.
- Missing
chafamust degrade to plain text rendering. - Non-TTY output must support plain text or JSONL output.
- CLI rendering changes must not be mixed with coding memory or runner runtime refactors.
Proposed Location Split
- Core runtime:
services/computer-use-mcp. - CLI package:
packages/airi-cli. - Event contract: initially colocated with the runner that emits it, then exported for CLI consumption.
- Text renderer:
packages/airi-cli/src/renderers/text.ts. - Chafa adapter:
packages/airi-cli/src/renderers/chafa-avatar.ts. - JSONL adapter:
packages/airi-cli/src/adapters/jsonl.ts.
Runner Event Contract Draft
Use an append-only event envelope. The first transport should be an in-process callback. JSONL is an adapter over the same envelope.
interface RunnerEventEnvelope<TKind extends string = string, TPayload = unknown> {
runId: string
seq: number
at: string
kind: TKind
payload: TPayload
}
Contract rules:
seqis strictly increasing perrunId.atis an ISO timestamp.- events are append-only; later events must not rewrite earlier events.
- crash and timeout paths must emit deterministic terminal events.
Minimum Event Kinds
run_startedpreflight_startedpreflight_completedstep_startedtool_call_startedtool_call_completedassistant_messagestep_timeoutreport_statusrun_finishedrun_crashed
Minimum Payloads
run_started:
interface RunStartedPayload {
workspacePath: string
taskGoal: string
maxSteps: number
stepTimeoutMs: number
}
step_started:
interface StepStartedPayload {
stepIndex: number
maxSteps: number
}
tool_call_started:
interface ToolCallStartedPayload {
toolName: string
argsSummary: string
}
tool_call_completed:
interface ToolCallCompletedPayload {
toolName: string
ok: boolean
status?: string
summary: string
error?: string
}
assistant_message:
interface AssistantMessagePayload {
text: string
}
report_status:
interface ReportStatusPayload {
status: 'completed' | 'failed' | 'blocked'
summary?: string
}
run_finished:
interface RunFinishedPayload {
finalStatus: 'completed' | 'failed' | 'blocked' | 'timeout'
totalSteps: number
error?: string
}
CLI Architecture
The CLI should have three separable layers.
1. Input Adapter
Input adapters convert transport-specific input into RunnerEventEnvelope
events.
Initial adapters:
- in-process runner callback
- stdin JSONL
- JSONL file replay
2. State Reducer
The reducer builds deterministic CliViewState from events.
Rules:
- no terminal I/O in the reducer
- no process spawning in the reducer
- no animation timing in the reducer
- reducer tests should use fixture event streams
3. Renderer Adapter
Renderer adapters consume CliViewState.
Initial renderers:
- text renderer, always available
- JSONL passthrough renderer for tooling
- optional
chafaavatar renderer
Chafa Adapter
The chafa adapter should:
- probe
chafabinary availability at startup - disable itself when stdout is not a TTY
- convert sprite or frame assets to ANSI frames
- pace animation independently from runner event rate
- fall back to text-only rendering on failure
Initial CLI flags:
--avatar=chafa|none--no-avatar--events=runner|stdin|jsonl-file--output=pretty|jsonl
Testing Strategy
- Contract tests for event schema and monotonic
seq. - Reducer tests from fixture JSONL streams.
- Text renderer snapshot tests.
- Chafa adapter tests with mocked binary probing and mocked child process execution.
- CI defaults to text mode and does not require
chafa.
Delivery Stages
Stage 1: Contract
- define the runner event envelope
- add success, failure, and timeout fixture streams
- do not render terminal UI yet
Stage 2: Text CLI
- scaffold
packages/airi-cli - consume runner events
- render run, step, tool, error, and final report state in plain text
Stage 2.5: JSONL Adapter
- support stdin JSONL replay
- support JSONL file replay
- use fixtures for offline demos and tests
Stage 3: Chafa Renderer
- add optional
chafarenderer - keep plain text as the default fallback
- keep CI and headless runs independent from
chafa
Acceptance Criteria
- No
chafadependency is added underservices/computer-use-mcp. - CLI works when
chafais not installed. - CI does not require
chafa. - The reducer is testable from mocked event streams.
- Terminal output degrades to plain text.
- Runner behavior is not changed for animation-first UX.
Review Checklist
Layering:
- no renderer code in
computer-use-mcpruntime - no
chafadependency in runtime packages - CLI code stays under
packages/airi-cli
Runtime:
- runner remains headless-safe
- runner emits events without depending on terminal state
- failures and timeouts produce deterministic events
Fallback:
- missing
chafadoes not fail CLI execution - non-TTY mode uses text or JSONL output
Scope:
- do not mix CLI rendering with coding memory changes
- do not mix CLI rendering with desktop/browser runtime changes
Out of Scope
- long-term memory promotion and governance
- desktop/browser runtime refactors
- terminal animation before a runner event contract exists
- changing coding runner completion semantics for display purposes
Suggested Follow-up PRs
feat(cli): define coding runner event contractfeat(cli): scaffold airi coding cli text rendererfeat(cli): add optional terminal AIRI avatar renderer with chafa