jdx command reference
The user-facing catalogue. Every shipped flag must appear in jdx <command> --help,
here, and in docs/PROPOSAL.md Appendix B. (Moved out of README.md to keep it a
hook, demo, install, quickstart, and links.)
jdx <command> --help documents each command; jdx help --agent prints the compact
agent block. Every query command accepts --json (same information, structured envelope)
and --no-daemon (force in-process even when the daemon is up).
Read: declaration, members, structure#
| Command | IDE equivalent | Key flags |
|---|---|---|
jdx show <type> |
Go to declaration | classpath flags only |
jdx members <type> |
Code completion after . |
--declared / --inherited (default), --kind all|method|field|ctor|property, --access public|protected|package|private|all, --static / --instance, --from <supertype>, --grep <regex>, --include-synthetic, --limit (50), --with-doc, --brief, --max-lines, --sort kind|name|declaring, --view kotlin|jvm |
jdx outline <type> |
File structure (Ctrl+F12) |
Same filters as members --declared (never inherited): --kind, --access, --static / --instance, --grep, --include-synthetic, --limit, --with-doc, --brief, --max-lines, --sort, --view |
jdx signature <member> |
Parameter info (Ctrl+P) |
--include-synthetic, --view kotlin|jvm, --limit (50) |
jdx doc <symbol> |
Quick documentation (Ctrl+Q) |
--inherited (default) / --no-inherited, --raw, --max-lines (200). Undocumented members fall back to the nearest documenting supertype. |
jdx body <member> |
Open the method | --context N, --line-numbers, --max-lines (200), --engine vineflower|javap, --with-doc, --with-signature |
jdx source <type> |
Open the file / decompile | --lines A:B, --around '<type>#<member>' + --context N, --line-numbers, --max-lines (200), --engine vineflower|javap |
body/source ladder: paired sources → Vineflower reconstruction → javap disassembly →
signatures → not found. --engine vineflower forces reconstruction even when sources are
paired; --engine javap shows raw bytecode. Decompiled output is always labelled
⚠ reconstructed with the engine named.
Search and browse#
| Command | IDE equivalent | Key flags |
|---|---|---|
jdx search <pattern> |
Search everywhere (Shift Shift) |
--kind all|type|class|interface|enum|record|annotation|object|companion|method|field|package|module, --regex, --fuzzy (Levenshtein retry on miss), --in <artifact-glob>, --package <glob>, --limit (50). Bare words match case-insensitively or as camel humps (HMap finds HashMap). |
jdx resolve <name> |
"What is this symbol?" | --limit (50). Several candidates are success (exit 0); none is exit 1 with did-you-mean. |
jdx ls [package-glob] |
External library browser (packages/types) | --limit (50). A glob lists packages with type counts; an exact package lists its types. |
jdx tree [artifact-glob] |
External library browser (artifacts) | --depth (8; 0 = top segments), --counts, --limit (50) |
Graph: usages, hierarchy, calls, samples#
| Command | IDE equivalent | Key flags |
|---|---|---|
jdx usages <symbol> |
Find usages (Alt+F7) |
--kind all|call|read|write|ref|new|throw|annotation (impl/override redirect to hierarchy/implementors; --context redirects to samples), --in / --exclude <artifact-glob>, --limit (50), --src <dir> (repeatable source-dir roots). new = constructor call sites; throw = methods declaring the type in throws (declaration-level, not ATHROW throw sites); annotation = annotated classes/members. Source-dir hits are textual mentions (ref only). |
jdx hierarchy <type> |
Type hierarchy (Ctrl+H) |
--up / --down (default both), --direct, --depth N, --in / --exclude, --limit (50). Member refs exit 3. |
jdx implementors <type> |
Who implements this? | Alias for hierarchy --down: --direct, --depth N, --in / --exclude, --limit (50) |
jdx callers <member> |
Call hierarchy in (Ctrl+Alt+H) |
--depth N (default 1), --in / --exclude, --limit (50). Methods + constructors only; type/field refs exit 3. Cycle-safe (…(cycle)). Exact name+descriptor matching — not override-aware (see limitations). |
jdx calls <member> |
Call hierarchy out | Same as callers, plus --external-only (hide callees in the method's own artifact — dependency view) |
jdx samples <symbol> |
(no IDE equivalent) | --limit (default 3), --in / --exclude, --prefer-sources (rank snippet-capable callers first). Ranked by exemplariness: non-test before test, non-generated before generated, fuller overloads first. Snippets capped at 15 lines. Type refs match calls to any member; field refs exit 3. |
Upgrades: API diff#
| Command | IDE equivalent | Key flags |
|---|---|---|
jdx diff <old> <new> |
"What did this upgrade break?" | --visibility public|all (default public: public + protected declarations; all = every declared member, for refactors and mod/mixin work), --include-synthetic, --severity all|suspicious|breaking (cumulative), --fail-on none|breaking|any, --limit (200), --fetch, --repo, --json. Each of the two specs is a jar, class directory, glob, or group:artifact:version. Reads bytecode only — no sources, no decompilation, no classpath. Every finding names one rule (MEMBER_REMOVED, RETURN_TYPE_CHANGED, KOTLIN_SUSPEND_CHANGED, …) at breaking / suspicious / info, and every line is a canonical ref. The full rule set is docs/PROPOSAL.md §7.7. |
jdx diff gson-2.11.0.jar gson-2.14.0.jar --fail-on breaking
api diff gson-2.11.0.jar -> gson-2.14.0.jar (public surface)
info FIELD_CONSTANT_VALUE_CHANGED com.google.gson.internal.GsonBuildConfig#VERSION: "2.11.0" -> "2.14.0"
0 breaking · 0 suspicious · 17 informational · 2 types added · 0 types removed
fail-on breaking: no breaking changes (exit 0)
source: gson-2.11.0.jar (bytecode)
source: gson-2.14.0.jar (bytecode)
next: jdx members com.google.gson.internal.GsonBuildConfigdiff exits 0 whenever the comparison ran, whatever it found — the answer is in
the report, not in the process status. --fail-on breaking (or any) is the CI gate
and is the only way a successful diff exits non-zero (see the exit-code table). It needs
no workspace, no --jars and no --no-daemon, and is answered by the MCP tool
jdx_diff and GET /v1/diff?query=<old>&new=<new> with identical bytes.
Environment and maintenance#
| Command | Purpose | Key flags / notes |
|---|---|---|
jdx version |
Print the version | --json for the envelope form |
jdx upgrade |
Self-update from GitHub Releases (release installs only) | --version <tag> (default latest), --check (report only), --repo OWNER/NAME, --json. Exits 1 on unknown tag, 3 on non-release installs, 5 on download failure |
jdx doctor |
Self-diagnosis | One ok/warn/fail row per check: JDK, jrt:/, javap, JDK sources, cache, config, index DB, Kotlin sidecar, AppCDS archive (present/absent/stale via size + mtime vs the fat jar; missing/stale degrades via -Xshare:auto, never fails), daemon (probed live: running vs stale), workspace, agent setup (OpenCode project/system wiring + detected v1/v2 line via opencode --version; Claude Code .mcp.json/~/.claude.json wiring + claude --version presence; Cursor .cursor/mcp.json/~/.cursor/mcp.json wiring + cursor-agent --version presence; Kilo Code project/system wiring; Cline global cline_mcp_settings.json wiring, both scopes; Codex CLI .codex/config.toml/~/.codex/config.toml wiring + codex --version presence; GitHub Copilot CLI .mcp.json/~/.copilot/mcp-config.json wiring + copilot --version presence; Antigravity .agents/mcp_config.json/~/.gemini/config/mcp_config.json wiring + agy --version presence). Exits 6 if any check fails. |
jdx setup --agent opencode|claude-code|cursor|kilo|cline|codex|copilot|antigravity --scope project|system |
Wire jdx into an agent | OpenCode: writes the jdx mcp MCP entries into opencode.json/opencode.jsonc (project checkout or ~/.config/opencode): both the v1 entry (mcp.jdx) and the v2 entry (mcp.servers.jdx, enabled → disabled) so either OpenCode line picks it up (v1 support is deprecated, slated for removal). Claude Code: writes the mcpServers.jdx entry ({"command": "jdx", "args": ["mcp"]}, the claude mcp add jdx -- jdx mcp equivalent) into .mcp.json (project checkout) or ~/.claude.json (system). Cursor: writes the same mcpServers.jdx shape ({"command": "jdx", "args": ["mcp"]}, recognised by agent mcp list in cursor-agent 2026.09.26-dd393fe) into .cursor/mcp.json (project checkout) or ~/.cursor/mcp.json (system). Kilo Code (an OpenCode fork sharing the mcp map shape): writes the single mcp.jdx entry into kilo.json/kilo.jsonc (project root or .kilo/ — the .kilo/ variant wins when both exist — or ~/.config/kilo). Cline: writes the single mcpServers.jdx transport entry ({"transport": {"type": "stdio", "command": "jdx", "args": ["mcp"]}}, the cline mcp add jdx -- jdx mcp equivalent) into the single global ~/.cline/data/settings/cline_mcp_settings.json for either scope (verified against cline 3.0.65 + extension 4.1.21 — Cline keeps no project-level MCP file). Codex CLI: writes the [mcp_servers.jdx] table (command = "jdx", args = ["mcp"], the codex mcp add jdx -- jdx mcp equivalent) into .codex/config.toml (project checkout, trusted projects) or ~/.codex/config.toml (system, $CODEX_HOME honoured). GitHub Copilot CLI: writes the mcpServers.jdx entry ({"type": "local", "command": "jdx", "args": ["mcp"]}, the copilot mcp add jdx -- jdx mcp equivalent, verified against GitHub Copilot CLI 1.0.88) into .mcp.json (project checkout — the nearest one walking up, .github/mcp.json as fallback — trusted directories) or ~/.copilot/mcp-config.json (system, $COPILOT_HOME honoured). Antigravity: writes the mcpServers.jdx entry ({"command": "jdx", "args": ["mcp"]}, the agy mcp add jdx -- jdx mcp equivalent, verified against agy 1.3.0) into .agents/mcp_config.json (project checkout — the nearest one walking up) or ~/.gemini/config/mcp_config.json (system). Reports the detected line. Merges, never clobbers; --check reports without writing (exit 1 when absent); --remove uninstalls cleanly; re-runs are no-ops. Restart the agent after changing config (it loads once at startup). |
jdx ws create|list|info|remove|use|add |
Project & library configuration | create <name> --jars … --src … --coord … --repo … [--jdk|--no-jdk]; add <name> <root>; use <name> [--clear] sets the default; list / info <name> / remove <name> |
jdx cache info|gc|clear |
Index and cache maintenance | info (DB location, size, schema, counts); gc [--dry-run] [--cache-dir …] (evicts unreferenced + stale artifacts + orphan daemon logs); clear (wipes regenerable cache) |
jdx kotlin install |
Fetch the Kotlin PSI sidecar | --repo … (repeatable), --force (re-download). 7 jars, SHA-1 verified, into <cache-dir>/kotlin/ (~/.cache/jdx/kotlin/ on Linux; per-OS defaults in docs/PROPOSAL.md §17.1); present jars are skipped, re-runs resume. |
jdx help [--agent] [--json] |
Cheat sheet | --agent prints the paste-ready agent block |
jdx bench |
Benchmark the read path | --iterations N (default 3, median reported), classpath flags. Fixed load/show/members/search/hierarchy workload with §15 advisory targets; always exits 0 on success. Falls back to the local minecraft-client.jar when no roots are given. |
Serving: daemon, MCP, HTTP, batch#
| Command | Purpose | Notes |
|---|---|---|
jdx daemon start|stop|status|restart |
Warm background JVM | Per-workspace unix socket under the OS runtime dir ($XDG_RUNTIME_DIR/jdx/<hash>-v1.sock on Linux; macOS $TMPDIR/jdx-$UID, Windows %LOCALAPPDATA%/jdx/run — full table in docs/PROPOSAL.md §17.1; a missing XDG_RUNTIME_DIR falls back, never exit 3); over-long socket paths exit 3 with the JDX_RUNTIME_DIR hint (104 B macOS / 108 B elsewhere); concurrent start fails fast on the socket lock; stop never kills a reused pid; --idle 5m default (0 disables); start is idempotent. status: uptime, memory, query count. run (foreground) is the internal spawn target. |
jdx mcp [-w name] |
MCP stdio server | One typed jdx_* tool per query (21 tools) with generated schemas; per-call workspace override; answers byte-identical to --json. |
jdx serve [-w name] [--port 7070] [--bind 127.0.0.1] |
Local HTTP/JSON API | GET /v1/<command>?query=…&<param>=…, POST /v1/batch (NDJSON), GET /v1/health. Localhost by default; blocks until interrupted. Bodies byte-identical to --json. |
jdx batch |
Many queries, one process | NDJSON RpcRequest lines on stdin ({"command":"members","query":"…","params":{…}}), one envelope per line on stdout; exit code is the max query exit code. Roots resolved once. --json accepted and ignored (output is always envelopes). |
Classpath flags (every query command)#
--jars <jar|dir|glob> (repeatable, merged in front of the workspace) ·
--coord group:artifact:version (repeatable; local ~/.gradle/caches + ~/.m2 first) ·
--repo <url> (repeatable Maven mirror, tried before Central) ·
--fetch (allow downloads incl. -sources.jar, checksum-verified into <cache-dir>/m2/ (~/.cache/jdx/m2/ on Linux)) ·
--no-jdk (exclude the running JDK stdlib, included by default via jrt:/ + src.zip) ·
-w/--workspace <name> (also JDX_WORKSPACE env or jdx ws use default; Gradle/Maven
project roots auto-discover from the working directory) ·
--src <dir> (only usages, batch, bench, and ws create: source dirs scanned textually).
Global output flags: --json (accepted before or after the subcommand, e.g.
jdx --json show …), --no-color (piped output is always plain),
--no-daemon (force in-process). Warm (daemon) text is always plain; --json bytes are
identical cold and warm.
Exit codes and symbol references#
| Code | Meaning |
|---|---|
0 |
Success, results found |
1 |
Valid query, no results |
2 |
Ambiguous reference — candidates printed, retry with one |
3 |
Usage / argument error |
4 |
No index or workspace resolved for this query |
5 |
Artifact read error (corrupt jar, unreadable file) |
6 |
Internal error |
The one exception is jdx diff's --fail-on breaking\|any gate, which exits 1 when it
trips: a successful comparison otherwise always exits 0, and the verdict is in the
envelope as result.gate too.
References are Javadoc style — com.example.Outer, com.example.Outer#method(Type),
short Outer#method (resolved, or exit 2 with candidates). Always quote the ref:
# and ( are shell-hostile. :: and . are accepted in place of #.
Constructors are <init>, static initialisers <clinit>.
Every --json answer uses one envelope:
{"jdx":1, "ok":…, "command":…, "query":…, "result":…, "truncated":…, "warnings":…, "provenance":…}.
Warnings carry stable codes (DUPLICATE_FQN, CORRUPT_CLASS, SOURCES_VERSION_MISMATCH, …);
provenance names the artifact, the source (sources / bytecode / decompiled + engine), and
the file:lines.
Kotlin note#
Kotlin signatures come from @Metadata (suspend, properties, default args, @JvmName);
Kotlin member bodies and KDoc come from .kt sources through a side-loaded
kotlin-compiler-embeddable (never on the compile classpath, never in the fat jar).
Without the sidecar, body/source/doc over .kt-only roots degrade to
decompile/javap — they emit something and say what it is, never an error.
Run jdx kotlin install to fetch the sidecar set (SHA-1 checked) from Maven Central;
jdx doctor reports its status. File facades stay JVM-projected and nullability is not
rendered (see limitations).