# 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](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 `. | | 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](https://github.com/anthropics/claude-code/issues/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:` (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]:` 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](https://github.com/anthropics/claude-code/issues/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 ``. **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.