Running Claude on a PowerPC iMac G4 (Debian Ports)
A practical guide for chatting with Claude via the API on old PowerPC hardware, where claude.ai itself won't run. Built from a real end-to-end debugging session — every gotcha here actually happened.
Why this approach
claude.ai needs a modern browser with current JavaScript support. PowerPC Macs (G4, G5) can't run one — TenFourFox-derived browsers (ArcticFox, Spiderweb, etc.) max out well below what the site needs. The fix: skip the browser entirely and talk to the Claude API directly with bash and wget, both of which exist on virtually any Linux system.
What you'll need
• A PowerPC Mac running a Linux distro (Debian Ports is the realistic choice — there's no official Ubuntu/Lubuntu build for PowerPC)
• bash and wget (check with which wget — almost always preinstalled, even on minimal systems)
• An Anthropic API key with billing credit added
• A second, modern device (phone, laptop, anything with a current browser) — you'll need this to create the API key, since console.anthropic.com won't load on the G4 itself
Step 1: Get an API key (on a different device)
The Anthropic console is a modern web app and won't load in old PowerPC browsers. Use any other device for this part:
1. Go to console.anthropic.com, sign up or log in
2. Settings → API Keys → Create Key
3. Copy the key immediately — it's only shown once. It looks like sk-ant-api03-... and is over 100 characters long
4. Go to Plans & Billing and add credit (even $5 covers a lot of casual chatting)
Save the key as a plain text file if possible — typing/pasting a 100+ character string is the source of most problems in this whole process, and you may need to retype it more than once.
Step 2: Get the key onto the iMac
Clipboard paste between devices is unreliable on old terminal emulators — budget for this not working on the first try. The most reliable method:
1. Save the key in a plain text file on your other device (e.g. key.txt)
2. Transfer the file to the iMac via USB stick (or email-to-self, if networking allows)
3. On the iMac, load it into an environment variable directly from the file — don't rely on copy/paste into the terminal:
ANTHROPIC_API_KEY=$(cat ~/Downloads/key.txt)
export ANTHROPIC_API_KEY
4. Verify it actually landed (a real key is 100+ characters):
echo "$ANTHROPIC_API_KEY" | wc -c
If this shows 1, the variable is empty — the most common cause is a stray character (missing $, accidental backslash) when typing the export line, or running it in a fresh terminal session after the original one closed. Redo it carefully, one line at a time.
Important: this variable only lasts for the current terminal session. Logging out, closing the terminal, or rebooting will wipe it. To make it permanent:
echo 'export ANTHROPIC_API_KEY="'$(cat ~/Downloads/key.txt)'"' >> ~/.bashrc
This writes the export line into your shell startup file, so every new terminal session has it automatically.
Step 3: Install curl — or skip it entirely
Try this first:
sudo apt update && sudo apt install curl
On Debian Ports systems mixing old snapshot archives with unstable/sid repos, this very likely fails with dependency conflicts or GPG key errors. Don't fight this with forced/unauthenticated installs — it risks destabilizing the whole system for little benefit.
Instead, check for wget, which is almost always already present and works just as well for this purpose:
which wget
wget --version
If wget exists (it almost certainly does), skip curl entirely and use the wget-based script below.
Step 4: The chat script
Save this as claude-chat.sh:
#!/bin/bash
#
# claude-chat.sh — minimal terminal chat client for the Claude API
# Requires only: bash, wget
API_KEY="${ANTHROPIC_API_KEY:-}"
MODEL="claude-sonnet-4-6"
MAX_TOKENS=1024
API_URL="https://api.anthropic.com/v1/messages"
if [ -z "$API_KEY" ]; then
echo "No API key found."
echo "Set it with: export ANTHROPIC_API_KEY=\"sk-ant-your-key-here\""
exit 1
fi
HISTORY=""
TMP_BODY_FILE="/tmp/claude_chat_body_$$.json"
TMP_RESP_FILE="/tmp/claude_chat_resp_$$.json"
cleanup() { rm -f "$TMP_BODY_FILE" "$TMP_RESP_FILE"; }
trap cleanup EXIT
json_escape() {
local s="$1"
s="${s//\\/\\\\}"
s="${s//\"/\\\"}"
s="${s//$'\n'/\\n}"
s="${s//$'\t'/\\t}"
s="${s//$'\r'/\\r}"
printf '%s' "$s"
}
extract_json_string_field() {
local json="$1" field="$2"
local marker="\"${field}\":\""
local rest="${json#*$marker}"
if [ "$rest" = "$json" ]; then printf ''; return; fi
local out="" i=0 len=${#rest} c next
while [ $i -lt $len ]; do
c="${rest:$i:1}"
if [ "$c" = '"' ]; then break; fi
if [ "$c" = '\' ]; then
next="${rest:$((i+1)):1}"
case "$next" in
n) out="${out}"$'\n'; i=$((i+2)); continue ;;
t) out="${out}"$'\t'; i=$((i+2)); continue ;;
r) out="${out}"$'\r'; i=$((i+2)); continue ;;
\") out="${out}\""; i=$((i+2)); continue ;;
\\) out="${out}\\"; i=$((i+2)); continue ;;
*) out="${out}${c}"; i=$((i+1)); continue ;;
esac
fi
out="${out}${c}"; i=$((i+1))
done
printf '%s' "$out"
}
extract_text() { extract_json_string_field "$1" "text"; }
extract_error() { extract_json_string_field "$1" "message"; }
echo "Claude terminal chat (model: $MODEL)"
echo "Type 'exit' or 'quit' to leave."
echo "---------------------------------------"
while true; do
printf "\nYou: "
IFS= read -r USER_INPUT
if [ "$USER_INPUT" = "exit" ] || [ "$USER_INPUT" = "quit" ]; then
echo "Goodbye."; break
fi
if [ -z "$USER_INPUT" ]; then continue; fi
ESCAPED_INPUT=$(json_escape "$USER_INPUT")
NEW_MSG="{\"role\":\"user\",\"content\":\"${ESCAPED_INPUT}\"}"
if [ -z "$HISTORY" ]; then HISTORY="$NEW_MSG"; else HISTORY="${HISTORY},${NEW_MSG}"; fi
BODY="{\"model\":\"${MODEL}\",\"max_tokens\":${MAX_TOKENS},\"messages\":[${HISTORY}]}"
printf '%s' "$BODY" > "$TMP_BODY_FILE"
wget -q -O "$TMP_RESP_FILE" \
--header="x-api-key: ${API_KEY}" \
--header="anthropic-version: 2023-06-01" \
--header="content-type: application/json" \
--post-file="$TMP_BODY_FILE" \
"$API_URL" 2>/tmp/claude_chat_err_$$.log
WGET_EXIT=$?
rm -f /tmp/claude_chat_err_$$.log
if [ ! -s "$TMP_RESP_FILE" ]; then
echo ""
echo "No response received (wget exit code: $WGET_EXIT)."
echo "Check your network connection and API key."
continue
fi
RESPONSE=$(cat "$TMP_RESP_FILE")
if printf '%s' "$RESPONSE" | grep -q '"type":"error"'; then
ERR_MSG=$(extract_error "$RESPONSE")
echo ""
echo "Error: ${ERR_MSG:-unknown error}"
echo "(raw response below for debugging)"
echo "$RESPONSE"
continue
fi
REPLY=$(extract_text "$RESPONSE")
if [ -z "$REPLY" ]; then
echo ""
echo "Got an empty or unparseable response. Raw output:"
echo "$RESPONSE"
continue
fi
printf "\nClaude: %s\n" "$REPLY"
ESCAPED_REPLY=$(json_escape "$REPLY")
HISTORY="${HISTORY},{\"role\":\"assistant\",\"content\":\"${ESCAPED_REPLY}\"}"
done
Make it executable and run it:
chmod +x claude-chat.sh
./claude-chat.sh
Troubleshooting reference
Symptom
Likely cause
Fix
curl: command not found
curl isn't installed
Use the wget version of the script above
apt fails with dependency/GPG errors
Mismatched sid/snapshot repos
Don't force it — use wget instead, skip apt
Cookie banner won't dismiss on console.anthropic.com
Old browser can't render the modern site
Use a different device for console access entirely
echo "$VAR" prints the literal variable name, not its value
Typo broke the $ expansion (missing $, stray backslash, single quotes)
Retype the export line carefully, test with a throwaway variable first
`echo "$VAR"
wc -cshows1`
Variable is empty — paste failed silently, or session/terminal changed since export
Stuck at a > prompt after a command
Unmatched quote or parenthesis
Ctrl+C to cancel, retype carefully or split into separate lines
wget exit code 8
Server returned an HTTP error status
Add --server-response and --content-on-error, save output to a file, and cat it to see the actual JSON error
wget error: "Username/Password Authentication failed"
This is wget's generic phrasing for HTTP 401 — bad/missing API key
Re-check the key is correctly loaded (see the wc -c check above)
HTTP 400 with body "Your credit balance is too low..."
No billing credit on the account
Add credit at console.anthropic.com → Plans & Billing
File reappears empty / commands vanish after logging back in
/tmp and exported variables don't survive logout/reboot
Add the export line to ~/.bashrc so it's set automatically every session
JSON test file looks subtly wrong when you cat it (missing }, swapped characters)
Manual typing/pasting dropped or altered characters
Use nano to write the file directly and check it carefully before using it; rely on file-based input over long pasted one-liners
Notes
• Conversation history in this script lives in memory only — closing the script loses it. Nothing is saved to disk.
• The script makes one HTTP request per message; there's a brief pause while waiting for the full reply (no streaming).
• API usage is billed by usage, not a flat subscription — keep half an eye on the Billing section if chatting heavily.