Files
hqt/.hq/2026-06-09-plan-hq-terminal.md
T
felixm 90944948f5 Initial commit: hqt — HQ Terminal TUI
TUI for orchestrating AI coding harness sessions (Claude Code, Codex,
Kiro, etc.) via tmux. Click CLI bootstraps a Textual TUI over
ProjectService/SessionService backed by SQLite, spawning harness
sessions as tmux windows through TmuxManager.

Includes recent fixes:
- Visible Tab focus highlight on dialog OK/Cancel buttons
- Auto-select first project on launch
- Auto-select first session + per-project session-selection memory
- tmux new-window targets an explicit free index, fixing
  "index N in use" failures (broken spawn/attach in attached sessions)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 17:06:57 -04:00

9.5 KiB

HQ Terminal — Implementation Plan

Reference spec: .hq/2026-06-09-spec-hq-terminal.md

Phase 1: Project Scaffold

Set up the new workspace with tooling, dependencies, and basic structure.

Steps

  1. Create workspace at ~/dev/hqt/ with uv init --lib --name hqt
  2. Configure pyproject.toml:
    • Python ≥ 3.12
    • Dependencies: textual>=2.0, sqlalchemy>=2.0, click>=8.0
    • Dev dependencies: pytest, pytest-asyncio, ruff
    • Entry point: [project.scripts] hqt = "hqt.cli:main"
  3. Create package structure per spec: src/hqt/ with all subdirectories
  4. Create .hq/PROJECT.md for the new project
  5. Verify: uv run hqt --help produces output

Phase 2: Database Layer

SQLite models, engine, and schema management.

Steps

  1. src/hqt/config.py — Settings dataclass with paths:
    • db_path: ~/.local/share/hqt/hqt.db
    • config_dir: ~/.config/hqt/
    • skills_dir: ~/.config/hqt/skills/
    • tmux_path: tmux
    • tui_session_name: hqt-main
  2. src/hqt/db/models.py — SQLAlchemy models: Project, Harness, Session, McpServer, ProjectMcpServer, ProjectSkill
  3. src/hqt/db/session.py — Engine factory, session factory, ensure_db() (creates dir + tables)
  4. src/hqt/db/migrate.py — Additive migration helper (add missing columns)
  5. Tests: model creation, ensure_db on fresh + existing databases
  6. Verify: uv run pytest tests/test_db.py -q passes

Phase 3: TmuxRunner

The async tmux command abstraction. Largely ported from HQ.

Steps

  1. src/hqt/tmux/runner.py — Port TmuxRunner from HQ:
    • new_session(name, cwd, command, width, height)
    • has_session(name) -> bool
    • kill_session(name)
    • send_text(name, text)
    • send_enter(name)
    • capture_pane(name) -> str
    • switch_client(target) ← NEW (not in HQ)
    • list_sessions() -> list[str] ← NEW
  2. src/hqt/tmux/manager.py — Higher-level session lifecycle:
    • spawn_session(session: Session, config: SpawnConfig) -> None
    • resume_session(session: Session, config: SpawnConfig) -> None
    • kill_session(session: Session) -> None
    • attach_session(session: Session) -> None (switch-client)
    • is_alive(session: Session) -> bool
    • poll_all_sessions(sessions: list[Session]) -> dict[int, bool]
  3. Tests: mock _exec function, verify command construction
  4. Verify: uv run pytest tests/test_tmux.py -q passes

Phase 4: Harness Abstraction Layer

The configurator protocol and concrete implementations.

Steps

  1. src/hqt/harnesses/base.pyHarnessConfigurator protocol, SpawnConfig, HarnessIdentity dataclasses
  2. src/hqt/harnesses/claude.py — Claude Code configurator:
    • UUID generation via uuid5
    • Spawn: claude --session-id {uuid} --model {model}
    • Resume: claude --resume {uuid}
    • MCP: write project .mcp.json
    • Skills: write/append CLAUDE.md
    • Ready/busy regexes from terminal profiles
  3. src/hqt/harnesses/kiro.py — Kiro CLI configurator (stub for now):
    • Basic spawn command
    • MCP: Kiro-managed (no injection in v1)
  4. src/hqt/harnesses/aider.py — Aider configurator:
    • Spawn: aider --model {model} --restore-chat-history
    • Skills: --read {skill_file} flags
    • No MCP support
  5. src/hqt/harnesses/generic.py — Fallback for unknown harnesses:
    • Env-var based config only
  6. src/hqt/harnesses/registry.py — Discover available harnesses (shutil.which), return configurator instances
  7. Tests: each configurator produces correct SpawnConfig for given inputs
  8. Verify: uv run pytest tests/test_harnesses.py -q passes

Phase 5: Skills & MCP Services

Skill registry and MCP server management.

Steps

  1. src/hqt/skills/registry.py — Port from HQ: scan skills_dir, parse frontmatter, return Skill objects
  2. src/hqt/skills/injection.py — Port from HQ: wrap_prompt_with_skills()
  3. src/hqt/mcp/service.py — CRUD for MCP servers and project bindings (DB operations)
  4. src/hqt/projects/service.py — Project CRUD: add, list, archive, git status reading
  5. Tests: skill discovery with fixture directory, MCP CRUD, project CRUD
  6. Verify: uv run pytest tests/test_skills.py tests/test_mcp.py tests/test_projects.py -q passes

