| name | codebase-map |
| description | Regenerate apps/live/codebase.html — the self-contained D3 force-directed graph of the Karinda Live module tree. Use when the user asks to "update the codebase map", "regenerate the architecture diagram", "refresh codebase.html", or when a new/renamed/deleted module under apps/live/lib/ has invalidated the existing map. |
| user-invocable | true |
| allowed-tools | ["Read","Write","Edit","Glob","Grep","Bash(wc *)","Bash(find apps/live/lib *)","Bash(ls apps/live/lib *)"] |
/codebase-map — Regenerate the Karinda Live codebase map
Regenerates apps/live/codebase.html so it reflects the current apps/live/lib/ tree. The file is a standalone, self-contained D3 force-directed graph — one node per Elixir module, edges for inter-module calls, categorical colors, hover tooltip, click-to-deep-dive side panel. It's a navigation aid for humans, not something the app reads at runtime. The file is gitignored (.gitignore → apps/live/codebase.html); regenerate on demand.
What the file is
A single self-contained HTML file with three layered parts:
- HTML/CSS shell (top ~345 lines) — header, legend, SVG canvas, side panel markup, about overlay, tooltip div. Do not touch this unless styling is genuinely broken or a new category needs a legend entry.
deepDives object (~line 354 onwards inside the <script> block) — keyed by module id, value is an HTML string rendered into the side panel when a node is clicked. Only the "flagship" modules have entries (agent, runner, home_live, chat_live, admin_live, etc. — not every module). Rich, hand-written prose with <pre><code> blocks and <table>s.
- Three data arrays —
modules, deps, catColor — the actual graph data.
The three data blocks are the only thing most regenerations need to touch:
const modules = [
{ id: 'application', cat: 'core', loc: 91, doc: 'OTP application root. ...' },
];
const deps = [
['application', 'agent_supervisor'],
];
const catColor = {
core: '#C17F3A',
liveview: '#6B8E4E',
web: '#A0522D',
components: '#8B7355',
};
id = the Elixir module's file stem (agent.ex → agent, home_live.ex → home_live).
cat = one of the keys in catColor.
loc = wc -l of the source file (just the integer).
doc = one sentence — what the module does, not what it is.
Categories
- core (
#C17F3A) — anything in lib/karinda_live/ that isn't test infra. The trust kernel: Agent, Runner, Store, Config, Agent{Supervisor,Yaml,Runner}, Session, Store, ThreadStream, Push, IdleReaper, TitleGen, StreamWriter, LiveState, Kn, etc.
- liveview (
#6B8E4E) — lib/karinda_live_web/live/*.ex — HomeLive, ChatLive, ChatListLive, SessionLive, AdminLive, AgentDetailLive, AgentsLive, ToolsLive, SpikeLive.
- web (
#A0522D) — Phoenix plumbing: Endpoint, Router, Telemetry, UserSocket, controllers (page, widget, push, error_{html,json}), channels (ThreadChannel, SpikeChannel).
- components (
#8B7355) — lib/karinda_live_web/components/*.ex — CoreComponents, Layouts, Widgets, ThreadCard.
If a new top-level category emerges (e.g. native-view templating for LVN), add it to catColor and to the "Legend" block in the HTML header. That's the one case where you touch the shell.
Regeneration procedure
Do this as a single focused pass in the main context. Do not delegate to a sub-agent — the quality of the one-line doc strings and the deep-dive prose is what makes the map useful, and that needs main-context judgment.
1. Enumerate modules
find apps/live/lib -name "*.ex" -type f | sort
Filter out test support and one-off mix tasks unless they're load-bearing. karinda_live.ex (just the @moduledoc shell) is optional — skip it. lvn_template* and spike_* count if they're live parts of the LVN spike.
2. For each module, collect four fields
id — file stem
cat — by rules above
loc — wc -l < path/to/file.ex — integer only
doc — read the @moduledoc (or top ~30 lines if there's none) and distill one sentence. What does this module own / do? Not "a module that handles X" — name the thing.
Good:
"One GenServer per agent. Owns refresh schedule, conversations, pi lifecycle hooks."
Bad:
"Agent management module."
3. Build deps
For each module, Grep:
alias KarindaLive.*
alias KarindaLiveWeb.*
...and direct ModuleName.function calls. Each inter-module use is one [from, to] pair. Don't double-count (if home_live uses widgets in five places, that's still one edge). Don't include standard-library, hex-dep, or Phoenix-builtin calls — only first-party modules. Drop edges where either side isn't in modules.
4. deepDives prose
Only update a deepDives entry if the module's behavior actually changed since it was last written. Don't rewrite these on every regen — the rich prose is the high-value, hand-crafted part. Add new entries only for modules whose architectural role is worth a deep dive (heart-of-the-system modules, not leaf controllers).
5. Write the file
The HTML shell, deepDives object, and data arrays all live in one file. Either rewrite the whole thing in one Write call, or use targeted Edit calls scoped strictly to the three data arrays. Prefer the edit path when the shell is unchanged — it's easier to review and less error-prone.
6. Smoke-test
Open the file in a browser (or file:// it) and confirm: D3 loads from CDN, nodes render, edges render, clicking a node with a deepDives entry opens the side panel. No JS console errors.
Rules
- One sentence per
doc. Longer belongs in deepDives, not the hover tooltip.
- Keep
modules.length under ~40. If there are more files than that, they probably aren't all architecturally interesting — group or drop the noise (e.g. karinda_live.ex shell, user_socket.ex).
- Don't invent edges. If Module A doesn't actually reference Module B, no edge. Grep is authoritative; memory is not.
- Don't stylistically redesign the HTML. This file has a look. Keep it.
- Don't commit the regenerated file.
apps/live/codebase.html is gitignored. Regeneration is on-demand; the source of truth is the code itself.
- LOC is just for node sizing (
radius: Math.max(12, Math.sqrt(m.loc) * 2.2)). It doesn't need to be precisely current, but shouldn't be wildly stale. If you're regenerating, update it.
Known gaps in the existing file (as of 2026-04-11)
Modules in the current tree that are missing from the modules array — fold them in on next regen:
agent_yaml (core) — YAML writer for agent.yaml self-configuration
idle_reaper (core) — reaps idle pi processes after N seconds
live_state (core) — ETS live state helpers
push (core) + mix/tasks/karinda.push.gen_vapid.ex — web push notifications
title_gen (core) — auto-generates chat thread titles
kn (core) — check moduledoc for purpose
lvn_template / lvn_template/tag_handler — LiveView Native template handling (may warrant its own category)
spike_live / spike_channel — experimental LVN spike
push_controller, widget_controller (web) — may or may not be in the existing modules array
page_html (web) — Phoenix-generated page rendering helper
Also: thread_stream was marked "being phased out" — verify it's still in use. If deleted, drop from modules and deps.