Hands-On Coding Examples with Little-Coder
This chapter walks through five real-world scenarios demonstrating how little-coder uses its local skills config to execute, test, and write code safely with local Gemma 4 models.
Dear reader, This chapter documents my current experiments for improving tougher edge-cases of using small local models for agentic coding. Please consider this chapter to be a work in progress.
A note on names: the Write-and-Notify strategy is defined by the skill file .pi/agent/skills/write-temp-strategy.md (skill id no-edit-create-new-files). When this chapter says Write-and-Notify, it means that skill.
Example 1: Headless Common Lisp Execution
Interacting with interactive Lisp environments (REPLs) can be dangerous for automated agents. If an agent executes a command that drops into an interactive debugger or waits for keyboard input, the agent’s execution will hang and time out.
The common-lisp.md skill prevents this by forcing all SBCL actions to be headless and non-interactive.
Scenario: Verifying a Lisp Script compiles
An agent needs to compile and test a new macro defined in utils.lisp.
Unoptimized command (Will hang on failure/repl):
1 sbcl --load utils.lisp
Optimized agent command (From Skill):
1 sbcl --no-userinit --non-interactive --load utils.lisp --eval "(quit)"
Scenario: Running tests via ASDF
If the agent needs to load a system and execute tests, the skill defines a clean exit sequence:
1 sbcl --no-userinit --non-interactive \
2 --eval "(asdf:load-system :my-app)" \
3 --eval "(asdf:test-system :my-app)" \
4 --eval "(quit)"
By appending --eval "(quit)" and utilizing --non-interactive, any error encountered during test loading will dump its stack trace to stderr and exit immediately, allowing the agent to parse the logs and self-correct.
Example 2: Clojure Deps Automation and Execution
When working in Clojure, agents sometimes default to legacy tools like Leiningen (lein). This causes build overhead and configuration mismatches if the project uses the modern CLI deps structure (deps.edn).
The clojure.md skill enforces modern CLI tool usage and provides exact invariants for execution.
Scenario: Evaluating inline namespaces
To test if a particular utility function works, the agent runs:
1 clojure -M -e "(use 'my.namespace) (some-function)"
Scenario: Running tests
Instead of guessing the runner, the agent checks the repository structure and defaults to the configured testing alias:
1 clojure -M:test
The rule mandates that the agent must not call lein unless a project.clj is explicitly detected via glob tools.
Example 3: Rapid TypeScript Iteration via TSX
Traditionally, running TypeScript requires compiling files to JavaScript using the TypeScript Compiler (tsc) and then executing them with Node.js. This introduces disk write overhead and creates temporary .js files that clutter the directory.
The typescript.md skill optimizes this loop using tsx (TypeScript Execute).
Scenario: Execution and Watch Loop
The agent wants to execute a test script test-api.ts directly:
1 npx tsx test-api.ts
Scenario: Strict Type Validation
Before completing a task, the agent runs a compiler check to ensure no type errors were introduced:
1 npx tsc --noEmit
Using --noEmit validates the entire type tree without writing anything to disk.
Example 4: The Write-and-Notify File Strategy
Agents that perform search-and-replace regex edits on existing production files frequently corrupt code or mess up line indentation.
To mitigate this, the write-temp-strategy.md skill enforces the Write-and-Notify strategy.
Workflow in Action:
Instead of running an inline edit tool on src/auth.ts, the agent:
Creates a new, isolated temporary file containing the full implementation:
tmp_auth_validation.ts-
Writes the complete, functional code block with imports included:
1 // tmp_auth_validation.ts 2 import { User } from "./types"; 3 4 export function validateUser(user: User): boolean { 5 return !!user.email && user.age >= 18; 6 }
-
Informs the user in the final response:
“I have created the new validation logic in
tmp_auth_validation.ts. You can runnpx tsx tmp_auth_validation.tsto test it, and copy it tosrc/auth.tswhen ready.”
This strategy preserves codebase integrity and lets the user control the merge step manually. Clean up tmp_* files once you merge them.
Example 5: Headless Python Execution via uv
Python is half of my daily work in this setup, so it gets the same treatment: a python.md skill that pins the runtime loop.
The skill enforces one runner per project. If the project has pyproject.toml or uv.lock, the agent uses uv run. Otherwise it uses python3 -m venv plus pytest. The agent never installs packages globally and never guesses between pip, conda, and uv.
Scenario: Running a script headless
1 uv run python csv_stats.py data.csv
Scenario: Running tests
1 uv run pytest -q
Scenario: Adding a dependency
1 uv add httpx
2 uv run pytest -q
Small models corrupt Python files the same way they corrupt TypeScript files, so the Write-and-Notify strategy applies here too: new logic goes in tmp_* files first, and you merge by hand.
Writing Your First Skill
When you adopt a new language or build tool, add one skill file. The recipe is short:
- Create
.pi/agent/skills/<name>.mdin this repo, then copy it to~/.pi/agent/skills/per the Setup chapter. -
Start with front matter the loader reads:
1 --- 2 name: <name> 3 description: <one line, headless focus> 4 ---
- Write one
# Skill:title, a## Tool Invariantssection with exact commands the agent must run, and a## Rulessection with bans (for example: never open a REPL, never use the global installer). - Test with the prompt from Setup: ask what skills are loaded for your topic and check the answer names your file. Then give the agent one small real task and confirm it ran your invariant commands.
- Keep skills short. Three invariants and three rules beat ten. Prune lines the agent never cites.