# cf — bash CLI for clawdforge Single-file shell client for [clawdforge](../../README.md). Wraps `curl` so you can drive clawdforge from cron jobs, deploy scripts, one-off pipes, or any shell where pulling in a Python/Go runtime is overkill. ## Install ```sh sudo install -m 755 cf /usr/local/bin/cf ``` Or just symlink into `~/bin`: ```sh ln -s "$(pwd)/cf" ~/bin/cf ``` No dependencies beyond `curl` + standard POSIX tools. `jq` is optional — used for prettier error output if available, never required. ## Configuration Reads from env or `~/.config/clawdforge/cf.env` (env wins on conflict): | Variable | Default | Purpose | |---|---|---| | `CLAWDFORGE_URL` | `http://192.168.0.5:8800` | clawdforge base URL | | `CLAWDFORGE_TOKEN` | — | per-app bearer; required for `/run`, `/files` | | `CLAWDFORGE_ADMIN_TOKEN` | — | bootstrap admin bearer; required for `cf admin *` | Example `cf.env`: ```sh CLAWDFORGE_URL=http://192.168.0.5:8800 CLAWDFORGE_TOKEN=cf_AbCd... CLAWDFORGE_ADMIN_TOKEN=... ``` ## Commands ``` cf healthz cf run "" [--model sonnet] [--system "..."] [--timeout 60] [--files token1,token2] cf run - # read prompt from stdin (any size) cf upload [--ttl 3600] cf admin token-mint [--ip-cidrs cidr1,cidr2] cf admin token-list cf admin token-revoke # Sessions (v0.2 — multi-turn) cf session new [--agent claude] [--meta '{"k":"v"}'] [--json] cf session turn "" [--files tok1,tok2] [--timeout 120] [--json] [--trace path] cf session turn - # read prompt from stdin cf session get [--json] cf session list [--include-closed] [--json] cf session close [--json] ``` Output is JSON to stdout — pipe to `jq` for shaping. Errors go to stderr. ### Exit codes | Code | Meaning | |---|---| | 0 | ok | | 1 | curl/transport failure | | 2 | usage error (bad/missing args) | | 3 | missing required token | | 4 | HTTP 4xx (auth, not found, bad request) | | 5 | HTTP 5xx (server / claude failure) | ## Examples ### Health check in a cron preamble ```sh cf healthz | jq -e '.claude_present' >/dev/null || { echo "clawdforge not ready"; exit 1; } ``` ### One-shot prompt with JSON output ```sh cf run 'Reply with JSON: {"city":"Lake Elsinore","feel":"summer"}' --model sonnet \ | jq -r '.result.city' ``` ### Long prompt via stdin (anything bigger than the OS argv limit) ```sh cat <<'PROMPT' | cf run - --timeout 180 You are a precise recipe parser. Given the following text… … PROMPT ``` The bash CLI doesn't do anything special for size — it relies on clawdforge's server-side stdin path for prompts > 64KB. ### Upload a file then attach it to a run ```sh ft=$(cf upload /tmp/recipe.png --ttl 3600 | jq -r '.file_token') cf run "extract the recipe from this image as JSON" --files "$ft" --timeout 120 ``` ### Mint a per-app token ```sh cf admin token-mint johnny5 --ip-cidrs 172.24.0.0/16 # → {"name":"johnny5","token":"cf_...","ip_cidrs":["172.24.0.0/16"]} ``` ## Sessions (v0.2) Multi-turn sessions backed by [ACPX](https://github.com/openclaw/acpx) on the server. Use these when you need context to persist across turns — "build this with me step by step", "now try X… now try Y", etc. For one-shot prompts, stick with `cf run`. > Sessions don't autoclose — call `cf session close ` when done. > They time out server-side after 1h idle anyway. ### The 5 subcommands | Command | Purpose | |---|---| | `cf session new` | Create a session. Prints just the UUID to stdout for piping. | | `cf session turn ""` | Send a prompt. Default output = concatenated text events. | | `cf session get ` | Print the session's state JSON (turn count, timestamps, closed_at). | | `cf session list` | List the calling token's sessions as a tab-separated table (or JSON with `--json`). | | `cf session close ` | Soft-close the session. Idempotent — exits 0 even on already-closed. | The `--json` flag mirrors the v0.1 convention: when present, every subcommand prints the full server response JSON to stdout instead of its default human-readable shape. ### End-to-end: build a feature across 3 turns ```sh sid=$(cf session new --agent claude --meta '{"task":"add-cache-layer"}') cf session turn "$sid" "Read src/store.go and tell me where caching should live." cf session turn "$sid" "Now write a Redis-backed cache wrapping the existing Get/Put." cf session turn "$sid" "Add tests for cache hit / miss / TTL expiry." cf session close "$sid" # → "closed" ``` ### Default vs JSON output `cf session turn` defaults to concatenating just the `text` events to stdout (matches `cf run` style). Use `--json` for the full event batch including `thinking` and `tool_call` frames, plus `stop_reason` and `duration_ms`: ```sh cf session turn "$sid" "summarize" --json | jq '.events | map(.type) | unique' # → ["text","thinking","tool_call"] ``` `--trace path` writes the full JSON response to a file regardless of `--json`. Useful when you want the human text on stdout AND a structured audit trail in the same call: ```sh cf session turn "$sid" "explain the PR" --trace ./traces/turn-$(date +%s).json ``` ### Listing and inspecting ```sh cf session list # SESSION_ID AGENT TURNS CREATED_AT CLOSED_AT # 9f1c... claude 3 1714000000 - # c71e... claude 1 1714003600 1714005400 cf session list --json | jq '.sessions[] | select(.closed_at == null) | .session_id' cf session get "$sid" | jq '.turn_count' ``` ### Idempotent close in cleanup paths `cf session close` exits 0 whether the session was already closed or not, so it's safe to call from `trap` handlers: ```sh sid=$(cf session new) trap 'cf session close "$sid" >/dev/null 2>&1 || true' EXIT cf session turn "$sid" "long-running task..." # trap fires on exit; "closed" first time, "already-closed" any subsequent. ``` ### Errors The same exit codes as v0.1 apply: - `2` — bad usage (unknown flag, invalid session id, malformed `--meta`) - `3` — `CLAWDFORGE_TOKEN` not set - `4` — HTTP 4xx (404 for cross-token access — server doesn't leak existence) - `5` — HTTP 5xx (acpx pool full, internal failure, etc.) Bearer tokens never appear in error output, the same hardening as v0.1. ## Pattern: bash-only no-jq fallback If you can't install `jq`, parse with `read`: ```sh read -r status size < <(cf upload "$path" | grep -o '"file_token":"[^"]*"\|"size":[0-9]*' | tr '\n' ' ') ``` But really, install `jq`. ## License Same as the rest of clawdforge (MIT).