Literate source for all root-level project configuration files. Tangle pass: dir = "project/", gen = ".", << >> delimiters.

See architecture.adoc for the high-level overview.

Workspace Cargo.toml

Defines the Cargo workspace, shared versions, profile settings, and all workspace-level dependency versions.

# <<@file Cargo.toml>>=
# Cargo.toml

[workspace]
resolver = "2"

members = [
    "crates/weaveback-api",
    "crates/weaveback-macro",
    "crates/weaveback-tangle",
    "crates/weaveback-docgen",
    "crates/weaveback-core",
    "crates/weaveback-lsp",
    "crates/weaveback-agent-core",
    "crates/weaveback-py",
    "crates/wb-tangle",
    "crates/wb-query",
    "crates/weaveback-serve",
    "crates/wb-serve",
    "crates/wb-mcp",
]

[workspace.package]
version = "0.13.4"
edition = "2024"
authors = ["Gianni Ferrarotti <gianni.ferrarotti@gmail.com>"]
license = "0BSD OR MIT OR Apache-2.0"
repository = "https://github.com/giannifer7/weaveback"

[profile.release]
strip        = true
lto          = true
codegen-units = 1
opt-level    = 3
debug        = 0

[profile.release-debug]
inherits      = "release"
strip         = false
lto           = false
codegen-units = 16

[workspace.dependencies]
# Shared dependencies, mandated for the entire workspace:
clap = { version = "4.4", features = ["derive"] }
thiserror = "2.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
toml = "0.8"
regex = "1.9"
lazy_static = "1.4"
chrono = "0.4"

rusqlite = { version = "0.31", features = ["bundled"] }
similar = "2"
tiny_http = "0.12"
notify = "6"
ureq = { version = "2", features = ["json"] }

memchr = "2"
monty = { git = "https://github.com/pydantic/monty" }

blake3 = "1"
rayon = "1"
pulldown-cmark = { version = "0.12", default-features = false }

# Other potential shared dependencies:
wasm-bindgen = "0.2.84"
tempfile = "3.8"

# Dev/test dependencies we might want across the workspace:
pretty_assertions = "1.4"
assert_cmd = "2.0"
predicates = "3.0"
escargot = "0.5"

syn = { version = "2", features = ["full"] }
walkdir = "2"
lsp-types = "0.95"
url = "2.4"
pyo3 = { version = "0.28", features = ["extension-module"] }
pythonize = "0.28"

# Internal crate dependencies (points to the sub-crate on disk)
weaveback-api = { path = "crates/weaveback-api" }
weaveback-serve = { path = "crates/weaveback-serve" }
weaveback-core = { path = "crates/weaveback-core" }
weaveback-macro = { path = "crates/weaveback-macro" }
weaveback-tangle = { path = "crates/weaveback-tangle" }
weaveback-lsp = { path = "crates/weaveback-lsp" }
weaveback-agent-core = { path = "crates/weaveback-agent-core" }
acdc-parser = { git = "https://github.com/nlopes/acdc", rev = "56000a96343809a4d7ae7d09c71680b101d1a978" }
acdc-converters-core = { git = "https://github.com/nlopes/acdc", rev = "56000a96343809a4d7ae7d09c71680b101d1a978" }
acdc-converters-html = { git = "https://github.com/nlopes/acdc", rev = "56000a96343809a4d7ae7d09c71680b101d1a978", features = ["highlighting"] }
# @

justfile

Task runner configuration. just is the build system for weaveback — it dispatches to cargo, node, python scripts, and weaveback itself. The _wb variable prefers a locally-built release binary.

# <<@file justfile>>=
# justfile — weaveback workspace

# Prefer locally-built release wb-tangle; fall back to debug, then PATH.
_wb_tangle := if path_exists("target/release/wb-tangle") == "true" { \
                  "./target/release/wb-tangle" \
              } else if path_exists("target/debug/wb-tangle") == "true" { \
                  "./target/debug/wb-tangle" \
              } else { "wb-tangle" }

_pyproj := "."

# Default: list available recipes
default:
    @just --list

# ── Build ─────────────────────────────────────────────────────────────────────

# Build the whole workspace (debug)
build:
    cargo build

# Build the whole workspace (release)
release:
    cargo build --release

# Build the PyO3 extension in place for local Python development
py-build:
    cd {{_pyproj}} && uv run maturin develop

# Build a wheel for the Python package
py-wheel:
    cd {{_pyproj}} && uv run maturin build

