signpost

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, run on its own repository
$ 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. verify exits 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_file is recorded by path and never opened. The bundle gets committed.
  • No third-party dependencies. go.mod has no require block. 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.

Solid rows have shipped. Dashed rows have not.
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.