Skip to content
Open
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
69 changes: 69 additions & 0 deletions .agents/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
name: codegraph-orchestrator
description: Global coordination and structural codebase navigation via CodeGraph MCP
trigger: auto
paths:
- "**/*"
---

# CodeGraph System Instructions

This project is backed by a **CodeGraph MCP server** — a local tree-sitter
semantic graph of every symbol and call chain in the workspace. Reads are
sub-millisecond and return structural information grep cannot match.

---

## 🚨 CRITICAL CONSTRAINTS (Read First)

- **NEVER use generic text-search, grep, or file-reading tools** when a
symbol, reference, or definition can be located with CodeGraph.
- **Do NOT re-verify** CodeGraph results with file reads — the graph is the
single source of truth for codebase structure.
- **Handle unbound sessions:** query tools refuse until the session is bound.
Call `codegraph_init {"path": ...}` (non-blocking, does NOT index), then
`codegraph_index {}` to build/refresh the index.
- **Minimize token overhead:** prefer targeted structural queries and
`id`-based lookups over dumping file contents into context.

---

## 🛠️ Tool Selection Guide

Prefer codegraph for **structural** questions. Use filesystem tools only for
literal text queries or applying edits.

| Intent / Question | Recommended MCP Tool |
| :--- | :--- |
| *"Where is symbol X defined?"* | `codegraph_search_symbol` (contains/prefix/suffix/exact) |
| *"Show me this symbol by id / exact name"* | `codegraph_symbol` |
| *"What calls function Y?"* | `codegraph_callers` |
| *"What does Y call directly?"* | `codegraph_callees` |
| *"What breaks if I modify Z?"* | `codegraph_impact` |
| *"Show me Y's call chain"* | `codegraph_flow` |
| *"Find flows containing a pattern (loop + call)"* | `codegraph_search_flow` |
| *"Give me focused, aggregated context for a task"* | `codegraph_context` |
| *"Who calls the library function foo?"* | `codegraph_references` |
| *"What fields/methods does class C have?"* | `codegraph_class` |
| *"Which symbols are annotated @X?"* | `codegraph_search_by_annotation` |
| *"What files exist under path/?"* | `codegraph_files` |
| *"Is the index healthy?"* | `codegraph_status` |
| *"What does this MR change in the graph?"* | `codegraph_diff` |
| *"Simulate a flow's behavior with mocks"* | `codegraph_sandbox` / `codegraph_diff_simulate` |

---

## 💡 Rules of Thumb

1. **`codegraph_context` first** — it aggregates search + callers + callees
in one call; don't chain searches manually.
2. **Query impact before editing** — `codegraph_impact` pinpoints downstream
effects so you only touch relevant files.
3. **Trust the results** — AST-derived. If a lookup yields nothing, the
symbol is not in the active workspace index.
4. **Duplicate names** → the tool returns `ambiguous: true` with matches;
retry with the numeric `id` alone.

The full, always-current guide (timeout/resume protocol, response formats,
sandbox contracts) ships inside the binary as the server instructions — see
`docs/codegraph.md` in the CodeGraph repository.
12 changes: 12 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ jobs:
path: crates/codegraph-web/assets/
if-no-files-found: error

sonarqube:
name: SonarQube
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: SonarQube Scan
uses: SonarSource/sonarqube-scan-action@7006c4492b2e0ee0f816d36501671557c97f5995 # v8.1.0
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

clippy:
name: clippy
needs: web
Expand Down
21 changes: 21 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ members = [
"crates/codegraph-docs",
"crates/codegraph-source",
"crates/codegraph-web",
"crates/codesmell",
]

[workspace.package]
Expand Down
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,27 @@ The agent binds the workspace with `codegraph_init {"path": ...}` and gets tools

→ [Full comparison with decision matrix](docs/comparison.md)

## 🧹 CodeSmell — convention linter for LLM agents

The workspace also ships [`codesmell`](docs/codesmell.md), a team-convention
linter built on CodeGraph facts. LLM agents read the conventions pack before
writing code and fix every reported violation afterwards — each violation
carries a `fix_hint`, so the agent repairs code instead of guessing:

```bash
codesmell init # write .codesmell/policy.toml
codesmell guide # conventions pack for the LLM / team
codesmell check # lint the repo (style, architecture, testing)
git diff | codesmell check --diff - # change-aware validation
codesmell coverage # test-coverage estimate + threshold
```

