How to Set Up Claude Code on Daytona

How to create a Daytona workspace, install Claude Code inside it, and run a fully cloud-based agent — laptop closed, session persistent, optionally accessible from your phone.

To set up Claude Code on Daytona, create a workspace from your Git repo, install Claude Code with npm install -g @anthropic-ai/claude-code, wrap the session in tmux, and — critically — disable the workspace auto-stop timer before running any long task. Daytona workspaces spin up in under 90ms and run on cloud infrastructure independently of your laptop, but four non-obvious gotchas can silently kill sessions mid-task if you skip them. This guide covers the full lifecycle: workspace provisioning, Claude Code installation, Grass CLI setup for phone-based monitoring without SSH, and the devcontainer approach for zero-reinstall workspace restarts.

TL;DR

  • Create workspace: daytona create --repo https://github.com/your-org/your-repo
  • Set auto_stop_interval = 0 in workspace settings before starting any long task
  • Install both tools: npm install -g @anthropic-ai/claude-code @grass-ai/ide
  • Wrap in tmux, set ANTHROPIC_API_KEY, run grass start --network tailscale
  • Scan the QR code from the Grass app — no SSH terminal needed on your phone from that point

Why Daytona instead of a DIY VPS?

Daytona workspaces cold-start in under 90ms — compared to 30–60 seconds to provision a DigitalOcean or Hetzner droplet from scratch — per a comparison of Daytona, AgentBox, and DIY VPS setups. On a DIY VPS you also manage OS updates, SSH hardening, Node.js version pinning, and disk cleanup. That maintenance burden compounds across multiple projects. Daytona gives you isolated, per-repo Linux VMs with workspace-level environment variables, devcontainer support, and integrated SSH — none of which require manual setup. For running Claude Code persistently across multiple repos, that startup speed advantage (90ms vs. 30–60 seconds per cold start) compounds every time you spin up a new workspace.

Prerequisites

  • A Daytona account at daytona.io — the free tier is sufficient for this setup
  • A Git repository to work in
  • An Anthropic API key from console.anthropic.com
  • The Grass iOS or Android app if you want phone-based monitoring

Step 1: Create a Daytona workspace

From the Daytona CLI (2026 commands):

# Install the Daytona CLI
brew install daytonaio/tap/daytona            # macOS
# or: curl -sfL https://download.daytona.io/daytona/install.sh | sudo bash  # Linux

# Authenticate
daytona login

# Create a workspace from a Git repo
daytona create --repo https://github.com/your-org/your-repo

# List your workspaces
daytona list

# SSH into a workspace
daytona ssh your-workspace-name

From the Daytona web UI: click New Workspace, paste your repository URL, and choose a base image. The default Ubuntu image includes Node.js 20 — no additional setup needed for Claude Code.

See the Daytona workspaces documentation for devcontainer configuration and custom base image options.

Step 2: Disable the auto-stop timer (critical — read before doing anything else)

Daytona sandboxes auto-stop after 15 minutes of inactivity by default. The timer measures user interaction, not process activity. A long-running Claude Code task running inside tmux does not reset the timer — the workspace can pause mid-task with no warning, dropping your Grass connection and stopping the agent.

"Merely having a script or background task running is not sufficient to keep the sandbox alive. The auto-stop triggers even if there are internal processes running in the sandbox." — Daytona sandboxes documentation

Fix this before starting any Claude Code session. In the Daytona web UI, navigate to Workspace Settings → Inactivity and set the auto-stop interval to Never.

This is the most common failure mode for new users. The workspace appears to be running from the dashboard, but silently pauses mid-task.

Step 3: Install Claude Code and Grass

Inside the workspace terminal (daytona ssh your-workspace-name):

npm install -g @anthropic-ai/claude-code @grass-ai/ide

Verify both installed correctly:

claude --version
grass --version

If npm install fails with an EACCES permissions error, fix the global install path:

mkdir -p ~/.npm-global
npm config set prefix ~/.npm-global
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

Then re-run the install. This is a Daytona-specific gotcha — the default workspace user may not have write access to the system npm prefix.

Step 4: Authenticate Claude Code in the terminal

