DEV Community

Paradane
Paradane

Posted on

Claude Code Mac Setup Tutorial: Spare Mac Automation Server

Claude Code Mac Setup Tutorial: Spare Mac Automation Server

If you have an old Mac gathering dust on a shelf, you can repurpose it into a dedicated, always-on automation server for Claude Code. Instead of letting that hardware go to waste, you can transform it into a headless AI agent that handles coding, writing, data processing, file management, and more—all without manual intervention. This tutorial walks you through the entire setup: preparing your spare Mac for unattended use, installing Claude Code, configuring secure remote access, and running your first automated tasks. By the end, you’ll have a fully functional remote automation server that you can control from anywhere. Claude Code CLI gives you an AI-powered assistant that can execute shell commands, edit files, scrape websites, run test suites, and even review code—right from the terminal. This guide is aimed at solo developers and small teams who have unused Mac hardware and want to automate repetitive workflows without relying on expensive cloud services. You’ll need a spare Mac (any model running macOS 12 or later), an internet connection, and basic familiarity with the terminal. No advanced DevOps experience is required.

Preparing Your Spare Mac for Headless Use

Before you can rely on your spare Mac as a dedicated automation server, you must configure it to run unattended without interruptions. Start by performing a full macOS update via System Settings > General > Software Update to ensure the latest security patches are applied. This reduces vulnerabilities when the machine is exposed to a network.

Next, enable remote access so you can control the Mac from elsewhere. Go to System Settings > General > Sharing and turn on Remote Login. This activates SSH and allows you to connect securely. For day‑to‑day use, create a dedicated user account with limited privileges—for example, name it claude-automation and assign it to the standard group, not admin. You can do this from the command line:

sudo sysadminctl -addUser claude-automation -fullName "Claude Automation" -password "your-strong-password" -home /Users/claude-automation
Enter fullscreen mode Exit fullscreen mode

Because this Mac will run headless, you must disable sleep and screen lock to keep the system always responsive. Under System Settings > Lock Screen, set both “Turn display off on power adapter when inactive” and “Require password after screen saver begins” to Never. For added certainty, run these terminal commands:

sudo pmset -a sleep 0
sudo pmset -a displaysleep 0
sudo pmset -a disablesleep 1
Enter fullscreen mode Exit fullscreen mode

Now configure networking so you can reliably reach the machine. Assign a static IP address via System Settings > Network > Advanced > TCP/IP (choose “Manually”) or set up a dynamic DNS service (e.g., DuckDNS) if the Mac is on a network with frequently changing IPs. With these steps completed, your spare Mac is ready for the Claude Code installation that follows.

Installing Claude Code on macOS

With your spare Mac configured for headless operation, the next step is to install Claude Code itself. Since you’ll be running this on a dedicated automation server, using a version manager for Node.js is a best practice to avoid conflicts and simplify updates.

Start by installing nvm (Node Version Manager). Connect via SSH and run:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
Enter fullscreen mode Exit fullscreen mode

After installation, reload your shell configuration or source the profile file. Then install the latest LTS version of Node.js:

nvm install --lts
nvm use --lts
Enter fullscreen mode Exit fullscreen mode

Verify Node.js and npm are available:

node --version
npm --version
Enter fullscreen mode Exit fullscreen mode

Now install the Claude Code CLI globally via npm:

npm install -g @anthropic-ai/claude-code
Enter fullscreen mode Exit fullscreen mode

To confirm the installation succeeded, run:

claude --help
Enter fullscreen mode Exit fullscreen mode

You should see a list of available commands and options. If you encounter permission errors (e.g., EACCES), it often means the global npm prefix requires elevated privileges. A clean solution is to configure npm to use a local directory (recommended for headless setups) rather than using sudo. Alternatively, if you used nvm, the global packages are installed in your home directory by default, avoiding permission issues entirely.

Another common issue is an incomplete shell environment when running over SSH. Ensure that your shell profile (.bashrc, .zshrc, etc.) sources nvm correctly and that the claude command is in your PATH. If you see "command not found", check that the npm global bin directory (typically ~/.nvm/versions/node/.../bin) is part of your PATH.

Once claude --help runs without errors, the installation is complete and ready for API configuration.

Configuring API Access and macOS Permissions

With Claude Code installed, the next step is to connect it to the Anthropic API and grant the necessary macOS permissions so it can operate in a headless, automated environment.

Obtaining and Storing Your API Key

  1. Log in to the Anthropic Console and navigate to the API Keys section. Click Create Key, give it a descriptive name (e.g., claude-code-automation), and copy the generated key immediately — it will not be shown again.
  2. On your spare Mac, create a secure environment file to store the key. As the dedicated automation user, run:
   mkdir -p ~/.anthropic
   echo 'ANTHROPIC_API_KEY="sk-ant-..."' > ~/.anthropic/config
   chmod 600 ~/.anthropic/config
