Skip to content

Analysis

One reading of a repository, once per commit SHA. It takes no document type and must not — the moment analysis knows what you intend to do with it, the apps stop being interchangeable.

The graph is a LangGraph StateGraph in codelith/workflows/analysis_workflow.py. Ten stages, in order.

The ten stages

1. repo_analyzer

Clones or opens the source, walks it, and parses every file a language provider claims. Produces the file list, the symbol spans, and the raw material everything downstream reads.

Skips the directories nobody means to analyse — .git, node_modules, .venv, __pycache__, dist, build — and files over 500 KB.

Writes: the parsed codebase, in memory. Model calls: none.

2. structured_extractor

Finds the facts that are true whether or not a model reads the code: routes, entrypoints, environment variables, datastores, dependencies, config files, CLI commands, scheduled tasks, external APIs, infra resources, test suites.

Some of this is pattern work in a language provider (a FastAPI decorator is a route); some is manifest reading (pyproject.toml, package.json); some is a fast-tier model call for the parts that need judgement.

Writes: kb_entities. Model tier: fast.

3. graph_builder

Turns the parsed symbols and imports into the code graph: six tables of files, modules, packages, symbols, imports and calls.

Writes: graph_*. Model calls: none.

4. semantic_indexer

Splits the source into chunks and embeds them. Code is split on symbol boundaries where the provider gave spans, and on line windows where it did not. Prose — docstrings, markdown — is chunked separately and labelled, so nothing downstream can mistake a README for evidence.

Writes: code_chunks, each with its vector. Model tier: embedding.

5. module_summarizer

A paragraph per module: what it is for, not what it contains. This is the stage that costs, and the one with a ceiling.

Writes: kb_modules.summary. Model tier: fast, six concurrent.

It stops at 40 modules

ANALYSIS_MAX_SUMMARISED_MODULES defaults to 40. Beyond that, the largest modules are summarised and the rest are left with no prose — visible in the studio as a module with no paragraph. Raise it if you want full coverage; it costs one call per extra module.

6. architecture_synthesizer

Reads the whole picture and names the components this system actually has: not service and api, but "Worker Face Tracking Engine" and "Controller Persistence". Each component gets a type, a description, and the modules that make it up, plus the relations between them.

This is what the knowledge graph groups by, and what What changed compares between two readings.

Writes: knowledge_bases.architecture_json. Model tier: quality.

7. narrative_writer

Twelve cross-cutting topics — architecture, request lifecycle, data model, configuration, deployment, error handling, testing, observability, integrations, state management, CLI usage, overview — each written from the modules it drew on, with those modules recorded as provenance.

Writes: kb_narratives, with source_refs_json. Model tier: quality.

8. site_planner

Decides which document types this codebase can actually support, from evidence rather than from a menu. A project with no HTTP routes is never offered an API reference.

Writes: knowledge_bases.site_map_json. Model tier: quality.

9. question_seeder

The suggested questions on the Ask page, derived from what was found. "Which service handles diagram generation?" is a real question about a real module, not a template.

Writes: knowledge_bases.suggested_questions_json. Model tier: fast.

10. kb_persister

Marks the knowledge base ready and writes the aggregate statistics: module and entity counts, role distribution, languages, embedding model and measured width.

Writes: knowledge_bases.stats_json, status. Model calls: none.

What happens to the clone

It is deleted. The checkout is working material for the run; nothing needs it afterwards, because a file is rebuilt from stored chunks.

Removal happens in a finally, so a run that failed halfway releases the disk exactly as one that succeeded does, and clones left by earlier versions are swept at startup.

A folder source is your own directory. It is passed straight through and never registered for deletion, which is a structural guarantee rather than a check.

Cancelling

Long work stays cancellable throughout. JobCancelled is never swallowed by a broad except and never retried; a cancelled run leaves no half-built knowledge base looking usable.

Re-running

Analysing a commit that already has a ready knowledge base reuses it. Pass force to rebuild. Analysing a different commit builds a second reading alongside the first, which is the raw material for What changed.