# Build Linux wheels via cibuildwheel
py-wheel-ci:
    cd {{_pyproj}} && uv run --with cibuildwheel python -m cibuildwheel . --platform linux

# Build a manylinux wheel for CPython 3.14
py-wheel-manylinux:
    cd {{_pyproj}} && CIBW_BUILD='cp314-manylinux_x86_64' uv run --with cibuildwheel python -m cibuildwheel . --platform linux

# Build a musllinux wheel for CPython 3.14
py-wheel-musllinux:
    cd {{_pyproj}} && CIBW_BUILD='cp314-musllinux_x86_64' uv run --with cibuildwheel python -m cibuildwheel . --platform linux

# Sync the Python project environment
py-sync:
    cd {{_pyproj}} && uv sync

# Render the experimental option-spec sample into Rust/Python/docs/facts outputs
option-spec-demo:
    python3 scripts/option_spec/render.py --spec scripts/option_spec/specs/tangle.toml --out /tmp/weaveback-option-spec

# Run the option-spec experiment tests
option-spec-test:
    python3 -m unittest scripts/option_spec/tests/test_render.py

# Full local Python check cycle
py-check: py-build lint-python test-python

# ── Test ──────────────────────────────────────────────────────────────────────

# Run all tests
test:
    cargo test

# Run tests for weaveback-macro only
test-macros:
    cargo test --package weaveback-macro

# Run tests for weaveback-tangle only
test-noweb:
    cargo test --package weaveback-tangle

# Run Python tests
test-python:
    cd {{_pyproj}} && uv run pytest

# Measure Rust test coverage with cargo-llvm-cov
coverage:
    cargo llvm-cov --workspace --lcov --output-path lcov.info

# Regroup LCOV coverage by owning literate source and section
coverage-source:
    cargo llvm-cov --workspace --lcov --output-path lcov.info
    cargo run --package wb-query -- coverage lcov.info > coverage_by_source.json

# Generate an HTML Rust coverage report under coverage_report/
coverage-html:
    cargo llvm-cov --workspace --html --output-dir coverage_report

# ── Lint ──────────────────────────────────────────────────────────────────────

# Clippy (warnings as errors)
lint:
    cargo clippy -- -D warnings

# Python lint/type-check suite
lint-python:
    cd {{_pyproj}} && uv run ruff check .
    cd {{_pyproj}} && uv run pyright
    cd {{_pyproj}} && uv run --with mypy mypy python/weaveback-agent/src
    cd {{_pyproj}} && uv run --with pylint pylint python/weaveback-agent/src/weaveback_agent

# Format check
fmt-check:
    cargo fmt --check

# Apply formatting
fmt:
    cargo fmt

# Apply Python formatting
fmt-python:
    cd {{_pyproj}} && uv run ruff format .

# Find code duplicates
duplicates TARGET='.':
    npx jscpd -g --ignore "test-data/**,tree-sitter-weaveback/src/*.json" {{TARGET}}

# ── Run ───────────────────────────────────────────────────────────────────────

# Run wb-tangle on a file (usage: just tangle-file src/foo.adoc)
tangle-file FILE:
    cargo run --package wb-tangle -- "{{FILE}}"

# Serve docs/html/ locally with live reload and inline editor (dev build)
serve *ARGS:
    cargo run --release --package wb-serve -- {{ARGS}}

# Serve with auto-rebuild: edits to .adoc or theme sources trigger tangle + docs
dev *ARGS:
    cargo run --release --package wb-serve -- --watch {{ARGS}}

# Run weaveback-macro on a file (usage: just macros src/foo.md)
macros FILE:
    cargo run --package weaveback-macro -- "{{FILE}}"

# Run weaveback-tangle on a file (usage: just noweb src/foo.md)
noweb FILE:
    cargo run --package weaveback-tangle -- "{{FILE}}"

# ── Examples ──────────────────────────────────────────────────────────────────

# Regenerate the c_enum example
example-c-enum:
    cd examples/c_enum && cargo run --package wb-tangle -- status.adoc --gen .

# Regenerate the events fan-out example
example-events:
    cd examples/events && cargo run --package wb-tangle -- events.adoc --gen .

# Regenerate the nim-adoc example via meson/ninja
example-nim-adoc:
    meson setup examples/nim-adoc/build examples/nim-adoc --wipe
    ninja -C examples/nim-adoc/build

# Remove build intermediates from nim-adoc; keep gen/ and docs/html/ for commit
example-nim-adoc-clean:
    rm -rf examples/nim-adoc/build examples/nim-adoc/weaveback.db

