How-to

Running Claude Code Across Multiple Projects: A Structured Approach

How to organise and schedule Claude Code automation when you have more than one codebase to maintain — without it becoming a second job.

O
OpenHelm Team· Engineering
··9 min read
Running Claude Code Across Multiple Projects: A Structured Approach

Running Claude Code on a single project is relatively straightforward. You write a goal, set up a cron entry or a scheduled job, and check the results in the morning. Running it on five projects is a different matter.

The problems compound. You're now managing five sets of credentials and project paths. Five sets of logs. Five different job schedules that might conflict with each other or with your working hours. Five places where silence detection can fail silently and not get noticed for days.

Most developers who use Claude Code regularly across multiple projects end up building their own ad hoc system for managing this — a folder of shell scripts, a shared log directory, a few notes about which jobs are running when. This guide describes a more structured approach that scales without becoming a maintenance burden.

The Core Problem With Multiple Projects

When you run Claude Code on one project, there's a natural feedback loop. You notice if last night's job didn't run. You see the output when you open the project. The connection between action and result is direct.

With multiple projects, that feedback loop degrades. The project you haven't touched in two weeks might have had three failed overnight jobs that you didn't notice. The dependency update job you set up three months ago is still running even though that project is now deprecated. The gap between "jobs are scheduled" and "jobs are doing something useful" widens.

The goal of a multi-project setup isn't just automation — it's automation with visibility. You want to know, at a glance, which projects have active jobs, whether those jobs succeeded recently, and where to look if something failed.

Structuring Your Projects

A Single Configuration Directory

The most practical first step is centralising your job configuration. Rather than keeping shell scripts spread across project directories, collect them:

~/.claude-jobs/
  config/
    project-a.sh
    project-b.sh
    project-c.sh
  logs/
    project-a/
    project-b/
    project-c/
  run-all.sh

Each project gets its own script in config/, its own log directory in logs/, and you have a central run-all.sh that can invoke whichever jobs you want to run together.

Per-Project Scripts

A project script should be self-contained — given the script, you can understand exactly what Claude Code will do for that project:

#!/bin/bash
# project-a.sh — nightly test fixes for Project A

PROJECT_DIR="/Users/you/projects/project-a"
LOG_DIR="$HOME/.claude-jobs/logs/project-a"
DATE=$(date +%Y%m%d-%H%M)
LOG="$LOG_DIR/$DATE.log"

mkdir -p "$LOG_DIR"

echo "=== Starting project-a job at $(date) ===" >> "$LOG"

timeout 3600 claude   -p "Run the test suite. For each failing test, identify the cause and fix it. If a test has been failing for more than 3 attempts, add a comment explaining why it's non-trivial and stop. Run the suite again after fixes to confirm all passing tests still pass. Commit all changes."   --max-turns 15   --project "$PROJECT_DIR"   >> "$LOG" 2>&1

echo "=== Completed at $(date), exit code: $? ===" >> "$LOG"

What matters here: the goal is specific and has a defined completion state, there's a timeout and turn limit, and the logs include timestamps for the start and end of the run.

Cron Scheduling

With multiple projects, scheduling matters more than with a single project. You generally don't want all your jobs running at the same time — they compete for API rate limits and make debugging harder.

A spread schedule might look like:

# project-a: test fixes, runs nightly at 1am
0 1 * * * ~/.claude-jobs/config/project-a.sh

# project-b: dependency updates, runs every Sunday at 2am
0 2 * * 0 ~/.claude-jobs/config/project-b.sh

# project-c: documentation updates, runs on the 1st of each month
0 3 1 * * ~/.claude-jobs/config/project-c.sh

Spread jobs by at least 30–60 minutes to avoid API contention and give yourself a clean audit trail in logs.

Handling Different Job Types Across Projects

Not all projects need the same automation. A rough taxonomy:

Maintenance jobs (every project): test suite health, dependency freshness, lint compliance. Run these regularly — weekly or nightly for active projects.

Improvement jobs (active projects): refactoring, documentation, performance optimisations. Run these on a slower cadence — monthly or triggered manually.

One-off jobs (as needed): large refactors, migrations, version upgrades. Not scheduled; triggered on demand when the need arises.

A common mistake is setting up improvement jobs for projects that are in maintenance mode, or scheduling heavy one-off jobs to run automatically. Both lead to unexpected costs and confusing results.

For each project, decide upfront which category applies:

ProjectStatusJob typeCadence
main-apiActiveMaintenanceNightly
frontendActiveMaintenance + ImprovementNightly + Weekly
legacy-serviceMaintenanceMaintenance onlyWeekly
internal-toolsInactiveNone

Review this table quarterly. Kill jobs for inactive projects. Downgrade improvement jobs for projects you're not actively developing.

Making Results Visible

The biggest gap in a DIY multi-project setup is visibility. You have logs, but you don't have a dashboard.

