From 783d56762fb32ebc1bf570793e6622f149eb8699 Mon Sep 17 00:00:00 2001 From: Lucas Tortora Date: Wed, 6 May 2026 15:41:36 -0300 Subject: [PATCH] feat(skills): add shared Cursor agent skills for Diataxis, Google tech writing, and frontmatter review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds .cursor/skills/ shipping four project-level Cursor agent skills that enforce Tether's documentation standards on any repo derived from this template: - diataxis: classify each MDX page as tutorial / how-to / reference / explanation, enforce mode-specific structure and voice, align with docType in @tetherto/docs-seo-schema. - google-tech-writing: Google developer documentation style guide (active voice, second person, present tense, sentence-case headings, banned filler, tiered review severity). - docs-frontmatter: SEO frontmatter contract (description, docType, ogImage, noIndex, lastModified) mirroring tetherSeoFrontmatterSchema. - docs-review: orchestrator running the three skills above against a file list or PR diff and emitting a single tiered report (must-fix / consider / nit). Cursor reads project skills from .cursor/skills/ automatically. To pull updates from this repo into a consumer repo, three flows are documented (tiged, npm run sync-skills, git subtree). Adds scripts/sync-skills.mjs + npm run sync-skills for the second flow: - spawnSync (no shell-quoting risks) with explicit error paths for missing git binary, raw commit SHAs in --branch, and other failures. - Refuses to run inside docs-template itself (package-name + git-remote cross-check) so the source of truth cannot self-overwrite. - Refuses to clobber dirty .cursor/skills/ in a consumer repo unless --force is passed, so contributors do not lose local edits. Replaces the placeholder content/docs/about/about.mdx with a real Diataxis explanation page (content/docs/explanation/explanation.mdx, "Why DOCS is a template, not a SaaS"), and updates index.mdx, custom-tree.ts, and the three sibling section landings to match. Drops the accent on "Diátaxis" -> "Diataxis" across content/docs and the schema's warn message for consistency. Top-level README gains a "Documentation skills" section with a skill table and a repository-layout bullet pointing at .cursor/skills/. Co-authored-by: Cursor --- .cursor/skills/README.md | 122 ++++++++++ .cursor/skills/diataxis/SKILL.md | 107 +++++++++ .cursor/skills/diataxis/explanation.md | 68 ++++++ .cursor/skills/diataxis/how-to.md | 89 +++++++ .cursor/skills/diataxis/reference.md | 126 ++++++++++ .cursor/skills/diataxis/tutorial.md | 80 +++++++ .cursor/skills/docs-frontmatter/SKILL.md | 199 ++++++++++++++++ .cursor/skills/docs-review/SKILL.md | 218 ++++++++++++++++++ .cursor/skills/google-tech-writing/SKILL.md | 137 +++++++++++ .../skills/google-tech-writing/checklist.md | 68 ++++++ .../skills/google-tech-writing/examples.md | 135 +++++++++++ README.md | 16 +- content/docs/about/about.mdx | 26 --- content/docs/explanation/explanation.mdx | 59 +++++ content/docs/how-tos/how-to.mdx | 6 +- content/docs/index.mdx | 4 +- content/docs/references/references.mdx | 4 +- content/docs/tutorials/tutorials.mdx | 2 +- package.json | 7 +- packages/docs-seo-schema/src/index.ts | 2 +- scripts/sync-skills.mjs | 202 ++++++++++++++++ src/lib/custom-tree.ts | 6 +- 22 files changed, 1641 insertions(+), 42 deletions(-) create mode 100644 .cursor/skills/README.md create mode 100644 .cursor/skills/diataxis/SKILL.md create mode 100644 .cursor/skills/diataxis/explanation.md create mode 100644 .cursor/skills/diataxis/how-to.md create mode 100644 .cursor/skills/diataxis/reference.md create mode 100644 .cursor/skills/diataxis/tutorial.md create mode 100644 .cursor/skills/docs-frontmatter/SKILL.md create mode 100644 .cursor/skills/docs-review/SKILL.md create mode 100644 .cursor/skills/google-tech-writing/SKILL.md create mode 100644 .cursor/skills/google-tech-writing/checklist.md create mode 100644 .cursor/skills/google-tech-writing/examples.md delete mode 100644 content/docs/about/about.mdx create mode 100644 content/docs/explanation/explanation.mdx create mode 100644 scripts/sync-skills.mjs diff --git a/.cursor/skills/README.md b/.cursor/skills/README.md new file mode 100644 index 0000000..43623f5 --- /dev/null +++ b/.cursor/skills/README.md @@ -0,0 +1,122 @@ +# Docs skills + +Cursor [Agent Skills](https://docs.cursor.com/agent/skills) that enforce our documentation standards on every repo that uses this template. The skills are the source of truth for **what good docs look like at Tether** and are intended to be shared, versioned, and updated centrally from `docs-template`. + +## What's in here + +| Skill | Purpose | +|---|---| +| [`diataxis/`](./diataxis/) | Classifies each MDX page as tutorial, how-to, reference, or explanation, enforces the structure and voice of each, and aligns with the `docType` enum in `@tetherto/docs-seo-schema`. | +| [`google-tech-writing/`](./google-tech-writing/) | Applies Google's developer documentation style guide: active voice, second person, present tense, sentence-case headings, defined acronyms, banned filler ("easy", "simple", "just"), tiered severity for review. | +| [`docs-frontmatter/`](./docs-frontmatter/) | Enforces the SEO frontmatter contract from `@tetherto/docs-seo-schema`: required `description`, recommended `docType` matching directory, and optional `ogImage`, `noIndex`, and `lastModified`. | +| [`docs-review/`](./docs-review/) | Orchestrates the three skills above against a file list or PR diff and emits a single tiered report (must-fix / consider / nit). | + +All four are **project-level** skills — placed under `.cursor/skills/` so Cursor picks them up automatically for anyone working in the repo. + +## How Cursor discovers them + +Cursor reads project skills from `.cursor/skills/` in the workspace root. No installation step is required for users of a repo that contains this directory; the skills are visible to the agent the moment the repo is opened. + +If you want these skills available across every project on your machine (in addition to the project-level pickup above), symlink them into `~/.cursor/skills/`. Run from the root of a checked-out copy of `docs-template` so `$PWD` resolves to the right location: + +```bash +# from the docs-template repo root +ln -s "$PWD/.cursor/skills/diataxis" ~/.cursor/skills/diataxis +ln -s "$PWD/.cursor/skills/google-tech-writing" ~/.cursor/skills/google-tech-writing +ln -s "$PWD/.cursor/skills/docs-frontmatter" ~/.cursor/skills/docs-frontmatter +ln -s "$PWD/.cursor/skills/docs-review" ~/.cursor/skills/docs-review +``` + +Project-level skills in any repo's `.cursor/skills/` take precedence over personal skills with the same name, so the symlinks are a safety net for repos that have not yet adopted the template. + +## Sharing across the org + +`docs-template` is the single source of truth. Consumer repos pick up skills via one of three flows. Pick the one that matches your team's update cadence. + +### Option A — One-shot copy (`tiged` / `degit`) + +Best for: new repos, occasional manual re-syncs, no need to track upstream changes. + +```bash +# from the consumer repo root +npx --package=tiged@2 -- tiged tetherto/docs-template/.cursor/skills .cursor/skills --force +``` + +Pin a tag or commit: + +```bash +npx --package=tiged@2 -- tiged tetherto/docs-template/.cursor/skills#v1.2.0 .cursor/skills --force +``` + +### Option B — `npm run sync-skills` (recommended) + +Best for: repos that want a documented, reproducible sync command in their own `package.json`. + +The template ships [`scripts/sync-skills.mjs`](../../scripts/sync-skills.mjs) and an `npm run sync-skills` entry. Copy both into your consumer repo (or call the script via `tiged` once and commit it). Then: + +```bash +# default: pulls latest main from tetherto/docs-template +npm run sync-skills + +# pin to a tag +npm run sync-skills -- --ref=v1.2.0 + +# point at a fork +npm run sync-skills -- --repo=myorg/my-docs-template --ref=main + +# preview without writing +npm run sync-skills -- --dry-run +``` + +Environment variables also work (`DOCS_SKILLS_REPO`, `DOCS_SKILLS_REF`). The script refuses to run inside `docs-template` itself, so it cannot clobber the source of truth. + +### Option C — `git subtree` (history-preserving) + +Best for: teams that want upstream history merged into their repo and clean conflict resolution when both sides edit a skill. + +First-time set-up in the consumer repo: + +```bash +git remote add docs-template https://github.com/tetherto/docs-template.git +git subtree add --prefix=.cursor/skills docs-template main --squash +``` + +Subsequent updates: + +```bash +git fetch docs-template +git subtree pull --prefix=.cursor/skills docs-template main --squash +``` + +Send local improvements back upstream: + +```bash +git subtree push --prefix=.cursor/skills docs-template feature/ +# then open a PR in docs-template +``` + +## Update workflow (org-wide) + +1. Open a PR against [`tetherto/docs-template`](https://github.com/tetherto/docs-template) modifying the relevant skill under `.cursor/skills/`. +2. Tag a release (`v1.x.y`) when the change is ready to roll out. +3. Consumer repos run their sync command (Option A / B) or `git subtree pull` (Option C), pinning to the new tag if they want stable rollout. +4. To detect drift in CI, run `npm run sync-skills` followed by `git diff --exit-code .cursor/skills/`. The diff returns non-zero when local skills differ from the upstream ref, which fails the build (optional, opinionated). `--dry-run` only logs the planned action; it does not perform a comparison on its own. + +## Authoring conventions for skills in this directory + +Anyone editing skills here should keep them tight and predictable so the agent can rely on them across many repos: + +- **One concern per skill.** Cross-link instead of duplicating. +- **Top-level `SKILL.md` under 500 lines.** Push depth into sibling `.md` files (progressive disclosure). +- **Third-person, specific descriptions** in YAML frontmatter — the agent reads only the description until the skill is invoked. +- **Tiered severity** (must-fix / consider / nit) wherever the skill produces review output, so `docs-review` can aggregate cleanly. +- **No time-sensitive content** ("by August 2025…"); use a "deprecated patterns" section if needed. +- **Match the schema and directory layout of this template.** Mode-to-directory tables in `diataxis/SKILL.md` and the `docType` enum in `@tetherto/docs-seo-schema` must stay aligned. + +## Reference + +- [Cursor Agent Skills documentation](https://docs.cursor.com/agent/skills) +- [Diataxis framework](https://diataxis.fr) +- [Google developer documentation style guide](https://developers.google.com/style) +- [Google technical writing courses](https://developers.google.com/tech-writing) +- Schema source: [`packages/docs-seo-schema/src/index.ts`](../../packages/docs-seo-schema/src/index.ts) diff --git a/.cursor/skills/diataxis/SKILL.md b/.cursor/skills/diataxis/SKILL.md new file mode 100644 index 0000000..6642ccd --- /dev/null +++ b/.cursor/skills/diataxis/SKILL.md @@ -0,0 +1,107 @@ +--- +name: diataxis +description: >- + Classifies documentation pages into the four Diataxis modes (tutorial, + how-to, reference, explanation) and enforces the structure, voice, and + scope of each. Use when authoring, reviewing, or refactoring docs in + content/docs/**, when the user mentions Diataxis, tutorials, how-to guides, + reference, or explanation, or when frontmatter docType is set or missing. +--- + +# Diataxis + +Diataxis is a documentation framework that splits docs into four modes based on what the reader needs *right now*. Mixing two modes in one page is the most common documentation defect this skill exists to prevent. + +| Mode | Reader's need | Reader's question | Voice | +|---|---|---|---| +| Tutorial | Learning by doing | "Teach me." | Confident, hand-holding, present tense | +| How-to guide | Solving a specific task | "Show me how." | Direct, imperative, goal-focused | +| Reference | Looking up facts | "Tell me." | Austere, neutral, complete | +| Explanation | Understanding context | "Help me think about this." | Discursive, analytical | + +Source: [diataxis.fr](https://diataxis.fr). + +## Step 1 — Classify the page + +Before writing or reviewing, decide which mode the page is in. Use this decision tree, **in order**: + +1. Is the reader expected to **follow concrete steps and finish with a working artifact they did not have before**? + - **Yes, and they are new to the system** → **Tutorial** + - **Yes, but they already know the system and want to accomplish a specific goal** → **How-to** +2. Is the reader looking up **facts about an API, schema, CLI, config, or behaviour** with no narrative arc? + → **Reference** +3. Is the reader trying to **understand why something works the way it does**, the trade-offs, or the historical context, with no concrete steps required? + → **Explanation** + +If two answers feel correct, the page is doing two jobs and must be split. + +### Mapping to this template's directory and frontmatter + +| Diataxis mode | `content/docs/` directory | `docType` value (from `@tetherto/docs-seo-schema`) | +|---|---|---| +| Tutorial | `tutorials/` | `tutorial` | +| How-to guide | `how-tos/` | `how-to` | +| Reference | `references/` | `reference` | +| Explanation | `explanation/` | `explanation` | +| Onboarding orientation | `getting-started/` | `getting-started` | +| FAQ | `faqs/` | `faq` | +| Generic landing/index | top-level `index.mdx` | `page` | + +`getting-started`, `faq`, and `page` are template-specific helpers, not Diataxis modes. Treat them as follows: + +- `getting-started` is a **tutorial** in spirit. Apply tutorial rules. +- `faq` answers concrete questions. Apply how-to rules per answer. +- `page` (landing pages) should orient readers toward the four real modes; do not pack content here. + +## Step 2 — Apply the mode-specific rules + +Read only the file for the mode you are working on: + +- Tutorial → [tutorial.md](tutorial.md) +- How-to guide → [how-to.md](how-to.md) +- Reference → [reference.md](reference.md) +- Explanation → [explanation.md](explanation.md) + +If you are reviewing several pages in one session, read each mode file once at the start and keep it in context. + +## Step 3 — Run the universal Diataxis checklist + +Apply this to every page regardless of mode: + +- [ ] The page has exactly **one** Diataxis mode. No tutorial-style narrative inside reference. No how-to checklist inside explanation. No conceptual essay inside a tutorial. +- [ ] The directory under `content/docs/` matches the mode (see table above). +- [ ] `docType` in frontmatter matches the directory and the actual content. +- [ ] The opening paragraph signals the mode to the reader (for example, a tutorial opens with "In this tutorial you will…", a how-to opens with "This guide shows you how to…", a reference opens with a one-line factual summary, an explanation opens with the question it answers). +- [ ] Cross-links point to the right mode for follow-up: tutorials link to how-tos and reference, how-tos link to reference, reference links to explanation, explanation links to tutorials and how-tos. Avoid linking like-to-like in long chains. +- [ ] Content from another mode that crept in is either removed, inlined as a single short sentence, or extracted to a sibling page in the correct directory and linked. + +## Step 4 — Report findings + +When reviewing, output findings using the [tiered severity](../docs-review/SKILL.md) the rest of the suite uses: + +- **must-fix**: page is in the wrong directory or `docType`, or mixes two modes in a way that confuses the reader. +- **consider**: a section belongs in another mode and should be split out, or cross-links go to the wrong mode. +- **nit**: opening paragraph does not signal the mode, headings do not match the mode's voice. + +## Anti-patterns + +- A "tutorial" that is really a feature tour — readers do not finish with a working artifact. Reclassify as explanation or split. +- A "how-to" with motivation, history, and trade-offs woven through — move that prose into a sibling explanation. +- A "reference" page that teaches — move teaching content into a tutorial; keep reference dry. +- An "explanation" with copy-pasteable steps — extract the steps into a how-to. +- Calling everything "Getting started" — only the **first** orientation page is `getting-started`. Subsequent learning material is tutorial; subsequent task material is how-to. + +## When the user asks you to write a new page + +1. Ask (or infer) the Diataxis mode using Step 1. +2. Place the file in the directory from Step 1's table. +3. Set `docType` in frontmatter (see [`docs-frontmatter`](../docs-frontmatter/SKILL.md)). +4. Open the relevant mode file and follow its template. +5. Run the universal checklist before finishing. + +## When the user asks you to review or refactor docs + +1. Classify each page (Step 1). +2. For each page, run the mode-specific rules and the universal checklist. +3. Group findings by file and severity. +4. Hand off to [`docs-review`](../docs-review/SKILL.md) if the user asked for a full audit (Diataxis + Google style + frontmatter). diff --git a/.cursor/skills/diataxis/explanation.md b/.cursor/skills/diataxis/explanation.md new file mode 100644 index 0000000..00c8d40 --- /dev/null +++ b/.cursor/skills/diataxis/explanation.md @@ -0,0 +1,68 @@ +# Explanation mode + +Explanation is **understanding**. The reader steps back from the keyboard and wants to know *why* the system is the way it is — the model, the trade-offs, the history, the alternatives that were rejected. The reader does not need to act after reading. + +## Rules + +1. **The page answers a question, not a task.** Good titles are nouns and questions: "How replication works", "Why Pear chose hypercore", "Trade-offs of P2P discovery". Avoid "How to…" titles in this mode. +2. **Open with the question and the audience.** "This page explains *why* we use X. Read it if you are deciding whether to adopt X or wondering about its limits." +3. **Discursive prose is allowed and welcome.** Explanation is the only Diataxis mode where long-form paragraphs and analogies are appropriate. +4. **Discuss alternatives and trade-offs.** Naming the alternatives the team rejected is often the most useful part of an explanation page. +5. **Do not include step-by-step instructions.** If the reader asks "how do I do this?" after reading, link them to a how-to. +6. **Do not duplicate reference content.** Do not list every parameter. Describe the *shape* of the API and link to reference for facts. +7. **Cite sources where useful** — RFCs, papers, prior art, internal design docs. Make the reasoning checkable. +8. **End with "Where to go next"** that points to a tutorial, how-to, or reference based on what the reader will likely do next. + +## Template + +```mdx +--- +title: +description: +docType: explanation +--- + + + +# + +This page explains <topic>. Read it if you are <audience signal>. + +## The short version + +<Two- or three-sentence summary of the answer. Readers should be able to stop here if they only need the headline.> + +## <Section: the model> + +<Discursive prose explaining the conceptual model.> + +## <Section: trade-offs and alternatives> + +<What we picked, what we did not, and why.> + +## <Section: limits and open questions> + +<Honest accounting of where the design is incomplete.> + +## Where to go next + +- To try it, follow [<tutorial>](/tutorials/<slug>). +- To do <related task>, see [<how-to>](/how-tos/<slug>). +- For exhaustive details, see [<reference>](/references/<slug>). +``` + +## Common defects + +- **Sales pitch.** Explanation should be honest, not promotional. Name the trade-offs. +- **How-to disguise.** If the page contains numbered steps the reader is expected to run, move them to a how-to. +- **Reference dump.** If the page lists every option, move that to reference and keep only the conceptual map here. +- **Unbounded scope.** "About X" pages tend to grow into everything. Split when the page exceeds ~1500 words or covers more than one question. +- **No links out.** Explanation that does not point to actions leaves the reader stranded. + +## Examples of good and bad opens + +**Good:** "This page explains why Pear uses Hypercore for storage rather than a traditional database. Read it if you are evaluating Pear or wondering about durability guarantees." + +**Bad:** "Pear is awesome and here is everything about it." (No question, no audience, no trade-offs.) + +**Bad:** "How replication works: 1. Open a feed. 2. Append blocks. 3. Sync." (Steps belong in a how-to. Use prose to describe the model.) diff --git a/.cursor/skills/diataxis/how-to.md b/.cursor/skills/diataxis/how-to.md new file mode 100644 index 0000000..60310e4 --- /dev/null +++ b/.cursor/skills/diataxis/how-to.md @@ -0,0 +1,89 @@ +# How-to guide mode + +A how-to guide is a **recipe** for solving a specific real-world problem. The reader already knows the basics — they have a goal and need the shortest reliable path to it. + +## Rules + +1. **Title states the goal as a task.** "How to <verb> <object>." If you cannot phrase the title that way, the page is probably reference or explanation. +2. **Open with one sentence stating who the guide is for and what they will accomplish.** "This guide shows you how to <X> when you already have <Y>." +3. **Assume working knowledge.** Do not re-teach the basics. Link to a tutorial if a foundation is needed. +4. **Steps must be ordered, numbered, and minimal.** No motivational interludes between steps. +5. **State preconditions explicitly** (versions, permissions, files, environment variables) before step 1. +6. **Use second person, imperative, present tense.** Same voice as tutorials. +7. **Cover the realistic variations** the reader is likely to hit (one OS detour, one auth variant), but resist branching into a tree. +8. **End with verification** — how the reader confirms they succeeded — and links to related how-tos and reference. +9. **Do not explain *why*.** Link to an explanation page if the design choice is non-obvious. + +## Template + +````mdx +--- +title: How to <verb> <object> +description: <One sentence: the goal and the precondition.> +docType: how-to +--- + +# How to <verb> <object> + +This guide shows you how to <goal> when you already have <precondition>. + +## Before you begin + +You need: + +- <Tool / version> +- <Permission / access> +- <Existing artifact, if any> + +## Steps + +1. <Imperative verb>. <One line of context if essential.> + + ```bash + <command> + ``` + +2. <Imperative verb>. + + ```bash + <command> + ``` + +3. <Imperative verb>. + +## Verify + +Run: + +```bash +<verification command> +``` + +You should see <expected outcome>. + +## Troubleshooting + +- **<Symptom>.** <Cause and fix in one sentence.> +- **<Symptom>.** <Cause and fix in one sentence.> + +## Related + +- [How to <related task>](/how-tos/<slug>) +- [<Reference page>](/references/<slug>) +```` + +## Common defects + +- **Tutorial drift.** A how-to that opens with "In this tutorial…" or includes long context. Tighten the open and cut context. +- **Reference drift.** A how-to that lists every flag of a command. Move flags to reference; keep only the ones used in the steps. +- **Explanation drift.** A how-to that justifies each design decision in prose. Cut or link out. +- **Bag of tips.** A page titled "How to use X" is too broad. Split into specific goals: "How to migrate X", "How to back up X", "How to monitor X". +- **No verification step.** The reader cannot tell if it worked. Always include a confirmation. + +## Examples of good and bad opens + +**Good:** "This guide shows you how to publish a Pear application to a private hyperdrive when you already have a working app and a hyperdrive key." + +**Bad:** "Publishing Pear apps is an important part of the workflow. This guide will help you understand and execute the publishing process." (Padding, no goal.) + +**Bad:** "How to use Pear" (Too broad. Split.) diff --git a/.cursor/skills/diataxis/reference.md b/.cursor/skills/diataxis/reference.md new file mode 100644 index 0000000..ee44a74 --- /dev/null +++ b/.cursor/skills/diataxis/reference.md @@ -0,0 +1,126 @@ +# Reference mode + +Reference is **information** — austere, accurate, complete, and predictable in shape. The reader is not learning; they are looking up a fact. Treat reference like a dictionary entry, not an article. + +## Rules + +1. **Mirror the structure of the thing being described.** API reference follows the API. CLI reference follows command groups. Config reference follows the config schema. +2. **One entity per page or per heading** (function, command, type, option, event). Do not interleave. +3. **Open with a one-line factual summary.** "`pear run` runs a Pear application from a key or path." No marketing, no tutorial framing. +4. **Use neutral, declarative voice.** "Returns a Promise." Not "You will get a Promise back." +5. **Be exhaustive about the thing being described.** Every parameter, every flag, every return shape, every error code. If you skip something, say why. +6. **Be ruthlessly consistent.** Same heading order, same field names, same code-block style across every entry. Inconsistency is the main defect of reference docs. +7. **Examples are minimal and illustrative**, not pedagogical. One short example per entity is enough; link to a tutorial or how-to for full walk-throughs. +8. **No motivation, no rationale, no history.** Move that to an explanation page and link. +9. **Link out** to how-tos for tasks and to explanation for design rationale. +10. **Keep the prose deletable.** If a sentence does not describe behaviour, signature, or constraint, cut it. + +## Standard sections per entity + +For each function, method, command, event, type, or option, use the same section order. Pick one of the schemas below and stay with it across the page. + +### Function or method + +````mdx +## `name(args)` { #name } + +<One-line factual description.> + +### Parameters + +| Name | Type | Required | Description | +|---|---|---|---| +| `arg1` | `string` | Yes | <one line> | +| `arg2` | `Options` | No | <one line> | + +### Returns + +`Promise<Result>` — <one line>. + +### Throws + +- `ErrorName` — <when>. + +### Example + +```ts +const result = await name('foo') +``` +```` + +### CLI command + +````mdx +## `pear <command>` { #pear-command } + +<One-line factual description.> + +### Synopsis + +```text +pear <command> [options] <args> +``` + +### Arguments + +| Name | Required | Description | + +### Options + +| Flag | Type | Default | Description | + +### Exit codes + +| Code | Meaning | + +### Example + +```bash +pear <command> ... +``` +```` + +### Configuration option + +````mdx +## `optionName` { #optionname } + +- **Type:** `string` +- **Default:** `"foo"` +- **Required:** No +- **Since:** `1.4.0` + +<One- to two-sentence factual description, including units, valid range, and side effects.> + +### Example + +```json +{ "optionName": "bar" } +``` +```` + +## Frontmatter + +```yaml +--- +title: <Entity, package, or surface name> +description: <One sentence: what this reference page covers and for whom.> +docType: reference +schemaType: APIReference +--- +``` + +## Common defects + +- **Tutorial in disguise.** Long narrative around each entry. Cut it; link to a tutorial. +- **Inconsistent shape.** Some functions have a Returns section, others do not; parameter tables have different columns. Pick one schema and apply it to every entity. +- **Missing fields.** No type, no default, no error list. Reference must be exhaustive. +- **Editorial commentary.** "This is a powerful function." Delete. +- **Nested examples that grow into stories.** Trim to the smallest illustrative snippet. +- **Cross-mode links missing.** Reference should always link out to how-tos for tasks and explanation for design. + +## Examples of good and bad opens + +**Good:** "`pear run <key>` starts a Pear application identified by `<key>`. It returns the process exit code." + +**Bad:** "Running Pear apps is one of the most powerful features. With `pear run` you can…" (Marketing, not reference.) diff --git a/.cursor/skills/diataxis/tutorial.md b/.cursor/skills/diataxis/tutorial.md new file mode 100644 index 0000000..af9e82c --- /dev/null +++ b/.cursor/skills/diataxis/tutorial.md @@ -0,0 +1,80 @@ +# Tutorial mode + +A tutorial is a **lesson**. The reader is a learner who follows you and ends with a small working result they built themselves. Success is measured by whether they can finish without help. + +## Rules + +1. **Promise a concrete outcome in the opening paragraph.** "By the end of this tutorial you will have a running X that does Y." If you cannot fill that template, the page is not a tutorial. +2. **Hold the reader's hand.** Every step that can fail must include the exact command, file path, expected output, and what to do if the output differs. +3. **Use second person and imperative mood.** "Run `npm install`." Not "Users should run `npm install`." +4. **Use present tense.** "The script writes a file" — not "will write." +5. **Do not explain trade-offs, history, or alternative approaches.** A tutorial is not the place. Link to an explanation page if the reader is likely to wonder. +6. **Do not branch.** No "if you are on Windows do X, otherwise Y" detours longer than two lines. Pick the supported path; link out for variants. +7. **Show the result after each step that produces visible output** — terminal output, file contents, screenshot, or a single-line "you should now see…" cue. +8. **End with a "What you built" recap and pointers** to the next tutorial, the relevant how-tos, and reference docs. + +## Template + +````mdx +--- +title: <Verb-first title — what the reader builds> +description: <One sentence: who this is for and what they will have at the end.> +docType: tutorial +--- + +# <Title> + +In this tutorial you will <build / configure / publish> <X>. By the end you will have <concrete artifact>. + +## Before you start + +You need: + +- <Prerequisite 1, with version> +- <Prerequisite 2> +- <Account / credential, if any> + +## Step 1 — <Verb the reader does> + +<One short paragraph of context, no more.> + +```bash +<exact command> +``` + +You should see: + +```text +<expected output> +``` + +## Step 2 — <Verb the reader does> + +… + +## What you built + +You now have <artifact>. It does <X>. + +## Where to go next + +- To <accomplish related task>, see [<how-to title>](/how-tos/<slug>). +- For the full <thing> options, see [<reference title>](/references/<slug>). +- To understand <why this design>, read [<explanation title>](/explanation/<slug>). +```` + +## Common defects + +- **No artifact.** If the reader finishes and has nothing they can keep, it is a feature tour or an explanation, not a tutorial. Reclassify. +- **Branching choices.** "Choose A or B based on your needs" pushes the reader into decisions they cannot make yet. Pick one for them. +- **Hidden prerequisites.** Steps that fail without warning destroy trust. List every prerequisite up front. +- **Why this works essays.** Cut them. Link to an explanation page instead. +- **Reference dumps.** Long flag tables belong in reference. Link out. + +## Examples of good and bad opens + +**Good:** "In this tutorial you will create a new chat room application using Pear. By the end you will have a peer-to-peer chat that runs without a server." + +**Bad:** "Pear is a peer-to-peer runtime. This tutorial covers how Pear works and shows some examples." (This is explanation pretending to be a tutorial.) + +**Bad:** "Run the following commands to set up Pear." (This is a how-to with no learning arc.) diff --git a/.cursor/skills/docs-frontmatter/SKILL.md b/.cursor/skills/docs-frontmatter/SKILL.md new file mode 100644 index 0000000..a6e30d6 --- /dev/null +++ b/.cursor/skills/docs-frontmatter/SKILL.md @@ -0,0 +1,199 @@ +--- +name: docs-frontmatter +description: >- + Enforces the SEO frontmatter contract from @tetherto/docs-seo-schema on + every MDX page in content/docs. Required description, recommended docType + matching the directory and Diataxis mode, optional ogImage, schemaType, + noIndex, and lastModified. Use when authoring or editing MDX, when the + build emits [@tetherto/docs-seo] warnings, or when the user asks to fix + frontmatter, SEO metadata, or social cards. +--- + +# Docs frontmatter + +Every MDX page under `content/docs/**` must satisfy the schema in `@tetherto/docs-seo-schema` (see [`packages/docs-seo-schema/src/index.ts`](../../../packages/docs-seo-schema/src/index.ts)). This skill is the rulebook. + +## The schema (authoritative) + +```yaml +--- +title: <string — page title; rendered in <h1>, sidebar, breadcrumbs> +description: <string, REQUIRED — non-empty after trim, used for meta, OG, JSON-LD> +docType: tutorial | how-to | reference | explanation | page | faq | getting-started +schemaType: TechArticle | APIReference | WebPage # optional; inferred from path/docType if omitted +ogImage: /path/to/image.png | https://... # optional override; defaults to generated OG WebP +noIndex: true | false # optional; excludes from sitemap, sets robots noindex +lastModified: 2026-04-01 # optional; sitemap lastmod and JSON-LD dates +--- +``` + +The schema is enforced at MDX compile time by `tetherSeoFrontmatterSchema`. Builds also emit `[@tetherto/docs-seo]` console warnings for missing optional fields, deduped per page. + +- `DOCS_SEO_QUIET_GENERATED=1` silences only the warnings for fields with sensible auto-generated / inferred defaults (`ogImage`, `schemaType`, `lastModified`). Recommended when the site uses the Takumi OG prebuild and the `fumadocs-mdx` `lastModified` plugin. +- `DOCS_SEO_SILENT=1` silences ALL warnings (including required-`description`). Use sparingly. + +## Required: `description` + +- **Always provide it.** Empty or missing description fails the schema and breaks meta tags, Open Graph, Twitter cards, and JSON-LD. +- **One sentence, 100–155 characters** is ideal for search snippets. Stay under 200 — longer descriptions get truncated by Google and most OG renderers, and the truncation point is not under our control. +- **State who and what.** "<Who this is for> <what they will learn or look up>." Avoid restating the title. +- Do not end with the project name; the layout adds that. + +**Good:** +> Walks first-time Pear users through creating a peer-to-peer chat application end to end. + +**Bad:** +> A page about chat. *(useless)* +> +> This page is the official documentation page for the chat tutorial in the Pear documentation, where users can learn... *(filler, over the cap)* + +## Strongly recommended: `docType` + +`docType` ties the page to a Diataxis mode and drives JSON-LD inference. Set it explicitly even though it is optional, so reviewers can trust it. + +The `docType` value **must match the directory** the file lives in: + +| Directory under `content/docs/` | `docType` | +|---|---| +| `tutorials/` | `tutorial` | +| `how-tos/` | `how-to` | +| `references/` | `reference` | +| `explanation/` | `explanation` | +| `getting-started/` | `getting-started` | +| `faqs/` | `faq` | +| top-level landing pages | `page` | + +If the directory and the content disagree, the page is in the wrong place. Apply the [`diataxis`](../diataxis/SKILL.md) skill to reclassify before fixing frontmatter. + +### `docType` → inferred `schemaType` + +When `schemaType` is omitted, the build infers JSON-LD `@type` from `docType` and the path: + +| `docType` | Inferred `schemaType` | +|---|---| +| `tutorial`, `how-to`, `getting-started` | `TechArticle` | +| `reference` | `APIReference` | +| `explanation`, `faq`, `page` | `WebPage` | + +Set `schemaType` explicitly only when you want to override the inference (rare). + +## Optional but useful + +### `ogImage` + +- Leave **unset** by default. The Takumi prebuild generates a per-page WebP at `public/og/docs/<slug>/image.webp` and `getPageImage()` resolves it automatically. +- Set `ogImage` only to override with a custom illustration. Use a **site-relative path** (`/og/custom/foo.png`) or an absolute URL. Relative paths are normalized as static assets — no trailing slash before the extension. +- Required size: **1200×630**. + +### `noIndex` + +- Set `noIndex: true` for drafts, internal-only pages, or content excluded from search. +- The build excludes the page from the sitemap and emits `<meta name="robots" content="noindex">`. + +### `lastModified` + +- Set when content changes materially (not for typo fixes). +- Accepts an ISO date string (`2026-04-01`) or a JS Date. +- Drives sitemap `<lastmod>` and JSON-LD `datePublished` / `dateModified` on `WebPage`, `TechArticle`, and `APIReference` graphs. + +## Tiered severity for review + +| Label | Trigger | +|---|---| +| **must-fix** | `description` missing or empty (schema failure). `docType` does not match directory. `ogImage` points to a non-existent path. `noIndex` accidentally set on a public page. | +| **consider** | `docType` missing on a page where it would help (any page under a Diataxis directory). `lastModified` not bumped on a substantively edited page. `description` over 200 chars or under 60. | +| **nit** | `description` restates the title. `schemaType` set redundantly to the inferred value. | + +## Workflow + +### When creating a new MDX page + +1. Decide the Diataxis mode (run [`diataxis`](../diataxis/SKILL.md) Step 1 if unsure). +2. Place the file in the matching directory. +3. Fill the frontmatter using this template: + + ```yaml + --- + title: <Page title> + description: <One sentence, 100–155 chars, who + what.> + docType: <tutorial | how-to | reference | explanation | getting-started | faq | page> + --- + ``` + +4. Add `lastModified` if the content has a meaningful publish date. +5. Add `ogImage` only if you have a custom asset. +6. Run the build (`npm run dev` or `npm run build`); resolve any `[@tetherto/docs-seo]` warnings. + +### When reviewing existing MDX + +1. Open the page; read frontmatter first. +2. Check description (required), docType (matches directory), ogImage (path resolves), noIndex (intentional?), lastModified (current?). +3. Group findings by file with the severity labels above. +4. For must-fix issues, propose the corrected frontmatter as a code block. + +### When the build emits `[@tetherto/docs-seo]` warnings + +Each warning identifies the page slug and the missing field. Address them in this order: + +1. **Missing description** — must-fix; schema will fail. +2. **Missing docType** — consider; add to match directory. +3. **Missing ogImage** — usually fine (auto-generated). Add only if you want a custom social card. +4. **Missing schemaType** — usually fine (inferred). Add only to override. +5. **Missing lastModified** — add when the page has a meaningful update. + +If a site uses the Takumi OG prebuild and the `fumadocs-mdx` `lastModified` plugin, prefer `DOCS_SEO_QUIET_GENERATED=1` over `DOCS_SEO_SILENT=1` so `description` warnings stay loud. Use `DOCS_SEO_SILENT=1` only when the warnings are temporarily noisy, never as a fix. + +## Example: full frontmatter for each docType + +### Tutorial + +```yaml +--- +title: Build a peer-to-peer chat with Pear +description: Walks first-time Pear users through creating a peer-to-peer chat application end to end, from project init to first message. +docType: tutorial +lastModified: 2026-04-15 +--- +``` + +### How-to + +```yaml +--- +title: How to publish a Pear app to a private hyperdrive +description: Steps to publish a working Pear application to a private hyperdrive when you already have a hyperdrive key. +docType: how-to +lastModified: 2026-03-20 +--- +``` + +### Reference + +```yaml +--- +title: pear run +description: Reference for the pear run CLI command, including arguments, options, environment variables, and exit codes. +docType: reference +schemaType: APIReference +lastModified: 2026-04-10 +--- +``` + +### Explanation + +```yaml +--- +title: Why Pear uses Hypercore for storage +description: Explains the trade-offs behind choosing Hypercore over a traditional database for Pear's append-only storage layer. +docType: explanation +lastModified: 2026-02-01 +--- +``` + +## Reference + +- Schema source: [`packages/docs-seo-schema/src/index.ts`](../../../packages/docs-seo-schema/src/index.ts) +- Warn helper: `warnMissingSeoFrontmatterFields` in the same file +- Build-time merge: [`source.config.ts`](../../../source.config.ts) +- Per-page metadata pipeline: [`src/lib/seo-config.ts`](../../../src/lib/seo-config.ts) +- Diataxis classification: [`diataxis`](../diataxis/SKILL.md) diff --git a/.cursor/skills/docs-review/SKILL.md b/.cursor/skills/docs-review/SKILL.md new file mode 100644 index 0000000..1635aba --- /dev/null +++ b/.cursor/skills/docs-review/SKILL.md @@ -0,0 +1,218 @@ +--- +name: docs-review +description: >- + Runs a full documentation review by orchestrating the diataxis, + google-tech-writing, and docs-frontmatter skills against a set of MDX or + Markdown files (or a PR diff) and returns a single tiered report + (must-fix / consider / nit). Use when the user asks to "review docs", + "audit a docs page", "check this PR", or runs a docs review on changed + files. +--- + +# Docs review + +This skill is the orchestrator for the docs review suite. It runs three sub-skills against the same input and produces one combined report. + +Sub-skills it composes: + +1. [`diataxis`](../diataxis/SKILL.md) — page is in the right Diataxis mode and directory. +2. [`google-tech-writing`](../google-tech-writing/SKILL.md) — prose follows Google's style guide. +3. [`docs-frontmatter`](../docs-frontmatter/SKILL.md) — frontmatter satisfies `@tetherto/docs-seo-schema`. + +## When to apply this skill + +- The user asks to "review", "audit", or "check" docs. +- A PR touches files under `content/docs/**`, `**/*.mdx`, `**/*.md`, or `README.md`. +- The user references multiple docs files at once and asks for feedback. +- Pre-merge gate before publishing a docs change. + +If the user asks for *only* style review, *only* Diataxis classification, or *only* frontmatter cleanup, skip this orchestrator and apply the specific skill directly. + +## Input shapes this skill handles + +- **A single file path.** Review that file end-to-end. +- **A list of file paths.** Review each, then aggregate. +- **A PR or branch reference** (e.g. "review PR #42", "review the changes on this branch"). Resolve the changed files first (via `gh` or `git diff --name-only`), filter to docs files, and treat as a list. +- **A diff or pasted MDX block.** Review the visible content as a single page; flag if the file location is unknown (Diataxis classification needs the path). + +## Workflow + +Track progress with this checklist; complete every step before reporting. + +``` +Review progress: +- [ ] Step 1: Resolve the file list +- [ ] Step 2: Read each file (frontmatter + body) +- [ ] Step 3: Apply diataxis classification per file +- [ ] Step 4: Apply google-tech-writing rules per file +- [ ] Step 5: Apply docs-frontmatter checks per file +- [ ] Step 6: Aggregate findings, dedupe, sort by severity +- [ ] Step 7: Emit the report (see template below) +``` + +### Step 1 — Resolve the file list + +If given a PR or branch: + +```bash +git diff --name-only <base>..HEAD -- 'content/docs/**' '**/*.mdx' '**/*.md' +``` + +Or, with `gh`: + +```bash +gh pr diff <number> --name-only | grep -E '\.(mdx?|md)$' +``` + +If the user pasted a single file or block, treat it as a one-file list. + +### Step 2 — Read each file + +Read the **whole** file. Do not skim. Frontmatter and body must be in context together because Diataxis mode and `docType` are checked against directory and content simultaneously. + +### Step 3 — Diataxis pass + +For each file: + +1. Classify (Step 1 of [`diataxis`](../diataxis/SKILL.md)). +2. Read the relevant mode file under `diataxis/` (tutorial.md, how-to.md, reference.md, or explanation.md). +3. Apply the universal Diataxis checklist. +4. Record findings tagged `[diataxis]`. + +### Step 4 — Google tech writing pass + +For each file: + +1. Read the body once for audience and outcome. +2. Apply the [Core rules](../google-tech-writing/SKILL.md#core-rules--apply-to-every-sentence) and the [checklist](../google-tech-writing/checklist.md). +3. For style fixes worth flagging, propose the rewrite. +4. Record findings tagged `[style]`. + +### Step 5 — Frontmatter pass + +For each file: + +1. Apply the [`docs-frontmatter`](../docs-frontmatter/SKILL.md) workflow. +2. Verify `description` is present and well-shaped, `docType` matches directory, `ogImage`/`noIndex`/`lastModified` are correct. +3. Record findings tagged `[frontmatter]`. + +### Step 6 — Aggregate + +- Group findings by file. +- Within each file, sort by severity: **must-fix**, then **consider**, then **nit**. +- Within each severity bucket, sort by line number. +- Dedupe identical findings raised by more than one sub-skill (rare, but happens with terminology-vs-Diataxis overlap). Keep the most specific tag. + +### Step 7 — Emit the report + +Use the [report template](#report-template) below. Include counts, the top three issues, and per-file detail. + +## Severity rubric (shared across all three sub-skills) + +| Severity | Definition | Effect on merge | +|---|---|---| +| **must-fix** | Misleading, factually broken, fails the schema, violates inclusivity, or breaks the Diataxis contract (page in the wrong directory). | Block merge. | +| **consider** | Substantive style or structure improvement. The page works but is harder to read or maintain than it should be. | Strongly suggested; not blocking. | +| **nit** | Cosmetic preference. | Author may take or leave. | + +When in doubt between **consider** and **nit**, ask: "Would a reader notice this?" If yes, it is **consider**. + +## Report template + +````markdown +# Docs review + +**Files reviewed:** N +**Findings:** X must-fix, Y consider, Z nit + +## Top three to address first + +1. [<severity>][<tag>] <file>:<line> — <one-line problem> +2. [<severity>][<tag>] <file>:<line> — <one-line problem> +3. [<severity>][<tag>] <file>:<line> — <one-line problem> + +## Per-file findings + +### `content/docs/<path>.mdx` + +**Diataxis mode:** <tutorial | how-to | reference | explanation | …> +**docType:** <value, or "missing"> + +#### must-fix + +- [diataxis] line N — <problem>. Suggested action: <…>. +- [frontmatter] frontmatter — `description` missing. Suggested: + ```yaml + description: <…> + ``` + +#### consider + +- [style] line N — <problem>. Suggested rewrite: "<…>". + +#### nit + +- [style] line N — <note>. + +### `content/docs/<other>.mdx` + +… + +## Summary + +- <One-paragraph summary of the patterns seen across the review.> +- <Suggested follow-ups: e.g. "split <file> into a tutorial and a reference page", "add a glossary section to define <term>".> +```` + +## Worked example + +For a tutorial page at `content/docs/tutorials/chat-app.mdx`, a typical condensed report: + +``` +# Docs review + +Files reviewed: 1 +Findings: 2 must-fix, 3 consider, 1 nit + +## Top three to address first + +1. [must-fix][frontmatter] content/docs/tutorials/chat-app.mdx — `description` is empty; schema fails. +2. [must-fix][diataxis] content/docs/tutorials/chat-app.mdx:120 — section "Why hypercore?" is explanation in a tutorial; split into explanation/why-hypercore.mdx. +3. [consider][style] content/docs/tutorials/chat-app.mdx:8 — opening paragraph does not promise a concrete artifact. + +## Per-file findings + +### content/docs/tutorials/chat-app.mdx + +Diataxis mode: tutorial +docType: tutorial + +#### must-fix +- [frontmatter] frontmatter — `description` empty. Suggested: + description: Walks first-time Pear users through building a peer-to-peer chat app, from project init to first message. +- [diataxis] line 120 — "Why hypercore?" section is explanation in a tutorial. Move to content/docs/explanation/why-hypercore.mdx and link. + +#### consider +- [style] line 8 — opening sentence is passive ("The reader will be guided…"). Rewrite: "In this tutorial you will build a peer-to-peer chat app." +- [style] line 45 — "simply run" — drop "simply". +- [style] line 78 — sentence is 41 words; split. + +#### nit +- [style] line 102 — heading "How To Run The App" is title-case; prefer "How to run the app". + +## Summary +The page is a real tutorial in spirit but mixes one explanation section and uses passive voice in the open. Splitting "Why hypercore?" out and tightening the open will fix the structural issues; the rest is style polish. +``` + +## Tips for keeping reviews useful + +- **Do not list every nit if there are dozens.** Cap nits at five per file; tell the author there are more. +- **Always propose a rewrite for must-fix and consider** unless the fix is purely structural (split this page, move this section). +- **Do not duplicate findings across tags.** If a sentence is both passive and uses banned filler, list once with both issues mentioned. +- **Surface patterns in the Summary** when a defect repeats across the review — "passive voice throughout the tutorials section" is more useful than 20 individual line-level flags. + +## Reference + +- [`diataxis`](../diataxis/SKILL.md) +- [`google-tech-writing`](../google-tech-writing/SKILL.md) +- [`docs-frontmatter`](../docs-frontmatter/SKILL.md) diff --git a/.cursor/skills/google-tech-writing/SKILL.md b/.cursor/skills/google-tech-writing/SKILL.md new file mode 100644 index 0000000..f507d62 --- /dev/null +++ b/.cursor/skills/google-tech-writing/SKILL.md @@ -0,0 +1,137 @@ +--- +name: google-tech-writing +description: >- + Enforces Google's developer documentation style guide and technical writing + principles when authoring or reviewing docs, MDX, Markdown, READMEs, release + notes, comments, or commit messages. Covers active voice, second person, + present tense, sentence-case headings, defined acronyms, short sentences, + consistent terminology, parallel lists, banned filler words ("easy", + "simple", "just"), and tiered severity for review feedback. +--- + +# Google tech writing + +This skill applies Google's [developer documentation style guide](https://developers.google.com/style) and [technical writing](https://developers.google.com/tech-writing) principles to any prose the agent writes or reviews. + +## When to apply this skill + +- Writing or editing files under `content/docs/**`, `README.md`, `docs/**`, `*.mdx`, `*.md`. +- Reviewing a docs PR or pull-request description. +- Writing release notes, changelog entries, or substantial code comments. +- The user asks to "review", "audit", "tighten", or "rewrite" prose. + +## Core rules — apply to every sentence + +These are the rules with the highest cost-benefit ratio. Apply them automatically to anything you write or revise. + +### 1. Voice and tense + +- **Use active voice.** Subject performs the verb. "The server validates the token," not "The token is validated by the server." +- **Use present tense.** "The function returns a string," not "will return." +- **Use second person.** Address the reader as "you." Avoid "we" except for genuinely shared work ("we recommend"). Never "the user" when you mean "you." +- **Use the imperative for instructions.** "Run `npm install`," not "You should run `npm install`." + +### 2. Sentence shape + +- **One idea per sentence.** If a sentence has two clauses joined by "and" doing different work, split it. +- **Short sentences.** Aim for an average under 20 words. If a sentence is over 30, rewrite it. +- **Avoid ambiguous pronouns.** Replace "it", "this", "they" with the noun whenever the referent is more than one clause away. + - Bad: "The cache flushes when the queue is empty. This is configurable." + - Good: "The cache flushes when the queue is empty. The flush threshold is configurable." +- **Use "that" for restrictive clauses, "which" for non-restrictive (preceded by a comma).** + +### 3. Word choice + +- **Define every term on first use.** Acronyms get spelled out the first time they appear in a page; abbreviations get a one-line definition. +- **Use terms consistently.** Pick one term and use it throughout. Do not alternate between "API endpoint", "URL", "route", "path". +- **Cut filler words.** Banned in instructional prose: "easy", "simple", "simply", "just", "obviously", "of course", "merely", "basically", "actually". They condescend and add no information. +- **Cut hedges that hide uncertainty.** "Sort of", "kind of", "tends to", "may sometimes". Either it does or it does not; if it depends, say on what. +- **Prefer plain words.** "Use" over "utilize". "Help" over "facilitate". "Start" over "initiate". "Show" over "demonstrate". +- **Avoid "please" in instructions.** "Run the command," not "Please run the command." +- **Avoid "we" in reference docs.** Reference is impersonal. Use the API name as the subject. + +### 4. Structure + +- **Sentence-case headings.** "How to publish a build", not "How To Publish A Build". Proper nouns keep their capitalization. +- **Headings describe the content.** A reader scanning the table of contents should know what is in the section. +- **Lists for parallel items, tables for parallel comparisons.** Three or more items joined by "and" or "or" in prose almost always read better as a list. +- **Use parallel grammatical structure within a list.** Either every bullet starts with an imperative verb, or none do. Either every bullet ends with a period, or none do. +- **Top of page states audience and outcome.** The first paragraph tells the reader who the page is for, what they will know or be able to do after reading, and what knowledge it assumes. + +### 5. Code, UI, and product names + +- **Format inline code, file paths, env vars, commands, and identifiers in backticks.** +- **Bold UI elements** the user clicks or sees: "Click **Settings**, then **Profile**." +- **Use the official capitalization** of product, command, and brand names. Match casing from upstream docs. +- **Don't paraphrase error messages.** Quote them verbatim in code formatting. + +### 6. Links + +- **Link text describes the destination.** Not "click here" or "this page". "See [the publishing guide](…)". +- **Do not bury links inside long sentences.** Put them where the reader expects to act. + +### 7. Inclusivity + +- **Use gender-neutral language.** "They" for unknown singular. "Operator", "maintainer", "team" instead of gendered nouns. +- **Avoid culture-specific idioms** ("piece of cake", "low-hanging fruit") in docs read internationally. +- **Avoid "blacklist/whitelist", "master/slave"**, and similar pairs. Use "allowlist/denylist", "primary/replica". + +## Tiered severity for review + +When reviewing existing docs, classify each finding so the author knows what to do first. Use these labels in feedback: + +| Label | Meaning | Examples | +|---|---|---| +| **must-fix** | Misleading, factually unclear, or violates inclusivity. Block merge. | Passive voice that hides who acts, ambiguous pronouns that could mean two things, undefined acronyms on first use, banned filler words in instructional sentences, broken links, wrong product casing. | +| **consider** | Style improvement that meaningfully helps readers. Strongly suggested. | Long sentences (>30 words) that could split, weak headings, missing audience statement at top of page, inconsistent terminology across sections. | +| **nit** | Cosmetic. Author may take or leave. | Heading title-case vs sentence-case for a single heading, oxford comma preference, link text that is acceptable but not ideal. | + +Format each finding as: + +``` +- [must-fix] <file>:<line> — <one-sentence problem>. Suggested rewrite: "<…>" +- [consider] <file>:<line> — <one-sentence problem>. Suggested rewrite: "<…>" +- [nit] <file>:<line> — <one-sentence note>. +``` + +Always provide a suggested rewrite for **must-fix** and **consider** unless the fix is obvious. + +## Review workflow + +When asked to review a docs page or diff: + +1. Read the page top-to-bottom once for **audience and outcome** — does the first paragraph tell the reader who and what? +2. Read again, scanning for the [Core rules](#core-rules--apply-to-every-sentence). Use the [checklist](checklist.md) to avoid missing categories. +3. Group findings by file, then by severity (must-fix → consider → nit). +4. For each must-fix and consider, propose a rewrite. +5. Summarise at the end: total counts per severity, and the top three issues to address first. + +## Worked examples + +For before-and-after rewrites of common defects, see [examples.md](examples.md). + +## Banned and preferred phrases (cheat sheet) + +| Avoid | Prefer | +|---|---| +| "It is easy to…" | Cut. Show the steps. | +| "Simply run…" | "Run…" | +| "Just call…" | "Call…" | +| "Please note that…" | Cut, or "Note:" | +| "In order to…" | "To…" | +| "Utilize" | "Use" | +| "Leverage" | "Use" | +| "Functionality" | "Feature" or "behaviour" | +| "Obviously," | Cut. If it were obvious you would not be writing it. | +| "Basically," | Cut. | +| "The user should…" | "You…" | +| "We will now…" | Imperative: "Run…" / "Open…" | +| "Allows you to" | "Lets you" or rewrite as a direct verb | +| "Click here" (link text) | Describe the destination | + +## Reference + +- [Google developer documentation style guide](https://developers.google.com/style) +- [Google technical writing courses](https://developers.google.com/tech-writing) +- Project supplement: [checklist.md](checklist.md) +- Worked examples: [examples.md](examples.md) diff --git a/.cursor/skills/google-tech-writing/checklist.md b/.cursor/skills/google-tech-writing/checklist.md new file mode 100644 index 0000000..a6b99ee --- /dev/null +++ b/.cursor/skills/google-tech-writing/checklist.md @@ -0,0 +1,68 @@ +# Review checklist + +Run this checklist when reviewing a docs page or diff. Mark each item per page. + +Pear-runtime names are used as concrete examples below (`pear`, Hypercore, Hyperbee) because this skill ships from `tetherto/docs-template`. Substitute the product, command, and brand names of your own project when applying the rules. + +## Audience and orientation + +- [ ] First paragraph names the audience (who this is for). +- [ ] First paragraph states the outcome (what the reader will know or be able to do). +- [ ] First paragraph names prerequisites (what knowledge / setup is assumed). +- [ ] Page belongs in one Diataxis mode (see [`diataxis`](../diataxis/SKILL.md)). + +## Voice and tense + +- [ ] Active voice throughout. Passive only where the agent is genuinely unknown. +- [ ] Present tense for behaviour ("returns", not "will return"). +- [ ] Second person ("you"), not "the user" or "one". +- [ ] Imperative for instructions ("Run…"), not "You should run…". + +## Sentence shape + +- [ ] No sentence over 30 words; few over 25. +- [ ] One main idea per sentence. +- [ ] No ambiguous "it", "this", "they", "these" — always check the referent is one clause away or replace with the noun. +- [ ] "That" for restrictive clauses, "which" + comma for non-restrictive. + +## Word choice + +- [ ] No banned filler: "easy", "simple", "simply", "just", "obviously", "of course", "merely", "basically", "actually". +- [ ] No condescending hedges: "sort of", "kind of", "tends to", "may sometimes". +- [ ] No "please" in instructions. +- [ ] Plain over fancy: "use" not "utilize", "help" not "facilitate", "start" not "initiate". +- [ ] Acronyms spelled out on first use per page; specialised terms defined. +- [ ] Same term used throughout (no alternation between "API endpoint" / "URL" / "route"). + +## Structure + +- [ ] Sentence-case headings (proper nouns excepted). +- [ ] Headings describe content, not section number or filler ("Overview" is rarely useful). +- [ ] Three or more parallel items rendered as a list. +- [ ] Lists are grammatically parallel (all imperative, or all noun phrases). +- [ ] Tables compare alternatives or list reference data; not used for layout. + +## Code, UI, product names + +- [ ] Inline code (`backticks`) for commands, file paths, env vars, identifiers. +- [ ] **Bold** for UI elements the reader clicks. +- [ ] Product, command, brand names match upstream casing (Pear, Hypercore, Hyperbee, npm, GitHub). +- [ ] Error messages quoted verbatim in code formatting. + +## Links + +- [ ] Link text describes the destination (no "click here", "this page", bare URLs). +- [ ] Cross-mode links present where useful (tutorial → how-to → reference → explanation). +- [ ] No broken links (run `npm run check-links`). + +## Inclusivity + +- [ ] Gender-neutral language; singular "they" for unknown person. +- [ ] No "blacklist/whitelist", "master/slave", "guru/ninja" — use neutral alternatives. +- [ ] No idioms or jokes that depend on a specific culture or first language. + +## Accuracy + +- [ ] Code samples run as written (verify, don't trust). +- [ ] Versions, env var names, file paths match the current code. +- [ ] `lastModified` frontmatter updated if the content changed materially (see [`docs-frontmatter`](../docs-frontmatter/SKILL.md)). diff --git a/.cursor/skills/google-tech-writing/examples.md b/.cursor/skills/google-tech-writing/examples.md new file mode 100644 index 0000000..f65c7d4 --- /dev/null +++ b/.cursor/skills/google-tech-writing/examples.md @@ -0,0 +1,135 @@ +# Worked examples + +Before-and-after rewrites for the most common defects in our docs. Use these as patterns when rewriting. + +The examples use Pear-runtime terminology (`pear`, Hypercore, Hyperbee) because this skill ships from `tetherto/docs-template`, which was first used for Pear docs. The principles apply to any project; substitute your own product, command, and brand names when applying the patterns. + +## Active voice and imperative + +**Before** (passive, indirect): +> The configuration file should be loaded by the application before any requests are handled. + +**After** (active, present): +> The application loads the configuration file before handling any requests. + +**Before** (instruction in passive / future tense): +> The `pear init` command should be run by the user, after which a new project will be created. + +**After** (imperative, present): +> Run `pear init`. This creates a new project. + +## Cut filler + +**Before:** +> It's easy to deploy your app — simply run the deploy script and you're done. Obviously, you should make sure your environment variables are set first. + +**After:** +> To deploy your app, set the required environment variables, then run `pear deploy`. + +The "easy", "simply", "obviously", and the second-person scolding all go. + +## Ambiguous pronouns + +**Before:** +> The cache flushes when the queue is empty. This is configurable. + +**After:** +> The cache flushes when the queue is empty. The flush threshold is configurable. + +"This" could refer to the flush, the queue, or the relationship. Replace with the actual noun. + +## Long sentence with two ideas + +**Before** (38 words, two ideas): +> When a node receives a block over the wire it validates the signature against the known peer set, and if validation succeeds it appends the block to the local feed and notifies any subscribed listeners that new data is available. + +**After** (two sentences, one idea each): +> When a node receives a block, it validates the signature against the known peer set. If validation succeeds, the node appends the block to the local feed and notifies subscribed listeners. + +## Heading case + +**Before:** +> ## Configuring The Application For Production Use + +**After:** +> ## Configure the application for production + +Sentence case, imperative, no filler ("for use"). + +## Lists from prose + +**Before:** +> The `pear run` command accepts a key, optionally a path to a manifest, optionally one or more environment overrides, and an optional debug flag. + +**After:** +> The `pear run` command accepts: +> +> - A key (required). +> - A path to a manifest (optional). +> - One or more environment overrides (optional). +> - A `--debug` flag (optional). + +## Parallel list structure + +**Before** (mixed grammatical structure): +> - Run the install script. +> - You should then configure the env vars. +> - Restarting the service. + +**After** (all imperative): +> - Run the install script. +> - Configure the environment variables. +> - Restart the service. + +## "User" → "you" + +**Before:** +> The user must authenticate before the user can access the API. + +**After:** +> Authenticate before you can access the API. + +Or, in reference voice: +> The API requires authentication. + +## Plain words + +**Before:** +> This functionality leverages the underlying replication mechanism to facilitate real-time updates. + +**After:** +> This feature uses replication to deliver real-time updates. + +## Defining an acronym on first use + +**Before:** +> Configure the CDN to point at your static export. + +**After (first use on the page):** +> Configure your content delivery network (CDN) to point at your static export. + +Subsequent uses on the same page can use "CDN" alone. + +## Link text + +**Before:** +> For more information [click here](/explanation/replication). + +**After:** +> See [how replication works](/explanation/replication). + +## Quoting error messages + +**Before:** +> If you see an error about the manifest, check the file path. + +**After:** +> If you see `Error: manifest not found at <path>`, check the file path is correct. + +## Inclusive language + +**Before:** +> Add the IP to the whitelist; the master node will sync to the slaves. + +**After:** +> Add the IP to the allowlist; the primary node syncs to the replicas. diff --git a/README.md b/README.md index 26c99ee..e8612c8 100644 --- a/README.md +++ b/README.md @@ -198,6 +198,19 @@ npm run serve This serves the **`out/`** directory (Next.js static export output). +## Documentation skills (Diataxis + Google style) + +This template ships [Cursor Agent Skills](https://docs.cursor.com/agent/skills) under [`.cursor/skills/`](.cursor/skills/) that enforce Tether's documentation standards on any repo derived from the template: + +| Skill | Purpose | +|---|---| +| [`diataxis`](.cursor/skills/diataxis/) | Classifies each page as tutorial, how-to, reference, or explanation, enforces the structure and voice of each, and aligns with `docType` in `@tetherto/docs-seo-schema`. | +| [`google-tech-writing`](.cursor/skills/google-tech-writing/) | Applies Google's developer documentation style guide: active voice, second person, present tense, sentence-case headings, banned filler, tiered review severity. | +| [`docs-frontmatter`](.cursor/skills/docs-frontmatter/) | Enforces the SEO frontmatter contract from `@tetherto/docs-seo-schema`: required `description`, recommended `docType` matching directory, and optional `ogImage`, `noIndex`, and `lastModified`. | +| [`docs-review`](.cursor/skills/docs-review/) | Orchestrates the three skills above against a file list or PR diff and emits a single tiered report (must-fix / consider / nit). | + +Cursor reads project skills from `.cursor/skills/` automatically — no installation step. To pull updates from this repo into a consumer repo, see the three sync flows ([`tiged`](.cursor/skills/README.md#option-a--one-shot-copy-tiged--degit), [`npm run sync-skills`](.cursor/skills/README.md#option-b--npm-run-sync-skills-recommended), or [`git subtree`](.cursor/skills/README.md#option-c--git-subtree-history-preserving)) documented in [`.cursor/skills/README.md`](.cursor/skills/README.md). The script entry point is `npm run sync-skills`, defined in [`scripts/sync-skills.mjs`](scripts/sync-skills.mjs). + ## Repository layout - `src`: Next.js app and UI. @@ -205,7 +218,8 @@ This serves the **`out/`** directory (Next.js static export output). - `packages`: workspace packages (`@tether/docs-seo-*`). - `public`: static assets; **`public/og/docs/**`** holds prebuilt OG WebP files after `prebuild`. - `examples`: runnable DOCS code samples for snippets and tooling. -- `scripts`: automation (including [`scripts/generate-takumi-og.mts`](scripts/generate-takumi-og.mts)). +- `scripts`: automation (including [`scripts/generate-takumi-og.mts`](scripts/generate-takumi-og.mts) and [`scripts/sync-skills.mjs`](scripts/sync-skills.mjs)). +- [`.cursor/skills/`](.cursor/skills/): shared documentation skills (Diataxis, Google tech writing, frontmatter, review) — see section above. - [`env.example`](env.example): environment variable template (SEO required for prod; Inkeep optional). - [`REVIEW-CHECKLIST.md`](REVIEW-CHECKLIST.md): optional manual QA checklist for SEO / static export (stage it if you want it in the repo). - **`.source/`** (gitignored, not in git): Fumadocs MDX output; created by **`npm install`** / **`npm run postinstall`**. Regenerate after changing [`source.config.ts`](source.config.ts). diff --git a/content/docs/about/about.mdx b/content/docs/about/about.mdx deleted file mode 100644 index b9da104..0000000 --- a/content/docs/about/about.mdx +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: About -description: Essential context on the DOCS project—goals, vision, and the problems this white-label documentation platform aims to solve. ---- - -# About This Documentation - -The About section provides essential context for understanding the DOCS project and its documentation. Here, you will find information about the project's goals, vision, and the problems it aims to solve. - -## Project Aims - -DOCS is designed as a white-label documentation solution, enabling organizations to easily create, manage, and deploy high-quality technical documentation. The project focuses on flexibility, scalability, and ease of integration, making it suitable for a wide range of use cases. - -## Overview - -- **Purpose:** To provide a robust, customizable platform for technical documentation. -- **Audience:** Developers, technical writers, and organizations seeking a modern docs solution. -- **Features:** Modular content structure, search integration, easy theming, and static site generation for fast, reliable delivery. - -Explore the About pages to learn more about the philosophy, architecture, and roadmap of the DOCS project. - ---- - -## Learn More About Explanations - -For a deeper understanding of explanation articles and their role in documentation, see the [Diátaxis explanation guide](https://diataxis.fr/explanation/). \ No newline at end of file diff --git a/content/docs/explanation/explanation.mdx b/content/docs/explanation/explanation.mdx new file mode 100644 index 0000000..16fd580 --- /dev/null +++ b/content/docs/explanation/explanation.mdx @@ -0,0 +1,59 @@ +--- +title: Why DOCS is a template, not a SaaS +description: Explains why DOCS ships as a template with shared packages and Cursor agent skills instead of a centrally hosted SaaS, and the trade-offs that follow. +docType: explanation +--- + +# Why DOCS is a template, not a SaaS + +This page explains why DOCS is built as a white-label template instead of a hosted documentation service. Read it if you are evaluating DOCS, deciding whether to adopt it, or wondering why specific pieces (SEO packages, OG image pipeline, agent skills) live where they do. You will not find step-by-step instructions here; for those, see the [How-tos](/how-tos/how-to) and [Tutorials](/tutorials/tutorials). + +## The short version + +DOCS centralizes the parts that benefit from consistency (frontmatter schema, social-card generation, writing standards) and decentralizes the parts that benefit from team ownership (content, build pipeline, deployment). A template plus shared npm packages and Cursor agent skills hits that split better than a SaaS would, at the cost of a sync workflow each consumer repo opts into. + +## The model + +DOCS has three layers, each with a clear ownership boundary. + +- **The template.** A Next.js + Fumadocs static export. Each consumer repo clones it, replaces content, and ships its own deployment. The template contains the rendering pipeline and the section structure, but no organization-specific content. +- **The shared packages** (`@tetherto/docs-seo-*`). Published to GitHub Packages. They define the SEO frontmatter schema, generate Open Graph images, and emit Next.js metadata, sitemap, and JSON-LD. Consumers upgrade the package version like any other dependency. +- **The agent skills** (`.cursor/skills/`). Diataxis classification, Google tech-writing rules, frontmatter validation, and a review orchestrator. Cursor reads them automatically from a consumer repo's `.cursor/skills/` directory, so editing rules apply everywhere without per-repo configuration. See [Shared skills](#shared-skills) below. + +The first layer is owned by the consumer team after the initial clone. The second and third layers stay in sync with `tetherto/docs-template` through normal package upgrades or a sync command. + +## Trade-offs and alternatives + +The template + packages + skills split is a deliberate choice. Three alternatives were considered. + +- **A hosted SaaS** ("Tether Docs Cloud"). Ruled out because each team already runs its own deployment pipeline and wants its docs colocated with the product code that ships them. A SaaS would force teams to push content into a central system, route traffic through a third party, and depend on someone else's uptime for a static asset. +- **A monorepo holding every team's docs.** Ruled out because docs versioning is tightly coupled to product versioning. A monorepo creates cross-team merge contention on otherwise independent content. +- **Fork-each-project, no shared layer.** Ruled out because consistency is the main thing readers notice across an organization's docs. Without shared schema, OG generation, and writing standards, every repo reinvents the same primitives badly. + +The cost of the chosen split is the sync workflow: shared packages move forward, the template moves forward, and each consumer repo opts into upgrades. The README documents the three sync flows ([`tiged`](https://github.com/tetherto/docs-template/blob/main/.cursor/skills/README.md), [`npm run sync-skills`](https://github.com/tetherto/docs-template/blob/main/.cursor/skills/README.md), and `git subtree`); pick the one that matches the team's update cadence. + +## Limits and open questions + +- **Drift detection is opt-in.** Nothing forces a consumer repo to stay current with the template. Teams that pin to an old tag and stop syncing get stale skills and stale SEO behavior. CI-side drift checks are possible but not bundled by default. +- **Skill versioning is by branch / tag.** There is no semver contract on `.cursor/skills/` yet. A breaking change to a skill (renaming a directory, retiring a docType value) requires consumer-side coordination. +- **Schema coupling.** `@tetherto/docs-seo-schema` defines the docType enum; the Diataxis skill mirrors it; the directory layout in `content/docs/` mirrors both. The three are aligned today, but a change in any one requires touching the other two. + +## Shared skills + +The four agent skills shipped under `.cursor/skills/` are the writing-standard counterpart to the SEO packages. Each skill is independently invocable; `docs-review` is the orchestrator. + +| Skill | What it covers | +|---|---| +| [`diataxis`](https://github.com/tetherto/docs-template/tree/main/.cursor/skills/diataxis) | Classifies each page as tutorial, how-to, reference, or explanation, and enforces the structure and voice of each. Aligned with `docType` in `@tetherto/docs-seo-schema`. | +| [`google-tech-writing`](https://github.com/tetherto/docs-template/tree/main/.cursor/skills/google-tech-writing) | Applies Google's developer documentation style guide: active voice, second person, present tense, sentence-case headings, banned filler. | +| [`docs-frontmatter`](https://github.com/tetherto/docs-template/tree/main/.cursor/skills/docs-frontmatter) | Enforces the SEO frontmatter contract: required `description`, recommended `docType` matching the directory, optional `ogImage`, `noIndex`, and `lastModified`. | +| [`docs-review`](https://github.com/tetherto/docs-template/tree/main/.cursor/skills/docs-review) | Orchestrates the three skills above against a file list or PR diff and emits a single tiered report (must-fix / consider / nit). | + +Cursor picks these up automatically from any repo that contains `.cursor/skills/`; no per-repo install is required. + +## Where to go next + +- To learn DOCS by building, follow a [tutorial](/tutorials/tutorials). +- To accomplish a specific task, see the [how-tos](/how-tos/how-to). +- For the API and configuration surface, see the [references](/references/references). +- To start from zero, read [getting started](/getting-started/quickstart). diff --git a/content/docs/how-tos/how-to.mdx b/content/docs/how-tos/how-to.mdx index f308ea2..de4d26d 100644 --- a/content/docs/how-tos/how-to.mdx +++ b/content/docs/how-tos/how-to.mdx @@ -1,13 +1,13 @@ --- title: How-to slug: how-tos/how-to -description: Task-focused guides for accomplishing specific outcomes with DOCS, aligned with the Diátaxis how-to style. +description: Task-focused guides for accomplishing specific outcomes with DOCS, aligned with the Diataxis how-to style. --- # How-to -This section provides practical, step-by-step guides for accomplishing specific tasks with DOCS. Our How-tos are structured according to the [Diátaxis documentation framework](https://diataxis.fr/), which emphasizes clear, actionable instructions for real-world scenarios. +This section provides practical, step-by-step guides for accomplishing specific tasks with DOCS. Our How-tos are structured according to the [Diataxis documentation framework](https://diataxis.fr/), which emphasizes clear, actionable instructions for real-world scenarios. How-tos are ideal when you need to solve a particular problem or achieve a defined outcome. Each guide is focused, concise, and designed to help you get things done efficiently. -Learn more about the Diátaxis framework and its approach to documentation at [diataxis.fr](https://diataxis.fr/). +Learn more about the Diataxis framework and its approach to documentation at [diataxis.fr](https://diataxis.fr/). diff --git a/content/docs/index.mdx b/content/docs/index.mdx index 3b964bb..be39d94 100644 --- a/content/docs/index.mdx +++ b/content/docs/index.mdx @@ -10,9 +10,9 @@ DOCS is a flexible, white-label documentation platform designed to help you crea ## Main Sections -- **About:** Learn about the DOCS project, its goals, and the philosophy behind it. +- **Explanation:** Conceptual context behind the DOCS project — goals, design decisions, and trade-offs. - **Getting Started:** Step-by-step instructions to help you install and use DOCS, including a quickstart guide. -- **How-tos:** Practical, task-oriented guides for solving specific problems using DOCS, following the [Diátaxis](https://diataxis.fr/) framework. +- **How-tos:** Practical, task-oriented guides for solving specific problems using DOCS, following the [Diataxis](https://diataxis.fr/) framework. - **References:** Comprehensive, factual reference material for APIs, configuration, and more. - **Tutorials:** Hands-on, project-based tutorials to help you learn by doing. diff --git a/content/docs/references/references.mdx b/content/docs/references/references.mdx index 37fac8f..d6dd73d 100644 --- a/content/docs/references/references.mdx +++ b/content/docs/references/references.mdx @@ -7,7 +7,7 @@ noIndex: true # References -Reference documentation provides detailed, authoritative information about the DOCS project's APIs, components, and configuration options. According to the [Diátaxis documentation framework](https://diataxis.fr/), references are designed to be comprehensive and factual, serving as the single source of truth for users and developers. +Reference documentation provides detailed, authoritative information about the DOCS project's APIs, components, and configuration options. According to the [Diataxis documentation framework](https://diataxis.fr/), references are designed to be comprehensive and factual, serving as the single source of truth for users and developers. ## How References Should Be Generated @@ -23,4 +23,4 @@ npx typedoc --out docs/api src/index.ts This will create a set of HTML files in the `docs/api` directory, documenting all exported symbols from your codebase. -For more on the Diátaxis approach to reference documentation, visit [diataxis.fr](https://diataxis.fr/reference/). +For more on the Diataxis approach to reference documentation, visit [diataxis.fr](https://diataxis.fr/reference/). diff --git a/content/docs/tutorials/tutorials.mdx b/content/docs/tutorials/tutorials.mdx index 36ae1e5..968b33a 100644 --- a/content/docs/tutorials/tutorials.mdx +++ b/content/docs/tutorials/tutorials.mdx @@ -16,4 +16,4 @@ Tutorials are step-by-step guides designed to help you learn by doing. In this s Tutorials are ideal for beginners or anyone looking to gain a deeper understanding of how to use DOCS in real-world scenarios. -Learn more about the role of tutorials in documentation from the [Diátaxis framework](https://diataxis.fr/tutorials/). +Learn more about the role of tutorials in documentation from the [Diataxis framework](https://diataxis.fr/tutorials/). diff --git a/package.json b/package.json index 667b902..de27a07 100644 --- a/package.json +++ b/package.json @@ -7,15 +7,16 @@ "packages/*" ], "scripts": { + "dev": "next dev --turbo -p 3001", "prebuild": "tsx scripts/generate-takumi-og.mts", "build": "next build && npx @vahor/next-broken-links", "build:static": "next build && npx @vahor/next-broken-links", "build:og": "tsx scripts/generate-takumi-og.mts", - "dev": "next dev --turbo -p 3001", + "postinstall": "fumadocs-mdx", "start": "next start", "serve": "serve out -p 8080", - "postinstall": "fumadocs-mdx", - "check-links": "node scripts/check-links.js" + "check-links": "node scripts/check-links.js", + "sync-skills": "node scripts/sync-skills.mjs" }, "dependencies": { "@tetherto/docs-seo-next": "1.0.0", diff --git a/packages/docs-seo-schema/src/index.ts b/packages/docs-seo-schema/src/index.ts index 55d2f2a..8e83908 100644 --- a/packages/docs-seo-schema/src/index.ts +++ b/packages/docs-seo-schema/src/index.ts @@ -157,7 +157,7 @@ export function warnMissingSeoFrontmatterFields( if (missingOptionalEnumish(data, 'docType')) { warn( - `${DOCS_SEO_WARN_PREFIX} ${label} frontmatter "docType" is missing (set for clearer Diátaxis / JSON-LD defaults).`, + `${DOCS_SEO_WARN_PREFIX} ${label} frontmatter "docType" is missing (set for clearer Diataxis / JSON-LD defaults).`, ); } diff --git a/scripts/sync-skills.mjs b/scripts/sync-skills.mjs new file mode 100644 index 0000000..0e770d8 --- /dev/null +++ b/scripts/sync-skills.mjs @@ -0,0 +1,202 @@ +#!/usr/bin/env node +/** + * sync-skills.mjs + * + * Pull `.cursor/skills/` from the docs-template repo into the current repo so + * org-wide doc skills (diataxis, google-tech-writing, docs-frontmatter, + * docs-review) stay in sync without copy-paste drift. + * + * Defaults are tuned for `tetherto/docs-template`. Override with flags or env + * vars for forks. + * + * Usage from a consumer repo: + * + * # default: clone main from tetherto/docs-template + * npx --package=tiged@2 -- tiged tetherto/docs-template/.cursor/skills .cursor/skills --force + * + * # or, with this script (same defaults, more controllable): + * node scripts/sync-skills.mjs + * node scripts/sync-skills.mjs --ref=v1.2.0 + * node scripts/sync-skills.mjs --repo=myorg/my-docs-template --ref=main + * node scripts/sync-skills.mjs --dest=.cursor/skills --dry-run + * + * Inside docs-template itself this script is a no-op safeguard: it refuses to + * overwrite the source of truth. + */ + +import { spawnSync } from 'node:child_process'; +import { mkdtempSync, rmSync, cpSync, existsSync, readFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join, resolve } from 'node:path'; +import process from 'node:process'; + +const DEFAULTS = { + repo: process.env.DOCS_SKILLS_REPO ?? 'tetherto/docs-template', + ref: process.env.DOCS_SKILLS_REF ?? 'main', + src: process.env.DOCS_SKILLS_SRC ?? '.cursor/skills', + dest: process.env.DOCS_SKILLS_DEST ?? '.cursor/skills', +}; + +const TEMPLATE_PACKAGE_NAMES = [ + '@tether/docs-site', + '@tetherto/docs-template', + '@tether/docs-template', +]; + +const TEMPLATE_REMOTE_PATTERNS = [ + /[/:]tetherto\/docs-template(?:\.git)?$/i, + /[/:]tether\/docs-template(?:\.git)?$/i, +]; + +function parseArgs(argv) { + const out = { ...DEFAULTS, dryRun: false, force: false, help: false }; + for (const arg of argv.slice(2)) { + if (arg === '--help' || arg === '-h') out.help = true; + else if (arg === '--dry-run') out.dryRun = true; + else if (arg === '--force') out.force = true; + else if (arg.startsWith('--repo=')) out.repo = arg.slice('--repo='.length); + else if (arg.startsWith('--ref=')) out.ref = arg.slice('--ref='.length); + else if (arg.startsWith('--src=')) out.src = arg.slice('--src='.length); + else if (arg.startsWith('--dest=')) out.dest = arg.slice('--dest='.length); + else throw new Error(`Unknown argument: ${arg}`); + } + return out; +} + +function printHelp() { + console.log(`sync-skills — pull .cursor/skills/ from a docs-template repo + +Options: + --repo=<owner/name> Source repo (default: ${DEFAULTS.repo}) + --ref=<branch|tag> Git ref (default: ${DEFAULTS.ref}) + --src=<path> Path inside source repo (default: ${DEFAULTS.src}) + --dest=<path> Local destination (default: ${DEFAULTS.dest}) + --dry-run Print actions without writing + --force Overwrite local destination even if it has uncommitted changes + --help This text + +Env equivalents: DOCS_SKILLS_REPO, DOCS_SKILLS_REF, DOCS_SKILLS_SRC, DOCS_SKILLS_DEST. +`); +} + +function readPackageName() { + const pkgPath = resolve(process.cwd(), 'package.json'); + if (!existsSync(pkgPath)) return null; + try { + const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')); + return typeof pkg.name === 'string' ? pkg.name : null; + } catch { + return null; + } +} + +function readGitOriginUrl() { + const result = spawnSync( + 'git', + ['config', '--get', 'remote.origin.url'], + { encoding: 'utf8' }, + ); + if (result.status !== 0) return null; + const url = result.stdout?.trim(); + return url || null; +} + +function hasUncommittedChanges(relativePath) { + const result = spawnSync( + 'git', + ['status', '--porcelain', '--', relativePath], + { encoding: 'utf8' }, + ); + if (result.status !== 0) return false; + return result.stdout.trim().length > 0; +} + +function isInsideDocsTemplate() { + const name = readPackageName(); + if (name && TEMPLATE_PACKAGE_NAMES.includes(name)) return true; + + const remote = readGitOriginUrl(); + if (remote && TEMPLATE_REMOTE_PATTERNS.some((re) => re.test(remote))) return true; + + return false; +} + +function runCloneShallow(repo, ref, intoDir) { + const url = `https://github.com/${repo}.git`; + const result = spawnSync( + 'git', + ['clone', '--depth=1', '--branch', ref, url, intoDir], + { stdio: 'inherit' }, + ); + if (result.error) { + if (result.error.code === 'ENOENT') { + throw new Error('git binary not found on PATH; install git first.'); + } + throw new Error(`git clone failed: ${result.error.message}`); + } + if (result.status !== 0) { + throw new Error( + `git clone failed (exit ${result.status}) for ${repo}#${ref}. ` + + `--ref must be a branch or tag (commit SHAs are not accepted by ` + + `git clone --branch; use the tiged flow for SHA pinning).`, + ); + } +} + +function main() { + const args = parseArgs(process.argv); + if (args.help) { + printHelp(); + return; + } + + if (isInsideDocsTemplate()) { + console.error( + 'sync-skills: refusing to run inside docs-template itself (this repo is the source of truth).', + ); + process.exit(2); + } + + const cwd = process.cwd(); + const destAbs = resolve(cwd, args.dest); + + console.log(`sync-skills: ${args.repo}#${args.ref}:${args.src} → ${args.dest}`); + + if (args.dryRun) { + console.log('sync-skills: dry-run, no changes written.'); + return; + } + + const tmp = mkdtempSync(join(tmpdir(), 'docs-skills-')); + try { + runCloneShallow(args.repo, args.ref, tmp); + + const srcAbs = resolve(tmp, args.src); + if (!existsSync(srcAbs)) { + throw new Error( + `Source path "${args.src}" not found in ${args.repo}#${args.ref}.`, + ); + } + + if (existsSync(destAbs)) { + if (!args.force && hasUncommittedChanges(args.dest)) { + throw new Error( + `${args.dest} has uncommitted changes. ` + + `Commit or stash them, or rerun with --force.`, + ); + } + rmSync(destAbs, { recursive: true, force: true }); + } + cpSync(srcAbs, destAbs, { recursive: true }); + console.log(`sync-skills: wrote ${args.dest}`); + } finally { + rmSync(tmp, { recursive: true, force: true }); + } +} + +try { + main(); +} catch (err) { + console.error(`sync-skills: ${err.message}`); + process.exit(1); +} diff --git a/src/lib/custom-tree.ts b/src/lib/custom-tree.ts index 6e6269d..c1f8315 100644 --- a/src/lib/custom-tree.ts +++ b/src/lib/custom-tree.ts @@ -12,13 +12,13 @@ export const customTree: Node[] = [ icon: resolveIcon('Map'), }, { - name: 'About', + name: 'Explanation', type: 'folder', icon: resolveIcon('Rocket'), children: [ { - name: 'About', - url: '/about/about', + name: 'Explanation', + url: '/explanation/explanation', type: 'page', }, ]