Code navigation toolkit for Claude Code, Codex CLI, and OpenCode on large C#, TypeScript/TSX, Kotlin, and Python codebases.
Most approaches to reducing token usage focus on compacting what the agent reads: tighter prompts, summarised context, leaner encoding. Context King addresses a different problem: the token cost of getting there. On a large codebase, navigating to the right method without guidance means scanning many wrong files before finding the right one, and that over-reading during navigation dominates the total cost.
The goal is to reach the right method body in as few steps as possible, spending tokens only on what is relevant. Context King indexes source files with lightweight lexical metadata and replaces broad file searches with a four-step navigation system:
file-first lexical retrieval -> optional metadata reranking -> scoped exploration -> live AST signature extraction -> targeted method extraction
A large solution or monorepo can have tens of thousands of C#, TypeScript/TSX, Kotlin, and Python files spread across thousands of folders. When Claude Code needs to find a specific piece of logic, the typical unguided path is:
- Grep or Glob across the whole repo, returning dozens of hits across unrelated modules.
- Scan candidate files for keywords. Many files touched, and grep misses cross-module naming/context clues.
- Eventually find the right method, but only after pulling a lot of surrounding noise into the context window.
On a 20,000-file codebase this is expensive. Unscoped searches return false positives from test projects, generated code, node_modules, and unrelated modules. Every wrong file wastes tokens and pushes relevant context out of the window.
Context King installs these commands into your AI CLI tool:
| Command | What it does |
|---|---|
ck find-files |
Lexical file search over path/file/type/method names |
ck get-keyword-map |
Returns a seed→related keyword map from indexed results to refine broad queries |
ck expand-folder |
Scoped folder browser: enumerates source files and extracts signatures, with an optional regex filter |
ck signatures |
Live AST extraction. Lists every method/property signature in a set of files |
ck get-method-source |
Reads one named member using AST and returns exact line and char spans |
ck get-type-source |
Reads one supported type declaration by name with exact line and char spans |
ck get-enum-members |
Lists enum members for a named enum without reading the full file |
ck read-full-file |
Reads one supported source file with a large-file guardrail and explicit override |
ck build-check |
Runs dotnet build -v q and prints compact diagnostics |
ck index |
Builds or refreshes the source-map index (runs automatically on first use) |
ck init |
Initializes Context King in a repository (see Installation) |
ck find-symbol |
Finds type or member declarations in C#, TypeScript/TSX, Kotlin, and Python files across a scoped path |
ck refs |
Finds textual references (call-sites) for a symbol across a scoped path |
ck recall |
Retrieves knowledge snippets for a folder or a cross-folder ranked query (step 2.5) |
ck learn |
Records a knowledge snippet to a session-specific .ck-knowledge/**/*.jsonl file |
ck forget |
Removes a stale snippet by ID |
The file-first flow in practice:
1. ck find-files --query "order reservation inventory allocation" --task "Find inventory reservation allocation logic." --top 20 --path src/
-> 0.71 src/Modules/Inventory/Reservations/InventoryReservationService.cs
0.69 src/Modules/Inventory/Allocations/AllocationService.cs
2. ck get-method-source src/Modules/Inventory/Reservations/InventoryReservationService.cs AllocateReservation
-> just that method body, with exact start_line / start_char / end_char
3. Edit
Fallback when file-first results are weak/noisy: ck get-keyword-map -> ck find-files -> ck expand-folder.
The biggest savings come during investigation: answering "where does X live?", tracing cross-module behaviour, scoping a refactor. A typical end-to-end task that mixes investigation and implementation saves around 30% in tokens overall.
| With Context King | Without Context King | |
|---|---|---|
.cs files read in full |
1 | 43 |
| Repo-wide Glob/Grep/Bash searches | 0 | 7 |
ck find-files calls |
1 | - |
ck signatures calls |
2 | - |
ck get-method-source calls |
3 | - |
| Total tool calls | 11 | 54 |
| New tokens processed | 21,283 | 97,937 |
| Ratio | 1x | 4.6x more |
The no-CK session delegated navigation to an Explore sub-agent, which internally read 43 full .cs files and accumulated 84,000 cache-creation tokens in the sub-agent alone. Delegating navigation to a sub-agent amplifies the token cost rather than reducing it.
| With Context King | Without Context King | |
|---|---|---|
.cs files read in full |
0 | 9 |
| Repo-wide Glob/Grep searches | 0 | 2 |
ck find-files calls |
2 | - |
ck signatures calls |
2 | - |
| Total tool calls | 5 | 20 |
| New tokens processed | 22,280 | 234,842 |
| Ratio | 1x | 10.5x more |
The CK session read zero .cs files in full. Two ck find-files passes identified the relevant files; two ck signatures passes confirmed member lists without opening any file body.
File-level lexical index. Context King indexes each supported source file (.cs, .ts, .tsx, .kt, .kts, .py) as one row. A 20,000-file repo typically produces 15,000-20,000 indexed files. The index is incremental and updates only changed files.
Each indexed file stores normalized tokens from:
- Full relative path segments
- File name tokens
- Type names and method names/signatures extracted from source
PascalCase and camelCase identifiers are split at case boundaries. Symbol names are preserved in normalized token form so queries can match operation names, DTO/type names, and domain terms.
Scoring. ck find-files uses weighted lexical scoring across path/file/type/method fields, with term-coverage boosts and recency/scope heuristics. --must is a soft boost, not a hard filter, so the command can still return best-effort results when exact must terms are missing.
ck find-files uses lexical search as its first-stage retriever. Internally, CK may overfetch lexical candidates and rerank that small candidate set using compact metadata cards built from path, type, and member names.
This avoids maintaining a repository-wide semantic index while improving result precision for ambiguous searches. No full source files are read during reranking, and candidate embeddings are not persisted.
Always pass --task to provide reranking context while keeping the main query lexical:
ck find-files "adyen terminal refund retry" --task "Find retry handling for terminal refunds after transient provider errors. Ignore card refunds."Staleness detection. The index is keyed by file path + content fingerprint. A file row is refreshed when that file changes (add, remove, rename, content edit). Untracked new files and working-tree deletions are included, not just committed state.
Navigation solves one problem: getting to the right code fast. But it doesn't help an agent understand what it finds. Every session starts from zero — no knowledge of why the code is structured the way it is, which modules are tricky, what was tried and rejected, what a domain concept actually means, or how two modules interact above the method level. An agent that can find the right file quickly is still slower than one that also knows what the team spent three weeks debugging in it.
CK Brain is the knowledge layer on top of the navigation layer. Where ck find-files answers "where is the code?", CK Brain answers "what do we know about that code?" — domain rules, architectural decisions, gotchas, cross-module relationships, anything a senior developer would tell a new joiner.
How knowledge accumulates. The brain starts empty and grows automatically. A hook runs after every agent turn and scans the new portion of the session transcript for code exploration signals: use of ck find-files, ck signatures, or ck get-method-source are strong signals; reading supported source files, writing code, and running ck recall are moderate ones. Large investigation/edit windows can also trigger capture even without a strong signal. When enough signals are present, the hook injects a knowledge-capture prompt asking the agent to reflect on what it just discovered. The agent then calls ck learn to record the insight as a short snippet (2-4 sentences). CK writes new snippets to session-specific JSONL files under .ck-knowledge/sessions/, while recall reads every .jsonl file under .ck-knowledge/ into one in-memory knowledge set. This keeps knowledge git-tracked and shared without forcing every session to append to the same file. Snippets are stored with schema-aware lifecycle metadata, and recall can lazily backfill older entries without breaking readability. Turns that involve no meaningful code exploration never trigger the prompt. No manual curation required.
After a dozen sessions on an active module, the brain holds the kind of contextual depth that normally takes months to accumulate, and it's available to every agent on every machine from the moment they pull the repo.
How knowledge is retrieved. Knowledge retrieval is step 2.5 in the navigation protocol: once an agent has confirmed the folder it will work in (via ck expand-folder or ck signatures), it runs ck recall --folder <path> before reading any method body. This returns all snippets associated with that folder, newest first. During recall, CK computes a folder-level semantic scope checksum/hash from current source content and compares it with each snippet's stored fingerprint to evaluate lifecycle status. Entries are flagged as fresh, review_needed, or unknown, with confidence metadata, so teams can rate reliability and focus review effort where code drift occurred. Only the snippets for the folder being worked in are surfaced, so sessions touching unrelated code pay no token cost for knowledge they won't use.
For questions that span multiple folders, ck recall --query "<text>" performs ranked lexical retrieval across all snippets. This is supplementary and optional; the folder-scoped recall at step 2.5 covers most cases.
Token cost. Unlike the navigation commands, brain recall does add tokens to the context window — the snippets are injected as text. This is intentional: the value is precisely that the agent reads and reasons over that knowledge. Snippets are kept short (2-4 sentences) to keep the cost low. Sessions working on code with no associated knowledge pay nothing.
Opt-out. Set "brain": false in .ck.json to disable all brain commands (recall, learn, forget) for a repository. The post-session hook also respects this flag. All three commands exit silently, so the navigation workflow continues without changes.
- .NET 10 runtime (required for Roslyn C# analysis; TypeScript/TSX, Kotlin, and Python analysis use bundled tree-sitter support)
- At least one of: Claude Code, Codex CLI, or OpenCode
- Bash (Mac/Linux) or PowerShell 7+ (Windows)
- Git
Mac / Linux:
curl -fsSL https://github.com/Fredrik-C/ContextKing/releases/latest/download/install-global.sh | bashWindows:
irm https://github.com/Fredrik-C/ContextKing/releases/latest/download/install-global.ps1 | iexThis installs the ck binary to ~/.ck/bin/ and registers skills, hooks, and rules in ~/.claude/, ~/.codex/, ~/.config/opencode/, and ~/.agents/. After install, start a new shell or add ~/.ck/bin to your PATH manually.
Windows equivalents use %USERPROFILE% (for example %USERPROFILE%\\.ck\\bin\\ck.exe, %USERPROFILE%\\.claude\\, %USERPROFILE%\\.codex\\, %USERPROFILE%\\.agents\\) and %APPDATA%\\opencode\\.
From the root of any repo you want to use Context King in:
ck initThis creates .ck.json (with a minimum version requirement and default findFiles reranking settings), adds .ck-index/ to .gitignore, and creates the .ck-knowledge/ directory. Commit these files to share the setup with your team.
If the repo was previously set up with the old per-repo deploy.sh, run:
ck init --migrateThis detects and removes per-repo artifacts (binary, hook scripts, rule file) and cleans up the relative-path hook registrations and CK allowedTools entries from .claude/settings.json, leaving all non-CK content intact.
Global (from install-global.sh):
~/.ck/
bin/ck <- ck binary
~/.claude/
skills/ck*/ <- skill docs + binary wrapper
hooks/ck-*.sh <- PreToolUse guards
rules/ck-code-search-protocol.md <- always-apply rule
settings.json <- hook + permission registrations (merged)
~/.codex/
skills/ck*/ <- Codex skills
hooks/ck-*.sh <- Codex guard scripts
hooks.json <- Codex hook registrations (merged)
ck-code-search-protocol.md <- Codex protocol reference
~/.config/opencode/
skills/ck*/ <- OpenCode skills
plugins/ck-guards.ts <- hook plugin
~/.agents/skills/ck*/ <- generic agent skills
Windows equivalents:
%USERPROFILE%\.ck\
%USERPROFILE%\.claude\
%USERPROFILE%\.codex\
%APPDATA%\opencode\
%USERPROFILE%\.agents\
Per-repo (from ck init):
<repo-root>/
.ck.json <- version requirement (commit this)
.ck-knowledge/ <- knowledge base directory (commit this)
.ck-index/ <- lexical source index (gitignored, built on first use)
To reverse the global install, run the uninstaller the same way you installed:
Mac / Linux:
curl -fsSL https://github.com/Fredrik-C/ContextKing/releases/latest/download/uninstall-global.sh | bashWindows:
irm https://github.com/Fredrik-C/ContextKing/releases/latest/download/uninstall-global.ps1 | iexThis removes the ~/.ck tree (binary + model), strips ~/.ck/bin from your PATH, deletes the CK skills/hooks/rules from ~/.claude/, ~/.codex/, ~/.config/opencode/, and ~/.agents/, and removes only the CK entries from each client's config files (settings.json, hooks.json, opencode.json(c), Codex AGENTS.md / config.toml) — all other content is left intact.
To preview without changing anything, or to use the skip flags, download and run the script directly:
curl -fsSL https://github.com/Fredrik-C/ContextKing/releases/latest/download/uninstall-global.sh -o uninstall-global.sh
bash uninstall-global.sh --dry-runSupported flags mirror the installer: --dry-run (PowerShell: -DryRun), --no-path, --no-claude, --no-codex, --no-opencode, --no-agents, and the --*-home overrides.
Per-repo files created by ck init are not removed (they may be git-tracked). To clean a repository manually:
rm -rf .ck-index .ck-knowledge .ck.jsonContext King enforces the navigation workflow through rules, hooks, and skill instructions. The mechanism varies by CLI tool.
Always-apply rule (~/.claude/rules/ck-code-search-protocol.md, Windows: %USERPROFILE%\\.claude\\rules\\ck-code-search-protocol.md), loaded automatically in every session. Instructs the agent to run ck find-files first for source discovery, then use folder-scope workflow (get-keyword-map/find-files/expand-folder) only as fallback.
PreToolUse hooks fire before every tool call:
ck-bash-guard: blocks pipingck find-filesoutput through head/grep/tail (which destroys ranking signals), and blocks runninggrepon known source files whenck get-method-sourceshould be used instead.agent-usage-guard: injects the full CK code search protocol into every sub-agent's context viaadditionalContext, so sub-agents use CK tools natively instead of broad searches.
The full code search protocol is deployed to ~/.codex/ck-code-search-protocol.md (Windows: %USERPROFILE%\\.codex\\ck-code-search-protocol.md). The inline 4-step workflow is injected into ~/.codex/AGENTS.md (Windows: %USERPROFILE%\\.codex\\AGENTS.md) so the agent sees it on every session without needing to follow a pointer. The project_doc_fallback_filenames entry in ~/.codex/config.toml (Windows: %USERPROFILE%\\.codex\\config.toml) ensures per-repo ck-code-search-protocol.md files are auto-loaded alongside AGENTS.md traversal.
Global install registers Codex hooks in ~/.codex/hooks.json (Windows: %USERPROFILE%\\.codex\\hooks.json):
SessionStart->ck-update-checkPreToolUse(Bash) ->ck-bash-guardPostToolUse(Bash) ->ck-scope-hintStop->ck-postsession(CK Brain capture prompt)
Codex hook interception is still partial by tool surface and version. For that reason, CK still keeps protocol guidance in AGENTS/rules and uses ck read-full-file as the explicit full-file path when targeted reads are insufficient.
A TypeScript plugin (ck-guards.ts) is installed to ~/.config/opencode/plugins/ (Windows: %APPDATA%\\opencode\\plugins\\) and auto-loaded on session start. It enforces the protocol through both reactive guards and proactive hooks:
Reactive guards (fire before tool execution):
- Broad
globorgrepon source files (3 or fewer path segments): redirects tock find-filesfirst (withfind-filesfallback guidance when needed). bash caton source files: redirects tock get-method-sourceorck read-full-file.bash grepon source files: redirects to the three-step protocol.bashpipe onck find-filesoutput: blocks to preserve ranking signals and structure.
Proactive hooks (shape the agent's behaviour before guards are needed):
tool.definition: rewrites the descriptions ofgrepandglobthat the model sees, prepending the CK protocol mandate so the model prefers CK tools without being blocked first.experimental.chat.system.transform: injects the full CK protocol at the top of the system prompt on every turn, ahead of all other instructions.session.idleevent: if CK tools were used during a turn butck learnwas not called, writes a marker file. The next turn's system-prompt injection reads the marker and adds a reminder to runck learnbefore finishing.
ck init [--force] [--quiet] [--migrate]
Initializes Context King in the current git repository. Creates .ck.json with default findFiles reranking settings, adds .ck-index/ to .gitignore, and creates .ck-knowledge/. Use --migrate to remove legacy per-repo deploy artifacts and clean up settings.json.
ck find-files "<query>" --task <text> [--must <text>] [--top <n>] [--min-score <f>] [--path <folder-or-file>] [--explain]
Lexical file retrieval using weighted term matching across path, file, type, and method fields.
--must applies soft score boosts (it does not hard-filter to zero results).
--task is required and provides extra intent for candidate reranking; the lexical query still controls first-stage retrieval.
Output rows are <score>\t<relative-file-path>, optionally with compact score components when --explain is set.
Write --query as lexical code terms (path/file/type/member words), not natural-language questions.
Example: use terminal refund adyen async instead of where is the refund logic implemented.
Use this as the default discovery step.
ck get-keyword-map --query "<multi-keyword description>" [--must <text>] [--top <n>] [--per-keyword <n>] [--repo <path>] [--verbose]
Builds a keyword neighborhood map from the top file-first results for your query. Output includes matched query keywords, unmatched query keywords, global keyword hints, and a per-seed map (seed: related1, related2, ...). Default --per-keyword is 12 with adaptive quality cut-off (returns fewer when signal is weak). The command also persists a session keyword atlas in .ck-index/session-keyword-atlas.json, which is reused by later refinements until direction shifts.
Use the same lexical query style as find-files: path/file/type/member words, not natural-language questions.
ck expand-folder [--pattern <regex>] [--limit <n>] [--offset <n>] [--max-signatures <n>] [--all] <folder> [--repo <path>]
Enumerates every supported source file under <folder> recursively, extracts signatures, and filters to only files with a matching signature when --pattern is given. \| in the pattern is normalised to | automatically. Results are paged (--limit, --offset) and include pagination metadata on stderr. --max-signatures limits signatures printed per file (0 = unlimited). Broad matches return a paged shortlist with narrowing hints; use --all only when broad output is intentional.
ck signatures <file> [file2 ...]
ck signatures [--all] <folder>
Supports .cs, .ts, .tsx, .kt, .kts, and .py files. Output: <filepath>:<line>\t<containingType>\t<memberName>\t<signature>, one line per member. Always live, no index required. For large folders, adaptive relevance ranking is applied unless --all is passed.
ck get-method-source <file> <member-name> [--type <TypeName>] [--mode <mode>]
Supports .cs, .ts, .tsx, .kt, .kts, and .py files. Modes: signature_plus_body (default), signature_only, body_only, body_without_comments. Output: JSON array with file, member_name, containing_type, signature, mode, start_line, end_line, start_char, end_char, and content.
ck get-type-source <file> <TypeName> [--kind <class|interface|struct|record|enum|type_alias>]
Supports .cs, .ts, .tsx, .kt, .kts, and .py files. Output: JSON array with file, type_name, kind, start_line, end_line, start_char, end_char, and content.
ck get-enum-members <file> <EnumName>
Supports .cs, .ts, .tsx, .kt, .kts, and .py files. Output: JSON object with file, enum_name, start_line, end_line, and members.
ck read-full-file <file> [--max-lines <n>] [--allow-large]
Reads one supported source file. By default it refuses files above 300 lines and points to targeted commands (get-method-source, get-type-source, get-usings, etc). If full context is truly required, rerun with --allow-large.
ck find-symbol <symbol> [--path <folder-or-file>] [--kind type|member] [--top <n>]
ck find-symbol <symbol> <folder-or-file> [more paths...]
Finds type or member declarations in C#, TypeScript/TSX, Kotlin, and Python files. Uses --path roots when provided; otherwise falls back to the latest CK boundaries. Output: <score>\t<file:line>\t<kind>\t<symbol>\t<container>\t<signature>. Works on live disk content (uncommitted edits included).
ck refs <symbol> [--path <folder-or-file>] [--top <n>] [--ignore-case]
ck refs <symbol> <folder-or-file> [more paths...]
Finds textual references (call-sites) for a symbol in C#, TypeScript/TSX, Kotlin, and Python files. Uses identifier-boundary matching on the symbol's right-most segment. Uses --path roots when provided; otherwise falls back to the latest CK boundaries. Output: <score>\t<file:line>\t<line snippet>. Works on live disk content.
ck build-check <project.csproj> [--max <n>] [--configuration <Debug|Release>] [--framework <tfm>] [--runtime <rid>] [--no-restore]
Runs dotnet build -v q and prints compact error/warning summaries.
ck index [--status] [--force] [--repo <path>]
--status prints fresh, stale, or missing. Normally not needed since ck find-files triggers an incremental update automatically.
ck recall --folder <path> [--repo <path>]
ck recall --query <text> [--top <n>] [--repo <path>]
Retrieves knowledge snippets from all .jsonl files under .ck-knowledge/. --folder returns all snippets for a specific folder (no index), runs lifecycle validation, and prints status (fresh, review_needed, unknown) based on folder-scope hash comparison — this is step 2.5 in the navigation protocol. --query does a ranked cross-folder lookup and requires the knowledge index (auto-built). Silent when no snippets exist or when "brain": false is set in .ck.json.
ck learn --content "<text>" [--folders <f1,f2,...>] [--tags <t1,t2,...>] [--repo <path>]
Appends a snippet to a session-specific JSONL file under .ck-knowledge/sessions/. Keep content to 2-4 sentences of non-obvious insight: domain rules, architectural decisions and their reasons, gotchas, cross-module relationships. Omit anything derivable by reading the code. Silent when "brain": false is set in .ck.json.
ck forget --id <uuid> [--repo <path>]
Removes a stale snippet by ID. Use when code described by a snippet has been refactored or the information is no longer accurate. Get the ID from ck recall output. Silent when "brain": false is set.
Requires .NET 10 SDK.
dotnet build src/ContextKing.Cli/ContextKing.Cli.csproj -v q
dotnet publish src/ContextKing.Cli/ContextKing.Cli.csproj \
-c Release -r osx-arm64 -p:PublishSingleFile=true \
-o skills/ck -v q
mv skills/ck/ContextKing.Cli skills/ck/ck-osx-arm64
chmod +x skills/ck/ck-osx-arm64 skills/ck/ckValid RIDs: osx-arm64, osx-x64, linux-x64, linux-arm64, win-x64.
Pre-built binaries for all platforms are published as GitHub Release assets and rebuilt automatically by GitHub Actions on each tagged release.
To install a local build globally (useful during development):
bash scripts/install-global.sh # Mac / Linux
pwsh scripts/install-global.ps1 # WindowsTo force-install a locally published dev binary (recommended for local testing):
dotnet publish src/ContextKing.Cli/ContextKing.Cli.csproj \
-c Release -r osx-arm64 --self-contained false -v q \
-o artifacts/publish/local
bash scripts/install-local-dev.shinstall-local-dev.sh first runs install-global.sh (baseline release assets), then force-overrides with your local binary. The script prints a version summary:
- baseline after
install-global.sh - local dev binary source
- final installed version
Use the release helper script to create/push a tag, wait for the GitHub release workflow, and then update release notes after release creation:
bash scripts/release.sh --tag v1.8.0 --notes-file RELEASE_NOTES_v1.8.0.mdNotes:
- Working tree must be clean before running.
--tagcan be omitted to auto-bump the latest patch version.- Release notes are intentionally updated after the release object is created.
Context King is licensed under CC BY-NC-SA 4.0. You are free to use it in any organisation, copy it, and build on it, as long as you attribute the original source and share modifications under the same terms. Selling or commercialising the tool itself is not permitted. See LICENSE for the full terms.