From 0ad25975bb6e5cc1334323e680080acbdf0480ff Mon Sep 17 00:00:00 2001 From: Sam OT Date: Thu, 2 Jul 2026 16:52:15 +0100 Subject: [PATCH] add ccp helper: run the proxy as a systemd user service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit scripts/ccp/install.sh writes a claude-code-proxy.service user unit and a ccp wrapper (start/stop/restart/status/logs [-f]/on/off/health); README.md documents setup and usage. Linux/WSL only — the installer refuses to run without systemd. Local convenience, not shipped by the proxy itself. --- scripts/ccp/README.md | 49 +++++++++++++++++++++ scripts/ccp/install.sh | 98 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 scripts/ccp/README.md create mode 100755 scripts/ccp/install.sh diff --git a/scripts/ccp/README.md b/scripts/ccp/README.md new file mode 100644 index 0000000..7bd7dc9 --- /dev/null +++ b/scripts/ccp/README.md @@ -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. diff --git a/scripts/ccp/install.sh b/scripts/ccp/install.sh new file mode 100755 index 0000000..c615b58 --- /dev/null +++ b/scripts/ccp/install.sh @@ -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" \ No newline at end of file