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
mod commands;
use clap::Parser;
#[derive(Parser)]
#[command(
name = "kodegraf",
version,
about = "Structural code intelligence for AI coding assistants",
long_about = "Kodegraf builds a knowledge graph of your codebase, validates AI-written code \
at write-time, and learns from failure patterns to prevent recurring mistakes."
)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(clap::Subcommand)]
enum Commands {
/// Initialize Kodegraf in the current project
Init,
/// Build the knowledge graph (full parse)
Build,
/// Incrementally update the graph (changed files only)
Update {
/// Fast mode: skip edge resolution, only re-parse changed files. For hook usage.
#[arg(long)]
fast: bool,
},
/// Show graph statistics
Status,
/// Find a symbol by name
Find {
/// Symbol name to search for
query: String,
},
/// Show dependencies of a file
Deps {
/// File path to check
file: String,
},
/// Show what depends on a file (reverse dependencies)
Dependents {
/// File path to check
file: String,
},
/// Show blast radius for current changes
Impact,
/// Validate a file against the graph (DiffGuard)
Check {
/// File path to validate
file: String,
},
/// Show quality insights and failure patterns
Insights {
/// Output as JSON
#[arg(long)]
json: bool,
},
/// Auto-detect and configure AI coding platforms
Install {
/// Target a specific platform
#[arg(long)]
platform: Option<String>,
/// Preview changes without writing
#[arg(long)]
dry_run: bool,
},
/// Run evaluation benchmarks (token efficiency, search quality, performance)
Eval {
/// Output as JSON instead of markdown
#[arg(long)]
json: bool,
},
/// Generate CLAUDE.md rules from failure patterns
GenerateRules,
/// Start the MCP server
Serve,
/// Print graph stats for session start (used by Claude Code hooks)
SessionGreeting,
/// Hook subcommands (for PostToolUse and SessionStart events)
Hook {
#[command(subcommand)]
event: HookEvent,
},
}
#[derive(clap::Subcommand)]
enum HookEvent {
/// PostToolUse hook — validates AI-written code
PostToolUse,
/// SessionStart hook — update graph if HEAD changed
SessionStart,
}
fn main() -> anyhow::Result<()> {
let cli = Cli::parse();
match cli.command {
Commands::Init => commands::init::run(),
Commands::Build => commands::build::run(),
Commands::Status => commands::status::run(),
Commands::Update { fast } => {
if fast {
commands::build::run_fast_update()
} else {
commands::build::run_update()
}
}
Commands::Find { query } => commands::find::run(&query),
Commands::Deps { file } => commands::deps::run(&file),
Commands::Dependents { file } => commands::dependents::run(&file),
Commands::Impact => commands::impact::run(),
Commands::Check { file } => commands::check::run(&file),
Commands::Insights { json } => commands::insights::run(json),
Commands::Eval { json } => commands::eval::run(json),
Commands::GenerateRules => commands::generate_rules::run(),
Commands::Install { platform, dry_run } => {
commands::install::run(platform.as_deref(), dry_run)
}
Commands::Serve => {
// The MCP server is the kodegraf-mcp binary. When invoked via CLI,
// we exec the MCP binary. In practice, AI platforms call kodegraf-mcp directly.
eprintln!("Starting MCP server over stdio...");
eprintln!("(Press Ctrl+C to stop, or configure your AI tool to call `kodegraf-mcp` directly)");
let status = std::process::Command::new("kodegraf-mcp")
.stdin(std::process::Stdio::inherit())
.stdout(std::process::Stdio::inherit())
.stderr(std::process::Stdio::inherit())
.status();
match status {
Ok(s) if s.success() => Ok(()),
Ok(s) => anyhow::bail!("MCP server exited with status: {}", s),
Err(e) => anyhow::bail!("Failed to start MCP server: {}. Is kodegraf-mcp in your PATH?", e),
}
}
Commands::SessionGreeting => commands::session_greeting::run(),
Commands::Hook { event } => match event {
HookEvent::PostToolUse => commands::hook::run_post_tool_use(),
HookEvent::SessionStart => commands::hook::run_session_start(),
},
}
}