Skip to content
agent-groundsPublic

About

Keep your agents grounded — specs, docs, and code as one knowledge graph, always in sync.

Topics

Resources

Contributing

Security policy

Stars

4 stars

Watchers

0 watching

Forks

Repository files navigation

grund

Keep your agents grounded — docs, values, and code as one knowledge graph, checked on every commit.

1 · Declare
Write a spec in docs/functional-spec/
# FS-login: Login
## format: Username format
### format.1: Surrounding whitespace
Trim surrounding whitespace.
2 · Cite
Cite it from the code in src/login.py
def clean_username(username):
    # §FS-login.format.1
    return username.strip()
3 · Read
Look it up before you change the code
$ grund FS-login.format.1
### format.1: Surrounding whitespace
Trim surrounding whitespace.
4 · Check
Misspell format, and CI fails
$ grund check
… not found: FS-login.fromat.1; …

CI crates.io License: MIT

Default structure

grund init lays a project out in layers, each citing the one that explains it, under rules it writes commented out in grund.toml until you adopt them:

Kind Home Cites
Why GRUND docs/grund.md
Where GOAL docs/goals.md should cite GRUND or GOAL
What FS docs/functional-spec/ should cite GOAL or FS; never AR
REQ docs/requirements/ should cite GRUND or GOAL; never AR
How AR docs/architecture/ should cite FS or GOAL
Proof e2e tests/e2e/ must cite FS; avoid AR
integration tests/integration/ should cite AR
Code code any other file should cite FS or AR
Decisions DF docs/decisions/functional/ should cite FS or GOAL
DA docs/decisions/architectural/ should cite AR or FS
Plan RM docs/roadmap.md

Every rule grund check holds a project to, what each one means underneath, and the finding it reports is listed in Schema and links. grund schema prints the ones a repository is held to on one screen, read from its grund.toml alone; examples/schema/ shows its table and Mermaid output.

Agent instructions

init also writes the structure into your agent's instructions, a managed block in AGENTS.md that grund check keeps current. The number in its heading is the block's revision, not a grund release (the setup guide says how the two differ). For example, grund's own AGENTS.md tells an agent how to read a citation:

A §<ID> is a pointer to a fact, not a file path. Resolve it with grund and climb only as far as needed:

  • grund <ID> — the lead, cut at the first child section: heading-less for a whole declaration, while grund <ID>.<section> opens with that section's heading line. The cheap first read for a bare §<ID> citation.
  • grund <ID> --toc — the lead plus the nested section map. Use to choose which subsection to fetch next.
  • grund <ID> --full — the entire body. Escalate to this when narrower reads aren't enough.

Where each kind lives in this repository:

  • GRUND: Why: project motivation
  • GOAL: Where: project direction and outcomes
  • FS: What: behavior, requirements, and constraints
  • REQ: Hard requirements: what grund must never break
  • AR: How: high-level implementation, structure, and design
  • …

