Documentation
¶
Overview ¶
Package onboarding implements cc-fleet's first-run guided setup: it covers two teammate-mode prerequisites — tmux and agent-teams — guides the user to fix them WITH CONSENT, and persists the user's decisions so later runs never re-nag.
What each prerequisite detects differs deliberately:
- tmux presence is something cc-fleet CAN observe directly (tmux.go).
- agent-teams *runtime enablement* can NOT be observed by an external process (it's a Claude runtime state, commonly default-on via GrowthBook with no env var). So we only detect whether agent-teams has been EXPLICITLY CONFIGURED — AgentTeamsConfigured (agentteams.go) reads four sources: the current env, the user's shell rc files, and the global + project settings.json env blocks — and word the nudge as a suggestion, never an assertion that it's "off".
The consented, idempotent ~/.claude/settings.json merge (EnableAgentTeams) also lives in agentteams.go; it is cc-fleet's only write to the user's main settings, fired only when the user explicitly chooses "enable it for me".
The orchestration (TUI screens, TTY gating) lives in cmd/cc-fleet/onboarding.go + internal/tui; this package holds the pure, unit-testable pieces: per- capability decision persistence (state.go — State stores TmuxAck / AgentTeamsAck, NOT a single FirstRunDone), agent-teams config detection + settings merge (agentteams.go), tmux presence + setup gating (tmux.go), and the OS-specific tmux install hint (osinfo.go).
It is invoked ONLY from the bare-interactive TUI path, so it never blocks headless / agent callers.
Index ¶
Constants ¶
const AgentTeamsEnvVar = "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS"
AgentTeamsEnvVar is the env key Claude Code reads to enable its experimental agent-teams runtime (native TeamCreate / SendMessage).
Variables ¶
This section is empty.
Functions ¶
func AgentTeamsConfigured ¶
func AgentTeamsConfigured() bool
AgentTeamsConfigured reports whether the agent-teams env var is set truthy in ANY source cc-fleet can read: the current environment, the user's shell rc files, or Claude's global / project settings.json env block. Every probe is best-effort — an unreadable or malformed source is simply skipped.
func EnableAgentTeams ¶
EnableAgentTeams idempotently merges
{"env": {"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"}}
into the user's MAIN ~/.claude/settings.json. It is invoked ONLY when the user explicitly chooses "enable it for me" in the first-run setup screen, so the write is consented. It is deliberately conservative:
- reads + parses the existing file (missing/empty → start from {});
- preserves EVERY other top-level key and env entry byte-for-byte (json.RawMessage), touching only env.<var>;
- writes atomically at 0600 via fileutil.AtomicWrite (a failed write never truncates the existing file);
- is idempotent: when the var is already "1" it writes nothing and returns already=true.
A top-level non-object document, or a non-object `env`, is a hard error — we refuse to clobber a shape we don't understand. The caller must tell the user to restart claude: the env block applies at claude STARTUP, so the write has no effect on the running session.
func NeedsAgentTeamsSetup ¶
func NeedsAgentTeamsSetup() bool
NeedsAgentTeamsSetup reports whether the first-run TUI should show the agent-teams setup nudge: the var is not configured in any source we can read AND the user hasn't dismissed the nudge before.
IMPORTANT — this detects whether agent-teams has been EXPLICITLY CONFIGURED, NOT whether it is ENABLED at runtime. Claude commonly turns agent-teams on by default (GrowthBook) leaving no env var / flag, which an external process can't observe. So "not configured" ≠ "off": the nudge is therefore worded as a suggestion (never an assertion that it's off) and is shown at most once — after any choice, AgentTeamsAck is set.
func NeedsTmuxSetup ¶
func NeedsTmuxSetup() bool
NeedsTmuxSetup reports whether the first-run TUI should show the tmux setup screen: tmux isn't installed AND the user hasn't already chosen "skip — subagent mode only" (TmuxAck).
func StatePath ¶
StatePath returns ~/.config/cc-fleet/onboarding.json (XDG-aware via config.ConfigDir).
func TmuxInstallHint ¶
func TmuxInstallHint() string
TmuxInstallHint returns the OS-appropriate command to install tmux. It NEVER runs anything and NEVER uses sudo on the user's behalf: the string is shown for the user to run themselves. Detection is deliberately coarse — GOOS plus a light /etc/os-release sniff on Linux is enough to pick the right package manager; we don't enumerate every distro.
Types ¶
type State ¶
type State struct {
Version int `json:"version"`
TmuxAck bool `json:"tmux_ack"`
AgentTeamsAck bool `json:"agent_teams_ack"`
}
State is the persisted record of the user's onboarding DECISIONS, one ack per capability:
- TmuxAck: the user chose "skip — subagent mode only" on the tmux setup screen, so we never nudge about tmux again. (Choosing "install it" does NOT ack — once tmux is actually present the nudge stops on its own; if it isn't, the nudge should keep showing.)
- AgentTeamsAck: the user dealt with the agent-teams setup screen (any choice), so it never shows again.
We do NOT persist a capability cache. tmux presence and agent-teams *configuration* are detected fresh each run (cheap, reliable). agent-teams *runtime enablement* is never detected — it's a Claude runtime state an external process can't observe; the ack only records that the user dealt with the one-time nudge.