superwiki 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/.claude-plugin/marketplace.json +16 -0
  2. package/.claude-plugin/plugin.json +17 -0
  3. package/.codex-plugin/plugin.json +12 -0
  4. package/LICENSE +21 -0
  5. package/README.md +197 -0
  6. package/bin/superwiki.mjs +116 -0
  7. package/commands/config.md +5 -0
  8. package/commands/explain.md +5 -0
  9. package/commands/implement.md +5 -0
  10. package/commands/ingest.md +5 -0
  11. package/commands/init.md +5 -0
  12. package/commands/lint.md +5 -0
  13. package/commands/migrate.md +5 -0
  14. package/commands/plan.md +5 -0
  15. package/commands/triage.md +5 -0
  16. package/commands/visualize.md +5 -0
  17. package/install.sh +27 -0
  18. package/package.json +45 -0
  19. package/skills/sw-config/SKILL.md +39 -0
  20. package/skills/sw-config/assets/implementer.md +15 -0
  21. package/skills/sw-config/assets/planner.md +17 -0
  22. package/skills/sw-config/scripts/config.mjs +104 -0
  23. package/skills/sw-explain/SKILL.md +30 -0
  24. package/skills/sw-implement/SKILL.md +46 -0
  25. package/skills/sw-ingest/SKILL.md +43 -0
  26. package/skills/sw-init/SKILL.md +52 -0
  27. package/skills/sw-init/assets/agents-block.md +29 -0
  28. package/skills/sw-init/assets/sw.mjs +523 -0
  29. package/skills/sw-init/assets/templates/page.md +18 -0
  30. package/skills/sw-init/assets/templates/plan.md +25 -0
  31. package/skills/sw-init/assets/templates/task.md +33 -0
  32. package/skills/sw-init/assets/viewer.html +1660 -0
  33. package/skills/sw-init/scripts/init.mjs +118 -0
  34. package/skills/sw-lint/SKILL.md +61 -0
  35. package/skills/sw-migrate/SKILL.md +61 -0
  36. package/skills/sw-migrate/scripts/migrate.mjs +225 -0
  37. package/skills/sw-plan/SKILL.md +46 -0
  38. package/skills/sw-triage/SKILL.md +42 -0
  39. package/skills/sw-visualize/SKILL.md +28 -0
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env node
2
+ // Reads and changes docs/.sw/config.json, and writes the planner and implementer agent
3
+ // definitions each tool needs. In all three tools a model is bound to an agent file, not chosen at run time.
4
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
5
+ import { dirname, join, resolve } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const assets = join(dirname(fileURLToPath(import.meta.url)), '..', 'assets');
9
+ const TOOLS = ['claude', 'codex', 'copilot'];
10
+ const ROLES = {
11
+ plan: { name: 'sw-planner', file: 'planner.md', readOnly: true, description: 'Writes the plan for one Superwiki task. Read-only. Use from sw-plan.' },
12
+ implement: { name: 'sw-implementer', file: 'implementer.md', readOnly: false, description: 'Implements one Superwiki task from its task and plan files. Use from sw-implement.' },
13
+ };
14
+ const HELP = `config.mjs <command> [--root <dir>]
15
+
16
+ show print the configuration
17
+ model <plan|implement> <tool> <model> set the model a tool uses for a role (tool: ${TOOLS.join(', ')})
18
+ model <plan|implement> <tool> --unset go back to the tool's default model
19
+ areas "M=Mobile,B=Backend" add or rename task areas (existing areas are never removed)
20
+ sync [--tools claude,codex] (re)write agent files for the given tools, or for every configured tool`;
21
+
22
+ const argv = process.argv.slice(2);
23
+ const ri = argv.indexOf('--root');
24
+ const root = resolve(ri >= 0 ? argv[ri + 1] : '.');
25
+ if (ri >= 0) argv.splice(ri, 2);
26
+ const [cmd, ...rest] = argv;
27
+ const fail = msg => { console.error(msg); process.exit(2); };
28
+ if (!cmd || cmd === '--help' || cmd === 'help') { console.log(HELP); process.exit(0); }
29
+
30
+ const configPath = join(root, 'docs/.sw/config.json');
31
+ if (!existsSync(configPath)) fail('no docs/.sw/config.json here; run sw-init first');
32
+ const config = JSON.parse(readFileSync(configPath, 'utf8'));
33
+ config.models = { plan: {}, implement: {}, ...config.models };
34
+ config.tools = config.tools || [];
35
+
36
+ const put = (rel, content) => {
37
+ const p = join(root, rel);
38
+ const before = existsSync(p) ? readFileSync(p, 'utf8') : null;
39
+ if (before !== content) { mkdirSync(dirname(p), { recursive: true }); writeFileSync(p, content); }
40
+ console.log(`${before === null ? 'created ' : before === content ? 'unchanged' : 'updated '} ${rel}`);
41
+ };
42
+ const header = 'Generated by sw-config from docs/.sw/config.json. Change models with sw-config, not here.';
43
+
44
+ function sync(tools) {
45
+ for (const [role, r] of Object.entries(ROLES)) {
46
+ const body = readFileSync(join(assets, r.file), 'utf8').trim();
47
+ const model = tool => config.models[role]?.[tool];
48
+ if (tools.includes('claude')) {
49
+ const fm = ['---', `name: ${r.name}`, `description: ${r.description}`];
50
+ if (r.readOnly) fm.push('tools: Read, Grep, Glob');
51
+ if (model('claude')) fm.push(`model: ${model('claude')}`);
52
+ put(`.claude/agents/${r.name}.md`, `${fm.join('\n')}\n---\n\n<!-- ${header} -->\n\n${body}\n`);
53
+ }
54
+ if (tools.includes('codex')) {
55
+ const lines = [`# ${header}`, `name = "${r.name.replace(/-/g, '_')}"`, `description = ${JSON.stringify(r.description)}`];
56
+ if (model('codex')) lines.push(`model = ${JSON.stringify(model('codex'))}`);
57
+ if (r.readOnly) lines.push('sandbox_mode = "read-only"');
58
+ lines.push(`developer_instructions = '''\n${body.replace(/'''/g, "' ' '")}\n'''`);
59
+ put(`.codex/agents/${r.name}.toml`, lines.join('\n') + '\n');
60
+ }
61
+ if (tools.includes('copilot')) {
62
+ const fm = ['---', `name: ${r.name}`, `description: ${r.description}`];
63
+ if (r.readOnly) fm.push('tools: ["read", "search"]');
64
+ if (model('copilot')) fm.push(`model: ${model('copilot')}`);
65
+ put(`.github/agents/${r.name}.agent.md`, `${fm.join('\n')}\n---\n\n<!-- ${header} -->\n\n${body}\n`);
66
+ }
67
+ }
68
+ }
69
+ const save = () => writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
70
+
71
+ if (cmd === 'show') {
72
+ console.log(`tasks: ${config.tasks ? 'on' : 'off'}`);
73
+ if (config.tasks) console.log(`areas: ${Object.entries(config.areas).map(([k, v]) => `${k}=${v}`).join(', ')}`);
74
+ for (const role of Object.keys(ROLES)) {
75
+ console.log(`${role}: ${TOOLS.map(t => `${t}=${config.models[role][t] || 'default'}`).join(' ')}`);
76
+ }
77
+ console.log(`agent files for: ${config.tools.join(', ') || 'none'}`);
78
+ } else if (cmd === 'model') {
79
+ const [role, tool, model] = rest;
80
+ if (!ROLES[role] || !TOOLS.includes(tool) || !model) fail(`usage: config.mjs model <plan|implement> <${TOOLS.join('|')}> <model|--unset>`);
81
+ if (model === '--unset') delete config.models[role][tool];
82
+ else config.models[role][tool] = model;
83
+ if (!config.tools.includes(tool)) config.tools.push(tool);
84
+ save();
85
+ sync([tool]);
86
+ } else if (cmd === 'areas') {
87
+ if (!config.tasks) fail('the task module is off; run sw-init with --tasks first');
88
+ for (const pair of (rest[0] || '').split(',').map(s => s.trim()).filter(Boolean)) {
89
+ const [id, ...name] = pair.split('=');
90
+ if (!/^[A-Za-z][A-Za-z0-9]*$/.test(id)) fail(`bad area id "${id}"`);
91
+ config.areas[id] = name.join('=').trim() || config.areas[id] || id;
92
+ }
93
+ save();
94
+ console.log(`areas: ${Object.entries(config.areas).map(([k, v]) => `${k}=${v}`).join(', ')}`);
95
+ } else if (cmd === 'sync') {
96
+ const ti = rest.indexOf('--tools');
97
+ const tools = ti >= 0 ? rest[ti + 1].split(',').map(s => s.trim()) : config.tools;
98
+ const bad = tools.filter(t => !TOOLS.includes(t));
99
+ if (bad.length) fail(`unknown tool: ${bad.join(', ')}`);
100
+ if (!tools.length) fail('no tools configured; pass --tools claude,codex,copilot');
101
+ for (const t of tools) if (!config.tools.includes(t)) config.tools.push(t);
102
+ save();
103
+ sync(tools);
104
+ } else fail(`unknown command ${cmd}\n\n${HELP}`);
@@ -0,0 +1,30 @@
1
+ ---
2
+ name: sw-explain
3
+ description: Use when the user asks what a Superwiki task is, why it exists, what it depends on, what it blocks or what changes once it is done, or invokes sw-explain or sw:explain with a task id.
4
+ ---
5
+
6
+ # sw-explain
7
+
8
+ Explains one task so that someone who has not followed the project understands it. Changes no file.
9
+
10
+ Run commands from the project root.
11
+
12
+ ## Steps
13
+
14
+ 1. `node docs/.sw/sw.mjs explain <ID>`. It prints the task's state, what it depends on, what it blocks, what becomes ready when it is done, its plan and the wiki pages it links, each with a one-line summary. No id given: ask which task, offering the ones from `node docs/.sw/sw.mjs ready`.
15
+
16
+ The state is derived: `ready` is a `todo` task whose dependencies are done, `blocked` is a `todo` task still waiting on one, `progress` is `in-progress`. Say it in words, not as a label.
17
+ 2. Read `docs/tasks/<ID>.md`.
18
+ 3. Read more only when the answer needs it:
19
+ - the plan's `## Approach` section, if the user will want to know how it is to be done;
20
+ - one linked page, if the task's "Goal" does not itself say why the task exists: a `decision` page if there is one, otherwise the page whose summary is closest to the goal;
21
+ - nothing else. Summaries from step 1 stand in for the other pages.
22
+ 4. **Answer in the user's language**, in this order, one to a few sentences each:
23
+ - **What**: the task in plain words, without restating its title.
24
+ - **Why**: the reason it exists and the decision or source behind it, as `[[page]]`. If neither the task nor the page you read gives a reason, say the brain does not record one.
25
+ - **Depends on**: each dependency with its state. A dependency listed under "depends on" must be done before the task can start; one under "soft depends on" lets it start but must be done before it can finish.
26
+ - **Blocks**: the tasks waiting on it, and which of them become ready the moment it is done.
27
+ - **What changes when it is done**: for the product or the user, from "Done when", and for the project, from what it unblocks.
28
+ - **Where it stands**: state, dates, whether a plan exists, and the next step. Ready or in progress: `sw-implement <ID>` (or `sw-plan <ID>` first if there is no plan and the task is not small). Blocked: name the tasks to finish first; planning it meanwhile with `sw-plan <ID>` is allowed.
29
+
30
+ Leave out a heading that has nothing to say rather than writing "none" under each. If the task file is thin (no "Goal", no "Done when"), say that this is all the brain records; do not fill the gap with guesses from the code.
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: sw-implement
3
+ description: Use when the user wants to implement, build, execute, start or continue a Superwiki task or its plan, or invokes sw-implement or sw:implement, with or without a task id.
4
+ ---
5
+
6
+ # sw-implement
7
+
8
+ Runs one task. You keep the task's status true and judge the result; an implementer subagent, running the model set in sw-config, does the work from the task and plan files.
9
+
10
+ Run commands from the project root. `<skill-dir>` is the directory this SKILL.md is in.
11
+
12
+ ## Steps
13
+
14
+ 1. **Pick the task.** Id given: use it. Otherwise `node docs/.sw/sw.mjs ready` and let the user choose; tasks already in progress come first.
15
+ 2. **Gate**: `node docs/.sw/sw.mjs check <ID>`.
16
+ - `can start: no open deps: ...`: stop. Tell the user which tasks block it and offer to run the first blocker instead; do not run it unasked. Do not start the task anyway, and do not edit `deps` to get past this.
17
+ - `can start: n/a, status is in-progress`: this is a continuation; skip step 3.
18
+ - `can start: n/a, status is done` or `cancelled`: stop and ask what the user wants.
19
+ - `plan: none`: say so. Small tasks can run from "Goal" and "Done when"; for anything larger, recommend sw-plan first and let the user choose.
20
+ 3. **Mark it started** before any work: in the frontmatter of `docs/tasks/<ID>.md` set `status: in-progress` and `started:` today. Append `## [date] task | <ID> started` to `docs/log.md`, in the layout its last entries use.
21
+ 4. **Dispatch the implementer.** Its prompt is the task id, plus the project root if it is not your working directory. Do not paste the plan into the prompt; it reads the files.
22
+
23
+ | Tool | How |
24
+ |---|---|
25
+ | Claude Code | agent `sw-implementer`. If it is not among your agent types, use a general-purpose agent, put the content of `<skill-dir>/../sw-config/assets/implementer.md` at the top of its prompt, and pass the model from `models.implement.claude` in `docs/.sw/config.json` if set |
26
+ | Codex | spawn the custom agent `sw_implementer` |
27
+ | Copilot CLI | `task` tool with agent `sw-implementer` |
28
+ | No subagents available, or the agent is not defined | follow `implementer.md` yourself, in this session, and tell the user the configured model was not used |
29
+
30
+ 5. **Judge the report** against the task's "Done when" list. Every item needs evidence: a command and its result. Re-run a verification command yourself when the report is vague. An item without evidence is not met.
31
+ 6. **Record the outcome.**
32
+
33
+ | Outcome | Task file | Log entry |
34
+ |---|---|---|
35
+ | Every item met, and `check <ID>` says `can finish: yes` | `status: done`, `finished:` today | `task \| <ID> done`, then one body line on what was verified |
36
+ | Items met but soft deps open | stays `in-progress` | `task \| <ID> waiting on <ids>` |
37
+ | Blocked or partly done | stays `in-progress`; add what is left to "Notes" | `task \| <ID> blocked: <reason>` |
38
+
39
+ 7. **File what was learned.** If the implementer reported a decision or constraint the wiki should hold, offer to save it as a wiki page (`type: decision` or `concept`) and add it to `index.md`. If the task fixed a problem whose cause is now known, offer a `type: lesson` page (Symptom, Cause, Fix, How to notice it earlier); sw-triage finds these later. If it reported follow-up work, offer to create the tasks. These are separate offers: act on each only when the user says yes to that one.
40
+ 8. **Report** to the user: outcome, evidence per "Done when" item, files changed, deviations from the plan, and which tasks this unblocked (`node docs/.sw/sw.mjs ready`). Commit only if the user asks.
41
+
42
+ ## Common mistakes
43
+
44
+ - Marking `done` because the implementer said so. Done means every "Done when" item has evidence.
45
+ - Starting work before the task file says `in-progress`. If the session dies, nobody knows the task was touched.
46
+ - Letting the implementer edit the task file or the log. One writer for status: you.
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: sw-ingest
3
+ description: Use when the user adds or points to a source (article, paper, transcript, notes, meeting record, PDF, URL, data file) to be filed, processed or ingested into Superwiki, or invokes sw-ingest or sw:ingest.
4
+ ---
5
+
6
+ # sw-ingest
7
+
8
+ Turns one source into wiki knowledge. A source touches few files by default: its summary page, `index.md` and `log.md`. Wider cross-updates are recorded as follow-ups and done in sw-lint, so an ingest stays cheap.
9
+
10
+ ## Steps
11
+
12
+ 1. **Put the source in `docs/raw/`** as `<yyyy-mm-dd>-<slug>.<ext>` (date of the source if known, else today):
13
+ - a file outside `docs/`: copy it in under that name and leave the original where it is;
14
+ - a file already in `docs/raw/`: use it as it is;
15
+ - a URL or pasted text: save it as markdown, with the URL on the first line.
16
+
17
+ After this, never edit anything in `raw/`.
18
+ 2. **Read the source.** Read `docs/index.md` (not the wiki pages) to see what already exists.
19
+ 3. **Tell the user the three to five points worth keeping** and which existing pages they bear on, judged from the index lines. Wait for their steer unless they asked for a batch or unattended ingest.
20
+ 4. **Write the summary page** `docs/wiki/<slug>.md` from `docs/.sw/templates/page.md`. The slug is lowercase words joined by hyphens, says what the source is, and is not used by any other file in the vault.
21
+ - Frontmatter: `type: source`, a one-line `summary:`, `sources: [<raw file name>]`, `updated:` today.
22
+ - Body: the points, each traceable to the source; a normal markdown link to the raw file; `[[links]]` to the existing pages it relates to.
23
+ 5. **Check at most three existing pages** whose index line says they make a claim on the same subject. Open each, and edit it only if the source contradicts, corrects or dates what it says; add a `[[link]]` to the summary page where you edit. Everything else you noticed goes to the follow-up line in step 7. If the source introduces a concept or entity that several of its points depend on and no page covers, create that page; one or two per source at most.
24
+ 6. **Add the page to `index.md`**: `- [[slug]]: summary`, under its type.
25
+ 7. **Append to `docs/log.md`**, in the layout the log's last entries use (`tail -5 docs/log.md`):
26
+
27
+ ```
28
+ ## [YYYY-MM-DD] ingest | <source title>
29
+ Added [[slug]]. Updated [[page-a]]. Follow-up: [[page-b]] may need the new figures; no page yet for "<concept>".
30
+ ```
31
+
32
+ The `Follow-up` part is where everything you noticed but did not do goes. sw-lint reads it.
33
+ 8. **Run** `node docs/.sw/sw.mjs lint` and fix errors in the pages you wrote or edited.
34
+
35
+ ## Several sources at once
36
+
37
+ Do steps 1 to 8 per source, in order. Skip step 3's wait after the first source if the user said to continue. Do not read all sources before writing: each one is read, filed and left.
38
+
39
+ ## Common mistakes
40
+
41
+ - Reading wiki pages "for context" before writing. The index line is the context; step 5 is the only reading of existing pages.
42
+ - Rewriting many pages because the source mentions them. Mention is not change; log a follow-up.
43
+ - Copying the source into the wiki. The summary page holds what matters and links to the rest.
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: sw-init
3
+ description: Use when the user asks to set up, initialize, scaffold or upgrade a second brain, LLM wiki or Superwiki vault in a project's docs folder, or invokes sw-init or sw:init.
4
+ ---
5
+
6
+ # sw-init
7
+
8
+ Turns `docs/` into a Superwiki vault: an LLM-maintained wiki that is also an Obsidian vault, with an optional task module. A script does the scaffolding; do not create the files by hand.
9
+
10
+ The vault is always `<project root>/docs`. Run every command below from the project root. `<skill-dir>` is the directory this SKILL.md is in.
11
+
12
+ ## Steps
13
+
14
+ 1. **Check Node**: `node --version` must be 18 or newer. If not, go to "Without Node".
15
+ 2. **Upgrade or new?** If `docs/.sw/config.json` exists this is an upgrade: skip step 3 and run the script with no flags; it reuses the saved choices.
16
+ 3. **Ask the user, in one message** (new vault only):
17
+ - Task module on or off. Recommend on when the project is mainly code, off for a pure knowledge base.
18
+ - If on, the area prefixes for task ids (`M-01`, `B-01`). Recommend the single default area `T` unless the project already has separately named parts. Area names are optional labels; do not ask for them separately.
19
+ 4. **Run the script**, with the flags that match the answer:
20
+
21
+ ```bash
22
+ node <skill-dir>/scripts/init.mjs --tasks # tasks on, default area T
23
+ node <skill-dir>/scripts/init.mjs --tasks --areas "M=Mobile,B=Backend" # tasks on, named areas
24
+ node <skill-dir>/scripts/init.mjs --no-tasks # wiki only
25
+ node <skill-dir>/scripts/init.mjs # upgrade
26
+ ```
27
+
28
+ 5. **Check**: run `node docs/.sw/sw.mjs lint`. A new vault reports `0 errors, 0 warnings`. On an upgrade, findings are about the user's existing pages: show them, do not fix them unasked.
29
+ 6. **Report** to the user from the script's output. Each line starts with a status:
30
+
31
+ | Status | Say |
32
+ |---|---|
33
+ | `created`, `updated` | what is new or changed |
34
+ | `kept`, `unchanged` | that user content and settings were not touched (one sentence, no list) |
35
+ | `missing` | that this Superwiki build lacks the file; name it, and do not point the user at it |
36
+ | `note` about `CLAUDE.md` | offer to add the `@AGENTS.md` line. Add it only after the user agrees to that specific change |
37
+ | "docs/ already had content" | that content is untouched and outside the vault; sw-migrate converts it |
38
+
39
+ End with how to look at the result: open `docs/` as an Obsidian vault, or open `docs/viewer.html` in Chrome or Edge and pick the project folder (only if the viewer was not reported `missing`).
40
+
41
+ ## What the script guarantees
42
+
43
+ | File | On re-run |
44
+ |---|---|
45
+ | `docs/index.md`, `docs/log.md`, everything in `raw/`, `wiki/`, `tasks/`, `plans/` | kept |
46
+ | `docs/.sw/sw.mjs`, `docs/.sw/templates/`, `docs/viewer.html` | replaced with this version |
47
+ | `AGENTS.md` | only the Superwiki block (from the `sw:start` comment to the `sw:end` comment) is replaced |
48
+ | `docs/.sw/config.json` | areas and models kept unless new flags are passed |
49
+
50
+ ## Without Node
51
+
52
+ The script and `docs/.sw/sw.mjs` need Node 18 or newer. If `node` is missing or older, say so and stop; continue by hand only if the user asks for that. By hand: create `docs/{raw/assets,wiki}` (plus `tasks`, `plans`), copy `assets/templates/` to `docs/.sw/templates/` and `assets/viewer.html` to `docs/`, write `index.md` and `log.md` as the script would, and paste `assets/agents-block.md` into `AGENTS.md` with the `{{...}}` lines resolved. Tell the user the `sw.mjs` commands in that block will not work until Node is installed.
@@ -0,0 +1,29 @@
1
+ <!-- sw:start (managed by sw-init; write your own rules outside these markers) -->
2
+ ## Superwiki (`docs/`)
3
+
4
+ `docs/` is a wiki you write and keep current, and an Obsidian vault the user reads.
5
+
6
+ - `docs/index.md`: catalog, one line per wiki page. Read it first, then open only the pages you need.
7
+ - `docs/log.md`: append-only. Add `## [YYYY-MM-DD] <kind> | <title>` at the end; read it with `tail`, never whole.
8
+ - `docs/raw/`: sources. Read, never modify.
9
+ - `docs/wiki/`: flat, one page per topic, frontmatter `type:` and one-line `summary:`.
10
+ {{#tasks}}
11
+ - `docs/tasks/<ID>.md`: one task per file. `docs/plans/<ID>-plan.md`: its plan, if any.
12
+ {{/tasks}}
13
+ - Anything else under `docs/` belongs to other tools. Leave it alone.
14
+
15
+ Rules:
16
+
17
+ - Link vault pages as `[[file-name]]`; file names are unique across the vault. Use normal markdown links for `raw/` files and URLs, and plain paths for code.
18
+ - When you add or rename a wiki page, update its line in `index.md`.
19
+ - Answer questions from the wiki, index first. Offer to save an answer worth keeping as a wiki page.
20
+ {{#tasks}}
21
+ - A task's status lives only in its frontmatter. Before you start: `status: in-progress` and `started:`. When its "Done when" list is met: `status: done` and `finished:`. Each change gets a `task` entry in `log.md`.
22
+ - Do not start a task while any of its `deps` is not done.
23
+ - `node docs/.sw/sw.mjs status|ready|check <ID>|explain <ID>|search <words>|next-id <AREA>|lint` answers overview, startable tasks, blockers, a task's place in the chain, where something is mentioned, new ids and structural checks without reading files. Run `lint` after you add, rename or relink pages.
24
+ {{/tasks}}
25
+ {{^tasks}}
26
+ - `node docs/.sw/sw.mjs search <words>` finds where something is mentioned; `lint` checks links and frontmatter. Neither needs you to read files. Run `lint` after you add, rename or relink pages.
27
+ {{/tasks}}
28
+ - File formats: `docs/.sw/templates/`.
29
+ <!-- sw:end -->