Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 174 additions & 0 deletions docs/ai/design/2026-06-01-feature-agent-console-start.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
---
phase: design
title: System Design & Architecture
description: Define the technical architecture, components, and data models
---

# System Design & Architecture

## Architecture Overview
**What is the high-level system structure?**

```mermaid
graph TD
User[User presses s in agent console]
Shell[ConsoleAppShell]
StartHook[useStartAgentPane]
Workspace[RightPaneWorkspace]
StartPane[StartAgentPane]
Preview[Preview + Chat]
NameGen[Existing name generation helper]
Action[runAction start action]
CLI[Current CLI entry]
StartCmd[agent start --type --name --cwd]
Provider[ConsoleProvider / agent polling]
List[AgentListPane]

User --> Shell
Shell --> Workspace
Workspace --> Preview
Workspace --> StartPane
NameGen --> StartPane
Shell --> StartHook
StartPane -->|submit values| StartHook
Shell --> Action
Action -->|spawn piped stdio| CLI
CLI --> StartCmd
StartCmd -->|registry/tmux side effects| Provider
Provider --> List
```

The console remains the orchestration layer. The agent list is the stable left navigation pane. The right pane is a mode-driven workspace: the default mode renders preview + chat input, and `start-agent` mode renders the start-agent form. `useStartAgentPane` owns the start lifecycle, and `runAction` handles process execution as the only bridge from TUI actions to CLI subcommands. Existing `agent start` code remains responsible for validation, tmux creation, PID polling, registry writes, and attach instructions.

## Data Models
**What data do we need to manage?**

```typescript
type StartableAgentType = 'claude' | 'codex' | 'gemini_cli' | 'opencode';

interface StartAgentFormState {
type: StartableAgentType;
cwd: string;
name: string;
focus: 'type' | 'cwd' | 'name' | 'submit' | 'cancel';
error?: string;
isSubmitting: boolean;
}

type RightPaneMode =
| { type: 'preview' }
| { type: 'start-agent' };

type ConsoleAction =
| { type: 'open'; agentName: string }
| { type: 'send'; agentName: string; message: string }
| { type: 'start'; agentType: StartableAgentType; name: string; cwd: string };
```

No new persistent data is introduced. Persistent agent state remains owned by `agent start` and the existing agent registry.

## API Design
**How do components communicate?**

### `StartAgentPane`

```typescript
interface StartAgentPaneProps {
initialType?: StartableAgentType;
initialName: string;
initialCwd: string;
onSubmit(values: { type: StartableAgentType; name: string; cwd: string }): void;
onCancel(): void;
error?: string | null;
isSubmitting?: boolean;
width: number;
height: number;
}
```

The pane is controlled by `ConsoleAppShell` and `useStartAgentPane`: the shell decides the active `RightPaneMode`, passes defaults, and routes submit/cancel events to the start lifecycle hook. The hook invokes `runAction`, manages inline errors/submitting state, returns to preview mode after success/cancel, and calls `refresh()` after a successful start.

### `runAction`

Extend the existing action union and argv switch:

```typescript
case 'start':
return [
...baseArgs,
'agent',
'start',
'--type',
action.agentType,
'--name',
action.name,
'--cwd',
action.cwd,
];
```

Spawn behavior stays unchanged: `stdio: ['ignore', 'pipe', 'pipe']`.

### Console refresh

`useAgentList` currently owns `manager.listAgents({ sortBy: 'status' })` inside its polling effect. Add a `refresh(): Promise<void>` method to `UseAgentListResult` by extracting the existing fetch-once logic into a stable callback. `ConsoleProvider` can pass that through context. `ConsoleAppShell` calls `refresh()` after successful start so the new agent appears immediately, without duplicating list-loading logic outside the hook.

### Generated name helper

`generateAgentName(cwd)` currently lives in `packages/cli/src/util/agent.ts` after being extracted from `packages/cli/src/commands/agent.ts`. Import it from both `commands/agent.ts` and the console start-pane lifecycle hook. Preserve current behavior exactly:

```typescript
const folder = path.basename(cwd)
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '')
.slice(0, 50) || 'agent';
return `${folder}-${Date.now().toString(36)}`;
```

## Component Breakdown
**What are the major building blocks?**

