---
title: tld analyze
description: Static analysis that extracts architecture from source code. Go,
  TypeScript, Python, Java, C++, Rust.
editUrl: true
head: []
template: doc
sidebar:
  hidden: false
  attrs: {}
pagefind: true
draft: false
---

`tld analyze` reads your source code and generates architecture diagrams from it. It's a one-shot command: scan, discover, write.

```bash
tld analyze .
```

:::caution
This feature is in early stages of development. It is not yet production-ready. Expect rough edges, performance issues on large codebases, and frequent updates. We recommend trying it on small projects or branches until it's more mature.
:::

## How it works

Under the hood, `tld analyze` runs a pipeline:

1. **Parse**: Tree-sitter grammars parse every source file into abstract syntax trees. Each supported language has its own grammar, so the parsing is language-aware, not regex-based.

2. **Extract**: The parser extracts named symbols , functions, classes, structs, interfaces, modules. It also extracts references , imports, function calls, method invocations, type annotations.

3. **Filter**: Noise filters remove test files, generated code, and boilerplate that would clutter the diagram.

4. **Cluster**: Components are grouped by heuristics. Related files in the same package become a single element. Dependencies between packages become connectors.  

5. **Threshold**: Density controls prevent "hairball" diagrams. If a utility is imported by 50 files, it gets collapsed into a group rather than generating 50 connector lines.

6. **Write**: The results go into your workspace YAML files (`elements.yaml`, `connectors.yaml`).

## Supported languages

| Language | Extensions | Tree-sitter grammar |
|---|---|---|
| Go | `.go` | tree-sitter-go |
| TypeScript / JavaScript | `.ts`, `.tsx`, `.js`, `.jsx` | tree-sitter-typescript |
| Python | `.py` | tree-sitter-python |
| Java | `.java` | tree-sitter-java |
| C++ | `.cpp`, `.hpp`, `.cc`, `.h` | tree-sitter-cpp |
| Rust | `.rs` | tree-sitter-rust |

:::tip
**Exclude noise**: Make sure `.tld.yaml` excludes test files, generated code, and vendored dependencies. The defaults are good but tune them for your project.
:::

[Open an issue](https://github.com/Mertcikla/tld/issues) or even better, open a PR :). Tree-sitter supports 150+ languages, it is relatively easy to add new ones but might take time to polish.

## Basic usage

```bash
# Scan everything
tld analyze .

# Scan a specific directory
tld analyze ./src

# Scan only Go files
tld analyze . --language go

# Multiple languages
tld analyze . --language go --language python
```

## Density control

Dense codebases produce dense diagrams. These flags control how much detail you get:

```bash
tld analyze . \
  --max-elements-per-view 30 \
  --max-connectors-per-view 60 \
  --max-incoming-per-element 10 \
  --max-outgoing-per-element 10
```

| Flag | Default | What it does |
|---|---|---|
| `--max-elements-per-view` | 50 | Cap on elements in a single view |
| `--max-incoming-per-element` | 15 | Collapses connections if an element receives too many |
| `--max-outgoing-per-element` | 15 | Collapses connections if an element sends too many |
| `--max-expanded-connectors-per-group` | 30 | Merges file-level connectors into folder-level ones |

The defaults are reasonable for most projects. If output diagrams look sparse, raise the limits. If they're noisy, lower them.

### How collapsing works

When an element exceeds a threshold, the connectors are collapsed into a group connector. Instead of 50 individual lines to a utility file, you get one group connector saying "50 connections to utils/". The tooltip shows the details. The diagram stays clean.

## CI/CD automation

### Dry run

Preview changes without modifying files:

```bash
tld analyze . --dry-run
```

Shows what would be added, updated, or removed. Nothing is written.

### Fail on drift

Detect when code and diagrams have diverged:

```bash
tld analyze . --dry-run --fail-on-drift
```

Returns exit code 1 if the code has elements or connections not yet reflected in the diagrams. Designed to be suitable for CI, fail the build if architecture docs are stale.

### JSON output

Machine-readable results:

```bash
tld analyze . --format json
```

```json
{
  "elements_found": 42,
  "connectors_found": 89,
  "drift": [
    {"type": "new_element", "ref": "payment-svc", "reason": "found in source but not in YAML"}
  ]
}
```

### Common CI commands

```bash
# Validate diagrams match code
tld analyze ./src --dry-run --fail-on-drift

# Specific language + density limits for cleaner output
tld analyze ./pkg --language go --max-elements-per-view 50

# Machine-readable for custom reporting
tld analyze . --format json
```

## Additive by design

`tld analyze` is non-destructive. It adds new elements and updates existing ones, but never removes things you've manually documented. If you hand-crafted a beautiful diagram and the code scan finds additional services, it adds them alongside your work.

This is by design. Static analysis can't understand intent. It finds what's in the code, but you know what's in the architecture. The two should complement each other.

## When code and diagrams disagree

Sometimes the scanner finds things that don't match your mental model. Maybe it grouped things differently than you would. Maybe it found a dependency that doesn't actually exist at the architecture level.

## When to use analyze vs watch

`tld analyze` is **one-shot**. 
Ideal for:

- Initial diagram from an existing codebase
- Periodic sync before reviews
- CI checks for drift

`tld watch` is **continuous**. It stays running, monitoring changes. Ideal for:
- Seeing live impact of code changes on architecture
- Keeping diagrams in sync during active development

They use the same scanning engine under the hood.

## Embedding support (optional)

For semantic grouping beyond folder structure:

```bash
tld analyze . --embedding-provider openai --embedding-model text-embedding-3-small
```

With embeddings, related components cluster together based on what they do, not just where they live. A `validation.go` file and a `validator.py` file might share nothing structurally but serve the same purpose, embeddings allow tld to catch this. Also helps with refactoring and renaming symbols.

Requires an OpenAI compatible endpoint. Configure via global config or environment variables.