Architecture & Steering

IKA: Analyst vs Builder

Two AI brains in one system. The left column documents IKA Analyst (the BI analyst). The right column documents IKA Builder (the dev agent). Same infrastructure, completely different steering.

v2.0 (current) · v1.2 · Last updated: 2026-04-22
IKA Analyst IKA Builder
IKA Analyst
THE BI ANALYST
01
Big Picture
The main IKA prompt bar — a BI analyst that answers business questions with charts and data.
This is the main search bar at the top of the IKA dashboard. You type a question like "How are Lancôme sales?" or "Which division has the best margins?" and IKA responds with a written analysis plus interactive charts — all in Spanish, with real numbers from the company's data. No coding, no technical knowledge needed. Just ask.
1
System prompt
9
Chart templates
107
Prompt lines
3
LLM steps (plan+sql+narrate)
0
Hooks/gates

User types a business question → LLM analyzes with embedded dataset → returns text + charts. No task system, no memory, no hooks. Pure LLM with smart prompt assembly.

02
Steering Layers
Only one layer: the system prompt. No memory, no hooks, no gates.
Unlike the Builder (which has three layers of control), the Prompt Bar is simple: one big set of instructions given to the AI each time. No memory between sessions, no gates or locks. Think of it as a very knowledgeable consultant who forgets you after each meeting — but during the meeting, they have your entire dataset memorized.

Single-Layer Architecture

Unlike the Builder which has 3 concentric layers (CLAUDE.md → Memory → Hooks), the Prompt Bar has only one: a monolithic system prompt assembled per-question. Everything the LLM needs is in that single prompt — identity, data, rules, chart instructions, language enforcement.

No Persistence

No memory files. No task state. No cross-session learning. Each conversation window keeps the last 10 turns, but when you reload — it's gone. The prompt bar is stateless by design: every question gets a fresh context with the full dataset.

03
The System Prompt
The core of the BI analyst. A ~107-line prompt with the ENTIRE Grupo MSP dataset embedded inline.
Every time you ask a question, the AI receives a ~107-line instruction set that includes: who it is ("you are IKA BI Analyst"), the ENTIRE company dataset (every division, brand, sales rep, monthly number), and rules for how to answer. The AI doesn't need to look anything up — all the data is literally pasted into the prompt. It's like giving someone a complete report and saying "answer questions about this."
# Identity "You are IKA BI Analyst, an expert business intelligence assistant for Grupo MSP, a cosmetics and luxury goods distributor in Honduras." # Embedded data (ALL in the prompt) GLOBAL: L474.5M revenue, 35.1% margin, +8.3% YoY DIVISIONS: 8 with sales, margin%, YoY%, discount% TOP 25 BRANDS: Full table with all metrics SALES REPS: Top 8 by volume + discount rates MONTHLY: Jan-Dec for 2014 and 2015 CATEGORIES: ROSTRO, CABELLO, MUJER, HOMBRE, OJOS DISCOUNTS: Distribution across 8 brackets

Key Design Decision

This system prompt is used for follow-up questions within an existing query session (via /bi/prompt). The main query flow uses the SQL pipeline (Section 11) which runs real queries against PostgreSQL. The embedded data here provides conversational context for follow-ups.

IdentityDatasetRulesGRAPHS_JSONSYSTEM PROMPT STRUCTURE
04
Data Architecture
The complete dataset embedded in the system prompt.
This is the "brain" of the analyst — all the numbers it knows. 8 divisions, 25 brands, 8 sales reps, monthly sales for 2 years, product categories, and discount distributions. Currently this is demo data from 2014-2015. With live data, the system would query the real database instead of using embedded numbers.
EntityCountMetrics
Divisions8Sales, Margin%, YoY%, Avg Discount%
Brands25Sales, Margin%, YoY%, Discount%, Avg Ticket
Sales Reps8Sales, Avg Discount%, Transactions
Monthly Sales24Jan-Dec × 2 years (2014, 2015)
Categories6ROSTRO, CABELLO, MUJER, HOMBRE, OJOS, DESODORANTES
Discount Brackets80-1% through 50-100% with transaction counts

Scope

  • Total revenue: L474.5M across 35,820 transactions
  • 9,351 unique products
  • Period: Jan 2014 – Dec 2015
  • Currency: Honduran Lempiras (L)
