mikoshi
v0.4.0
Published
Local-first code search, graph analysis, and MCP context engine. No cloud, no telemetry.
Downloads
473
Maintainers
Readme
What Is Mikoshi?
Mikoshi is a CLI (and MCP/ACP server) for local-first code search and understanding. It parses your codebase into an AST-based dependency graph and a local vector index, then serves search, symbol explanation, blast-radius analysis, and graph-verified PR review — entirely offline, with no LLM required for any of that. On top of this, it optionally offers: an AI agent (mikoshi run) that can use your configured LLM provider and call tools against your codebase; an MCP server and an ACP server so external AI editors can call the same tools; and optional Supabase project access (schema inspection, SQL execution) for connected agents.
Supported OS: macOS is supported and validated — the full test suite and packed-install QA are run and passing on macOS as of each release. Linux and Windows are experimental and not officially supported: the code includes Linux/Windows-specific handling (e.g. native ACLs for credential-file protection on Windows, since it has no POSIX permission bits), but cross-platform validation has surfaced unresolved platform-specific issues on both (see docs/investigations/ for details), so neither is currently backed by a passing CI run.
Node.js >=22.0.0 is required (enforced via package.json's engines field).
What's New in 0.4.0
Controlled Writes. A mechanically-verified path for single-statement Supabase mutations: plan → approve at a real terminal → execute, with the precondition check and the write folded into one atomic statement. No agent, script, or MCP/ACP client can approve its own write. Read more ↓
Cross-System Supabase Audit. mikoshi supabase audit joins your indexed code graph with live Supabase state — RLS policies against real call-site reachability, RPC/table ↔ source mapping, semantic schema drift. Every finding is resolved or honestly labeled unresolved_evidence, never a guess. Read more ↓
Fixed. correlation.js no longer mistakes test fixtures or comments for real call sites, and Supabase graph tools no longer re-parse the whole repo per Edge Function.
Breaking. keepalive no longer falls back to a legacy anon/service_role key — only sb_publishable_.../sb_secret_.... Affected projects get a clear, one-time fix.
Full detail for every change: CHANGELOG.md.
60-Second Quickstart
# Install globally (or use npx)
npm install -g mikoshi
# Index your project — everything stays local
cd ~/your-project
mikoshi index .
# Understand your code — no LLM needed
mikoshi explain mergeScores # callers, callees, imports, tests
mikoshi impact auth.js # blast radius: every affected function
mikoshi search . "retry logic" # BM25 + semantic hybrid search
mikoshi diff-review # graph-verified PR review
# Machine-readable output for scripts & CI
mikoshi explain mergeScores --json
mikoshi impact auth.js --jsonOr try the self-demo (indexes the current repo and runs 3 showcase queries):
npx mikoshi demoWhy Mikoshi?
| | Mikoshi | Cloud search tools |
|---|---|---|
| Privacy | 100% local — zero network calls during search/index | Sends code to cloud |
| Call graph | Real call/import edges with confidence scores | Embeddings only |
| explain | Shows callers, callees, imports, tests — no LLM needed | N/A |
| impact | Blast radius: "change X → these 14 functions break" | N/A |
| diff-review | Graph-verified PR review — --strict = zero hallucination | LLM-only |
| MCP | Built-in MCP server for Claude, Cursor, Copilot | Varies |
| Cost | Free forever | Per-seat pricing |
Indexing and search never leave your machine. Optional features you explicitly enable — AI chat (mikoshi run/mikoshi chat), MCP tool calls from a connected AI client, and Supabase project access — do make network calls, only when you use them. See PRIVACY.md for the full breakdown.
Core Commands
Index
mikoshi index . # first run: AST parse + embed (local ONNX)
mikoshi watch # live re-index on file saveUnderstand
mikoshi explain <symbol> # definition, callers, callees, imports, tests
mikoshi impact <symbol|file> # transitive dependents + affected tests
mikoshi diff-review # graph-verified review of git diff (--strict default)
mikoshi diff-review --staged # review only staged changesSearch
mikoshi search . "query" [k] # 7-stage retrieval: BM25 + semantic + smart rankingAgent
mikoshi run "summarize this repo"
mikoshi run --print --max-turns 6 "refactor auth module"Health
mikoshi doctor # node, config, index, graph, embeddings, stalenessGuardian
Guardian is Mikoshi's static-analysis engine: 7 detectors (duplicate code, architecture-boundary violations, dead code, doc/code drift, responsibility drift, state ownership, and their runtime-binding variants) run against a real git repository and report every finding as violation, compliant, or unresolved — Guardian never guesses; when it can't reach a trustworthy answer it says so explicitly (unresolved) rather than fabricating a pass or fail.
mikoshi guardian scan [path] # human-readable report; [path] defaults to the current directory
mikoshi guardian scan [path] --json # full machine-readable result (evaluations, per-detector breakdown)
mikoshi guardian scan [path] --fail-on violation # CI gate: exit 1 if any violation is found
mikoshi guardian scan [path] --fail-on unresolved # CI gate: exit 1 if any unresolved finding is found
mikoshi guardian scan [path] --fail-on violation --fail-on unresolved # fail on either (repeatable, deduplicated)--fail-on is a policy layer only — the scan's own structured result (JSON/MCP/ACP) is always the same regardless of what --fail-on was passed; the flag only changes this command's exit code.
Exit codes:
| Code | Meaning |
|---|---|
| 0 | Scan completed, policy gate passed (or no --fail-on given) |
| 1 | Scan completed successfully, but a requested --fail-on status occurred |
| 2 | Usage error (bad --fail-on value, unknown subcommand) |
| 3 | Guardian could not produce a complete, trustworthy scan result |
| 130 | Interrupted by SIGINT |
| 143 | Interrupted by SIGTERM |
MCP/ACP: Guardian is available as the guardian_scan tool over MCP (see MCP Integration below for client setup) and as an internal tool in Mikoshi's own agent loop (mikoshi run) over ACP — both call the exact same underlying scan service as the CLI, so results are consistent across every transport.
Known limitations
- TypeScript enum/namespace cross-file identity. A free reference to a shared
enumornamespaceacross files always resolvesunresolvedrather than a fabricated match — correctly resolving it requires real TypeScript declaration-merging semantics, which Guardian's syntax-only (Babel-based) parsing cannot determine. This is a missed-detection gap, never a false positive. - Windows SIGINT/SIGTERM delivery. Node.js cannot deliver a catchable SIGINT/SIGTERM to a child process on Windows through the normal
child_processsignal mechanism — this is a Node/Windows platform constraint, not a Guardian defect. Guardian's own cancellation logic is unaffected and is fully covered through every path Windows does support (in-process cancellation, process termination).
MCP Integration
Mikoshi ships a built-in MCP server over stdio. Works with Claude Code, Cursor, VS Code Copilot, Windsurf, or any MCP-compatible client.
mikoshi-mcp # starts stdio MCP serverTools exposed via MCP:
| Tool | Description |
|---|---|
| Mikoshi Context-Engine | Full 7-stage retrieval pipeline |
| get_code_web | Structured symbol neighborhood with evidence + confidence |
| explain_symbol | Callers, callees, imports, tests for a symbol |
| guardian_scan | Guardian static-analysis scan (see Guardian above) |
| impact_analysis | Blast radius: transitive dependents + affected tests |
| diff_review | Graph-verified git diff review |
Claude Code / Claude Desktop
Add to ~/.claude/claude_desktop_config.json or project .mcp.json:
{
"mcpServers": {
"mikoshi": { "command": "mikoshi-mcp", "args": [] }
}
}Cursor
Add to .cursor/mcp.json in your project root:
{
"mcpServers": {
"mikoshi": {
"command": "mikoshi-mcp",
"args": []
}
}
}VS Code Copilot
Add to .vscode/mcp.json:
{
"servers": {
"mikoshi": {
"type": "stdio",
"command": "mikoshi-mcp",
"args": []
}
}
}Windsurf
Add to ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"mikoshi": {
"command": "mikoshi-mcp",
"args": []
}
}
}No Native Tool Calls? Use Evidence Packs
Tool calling depends on the host client (mode, permissions, local stdio policy) — not just the model. If your AI editor doesn't support MCP, or your model can't emit tool calls, Mikoshi still works.
The --clip flag outputs a compact JSON evidence pack you can paste into any model:
# Search → evidence pack → clipboard
mikoshi search . "retry logic" --clip | pbcopy
# Explain a symbol → evidence pack → clipboard
mikoshi explain mergeScores --clip | pbcopy
# Impact analysis → evidence pack
mikoshi impact auth.js --clip | pbcopy
# Diff review → evidence pack
mikoshi diff-review --clip | pbcopyThen paste into ChatGPT, Claude, Gemini, or any model:
Here is grounded evidence from my codebase. Answer based on this context:
⌘V
Evidence packs include:
- File paths, line numbers, and code snippets
- Call graph relationships (callers, callees, imports)
- Confidence scores for every edge
- Structured JSON that models parse easily
mikoshi doctor detects MCP and tool availability and prints fixes:
mikoshi doctor
# ✅ MCP server: /opt/homebrew/bin/mikoshi-mcp
# ⚠️ MCP config: no Mikoshi MCP config found
# Fix: mikoshi init
# Or paste into any model with: mikoshi search . "query" --clipACP Integration
Mikoshi implements the Agent Client Protocol (ACP) over stdio, for editors/clients that speak ACP directly (as opposed to MCP).
mikoshi --acp # ACP server over stdio
mikoshi acp setup . # generate config for ACP-compatible editorsSupported: session lifecycle (session/new, session/cancel, session/prompt), streamed response text (session/update notifications), and tool-call capability negotiation (filesystem write, process spawn, external network — each configurable via MIKOSHI_ACP_ALLOW_* env vars, all deny-by-default except network).
Not supported in this release:
session/load(resuming a previously-created session) — the client capability response reportsloadSession: false.- Audio/image prompt content, embedded context, and MCP-over-SSE/HTTP — all reported as unsupported in
agentCapabilities. - Mid-stream cancellation is best-effort, not instant.
session/cancelis registered immediately, but Mikoshi's ACP server processes one step of a session at a time — an in-flight LLM call or tool invocation is not aborted mid-call. In practice, a cancel sent during a response is honored at the next step boundary, which can take several seconds on a slow model response, not immediately. This is spec-legal (the ACP spec says agents "SHOULD" stop as soon as possible, not "MUST" stop instantly) but should not be assumed to behave like killing a process. Making cancellation interrupt in-flight requests is tracked as follow-up architecture work (#2), not implemented yet.
Supabase Integration
Mikoshi's agent (and connected MCP/ACP clients) can optionally inspect and query a Supabase project you authorize — for schema exploration, table/RLS/role inspection, and running SQL against your own database on request.
mikoshi supabase connect # OAuth-authorize a Supabase organization (opens a browser)
mikoshi supabase projects # list every project across every connected organization
mikoshi supabase use <ref> # set the default project (by ref, project id, or nickname)
mikoshi supabase alias <ref> <nickname> # give a project a short nickname
mikoshi supabase sql "SELECT ..." # run SQL against the resolved/default project
mikoshi supabase sql --project staging "SELECT ..." # target a specific project by ref/id/nickname
mikoshi supabase status # show connected organizations and their projects
mikoshi supabase disconnect [org] # remove one organization's connection (or --all)Multiple organizations and projects: each Supabase organization you authorize is stored as an independent OAuth connection (Supabase's own consent flow authorizes one organization per grant), so you can connect several organizations and Mikoshi will aggregate every project across all of them. Target a specific project by ref, id, or nickname with --project <target>; with no target, Mikoshi resolves to your saved default, auto-resolves if you only have one connected project, or returns a clear "ambiguous — pick one" response rather than guessing. Tokens refresh automatically per-organization when they're near expiry; if a refresh fails for one organization, only that organization needs reconnecting — others are unaffected.
SQL safety controls: by default, mikoshi supabase sql and the supabase_sql tool run in read-only mode — any statement matching a blocklist of mutating keywords (INSERT, UPDATE, DELETE, DROP, ALTER, TRUNCATE, CREATE, GRANT, REVOKE, and others) is rejected before it reaches your database. Running a write requires an explicit --i-understand-this-can-destroy-data flag (CLI) or i_understand_this_can_destroy_data: true parameter (MCP/ACP tool call) — there's no path for an agent to silently escalate to a destructive statement. Every execution (read or write) is recorded in a local audit log with secrets redacted.
Controlled Writes — mechanically-verified single-statement mutations with mandatory human approval
For a supabase_sql write that's more than a one-off (or when you want a mechanically-verified, auditable mutation rather than a blocklist-gated bypass), Mikoshi offers Controlled Writes: a separate, higher-assurance path for exactly one UPDATE/DELETE/INSERT statement per operation, built around a plan → human-approve → execute lifecycle that no agent, script, or MCP/ACP client can complete on its own.
mikoshi supabase controlled-write plan "UPDATE orders SET status = 'shipped' WHERE id = 42"
# -> builds a canonical plan, prints it, prints the exact confirm command. Nothing is sent to your database yet.
mikoshi supabase controlled-write confirm <operation-id>
# -> the ONE step that requires a real interactive terminal. Reviews the plan and asks you to type
# the operation-id back to approve it. This step cannot be scripted, piped, or called by an agent.
mikoshi supabase controlled-write execute <operation-id>
# -> executes the approved plan exactly once. Callable by an agent/MCP/ACP client -- but only ever
# succeeds against a plan a human already approved at a real terminal.
mikoshi supabase controlled-write status <operation-id>
# -> inspect a plan/approval/execution's current state at any point in the lifecycle.What's supported: exactly one UPDATE or DELETE statement per plan, with a WHERE clause made up of one or more column = literal equalities joined by AND (e.g. WHERE org_id = 12 AND user_id = 42), bound to a real, mechanically-proven PRIMARY KEY or UNIQUE constraint on the table — so the row a human approves is provably the row that gets mutated, never "whichever row happens to match right now." A selector on a column with no uniqueness guarantee at all (e.g. WHERE email = '...') is still plannable, as long as it resolves to exactly one row and the table has its own real primary key to bind to. UPDATE additionally supports multiple SET column = literal assignments in one statement. INSERT is supported for the simple "no precondition to verify" case. Everything else — OR/IN/subqueries/expressions in the WHERE clause, joins, multi-statement batches, multi-row writes, mutating the column the row's identity is bound to — is rejected outright at plan time, never partially modeled or silently narrowed.
The lifecycle, and what each step actually guarantees:
- Plan — Mikoshi reads your statement, resolves which row(s) it targets and what a real, mechanically-provable identity for them looks like, reads the current value of every column your statement would change (and every identity column, in one bounded read), and produces a canonical plan: the exact normalized SQL, the resolved selector and row identity, the observed "before" values, the expected "after" values, and a content-derived
operation_id. No mutation happens at this step. - Confirm — the only step that can create an approval record, and it refuses outright unless run at a real, interactive terminal (
stdin/stdoutboth TTYs) — never from a script, a CI job, an agent's own tool call, or a piped/redirected invocation. A confirmed approval is bound to that exact plan'soperation_id; a different plan (even one that looks nearly identical, or the same SQL against a different project) is never authorized by it. - Execute — re-checks the approval exists and hasn't expired, re-reads the row and compares it against what was approved (catching anything that changed since approval), then issues the mutation as ONE atomic, row-locked SQL statement that folds the approved identity, selector, and every observed precondition directly into its own
WHEREclause — the check and the write are the same database statement, not a separate look-then-act pair, so there's no window for a concurrent change to slip through. Execution claims theoperation_idexclusively on first attempt (a filesystem-level compare-and-set) — a secondexecutecall for the same operation_id can never run it twice, and Mikoshi never automatically retries anything, regardless of outcome. - Verify — after a successful mutation, Mikoshi independently re-reads the affected row(s) and confirms they now hold the expected values before reporting success.
Terminal outcomes are explicit and named — there is no bare {success: true}. The two you'll see on the happy path are VERIFIED (the mutation happened and was independently confirmed) and EXECUTED_UNVERIFIED (the mutation almost certainly happened, but there was nothing to independently verify against, e.g. a plain INSERT). Every other outcome names exactly what stopped the write and guarantees zero rows were touched: NO_APPROVAL/APPROVAL_EXPIRED/PLAN_EXPIRED (nothing was ever approved, or the approval/plan window closed), STALE_PLAN (something changed since you approved it), ALREADY_CLAIMED (this operation already ran), VERIFICATION_MISMATCH (the mutation ran but the row doesn't hold what was expected — reported honestly rather than assumed), EXECUTION_PRECONDITION_OR_VISIBILITY_FAILED (the row no longer matched at mutation time, or Row-Level Security made it invisible to the executing role — Mikoshi discloses both possibilities rather than guessing which), EXECUTION_TRIGGER_STATE_CHANGED/EXECUTION_UNSUPPORTED_REWRITE_RULE/EXECUTION_UNSUPPORTED_REFERENTIAL_SIDE_EFFECT (a trigger, CREATE RULE, or cascading foreign key would make the approved plan's effect different from what was disclosed, so it's blocked instead), EXECUTION_MULTI_ROW_SAFETY_FAILURE (PostgreSQL itself refused because more than one row would have matched — should never happen given a mechanically-proven identity, and if it does, nothing was mutated), EXECUTION_SCHEMA_LOCK_UNAVAILABLE (a conflicting concurrent operation held the table lock; never waited on, never retried), and EXECUTION_OUTCOME_UNKNOWN (a network-level failure with no way to know if the request reached Supabase — deliberately never reported as either success or failure).
Safety properties, summarized (full architecture and the complete adversarial test matrix: Iteration 5 DESIGN.md, CAS repair CLOSURE.md, side-effect repair CLOSURE.md, Iteration 6B CLOSURE.md): the row a human approves is the row that gets mutated, mechanically proven, never inferred from "it looked unique"; the precondition check and the mutation are one atomic statement, never a separate check-then-write race; an approval can never be produced by anything other than a human at a real terminal, and can never be replayed, reused across plans/projects, or executed more than once; a table/rule/foreign-key that would make the write do more than what was disclosed is detected and blocked, atomically, at the moment of execution — not just at plan time; nothing is ever automatically retried.
Capability model for agents: when your AI agent (or a connected MCP/ACP client) wants to call a Supabase tool, that call is gated by the same capability-authorization system as every other tool action (filesystem.write, process.spawn, etc.) — supabase.project.read, supabase.project.config.write, supabase.database.read, supabase.database.write, supabase.database.destructive, supabase.auth.config.read, supabase.storage.read, supabase.functions.read, supabase.logs.read, supabase.branches.read, and supabase.realtime.watch are independently allow/deny/prompt, default prompt. A denied or not-yet-approved capability means zero network calls to Supabase, not just a blocked local action. Read operations, additive writes (INSERT/UPDATE/...), and destructive operations (DELETE/DROP/TRUNCATE/...) are distinct capabilities, so approving read access never implicitly approves anything else. A small number of tools that genuinely span multiple surfaces (supabase_app_graph, supabase_realtime_diagnose, supabase_object_reachability, supabase_audit) require all of their listed capabilities at once — a deny or missing grant on any one of them blocks the whole operation, with no partial result, and there is no way to reach that data indirectly by approving only one of the required capabilities. supabase.realtime.watch protects exactly one tool (supabase_realtime_watch) and nothing else — granting it never unlocks any other Supabase capability, since it authorizes a materially different kind of action (a live client connection using a project API key) from every other capability here (which all gate Management-API/SQL calls using your OAuth connection). Running mikoshi supabase sql yourself at the terminal is unaffected by this — a command you type directly is its own authorization, the same as running psql yourself. Secrets, service-role credentials, and Auth-user administration (listing/deleting/inviting users) are never requested or exposed by any current tool. See DESIGN.md for the full architecture, capability matrix, error taxonomy, and OAuth-scope verification status/instructions.
Auth, Storage, Functions, Logs, and Branches inspection
Beyond schema/SQL, Mikoshi can inspect a connected project's Auth configuration, Storage buckets, Edge Functions, recent logs, and preview branches — and correlate each against how your codebase actually uses them, so you can see mismatches (a bucket your code references that doesn't exist remotely, a function deployed locally but never pushed, an OAuth provider your code initializes that's disabled on the remote project) without opening the Dashboard.
mikoshi supabase auth-inspect # Auth provider/config summary + local OAuth-usage correlation
mikoshi supabase storage list # list buckets
mikoshi supabase storage inspect <bucket> # one bucket + local storage.from("...") correlation
mikoshi supabase functions list # Edge Function inventory
mikoshi supabase functions inspect <name> # one function + local/remote drift (LOCAL_ONLY/REMOTE_ONLY/MATCH)
mikoshi supabase logs recent-errors [--source X] # recent error-level logs (default: last 15 min, max 200 rows)
mikoshi supabase logs function <name> # recent logs for one Edge Function
mikoshi supabase logs postgres # recent Postgres logs
mikoshi supabase logs request <request-id> # trace a single request
mikoshi supabase branches list # preview/database branches
mikoshi supabase branches inspect <branch> # one branch's config (credentials always stripped)What's deliberately excluded: no Auth user listing/deletion/invitations/password resets, no Edge Function source code or secrets retrieval, no continuous/unbounded log streaming (every logs call is a single bounded fetch — max 24-hour lookback, max 200 rows), and no branch diff/create/push/merge/delete (branch diff requires a write-tier Supabase scope despite being a read, so it's reserved for a later, explicitly elevated capability phase, not exposed here). Auth/Storage/Functions/Branches results are cached briefly per-project (3–10 minutes depending on how often each changes) to avoid repeated round-trips; every result reports its own fetched_at and whether it came from cache, and --refresh forces a live re-fetch. Logs are never cached.
Cross-system reasoning (Edge Function dependencies, Auth flow diagnosis, storage access posture, schema drift)
Beyond listing and correlating individual surfaces, Mikoshi can reason across them — combining local source analysis with the remote data above to answer questions like "why can't users upload avatars" or "why is login failing" directly, rather than requiring you to manually cross-reference the Dashboard, source, and logs yourself. Every result carries an explicit confidence marker (FACT_LOCAL/FACT_REMOTE/INFERENCE/UNRESOLVED) and cites its evidence — nothing is asserted without a source.
mikoshi supabase functions-dependencies <name> # local table/RPC/bucket call sites for one Edge Function, cross-checked against live existence
mikoshi supabase functions-auth-analysis <name> # verify_jwt (gateway-only meaning) + local getSession()/service-role anti-pattern detection
mikoshi supabase storage-access-analysis <bucket> # combines public flag + storage.objects RLS into one explicit read/write posture
mikoshi supabase auth-flow-diagnose [--provider X] # correlates local auth call sites, remote provider config, and recent auth-log signals
mikoshi supabase schema-drift [--live] # exact migration-history drift; --live adds a disclosed-heuristic live-schema approximation
mikoshi supabase logs-correlate <function-name> # best-effort timestamp-proximity grouping of function + Postgres logs
mikoshi supabase app-graph # normalized dependency graph composing all of the aboveTwo things this deliberately never claims: first, there is no Supabase API that reveals which tables/RPCs/buckets an Edge Function actually touches, and no shared identifier links a Postgres log entry to the Edge Function invocation that issued it — so dependency extraction and log correlation are both local pattern-matching / timestamp-proximity heuristics, not proofs; a match is likely real, but absence of a match is never treated as evidence of absence. Second, --live schema drift is explicitly not equivalent to supabase db diff (which requires a real Docker shadow database Mikoshi does not run) — it's a lighter approximation, always labeled as such. Every result that relies on either limitation says so directly in its own output, not just in this document.
supabase_app_graph requires three capabilities at once, since it's the one operation that reads Storage, Edge Functions, and Auth config together: supabase.storage.read and supabase.functions.read and supabase.auth.config.read must all independently resolve to allow (or be interactively granted) before it runs — granting only one or two does not unlock the rest through this tool. This is enforced by the same generic capability-authorization system every other Supabase tool uses, extended to support "all of these" requirements alongside the existing one-capability-per-tool model; no new capability was added for it.
Realtime Intelligence
Mikoshi can trace how your codebase uses Supabase Realtime — channel subscriptions, postgres_changes, broadcast, presence — and correlate that against the project's actual publication membership, RLS/grant posture, and (once Supabase's own API supports it) Realtime configuration, to answer questions like "why isn't my subscription firing" with cited evidence rather than a guess.
mikoshi supabase realtime-source-scan [--directory X] # local channel/postgres_changes/broadcast/presence/cleanup scan (real AST parsing, not regex)
mikoshi supabase realtime-publication-status [--table X] # tables actually in the supabase_realtime publication
mikoshi supabase realtime-authorization-check <table> # publication + RLS + grants + replica identity for one table
mikoshi supabase realtime-private-channel-check [topic-pattern] # realtime.messages RLS policies for private Broadcast/Presence channels
mikoshi supabase realtime-config-inspect # rate limits/private_only/presence_enabled (currently unavailable — see below)
mikoshi supabase realtime-logs-recent # recent realtime_logs (connection logging is opt-in)
mikoshi supabase realtime-diagnose <table> # combines all of the above into cited, confidence-rated findings
mikoshi supabase realtime-watch <topic> [--table X] [--seconds N] # bounded live observation of ONE channel (see below)Local source analysis uses real AST parsing with bounded same-scope binding resolution, not regex — this is what correctly resolves a channel's options object even when it's built as a separate const config = {...} and passed by reference, and correctly extracts a template-literal channel name's static prefix (e.g. `room:${roomId}:messages` → "room:") without ever fabricating the dynamic part. Anything genuinely unresolvable in that bounded scope is reported as such, never guessed.
Two authorization systems that are never conflated: postgres_changes subscriptions are gated by table grants plus optional RLS on the business table itself; private Broadcast/Presence channels are gated by RLS policies on a completely different table, realtime.messages. realtime-authorization-check covers the first; realtime-private-channel-check covers the second — Mikoshi never merges these into one finding, since a fix for one does nothing for the other.
realtime-config-inspect is currently unavailable, honestly: Supabase's own config/realtime endpoint does not yet support OAuth-token access at all (confirmed directly against Supabase's API, not a Mikoshi limitation) — the tool reports this as a structured "unsupported" result rather than retrying or working around it with a different credential, and will start returning real data automatically the moment Supabase adds support, no update needed.
realtime-watch is a narrowly-bounded, explicitly-invoked live observation — default 15 seconds, hard-capped at 60; default 20 events, hard-capped at 50; exactly one channel per call; no daemon, no continuous mode. It connects using only the project's Publishable Key (sb_publishable_...) — never a legacy anon key, never the Secret Key. A private channel additionally requires --user-jwt (an ephemeral end-user Auth session token, never persisted or logged) — without it, the tool reports that auth context is required rather than escalating to a more privileged credential. Every captured payload is redacted and size-capped before being returned; nothing from a watch is ever written to disk.
Cross-System Supabase Audit (joining your code graph with live Supabase state)
Mikoshi can join the Supabase intelligence above with its own indexed code graph — the same graph explain_symbol/get_code_web/impact_analysis/diff_review use — to answer questions neither side can answer alone: "is this RLS policy actually compatible with how the app queries this table," "is this RPC ever called from real application code, or only from tests," "does live schema still match what the last migration declared." Requires the repo to be indexed (mikoshi index .) for the code-graph-dependent parts; degrades gracefully (documented per result) if it isn't.
mikoshi supabase security-code-audit [--repo-path X] # live RLS/policy findings joined with real call-site reachability
mikoshi supabase object-reachability [--repo-path X] # RPC/table <-> source: unused remote objects, missing local targets, stale/dead call sites, suspected duplicate wrappers
mikoshi supabase schema-drift --semantic # columns/function signature+security+body/triggers/policies/views/indexes/Realtime-publication drift, beyond the existing table-presence check
mikoshi supabase audit [--repo-path X] # one orchestrated call combining all of the above, plus schema drift when migration files are presentsecurity-code-audit takes every live RLS finding shaped as a simple auth.uid() = <column> restriction, finds the local call sites that reference that table (resolved through the real code graph, not just a text match), and flags a call site that doesn't filter on the same column via a recognized shape. This is always a flagged-for-review inference, never a proven bug — Mikoshi cannot execute the query, and a call site with no recognized filter may still be safe (RLS itself still enforces the restriction server-side). A call site that DOES filter on the policy's own column is never flagged, even if the match isn't textually perfect.
object-reachability classifies every table/RPC into REMOTE_NO_LOCAL_CALLERS (exists remotely, no local reference found — not proof of disuse, just absence of a textual match), LOCAL_REFERENCE_MISSING_REMOTE (local code references an object that doesn't exist remotely — a possible removed/renamed object or typo), STALE_RPC_USAGE (a resolved call site with zero reaching callers in Mikoshi's bounded call graph — may be dead code, or reached via a path the graph doesn't model), and DUPLICATE_WRAPPER_SUSPECTED (2+ distinct functions independently invoking the same resource — flagged for review, never auto-merged).
schema-drift --semantic extends the existing migration-history/table-presence drift checks with columns, function signature/security/body, trigger/policy presence, views, indexes, and Realtime publication membership. Every sub-result is only ever FACT_REMOTE (normalized-identical, provably in sync) or UNRESOLVED (not proven either way) — never a probabilistic "probably drifted" claim, since Mikoshi cannot execute or semantically compare SQL; two functions doing the same thing with different SQL are never claimed equivalent.
audit orchestrates all of the above (plus the existing app-graph) into one call, separating findings into resolved_findings (evidence-backed) vs. unresolved_evidence (flagged, not proven) rather than collapsing everything into one undifferentiated list. No writes — this whole surface is read-only, same as every other Supabase inspection tool.
object-reachability and audit each require multiple capabilities at once (supabase.database.read and supabase.storage.read and supabase.functions.read for the former; those three and supabase.auth.config.read and supabase.logs.read for the latter — audit's requirement is the union of every capability its component calls already need), using the same conjunctive authorization mechanism as supabase_app_graph. security-code-audit needs only supabase.database.read — its code-graph half is local and reuses no remote capability of its own, matching the same "local codebase Mikoshi already indexes" precedent as every other local-source-analysis tool. Zero new capabilities were added for this surface.
Keepalive for Supabase Free-tier projects
Supabase pauses Free-tier projects after a period of inactivity. Mikoshi can ping a connected project on a schedule (via a GitHub Actions workflow you set up in your own repo) to keep it active:
mikoshi supabase keepalive enable <project> # sets up a real keepalive table + GitHub Actions secret
mikoshi supabase keepalive test # ping enabled project(s) right now and report the result
mikoshi supabase keepalive status # show last success/failure and next scheduled run
mikoshi supabase keepalive disable <project> # stop pinging this project (leaves the table/secret in place)<project> accepts a ref, project id, or saved nickname (same targeting as --project elsewhere).
This is best-effort, not a guarantee. Supabase's own documentation does not promise that periodic pings prevent pausing — the only official guarantee against pausing is upgrading the organization to a paid plan. Keepalive queries a real, dedicated table (not just the API root, which Supabase's gateway rejects independent of the database being awake) using the project's own modern Publishable Key (sb_publishable_...), so a reported "success" reflects an actual database round-trip, not a false-positive gateway response. Mikoshi never requests, stores, or uses a legacy anon or service_role API key for this (or anything else) — if a project has never had a Publishable Key created, keepalive enable/keepalive test fail with a clear, actionable message telling you to create one in the Supabase dashboard, rather than silently using the older key type.
GitHub Actions secret naming: keepalive enable stores the Publishable Key in a repo secret named SUPABASE_PUBLISHABLE_KEY_<ref> — this is the canonical name for every newly-enabled project. If you enabled a project before this naming was introduced, it may still be using the older SUPABASE_ANON_KEY_<ref> name; that name is not a description of a legacy credential — it still only ever holds a modern Publishable Key. It is a deprecated compatibility alias with no current removal date: it will not be removed in a minor/patch release or silently migrated, and any future removal will go through an explicit major-version compatibility decision with a documented migration path. mikoshi supabase keepalive status will note if any of your enabled projects are using the older name and how to migrate (re-run keepalive enable <project>) whenever you're ready.
Model Providers
Mikoshi's agent (mikoshi run, MCP/ACP tool calls) supports four LLM providers: OpenAI, Anthropic, MiniMax, and Kimi (Moonshot). Configure a provider and API key via mikoshi settings or the /models command inside the interactive shell; keys are stored locally, per provider.
mikoshi models doctor # verify every configured model against its provider's real API
mikoshi models doctor openai # check just one provider
mikoshi models doctor --call # also make one minimal real request per model (uses a small amount of your quota)Without --call, models doctor checks account authentication and the provider's official model-list endpoint only — no spend, and it never runs automatically in CI. --call requires confirmation (or --yes) since it consumes real quota/credits on your account.
Only models that are actually reachable through Mikoshi's request path are offered: for example, OpenAI's Responses-API-only models (gpt-5.2-codex, gpt-5.2-pro) are intentionally not configured, since Mikoshi's chat client currently only implements the Chat Completions API (/v1/chat/completions). Support for those models is real future work, not something silently half-implemented.
Authentication
mikoshi login authenticates your NEET account (used for optional cloud features), via a browser-based OAuth flow with PKCE — it opens a sign-in page, you paste back the response, and Mikoshi exchanges it for a session token stored locally at ~/.mikoshi/auth.json with owner-only permissions (POSIX 0600, or an equivalent Windows ACL). mikoshi logout clears it.
This is separate from mikoshi supabase connect, which authorizes Mikoshi to access a Supabase project on your behalf — the two are independent credentials for independent services.
Troubleshooting
mikoshi doctoris the first stop for any install/index problem — it checks Node version, config, index health, dependency graph, embeddings, and staleness, and prints a concrete fix for anything wrong.- MCP tools not showing up in your editor? Run
mikoshi doctor— it detects whether an MCP config exists for your client and suggestsmikoshi initto generate one. If your client truly can't do tool calls, use evidence packs instead. - Model/API errors? Run
mikoshi models doctorto check whether the issue is your API key, the model mapping, or the provider's endpoint compatibility. - Supabase errors?
mikoshi supabase statusshows every connected organization and whether its token is currently valid;mikoshi supabase doctorruns a deeper connectivity check. - Corrupted or stale index?
mikoshi clear <path>removes the local index for that repo, thenmikoshi index <path>rebuilds it from scratch. A full re-index always recovers from a corrupted index store. - Fully offline? Set
MIKOSHI_OFFLINE=1after the embedding model has been cached once (mikoshi indexon first run downloads it); this skips any model-download network access thereafter.
Uninstalling
npm uninstall -g mikoshiMikoshi has no separate uninstall command. To also remove locally stored data (indexes, cached embeddings, auth session, Supabase connections):
rm -rf ~/.mikoshi # macOS/Linux
# or delete the %USERPROFILE%\.mikoshi folder on WindowsSee PRIVACY.md for exactly what's stored there and why.
How It Works
Source → AST Parser → Hierarchical Chunks (file/class/function/method)
→ Local ONNX Embeddings (all-MiniLM-L6-v2, no API key)
→ Dependency Graph (imports + call edges + symbol table)
Query → Query Understanding → Multi-Query Expansion
→ BM25 + Semantic Hybrid Search
→ 6-Factor Smart Ranking (semantic, structural, recency, frequency, type, task)
→ Reranking → Context Enrichment + Web Neighborhood
→ Token-Budget Compression → AI-Readable OutputEvery call edge carries a confidence score (high / medium / low) so the AI — and you — know what's verified vs. heuristic.
Graph correctness: call-edge resolution follows re-export/barrel chains and tsconfig/jsconfig path aliases, and uses receiver-type inference to disambiguate same-named methods on different classes. Measured at 100%/80%/80% recall (per-repo) with a 0% false-edge rate across a 3-repo, 61-task benchmark; see benchmarks/graph/ for methodology and CHANGELOG.md for full results and one disclosed known limitation (a low- vs. medium-confidence miss on a hard receiver-collision case).
Shadow detection (detectShadows) surfaces duplicate/shadowing definitions of a symbol — same-scope redefinitions vs. cross-file duplicates — with full disclosure of every location found, while excluding control-flow chunks, parent/child overlap, and dunder-convention methods by structure. Measured at 100% recall, 0% false-positive rate.
Bounded context expansion sources all cross-chunk data (types, callers, callees, tests) from one bounded graph-neighborhood traversal per expansion, instead of scanning the full corpus — measured at 97–99% lower scan cost than the previous full-scan approach while also achieving 100% completeness (not a cost/completeness tradeoff).
These three areas — graph correctness, shadow disclosure, and bounded expansion — are what this release's benchmarked numbers cover. Retrieval quality more broadly (e.g. confidence-tier calibration) is ongoing work, benchmarked separately.
Configuration
mikoshi settings # interactive config (shell, auto-updates, provider)
mikoshi login # optional — for cloud featuresEnvironment variables:
| Variable | Default | Description |
|---|---|---|
| MIKOSHI_INDEX_ROOT | ~/.mikoshi | Where indexes and local config are stored |
| MIKOSHI_EMBEDDINGS_PROVIDER | local | local (ONNX) or openai |
| MIKOSHI_EMBED_MODEL | all-MiniLM-L6-v2 | Embedding model |
| MIKOSHI_OFFLINE | unset | Skip embedding-model download; requires the model already cached |
| MIKOSHI_AUTO_UPDATES | unset (config default: on) | Set to 0 to disable the npm-registry update check |
Developer
npm install
npm test # runs all tests
mikoshi doctor . # validate install + index healthProvenance
See PROVENANCE.md for implementation provenance and design constraints.
