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

Will publish 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

Pre-release — 0.1.0.dev0. Phases 1–3 are shipped: each phase gate (TASK-039, TASK-062, TASK-083) returned ship, and salak scan, salak check, salak diff, salak validate, salak doctor and salak version all work today, against real repositories. Not yet on PyPI — publication is TASK-086/087, deliberately deferred until the owner runs it with publish credentials. Install from source for now (below).

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 in progress

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 source

Not on PyPI yet, so install from a clone:

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

That's it — no Node, no language servers required to run salak scan and get a full graph. uv run salak ... now works from inside the salak checkout.

To get a plain salak command on your PATH instead of prefixing every call with uv run from inside this checkout:

uv tool install --editable .

(Verified on this machine: uv tool install --editable . installs cleanly, and the resulting salak version prints the same output as uv run salak version.)

If you also want salak doctor to report on the language servers (informational only — see Requirements above), install Node.js, then from this checkout:

npm ci

Quickstart

Four commands, from install to a generated graph, run against any repository on your machine — not just this one:

uv sync
uv run salak scan /path/to/your/repo
uv run salak validate /path/to/your/repo/project-memory/repo-graph.json
uv run salak check /path/to/your/repo

scan writes the graph; validate confirms it matches its own declared schema version; check confirms the graph is still fresh against the working tree (it will be, immediately after a scan). 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 ..:

uv run 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:

$ uv run 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/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.1.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.1.0-py3-none-any.whl (298.1 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: salak-0.1.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.1.0.tar.gz
Algorithm Hash digest
SHA256 9b8fc2ba685cb1f891ab885d1237647c66129eb0230e35c9f295710db16b8d7f
MD5 3f2aebc7e33a074b3c9a5ec944a44a00
BLAKE2b-256 08a3926a025829cabda6aaa7efec4d1a7c20f0a46a58fc21ccc7bf2a73e5fd2b

See more details on using hashes here.

Provenance

The following attestation bundles were made for salak-0.1.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.1.0-py3-none-any.whl.

File metadata

  • Download URL: salak-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 298.1 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.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 71402ff9bc507363676dd005bee0f42ff498ff9fff5f3ba5158b26f7afcc4050
MD5 1e095021dc86c490a29ab4e6ff93abe0
BLAKE2b-256 d9c9532b013dd5cb262249e35c657ec99cb501c9b49413834bdeb7ecaf67f3bc

See more details on using hashes here.

Provenance

The following attestation bundles were made for salak-0.1.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

0.2.0

2 files

This release

0.1.0 This release

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