How to Contribute
Contribution workflow. Read more
This document explains how Unfault’s client-side components work. If you’re contributing to the CLI, core library, or VS Code extension, this context helps you understand where your changes fit.
Unfault runs entirely on your machine:
Everything runs on your machine. The CLI and VS Code extension use the core library to parse source code and build a semantic graph. The analysis crate then runs rules against that graph in-process. No source code, IR, or findings leave your machine.
This architecture provides:
core/)The core library is the foundation of client-side analysis. It handles:
core/├── src/│ ├── lib.rs # Public API│ ├── parse/ # Tree-sitter parsing│ │ ├── python.rs│ │ ├── go.rs│ │ ├── rust.rs│ │ └── typescript.rs│ ├── semantics/ # Semantic extraction│ │ ├── mod.rs│ │ ├── python/ # Python-specific semantics│ │ ├── go/│ │ └── ...│ ├── graph/ # Graph construction│ │ ├── mod.rs # CodeGraph implementation│ │ ├── nodes.rs # Node types│ │ └── edges.rs # Edge types│ └── ir.rs # Intermediate representationThe CodeGraph is the central data structure:
pub struct CodeGraph { nodes: Vec<GraphNode>, edges: Vec<GraphEdge>, // Indexes for efficient lookups file_index: HashMap<PathBuf, NodeIndex>, function_index: HashMap<String, NodeIndex>,}
pub enum GraphNode { File { path: PathBuf, language: Language }, Function { name: String, qualified_name: String, ... }, Class { name: String, ... }, ExternalModule { name: String, category: ModuleCategory }, // Framework-specific nodes Route { method: HttpMethod, path: String, ... }, Middleware { name: String, ... },}
pub enum GraphEdgeKind { Contains, // File contains Function Calls, // Function calls Function Imports, // File imports Module Inherits, // Class inherits Class UsesLibrary, // Function uses external library // Framework-specific edges RegistersRoute, AppliesMiddleware,}cli/)The CLI orchestrates the analysis workflow:
cli/├── src/│ ├── main.rs # Entry point, argument parsing│ ├── commands/ # Subcommands│ │ ├── review.rs # `unfault review`│ │ ├── lint.rs # `unfault lint`│ │ ├── graph.rs # `unfault graph`│ │ ├── info.rs # `unfault info`│ │ ├── config.rs # `unfault config`│ │ ├── lsp.rs # `unfault lsp`│ │ └── agent_skills.rs # `unfault config agent`│ ├── session/ # Analysis session management│ │ ├── mod.rs # Session lifecycle│ │ └── workspace.rs # Workspace detection│ └── integration/ # Observability integrations│ └── (gcp, datadog, dynatrace)The review flow:
core to parse files and build graphunfault-analysis which runs rules in-processThe extension provides real-time analysis via LSP:
vscode/├── src/│ ├── extension.ts # Extension entry point│ ├── contextView.ts # Context sidebar webview│ └── welcomePanel.ts # Onboarding UIThe extension spawns the CLI in LSP mode (unfault lsp) and communicates via the Language Server Protocol. The CLI handles all parsing and analysis; the extension focuses on UI.
Analysis runs entirely on your machine:
The core library is a separate crate from the CLI. This is good practice:
The analysis crate lives separately from core and cli:
The Intermediate Representation (IR) passed from core to analysis contains:
The IR does not contain:
To add support for a new language:
core/Cargo.tomlcore/src/parse/{language}.rscore/src/semantics/{language}/SourceSemantics enumTo add support for a new framework:
core/src/semantics/{language}/frameworks/FrameworkGuess signalsTo capture more semantic information:
core/src/semantics/{language}/model.rscore/src/semantics/{language}/mod.rsThe CLI can discover SLOs from observability platforms and link them to route handlers. Currently supported: GCP Cloud Monitoring, Datadog, Dynatrace.
To add a new provider:
cli/src/slo/{provider}.rsfetch_slos to query the provider’s APISloDefinition structs with name, target, path patternSloEnricher (cli/src/slo/mod.rs)Example provider structure:
pub struct MyProvider { api_key: String, endpoint: String,}
impl MyProvider { pub fn is_available() -> bool { env::var("MY_PROVIDER_API_KEY").is_ok() }
pub fn from_env() -> Option<Self> { let api_key = env::var("MY_PROVIDER_API_KEY").ok()?; Some(Self { api_key, endpoint: "https://api.myprovider.com".into() }) }
pub async fn fetch_slos(&self, client: &Client) -> Result<Vec<SloDefinition>> { // Query API and map to SloDefinition }}cd corecargo test # All testscargo test python # Python-related testscargo test semantics::python # Specific modulecd clicargo test# Run the full workspace testscargo test --workspaceHow to Contribute
Contribution workflow. Read more
CLI Repository
Browse the CLI source code. View on GitHub
Core Repository
Parsing and semantics. View on GitHub