# Quickstart The inference server lives at [github.com/riposta/CrossbowReviewer](https://github.com/riposta/CrossbowReviewer). It has two backends that return the same decisions. | Backend | Weights | Hardware | Speed (one file, ~16 questions) | |---|---|---|---| | `transformers` (default) | BF16 safetensors (17.9 GB) | CUDA GPU ≥ 24 GB, Apple Silicon ≥ 32 GB, or CPU | ~0.2 s on an A100 | | `llamacpp` | Q8_0 GGUF (9.5 GB) | GPU ≥ 12 GB, Apple Silicon ≥ 16 GB, or CPU | ~3 s on an M5 Pro (Metal) | ## transformers backend ```bash git clone https://github.com/riposta/CrossbowReviewer && cd CrossbowReviewer uv run uvicorn server:app --port 8000 ``` On the first request the server downloads `riposta/CrossbowReviewer-9B`. To use a local copy, set `MODEL`: ```bash huggingface-cli download riposta/CrossbowReviewer-9B --exclude "gguf/*" --local-dir CrossbowReviewer-9B MODEL=./CrossbowReviewer-9B uv run uvicorn server:app --port 8000 ``` ## llama.cpp backend ```bash huggingface-cli download riposta/CrossbowReviewer-9B gguf/CrossbowReviewer-9B-Q8_0.gguf \ tokenizer.json tokenizer_config.json decision_config.json --local-dir CrossbowReviewer-9B # 1. llama.cpp with Qwen3.5 support (a recent build) llama-server -m CrossbowReviewer-9B/gguf/CrossbowReviewer-9B-Q8_0.gguf --port 8080 -ngl 99 -c 16384 # 2. the decision server in front of it BACKEND=llamacpp LLAMA_URL=http://127.0.0.1:8080 MODEL=./CrossbowReviewer-9B \ uv run uvicorn server:app --port 8000 ``` How the llama.cpp backend works: - The decision server tokenizes the prompt with the model's own tokenizer. - It then asks `llama-server` for the next-token log-probabilities at each answer slot, on a growing token prefix. - `llama-server`'s prompt cache evaluates only the new tokens of each question. ## Requests All built-in rules for a language: ```bash curl -s localhost:8000/v1/systemone -H 'content-type: application/json' \ -d '{"state": {"language": "java", "code": "public class A { void run() { try { db.save(); } catch (Exception e) {} } }"}}' ``` Selected rules and custom questions: ```bash curl -s localhost:8000/v1/systemone -H 'content-type: application/json' -d '{ "state": {"language": "go", "code": "..."}, "questions": { "swallowed_exceptions": {"type": "noul", "instructions": "Is the code free of swallowed or ignored errors?"}, "owner": {"type": "choice", "instructions": "Which team should review this change?", "criteria": {"backend": "business logic, APIs", "platform": "infrastructure, CI", "security": "auth, crypto, secrets"}}, "risk": {"type": "score", "instructions": "Merge risk", "criteria": {"1": "none", "2": "low", "3": "medium", "4": "high"}}}}' ``` Response, one entry per question: ```json {"decisions": {"owner": {"choice": "backend", "confidence": 0.81, "distribution": {"backend": 0.81, "platform": 0.12, "security": 0.07}}}} ``` **Validation:** `choice` needs 2–26 criteria and `score` needs 2–10 levels. An invalid request returns HTTP 422. **Language:** `state.language` is optional. Without it, only the language-agnostic rules are asked.