1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
use clap::{Parser, Subcommand};
use std::path::PathBuf;
#[derive(Parser, Debug)]
#[command(
name = "codebase-recall",
version,
about = "CLI codebase context dumper for LLMs and code relation grapher",
propagate_version = true
)]
pub struct Cli {
#[command(subcommand)]
pub command: Command,
}
#[derive(Subcommand, Debug)]
pub enum Command {
/// Dump the codebase into a single Markdown context file
Dump(DumpArgs),
/// Create .code-rcl/ (graph cache DB + config) in the target project
Init(InitArgs),
/// Parse changed source files into the graph cache
Sync(SyncArgs),
/// Render a relation graph to a file (html, json, dot)
Graph(GraphArgs),
/// Serve the relation graph in the browser; the server exits when you close the tab
Serve(ServeArgs),
/// Analyze blast radius and downstream/upstream callers affected by modifying a symbol
Impact(ImpactArgs),
/// Generate an architecture outline and public API digest of the codebase
Digest(DigestArgs),
/// Run Model Context Protocol (MCP) server over stdio for AI agent integration
Mcp(McpArgs),
/// Self-install the AI agent skill and configure MCP servers (Antigravity/Gemini, Claude Code)
Setup(SetupArgs),
}
#[derive(Parser, Debug)]
#[command(
about = "Dump the codebase into a single Markdown context file",
after_help = "Examples:\n code-rcl dump\n code-rcl dump path/to/project -o my-context.md\n code-rcl dump -r handle_request --depth 2\n code-rcl dump --max-size-kb 100"
)]
pub struct DumpArgs {
/// Target project directory or root path to dump
#[arg(default_value = ".")]
pub path: PathBuf,
/// Output markdown file path stem or full filename
#[arg(short = 'o', long = "output", default_value = "codebase-context")]
pub output: PathBuf,
/// Skip source files larger than this many KB
#[arg(long, default_value_t = 50)]
pub max_size_kb: u64,
/// Focus on a symbol or file and dump only its connected neighborhood
#[arg(short = 'r', long = "relation")]
pub relation: Option<String>,
/// Hop depth for relation neighborhood extraction
#[arg(long, default_value_t = 2)]
pub depth: u32,
/// Skip auto-syncing changed files before dumping
#[arg(long)]
pub no_sync: bool,
}
#[derive(Parser, Debug)]
#[command(
about = "Create .code-rcl/ (graph cache DB + config) in the target project",
after_help = "Examples:\n code-rcl init\n code-rcl init --project path/to/project\n code-rcl init --force"
)]
pub struct InitArgs {
/// Project directory to initialize
#[arg(long, default_value = ".")]
pub project: PathBuf,
/// Overwrite an existing config.toml
#[arg(long)]
pub force: bool,
}
#[derive(Parser, Debug)]
#[command(
about = "Parse changed source files into the graph cache",
after_help = "Examples:\n code-rcl sync\n code-rcl sync --language rust,py\n code-rcl sync --precise\n code-rcl sync --precise --precise-full"
)]
pub struct SyncArgs {
/// Project directory to sync
#[arg(long, default_value = ".")]
pub project: PathBuf,
/// Skip source files larger than this many KB
#[arg(long, default_value_t = 512)]
pub max_file_kb: u64,
/// Restrict to a subset of languages (e.g. rust,js,py)
#[arg(long, value_delimiter = ',')]
pub language: Vec<String>,
#[command(flatten)]
pub precise: PreciseArgs,
}
/// Opt-in compiler-grade resolution, shared by `sync`, `graph`, `serve`, and `impact`.
#[derive(Parser, Debug, Clone)]
pub struct PreciseArgs {
/// Resolve references through the real language server for each language
/// (rust-analyzer, pyright, jdtls, kotlin-language-server, typescript-language-server) instead of
/// guessing from the AST. Needs those servers installed; any that are
/// missing are reported and their language keeps its heuristic edges.
#[arg(long)]
pub precise: bool,
/// Re-ask the language servers about every file, not just the ones with no
/// answer yet. Use after edits whose effects reach other files.
#[arg(long, requires = "precise")]
pub precise_full: bool,
/// Seconds to wait for a single language-server answer
#[arg(
long,
default_value_t = 15,
value_name = "SECONDS",
requires = "precise"
)]
pub precise_timeout: u64,
}
impl Default for PreciseArgs {
fn default() -> Self {
Self {
precise: false,
precise_full: false,
precise_timeout: 15,
}
}
}
/// Filters shared by `graph` and `serve`: they select which nodes and edges the
/// resolved [`crate::graph::CodeGraph`] ends up containing.
#[derive(Parser, Debug)]
pub struct GraphQuery {
/// Project directory to graph
#[arg(long, default_value = ".")]
pub project: PathBuf,
/// Graph scope: file, symbol, or both
#[arg(long, default_value = "both")]
pub scope: String,
/// Edge kinds to include, comma-separated: imports, calls, references, contains
/// (`references` is noisy on large graphs, so it is off by default)
#[arg(long, value_delimiter = ',', default_value = "imports,calls,contains")]
pub kinds: Vec<String>,
/// Only include files matching this glob
#[arg(long)]
pub path: Option<String>,
/// Restrict the graph to the neighborhood of this symbol name
#[arg(long)]
pub focus: Option<String>,
/// BFS depth around --focus
#[arg(long, default_value_t = 2)]
pub depth: u32,
/// Drop edges below this confidence
#[arg(long, default_value_t = 0.4)]
pub min_confidence: f32,
/// Include edges to external modules (npm/pypi/crate deps)
#[arg(long)]
pub include_external: bool,
/// Cap on total graph nodes; past this the lowest-degree symbols are dropped
/// (files, dirs and externals are always kept). 0 disables the cap.
#[arg(long, default_value_t = 4000)]
pub max_nodes: usize,
/// Do not auto-sync changed files before rendering
#[arg(long)]
pub no_sync: bool,
#[command(flatten)]
pub precise: PreciseArgs,
}
#[derive(Parser, Debug)]
#[command(
about = "Render a relation graph to a file (html, json, dot)",
after_help = "Examples:\n code-rcl graph\n code-rcl graph --format json -o graph.json\n code-rcl graph --focus calculate_total --depth 2\n code-rcl graph --kinds calls --path \"src/**/*.rs\""
)]
pub struct GraphArgs {
#[command(flatten)]
pub query: GraphQuery,
/// Output formats, comma-separated: html, json, dot
#[arg(long, value_delimiter = ',', default_value = "html")]
pub format: Vec<String>,
/// Output file or path stem. Defaults to <project>/.code-ctx/code-graph.<ext>
#[arg(short = 'o', long)]
pub output: Option<PathBuf>,
}
#[derive(Parser, Debug)]
#[command(
about = "Serve the relation graph in the browser; the server exits when you close the tab",
after_help = "Examples:\n code-rcl serve\n code-rcl serve --port 8080 --no-open\n code-rcl serve --focus execute_query"
)]
pub struct ServeArgs {
#[command(flatten)]
pub query: GraphQuery,
/// Port to bind on 127.0.0.1 (0 picks a free port)
#[arg(long, default_value_t = 0)]
pub port: u16,
/// Do not open a browser window automatically
#[arg(long)]
pub no_open: bool,
}
#[derive(Parser, Debug)]
#[command(
about = "Analyze blast radius and downstream/upstream callers affected by modifying a symbol",
after_help = "Examples:\n code-rcl impact parse_config\n code-rcl impact execute_query --depth 10\n code-rcl impact validate_input --kinds calls\n code-rcl impact delete_user --json"
)]
pub struct ImpactArgs {
/// Target symbol name or identifier to analyze blast radius for
pub symbol: String,
/// Project directory to inspect
#[arg(long, default_value = ".")]
pub project: PathBuf,
/// Maximum upstream caller traversal depth
#[arg(long, default_value_t = 5)]
pub depth: u32,
/// Edge kinds to traverse in reverse, comma-separated (e.g. calls,imports)
#[arg(long, value_delimiter = ',', default_value = "calls,imports")]
pub kinds: Vec<String>,
/// Output result as JSON instead of ASCII tree
#[arg(long)]
pub json: bool,
/// Skip auto-syncing changed files before analyzing
#[arg(long)]
pub no_sync: bool,
#[command(flatten)]
pub precise: PreciseArgs,
}
#[derive(Parser, Debug)]
#[command(
about = "Generate an architecture outline and public API digest of the codebase",
after_help = "Examples:\n code-rcl digest\n code-rcl digest src/analysis\n code-rcl digest -o architecture.md\n code-rcl digest --all\n code-rcl digest --json"
)]
pub struct DigestArgs {
/// Target project directory or sub-path to outline [default: .]
#[arg(default_value = ".")]
pub path: PathBuf,
/// Explicit project root — overrides PATH's auto-detection (walking up
/// for .code-rcl/Cargo.toml/package.json/pyproject.toml). PATH, if also
/// given, is then read as a sub-path filter within this root instead of
/// a location to search from.
#[arg(long)]
pub project: Option<PathBuf>,
/// Output file path for the generated markdown digest
#[arg(short = 'o', long = "output")]
pub output: Option<PathBuf>,
/// Include private/internal functions and types (default: public only)
#[arg(long)]
pub all: bool,
/// Output result as structured JSON instead of Markdown
#[arg(long)]
pub json: bool,
/// Skip auto-syncing changed files before generating digest
#[arg(long)]
pub no_sync: bool,
}
#[derive(Parser, Debug, Clone)]
#[command(
about = "Run Model Context Protocol (MCP) server over stdio for AI agent integration",
after_help = "Examples:\n code-rcl mcp\n code-rcl mcp --project /path/to/repo"
)]
pub struct McpArgs {
/// Default project directory to analyze [default: .]
#[arg(long, default_value = ".")]
pub project: PathBuf,
}
#[derive(Parser, Debug, Clone)]
#[command(
about = "Self-install the AI agent skill and configure MCP servers (Antigravity/Gemini, Claude Code)",
after_help = "Examples:\n code-rcl setup\n code-rcl setup --workspace\n code-rcl setup --global\n code-rcl setup --target claude\n code-rcl setup --print-skill"
)]
pub struct SetupArgs {
/// Install globally to user profile config (~/.gemini/config and ~/.claude.json)
#[arg(long)]
pub global: bool,
/// Install locally into the current workspace (.agents/ and .mcp.json)
#[arg(long)]
pub workspace: bool,
/// Target AI agent environment: gemini, claude, or all [default: all]
#[arg(long, default_value = "all")]
pub target: String,
/// Print the embedded SKILL.md to stdout and exit
#[arg(long)]
pub print_skill: bool,
/// Only install the skill file, do not modify MCP configs
#[arg(long)]
pub skill_only: bool,
/// Only configure MCP server, do not install skill file
#[arg(long)]
pub mcp_only: bool,
/// Custom target directory for the skill (overrides defaults)
#[arg(long)]
pub skill_dir: Option<PathBuf>,
}