Tech 6 min read

Letting Claude Code and Codex Run Overnight in tmux (Optimization)

Recap

In the setup article I described the idea of linking Claude Code and Codex, and in the practice article I actually ran it. The result was 1,134 lines of game code.

Hitting Rate Limits

Running the practice script on a different project immediately hit the Claude Code MAX plan (x20, the highest tier) cap. Switching to Codex as the primary then hit the Codex Pro plan (also the highest tier) cap.

Thinking about why: the overhead from tmux command-chaining every round was too high.

The underlying issue:

  • Codex (5.2) is smart enough and capable of managing its own context
  • Claude Code’s context overflows fast, but it doesn’t completely forget the immediate past

So the approach became:

  • Keep the same Claude session for a single task
  • Close Claude after push completes → next task starts fresh from the instruction file
  • Don’t restart Codex every time → avoid full file scans each round

This should reduce both limits. That hypothesis drove the improvements.


Redesigning the Roles

Previous (Practice Article)

Equal loop structure. Claude and Codex take turns.

Claude (implement) → Codex (review) → Claude (fix) → ...

Improved Version

Two-tier structure where Codex manages Claude.

Codex (meta layer): instructions, reviews, progress management
  ↓ via files
Claude (worker layer): implement, commit, push

All communication goes through files:

FilePurpose
work/task.mdCodex → Claude task instructions
work/review.mdCodex → Claude review feedback
logs/.claude_doneClaude → Codex completion signal

Reducing API Calls: Blocking Wait

The Original Problem

while [ ! -f "$REVIEW_SIGNAL" ]; do
    sleep 2
done

Checks for a file every 2 seconds. The loop itself doesn’t call the API, but when Codex runs in agent mode, it may still make periodic API calls during the wait.

Improvement: Blocking Wait

timeout 3600 bash -c "while [ ! -f logs/.claude_done ]; do sleep 10; done"

Add this to AGENTS.md: “Do not make any additional API requests until this command completes.” Codex follows the instruction and does nothing while waiting.

### 6. Blocking Wait
**Important**: Do not make any additional API requests until this command completes.
\`\`\`bash
timeout 3600 bash -c "while [ ! -f logs/.claude_done ]; do sleep 10; done"
\`\`\`

Timeout is 1 hour. Prevents infinite loops.


Reducing Context Size

1. Explicitly List Files That Must Not Be Read

AGENTS.md (for Codex):

## Prohibited Actions

- Do not read log files inside `logs/`
- Do not read `docs/progress-archive/`
- Do not read large amounts of past commit history
- Do not have Claude read unnecessary files (logs, history)

CLAUDE.md (for Claude):

### Files That Must Not Be Read

To conserve context, do not read:
- Files inside `logs/` (except signals)
- `docs/progress-archive/`
- Past files in `work/` (other than the current task)

LLMs are fairly obedient when told “don’t do this.”

2. Force-Delete Temp Files

Always clean up after a task:

# Remove signals and temp files (required for context efficiency)
rm -f logs/.claude_done
rm -f work/task.md work/review.md work/progress.md

Adding a comment explaining why prevents LLMs from skipping it.

3. Session Isolation

Restart Claude for each task:

# Reset environment
rm -f logs/.claude_done
tmux kill-window -t codex-dev:claude-worker 2>/dev/null || true

# Launch Claude (new window)
tmux new-window -t codex-dev -n claude-worker -c $(pwd)
tmux send-keys -t codex-dev:claude-worker "claude --dangerously-skip-permissions" C-m

This prevents context from carrying over from the previous task. Each new Claude starts fresh.


Task Execution Flow

9 steps:

1. Select task (from todo.md)
2. Reset environment (delete signals, kill Claude window)
3. Launch Claude (new tmux window)
4. Write task instructions (work/task.md)
5. Send instructions
6. Blocking wait (no API calls)
7. Review (up to 3 fix cycles)
8. Completion processing (delete temp files, update todo.md)
9. Move to next task

The key steps are 2, 6, and 8.

  • Step 2: Clear leftovers from the previous task
  • Step 6: No API calls during the wait
  • Step 8: Don’t carry unnecessary context into the next task

Comparison: Before vs. After

AspectPrevious (Practice)Improved
Wait methodsleep 2 pollingSignal file + blocking wait
ContextAccumulatesReset per task
Role structureEqual loopCodex-led two-tier
Prohibited actionsNoneExplicitly list logs/archive

Launch Script

The improved version launches with one line:

codex --sandbox danger-full-access --ask-for-approval never

Codex starts in agent mode and auto-loads AGENTS.md.

That said, just reading AGENTS.md isn’t enough — it will pause. The first time, explicitly tell it “read AGENTS.md and run it.” After that, it runs on its own.

tmux session creation is handled by a script:

#!/bin/bash
# codex-main.sh

set -e
cd "$(dirname "$0")/.."

SESSION_NAME="codex-dev"
PROJECT_DIR="$(pwd)"

mkdir -p logs work

if ! tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
    tmux new-session -d -s "$SESSION_NAME" -n "main" -c "$PROJECT_DIR"
fi

codex --sandbox danger-full-access --ask-for-approval never

Writing Instructions for LLMs

Lessons from practice.

”Don’t do X” works; “do X” gets skipped

LLMs are fairly obedient with prohibitions. But “do this” instructions can get skipped.

Countermeasures:

  • Use strong language for important instructions (“required,” “always,” “every time”)
  • Keep instruction files short so nothing falls off the end of context
  • Repeat the same instruction in multiple places (research confirms repetition improves LLM accuracy)
# Bad: likely to be skipped
After finishing, create a signal file.

# Good: emphasized + reason given
**After finishing, always run `touch logs/.claude_done`** (required to notify Codex of completion)

Keep instruction files short

When AGENTS.md or CLAUDE.md gets long, instructions near the end drop out of context.

  • Limit to the bare minimum
  • Move details to separate files and write “read only when needed”
  • Put the most critical instructions at the top of the file

Key points for keeping costs down:

  1. Blocking wait reduces API calls: explicitly say “do nothing while waiting”
  2. List files that must not be read: ban logs and archives
  3. Reset session per task: prevent context accumulation
  4. Instruction phrasing: use strong language for “do”; keep files short