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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 75 additions & 46 deletions .claude/skills/netclaw-docs/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,64 +3,93 @@ name: netclaw-docs
description: Voice and style contract for netclaw.dev docs (Astro + Starlight, dark-mode only). The how-it-should-sound layer on top of CLAUDE.md's authoring process.
---

# netclaw.dev Docs Voice
# netclaw.dev docs voice

Write like you're explaining netclaw to a sharp coworker who knows Linux, Docker, and Slack but has never touched netclaw. Confident, casual-technical, code-first. Open by telling the reader what the thing does and when they'd reach for it, then get out of the way and show commands. The published pages earn trust by being correct and dense, not by being long. CLAUDE.md owns the process (page types, templates, the critique/humanizer pipeline); this skill owns the voice.
Write like you're explaining netclaw to a sharp coworker who knows Linux, Docker, and Slack but has never touched netclaw. Confident, casual-technical, code-first. Open by saying what the thing does and when you'd reach for it, then show commands. The pages earn trust by being correct and dense, not long. CLAUDE.md owns the process (page types, templates, critique and humanizer steps). This skill owns how the page reads.

## Do

- **Open with the payload.** First sentence states what the feature does and when you'd use it. No "In this section" runway. See `getting-started/installation.md`: "Netclaw has two components..."
- **Use direct imperative voice.** "Run `netclaw status`." "Store tokens with `netclaw secrets`." Never "You can run" or "Users may wish to."
- **Show, don't tell.** A config block, command, or screenshot beats a paragraph. If CLI help already explains a flag, show the output instead of rewriting it.
- **Tables for anything with a shape** - flags, config fields (Field / Type / Default / Description), scopes, error→cause→fix, mode comparisons. Prose is for the one idea a table can't hold.
- **Name the #1 mistake.** The best pages flag the common footgun in bold ("This is the number one setup mistake"). Lead readers away from the trap.
- **Use Starlight callouts** `:::caution` / `:::note` for breaking changes, footguns, and security boundaries. Reserve them for things that bite.
- **Comment real screenshots in, stub honest TODOs out.** `<!-- TODO(screenshots): ... -->` and `<!-- TODO: needs user input - <question> -->` are the house pattern; never ship fake "coming soon" prose.
- **Close with cross-links.** End with Related pages + Resources (2+ external links to upstream docs/RFCs).
## Relationship to aarons-voice and humanizer

## Don't
For anything under `src/content/docs/`, this skill supersedes `aarons-voice` and both humanizer skills. It already contains the parts of `aarons-voice` that apply to product docs, so don't load it alongside this one. Deliberately not carried over: bare URLs (use markdown links with descriptive text), the no-bold rule (see Bold), first-person "I", exclamation points, and the email phrase list. Humanizer runs on prose only. Where it disagrees with this skill, this skill wins.

- No filler: "It is important to note that", "This section describes", "The following table shows", "In this guide we will". Cut the sentence; keep the table.
- No hedging: "you may want to", "it is recommended that", "it should be noted". State it.
- No rule-of-three padding ("fast, simple, and powerful") or negative parallelism ("not X, but Y") used for rhythm.
- No inflated symbolism, no "seamless / robust / leverage / delve". Plain verbs.
- Don't explain the obvious. If a reader of this audience already knows it, delete it.
- Don't restate code in prose right after showing it.
## Two registers

## Punctuation
- **Reference** (`cli/`, `configuration/`, `channels/`, `deployment/`, `observability/`, most `guides/`): "you" plus imperative. netclaw is the subject of behavior sentences ("netclaw resolves symlinks first"). No "we", no "I". Opinions stop at "use X unless Y". Exact beats charming.
- **Narrative** (design philosophy, comparisons, tutorials, the landing page): "we" is fine for the project's decisions and opinions. State opinions as opinions. A little roughness is fine. Still never "I".

Use the spaced hyphen ` - ` (space-hyphen-space), not the em-dash (`—`), for parenthetical asides and appositives. As of 2026-07-22 the docs drop the em-dash to match the house writing voice, where the em-dash reads as an AI tell and ` - ` is the connector that replaces it. Outbound email and marketing already ban the em-dash, so there's now one rule everywhere - no docs-versus-email split to remember.
A page is one or the other. If a reference page needs a "why", link to the narrative page.

Style notes for ` - `: it joins clauses mid-sentence only, never after a terminal `.`, `?`, or `!`. If the prior sentence ended, start a new one. Don't stack more than one per sentence, and skip it where a period, colon, comma, or parentheses read cleaner.
## Do

