docs(agents): add generated LLM context workflow

This commit is contained in:
Tommaso Casaburi
2026-05-20 14:48:34 +07:00
parent 6a7df90129
commit d6d01c0571
6 changed files with 3328 additions and 155 deletions
+16
View File
@@ -30,6 +30,21 @@ Only record items that are repo-specific, likely to recur, and have a concrete m
- Clean up only artifacts created by the current change, such as newly unused imports or dead helper code. - Clean up only artifacts created by the current change, such as newly unused imports or dead helper code.
- For non-trivial work, define success criteria and verify them with the narrowest reliable checks before marking the task complete. - For non-trivial work, define success criteria and verify them with the narrowest reliable checks before marking the task complete.
## LLM Knowledge Base Policy
Use compiled context for orientation, not as source of truth.
Source of truth:
- Code, tests, package manifests, docs, and runtime/live evidence when relevant.
Compiled context:
- `AGENTS.md`, directory-specific `AGENTS.md` files, `CLAUDE.md`, and repo-managed `.codex/`, `.cursor/`, and `.claude/` workflow files.
- `docs/agent-playbooks/**`, `docs/agent-runs/**`, `docs/agent-playbooks/known-surprises.md`, and tracked `llms.txt` / `llms-full.txt` files when present.
Agents may use compiled context to navigate quickly, but must verify against source files before making behavioral claims or edits. External code graph, RAG, MCP, or wiki tools are optional local accelerators unless the developer explicitly asks to make one part of the committed workflow.
## Task Router (Read First) ## Task Router (Read First)
| Situation | Required action | | Situation | Required action |
@@ -38,6 +53,7 @@ Only record items that are repo-specific, likely to recur, and have a concrete m
| `package.json` changed | Run `corepack yarn install` to keep `yarn.lock` in sync | | `package.json` changed | Run `corepack yarn install` to keep `yarn.lock` in sync |
| Dependencies or import graph changed | Run `yarn knip` as an advisory manifest/import audit | | Dependencies or import graph changed | Run `yarn knip` as an advisory manifest/import audit |
| Translation key/value changed | Use `docs/agent-playbooks/translations.md` | | Translation key/value changed | Use `docs/agent-playbooks/translations.md` |
| Public-facing English content or AI context changed (`README.md`, `index.html`, `AGENTS.md`, `PRODUCT.md`, `DESIGN.md`, docs pages, or `scripts/generate-llms-files.mjs`) | Run `yarn llms:generate`; inspect and commit any resulting changes to `public/llms*.txt` so LLM indexes stay current |
| Bug report in a specific file/line | Start with git history scan from `docs/agent-playbooks/bug-investigation.md` before editing | | Bug report in a specific file/line | Start with git history scan from `docs/agent-playbooks/bug-investigation.md` before editing |
| `CHANGELOG.md` or package version changed | Run `yarn blotter:check`; if needed add a concise release one-liner | | `CHANGELOG.md` or package version changed | Run `yarn blotter:check`; if needed add a concise release one-liner |
| UI/visual behavior changed | Verify in browser with `playwright-cli` across Chrome/Blink, Firefox/Gecko, and WebKit/Safari; test desktop and mobile viewport; if existing browser state matters, confirm whether to use a fresh session or the contributor's current browser session | | UI/visual behavior changed | Verify in browser with `playwright-cli` across Chrome/Blink, Firefox/Gecko, and WebKit/Safari; test desktop and mobile viewport; if existing browser state matters, confirm whether to use a fresh session or the contributor's current browser session |
+1
View File
@@ -54,6 +54,7 @@
}, },
"scripts": { "scripts": {
"generate:assets": "node scripts/generate-asset-manifest.js", "generate:assets": "node scripts/generate-asset-manifest.js",
"llms:generate": "node scripts/generate-llms-files.mjs",
"release:manifest": "node scripts/generate-release-manifest.mjs", "release:manifest": "node scripts/generate-release-manifest.mjs",
"release:manifest:keygen": "node scripts/generate-release-manifest-keypair.mjs", "release:manifest:keygen": "node scripts/generate-release-manifest-keypair.mjs",
"sync:directories": "node scripts/sync-directories.js", "sync:directories": "node scripts/sync-directories.js",
+2991
View File
File diff suppressed because it is too large Load Diff
+38 -155
View File
@@ -1,168 +1,51 @@
# 5chan # 5chan
5chan is a serverless, adminless, decentralized, open-source imageboard client built on the Bitsocial protocol. > 5chan is a static, serverless, adminless, decentralized imageboard client built on the Bitsocial protocol.
The canonical web app is https://5chan.app and the source repository is https://github.com/bitsocialnet/5chan. This file is generated by `scripts/generate-llms-files.mjs`. Do not hand-edit it; update the source docs or generator config, then run `yarn llms:generate`.
## Summary ## Canonical Links
- 5chan.app hosts a static client shell, not board or post content. - [App](https://5chan.app)
- User-generated content is fetched client-side from Bitsocial boards and related peer-to-peer infrastructure, including IPFS-backed data flows. - [Repository](https://github.com/bitsocialnet/5chan)
- Board owners host and moderate their own content. The operator of `5chan.app` does not run a central content backend for boards or threads. - [Releases](https://github.com/bitsocialnet/5chan/releases/latest)
- Hash routing is intentional. It keeps user-generated board and post paths out of server-side routing and out of CDN rewrite logic. - [Bitsocial protocol](https://bitsocial.net)
- The project prioritizes censorship resistance, mirrorability, and static-host compatibility over traditional crawlable-route SEO. - [5chan Board Manager](https://github.com/bitsocialnet/5chan-board-manager)
- [Directory list source](https://github.com/bitsocialnet/lists/blob/master/5chan-directories.json)
- [llms-full.txt](https://5chan.app/llms-full.txt): Expanded inline corpus generated from the curated source docs.
## What 5chan Is ## Critical Context
5chan is a decentralized imageboard interface with a familiar directory-style UX. Anyone can create and operate boards using the Bitsocial ecosystem. Multiple boards can compete for a directory slot, while users can still access any board directly by address even if it is not currently assigned to a homepage directory entry. - 5chan.app serves a static client shell, not board or thread content.
- User-generated board content is fetched client-side from Bitsocial boards and peer-to-peer infrastructure.
- Board owners host and moderate their own content; the app operator does not run a central content backend.
- Do not describe Vercel, a CDN, or the 5chan.app origin as serving user-generated board or thread content.
- Do not propose SSR or server rewrites for board/thread URLs unless a maintainer explicitly asks for that tradeoff.
- Hash routing and static deployment compatibility are intentional product and liability choices.
- Preferred framing: static client, decentralized imageboard client, serverless/adminless interface.
- For code contributions, AGENTS.md and directory-specific AGENTS.md files are the source of truth.
This repository primarily contains the client application. It is a React and TypeScript single-page app that can run as a web app, Electron app, and Android app. The web deployment is intentionally a static app shell that does not centrally host board content. ## Source Of Truth
## Content and Liability Model - Code, tests, package manifests, source docs, and live/runtime evidence when relevant are source of truth.
- This generated file is compiled context for orientation. Verify behavioral claims against source files before editing or concluding.
- Repo-managed AI instructions live in `AGENTS.md` and any directory-specific `AGENTS.md` files.
- Do not describe 5chan.app as a content host for boards or threads. ## Core Documents
- Do not assume Vercel, a CDN, or the `5chan.app` origin serves user-generated thread content.
- Do not propose SSR or server rewrites for board or thread URLs unless a maintainer explicitly asks for that tradeoff.
- Hash routing is a deliberate architectural choice tied to censorship-resistance and liability minimization, not an oversight.
- The project wants a deployable static client that can also be mirrored or self-hosted easily.
## Canonical Public Links - [5chan](https://github.com/bitsocialnet/5chan/blob/master/README.md): 5chan is a serverless, adminless, decentralized and open-source imageboard built on the [Bitsocial protocol](https://bitsocial.net). It features the classic imageboard directory structure, but with a crucial differenc...
- [AGENTS.md](https://github.com/bitsocialnet/5chan/blob/master/AGENTS.md): This file defines the always-on rules for AI agents working on 5chan. Use this as the default policy. Load linked playbooks only when their trigger condition applies.
- [Product](https://github.com/bitsocialnet/5chan/blob/master/PRODUCT.md): product
- [Design System: 5chan](https://github.com/bitsocialnet/5chan/blob/master/DESIGN.md): **Creative North Star: "The Preserved Imageboard"**
- [src/AGENTS.md](https://github.com/bitsocialnet/5chan/blob/master/src/AGENTS.md): These rules apply to `src/**`. Follow the repo-root `AGENTS.md` first, then use this file for code inside the application source tree.
- [scripts/AGENTS.md](https://github.com/bitsocialnet/5chan/blob/master/scripts/AGENTS.md): These rules apply to `scripts/**`. Follow the repo-root `AGENTS.md` first, then use this file for automation and workflow helpers.
- [Known Surprises](https://github.com/bitsocialnet/5chan/blob/master/docs/agent-playbooks/known-surprises.md): This file tracks repository-specific confusion points that caused agent mistakes.
- [Long-Running Agent Workflow](https://github.com/bitsocialnet/5chan/blob/master/docs/agent-playbooks/long-running-agent-workflow.md): Use this playbook when a task is likely to span multiple sessions, handoffs, or spawned agents.
- [Bug Investigation Workflow](https://github.com/bitsocialnet/5chan/blob/master/docs/agent-playbooks/bug-investigation.md): Use this when a bug is reported in a specific file/line/code block.
- [Translations Workflow](https://github.com/bitsocialnet/5chan/blob/master/docs/agent-playbooks/translations.md): This project uses i18next translation files in `public/translations/{lang}/default.json`.
- [Skills and Tools](https://github.com/bitsocialnet/5chan/blob/master/docs/agent-playbooks/skills-and-tools.md): Use this playbook when setting up/adjusting skills and external tooling.
- App: https://5chan.app ## Optional
- Repository: https://github.com/bitsocialnet/5chan
- Releases: https://github.com/bitsocialnet/5chan/releases/latest
- README: https://github.com/bitsocialnet/5chan/blob/master/README.md
- Agent instructions: https://github.com/bitsocialnet/5chan/blob/master/AGENTS.md
- Bitsocial protocol site: https://bitsocial.net
- 5chan Board Manager: https://github.com/bitsocialnet/5chan-board-manager
- Directory list source: https://github.com/bitsocialnet/lists/blob/master/5chan-directories.json
## Architecture - [Changelog](https://github.com/bitsocialnet/5chan/blob/master/CHANGELOG.md): * **blotter:** render on multiboard feeds ([918ed5b](https://github.com/bitsocialnet/5chan/commit/918ed5b11b0ef7c2a982725077575d91853ed0f0)) * **boards bar:** preserve catalog multiboard links ([29f5e67](https://githu...
- [Upload Automation Retest Checklist](https://github.com/bitsocialnet/5chan/blob/master/docs/upload-automation-retest-checklist.md): Retest checklist for Android and desktop after changes to media upload automation (`MediaUploadAutomationRunner`, `MediaUploadRecipes`, `upload-orchestrator`, etc.).
- Frontend stack: React 19, TypeScript, React Router v6, Zustand, Vite, i18next, bitsocial-react-hooks
- Package manager: yarn
- Linting: oxlint
- Type checking: tsgo
- React app entry: `src/index.tsx`
- Static HTML shell and base metadata: `index.html`
- Main route tree: `src/app.tsx`
- Shared UI: `src/components/`
- Route views: `src/views/`
- Shared hooks: `src/hooks/`
- Shared state: `src/stores/`
- Utilities: `src/lib/`
## Important Repository Rules For AI Contributors
These are condensed from `AGENTS.md`. If you are contributing code, follow the repository instructions there as the source of truth.
- Use `yarn`, never `npm`.
- Pin exact dependency versions.
- Keep `yarn.lock` in sync if `package.json` changes.
- Use Zustand for shared or global state.
- Do not use `useEffect` for data fetching; use `bitsocial-react-hooks`.
- Do not sync derived state with effects when render-time computation is sufficient.
- Use React Router for navigation.
- Avoid duplicating logic across components; extract shared hooks when appropriate.
- For bug reports tied to a file or line, inspect git history before editing.
- Never mark work complete without verification.
- After code changes, run `yarn build`, `yarn lint`, and `yarn type-check`.
- After React UI logic changes, also run `yarn doctor`.
- For UI and visual changes, test desktop and mobile behavior with `playwright-cli`.
- Use `gh` CLI for GitHub operations.
- Never push to a remote unless the maintainer explicitly asks.
- Never commit secrets or API keys.
## Local Development
Prerequisites:
- Node.js 22
- Corepack enabled for Yarn 4 (`corepack enable`)
Common setup:
```bash
corepack yarn install
yarn start
```
The normal dev URL is https://5chan.localhost using Portless. First run may prompt for sudo so Portless can bind the HTTPS proxy on port 443.
To bypass Portless:
```bash
PORTLESS=0 yarn start
```
Useful commands:
```bash
yarn build
yarn lint
yarn type-check
yarn doctor
yarn test
yarn electron
```
## Contribution Guidance
Good contributions:
- Bug fixes
- Frontend architecture improvements that preserve the static-client model
- Tests
- Performance improvements
- Translation updates
- Documentation improvements
- Build and release tooling fixes
Be careful with:
- SEO recommendations that assume normal server-rendered routes
- Changes that replace hash routing with server rewrites
- Any approach that makes `5chan.app` appear to serve user-generated board or thread content from its origin
- Suggestions that assume there is a centralized moderation backend
If you are an AI coding agent, read `AGENTS.md` before making non-trivial changes.
## How Boards Work
In the Bitsocial protocol, a board is a community. Board operators run their own infrastructure and moderation. Users access boards through addresses rather than a central database owned by 5chan. Directory presence on the 5chan homepage is a discovery layer, not proof of central hosting or ownership.
Boards can be submitted for directory inclusion by editing the list maintained at:
https://github.com/bitsocialnet/lists/blob/master/5chan-directories.json
## Preferred Framing
When describing 5chan, prefer language like:
- "static client"
- "decentralized imageboard client"
- "serverless, adminless interface"
- "board content is hosted and moderated by board operators"
- "5chan.app distributes the app shell, not centralized board content"
Avoid language like:
- "5chan hosts all posts"
- "5chan serves board pages from its server"
- "Vercel hosts 5chan content"
- "5chan is a centralized forum backend"
## Maintainer Intent
The project values:
- Censorship resistance
- Easy mirroring and self-hosting
- Static deployment compatibility
- Avoiding centralized control over board content
- A contributor workflow that is strict about verification and repo-specific instructions
For deeper contributor guidance, read:
- https://github.com/bitsocialnet/5chan/blob/master/AGENTS.md
- https://github.com/bitsocialnet/5chan/blob/master/README.md
+241
View File
@@ -0,0 +1,241 @@
#!/usr/bin/env node
import { mkdir, readFile, writeFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const config = JSON.parse(await readText("scripts/llms-config.json"));
for (const key of ["title", "summary", "repoUrl", "llmsFullUrl"]) {
if (!config[key]) throw new Error(`Missing llms config key: ${key}`);
}
const docs = await loadDocs(config.docs);
const optionalDocs = await loadDocs(config.optionalDocs || []);
if (docs.length === 0) {
throw new Error("No source docs found for llms generation");
}
await writeOutputs(config.shortOutputs, buildShortFile(config, docs, optionalDocs));
await writeOutputs(config.fullOutputs, buildFullFile(config, docs, optionalDocs));
function buildShortFile(config, docs, optionalDocs) {
const lines = [
`# ${config.title}`,
"",
`> ${config.summary}`,
"",
"This file is generated by `scripts/generate-llms-files.mjs`. Do not hand-edit it; update the source docs or generator config, then run `yarn llms:generate`.",
"",
"## Canonical Links",
"",
...config.links.map(([label, url]) => `- [${label}](${url})`),
`- [llms-full.txt](${config.llmsFullUrl}): Expanded inline corpus generated from the curated source docs.`,
"",
"## Critical Context",
"",
...config.notes.map((note) => `- ${note}`),
"",
"## Source Of Truth",
"",
"- Code, tests, package manifests, source docs, and live/runtime evidence when relevant are source of truth.",
"- This generated file is compiled context for orientation. Verify behavioral claims against source files before editing or concluding.",
"- Repo-managed AI instructions live in `AGENTS.md` and any directory-specific `AGENTS.md` files.",
"",
"## Core Documents",
"",
...docs.map(formatDocLink)
];
if (optionalDocs.length > 0) {
lines.push("", "## Optional", "", ...optionalDocs.map(formatDocLink));
}
return `${lines.join("\n")}\n`;
}
function buildFullFile(config, docs, optionalDocs) {
const allDocs = [...docs, ...optionalDocs];
const lines = [
`# ${config.title} Full LLM Context`,
"",
`> ${config.summary}`,
"",
"This file is generated by `scripts/generate-llms-files.mjs`. Do not hand-edit it; update the source docs or generator config, then run `yarn llms:generate`.",
"",
"Use this as compiled context only. Source files, tests, manifests, and live/runtime evidence remain authoritative.",
"",
"## Index",
"",
...allDocs.map((doc) => `- [${doc.relativePath}](#${anchorFor(doc.relativePath)})`),
"",
"---"
];
for (const doc of allDocs) {
lines.push(
"",
`## ${doc.relativePath}`,
"",
`Source: ${doc.url}`,
"",
"```markdown",
doc.content.trim(),
"```",
"",
"---"
);
}
return `${lines.join("\n")}\n`;
}
function formatDocLink(doc) {
return `- [${doc.title}](${doc.url}): ${doc.summary}`;
}
async function loadDocs(relativePaths) {
const docs = [];
for (const relativePath of relativePaths) {
const content = await readOptional(relativePath);
if (!content) continue;
docs.push({
relativePath,
content,
title: titleFromMarkdown(content, relativePath),
summary: summaryFromMarkdown(content),
url: `${config.repoUrl}/blob/master/${encodeURI(relativePath).replace(/%2F/g, "/")}`
});
}
return docs;
}
function titleFromMarkdown(content, fallback) {
if (fallback.endsWith("CHANGELOG.md")) return "Changelog";
if (fallback.endsWith("TODO.md")) return "TODO";
let inFence = false;
let inFrontmatter = false;
let fallbackHeading = "";
const lines = content.split(/\r?\n/);
for (let index = 0; index < lines.length; index += 1) {
const trimmed = lines[index].trim();
if (index === 0 && trimmed === "---") {
inFrontmatter = true;
continue;
}
if (inFrontmatter) {
if (trimmed === "---") inFrontmatter = false;
continue;
}
if (trimmed.startsWith("```")) {
inFence = !inFence;
continue;
}
if (inFence) continue;
const h1 = trimmed.match(/^#\s+(.+)$/);
if (h1) return h1[1].trim();
const h2 = trimmed.match(/^##\s+(.+)$/);
if (h2 && !fallbackHeading) fallbackHeading = h2[1].trim();
}
return fallbackHeading || fallback;
}
function summaryFromMarkdown(content) {
const lines = content.split(/\r?\n/);
const paragraphs = [];
let current = [];
let inFence = false;
let inFrontmatter = false;
for (let index = 0; index < lines.length; index += 1) {
const line = lines[index];
const trimmed = line.trim();
if (index === 0 && trimmed === "---") {
inFrontmatter = true;
continue;
}
if (inFrontmatter) {
if (trimmed === "---") inFrontmatter = false;
continue;
}
if (trimmed.startsWith("```")) {
inFence = !inFence;
continue;
}
if (inFence || !trimmed || trimmed.startsWith("#") || trimmed.startsWith("|")) {
if (current.length > 0) {
paragraphs.push(current.join(" "));
current = [];
}
continue;
}
if (
trimmed.startsWith("[![") ||
trimmed.startsWith("_Telegram") ||
trimmed.startsWith("<img") ||
trimmed.startsWith("<p") ||
trimmed.startsWith("<br") ||
trimmed.startsWith("</") ||
trimmed.startsWith("<!--")
) {
continue;
}
current.push(trimmed.replace(/\s+/g, " "));
}
if (current.length > 0) paragraphs.push(current.join(" "));
const summary = paragraphs.find(Boolean) || "Repository documentation.";
return summary.length > 220 ? `${summary.slice(0, 217).trimEnd()}...` : summary;
}
function anchorFor(value) {
return value
.toLowerCase()
.replace(/[^a-z0-9\s-]/g, "")
.trim()
.replace(/\s+/g, "-");
}
async function writeOutputs(relativePaths, content) {
for (const relativePath of relativePaths) {
const absolutePath = path.join(rootDir, relativePath);
await mkdir(path.dirname(absolutePath), { recursive: true });
await writeFile(absolutePath, content);
console.log(`[llms] wrote ${relativePath}`);
}
}
async function readOptional(relativePath) {
try {
return await readText(relativePath);
} catch (error) {
if (error && error.code === "ENOENT") return "";
throw error;
}
}
async function readText(relativePath) {
return readFile(path.join(rootDir, relativePath), "utf8");
}
+41
View File
@@ -0,0 +1,41 @@
{
"title": "5chan",
"summary": "5chan is a static, serverless, adminless, decentralized imageboard client built on the Bitsocial protocol.",
"repoUrl": "https://github.com/bitsocialnet/5chan",
"llmsUrl": "https://5chan.app/llms.txt",
"llmsFullUrl": "https://5chan.app/llms-full.txt",
"shortOutputs": ["public/llms.txt"],
"fullOutputs": ["public/llms-full.txt"],
"links": [
["App", "https://5chan.app"],
["Repository", "https://github.com/bitsocialnet/5chan"],
["Releases", "https://github.com/bitsocialnet/5chan/releases/latest"],
["Bitsocial protocol", "https://bitsocial.net"],
["5chan Board Manager", "https://github.com/bitsocialnet/5chan-board-manager"],
["Directory list source", "https://github.com/bitsocialnet/lists/blob/master/5chan-directories.json"]
],
"notes": [
"5chan.app serves a static client shell, not board or thread content.",
"User-generated board content is fetched client-side from Bitsocial boards and peer-to-peer infrastructure.",
"Board owners host and moderate their own content; the app operator does not run a central content backend.",
"Do not describe Vercel, a CDN, or the 5chan.app origin as serving user-generated board or thread content.",
"Do not propose SSR or server rewrites for board/thread URLs unless a maintainer explicitly asks for that tradeoff.",
"Hash routing and static deployment compatibility are intentional product and liability choices.",
"Preferred framing: static client, decentralized imageboard client, serverless/adminless interface.",
"For code contributions, AGENTS.md and directory-specific AGENTS.md files are the source of truth."
],
"docs": [
"README.md",
"AGENTS.md",
"PRODUCT.md",
"DESIGN.md",
"src/AGENTS.md",
"scripts/AGENTS.md",
"docs/agent-playbooks/known-surprises.md",
"docs/agent-playbooks/long-running-agent-workflow.md",
"docs/agent-playbooks/bug-investigation.md",
"docs/agent-playbooks/translations.md",
"docs/agent-playbooks/skills-and-tools.md"
],
"optionalDocs": ["CHANGELOG.md", "docs/upload-automation-retest-checklist.md"]
}