Enter fullscreen mode Exit fullscreen mode

This restricts access to the file to only your user.

Setting the Environment Variable

Claude Code reads the ANTHROPIC_API_KEY environment variable at runtime. To make it persistent across SSH sessions, add the export to your shell’s startup file. For Zsh (macOS default), edit ~/.zshenv:

echo 'export ANTHROPIC_API_KEY="sk-ant-..."' >> ~/.zshenv
source ~/.zshenv
Enter fullscreen mode Exit fullscreen mode

If you use a different shell, add the same line to ~/.profile or ~/.bash_profile. Verify it’s set correctly:

echo $ANTHROPIC_API_KEY
Enter fullscreen mode Exit fullscreen mode

Granting macOS Permissions

Claude Code needs special permissions to execute commands, access files, and automate system tasks. Since your Mac runs headless, you’ll grant these permissions once via the GUI or by editing the TCC database directly (advanced).

Accessibility Permission

Claude Code (or the terminal emulator through which you launch it) must be allowed to control the system. To enable this:

  • Go to System Settings > Privacy & Security > Accessibility.
  • Click the lock icon to make changes.
  • Add Terminal (or your automation wrapper script) from the Applications folder. If you use a wrapper script, ensure the script has the proper bundle identifier or is added directly.

Files and Folders Permission

Claude Code will read and write to the directories you specify (e.g., project folders). Under System Settings > Privacy & Security > Files and Folders, add Terminal and grant access to the folders you plan to use, such as ~/Projects or /var/www.

Automation Permission (Optional)

If you plan to have Claude Code interact with other apps (e.g., trigger a build in Xcode), you may also need to grant Automation permission for Terminal to control those applications.

After granting these permissions, log out and back in or restart the Terminal session. Your spare Mac is now ready to accept remote commands via Claude Code with full API access and proper system integration.

Setting Up Secure Remote Access

With your spare Mac headless-ready and Claude Code installed, you now need secure remote access to send tasks from your main machine. The goal is to connect from anywhere without exposing your system to unnecessary risk.

Generate an SSH Key Pair

On your client machine (the one you’ll connect from), generate a new SSH key pair if you don’t have one:

ssh-keygen -t ed25519 -C "claude-remote"
Enter fullscreen mode Exit fullscreen mode

Accept the default location or choose a custom path. This creates a private key (id_ed25519) and a public key (id_ed25519.pub). Never share the private key.

Copy the Public Key to Your Spare Mac

Use ssh-copy-id to transfer the public key to the automation user you created earlier (replace automation_user and mac-ip with your actual values):

ssh-copy-id automation_user@mac-ip
Enter fullscreen mode Exit fullscreen mode

You’ll be prompted for the password once. After that, future logins will use the key instead of a password.

Disable Password Authentication

For maximum security, prevent anyone from logging in with a password. On the spare Mac, edit the SSH daemon config:

sudo nano /etc/ssh/sshd_config
Enter fullscreen mode Exit fullscreen mode

Set or uncomment these lines:

PasswordAuthentication no
ChallengeResponseAuthentication no
PermitRootLogin no
Enter fullscreen mode Exit fullscreen mode

Then restart SSH:

sudo systemctl restart sshd
Enter fullscreen mode Exit fullscreen mode

(On older macOS versions, use sudo launchctl unload /System/Library/LaunchDaemons/ssh.plist then sudo launchctl load to restart.)

Now only users with a valid SSH key can connect.

Test the Remote Connection

From your client machine, verify you can log in without a password:

ssh automation_user@mac-ip
Enter fullscreen mode Exit fullscreen mode

You should land directly in the automation user’s shell. Run a quick command like echo "Claude Code server ready" to confirm.

Optional: Access from Outside Your Network

To reach your spare Mac over the internet, you have two clean options:

  • Tailscale – Install Tailscale on both the spare Mac and your client. It creates a secure mesh VPN with no port forwarding. Once both devices are connected to your Tailscale network, simply use the Tailscale IP to SSH.
  • Port forwarding with a static IP or DDNS – If you prefer direct access, forward port 22 on your router to the Mac’s local IP. Pair this with a dynamic DNS service if your home IP changes. This approach requires more careful firewall rules.

Tailscale is simpler for most developers and avoids exposing SSH to the open internet. Either way, you now have secure remote control of your automation server.

Running Your First Claude Code Task Remotely

