# claude --bg Explained: How Claude Code Runs Background Agents, the Daemon and FleetView

> Source: `2.1.139-unbundled/extracted/src/entrypoints/cli.js` (build version `208bf4b4`, 2026-05-11).
> Official blog reference: [Agent view in Claude Code](https://claude.com/blog/agent-view-in-claude-code).

"Agent view" is **one feature, three entry points, and one on-disk job model**:

| Entry point | Behavior |
|---|---|
| `claude agents` (CLI subcommand) | When the daemon is enabled, it takes the **fast path**: it intercepts before Commander parses `argv` and mounts the **FleetView** TUI. When the daemon is disabled, it falls back to the Commander-registered `agentsHandler`, which is merely a plain-text list of configured subagent definitions. |
| `claude --bg [task]` / `--background` | A brand-new session is started in the background directly by the on-demand daemon; the parent process prints a prompt and exits. |
| `/bg` (slash command, alias of `/background`) | Forks the **current** REPL session into the background, then the foreground process exits. In the interactive REPL, pressing the left arrow key on **empty input** triggers the same fork path, and additionally **remounts** FleetView in-process. |

All three paths ultimately converge on `~/.claude/bg-jobs/<short>/state.json` files plus a Unix domain socket daemon, namely the "on-demand daemon." FleetView is essentially a polling reader for that directory, plus an RPC client connected to the daemon.

Naming convention used below: obfuscated symbols are renamed to semantic names, with the original name attached on first appearance as `/* <original name> */`. Unrenamed symbols (`oqH`, `pT`, `Q7`, `B9`, `Q`, `yH`, `xH`, etc.) are shared helper functions from the host process (state-file I/O, telemetry, graceful shutdown). When porting this to another project, replace them one by one.

---

## 1. Data Model

```ts
// state.json — one per background job, stored in ~/.claude/bg-jobs/<short>/
interface JobState {
  proto: number;                       // I1, schema version number
  short: string;                       // 8-digit hex prefix, used for addressing in CLI / FleetView
  sessionId: string;                   // full uuid, corresponding to transcript filename
  createdAt: string;                   // ISO
  updatedAt: string;                   // ISO, bumped on every write
  firstTerminalAt?: string;            // time it first entered a terminal state

  // Identity / display
  template: { name: string; description: string; initialPrompt?: string };
  agent?: string;                      // if --agent was used, this is the subagent type
  intent: string;                      // first user message, ≤200 characters
  name?: string;                       // explicit -n/--name; otherwise auto-derived
  nameSource?: "user" | "auto";
  detail?: string;                     // excerpt from latest assistant output, ≤120 characters
  color?: string;

  // Activity state
  state: "running" | "stopped" | "errored" | "done" | ...;
  tempo?: "active" | "idle" | "blocked";
  needs?: string;                      // what the agent is waiting for
  block?: { questions?: Question[] };  // when tempo === "blocked"
  suggestedReply?: string;             // prefilled reply completable with Tab in PeekPane
  output?: Record<string, string>;     // several headline lines displayed inline
  inFlight?: unknown;
  resumeSessionId?: string;

  // Sorting / pinning
  sortOrder?: number;
  stateSortOrder?: number;
  pinned?: boolean;

  // Location
  cwd: string;
  originCwd?: string;
  worktreePath?: string;
  worktreeBranch?: string;
  worktreeHookBased?: boolean;

  // Links
  children?: Array<{ id: string; kind: "frame" | "pr" | ...; href: string }>;
  source?: "shell" | "slash" | "fleet" | "spare" | "respawn" | "left_arrow";

  // Other bookkeeping
  respawnFlags?: string[];
  env?: Record<string, string>;
}

interface Question { text: string; options: string[] }

// Row structure constructed in FleetView memory from a JobState
interface JobRow {
  id: string;          // === short
  state: JobState;
  activity: "flowing" | "slowing" | "stuck" | "success" | "failure" | "stopped";
  tempo?: "active" | "idle" | "blocked";
  template: string;    // state.template.name
  children?: JobState["children"];
  origin?: "C8" | ...; // current cwd or another cwd
  group?: string;
}

// FleetView reports back to mountFleetView through this action
type FleetAction =
  | { type: "done" }
  | { type: "open"; job: JobRow; query?: string; collapsed: string[];
      groupMode: "state" | "directory"; jobs: JobRow[];
      loopKicks: Map<string,number>; statuses: Map<string,number>;
      statusesTs: number; prStatuses: Map<string,unknown>;
      respawnResult?: RespawnResult; freshDispatch?: boolean };
```

The “agents” seen by the `agentsHandler` fallback handler are something else: a list of *subagent definitions* (`activeAgents` returned by `uk()`), grouped by source (user / project / local / plugin / built-in). **This has nothing to do with the “session rows” in FleetView.**

---

## 2. Constants and Copy

```ts
// Master switch
const ENV_DISABLE = "CLAUDE_CODE_DISABLE_AGENT_VIEW";
const SETTING_DISABLE = "disableAgentView";            // Managed configuration
const SETTING_DEFAULT_TO_FLEET = "defaultToAgentsView";// User configuration (line 462620)

// Preselect job when launching `claude agents` from a fork
const ENV_PRESELECT = "CLAUDE_AGENTS_SELECT";

// Automatically restart an unfocused fleet view (heartbeat)
const ENV_AUTORELAUNCH = "CLAUDE_AGENTS_AUTO_RELAUNCHED_AT";
const AUTO_RELAUNCH_UNFOCUSED_MS = 3_600_000;          // 1 hour
const AUTO_RELAUNCH_MIN_INTERVAL_MS = 21_600_000;      // 6 hours

// daemon protocol version
declare const I1: number;

// stdin limit for `claude --bg < piped`
const zB8 = 16 * 1024;                                 // bytes

// Hint block printed after each bg dispatch
function formatPostBackgroundHints(short: string, idle?: string) {
  return [
    `backgrounded · ${cyan(short)}${idle ? dim(" " + idle) : ""}`,
    dim("  claude agents".padEnd(28) + "list sessions"),
    dim(`  claude attach ${short}`.padEnd(28) + "open in this terminal"),
    dim(`  claude logs   ${short}`.padEnd(28) + "show recent output"),
    dim(`  claude stop   ${short}`.padEnd(28) + "stop this session"),
  ].join("\n");
}
```

Several key copy strings related to backgrounding:

* `"Backgrounding…"` — spinner shown while starting in the background.
* `"<N> tasks running — the forked session won't carry live processes."` — confirmation dialog subtitle.
* `"Background anyway (tasks will be abandoned)"` / `"Stay"` — confirm / cancel buttons.
* `"Cannot background — session persistence is disabled, so the forked job would have nothing to resume."`

---

## 3. Host-Framework Contract

The table below lists helper functions that the agent view module depends on and that are provided by other modules in `cli.js`. When porting to another project, replace each item with the corresponding implementation on your side.

| Symbol | Signature | Line Number | Purpose |
|---|---|---|---|
| `oqH` | `(seed) => JobState` | used at 542886 | Constructs a new `JobState` with default values. |
| `pT` | `(jobDir, partial) => Promise<void>` | used at 542884 | Atomically merge-writes `state.json`. |
| `Q7` | `(jobDir) => Promise<JobState\|null>` | 542964 | Reads `state.json`. |
| `W4` | `(short) => string` | 542879 | `~/.claude/bg-jobs/<short>/`. |
| `rW` | `() => string` | 543233 | Jobs root directory; prefix lookup scans this with `readdir`. |
| `k_` | `() => string` | 542814 | Current process session id (set in the fork). |
| `L7` | `() => boolean` | 543959 | Whether `CLAUDE_JOB_DIR` exists → i.e. “am I already a background fork”. |
| `getCurrentJobDir` / `Xv3` | `() => string \| undefined` | 544011 | Returns `process.env.CLAUDE_JOB_DIR`. |
| `V$` | `(req, opts?) => Promise<DaemonResp>` | 543031 | Unix socket RPC with the daemon (`op: "list" \| "dispatch"`). |
| `mW_` | `() => Promise<{ok,reason?}>` | 543277 | Daemon health check (used by `claude attach`). |
| `MQ` | `(short) => Promise<{outcome,msg?}>` | 543286 | RPC to “attach me to this job”. |
| `PGK` | `(short, {alreadyInAlt}) => Promise<AttachResult>` | 606723 | Handles bidirectional bridging between the local PTY and the daemon job during attach. |
| `fW6` | `(jobId, {force?,knownState?,knownAlive?}) => Promise<RespawnResult>` | 606700 | Wakes the worker if it has died (re-spawn). |
| `B9` | `(exitCode, reason, opts?) => Promise<never>` | 543885 | Graceful exit for the foreground process. |
| `aH7.setupGracefulShutdown` | — | 651511 | Hooks SIGINT/SIGTERM into `B9`. |
| `cH.createRoot` / `Mu` | `(opts) => Promise<InkRoot>` | 651518 | Creates an Ink root node sharing stdout. |
| `v3_` | `({exitOnCtrlC}) => Promise<InkRoot>` | 606748 | Rebuilds the Ink root after PTY handoff. |
| `Q5.get(process.stdout)?.handoffAltScreen` | — | 606681 | Hands alt-screen control to the PTY for attach. |
| `Q5.get(process.stdout)?.unmount` | — | 606926 | Unmounts Ink before remounting the fleet view in-process. |
| `Q("tengu_*")` / `yH` / `xH` / `j6` | telemetry sink | various | `tengu_bg_dispatch`, `tengu_background_fork`, `fleet_view_*`. |
| `IK("allow_remote_sessions")` | policy check | 644468 | Organization-level switch. |
| `Xc` = `isAgentsFleetEnabled()` | — | 149497 | Main gate: merges managed config, env, and fast-path policy. |
| `fleetGateRejected(verb)` | `(string) => Promise<never>` | 651424 | Prints the rejection reason and exits. |
| `EAH("claude agents")` | — | 604574 | Sets the terminal window title. |
| `vh()` / `zAH()` | string | 606686/606747 | ANSI sequences for entering / leaving alt-screen. |
| `b_()` / `H6(updater)` | config store | 604558/605650 | Persists `fleetViewGroupMode`, etc. |
| `B26(cwd, {q,collapsed})` / `ebK` / `qxK` | bg-view UI state | 604647 | Remembers “last search and collapsed state” by cwd. |
| `s6()` | `() => {columns, rows}` | 604583 | Terminal size. |
| `pA()` | `() => boolean` | 604578 | Whether the terminal is currently focused. |
| `un_()` | alt-screen flag | 606680 | Whether alt-screen is owned. |
| `lT()` | `() => WorktreeInfo \| null` | 606956 | Current worktree information. |
| `g$()` / `qp()` | name lookup | 543840 | User-set / auto-derived job name. |
| `WE(msg)` / `oI(msg)` | transcript helpers | 543828 | Extract assistant/user message body. |
| `viH(text)` | metadata-text predicate | 543834 | Used to skip slash-command echoes when selecting intent. |
| `LD(state)` | `(JobState) => boolean` | 544019 | Whether the job is in a terminal state. |
| `npH(state)` | activity classifier | 602954 | `"success"`/`"failure"`/`"stopped"` or undefined. |

The daemon protocol (`V$`) accepts at least these requests:

```ts
type DaemonReq =
  | { proto: number; op: "list" }
  | { proto: number; op: "dispatch"; d: JobDispatch; timeoutMs?: number };
type JobDispatch = {  // 543001-543027
  proto: number; short: string; sessionId: string; createdAt: number;
  source: "shell"|"slash"|"fleet"|"spare"|"respawn"|"left_arrow";
  cwd: string;
  launch:
    | { mode: "prompt"; args: string[] }
    | { mode: "resume"; sessionId: string; fork: boolean; flagArgs: string[] };
  respawnFlags: string[]; env: Record<string,string>; reattachEnv?: unknown;
  worktree?: { path: string; ownershipToken: string };
  isolation: "worktree" | "none";
  agent?: string; routine?: string;
  seed: { intent: string; name?: string };
  cols?: number; rows?: number;
};
```

---

## 4. Registration

### 4a. `/bg` Slash Command (line 543995)

```ts
const backgroundCommand = {
  type: "local-jsx",
  name: "background",
  aliases: ["bg"],
  description: "Continue this session in the background and free the terminal",
  immediate: (raw) => !raw.trim(),               // Skip confirmation when there is no extra prompt
  isEnabled: () => true,
  load: () => Promise.resolve().then(() => (_loadBgImpl(), _bgImplExports)),
};
```

After `load()` resolves, it yields a module exporting `{ default: handleBgSlashCommand }`, where:

```ts
// line 543958 —— Yv3
const handleBgSlashCommand = async (
  onDone: (err?: string) => void,
  ctx: { messages: Message[] },
  args: string
) => {
  if (L7() /* this is already a bg session */) {
    Q("tengu_background_already_bg", {});
    onDone(); q4H();
    return null;
  }
  if (YDH() /* session persistence is disabled */)
    return (onDone(
      "Cannot background — session persistence is disabled, so the forked job would have nothing to resume."
    ), null);

  const extraPrompt = (args ?? "").trim();
  const seed = extractSeedFromTranscript /*Bf6*/ (ctx.messages, extraPrompt);
  if (seed === null)
    return (onDone("Nothing to background yet — send a message first."), null);

  return React.createElement(BackgroundConfirmDialog /*Jv3*/, {
    onDone, prompt: extraPrompt, seed, messages: ctx.messages,
  });
};
```

### 4b. `/stop` Slash Command (only active inside a bg job, line 544066)

```ts
const stopJsx = {
  type: "local-jsx", name: "stop", immediate: true, isEnabled: L7,
  description: "Stop this background session; transcript and worktree are kept",
  requires: { ink: true },
  load: () => ({ call: (done) => (done(), markSelfStoppedAndExit("stop_command"), null) }),
};
const stopNonInteractive = {
  type: "local", name: "stop", supportsNonInteractive: true,
  isEnabled: L7,
  load: () => ({ call: () => (markSelfStoppedAndExit("bridge"), { type: "skip" }) }),
};
```

### 4c. `claude agents` Commander Subcommand (line 647846, **fallback only**)

```ts
H.command("agents")
  .description("Manage background and configured agents")
  .option("--setting-sources <sources>",
          "Comma-separated list of setting sources to load (user, project, local).")
  .action(async () => {
    const [{ agentsHandler }, { createSubcommandRoot }] = await Promise.all([
      import("./agents-handler.js"),
      import("./subcommand-root.js"),
    ]);
    await agentsHandler(await createSubcommandRoot());
    process.exit(0);
  });
```

### 4d. Global Toggle Configuration Item (line 53308)

```ts
disableAgentView: {
  type: "boolean",
  description:
    "Disable agent view (`claude agents`, `--bg`, /background, the on-demand daemon). " +
    "Typically set in managed settings. Equivalent to CLAUDE_CODE_DISABLE_AGENT_VIEW=1.",
};
```

---

## 5. Entry / Dispatch — `mainCliEntry()` (the CLI `main`)

`mainCliEntry` (obfuscated name `je3`) runs **before Commander**, allowing `claude agents` to enter FleetView directly without going through the heavyweight imports in `main()`.

```ts
// 651265
async function mainCliEntry /*je3*/ () {
  const argv = process.argv.slice(2);

  // … early-return paths for --version / --daemon-worker / --bg-pty-host / --bg-spare / bridge / daemon, etc.

  // ───────── bg verb fast path (line 651387) ─────────
  if (
    argv[0] === "logs" || argv[0] === "attach"  || argv[0] === "stop" ||
    argv[0] === "kill" || argv[0] === "respawn" || argv[0] === "rm"   ||
    argv.includes("--bg") || argv.includes("--background")
  ) {
    if (!isAgentsFleetEnabled()) return fleetGateRejected(verb);
    const bg = await import("./bg-cli.js"); // QGK
    switch (argv[0]) {
      case "logs":    return bg.logsHandler(argv[1]);
      case "attach":  return bg.attachHandler(argv[1]);
      case "stop":    case "kill":  return bg.stopHandler(argv[1]);
      case "rm":      return bg.rmHandler(argv[1]);
      case "respawn": return bg.respawnHandler(argv[1]);
      default: {
        // --bg / --background is still in argv; the first positional is the prompt
        Q("tengu_background", { via_flag: true, via: "flag" });
        await bg.handleBgFlag(argv);
        return process.exit(process.exitCode ?? 0);
      }
    }
  }

  // ───────── fleet-view fast path (line 651485) ─────────
  const wantsAgents = argv[0] === "agents" && argsAreOnlyDebugFlags(argv.slice(1));
  const wantsDefault = argsAreOnlyDebugFlags(argv) && process.stdin.isTTY && process.stdout.isTTY;
  if ((wantsAgents || wantsDefault)) {
    enableConfigs();
    const defaultsToAgents = getGlobalConfig().defaultToAgentsView === true;
    if (wantsAgents || defaultsToAgents) {
      const policyErr = await loadFastPathPolicy();
      if (policyErr) exitWithError(policyErr);
      await ensureFleetGateHydrated();
      if (isAgentsFleetEnabled()) {
        initSinks(); setupGracefulShutdown(); setIsInteractive(true);
        Q("tengu_fleetview", { defaultToAgentsView: defaultsToAgents });
        const root = await createRoot({ exitOnCtrlC: false });
        consumeEarlyInput();
        await mountFleetView(root);
        await gracefulShutdown(0, "other", { suppressResumeHint: true });
        return;
      }
    }
  }

  // … all other cases → main() (i.e. Commander, including the fallback for the agents subcommand)
}

function argsAreOnlyDebugFlags /*caK*/ (argv) {
  for (let i = 0; i < argv.length; i++) {
    const a = argv[i];
    if (["--debug","-d","--debug-to-stderr","-d2e"].includes(a)
        || a.startsWith("--debug=") || a.startsWith("--debug-file=")) continue;
    if (a === "--debug-file" && i + 1 < argv.length) { i++; continue; }
    return false;
  }
  return true;
}
```

> Two key conclusions:
> 1. `claude agents` is the **only** Commander subcommand hijacked before parsing, so its real implementation is `mountFleetView`, not the body inside `.action()` — the latter only runs when `isAgentsFleetEnabled()` returns false.
> 2. A parameterless `claude` also enters FleetView directly when `defaultToAgentsView: true`; otherwise it falls through to `main()` normally and enters the REPL.

---

## 6. `--bg` flag → `handleBgFlag` → daemon dispatch

```ts
// line 543089 — sN3
async function handleBgFlag(argvWithoutFlag: string[]) {
  // argvWithoutFlag is argv after removing --bg / --background
  const rest = argvWithoutFlag.filter((a) => !["--bg","--background"].includes(a));
  const stdinTail = await readBgStdin();      // pGK; truncated past 16 KiB
  const merged = stdinTail ? withStdinPositional(rest, stdinTail) : rest;

  const res = await spawnBgSession(merged);   // pHH → aN3
  if (!res.ok) {
    process.stderr.write(res.error + "\n");
    process.exitCode = 1;
    return;
  }
  process.stdout.write(formatPostBackgroundHints(res.short, res.idle ? "(idle — waiting for…)" : undefined) + "\n");
}
```

### 6a. `spawnBgSession` core — `spawnBgSessionAndDispatch` / `aN3` (line 542926)

Here is the pseudocode after splitting it apart:

```ts
async function spawnBgSessionAndDispatch /*aN3*/ (
  argv, source, cwd, seed /* result of Bf6 */, reattachEnv, t /*ids*/
) {
  const { sessionId, short, jobDir, freshDir } = t;
  const dashDash = argv.indexOf("--");
  const flagArgs = dashDash >= 0 ? argv.slice(0, dashDash) : argv;

  const agentName  = readFlag("--agent", flagArgs);
  const sessionName = readFlag("--name", flagArgs) ?? readFlag("-n", flagArgs);
  const resumeId    = parseResumeTarget(flagArgs);       // FGK
  const promptArg   = dashDash >= 0
    ? argv.slice(dashDash + 1).join(" ")
    : positionalArgFor(argv, resumeId);

  const isResume = flagArgs.some(f => f === "-c" || f === "--continue" ||
                                       f === "-r" || f === "--resume" ||
                                       f.startsWith("--resume=") || f.startsWith("-r="));
  const isFork = flagArgs.includes("--fork-session");
  const respawnFlags = respawnableFlags(flagArgs);       // Ov3
  const dispatchFlagArgs = dashDash >= 0 ? respawnFlags : flagsWithoutPositional(respawnFlags);
  const resumingSelf = resumeId !== undefined && resumeId === sessionId;
  const forkFlag = isResume && !isFork ? ["--fork-session"] : [];
  const sessionArgs = resumingSelf ? [] : ["--session-id", sessionId, ...forkFlag];

  if (source === "shell" && readFlag("--session-id", flagArgs))
    warn("--bg manages the session id; ignoring --session-id (use --resume <id> instead)");

  const subagent = agentName
    ? (await uk(cwd ?? process.cwd())).activeAgents.find(a => a.agentType === agentName)
    : undefined;
  if (agentName && !subagent && source === "shell")
    warn(`no agent named '${agentName}' — spawning with default template`);

  const intent = seed?.intent ?? promptArg ?? "";
  const isIdle = !agentName && intent === "" && !seed?.detail;

  // Pre-write state.json (fleet / spare sources skip this; they carry seed through dispatch)
  if (source !== "fleet" && source !== "spare") {
    const prior = freshDir ? null : await readJobState(jobDir);
    if (prior === null)
      writeJobState(jobDir, oqH({
        template: {
          name: agentName ?? "bg",
          description: subagent?.whenToUse ?? "",
          initialPrompt: subagent?.initialPrompt,
        },
        respawnFlags: dispatchFlagArgs,
        intent,
        name: sessionName ?? seed?.name,
        nameSource: sessionName ? "user" : seed?.nameSource,
        detail: seed?.detail ?? (isIdle ? "(blocked)" : undefined),
        tempo: isIdle ? "blocked" : undefined,
        sessionId, cwd: cwd ?? process.cwd(),
        worktreePath: seed?.worktree?.path,
        worktreeBranch: seed?.worktree?.branch,
        worktreeHookBased: seed?.worktree?.hookBased,
        originCwd: seed?.worktree?.originCwd,
      }));
    else if (dispatchFlagArgs.length && !prior.respawnFlags.length)
      writeJobState(jobDir, { ...prior, respawnFlags: dispatchFlagArgs });
  }

  // Dispatch to daemon
  const dispatch = {
    proto: I1, short, sessionId, createdAt: Date.now(),
    source: source === "repl" ? "slash" : source,
    cwd: cwd ?? process.cwd(),
    launch: isResume && resumeId
      ? { mode: "resume", sessionId: resumeId,
          fork: !resumingSelf && (isFork || forkFlag.length > 0),
          flagArgs: [...respawnFlags, ...(dashDash >= 0 ? argv.slice(dashDash) : [])] }
      : { mode: "prompt", args: [...sessionArgs, ...positionalsAfterFlags(argv)] },
    respawnFlags, env: bgEnvWhitelist(), reattachEnv,
    worktree: seed?.worktree && { path: seed.worktree.path, ownershipToken: sessionId },
    isolation: subagent?.isolation === "worktree" && subagent.source !== "built-in" ? "worktree" : "none",
    agent: agentName, routine: undefined,
    seed: { intent, name: sessionName ?? seed?.name },
    cols: process.stdout.columns, rows: process.stdout.rows,
  };
  const r = await daemonRpcDispatch(dispatch);          // AB8 → V$
  if (r.ok) return { ok: true, short, sessionId, idle: isIdle };

  // Fallback branches:
  //  - ack-timeout / enoconn but op:"list" shows the worker is still alive → treat as success
  //  - ack-timeout and it does not appear in list → dispatch once more
  //  - short-alive → friendly "session is already running" error
  //  - stale-short → "previous session is still shutting down; try again later"
  //  - daemon-unreachable → exit and suggest running status
  // (see lines 543030-543087)
}
```

### 6b. Merging stdin as a positional — `withStdinPositional` / `BGK` (line 543129)

If the user pipes prompt text into `--bg` and argv already contains a positional, the stdin tail is **appended to the final positional** (separated by a newline), so the daemon only sees one merged prompt. If argv contains no positional, a new entry is added after the `--` sentinel.

### 6c. Supporting CLI verbs (from line 543217)

* `claude logs <prefix>` → `logsHandler` — opens a 500 ms RPC subscription to the daemon, prints the `streamTail` snapshot, then exits.
* `claude attach <prefix>` → `attachHandler` — first performs a health check (`mW_`), then `MQ(short)` takes over the PTY; retries up to 20 times on `ERESPAWNING`; for `ENOJOB`, reads content from `state.json` to provide a more useful error message.
* `claude stop / kill / rm / respawn <prefix>` → corresponding handlers (registered together via `M_(QGK,…)` at line 542861).

All prefix arguments are resolved through `resolveJobByShortPrefix /* jB8 */` (line 543217): it scans `~/.claude/bg-jobs/` with `readdir` and ensures the prefix is unique.

---

## 7. `/bg` Slash Command — Confirmation Dialog and Seed Extraction

### 7a. `extractSeedFromTranscript` — `Bf6` (line 543822)

Traverses the transcript from bottom to top and produces `{ intent, name, nameSource, detail }`:

```ts
function extractSeedFromTranscript(messages, override) {
  let firstUserText = override, hasNonMetaUser = false, lastAssistant: string|undefined;
  for (let i = messages.length - 1; i >= 0; i--) {
    const m = messages[i];
    if (m.type === "assistant" && lastAssistant === undefined) {
      const text = WE(m);                   // body text of the bottom-most assistant message
      if (text) lastAssistant = text.replace(/\s+/g," ").trim().slice(0,120);
    }
    if (m.type === "user" && !m.isMeta && !QY6(m)) {
      const text = oI(m)?.trim();
      if (text && viH(text)) continue;      // skips slash-command echo
      hasNonMetaUser = true;
      if (!firstUserText && text) firstUserText = text;
    }
    if (hasNonMetaUser && firstUserText && lastAssistant !== undefined) break;
  }
  if (!hasNonMetaUser) return null;         // "Nothing to background yet"
  const userName = g$(jobSessionId());
  const autoName = qp(jobSessionId());
  return {
    intent: (firstUserText || "(backgrounded)").slice(0, 200),
    name:   userName ?? autoName,
    nameSource: userName ? "user" : autoName ? "auto" : undefined,
    detail: lastAssistant,
  };
}
```

### 7b. `BackgroundConfirmDialog` — `Jv3` (line 543849)

* Reads two AppState fields via `J_`:
  * `effortValue` (`Dv3`)
  * `taskCount` (`jv3` — `state.tasks`)
* **If the number of in-flight tasks is 0**, the component auto-confirms on its first render (`React.useState(taskCount === 0)`).
* Otherwise, renders a `<ConfirmDialog>` with title **"Background this session?"**, subtitle `"<N> tasks running — the forked session won't carry live processes."`, and buttons **"Background anyway (tasks will be abandoned)"** and **"Stay"**.
* After confirmation:
  ```ts
  const r = await forkCurrentSessionToBackground /*pf6*/ (
    seed, extraPrompt, effortValue, "command", messages
  );
  Q("tengu_background_fork", {
    confirmed: taskCount > 0, inflight_count: taskCount,
    had_prompt: extraPrompt.length > 0,
    had_worktree: r.hadWorktree, worktree_handed_off: r.handedOff,
  });
  onDone();
  await B9(0, "prompt_input_exit", {
    suppressResumeHint: true,
    finalMessage: formatPostBackgroundHints(r.short, r.handedOff ? "(worktree handed off)" : undefined),
  });
  ```
* `forkCurrentSessionToBackground` (`pf6`, same module) — calls `spawnBgSession` with `source: "slash"`, hands off the active worktree, and tears down the bridge / daemon listeners (`DV()`).

### 7c. `markSelfStoppedAndExit` — `Uf6` (line 544013)

```ts
async function markSelfStoppedAndExit(source: "stop_command"|"bridge") {
  Q("tengu_bg_agent_action", { action: "stop", source, jobSessionId: jobSessionId() });
  const dir = process.env.CLAUDE_JOB_DIR;
  if (L7() && dir) {
    const now = new Date().toISOString();
    const cur = await readJobState(dir);
    if (cur && !isJobTerminal(cur))
      await writeJobState(dir, {
        ...cur, state: "stopped", detail: "stopped from session",
        tempo: "idle", needs: undefined, block: undefined, inFlight: undefined,
        updatedAt: now,
        firstTerminalAt: cur.firstTerminalAt ?? now,
      });
    if (isInteractive()) process.stdout.write(formatExitNotice("Session stopped."));
  }
  return B9(0, "prompt_input_exit", { suppressResumeHint: true });
}
```

---

## 8. FleetView — TUI Section

### 8a. `mountFleetView` — `uQ3` (line 606636)

The main loop is simply **render → wait for action → maybe attach → unmount and remount**. It has exclusive ownership of the alt-screen for the entire lifecycle of the agent view.

```ts
async function mountFleetView(inkRoot) {
  Q("tengu_bg_agent_action", { action: "list_open" });
  setTerminalTitle("claude agents");

  const preselectId = process.env.CLAUDE_AGENTS_SELECT;
  delete process.env.CLAUDE_AGENTS_SELECT;               // one-time use
  const persisted = await loadFleetUiState(currentCwd());// qxK
  let query     = persisted?.q;
  let collapsed = persisted?.collapsed;
  let jobId     = preselectId;
  let error: string | undefined;
  let groupMode: "state"|"directory"|undefined;
  let savedAppState: any;

  for (;;) {
    const action = await new Promise<FleetAction>((resolve) => {
      inkRoot.render(
        <ProcessTitleProvider>
          <AppStateBoundary
            initialState={savedAppState && {...savedAppState, notifications:{current:null,queue:[]}}}
            onChangeAppState={({newState}) => savedAppState = newState}
          >
            <ContextProviders>
              <ScrollFrame>
                <FleetView
                  onAction={resolve}
                  initialJobId={jobId}
                  initialQuery={query}
                  initialCollapsed={collapsed}
                  initialError={error}
                  initialGroupMode={groupMode}
                />
              </ScrollFrame>
            </ContextProviders>
          </AppStateBoundary>
        </ProcessTitleProvider>,
      );
    });

    const inAlt = ownsAltScreen();                       // un_
    if (inAlt && action.type === "open") handoffAltScreen();
    if (!inAlt) inkRoot.render(null);
    inkRoot.unmount();

    if (action.type === "done") break;

    // ── action.type === "open" → attach ──
    if (isWindows() && process.stdin.isTTY) { process.stdin.setRawMode(true); process.stdin.ref(); }
    const restoreCursor = inAlt
      ? batchUpdate(() => process.stdout.write(altScreenReentry()))
      : () => {};

    jobId     = action.job.id;
    query     = action.query;
    collapsed = action.collapsed;
    groupMode = action.groupMode;
    cachedJobs       = action.jobs;
    cachedLoopKicks  = action.loopKicks;
    cachedStatuses   = action.statuses;
    cachedStatusesTs = action.statusesTs;
    cachedPrStatuses = action.prStatuses;
    cachedFirstMount = true;

    const respawn = action.respawnResult ?? await respawnJob(action.job.id, {
      knownState: action.freshDispatch ? undefined : action.job.state,
      knownAlive: (Date.now() - action.statusesTs < 1500
                   && action.statuses.get(action.job.state.resumeSessionId
                                          ?? action.job.state.sessionId) !== undefined)
                  ? true : undefined,
    });

    if (respawn.ok || respawn.alive) {
      logFleetViewLifecycle("attach", action.job.state);
      process.stdout.write(SET_TITLE(renderJobLabel(action.job.state, true)));
      let attach = await attachJob(respawn.short ?? action.job.id, { alreadyInAlt: inAlt });

      if (attach.kind === "error" && attach.orphaned) {
        // last-ditch effort: force one respawn and retry
        const re = await respawnJob(action.job.id, { force: true, knownState: action.job.state });
        if (re.ok || re.alive) attach = await attachJob(re.short ?? action.job.id, { alreadyInAlt: inAlt });
        else attach = { kind: "error", msg: re.error };
      }
      if (attach.kind === "error" && !attach.ended) {
        error = attach.msg;
        xH("fleet_view_open", "attach_failed");
      } else {
        if (attach.msg) error = attach.msg;
        yH("fleet_view_open");
      }
      logFleetViewLifecycle("detach", action.job.state, { attachDurationMs: Date.now() - tStart });
    } else {
      error = respawn.error;
      xH("fleet_view_open", "respawn_failed");
    }

    if (inAlt) process.stdout.write(restoreAltMargins());
    inkRoot = await createRoot({ exitOnCtrlC: false });
    restoreCursor();
  }
}
```

### 8b. `FleetView` Component — `tmK` (line 604467) — State Machine

Internal component state, roughly ordered by `useState` / `useRef` order:

| Slot | Purpose |
|---|---|
| `jobs` / `setJobs` (`A, z`) | The currently mounted `JobRow` list. `null` during bootstrap. Snapshot mirrored into `$.current` for callbacks. |
| `incomingJobs` (`Y, w`) | Jobs launched during this mount that are still waiting for `state.json` to land on disk. |
| `prStatuses` (`F, g`) | PR check status cache. |
| `cursorIndex` (`d, a`) | Index into the flattened row list `h9`. |
| `peekJob` (`_H, t`) | The job currently being peeked. |
| `dispatchFolded` (`qH, i`) | Whether the `"queued/folded"` section is collapsed. |
| `replyDrafts` (`e.current`) | `Map<jobId, draftText>`: inline reply drafts in the peek panel. |
| `replyErr` (`$H, AH`) | Most recent reply failure message. |
| `helpOpen` (`s, o`) / `confirmDelete` (`HH, KH`) / `selectMenu` (`jH, YH`) | Various overlay modals. |
| `exiting` (`MH, kH`) | Secondary exit confirmation; `LH = ph(setExiting, () => onAction({type:"done"}))` wires together Ctrl+C. |
| `renaming` (`WH, DH`) | The job currently being renamed, or `null`. |
| `attaching` (`XH, NH`) | ID of the job currently being respawned before attach. |
| `error` (`$9, L6`) | Toast / error row. |
| `groupMode` (`tH, v_`) — `"state" \| "directory"` | Persisted to `b_().fleetViewGroupMode`. |
| `collapsedGroups` (`UH, BH`) — `Set<string>` | Persisted per cwd. |
| `manuallyCollapsedPinned` (`FH, q_`) | Used when the pinned section is manually collapsed without affecting the persisted set. |
| `cwd` (`L`) → ultimately resolved to repo root (`_Y(cwd)`). |
| `pinnedDir` map (`u, b`) | Fast pin mapping by cwd. |
| `query` / `cursorOffset` (from the multiline input hook `v0(...)`) | Search box. |

It also imports several helpers from the same module (lines 602820–602850), including `repoGroup({cwd})` (`Nd8`), `pickIcon`, `jobLabel`, and `childStatusColor`.

### 8c. Key Bindings — `handleFleetViewKeyDown` / `wS` (line 605589)

```markdown
When the overlay is showing (`renaming` / `attaching`):
  Ctrl+C        Cancel overlay
  up/down       Pass through to the overlay’s own scrolling logic
  other         Forward to the overlay’s internal input handling

Global:
  Ctrl+C        Clear input → close help / delete confirmation if open → otherwise exit
  Escape        Close help → close delete confirmation → close fold help → close menu → clear input → disarm armed action → onAction("done")
  Shift+up/dn   Move job within group (`Sy` / `SY`)
  Ctrl+R        Rename selected job   (`renaming = job.id`)
  Ctrl+S        Toggle grouping mode between "state" ↔ "directory"
  Ctrl+G        Expand / replace in query
  Ctrl+T        Pin / unpin selected job
  up / Ctrl+P   Move cursor (or scroll completion suggestions)
  down / Ctrl+N Move cursor
  Ctrl+X (when help is open) → Kill armed action target
  Tab           Accept slash suggestion / toggle `dispatchFolded`
  →             Attach current row (i.e. the right-arrow in the blog post)
  ⌘/Super+1-9   Attach the Nth row in the current cwd group
  Return        If input is empty: recognize /exit/quit and exit → otherwise submit suggestion → parse "<template> <intent>",
                  dispatch a new bg job → (Shift+Return ⇒ additionally auto-attach via {type:"open", freshDispatch:true})
  Space-empty input Toggle peek mode for current row (i.e. "peek" in the blog post)
```

The "left arrow key" in FleetView is handled by the multiline input hook (`v0`’s default cancel) — when the input is empty, it falls back to `onCancel: setExiting`, then `ph` takes over to perform the "press once more to confirm exit" flow (`LH`).

### 8d. Peek pane — `PeekPane` / `WQ3` (line 603580)

This is the "peek mode" described in the blog post: selecting a row without fully attaching.

* Reads `q.state.updatedAt` and renders `r7(now - updated)` to show "Last interaction X ago". It re-renders every 1s within the most recent minute, otherwise every 30s.
* Picks three informational lines from `q.state.output` (excluding duplicates of inline child-list labels), then adds `state.needs` and `state.detail`, adapting to terminal height.
* It has **its own** `v0` input box, bound to `replyDrafts.get(jobId)`:
  * `onSpaceOnEmpty: onBack` — Space exits peek.
  * `onTabOnEmpty: () => setQuery(suggestedReply); Q("tengu_prompt_suggestion", { outcome: "accepted", source: "fleetview_peek" })` — Tab accepts `state.suggestedReply` (only present when `tempo === "blocked"` and there is no questions form).
  * `onExit` → submits the draft via `onReply(formattedDraft)`; after success, the worker on the daemon side automatically resumes — this is the implementation of "inline replies auto-resume" from the blog post.
* If `state.tempo === "blocked"` and `state.block.questions` exists, renders a `<QuestionForm>` (`jH = 2 + opts.length + 1` lines of extra layout space).

### 8e. Visual indicator rules

* **Row color / activity glyph** = `jobActivityForRow(jobRow, prStatuses)` → `"flowing" | "slowing" | "stuck" | "success" | "failure" | "stopped"`. The "slowing" / "stuck" thresholds come from `updatedAt`:
  * `tempo === "active"`: 3 minutes → "flowing"; over 15 minutes → "stuck".
  * Otherwise: 15 minutes → "flowing"; over 75 minutes → "stuck".
* **"awaits input"** = `tempo === "blocked"` (when `block.questions` exists) or `state.needs` is non-empty.
* **"actively processing"** = `tempo === "active"` and not in a terminal state.
* **"completed"** = `LD(state)` is true.
* **"next run time"** (looping job) = `vd8(jobRow, loopNextRun)`, displayed as `"in <duration>"`.

---
```

## 9. Persistence

* **One `state.json` per job** — The single source of truth for FleetView and `claude logs/attach/...`. Written via atomic merge with `pT(jobDir, partial)`.
* **`~/.claude/bg-jobs/`** — A collection of `<short>/` subdirectories. stdout/stderr are the worker’s PTY history (read via daemon RPC, **not** from disk).
* **FleetView UI state (by cwd)** — `B26(cwd, { q, collapsed })` uses the repo path as the key, loads via `qxK(repoRoot)`, and writes with a 300 ms debounce.
* **Grouping mode preference** — `b_().fleetViewGroupMode` is written to the user config repository via `H6(updater)`.
* **Daemon socket / heartbeat** — `.fleetview-heartbeat` lock file (`Moq`, line 104916).

---

## 10. End-to-End Timing

```text
A) `claude --bg "ship the redis fix"`

  argv enters mainCliEntry() → hits `argv.includes("--bg")` (line 651394)
        │
        ▼
  fleetGate ok → handleBgFlag(argv)                  [543089]
        │   stdin (TTY) → ""; rest = argv \ ["--bg"]
        ▼
  spawnBgSession(rest)                               [pHH, 542905]
        │ generates sessionId, short, jobDir
        ▼
  spawnBgSessionAndDispatch                          [aN3, 542926]
        │  • writes state.json (seed data)
        │  • constructs JobDispatch
        ▼
  daemon V$ {op:"dispatch", d}                       [543031]
        │  daemon may return ok / ack-timeout / enoconn / short-alive / stale-short
        ▼  redispatch / rescue loop on ack-timeout
  stdout ← formatPostBackgroundHints(short, idle?)   [543177]
  exit 0


