CLAUDE LABJP
FORK — Claude Code 2.1.212 changes what /fork does: it copies your conversation into a new background session with its own row in claude agents, so you can keep working. The old in-session subagent is now /subtaskLIMITS — WebSearch calls are now capped at 200 per session by default, and subagent spawns get the same 200 ceiling, so a runaway search or delegation loop stops on its ownMCPBG — MCP tool calls running past two minutes now move to the background automatically, keeping the session usable. Tune the threshold with CLAUDE_CODE_MCP_AUTO_BACKGROUND_MSPLANFIX — Fixed plan mode auto-running file-modifying Bash commands such as touch and rm without a permission prompt or an SDK canUseTool callbackSONNET5 — Claude Sonnet 5 is running on introductory pricing of $2 per million input tokens and $10 per million output. After August 31 it moves to $3 and $15IPO — Bankers are reportedly lining up investor meetings for Anthropic ahead of a possible public listing as soon as OctoberFORK — Claude Code 2.1.212 changes what /fork does: it copies your conversation into a new background session with its own row in claude agents, so you can keep working. The old in-session subagent is now /subtaskLIMITS — WebSearch calls are now capped at 200 per session by default, and subagent spawns get the same 200 ceiling, so a runaway search or delegation loop stops on its ownMCPBG — MCP tool calls running past two minutes now move to the background automatically, keeping the session usable. Tune the threshold with CLAUDE_CODE_MCP_AUTO_BACKGROUND_MSPLANFIX — Fixed plan mode auto-running file-modifying Bash commands such as touch and rm without a permission prompt or an SDK canUseTool callbackSONNET5 — Claude Sonnet 5 is running on introductory pricing of $2 per million input tokens and $10 per million output. After August 31 it moves to $3 and $15IPO — Bankers are reportedly lining up investor meetings for Anthropic ahead of a possible public listing as soon as October
Articles/Claude Code
Claude Code/2026-05-18Intermediate

Why Your `cd` and `export` Vanish Between Claude Code Bash Calls

Claude Code's Bash tool runs each call in a fresh shell, so cd and export never persist. Here's the symptom, the cause, and five practical patterns I use across my Dolice Labs pipelines.

Claude Code197Bash4Shell2Troubleshooting11Automation39

If you've started handing Claude Code anything more than the simplest tasks, you've probably run into this: you call cd some-dir in one Bash invocation, then run ls in the next, and the output comes back from your home directory instead. The same thing happens with export FOO=bar — the next call sees an empty $FOO.

I burned the better part of a morning on this when I rebuilt the automated content pipeline for Dolice Labs, the four-site Claude/Gemini/Antigravity/Rork blog network I run as an indie developer. Once you understand the reason, the fix is one line. But until you do, it really looks like Claude Code is broken.

Symptom — Your cd is Silently Discarded

A short reproduction:

# Bash call #1
cd /tmp/repos/claudelab.net
# Bash call #2
ls
# → returns the home directory listing, not the repo

export behaves the same way:

# Call #1
export GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxx
# Call #2
echo "$GITHUB_TOKEN"
# → empty

What makes this confusing is that if you paste both calls into your own terminal, it works exactly as expected. That's why so many people start assuming the tool is buggy. It isn't — the behavior is intentional.

Cause — Each Bash Call Spawns a Brand-New Shell

Claude Code (and the mcp__workspace__bash tool in Cowork mode) starts a new subprocess for every Bash invocation. The moment the call returns, the process is destroyed along with any state mutations: cwd, exported variables, shell options, all of it.

The Cowork bash tool description spells this out: "Each call is independent — no cwd/env carryover between calls. Use absolute paths." Claude Code's main Bash tool follows the same model. Mentally, it's closest to "a remote shell that does not share history between commands."

Once you internalize that, the fix is simple: stop trying to carry state across calls. Below are the five patterns I rely on day to day.

Fix 1 — Chain Everything with && in a Single Call

This is the workhorse. Whenever a cd is followed by an action, both belong in the same Bash invocation, joined with &&.

# Bad — the cd is lost
cd /tmp/repos/claudelab.net
git pull --rebase origin main
 
# Good — one call, one shell
cd /tmp/repos/claudelab.net && git pull --rebase origin main

It's a one-line trick, but in my experience it eliminates roughly 70% of the related failures by itself. Pinning this rule in CLAUDE.md (something like "when running multiple shell steps, combine them into a single Bash call with &&") cuts down on auto-generation accidents as well.

Fix 2 — Use Absolute Paths Aggressively

The other half of the answer is "don't use cd if you don't have to." Across my Dolice Labs scheduled tasks, I deliberately avoid cd and operate on absolute paths.

# Bad — depends on an implicit cwd
cd content/articles/ja
ls
 
# Good — absolute
ls /tmp/repos/claudelab.net/content/articles/ja

git -C <dir> <subcmd> follows the same spirit and lets you pin the working directory without ever moving:

git -C /tmp/repos/claudelab.net pull --rebase origin main
git -C /tmp/repos/claudelab.net add content/
git -C /tmp/repos/claudelab.net commit -m "Add new article"
git -C /tmp/repos/claudelab.net push origin main

This survives being split across multiple Bash calls without any extra ceremony.

Fix 3 — Pass Environment Variables Inline

