Instructions for AI coding agents working with this codebase.
cli-agent is a CLI-daemon system for managing background tasks with a terminal UI. The architecture separates the user-facing CLI/TUI from a persistent background daemon, enabling parallel task execution and real-time updates.
Read these documents before making changes:
| Document | Purpose |
|---|---|
docs/architecture.md |
System design, component diagram, file organization |
docs/protocol.md |
IPC format, command schemas, how to add new commands |
docs/task-runner.md |
Task lifecycle, queue management, event emission |
docs/tui.md |
OpenTUI React implementation, UI components |
docs/decisions.md |
Design rationale, trade-offs, future considerations |
src/
├── cli/index.ts # CLI entrypoint, argument parsing
├── daemon/index.ts # Daemon server, command dispatch
├── tui/
│ ├── app.tsx # OpenTUI React UI component
│ └── index.tsx # TUI entrypoint
├── commands/ # Command handlers
│ ├── context.ts # Session state
│ ├── index.ts # Dispatch router
│ └── *.ts # Individual commands
├── tasks/runner.ts # Task queue and execution
├── protocol.ts # Zod schemas for IPC
├── transport.ts # Socket utilities
└── stream.ts # Event subscription helper
bun run dev # Run CLI (auto-starts daemon)
bun run dev:daemon # Run daemon only
bun run tui # Run TUIRun these checks after any file edits. If errors occur, fix them and re-run until clean.
bun run tsc --noEmit
bun run biome check --writebun run build # Compile TypeScript to dist/
node dist/cli/index.js ping # Run with Node.js- Node.js Compatibility: Do not use Bun-specific APIs. Target Node.js runtime.
- JSX: Use
@opentui/reactfor JSX. Files with JSX must use.tsxextension. - Imports: Use
.jsextension in import paths (TypeScript compiles to JS).
-
Define schema in
src/protocol.ts:const myCommandSchema = sessionCommandSchema.extend({ action: z.literal("my_command"), // ... fields });
-
Add to union in
src/protocol.ts:export const commandSchema = z.discriminatedUnion("action", [ // ... existing myCommandSchema, ]);
-
Create handler
src/commands/my-command.ts:export async function myCommand(cmd: MyCommand, ctx: CommandContext) { // implementation return { result: "..." }; }
-
Register in
src/commands/index.ts -
Add CLI parsing in
src/cli/index.ts
- Create component in
src/tui/using OpenTUI React primitives - See
opensrc/repos/github.com/anomalyco/opentui/packages/react/for API reference - Available components:
box,text,input,scrollbox - Use
useKeyboardhook for keyboard handling
To broadcast events to TUI clients:
- Define event type in
src/protocol.ts(extendEventMessageunion) - Call
broadcast()in daemon when event occurs - Handle in TUI's event subscription
# Terminal 1: Start daemon
bun run dev:daemon
# Terminal 2: Run commands
bun run dev ping
bun run dev run my-task --duration 3000
bun run dev status
# Terminal 3: Watch events in TUI
bun run tui- Daemon-client IPC (Unix socket / TCP)
- Command protocol with Zod validation
- Task queue with lifecycle events
- Session isolation
- Event streaming to TUI
- Basic TUI with event log and input
- Real task execution (currently simulated with timeout)
- Task persistence across daemon restarts
- Multiple sessions in TUI
- Auto-scroll in event log
- Error display in TUI
- Graceful daemon shutdown on last client disconnect
- Add new command type (e.g.,
chat) inprotocol.ts - Create command handler that calls LLM API
- Emit progress events during streaming
- Update TUI to display chat messages
- Define tool registry in new file
src/tools/ - Add
tool_callcommand type - Implement sandboxed execution in task runner
- Add confirmation flow in TUI before execution
- Choose storage (SQLite recommended for structured data)
- Save task state on every transition
- Load on daemon startup
- Consider
docs/decisions.mdfor design rationale
Source code for dependencies is available in opensrc/ for deeper understanding of implementation details.
See opensrc/sources.json for the list of available packages and their versions.
Use this source code when you need to understand how a package works internally, not just its types/interface.
To fetch source code for a package or repository you need to understand, run:
npx opensrc <package> # npm package (e.g., npx opensrc zod)
npx opensrc pypi:<package> # Python package (e.g., npx opensrc pypi:requests)
npx opensrc crates:<package> # Rust crate (e.g., npx opensrc crates:serde)
npx opensrc <owner>/<repo> # GitHub repo (e.g., npx opensrc vercel/ai)When working on tasks about a library/framework/runtime/platform, first consult
llms-furl/, which contains llms-full.txt split into a tree of leaves — small,
searchable files for quick lookup.
Workflow:
- Check domains in
llms-furl/AGENTS.md. - Search within the relevant domain (e.g.
rg -n "keyword" llms-furl/bun.sh). - If needed, navigate with
index.jsonusingjq. - If no relevant info is found, state that and then move on to other sources.