05
Chart Templates
9 visual templates the LLM can emit via GRAPHS_JSON.
Every response includes both text analysis and charts. The AI picks the chart type automatically — bar charts for rankings, line charts for trends, donuts for market share, radar for multi-metric comparisons, KPI cards for headline numbers. 9 chart types total, selected based on the question.
TemplateFamilyUse Case
ranked_barBarTop/bottom N rankings
diverging_barBarYoY winners vs losers (+/-)
column_barColumnVolume comparison
grouped_columnColumnSide-by-side (2014 vs 2015)
share_donutDonutComposition / market share
trend_lineLineSingle-series monthly trend
multi_lineLineMulti-series comparison / projections
compare_radarRadarMulti-metric entity profile
kpi_stripKPIHeadline numbers / snapshot

Template Selection Logic

searchBIGraphTemplates(question) scores each template against the question using intent tags, aliases, and keyword matching. Top 3-4 candidates are injected into the system prompt as hints. The LLM makes the final choice.

QUESTION TYPE → TEMPLATE SELECTIONQuestionsearchTemplatesScore + RankTop 3-4 → Prompt HintBarLineDonutRadarKPI
06
Smart Prompt Assembly
The system prompt is not static — it's assembled per-question with dynamic hints.
The instructions the AI receives aren't the same every time. IKA detects what KIND of question you're asking (ranking? trend? comparison? snapshot?) and adds a hint like "this looks like a ranking question — prefer a bar chart." It also detects the language and enforces Spanish. This happens automatically before the AI even sees your question.
buildBISystemPrompt(question) = biSystemPrompt // identity + data + rules + suggestedGraphTemplate() // "prefer ranked_bar" + buildQuestionStyleHint() // "treat as ranking" + buildLanguageHint() // "responde en español"

Style Detection

  • Monthly breakdown → "prefer trend_line"
  • Comparison → "prefer multi_line or grouped_column"
  • Snapshot/overview → "prefer kpi_strip"
  • Composition/mix → "prefer share_donut"
  • Ranking (top/bottom) → "prefer ranked_bar"
  • Brand-scoped → "keep tightly focused on that brand"
07
The Two Paths
Every input becomes either navigation or a query. Two completely separate pipelines.
IKA does one of two things with your input: navigate to something (instant, no AI involved) or run a deep query (SQL against real database, AI narration, editorial charts). There is no "quick" mode — every query goes through the full SQL pipeline.

Path 1: Navigation (no LLM, no SQL)

classifyPrompt says "nav" → tryVoiceNavigation() matches against dashboard_data_full.json (pre-loaded 121KB). Finds the division/brand, slides the 3D scene, loads charts from local data. Zero API calls, zero latency. See Section 12.

Path 2: Query (SQL + AI narration)

classifyPrompt says "query" → confirmation modal → user confirms → executeQuery() → single pipeline:

  • fetchIkaBiAsk(query) → POST /bi/ask → Go proxy → Flask:3055
  • Flask: LangChain planner → SQL generator → PostgreSQL executor → narrator
  • Returns: reasoning, answer narrative, charts with real verified data
  • Frontend: editorial two-column grid + text tiles + Show SQL + Investigar

The code comment says: "SINGLE PIPELINE: ika-bi SQL (with Senior Analyst narration)"

Drill-Down (inside query results)

Click a chart element → drill confirmation modal (same re-classification gate) → if still query → fetchIkaBiAsk() again → SQL pipeline → results in a new tab inside the query view. Multiple drill levels = multiple tabs.

Follow-Up Questions (conversational)

"Seguir preguntando..." input below results → fetchAICached() → /bi/prompt → LLM with embedded data + conversation history. This is the only path that uses the embedded-data LLM — for follow-up context within an existing query session.

MyPanel: Pin Query Results

After a query produces results (charts + narrative + drill tabs), the user can pin the entire query view — including all tabs and drill-downs — into MyPanel. Persists as a personal dashboard card.

08
Response Rules
Strict formatting and language requirements baked into the prompt.
Every response follows strict rules: start with a headline and key number, use Honduran Spanish with natural voseo ("podés", "mirá"), cite exact Lempira figures, never say "I can't calculate this", include 1-3 supporting charts. These rules are hard-coded into every prompt.

Format

  • Start with H3 headline + key number: ### L68.9M en ventas totales
  • 2-4 short paragraphs, direct answer first
  • Currency always in Lempiras: L1.2M, L450K
  • NEVER say "can't calculate" — always estimate with stated assumptions
  • 1-3 charts per response, each supporting a specific claim

Language

  • Always español hondureño ejecutivo
  • Voseo when natural: "podés", "fijate", "mirá"
  • No street slang — executive tone
  • Even if question is in English → respond in Spanish

Chart Rules

  • Think before emitting GRAPHS_JSON (4-step process in prompt)
  • Entity must be exact dataset name — never invent categories
  • No duplicates or near-duplicates
  • Projections use multi_line with 3 series (2014, 2015, 2016 Proy.)
  • Every graph must support a specific claim