export doesn't survive between calls either. For values used in a single command, set them inline:

# Bad
export GITHUB_TOKEN=ghp_xxxxxxxx
git clone https://${GITHUB_TOKEN}@github.com/foo/bar.git
 
# Good — variable scoped to the single command line
GITHUB_TOKEN=ghp_xxxxxxxx git clone https://${GITHUB_TOKEN}@github.com/foo/bar.git

Hardcoding a token per call is obviously a bad idea, so in my pipelines I read it from a file on the workspace each time I need it:

GITHUB_TOKEN=$(grep -A1 "^Claude Lab" "${WS}/_documents/_github_tokens/github_tokens.txt" | tail -1 | tr -d '[:space:]')
git clone --depth 1 "https://${GITHUB_TOKEN}@github.com/masakihirokawa/claudelab.net.git" /tmp/repos/claudelab.net

Variables that you reference repeatedly, like $WS, are simpler to recompute at the top of each Bash call (WS=$(ls -d /sessions/*/mnt/Dolice\ Labs | head -1)) than to try to share.

Fix 4 — Persist Long-Lived Values in CLAUDE.md or a Tempfile

For values you'd otherwise want to set once and forget — repo paths, the location of your tokens — put the convention in CLAUDE.md ("repos live under /tmp/repos/<site>", "PATs are read from _documents/_github_tokens/"). Claude Code will pick up those rules and reconstruct them in each Bash call.

If you really need to round-trip a value between two calls, write it to a tempfile:

# Call #1: stash state on disk
echo "/tmp/repos/claudelab.net" > /tmp/cc_workdir
echo "ghp_xxxxxxxx" > /tmp/cc_token
 
# Call #2: read it back
WORK=$(cat /tmp/cc_workdir)
TOKEN=$(cat /tmp/cc_token)
git -C "$WORK" push "https://${TOKEN}@github.com/foo/bar.git" main

For anything sensitive, delete the file right after use (rm /tmp/cc_token).

Fix 5 — Pull Complex Pipelines Into a Shell Script

Once a workflow involves three or more cd/export moves, stop fighting one-liners. Write the whole thing to a script file and invoke it:

cat << 'EOF' > /tmp/deploy.sh
#!/bin/bash
set -euo pipefail
WORK=/tmp/repos/claudelab.net
TOKEN=$(cat /tmp/cc_token)
cd "$WORK"
git pull --rebase origin main
# the actual long-running steps
git add content/
git commit -m "Daily content update"
git push "https://${TOKEN}@github.com/masakihirokawa/claudelab.net.git" main
EOF
chmod +x /tmp/deploy.sh
 
# A separate Bash call runs the script
bash /tmp/deploy.sh

set -euo pipefail makes the script fail loudly instead of silently skipping past a broken step, which saves a lot of debugging time. There's also a side benefit: you can reproduce the exact same script in your own terminal.

The Same Constraint Applies to Related Tools

The "discard state on return" model isn't unique to the Bash tool. Claude Code's PowerShell tool starts a fresh session per call, so Set-Location doesn't persist either. Cowork's mcp__workspace__bash works the same way. Sub-agents (the Task tool) also don't inherit variables or cwd from the caller.

The Claude Code ecosystem as a whole is built around stateless execution units. Aligning your own scripts with that assumption — rather than fighting it — turns out to be the durable path.

Design Rules I Settled On

When I cleaned up the four Dolice Labs pipelines, I converged on three rules and have stuck with them since:

  1. Every Bash call should be safely re-runnable on its own. Makes partial reruns and debugging much easier.
  2. State travels via files or path arguments, not variables. A tempfile under /tmp, or a fully qualified path passed in.
  3. Anywhere you'd write cd, replace it with && chaining or git -C. Over the long run this has been the lowest-incident policy.

Across the Cowork-scheduled jobs that push 4 articles per day per site (16 articles daily across the network), incidents in the "the cd didn't take effect" category have essentially fallen to zero since the switch. I've been online since 1997 and writing software professionally for years, but the "discard state per call" model still felt unusual at first. Getting fluent with it is, I'd argue, part of the shell literacy required for the agentic era.

Hope this saves someone the half-day I lost to it. Next time you hand Claude Code a multi-step Bash plan, the first question to ask is simply: "can this be one line joined with &&?"

Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Claude Code2026-06-19
An Article My Gate Rejected Got Published — The Cost of Chaining the Quality Gate and git push in One Call
In an unattended publishing pipeline, an article my quality gate had rejected went live anyway. The cause was chaining the gate and git push into a single shell call. Here is how the exit code gets swallowed, and a two-phase publish-marker design that refuses to push until every gate has demonstrably passed.
Claude Code2026-05-20
Claude Code Says 'All Tests Pass' but CI Goes Red — Designing Around Exit Code Pitfalls
Locally, Claude Code reports 'all tests pass.' You push it, and GitHub Actions turns red within minutes. The root cause is usually not Claude Code itself but how the shell and the test runner interpret exit codes. Here is a practical, experience-backed walkthrough.
Claude Code2026-07-18
Branch with /fork, Delegate with /subtask — Two Commands That Traded Jobs
In Claude Code 2.1.212, /fork now clones your conversation into a background session, and in-session subagents moved to /subtask. Here is how I decide between them, and the budgets worth setting before you start branching freely.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →