Commentray storage layout
June 27, 2026 · View on GitHub
Repository root
- Config:
.commentray.toml(TOML). Omitted keys use built-in defaults. - Storage root: defaults to
.commentray/under the repository root.
Directories
.commentray/source/: paired commentray (Markdown) for each source file—what you author in commentray (see vocabulary below)..commentray/metadata/: Machine-oriented JSON (indices, fingerprints, diagnostics).
Vocabulary: Commentray the tool vs commentray the writing
- Commentray (capital C): the project, CLI, editor extension, and render stack in this repository.
- commentray (lowercase, uncountable): the documentation language—the practice of keeping narrative, diagrams, and rationale in paired Markdown under
.commentray/source/instead of bloating the primary file. You write in commentray, review in commentray, or onboard through commentray alongside the code.
Example: “We have to document our architecture in commentray so that newcomers can have an effective source code onboarding experience.”
Implementation detail: each file is still Markdown on disk; the path layout is defined in the next section.
Commentray file naming
Given a repo-relative primary file path P (POSIX-style, no .. segments), the commentray Markdown path is:
.commentray/source/{P}.md
Examples:
src/server.ts→.commentray/source/src/server.ts.mdREADME.md→.commentray/source/README.md.md
The mapping is intentionally transparent: append .md to the original path under a stable prefix.
This is the single-angle (implicit default) layout: one commentray Markdown file per primary file.
Angles (named perspectives on the same source)
Sometimes one source file deserves more than one commentray: an Introduction, an Architecture walkthrough, a Meeting notes angle, and so on. Commentray calls these Angles.
Configuration (.commentray.toml)
The [angles] table is optional:
default_angle— Angle id selected by default in tooling (e.g. VS Code) and as the initial tab on the static hub when several angles exist. When[[angles.definitions]]is non-empty, this id must match one of the listed definitions (validated at config merge).[[angles.definitions]]— Optional list of{ id, title? }rows. Titles are for UI labels (e.g. VS Code angle picker); if omitted, the id is shown.
You can set default_angle alone to prefer a disk angle before the definitions table is filled in.
The VS Code extension exposes Add angle to project (writes [angles] in .commentray.toml and creates the sentinel) and Open commentray beside source (pick angle) once Angles layout is enabled.
On-disk layout: sentinel {storage}/source/.default
Angles use a different directory shape than the flat default. The switch is explicit and file-system driven:
- No path
{storage}/source/.default→ only the flat layout above (.commentray/source/{P}.md). - Any file or directory at
{storage}/source/.default→ the repo opts into per-source folders undersource/. For each repo-relative primary pathPand Angle idA(see@commentray/coreassertValidAngleId:[a-zA-Z0-9_-]{1,64}):
{storage}/source/{P}/{A}.md
Examples (default storage.dir = .commentray):
README.md+ anglearchitecture→.commentray/source/README.md/architecture.mdsrc/app.ts+ angleintroduction→.commentray/source/src/app.ts/introduction.md
The sentinel .default does not by itself pick which Angle is “default” for a file; that remains angles.default_angle in TOML (and, when definitions are empty, convention in tooling may still treat a primary angle id as configured or as the only file present).
Migration from flat layout: run commentray migrate-angles (optional --angle-id, default main, and --dry-run). It moves every flat companion {storage}/source/{P}.md → {storage}/source/{P}/{angle}.md, creates the .default sentinel, merges [angles] into .commentray.toml, rewrites [static_site].commentray_markdown when it pointed at a moved file, and updates index.json keys via byCommentrayPath. The schema-only command remains commentray migrate (packages/core/src/migrate.ts). You can still adopt Angles manually (VS Code Commentray: Add angle to project… or hand edits) if you prefer not to bulk-move files.
GitHub Pages static browser (single index.html)
The Pages build emits one HTML file: one code pane (static_site.default_source_file; deprecated alias static_site.source_file) and one or more commentray bodies. When Angles are enabled and two or more definitions on disk exist for that source, the hub renders an Angle <select> and swaps the commentray pane client-side (stretch layout is skipped in that mode). Default hub pairing can be derived from static_site.default_angle; an explicit static_site.commentray_markdown still overrides. When .commentray/metadata/index.json lists blocks for the active pair and the Markdown has matching <!-- commentray:block id=… --> markers, a single-angle build can still use a single-scroll, blame-style table (one row per block) instead of dual panes.
[[static_site.related_github_files]]— optional rows with repo-relativepathand optionallabel(defaults to the file’s basename). Whenstatic_site.github_urlis a GitHub repository home URL (https://github.com/owner/repo), the toolbar gains Also on GitHub links to…/blob/<branch>/pathso readers can jump to other Markdown or code on GitHub. Setstatic_site.github_blob_branchwhen your default branch is notmain.- Search — Escape clears the query and hides hit results (same as the Clear control). The Pages build uses scoped search: only commentray Markdown (and path labels), not every line of the primary source file, plus a sidecar
commentray-nav-search.json. That JSON is built from every pair in.commentray/metadata/index.jsonbyCommentrayPath(so multiple angles for the samesourcePathappear as separate rows when indexed). When the index is empty, the build falls back to one pair from[static_site]only—it does not scansource/{P}/*.mdon disk, so unindexed angle files are omitted from hub search on Pages. - Generator / build stamp — emitted HTML includes
<meta name="generator" content="Commentray @commentray/render@…; @commentray/code-commentray-static@…; builtAt=…">(ISO instant) when the default generator is used, and a footer with that instant as<time datetime>plus a locale-formatted local date/time with timezone from the build machine. Omit the meta tag by passing an emptygeneratorLabelfrom the static builder API.
Images and other local assets (static HTML)
Local a[href] / img[src] in commentray Markdown are rewritten for static HTML (commentray render, Pages) to paths relative to the output file. https:, mailto:, … are unchanged.
a[href]: target must stay inside the repo (leading/= repo root; otherwise CommonMark paths from the.md’s directory—same as the VS Code Markdown preview).img[src]: target must stay inside{storage}/(e.g..commentray/). Otherwise static HTML dropssrc.
Put files next to the companion .md (e.g. ./assets/diagram.svg) so editor completions and static output match. Diagrams elsewhere: use https://…, not  as a local image.
Dogfood: assets/paired-editors.svg beside main.md. Maintainer captures: bash scripts/refresh-root-readme-screenshots.sh (or npm run extension:commentray-screenshots), then save under ./assets/ next to that angle’s .md. VS Code extension README PNGs: bash scripts/refresh-vscode-readme-screenshots-desktop.sh and companion .commentray/source/packages/vscode/README.md/main.md (Maintainer).
Metadata
The default index file is:
.commentray/metadata/index.json
It is plain JSON with a schemaVersion field so migrations remain explicit and auditable.