# ringagent

An LLM ring-design product with a **total harness**: the model only writes
**RingSpec** — a declarative JSON language (shank/head/accents/details, or
classic archetype presets) — and a deterministic CLI compiles it into
manufacturable rings: one watertight castable body, print STLs with sprues,
production seats for real certified diamonds, work orders, and test-fit
coupons. Judged against real product photos round over round; every fix lands
in the compiler, so quality only ratchets up. Built on build123d / CadQuery.

**Product flow**: Telegram message → agent writes the spec & builds →
customer gets a studio link (3D + notes + Approve) → production files →
AgentMail to the printer. See `docs/SPEC.md`.

## Layout

```
ringcli/     the product: spec (RingSpec language), templates (STYLE table),
             parts kit, shanks, cli, cast/coupon/workorder, render, validate
prompts/     the shipped prompts: design agent manual + judge rubric
designs/     generated spec files (inspectable, committed)
harness/     serve (studio + API), telegram_bot, triage, revise,
             eval loop (author, judge, newround)
viewer/      design.html (customer studio) · review.html · eval.html · 3D viewer
eval/rounds/ random benchmarks
.agents/     CAD STEP/GLB engine (runtime dependency)
```

## Architecture

```
spec {cut, carat, size, archetype, metal}
  └─> ringcli/cli.py          build --spec-json / bench <round.json>
        └─> ringcli/templates.py   archetype templates (solitaire, bezel,
        │                            halo, three_stone, pavé) + STYLE table —
        │                            every proportion constant the eval tunes
        └─> ringcli/parts.py       parts kit: band, faceted gems (34°/41°/55%
        │                            faceting refs), claws, gallery rail,
        │                            cathedral arms, bezel, halo_ring, pavé
        └─> STEP + GLB (validated)   artifacts/cli/<name>/
```

**Eval loop** (`harness/author.py <iteration>`):
1. Build every design of the round via the CLI.
2. Render with `ringcli/render.py` — numpy z-buffer rasterizer, per-part
   colors (the STEP pipeline drops Compound child colors), full view + head
   close-up.
3. Judge with a vision model via OpenRouter (`PI_JUDGE_MODEL`, default Claude):
   7-axis boolean rubric vs a real reference photo, 3-of-5 majority per axis,
   768px inputs (cost-capped). Prompt calibrated for schematic renders with a
   bad-geometry control test.
4. Write the dashboard, commit, push.

**Random benchmarks** (`harness/newround.py <iter> --n 8`): seeded random
cut × archetype × carat × metal draws; web-searches a real product photo per
design (DuckDuckGo → retailer og:image, paced + backoff); references are
vision-verified, `--set-ref` records hand-corrected ones.

**Human review** (`harness/serve.py`, port 8770):
- `/viewer/review.html` — reference vs build, per-axis fails, judge diffs,
  embedded 3D viewer (GLB), comment box → revision requests
- `/viewer/eval.html` — score history dashboard
- Comments land in `artifacts/review/comments.json`; the improvement loop
  translates open ones into spec/STYLE changes and resolves them.

## Run it

```bash
uv venv --python 3.12 .cad-venv
uv pip install --python .cad-venv/bin/python cadquery build123d numpy matplotlib pytest

# build one ring from a spec
.cad-venv/bin/python -m ringcli.cli build --name my-ring \
    --cut round --carat 1.5 --size 6.5 --archetype solitaire --metal yellow

# draw a fresh random benchmark + judge it (needs OPENROUTER_API_KEY in .env)
.cad-venv/bin/python harness/newround.py 70 --n 8
BENCH_FILE=eval/rounds/r70.json .cad-venv/bin/python harness/author.py 70

# review UI
.cad-venv/bin/python harness/serve.py
```

## History

The scoreboard resets every time the eval gets more honest (colored renders,
z-buffer, close-ups, 5 votes) — see `artifacts/eval-dashboard/results.json`
and the git log: every round and every harness change is one commit.

Legacy: the original `ring-design`/`ringkit` conversational MVP described in
[PLAN.md](PLAN.md) predates the harness; `docs/` keeps the design notes.