09
Request Flow
Complete pipeline from question to rendered charts.
Your question goes through classifyPrompt first. If navigation → instant, no API. If query → confirmation modal → user confirms → executeQuery() → POST /bi/ask → Go proxy → Flask:3055 → planner LLM picks charts → SQL generator writes queries → PostgreSQL executes → narrator LLM writes analysis → frontend renders editorial grid with charts, text tiles, Show SQL, and Investigar buttons.
User types question in prompt bar → classifyPrompt() → nav or query? → If nav: tryVoiceNavigation() → done (no API) → If query: showAnalyzeConfirm() → modal → User confirms → re-classify → still query? → executeQuery() → POST /api/v1/bi/ask → Go proxy → Flask:3055 → plan_charts() → SQL gen → PostgreSQL → narrate → Return { reasoning, answer, charts[] } → Frontend: editorial grid + text tiles → Investigar / Show SQL / Show data → Follow-up: "Seguir preguntando..." input → fetchAICached() → /bi/prompt → LLM + embedded data → Update UI with deep findings + new charts

Key Files

  • bi_prompt.go — handlers, system prompt, style hints
  • bi_graph_templates.go — 9 templates, scoring, aliases
  • bi_upload.go — data upload/management
10
Decision Tree
Every user input goes through classifyPrompt() before anything happens. Navigation, query, identity, catalog — all classified first.
Every input goes through classification before anything happens. "How are Lancôme sales?" → query mode, show the analysis modal. "Show me Givenchy" → navigate directly, no AI needed. "Who is IKA?" → identity card. This split-second classification determines the entire path.
USER INPUT DECISION TREEUser InputclassifyPrompt(query)kind: navkind: querykind: catalogkind: nooptryVoiceNavigation()navigate to division/brandshowAnalyzeConfirm()User confirms → executeexecuteQuery()→ Flask SQL pipelinetogglePromptCatalog()show saved queriestoast message

Classification Logic

  • noop — empty input, nonsense, "test", "hola"
  • catalog — trigger words for saved query catalog
  • query — analyze keywords, query signals (reasons, simulations, comparisons, dates), or navigation router rejected the input
  • nav — navigation router accepted via dry-run (tryVoiceNavigation in dry-run mode)

The Confirmation Modal (Second Gate)

When classified as query, showAnalyzeConfirm() opens an editable modal — this is a CRITICAL gate:

  • User sees the question in an editable textarea — can modify, refine, or completely change it
  • On confirm, the text is RE-CLASSIFIED via classifyPrompt() again:
  • → If the edited text is now a navigation (e.g. user simplified to "show me Givenchy") → modal closes, tryVoiceNavigation() executes directly. No query, no LLM.
  • → If it's a catalog trigger → opens prompt catalog
  • → If it's still a query → proceeds to executeQuery
  • → Special: bare "analizar X" (2-3 words) → stripped to just "X" and re-classified as nav
  • → Scope check: if the query is too complex for the demo dataset → shows a notice with split suggestions

This modal re-classifies the input every time the user confirms. Whatever the user types in the modal decides the final path — navigation or query.

Query Pipeline (after modal confirmation)

  • 1. Modal confirmed as query → executePromptInput()
  • 2. executeQuery() → fetchIkaBiAsk() → POST /api/v1/bi/ask
  • 3. Go proxy → Flask:3055 → planner → SQL → PostgreSQL → narrator
  • 4. Frontend renders editorial grid + text tiles + charts
  • 5. Each chart: Investigar (deeper drill) + Show SQL + Show data table

Chart Drill-Down → Tab Flow

When the user clicks on a chart element (a bar, a slice, a data point) inside the query view:

  • 1. A drill confirmation modal appears with a pre-built prompt about that specific element (e.g. "Desglose mensual de Lancôme en Division I")
  • 2. Same gate as before: user can edit the prompt. On confirm, it re-classifies — could become navigation or stay as query.
  • 3. If query → runs the full SQL pipeline again (planner → SQL → executor → narrator)
  • 4. Results open as a new tab inside the query view — the original results stay in their tab, the drill results appear in a second tab
  • 5. User can drill further → more tabs. Each tab is an independent query result with its own charts + narrative.
  • 6. Tabs are navigable — click between drill levels to compare findings.

⚠ Known issue: drill-down tab creation is currently broken. The confirmation modal appears but the tab fails to render. Pending fix.

Identity Gate

Before classification: "quien eres" / "who are you" / "que es ika" → opens the IKA identity modal. Never reaches the LLM.