Policies cover function size/parameter/nesting limits, naming conventions
(`*Service`, `Async` suffix), layer boundaries (`controller !-> repository`,
severity `blocking`), and required unit tests for changed business logic
(severity `required`), with per-area `[[override]]` scopes. See
[docs/codesmell.md](docs/codesmell.md) for the full policy schema.

## 📄 Supported Formats

CodeGraph supports parsing both **source code** (via tree-sitter) and **configuration/document** files:
Expand Down Expand Up @@ -86,6 +107,8 @@ Document files can be ingested into a **document graph** and queried via:

## 📦 Install

Read the [server instructions](docs/codegraph.md) that ship with the binary — they tell your agent when to reach for which tool.

**Automatic (recommended)**

```bash
Expand Down Expand Up @@ -145,6 +168,8 @@ binaries → radare2 (r2pipe) ──┘
| Storage Backends | `docs/storage-backends.md` |
| Semantic Search | `docs/semantic-search.md` |
| Binary Analysis (radare2) | `docs/binary-analysis.md` |
| CodeSmell Linter | `docs/codesmell.md` |
| CodeSmell Coverage | `docs/codesmell-coverage.md` |
| Why Rust (Rewrite Story) | `docs/why-rust.md` |
| Development Guide | `docs/development.md` |

Expand Down
46 changes: 28 additions & 18 deletions crates/codegraph-graph/src/lru.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,36 +124,41 @@ where
pub fn get(&self, key: &K) -> Option<V> {
let index = *self.mapping.get(key)?;

// Đọc giá trị an toàn (Node này chắc chắn tồn tại vì mapping đang giữ nó)
let val = self.caching[index].value.as_ref()?.clone();

// Optimistic LRU Update: Dùng try_lock để không làm chậm luồng Read
// Key/value của node chỉ được chạm dưới khoá shard của key — nếu không
// `put` (overwrite value) và `clear` (reset slot) sẽ race với phép đọc này.
let shard_idx = self.get_shard_idx(key);
if let Some(mut ht) = self.shards[shard_idx].mutex.try_lock() {
self.move_to_front_inside_lock(&mut ht, index);
let mut ht = self.shards[shard_idx].mutex.lock();
// Slot có thể đã bị tái sử dụng (key bị `remove` rồi `put` mới chiếm
// chỗ) giữa lúc tra mapping và lúc khoá shard — xác minh lại key.
if self.caching[index].key.as_ref() != Some(key) {
return None;
}
let val = self.caching[index].value.as_ref()?.clone();
self.move_to_front_inside_lock(&mut ht, index);

Some(val)
}

pub fn put(&self, key: K, value: V) {
let shard_idx = self.get_shard_idx(&key);

// Case 1: Key đã tồn tại (Update)
if let Some(entry) = self.mapping.get_mut(&key) {
let index = *entry.value();
// Case 1: Key đã tồn tại (Update). Không giữ DashMap guard khi chờ
// shard mutex — Case 2 giữ mutex rồi mới insert vào mapping, giữ guard
// cùng lúc sẽ tạo chu trình khoá chéo giữa DashMap shard và shard mutex.
let existing = self.mapping.get(&key).map(|e| *e.value());
if let Some(index) = existing {
if let Some(cb) = &self.on_updating {
cb(key.clone(), value.clone());
}

unsafe {
let node_ptr = &self.caching[index] as *const Node<K, V> as *mut Node<K, V>;
(*node_ptr).value = Some(value);
}
drop(entry);

// Cập nhật thứ tự (Có thể dùng try_lock hoặc lock tùy độ ưu tiên)
if let Some(mut ht) = self.shards[shard_idx].mutex.try_lock() {
let mut ht = self.shards[shard_idx].mutex.lock();
// Re-check dưới khoá shard: `remove`/`clear` có thể đã xoá key
// sau bước tra trên — bỏ qua update thay vì ghi vào slot mồ côi.
if self.mapping.get(&key).map(|e| *e.value()) == Some(index) {
unsafe {
let node_ptr = &self.caching[index] as *const Node<K, V> as *mut Node<K, V>;
(*node_ptr).value = Some(value);
}
self.move_to_front_inside_lock(&mut ht, index);
}
return;
Expand Down Expand Up @@ -191,7 +196,12 @@ where
/// Chỉ remove khỏi DashMap, slot trong arena được tái sử dụng khi `put` overwrite.
pub fn remove(&self, key: &K) -> Option<V> {
let (_, index) = self.mapping.remove(key)?;
self.caching[index].value.clone()
// Khoá shard trước khi đọc value — `clear`/`put` ghi slot dưới cùng khoá này.
let shard_idx = self.get_shard_idx(key);
let ht = self.shards[shard_idx].mutex.lock();
let val = self.caching[index].value.clone();
drop(ht);
val
}

/// Số entry đang cache — `DashMap::len()` O(1), dùng cho báo cáo memory.
Expand Down
16 changes: 10 additions & 6 deletions crates/codegraph-installer/src/instructions-template.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# CodeGraph

This project has a CodeGraph MCP server configured. CodeGraph is a tree-sitter
knowledge graph of every symbol, edge, and file in the workspace. Reads are
semantic graph of every symbol and call chain in the workspace. Reads are
sub-millisecond and return structural information grep cannot.

## When to prefer codegraph
Expand All @@ -13,10 +13,11 @@ for literal text queries.
| Question | Tool |
|---|---|
| "Where is X defined?" | `codegraph_search_symbol` |
| "Show me X by id / exact name" | `codegraph_symbol` |
| "What calls Y?" | `codegraph_callers` |
| "What does Y call?" | `codegraph_callees` |
| "What would break if I changed Z?" | `codegraph_impact` |
| "Show me Y's signature / source" | `codegraph_symbol` |
| "Show me Y's call chain" | `codegraph_flow` |
| "Give me focused context for a task" | `codegraph_context` |
| "What files exist under path/" | `codegraph_graphcode_files` |
| "Is the index healthy?" | `codegraph_status` |
Expand All @@ -26,9 +27,12 @@ for literal text queries.
- **Trust codegraph results.** They come from a full AST parse. Do NOT
re-verify with grep.
- **Don't grep first** when looking up a symbol by name.
- **`codegraph_context` is one call** — don't chain search + node yourself.
- **`codegraph_context` is one call** — don't chain search + symbol yourself.
- **Duplicate names** return `ambiguous: true` — retry with the numeric `id`.

## If `.codegraph/` doesn't exist
## If no index exists yet

The MCP server returns "not initialized." Run `codegraph init -i` to build
the index.
Query tools refuse until the session is bound. Call
`codegraph_init {"path": ...}` (non-blocking — does NOT index by default),
then `codegraph_index {}` to build the index. On the CLI, `codegraph init`
creates `.codegraph/` and indexes in one step.
35 changes: 27 additions & 8 deletions crates/codegraph-installer/src/targets/antigravity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,33 +162,48 @@ paths:

# CodeGraph System Instructions

This project is backed by a custom **CodeGraph MCP server**. CodeGraph maintains a local Tree-sitter knowledge graph encompassing every symbol, edge, boundary, and file within this workspace. Reads operate at sub-millisecond speeds and deliver accurate structural insights that traditional text-based tools (like grep) cannot match.
This project is backed by a **CodeGraph MCP server** — a local tree-sitter
semantic graph of every symbol and call chain in the workspace. Reads are
sub-millisecond and return structural information grep cannot match.

---

## 🚨 CRITICAL CONSTRAINTS (Read First)

- **NEVER use generic text-search, grep, or file-reading tools** if a symbol, reference, or definition can be located using CodeGraph.
- **DO NOT double-check or re-verify** CodeGraph results with native file reads. Treat the knowledge graph as the absolute, single source of truth for codebase architecture.
- **Handle uninitialized states immediately:** If any CodeGraph tool returns a `"not initialized"` or missing index error, **STOP execution immediately** and instruct the user to run `codegraph init -i` in their terminal. Do not attempt to parse or scan the codebase manually to compensate.
- **Minimize token overhead:** Prefer targeted structural queries over dumping entire file contents into the context window.
- **NEVER use generic text-search, grep, or file-reading tools** when a
symbol, reference, or definition can be located with CodeGraph.
- **Do NOT re-verify** CodeGraph results with file reads — the graph is the
single source of truth for codebase structure.
- **Handle unbound sessions:** query tools refuse until the session is bound.
Call `codegraph_init {"path": ...}` (non-blocking, does NOT index), then
`codegraph_index {}` to build/refresh the index.
- **Minimize token overhead:** prefer targeted structural queries and
`id`-based lookups over dumping file contents into context.

---

## 🛠️ Tool Selection Guide

Always prefer `codegraph` tools for **structural** questions — tracing call hierarchies, mapping dependencies, determining definitions, and verifying signatures. Use standard filesystem tools *only* for literal text queries or applying actual code edits.
Prefer codegraph for **structural** questions. Use filesystem tools only for
literal text queries or applying edits.

| Intent / Question | Recommended MCP Tool |
| :--- | :--- |
| *"Where is symbol X defined?"* | `codegraph_search_symbol` |
| *"Where is symbol X defined?"* | `codegraph_search_symbol` (contains/prefix/suffix/exact) |
| *"Show me this symbol by id / exact name"* | `codegraph_symbol` |
| *"What callers invoke function Y?"* | `codegraph_callers` |
| *"What methods or functions does Y call?"* | `codegraph_callees` |
| *"What components or files will break if I modify Z?"* | `codegraph_impact` |
| *"Show me Y's exact signature and internal block"* | `codegraph_symbol` |
| *"Show me Y's call chain"* | `codegraph_flow` |
| *"Find flows containing a pattern (loop + call)"* | `codegraph_search_flow` |
| *"Give me focused, aggregated context for this task"* | `codegraph_context` |
| *"Who calls the library function foo?"* | `codegraph_references` |
| *"What fields/methods does class C have?"* | `codegraph_graphcode_class` |
| *"Which symbols are annotated @X?"* | `codegraph_graphcode_search_by_annotation` |
| *"What files exist under a specific path/ directory?"* | `codegraph_graphcode_files` |
| *"Is the local knowledge graph healthy and active?"* | `codegraph_status` |
| *"What does this MR change in the graph?"* | `codegraph_diff` |
| *"Simulate a flow's behavior with mocks"* | `codegraph_sandbox` / `codegraph_diff_simulate` |

---

Expand All @@ -202,4 +217,8 @@ Before updating an API route, a UI component, or a system utility, query `codegr

