Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions scripts/ccp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# The `ccp` helper: running the proxy as a background service

`ccp` is a small wrapper that runs `claude-code-proxy` as a **systemd user service**, so the proxy stays up in the background (with auto-restart) instead of needing a terminal running `cargo run -- serve`. The installer writes the unit and the wrapper automatically.

> **Linux/WSL only — not macOS.** This uses a systemd `--user` service; macOS has no systemd — it would need a launchd agent instead. The installer refuses to run without systemd. It's an optional convenience helper, not part of what the proxy itself ships.

## Quick install

Run the installer, which writes both files below and reloads systemd:

```sh
bash scripts/ccp/install.sh
```

It's idempotent (safe to re-run), warns if the proxy binary isn't installed yet, and does **not** enable the service — run `ccp on` yourself when you want it live.

## What it installs

Two files, both written outside the repo (see `install.sh` for the exact contents):

1. **The systemd user unit** — `~/.config/systemd/user/claude-code-proxy.service`
2. **The `ccp` wrapper script** — `~/.local/bin/ccp` (must be on `PATH`)

Both drive the compiled binary at `~/.local/bin/claude-code-proxy` — the unit runs whatever is installed there, independent of the repo checkout. Rebuild/reinstall the binary (eg, `just install`, or copy a fresh build over it) and `ccp restart` picks it up.

The unit runs `... serve` with no TUI (no TTY as a service) and `CCP_LOG_STDERR=1`, so systemd captures the logs for `ccp logs`. It restarts on failure and listens on the default `127.0.0.1:18765` — to change the port add `Environment=PORT=...` to the unit and `systemctl --user daemon-reload` (or just re-run the installer after editing it there).

## Commands

| Command | What it does |
|-|-|
| `ccp start` | Start the proxy now (this boot only) |
| `ccp stop` | Stop the proxy now |
| `ccp restart` | Restart — use after reinstalling the binary or editing the unit (`daemon-reload` first for unit edits) |
| `ccp status` | Show service state (active/inactive, PID, recent log lines) |
| `ccp logs` | Print the current logs and exit |
| `ccp logs -f` | Follow live logs (`journalctl -f`) — Ctrl-C to stop |
| `ccp on` | **Enable + start** — start now and on every login |
| `ccp off` | **Disable + stop** — stop now and don't start on login |
| `ccp health` | `curl` the `/healthz` endpoint to confirm it's actually serving |

`on`/`off` toggle the persistent (enabled-at-login) state; `start`/`stop` are just for the current session.

## Turning it on / off

- **Run the proxy persistently:** `ccp on`, then point Claude Code at it (`ANTHROPIC_BASE_URL=http://127.0.0.1:18765` etc — see README §4).
- **Go back to direct Anthropic:** `ccp off` and remove/comment the proxy env from Claude Code's settings.

Verify which one is live: `ccp status` (should say `active (running)`) and `ccp health` (should print `ok`/200). When off, `ccp health` fails to connect — that's expected.
98 changes: 98 additions & 0 deletions scripts/ccp/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#!/usr/bin/env bash
# Install the `ccp` helper: a systemd user service for claude-code-proxy plus a wrapper script.
# Linux/WSL only (needs systemd --user). Idempotent — safe to re-run; overwrites the unit and wrapper with these versions.
# See README.md (in this dir) for details
set -euo pipefail

bin="$HOME/.local/bin/claude-code-proxy"
wrapper="$HOME/.local/bin/ccp"
unit="$HOME/.config/systemd/user/claude-code-proxy.service"

# --- sanity: systemd --user must be available (Linux/WSL only; not macOS) ---
if ! systemctl --user show-environment >/dev/null 2>&1; then
echo "error: 'systemctl --user' isn't available. This installer is Linux/WSL only — it uses systemd." >&2
echo " macOS has no systemd (it would need a launchd agent instead); this script doesn't set that up." >&2
echo " WSL: set systemd=true in /etc/wsl.conf, then 'wsl --shutdown' and reopen." >&2
exit 1
fi

# --- sanity: the proxy binary the service will run ---
if [[ ! -x "$bin" ]]; then
echo "warning: $bin not found or not executable." >&2
echo " Install it first (eg 'just install' in the repo, or copy a build there); the service ExecStart points at it." >&2
fi

mkdir -p "$(dirname "$unit")" "$(dirname "$wrapper")"

# --- systemd user unit ---
cat > "$unit" <<'EOF'
[Unit]
Description=Claude Code Proxy for Codex

[Service]
Type=simple
ExecStart=%h/.local/bin/claude-code-proxy serve
Restart=on-failure
RestartSec=2
Environment=CCP_LOG_STDERR=1

[Install]
WantedBy=default.target
EOF
echo "wrote $unit"

# --- ccp wrapper ---
cat > "$wrapper" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

svc="claude-code-proxy.service"

case "${1:-status}" in
start)
systemctl --user start "$svc"
;;
stop)
systemctl --user stop "$svc"
;;
restart)
systemctl --user restart "$svc"
;;
status)
systemctl --user status "$svc" --no-pager
;;
logs)
if [[ "${2:-}" == "-f" || "${2:-}" == "--follow" ]]; then
journalctl --user -u "$svc" -f
else
journalctl --user -u "$svc" --no-pager
fi
;;
on)
systemctl --user enable --now "$svc"
;;
off)
systemctl --user disable --now "$svc"
;;
health)
curl -fsS http://127.0.0.1:18765/healthz && echo
;;
*)
echo "Usage: ccp {start|stop|restart|status|logs [-f]|on|off|health}"
exit 2
;;
esac
EOF
chmod +x "$wrapper"
echo "wrote $wrapper (executable)"

# --- reload so systemd sees the (re)written unit ---
systemctl --user daemon-reload
echo "reloaded systemd user units"

echo
echo "Done. Next steps:"
echo " - ensure ~/.local/bin is on your PATH"
echo " - 'ccp on' enable + start (also starts on login)"
echo " - 'ccp status' check it's active"
echo " - 'ccp health' confirm it's serving on 127.0.0.1:18765"