Give models signposting
for repos.
signpost compiles a repository into a map an agent reads before it starts work — so it begins oriented instead of re-deriving the same structure every session. One binary. No server, no embeddings, no index to keep warm.
$ signpost graph . analysed 143 files: 25 nodes, 27 edges no extractor for: .ps1 (1), .sh (1) history: 21 commits, 4 co-change pair(s) 25 nodes, 27 edges, 18 clusters hubs (top 10 by degree) /modules/signpost in 2 out 10 /modules/okf in 4 out 4 /modules/vcs in 4 out 3 /modules/assemble in 1 out 5 cross-cluster edges (7) /modules/assemble -imports-> /modules/graph /modules/signpost -imports-> /modules/discover disconnected components (17) 9 nodes: /modules/assemble, /modules/discover, and 7 more 1 nodes: /references/adr-0001-hand-written-tolerant-yaml-reader
The second line is signpost reporting two files it has no extractor for. Coverage is not opt-in: the absence of a measurement is never a clean bill of health. See this graph rendered.
install
macOS, Linux
curl -fsSL https://raw.githubusercontent.com/3rg0n/signpost/main/install.sh | sh
Windows
iex "& { $(irm https://raw.githubusercontent.com/3rg0n/signpost/main/install.ps1) }"
With a Go toolchain
go install github.com/3rg0n/signpost/cmd/signpost@latest
Both scripts verify the release archive against the SHA-256 digests
published with that tag, and install nothing if the digest does not
match. Pass --version v0.1.0 to pin a release.
why
An agent opening an unfamiliar repository rediscovers the same things every time: which module owns what, where the entrypoints are, which files move together, what the docs claim versus what the code does.
That work is paid for on every session, thrown away at the end of every session, and inconsistent between runs. signpost does the derivation once, at a known commit, and writes it down where people can correct it in place — so the corrections survive.
The output is Open Knowledge Format markdown committed to the repository. Agents, people, and static site generators read it directly, which means the bundle keeps working for everyone who does not have signpost installed. It maintains the bundle; it does not serve it.
confidence
A guess and a fact are drawn differently.
- extracted
- Read directly out of the repository. An import statement, a service in a compose file, a line in CODEOWNERS.
- inferred
- Proposed rather than read, and marked as such in every format signpost writes — dashed in the diagrams, verbatim in the data.
storage imports auth read out of an import statement and the same edge proposed by a model are different claims. A rendered graph that flattened the two would make the guess look like a measurement, which is the failure this tool exists to avoid — so no export format is permitted to drop the distinction, and an edge to a concept that does not exist is dropped rather than drawn to an invented one.
Everything amber on this page is something signpost has not verified.
properties
- Human edits compound. Generated prose lives between managed markers. Everything outside them is yours and is never touched. A generator that clobbers corrections teaches people to ignore it.
-
Stale fails loudly.
verifyexits non-zero. A silently stale knowledge artifact is worse than none, because it is confidently wrong. - Deterministic. Same commit in, identical bytes out. CI commits the bundle, so nondeterminism would mean commit churn in your repository.
- Works with no model at all. The deterministic pass produces a complete structural bundle on its own. A model only adds what prose alone can supply.
-
Secrets are references.
A Kubernetes Secret contributes its name and its key names; an
env_fileis recorded by path and never opened. The bundle gets committed. -
No third-party dependencies.
go.modhas norequireblock. The policy is not zero dependencies but patchable ones — few enough that shipping a CVE fix the day it lands stays routine.
reads
Go, TypeScript, JavaScript, Python, and Rust — imports, public surface, and entrypoints. Each extractor is scored against hand-labeled fixtures rather than asserted, at F1 1.000 for both imports and symbols.
Beyond source, signpost reads what a repository states about
itself: go.mod, package.json,
pyproject.toml, requirements.txt and
Cargo.toml for dependencies; Containerfiles, compose
files, GitHub Actions workflows, Kubernetes manifests and Helm
charts for deployment; protobuf, OpenAPI and GraphQL SDL for
contracts; SQL migrations, CODEOWNERS, ADRs and Makefiles for the
rest.
status
v0.1 in progress — the deterministic core. No model required, no network.
| Component | State |
|---|---|
| Graph model, metrics, Louvain clustering | done |
| Discovery: gitignore, classification, bounded reads | done |
| Extractors: Go, TS/JS, Python, Rust | done |
| Manifest and infrastructure extraction | done |
| Graph assembly and import resolution | done |
| Export: Mermaid, DOT, GraphML, JSON | done |
signpost graph, signpost export |
done |
| Git signals: co-change, churn, ownership | done |
signpost build — OKF emit, edit preservation |
done |
signpost verify |
done |
signpost.yml — rebuild on push, gate pull requests |
done |
| Semantic pass: local IPC, or any OpenAI-compatible endpoint | v0.2 |
| The graph viewer — in this repo, no JS dependencies | done |
| Viewer: search, diff between commits, deep links | v0.4 |
The deterministic core is usable end-to-end: build a bundle, commit it, and the workflow keeps it honest. What v0.2 adds is the summary that says what a module is for — the one thing no deterministic read can honestly produce, and so the one thing left as a placeholder rather than guessed at.