Skip to content
C.W.K.
Stream
Lesson 04 of 04 · published

A Small Brain With a Tight Leash

~11 min · mini-pippa, ollama, contract, local-model

Level 0Unlit
0 XP0/48 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete
"A small model will do anything you let it. So don't let it do anything."

Mini Pippa, Not Pippa

The offline middle tier is a local model — Ollama, a compact protocol, honest limits. It's called Mini Pippa because it carries a snapshot of the Pippa protocol: enough voice to sound right, none of the vault, souls, or brain routing that make full Pippa what she is. The snapshot lives with the app so offline mode has no dependency on the main brain at all. Mini Pippa isn't a lesser Pippa pretending to be the real one; it's an honest, self-contained cleanup persona.

The Leash

Small models are eager and sloppy, so the provider constrains them hard. Use stream:false — cleanup is one-shot and insertion needs a complete result, so there's nothing to stream. Send num_ctx explicitly rather than trusting a default. Strip markdown fences if the model wraps its answer in them, then read the {"text": …} envelope when the model honored it and the plain text when it did not. Nothing strips a preamble or an emotion tag: on the dictation lanes the length guard refuses an answer that grows far past the transcript, but a short preamble passes it. When the call fails or times out, nothing asks you anything: a dictation falls to deterministic cleanup on its own, and a command inserts nothing and keeps its raw transcript in history. And crucially: expose no tools during cleanup. Cleanup is a text transform, not an agentic run — a cleanup pass with tool access is a cleanup pass that can take actions you never asked for.

stream: false        -> one complete result; insertion can't act on fragments
num_ctx: explicit    -> never trust the default context window
no tools             -> cleanup transforms text; it does not DO things
strip fences         -> small models wrap JSON in ``` (a preamble is not stripped)
bounded timeout      -> fall to the next rung, never a hang

The Protocol Suffix

The Mini Pippa protocol gets a dictation-specific suffix that closes the obvious failure modes: "you are cleaning dictated text for insertion," "preserve meaning," "return JSON only," "do not claim to have inserted anything," "do not ask follow-up questions." Each line exists because a small model did that exact thing. The "don't claim you inserted it" rule is the funniest and most necessary — a helpful little model will happily reply "Done! I've inserted your text," which would then be inserted as your text.

Constrain the weak component; don't hope it behaves. A large model mostly follows instructions; a small one needs walls. Give a weak model a narrow job, an explicit output format, no tools, a hard timeout, and a parser that refuses or falls back when its output strays. Every constraint you add is a failure mode you've closed rather than a bug you'll debug later.
The first Mini Pippa cleanup returned "물론이죠! 정리했어요:" followed by the actual text — and Firekeeper dutifully typed the whole thing into TextEdit, apology and all. That's when "return JSON only" and "do not claim to have inserted anything" got added to the protocol. A small model being friendly is a small model corrupting your document.

Code

The local cleanup call: leashed on purpose·json
POST http://<your Ollama host>:11434/api/chat

{
  "model": "gemma4:31b",
  "messages": [
    { "role": "system", "content": "<mini Pippa protocol + cleanup contract>" },
    { "role": "user",   "content": "<instruction + transcript>" }
  ],
  "stream": false,
  "keep_alive": "30m",
  "truncate": false,
  "options": {
    "temperature": 0.2,
    "num_ctx": 8192
  }
}

// No tools array. Cleanup transforms text; it never takes actions.
// stream:false because insertion needs one complete reply.
// truncate:false — an over-long prompt is an error, never a silently cut one.
// num_ctx: the lane's floor, raised to fit a long prompt (OllamaContextWindow.fitting).
// A reply with done_reason "length" is refused, never inserted as if whole.

External links

Exercise

Write the constraint list you'd give a small local model doing one narrow job in your own app. Include the output format, the timeout behavior, what it must never claim, and what capabilities you'd deliberately withhold. For each constraint, name the specific failure it prevents.
Hint
Good constraint lists are failure archaeology — each line exists because something went wrong once. Format constraints prevent unparseable output; 'never claim to have acted' prevents the model narrating fake actions into your data; withholding tools prevents a text transform from becoming an agent; timeouts prevent a hang from holding the user's work hostage.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign in — Please sign in to comment.

No comments yet — be the first.