B) Entering `/bg` in a live session

  REPL receives /bg → loads handleBgSlashCommand      [Yv3, 543958]
        │ guards: already bg / persistence disabled
        ▼
  extractSeedFromTranscript walks transcript → {intent,name,detail}
        ▼
  <BackgroundConfirmDialog/>                         [Jv3, 543849]
        │  task=0 auto-confirms; otherwise shows <ConfirmDialog>
        ▼
  forkCurrentSessionToBackground(seed, prompt, effort, "command", messages)  [pf6]
        │  same dispatch path as --bg, but source="slash"; hands off worktree, detaches bridge
        ▼
  Q("tengu_background_fork", …)
  onDone() → B9(0, "prompt_input_exit", {finalMessage: formatPostBackgroundHints(short, …)})


C) `claude agents` (or pressing ← in the REPL)

  ← in REPL → forkAndOpenFleetViewFromRepl(messages, effort, autoName)  [KpK, 606947]
        │  extractSeedFromTranscript (allows empty) → wB8 prewrites state.json
        │  forkCurrentSessionToBackground starts bg fork
        │  Q("tengu_open_agents_via_left")
        │  if tengu_bg_leftarrow_inprocess flag is true:
        │    → remountFleetViewInProcess (preselects this short)
        │  otherwise:
        │    → FjH({ args:["agents"], env:{CLAUDE_AGENTS_SELECT: short} })  ← execs a new claude

  `claude agents`  →  mainCliEntry() → argsAreOnlyDebugFlags passes → isAgentsFleetEnabled()
        │
        ▼
  mountFleetView(root)                               [uQ3, 606636]
        ┌──────────────── loop ────────────────┐
        ▼                                      │
  <FleetView/> renders → user navigation ──────┤
        │                                      │
        ▼ onAction === "open"                  │
  respawnJob → attachJob (PTY)                 │
        │ user work → eventually detach        │
        ▼ onAction === "done"                  │
  gracefulShutdown(0)                          │
        └──────────────────────────────────────┘