Navigation Pipeline (kind: nav)

When classified as navigation, tryVoiceNavigation() executes:

  • 1. Normalize — lowercase, strip accents, replace synonyms (compañía→marca, objetivos→metas)
  • 2. Special commands — mute/unmute, "mi panel", prompt catalog triggers
  • 3. Panel actions — "abrir todo", "cerrar todo", "resetear" → find active panel buttons in DOM
  • 4. Compound commands — "ir a Givenchy y abrir todo" → navigate first, queue action with 5s delay
  • 5. Navigation verbs — regex match: "ir a", "muestrame", "show me", "go to" + target
  • 6. Target matching — fuzzy match target against DATA divisions/brands/categories using Levenshtein distance
  • 7. Tab routing — "metas de X" → navigate to X + switch to OKR tab. "KPIs de X" → KPI tab
  • 8. Home/Global — "home", "global", "cómo vamos" → navigate to overview
  • 9. Execute — slide 3D scene, load panel, update deep link hash

Key: navigation is entirely client-side — no LLM call, no API request. It searches the existing DOM/DATA for UI elements and navigates to them.

Dry-Run Pattern

classifyPrompt() uses a dry-run flag to test navigation without side effects. Sets _navDryRun = true, calls tryVoiceNavigation(), checks if it would succeed, then restores state. If dry-run succeeds → classify as nav. If not → classify as query.

Model Selection

  • Quick analysis: utils.AIPrimaryModel() — configured in .env
  • Deep research: same model, second pass with biDeepSystemPrompt
  • Voice transcription: Whisper (whisper-1) via OpenAI API
  • Analyze mode toggle: bypasses classifier — all input goes directly to query
11
SQL Pipeline (Deep Research)
The full flow from question to SQL-verified charts — powered by Flask + LangChain + PostgreSQL.
Every query goes through this pipeline. A Python service (Flask on port 3055) runs permanently. One LLM plans which charts to create, another writes the SQL queries, those queries run against the real PostgreSQL database, and a third LLM writes a CEO-grade narrative analyzing the results. The charts render in a two-column editorial grid with text boxes for context. Drill-downs and "Investigar" re-enter this same pipeline.

Step 1: Planner

planner.py — LLM (gpt-5.4) decides which charts to create for the question. Receives the database schema + available chart types. Returns a chart plan (what to visualize, what metrics, what dimensions).

Step 2: SQL Generator

sql_generator.py — LLM (gpt-5.4-mini) generates actual SQL SELECT queries for each chart in the plan. Runs in parallel (ThreadPoolExecutor). Each query has safety checks: only SELECT/WITH allowed, 30s timeout, read-only transaction, LIMIT 500.

Step 3: Executor

executor.py — Runs the SQL against PostgreSQL via psycopg2. Returns columns + rows. Safety: statement_timeout=30s, read-only mode, only SELECT allowed.

Step 4: Narrator

sql_generator.py — LLM (gpt-5.4, temperature=0.3) writes a CEO-grade narrative analyzing the SQL results. Executive Spanish with real numbers from the verified data.

Step 5: Frontend Rendering

  • fetchIkaBiAsk() → POST /bi/ask → Go proxy → Flask:3055
  • detectSqlChartType() auto-picks: bar, line, donut, KPI, treemap, or table
  • Two-column editorial grid (.sql-charts-grid) with text tiles every 2 charts
  • Each chart has: Investigar (deeper drill) + Show SQL + Show data table
  • Text tiles offset the charts for editorial rhythm and proportion
User clicks "Investigar" or asks deep question → fetchIkaBiAsk(question) → POST /api/v1/bi/ask → Go proxy → Flask:3055 /api/ask → plan_charts() — LLM plans chart layout → generate_all_charts_parallel() → LLM writes SQL per chart (parallel) → execute_query() — PostgreSQL → generate_narrative() — CEO analysis → Return { reasoning, answer, charts[] } → Frontend: detectSqlChartType() → Render two-column grid + text tiles → Show SQL / Data table / Investigar buttons
12
Navigation Data Layer
How the 3D navigation uses pre-computed data for instant, accurate matching.
When you say "show me Givenchy", the system doesn't ask an AI — it searches a pre-loaded JSON file with all 8 divisions and 43 brands. It fuzzy-matches your words against brand names, division labels, and even number words ("division four"). If multiple brands match, a disambiguation modal appears. Once matched, it navigates the 3D scene and loads the right charts from the same data file — zero latency, no API call.

dashboard_data_full.json (121KB)

