Skip to main content

Salak

Deterministic, provenance-tagged code knowledge graph generator.

Salak parses a source repository and emits a single JSON file — repo-graph.json — describing its structure and the relations between its symbols, so an AI coding assistant can answer "what depends on this module?" from a recorded fact instead of a guess.

The graph is a build artifact, not a database. It is regenerated from source, committed to git, and read by tools. Salak owns the generation and nothing else.

Package name

Published on PyPI as salak. The name salak is taken on npm; if a JavaScript distribution is ever needed it ships as salak-graph (decision D5).

Status

0.1.0, shipped 2026-08-26 — ship verdict. Every phase gate (TASK-039, TASK-062, TASK-083, TASK-098) returned ship. salak scan, salak check, salak diff, salak validate, salak doctor and salak version all work today, verified against the published PyPI package on real repositories, not just this checkout. 0.1.0 rather than 1.0.0 on purpose (decision D55) — the WBS's internal "v1.0" phase label was never a semver stability promise.

Phase Deliverable State
Spike 0 Feasibility and readiness done
v0.1 Structure pass: files/nodes/defines/imports/depends_on, published JSON Schema, salak validate shipped
v0.2 Resolution pass (§4.1 Levels 1–2), extends/implements/instantiates/references, full provenance shipped
v0.3 Incremental scan (the run_incremental library entry point), salak check, salak diff shipped
v1.0 Packaging, salak doctor, --stdout, docs, clean-machine install proof shipped

No further phase is currently open. --update (incremental scanning via the CLI, rather than the run_incremental library entry point) has no flag yet — the library is proven correct and ships in the package, but nothing wires it to salak scan.

Level 3 (method-call resolution) was decided void at the v0.1 exit gate (K15, decision D43): it resolved only 23.1% of import edges against 95.4–99.6% for Levels 1–2, with no language server at all. See "Degraded mode and resolution levels" below.

Design principles

  1. Deterministic over clever. Same input, same bytes out. No LLM anywhere — the pipeline is offline, free and reproducible.
  2. Precision over recall. An extracted edge that is wrong is worse than a missing edge. When unsure, downgrade the provenance tag; never upgrade it.
  3. The schema is the contract. Consumers talk to the schema, never to Salak internals. A formal JSON Schema ships with the package and is authoritative over the prose (SDD §3.7).
  4. One language, one adapter. Adding a language must not modify core; adapters register through an entry-point group (decision D3), not an import in core.
  5. A graph declares its own scope. Reading the file's scan block tells you which languages ran, whether anything failed, and what the run did not attempt.

Requirements

  • Python 3.11+
  • Node.js — optional. pyright and typescript-language-server are the two language servers Salak knows how to detect, but method-call resolution (Level 3) is void (K15/D43), and Levels 1–2 resolve from tree-sitter and filesystem heuristics alone — no module under salak.resolution imports salak.lsp. The practical result: today, repo-graph.json comes out byte-for-byte the same with or without Node installed. salak doctor still reports Node/server presence and version drift as information (decision D45 — a missing server is never treated as unhealthy), because that detection work is what a future Level-3 revival would need, not because anything currently emitted depends on it.
  • TypeScript ≤ 5.9.x as the tsserver host, only relevant if you install the language servers for salak doctor to report on. TypeScript 7 ships no lib/tsserver.js, and typescript-language-server works by spawning tsserver, so the latest dist-tag is broken for this purpose (decision D15).

Installing

From PyPI (recommended for using Salak on your own repositories):

uv tool install salak

(No uv? pip install salak works the same way, into whatever environment pip targets.) That's it — no Node, no language servers required to run salak scan and get a full graph. This puts a plain salak command on your PATH; verify with:

salak version

If you also want salak doctor to report on the language servers (informational only — see Requirements below; installing them changes nothing about what scan emits), install Node.js and then, globally or in whatever project you're scanning:

npm i -g pyright@1.1.411 typescript-language-server@5.3.0 typescript@5.9.3

From source (for contributing to Salak itself):

git clone https://github.com/edhoferdian/salak
cd salak
uv sync

uv run salak ... now works from inside the checkout. uv tool install --editable . puts an editable salak on your PATH instead of prefixing every call with uv run. npm ci (from this checkout) installs the exact pinned language-server versions the test suite spawns — only needed for Salak's own development, not for using it.

Quickstart

Three commands, from install to a generated graph, run against any repository on your machine:

uv tool install salak
salak scan /path/to/your/repo
salak validate /path/to/your/repo/project-memory/repo-graph.json

scan writes the graph; validate confirms it matches its own declared schema version. salak check /path/to/your/repo confirms the graph is still fresh against the working tree (it will be, immediately after a scan) — useful as a pre-commit hook or CI step once the graph is committed alongside your source. Run against this repository itself, scan reports:

salak: wrote <repo>/project-memory/repo-graph.json
salak: 213 parsed, 2 failed, 0 skipped · 2824 nodes, 9524 edges · 2 error(s), 0 warning(s)

(Exact counts drift as the repository grows; the shape — most files parsed, two deliberately-broken fixtures failing, the run still completing — is what to expect.)

The two PARSE_FAILED errors above are two deliberately-broken fixture files under tests/fixtures/broken/ used to test the parser's recovery path — exit code 2 ("completed with diagnostics", not a crash) is expected there. On an ordinary repository, scan exits 0.