| Component | Location | Change |
|---|---|---|
| `ConsoleAppShell` | `packages/cli/src/tui/console/ConsoleApp.tsx` | Own right-pane mode state, handle `s`, route submit/cancel flow, and render the active workspace |
| `useStartAgentPane` | `packages/cli/src/tui/console/hooks/useStartAgentPane.ts` | Own start defaults, submit/cancel lifecycle, success transient, refresh, and inline start-pane errors |
| `StartAgentPane` | `packages/cli/src/tui/console/StartAgentPane.tsx` | New native Ink right-pane workspace with type selector, cwd field, name field |
| Console action types | `packages/cli/src/tui/console/actions/types.ts` | Add `start` action |
| `runAction` | `packages/cli/src/tui/console/actions/runAction.ts` | Add argv mapping for `agent start --type --name --cwd` |
| Name helper utility | `packages/cli/src/util/agent.ts` | Shared `generateAgentName(cwd)` imported by command + console |
| `useAgentList` / console context | `packages/cli/src/tui/console/hooks/useAgentList.ts`, `state/ConsoleContext.tsx` | Expose `refresh()` for immediate post-start list reload |
| Footer | `packages/cli/src/tui/console/StatusFooter.tsx` | Add `s start` to shortcut text |
| Tests | `packages/cli/src/__tests__/tui/console/**` | Cover new action argv and start-pane behavior |

## Design Decisions
**Why did we choose this approach?**

**Right-pane workspace pattern:** The left agent list stays stable as navigation while the right pane changes based on the active feature. This avoids terminal overlay artifacts and establishes a reusable pattern for future console features such as web, logs, or settings.

**Shell out via `runAction`:** This follows the existing `open` and `send` pattern. It keeps `agent start` as the behavior source of truth and avoids introducing a second start path with subtly different validation or tmux handling.

**Simple cwd text field:** Directory browsing is useful but out of scope for v1. A text field maps directly to `--cwd` and keeps the start pane small.

**Generated default name:** Reusing the existing generation function keeps console defaults aligned with CLI defaults and reduces repeated naming logic.

**Refresh in hook/context:** The hook already centralizes loading, equality checks, in-flight suppression, and error state. Exposing `refresh()` keeps those rules in one place and avoids a one-off `manager.listAgents` call in `ConsoleAppShell`.

**Type values passed exactly:** The start-pane selections use the supported `agent start` type values directly, including `gemini_cli`, so there is no hidden display-to-value mapping to test or maintain.

**Inline failure retry:** Failed start keeps the start-agent workspace active and displays stderr inline. This lets users fix invalid cwd/name/type values without changing modes.

**Alternatives considered:**
- Use Inquirer after pausing the TUI: simpler implementation, but it is not a native console popup and would interrupt the console model.
- Call start service internals directly: avoids a subprocess, but diverges from the established console action pattern and requires more coupling between the TUI and start implementation.
- Add directory picker: better UX for path discovery, but more scope and keyboard complexity than needed for this version.
- Overlay modal: looked like a popup but introduced terminal-specific background/opacity artifacts and obscured the future workspace pattern.

## Non-Functional Requirements
**How should the system perform?**

- Right-pane mode switching should not block polling or conversation preview updates.
- Subprocess output must not write directly to the TUI terminal.
- Error output should be trimmed to fit transient/start-pane display without overflowing narrow terminals.
- User-supplied values must only be passed as argv entries to `spawn`, never interpolated into a shell command.
- Existing console shortcuts and input focus behavior must remain stable.
82 changes: 82 additions & 0 deletions docs/ai/implementation/2026-06-01-feature-agent-console-start.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
phase: implementation
title: Implementation Guide
description: Technical implementation notes, patterns, and code guidelines
---

# Implementation Guide

## Development Setup
**How do we get started?**

- Worktree: `.worktrees/feature-agent-console-start`
- Branch: `feature-agent-console-start`
- Dependency bootstrap: `npm ci` completed in the worktree.
- Validation entrypoints used during implementation:
- `npx vitest run src/__tests__/util/agent-name.test.ts src/__tests__/tui/console/actions/runAction.test.ts`
- `npx vitest run src/__tests__/tui/console/StartAgentPane.test.ts`
- `npx vitest run src/__tests__/tui/console/computeLayout.test.ts src/__tests__/tui/console/StartAgentPane.test.ts src/__tests__/tui/console/actions/runAction.test.ts src/__tests__/util/agent-name.test.ts`
- `npx nx build cli`
- `npx ai-devkit@latest lint --feature agent-console-start`
- Manual TTY smoke: `npm run dev -- agent console`, press `s`, press `Esc`, press `q`.