Phase 6: Session Service (Orchestration Core)

The service that ties together DB, tmux, and harness configurators.

Steps

  1. src/hqt/sessions/service.py — Session lifecycle:
    • create_session(project_id, harness_name, nickname, model, skill_names, mcp_ids) -> Session
      • Generates harness UUID via configurator
      • Builds SpawnConfig
      • Calls tmux manager to spawn
      • Persists session row
    • resume_session(session_id) -> None
      • Loads session from DB
      • Builds resume SpawnConfig with stored UUID
      • Calls tmux manager to spawn
    • stop_session(session_id) -> None
      • Kills tmux session
      • Updates DB (last_activity_at)
    • delete_session(session_id) -> None
      • Kills tmux if alive
      • Removes DB row
    • attach_session(session_id) -> None
      • Calls tmux switch-client
    • list_sessions(project_id) -> list[SessionInfo]
      • Joins DB data with tmux liveness
  2. Tests: mock tmux manager, verify session lifecycle
  3. Verify: uv run pytest tests/test_sessions.py -q passes

Phase 7: Textual TUI

The user interface.

Steps

  1. src/hqt/tui/app.py — Textual App subclass:
    • Bindings: q=quit, n=new session, a=add project, /=filter
    • Compose: Header, ProjectList, SessionList, Footer
    • Timer: poll tmux liveness every 3s
  2. src/hqt/tui/widgets/project_list.py — ListView of projects:
    • Shows name, path, branch
    • Selection updates session list
    • Keybindings: Enter=select, a=add, d=archive
  3. src/hqt/tui/widgets/session_list.py — ListView of sessions for selected project:
    • Shows harness icon, nickname, alive/dead status
    • Keybindings: Enter=attach, n=new, d=delete, r=rename, R=resume (if dead)
  4. src/hqt/tui/screens/new_session.py — Modal screen:
    • Harness selector (dropdown)
    • Nickname input
    • Model selector (populated from configurator.supported_models)
    • Skills multi-select
    • MCP servers multi-select
    • Create / Cancel buttons
  5. src/hqt/tui/screens/add_project.py — Modal:
    • Path input (with directory completion if feasible, or paste)
    • Name override (optional)
  6. src/hqt/tui/styles.tcss — Textual CSS for layout
  7. Integration test: App mounts, projects display, key bindings respond
  8. Verify: uv run pytest tests/test_tui.py -q passes (headless Textual testing)

Phase 8: CLI Entry Point & tmux Bootstrap

Wire everything together.

Steps

  1. src/hqt/cli.py — Click CLI:
    • hqt (default) — bootstrap into tmux + launch TUI
    • hqt list — print projects/sessions table
    • hqt attach <id> — switch to session
    • hqt new <project> <harness> — create session non-interactively
    • hqt doctor — check tmux, harness availability
  2. src/hqt/__main__.pypython -m hqt support
  3. tmux bootstrap logic:
    def bootstrap():
        if not in_tmux():
            # Create hqt-main session with TUI as the command
            exec tmux new-session -s hqt-main "hqt --inside-tmux"
        else:
            # Already in tmux, just run the TUI
            run_tui()
    
  4. First-run setup: suggest tmux keybinding, create config dir/skills dir
  5. Verify: hqt doctor works, hqt launches TUI inside tmux

Phase 9: Integration Testing & Polish

Steps

  1. End-to-end test: create project → create session → verify tmux session exists → attach → kill → verify dead
  2. Handle edge cases:
    • tmux not installed → clear error
    • Harness not found → show in UI, disable create
    • DB locked → retry pattern
    • Session name collision → fail gracefully
  3. README.md with quick start
  4. Verify: full test suite passes, manual smoke test with claude-code

Dependency Graph

Phase 1 (scaffold)
    │
    ├── Phase 2 (database)
    │       │
    │       ├── Phase 5 (skills + MCP)
    │       │       │
    │       │       └──────┐
    │       │              │
    │       └── Phase 6 (session service) ◄── Phase 4 (harness abstraction)
    │               │
    ├── Phase 3 (tmux runner) ──────────────┘
    │                                        │
    │                                        ▼
    └── Phase 7 (TUI) ◄──────────── Phase 6
            │
            ▼
        Phase 8 (CLI + bootstrap)
            │
            ▼
        Phase 9 (integration + polish)

Estimated Effort

Phase Complexity Approx. LOC
1. Scaffold Low ~50 (config)
2. Database Low ~150
3. TmuxRunner Low ~120 (mostly port)
4. Harness abstraction Medium ~300
5. Skills + MCP Low ~150 (mostly port)
6. Session service Medium ~200
7. TUI Medium-High ~400
8. CLI + bootstrap Low ~100
9. Integration Medium ~150
Total ~1,620

Implementation Order (sequential for a single agent)

  1. Phase 1 → 2. Phase 2 → 3. Phase 3 → 4. Phase 4 → 5. Phase 5 → 6. Phase 6 → 7. Phase 7 → 8. Phase 8 → 9. Phase 9

Each phase produces a working, testable increment. The TUI (Phase 7) is the largest single piece but depends on everything below it being solid.