With your spare Mac prepared, Claude Code installed, API key configured, and SSH access secured, it’s time to run your first remote task. This section walks through both interactive and non-interactive modes, demonstrating how to execute commands, capture output, and handle errors—all over SSH.

1. SSH Into the Spare Mac and Test Claude Code Interactively

Start by connecting to your automation server from your main machine:

ssh automation@your-spare-mac-ip
Enter fullscreen mode Exit fullscreen mode

Once logged in, verify Claude Code works by launching it interactively:

claude
Enter fullscreen mode Exit fullscreen mode

You’ll see a prompt like >. Type a simple request, for example:

What is the current date and time on this system?
Enter fullscreen mode Exit fullscreen mode

Claude Code will execute the command and return the output. This confirms that the tool can interact with macOS in a headless environment. Press Ctrl+D or type /exit to leave interactive mode.

2. Non-Interactive Mode for Scripted Automation

For automated workflows, use non-interactive mode by piping a prompt through stdin. This allows you to execute tasks without manual input:

echo "Show me the disk usage of the home directory in a table" | claude
Enter fullscreen mode Exit fullscreen mode

Claude Code processes the prompt, runs the necessary system commands, and prints the result to stdout. You can capture that output by redirecting:

echo "List all running processes with their memory usage" | claude > processes.txt
Enter fullscreen mode Exit fullscreen mode

3. Automating Log File Analysis – A Practical Script

A common automation use case is monitoring log files. Below is a bash script that uses Claude Code to analyse the system log and generate a daily summary:

#!/bin/bash
# daily_log_summary.sh - Runs on the spare Mac via SSH

LOG_FILE="/var/log/system.log"
OUTPUT_FILE="~/log_summary_$(date +%Y-%m-%d).txt"

# Check if log file exists and is readable
if [ ! -r "$LOG_FILE" ]; then
    echo "Error: Cannot read $LOG_FILE" >&2
    exit 1
fi

# Extract last 100 lines and ask Claude Code for a summary
{
    echo "Analyze the following system log entries and provide a concise summary of any errors, warnings, or unusual patterns. List them in bullet points:"
    tail -100 "$LOG_FILE"
} | claude > "$OUTPUT_FILE" 2>&1

# Check exit status of claude
if [ $? -ne 0 ]; then
    echo "Claude Code failed to process the log." >> "$OUTPUT_FILE"
    exit 1
fi

echo "Summary written to $OUTPUT_FILE"
Enter fullscreen mode Exit fullscreen mode

Save this script on the spare Mac as daily_log_summary.sh, make it executable (chmod +x daily_log_summary.sh), and run it over SSH from your main machine:

ssh automation@your-spare-mac-ip ./daily_log_summary.sh
Enter fullscreen mode Exit fullscreen mode

The script uses 2>&1 to capture both stdout and stderr into the output file, and includes basic error handling: it checks file readability and the exit code of claude. You can adapt this pattern for any automation task, such as analysing web server logs or monitoring backup status.

4. Error Handling and Reliable Execution

When running Claude Code non-interactively, always check the exit code and capture stderr. A robust template is:

if output=$(echo "your prompt" | claude 2>&1); then
    echo "Success: $output"
else
    echo "Failed with exit code $?"
    echo "Output: $output"
    # Send alert or retry
fi
Enter fullscreen mode Exit fullscreen mode

This ensures your automation scripts can detect failures and react appropriately, whether by logging, retrying, or sending a notification.

Next Step

You now have a working foundation for running Claude Code tasks remotely. The next section will expand this into more complex, production-ready workflows—automating code reviews, scheduled data collection, and test execution.

Building Practical Automation Workflows

Once you have a secure remote connection and a working Claude Code instance, it's time to automate real tasks. The workflows below are production-ready and can be adapted to your own needs. Each example includes a bash script that you can schedule with cron, and all incorporate rate limiting and error handling to keep your automation server reliable.

Automated Code Review of Pull Requests

One powerful use case is having Claude Code review pull requests autonomously. The following script fetches a PR diff using the GitHub CLI, pipes it to Claude Code with a code review prompt, and saves the output to a file. You can then post the results back to the PR via gh pr comment.

#!/bin/bash
# review_pr.sh – usage: ./review_pr.sh OWNER/REPO PR_NUMBER
REPO=$1
PR=$2
OUTPUT_DIR="$HOME/pr_reviews"
mkdir -p "$OUTPUT_DIR"
gh pr diff "$REPO" "$PR" | claude -p "Perform a thorough code review. List any bugs, security issues, and style improvements." > "$OUTPUT_DIR/review_${REPO//\//_}_${PR}.md"
gh pr comment "$REPO" "$PR" --body-file "$OUTPUT_DIR/review_${REPO//\//_}_${PR}.md"
Enter fullscreen mode Exit fullscreen mode