## Code Structure
**How is the code organized?**

- `packages/cli/src/util/agent.ts`: shared `generateAgentName(cwd)` helper extracted from the `agent start` command.
- `packages/cli/src/tui/console/actions/types.ts`: adds the `start` console action.
- `packages/cli/src/tui/console/actions/runAction.ts`: maps `start` to `agent start --type --name --cwd` through the same subprocess path as `open` and `send`.
- `packages/cli/src/tui/console/StartAgentPane.tsx`: native Ink right-pane workspace with type selection, cwd/name text fields, submit/cancel controls, submitting state, and inline errors.
- `packages/cli/src/tui/console/ConsoleApp.tsx`: switches the right pane to start-agent mode on `s`, routes start-pane submit/cancel callbacks, renders the active workspace, and keeps global shortcuts disabled while the start pane owns keyboard input.
- `packages/cli/src/tui/console/hooks/useStartAgentPane.ts`: owns generated defaults, start submit/cancel lifecycle, inline error state, success transient, and post-success list refresh.
- `packages/cli/src/tui/console/hooks/useAgentList.ts`: exposes `refresh()` while preserving existing polling/equality behavior.
- `packages/cli/src/tui/console/StatusFooter.tsx`: documents the new `s start` shortcut.

## Implementation Notes
**Key technical details to remember:**

### Core Features
- `generateAgentName(cwd)` behavior was preserved exactly and covered with unit tests for sanitized folder names and fallback `agent-*` names.
- `runAction({ type: 'start', agentType, name, cwd })` shells out to the current CLI entry with argv entries, not shell interpolation.
- `StartAgentPane` owns form state locally. Type selection cycles through `claude`, `codex`, `gemini_cli`, and `opencode`; cwd and name use `ink-text-input`.
- `ConsoleAppShell` ignores global shortcuts while the start pane is active so the pane owns keyboard handling.
- The left agent list remains the stable navigation area in wide terminals; the right workspace switches between preview/chat and start-agent. In narrow terminals, start-agent replaces the available main pane.
- `useStartAgentPane` creates fresh generated defaults each time the start workspace opens.
- Start failure keeps the start-agent pane active and displays inline error text. Start success returns to preview/chat, shows `Started <name>`, and awaits `refresh()`.
- Manual TTY smoke confirmed narrow-mode behavior: `s` replaces the available main pane with `START AGENT`, `Esc` returns to the default view, and `q` exits cleanly.

### Patterns & Best Practices
- Keep TUI subprocess interactions centralized in `runAction`.
- Keep agent-list loading centralized in `useAgentList`; `refresh()` reuses the hook's same in-flight guard, equality check, and error handling.
- Use stable callbacks for console actions to avoid unnecessary React churn.
- Keep right-pane workspace dimensions derived from the existing console layout calculation.

## Integration Points
**How do pieces connect?**

- `agent start` remains the source of truth for validation, tmux creation, PID polling, registry updates, and attach output.
- The console start pane only collects values and invokes the CLI through `runAction`.
- `ConsoleProvider` passes through `refresh()` from `useAgentList`; `useStartAgentPane` calls it after successful start.

## Error Handling
**How do we handle failures?**

- `runAction` captures stderr from the `agent start` subprocess.
- Non-zero start exits keep `StartAgentPane` active and render the captured stderr inline.
- If stderr is unavailable, the pane displays `start exited <code>`.
- Duplicate submits are ignored while `isStartingAgent` is true.
- Cancel is ignored while a start action is in flight.

## Performance Considerations
**How do we keep it fast?**

- The start pane does not introduce new polling.
- `refresh()` preserves the existing in-flight guard so manual refresh cannot overlap the poller's active request.
- Quiet polls still skip state updates when agent data is unchanged.

## Security Notes
**What security measures are in place?**

- User-provided `type`, `name`, and `cwd` values are passed as `spawn` argv entries, never interpolated into a shell string.
- Validation stays in `agent start`; the pane does not duplicate or weaken command validation.
- No secrets or persistent data are introduced by the pane itself.
76 changes: 76 additions & 0 deletions docs/ai/planning/2026-06-01-feature-agent-console-start.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
phase: planning
title: Project Planning & Task Breakdown
description: Break down work into actionable tasks and estimate timeline
---