Pre-computed JSON loaded at page start. Contains ALL data for every neuron and tab:

  • global: total_sales, margin, yoy, monthly_sales, top10_brands, divisions
  • divisions (8): label, sales, margin, qty, txns, disc, yoy, monthly_sales, brands list
  • brands (43): full metrics per brand
  • drill_div_brand_month: cross-dimensional drill data for monthly breakdowns

Matching Functions

  • findBrandInText(text) — fuzzy word matching against all 43 brand names in DATA.brands. Exact full-name match scores highest, then individual word matches (4+ chars). If multiple brands tie → disambiguation modal.
  • findDivisionInText(text) — matches by number ("division 4", "div eight"), Roman numerals (I-VIII), or label text ("prestige", "gran consumo").
  • findDrillKeyword(text) — detects chart-specific keywords (ventas, margen, ranking, tendencia) to navigate to specific drills within a panel.
  • CHART_HIGHLIGHT_MAP — maps keywords to chart IDs per panel (global, division, brand). Used for "show me the radar" or "ventas mensuales" to scroll to the exact chart.

Navigation Execution

  • Brand found → slide 3D scene → load brand panel with KPIs, charts from DATA
  • Division found → navigate to division → load division panel with brands list
  • Drill keyword found → auto-open specific chart, scroll to it, add glow highlight
  • Tab detection: "metas de Lancôme" → navigate + switch to OKR tab. "KPIs de Givenchy" → KPI tab.
  • Compound: "ir a Givenchy y abrir todo" → navigate first, then queue panel action with 5s delay
  • All client-side — no API call, no LLM. Instant from pre-loaded DATA.
IKA Builder
THE DEV AGENT
01
Big Picture
The Builder feed — a mechanically enforced AI development workflow.
The Builder is where you talk to the AI and it builds things for you — edits code, deploys websites, creates pages. This agent has rules it physically cannot break. It must clock in before working. It must show you its thinking. It must ask before doing complex things. And only you can mark work as done.
4
CLAUDE.md files
25
Memory files
10
Scripts
2
Hook triggers
7
Gate checks

Mats sends tasks in the Builder feed → agent reads code, edits files, deploys. Every action gated by task status. Every response posted to feed. Full mechanical enforcement.

02
Steering Layers
Three concentric layers, from cultural instructions to physical gates.
Imagine three concentric security rings. The outer ring (CLAUDE.md) is like posting rules on the wall — the AI reads them and usually follows. The middle ring (Memory) is like the AI's personal notebook — it remembers past corrections. The inner ring (Hooks & Gates) is like actual locked doors — no amount of "forgetting" can bypass them. Most AI tools only have the outer ring. IKA Builder has all three.

Layer 1: CLAUDE.md (Outer)

4 files across repos. Loaded every conversation. Defines workflow rules, network config, project structure. Cultural enforcement — agent reads and follows.

Layer 2: Memory (Middle)

25 persistent files. Feedback rules, project context, user profile. Persists across conversations. Cultural enforcement — agent recalls and applies.

Layer 3: Hooks & Gates (Core)

PreToolUse/PostToolUse hooks that physically block or trigger actions. Mechanical enforcement — agent CANNOT bypass. This is the differentiator.

