-
Notifications
You must be signed in to change notification settings - Fork 68.2k
Add CLAUDE.md documenting codebase structure and workflows #45205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| # CLAUDE.md | ||
|
|
||
| This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. | ||
|
|
||
| ## What this repository is | ||
|
|
||
| This is the source for [docs.github.com](https://docs.github.com) — a Next.js/Express application that renders Markdown content (with Liquid templating and versioning) into GitHub's product documentation site. The vast majority of contributions are content changes (Markdown in `content/`); application code (Node.js/Express/React/Next.js) is a smaller, separate concern. | ||
|
|
||
| Note: GitHub's Docs team writes pre-production content in a private repo (`docs-internal`) that syncs with this public repo, so some workflows referenced in docs (e.g. Early Access) assume that private counterpart. | ||
|
|
||
| ## Commands | ||
|
|
||
| ```sh | ||
| npm ci # install deps (run once per pulled branch) | ||
| npm ci --include=optional # also installs test-only deps like puppeteer (needed to run full test suite locally) | ||
| npm run build # next build — creates static assets (run once per pulled branch, and again if tests fail complaining about missing production build) | ||
| npm start # dev server at localhost:4000, only 'en' and 'ja' enabled by default (NODE_ENV=development) | ||
| npm run debug # dev server with --inspect for VS Code's Node debugger | ||
|
|
||
| npm test # run full jest suite | ||
| npm test -- <TEST_NAME> # run tests matching a filename/partial filename/path | ||
| NODE_OPTIONS=--experimental-vm-modules npx jest tests/unit # run a specific test directory directly | ||
| npm run test-watch # watch mode with coverage | ||
|
|
||
| npm run lint # eslint on **/*.{js,mjs,ts,tsx} | ||
| npm run tsc # typescript check (tsc --noEmit) | ||
| npm run prettier # auto-format ts/tsx/js/mjs/scss/yml/yaml | ||
| npm run prettier-check # check formatting without writing | ||
| ``` | ||
|
|
||
| - Node version is pinned to **16.x** (see `.node-version` / `engines` in `package.json`). | ||
| - To enable more languages locally, temporarily edit `ENABLED_LANGUAGES` in the `start` script in `package.json` (language codes defined in `lib/languages.js`). | ||
| - Visit `localhost:4000/dev-toc` while the dev server is running to see the full site table of contents (internal-only route, not on production). | ||
| - Git LFS is required (`pre-push`/`post-checkout`/`post-merge` husky hooks call into `git-lfs`). | ||
| - `husky` pre-commit hook runs `script/prevent-translation-commits.js` (blocks commits that touch `translations/`, since those are Crowdin-managed) and `lint-staged` (eslint --fix + prettier on staged files). | ||
| - `script/` follows the ["Scripts to Rule Them All"](https://githubengineering.com/scripts-to-rule-them-all/) pattern: `script/bootstrap` = install, `script/server` = start dev server, `script/test` = run tests. Prefer writing new scripts in JavaScript over Bash (repo is developed cross-platform, including Windows). | ||
|
|
||
| ## Architecture | ||
|
|
||
| ### Request flow | ||
|
|
||
| `server.mjs` boots an Express app (`lib/app.js`) that composes middleware from `middleware/index.js` in a specific, order-sensitive pipeline: language detection → request `context` building → redirects → `find-page` (resolves URL to a content file) → Next.js page rendering. Two middleware subdirectories matter: | ||
| - `middleware/contextualizers/` — populate `req.context` (the object templates/pages render from). | ||
| - `middleware/redirects/` — handle the various redirect mechanisms (external sites, language-code redirects, `redirect_from` frontmatter, etc). | ||
|
|
||
| Pages live under `pages/[versionId]/...` using Next.js file-system routing; most product content is served through the catch-all `pages/[versionId]/[productId]/[...restPage].tsx`, with a few products (REST, GraphQL, Admin release notes) having dedicated page files because they need custom rendering. | ||
|
|
||
| ### Content model (the part contributors touch most) | ||
|
|
||
| - **`content/`** — all English Markdown source, organized by product/category. Every Markdown file has YAML frontmatter validated against a schema in `lib/frontmatter.js` (see `contributing/content-markup-reference.md` for the full field reference). Key frontmatter: | ||
| - `versions` (required on every page) — which products/releases (`fpt`, `ghes`, `ghae`, etc., see `lib/all-versions.js`) the page applies to. Drives both routing and in-page Liquid conditionals. | ||
| - `redirect_from` — old URLs that should redirect to this page. | ||
| - `children` (required on `index.md`) — the site only knows about pages listed in some ancestor's `children`; anything not reachable via `children` 404s. `childGroups` is additionally required on the homepage `index.md`. | ||
| - Filenames must be a kebab-case match of `title` (enforced by tests) unless `allowTitleToDifferFromFilename: true` is set. | ||
| - **`data/`** — YAML/Markdown exposed to templates via the `{% data %}` Liquid tag. Subdirectories: `reusables/` (long reusable text blocks, one per Markdown file), `variables/` (short reusable strings), `features/` (feature-based versioning), `glossaries/`, `learning-tracks/`, `graphql/` (schema synced from `github/github`), `webhooks/` (payload JSON), `release-notes/`. Most YAML/Markdown under `data/` and `content/` is translated via Crowdin by default. | ||
| - **`includes/`** — Liquid include templates (`.html`), notably `includes/liquid-tags/` for custom tags. | ||
| - **Rendering pipeline** — `lib/render-content/` turns Markdown + Liquid + context into HTML, built on `remark`/`unified` with custom plugins in `lib/render-content/plugins/` (link rewriting per language/version, asset path rewriting, code block headers, etc). | ||
| - **Versioning happens at two layers**: frontmatter `versions` (page-level availability) and inline Liquid conditionals (`{% ifversion %}` etc., can appear in `content`, `data`, and `includes`) for version-specific content within a single page. See `contributing/liquid-helpers.md` and `contributing/permalinks.md`. | ||
| - **Custom Markdown extensions**: callout tags (`{% note %}`/`{% warning %}`), OS tags (`{% mac %}`/`{% windows %}`/`{% linux %}`), tool tags (`{% webui %}`/`{% cli %}`/`{% desktop %}`/`{% curl %}`/`{% codespaces %}`/`{% vscode %}`/`{% importer_cli %}`/`{% graphql %}`), Octicons (`{% octicon "name" %}`) — see `contributing/content-markup-reference.md`. | ||
| - **Local links** must start with a product ID (e.g. `/actions`); image paths must start with `/assets`. These get rewritten server-side per language/version (`lib/render-content/plugins/rewrite-local-links.js`). To stop a link from being enterprise-ified, use raw HTML with `class="dotcom-only"`. | ||
|
|
||
| ### Translations | ||
|
|
||
| `translations/<lang>/` mirrors `content/` and `data/` per locale (currently `es-ES`, `ja-JP`, `pt-BR`, `zh-CN`), synced via Crowdin. **Never hand-edit files under `translations/`** — the pre-commit hook (`script/prevent-translation-commits.js`) blocks this by default; it's only overridable via `ALLOW_TRANSLATION_COMMITS` for the sync tooling itself. | ||
|
|
||
| ### REST/GraphQL/webhook docs | ||
|
|
||
| Reference docs for REST, GraphQL, and webhooks are largely generated/synced rather than hand-authored: | ||
| - REST: `script/rest/update-files.js` pulls OpenAPI schemas from `github/github`, dereferences, and decorates them; served via `pages/[versionId]/rest/`. | ||
| - GraphQL: `script/graphql/update-files.js` keeps `data/graphql/` in sync with `github/github`'s schema. | ||
| - Webhooks: JSON payloads live in `data/webhooks/`. | ||
| Avoid hand-editing generated output in these areas; change the source script/schema instead. | ||
|
|
||
| ### Components | ||
|
|
||
| `components/` holds React components rendered via Next.js (server or client). `pages/` is the entry point — file-system routing matches a URL to a page component, which composes components from `components/`. This area is explicitly noted as a work in progress in `components/README.md`, so expect some inconsistency. | ||
|
|
||
| ## Testing conventions | ||
|
|
||
| - Tests use Jest and live under `tests/` (`tests/unit`, `tests/content`, `tests/rendering`, `tests/routing`, `tests/graphql`, `tests/javascripts`, `tests/browser`, `tests/linting`, `tests/meta`, `tests/translations`). | ||
| - `tests/linting/lint-files.js` is the content linter — validates frontmatter schema, Markdown structure, filename/title consistency, link/reusable/variable usage, etc. across every content file. This is usually the relevant test when a content change fails CI. | ||
| - Content-focused tests are often slow given the size of `content/`; scope test runs with `npm test -- <TEST_NAME>` rather than always running the full suite. | ||
|
|
||
| ## Repo-specific gotchas | ||
|
|
||
| - Don't create new abstractions/refactors for docs content changes — content PRs should stay scoped to the Markdown/data being changed. | ||
| - `main` is protected; `script/prevent-pushes-to-main.js` (pre-push hook) blocks direct pushes to `main`. | ||
| - When adding a new article, the filename must kebab-case-match the `title` frontmatter, or a test will fail. | ||
| - Windows contributors: use `\r?\n` instead of `\n` in regexes, prefer `path.posix`/the `slash` module for forward-slash paths, and prefer JS scripts over Bash — see the Windows section of `CONTRIBUTING.md`. | ||
|
|
||
| ## Subdirectory READMEs | ||
|
|
||
| Many directories have their own README with more detail; consult them before making non-trivial changes in that area: `content/README.md`, `content/graphql/README.md`, `content/rest/README.md`, `contributing/README.md`, `data/README.md`, `data/reusables/README.md`, `data/variables/README.md`, `includes/README.md`, `includes/liquid-tags/README.md`, `components/README.md`, `lib/liquid-tags/README.md`, `lib/render-content/README.md`, `middleware/README.md`, `script/README.md`, `stylesheets/README.md`, `tests/README.md`. | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.