# Project Planning & Task Breakdown

## Milestones
**What are the major checkpoints?**

- [x] Milestone 1: Console action contract supports `agent start`.
- [x] Milestone 2: Native Ink start workspace is wired into `agent console`.
- [x] Milestone 3: Tests and manual console smoke validate start, cancel, and failure flows.

## Task Breakdown
**What specific work needs to be done?**

### Phase 1: Foundation
- [x] Task 1.1: Locate the existing generated-name helper used by `agent start` and export/reuse it from TUI code without changing generated output.
- [x] Task 1.2: Extend `ConsoleAction` with `{ type: 'start'; agentType; name; cwd }`.
- [x] Task 1.3: Extend `runAction` to map the start action to `agent start --type --name --cwd`.
- [x] Task 1.4: Add action runner tests for start argv, piped stdio, and error propagation.

### Phase 2: Core Features
- [x] Task 2.1: Implement `StartAgentPane` as a native right-pane workspace with type selection, cwd text input, name text input, submit, cancel, error, and submitting states.
- [x] Task 2.2: Add pane/helper unit tests for rendering, navigation, submit, cancel, and error display.
- [x] Task 2.3: Wire `s` in `ConsoleAppShell` to switch the right pane to start-agent mode only when list focus owns keyboard input.
- [x] Task 2.4: On pane submit, invoke `runAction({ type: 'start', ... })`, show success/error transient feedback, and prevent duplicate submits while running.
- [x] Task 2.5: Expose or reuse a console refresh method so successful start can refresh the list immediately.

### Phase 3: Integration & Polish
- [x] Task 3.1: Update `StatusFooter` shortcut text to include `s start`.
- [x] Task 3.2: Add focused tests for action argv, layout calculation, start-pane helpers, generated names, and existing shortcut regressions. Full Ink interaction harness remains absent and is covered by manual smoke.
- [x] Task 3.3: Run focused test suites and broader CLI tests as needed.
- [x] Task 3.4: Manually smoke-test `agent console` in a terminal for start-workspace layout and keyboard behavior.
- [x] Task 3.5: Update implementation notes with evidence and any deviations.

## Dependencies
**What needs to happen in what order?**

- Task 1.1 should happen before pane wiring so defaults use the real helper.
- Task 1.2 and 1.3 should happen before pane submit wiring.
- Task 2.1 can start once pane props and action shape are clear.
- Task 2.5 depends on how `ConsoleProvider` currently owns polling/list loading.
- Manual smoke depends on local availability of at least one supported agent binary and tmux.

## Timeline & Estimates
**When will things be done?**

- Foundation/action runner: 1-2 hours.
- Modal component and keyboard handling: 3-5 hours.
- Console integration and refresh: 2-3 hours.
- Tests and manual smoke: 2-4 hours.
- Main uncertainty: Ink text-input/selection ergonomics in the existing layout.

## Risks & Mitigation
**What could go wrong?**

- **Keyboard handling conflict:** Start-pane shortcuts could conflict with list/chat input. Mitigation: gate `s` by focus and let the active right-pane workspace own relevant input.
- **Duplicate submissions:** Users could press Enter repeatedly. Mitigation: `isSubmitting` disables repeated submit.
- **Name helper coupling:** Existing helper may be command-local. Mitigation: extract to a small utility with tests preserving current behavior.
- **Refresh duplication:** Console list loading may not be externally triggerable. Mitigation: expose a minimal refresh callback from context instead of duplicating manager calls.
- **Narrow terminal layout:** The right-pane workspace may be hidden in narrow mode. Mitigation: when narrow, replace the main content area with the start-agent pane rather than requiring the preview column.

## Resources Needed
**What do we need to succeed?**

- Existing console implementation in `packages/cli/src/tui/console`.
- Existing `agent start` implementation in `packages/cli/src/commands/agent.ts`.
- Existing console action tests under `packages/cli/src/__tests__/tui/console`.
- Local terminal for manual Ink smoke testing.

## Current Status

Implementation now uses the right-pane workspace pattern. `s` switches the dynamic workspace from preview/chat to the native Ink start-agent form, name/cwd are prefilled, type is selectable, submit shells out through the existing console action runner to `agent start --type --name --cwd`, failures stay inline, and successful starts refresh the agent list before returning to preview/chat. This replaces the earlier overlay/modal approach and establishes the intended pattern for future console features.
Loading
Loading