GitHub - NehmeAILabs/bonsai

8 min read Original article ↗

A practical guide to not over-engineering your AI stack.

Before you reach for a frontier model, ask yourself: does this actually need a trillion-parameter model?

Most tasks don't. This repo helps you figure out which ones.

This repo is an Agent Skill called bonsai — an open standard for extending AI agents with reusable expertise, supported by Claude Code, opencode, Cursor, Gemini CLI, OpenAI Codex, GitHub Copilot, VS Code, Goose, Roo Code, Amp, and 70+ other tools. The decision logic lives in skills/bonsai/SKILL.md; this README is the full human-readable guide.


Install

This skill follows the Agent Skills standard, so it installs into any compatible harness. Two ways:

skills CLI (one command, every harness)

skills is the CLI for the open agent skills ecosystem — npm for skills. It auto-detects your installed agents, writes the skill to each one's discovery directory, and symlinks (or copies) so a single source of truth stays updateable. Zero install via npx:

npx skills add nehmeailabs/bonsai

That's it. The repo is the source; the skill inside is bonsai. Pick your agent (detected ones are pre-selected), confirm, done. Works across 72+ agents — Claude Code, Cursor, Codex, Gemini CLI, opencode, GitHub Copilot, Windsurf, Aider, and the rest.

Common flags:

npx skills add nehmeailabs/bonsai --list                          # preview before installing
npx skills add nehmeailabs/bonsai --skill bonsai -g                # install just bonsai, globally
npx skills add nehmeailabs/bonsai -a claude-code -a opencode       # target specific agents
npx skills add nehmeailabs/bonsai --skill bonsai -g -a claude-code -y  # non-interactive (CI/CD)

Other commands: npx skills list, npx skills find <query>, npx skills update, npx skills remove, npx skills use <source> (use without installing).

Manual clone (no CLI)

No package manager needed — each harness discovers skills from its own directory. The .agents/skills/ path is the cross-harness discovery alias: opencode, Cursor, Gemini CLI, Codex, GitHub Copilot, and Amp all pick it up, so a single clone covers several tools. The skill lives at skills/bonsai/ in the repo, so clone to that name.

# Universal — opencode, Cursor, Gemini CLI, Codex, Copilot, Amp, and any .agents/-aware harness
git clone https://github.com/nehmeailabs/bonsai.git ~/.agents/skills/bonsai   # global
git clone https://github.com/nehmeailabs/bonsai.git .agents/skills/bonsai      # project-local

Some harnesses only read their own directory. Clone into the path your harness scans:

Harness Global path Project path
Claude Code ~/.claude/skills/bonsai .claude/skills/bonsai
opencode ~/.config/opencode/skills/bonsai .opencode/skills/bonsai
Cursor ~/.cursor/skills/bonsai .cursor/skills/bonsai
Gemini CLI ~/.gemini/skills/bonsai .gemini/skills/bonsai
OpenAI Codex ~/.codex/skills/bonsai .codex/skills/bonsai
Goose ~/.config/goose/skills/bonsai .goose/skills/bonsai
Roo Code ~/.roo/skills/bonsai .roo/skills/bonsai

Gemini CLI also ships a native install command:

gemini skills install https://github.com/nehmeailabs/bonsai.git --consent

Verify

After installing, restart your harness (Gemini CLI picks up new skills with /skills reload). The skill loads automatically and is surfaced when you ask about model selection, RAG, agent architecture, structured output, or extraction. In Claude Code, invoke it directly with /bonsai.

Validate against the spec

npx skills-ref validate .

Checks that skills/bonsai/SKILL.md frontmatter follows the Agent Skills spec.

