sealmap 0.2.1

Deterministic code maps and sealed diagram contracts for LLM development harnesses: stable symbol ids, signature and body hashes, a seal lockfile checked in CI, and dense Mermaid views
Documentation

sealmap

crates.io docs.rs

Deterministic code maps for LLM development harnesses: the facade and command-line tool of sealmap.

sealmap reads source without compiling it, builds a language-neutral model (symbols, relations, the ordered call flow of every function) and projects it into Mermaid diagrams with one document per source file. The same sources always give byte-identical output. Every symbol has a stable sym: id (no file path) and two fingerprints: sig_hash for its contract, body_hash for its implementation, both blind to formatting, comments and moves.

Hand-written diagram topics cite those ids, and a lockfile, seals.lock, records the hashes each cited symbol had when the topic was reviewed. sealmap verify checks every seal against the code in CI, with no LLM involved, and sealmap stale lists only the topics whose sealed symbols changed. sealmap dense writes a compact agent projection of the code, and sealmap pack a bounded review pack of chosen topics with the code they cite (see the design).

Crate Role
sealmap-model language-neutral code model
sealmap-mermaid typed Mermaid writers and injective diagram ids (no dependencies without the default model feature)
sealmap-extract logic shared by every language adapter (replaces sealmap-frontend, now a deprecated forwarding shim)
sealmap-rust Rust language adapter (syn)
sealmap-corpus projections, index and write; the seal lock, verify, seal_check, stale, resolve, sign; review packs (pack)
sealmap-dense compact agent projection: skeletons, call trees, short-name index, budgeted slices (sealmap::dense)

Command line

cargo install sealmap

sealmap generate .                  # write the corpus, model and index to .sealmap/ (gitignore it)
sealmap generate . --check          # exit 1 if .sealmap/ no longer matches a fresh generation
sealmap model    .  > model.json    # just the model
sealmap generate --repo api=../api --repo core=../core -o .sealmap   # several repositories as one
sealmap dense    . --stats          # the agent projection: dense.txt + _index.txt in .sealmap/dense

# Seals over the authored topics in docs/diagrams/ (lock: docs/diagrams/seals.lock)
sealmap resolve 'sym:cargo shop . db/Db#insert().'      # span and hashes, or absent + rename candidates
sealmap seal sign CP-03 --reviewer zai:glm-5.3 --model claude:sonnet   # seal one topic
sealmap verify                      # the CI gate: exit 1 unless every seal holds
sealmap seal-check CP-03            # classify chosen lock entries
sealmap stale --since main          # sealed symbols changed since a revision; exit 0

# Review packs: topics, dense slices of the code they cite, source windows
sealmap pack CP-03 CP-07 --budget 200000             # stdout; exit 1 naming each topic's size if over
sealmap pack --diff main --budget 200000 --shard -o packs/   # changed topics, split by topic

Exit codes: 0 success; 1 a check failed, an id is not found, or a seal was refused; 2 usage or IO error.

Library

use std::path::Path;

let corpus = sealmap::generate_dir(Path::new("."), &sealmap::Options::default())?;
let report = sealmap::corpus::write(Path::new(".sealmap"), &corpus)?;
println!("{} files updated", report.entries.len());
# Ok::<(), std::io::Error>(())

Ids and fingerprints, on sources held in memory:

use sealmap::model::{Fingerprint, SymbolId};
use sealmap::{SourceSet, rust};

let mut src = SourceSet::new();
src.insert("src/lib.rs", "pub struct Db;\nimpl Db { pub fn get(&self) -> u8 { 1 } }").unwrap();
let model = rust::extract(&src, &rust::RustOptions { name: "shop".into(), ..Default::default() }).codebase;

let id = SymbolId::parse("sym:cargo shop . Db#get().").unwrap();
let get = model.symbol(&id).unwrap();
assert!(get.sig_hash.to_string().starts_with(Fingerprint::PREFIX));

// Reformatting and comments change neither fingerprint.
let mut again = SourceSet::new();
again.insert("src/lib.rs", "pub struct Db;\n\n// note\nimpl Db {\n    pub fn get(&self) -> u8 {\n        1\n    }\n}\n").unwrap();
let model2 = rust::extract(&again, &rust::RustOptions { name: "shop".into(), ..Default::default() }).codebase;
let get2 = model2.symbol(&id).unwrap();
assert_eq!((get.sig_hash, get.body_hash), (get2.sig_hash, get2.body_hash));

Sealing in memory, and catching a behaviour change:

use sealmap::corpus::seal::{self, Class, Lock, Signature};
use sealmap::model::SourcePath;
use sealmap::{SourceSet, rust};

let opts = rust::RustOptions { name: "shop".into(), ..Default::default() };
let model = |body: &str| {
    let mut src = SourceSet::new();
    src.insert("src/lib.rs", format!("pub struct Db;\nimpl Db {{ pub fn get(&self) -> u8 {{ {body} }} }}")).unwrap();
    rust::extract(&src, &opts).codebase
};
let file = SourcePath::new("store/01-db.md").unwrap();
let topic = "---\nid: ST-01\n---\nReads go through `sym:cargo shop . Db#get().`.\n";
let who = Signature { reviewer: "r".into(), model: "m".into(), date: "2026-10-05".into() };

let mut lock = Lock::new();
let sealed = seal::sign(&mut lock, &file, topic, &model("1"), seal::LOCK_FILE, &who).unwrap();
let topics = [(file, sealed)].into_iter().collect();
let lock_text = lock.to_toml();

assert!(seal::verify(Some(&lock_text), seal::LOCK_FILE, &topics, &model("1")).passes());
let report = seal::verify(Some(&lock_text), seal::LOCK_FILE, &topics, &model("2"));
assert_eq!(report.failures().next().unwrap().class, Class::Behaviour);

Licence

Licensed under either of Apache License, Version 2.0 or MIT licence, at your option. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 licence, shall be dual licensed as above, without any additional terms or conditions.