The minimum viable version is a summary script:

#!/bin/bash
# check-jobs.sh — show recent job results across all projects

for PROJECT in project-a project-b project-c; do
  LOG_DIR="$HOME/.claude-jobs/logs/$PROJECT"
  LATEST=$(ls -t "$LOG_DIR" 2>/dev/null | head -1)

  if [ -z "$LATEST" ]; then
    echo "$PROJECT: no logs found"
    continue
  fi

  # Check if the log mentions success or failure
  if grep -q "TASK COMPLETE" "$LOG_DIR/$LATEST" 2>/dev/null; then
    echo "$PROJECT: ✓ $(date -r "$LOG_DIR/$LATEST" '+%Y-%m-%d %H:%M')"
  elif grep -q "TASK FAILED" "$LOG_DIR/$LATEST" 2>/dev/null; then
    echo "$PROJECT: ✗ FAILED — $(grep 'TASK FAILED' "$LOG_DIR/$LATEST" | tail -1)"
  else
    echo "$PROJECT: ? Unknown status — check $LOG_DIR/$LATEST"
  fi
done

Run this as part of your morning routine. It gives you a one-line summary per project: succeeded, failed, or unknown.

For this to work reliably, your Claude Code goals need to emit consistent completion signals — which is another reason why the "CLAUDE.md Best Practices" section on task completion signals matters for multi-project setups. If every project's jobs output "TASK COMPLETE" on success, your summary script is reliable. If they don't, you're left parsing unstructured log text.

Using a Desktop App for Multi-Project Management

The shell script approach above is functional but requires ongoing maintenance. For developers managing five or more projects, a dedicated tool reduces that overhead significantly.

OpenHelm is a macOS app built around this use case — scheduling, silence detection, structured run history, and failure notifications across multiple Claude Code projects. Rather than a folder of shell scripts and a cron table, you configure jobs through a GUI and check results in a dashboard.

The practical difference, beyond convenience:

Silence detection per project. Each job has independent silence monitoring. A job on project-b that hangs doesn't affect project-a, and both get logged correctly.

Failure correlation. If the same goal fails on three consecutive nights, OpenHelm flags it. With log files, spotting that pattern requires manual inspection.

Self-correction. When a job fails, OpenHelm can queue a retry with the failure output fed back to Claude Code as context. The second attempt often succeeds because Claude Code now knows what went wrong.

Whether you use a desktop app or a shell script setup depends on the number of projects and how much you value structured visibility. For one or two projects, scripts work fine. For five or more, the overhead of the shell approach tends to outweigh any simplicity advantage.

Common Multi-Project Mistakes

Using the same goal across all projects. A goal that works well for one project — "update all dependencies" — might behave completely differently in another project with a different test suite, different package manager, or different CI requirements. Write project-specific goals, not generic ones.

Forgetting to update CLAUDE.md files. If a project changes significantly — new stack, new conventions, new prohibitions — and the CLAUDE.md doesn't reflect it, Claude Code will continue applying old conventions to a changed codebase. Keep them current.

Scheduling jobs for projects you no longer actively work on. Automation on inactive projects accumulates API costs without producing anything you care about. Review your job list quarterly and archive what you're not using.

Not testing new goals before scheduling them. Always run a new Claude Code goal interactively once before scheduling it as an overnight job. Interactive runs are more expensive per session but much cheaper than a poorly-scoped goal running unattended and producing unusable output.

FAQ

Can Claude Code work on two projects simultaneously?

Not in a single session. Each Claude Code invocation works on one project at a time. If you want to run jobs on multiple projects at the same time, you need separate processes — which is what a cron-based or scheduled setup provides naturally.

How do I keep API costs predictable across multiple projects?

Set a monthly budget in the Anthropic Console, and break down your estimate per project. Track actual spend in the Console weekly for the first month; your estimates will improve quickly as you see real numbers. See Controlling AI Coding Costs for more detail.

What if a job fails halfway through and leaves the codebase in a broken state?

This is why you should always run automated Claude Code jobs on a branch, not directly on main. If the job produces a broken state, you can simply delete the branch. Add git checkout -b claude-auto-$(date +%Y%m%d) at the start of your job script to enforce this.

Is there a limit to how many projects I can automate?

There's no hard technical limit, but practical limits kick in — API rate limits, log management overhead, the cognitive load of reviewing results across many projects. Most developers find five to ten projects is a manageable ceiling for regular automation; beyond that, the coordination overhead starts to resemble a part-time job.

---

Multi-project Claude Code automation is genuinely powerful once you have a structure that gives you visibility without adding maintenance overhead. The key is starting simple — one configuration directory, clear per-project goals, a basic summary script — and adding complexity only where the simple approach creates friction.

Related reading: How to Schedule Claude Code Jobs, Why Claude Code Hangs (and How to Stop It)

More from the blog