Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 21 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,11 @@ codegraph index .
### 4. Start the MCP server

```bash
codegraph serve --repo-root .
codegraph serve
```

Repo root is auto-detected from git (or falls back to your current working directory).

That's it. Your AI assistant now has deep structural code understanding.

---
Expand All @@ -169,7 +171,7 @@ codegraph install
"mcpServers": {
"codegraph": {
"command": "codegraph",
"args": ["serve", "--repo-root", "."]
"args": ["serve"]
}
}
}
Expand All @@ -184,7 +186,7 @@ codegraph install
"mcpServers": {
"codegraph": {
"command": "codegraph",
"args": ["serve", "--repo-root", "."]
"args": ["serve"]
}
}
}
Expand All @@ -197,7 +199,7 @@ codegraph install
```toml
[mcp_servers.codegraph]
command = "codegraph"
args = ["serve", "--repo-root", "/path/to/repo"]
args = ["serve"]
startup_timeout_sec = 60
```
</details>
Expand Down Expand Up @@ -278,7 +280,7 @@ codegraph watch <path> # Watch and auto-reindex
codegraph clean <path> # Clean database

# MCP Server
codegraph serve --repo-root <path> # Start MCP server
codegraph serve [--repo-root <path>] # Start MCP server (auto-detects repo root)

# Query
codegraph stats <path> # Graph statistics
Expand All @@ -292,7 +294,7 @@ codegraph impact <path> --symbol <name> # Impact analysis
codegraph affected-tests [--stdin] <files> # Tests affected by changed files

# Visualization & Export
codegraph visualize --repo-root <path> # Interactive D3.js graph
codegraph visualize [--repo-root <path>] # Interactive D3.js graph (auto-detects repo root)
codegraph graph export <path> --format dot # Export as Graphviz DOT
codegraph graph export <path> --format json # Export as JSON

Expand All @@ -307,10 +309,12 @@ codegraph benchmark # Token savings benchmark
git diff --name-only | codegraph affected-tests --stdin

# CI integration
TESTS=$(git diff --name-only HEAD~1 | codegraph affected-tests --stdin --repo-root .)
TESTS=$(git diff --name-only HEAD~1 | codegraph affected-tests --stdin)
go test $TESTS
```

Replace `--repo-root .` with nothing if you are already in the repo you want to inspect.

---

## Optional: Embeddings & Agentic Mode
Expand Down Expand Up @@ -397,6 +401,16 @@ Created with `codegraph config init --repo .` at `.codegraph/config.json`:
}
```

### Repo Root Resolution

When `--repo-root` (CLI) or `repo_root` (MCP tool parameter) is omitted, codegraph resolves the repo root using:

1. Per-call `repo_root` MCP tool parameter
2. `--repo-root` CLI flag (process-level default)
3. `git rev-parse --show-toplevel` from the current working directory
4. `os.Getwd()` (current working directory)
5. Return error

### Ignore file

Create `.codegraphignore` in the repo root (same syntax as `.gitignore`):
Expand Down
2 changes: 1 addition & 1 deletion docs/ai-assistant-guidance.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This repository ships `codegraph`, a local-first code context engine and MCP ser

- Run `codegraph install` once to set up local configuration and optional editor/tool integration.
- Run `codegraph index <repo>` to build the initial graph.
- Use `codegraph serve --repo-root <repo>` for stdio MCP integration.
- Use `codegraph serve` for stdio MCP integration (repo root auto-detected).
- Prefer MCP tools for repository context instead of repeated shelling out.

## Guidance For Tool-Driven Work
Expand Down
6 changes: 3 additions & 3 deletions docs/codegraph-roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ Observed in `internal/cli/app.go:Run` dispatch and `printUsage`:
- `doctor`
- `config <show|edit-path|validate|init>`
- `benchmark`
- `serve --repo-root <repo-path>`
- `serve [--repo-root <repo-path>]`
- `watch <repo-path>`
- `graph export <repo-path> [--format json|dot] ...`
- `affected-tests [--repo-root PATH] [--stdin] [--json] [--limit N] <file>...`
- `visualize [--repo-root PATH] ...`
- `affected-tests [--repo-root PATH] [--stdin] [--json] [--limit N] <file>...` (repo root auto-detects when omitted)
- `visualize [--repo-root PATH] ...` (repo root auto-detects when omitted)
- `clean [repo-path] [--vacuum]`

Notes:
Expand Down
6 changes: 3 additions & 3 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ This directory contains minimal `codegraph` MCP server configuration examples fo
All examples start the same server command:

```text
codegraph serve --repo-root /absolute/path/to/repo
codegraph serve
```

Replace `/absolute/path/to/repo` with the repository you want `codegraph` to serve.
Expand All @@ -23,7 +23,7 @@ Replace `/absolute/path/to/repo` with the repository you want `codegraph` to ser
`codex-mcp.toml` includes:

- `command = "codegraph"`
- `args = ["serve", "--repo-root", "..."]`
- `args = ["serve"]`
- `startup_timeout_sec = 60`

Keep `startup_timeout_sec = 60` so Codex allows enough time for the server to open or migrate the local SQLite database on startup.
Expand All @@ -33,7 +33,7 @@ Keep `startup_timeout_sec = 60` so Codex allows enough time for the server to op
The JSON examples are intentionally minimal:

- `command`: `codegraph`
- `args`: `["serve", "--repo-root", "/absolute/path/to/repo"]`
- `args`: `["serve"]`

If `codegraph` is not on `PATH`, replace `command` and `args` with a form that launches it through `go run` from the repository checkout.

Expand Down
8 changes: 3 additions & 5 deletions examples/claude-desktop-mcp.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@
"mcpServers": {
"codegraph": {
"command": "codegraph",
"args": [
"serve",
"--repo-root",
"/absolute/path/to/repo"
]
"args": [
"serve"
]
}
}
}
2 changes: 1 addition & 1 deletion examples/codex-mcp.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[mcp_servers.codegraph]
command = "codegraph"
args = ["serve", "--repo-root", "/absolute/path/to/repo"]
args = ["serve"]
startup_timeout_sec = 60
8 changes: 3 additions & 5 deletions examples/gemini-mcp.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@
"mcpServers": {
"codegraph": {
"command": "codegraph",
"args": [
"serve",
"--repo-root",
"/absolute/path/to/repo"
]
"args": [
"serve"
]
}
}
}
102 changes: 60 additions & 42 deletions internal/cli/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,11 @@ func runDoctor(ctx context.Context, cfg config.Config, stdout io.Writer, args []
deep := fs.Bool("deep", false, "run deeper (potentially slow) diagnostics, including integrity_check")
repoRootFlag := fs.String("repo-root", "", "repository root to inspect (optional)")

defaultRepoRoot := ""
if config.IsRepoDBDir(cfg.DBDir) {
defaultRepoRoot = "."
repoRootCandidate, err := parseOptionalRepoRootArg(fs, args, repoRootFlag, "")
if err != nil {
return err
}
repoRoot, err := parseOptionalRepoRootArg(fs, args, repoRootFlag, defaultRepoRoot)
repoRoot, err := config.ResolveRepoRoot(repoRootCandidate, "")
if err != nil {
return err
}
Expand Down Expand Up @@ -601,8 +601,8 @@ func runInstall(stdout io.Writer) error {
}`)

// Always print manual snippets as a fallback / reference.
codexSnippet := fmt.Sprintf("[mcp_servers.codegraph]\ncommand = %q\nargs = [\"serve\", \"--repo-root\", \"/absolute/path/to/repo\"]\nstartup_timeout_sec = 60", appname.BinaryName)
clientSnippet := fmt.Sprintf(`{"mcpServers":{"codegraph":{"command":%q,"args":["serve","--repo-root","/absolute/path/to/repo"]}}}`, appname.BinaryName)
codexSnippet := fmt.Sprintf("[mcp_servers.codegraph]\ncommand = %q\nargs = [\"serve\"]\nstartup_timeout_sec = 60", appname.BinaryName)
clientSnippet := fmt.Sprintf(`{"mcpServers":{"codegraph":{"command":%q,"args":["serve"]}}}`, appname.BinaryName)
fmt.Fprintln(stdout)
fmt.Fprintln(stdout, "Manual MCP snippets (if auto-configure did not apply):")
fmt.Fprintln(stdout)
Expand Down Expand Up @@ -639,9 +639,13 @@ func runIndex(ctx context.Context, cfg config.Config, stdout io.Writer, cmdName
if err := fs.Parse(filtered); err != nil {
return err
}
repoRoot := "."
repoRootCandidate := ""
if fs.NArg() > 0 {
repoRoot = fs.Arg(0)
repoRootCandidate = fs.Arg(0)
}
repoRoot, err := config.ResolveRepoRoot(repoRootCandidate, "")
if err != nil {
return err
}
app, repo, repoID, err := openApp(ctx, cfg, repoRoot)
if err != nil {
Expand Down Expand Up @@ -1150,11 +1154,13 @@ func runStats(ctx context.Context, cfg config.Config, stdout io.Writer, args []s
if err := fs.Parse(args); err != nil {
return err
}
repoRoot := "."
if *repoRootFlag != "" {
repoRoot = *repoRootFlag
} else if fs.NArg() > 0 {
repoRoot = fs.Arg(0)
repoRootCandidate := strings.TrimSpace(*repoRootFlag)
if repoRootCandidate == "" && fs.NArg() > 0 {
repoRootCandidate = fs.Arg(0)
}
repoRoot, err := config.ResolveRepoRoot(repoRootCandidate, "")
if err != nil {
return err
}
app, _, repoID, err := openApp(ctx, cfg, repoRoot)
if err != nil {
Expand Down Expand Up @@ -1185,15 +1191,12 @@ func runQueryCommand(ctx context.Context, cfg config.Config, stdout io.Writer, q
return err
}

repoRoot := "."
if *repoRootFlag != "" {
repoRoot = *repoRootFlag
}
repoRootCandidate := strings.TrimSpace(*repoRootFlag)
queryValue := *queryFlag
symbol := ""
rest := fs.Args()
if *repoRootFlag == "" && len(rest) > 0 {
repoRoot = rest[0]
if repoRootCandidate == "" && len(rest) > 0 {
repoRootCandidate = rest[0]
rest = rest[1:]
}
if queryValue == "" && len(rest) > 0 {
Expand All @@ -1209,6 +1212,10 @@ func runQueryCommand(ctx context.Context, cfg config.Config, stdout io.Writer, q
symbol = queryValue
}

repoRoot, err := config.ResolveRepoRoot(repoRootCandidate, "")
if err != nil {
return err
}
app, _, repoID, err := openApp(ctx, cfg, repoRoot)
if err != nil {
return err
Expand Down Expand Up @@ -1309,18 +1316,20 @@ func runServe(ctx context.Context, cfg config.Config, stdout, stderr io.Writer,
if err := fs.Parse(args); err != nil {
return err
}
repoRoot := "."
if *repoRootFlag != "" {
repoRoot = *repoRootFlag
} else if fs.NArg() > 0 {
repoRoot = fs.Arg(0)
repoRootCandidate := strings.TrimSpace(*repoRootFlag)
if repoRootCandidate == "" && fs.NArg() > 0 {
repoRootCandidate = fs.Arg(0)
}
repoRoot, err := config.ResolveRepoRoot(repoRootCandidate, "")
if err != nil {
return err
}
app, repo, repoID, err := openApp(ctx, cfg, repoRoot)
if err != nil {
return err
}
defer app.Close()
server := mcp.NewServer(repo.RootPath, repoID, app.Store, app.Indexer, app.Query, stderr)
server := mcp.NewServer(repoRootCandidate, repo.RootPath, repoID, app.Store, app.Indexer, app.Query, stderr)
if repoCfg, err := config.LoadRepo(repo.RootPath); err == nil {
if repoCfg.Agent.Enabled || repoCfg.Agent.BaseURL != "" || repoCfg.Agent.Model != "" {
server.SetAgentConfig(repoCfg.Agent.BaseURL, repoCfg.Agent.Model)
Expand All @@ -1337,11 +1346,13 @@ func runWatch(ctx context.Context, cfg config.Config, stdout io.Writer, args []s
if err := fs.Parse(args); err != nil {
return err
}
repoRoot := "."
if *repoRootFlag != "" {
repoRoot = *repoRootFlag
} else if fs.NArg() > 0 {
repoRoot = fs.Arg(0)
repoRootCandidate := strings.TrimSpace(*repoRootFlag)
if repoRootCandidate == "" && fs.NArg() > 0 {
repoRootCandidate = fs.Arg(0)
}
repoRoot, err := config.ResolveRepoRoot(repoRootCandidate, "")
if err != nil {
return err
}
app, repo, repoID, err := openApp(ctx, cfg, repoRoot)
if err != nil {
Expand Down Expand Up @@ -1498,18 +1509,24 @@ func runGraph(ctx context.Context, cfg config.Config, stdout io.Writer, args []s
func runVisualize(ctx context.Context, cfg config.Config, stdout io.Writer, args []string) error {
fs := flag.NewFlagSet("visualize", flag.ContinueOnError)
fs.SetOutput(io.Discard)
repoRoot := fs.String("repo-root", ".", "repository root")
repoRootFlag := fs.String("repo-root", "", "repository root")
symbol := fs.String("symbol", "", "focus on a specific symbol")
output := fs.String("output", "", "write HTML to this file instead of opening a browser")
depth := fs.Int("depth", 2, "traversal depth from focus symbol")
if err := fs.Parse(args); err != nil {
return err
}
if fs.NArg() > 0 && *repoRoot == "." {
*repoRoot = fs.Arg(0)

repoRootCandidate := strings.TrimSpace(*repoRootFlag)
if repoRootCandidate == "" && fs.NArg() > 0 {
repoRootCandidate = fs.Arg(0)
}
repoRoot, err := config.ResolveRepoRoot(repoRootCandidate, "")
if err != nil {
return err
}

app, _, repoID, err := openApp(ctx, cfg, *repoRoot)
app, _, repoID, err := openApp(ctx, cfg, repoRoot)
if err != nil {
return err
}
Expand Down Expand Up @@ -1571,11 +1588,11 @@ func runClean(ctx context.Context, cfg config.Config, stdout io.Writer, args []s
incrementalVacuum := fs.Bool("incremental-vacuum", false, "run PRAGMA incremental_vacuum (requires auto_vacuum=INCREMENTAL)")
repoRootFlag := fs.String("repo-root", "", "repository root to clean")

defaultRepoRoot := ""
if config.IsRepoDBDir(cfg.DBDir) {
defaultRepoRoot = "."
repoRootCandidate, err := parseOptionalRepoRootArg(fs, args, repoRootFlag, "")
if err != nil {
return err
}
repoRoot, err := parseOptionalRepoRootArg(fs, args, repoRootFlag, defaultRepoRoot)
repoRoot, err := config.ResolveRepoRoot(repoRootCandidate, "")
if err != nil {
return err
}
Expand Down Expand Up @@ -1962,9 +1979,10 @@ func runAffectedTests(ctx context.Context, cfg config.Config, stdout io.Writer,
return err
}

repoRoot := "."
if *repoRootFlag != "" {
repoRoot = *repoRootFlag
repoRootCandidate := strings.TrimSpace(*repoRootFlag)
repoRoot, err := config.ResolveRepoRoot(repoRootCandidate, "")
if err != nil {
return err
}

var files []string
Expand Down Expand Up @@ -2049,7 +2067,7 @@ func printRootHelp(w io.Writer) {
fmt.Fprintf(w, " %s index .\n", appname.BinaryName)
fmt.Fprintf(w, " %s stats .\n", appname.BinaryName)
fmt.Fprintf(w, " %s find_symbol . MySymbol\n", appname.BinaryName)
fmt.Fprintf(w, " %s serve --repo-root .\n", appname.BinaryName)
fmt.Fprintf(w, " %s serve\n", appname.BinaryName)
}

func formatCommandExample(ex string) string {
Expand Down
Loading
Loading