aigiscode evaluates codebases in a way that is:
- machine-readable
- policy-driven
- adaptable across projects
- usable by AI agents without rewriting core logic for each repository
The core design goal is to separate generic analysis from project-specific interpretation.
The system has four layers of responsibility:
- index and graph construction
- generic detectors
- project policy and exclusion rules
- AI-assisted review and tuning
Only the first two layers should contain generic analysis logic. Project-specific behavior belongs in policy or plugin modules.
The indexer parses supported files and stores:
- files
- symbols
- dependencies
- semantic envelopes
Current parsing backends:
tree-sitterfor PHP, TypeScript, JavaScript, and Vue- Python
astfor Python source
Storage is SQLite in .aigiscode/aigiscode.db.
Incremental indexing prunes stale file rows automatically. When parser behavior changes, analyze --reset is the explicit full-refresh path.
Graph analysis builds a file-level dependency graph and computes:
- strong circular dependencies
- total circular dependencies
- coupling
- bottlenecks
- layer violations
- likely orphan files
- runtime entry candidates
- god classes
This stage is meant to answer architectural questions, not stylistic ones.
The graph now distinguishes two related but different concepts:
- runtime truth: include/load/bootstrap edges are useful for understanding how code is reached
- architectural truth: strong-cycle reporting excludes load-only edges so framework bootstraps do not dominate the cycle metric
- registration truth: callback/class-string registration edges keep listener/controller/handler wiring explicit enough for graph and dead-code analysis
Detectors currently include:
- dead code
- hardwiring
Detectors are intentionally generic. They should emit candidates, not project-specific verdicts.
Detector coverage can still be partial by language. That state must be surfaced in reports instead of silently treating newly indexed languages as fully covered.
Current hardwiring design is precision-first:
- strip syntax-only noise before counting findings
- analyze
.vuefiles from script sections instead of template markup - include Python in generic string/network/env analysis
- require sink/context evidence for entity coupling
- keep repeated-literal reporting focused on route, selector, path, and API contracts
- gate simple magic-string tokens by signal context and suppress metadata-heavy contexts
- suppress protocol/header/query/page markers when the surrounding context proves standards-driven or framework-contract usage
- distinguish operational URLs from documentation/help/schema/namespace URLs before emitting
hardcoded_network - harvest explicit symbolic contracts from type unions,
as constarrays, and registration maps before treating later string comparisons as generic hardwiring
Saved rules in .aigiscode/rules.json pre-filter known false positives.
Rules are the durable memory of prior audits. They should stay narrow and explainable.
The report layer now also emits built-in derived context under report.extensions.
Current built-in extension:
contract_inventory- routes
- hooks
- registered keys
- symbolic literals
- env keys
- config keys
This is descriptive evidence, not a detector. The point is to make runtime contracts explicit so later detector and policy work has better grounding.
That grounding is now used by hardwiring analysis: declared contract values are excluded from generic repeated-literal duplication findings. It is also used to suppress magic-string findings when a literal is already a declared runtime contract.
AI review examines remaining findings and can:
- classify true positives versus false positives
- propose new exclusion rules
- synthesize higher-level insights
AI review is intentionally downstream of static analysis. The deterministic engine generates candidates; Codex is the final reviewer that decides whether a sampled finding is acceptable, wrong, or needs more context. Codex SDK is the primary backend for that stage; Codex CLI and Claude are optional fallbacks.
Analytical mode asks Codex for a policy patch.
Tune mode is stricter:
- it proposes a candidate patch
- reruns metrics
- accepts only non-regressive improvements
This prevents blind optimization against a single weighted score.
Policy has four sections:
graphdead_codehardwiringai
Examples of policy responsibilities:
- JS alias resolution
- layer name overrides
- orphan entrypoint patterns
- runtime entrypoint patterns
- framework entry-point patterns
- abandoned-class language scope
- dynamic reference surfaces for dead-code rescue
- hardwiring entity require-context regexes
- hardwiring allow-context regexes
- magic-string signal/noise context regexes
- repeated-literal skip regexes
- literal thresholds and path excludes
- allowed JS env names
- AI backend ordering
Examples of non-policy responsibilities:
- parsing source code
- building the dependency graph
- generic detector algorithms
There are two extension mechanisms today:
- plugin profiles
Built-in named profiles such as
generic,laravel,newerp,django, andwordpress. - external plugin modules Python modules that can return policy patches dynamically and optionally refine graph/dead-code/hardwiring/report results at runtime. They can now also enrich declared contract lookup and refine hardwiring findings per category before the final result is aggregated.
This keeps the system decoupled without turning every project into a fork of the analyzer.
- Decoupling over convenience.
- DRY in backend and policy orchestration.
- YAGNI for detector complexity until a real corpus proves the need.
- Prefer explainable heuristics over opaque model-only decisions.
- Treat counts as signals, not goals.
- Prefer partial but explicit coverage over false certainty.
The system is not trying to be:
- a fully sound program analysis engine
- a universal architecture truth machine
- an auto-suppressor that hides findings until the dashboard looks good
It is a practical evaluator for large real repositories.