Schedule this with a cron job every morning to catch open PRs, or trigger it via a webhook. Add a delay between reviews to avoid hitting API rate limits: sleep 10 after each call.

Scheduled Data Scraping with Claude Code

Claude Code can also serve as an intelligent scraper. The example below fetches the Hacker News front page, extracts headlines, and asks Claude Code to summarize the top three trends.

#!/bin/bash
# scrape_hn.sh – runs daily at 8 AM
URL="https://news.ycombinator.com"
curl -s "$URL" | grep -oP '(?<=<a href="item\?id=)[^"]+' | head -20 > /tmp/hn_ids.txt
echo "Extracted headlines:" > /tmp/hn_input.txt
while read id; do
  title=$(curl -s "https://hacker-news.firebaseio.com/v0/item/$id.json" | jq -r '.title')
  echo "$title" >> /tmp/hn_input.txt
done < /tmp/hn_ids.txt
claude -p "Read the following headlines and write a short summary of the top three trends." < /tmp/hn_input.txt > $HOME/scrapes/hn_summary_$(date +%Y%m%d).txt
Enter fullscreen mode Exit fullscreen mode

Add a sleep 2 between each curl call to be polite to the server, and wrap the whole script in a while loop with retries in case of network failures.

Test Failure Analysis and Fix Suggestions

When your test suite fails, Claude Code can analyze the output and suggest fixes. This workflow runs after each test run (triggered by a post-commit hook or nightly cron).

#!/bin/bash
# analyze_tests.sh
TEST_OUTPUT=$(pytest --tb=short 2>&1 || true)
if echo "$TEST_OUTPUT" | grep -q "FAILED"; then
  claude -p "The following test output shows failures. Identify the root cause and suggest a fix. If the issue is flaky, note that too." <<< "$TEST_OUTPUT" > $HOME/test_reports/fix_suggestions_$(date +%Y%m%d_%H%M).txt
fi
Enter fullscreen mode Exit fullscreen mode

To avoid overwhelming the API when many tests fail, batch the output and use a single Claude Code call. If you receive a 429 Too Many Requests error, implement a retry with exponential backoff.

Rate Limiting and Error Handling Strategies

Claude Code’s API enforces rate limits. Build a small retry wrapper in your scripts:

call_claude_with_retry() {
  local retries=5
  local delay=10
  for i in $(seq 1 $retries); do
    output=$(claude "$@" 2>&1) && return 0
    if echo "$output" | grep -q "429\|rate limit"; then
      sleep $((delay * 2 ** (i-1)))
    else
      echo "$output" >&2
      return 1
    fi
  done
  return 1
}
Enter fullscreen mode Exit fullscreen mode

Insert this function into every automation script. Also set environment variables like CLAUDE_CODE_MAX_TOKENS and CLAUDE_CODE_TIMEOUT to fine-tune behavior.

By combining these workflows with cron and proper error handling, your spare Mac becomes a tireless automation server that can review code, scrape data, and analyze tests with minimal intervention. Start simple, then extend each script to handle more complex logic as your needs grow.

Taking Your Automation Server Further

With your spare Mac now running Claude Code as a headless automation server, you have a flexible platform to automate countless development and system tasks. To get the most out of this setup, consider extending it with integrations that make it part of your broader workflow.

Start by connecting your automation server to notification channels. For example, you can configure Claude Code to post results to a Slack channel using incoming webhooks. A simple bash wrapper can capture Claude’s output and curl it to your Slack webhook URL. Similarly, you can trigger tasks from Slack using slash commands or a bot that SSHes into the Mac.

For more visibility, build a lightweight web dashboard using a framework like FastAPI or Express. This dashboard could show task history, allow you to start predefined automations with one click, and display real-time logs. You can also expose a REST API to trigger Claude Code tasks from other tools like GitHub Actions, CI/CD pipelines, or Zapier.

Monitoring is essential—track API usage and costs by logging every request to Anthropic's API, and set up alerts if usage exceeds thresholds. You can also schedule Claude Code to run periodic maintenance tasks such as cleaning up old files, checking disk space, or generating system health reports.

To apply this tutorial to a real project, consider setting up a daily code review assistant that examines new pull requests in your repository, runs Claude Code on the diff, and sends a summary to your team. Or use it to automate your personal blog: have Claude Code draft posts from audio transcriptions or outline ideas.

If your automation needs grow into complex, multi-step workflows that require robust error handling, scheduling, or custom integrations, the team at Paradane (https://paradane.com) can help you architect a production-ready solution that scales beyond a single Mac. For now, start small, expand gradually, and enjoy the productivity gains from your new automation server.

Top comments (0)