API-to-tmux Pipeline—Injecting Prompts into Claude Code CLI via Container

You can do this by piping the text via an API → File → Container → Tmux Send Keys pipeline.

It's a pretty clean pipeline once you break it into layers. Here's how each piece works and how they connect.

The Full Pipeline

API response → file → container → tmux send-keys → Claude Code stdin

Approach 1: Non-interactive (claude -p)

The cleanest path if you don't need a persistent interactive session:

# 1. Fetch from API, write to shared volume file
curl -s https://your-api/prompt \
  -H "Authorization: Bearer $TOKEN" \
  | jq -r '.text' > ./shared/prompt.txt

# 2. Inside the container, pipe it into Claude Code in print mode
docker exec my-container bash -c "cat /shared/prompt.txt | claude -p"

The -p / --print flag runs Claude Code non-interactively, reads stdin, prints output, and exits — no tmux needed.

Approach 2: Send to a live tmux session (interactive)

If you need to inject into a running Claude Code session:

# 1. Write API response to a file mounted into the container
curl -s https://your-api/prompt | jq -r '.text' > ./shared/prompt.txt

# 2. From inside the container (or exec into it), send to tmux pane
docker exec my-container bash -c '
  PROMPT=$(cat /shared/prompt.txt)
  tmux send-keys -t claude-session:0.0 "$PROMPT" Enter
'

The tmux send-keys target format is session:window.pane — adjust to match your session name.

Full Script Example

#!/usr/bin/env bash
set -euo pipefail

CONTAINER="claude-runner"
TMUX_TARGET="claude-session:0.0"
SHARED_FILE="./shared/prompt.txt"
API_URL="https://your-api/endpoint"

# Step 1: Fetch and write
echo "Fetching from API..."
curl -s "$API_URL" \
  -H "Authorization: Bearer ${API_TOKEN}" \
  | jq -r '.prompt' > "$SHARED_FILE"

# Step 2: Send to tmux session in container
echo "Sending to Claude Code session..."
docker exec "$CONTAINER" bash -c \
  "tmux send-keys -t '$TMUX_TARGET' \"\$(cat /shared/prompt.txt)\" Enter"

echo "Done."

Container Setup Requirements

Your container needs:

# Dockerfile snippet
RUN npm install -g @anthropic-ai/claude-code
RUN apt-get install -y tmux

# Entrypoint starts tmux with claude
CMD ["tmux", "new-session", "-s", "claude-session", "claude"]

Mounting Claude Code Subscription Credentials from the Host

If you pay for a Claude Code subscription (Pro/Max) instead of using a raw ANTHROPIC_API_KEY, the container needs access to the OAuth credentials and config that the claude CLI writes to your host. These all live under ~/.claude on the host (plus ~/.claude.json for the top-level config).

What to mount

Host path Container path Purpose
~/.claude /root/.claude OAuth tokens (.credentials.json), session state, projects, todos, shell snapshots
~/.claude.json /root/.claude.json Top-level CLI config (account, login method, MCP servers, trusted dirs)

Note: on macOS the credentials are stored in the Keychain, not in ~/.claude/.credentials.json. Before mounting, run claude once on a Linux box (or inside the container itself) to log in — that forces the file-based credential store. Alternatively, copy them out of Keychain via security find-generic-password -s "Claude Code-credentials" -w.

docker run

docker run -it --rm \
  -v "$HOME/.claude:/root/.claude" \
  -v "$HOME/.claude.json:/root/.claude.json" \
  -v "$(pwd)/shared:/shared" \
  --name claude-runner \
  my-claude-image

docker-compose

services:
  claude-runner:
    image: my-claude-image
    container_name: claude-runner
    volumes:
      - ${HOME}/.claude:/root/.claude
      - ${HOME}/.claude.json:/root/.claude.json
      - ./shared:/shared
    tty: true
    stdin_open: true

Permissions gotchas

Verifying it worked

docker exec claude-runner claude --version
docker exec claude-runner claude -p "say hi"   # should respond without prompting for login

If the second command asks you to log in, the credentials aren't being seen — re-check the mount paths and the container's $HOME (it must match the directory where .claude/ was mounted).

Gotchas

Issue Fix
Multiline prompts break send-keys Use a heredoc or escape newlines with \n, or use -p mode instead
Tmux session not found Make sure the session name matches exactly; use tmux ls inside the container to verify
Auth not available in container Mount ~/.claude or set ANTHROPIC_API_KEY as an env var
Race condition (API slow, tmux not ready) Add a sleep or poll with tmux has-session before sending

If you're doing this repeatedly/programmatically, the -p non-interactive mode is more reliable than send-keys since it doesn't depend on terminal state. send-keys shines when you want a human-watchable session that also accepts programmatic input.