Claude Code authentication must be completed in an interactive terminal session. It cannot be done from the Grass mobile app or via non-interactive SSH. Set your API key now:

export ANTHROPIC_API_KEY="sk-ant-your-key-here"

For persistence across workspace restarts, add it to ~/.bashrc:

echo 'export ANTHROPIC_API_KEY="sk-ant-your-key-here"' >> ~/.bashrc
source ~/.bashrc

Alternatively, set the API key as a workspace-level environment variable in Daytona's settings — it persists across workspace stops and restarts without touching shell configs. Workspace-level env vars are the cleanest approach since they survive reprovisioning.

Test authentication before proceeding:

cd /workspace/your-repo
claude --print "describe this repo in one sentence"

If Claude Code returns a response, authentication is working.

Step 5: Wrap everything in tmux

The Daytona VM keeps running when you close the SSH connection or web IDE. The Claude Code process itself does not — it exits when the terminal that spawned it closes. tmux keeps the process alive independent of any terminal connection:

# Start a named tmux session
tmux new -s claude

# Inside tmux: navigate to your repo and start Claude Code
cd /workspace/your-repo
claude

# Detach without killing the session
# Press: Ctrl+B, then D

Reconnect from any SSH session later:

daytona ssh your-workspace-name
tmux attach -t claude

If the Claude Code session exited after completing a task, resume from the last checkpoint:

claude --continue

claude --continue restores conversation history from the .jsonl transcript at ~/.claude/projects/<cwd>/<session-id>.jsonl. These files survive workspace stops — session history is durable even across Daytona pauses. For a complete tmux reference including multiple parallel windows per project, see How to Run Claude Code with tmux on a VPS.

Step 6: Connect Grass for phone-based monitoring

This step is what makes the Daytona + Claude Code setup genuinely different from any other remote server guide. Grass is a machine built for AI coding agents — an always-on cloud VM you can reach from your phone. Without it, monitoring a Daytona-hosted agent requires SSH, a terminal app on your phone, and manual tmux navigation. With Grass, you scan a QR code once and get a native mobile interface: live output streaming, permission approval modals, a diff viewer, and prompt input — no terminal needed.

Grass is already installed from Step 3. Start the Grass server in a second tmux window inside the workspace:

# Open a second tmux window: Ctrl+B, then C
cd /workspace/your-repo
grass start --network tailscale

Grass prints a URL and QR code. Scan it from the Grass app (iOS or Android), or open the URL in any browser connected to your Tailscale tailnet.

Why --network tailscale for Daytona specifically? Daytona workspace IPs are internal and not directly reachable from the public internet. --network tailscale uses the workspace's Tailscale IP (100.x.x.x range), which is reachable from your phone over any network — WiFi, cellular, anywhere. --network remote-ip works if the workspace has a public IP, but Tailscale is more reliable and doesn't expose the port publicly.

For Tailscale setup inside a Daytona workspace — including the TUN kernel module workaround required for userspace networking mode — the complete walkthrough is at Setting Up Grass with a Daytona Remote Server.

Once the Grass app is connected:

  • Live Claude Code output streams to your phone in real time
  • Permission requests (bash commands, file writes, web fetches) appear as native modals — tap Allow or Deny
  • You can send new prompts, check git diffs, and browse repo files
  • Closing the app does not kill the agent — it keeps running on the Daytona VM
  • Reopening the app reconnects and replays all output since your last connection via sequence-numbered SSE frames

How the Grass + Daytona architecture works

The Grass CLI server runs inside the Daytona workspace — not on your laptop. Your phone connects over Tailscale. The architecture is:

Phone (Grass app)  ←—Tailscale—→  Grass server (Daytona VM)  ←→  Claude Code
                                    port 32100                    /workspace/repo

This is architecturally different from tools that assume your laptop is always on. With Daytona + Grass, your laptop is entirely out of the loop. You close it; the agent keeps running; your phone stays connected to it. The Grass server process is independent of the mobile app — closing the app only drops the SSE stream. The agent continues writing the transcript, and approval gates queue on the server side until you respond.

Optional: Auto-install with devcontainer.json