### 3. Strict AST Reliance
Because CodeGraph parses the Abstract Syntax Tree (AST), its structural insights are guaranteed. If a symbol look-up yields no results, assume the symbol does not exist in the current active workspace index.

### 4. Duplicate names
The tool returns `ambiguous: true` with the full match list — retry with the
numeric `id` alone.
"#;
3 changes: 2 additions & 1 deletion crates/codegraph-mcp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ use rmcp::{ErrorData as McpError, RoleServer};
use serde_json::{json, Value};

/// Hướng dẫn sử dụng tools — client render trong instructions sau `initialize`.
pub const SERVER_INSTRUCTIONS: &str = include_str!("server-instructions.md");
/// Nguồn chân lý nằm ở `docs/codegraph.md` (gom chung tài liệu trong docs/).
pub const SERVER_INSTRUCTIONS: &str = include_str!("../../../docs/codegraph.md");
pub const SERVER_NAME: &str = "codegraph";
pub const SERVER_VERSION: &str = env!("CARGO_PKG_VERSION");

Expand Down
2 changes: 1 addition & 1 deletion crates/codegraph-mcp/src/tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1399,7 +1399,7 @@ fn normalize_response(value: &mut Value, root: &str, detail: DetailLevel, style:
}

/// Symbol JSON theo `detail` + `style`. `Minimal` (mặc định) → mảng vị trí cố
/// định (order được document trong server-instructions.md; file đã relativize
/// định (order được document trong docs/codegraph.md; file đã relativize
/// theo root — relativize_paths chỉ chạm object key, không chạm phần tử mảng);
/// `Medium` → object giữ key (field default bị lược trong formatter chung).
fn symbol_json(root: &str, s: &Symbol, detail: DetailLevel, style: OutputStyle) -> Value {
Expand Down
25 changes: 25 additions & 0 deletions crates/codesmell/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "codesmell"
version.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true

[dependencies]
codegraph-core = { path = "../codegraph-core" }
codegraph-extract = { path = "../codegraph-extract" }
codegraph-graph = { path = "../codegraph-graph" }
serde = { workspace = true }
serde_json = { workspace = true }
toml = "0.8"
camino = { workspace = true }
globset = { workspace = true }
anyhow = { workspace = true }
dirs = "5"
clap = { workspace = true }
tokio = { workspace = true }
rhai = { version = "1", features = ["sync"] }
regex = "1"

[dev-dependencies]
tempfile = "3"
Loading
Loading