Migration: use ` - ` in every new page and in any page you edit. The ~50 legacy pages still contain em-dashes (`security-model.md` alone has ~38) and stay as they are until you edit the page for another reason, or a dedicated sweep converts them. Some channel pages use the double-hyphen ` -- ` instead. Normalize those to ` - ` when you touch them.
- **Open with the payload.** First sentence says what the feature does and when you'd use it.
- **Lead guides with the answer.** Put an "I want / do this" table first where it fits, then explain.
- **Use the words people search for.** Titles and headings say "turn off", "stop asking", "disable", not internal names.
- **Name the thing.** "Slack, Discord, or Mattermost", not "your chat app".
- **Show, don't tell.** A config block, command or screenshot beats a paragraph. Tables for anything with a shape. Prose is for the one idea a table can't hold, and never restates the table.
- **Name the number one mistake**, once per section at most.
- **Use `:::caution` and `:::note`** for breaking changes, footguns and security boundaries only.
- **One concept page, one guide, one reference per topic.** Other pages link instead of re-explaining.
- **Stub honestly.** `<!-- TODO(screenshots): ... -->` and `<!-- TODO: needs user input - <question> -->`. Never ship "coming soon" prose.

## Per-page-type quick reference
## Don't

- **CLI** (`cli/`): one-line intent → `## Usage` → options table → examples with a screenshot each → Related Commands.
- **Tutorial** (`getting-started/`): what we're building → Prerequisites (with versions) → numbered Steps with exact commands + expected output → Verify It Works → Next Steps.
- **Guide** (`guides/`): the problem in one line → Before You Begin → steps (call out conditional branches) → Troubleshooting (symptom / cause / fix).
- **Concept** (`architecture/`, `security/`): 2–3 paragraph mental model → key-concept sections → Limitations.
- **Configuration** (`configuration/`): what routes through this → minimal JSON block → full fields table (Field/Type/Default) → invalid-config behavior → diagnosing-errors table.
- **Integration** (`channels/`): transport in one line → Prerequisites → third-party setup (app/tokens/scopes, scopes table) → Configure netclaw → Access control → Verify it works → Troubleshooting.
- **Operations** (`deployment/`): when you need a non-default mode → modes table → per-mode config → restart/validation behavior → `netclaw doctor` troubleshooting.
- No filler ("It is important to note", "This page covers", "The following table shows") and no hedging ("you may want to", "it is recommended").
- No "No X, no Y, no Z" more than once per page. No slogan triads or punchline fragments for rhythm ("That's unrealistic.").
- No screenshot captions shaped like `Label - fragment; fragment`. A caption is one sentence.
- Cut: "surface" as a noun, "just" as a minimiser, "walks through", "the full breakdown", "out of the box" (say "by default"), "first-class", "at a glance", "worth knowing".
- Don't explain what this audience already knows. Don't restate code in prose after showing it.
- Don't sand good sentences flat to chase a clean score. Fix the tell and keep the sentence. A page that passes every check and reads like a compliance form is worse than one with a stray dash.

## Terminology & product facts
## Punctuation

- **netclaw** is lowercase in running prose. CLI is `netclaw`; daemon is `netclawd`.
- Commands and flags go in backticks: `netclaw status`, `--channel beta`. Config keys too: `Search.Backend`, `Daemon.ExposureMode`.
- **`netclaw init`** = focused 5-step first-run setup (provider, identity, security posture, features) that also powers factory reset. Don't pile post-install config into it.
- **`netclaw config`** = the re-entrant, menu-driven dashboard for everything else (channels, search, exposure, webhooks, skills); safe to re-run, autosaves on completion.
- Cross-link slugs: `/cli/<command>/`, `/channels/<platform>/`, `/configuration/<topic>/`, `/deployment/<topic>/`, `/security/<topic>/`, `/getting-started/<page>/`. Trailing slash, lowercase.
- Config lives in `~/.netclaw/config/netclaw.json`; secrets in `~/.netclaw/config/secrets.json` (encrypted at rest, written via `netclaw secrets set`). Env override prefix is `NETCLAW_` with `__` path separators.
- **Contractions everywhere:** it's, don't, you'll, can't. Spell out "do not" or "cannot" only inside a `:::caution` or a security boundary statement, where the stiffness is the point.
- **No semicolons in prose.** Write two sentences.
- **No exclamation points.** No emoji, except status glyphs that mirror real CLI output.
- **Sentence-case headings:** `## Related pages`, `## Before you begin`. Proper nouns and command names keep their case.
- **No em dashes at all.** Pick the replacement by position:
- List separators and table cells: ` - ` or a colon. An empty cell is `-`.
- Headings: a colon (`### 401 Unauthorized: secret mismatch`). Heading edits change anchors, so check inbound links.
- Prose: rewrite with a period, colon or comma first. Keep ` - ` for a real aside, about once per paragraph at most, never after a terminal `.`, `?` or `!`.
- Don't search-and-replace. Forty em dashes turned into forty spaced hyphens is a new tic. Normalize ` -- ` the same way.

