Contributing to PickySteve
July 6, 2026 · View on GitHub
PickySteve is Phase 1 (MVP) only, built strictly to an architecture spec — see the README's "Phase 1 non-goals" before proposing new subsystems (tracing, standing eval harness, credential vault, sandbox). Those are added only when a real, observed Phase-1 failure justifies them.
Dev setup
# from the repo root (Windows; uv 0.10+, Ollama with qwen3:8b running locally)
uv venv --python 3.11 .venv
uv pip install --python .venv/Scripts/python.exe -r requirements.txt
Or with plain pip:
python -m venv .venv
.venv/Scripts/python.exe -m pip install -r requirements.txt
Models are served locally via Ollama, default qwen3:8b:
ollama pull qwen3:8b
ollama serve
Config is all PS_* environment variables — see pickysteve/config.py. The client
uses Ollama's native /api/chat endpoint (think:false) by default, not the
OpenAI-compat one — the compat endpoint doesn't honor thinking control for qwen3.
Running the eval / test suites
# Ollama-free, no downloads — pure Python, run this before every commit (<1s)
.venv/Scripts/python.exe eval/test_gate_security.py
# Requires the real ONNX defender + a running Ollama (router/judge calls, HF model downloads
# for the reranker/embeddings on first run)
.venv/Scripts/python.exe tests/test_security_gate.py
.venv/Scripts/python.exe tests/test_fixes.py
# Routing-quality trifecta — requires Ollama + calibrated floor (eval/calibrate.py first)
.venv/Scripts/python.exe eval/run_sim.py # sim_registry, PS_SIM_TASKS override
PS_SIM_TASKS=eval/sim_tasks_harder.jsonl .venv/Scripts/python.exe eval/run_sim.py
PS_SIM_TASKS=eval/sim_tasks_heldout.jsonl .venv/Scripts/python.exe eval/run_sim.py
CI (.github/workflows/ci.yml) only runs eval/test_gate_security.py — everything
else needs a live Ollama and/or first-run Hugging Face model downloads, so it's a local
gate, not (yet) a CI gate.
Any change that can affect routing quality (router prompts, retrieval, reranker,
floor/dedupe, dominance ratio, compat check) must re-run the trifecta
(base/harder/held-out run_sim.py suites) before merge and report the resulting
pass rate in the PR description. Don't merge a routing change on vibes.
Code style
Match what's already there — no new formatter/linter config, no reformatting unrelated
lines. Broadly: from __future__ import annotations, type hints on public functions,
env-var config through pickysteve/config.py (no ad-hoc os.getenv scattered through
modules), fail-closed on anything security-gate related, and plain scripts over pytest
for eval/test runners (keeps the dependency list minimal per spec §6.5).
Opening a PR
- Small, focused diffs. If it touches
security_gate.pyorassembly.py, call that out explicitly in the PR description — those are the highest-risk-surface files. - If you found or fixed a real bug during review, add a regression check to
eval/test_gate_security.py(see its docstring for the pattern: onecheck()per invariant, tied to the bug that was live). - No PyPI package or
pyproject.tomlyet — don't add packaging config in an unrelated PR.
Reporting issues
Open an issue with a failing request + the skill you expected, or a PR against a
registry/*.md skill doc if it's a routing/content problem rather than a code bug.