03
The Mechanical Gate
task-gate.sh — runs before EVERY Edit, Write, and Bash command.
This is the bouncer at the door. Every time the AI tries to edit a file, write code, or run a command, this script runs first and checks seven things: (1) Do you have an active task? (2) Are all your questions answered? (3) Are you trying to mark something as "completed"? (4) Are you trying to overwrite, revert, or delete a protected file? (5) When marking done — did you actually verify your work? (6) Is the diff size proportional to the task description? Short task + big diff = over-engineered. (7) Do the changed files relate to the task keywords? >50% unrelated files = flagged. If any check fails — BLOCKED. The AI physically cannot proceed. Only Mats can mark tasks as completed or authorize destructive changes.
# PreToolUse Hook → Edit|Write|Bash # BLOCKED if no active task (in_progress + owner:agent) # BLOCKED if active task has unanswered questions # BLOCKED if agent tries to set any task to "completed" # BLOCKED if agent tries to overwrite/revert/delete protected files # BLOCKED if done.sh called without verification after last edit # BLOCKED if agent tries to overwrite/revert/delete key files without permission # FLAGGED if diff size disproportionate to task scope (simplicity gate) # FLAGGED if >50% changed files unrelated to task keywords (surgical gate) Flow: User sends message → Agent runs work.sh "task name" → Gate opens → Agent can edit code → Agent works... → Agent runs done.sh "task name" → Gate closes → No more edits Always allowed through: work.sh, done.sh, resume.sh POST to /bi/feed push-tasks.sh, backup-tasks.sh Read-only commands successCriteria: Tasks support successCriteria field → Array of verifiable conditions → done.sh prints as checklist before marking done → Criteria posted to feed as role:"thought"
GATE DECISION FLOWTool Usetask-gate.sh✓ ALLOWED✗ BLOCKEDactive task existsno task / questions pending
04
CLAUDE.md Files
Four files, each tailored to its project context.
CLAUDE.md is like an employee handbook that the AI reads every single time it starts working. It tells the agent: "here's how we work, here's the network setup, here are the rules, here's where everything is." There are 4 copies — one for each project area (root, backend, frontend, tests) — so the AI always has the right context for whatever it's working on.
FileScopeKey Content
~/CLAUDE.mdRootMaster rules, workflow, scripts, network
~/ika-api/CLAUDE.mdBackendGo 1.24 + Fiber context
~/ika/CLAUDE.mdFrontendFlutter 3.38.1 + FVM
~/e2e/CLAUDE.mdTestsPython 3.10 + nodriver + CDP
05
Agent Memory
25 markdown files + SQLite database. Persists across conversations.
Think of this as the agent's long-term memory. Every time you correct it ("don't do that"), praise it ("yes, keep doing that"), or teach it something about the project — it writes it down. Next conversation, it reads all 25 files before starting. That's how it knows your name is Mats (not Ben from the git config), that IKA is female, and that it should never mark tasks as completed without your approval. A SQLite database now adds structured session history — every work/done event, decisions, errors, and lessons are logged and queryable across sessions.

12 Feedback Memories

  • Always post to feed (CLI invisible to Mats)
  • Post CoT thoughts for transparency
  • Sub-agents are DEFAULT (parallel)
  • work.sh BEFORE starting anything
  • Ask before complex tasks
  • Never mark tasks completed (only Mats)
  • Never erase tasks
  • Never overwrite source files
  • Sync from feed before pushing tasks
  • IKA is female (Spanish agreement)
  • No vulgarities
  • Always test before presenting

SQLite Session Memory

  • ~/.claude/session-memory.db — persistent session history
  • 3 tables: sessions, events, lookups
  • Auto-logs work.sh/done.sh events with timestamps
  • Queryable history: decisions, errors, lessons learned
  • Complements markdown files with structured, searchable data

6 Project + 1 User

  • Theme system design spec
  • IKA OS project spec
  • Flutter build performance
  • RC backport list
  • Pending tasks
  • User: Mats — CEO, technologist, artist
06
Automation Scripts
10 scripts that mechanize the entire task lifecycle.
Instead of relying on the AI to "remember" to track its work, these scripts force it. work.sh is like clocking in — the AI can't touch code until it runs this. done.sh is clocking out. resume.sh lets multiple agents work at the same time. backup-tasks.sh keeps 20 rotating copies of the task list so nothing gets lost. It's a factory floor, not a suggestion box.
ScriptPurposeKey Behavior
work.shActivate taskAuto-pauses others. Opens gate. Warns on multi-task titles (detects " + ", " & ", 3+ verbs).
done.shReady for reviewSets owner:user. Closes gate.
resume.shReactivateNo pause. Parallel work.
subtask.shAdd subtaskNested under parent.
push-tasks.shSync to feedPosts task array to feed.
backup-tasks.shRotate backups20 backups + git commit.
snapshot.shVersion snapshotNamed backup + infra + git.
task-gate.shPreToolUse gateBLOCKS without active task.
sync-tasks-hook.shPostToolUse syncAuto-push on TaskCreate/Update.
session-log.shSQLite memoryLogs events/decisions/errors to session-memory.db. Integrated into work.sh/done.sh.
07
Communication Layer
The Builder feed — JSON file-based message store.
The feed is like a group chat between you and the AI agents. Every message has a "role" — you're "user", the agent is "agent", its reasoning is "thought", its questions are "question". The system auto-detects questions in agent messages and routes them to the Q&A tab. It also auto-linkifies URLs and confirms receipt of task messages. All of this happens without anyone needing to remember to do it.

Feed Architecture

  • Backend: bi_feed.go (Go Fiber)
  • Storage: JSON files on disk (one per scope)
  • Polling: Frontend every 2-3 seconds
  • Roles: user, agent, thought, question, answer, receipt, status, tasks

Auto-Features (Mechanical)

  • Auto-extract questions from agent messages → Q&A
  • Auto-linkify bare *.ika.ai domains
  • Auto-confirm receipts for task messages
  • Auto-trim at 600 messages
  • Scoped feeds (main.ika.ai → separate feed)
  • Hostname-based routing