## Bold

Four uses only: UI labels the reader looks for, one warning per section, Symptom / Cause / Fix labels, and a term where it's defined. No bolded thesis sentences. No bold-label bullet lists where a table or subheadings would do.

## Structure

- Every page ends with exactly `## Related pages` (three to five internal links) then `## Resources` (two or more external links). No "Next steps", "See also" or "Keep reading". Tutorials may put `## What's next` before them.
- Every screenshot has the instruction before it and a one-sentence caption after it that says something the alt text doesn't.
- Page-type shapes:
- **CLI:** intent, `## Usage`, options table, examples with a screenshot each.
- **Tutorial:** goal, prerequisites with versions, numbered steps with expected output, verify it works.
- **Guide:** problem in one line, before you begin, steps, troubleshooting (Symptom / Cause / Fix).
- **Concept:** two or three paragraphs of mental model, key sections, limitations.
- **Configuration:** what routes through it, minimal JSON, fields table (Field / Type / Default), invalid-config behavior.
- **Integration:** transport in one line, prerequisites, third-party setup, configure netclaw, access control, verify, troubleshooting.
- **Operations:** when you need a non-default mode, modes table, per-mode config, restart behavior, `netclaw doctor`.

## Terminology and product facts (0.27.1)

- netclaw is lowercase in running prose. The CLI is `netclaw`, the daemon is `netclawd`. Commands, flags and config keys go in backticks.
- `netclaw init` is first-run bootstrap only: provider, identity, security posture, then health check. That's four steps for Personal and five for Team or Public, which add a feature-selection step. Channels, search, exposure, webhooks and skill sources live in `netclaw config`, the re-entrant menu dashboard.
- Default base directory is `~/.netclaw`, or `$NETCLAW_HOME` if set. Config is `config/netclaw.json`, secrets are `config/secrets.json` (written with `netclaw secrets set`). Env overrides use the `NETCLAW_` prefix with `__` between path segments.
- `Ctrl+Q` quits every TUI. Escape is per screen: it never quits the config, provider, model, init or chat screens (in chat it denies a pending approval), but it does quit from the `netclaw mcp` server list. State keys per screen from the key-handling code, never as a global rule.
- There is no `netclaw daemon restart`. The daemon restarts itself, after draining sessions, when `netclaw.json` changes. Nothing else triggers it, so secrets and environment changes need a manual restart:
- native: `netclaw daemon stop`, then `netclaw daemon start`
- systemd user unit: `systemctl --user restart netclaw`
- Docker: `docker restart <container>` (the image's entrypoint supervises the daemon)
- Screenshots and command output come from the release container (`ghcr.io/netclaw-dev/netclaw:<version>`), never a host binary. No private hostnames in samples or screenshots. Use `llm.example.internal` or a named public provider.
- Cross-link slugs are lowercase with a trailing slash: `/cli/<command>/`, `/channels/<platform>/`, `/configuration/<topic>/`.

## Pre-ship checklist

- [ ] Frontmatter `title` + `description` set.
- [ ] Opens with what/when, not runway. No filler or hedge phrases.
- [ ] Reference material is in tables; code/screenshots carry the weight.
- [ ] netclaw lowercase; commands and config keys backticked; cross-links use correct trailing-slash slugs.
- [ ] No placeholder prose - only `<!-- TODO -->` comments for gaps; all referenced screenshots exist.
- [ ] 2+ external resource links.
- [ ] Every runnable snippet was actually run against the current release.
- [ ] `/humanizer` pass done; `npm run build` passes.
- [ ] Frontmatter `title` and `description` set. Headings in sentence case and built from search words.
- [ ] Opens with what and when. Guides lead with the answer. No filler, hedges or cut-list phrases.
- [ ] No em dashes, ` -- `, or semicolons in prose. ` - ` within budget. Contractions used.
- [ ] Reference page has no "we". No page has "I". Bold only in the four permitted uses.
- [ ] Tables carry reference material and aren't restated in prose.
- [ ] Every screenshot has an instruction before it and a one-sentence caption after it, and the file exists.
- [ ] Ends with `## Related pages` then `## Resources` (2+ external links).
- [ ] Every runnable snippet was run against the release container. No private hostnames.
- [ ] No placeholder prose. Only `<!-- TODO -->` comments for gaps.
- [ ] `humanizer:humanizer` pass done on prose only. `npm run build` passes.
22 changes: 21 additions & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ on:
jobs:
deploy:
name: "Deploy to Cloudflare Pages"
runs-on: ubuntu-latest
# Pinned: the Playwright version in package-lock.json has no Chromium build for ubuntu-latest (26.04).
runs-on: ubuntu-24.04
environment:
name: production
url: https://netclaw.dev
Expand All @@ -31,6 +32,25 @@ jobs:
- name: Install dependencies
run: npm ci

- name: Cache Playwright browser
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}