The Decision Tree

                         You have a task.
                                │
                                ▼
              ┌─────────────────────────────────┐
              │  Can regex, rules, or lookup    │
              │  tables solve it?               │──── YES ───► Use that. Stop.
              └─────────────────────────────────┘
                                │ NO
                                ▼
              ┌─────────────────────────────────┐
              │  Is it structured/tabular data? │──── YES ───► XGBoost, random forest,
              │  (predictions from features)    │              or logistic regression.
              └─────────────────────────────────┘              Often beats LLMs here.
                                │ NO
                                ▼
              ┌─────────────────────────────────┐
              │  Is it search/retrieval?        │──── YES ───► BM25 first. Add vector
              │                                 │              search if needed.
              └─────────────────────────────────┘
                                │ NO
                                ▼
              ┌─────────────────────────────────┐
              │  Does it need external knowledge│──── YES ───► <100 pages? Stuff in context.
              │  beyond the input text?         │              Larger? Then consider RAG.
              └─────────────────────────────────┘
                                │ NO
                                ▼
              ┌─────────────────────────────────┐
              │  Is the task simple?            │──── YES ───► Small model (1B-8B).
              │  (classification, extraction,   │              Test it first.
              │   summarization)                │
              └─────────────────────────────────┘
                                │ NO
                                ▼
                      You might need a frontier
                      model. But measure first.

Quick Checks

Check 1: Can you describe the task in one sentence?

If yes → probably a small model task.

  • "Extract the company name from this email" → Gemma 4B (or regex, if the pattern is stable)
  • "Classify this support ticket as billing/technical/other" → Gemma 1B
  • "Summarize this paragraph in 2 sentences" → Phi-4

If no → you might have an architecture problem, not a model problem.

Check 2: What's your accuracy requirement?

Accuracy needed Model size Why
70-80% 1B-4B Good enough for suggestions, drafts, triage
85-95% 4B-12B Production-ready for most tasks
95%+ Consider fine-tuning a small model, not scaling up

Scaling to frontier models rarely buys you more than 5% accuracy on simple tasks. That 5% costs 50x more.

Check 3: How many output tokens do you need?

Output tokens are the bottleneck. They determine latency and cost.

Output type Tokens Consider
Yes/No, True/False 1-5 Tiny model. Constrained decoding guarantees the format — no parsing.
Category label 1-10 1B model. Constrained decoding limits output to valid labels.
Short extraction 10-50 Delimiter-separated, or grammar-constrained output > JSON
Paragraph 50-200 4B-8B models
Long generation 500+ Maybe you need a bigger model

The JSON Tax

Everyone defaults to JSON for structured output. But JSON has overhead:

# JSON output (35 tokens)
{"name": "John Smith", "company": "Acme Corp", "title": "CTO", "status": "lead"}

# Delimiter output (11 tokens)
John Smith::Acme Corp::CTO::lead

For simple extraction tasks:

  • 3x fewer output tokens
  • 3x faster inference
  • 3x cheaper

The strongest option: constrained decoding. Grammar-constrained generation (llama.cpp GBNF, Outlines, xgrammar) forces the model to emit valid JSON — or any format — at the sampler level. Zero invalid outputs, no retries, no parse failures. The JSON-vs-delimiter tradeoff disappears: JSON's token cost is real, but its parse failures go to zero. For local small models this is usually the right default.

When to use JSON: nested structures, optional fields, API contracts. When to use delimiters: simple extraction, high-volume pipelines, when you can't constrain decoding. When to use constrained decoding: you control inference (local model, or an API that exposes it) and want guaranteed-valid output.

Read more: The JSON Tax →


Model Selection Cheat Sheet

Tiny (1B-4B params)

Best for: classification, yes/no, simple extraction

Model Params Good at
Gemma 3 1B 1B Classification, simple Q&A
Phi-4-mini 3.8B Reasoning, function calling
Gemma 3 4B 4B Best tiny all-rounder

Small (8B-17B params)

Best for: most production tasks, RAG, extraction, summarization

Model Params Good at
Qwen 3 8B 8B Multilingual, reasoning
Gemma 3 12B 12B Quality/speed balance
Phi-4 14B Reasoning, math
Llama 4 Scout 17B Multimodal, long context (10M tokens)

