Metadata-Version: 2.4
Name: svitovyd
Version: 0.1.8
Summary: Project map builder and structural query tool — index, find, trace, deps, idiff
Project-URL: Homepage, https://github.com/szholobetsky/svitovyd
Project-URL: Repository, https://github.com/szholobetsky/svitovyd
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: tqdm>=4.60
Requires-Dist: flask>=2.3
Requires-Dist: waitress>=2.1
Provides-Extra: mcp
Requires-Dist: mcp>=1.0; extra == "mcp"
Provides-Extra: http
Requires-Dist: mcp>=1.0; extra == "http"
Requires-Dist: uvicorn>=0.24; extra == "http"
Provides-Extra: ui
Provides-Extra: gradio
Requires-Dist: gradio>=4.0; extra == "gradio"
Dynamic: license-file

![svitovyd](https://raw.githubusercontent.com/szholobetsky/simrgl/main/images/logo/svitovyd.png)

# svitovyd

Project map builder and structural query tool for codebases — scans a project (33 file types: Python, Java, JavaScript/TypeScript, C#, Go, Rust, C/C++, SQL, YAML and more) into a plain-text map of what every file defines and which files it refers to, and answers questions about it from the command line, a web UI or an MCP server, without an LLM.

## What it does

svitovyd reads the source files of a project and writes `.svitovyd/map.txt`: for every file, the
identifiers it defines (classes, functions, endpoints, tables, …) with their line numbers, and the
links to other files, each with its kind (`import`, `call`, `ref`, `expr`).

The map is then used to:

- **find** — filter the map by file name and content;
- **trace / deps** — who refers to an identifier, and what it depends on, step by step;
- **search** — which files a task description is about: its words become the identifiers the code
  defines, and those lead to the files;
- **keywords** — the identifiers of the code as a vocabulary, and the ones a text mentions;
- **sym** — a health report: identifiers defined but never referred to, cohesion of the hotspots,
  orphan files;
- **idiff** — what changed in the structure between two snapshots of the map;
- **ui** — the project as an interactive map in the browser, layer by layer.

AI agents get the same through the MCP server, so they can navigate a large code base without
reading it file by file.

---

## Statement of need

Developers and AI coding agents both need to know how a code base is put together before they
change it: where a name is defined, who uses it, what a change will touch. In a large project
reading the files is slow, and an agent with a small context window cannot hold them at all.
Language servers answer such questions, but each works for one language and needs the project to
build.

svitovyd builds one map for a whole project in many languages, from the text of the files alone,
with no build, no compiler and no model. The map is a small text file that a person can read, `grep`
can search, and an agent can load. It is meant for:

- **developers** who join or maintain a large code base and want to see its structure and the
  dependencies between its parts;
- **AI coding agents**, local or remote, that need a cheap way to find the right files and follow
  references (through the MCP server or the command line);
- **researchers in software engineering** who need the structure of many projects in one simple
  format.

---

## Install

```bash
pip install svitovyd                 # CLI + web UI
pip install "svitovyd[mcp]"          # + the MCP server (stdio)
pip install "svitovyd[http]"         # + MCP over HTTP/SSE (remote agents, LAN)
pip install "svitovyd[gradio]"       # + the older Gradio UI (svitovyd ui --gradio)
```

Python 3.10+. The core needs only Flask and waitress, so it installs anywhere Python runs.

---

## Quick start

```bash
cd my-project
svitovyd index .                     # -> .svitovyd/map.txt
svitovyd index . 3                   # depth 3: also variables and parameters

svitovyd find auth                   # files whose name contains "auth"
svitovyd trace SessionManager        # who refers to it
svitovyd deps Cart                   # what it depends on
svitovyd search "Login fails after the session expires"
svitovyd sym --k 10                  # health report
svitovyd ui                          # http://127.0.0.1:8097/
```

After a change, compare the structure with the previous map:

```bash
cp .svitovyd/map.txt .svitovyd/map.prev.txt
svitovyd index .
svitovyd idiff --prev .svitovyd/map.prev.txt
```

---

## Commands

| Command | What it does |
|---|---|
| `svitovyd index [PATH] [DEPTH]` | Scan a folder and build the map (depth 2 = definitions + links, 3 = also variables and parameters) |
| `svitovyd find QUERY` | Filter map blocks by file name and content (syntax below) |
| `svitovyd search TEXT\|FILE [--top N] [--json]` | The files a task text is about |
| `svitovyd trace IDENT` | Who refers to an identifier, step by step backwards |
| `svitovyd deps IDENT` | What an identifier or file depends on, step by step forwards |
| `svitovyd keywords [index\|extract TEXT]` | The identifier vocabulary: build it, extract the identifiers of a text, or list the most referred-to |
| `svitovyd sym [--k K]` | Asymmetry and cohesion health report |
| `svitovyd idiff --prev MAP` | Structural diff between two map snapshots |
| `svitovyd ui [--port 8097] [--host 0.0.0.0] [--root FOLDER] [--map FILE]` | The web UI |
| `svitovyd serve [--http --port 8766]` | The MCP server (also `svitovyd-mcp`) |

### `find` syntax

| Token | Meaning |
|---|---|
| `term` | the file name contains `term` |
| `!term` | leave out files whose name contains `term` |
| `\term` | keep a file if any of its lines contains `term` |
| `\!term` | leave out a file if any of its lines contains `term` |
| `-term` | show only the lines that contain `term` |
| `-!term` | hide the lines that contain `term` |

---

## Example

The output below comes from a small demo shop project (modules auth, checkout, billing,
catalog).

The map itself is plain text:

```
auth\src\LoginController.java
  defines : LoginController(ln:2)
  links  → auth\src\SessionManager.java (call:SessionManager)

auth\src\SessionManager.java
  defines : SessionManager(ln:2)
  links  → auth\src\TokenRefresher.java (call:TokenRefresher)
```

Which files a task is about:

```
$ svitovyd search "Login fails after the session expires" --top 3
words -> code: Login (1 id / 1 files), session (1 id / 1 files)
  1. auth/src/LoginController.java     2.56  LoginController
  2. auth/src/SessionManager.java      2.56  SessionManager
```

Who uses a class, and what a class depends on:

```
$ svitovyd trace TaxCalculator
trace: TaxCalculator
billing\src\TaxCalculator.java  [defines TaxCalculator(ln:2)]
  ← call:TaxCalculator  billing\src\InvoiceService.java
  ← import,call:TaxCalculator  checkout\src\PriceCalculator.java
    ← call:PriceCalculator  checkout\src\Cart.java

$ svitovyd deps Cart
deps: Cart(ln:3)
checkout\src\Cart.java
  → import,expr:Product  catalog\src\Product.java
  → expr:DiscountRule  checkout\src\DiscountRule.java
  → call:PriceCalculator  checkout\src\PriceCalculator.java
    → import,call:TaxCalculator  billing\src\TaxCalculator.java
```

---

## From a task text to files

`svitovyd search`, the **Task** page of the web UI and `svitovyd.graph.files_for_text()` all work
the same way. The task's words become identifiers the code defines:

- a word that **is** a defined identifier (`SessionManager`) means exactly it;
- any other word means every defined identifier whose parts contain its parts of 5 or more letters
  (`session` → `SessionManager`).

A word weighs `log(files / files defining its identifiers)`, so a word that is rare in the code
says more. Words found in more than 2 % of the files are skipped, and so are common English words.
svitovyd reads only the map: it needs no task history.

---

## Keywords

The keyword vocabulary links the words of a task to the identifiers of the code.

```bash
svitovyd keywords index                                       # -> .svitovyd/keyword.txt
svitovyd keywords extract "apply a discount to the cart total" -f
svitovyd keywords extract "tax" -l -o                         # substring match + the files
svitovyd keywords --k 100                                     # the most referred-to identifiers
```

```
$ svitovyd keywords extract "apply a discount to the cart total" -f
DiscountRule

$ svitovyd keywords extract "tax" -l -o
TaxCalculator -> billing\src\InvoiceService.java, billing\src\TaxCalculator.java, checkout\src\PriceCalculator.java
```

| Flag | Meaning |
|---|---|
| (none) | exact match: the word is an identifier |
| `-f` / `--fuzzy` | the identifier's camelCase / snake_case parts contain the word's parts of 5+ letters |
| `-l` / `--like` | the identifier contains the word as a substring |
| `-o` / `--origin` | also the files each identifier appears in |
| `-n` / `--counts` | the frequency of each identifier |
| `-s` / `--sort-count` | sort by frequency |
| `-a` / `--alpha` | sort alphabetically (default: the order in the text) |
| `-c` / `--csv` | one comma-separated line |

---

## Web UI

```bash
svitovyd ui                          # http://127.0.0.1:8097/
svitovyd ui --root ~/projects        # look for maps under this folder
svitovyd ui --map /path/to/map.txt   # open this map
svitovyd ui --host 0.0.0.0           # reachable from other devices on the LAN
```

The UI lists the maps under the folder it was started in and remembers every map opened or built
(`~/.svitovyd/maps.json`). One map is worked on at a time.

- **Map:** the project as an interactive map, layer by layer: the top folders first, then the
  inside of the one you click. Folders are sized by their files and coloured by cohesion. Click a
  link to see what it is made of, or a file to see what it defines, uses and is used by.
- **Task:** paste a task and get the files it is about, marked on the map.
- **Find:** the `find` syntax, with clickable files.
- **Paths:** `trace` and `deps` as trees, with the link kind of every step.
- **Keywords:** the identifiers of a text that exist in the code, and the most referred-to ones.
- **Health:** asymmetry, cohesion of the hotspots, orphans, and drift against an earlier map.
- **Maps:** open a map, build one for a folder, download `map.txt` / `keyword.txt`.

Which link kinds count is chosen once for every page. `expr` (a word of one file that equals a
name of another) is off by default, because in a large project it is mostly common words. The UI
has 8 colour themes and 6 languages (English, Ukrainian, German, French, Spanish, Portuguese).

---

## MCP server

The MCP server exposes 6 tools to any connected agent:

| Tool | Description |
|---|---|
| `map_index` | Build or update the project map |
| `map_find` | Filter map blocks by filename/content |
| `map_trace` | BFS backwards — who calls this identifier? |
| `map_deps` | BFS forward — what does this depend on? |
| `map_sym` | Asymmetry and cohesion health report |
| `map_idiff` | Structural diff between two map snapshots |

### Start the server

**Stdio** (for local agents — Claude Code, 1bcoder):
```bash
svitovyd-mcp
```

**HTTP/SSE** (for remote agents — opencode, nanocoder, LAN):
```bash
svitovyd-mcp --http --port 8766
# or
svitovyd serve --http --port 8766
```

With a specific map file:
```bash
svitovyd-mcp --http --port 8766 --map-file /path/to/project/.svitovyd/map.txt
```

---

## Setup per agent

### Claude Code

Add to `.claude/settings.json` in your project or `~/.claude/settings.json` globally:

```json
{
  "mcpServers": {
    "svitovyd": {
      "command": "svitovyd-mcp",
      "args": []
    }
  }
}
```

With a specific map file:
```json
{
  "mcpServers": {
    "svitovyd": {
      "command": "svitovyd-mcp",
      "args": ["--map-file", "/path/to/project/.svitovyd/map.txt"]
    }
  }
}
```

### opencode

Start the HTTP server first:
```bash
svitovyd-mcp --http --port 8766
```

Add to your opencode config (`~/.config/opencode/config.json` or project-local):
```json
{
  "mcp": {
    "svitovyd": {
      "type": "sse",
      "url": "http://localhost:8766/sse"
    }
  }
}
```

Or connect interactively if opencode supports it:
```
/mcp connect svitovyd http://localhost:8766/sse
```

### nanocoder

Start the HTTP server:
```bash
svitovyd-mcp --http --port 8766
```

Add to nanocoder config:
```json
{
  "mcpServers": {
    "svitovyd": {
      "url": "http://localhost:8766/sse"
    }
  }
}
```

### 1bcoder

```
/mcp connect svitovyd http://localhost:8766/sse
```

Or add to `.1bcoder/mcp.yaml` for auto-connect:
```yaml
servers:
  - name: svitovyd
    url: http://localhost:8766/sse
```

### Cursor

Add to `.cursor/mcp.json` in your project:
```json
{
  "mcpServers": {
    "svitovyd": {
      "command": "svitovyd-mcp",
      "args": []
    }
  }
}
```

### Any MCP-compatible client (generic)

**Stdio transport** — command: `svitovyd-mcp`

**SSE transport** — start server then connect to: `http://localhost:8766/sse`

---

## MCP tools reference

### `map_index`
```
path      directory to scan (default: ".")
depth     2 = definitions + links (default)
          3 = also variables and parameters
map_file  output path (default: <path>/.svitovyd/map.txt)
```

### `map_find`
```
query     filter string — token syntax:
            term    filename contains term
            !term   exclude if filename contains term
            \term   include block if any child line contains term
            \!term  exclude block if any child line contains term
            -term   show ONLY child lines containing term
            -!term  hide child lines containing term
map_file  map file to query (default: .svitovyd/map.txt)
```

### `map_trace`
```
identifier  function/class name defined in the codebase
depth       max BFS depth (default: 8)
map_file    map file to query
```

### `map_deps`
```
identifier  function/class name OR file path substring
depth       max BFS depth (default: 8)
map_file    map file to query
```

### `map_sym`
```
k           top-K hotspots for cohesion score (default: 5)
map_file    map file to query
```

### `map_idiff`
```
prev_map_file   path to previous map snapshot (required)
map_file        current map file (default: .svitovyd/map.txt)
```

---

## Supported languages

`.py` `.js` `.ts` `.java` `.cs` `.go` `.rs` `.cpp` `.c` `.h`
`.rb` `.php` `.kt` `.scala` `.swift` `.lua`
`.html` `.css` `.jsx` `.tsx` `.vue` `.svelte`
`.sql` `.yaml` `.yml` `.toml` `.json` `.xml`
`.tf` `.hcl` `.sh` `.bat` `.ps1`

---

## Python API

```python
from svitovyd import graph as G
from svitovyd.query import keyword_to_files

idx = G.load(".svitovyd/map.txt")
r = G.files_for_text(idx, "Login fails after the session expires")
r["files"][:3]    # [{"file", "score", "names": the identifiers it defines that matched}, ...]
r["words"]        # every word that counted, with its identifiers and weight

keyword_to_files(".svitovyd/map.txt", "TaxCalculator")   # the files an identifier appears in
```

---

## Tests

```bash
git clone https://github.com/szholobetsky/svitovyd
cd svitovyd
pip install -e .
pip install pytest
pytest
```

## Support

The project is on GitHub: [github.com/szholobetsky/svitovyd](https://github.com/szholobetsky/svitovyd).
Questions, bug reports and suggestions go to its
[issues](https://github.com/szholobetsky/svitovyd/issues).

---

## Part of the SIMARGL toolkit

svitovyd is one of ten tools that together form an **intellectual development support system**:

| Tool | Role |
|---|---|
| **[simargl](https://github.com/szholobetsky/simargl)** | Task-to-code retrieval — given a task description, finds which files and modules are likely affected, using semantic similarity over git history |
| **[svitovyd](https://github.com/szholobetsky/svitovyd)** | Project map — scans any codebase and produces a structural map of definitions and cross-file dependencies; queried from the CLI, a web UI with a layered map, or an MCP server |
| **[1bcoder](https://github.com/szholobetsky/1bcoder)** | AI coding assistant for small local models — surgical context management, agents, parallel inference, proc scripts |
| **[yasna](https://github.com/szholobetsky/yasna)** | Session memory — indexes conversations from all AI agents so you can find what was discussed, when, and where |
| **[radogast](https://github.com/szholobetsky/radogast)** | Context drift monitor — measures how far an AI agent's conversation has drifted from the original task |
| **[vyrii](https://github.com/szholobetsky/vyrii)** | Local AI web UI — chat, translate, web research, RAG and file management in the browser (Flask; Gradio optional); powered by Ollama or any OpenAI-compatible backend |
| **[syryn](https://github.com/szholobetsky/syryn)** | Bluetooth identity beacon for headless devices — the device's IP is its Bluetooth name; hostname, mDNS and network interfaces on request |
| **[alkonost](https://github.com/szholobetsky/alkonost)** | Browser cockpit for 1bcoder's flows — the `deepagent_*` spec pipeline (plan tree → specs → task board) and the glossary (build, browse, search), tuned for small local models |
| **[gamayun](https://github.com/szholobetsky/gamayun)** | Statistical ontology without an LLM — builds triples of terms, identifiers, files and modules from task history or a folder of documents and code; every triple carries its significance test |
| **[mokosh](https://github.com/szholobetsky/mokosh)** | Dataset gathering — commits of a git repository and the tasks of its tracker (Jira, GitHub, GitLab, YouTrack) in one SQLite database that the other tools read |

- **simargl** finds the code related to a task by vector search over the task history (embeddings).
- **svitovyd** answers: *how is the code structured and what depends on what?*
- **1bcoder** answers: *how do I work with local models efficiently?*
- **yasna** answers: *where did I already discuss this?*
- **radogast** answers: *is the AI agent still on track toward the goal?*
- **vyrii** answers: *how do I access all of this through a browser?*
- **syryn** answers: *what is the address of this headless device?*
- **alkonost** answers: *how do I turn one task description into a reviewed, working plan — and see the project's glossary — without a big model or a big context window?*
- **gamayun** finds the code related to a task through an ontology of significant links between words, files and modules (no LLM).
- **mokosh** prepares the initial dataset from version control and the issue tracker.

Together they cover the full development loop: understand the codebase, find relevant history, work with AI locally, remember what was decided, and verify the context stays on target.

The name comes from Slavic mythology. Svitovyd (Світовид) is the four-faced god who sees all directions simultaneously — past, future, war, and harvest. A fitting name for a tool that maps an entire codebase at once.

---

## License

MIT. See [LICENSE](LICENSE).

## About

(c) 2026 Stanislav Zholobetskyi, Oleh Andriichuk  
Institute for Information Recording, National Academy of Sciences of Ukraine, Kyiv  
PhD research: «Intelligent Technology for Software Development and Maintenance Support»