FEED MESSAGE ROLESuseragentthoughtquestionanswerstatustasksvisible in feedsystem / metadata
08
Version History
The evolution from V1 to V2.8.
Builder has gone through 10 major versions in one week. Each version added new capabilities — from a simple chat panel (V1) to a full 7-gate mechanical enforcement system with SQLite memory, voice, parallel agents, deep linking, and all 4 Karpathy principles mechanically enforced (V2.8). Every version is saved as a named snapshot you can switch back to.
  • V2.8 (Apr 22) — Three.js r180, 7-gate system (simplicity + surgical + verify-before-done + destructive-action protection), SQLite session memory, successCriteria field, file upload support (XLS/CSV/PDF), PNUD IKA Converter, editable backup titles/descriptions
  • V2.7 (Apr 22, pre-3JS) — 5-gate enforcement, work.sh auto-subtask + topic-based parent matching, multi-task detection warning, auto-linkify domains, status/CoT persistence, resizable Builder panel, voice ENTER/SPACE, feed markdown renderer, deploy regression gate
  • V2.6 (Apr 21) — Steering page v2.5, mechanical only-user-completes gate, work.sh auto-subtask, auto-linkify domains
  • V2.5 (Apr 20) — Orchestrator with CLI detection, deep linking v12, Whisper voice, Three.js r160, Gemini, Agent SDK, tab cycling
  • V2.4 (Apr 19) — Feed linkify, task indentation, builder toggle, main.ika.ai, gate hooks
  • V2.3 (Apr 18) — Voice mic, X clear buttons, auto-router, subtask.sh, mobile fixes
  • V2.2 (Apr 18) — Auto-ping CLI, Q&A flash, task merge, builder slide
  • V2.1 (Apr 18) — work.sh/done.sh automation, auto-confirm, deploy notify
  • V2.0 (Apr 18) — Centered panel, frosted glass, side panels, infra viz
  • V1.0 (Apr 16) — First Builder with Feed, voice, uploads
09
Request Flow
Complete pipeline from user message to deployed code.
Think of it like a relay race: your message lands in the feed → a watcher script detects it → the AI agent picks it up → activates a task (opening the gate) → reads and edits code → marks it done (closing the gate) → posts the result back to the feed where you see it. Every step is tracked and visible.
Mats sends message in Builder feed → POST /api/v1/bi/feed → Saved to feed.json → feed-watch detects ping → CLI agent reads /tmp/feed-ping → work.sh "task" → gate opens → Read code, edit files, run tests → done.sh "task" → gate closes → POST result as role:"agent" → Optional: make deploy-bi

Key Files

  • bi_feed.go — feed handlers, auto-features
  • bi_agent.go — orchestrator, context building
  • bi_voice.go — Whisper transcription
  • bi_image.go — Gemini image generation
  • bi_backups.go — version snapshots
10
Karpathy Comparison
Based on github.com/forrestchang/andrej-karpathy-skills (70.8K stars). Full analysis of how IKA Builder mechanically enforces what Karpathy only suggests culturally.
Andrej Karpathy (ex-Tesla AI director, OpenAI founding member) wrote a popular set of rules for making AI coding assistants behave better. His approach: write instructions and hope the AI follows them. IKA Builder does something different — it builds physical walls that the AI literally cannot bypass.

Karpathy's 3 Problems — All Solved

  • Unmanaged Assumptions — LLMs assume and run, never ask. IKA SOLVED ✅: task-gate blocks if questions pending + Q&A auto-extract from agent messages + thought feed for transparency.
  • Over-Engineering — 1000 lines when 100 would do. IKA SOLVED ✅: done.sh simplicity gate flags short-task + big-diff automatically.
  • Unintended Modifications — side-effect changes to unrelated code. IKA SOLVED ✅: done.sh surgical gate flags files unrelated to task keywords.

Karpathy's 4 Principles — All Mechanical

PrincipleKarpathyIKA Builder
1. Think Before CodingCLAUDE.md instructionMECHANICAL ✅ task-gate blocks without task + Q&A blocking
2. Simplicity FirstCLAUDE.md instructionMECHANICAL ✅ done.sh simplicity gate (diff size vs task scope)
3. Surgical ChangesCLAUDE.md instructionMECHANICAL ✅ done.sh surgical gate (file relevance to task)
4. Goal-Driven ExecutionCLAUDE.md instructionMECHANICAL ✅ work.sh/done.sh lifecycle + successCriteria + verify-before-done

