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
3 changes: 3 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 @@ -36,6 +36,7 @@ thiserror = "1"
sha2 = "0.10"
sha1_smol = "1"
rayon = "1.8"
globset = "0.4"

# Logging (rust-base-convention)
tracing = "0.1"
Expand Down
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,9 @@ codegraph install --yes # detects installed agents and wires them u
**Rules of thumb:** reach for `codegraph_explore` _before_ reading files; trust
its results (full AST parse — don't re-verify with grep); use `codegraph_impact`
for refactor blast-radius rather than walking callers by hand. The index lags
file writes by ~1s; tool responses flag any stale files.
file writes by ~1s; tool responses flag any stale files. If the question names
a source path, include it in the explore query: explicit paths are normalized
and pinned ahead of fuzzy matches, while unresolved paths are reported.

</details>

Expand Down Expand Up @@ -431,6 +433,19 @@ and newly included/custom-extension files are added without restarting the MCP
server. Invalid TOML keeps the last valid watcher scope and reports the error;
malformed JSON keeps the existing tolerant empty-override behavior.

Keep third-party or generated source searchable while ranking it below
first-party code with ranking-only rules:

```toml
[indexing]
deprioritize = ["vendor/**", "generated/**"]
```

`.codegraph/codegraph.json` also accepts a top-level `deprioritize` array for
compatibility. JSON rules run first, TOML rules run last, ordered `!pattern`
exceptions make matching last-rule-wins, and no file/node/edge is removed.
Search and explore reload the addressed project's policy on every request.

Full env-var table, HTTP server details, filesystem fallback behavior, and the
Claude prompt-hook: [`docs/mcp.md`](docs/mcp.md) and
[`docs/cli.md`](docs/cli.md#daemon-watch--environment-variables).
Expand All @@ -439,8 +454,9 @@ Claude prompt-hook: [`docs/mcp.md`](docs/mcp.md) and

## CLI Subcommands

Core commands: `init`, `index`, `sync`, `search`, `files`, `status`, `serve`,
`callers`, `callees`, `impact`, `affected`, `check`, `export`, `unlock`.
Core commands: `init`, `index`, `sync`, `search`, `explore`, `node`, `files`,
`status`, `serve`, `callers`, `callees`, `impact`, `affected`, `check`, `audit`,
`export`, `unlock`, `http`, `mcp`.

Agent / install commands: `install`, `uninstall`, `skill`, `self-update`,
`completions` (`--install` sets up tab completion for bash/zsh/fish/powershell/elvish).
Expand Down
12 changes: 10 additions & 2 deletions crates/codegraph-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ use anyhow::{Context, Result, anyhow, bail};
use clap::{CommandFactory, Parser, Subcommand, ValueEnum};
use clap_complete::{Shell, generate};
use codegraph_core::config::Config;
use codegraph_core::deprioritize::DeprioritizeMatcher;
use codegraph_core::generated_header::detect_generated_file;
use codegraph_core::logger::{LoggerConfig, init_logger};
use codegraph_core::node_id::hash_content;
use codegraph_core::types::{ExtractionResult, FileRecord, Language, Node, NodeKind};
use codegraph_extract::{ExtractOptions, detect_language_with, extract_source_with};
use codegraph_graph::graph::{GodotReach, GraphTraverser};
use codegraph_graph::query::{SearchOptions, search_nodes};
use codegraph_graph::{segment_match, segments};
use codegraph_mcp::{McpServer, RunUntilAdoption};
use codegraph_resolve::ReferenceResolver;
use codegraph_store::queries::SearchResult;
Expand All @@ -36,8 +38,6 @@ use time::OffsetDateTime;
use time::format_description::well_known::Rfc3339;

mod installer;
mod segment_match;
mod segments;
mod structural_gate;

/// Test-only: the ONE process-wide environment lock for this binary.
Expand Down Expand Up @@ -1963,6 +1963,12 @@ fn cmd_search(
) -> Result<()> {
let project = resolve_required_project(path)?;
let store = open_store(&project)?;
let paths = codegraph_core::IndexPaths::resolve(
&project,
std::env::var("CODEGRAPH_DIR").ok().as_deref(),
)?;
let config = Config::load_for_paths(None, &paths)?;
let deprioritize = Arc::new(DeprioritizeMatcher::load_for_paths(&paths, &config));
let kinds = kind
.as_deref()
.map(parse_node_kind)
Expand All @@ -1977,6 +1983,8 @@ fn cmd_search(
languages: Vec::new(),
limit: Some(limit),
offset: Some(0),
seed_names: Vec::new(),
deprioritize: Some(deprioritize),
},
&project_name_tokens(&project),
)?;
Expand Down
1 change: 1 addition & 0 deletions crates/codegraph-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ tracing-subscriber = { workspace = true }
tracing-appender = { workspace = true }
time = { workspace = true }
sha2 = { workspace = true }
globset = { workspace = true }
25 changes: 25 additions & 0 deletions crates/codegraph-core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ pub struct IndexingConfig {
/// behavior byte-identical). #1063.
#[serde(default)]
pub include: Vec<String>,
/// Root-relative gitignore-style patterns for source that remains indexed
/// and directly retrievable, but should lose ranking ties to first-party
/// code. Rules are evaluated in order with last-match-wins semantics;
/// `!pattern` clears an earlier match. The project's `codegraph.json`
/// rules run first and these TOML rules run last, so TOML is authoritative.
#[serde(default)]
pub deprioritize: Vec<String>,
}

fn default_max_file_size() -> u64 {
Expand Down Expand Up @@ -206,6 +213,7 @@ impl Default for IndexingConfig {
ignore_paths: default_ignore_paths(),
exclude: Vec::new(),
include: Vec::new(),
deprioritize: Vec::new(),
}
}
}
Expand Down Expand Up @@ -404,6 +412,7 @@ name = "my-project"
assert!(cfg.watch.enabled); // default
assert_eq!(cfg.watch.debounce_ms, 2000); // default
assert!(cfg.indexing.exclude.is_empty()); // off by default
assert!(cfg.indexing.deprioritize.is_empty()); // ranking-only, off by default
}

#[test]
Expand All @@ -429,6 +438,22 @@ max_file_size = 2097152
assert!(cfg.indexing.exclude.is_empty());
}

#[test]
fn test_deprioritize_parses_and_preserves_rule_order() {
let config = r#"
[app]
name = "p"

[indexing]
deprioritize = ["vendor/**", "!vendor/first-party/**", "generated/**"]
"#;
let cfg: Config = toml::from_str(config).expect("should parse");
assert_eq!(
cfg.indexing.deprioritize,
vec!["vendor/**", "!vendor/first-party/**", "generated/**"]
);
}

#[test]
fn test_include_parses_and_defaults_empty() {
let with_include = r#"
Expand Down
Loading
Loading