How Claude Code lays out the forks, subagents, workflows, tasks and teams of a session inside an identity's configuration directory. It is the reference the agent-tree reader is written against, and the disk half of the picture rc-agent-events.md joins to. The layout belongs to Claude Code, not this project: it has changed across versions, so every field below except the ones named as always present is optional, and a reader must tolerate absence rather than assume it.
All paths are relative to an identity's configuration directory. projects is a shared-history entry the farm links, so a reader follows symlinks.
A session's transcript is projects/<project-slug>/<session-id>.jsonl. Everything its agents produced sits in a sibling directory named for the session id:
projects/<project-slug>/<session-id>/subagents/agent-<agent-id>.jsonl
projects/<project-slug>/<session-id>/subagents/agent-<agent-id>.meta.json
projects/<project-slug>/<session-id>/subagents/workflows/wf_<run-id>/agent-<agent-id>.{jsonl,meta.json}
projects/<project-slug>/<session-id>/workflows/wf_<run-id>.json
A session that was superseded keeps its directory under <session-id>.superseded-<epoch-ms>. A replaced transcript may also be archived as <session-id>.orphaned-<epoch-ms>-<hash>.jsonl (reported upstream in anthropics/claude-code#85404); the reader treats both as archived copies of the session they name, not as live sessions.
The stem after agent- is the agent id, and for an unnamed agent it equals the task_id of the matching task_started event on the Remote Control read stream. An agent spawned with a name has a longer stem, the name and a hash, whose correspondence to the stream's task_id has not been observed.
One JSON object. Always present: agentType. Everything else is optional and appears only for the agent kinds and versions that write it.
| Field | Meaning |
|---|---|
agentType |
The subagent type, such as general-purpose, Explore, Plan, a plugin-namespaced type, workflow-subagent for an agent a workflow spawned, or fork. |
isFork |
true for a fork, which inherits the parent's context. Present beside agentType: "fork". |
description, name |
The spawn call's short description and the agent's addressable name. |
toolUseId |
The id of the tool_use block in the parent transcript that spawned it. The parent link. |
spawnDepth |
Nesting depth, where 1 is spawned by the session itself. |
parentAgentId |
The spawning agent, when that is another subagent. |
model |
The model the spawn recorded, or inherit; not necessarily the model that served its requests. |
requestShape, requestNonInteractive |
foreground or background, and whether the request was non-interactive. |
workflowPhase |
The workflow phase title an agent belongs to. |
taskKind, teamName |
in_process_teammate and the team, for a teammate. |
worktreePath, worktreeBranch, spawnedWithWorktree, inheritedWorktreePath, worktreeCleanlyRemoved |
Worktree isolation facts. |
stoppedByUser |
The user stopped it. |
A workflow agent's meta may hold nothing but agentType and spawnDepth; its run is identified by the wf_<run-id> directory it sits in, and its phase by workflowPhase where present.
JSON lines in the same shape as a session transcript: type (user, assistant, attachment), message, uuid, parentUuid, timestamp, isSidechain: true, agentId, sessionId, cwd, version. The first user message is the prompt the parent handed it.
workflows/wf_<run-id>.json is the run's record: runId, workflowName, status, startTime, durationMs, phases (titles), workflowProgress, defaultModel, agentCount, totalTokens, totalToolCalls, summary, result, script, scriptPath and taskId. ~/.claude/workflows/ itself holds workflow scripts, not runs.
tasks/session-<first eight characters of the session id>/<n>.jsonin current versions andtasks/<session-id>/<n>.jsonin older ones, and for a session with teammatestasks/<team-name>/<n>.json, the team's shared list: one file per task:id,subject,description,status,blocks,blockedBy, and optionallyactiveForm,owner(the assigned teammate) andmetadata. Status values seen includepending,in_progress,completed, and a few non-standard ones (todo,done), so treat it as an open string. A.highwatermarkand a.lockfile sit beside them. A session pointed at a shared list withCLAUDE_CODE_TASK_LIST_IDwrites totasks/<that-id>instead; the variable belongs to the process environment and appears in no session file, so a reader can only be told the id. A resumed session may write under a new runtime id, which is likewise unrecorded; the same option covers it.todos/<session-id>-agent-<agent-id>.json: a per-agent todo array, empty when unused.teams/<team>/config.json:name,createdAt,leadAgentId,leadSessionIdandmembers(agentId,name,agentType,joinedAt,cwd,backendType,subscriptions). Messages live inteams/<team>/inboxes/<member>.json, an array offrom,text,timestamp,color,read.jobs/<id>/state.json: a background job'sstate(running,working,blocked,done,failed,stoppedseen),detail,inFlight,sessionId,resumeSessionId,cwd,createdAtandupdatedAt;timeline.jsonlbeside it holdsat,state,detail,textrows.
The session transcript's bridge-session entries carry sessionId (local) and bridgeSessionId (the cse_ id) with lastSequenceNum, which is the join to Remote Control. See rc-agent-events.md.