How it writes:

  • Cite as you write. Place §<ID> at the point a claim or behavior is made — on the doc-comment for a whole behavior, inline beside the clause it enforces.
  • …
  • Inline citation style. Inline notes: ≤ 1 line preferred, hard cap 3 lines; ≤ 100 columns. A note is one comment block: a blank line splits it, an empty comment line does not. Doc-comments (///, //!, /** */, a docstring, a Go, Ruby, shell, SQL or Lisp comment right above a definition) are documentation, not notes: they are never measured, so cite in-sentence there.
  • Always cite the most-specific point.

And the table's rules, as it reads them:

must/never are grund check errors; should/avoid are suggestions (grund check --suggestions). …

  • Each FS declaration should cite GOAL or FS; never cite AR.
  • Each REQ declaration should cite GRUND or GOAL; never cite AR.
  • …
  • Each file in tests/e2e/ must cite FS; avoid citing AR.

For an agent without the managed block, the loop fits in one rule for its system prompt:

When you see §<ID> or §<ID>.<section> in any file you are reading, run grund <ID>[.<section>] and treat the output as the authoritative definition. Do not paraphrase or guess — quote what grund returned, or cite the ID and move on.

Quick start

cargo install grund

Run the following inside your repository if you are starting with new specs:

grund init --scaffold # config, agent instructions and starter files
grund check

Already have specs? Hand the setup to your agent:

grund guide setup   # the adoption guide, for your agent

Your agent inspects the repository, recommends settings for the specs you have, confirms each one with you, then writes grund.toml, runs grund init and validates. The command prints the core of the guide; the agent fetches each further section it needs with --section. To set up by hand instead, see setup. The runnable existing-structure adoption example starts with grund init --template=none, asks for the first kind's offline help, then declares the repository's own kinds.

Then:

  • add grund check to pre-commit and CI;
  • look up any key in the grund.toml reference, and point your editor at its JSON Schema;
  • grund.toml has two versions: version 2 (grund_config_version = 2) is what grund init writes, holding only what differs from a default, and grund config show prints every effective setting; a file without a version is version 1 and keeps loading unchanged. Version 1 reads the extensions [scan] lists, and version 2 names the languages it reads, maps suffixes to them, and lets only doc comments declare — see sources and its runnable example;
  • for prebuilt binaries and the Python and Node APIs, see installation.

Declaration format

A heading # <ID>: <title> in the kind's home declares an ID. The headings under it are its sections, each at the depth its path names: numbered, or named once [id] named_sections = true is set. This README's own requirement mixes both:

# REQ-readme: the README is the grounded shop window
…
## 1. What it must say
…
### 1.1 The loop
…
## evidence: Positioning and performance claims have evidence

They are cited as §REQ-readme.1.1 and §REQ-readme.evidence.

A section heading may write only the component it adds: under ## format: Formatting, ### .1: Username declares FS-login.format.1, and every citation, refs line and --toc shows that full path, as does the first line of a read of the section itself. Moving the block under another parent changes its address, so after citing a relative section run grund fmt --write with no path at the workspace root, or at the project root outside a workspace, and commit the section lock it writes, .grund/sections/FS-login.lock; check then says where a cited text went. See section headings and examples/relative-sections/. For declaration renames, follow the maintenance workflow and try the copy-based exercise in examples/relative-sections-lock/. fmt's preview names every kind of rewrite a line gets, its --write summary totals them, and a lock file the rename deletes or creates says so; read both in examples/fmt-reporting/.

A declaration can also live in code: a doc-comment that opens with the ID declares it, and a link from the kind's index enrolls it with no stub file. Grund's own AR-checker is declared only on the function it describes, in crates/grund-core/src/checker/report.rs:

/// AR-checker: how grund validates the scanner's findings
///
/// …
/// ## placement: Where the checker sits
/// …
pub(crate) fn check_on_disk(

grund AR-checker prints that prose without the /// markers.

Citation format

     ┌─────────────────── citation ───────────────────┐
            ┌───────────── ID ───────────────┐
  [§] [alias /] KIND - [number -] slug [.section]
   │     │        │       │         │       │
   │     │        │       │         │       └─ section: .3, .3.1, .format
   │     │        │       │         └───────── slug: [a-z0-9][a-z0-9-]*
   │     │        │       └─────────────────── optional ordinal (e.g., 001)
   │     │        └─────────────────────────── kind: FS, AR, … or your own
   │     └──────────────────────────────────── alias: root, api, …
   └────────────────────────────────────────── citation marker

[id] format picks one of three ID schemes, and a kind may override it:

Scheme Example Trade-off
{kind}-{number}-{slug} (default) FS-014-user-login the number stays stable; allocate it with grund id
{kind}-{number} FS-014 the most stable, but says nothing until resolved
{kind}-{slug} (grund's own) FS-user-login reads like English; renaming a slug rewrites its citations

The structure guide has the rest of the syntax, and a runnable example of each scheme. A link you write around a citation, in any form Markdown has, stays yours: grund fmt leaves it as written and grund check still checks the citation in it, as examples/authored-citations/ shows. It also explains why an index-only declaration warns while refs still lists its entry.

Workspaces

A monorepo of independently checked projects is a workspace: each member keeps its own grund.toml and its own IDs, the root lists the members, and a citation that crosses a project boundary names the target's alias. From the workspace example, the root's grund.toml and a member's spec:

project_name = "root"
# …
[workspace]
members = ["packages/*"]
include_root = true
# FS-session: API session

The API session model lives in this project. The platform-level coordinator
is §root/FS-platform.

grund check at the root checks every member, each in its own namespace; repository options has the details. A member a checkout may lack, such as a private package CI does not get, goes under optional_members; in a checkout without it, grund check does not judge the managed blocks' member lists and grund init keeps them as they are, as the optional-member example shows.

External facts

A GitHub issue, or a Jira or Linear ticket, is cited like any spec once a kind names the executable that fetches it. grund fetch <ID> saves it as a declaration in the repository; every other command reads that committed snapshot offline. From the external-tickets example:

[[kinds]]
kind = "GH"
file = "docs/tickets.md"
format = "{kind}-{number}"
resolve = "should"
fetch = "scripts/fetch-ticket"
$ grund check
… no snapshot for GH-1234 in docs/tickets.md — run grund fetch GH-1234
$ grund fetch GH-1234
$ grund GH-1234
The issue requests committed snapshots that resolve offline.

The external facts guide has the fetch contract and a GitHub integration to start from.

Values

A number a spec declares can be checked wherever it is used. With values = true on a kind, a declaration's numbered headings are its components, and a backticked literal beside a citation must equal them. From the values example, a physics simulation's time step:

# CONST-time-step: Integration time step
## 1. 0.001
## 2. s
Each solver step advances time by `1.0e-3 s` (§CONST-time-step).

A use that still quotes the step from before it was tuned fails the check, naming the root the line cites and the literal it wrote:

$ grund check
… whole binding: value mismatch for CONST-time-step (component 1): bound `0.002 s`, declared `0.001 s` …

The citation is right and the literal is stale, so the fix is 0.001 s, cited as before. Until grund 0.22.0 the line opens with the older component-only message, and from then it is the root's alone.

The values guide covers JSON and YAML declarations, values inside prose specs, and bindings in code comments.

Chapter rules

A convention can be written as one sentence and checked. With rules = true on a kind, each declaration's title is a rule in a small controlled English and its body says why. From the rules example:

# RULE-requirements: The requirements chapter of each FS must cite at least one REQ.

The requirement chapter carries the evidence, because §GOAL-rules makes conventions executable.

A rule can count chapters as well as citations: RULE-security, in the same example, says FS-demo must have exactly one security chapter. A spec with no such chapter, which cites its requirement from another chapter, fails both:

$ grund check
…
docs/fs/FS-demo.md:1: error: FS-demo has 0 security chapters; RULE-security requires exactly one; …
…
docs/fs/FS-demo.md:6: error: FS-demo.requirements must cite REQ (RULE-requirements); add such a citation within it

A sentence that does not parse is refused rather than guessed at, offering the one that would where it can tell, so a reader and grund check never give a rule two meanings. Try one before you commit it:

$ grund check --rule "Each FS may not cite any AR." --only-rule
error: modality "may not" is not accepted; accepted form: Each FS must not cite any AR.

The same example's RULE-overview-ceiling uses cite each AR at most once: zero or one citation to a target passes; two physical sites to the same target fail. Per-target at most 1 times is refused with an at most once rewrite.

grund init repeats every valid rule under ### Chapter rules in the agent instructions, so an agent reads the sentence check enforces. The chapter rules guide lists every accepted sentence, the finding each one reports, and every refusal.

Make citations clickable

Turn a §<ID> in your terminal into something you click, landing at the exact line it cites:

grund integrations                  # what applies in this environment
grund integrations wezterm          # review what it installs
grund integrations wezterm --write  # install it

Supported clients are codium, iterm2, kitty, tmux, vscode, and wezterm. --write is a one-time, idempotent user setup — the integration, the grund-open resolver, and a global instruction block for whichever agents you have installed. It changes no repository.

~/.local/bin must be on your PATH — that is where the resolver is installed, and it is not there by default on macOS, where a missing PATH entry makes every click silently do nothing.

Clickable citations is the full setup guide: the per-client reload each one needs, the manual step WezTerm and iTerm2 require, how to check it works, what to do when a click does nothing, and how to control the citations agents write in conversations.

Editor support via LSP

Install the optional language server separately when you want citation completion, editor diagnostics, hover previews, usage counts on declaration titles, definition jumps, document links, references, and live $$ → § formatting:

cargo install grund-lsp

The server speaks LSP over stdio and has no daemon or socket. For IntelliJ family IDEs, grund-lsp integrations lsp4ij --write <directory> generates the LSP4IJ import template carried by the installed binary.

Type § or $$ and it completes the declared IDs; see authoring and client bindings. The setup guide has the complete import and verification flow plus snippets for VSCode, Vim/Neovim, Emacs, Helix, Zed, and Sublime Text. Put reusable client config in your editor's user (global) settings, so the configuration is available across projects rather than only in repos that ship an editor config. In VSCode / VSCodium, user settings do not grant Workspace Trust; see the guide's trust prerequisite for the affected clients.

Hover preview of the misplaced-declaration spec point shown directly above the grund code that implements the misplaced-declaration check
Hover previews — the spec and the code that satisfies it, in one frame.

Dangling citation diagnostic showing the nearest declared ID hint
Error reporting — dangling citations are flagged inline with a "did you mean" hint.

Go-to-definition results listing FS-check.3.7 declaration and citation targets
Definitions & references — jump between a declaration and every §citation of it.

Go deeper

Guide For
Checking a repository what grund check enforces, its report, --watch, --only, pre-commit
grund.toml reference every key of both config versions, and the JSON Schema for your editor
Config explain what a key or a check code means and what clears a finding, from the grund you run, in your config's version — runnable example
Migrating to version 2 preview, repairs and preserving listed comments — runnable example
Structure and IDs kinds, ID schemes, citation syntax, inline declarations, front matter — runnable example
Querying grund selectors, batch reads, refs, cover — runnable example of refs on what nothing cites
Reviewing code a citation's blast radius, diff recipes
Chapter rules checked rules in controlled English — runnable example
Sources which files a version-2 project reads, and which comments declare — runnable example
Fields a version-2 kind's chapters as fields, their order, titles and values checked, and front matter as a field — runnable example, front matter
Values one value, declared once, checked wherever it is quoted
External facts cite tickets as committed offline snapshots
Workspaces citations across sub-projects
Related work where grund stands among academic work and open tools
All guides each beside its runnable example

grund --help is one screen; grund <command> --help is one page with flags, examples, and exit codes.

grund follows its own scheme: why, goals, roadmap, changelog. This README is under spec too — §REQ-readme: excerpts come from this repository or its runnable examples, whose citations are checked in their own repositories.

About

Keep your agents grounded — specs, docs, and code as one knowledge graph, always in sync.

Topics

Resources

Contributing

Security policy

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages