Open-source CLI · 2026 · Designer and engineer · Independent
Stack: Python, Ollama, Rich, AST, pytest, GitHub Actions
Reading an unfamiliar repository is mostly orientation work: which files matter, what each directory is for, where execution starts. Existing tools either send the code to a cloud service or stop at a file tree. tldrepo is a local-first answer: run it in a repository and get a compact map with one short description beside every file and directory, with no account and no daemon left behind.
The design constraint was honesty. A description should say what a file does, not what a language model imagines it might do. That shaped the whole architecture: deterministic analysis handles everything it can prove, and the model is asked only for the prose that remains.
Deterministic first
- Traversal, .gitignore matching, language detection, hashing and Python AST parsing are ordinary Python.
- File tiers decide what is worth describing and which files are generated, vendored or binary.
- Docstrings and rule-based descriptions are used before any model call.
- Layout, colour and the final tree are computed, never generated.
Only files that still need prose are sent, as compact skeletons, in directory-grouped batches with temperature set to zero. Files get at most ten words; directories at most eight. Vague or invented answers are rejected before they reach the screen.
A cache that respects the model
Descriptions live in .tldrepo/cache.json, keyed by content hash, model and prompt version. A warm run never contacts Ollama: the cache is the difference between a tool you run once and a tool you run while working. The cache stores descriptions, hashes and source tags — never the source itself — and .tldrepo/.gitignore contains *, so it never appears in git status.
Deep analysis
The map answers where things are. The deep pass answers how a codebase works. It scores every file deterministically — entry points, import fan-in, substance, role names, penalties for tests and generated files — then extracts classes, signatures, docstrings, imports, CLI flags, environment variables, file and network access, and a depth-limited static call chain. Python uses ast; other languages use a conservative regex pass. Target code is never executed.
The deep model writes at most twenty words per symbol and one file narrative. A sentence naming a function, class, file or environment variable absent from the extracted facts is discarded. If the model is missing or the budget runs out, the report degrades to facts and the run still succeeds.
Measured, not estimated
| Scenario | v0.2.0 |
|---|---|
| Cold run (no cache) | 10.57 s |
| Warm run (nothing changed) | 0.11 s |
| Five files modified | 5.25 s |
| Deep run, cold (43 files) | 79.6 s |
| Deep run, unchanged | 0.32 s, zero model calls |
| Model resident after exit | none |
The numbers are measured on a 17-file target, not estimated. They also set expectations: local inference is not instant, so the tool has to make the second run almost free.
What it taught me
Local models are useful when the task is small and the system around them is strict. Most of the engineering was not prompting; it was deciding which claims the tool is allowed to make, and building the deterministic layer that makes those claims checkable. The same principle runs through my client work: keep the model inside a narrow contract.