Skip to content

Commit 6b10185

Browse files
committed
docs: add the journey components, page templates, lint scripts and the llms.txt generator
1 parent 712f321 commit 6b10185

24 files changed

Lines changed: 2331 additions & 4 deletions

.github/styles/config/vocabularies/TraceMachina/accept.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,3 +318,11 @@ subtree
318318
hardlink
319319
multiplicatively
320320
SELinux
321+
repoint
322+
inlines
323+
permalinked
324+
gitignored
325+
inlined
326+
protobufs
327+
arg
328+
rustfmt

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ bazel-*
22
!tools/bazel-retry.sh
33
target/
44
nativelink-test/fuzz/target/
5+
.turbo/
56
.vscode/
67
.idea/
78
.zed

AGENTS.md

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
# AGENTS.md
2+
3+
A machine-readable map of the NativeLink repository for AI coding agents and new
4+
contributors. NativeLink is a high-performance remote build cache and execution
5+
platform (Remote Execution API), written in Rust.
6+
7+
Full documentation: https://docs.nativelink.com. Two entry points for machine
8+
readers, both generated from the docs navigation so neither can drift from the
9+
sidebar: https://docs.nativelink.com/llms.txt is the link index, one line per
10+
page in reading order, and https://docs.nativelink.com/llms-full.txt is the same
11+
corpus with page bodies inlined. Human contributor guide:
12+
[`CONTRIBUTING.md`](CONTRIBUTING.md).
13+
14+
## The four roles
15+
16+
NativeLink is four cooperating roles that speak the Remote Execution API:
17+
18+
- **CAS**: content-addressable storage for build inputs/outputs, keyed by digest.
19+
- **Action Cache (AC)**: maps an action's digest to its cached result.
20+
- **Scheduler**: queues actions and matches them to workers by platform property.
21+
- **Workers**: execute actions and stream results back to the CAS.
22+
23+
A single binary can run any combination of these, configured in JSON5.
24+
25+
## Crate map (where things live)
26+
27+
| Crate | Owns |
28+
| ----- | ---- |
29+
| `nativelink` (root, `src/bin/nativelink.rs`) | The server binary; wires config to running services. |
30+
| `nativelink-config` | JSON5 config schema. Stores in `src/stores.rs`, server/worker in `src/cas_server.rs`. Source of truth for the config reference. |
31+
| `nativelink-service` | gRPC services: CAS, AC, Execution, Capabilities, ByteStream, Worker API, BEP, health, fetch/push. |
32+
| `nativelink-store` | Every store implementation: filesystem, memory, redis, S3/R2/GCS/Azure/OCI/Mongo, and the composition stores (`fast_slow`, `shard`, `size_partitioning`, `compression`, `dedup`, `existence_cache`, `verify`, `ref`). |
33+
| `nativelink-scheduler` | Scheduler internals: matching engine, awaited-action DB, worker registry, state manager, retries. |
34+
| `nativelink-worker` | Worker: action execution, input materialization, sandboxing/namespaces, directory cache. |
35+
| `nativelink-util` | Shared utilities: `fs`/`fs_util`, `evicting_map`, `action_messages`, digests, and the OTLP metrics (`metrics.rs`). |
36+
| `nativelink-proto` | Generated protobufs (REAPI + NativeLink extensions). |
37+
| `nativelink-metric` / `nativelink-macro` | The `#[metric]` component-metrics derive system and proc macros. |
38+
| `nativelink-error` | The `Error` type and `ResultExt`. |
39+
| `nativelink-test` / `nativelink-redis-tester` | Test harness (`nativelink_test`) and Redis test tooling. |
40+
41+
## Where to change what
42+
43+
- **Add or change a config field**: edit the relevant spec in
44+
`nativelink-config/src/stores.rs` or `cas_server.rs`; the config reference is
45+
generated from the doc comments, so document the field there.
46+
- **Add a store type**: implement `StoreDriver` in `nativelink-store/src`, add
47+
its spec to `nativelink-config/src/stores.rs`, and wire it in the store factory.
48+
- **Add or change a gRPC service**: `nativelink-service/src/*_server.rs`.
49+
- **Change scheduling/matching/retries**: `nativelink-scheduler/src`.
50+
- **Change action execution / worker behavior**:
51+
`nativelink-worker/src/running_actions_manager.rs`.
52+
- **Add an OTLP metric**: declare and record it in
53+
`nativelink-util/src/metrics.rs`; record it at the call site; regenerate the
54+
metrics reference. Do not leave a metric declared-but-never-recorded: the
55+
generated reference has a column for exactly that, and it will say so.
56+
57+
## Changing X: source of truth, and the doc that must follow
58+
59+
When a change lands, this table says what else has to move with it. The rule is
60+
that the source of truth is always in the repo, and the doc either regenerates
61+
from it or cites it, never restates it by hand. Every path in the right-hand
62+
column is a real page under `web/apps/docs/content/docs/`.
63+
64+
| You changed | Source of truth | Doc that must follow |
65+
| ----------- | --------------- | -------------------- |
66+
| A config field or its doc comment | `nativelink-config/src/{stores,cas_server}.rs` | `reference/nativelink-config/*`; regenerate with `gen:config-reference`, never hand-edit |
67+
| A store's behavior or defaults | `nativelink-store/src/*` | the backend page under `how-to/stores/`, plus `reference/nativelink-config/store-overview` if the composition model moved |
68+
| A metric name, type, or label | `nativelink-util/src/metrics.rs` and its call sites | `reference/metrics` (regenerate with `gen:metrics-reference`) and `operate/observability` |
69+
| A CLI flag or `NL_*` env var | the binary's arg parsing | `reference/cli-and-env` |
70+
| A gRPC service or the set of services a server exposes | `nativelink-service/src/*_server.rs` | `configuration/servers-and-services`, which names every service as the config spells it |
71+
| Scheduler matching or platform-property semantics | `nativelink-scheduler/src` | `remote-execution/platform-properties`, and `explanations/architecture` if the model changed rather than the mechanics |
72+
| Worker sandboxing or input materialization | `nativelink-worker/src/running_actions_manager.rs` | `explanations/architecture` and `operate/security-hardening`; the second one states what the sandbox is *not* |
73+
| The licence header on a file, or `LICENSE` | the headers themselves | `reference/oss-and-enterprise`, which is the only place the licence split is explained |
74+
| The canonical production config | `deployment-examples/`, `nativelink-config/examples/` | `operate/production-config`; the snippets are lifted from there, not invented |
75+
| A page's URL | `web/apps/docs/content/docs/**/meta.json` | add a redirect in `web/apps/docs/next.config.mjs` |
76+
77+
## Build, test, verify
78+
79+
NativeLink builds with both Bazel and Cargo.
80+
81+
```bash
82+
bazel test //... # all tests (first run 10-20 min)
83+
bazel test //nativelink-store/tests:s3_store_test # one target
84+
bazel build //nativelink:nativelink # the server binary
85+
cargo test -p nativelink-store # a single crate with cargo
86+
```
87+
88+
Run the built server against a config:
89+
90+
```bash
91+
bazel run //nativelink:nativelink -- ./path/to/config.json5
92+
```
93+
94+
Example configs live in `nativelink-config/examples/` and runnable deployments in
95+
`deployment-examples/` (docker-compose, including a multi-worker set) and
96+
`integration_tests/`.
97+
98+
## The docs, and their gates
99+
100+
The docs site is a [Fumadocs](https://fumadocs.dev) app at `web/apps/docs`. Pages
101+
are MDX under `content/docs/`, and `meta.json` in each directory controls both the
102+
sidebar order and which pages are published.
103+
104+
```bash
105+
cd web && bun install
106+
bun run --filter docs dev # local docs server; regenerates first
107+
bun run --filter docs build # what CI builds
108+
bunx biome check --write . # lint and format
109+
110+
bun --filter @nativelink/docs lint:snippets # JSON5 snippets against the config schema
111+
bun --filter @nativelink/docs lint:anchors # explicit anchors on headings and FAQ entries
112+
```
113+
114+
Six things a docs change has to satisfy:
115+
116+
- **Vale and typos** run in pre-commit. New product nouns go in
117+
`.github/styles/config/vocabularies/TraceMachina/accept.txt`.
118+
- **Biome** formats and lints the TypeScript and the MDX components.
119+
- **Every nav entry resolves.** A `meta.json` entry naming a page that doesn't
120+
exist is a broken sidebar link, and `gen:llms` fails loudly on one.
121+
- **Moved URLs redirect.** Agents cache URLs longer than humans keep bookmarks;
122+
a 404 on an old path is a regression.
123+
- **`lint:snippets` passes.** Every key in a JSON5 config snippet has to exist in
124+
the generated config reference. A snippet that is deliberately wrong (showing
125+
a mistake, or a foreign tool's config) opts out with
126+
`{/* lint-snippets: ignore */}` above it.
127+
- **`lint:anchors` passes.** Every heading and every `<Accordion>` carries an
128+
explicit anchor, so rewording a heading cannot silently repoint a citation.
129+
`lint:anchors --fix` writes the anchor Fumadocs would have derived anyway,
130+
which means running it never moves an existing link.
131+
132+
Four things under `web/apps/docs` are generated. Regenerate them; never hand-edit:
133+
134+
| Generated | From | Command |
135+
| --------- | ---- | ------- |
136+
| `content/docs/reference/nativelink-config/*` | the `nativelink-config` crate, via `build-schema` | `gen:config-reference` |
137+
| `content/docs/reference/metrics.mdx` | `nativelink-util/src/metrics.rs` and its call sites | `gen:metrics-reference` |
138+
| `content/docs/reference/changelog.md` | the repository-root `CHANGELOG.md` | `gen:changelog` |
139+
| `public/llms.txt`, `public/llms-full.txt` | the navigation and page frontmatter | `gen:llms` |
140+
141+
The last two are gitignored and rebuilt by `dev` and `build`, so they cannot be
142+
committed in a stale state.
143+
144+
Page structure follows four archetypes (tutorial, how-to, explanation,
145+
reference), with a template for each in `web/apps/docs/templates/`. The
146+
conventions those templates encode:
147+
148+
- A narrative page never inlines an exhaustive field list. It explains the
149+
fields that carry a decision and links the generated reference for the rest.
150+
- Pages on the reading path (Getting started, Remote execution, Configuration,
151+
How-to guides, plus Why NativeLink before and Operate after) open with
152+
`<Prerequisites>`, so a reader landing cold from a search knows what the page
153+
assumes.
154+
- Tutorials and how-tos close with `<VerifyBlock>`: a checkable claim, not "it
155+
should work now".
156+
- Behavioural claims carry `<SourceLink>`, permalinked to a release tag rather
157+
than to `main`. The pinned ref lives in `web/apps/docs/lib/source-ref.ts`; bump
158+
it in the same change that regenerates the reference for a new release.
159+
- Headings carry an explicit `[#anchor]`, and `<Accordion>` entries an `id`, so
160+
a citation to a specific claim keeps resolving after the prose is reworded.
161+
162+
## Conventions
163+
164+
- Pre-commit runs rustfmt, `typos`, and (for docs) `vale`. Write to pass them.
165+
- The config reference under `web/apps/docs/content/docs/reference/nativelink-config`
166+
is autogenerated via the `build-schema` binary; regenerate, never hand-edit.
167+
- Prefer generating docs/reference from a code source of truth over hand-writing,
168+
to prevent drift.

web/apps/docs/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,9 @@ next-env.d.ts
88
# Generated from the repository-root CHANGELOG.md by scripts/gen-changelog.mjs
99
# (runs as part of `dev` and `build`).
1010
content/docs/reference/changelog.md
11+
12+
# Generated from the navigation and page frontmatter by scripts/gen-llms.mjs
13+
# (runs as part of `dev` and `build`). Committing them would create a second
14+
# source of truth for the sidebar, which is the thing they exist to prevent.
15+
public/llms.txt
16+
public/llms-full.txt

web/apps/docs/app/layout.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ import "./globals.css";
1212
export const metadata: Metadata = {
1313
title: {
1414
default: "NativeLink Docs",
15-
template: "%s NativeLink Docs",
15+
template: "%s | NativeLink Docs",
1616
},
17-
description: "Documentation for NativeLink high-performance remote build cache & execution.",
17+
description: "Documentation for NativeLink, a high-performance remote build cache and execution service.",
1818
metadataBase: new URL("https://docs.nativelink.com"),
1919
};
2020

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { cn } from "@nativelink/ui";
2+
3+
interface MinVersionProps {
4+
/** The first release in which this works, without the leading `v`. */
5+
v: string;
6+
className?: string;
7+
}
8+
9+
/**
10+
* Inline "needs at least this release" badge.
11+
*
12+
* Put one next to any field, flag, or command that does not exist in every
13+
* supported release. Readers land on these pages from search engines and from
14+
* agent caches, on whatever version they happen to be running, so "which
15+
* version is this?" has to be answerable on the page itself.
16+
*/
17+
export function MinVersion({ v, className }: MinVersionProps) {
18+
return (
19+
<span
20+
data-min-version={v}
21+
className={cn(
22+
"ml-1 inline-flex items-center rounded-full border border-brand/40",
23+
"bg-brand-soft/40 px-2 py-0.5 align-middle font-mono text-[0.7rem]",
24+
"font-semibold text-brand",
25+
className,
26+
)}
27+
>
28+
{v}+
29+
</span>
30+
);
31+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { cn } from "@nativelink/ui";
2+
import type * as React from "react";
3+
4+
interface NextStepProps {
5+
/** Where the reader goes next. */
6+
href: string;
7+
/** The destination's name, as the reader will see it in the sidebar. */
8+
title: string;
9+
/**
10+
* `next` continues along the reading path; `aside` is a useful detour that does
11+
* not advance the reader's position. Rendering them differently keeps the
12+
* main path obvious when a page offers both.
13+
*/
14+
kind?: "next" | "aside";
15+
/** Why the reader would go there: one sentence, not a description. */
16+
children: React.ReactNode;
17+
className?: string;
18+
}
19+
20+
/**
21+
* The journey handoff.
22+
*
23+
* A page that ends without telling the reader where to go next has dumped
24+
* information on them. This component renders that handoff the same way on
25+
* every page, so the path through the docs is visible rather than implied.
26+
*/
27+
export function NextStep({
28+
href,
29+
title,
30+
kind = "next",
31+
children,
32+
className,
33+
}: NextStepProps) {
34+
const isNext = kind === "next";
35+
return (
36+
<a
37+
href={href}
38+
data-next-step={kind}
39+
className={cn(
40+
"my-4 flex items-start gap-3 rounded-xl border px-5 py-4 no-underline",
41+
"transition-colors",
42+
isNext
43+
? "border-brand/40 bg-brand-soft/30 hover:border-brand/70"
44+
: "border-border bg-surface-elevated hover:border-border-strong",
45+
className,
46+
)}
47+
>
48+
<svg
49+
width="18"
50+
height="18"
51+
viewBox="0 0 24 24"
52+
fill="none"
53+
stroke="currentColor"
54+
strokeWidth="2"
55+
strokeLinecap="round"
56+
strokeLinejoin="round"
57+
className={cn(
58+
"mt-1 shrink-0",
59+
isNext ? "text-brand" : "text-muted-foreground",
60+
)}
61+
aria-hidden="true"
62+
>
63+
{isNext ? (
64+
<path d="M5 12h14m-6-6 6 6-6 6" />
65+
) : (
66+
<path d="M5 12h14m-6-6 6 6-6 6" opacity="0.55" />
67+
)}
68+
</svg>
69+
<span className="flex-1">
70+
<span className="block font-mono text-[0.7rem] font-semibold uppercase tracking-[0.12em] text-muted-foreground">
71+
{isNext ? "Next" : "Sideways"}
72+
</span>
73+
<span className="block font-semibold text-foreground">{title}</span>
74+
<span className="mt-0.5 block text-sm text-muted-foreground">
75+
{children}
76+
</span>
77+
</span>
78+
</a>
79+
);
80+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { cn } from "@nativelink/ui";
2+
import type { ReactNode } from "react";
3+
4+
interface PrerequisitesProps {
5+
/**
6+
* What the page assumes the reader already has, written as the state they
7+
* are in rather than the page they read: "a cache serving hits", not "the
8+
* quickstart". Link to the page that gets them there when there is one.
9+
*/
10+
children: ReactNode;
11+
className?: string;
12+
}
13+
14+
/**
15+
* States what a page assumes before its first step.
16+
*
17+
* Readers arrive mid-corpus from search and from agent caches, not only from
18+
* the page before. A page in an ordered section therefore has to say what it
19+
* assumes. Without that, a reader who lands on remote execution with no
20+
* working cache follows correct instructions to a broken result and blames
21+
* the product.
22+
*/
23+
export function Prerequisites({ children, className }: PrerequisitesProps) {
24+
return (
25+
<div
26+
data-prerequisites
27+
className={cn(
28+
"my-6 rounded-xl border border-border bg-surface-elevated px-5 py-3",
29+
className,
30+
)}
31+
>
32+
<p className="my-0 font-mono text-xs font-semibold uppercase tracking-[0.12em] text-brand">
33+
Before you start
34+
</p>
35+
<div className="mt-1 text-sm text-muted-foreground [&>p]:my-0">{children}</div>
36+
</div>
37+
);
38+
}

0 commit comments

Comments
 (0)