Files
Triple-C/ROADMAP.md
T
shadow-testandClaude Opus 5 f68d10d5c2 Add DESIGN-REVIEW.md and ROADMAP.md
DESIGN-REVIEW.md is Fable's review of the v0.3.0 UI: token gaps and three
WCAG AA contrast failures, the modal/accessibility audit, and an IA
proposal that promotes the project from a sidebar card to a tabbed
main-area view.

ROADMAP.md covers Claude Code feature coverage — the five settings.json
keys currently surfaced, the gaps worth closing, the ones deliberately
skipped, the authentication handoff design, and phase sequencing.

Also published as an artifact for easier reading.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 10:56:26 -07:00

9.8 KiB

Triple-C Roadmap — Claude Code Feature Parity

Date: 2026-08-09 · Baseline: v0.3.0 · Claude Code reference: 2.1.226

Companion to DESIGN-REVIEW.md, which covers visual design and information architecture. This document covers which Claude Code capabilities Triple-C should surface, and why.


Guiding principle

Triple-C shows state and launches things. Claude Code edits its own config.

Triple-C's built-in MCP server management was removed in this cycle because Claude Code absorbed the capability natively (claude mcp add/list/remove, .mcp.json, /mcp). Hooks, skills, agents, plugins, output styles, and statusline are the same species: files under .claude/ with first-class Claude Code TUIs. Building GUI form editors for them means losing the same race again.

What Claude Code cannot do is what Triple-C uniquely owns: the container boundary and what persists behind it — the config volume, workspace mounts, lifecycle, the bundled scheduler, and the fleet view across many projects.


Current coverage (v0.3.0)

Triple-C sets exactly five settings.json keys, plus a sandbox block:

Key Surfaced as
tui TUI Mode select (fullscreen)
effort Effort Level select (low/medium/high)
autoScrollEnabled Auto-Scroll Disabled toggle
focusMode Focus Mode toggle
showThinkingSummaries Thinking Summaries toggle
sandbox.* Sandbox toggle (enabled, enableWeakerNestedSandbox, allowUnsandboxedCommands)

Plus four env feature flags — CLAUDE_CODE_NO_FLICKER, CLAUDE_CODE_ENABLE_AWAY_SUMMARY, CLAUDE_CODE_SUBPROCESS_ENV_SCRUB, ENABLE_PROMPT_CACHING_1H — and arbitrary user-set CLAUDE_CODE_* vars via the Env Vars modal.

Also covered: per-project auth backends (Anthropic OAuth, Bedrock incl. SSO refresh, Ollama, OpenAI-compatible), user-level CLAUDE.md composition, claude update on every container start, terminal ergonomics (OAuth URL detection, OSC 52 clipboard, image paste, file drag-drop, STT), the web terminal, and workspace backup.


Gap analysis

Committed for this cycle

# Gap Today Plan
1 Permission modes one boolean → --dangerously-skip-permissions Four-state control (Plan / Default / Accept Edits / Bypass) → --permission-mode. Verified choices on 2.1.226: acceptEdits, auto, bypassPermissions, manual, dontAsk, plan.
2 Session resume none List sessions from the config volume; [Resume] opens a terminal on claude --resume <id>.
3 Capability inventory none Read-only counts + names for skills / agents / hooks / plugins / commands / native MCP servers. Deep-link to the terminal to manage.
4 Automation triple-c-scheduler ships in every container with zero UI Task list, cron editor, run-now, logs, notification badges.
5 Container auth handoff manual code paste See "Authentication handoff" below — design decision pending.

Deliberately skipped

Status line builder · output-styles editor · hook editors · checkpoint/rewind browser · plugin marketplace browser. Each is niche, natively handled by Claude Code's own TUI, or a settings-editor trap. Surface counts and deep-link instead.

Not yet scheduled

  • Granular permissions.allow / ask / deny rules and additionalDirectories
  • Sandbox detail settings (filesystem.allowRead/allowWrite, allowedDomains, excludedCommands) — currently documented for hand-editing via SANDBOX_INSTRUCTIONS
  • Project-level .claude/settings.json vs user-level settings hierarchy
  • A model picker. Note: the only model strings in the app today are stale placeholders (anthropic.claude-sonnet-4-20250514-v1:0 in AwsSettings.tsx and ProjectCard.tsx, qwen3.5:27b, gpt-4o / gemini-pro / etc.). These are free-text placeholders, not dropdowns, but they should be refreshed to current model identifiers regardless.
  • The container's settings.json merge is shallow (jq -s '.[0] * .[1]'), so a user-authored nested block such as sandbox.filesystem.allowWrite is replaced wholesale on every container start. Worth deepening to * recursive merge.

Authentication handoff

Goal: stop making users hand-copy an auth code into every container.

Constraint discovered during research: claude login's callback server uses an ephemeral port and its redirect URI is not configurable for the main login flow (--callback-port and oauth.callbackPort apply to MCP server OAuth only). So a design that pre-assigns each container a fixed callback port and routes to it cannot work as stated — there is no fixed port to route.

There is also a known container gotcha: on Linux, Node resolves localhost to IPv6 first, so the callback server may bind [::1]:PORT only and be unreachable over IPv4 (anthropics/claude-code#44844).

Two viable options:

Option A — long-lived token injection (simple)

claude setup-token (verified present on 2.1.226: "Set up a long-lived authentication token (requires Claude subscription)") returns a ~1-year OAuth token. Triple-C runs it once on the host, stores the token in the OS keychain via the existing secure.rs, and injects CLAUDE_CODE_OAUTH_TOKEN into every container that uses the Anthropic backend.

  • No routing, no ports, no proxy.
  • One auth event covers every project.
  • Cost: small. Reuses existing keychain and env-injection plumbing.
  • Limits: token is subscription-scoped and expires annually; per the docs a setup-token token cannot drive Remote Control sessions or claude.ai connector fetches.

Option B — the Auth Bridge (general loopback-callback bridge)

Option A only solves Claude Code. The same problem affects every CLI that authenticates by starting a temporary loopback listener and opening a browser at a URL that redirects back to it — Concourse fly login (random loopback port serving /auth/callback), aws sso login, and many others. Inside a container the host browser cannot reach that listener, so login stalls.

Because the ports are ephemeral and unconfigurable, nothing can be pre-assigned. The bridge discovers listeners instead:

  1. While enabled for a running project, poll the container for loopback TCP listeners by reading /proc/net/tcp and /proc/net/tcp6 over docker exec — no dependency on ss/netstat/lsof, which aren't guaranteed in the image.
  2. For each newly-appeared loopback listener, bind the same port on the host's 127.0.0.1 (never 0.0.0.0 — that would expose container internals to the LAN).
  3. Proxy each accepted connection into the container over the Docker API via socat - TCP:127.0.0.1:<port> (socat already ships in the image), reusing the existing attached-exec streaming in docker/exec.rs. Going through the Docker API rather than a container IP keeps this working on Docker Desktop, where container IPs are not routable from the host.
  4. Fall back to TCP6:[::1]:<port> when the listener appeared only on IPv6 — on Linux, Node resolves localhost to IPv6 first, so claude login frequently binds ::1 only (anthropics/claude-code#44844).
  5. Tear down when the listener vanishes, the container stops, the bridge is disabled, or the app exits. Ports already covered by the project's explicit port mappings are skipped; host-side conflicts are reported rather than silently swallowed.

Opt-in per project (auth_bridge_enabled, default off), since it makes container-internal loopback services reachable from the host.

Plan: ship A for Claude Code specifically — it removes the pain for the common case at a fraction of the cost — and B as the general mechanism covering every other CLI. They compose: A means most users never trigger a browser login at all; B catches AWS SSO, Concourse, and anything else that needs a real callback.


Sequencing

Phase 0 — done. Remove MCP (frontend, backend, entrypoint, docs) with a self-healing migration for containers created against the old per-project Docker network.

Phase 1 — foundations. Permission modes end-to-end (including the scheduler bug fix below). Read-only introspection backend: sessions, capabilities, scheduler.

Phase 2 — Tier-1 polish. Focus rings, contrast fixes, real buttons, inline start/stop progress, status labels, onboarding welcome screen, shared accessible <Modal>.

Phase 3 — Project Home. Move project config out of the sidebar card into a tabbed main-area view (Overview / Sessions / Automation / Config), dissolving the modal pile and splitting the 1,257-line ProjectCard.

Phase 4 — authentication handoff. Option A, then evaluate B.

Phase 5 — Library. Global skills/agents/commands with per-project enable, synced into the config volume by the entrypoint. Generalizes the pattern the MCP tab was reaching for.


Bugs found during this review

  1. Scheduled tasks ignore the project's permission setting. container/triple-c-task-runner:69 runs claude -p "$PROMPT" --dangerously-skip-permissions unconditionally, regardless of the project's Full Permissions toggle. Being fixed as part of Phase 1.

  2. Docs claim Reset preserves credentials; it does not. rebuild_project_container calls remove_project_volumes, which deletes both triple-c-home-{id} (holding ~/.claude.json) and triple-c-claude-config-{id} (holding ~/.claude). README.md, HOW-TO-USE.md, and CLAUDE.md all still state that OAuth tokens survive a Reset. Pre-existing; not yet corrected.

  3. Stale model placeholders — see "Not yet scheduled" above.

  4. Silent save failures. Project config saves on blur; failures go only to console.error. No user-visible indication. Addressed in Phase 3.