Strategic Questions — Status

  • ✅ successCriteria field — Tasks have successCriteria array. done.sh prints checklist. Frontend shows in Status tab.
  • ✅ Complexity gate — done.sh simplicity check flags short-task + big-diff.
  • ✅ Diff audit — done.sh surgical check flags unrelated files.
  • ✅ Persistent agent memory — SQLite session-memory.db (sessions/events/lookups) + 25 markdown files. session-log.sh integrated into work.sh/done.sh.
  • ❌ UI enhancements — Visual diff viewer, task dependency graphs, agent timeline, live code preview — pending.
  • ❌ Portable Builder — Not started. Pending task exists.

The Differentiator

Karpathy's approach is 100% cultural — text instructions that the AI should follow. IKA Builder goes beyond with mechanical enforcement — 7 physical gates that the AI cannot bypass: no work without tasks, no implementation with pending questions, no over-engineered diffs, no unrelated file changes, no destructive actions on protected files, no completing tasks without user approval, and no marking done without verification. Not suggestions — walls. All 4 Karpathy principles mechanically enforced. 4 of 6 strategic questions implemented.

Side-by-Side Summary

DimensionIKA AnalystIKA Builder
Handlerbi_prompt.gobi_feed.go + bi_agent.go
System PromptSingle monolith with embedded dataCLAUDE.md + memory + buildContext()
CommunicationDirect JSON responseFeed with role-based messages
StateStateless (10-turn history)Stateful (tasks + memory + feed)
EnforcementNone (pure LLM instructions)Mechanical (hooks + gates + scripts)
OutputText + GRAPHS_JSON → chartsCode changes + deploys + feed posts
LanguageEspañol hondureño (voseo)English (technical)
Multi-agentNoYes (parallel sub-agents)
MemoryNone across sessions25 files + SQLite DB across conversations
Deep ModebiDeepSystemPrompt (2nd LLM pass)Sub-agents with isolated worktrees

Changelog

Version history of this steering page.
v2.9 2026-04-22 Added Section 11 (SQL Pipeline): full Flask+LangChain+PostgreSQL deep research flow — planner, SQL generator, executor, narrator, editorial grid rendering. Added Section 12 (Navigation Data Layer): dashboard_data_full.json, findBrandInText, findDivisionInText, CHART_HIGHLIGHT_MAP, compound commands. Renamed IKA Prompts → IKA Analyst. Version history updated to V2.8. Karpathy comparison fully expanded with 3 Problems + 4 Principles + Strategic Questions status.
v2.8 2026-04-22 SQLite session memory. successCriteria field. Simplicity + surgical gates. Topic-based parent matching. Editable backups. Voice in tasks. Three.js r180. Destructive-action protection.
v2.7 2026-04-21 Multi-task detection in work.sh: warns when task title contains separators (" + ", " & ") or 3+ action verbs, nudging agent to split into parallel sub-agents instead of bundling.
v2.6 2026-04-22 Gate now has 5 checks: (1) active task, (2) questions answered, (3) no marking completed, (4) no destructive actions on protected files (cp/git checkout/rm blocked), (5) NEW: must verify before marking done (edit timestamp vs verify timestamp). Three.js tested r180 on staging. Backup descriptions mechanized (JSON file instead of hardcoded map).
v2.5 2026-04-21 Mechanical enforcement: agent cannot mark tasks "completed". Layman explanations added. Text sizes increased. Task hygiene automated in work.sh.
v2.4 2026-04-21 Column titles added. Navigation pipeline (Section 10 left). Karpathy moved to Builder column only. Canvas sizing fixed. Changelog updated.
v2.3 2026-04-21 Canvas stretch fixed. 5 new SVG flow diagrams: system prompt structure, template selection, two-pass analysis (Prompt Bar), gate decision flow, feed message roles (Builder).
v2.2 2026-04-21 Restored canvas architecture graph + layers diagram to both columns. Added prompt bar equivalents. Fixed Karpathy "hybrid" label for unintended modifications.
v2.1 2026-04-21 Section 10 added to Prompt Bar: full decision tree (classifyPrompt), classification logic, query pipeline, identity gate, model selection.
v2.0 2026-04-21 Complete rebuild: two independently scrolling columns. Left = full 9-section Prompt Bar documentation. Right = full 9-section Builder documentation. Shared summary table at bottom. Version navigation added.
v1.2 2026-04-21 Section 10 expanded to two-column comparison. Prompt bar details added. view →
v1.1 2026-04-21 Added prompt bar vs Builder comparison, changelog, auto-linkify.
v1.0 2026-04-21 Initial page — 9 sections covering architecture, CLAUDE.md, memory, scripts, hooks, feed, versions, Karpathy.

IKA STEERING v2.0 — msp.ika.ai/steering