```

---

## 11. Pitfalls / Correction Notes

1. **`claude agents` is a blend of two commands.** The Commander-registered `agentsHandler` (`Cs3`) at line 647846 only takes effect when fleet view is **disabled**; it outputs a list of subagent definitions grouped by source. The "agent view" mentioned in the blog is actually the fast-path FleetView at line 651485.
2. **`/bg` is an alias.** The real name is `/background` (line 543999), with `bg` listed under `aliases`. `immediate: (raw) => !raw.trim()` means typing plain `/bg<Enter>` skips JSX confirmation; including prompt text will get stuck in the React tree.
3. **`/bg` and `--bg` use the same dispatch path.** The only differences are: (a) the `source` field written to `state.json` differs; (b) whether the parent process needs to split off a worktree/bridge. The daemon does not distinguish between them at all.
4. **`L7()` ("whether in bg") ≠ "session has been backgrounded".** It returns true if and only if this process has `CLAUDE_JOB_DIR` set — i.e. "I am that fork." The foreground process that just spawned the fork still does not count as "backgrounded"; therefore, after dispatch, `/bg` calls `B9(0, "prompt_input_exit")` to make the foreground exit proactively.
5. **`CLAUDE_AGENTS_SELECT` is one-shot.** `mountFleetView` deletes the env var as soon as it reads it (line 606640), preventing a long-lived fleet view from being locked onto some stale id.
6. **The "Background anyway" copy refers to tasks, not files.** The `taskCount` it reads (`jv3 = state => state.tasks`) comes from AppState’s `tasks` map — meaning bash/long-running tools — **not** in-flight requests. They are two different concepts, even though the UI copy only mentions tasks.
7. **Left-arrow exit only works when input is empty.** The actual trigger is the multiline input hook `v0`’s `onCancel`; when input has content, the left arrow only moves the cursor.
8. **`disableAgentView` is the sole global kill switch.** Once set (via managed config or env), `claude agents` falls back to `agentsHandler`, `--bg`/`--background` is blocked by the gate, and although the `/background` slash command’s `isEnabled` is always true, its internal `pHH` still fails at `fleetGateRejected`; the daemon also refuses to start it.
9. **`spawnBgSession` rescues two specific daemon failures**: `ack-timeout` (the worker is still alive, but the daemon’s reply was lost) and `enoconn` (the RPC socket disappeared mid-flight). It first sends `op:"list"` as a probe, then either declares success or attempts one resubmission.
10. **Polling cadence.** In FleetView, peek timestamps re-render every 1s (within the last minute) or 30s (older). But the file watcher / RPC poller frequency lives in another module (around `seedLastJobs` near 602820 plus another set of hooks). This part needs to be rewritten separately when porting.
11. **`claude` enters FleetView by default with `defaultToAgentsView: true`.** After the user enables it in the settings panel (line 462620), running bare `claude` goes straight in — easy to trigger accidentally.

---

## 12. Minimal Implementation Checklist for Porting to Other Projects

If you want to bring "agent view + /bg" to another shell (such as a fork of some Anthropic CLI, or an unrelated assistant CLI):

1. **Disk model.** `~/.claude/bg-jobs/<short>/state.json`: atomic merge writes, `readdir` prefix lookup, and the `JobState` schema defined in Section 1.
2. **Daemon.** A Unix socket service that supports at least `{op:"list"}`, `{op:"dispatch", d:JobDispatch}`, and a per-job PTY attach RPC. On macOS/Linux, use one per-user `unix:` protocol socket; on Windows, use a named pipe with the same JSON envelope. Include a `fast_path_policy` marker so it can be hard-disabled by managed config.
3. **Worker.** Launched by the daemon with the environment from `JobDispatch.env`; the environment includes `CLAUDE_JOB_DIR=<dir>` and `--session-id <uuid>`, with the prompt as the final positional argument. The worker updates its own `state.json` (intent, name, output, tempo, block).
4. **`/bg` slash command.** `local-jsx`, `aliases: ["bg"]`. The seed is obtained by scanning the transcript bottom-up (skipping meta and slash-command echoes). If `state.tasks > 0`, show a confirmation prompt; otherwise confirm automatically.
5. **`--bg` CLI flag.** Strip this flag, read piped stdin (truncate to 16 KiB), and invoke the same dispatcher. On success, print a 5-line hint block.
6. **`claude logs / attach / stop / kill / rm / respawn <prefix>`.** Resolve the prefix to the full short ID and send the RPC. Be careful with `attach`: it must take over the PTY and tolerate `ERESPAWNING`.
7. **FleetView TUI.**
   * `mountFleetView(inkRoot)` loop: render → wait for `{type:"open"|"done"}` → if `open`, respawn + attachJob + render again after detach.
   * Inside the component: UI state persisted by cwd (query + collapsed), state/directory grouping toggle, dual-purpose peek panel (both view and return), multiline input, rename overlay, delete confirmation overlay, help overlay, drag-to-reorder within groups.
   * Maintain a separate `attaching` ref to prevent the same row from being triggered twice by double-clicks.
8. **Gates.** Managed config `disableAgentView` + env `CLAUDE_CODE_DISABLE_AGENT_VIEW` + `fast_path_policy` returned by org policy. Every entry point must pass through the same `isAgentsFleetEnabled()`.
9. **Telemetry.** At minimum: `tengu_background` (flag/slash), `tengu_background_fork`, `tengu_bg_dispatch`, `tengu_bg_dispatch_fallback`, `tengu_bg_dispatch_rescued`, `tengu_open_agents_via_left`, `tengu_fleetview`, `tengu_bg_agent_action`, `tengu_prompt_suggestion`, plus all `fleet_view_*` action verbs (open / rename / pin_toggle / reorder / stop / attach / detach).
10. **Left arrow → agents.** Hook the REPL input box when it is "empty + left arrow": (a) seed a fresh bg fork from the current transcript, (b) tear down the current worktree/bridge, (c) prefer in-process remounting of fleet view; fall back to `exec` if that fails.
11. **Risk-disclosure gating.** `--bg` combined with `bypassPermissions` or `auto` permission mode must first be confirmed once interactively — do not bypass the checks around lines 543643-543646, to avoid headless dispatch sneaking past the UX gate.

---

## 13. Symbol Mapping Quick Reference

### bg-cli and slash command modules (`QGK` / `gW_`)

| Renamed | Obfuscated name | Line |
|---|---|---|
| `preSeedReplBgJob` | `wB8` | 542877 |
| `spawnBgSession` | `pHH` | 542905 |
| `spawnBgSessionAndDispatch` | `aN3` | 542926 |
| `markBgDispatchSucceeded` | `IGK` | 542802 |
| `markBgDispatchFellThrough` | `OB8` | 542820 |
| `handleBgFlag` | `sN3` | 543089 |
| `readBgStdin` | `pGK` | 543108 |
| `withStdinPositional` | `BGK` | 543129 |
| `humanizeDispatchFailureReason` | `tN3` | 543163 |
| `formatPostBackgroundHints` | `mf6` | 543177 |
| `bgVerbExtraArgsNote` | `UGK` | 543188 |
| `resolveJobByShortPrefix` | `jB8` | 543217 |
| `logsHandler` | `eN3` | 543246 |
| `attachHandler` | `Hv3` | 543271 |
| `stopHandler` | `qv3` | (see export at 542863) |
| `rmHandler` | `Kv3` | (see export at 542865) |
| `respawnHandler` | `_v3` | (see export at 542866) |
| `parseResumeTarget` | `FGK` | (see export at 542869) |
| `flagsWithoutPositional` | `gGK` | (see export at 542873) |
| `extractSeedFromTranscript` | `Bf6` | 543822 |
| `BackgroundConfirmDialog` | `Jv3` | 543849 |
| `handleBgSlashCommand` | `Yv3` | 543958 |
| `BG_CLI_FLAG_ALIASES` (`["--bg","--background"]`) | `oN3` | 543733 |
| `forkCurrentSessionToBackground` | `pf6` | (calls at 543875, 606981) |
| `BG_SLASH_COMMAND_DEF` | `Mv3` / `fv3` | 543999 |
| `getCurrentJobDir` | `Xv3` | 544011 |
| `markSelfStoppedAndExit` | `Uf6` | 544013 |
| `stopSlashJsxCall` | `Pv3` | 544047 |
| `stopBridgeNonInteractiveCall` | `Wv3` | 544055 |

### FleetView module (`bd8` / `xd8`)

| Renamed | Obfuscated name | Line |
|---|---|---|
| `FleetView` (component) | `tmK` | 604467 |
| `mountFleetView` | `uQ3` | 606636 |
| `remountFleetViewInProcess` | `emK` | 606921 |
| `forkAndOpenFleetViewFromRepl` | `KpK` | 606947 |
| `PeekPane` (component) | `WQ3` | 603580 |
| `renderJobLabel` | `ZW6` | 602868 |
| `formatJobAgeOrCountdown` | `vd8` | 602863 |
| `classifyJobActivity` | `jW6` | 602953 |
| `deriveStateBand` | `IvH` | 602971 |
| `repoGroupKey` | `Nd8` | 604497 |
| `parseDispatchInput` | `Zd8` | 603040 |
| `parseSearchQuery` | `BmK` | 603002 |
| `pruneMap` | `Pd8` | 602855 |
| `logFleetViewLifecycle("peek"\|"attach"\|"detach")` | `Rd8` | 603598 |
| `handleFleetViewKeyDown` | `wS` | 605589 |
| `swapAdjacentJobsInGroup` | `SY` | 605532 |
| `attachJobOrSurfaceError` | `YS` | 605454 |
| `runRowKeyAction` | `lj` | 605425 |

### CLI Entry and Commander

| Renamed | Obfuscated name | Line |
|---|---|---|
| `mainCliEntry` | `je3` | 651265 |
| `argsAreOnlyDebugFlags` | `caK` | 651245 |
| `agentsHandler` (fallback — lists agent definitions, not jobs) | `Cs3` | 644428 |
| `AgentsList` (fallback component) | `FoK` | 644390 |
| `formatAgentDefinitionRow` | `BoK` | 644383 |
| `renderAgentSourceGroup` | `Es3` | 644416 |
| `isAgentsFleetEnabled` | `Xc` | 149497 |
| `fleetGateRejected` | (re-exported under the same name) | 651424 |

### Configuration / Constants

| Renamed | Obfuscated name | Line |
|---|---|---|
| `SETTING_DISABLE` (`"disableAgentView"`) | `y` | 53308 |
| `SETTING_DEFAULT_TO_FLEET` (`"defaultToAgentsView"`) | — | 462620 |
| `ENV_PRESELECT` (`"CLAUDE_AGENTS_SELECT"`) | — | 606639 |
| `ENV_AUTORELAUNCH` (`"CLAUDE_AGENTS_AUTO_RELAUNCHED_AT"`) | `Xd8` | 606765 |
| `AUTO_RELAUNCH_UNFOCUSED_MS` | `YW6` | 606763 |
| `AUTO_RELAUNCH_MIN_INTERVAL_MS` | `umK` | 606764 |
| `FLEETVIEW_HEARTBEAT` (`.fleetview-heartbeat`) | `Moq` | 104916 |