# Mermaid diagrams render at build time through a headless browser. Without it
# the build still succeeds but pages with diagrams ship with an empty body
# (scripts/check-rendered-pages.mjs fails the build when that happens).
# The browser revision follows the playwright version pinned in package-lock.json.
- name: Install Playwright browser
run: |
if [ "${{ steps.playwright-cache.outputs.cache-hit }}" = "true" ]; then
npx playwright install-deps chromium-headless-shell
else
npx playwright install --with-deps chromium-headless-shell
fi

- name: Build site
run: npm run build
env:
Expand Down
44 changes: 42 additions & 2 deletions .github/workflows/pr-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ on:
jobs:
build-site:
name: "Build Astro"
runs-on: ubuntu-latest
# Pinned: the Playwright version in package-lock.json has no Chromium build for ubuntu-latest (26.04).
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -22,12 +23,32 @@ jobs:
- name: Install dependencies
run: npm ci

- name: Cache Playwright browser
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}

# Mermaid diagrams render at build time through a headless browser. Without it
# the build still succeeds but pages with diagrams ship with an empty body
# (scripts/check-rendered-pages.mjs fails the build when that happens).
# The browser revision follows the playwright version pinned in package-lock.json.
- name: Install Playwright browser
run: |
if [ "${{ steps.playwright-cache.outputs.cache-hit }}" = "true" ]; then
npx playwright install-deps chromium-headless-shell
else
npx playwright install --with-deps chromium-headless-shell
fi

- name: Build site
run: npm run build

link-validation:
name: "Link and URL Validation"
runs-on: ubuntu-latest
# Pinned: the Playwright version in package-lock.json has no Chromium build for ubuntu-latest (26.04).
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -41,6 +62,25 @@ jobs:
- name: Install dependencies
run: npm ci

- name: Cache Playwright browser
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}

# Mermaid diagrams render at build time through a headless browser. Without it
# the build still succeeds but pages with diagrams ship with an empty body
# (scripts/check-rendered-pages.mjs fails the build when that happens).
# The browser revision follows the playwright version pinned in package-lock.json.
- name: Install Playwright browser
run: |
if [ "${{ steps.playwright-cache.outputs.cache-hit }}" = "true" ]; then
npx playwright install-deps chromium-headless-shell
else
npx playwright install --with-deps chromium-headless-shell
fi

- name: Build site
run: npm run build

Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ netclaw.dev documentation site — Astro 6.2 + Starlight, dark-mode only, deploy

Two guides govern work here. Read both before writing or editing any doc page:

- **[CLAUDE.md](./CLAUDE.md)** — the authoring *process*: page types, per-type templates, the screenshot pipeline, the critique + `/humanizer` review steps, and build/preview commands.
- **[CLAUDE.md](./CLAUDE.md)** — the authoring *process*: page types, per-type templates, the screenshot pipeline, the critique + `humanizer:humanizer` review steps, and build/preview commands.
- **[`.claude/skills/netclaw-docs/SKILL.md`](./.claude/skills/netclaw-docs/SKILL.md)** — the *voice and style* contract: the "less is more" house voice, punctuation policy, per-page-type quick reference, terminology, and the pre-ship checklist.

CLAUDE.md owns *what* to write and *how to ship it*; the `netclaw-docs` skill owns *how it reads*. Use both.
Expand Down
Loading
Loading