If you've ever stared at a 15,000-file monorepo wondering "what actually breaks if I touch this file," you know the feeling: you either click through imports by hand, or you trust a tool that's quietly guessing.
ARCLUX is my answer to that β a dependency graph and impact analysis tool, CLI + web dashboard, built on one non-negotiable rule: every fact it reports has to trace back to real parsed code. An import statement. An export declaration. A resolved path. Not a probability. Not an embedding similarity score. A fact.
There's a wave of AI-powered "codebase intelligence" tools right now β semantic search, RAG over your repo, agents that summarize what a function does. Those are legitimate, useful tools solving a real problem.
ARCLUX solves a different one: can a machine tell you, with zero ambiguity, exactly how your code is structurally connected? No LLM in the loop, no "probably." Just parse β index β graph β impact β detect, every step traceable and reproducible.
repository -> parser -> graph -> detectors -> engine -> report
|
-> rules (framework conventions)
-> impact (consumer/dependent tracing)
This is the core of "what breaks if I touch this file." No heuristics, no scoring β just a breadth-first walk over the real dependency graph, starting from whoever directly imports the module and expanding outward until every transitive consumer is accounted for.
// Copyright 2026 Mikatoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
import type { Repository } from "../repository/Repository";
export interface ConsumerTraceResult {
direct: string[];
transitive: string[];
notFound: boolean;
}
export function traceConsumers(repository: Repository, moduleId: string): ConsumerTraceResult {
const startModule = repository.getModule(moduleId);
if (!startModule) {
return { direct: [], transitive: [], notFound: true };
}
const direct = [...startModule.importedBy];
const visited = new Set<string>([moduleId]);
const transitive: string[] = [];
const queue = [...direct];
while (queue.length > 0) {
const current = queue.shift()!;
if (visited.has(current)) continue;
visited.add(current);
transitive.push(current);
const module = repository.getModule(current);
if (!module) continue;
for (const consumer of module.importedBy) {
if (!visited.has(consumer)) queue.push(consumer);
}
}
return { direct, transitive, notFound: false };
}
direct
is everyone who imports the file right now. transitive
is everyone downstream of those, walked out through the whole graph. Nothing here is inferred β importedBy
is populated by the parser reading actual import statements, so every name in that result list is a file that will genuinely need attention if you change the module.
One of ARCLUX's 18 structural detectors looks for ambiguous symbol resolution β the same exported name defined in more than one place in your repo. It sounds like a minor annoyance until you realize what it actually causes: any tool (including AI coding assistants) that resolves "give me the definition of X" has to pick one, silently, with no principled criterion. Pick wrong, and you get confidently incorrect answers.
The categorization logic that powers this detector's severity model comes from a real-world failure case, and the code documents it directly:
// Copyright 2026 Mikatoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Logic contributed by ManSio (github.com/ManSio/mscodebase-intelligence).
// The categorisation + severity model is adapted from a runtime ranking fix
// for the D1 "wrong-source resolution" bug in that project: a symbol lookup
// that silently resolved to experiments/run_experiment_pagerank.py instead
// of src/symbol_index.py, producing wrong_rate = 1.0. The runtime fix
// (pick best candidate by path category at query time) translates here into
// a static detector: surface the collision to the developer upfront, before
// any tooling silently picks the wrong one.
function categorize(relativePath: string): SymbolCategory {
const normalized = relativePath.replace(/\\/g, "/").toLowerCase();
const segments = normalized.split("/");
const fileName = segments[segments.length - 1] ?? "";
if (
segments.some((seg) => TEST_DIR_SEGMENTS.has(seg)) ||
TEST_FILE_SUFFIXES.some((suffix) => fileName.endsWith(suffix))
) {
return "test";
}
if (segments.some((seg) => FIXTURE_DIR_SEGMENTS.has(seg))) return "fixture";
if (segments.some((seg) => MOCK_DIR_SEGMENTS.has(seg))) return "mock";
if (segments.some((seg) => EXAMPLE_DIR_SEGMENTS.has(seg))) return "example";
if (segments.some((seg) => SCRIPT_DIR_SEGMENTS.has(seg))) return "script";
// Real source β checked last so the test/fixture/mock overrides above win
if (segments.some((seg) => SOURCE_DIR_SEGMENTS.has(seg))) return "source";
return "other";
}
The interesting part is the severity model built on top of this: a collision is flagged high severity only when a real source definition has a shadow sitting in a test, example, fixture, mock, or script folder β because that's exactly the shape of bug where tooling picks the wrong file confidently. Two definitions that are both legitimately in source paths get medium (could be an intentional split, could be a leftover from a rename). Everything else is low.
Full credit to ManSio for the original categorization + severity model β the code comment traces exactly where the idea came from and why.
ARCLUX is Apache 2.0, and it's genuinely still alpha β expect stubs, expect rough edges, expect things marked "not yet built" in the project's own progress notes rather than silently pretended to work.
If deterministic, verifiable codebase analysis is a problem space you care about, I'd love more eyes on it β issues, PRs, or just poking around and telling me what's missing.