This directory contains a Bubble Tea client that talks to the live TaskForceAI multi-agent orchestrator API. It mirrors the operator dashboard in a terminal-first workflow: keyboard navigation, streaming agent progress, tool telemetry, and a bottom-docked chat input that submits prompts directly to the orchestrator.
- Runtime & UI
- Go 1.25.6, compiled to a single static binary.
- Bubble Tea drives the state machine, while Bubbles + Lipgloss render the run list, detail pane, and chat dock.
- The app entrypoint (
main.go → internal/app → internal/app/cli → internal/app/cli/models) isolates terminal UI logic from configuration, persistence, and API layers so tests can exercise each piece independently.
- Networking
internal/app/apiwraps TaskForceAI’s HTTP+SSE endpoints with typed structs, streaming readers, and context-aware retries. Long-lived streams run on their own goroutines and push updates into Bubble Tea messages.- Device login and auto-update flows live in the same package so authentication and binary swaps stay encapsulated.
- Persistence & Offline Workflow
- Session state persists to both
history.jsonand a SQLite database (internal/app/persistence). SQLC-generated code wraps every query so schema drift is caught at compile time. - The persistence layer exposes helpers for run hydration, snapshots, pending prompt queues, and local search. During startup the model loads history from disk, merges it with SQLite, and opens any pending retries.
- Session state persists to both
- Observability
- Structured logging uses
log/slogwith level + format controls exposed through/config logging. internal/app/observabilitywires Sentry; telemetry can be toggled or pointed to custom DSNs/environments at runtime.
- Structured logging uses
- Dev Experience
- Watcher-based dev loop (
bun run cli:dev) rebuilds and respawns the TUI on source changes. - Tests cover CLI state transitions, persistence edge cases, and API contracts (
go test ./...; see “Testing” below). - Auto-update logic uses
go-github-selfupdateto download signed releases and swap binaries in place.
- Watcher-based dev loop (
- Go 1.23 or newer (
brew install goon macOS,apt install golangon Debian/Ubuntu, etc.) - A TaskForceAI account with access to the
/api/v1endpoints
curl -fsSL https://taskforceai.chat/install.sh | bashThis downloads a prebuilt binary for your platform and installs it to ~/.local/bin. Override the install location with TASKFORCEAI_INSTALL_DIR:
curl -fsSL https://taskforceai.chat/install.sh | TASKFORCEAI_INSTALL_DIR=/usr/local/bin bashNative installs automatically update in the background. Set TASKFORCEAI_DISABLE_AUTOUPDATE=1 to opt out.
brew install ClayWarren/taskforceai/taskforceai-cliirm https://taskforceai.chat/install.ps1 | iexcurl -fsSL https://taskforceai.chat/install.cmd -o install.cmd && install.cmd && del install.cmdDownload the latest release for your platform from GitHub Releases, extract it, and add the binary to your PATH.
cd apps/tui
go run .bun run cli:devThis runs the bundled watcher (cmd/dev) so the TUI rebuilds and restarts whenever Go sources, templates, or config files change.
Prefer a manual launch? You can call the watcher directly:
cd apps/tui
go run ./cmd/devThe client stores configuration under ~/.config/taskforceai/ (override with $TASKFORCEAI_CONFIG_DIR).
Tabtoggles focus between the run list and the chat bar.Up/Down(ork/j) move through runs and refresh the detail pane.PgUp/PgDnor mouse wheel scroll through chat history when chat is focused.Entersends whatever is in the chat input.ctrl+ddeletes the currently selected run from local history.qorctrl+cexits.
Slash commands:
/login– open your browser to authenticate with TaskForceAI (device login flow)./logout– clear the cached token./sync– pull the latest conversation history from TaskForceAI./clear,/reset,/new– wipe the current session state and start fresh./search <query>– fuzzy search across local prompts, outputs, and logs./model [list|set <id>|reset]– choose which AI model powers new prompts./config theme <light|dark|system>– switch the accent palette for the terminal UI./config telemetry <on|off|dsn|env>– control crash-reporting (Sentry) and its DSN/environment./config logging <level|format>– set the structured log level (debug|info|warn|error) and format (text|json)./mock– toggle a local mock API server for SDK development (runs onlocalhost:4321)./help– list available commands and what they do./usage– show run usage stats from the local history./mcp– manage MCP servers and list configured tools (see below)./exit,/quit– close the terminal client.
Run the mock API server without the TUI for scripting and testing:
taskforceai --mockThis starts the server at http://localhost:4321/api/developer and blocks until Ctrl+C. Useful for SDK integration testing.
Anything else you type is posted to /api/v1/run; progress streams in from /api/v1/stream/<taskId>, and completed runs persist locally (history.json) so the dashboard survives restarts.
- Run list (left) – newest runs first, coloured by status.
- Run detail (right) – prompt, agent statuses, tool usage, logs, and synthesized output.
- Chat dock (bottom) – threaded messages with live-updating OpsBot responses as the stream unfolds.
- Theming – colors match the TaskForceAI dark theme palette so terminal and web console feel consistent.
- Telemetry (Sentry) is disabled by default. Provide a DSN via
/config telemetry dsn <value>or theTASKFORCEAI_SENTRY_DSNenv var, then run/config telemetry onto start capturing crashes./config telemetry env <name>sets the environment tag (defaults tocli). - Structured logging flows through
log/slog. Use/config logging format jsonwhen piping logs into other tools, and/config logging level debugfor verbose diagnostics. Defaults areinfolevel and human-friendly text output. - All settings persist in
~/.config/taskforceai/config.json(or$TASKFORCEAI_CONFIG_DIR). Toggle them back with/config telemetry offand/config logging level info.
- The TUI caches prompts, outputs, tool traces, and queued retries inside a local SQLite database (
~/.config/taskforceai/taskforceai.db). The normalized schema lives ininternal/app/persistence/schema.sql; the same file is embedded at runtime and feeds sqlc so schema drift is impossible. - All queries are defined under
sqlc/queries/(grouped by conversations, messages, and pending prompts). sqlc turns those statements into strongly-typed Go helpers ininternal/app/persistence/sqlc/. - Editing the schema or queries requires regenerating the bindings: install sqlc (
brew install sqlcorgo install github.com/sqlc-dev/sqlc/cmd/sqlc@latest), then runsqlc generatefromapps/tui. CI will fail to build if the generated file is stale or missing. - Tests that touch persistence (
go test ./internal/app/persistence ./internal/app/cli/models) automatically exercise the generated layer plus migrations, so always re-run them after changing schema/queries. - Need to run without SQLite? set
TASKFORCEAI_DISABLE_SQLITE=1before launching the CLI to skip local persistence entirely. The UI will inform you that on-disk caching is disabled.
- Publish prebuilt binaries alongside the npm installer for air-gapped environments.
- Stream metrics, traces, and workflow queues alongside agent/tool telemetry.
- Harden release automation with signed artifacts and channel promotion.
- The TUI checks GitHub releases for
claywarren/taskforceai-tuion startup. - If a newer semantic version exists, it downloads + swaps the binary in-place, then prompts you to restart.
- Set
TASKFORCEAI_DISABLE_AUTOUPDATE=1to skip the check (useful for air-gapped or QA scenarios). - Set
TASKFORCEAI_UPDATE_REPO=owner/repoto pull releases from a different fork/channel.
Run the Go format/lint/build loop from the repo root:
bun run format:cli
bun run lint:cli
bun run typecheck:cli
bun run test:clicd apps/tui
go test ./...
staticcheck ./...MCP helpers:
/mcpor/mcp list– show configured servers and their tools./mcp add <name> <endpoint> [tools=tool1,tool2] [enabled=true|false]– register or update a server./mcp remove <name>– delete a server entry./mcp tools <name> <tool1,tool2,...>– replace the tool list for a server./mcp enable <name>//mcp disable <name>– toggle a server without removing it.
