@dmthepm/commune 0.5.1 → 0.6.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.
package/README.md CHANGED
@@ -1,10 +1,41 @@
1
1
  # Commune
2
2
 
3
- A wiki engine for Astro, and a CLI that queries the wiki's link graph without running a build.
3
+ Keep your thinking connected.
4
4
 
5
- Write markdown. Link notes with `[[double brackets]]`. Get a static site where every link resolves both ways, every page has a plain-markdown twin, and the whole graph is one JSON file you can also query from a terminal.
5
+ Commune helps you maintain a personal wiki from markdown notes and dictated thoughts. Its CLI finds connections while you write. Optional agent skills capture a dump, ask a short round of questions, draft a revision for your review and ship on your word. Its Astro engine publishes linked notes with backlinks and a markdown twin of every page. MIT. It runs [devon.md](https://devon.md).
6
6
 
7
- MIT. It runs [devon.md](https://devon.md).
7
+ - **See it.** Explore [devon.md](https://devon.md).
8
+ - **Start a wiki.** Copy the starter below. You need Node 22.12 or newer, npm and Git.
9
+ - **Report a first run.** [Tell me where it broke](https://github.com/dmthepm/commune-wiki/issues/85). A failed attempt is useful.
10
+
11
+ **Status on September 8, 2026.** Commune runs Devon's personal wiki. A timed install on another machine, an outside author's return edit, and an end to end run with the installed authoring skills are still unproven. The [launch checklist](docs/launch/README.md) lists the evidence still owed.
12
+
13
+ ## Start a wiki
14
+
15
+ The starter is a separate project on the published package. Pick a new folder for it.
16
+
17
+ ```bash
18
+ git clone https://github.com/dmthepm/commune-wiki.git
19
+ cd commune-wiki
20
+ node scripts/create-wiki.mjs ../my-wiki
21
+ cd ../my-wiki
22
+ npm install
23
+ npm run build
24
+ npm run verify
25
+ npm run dev
26
+ ```
27
+
28
+ Open the local URL Astro prints. The [starter instructions](examples/starter/README.md) walk through editing a sample note, opening connected notes in panes, and checking backlinks and markdown twins. The copy command installs nothing. `npm install` runs in your new wiki, and the engine repository itself needs no install.
29
+
30
+ If you stop or have to guess, [tell me where](https://github.com/dmthepm/commune-wiki/issues/85). Include the step, your versions and what happened. No private vault needed. An existing Astro 7 project can skip the starter and use the [integration below](#install). The [agent skills](#author-with-the-skills) install separately into a wiki you already have and do not create a site.
31
+
32
+ ## Vision and mission
33
+
34
+ **Vision.** People can keep their thinking connected, current and in their own hands, and share it in public as it develops.
35
+
36
+ **Mission.** Commune turns markdown notes, dictated thoughts and the residue of everyday work into a maintained personal wiki through a shared link graph, authoring tools and portable publishing.
37
+
38
+ Commune grew out of [devon.md](https://devon.md). Devon built his own site and recognised the structure afterward, then extracted its tools so someone else could build on them. It is an MIT project with no company behind it and no plans for monetization.
8
39
 
9
40
  ## Install
10
41
 
@@ -14,7 +45,7 @@ You need an Astro 7 project on Node 22.12 or newer.
14
45
  pnpm add @dmthepm/commune @astrojs/markdown-remark
15
46
  ```
16
47
 
17
- Then three files, and your notes. `astro.config.mjs`, in full:
48
+ This minimal integration produces plain HTML notes. For the assembled wiki interface, use the [starter](examples/starter/README.md). Add three files, and your notes. `astro.config.mjs`, in full:
18
49
 
19
50
  ```js
20
51
  import { defineConfig } from 'astro/config';
@@ -70,7 +101,7 @@ const { Content } = await render(note);
70
101
  </html>
71
102
  ```
72
103
 
73
- Both are the smallest versions that work. [`tests/fixtures/consumer`](tests/fixtures/consumer) is the same project one step further along — it adds the `research` and `pages` collections and imports components off the package — and it is the reference to read when you want the fuller shape.
104
+ Both are minimal examples. [`examples/starter`](examples/starter) provides a separate wiki project. [`tests/fixtures/consumer`](tests/fixtures/consumer) tests integration against this repository through a local file dependency; it is a development fixture, not a portable starter.
74
105
 
75
106
  Notes go in `src/content/notes/`. Two frontmatter fields are load-bearing:
76
107
 
@@ -83,24 +114,24 @@ visibility: "public"
83
114
  A link to [[World]], and one to [Astro](https://astro.build).
84
115
  ```
85
116
 
86
- `title` is what `[[Hello]]` matches on. `visibility` defaults to private, so only `public` is published. Build that, and the paragraph renders as:
117
+ `title` is what `[[Hello]]` matches on. For notes, `visibility` defaults to private, so only `public` is published. Add a second public note with `title: "World"` before building; the link then resolves and the paragraph renders as:
87
118
 
88
119
  ```html
89
120
  A link to <a href="/notes/world/" class="wikilink">World</a>, and one to
90
121
  <a href="https://astro.build" target="_blank" rel="noopener noreferrer">Astro</a>.
91
122
  ```
92
123
 
93
- That route is a starting point, not an interface. The package ships the mechanism and none of `src/pages/` — the markup, the layout and the URL shape are yours to change, and Commune keeps the links inside them working.
124
+ That route is a starting point, not an interface. The package ships the mechanism and none of `src/pages/` — the markup, the layout and the URL shape are yours to change, with Commune resolving links through its shared graph.
94
125
 
95
126
  ## What ships
96
127
 
97
- - **WikiLinks.** `[[Title]]` and `[[Title|Display text]]` become real hrefs at build time, matched against titles and aliases. A link that resolves to nothing stays plain text instead of rendering a dead anchor.
128
+ - **WikiLinks.** Connect notes with `[[Title]]`, using the target title verbatim and rewriting the sentence around it. The renderer also resolves aliases and `[[Title|Display text]]`, but `check` and `gate` report these noncanonical spellings. A link that resolves to nothing stays plain text instead of rendering a dead anchor.
98
129
  - **Backlinks.** The build writes `backlinks.json` — every entry with its inbound and outbound edges — to `dist/` and `public/`. `Backlinks.astro` renders it on a page.
99
130
  - **Markdown twins.** Every published content entry gets its source written beside it, so `/notes/hello/` also answers at `/notes/hello.md`. Entries in the content directories only — a hand-written route under `src/pages/` has no source file to twin. Agents and readers get the same document without scraping HTML.
100
131
  - **External links.** Anything off your `site` origin gets `target="_blank" rel="noopener noreferrer"` without you marking it up.
101
- - **The graph as a library.** `@dmthepm/commune/graph` exports the content loader, the link resolver and the graph builder. The Astro build and the CLI both call it. That is the point: one resolver, not two that drift.
132
+ - **The graph as a library.** `@dmthepm/commune/graph` exports the content loader, the link resolver and the graph builder. The Astro build and the CLI both call it. Sharing the resolver reduces duplicated link logic; it does not guarantee that links never break.
102
133
  - **Updates.** A fourth collection, `src/content/updates/`, for the dated entries that say what changed. `Updates.astro` renders the newest few as a card. See [Updates](#updates) below.
103
- - **Honest dates.** `updated:` in frontmatter wins where you wrote one; where you did not, the date comes from the file's last commit, and from its mtime in a tree with no history. Every entry says which, so a page can show the honest one. See [Dates](#dates) below.
134
+ - **Dates with sources.** `updated:` in frontmatter wins where you wrote one; where you did not, the date comes from the file's last commit, and from its mtime in a tree with no history. Every entry says which, so a page can show where the date came from. See [Dates](#dates) below.
104
135
  - **A site-wide last-updated.** The build writes `site.json` beside `backlinks.json`: the newest date across the whole wiki, which entry it belongs to, and the newest commit date whatever the entries claim.
105
136
  - **Components and stylesheets.** `@dmthepm/commune/components/*.astro` and `@dmthepm/commune/styles/*.css`, shipped as source. These are the components off my own site rather than a theme system — take them as a starting point, not an API.
106
137
 
@@ -172,7 +203,7 @@ links:
172
203
  I rewrote the home note. [[Atomic Notes]] and [[Evergreen Notes]] are new.
173
204
  ```
174
205
 
175
- `links:` is the one place in frontmatter where a bare string is a link. Everywhere else a link has to be spelled `[[like this]]` — a page's own `url:` would otherwise become a self-edge — but `links:` means nothing else, so a title or a site path both resolve and both become real edges. Write it or don't: `[[wikilinks]]` in the body work the same way, and naming a page in both places is still one edge.
206
+ `links:` is the one place in frontmatter where a bare string is a link. Everywhere else a link has to be spelled `[[like this]]`; a page's own `url:` would otherwise become a self-edge; but `links:` means nothing else, so a title or a site path both resolve and both become edges. Write it or don't: `[[wikilinks]]` in the body work the same way, and naming a page in both places is still one edge.
176
207
 
177
208
  Register the collection alongside your notes in `src/content.config.ts`:
178
209
 
@@ -228,7 +259,7 @@ export async function GET(context) {
228
259
 
229
260
  ## The CLI
230
261
 
231
- `commune` installs as a bin. It reads markdown off disk and answers without an Astro process running, which is what makes it useful while you are still writing.
262
+ Find connections and check your notes while you write, without building the site. The `commune` executable reads markdown directly from disk and answers without an Astro process running.
232
263
 
233
264
  ```bash
234
265
  commune check
@@ -263,31 +294,35 @@ Every verb takes `--json` and emits one document on stdout with everything else
263
294
 
264
295
  Exit codes report whether the command finished, never what it found — `0` finished, `1` could not finish, `2` invalid invocation. Findings live in the payload. A command that exits non-zero because it *found* something is indistinguishable, to a shell, from one that crashed. `gate` is the one deliberate exception: a gate's entire job is a yes/no and a build has to stop on it, so `gate` exits `1` when the build it checked is wrong.
265
296
 
266
- `commune --help` prints the full surface. `commune --version` prints the installed version, which is the honest way to know what you have.
297
+ `commune --help` prints the full surface. `commune --version` prints the installed version, which is the way to know what you have.
267
298
 
268
299
  ## Author with the skills
269
300
 
270
- The loop above the CLI ships as four agent skills, in `skills/`, installed straight from this repository rather than from npm:
301
+ These optional skills require an existing Commune wiki and access to Claude Code or Codex. They do not install the engine or scaffold a site. Install the four authoring skills from this repository.
271
302
 
272
303
  ```bash
273
304
  npx skills add dmthepm/commune-wiki
274
305
  ```
275
306
 
276
- They install for Claude Code and Codex, globally or into one project, and they drive the `commune` your wiki already has — `node_modules/.bin/commune`, called by path, never downloaded — so the CLI a skill runs is the one your site builds with. They need 0.4.0 or newer, they check that first, and they install nothing themselves.
307
+ The skills install for Claude Code and Codex, globally or into one project. They call the wiki's existing `node_modules/.bin/commune` directly, so authoring and publishing use the same CLI. They require version 0.4.0 or newer, check it first and install nothing themselves.
277
308
 
278
- The loop is one dump, four files and two places it stops for you. `commune-dump` takes a dictated or pasted dump, writes it verbatim to `dumps/<date>-<slug>.md`, and asks the graph what it already touches — what it mentions, which of the target's links a rewrite would put at risk, which subjects have no note yet — into `dumps/<slug>.connect.md`. `commune-write` reads your `WRITING.md`, asks one short round of questions whose answers each change a file, stops while you answer them in `dumps/<slug>.answers.md`, then drafts into the real note and renders the original and the draft side by side as `dumps/<slug>.review.html`. `commune-ship` diffs `check` against the baseline, files the `updates` entry, builds, gates, greps `dist/` for every new href, commits and opens the PR — and never merges, because the last word is yours. `commune-setup` runs once per wiki and writes the `WRITING.md` the other three obey.
309
+ `commune-setup` runs once per wiki and writes its `WRITING.md` rules. `commune-dump` saves dictated or pasted text verbatim to `dumps/<slug>.md` and records connection candidates and the check baseline in `dumps/<slug>.connect.md`. Here `<slug>` includes the capture date.
279
310
 
280
- Status, honestly: the skills, their test and the `WRITING.md` template are here. The loop has been run once end to end by hand, before it was skills; it has not yet been run as skills on a real wiki. That run is [#10](https://github.com/dmthepm/commune-wiki/issues/10), and this paragraph changes when it lands.
311
+ `commune-write` asks one short round of editorial questions and waits for answers in `dumps/<slug>.answers.md`. It then drafts into the note and renders the original and draft side by side in `dumps/<slug>.review.html` for the author to review.
281
312
 
282
- ## What it is not
313
+ On the author's instruction, `commune-ship` compares finding identities against the baseline, files an update, builds, gates and verifies each new href and destination file. It commits according to `WRITING.md`'s `dumps.commit` policy, opens a PR and records the receipt in `dumps/<slug>.ship.md`. The author approves the content. This skill never merges. That boundary governs authored content, while code maintenance follows the repository's contribution rules.
283
314
 
284
- It is not a note-taking app and it is not trying to replace one. I write in Obsidian; Commune is what turns the vault into a site. There is no editor here, no sync, no account, no server. The graph is computed from files on disk at build time, and the files are yours whether or not you ever run this.
315
+ The four skills, their tests and the `WRITING.md` template ship today. The loop was run once end to end by hand before the skills existed. An end-to-end run using the installed skills remains unverified.
285
316
 
286
- ## Where this is going
317
+ ## Files and publishing
287
318
 
288
- Commune is the engine under a larger idea: own your canon. The wiki is one output surface, not the product. What I am building toward is an authoring loop — dictate a dump, have agents find what it already connects to, grill it, draft it, ship it — where the graph is what makes connection-finding possible *before* a draft exists. That is why the graph is a queryable library with a CLI on top instead of a build artifact, and why `graph related` reads stdin.
319
+ Commune is not a note-taking app. It works with markdown files on disk, written in whatever editor you like, and provides no editor, sync service, account or server of its own. The files remain yours whether or not you ever run it.
289
320
 
290
- The authoring half of that loop is here now, as the four skills above; `pnpm add @dmthepm/commune` still gives you the engine and the CLI and nothing else, which is what those skills drive. What is left — the email destination, the weekly intake from GitHub activity — is tracked in [the issues](https://github.com/dmthepm/commune-wiki/issues).
321
+ Only notes with `visibility: public` enter the graph and publishing output. Research, pages and updates are included regardless of visibility. Handoffs in `dumps/` are committed by default under the writing policy. They are outside the engine's content collections and do not automatically become site pages.
322
+
323
+ ## What needs testing
324
+
325
+ The [launch checklist](docs/launch/README.md) tracks first-install, installed-skills and return-edit proof, plus browsing and editing in Obsidian. Features follow what those sessions show is needed. Work is tracked in [the issues](https://github.com/dmthepm/commune-wiki/issues).
291
326
 
292
327
  ## Deploy
293
328
 
@@ -295,6 +330,8 @@ The build output is `dist/`, a static directory with no runtime, so any static h
295
330
 
296
331
  ## Working on Commune itself
297
332
 
333
+ Use Node 22.18+ (the current Node 22 release selected by `.nvmrc`) and pnpm 10. The repository runs TypeScript source directly in its tests. The published package has the lower Node 22.12+ minimum.
334
+
298
335
  ```bash
299
336
  pnpm install
300
337
  pnpm dev # the engine's own wiki, for developing against
@@ -302,7 +339,9 @@ pnpm build # compile lib/, build the site, then gate it
302
339
  pnpm test # node --test
303
340
  ```
304
341
 
305
- `pnpm test:consumer` installs `tests/fixtures/consumer` against the working tree and builds it. That fixture is a stranger's project in miniature, and it is the check that catches a package boundary this README describes wrongly.
342
+ `pnpm test:consumer` installs `tests/fixtures/consumer` against the working tree and builds it. This checks the package boundary locally. It does not substitute for an independent first install.
343
+
344
+ Run `pnpm test:starter` from the repository root to check the copier, destination safeguards and published dependency declarations. The registry install test is skipped by default. `COMMUNE_STARTER_INSTALL=1 pnpm test:starter` also copies the starter into a temporary directory, installs from npm, builds and verifies its output. Neither mode proves a timed first install on another machine.
306
345
 
307
346
  [CONTRIBUTING.md](CONTRIBUTING.md) has the rest. Issues and questions go to [the tracker](https://github.com/dmthepm/commune-wiki/issues).
308
347
 
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@dmthepm/commune",
3
3
  "type": "module",
4
- "version": "0.5.1",
5
- "description": "An Astro wiki engine with WikiLinks, sliding panes, backlinks and static search, plus a commune CLI that queries the content graph and checks links",
4
+ "version": "0.6.0",
5
+ "description": "Maintain a personal wiki from markdown notes, dictated thoughts and everyday work with authoring tools, a shared link graph and portable Astro publishing.",
6
6
  "license": "MIT",
7
7
  "keywords": [
8
8
  "astro",
@@ -63,6 +63,8 @@
63
63
  },
64
64
  "homepage": "https://github.com/dmthepm/commune-wiki#readme",
65
65
  "scripts": {
66
+ "create-wiki": "node scripts/create-wiki.mjs",
67
+ "test:starter": "node --test tests/starter.test.mjs",
66
68
  "build:lib": "tsc -p tsconfig.build.json",
67
69
  "prepare": "pnpm build:lib",
68
70
  "pretest": "pnpm build:lib",
@@ -34,15 +34,16 @@
34
34
  if (note?.isStarred) {
35
35
  // Check if star isn't already there
36
36
  if (!link.querySelector('.star-indicator-inline') && !link.nextElementSibling?.classList?.contains('star-indicator-inline')) {
37
- // Create wrapper to prevent line break between link and star
37
+ // The star must not land on a line of its own, but the link itself
38
+ // has to wrap like any other run of text: a whole-link nowrap
39
+ // pushed long titles onto their own line on phones. A no-break
40
+ // space glues the star to the link's last word and nothing else.
38
41
  const wrapper = document.createElement('span');
39
- wrapper.style.whiteSpace = 'nowrap';
40
- wrapper.style.display = 'inline';
41
42
 
42
43
  // Create star as a separate clickable element (not part of the link)
43
44
  const star = document.createElement('span');
44
45
  star.className = 'star-indicator-inline';
45
- star.textContent = ' ⭐';
46
+ star.textContent = '\u00A0⭐';
46
47
  star.setAttribute('aria-label', 'Top 5% most linked - click to learn more');
47
48
  star.setAttribute('role', 'button');
48
49
  star.setAttribute('tabindex', '0');
@@ -67,7 +68,7 @@
67
68
  }
68
69
  });
69
70
 
70
- // Wrap the link in the nowrap container
71
+ // Keep the link and its star as one span
71
72
  link.parentNode.insertBefore(wrapper, link);
72
73
  wrapper.appendChild(link);
73
74
  wrapper.appendChild(star);