Medium (27B-70B params)

Best for: complex reasoning, long context, multi-step tasks

Model Params Good at
Gemma 3 27B 27B Near-frontier quality
Qwen 3 32B 32B Complex tasks

Frontier (100B+ dense, or large MoE)

Best for: novel tasks, complex reasoning, when nothing else works

Model Params Good at
Llama 4 Maverick 400B (17B active) MoE, strong all-rounder, 10M context

Before you use these, ask: have you tried a smaller model?


Anti-Patterns

❌ "We use GPT-5 for everything"

That's not a flex. That's a $50K/month cloud bill waiting to happen.

❌ "We need the best model for our enterprise customers"

Your enterprise customers care about latency, reliability, and cost. Not model prestige.

❌ "Small models aren't accurate enough"

Did you test? With the right prompt? On your actual data?

❌ "We'll optimize later"

You'll optimize never. The technical debt compounds. Start right-sized.

❌ "JSON output is industry standard"

For simple extraction, it's industry waste. See: The JSON Tax.

❌ "We need RAG for our documents"

For small document sets? No you don't.

Context windows are now 2M-10M tokens. That's thousands of pages. If your knowledge base is <100 pages, just stuff it in context. Preprocess, convert to markdown, include directly.

RAG adds complexity: chunking strategies, embedding models, vector databases, retrieval tuning, reranking. All that infrastructure for documents that fit in a single prompt.

When RAG makes sense:

  • Millions of documents
  • Frequently changing content (re-embedding is cheaper than re-caching)
  • Cost-sensitive at scale (RAG is 8-80x cheaper per query for large, static corpora)

When to skip RAG:

  • <100 pages of docs
  • Static content that rarely changes
  • You value simplicity over marginal retrieval precision

Patterns

✅ Cascade Architecture

Start with smallest model. Verify output. Escalate only on failure.

Input Text
    │
    ▼
┌─────────┐              ┌────────────┐    verified?     ┌──────────┐
│ Gemma 4B│ ───────────► │  Verifier  │ ───────────────► │ Return   │
└─────────┘   output     └────────────┘   yes            └──────────┘
                              │ no
                              ▼
┌─────────────┐          ┌────────────┐    verified?     ┌──────────┐
│ Llama Scout │ ───────► │  Verifier  │ ───────────────► │ Return   │
└─────────────┘          └────────────┘                  └──────────┘

Verifier can be: format validation, a classifier, or FlashCheck for grounding checks.

See skills/bonsai/examples/cascade.py for a working extraction example.

✅ Task-Specific Models

One model per task type, sized appropriately.

  • Classification → 1B
  • Extraction → 4B
  • Summarization → 8B
  • Complex reasoning → Frontier

✅ Measure First, Scale Never

Before adding a bigger model:

  1. Benchmark current model on 100 real examples
  2. Identify failure modes
  3. Try prompt engineering
  4. Try fine-tuning small model
  5. Only then consider scaling

✅ Simple Tools Over Browser Automation

For research tasks, don't reach for computer use or Puppeteer.

Search API → Fetch URL → HTML to Markdown → LLM synthesis

Three tools. No browser. No screenshots. No vision model.

Browser automation is only for: login walls, dynamic forms, actions (booking, purchasing).

See skills/bonsai/patterns/agents.md for the full agent decision tree.


More Patterns


Tools

RightSize

Test your prompts against multiple model sizes. See what's actually needed.

→ Try RightSize

FlashCheck

Verify LLM outputs with tiny specialized models. Sub-10ms verification.

→ Learn about FlashCheck


Contributing

Found a pattern that works? Open a PR.

Keep it practical. Keep it measured. No vibes-based claims.


License

MIT. Use it. Share it. Don't over-engineer it.


Built by Nehme AI Labs — AI architecture consultancy.