👁 Byakugan
360° vision into any codebase — an adaptive code comprehension CLI built for the IBM Bob 2.0 Hackathon.
Byakugan scans any codebase, sends it through a multi-pass LLM pipeline, and gives you an adaptive HTML report, an interactive quiz, per-file explanations, change-impact analysis, and a RAG-powered chat assistant — all tailored to your skill level and intent.

Features
| Command | What it does |
|---|---|
byakugan profile |
5 questions → saves your skill level + intent to profile.json |
byakugan analyze <path> |
Multi-pass LLM analysis → analysis.json + embeddings.json |
byakugan report |
Self-contained interactive HTML report, opened in your browser |
byakugan explain <file> |
Deep plain-English explanation of one file, adapted to your level |
byakugan impact <file> |
Structured change-impact analysis — what breaks if this file changes |
byakugan chat |
RAG-powered interactive chat about the codebase |
byakugan doctor |
Checks backend reachability, your token, and the provider health behind it |
Architecture
This is one repository with two deployable halves.
package/ ← the published npm CLI. No API keys, ever.
bin/byakugan.js Commander.js CLI router
lib/scanner.js Walks target directory — ranks, filters, detects binary
lib/batching.js File selection + greedy batch packing within token budget
lib/profiler.js 5-question interactive setup → .byakugan/profile.json
lib/llm.js ALL backend calls (HTTP + SSE) — the only file that talks
to the network, and it only ever talks to Byakugan
lib/analyzer.js Multi-pass orchestration → analysis.json + embeddings.json
lib/reporter.js Reads analysis.json + profile.json → self-contained HTML
lib/explain.js Per-file explanation via the `explain` backend task
lib/impact.js Change-impact analysis via the `impact` backend task
lib/chat.js Adaptive RAG chat loop via the `chat` backend task
lib/spinner.js Terminal spinner
templates/report/ The offline HTML report (CSS/JS/partials, ASCII-only)
backend/ ← the private service. Holds every credential.
src/index.js HTTP server + process lifecycle
src/router.js Routes, auth, body limits, SSE, error sanitising
src/tasks.js Named-task registry — the CLI may only ask for these
src/prompts.js Loads and renders prompt templates
src/prompts/*.md Every prompt lives here, not in the published package
src/providers/groq.js Groq generation + streaming (reads GROQ_API_KEY)
src/providers/hf.js Hugging Face embeddings (reads HF_API_KEY)
src/providers/mock.js Deterministic fixtures, for running with no keys
src/billing.js Shared token/rate accounting
src/http-client.js Timeout + retry + concurrency for provider calls
src/config.js Environment configuration
src/logger.js Structured JSON logs
.byakugan/ Runtime output in the ANALYSED project — gitignored
profile.json
analysis.json
embeddings.json
report.html
partial/ Resume cache for an interrupted analyze
Why the split
The published package contains no provider credentials and no prompt text. It cannot call Groq or Hugging Face even if someone unpacks it and reads it. Every model call goes to a Byakugan backend, which authenticates the caller, checks the named task against a fixed allowlist, renders the prompt server-side, and only then talks to a provider.
The practical consequences:
- Rotating a provider key never requires a new npm release.
- Editing a prompt never requires a new npm release either — users get the improvement on their next command.
- A leaked key costs you one key, not a fleet of installs.
- The endpoint is not a generic prompt proxy.
/v1/generatetakes a task name and a bag of variables, not a prompt string. There is nothing to submit that isn't already one of the seven things the product is supposed to do. - Per-tenant rate and spend limits live in one place, where they can actually be enforced.
The tradeoff is honest: the backend must be an always-on host, and there is a network hop in the hot path. Serverless is not a good fit — cold starts would land in the middle of a streaming answer.
How the Analysis Pipeline Works
byakugan analyze <path>
│
▼
scanner.scan()
Walks the directory, ranks files by signal value (source > config > docs),
skips binaries, applies .byakuganignore rules.
│
▼
batching.packBatches()
Greedy first-fit packing — high-value files land in the earliest batches.
Budget: ~16 000 chars / batch (~5 300 tokens).
│
▼
startup: GET /v1/health
A bad backend URL or token costs one second here, rather than surfacing
three minutes in after the directory walk has already finished.
│
▼
Pass 1 — Survey POST /v1/generate task=analyze_survey
Backend renders the prompt from the file inventory + manifests
(package.json, README, etc.)
→ project name, language, architecture, entry points, summary
│
▼
Pass 2..N — File batches task=analyze_files
→ per-file purpose, exports, imports, techniques,
hotspots, state mutations, module-graph edges, external dependencies
│
▼
Final pass — Synthesis task=analyze_synthesize
→ cross-batch graph edges, ranked hotspots, 10 quiz questions
│
▼
mergePasses()
Deduplicates techniques, nodes, edges, dependencies across all passes.
Hotspot risk is always the maximum seen across any pass.
│
▼
analysis.json saved
Single source of truth for report, explain, impact, and chat.
│
▼
buildAndSaveEmbeddings()
Chunks analysis.json into semantically meaningful pieces
(overview, file:*, technique:*, hotspot:*, dep:*),
POST /v1/embed for each batch, saves embeddings.json for the RAG chat index.
How the RAG Chat Works
byakugan chat
│
▼
Loads analysis.json + embeddings.json + profile.json
Selects mode: full-context (small analysis) or retrieval (large analysis)
│
▼
You ask a question
│
▼ (--smart-route only)
task=route → SEARCH or CHAT
│
▼
SEARCH ──▶ POST /v1/embed(question)
cosine similarity vs all chunks in embeddings.json
top-3 chunks retrieved
│
▼
POST /v1/stream task=chat
The backend assembles the system prompt from chat.md plus a reader-profile
section keyed off your level and intent. Junior gets oriented, Senior gets
tradeoffs. The CLI sends the ingredients, not the finished message.
│
▼
Answer streams back over SSE — history updated
Quick Start
For users (installing the CLI)
nvm use # Node 20 required — see .nvmrc
npm install -g byakugan-macgpt
byakugan doctor # confirm the backend is reachable
byakugan profile # set your skill level + intent
byakugan analyze ./path/to/any/repo # analyse a codebase
byakugan report # open .byakugan/report.html
byakugan explain lib/analyzer.js # explain one file
byakugan impact lib/analyzer.js # blast-radius analysis
byakugan chat # ask anything about the codebase
The CLI needs no configuration. If you are pointing at your own backend rather than the hosted one, set two environment variables:
| Variable | Purpose |
|---|---|
BYAKUGAN_API_URL |
Backend base URL. Defaults to the hosted backend. |
BYAKUGAN_API_TOKEN |
Sent as x-byakugan-token. Only needed if the backend requires one. |
For developers (running both halves)
git clone <your-repo-url>
cd byakugan
nvm use # Node 20 required — see .nvmrc
npm ci # installs both workspaces
# Terminal 1 — the backend, which is where the keys live
cp backend/.env.example backend/.env
# fill in GROQ_API_KEY and HF_API_KEY (both free — see below)
npm run backend
# Terminal 2 — the CLI
npm run byakugan -- doctor
Or run a local backend with no keys at all, using deterministic fixtures:
BYAKUGAN_MOCK=true npm run backend
Mock mode is for exercising the protocol end to end. It never returns a real
model response, and it refuses to start in production unless you also set
BYAKUGAN_ALLOW_MOCK=true.
Getting Your API Keys
Both keys are free with no credit card required, and both belong to the backend only. The CLI never sees them.
| Key | Where to get it | What the backend uses it for |
|---|---|---|
GROQ_API_KEY |
console.groq.com | LLM generation + query routing |
HF_API_KEY |
huggingface.co/settings/tokens — create a "Read" token | Chunk embeddings for RAG chat |
Environment Variables
Backend (backend/.env)
| Variable | Required | Default | Description |
|---|---|---|---|
GROQ_API_KEY |
✅ | — | Groq API key |
HF_API_KEY |
✅ | — | Hugging Face token |
BYAKUGAN_API_TOKEN |
— | unset | If set, callers must present it. Strongly recommended in production. |
PORT |
— | 3000 |
Port to listen on |
HOST |
— | 0.0.0.0 |
Interface to bind |
NODE_ENV |
— | development |
Set to production in deployment |
LLM_MODEL |
— | openai/gpt-oss-120b |
Override generation model |
EMBED_MODEL |
— | BAAI/bge-small-en-v1.5 |
Override embedding model |
LLM_REASONING_EFFORT |
— | provider default | low \ |
LLM_MAX_COMPLETION_TOKENS |
— | 16000 |
Output token ceiling per call |
LLM_TIMEOUT_MS |
— | 120000 |
Per-provider-request timeout in ms |
LLM_MAX_ATTEMPTS |
— | 4 |
Retries on 429/5xx/socket errors |
LLM_TPM_LIMIT |
— | 8000 |
Shared tokens/min budget. Raise for a paid tier. |
BYAKUGAN_MAX_TOKENS_PER_DAY |
— | unset | Optional daily ceiling across all callers |
BYAKUGAN_TOKEN_TPM_LIMIT |
— | unset | Optional per-token rate limit |
BYAKUGAN_MAX_BODY_BYTES |
— | 2000000 |
Request body ceiling |
BYAKUGAN_MAX_EMBED_INPUTS |
— | 64 |
Max inputs per embed call |
BYAKUGAN_MOCK |
— | false |
Serve deterministic fixtures instead of calling providers |
BYAKUGAN_ALLOW_MOCK |
— | false |
Required to permit mock mode when NODE_ENV=production |
BYAKUGAN_LOG_LEVEL |
— | info |
debug \ |
CLI (real environment only — the package ships no .env)
| Variable | Required | Default | Description |
|---|---|---|---|
BYAKUGAN_API_URL |
— | hosted backend | Backend base URL |
BYAKUGAN_API_TOKEN |
— | unset | Token to send as x-byakugan-token |
MAX_FILES |
— | 800 |
Hard ceiling on files sent per run |
MAX_CONTENT_CHARS |
— | 1500000 |
Hard ceiling on total content characters |
BATCH_CHAR_BUDGET |
— | 16000 |
Characters per file-analysis batch |
BYAKUGAN_REVEAL_CPS |
— | 40 |
Streaming reveal pace. 0 prints as fast as the backend delivers. |
Backend API
Small, versioned, and deliberately not a prompt proxy. PROTOCOL = 1; the CLI
checks it during the startup health probe, so a version mismatch produces a
"update whichever is older" message instead of an inscrutable parse error.
| Endpoint | Purpose |
|---|---|
GET /v1/health |
Cheap config check. No token spent. |
GET /v1/health?deep=1 |
Also probes both providers. Used by doctor. |
GET /v1/tasks |
The task allowlist, with required variables per task. |
POST /v1/generate |
{ task, variables, options? } → { text, finish_reason, usage, task, protocol } |
POST /v1/stream |
Same body; returns SSE data: {"delta":…} frames, then done or error. |
POST /v1/embed |
{ inputs: [] } → { vectors: [[…]], dimensions } |
Auth, when BYAKUGAN_API_TOKEN is set, is x-byakugan-token: <token> or
Authorization: Bearer <token>.
Tasks are fixed: analyze_survey, analyze_files, analyze_synthesize,
explain, impact, chat, route. Anything else is a 404.
Command Reference
byakugan profile
Interactive 5-question setup. Saves your name, intent, skill level (Junior → GodMode), focus area, and notes. Every other command adapts to this profile.
byakugan analyze <path> [--max-files N] [--max-chars N]
Multi-pass LLM analysis. Produces analysis.json and embeddings.json inside <path>/.byakugan/. Automatically resumes if interrupted — partial pass results are cached in .byakugan/partial/.
byakugan report [-o output.html] [-p project-path] [--no-open]
Renders a self-contained HTML report and opens it in your browser. If profile.json is missing it asks first; if analysis.json is missing it offers to run analyze. Use --no-open in CI, or set BYAKUGAN_NO_OPEN=1, to write the file without launching anything.
The report is one file with no external requests, so it works from disk, offline, and with scripts disabled. It opens with a Byakugan activation sequence, then:
| Section | What it does |
|---|---|
| Mission Dossier | Stamped mission directive, your rank on a five-rung ladder, project cards, field report, entry points |
| Chakra Flow | Interactive dependency graph. Hover to light everything a node touches, click to pin, drag to pan, scroll to zoom. Toggle to a table for the same data. |
| Jutsu Library | Techniques with what-it-is / why-it-matters / without-it, plus the code that proves each one. Filter by load-bearing. |
| Fovea Vision | Blast radius per file, mutable state, and the ropes to the outside world. |
| Shinobi Registry | Every file with purpose, line count, and a complexity meter. Sortable columns, filter box. |
| The Dojo | A knowledge check scored in the page, with a rank stamp at the end. |
Also: Ctrl K (or /) opens a command palette, the theme button switches to a light theme, and the whole document prints cleanly to PDF.
byakugan explain <file> [-p project-path]
Looks up the file in analysis.json and asks for a focused explanation: what the file does, its key exports, what depends on it, and anything non-obvious. Output adapted to your profile level.
byakugan impact <file> [-p project-path]
Structured blast-radius analysis: direct dependents, second-order risk, state mutation risk, safe change zones, and a recommended approach. Uses the chakra network edges from analysis.json.
byakugan chat [--rag] [--no-rag] [--smart-route] [-p project-path]
RAG-powered chat. Automatically uses full-context mode for small analyses and retrieval mode for large ones. --smart-route adds an LLM call to classify each question before retrieving. Keeps a rolling 10-turn history.
byakugan doctor
Prints the backend URL, protocol version, mode (live or mock), and local analysis budgets, then asks the backend for a deep health check and prints a green ✓ or red ✗ per provider. There are no keys to check on this side any more — that is the point.
Deploying the Backend
Any always-on Node host works. Two things matter: it must stay up between calls,
and NODE_ENV must be production.
Render / Railway / Fly
| Setting | Value |
|---|---|
| Build command | npm ci |
| Start command | node backend/src/index.js |
| Health check path | /v1/health |
| Node version | 20 (.nvmrc) |
Set GROQ_API_KEY, HF_API_KEY, BYAKUGAN_API_TOKEN, and NODE_ENV=production
in the platform's secret store — not in a committed file. Real environment
variables always take precedence over backend/.env, so the same build runs
unchanged locally and in production.
Self-hosted
NODE_ENV=production \
GROQ_API_KEY=… HF_API_KEY=… BYAKUGAN_API_TOKEN=… \
node backend/src/index.js
Put it behind TLS. The token is a bearer credential.
Project Structure
byakugan/
├── package/ the published npm CLI
│ ├── bin/byakugan.js
│ ├── lib/
│ │ ├── analyzer.js
│ │ ├── batching.js
│ │ ├── chat.js
│ │ ├── explain.js
│ │ ├── impact.js
│ │ ├── llm.js
│ │ ├── profiler.js
│ │ ├── reporter.js
│ │ ├── scanner.js
│ │ └── spinner.js
│ ├── templates/report/ the offline HTML report
│ └── package.json
├── backend/ the private LLM gateway
│ ├── src/
│ │ ├── index.js
│ │ ├── router.js
│ │ ├── tasks.js
│ │ ├── prompts.js
│ │ ├── config.js
│ │ ├── billing.js
│ │ ├── http-client.js
│ │ ├── logger.js
│ │ ├── prompts/*.md
│ │ └── providers/{groq,hf,mock}.js
│ ├── .env.example
│ └── package.json
├── bob_session/
│ ├── images/ ← screenshots go here
│ ├── plan.md
│ └── session_notes.md
├── .nvmrc
└── package.json private workspace root
Built for the IBM Bob 2.0 Hackathon
Team: Brenda (@Enow-brenda) & Naran (@Naran121x)
See bob_session/ for the implementation plan and full session notes.
License
MIT
Built With
- bob
- css
- html
- imb
- javascript
- python
Log in or sign up for Devpost to join the conversation.