step-zero / field_notes.md
tc043's picture
refactor: update grammar, remove unused project files, and clean up workspace configuration
144132f
|
Raw
History Blame Contribute Delete
6.05 kB

Field Notes: Building Step-Zero (Cognitive Pacemaker)

Step-Zero is a local-first "Cognitive Pacemaker" application designed to break down overwhelming goals into atomic physical actions to overcome executive dysfunction.

Running small language models (≀4B parameters) entirely on consumer hardware forces you to confront the "Alignment Tax" head-on. Here is the honest developer log of the design decisions, engineering failures, and breakthroughs we encountered.


1. System Architecture

Step-Zero uses a dual-model orchestrator executing locally on CPU/laptop hardware via the llama.cpp runtime.

                  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                  β”‚ Goal & UI Input      β”‚
                  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
                             β–Ό
               β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
               β”‚ Primary Model (Nemotron)  β”‚
               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
                     [Output Valid?]
                     /             \
                   Yes              No (or "Too Hard")
                   /                 \
                  β–Ό                   β–Ό
      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
      β”‚ Render Action in UI  β”‚   β”‚ Fallback (MiniCPM)    β”‚
      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  1. Primary Model (Nemotron-Mini-4B): Fine-tuned using Unsloth SFT specifically on daily goal breakdown datasets (verbs.jsonl) to produce atomic, physical next-step instructions.
  2. Fallback Model (MiniCPM-3-4B): An instruction-following model used for stylistic tone adjustments (Calm vs. Encouraging), semantic repetition loops, and simplifying tasks when a user signals "Too Hard".

2. Technical Alignments & The GBNF Stop-Token Deadlock

During testing under real model inference, we noticed that Nemotron-Mini-4B suffered from severe over-generation, outputting long paragraphs containing prompt template headers, formatting guidelines, and repeat sentences. Every single task triggered our validation filters and fell back to MiniCPM, causing a 25-second latency penalty.

Here are the two breakthroughs that solved this:

Breakthrough A: Resolving the GBNF Sampler Deadlock

We originally constrained the model using a GBNF grammar:

root ::= [a-zA-Z0-9 ,.!?'-]+

We also specified a stop token of \n in the inference call (stop=["\n"]) to terminate the action after the first sentence.

The Failure: The GBNF grammar restricted the allowed character set to letters, numbers, and basic punctuation. Crucially, it did not include the newline character \n. Because GBNF constraints are enforced at the sampler level, the model's probability of selecting \n was set to exactly zero.

As a result, the model was mathematically forbidden from generating the stop token. It kept generating sentence after sentence until it hit the hard limit of max_tokens=64, leading to severe paragraph bloating and prompt echoing.

The Fix: We updated the GBNF grammar to permit newline characters:

root ::= [a-zA-Z0-9 ,.!?\n'-]+

This allowed the model to output a newline character as soon as it finished the task, instantly triggering the stop=["\n"] check and terminating generation after the first sentence. The model now outputs exactly 6 to 8 words, saving massive CPU latency.

Breakthrough B: Token-Level Early Stopping for Prompt Echoing

Small models are highly susceptible to "prompt echoing" (repeating headers like Completed Tasks: or Goal: when prompted). Rather than waiting for the model to generate a full 64-token sequence of echoed prompt template text before filtering it out in Python, we added the headers directly to the llama.cpp stop-words:

stop=["\n", "<extra_id_1>", "Completed Tasks", "Goal:", "User:", "Assistant:"]

If the model begins echoing the prompt template, it hits a stop word within 1 or 2 tokens and halts generation immediately. This terminates failed inference loops in under 50ms, allowing an instantaneous fallback to MiniCPM.


3. Custom UI/UX: The "Fog of War"

To support the cognitive design of the pacemaker (which aims to reduce cognitive load), the app features a minimal, custom dark theme. By leveraging Gradio's CSS custom properties on :root and .dark, we overrode Gradio's standard elements to deliver a clean, borderless dark UI styled like a game interface:

  • Fog of War: Completed history is styled with low opacity (opacity: 0.3) and blurred (filter: blur(2px)) to keep the user's attention anchored on the single next step.
  • Start Button Theme: Overrode Gradio's default primary orange buttons to match the deep forest green theme of the interface.
  • Timer and Recovery: Included a clean "Start Over" action flow to allow user recovery once the circuit breaker fires.

4. Key Takeaways & Small Model Constraints

  1. Syntax Constraints are Sampler Constraints: Constraining text syntax with GBNF without matching stop criteria can lead to sampler deadlocks. Always align your grammar's allowed character space with your engine's stop sequences.
  2. LoRA Fine-tuning is Highly Sensitive: A 4B parameter model is highly sensitive to format drift. Minor discrepancies between fine-tuning prompt structure and inference structure will cause formatting breakdowns.
  3. Optimized CPU Execution: With optimized GGUF quantizations and proper early stopping, both models run under 50ms per token on consumer CPU laptop hardware, making fully offline cognitive assistance viable.