Default output path

salak scan PATH writes to PATH/project-memory/repo-graph.json unless --out overrides it. From SDD §5: "chosen so the artifact lands where dev-kickoff already keeps project memory." Overridable per run; --stdout skips the file entirely and writes the graph to stdout instead (for CI or piping into salak validate -).

Point --out outside the repository when scanning this repository, or the scan overwrites its own working tree — use an absolute path or a sibling directory that isn't reached through ..:

salak scan . --out /path/outside/this/repo/salak-graph.json

Degraded mode and resolution levels

A run with no language server available, or one whose version doesn't match the pin, is not an error — it's a supported, expected state (rule 6). health_check() never raises, and a missing or mismatched server is reported as an LSP_VERSION_MISMATCH warning or plain information in doctor, never as unavailable (decision D45).

Concretely, on this machine right now:

$ salak doctor
Node.js: found (...)
python: ok — tree-sitter grammars available; resolution is §4.1 Levels 1-2 and needs
  no language server (K15/D43). pyright 1.1.411 ...
typescript: ok — tree-sitter grammars available; resolution is §4.1 Levels 1-2 and
  needs no language server (K15/D43). typescript-language-server 5.3.0 ...

Both adapters report ok regardless of whether the language server was actually consulted, because after K15/D43 neither adapter's resolution ever queries one — the scan.lsp field in the artifact records whether a server was available to be consulted, not whether an edge came from it (note N2). Every edge in repo-graph.json today is confirmed by tree-sitter structure and filesystem/alias/barrel heuristics alone (§4.1 Levels 1–2), tagged extracted only when the relation needs no further guessing (rule 1, rule 10).

A broken source file behaves the same way at the file level: a parse failure produces a PARSE_FAILED diagnostic and a thinner entry for that one file (no declarations, but its file node and any import edges above the syntax error still appear, D41/D42) — the rest of the scan completes and the graph is still written (rule 7).

Documentation

Document Role
docs/SALAK-SDD-v1_4.md Binding specification. §3 is a contract.
docs/salak-wbs-v1_5.md Binding plan. Task list, dependency graph, sprints.
docs/schema-guide.md How to read repo-graph.json as a consumer: node/edge kinds, provenance semantics.
docs/AI-CONSUMER-PLAYBOOK.md Task-oriented companion for an AI assistant consuming repo-graph.json — freshness check first, question-to-field map, copy-pasteable CLAUDE.md/AGENTS.md snippet.
docs/cli-reference.md Every subcommand, flag, and exit code.
docs/troubleshooting.md What each diagnostic code means and how to act on it.
docs/RELEASING.md TestPyPI rehearsal and real PyPI publish runbook (owner-only).
project-memory/ Decision register, gap analysis, progress ledger, Spike 0 findings.
CLAUDE.md · AGENTS.md · context-pack.md Context packs for AI assistants working in this repo.

Earlier SDD (v1_3, v1_2, v1_1, v1.0) and WBS (v1_4, v1_3, v1_2, v1_1) revisions are superseded archives. Do not implement from them.

Development

uv sync
uv run ruff check . && uv run mypy src tests && uv run pytest

mypy is given src tests explicitly — the test suite carries part of the contract (a Protocol-conformance check lives in a test file), so excluding tests would turn that guarantee into a comment.

Licence

MIT — see LICENSE.

Chosen 2026-07-29, closing gap-analysis item G2. MIT rather than Apache-2.0 because Salak's job is to unblock other projects: it is a build tool that emits a JSON file, its own §1 says it is "not meant to become a product", and the fewest possible conditions on reuse serves that. Apache-2.0's express patent grant is the one thing MIT lacks; it would be the better choice for something with patentable algorithms or corporate contributors, and Salak has neither. Reversible at no cost until the first PyPI upload, and effectively permanent after.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

salak-0.2.0.tar.gz (1.3 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

salak-0.2.0-py3-none-any.whl (309.3 kB view details)

Uploaded Python 3

File details

Details for the file salak-0.2.0.tar.gz.

File metadata

  • Download URL: salak-0.2.0.tar.gz
  • Upload date:
  • Size: 1.3 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for salak-0.2.0.tar.gz
Algorithm Hash digest
SHA256 f9b625c1e14e024d714ea912ae9fc3be3e0587c4befcede198e7054aaa1a31ab
MD5 28dae3b37bf38545650894175372206f
BLAKE2b-256 88716e217b4803544bbb9c4609dac1319c0e08088e3aba2a204382b7a4c023f7

See more details on using hashes here.

Provenance

The following attestation bundles were made for salak-0.2.0.tar.gz:

Publisher: release.yml on edhoferdian/salak

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file salak-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: salak-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 309.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for salak-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ef3789a36134496eddc96e3d26c70d0f69d54add2a7d319af311dcefa8427a3a
MD5 84ff4bf2e5d8950d08c81a59fca9d6bf
BLAKE2b-256 619126abf534018fe15ad91239441830361cc0cac546ed5b15649c9eed2a7842

See more details on using hashes here.

Provenance

The following attestation bundles were made for salak-0.2.0-py3-none-any.whl:

Publisher: release.yml on edhoferdian/salak

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page