← TinyGPT · docs · devlog · roadmap · speedup
source: docs/recipes/pace-planner.md · view on GitHub ↗

Recipe — Pace planner specialist

The factory’s first product-validating arc. Distill Pace’s qwen3-30b-a3b planner into a small student. See docs/prds/specialist-pace-planner.md for full spec.

This recipe is the executable form — the actual commands to run.

Prerequisites (verified 2026-06-07)

Pace’s system prompt (canonical)

you're pace, a voice companion in the user's menu bar. the user just spoke
to you via push-to-talk and you can see their screen. your reply is read
aloud, so write the way you'd actually talk.

rules:
- default to one or two sentences. be direct.
- all lowercase, casual, warm. no emojis.
- write for the ear. no lists, no bullets, no markdown.
- spell out small numbers, no "e.g." or "i.e.".
- if the question relates to what's on their screen, reference what you see.
  otherwise just answer the question.
- never say "simply" or "just".

pointing:
you have a cursor that can fly to and point at things on screen. point
whenever it would help. when you point, append [POINT:x,y:label] at the
very end. if pointing wouldn't help, append [POINT:none].

Tool-tag taxonomy (from fixtures)

TagUseExample
[POINT:x,y:label]Point cursor at element[POINT:412,40:save button]
[POINT:none]No pointing needed[POINT:none]
[CLICK:x,y:label]Click element (action mode)[CLICK:412,40:save button]
[DOUBLE_CLICK:x,y:label]Double-click
[TYPE:text]Type text[TYPE:hello world]
[SCROLL:dir:amount]Scroll[SCROLL:down:200]
[KEY:keys]Press keys[KEY:cmd+s]
[OPEN_APP:name]Launch app[OPEN_APP:Notes]
[VOLUME:dir]Adjust volume
[BRIGHTNESS:dir]Adjust brightness

Fixture categories (the eval signal)

FixtureTestsExpected output shape
qa-no-screen.jsonPure-knowledge Q&A[POINT:none] + natural sentence
screen-referential.json”save it for me” with screen state[POINT:x,y:label] with valid coords
multi-turn-continuation.jsonFollow-up questionConversational, no rehash
action-mode-off.jsonAction mode OFF, user asks for actionRefuse action tags, only [POINT:]

Pipeline

1. Generate input pool (no teacher needed)

Extract or synthesize prompts in Pace’s shape.

Option A — use clickyLocal’s existing tool:

cd /Users/sarthak/Desktop/fleet/clickyLocal/
python scripts/generate-intent-corpus.py --count 1000 --out ~/.cache/tinygpt/datasets/pace-prompts.jsonl

Option B — start with the 4 fixtures and synth variants:

# Parse fixtures, extract user messages, mutate variants
python scripts/pace-prompts-from-fixtures.py \
    --fixtures /Users/sarthak/Desktop/fleet/clickyLocal/evals/fixtures/ \
    --variants-per 100 \
    --out ~/.cache/tinygpt/datasets/pace-prompts.jsonl
# (TODO: write this; ~50 lines)

2. Label with teacher (qwen3-30b-a3b via LM Studio)

tinygpt synthesize \
    --teacher http://localhost:1234/v1 \
    --teacher-model qwen/qwen3-30b-a3b \
    --inputs ~/.cache/tinygpt/datasets/pace-prompts.jsonl \
    --input-field prompt \
    --system-file docs/recipes/pace-system-prompt.txt \
    --grammar grammars/pace-tool-tags.gbnf \
    --temperature 0.0 \
    --parallel 4 \
    --rate-limit 30 \
    --out ~/.cache/tinygpt/datasets/pace-labeled.jsonl

Wall time: ~30-60 min for 1K-10K samples, depending on LM Studio’s tok/s.

3. Distill into Qwen3-0.6B

QWEN_DIR=~/.cache/huggingface/hub/models--Qwen--Qwen3-0.6B/snapshots/<HASH>
mkdir -p ~/.cache/tinygpt/runs/pace-planner-v1

tinygpt sft "$QWEN_DIR" \
    --data ~/.cache/tinygpt/datasets/pace-labeled.jsonl \
    --template chatml \
    --rank 16 --alpha 32 \
    --steps 2000 \
    --lr 1e-4 \
    --max-seq 2048 \
    --out ~/.cache/tinygpt/runs/pace-planner-v1/pace-planner-v1.lora

Wall time: ~30 min on M5 Pro.

4. Eval against Pace’s fixtures

# Spin up student as OpenAI-compat endpoint
tinygpt serve ~/.cache/tinygpt/runs/pace-planner-v1/pace-planner-v1.lora \
    --base "$QWEN_DIR" \
    --port 8765 \
    --grammar grammars/pace-tool-tags.gbnf &

# Run Pace's eval against our endpoint
cd /Users/sarthak/Desktop/fleet/clickyLocal/
LOCAL_PLANNER_URL=http://127.0.0.1:8765/v1 \
LOCAL_PLANNER_MODEL=pace-planner-v1 \
python scripts/eval-planners.py

Compare to qwen3-30b-a3b’s 15/15 baseline + 925ms latency.

5. Ship into Pace

Add a TinyGPTPlannerClient.swift conformer in clickyLocal that implements BuddyPlannerClient against the serve port. Toggle via:

PlannerProvider = tinygpt-local
LocalPlannerModelIdentifier = pace-planner-v1
LocalPlannerURL = http://127.0.0.1:8765/v1

Acceptance criteria

CriterionTarget
Fixture pass rate≥ 14/15 (one miss tolerable)
Latency p50< 200ms
RAM footprint< 1.5 GB
Tag format compliance100% (constrained decoding)
Daily-driver in Pace1 week without rollback

Status — 2026-06-07 EOD