If you want Claude Code and Grass pre-installed automatically every time a new workspace is created for a repo — eliminating the reinstall after every workspace restart — add a devcontainer.json:

{
  "postCreateCommand": "npm install -g @anthropic-ai/claude-code @grass-ai/ide"
}

Save this to .devcontainer/devcontainer.json in your repo root and commit it. When Daytona provisions a new workspace from this repo, it runs postCreateCommand automatically. To also fix the npm global prefix in one shot:

{
  "postCreateCommand": "mkdir -p ~/.npm-global && npm config set prefix ~/.npm-global && echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc && npm install -g @anthropic-ai/claude-code @grass-ai/ide"
}

Troubleshooting

claude or grass not found after install
Run which claude. If empty, run source ~/.bashrc. If still empty, verify npm installed to ~/.npm-global/bin with ls ~/.npm-global/bin/.

Workspace paused mid-task
You skipped Step 2. Set auto_stop_interval = 0 in workspace settings. After restarting: daytona ssh your-workspace-name, then tmux attach -t claude to check if the session survived, or claude --continue to resume from the last transcript checkpoint.

Tailscale not working inside Daytona workspace
Daytona workspaces may not have the TUN kernel module loaded. Use userspace networking mode:

tailscale up --tun=userspace-networking

Full walkthrough including Tailscale install and the correct userspace networking flags: Setting Up Grass with a Daytona Remote Server.

PATH not inherited in SSH sessions
Add export PATH=~/.npm-global/bin:$PATH to both ~/.bashrc and ~/.profile. Non-interactive SSH sessions may only source ~/.profile.

Grass QR code not reachable from phone
Verify Tailscale is running: tailscale status. Confirm your phone is on the same Tailscale tailnet. If Tailscale isn't set up yet, use grass start --network remote-ip temporarily and follow the full Tailscale setup guide.

Frequently asked questions

How do I set up Claude Code on Daytona?

Create a Daytona workspace with daytona create --repo <your-repo-url>, SSH in with daytona ssh, install Claude Code with npm install -g @anthropic-ai/claude-code, set ANTHROPIC_API_KEY, wrap the session in tmux with tmux new -s claude, and run claude in your project directory. Disable the auto-stop timer in workspace settings before running any long task.

Does Daytona stop the workspace while Claude Code is running?

Yes, by default. Daytona's 15-minute inactivity timer measures user interaction, not process activity. A Claude Code task running in tmux does not reset the timer. Set auto_stop_interval = 0 in workspace settings before starting any long task.

How do I monitor Claude Code on Daytona from my phone without SSH?

Install Grass inside the workspace (npm install -g @grass-ai/ide), run grass start --network tailscale, and scan the QR code from the Grass iOS or Android app. You get live output streaming, one-tap permission approvals, a diff viewer, and prompt input — no terminal or SSH app needed on the phone.

Do I need Tailscale to connect Grass to a Daytona workspace?

Tailscale is the recommended approach because Daytona workspace IPs aren't publicly routable. grass start --network remote-ip works if the workspace has a public IP. The complete Tailscale setup guide including the userspace networking workaround is at Setting Up Grass with a Daytona Remote Server.

Is Daytona better than a DIY VPS for running Claude Code persistently?

For most developers, yes. Daytona starts in under 90ms vs. 30–60 seconds for a DIY cloud VM, requires no OS maintenance, and supports per-repo workspace isolation. A direct comparison of Daytona, AgentBox, and DIY VPS shows Daytona cold-starts in 90ms vs. 30–60 seconds for a DIY VM, with no OS maintenance overhead. DIY wins only on long-term cost at scale.

What happens to my Claude Code session if the Daytona workspace stops?

The tmux session and Claude Code process exit. The .jsonl transcript files in ~/.claude/projects/ survive the workspace stop. Restart the workspace, SSH back in, and run claude --continue to resume from the last checkpoint.

Can I run Claude Code on Daytona without keeping my laptop on?

Yes. Once Claude Code is running inside tmux on a Daytona workspace, you can close your laptop entirely. Connect Grass via Tailscale to monitor and interact from your phone. The agent runs on Daytona's cloud infrastructure regardless of whether your laptop is on, off, or asleep.