# ADR 0011: Repository Conventions — Git Hooks and Markdown Link Syntax

## Status

Accepted

## Date

2026-06-08

## Context

Two small operational conventions emerged together as the repo grew and want to be remembered:

- **Where verification runs.** The repository has a CraftOS-PC harness (`just test`) and a fuller local CI path (`just ci`) that adds tool checks, `luacheck`, and harness regression guards. Agents and humans can be asked to commit and push changes, so verification can happen in two places: manually before Git operations and automatically inside Git hooks. Running the same tests manually and again in hooks makes workflows slower without improving the success contract, and risks divergent habits between human and agent paths.
- **How docs reference each other.** The `docs/` tree increasingly cross-references itself, and ADRs reference one another by number. `lychee` is wired into `just check` (`lint-markdown` recipe) so broken local links fail the build. Lychee only validates *links it can see*: a bare prose mention of `docs/foo.md` or `ADR-0005`, or a backticked path like `` `docs/foo.md` ``, is invisible to it. When a doc is renamed or moved, those mentions silently rot until a human happens to read the surrounding paragraph.

## Decision

### 1. Git hooks own commit/push verification

Install two local Git hooks through `just install` / `just install-git-hooks`:

- `.git/hooks/pre-commit` runs `just check test`.
- `.git/hooks/pre-push` runs `just ci`.

When an agent is explicitly asked to commit and/or push, it should not run `just test` manually before the Git operation. The hook is the source of truth for that workflow: commit triggers `just check test`, and push triggers `just ci`.

Manual verification is still appropriate outside commit/push workflows. For example, run `just test` while developing a behavior change, and run `just ci` when checking the full local state without pushing.

### 2. Markdown link syntax for cross-references

In every markdown file in the repository, references to other `.md` files must use markdown link syntax `[text](relative/path.md)`. This includes:

- Direct file references (`` `docs/install-craftos-pc.md` `` → `` [`docs/install-craftos-pc.md`](docs/install-craftos-pc.md) ``).
- ADR-number references (`ADR-0005` → `[ADR-0005](docs/adrs/adr-0005-craftos-pc-harness-and-probes.md)`, with the path adjusted to be relative to the referencing file).
- Plain-prose mentions (`called out in CLAUDE.md` → `called out in [CLAUDE.md](../../CLAUDE.md)`).

Excluded by design:

- Mentions inside fenced code blocks. They are example/code content; `lychee.toml` skips them via `include_verbatim = false`.
- Mentions inside inline code spans used purely to *illustrate* the wrong form. The reader can see they are placeholders, and lychee does not extract them as links either.
- A file's own title (e.g. `# CLAUDE.md` as a heading is not a reference).

Link paths are written relative to the file containing the link, so `lychee --offline` resolves them on the local filesystem with no `--base` indirection.

## Consequences

- Commit and push verification is consistent for humans and agents.
- Commit workflows avoid duplicating the same CraftOS-PC test run before and during `git commit`.
- Push workflows still get the full local CI gate before remote updates.
- The hooks are local files under `.git/hooks`, so developers should run `just install` after cloning or after hook behavior changes.
- `just lint-markdown` (and therefore `just check`, pre-commit, and pre-push) catches dead cross-references the moment a doc is moved or renamed.
- The markdown-link convention is *social* — humans and agents must remember to apply it when writing prose. Lychee enforces correctness only once a link exists; it cannot flag a mention that should have been a link but wasn't.
- The `[`path`](path)` style (backticked path as link text) is preferred for direct file references, matching the existing house style in [`docs/README.md`](../README.md) and [`docs/adrs/README.md`](README.md). For ADR mentions in flowing prose, `[ADR-####](path)` reads better than the backticked form.

## Future Work

- Revisit the verification split if `just test` becomes too slow for pre-commit or `just ci` gains checks that should also block commits.
- If rot reappears in prose despite the link convention, add a small grep-based lint that flags unbracketed `.md` and `ADR-####` mentions and wire it into `just check`. Deferred until there is evidence the social convention is insufficient.