# Render the examples index page to HTML (weaveback-docgen handles all .adoc)
examples-index: docs

# ── Packaging ─────────────────────────────────────────────────────────────────

# Build container stage: glibc | musl | windows | fedora
build-container TARGET:
    podman build --target {{TARGET}} -t weaveback-{{TARGET}} .

# Build container and export artifacts into dist/TARGET/
export TARGET: (build-container TARGET)
    mkdir -p dist/{{TARGET}}
    podman create --name weaveback-export-{{TARGET}} weaveback-{{TARGET}}
    podman cp weaveback-export-{{TARGET}}:/out/. dist/{{TARGET}}/
    podman rm weaveback-export-{{TARGET}}

# Build and export all targets
export-all: (export "glibc") (export "musl") (export "windows") (export "fedora")

# Bump Cargo.toml version first, then: just tag
# Commits Cargo.lock, tags, waits for CI, writes PKGBUILD to aur-weaveback-bin/, updates flake.nix
tag: lint
    python packaging/update_release.py --tag

# Re-tag HEAD (same version, re-triggers CI) then publish
re-tag:
    python packaging/update_release.py --retag

# Re-run publish only — tag already pushed and CI already done
update-release:
    python packaging/update_release.py

# ── Literate programming ──────────────────────────────────────────────────────

# Tangle all .adoc literate sources from weaveback.toml
tangle:
    {{_wb_tangle}}

# Install the split CLI tools (+ JDK for PlantUML diagrams with --diagrams)
# Pass extra args: just install --diagrams  /  just install --source
install *ARGS:
    python3 scripts/install.py {{ARGS}}

PLANTUML_JAR := "/usr/share/java/plantuml/plantuml.jar"

# Render all .adoc files to dark-themed HTML under docs/html/ (with Rust xref)
# --sigil % de-escapes % in files that use % as the macro sigil
# --sigil ^ de-escapes ^ in weaveback-macro adocs (which use ^ as sigil)
# --sigil ¤ de-escapes ¤¤ in markup-prelude documents
docs:
    node scripts/serve-ui/build.mjs
    cargo run --release --package weaveback-docgen -- \
        --sigil % --sigil ^ --sigil ¤ \
        --plantuml-jar {{PLANTUML_JAR}}

# Generate documentation with precise LSP-based cross-references (requires rust-analyzer)
docs-ai:
    node scripts/serve-ui/build.mjs
    cargo run --release --package weaveback-docgen -- \
        --sigil % --sigil ^ --sigil ¤ \
        --plantuml-jar {{PLANTUML_JAR}} \
        --ai-xref

# Semantic language server operations (requires rust-analyzer)
# Usage: just lsp definition crates/wb-query/src/main.rs 123 45
lsp *ARGS:
    cargo run --package wb-query -- lsp {{ARGS}}

# ── Clean ─────────────────────────────────────────────────────────────────────

# cargo clean + dist/
clean:
    cargo clean
    rm -rf dist/
# @

mise.toml

Project-local mise environment configuration. This keeps Cargo build outputs under a shared external root while still isolating this repository from other projects by using the project root name.

# <<@file mise.toml>>=
[env]
# This tells mise to load variables from a .env file in the same directory
_.file = ".env"

# Keep Cargo build artifacts outside the repository while avoiding a single
# global target directory shared by unrelated workspaces.
CARGO_TARGET_DIR = "/mnt/sda3/target/{{ config_root | basename }}"
# @

.gitignore

# <<@file .gitignore>>=
/target
/docs/html/

__pycache__/
*.py[oc]
build/
dist/
wheels/
*.egg-info

.env
.venv

.mypy_cache
.pytest_cache
.coverage
coverage_report/
lcov.info
coverage_by_source.json
cobertura.xml
codecov.json
*.profraw
all_coverage.log
new_coverage.log
summary.log
tangle_output.txt
big_chunks.txt
coverage_raw.txt
coverage_summary.txt
full_test_output.log
*.so
**/_weaveback.*.so

*.db
*.db-shm
*.db-wal

tarpaulin-report.html

.idea

.hist.txt
hist-search.txt
codex-resume.txt
codex-resume.sh
gemini-resume.txt

.codex
.gemini/
docs/.plantuml-cache/

chats
python/*
!python/weaveback-agent/
!python/weaveback-agent/**
!python/tests/
!python/tests/**
resume.txt

gen/

examples/**/*.db
examples/**/*.html
examples/**/build.log
examples/**/tmp/
examples/**/gen_ast_tmp/
examples/**/mem_test
examples/**/session_test
examples/**/hello
examples/visualization/graph.json

weaveback_*.log

scripts/serve-ui/node_modules/
scripts/serve-ui/.npm/
scripts/serve-ui/.pnpm-store/
/weaveback-guarded-agent/
# @

rust-toolchain.toml

Pins the Rust toolchain to nightly (required for let-chain syntax in edition 2024).

# <<@file rust-toolchain.toml>>=
[toolchain]
channel    = "nightly"
components = ["clippy", "rustfmt", "llvm-tools-preview"]
# @

.mcp.json

MCP server configuration — points Claude Desktop to the standalone wb-mcp server.

// <<@file .mcp.json>>=
{
  "mcpServers": {
    "weaveback": {
      "command": "wb-mcp"
    }
  }
}
// @

.vscode/settings.json

// <<@file .vscode/settings.json>>=
{
    "cmake.sourceDirectory": "/home/g4/_prj/weaveback/divagations/azantlr"
}
// @

weaveback.toml

Multi-pass tangle configuration. Each maps to one weaveback invocation. The global gen = "crates/" provides the default output directory for passes that don’t override it.

Note

This file is both the tangle configuration AND a generated output from this chunk. If just tangle reports "modified externally" for weaveback.toml, it means the file was edited directly without updating this adoc source.

# <<@file weaveback.toml>>=
# weaveback.toml — multi-pass tangle configuration for `wb-tangle`
# Each [[pass]] maps to one `weaveback` invocation.  Fields not present use
# the weaveback CLI defaults: open_delim = "<[", close_delim = "]>",
# chunk_end = "@", ext = "md".

gen = "crates/"

[[pass]]
dir = "crates/weaveback-lsp/"
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "crates/weaveback-core/"
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "crates/weaveback-core/src-wvb/"
gen = "crates/"
ext = "wvb"
sigil = "¤"
macro_prelude = ["prelude/asciidoc.wvb"]
expanded_ext = "adoc"
expanded_adoc_dir = "expanded-adoc/crates/weaveback-core/src"
open_delim = "<["
close_delim = "]>"

[[pass]]
dir = "crates/weaveback-core/src-wvb/"
gen = "crates/"
ext = "wvb"
sigil = "¤"
macro_prelude = ["prelude/markdown.wvb"]
expanded_ext = "md"
expanded_md_dir = "expanded-md/crates/weaveback-core/src"
macro_only = true
open_delim = "<["
close_delim = "]>"

[[pass]]
dir = "crates/weaveback-agent-core/"
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "crates/weaveback-agent-core/src-wvb/"
gen = "crates/"
ext = "wvb"
sigil = "¤"
macro_prelude = ["prelude/asciidoc.wvb"]
expanded_ext = "adoc"
expanded_adoc_dir = "expanded-adoc/crates/weaveback-agent-core/src"
open_delim = "<["
close_delim = "]>"

[[pass]]
dir = "crates/weaveback-agent-core/src-wvb/"
gen = "crates/"
ext = "wvb"
sigil = "¤"
macro_prelude = ["prelude/markdown.wvb"]
expanded_ext = "md"
expanded_md_dir = "expanded-md/crates/weaveback-agent-core/src"
macro_only = true
open_delim = "<["
close_delim = "]>"

[[pass]]
dir = "crates/weaveback-macro/"
ext = "adoc"
open_delim = "<<"
close_delim = ">>"
sigil = "^"

[[pass]]
dir = "crates/weaveback-macro/src-wvb/"
gen = "crates/"
ext = "wvb"
sigil = "¤"
macro_prelude = ["prelude/asciidoc.wvb"]
expanded_ext = "adoc"
expanded_adoc_dir = "expanded-adoc/crates/weaveback-macro/src"
open_delim = "<["
close_delim = "]>"

[[pass]]
dir = "crates/weaveback-macro/src-wvb/"
gen = "crates/"
ext = "wvb"
sigil = "¤"
macro_prelude = ["prelude/markdown.wvb"]
expanded_ext = "md"
expanded_md_dir = "expanded-md/crates/weaveback-macro/src"
macro_only = true
open_delim = "<["
close_delim = "]>"

[[pass]]
dir = "crates/weaveback-tangle/"
ext = "adoc"
no_macros = true
open_delim = "<["
close_delim = "]>"
comment_markers = "//"
chunk_end = "@@"

[[pass]]
dir = "crates/weaveback-tangle/src-wvb/"
gen = "crates/"
ext = "wvb"
sigil = "¤"
macro_prelude = ["prelude/asciidoc.wvb"]
expanded_ext = "adoc"
expanded_adoc_dir = "expanded-adoc/crates/weaveback-tangle/src"
open_delim = "<["
close_delim = "]>"

[[pass]]
dir = "crates/weaveback-tangle/src-wvb/"
gen = "crates/"
ext = "wvb"
sigil = "¤"
macro_prelude = ["prelude/markdown.wvb"]
expanded_ext = "md"
expanded_md_dir = "expanded-md/crates/weaveback-tangle/src"
macro_only = true
open_delim = "<["
close_delim = "]>"

[[pass]]
dir = "crates/weaveback-docgen/src-wvb/"
gen = "crates/"
ext = "wvb"
sigil = "¤"
macro_prelude = ["prelude/asciidoc.wvb"]
expanded_ext = "adoc"
expanded_adoc_dir = "expanded-adoc/crates/weaveback-docgen/src"
open_delim = "<["
close_delim = "]>"

[[pass]]
dir = "crates/weaveback-docgen/src-wvb/"
gen = "crates/"
ext = "wvb"
sigil = "¤"
macro_prelude = ["prelude/markdown.wvb"]
expanded_ext = "md"
expanded_md_dir = "expanded-md/crates/weaveback-docgen/src"
macro_only = true
open_delim = "<["
close_delim = "]>"

[[pass]]
dir = "crates/weaveback-docgen/"
ext = "adoc"
no_macros = true
open_delim = "<["
close_delim = "]>"
comment_markers = "//"
chunk_end = "@@"

[[pass]]
dir = "crates/weaveback-docgen/examples/"
gen = "crates/weaveback-docgen/examples/"
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "crates/weaveback-py/src/"
gen = "crates/"
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "crates/weaveback-api/src/"
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "crates/weaveback-api/src-wvb/"
gen = "crates/"
ext = "wvb"
sigil = "¤"
macro_prelude = ["prelude/asciidoc.wvb"]
expanded_ext = "adoc"
expanded_adoc_dir = "expanded-adoc/crates/weaveback-api/src"
open_delim = "<["
close_delim = "]>"

[[pass]]
dir = "crates/weaveback-api/src-wvb/"
gen = "crates/"
ext = "wvb"
sigil = "¤"
macro_prelude = ["prelude/markdown.wvb"]
expanded_ext = "md"
expanded_md_dir = "expanded-md/crates/weaveback-api/src"
macro_only = true
open_delim = "<["
close_delim = "]>"

[[pass]]
dir = "crates/weaveback-serve/src/"
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "crates/weaveback-serve/src-wvb/"
gen = "crates/"
ext = "wvb"
sigil = "¤"
macro_prelude = ["prelude/asciidoc.wvb"]
expanded_ext = "adoc"
expanded_adoc_dir = "expanded-adoc/crates/weaveback-serve/src"
open_delim = "<["
close_delim = "]>"

[[pass]]
dir = "crates/weaveback-serve/src-wvb/"
gen = "crates/"
ext = "wvb"
sigil = "¤"
macro_prelude = ["prelude/markdown.wvb"]
expanded_ext = "md"
expanded_md_dir = "expanded-md/crates/weaveback-serve/src"
macro_only = true
open_delim = "<["
close_delim = "]>"

[[pass]]
dir = "crates/wb-serve/src/"
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "crates/wb-mcp/src/"
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "crates/wb-tangle/src/"
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "crates/wb-query/src/"
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "scripts/serve-ui/"
gen = "scripts/serve-ui/"
ext = "adoc"
no_macros = true
open_delim = "<["
close_delim = "]>"
comment_markers = "//"
chunk_end = "@@"

[[pass]]
dir = "project/"
gen = "."
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "cli-spec/"
gen = "."
ext = "adoc"
open_delim = "<<"
close_delim = ">>"
include = "."

[[pass]]
dir = ".github/workflows/"
gen = ".github/workflows/"
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "packaging/"
gen = "packaging/"
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "scripts/"
gen = "scripts/"
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "windows/"
gen = "windows/"
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "test-data/"
gen = "."
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "examples/events/"
gen = "."
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "examples/hello-world/"
gen = "."
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "examples/c_enum/"
gen = "."
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "examples/nim-adoc/"
gen = "."
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "examples/graph-prototype/"
gen = "."
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"

[[pass]]
dir = "tree-sitter-weaveback/"
gen = "tree-sitter-weaveback/"
ext = "adoc"
no_macros = true
open_delim = "<<"
close_delim = ">>"
# @

Containerfile

Multi-stage container build for producing release artifacts across four target platforms: glibc (Debian), musl (Alpine), Windows (MinGW), Fedora.

# <<@file Containerfile>>=
# Containerfile — multi-stage packaging builds for weaveback
#
# Stages:
#   glibc   — Debian binaries + tarball          — includes Python/PyO3 + docs tooling
#   musl    — Alpine static CLI binaries         — Python wheels built separately
#   windows — MinGW cross-compiled CLI .exe      — Python wheels built separately
#   fedora  — Fedora binaries                    — includes Python/PyO3 + docs tooling
#
# Usage:
#   podman build --target glibc  -t weaveback-glibc  .
#   podman build --target fedora -t weaveback-fedora .
#
# Python policy:
#   - use uv as the package/tool runner
#   - keep maturin available for crates/weaveback-py
#   - keep mypy and pylint installed for python/weaveback-agent even before
#     they are wired into CI
#   - keep the runtime stages simple; these are primarily build/dev images
#   - build weaveback-py wheels separately via maturin/cibuildwheel rather than
#     forcing the generic musl/MinGW CLI release stages to compile a cdylib

# ── Rust base (Debian bookworm) ───────────────────────────────────────────────
FROM debian:bookworm-slim AS rust-base

RUN apt-get update && apt-get install -y --no-install-recommends \
        curl ca-certificates build-essential pkg-config git graphviz \
        python3 python3-dev python3-venv \
    && rm -rf /var/lib/apt/lists/*

ENV RUSTUP_HOME=/usr/local/rustup \
    CARGO_HOME=/usr/local/cargo \
    UV_INSTALL_DIR=/usr/local/bin \
    UV_TOOL_BIN_DIR=/usr/local/bin \
    PATH=/usr/local/cargo/bin:/usr/local/bin:$PATH

RUN curl https://sh.rustup.rs -sSf \
    | sh -s -- -y --default-toolchain stable --no-modify-path
RUN cargo install cargo-llvm-cov
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
RUN curl -fsSL https://d2lang.com/install.sh | sh -s -- --prefix /usr/local
RUN uv tool install --python /usr/bin/python3 maturin \
    && uv tool install --python /usr/bin/python3 mypy \
    && uv tool install --python /usr/bin/python3 pylint

# ── cargo-chef planner ────────────────────────────────────────────────────────
FROM rust-base AS planner
WORKDIR /src
RUN cargo install cargo-chef
COPY . .
RUN cargo chef prepare --recipe-path recipe.json

# ── dependency cacher ────────────────────────────────────────────────────────
FROM rust-base AS cacher
WORKDIR /src
RUN cargo install cargo-chef cargo-llvm-cov
COPY --from=planner /src/recipe.json recipe.json
RUN cargo chef cook --release --recipe-path recipe.json

# ── glibc: Linux binaries + tarball ──────────────────────────────────────────
FROM cacher AS glibc
COPY . .
RUN cargo build --release --workspace
RUN mkdir -p /out \
    && cp target/release/weaveback-macro    /out/weaveback-macro-glibc \
    && cp target/release/weaveback-tangle   /out/weaveback-tangle-glibc \
    && cp target/release/weaveback-docgen   /out/weaveback-docgen-glibc \
    && cp target/release/wb-tangle          /out/wb-tangle-glibc \
    && cp target/release/wb-query           /out/wb-query-glibc \
    && cp target/release/wb-serve           /out/wb-serve-glibc \
    && cp target/release/wb-mcp             /out/wb-mcp-glibc \
    && tar -czf /out/weaveback-x86_64-linux.tar.gz \
         -C target/release weaveback-macro weaveback-tangle weaveback-docgen wb-tangle wb-query wb-serve wb-mcp

# ── musl: static CLI binaries (Alpine) ────────────────────────────────────────
FROM alpine:latest AS musl
RUN apk add --no-cache curl build-base python3 python3-dev py3-virtualenv git graphviz
ENV RUSTUP_HOME=/root/.rustup \
    CARGO_HOME=/root/.cargo \
    UV_INSTALL_DIR=/usr/local/bin \
    UV_TOOL_BIN_DIR=/usr/local/bin \
    PATH=/root/.cargo/bin:/usr/local/bin:$PATH
RUN curl https://sh.rustup.rs -sSf \
    | sh -s -- -y --default-toolchain stable --no-modify-path
RUN cargo install cargo-llvm-cov
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
RUN curl -fsSL https://d2lang.com/install.sh | sh -s -- --prefix /usr/local
RUN uv tool install --python /usr/bin/python3 maturin \
    && uv tool install --python /usr/bin/python3 mypy \
    && uv tool install --python /usr/bin/python3 pylint
WORKDIR /src
COPY . .
RUN cargo build --release --target x86_64-unknown-linux-musl \
        -p weaveback-macro \
        -p weaveback-tangle \
        -p weaveback-docgen \
        -p wb-tangle \
        -p wb-query \
        -p wb-serve \
        -p wb-mcp
RUN mkdir -p /out \
    && cp target/x86_64-unknown-linux-musl/release/weaveback-macro   /out/weaveback-macro-musl \
    && cp target/x86_64-unknown-linux-musl/release/weaveback-tangle  /out/weaveback-tangle-musl \
    && cp target/x86_64-unknown-linux-musl/release/weaveback-docgen  /out/weaveback-docgen-musl \
    && cp target/x86_64-unknown-linux-musl/release/wb-tangle         /out/wb-tangle-musl \
    && cp target/x86_64-unknown-linux-musl/release/wb-query          /out/wb-query-musl \
    && cp target/x86_64-unknown-linux-musl/release/wb-serve          /out/wb-serve-musl \
    && cp target/x86_64-unknown-linux-musl/release/wb-mcp            /out/wb-mcp-musl

# ── windows: MinGW cross-compilation for CLI binaries ────────────────────────
FROM fedora:latest AS windows
RUN dnf install -y \
        curl git gcc \
        mingw64-gcc \
        mingw64-python3 \
    && dnf clean all
ENV RUSTUP_HOME=/usr/local/rustup \
    CARGO_HOME=/usr/local/cargo \
    PATH=/usr/local/cargo/bin:$PATH \
    CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER=x86_64-w64-mingw32-gcc \
    PYO3_CROSS=1 \
    PYO3_CROSS_LIB_DIR=/usr/x86_64-w64-mingw32/sys-root/mingw/lib
RUN curl https://sh.rustup.rs -sSf \
    | sh -s -- -y --default-toolchain stable --no-modify-path
WORKDIR /src
COPY . .
RUN rustup target add x86_64-pc-windows-gnu \
    && cargo build --release --target x86_64-pc-windows-gnu \
        -p weaveback-macro \
        -p weaveback-tangle \
        -p weaveback-docgen \
        -p wb-tangle \
        -p wb-query \
        -p wb-serve \
        -p wb-mcp
RUN mkdir -p /out \
    && cp target/x86_64-pc-windows-gnu/release/weaveback-macro.exe    /out/weaveback-macro-mingw64.exe \
    && cp target/x86_64-pc-windows-gnu/release/weaveback-tangle.exe   /out/weaveback-tangle-mingw64.exe \
    && cp target/x86_64-pc-windows-gnu/release/weaveback-docgen.exe   /out/weaveback-docgen-mingw64.exe \
    && cp target/x86_64-pc-windows-gnu/release/wb-tangle.exe          /out/wb-tangle-mingw64.exe \
    && cp target/x86_64-pc-windows-gnu/release/wb-query.exe           /out/wb-query-mingw64.exe \
    && cp target/x86_64-pc-windows-gnu/release/wb-serve.exe           /out/wb-serve-mingw64.exe \
    && cp target/x86_64-pc-windows-gnu/release/wb-mcp.exe             /out/wb-mcp-mingw64.exe

# ── fedora: Linux binaries ───────────────────────────────────────────────────
FROM fedora:latest AS fedora
RUN dnf install -y curl gcc pkg-config git graphviz python3 python3-devel python3-virtualenv && dnf clean all
ENV RUSTUP_HOME=/usr/local/rustup \
    CARGO_HOME=/usr/local/cargo \
    UV_INSTALL_DIR=/usr/local/bin \
    UV_TOOL_BIN_DIR=/usr/local/bin \
    PATH=/usr/local/cargo/bin:/usr/local/bin:$PATH
RUN curl https://sh.rustup.rs -sSf \
    | sh -s -- -y --default-toolchain stable --no-modify-path
RUN cargo install cargo-llvm-cov
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
RUN curl -fsSL https://d2lang.com/install.sh | sh -s -- --prefix /usr/local
RUN uv tool install --python /usr/bin/python3 maturin \
    && uv tool install --python /usr/bin/python3 mypy \
    && uv tool install --python /usr/bin/python3 pylint
WORKDIR /src
COPY . .
RUN cargo build --release --workspace
RUN mkdir -p /out \
    && cp target/release/weaveback-macro   /out/weaveback-macro-fedora \
    && cp target/release/weaveback-tangle  /out/weaveback-tangle-fedora \
    && cp target/release/weaveback-docgen  /out/weaveback-docgen-fedora \
    && cp target/release/wb-tangle         /out/wb-tangle-fedora \
    && cp target/release/wb-query          /out/wb-query-fedora \
    && cp target/release/wb-serve          /out/wb-serve-fedora \
    && cp target/release/wb-mcp            /out/wb-mcp-fedora
# @

flake.nix

Nix flake: pre-built musl binaries for x86_64-linux + dev shell.

Note

flake.nix is owned by packaging/update_release.py (flake() function), which rewrites it on each release with fresh SHA-256 hashes. It is not tangled from this document — the block below is a snapshot for reference only.

{
  description = "Bidirectional literate programming toolchain (noweb, macros, source tracing)";

  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";

  outputs = { self, nixpkgs }:
    let
      lib     = nixpkgs.lib;
      version = "0.9.0";
      base    = "https://github.com/giannifer7/weaveback/releases/download/v${version}";

      # Pre-built musl binaries are x86_64-linux only.
      # They package the CLI tools, which are a good fit for Nix consumption.
      #
      # The PyO3 extension is intentionally *not* exposed here as a pre-built
      # Nix package because it is Python-ABI- and platform-specific: for that
      # side we want wheels or a source build inside a dev shell, not a single
      # "universal musl" artifact.
      #
      # The devShell works on all common systems and includes the Python build
      # and lint tools needed for python/weaveback-agent and crates/weaveback-py.
      devSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
      forEachDevSystem = f: lib.genAttrs devSystems (s: f nixpkgs.legacyPackages.${s});

      linuxPkgs = nixpkgs.legacyPackages.x86_64-linux;

      releaseBin = { pname, sha256 }: linuxPkgs.stdenv.mkDerivation {
        inherit pname version;
        src        = linuxPkgs.fetchurl { url = "${base}/${pname}-musl"; inherit sha256; };
        dontUnpack = true;
        installPhase = "install -Dm755 $src $out/bin/${pname}";
      };

    in {

      packages.x86_64-linux = {
        default          = releaseBin { pname = "weaveback";         sha256 = "sha256-7Xzi0E4k7YSsXv1npNZM3NJ025sql8CrcYibZ6MtS00="; };
        weaveback-macro  = releaseBin { pname = "weaveback-macro";   sha256 = "sha256-nuZsJn7d4lHj1syUs1kJ1a3cCapDqMQ2kEns0TVBNUg="; };
        weaveback-tangle = releaseBin { pname = "weaveback-tangle";  sha256 = "sha256-lETexegXBPU9rQAwxCOjm52YkOR28OST+kWKid/U6Q4="; };
        weaveback-docgen = releaseBin { pname = "weaveback-docgen";  sha256 = "sha256-/QfiTpvL6qNIWANm56Q6P3PXuzkVTDBvlToZSGn4V0s="; };
      };

      # Full documentation + development toolchain.
      # Usage: nix develop
      devShells = forEachDevSystem (pkgs: {
        default = pkgs.mkShell {
          buildInputs = with pkgs; [
            just         # task runner
            plantuml     # UML diagrams via --plantuml-jar (brings JDK)
            nodejs       # TypeScript bundle for the serve UI
            python3      # packaging scripts and Python project runtime
            uv           # Python package / tool runner
            maturin      # PyO3 build frontend
            ruff         # Python formatter / linter
            mypy         # Python static typing
            pylint       # Python lint baseline
            git
          ];
          shellHook = ''
            echo ""
            echo "weaveback dev shell — available recipes:"
            echo "  just tangle     regenerate source files from .adoc"
            echo "  just docs       render HTML documentation"
            echo "  just serve      live-reload server with inline editor"
            echo "  just test       run all tests"
            echo "  just py-check   build + lint + test the Python agent bridge"
            if [ -f pyproject.toml ]; then
              echo "  syncing Python project with uv..."
              if ! uv sync --project . --all-groups; then
                echo "  warning: uv sync failed; continuing with the shell environment"
              fi
            fi
            echo ""
          '';
        };
      });
    };
}