Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .claude/commands/llms.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Regenerate llms.txt + llms-full.txt

Regenerate `docs/llms.txt` (strict [llms.txt spec](https://llmstxt.org)) and `docs/llms-full.txt` (spec-aligned + preserved hand-written extras) from the current `docs/` tree.

## How it normally runs

The repo's `githooks/post-commit` hook runs `scripts/llms.js` automatically when a commit message contains the substring `llms.txt` (case-insensitive). If the regenerated files differ from what was committed, the hook creates a follow-up `chore: regenerate docs/llms.txt` commit.

So the day-to-day flow is just:

```bash
git commit -m "docs: add foo guide; updates llms.txt"
```

…and the hook handles the rest.

Use `/llms` only when you want to:
- Preview the output before committing
- Regenerate without committing (e.g., to sanity-check a refactor)
- Install the hook on a fresh clone

## Steps

1. **If `$ARGUMENTS` includes `install`:** Install the post-commit hook so future commits with the right trigger token regenerate automatically. Always use `--local` so the config lands in `.git/config`, not the global `~/.gitconfig`:
```bash
git config --local core.hooksPath githooks
chmod +x githooks/post-commit
```
Verify it stayed local: `git config --global --get core.hooksPath` should print nothing.

2. **Otherwise, run the generator:**
```bash
node scripts/llms.js
```

3. **If `$ARGUMENTS` includes `status`:** Show current file sizes and last-modified times instead of regenerating:
```bash
ls -lh docs/llms.txt docs/llms-full.txt
```

4. **Report the result:**
- File sizes for `docs/llms.txt` and `docs/llms-full.txt` (visible in script output)
- Section + page counts (visible in script output)
- Reminder: hand-written extras between `LLMS_EXTRAS_*` markers in `llms-full.txt` are preserved across regenerations
- Reminder: to commit the regenerated files via the post-commit hook, include `llms.txt` in the commit message

## Arguments

- No arguments: Regenerate both files
- `install`: Install the post-commit hook (one-time setup per clone)
- `status`: Show current file sizes and last-modified times without regenerating

## Output format

```
## llms.txt Generation

### Generated
- docs/llms.txt: 54.13 KB
- docs/llms-full.txt: 58.56 KB
- Sections: 5, pages: 300

### Notes
- Hand-written extras inside LLMS_EXTRAS markers in llms-full.txt preserved
- Include "llms.txt" in your commit message to trigger the hook on the next commit
```
4 changes: 3 additions & 1 deletion claude.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ Technical documentation for Base (Ethereum L2). Built with Mintlify.
| `mintlify dev` | Local dev server |
| `/lint` | Lint MDX files and fix issues |
| `/doc-feedback` | Review content quality |
| `/agents` | Generate AGENTS.md index for AI agents |
| `/agents` | Generate AGENTS.md index for AI agents (also runs via `githooks/post-commit` when commit message contains `agents.md`) |
| `/llms` | Regenerate `docs/llms.txt` and `docs/llms-full.txt` (also runs via `githooks/post-commit` when commit message contains `llms.txt`) |

## Structure

Expand Down Expand Up @@ -60,5 +61,6 @@ Edit `docs.json` to add/remove pages. Add redirects when removing pages.

1. Run `/lint` and fix errors
2. Run `/agents` if docs structure changed
- Or include `agents.md` / `llms.txt` in your commit message — the `githooks/post-commit` hook will regenerate the matching index files and create a follow-up commit. Enable hooks once per clone with `git config --local core.hooksPath githooks` (repo-scoped, never global).
3. Add redirects for removed pages
4. Verify links work
2 changes: 1 addition & 1 deletion docs/get-started/deploy-smart-contracts.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: 'Deploy Smart Contracts'
description: A guide to help you get started with deploying your smart contracts on Base.
description: Step-by-step guide to deploying smart contracts on Base.
---

Welcome to the Base deployment quickstart guide! This comprehensive walkthrough will help you set up your environment and deploy smart contracts on Base. Whether you're a seasoned developer or just starting out, this guide has got you covered.
Expand Down
326 changes: 323 additions & 3 deletions docs/llms-full.txt

Large diffs are not rendered by default.

428 changes: 311 additions & 117 deletions docs/llms.txt

Large diffs are not rendered by default.

100 changes: 94 additions & 6 deletions githooks/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,101 @@
# Hooks

To enable git hooks for this repo, run the following from the repo root:
Repo-local git hooks. Installation is scoped to **this clone only** — `git config --local` is used, so your global git config and other repos are untouched.

## Install

From the repo root:

```sh
# 1. Register the hooks directory
git config core.hooksPath githooks
./githooks/install.sh
```

Idempotent — safe to re-run. The script sets `core.hooksPath=githooks` (local to this `.git/config` only) and marks the hooks executable.

These hooks are scoped to this repo only:
- `--local` writes to `.git/config`, not your global `~/.gitconfig`.
- `githooks` is a relative path — it only resolves inside this repo.
- Every hook script `cd`s into the repo root and only modifies files under it.

# 2. Make the post-commit hook executable
chmod +x githooks/post-commit
Verify after install:

```sh
git config --local --get core.hooksPath # should print: githooks
git config --global --get core.hooksPath # should print nothing
```

Once installed, any commit message containing `agents.md` will automatically regenerate `docs/agents.md`.
## Configuration

Triggers, scripts, and outputs live in [`githooks/config.json`](./config.json). The hook logic itself never changes — to wire a new keyword to your own script, just add an entry:

```json
{
"skipToken": "[skip-docs]",
"generators": [
{ "name": "agents", "trigger": "agents.md", "script": "scripts/agents.js", "outputs": ["docs/agents.md"] },
{ "name": "llms", "trigger": "llms.txt", "script": "scripts/llms.js", "outputs": ["docs/llms.txt", "docs/llms-full.txt"] },
{ "name": "myindex", "trigger": "myindex.md", "script": "scripts/myindex.js", "outputs": ["docs/myindex.md"] }
]
}
```

Fields per generator:
- `name` — short label used in logs and the auto-commit subject
- `trigger` — case-insensitive substring matched against the commit message
- `script` — path (from repo root) to a node script that writes the outputs
- `outputs` — files the script writes; used to (a) detect a real diff vs `HEAD` and (b) exclude these files from structural-change detection so editing a generated file never auto-fires the hook

If `jq` isn't installed or `config.json` is missing/malformed, the hook falls back to built-in defaults equivalent to the two entries above. The hook never errors out just because the config layer is unavailable.

## post-commit

Regenerates docs index files when either:

1. **Auto** — the commit added, deleted, or renamed any `.md`/`.mdx` file under `docs/` (excluding the generated indexes themselves). Both generators run.
2. **Opt-in** — the commit message contains a trigger token (case-insensitive substring):

| Token in commit message | Regenerates | Generator |
|-------------------------|-------------|-----------|
| `agents.md` | `docs/agents.md` | `scripts/agents.js` |
| `llms.txt` | `docs/llms.txt` + `docs/llms-full.txt` | `scripts/llms.js` |

Both tokens may appear in the same message; both generators run. The auto path covers the "I added a new doc page and forgot the keyword" failure mode; the opt-in path covers content-only edits that affect `llms.txt` extraction without changing file structure.

If a regeneration produces a real diff vs `HEAD`, a single follow-up commit is created:

```
chore: regenerate docs/agents.md (post-commit of <short-sha>)
```

The `(post-commit of <sha>)` suffix links the auto-commit back to the commit that triggered it. Recursion is guarded so the follow-up commit doesn't re-trigger the hook.

## post-merge

Runs after `git pull` / `git merge`. **Does not modify the working tree** — it only prints a warning when the merge brought in structural docs changes (A/D/R), pointing you at `/agents` and `/llms` so you can regenerate when ready. The next docs commit will also auto-regenerate via `post-commit`.

This is intentional: regenerating files mid-pull would surprise you with uncommitted changes.

## Bypass

| When | How |
|------|-----|
| One commit (env) | `SKIP_DOCS_HOOK=1 git commit ...` |
| One commit (in message) | include literal `[skip-docs]` token |
| One pull/merge | `SKIP_DOCS_HOOK=1 git pull ...` |

Useful when you legitimately need to mention `agents.md` or `llms.txt` in a commit message without triggering regeneration ("fix link to agents.md").

## Debug

Set `DEBUG_DOCS_HOOK=1` for verbose logging on either hook:

```sh
DEBUG_DOCS_HOOK=1 git commit ...
DEBUG_DOCS_HOOK=1 git pull ...
```

## Uninstall

```sh
git config --local --unset core.hooksPath
```
70 changes: 70 additions & 0 deletions githooks/_lib.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# shellcheck shell=sh
# Shared loader for the docs hooks. Sourced by post-commit and post-merge.
#
# Reads githooks/config.json (via jq) and exposes:
# SKIP_TOKEN literal string that, when present in a commit msg, skips the hook
# GENERATORS_TSV one line per generator: name<TAB>trigger<TAB>script<TAB>outputs
# where outputs is a space-separated list
# EXCLUDE_REGEX ERE matching any generator output (used to exclude generated
# files from structural-change detection)
# ALL_OUTPUTS space-separated list of every output across all generators
#
# Falls back to built-in defaults if jq is missing or config.json is absent /
# malformed, so the hook never breaks just because someone uninstalled jq.

_lib_log() { [ -n "$DEBUG_DOCS_HOOK" ] && echo "[hooks-lib] $*" >&2; }

_use_defaults() {
SKIP_TOKEN='[skip-docs]'
GENERATORS_TSV=$(printf '%s\n%s\n' \
'agents agents.md scripts/agents.js docs/agents.md' \
'llms llms.txt scripts/llms.js docs/llms.txt docs/llms-full.txt')
EXCLUDE_REGEX='^docs/agents\.md$|^docs/llms(-full)?\.txt$'
ALL_OUTPUTS='docs/agents.md docs/llms.txt docs/llms-full.txt'
}

load_hooks_config() {
CONFIG_FILE="${REPO_ROOT:-$(git rev-parse --show-toplevel)}/githooks/config.json"

if ! command -v jq >/dev/null 2>&1; then
_lib_log "jq not installed; using built-in defaults"
_use_defaults
return
fi
if [ ! -f "$CONFIG_FILE" ]; then
_lib_log "$CONFIG_FILE missing; using built-in defaults"
_use_defaults
return
fi
if ! jq empty "$CONFIG_FILE" >/dev/null 2>&1; then
echo "[hooks-lib] WARN: $CONFIG_FILE is not valid JSON; falling back to defaults" >&2
_use_defaults
return
fi

SKIP_TOKEN=$(jq -r '.skipToken // "[skip-docs]"' "$CONFIG_FILE")

# TSV: name \t trigger \t script \t (outputs joined by space)
GENERATORS_TSV=$(jq -r '.generators[]
| [(.name // "?"), (.trigger // ""), (.script // ""), (.outputs // [] | join(" "))]
| @tsv' "$CONFIG_FILE")

ALL_OUTPUTS=$(jq -r '[.generators[].outputs[]] | join(" ")' "$CONFIG_FILE")

# Build an ERE that matches any output path exactly. Escapes . and / (the only
# regex metachars likely to appear in real output paths).
EXCLUDE_REGEX=$(jq -r '
[.generators[].outputs[]
| gsub("\\."; "\\.")
| "^" + . + "$"
] | join("|")
' "$CONFIG_FILE")

if [ -z "$GENERATORS_TSV" ]; then
echo "[hooks-lib] WARN: $CONFIG_FILE has no generators; falling back to defaults" >&2
_use_defaults
return
fi

_lib_log "loaded $(echo "$GENERATORS_TSV" | wc -l | tr -d ' ') generator(s) from config"
}
18 changes: 18 additions & 0 deletions githooks/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"_comment": "Trigger config for githooks/post-commit and githooks/post-merge. Edit to add your own triggers — the hook logic stays the same. Each generator: 'name' for the auto-commit subject; 'trigger' is a case-insensitive substring matched against the commit message; 'script' is run when triggered (or when a structural change is detected); 'outputs' are the files the script writes (used to detect real diffs and to exclude from structural-change detection).",
"skipToken": "[skip-docs]",
"generators": [
{
"name": "agents",
"trigger": "agents.md",
"script": "scripts/agents.js",
"outputs": ["docs/agents.md"]
},
{
"name": "llms",
"trigger": "llms.txt",
"script": "scripts/llms.js",
"outputs": ["docs/llms.txt", "docs/llms-full.txt"]
}
]
}
29 changes: 29 additions & 0 deletions githooks/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/sh
# Local install for this repo's git hooks.
# Scope: this clone only — never touches global git config or your $HOME.
#
# Usage: ./githooks/install.sh
set -e

REPO_ROOT=$(git rev-parse --show-toplevel)
cd "$REPO_ROOT"

# --local is the default for `git config`, but pass it explicitly so it's
# obvious from a code-read that this does NOT modify --global or --system.
git config --local core.hooksPath githooks
chmod +x githooks/post-commit githooks/post-merge

if ! command -v jq >/dev/null 2>&1; then
echo "Note: 'jq' not installed — hooks will use built-in defaults instead of githooks/config.json."
echo " Install with: brew install jq (or: apt-get install jq)"
fi

echo "Installed hooks for this repo (scope: --local, this clone only):"
echo " core.hooksPath = $(git config --local --get core.hooksPath)"
echo
echo "Hooks:"
echo " post-commit → regenerates docs indexes after a commit (auto on docs/ A/D/R, opt-in via 'agents.md' / 'llms.txt' keyword)"
echo " post-merge → warns when a pull/merge brought changes that drift docs indexes"
echo
echo "Bypass once: SKIP_DOCS_HOOK=1 git commit ... (or include [skip-docs] in the message)"
echo "Verify scope: git config --global --get core.hooksPath → should print nothing"
Loading
Loading