Tình huống

Bạn chưa có session nào đang chạy. Bạn gõ claude agents trong terminal, FleetView mở ra với list rỗng. Bạn muốn dispatch một session mới làm việc trong ~/WORK/some-project.

Làm thế nào để session mới đó có cwd = ~/WORK/some-project?

Câu trả lời thường bị nhầm và câu trả lời đúng nằm ở hai chỗ khác nhau. Đi qua từng cái.

Misconception lớn nhất: claude agents không tự tạo session

Trước khi nói về cwd, làm rõ điểm này. Nhiều người (kể cả tôi lúc mới chuyển từ tmux sang) gõ claude agents ở folder X, thấy UI mở ra rồi đóng lại (bấm q hoặc thoát terminal), expect là đã có một session mới được tạo ở folder X. Sau đó kiểm tra roster, không thấy session nào. Tưởng có bug.

Không phải bug. claude agents là lệnh mở UI, không phải lệnh tạo session. Hai chuyện tách biệt:

  1. claude agents → mở FleetView UI. Process này không tự sinh worker mới. Nó chỉ render list và đợi bạn dispatch.
  2. Trong UI, gõ prompt vào input ở phía dưới rồi Enter → mới spawn session mới.

Nếu chỉ làm bước 1 rồi quit, không có gì xảy ra. Tương đương mở top rồi đóng: không khởi động process mới.

Lưu ý phân biệt với lệnh claude (không có agents): gõ claude ở folder X tạo session mới ở folder X ngay lập tức (claim worker từ spare pool). Đó là vì sao reflex của nhiều người là claude agents = claude + view cũng tạo session, nhưng đó là sai.

LệnhMở UI?Tạo session ngay?
claudeKhông (attach trực tiếp vào session mới)
claude agentsCó (FleetView TUI)Không, đợi bạn dispatch trong UI

Anti-pattern: --cwd flag

Phản xạ đầu tiên là gõ:

claude agents --cwd ~/WORK/some-project

Sai. Đọc help của lệnh:

--cwd <path>    Show only background sessions started under <path>

--cwdfilter list view, không phải set cwd cho dispatch. (Flag được thêm vào CC 2.1.141 với mô tả chính thức scope the session list to a directory.) Nếu trong roster chưa có session nào start dưới path đó, FleetView sẽ hiển thị empty (vì filter loại hết), nhưng session bạn dispatch mới sẽ vẫn lấy cwd từ chỗ khác.

Bỏ flag đó. Dùng cách 1 hoặc cách 2 bên dưới.

Workflow ba bước. Cả ba đều bắt buộc:

Bước 1. cd vào folder bạn muốn session mới chạy:

cd ~/WORK/some-project

Bước 2. Mở FleetView:

claude agents

Lúc này UI mở ra. Chưa có session mới nào sinh ra. UI thừa hưởng process.cwd() của shell, ghi nhớ nó để dùng cho bước 3.

Bước 3. Trong UI, gõ prompt đầu tiên vào input phía dưới rồi Enter.

Đây là bước hay bị bỏ qua nhất. Bạn phải gõ một câu prompt (kể cả ngắn như “hello”) rồi Enter thì session mới spawn. Quit UI ở bước 2 mà chưa Enter prompt = không có session nào được tạo.

Cơ sở của bước 2 ghi nhớ cwd: trong code dispatch của FleetView (binary 2.1.143):

let A = K ?? E_();  // K là cwd argument, E_() là process.cwd()

Nếu dispatch không nhận cwd argument, FleetView lấy process.cwd() của chính nó. Tức là thư mục lúc bạn chạy claude agents.

Verify session mới có cwd đúng (chạy ở terminal khác sau khi đã dispatch):

jq '.workers | to_entries[] | select(.value.dispatch.source == "fleet") | {short:.key, cwd:.value.cwd}' \
  ~/.claude/daemon/roster.json

Workflow này predictable và không phải nhớ cú pháp gì. Chỉ cần nhớ là Bước 3 không phải optional.

Cách 2: @<alias> trong prompt FleetView

Parser prompt của FleetView (hàm on8 trong binary) hỗ trợ cú pháp @<keyword> ngay trong text bạn gõ. Cụ thể logic:

function on8(input, agents, cwdMap, routines) {
  // tách @<keyword> ra khỏi input string
  // match keyword theo thứ tự ưu tiên:
  //   1. tên agent  →  set agent template
  //   2. tên routine →  set routine
  //   3. key trong cwdMap → set cwd
  // còn lại của input là intent prompt
}

Vấn đề: cwdMap không phải là object mà bạn có thể gõ path tùy ý. Nó là một map có sẵn được FleetView khởi tạo từ:

  • Agent definitions có field cwd trong frontmatter (~/.claude/agents/*.md)
  • Routines (scheduled agents) có cwd config
  • Một số recent / pinned dirs (chưa kiểm chứng đầy đủ)

Tức là @my-project chỉ work nếu trước đó bạn đã định nghĩa một agent hoặc routine với cwd cho project đó. Default không có gì cả.

Khi mở FleetView, gõ @ rồi xem UI có suggest gì không. Nếu UI hiện autocomplete list các keyword với cwd kèm theo, đó chính là cwdMap của bạn. Nếu không suggest gì, map đang rỗng và bạn phải dùng cách 1.

Cách 3: đã lỡ start claude? Dùng /bg để convert

Workflow này dành cho ai đã quen claude foreground (không phải claude agents). Bạn start một session interactive bình thường, làm việc một lúc, rồi nhận ra muốn track session đó qua FleetView (ví dụ để check từ phone hoặc SSH session khác). Không phải kill rồi dispatch lại; có cách chuyển tại chỗ.

Bước 1. cd và start session foreground:

cd ~/WORK/some-project
claude

Lúc này bạn có session interactive, prompt đợi gõ. Trong daemon roster, session này có dispatch.source: "spare". FleetView filter spare worker (xem bài daemon architecture), nên session chưa xuất hiện trong claude agents ở terminal khác. Đây là behavior bình thường, không phải bug.

Bước 2. Ngay trong session đó, gõ slash command /bg:

/bg

/bg convert session foreground sang background:

  • Daemon update dispatch.source từ spare sang bg ngay lập tức.
  • Terminal được detach khỏi PTY của worker (session vẫn sống và giữ context, chỉ là terminal không attach nữa).
  • Lần refresh tiếp theo, FleetView thấy worker có source != "spare" mà chưa có state.json → trigger orphan adoption → session xuất hiện.

Bước 3. Mở claude agents (hoặc đợi nó refresh nếu đang mở). Session vừa convert sẽ nằm trong list, kèm cwd của folder ở bước 1.

So sánh tóm tắt:

CáchKhởi tạodispatch.sourceXuất hiện trong FleetView
1dispatch trực tiếp từ UIfleetNgay
3claude foreground rồi /bgsparebgSau orphan adoption (vài giây)
(không làm gì)claude foreground để nguyênspareTrễ 30-60s, đợi daemon tự update

Cách 3 hữu ích khi:

  • Đã start session vì cần interactive ngay, sau đó nhận ra cần track qua mobile (Telegram bridge hoặc SSH vào FleetView từ phone).
  • Muốn giữ workflow quen cd + claude, chỉ thêm một slash command khi cần tách session khỏi terminal.
  • Sắp đóng laptop / tắt terminal đi đâu đó, không muốn session theo đó mà die.

Reverse direction cũng có: từ FleetView attach lại vào session background, terminal sẽ pull session trở thành foreground tại chỗ. Hữu ích khi quay về desk và muốn tiếp tục interactive.

Cách 4: claude --bg để tạo background session ngay từ shell

Nếu bạn biết trước session này sẽ chạy background (không cần interactive trước), có cờ shell --bg để skip bước foreground luôn. Cách 3 là chuyển foreground sang background; cách 4 là start background trực tiếp.

Bước 1. cd vào folder muốn session chạy trong đó:

cd ~/WORK/some-project

Bước 2. Chạy claude --bg:

claude --bg

Daemon spawn worker mới với cwd inherit từ shell, đánh dấu là background ngay, ghi state.json, rồi trả về cho bạn shell prompt kèm hint commands:

backgrounded · ea956980 (idle, send a prompt to start)
  claude agents       list sessions
  claude attach ea956980  open in this terminal
  claude logs ea956980    show recent output
  claude stop ea956980    stop this session

ea956980 là short ID của session vừa tạo. Status là idle vì chưa có prompt. Để dispatch prompt đầu, dùng một trong các cách:

  • claude attach ea956980 rồi gõ prompt trực tiếp (terminal pull session về foreground).
  • Mở claude agents, navigate tới session đó, gõ prompt trong UI.
  • RemoteTrigger / Cron / SDK gọi vào session theo short ID.

Bước 3 (optional). claude agents để verify session đã trong list.

So sánh cách 3 và cách 4:

CáchKhởi tạoLúc nào dùng
3: claude rồi /bgĐã có session foreground, đang interactiveĐang làm việc rồi mới quyết định background, vd cần tắt terminal
4: claude --bgChưa có session, biết trước sẽ backgroundPre-create session để dispatch sau, dùng cho RemoteTrigger / Telegram / script

Cách 4 cleaner cho automation và workflow batch. Cách 3 mượt cho interactive-then-detach. Cả hai đều cho session hiện trong FleetView ngay sau khi chạy, source ban đầu là spare nhưng được đánh dấu background hợp lệ.

Shell alias để mượt

Nếu bạn thường xuyên mở claude agents cho nhiều project khác nhau, lưu một function vào shell rc:

# ~/.zshrc (hoặc ~/.bashrc)
ccagents() {
  if [ -z "$1" ]; then
    claude agents
  else
    cd "$1" && claude agents
  fi
}

Dùng:

ccagents ~/WORK/some-project
# hoặc không tham số = dispatch tại cwd hiện tại
ccagents

Với tab completion cho path, gõ rất nhanh. Đây là cách mình recommend cho ai làm việc nhiều project song song.

Verify session đã đúng cwd

Sau khi dispatch, có hai cách kiểm tra:

Trong UI FleetView: cột “cwd” của session sẽ hiển thị path. Nhìn lướt là ra.

Từ terminal khác:

# Liệt kê tất cả worker đang chạy với cwd của chúng
jq '.workers | to_entries[] | {short:.key, cwd:.value.cwd, source:.value.dispatch.source}' \
  ~/.claude/daemon/roster.json

Hoặc đọc file state của session vừa dispatch:

cat ~/.claude/jobs/<short>/state.json | jq '.cwd, .originCwd'

originCwd ghi nhớ cwd lúc dispatch (không đổi). cwd có thể thay đổi nếu session dùng worktree (sẽ thành path worktree thay vì path gốc).

TL;DR

Mục đíchCách làm
Tạo session mới (bất kể cwd)Sau claude agents, phải gõ prompt rồi Enter trong UI. Quit UI mà không Enter = không có session nào
Dispatch session với cwd cụ thểcd <folder> && claude agents rồi Enter prompt trong UI
Đã start claude foreground, muốn nó hiện trong FleetViewTrong session đó gõ /bg để convert sang background
Tạo background session trực tiếp từ shell (cho automation / pre-dispatch)cd <folder> && claude --bg, lấy short ID, dispatch prompt sau qua attach / FleetView
Quick switch giữa nhiều projectShell function ccagents <path>
Filter list chỉ session start dưới một pathclaude agents --cwd <path> (chú ý: filter, không phải set)
Dispatch với cwd preset đã định nghĩa@<alias> trong prompt FleetView (cần agent/routine có cwd field)

Mặc định: cách 1 nếu khởi tạo từ FleetView UI, cách 3 nếu đã start claude foreground rồi mới muốn track, cách 4 nếu biết trước sẽ background (automation, pre-create). Các cách còn lại cho use-case advanced.

Liên quan

Bài này bổ sung cho hai bài khác cùng chủ đề kiến trúc daemon + FleetView + session lifecycle: