Your coding agent giving you trust issues?
Enforce code quality, instead of asking nicely
graf run architecture-rules/
internal/http/handler.go:88
CreateOrder reaches the DB layer without a service
internal/http/user.go:41
GetUser calls legacy_fetch() — use fetch_v2()
2 violations · exit 1
Asking nicely doesn't scale.
Turn your architecture rules into checks that actually run — across files, through the call graph, through the type layer.
id: no-legacy-fetchseverity: errormatch: kind: function not: { files: "internal/legacy/**" } calls: legacy_fetch Bigger jobs run the same way.
A migration is the same file with more steps — each with its own selector, so one recipe threads a signature, repoints a constructor, relocates a file and reaps what that leaves dead, in turn.
id: retire-legacy-clientsteps: - id: thread-a-timeout # signature ripple — every call site remapped positionally match: { kind: symbol.method, name: fetch, memberOf: Client, files: "internal/legacy/**" } do: - sig: { append: "timeout: float = 5.0" } - id: repoint-the-constructor # every reference repo-wide, imports fixed per file match: { kind: symbol.function, name: new_legacy_client } do: - retarget: { to: "internal.data.client.new_client" } - id: relocate-the-helpers # move the file, rewrite every importer match: { kind: file, files: "internal/legacy/util.py" } do: - move: { to: "internal/data/util.py" } - id: reap-what-is-now-dead # only what nothing uses — a live decl is refused match: { kind: symbol.function, files: "internal/legacy/**", usedBy: { count: 0 } } do: - delete: {} verify: - match: { kind: symbol, name: new_legacy_client, referencedBy: {} } expect: { count: 0 }gate: "pytest -q"Every step commits atomically, behind one gate — and a step that would break something pauses instead, with the blockers listed.
One graph. Every layer of your code.
graf builds a semantic graph of your codebase — AST, cross-file symbols and types — and lets you write rules against actual structure in YAML rather than text patterns.
Local-first
One binary, no daemon or network access needed. Nothing leaves the machine.
Cross-file by construction
Symbols and types resolved repo-wide.
Polyglot by design
One graph schema, one rule language, per-language importers.
CLI-first, agent-ready
Drive it yourself from the terminal, or let your coding agent drive it — we ship a skill.
Your linter sees one file at a time. graf sees the whole project.
Platforms & languages.
Runs anywhere you build. macOS · Linux · Windows.
- Goshipped
- Pythonshipped
- TypeScriptnext
- Javaplanned
- JavaScriptplanned
- .NETplanned
- C / C++planned
- Rubyplanned
- PHPplanned
- Rustplanned