How-to

Claude Code agent teams that share files safely

Fred Chang ·

When Claude Code starts a helper agent, the helper gets every tool and every permission you have. So what could happen is that this agent you asked for could also happen to rewrite it. The better way is to give each agent its own agentleFS identity, limited to one folder, and then any mistake stays inside that folder.

TLDR: connect your main Claude Code session (the lead) to agentleFS. Have it create one limited identity per subagent. Point each subagent at its own key. Retire them all with one call when the work is done.

What are Claude Code subagents and agent teams?

Both split work across several Claude contexts:¹ ²

SubagentsAgent swarms
What it isA helper with its own context window, defined in .claude/agents/Several full Claude Code sessions: one lead, the rest teammates
How they talkReturn a result to the callerMessage each other and share a task list
StatusBuilt inExperimental, off until you set CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
NestingUp to three layers below the main conversationTeammates cannot spawn teammates

Use subagents when only the answer matters, and a swarm when the agents need to debate.

What does a Claude Code subagent inherit?

  • MCP tools. These are the outside services your session connects to, such as agentleFS. "Subagents inherit the built-in tools and MCP tools available in the main conversation."¹ So every subagent can write wherever your session can, unless disallowedTools removes the tool.
  • Permission mode. This decides whether Claude Code asks before it acts. If the main conversation runs in bypassPermissions, acceptEdits or auto mode, "the subagent runs in that same mode". Its own permissionMode is ignored.¹
  • Teammates too. "If the lead runs with --dangerously-skip-permissions, all teammates do too."²

How agentleFS scopes each agent

In agentleFS an agent is an identity under whoever started it. It can reach only what its person can reach.

  • A scope, not a copy. Each agent you spawn gets a role (Viewer, Editor or Manager) at one location, such as viewer@projects/launch. It can never exceed its parent. If your access shrinks, so does the agent's.
  • Ending a link cuts everything below. Retire an agent and everything it spawned ends too. A child never outlives its parent's expiry.
  • A record. agentleFS keeps every version. It logs every read, write and refusal with the chain: subagent, lead, person.

The caveat: a client that signs in through the browser, Claude Code included, acts as you, with your full access. Only the identities it spawns are narrowed.

A delegation chain. Fred, a person, connects a lead Claude Code session with a browser sign-in, which reaches everything Fred can open. The lead spawns researcher, scoped viewer@projects/launch, which can only read that folder, and drafter, scoped editor@projects/launch/drafts, which can write only there. Drafter spawns a helper limited to one file. Each scope sits inside its parent's. Revoking the lead ends all three below it at once.
Each link can only narrow what the one above it reaches. Revoke the lead and everything it spawned ends with it.

A worked example: a lead and two scoped subagents

projects/launch holds research notes and a drafts folder. I want one subagent that only reads, and one that writes only drafts.

1. Spawn two identities. In a Claude Code session connected to agentleFS:

In afs, spawn two agents with bootstrap keys, expiring Friday:
"researcher" with scope viewer@projects/launch, and
"drafter" with scope editor@projects/launch/drafts.
Don't print the keys. Save them to my macOS Keychain
as afs-researcher and afs-drafter.

Why not just have it show you each key once? Because whatever Claude prints lands in the chat transcript, and the transcript is saved. So the key you meant to see once is sitting there for good. In the Keychain it stays out of the chat, and you take it out only when an agent needs it.

Your terminal has the same problem. If you type export AFS_DRAFTER_KEY=afs_…, your shell saves that whole line, key included, to its history file. The better way is to load the key without ever typing it:

# From the Keychain, where Claude saved them
export AFS_RESEARCHER_KEY="$(security find-generic-password -s afs-researcher -w)"
export AFS_DRAFTER_KEY="$(security find-generic-password -s afs-drafter -w)"

# Or from 1Password (use your own vault and item names)
export AFS_DRAFTER_KEY="$(op read 'op://Private/afs-drafter/password')"

# Or paste it in: nothing shows on screen, and nothing goes to history
read -rs AFS_DRAFTER_KEY && export AFS_DRAFTER_KEY

Export each key only in the terminal that runs that agent, never in ~/.zshrc, where every program you start would get it. Here both subagents run under the lead, so both keys go in the terminal where you start that claude. And never paste a key into CLAUDE.md or into an .mcp.json you commit. The subagent file below holds only ${AFS_RESEARCHER_KEY}, the variable's name, and Claude Code fills in the key from your terminal.

If a key leaks anyway, it can't do much. It reaches one folder, it stops working on Friday, and retiring an agent cuts off every agent it started.

2. Give each subagent its own connection. A subagent file can define its own MCP server, with the same schema as .mcp.json. Claude Code fills in ${VAR} in its headers from your environment.¹ ⁴ .claude/agents/researcher.md:

---
name: researcher
description: Reads the launch notes and comments on gaps. Never edits.
disallowedTools: mcp__plugin_agentlefs_agentlefs
mcpServers:
  - afs-researcher:
      type: http
      url: https://mcp.agentlefs.com/mcp
      headers:
        Authorization: "Bearer ${AFS_RESEARCHER_KEY}"
---
Read projects/launch in afs. Where a claim has no source,
leave a comment on that sentence. Do not edit files.

drafter.md is the same, with AFS_DRAFTER_KEY and a prompt to write in projects/launch/drafts.

disallowedTools removes the lead's own agentleFS tools, which carry my full access. Their name depends on how you installed agentleFS. It is mcp__plugin_agentlefs_agentlefs from the plugin, which the connect prompt installs, or mcp__agentlefs if you ran claude mcp add agentlefs. /mcp shows which.

3. Run it. "Use the researcher to check the launch notes, then the drafter to write the announcement." If the drafter writes outside drafts, or the researcher tries to edit, the server refuses. The prompt said "never edits". The scope makes it true.

4. End it. "In afs, retire researcher and drafter." By default each gets an hour to publish anything worth keeping. Ask for a zero window to end them now. Then its key stops working, and anything it spawned ends too. If I forget, Friday's expiry does it.

With an agent team, use split panes. Teammates in split panes apply a subagent definition's mcpServers. In-process teammates load your project's servers instead,² and with them the lead's full access.

Can a subagent spawn its own subagents?

In Claude Code, up to three layers deep.¹ In agentleFS a child gets only part of its parent's scope. The drafter could give a helper editor@projects/launch/drafts/intro.md, but never projects. Retiring the drafter ends the helper.

Try it: sign up free at agentlefs.com, then paste into Claude Code: Set up agentleFS for me by following https://agentlefs.com/connect.md

Related

  1. 1. Anthropic, "Create custom subagents", Claude Code docs.
  2. 2. Anthropic, "Orchestrate teams of Claude Code sessions", Claude Code docs.
  3. 3. Anthropic, "Choose a permission mode", Claude Code docs.
  4. 4. Anthropic, "Connect Claude Code to tools via MCP": environment variable expansion in .mcp.json.