wiki-viewer 1.0.0 → 1.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.
- package/.next/standalone/README.md +365 -99
- package/.next/standalone/agents/bootstrap-prompt.md +1 -0
- package/.next/standalone/agents/wiki-viewer-skill/SKILL.md +236 -0
- package/.next/standalone/bin/wiki-viewer.js +431 -33
- package/.next/standalone/docs/agent-collab-plan.md +1615 -0
- package/.next/standalone/docs/agent-collab-v2-plan.md +771 -0
- package/.next/standalone/package.json +19 -2
- package/.next/standalone/pnpm-lock.yaml +1368 -325
- package/.next/standalone/pnpm-workspace.yaml +7 -1
- package/.next/standalone/src/app/api/agent/activity/route.ts +58 -0
- package/.next/standalone/src/app/api/agent/admin/agents/[agentId]/revoke/route.ts +40 -0
- package/.next/standalone/src/app/api/agent/admin/agents/route.ts +33 -0
- package/.next/standalone/src/app/api/agent/admin/registrations/[regId]/approve/route.ts +83 -0
- package/.next/standalone/src/app/api/agent/admin/registrations/[regId]/deny/route.ts +36 -0
- package/.next/standalone/src/app/api/agent/admin/registrations/route.ts +27 -0
- package/.next/standalone/src/app/api/agent/events/[...path]/route.ts +136 -0
- package/.next/standalone/src/app/api/agent/files/[...path]/route.ts +202 -0
- package/.next/standalone/src/app/api/agent/internal/span/route.ts +117 -0
- package/.next/standalone/src/app/api/agent/register/[regId]/route.ts +50 -0
- package/.next/standalone/src/app/api/agent/register/route.ts +110 -0
- package/.next/standalone/src/app/api/agent/settings/route.ts +30 -0
- package/.next/standalone/src/app/api/agent/settings/token/regenerate/route.ts +20 -0
- package/.next/standalone/src/app/api/agent/sidecar/[...path]/route.ts +49 -0
- package/.next/standalone/src/app/api/agents/install/route.ts +83 -0
- package/.next/standalone/src/app/api/agents/skill/route.ts +20 -0
- package/.next/standalone/src/app/api/agents/skill.tar.gz/route.ts +87 -0
- package/.next/standalone/src/app/api/auth/[...all]/route.ts +7 -0
- package/.next/standalone/src/app/api/owner/init/route.ts +14 -0
- package/.next/standalone/src/app/api/system/auth-settings/route.ts +85 -0
- package/.next/standalone/src/app/api/system/browse/route.ts +4 -0
- package/.next/standalone/src/app/api/system/clear-root/route.ts +8 -1
- package/.next/standalone/src/app/api/system/config/route.ts +5 -1
- package/.next/standalone/src/app/api/system/pins/route.ts +7 -0
- package/.next/standalone/src/app/api/system/reveal/route.ts +7 -0
- package/.next/standalone/src/app/api/system/root-status/route.ts +5 -1
- package/.next/standalone/src/app/api/system/set-root/route.ts +7 -0
- package/.next/standalone/src/app/api/wiki/app/route.ts +15 -0
- package/.next/standalone/src/app/api/wiki/content/route.ts +110 -11
- package/.next/standalone/src/app/api/wiki/folder/route.ts +7 -0
- package/.next/standalone/src/app/api/wiki/move/route.ts +7 -0
- package/.next/standalone/src/app/api/wiki/new-file/route.ts +55 -0
- package/.next/standalone/src/app/api/wiki/page/route.ts +7 -0
- package/.next/standalone/src/app/api/wiki/route.ts +10 -0
- package/.next/standalone/src/app/api/wiki/slugs/route.ts +5 -1
- package/.next/standalone/src/app/api/wiki/upload/route.ts +7 -0
- package/.next/standalone/src/app/api/wiki/watch/route.ts +6 -1
- package/.next/standalone/src/app/globals.css +70 -0
- package/.next/standalone/src/app/page.tsx +461 -217
- package/.next/standalone/src/app/signin/page.tsx +217 -0
- package/.next/standalone/src/components/ai-panel/activity-row.tsx +64 -0
- package/.next/standalone/src/components/ai-panel/ai-panel.tsx +322 -0
- package/.next/standalone/src/components/ai-panel/token-section.tsx +312 -0
- package/.next/standalone/src/components/auth-settings-sheet.tsx +209 -0
- package/.next/standalone/src/components/editor/bubble-menu.tsx +41 -2
- package/.next/standalone/src/components/editor/comment-pip.tsx +56 -0
- package/.next/standalone/src/components/editor/comment-thread.tsx +252 -0
- package/.next/standalone/src/components/editor/editor.tsx +513 -10
- package/.next/standalone/src/components/editor/extensions/proof-span.ts +60 -0
- package/.next/standalone/src/components/editor/extensions.ts +2 -0
- package/.next/standalone/src/components/editor/proof-span-popover.tsx +161 -0
- package/.next/standalone/src/components/editor/suggest-edit-popover.tsx +228 -0
- package/.next/standalone/src/components/editor/suggestion-card.tsx +201 -0
- package/.next/standalone/src/components/view-width-toggle.tsx +47 -0
- package/.next/standalone/src/components/wiki/markdown-preview.tsx +120 -0
- package/.next/standalone/src/lib/auth/allowlist.ts +50 -0
- package/.next/standalone/src/lib/auth/client.ts +4 -0
- package/.next/standalone/src/lib/auth/csrf.ts +68 -0
- package/.next/standalone/src/lib/auth/server.ts +164 -0
- package/.next/standalone/src/lib/config.ts +4 -0
- package/.next/standalone/src/lib/markdown/parse-frontmatter.ts +20 -0
- package/.next/standalone/src/lib/markdown/sanitize-schema.ts +106 -0
- package/.next/standalone/src/lib/markdown/to-html.ts +46 -8
- package/.next/standalone/src/lib/markdown/to-markdown.ts +14 -0
- package/.next/standalone/src/lib/proof/activity-shared.ts +31 -0
- package/.next/standalone/src/lib/proof/activity.ts +74 -0
- package/.next/standalone/src/lib/proof/auth.ts +132 -0
- package/.next/standalone/src/lib/proof/block-refs.ts +133 -0
- package/.next/standalone/src/lib/proof/blocks.ts +73 -0
- package/.next/standalone/src/lib/proof/client-auth.ts +23 -0
- package/.next/standalone/src/lib/proof/event-bus.ts +47 -0
- package/.next/standalone/src/lib/proof/file-lock.ts +38 -0
- package/.next/standalone/src/lib/proof/glob.ts +51 -0
- package/.next/standalone/src/lib/proof/idempotency.ts +32 -0
- package/.next/standalone/src/lib/proof/mutex.ts +32 -0
- package/.next/standalone/src/lib/proof/ops-applier.ts +678 -0
- package/.next/standalone/src/lib/proof/owner-auth.ts +2 -0
- package/.next/standalone/src/lib/proof/pending.ts +97 -0
- package/.next/standalone/src/lib/proof/proof-span.ts +141 -0
- package/.next/standalone/src/lib/proof/rate-limit.ts +53 -0
- package/.next/standalone/src/lib/proof/register-rate-limit.ts +53 -0
- package/.next/standalone/src/lib/proof/registry.ts +190 -0
- package/.next/standalone/src/lib/proof/sidecar.ts +66 -0
- package/.next/standalone/src/lib/proof/suggest-capture.ts +69 -0
- package/.next/standalone/src/lib/proof/types.ts +170 -0
- package/.next/standalone/src/lib/proof-config.ts +14 -0
- package/.next/standalone/src/middleware.ts +38 -0
- package/.next/standalone/src/stores/ai-panel-store.ts +58 -3
- package/.next/standalone/src/stores/editor-store.ts +115 -9
- package/.next/standalone/src/stores/proof-store.ts +123 -0
- package/.next/standalone/src/stores/view-width-store.ts +62 -0
- package/.next/standalone/src/tests/proof/activity-aggregator.test.ts +146 -0
- package/.next/standalone/src/tests/proof/agent-ownership.test.ts +140 -0
- package/.next/standalone/src/tests/proof/agents-install.test.ts +57 -0
- package/.next/standalone/src/tests/proof/better-auth.test.ts +68 -0
- package/.next/standalone/src/tests/proof/block-refs.test.ts +108 -0
- package/.next/standalone/src/tests/proof/blocks.test.ts +92 -0
- package/.next/standalone/src/tests/proof/comments-ops.test.ts +177 -0
- package/.next/standalone/src/tests/proof/editor-roundtrip.test.ts +85 -0
- package/.next/standalone/src/tests/proof/external-edit.test.ts +58 -0
- package/.next/standalone/src/tests/proof/file-lock.test.ts +80 -0
- package/.next/standalone/src/tests/proof/glob.test.ts +82 -0
- package/.next/standalone/src/tests/proof/helpers/auth-session.ts +27 -0
- package/.next/standalone/src/tests/proof/markdown-to-html.test.ts +46 -0
- package/.next/standalone/src/tests/proof/ops-applier.test.ts +368 -0
- package/.next/standalone/src/tests/proof/owner-init.test.ts +2 -0
- package/.next/standalone/src/tests/proof/parse-frontmatter.test.ts +60 -0
- package/.next/standalone/src/tests/proof/proof-span.test.ts +98 -0
- package/.next/standalone/src/tests/proof/rate-limit.test.ts +54 -0
- package/.next/standalone/src/tests/proof/registration-flow.test.ts +330 -0
- package/.next/standalone/src/tests/proof/registry.test.ts +169 -0
- package/.next/standalone/src/tests/proof/routes.test.ts +516 -0
- package/.next/standalone/src/tests/proof/sidecar-trim.test.ts +58 -0
- package/.next/standalone/src/tests/proof/suggestion-ops.test.ts +280 -0
- package/.next/standalone/src/tests/proof/wiki-content-put.test.ts +140 -0
- package/.next/standalone/src/tests/proof/wiki-routes-auth.test.ts +208 -0
- package/README.md +365 -99
- package/bin/wiki-viewer.js +431 -33
- package/package.json +19 -2
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
<img src="public/logo.svg" width="80" height="80" alt="wiki-viewer logo" />
|
|
3
3
|
<h1>wiki-viewer</h1>
|
|
4
|
-
<p><strong>Browse, read, and edit your local files from a clean web UI.</strong></p>
|
|
4
|
+
<p><strong>Browse, read, and edit your local files from a clean web UI. Now with multi-user auth and an HTTP API for AI agents.</strong></p>
|
|
5
5
|
<p>
|
|
6
6
|
Markdown · PDF · Office docs · Notebooks · Images · Code · and more
|
|
7
7
|
</p>
|
|
8
8
|
|
|
9
9
|
<p>
|
|
10
|
-
|
|
11
|
-
<!-- <a href="https://www.npmjs.com/package/wiki-viewer"><img src="https://img.shields.io/npm/v/wiki-viewer" alt="npm version" /></a> -->
|
|
12
|
-
<img src="https://img.shields.io/badge/npm-not%20yet%20published-lightgrey" alt="npm not yet published" />
|
|
10
|
+
<a href="https://www.npmjs.com/package/wiki-viewer"><img src="https://img.shields.io/npm/v/wiki-viewer" alt="npm version" /></a>
|
|
13
11
|
<img src="https://img.shields.io/badge/node-%3E%3D18-brightgreen" alt="Node.js ≥18" />
|
|
14
12
|
<img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT license" />
|
|
15
13
|
</p>
|
|
@@ -19,9 +17,15 @@
|
|
|
19
17
|
|
|
20
18
|
## What is it?
|
|
21
19
|
|
|
22
|
-
**wiki-viewer** is a
|
|
20
|
+
**wiki-viewer** is a local-or-remote file browser and editor you run from your terminal. It starts a small web server and lets you navigate, read, and edit any directory on your machine.
|
|
23
21
|
|
|
24
|
-
|
|
22
|
+
Originally a zero-config single-user tool, it now supports:
|
|
23
|
+
|
|
24
|
+
- Multi-user sign-in (Google OAuth or email + password) for teams of 3 to 10 sharing a VPS.
|
|
25
|
+
- An HTTP collaboration API that lets AI agents read and edit Markdown files alongside you, with provenance marks, comments, suggestions, and revision-checked mutations.
|
|
26
|
+
- Per-agent registration and scoped tokens. No shared bearer secret.
|
|
27
|
+
|
|
28
|
+
Single-user, no-auth mode still works. Auth turns on automatically once anyone signs up.
|
|
25
29
|
|
|
26
30
|
---
|
|
27
31
|
|
|
@@ -34,14 +38,14 @@ No cloud. No accounts. No syncing. Your files stay on your machine.
|
|
|
34
38
|
| **File ops** | Upload files, create folders, delete, drag-to-move |
|
|
35
39
|
| **Wiki links** | `[[page-name]]` links between Markdown files |
|
|
36
40
|
| **Dark mode** | System-aware, with manual toggle |
|
|
37
|
-
| **
|
|
41
|
+
| **Auth** | Google OAuth and email + password via [Better Auth](https://better-auth.com). Email allowlist. SQLite-backed sessions. |
|
|
42
|
+
| **AI agents** | Per-agent HTTP API. Trust On First Use registration. Comments, suggestions, inline provenance marks (`<proof-span>`). Block-level revision check. Idempotency keys. Per-IP rate limiting. |
|
|
43
|
+
| **HTTPS** | Required for remote access. Self-signed cert (OpenSSL), trusted local cert (mkcert), or your own TLS in front of plain HTTP. |
|
|
38
44
|
|
|
39
45
|
---
|
|
40
46
|
|
|
41
47
|
## Quick start
|
|
42
48
|
|
|
43
|
-
> **Note:** The npm package is not yet published. Use the [dev setup](#-dev-setup) below to run locally from source. The `npx` commands below will work once the package is on npm.
|
|
44
|
-
|
|
45
49
|
```bash
|
|
46
50
|
# Point it at a directory
|
|
47
51
|
npx wiki-viewer ~/notes
|
|
@@ -53,11 +57,15 @@ npx wiki-viewer
|
|
|
53
57
|
npx wiki-viewer ~/notes --https
|
|
54
58
|
```
|
|
55
59
|
|
|
56
|
-
|
|
60
|
+
Open **http://localhost:3000** (or **https://localhost:3000** with `--https`).
|
|
61
|
+
|
|
62
|
+
To switch the served directory later, click **Change** at the bottom of the sidebar and pick a new folder. No restart needed.
|
|
57
63
|
|
|
58
|
-
|
|
64
|
+
On first run with no users in the database, the app works in single-user mode and any visitor on `localhost` can sign up. Set `AUTH_ALLOWED_DOMAIN` or `AUTH_ALLOWED_EMAILS` before exposing the server to anyone else.
|
|
59
65
|
|
|
60
|
-
|
|
66
|
+
> ⚠️ **Running on a remote host?** The app must be accessed over **HTTPS**. Browsers gate several APIs (service workers, PDF.js, secure-context features) behind HTTPS. Plain HTTP only works on `localhost`.
|
|
67
|
+
|
|
68
|
+
### CLI options
|
|
61
69
|
|
|
62
70
|
```
|
|
63
71
|
wiki-viewer [directory] [options]
|
|
@@ -67,11 +75,19 @@ wiki-viewer [directory] [options]
|
|
|
67
75
|
Options:
|
|
68
76
|
-p, --port <port> Port to listen on (default: 3000)
|
|
69
77
|
-H, --host <host> Host to bind to (default: localhost)
|
|
70
|
-
--https Enable HTTPS (self-signed cert, required
|
|
78
|
+
--https Enable HTTPS (self-signed cert, required on remote)
|
|
71
79
|
-h, --help Show this help message
|
|
80
|
+
|
|
81
|
+
Commands:
|
|
82
|
+
service install [dir] [options] Install as a user service (persists across reboot)
|
|
83
|
+
service uninstall Remove the user service
|
|
84
|
+
service status Show service status
|
|
85
|
+
service logs Tail service logs
|
|
86
|
+
service restart Restart the service
|
|
87
|
+
update Update to the latest version and restart the service
|
|
72
88
|
```
|
|
73
89
|
|
|
74
|
-
|
|
90
|
+
Examples:
|
|
75
91
|
|
|
76
92
|
```bash
|
|
77
93
|
# Custom port
|
|
@@ -84,118 +100,352 @@ npx wiki-viewer ~/notes -H 0.0.0.0
|
|
|
84
100
|
npx wiki-viewer ~/notes --https -p 8443
|
|
85
101
|
```
|
|
86
102
|
|
|
103
|
+
### Run as a service (reboot persistence)
|
|
104
|
+
|
|
105
|
+
Install wiki-viewer as a user service so it starts at boot and restarts on failure. Linux uses `systemd --user`, macOS uses a launchd LaunchAgent. No root needed.
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# Install with the run config you want (dir, host, port, https)
|
|
109
|
+
wiki-viewer service install ~/notes -H 0.0.0.0 -p 3003 --https
|
|
110
|
+
|
|
111
|
+
# Manage it
|
|
112
|
+
wiki-viewer service status
|
|
113
|
+
wiki-viewer service logs
|
|
114
|
+
wiki-viewer service restart
|
|
115
|
+
wiki-viewer service uninstall
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The run config is saved to `~/.wiki-viewer/config.json`. Edit that file and run `wiki-viewer service restart` to change settings without reinstalling. To change just the served directory at runtime, you can also click **Change** in the sidebar.
|
|
119
|
+
|
|
120
|
+
On Linux, install enables lingering (`loginctl enable-linger`) so the service runs without an active login session and survives reboot. If that step needs privileges, the installer prints the command to run manually.
|
|
121
|
+
|
|
122
|
+
> Ad-hoc runs like `wiki-viewer ~/docs` ignore the saved config. Only the service (and `wiki-viewer service run`) reads `config.json`.
|
|
123
|
+
|
|
124
|
+
### Update
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
wiki-viewer update
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Updates the global install to the latest version (npm/pnpm/yarn auto-detected) and restarts the service if one is installed.
|
|
131
|
+
|
|
87
132
|
---
|
|
88
133
|
|
|
89
|
-
##
|
|
134
|
+
## Auth and multi-user mode
|
|
90
135
|
|
|
91
|
-
|
|
136
|
+
wiki-viewer uses [Better Auth](https://better-auth.com) with SQLite. State lives at `~/.wiki-viewer/auth.db` (WAL mode) and `~/.wiki-viewer/auth.secret` (chmod 0600). Both are created on first start. Set `BETTER_AUTH_SECRET` in the environment to override the file-stored secret.
|
|
92
137
|
|
|
93
|
-
|
|
138
|
+
Sign-in providers:
|
|
94
139
|
|
|
95
|
-
- **
|
|
96
|
-
- **
|
|
97
|
-
```bash
|
|
98
|
-
npm install -g pnpm
|
|
99
|
-
```
|
|
140
|
+
- **Google OAuth.** Enabled when both `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET` are set.
|
|
141
|
+
- **Email + password.** Always available. No verification email is sent by default.
|
|
100
142
|
|
|
101
|
-
###
|
|
143
|
+
### Email allowlist
|
|
144
|
+
|
|
145
|
+
By default any email can sign up. Lock it down before exposing the server.
|
|
146
|
+
|
|
147
|
+
There are two ways to set the allowlist. The settings sheet is the easy path; env vars are the fallback for headless or scripted deploys.
|
|
148
|
+
|
|
149
|
+
**From the UI (recommended).** Click the gear icon in the sidebar toolbar to open Signup allowlist. Enter allowed emails and domains, one per line or comma-separated, then save. Changes are stored in `~/.wiki-viewer/config.json` and apply on the next signup with no restart. Clearing both lists reverts to the environment variables below.
|
|
150
|
+
|
|
151
|
+
**From the environment.** Set either or both before starting the server:
|
|
102
152
|
|
|
103
153
|
```bash
|
|
104
|
-
|
|
105
|
-
|
|
154
|
+
# Allow specific accounts
|
|
155
|
+
export AUTH_ALLOWED_EMAILS="alice@team.com,bob@team.com"
|
|
156
|
+
|
|
157
|
+
# Or whole domains (csv)
|
|
158
|
+
export AUTH_ALLOWED_DOMAIN="team.com,partner.org"
|
|
106
159
|
```
|
|
107
160
|
|
|
108
|
-
|
|
161
|
+
**Precedence.** If the UI allowlist in `config.json` is non-empty, it wins and the env vars are ignored. If it is empty, the env vars are used. If neither is set, any email can sign up. When both an email and a domain list apply, either match grants access.
|
|
162
|
+
|
|
163
|
+
### Production guard
|
|
164
|
+
|
|
165
|
+
In production, the server refuses to boot unless `BETTER_AUTH_URL` is set to an `https://` origin. This prevents accidentally serving auth cookies over plain HTTP.
|
|
109
166
|
|
|
110
167
|
```bash
|
|
111
|
-
|
|
168
|
+
export BETTER_AUTH_URL="https://wiki.team.com"
|
|
112
169
|
```
|
|
113
170
|
|
|
114
|
-
|
|
171
|
+
For development or local smoke tests, set `WIKI_ALLOW_INSECURE=1` to bypass the guard.
|
|
172
|
+
|
|
173
|
+
### CSRF and trusted origins
|
|
174
|
+
|
|
175
|
+
All state-changing routes (`POST` / `PUT` / `DELETE` / `PATCH`) under `/api/wiki/*` and `/api/system/*` check the request's `Origin` header against an allowlist. Cross-origin requests with a session cookie are rejected with `403 FORBIDDEN`.
|
|
176
|
+
|
|
177
|
+
By default the allowlist includes `localhost` and `127.0.0.1`. Add hostnames you actually browse from:
|
|
115
178
|
|
|
116
179
|
```bash
|
|
117
|
-
|
|
118
|
-
|
|
180
|
+
export WIKI_OWNER_HOSTS="wiki.team.com,office.lan"
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Do not place wiki-viewer behind a reverse proxy that rewrites `Host`. The Origin check assumes the browser-visible hostname matches what wiki-viewer sees. Bind to loopback and front with a TLS-terminating proxy that preserves the original `Host` (nginx `proxy_set_header Host $host;` or Caddy default).
|
|
184
|
+
|
|
185
|
+
### Rate limits
|
|
186
|
+
|
|
187
|
+
| Endpoint | Default |
|
|
188
|
+
| ----------------- | ------------------------- |
|
|
189
|
+
| `/sign-in/email` | 20 requests / 60 seconds |
|
|
190
|
+
| `/sign-up/email` | 10 requests / 60 seconds |
|
|
191
|
+
| Other auth routes | 100 requests / 60 seconds |
|
|
192
|
+
|
|
193
|
+
Rate limiting is disabled in development (`NODE_ENV !== "production"`).
|
|
119
194
|
|
|
120
|
-
|
|
121
|
-
pnpm dev
|
|
195
|
+
### Recovering a locked-out account
|
|
122
196
|
|
|
123
|
-
|
|
124
|
-
|
|
197
|
+
The rate limiter stores counts in memory. Restart the server to clear it.
|
|
198
|
+
|
|
199
|
+
To delete and re-create a user from scratch:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
sqlite3 ~/.wiki-viewer/auth.db "DELETE FROM user WHERE email='you@team.com';"
|
|
203
|
+
sqlite3 ~/.wiki-viewer/auth.db "DELETE FROM account WHERE userId NOT IN (SELECT id FROM user);"
|
|
204
|
+
sqlite3 ~/.wiki-viewer/auth.db "DELETE FROM session WHERE userId NOT IN (SELECT id FROM user);"
|
|
125
205
|
```
|
|
126
206
|
|
|
127
|
-
|
|
207
|
+
Then sign up again.
|
|
208
|
+
|
|
209
|
+
### Editor save conflicts
|
|
210
|
+
|
|
211
|
+
The Markdown editor now sends a `baseRevision` with every save. If another user (or an agent) modified the file in the meantime, the server returns `409 STALE_REVISION` and the editor silently reloads the new content. Your in-progress edits in that tab are lost. Reload before making large changes if you know someone else is also editing.
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Working with AI agents
|
|
216
|
+
|
|
217
|
+
wiki-viewer exposes an HTTP collaboration protocol so agents (Claude, Cursor, ChatGPT desktop, custom scripts) can read and edit Markdown files. Every AI-authored insert is wrapped in an inline `<proof-span>` mark so the human reviewer can see, accept, or revert each change.
|
|
128
218
|
|
|
129
|
-
The
|
|
219
|
+
The protocol is intentionally API-compatible in spirit with [Proof SDK](https://github.com/EveryInc/proof-sdk).
|
|
130
220
|
|
|
131
|
-
###
|
|
221
|
+
### Trust On First Use registration
|
|
132
222
|
|
|
133
|
-
|
|
134
|
-
| ---------------- | ---------------------------------------- |
|
|
135
|
-
| `pnpm dev` | Start Next.js development server |
|
|
136
|
-
| `pnpm dev:https` | Start dev server with experimental HTTPS |
|
|
137
|
-
| `pnpm build` | Build production bundle |
|
|
138
|
-
| `pnpm start` | Start production server (after build) |
|
|
139
|
-
| `pnpm wiki` | Run the CLI entry point (after build) |
|
|
223
|
+
Each agent gets its own bearer token tied to a stable identity. No shared secret.
|
|
140
224
|
|
|
141
|
-
|
|
225
|
+
1. Agent calls `POST /api/agent/register` with `id`, `displayName`, and requested `scope`.
|
|
226
|
+
2. Server returns `registrationId` and `pollUrl`. The id itself is the pickup secret.
|
|
227
|
+
3. Owner opens the AI Panel, sees the pending request, clicks **Approve**.
|
|
228
|
+
4. Agent polls and receives a one-shot `token`. Pickup deletes the token from the server.
|
|
229
|
+
5. Agent sends `Authorization: Bearer <token>` and `X-Agent-Id: <id>` on every later request.
|
|
142
230
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
231
|
+
The registry lives in `~/.wiki-viewer/agents.json`. Only SHA-256 hashes of tokens are stored.
|
|
232
|
+
|
|
233
|
+
### Distribute the agent skill
|
|
234
|
+
|
|
235
|
+
The running server exposes itself as an installable [Agent Skill](https://github.com/anthropics/skills):
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
# Claude Code, Codex, Cursor, OpenCode
|
|
239
|
+
npx skills add anh-chu/wiki-viewer/agents/wiki-viewer-skill
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
For any chat agent, paste the bootstrap prompt from `<your-server>/agents/install` (also visible in the AI Panel). The agent fetches `/api/agents/install` and learns the full op vocabulary at runtime.
|
|
243
|
+
|
|
244
|
+
### Op vocabulary
|
|
245
|
+
|
|
246
|
+
Block-level edits (revision-checked, idempotent):
|
|
247
|
+
|
|
248
|
+
```json
|
|
249
|
+
{ "type": "block.replace", "ref": "b7f2c1", "markdown": "New content." }
|
|
250
|
+
{ "type": "block.insertAfter", "ref": "b7f2c1", "markdown": "..." }
|
|
251
|
+
{ "type": "block.insertBefore", "ref": "b7f2c1", "markdown": "..." }
|
|
252
|
+
{ "type": "block.delete", "ref": "b7f2c1" }
|
|
253
|
+
{ "type": "block.append", "markdown": "..." }
|
|
254
|
+
{ "type": "block.prepend", "markdown": "..." }
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Comments and suggestions:
|
|
258
|
+
|
|
259
|
+
```json
|
|
260
|
+
{ "type": "comment.add", "ref": "b7f2c1", "text": "Why end of June?" }
|
|
261
|
+
{ "type": "comment.reply", "commentId": "c4a1", "text": "API freeze." }
|
|
262
|
+
{ "type": "comment.resolve", "commentId": "c4a1" }
|
|
263
|
+
{ "type": "suggestion.add", "ref": "b7f2c1", "kind": "replace", "markdown": "...",
|
|
264
|
+
"basis": "described", "basisDetail": "user asked" }
|
|
265
|
+
{ "type": "suggestion.accept", "suggestionId": "s3b2" }
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
See [`docs/agent-collab-plan.md`](docs/agent-collab-plan.md) for the full spec: snapshot shape, event log, suggestion lifecycle, provenance attribute rules, and edge cases.
|
|
269
|
+
|
|
270
|
+
### Key routes
|
|
271
|
+
|
|
272
|
+
Anonymous:
|
|
273
|
+
|
|
274
|
+
| Method | Path | Description |
|
|
275
|
+
| ------ | ----------------------------- | ----------------------------------------------- |
|
|
276
|
+
| `POST` | `/api/agent/register` | Request registration. Returns `registrationId`. |
|
|
277
|
+
| `GET` | `/api/agent/register/<regId>` | Poll status. Returns token once approved. |
|
|
278
|
+
| `GET` | `/api/agents/install` | Discovery JSON for agents. |
|
|
279
|
+
| `GET` | `/api/agents/skill` | Raw SKILL.md. |
|
|
280
|
+
| `GET` | `/api/agents/skill.tar.gz` | Skill as gzip tarball. |
|
|
281
|
+
|
|
282
|
+
Owner-only (session cookie):
|
|
283
|
+
|
|
284
|
+
| Method | Path | Description |
|
|
285
|
+
| ------ | ------------------------------------------------ | --------------------------- |
|
|
286
|
+
| `GET` | `/api/agent/admin/registrations` | List pending registrations. |
|
|
287
|
+
| `POST` | `/api/agent/admin/registrations/<regId>/approve` | Approve, mint token. |
|
|
288
|
+
| `POST` | `/api/agent/admin/registrations/<regId>/deny` | Deny. |
|
|
289
|
+
| `GET` | `/api/agent/admin/agents` | List your approved agents. |
|
|
290
|
+
| `POST` | `/api/agent/admin/agents/<id>/revoke` | Revoke an agent. |
|
|
291
|
+
|
|
292
|
+
Agent routes (bearer + `X-Agent-Id`, scope-checked):
|
|
293
|
+
|
|
294
|
+
| Method | Path | Required scope |
|
|
295
|
+
| ------ | ---------------------------------------- | --------------------- |
|
|
296
|
+
| `GET` | `/api/agent/files/<path.md>` | `read` + path match |
|
|
297
|
+
| `POST` | `/api/agent/files/<path.md>` | `mutate` + path match |
|
|
298
|
+
| `GET` | `/api/agent/events/<path.md>?after=<id>` | `read` + path match |
|
|
299
|
+
| `POST` | `/api/agent/events/<path.md>` | `read` + path match |
|
|
300
|
+
| `GET` | `/api/agent/sidecar/<path.md>` | `read` + path match |
|
|
301
|
+
| `GET` | `/api/agent/settings` | `read` |
|
|
302
|
+
| `GET` | `/api/agent/activity` | `read` |
|
|
303
|
+
|
|
304
|
+
### Full curl trace
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
# 1. Agent registers
|
|
308
|
+
curl -s -X POST https://wiki.team.com/api/agent/register \
|
|
309
|
+
-H "Content-Type: application/json" \
|
|
310
|
+
-d '{"id":"ai:claude","displayName":"Claude",
|
|
311
|
+
"scope":{"paths":["**/*"],"ops":["read","mutate"]}}'
|
|
312
|
+
# -> { "registrationId":"reg_abc","pollUrl":"/api/agent/register/reg_abc","status":"pending" }
|
|
313
|
+
|
|
314
|
+
# 2. Owner approves in the AI Panel.
|
|
315
|
+
|
|
316
|
+
# 3. Agent picks up the token (one shot, 410 on replay)
|
|
317
|
+
TOKEN=$(curl -s https://wiki.team.com/api/agent/register/reg_abc | jq -r .token)
|
|
318
|
+
|
|
319
|
+
# 4. Read a file
|
|
320
|
+
curl -s \
|
|
321
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
322
|
+
-H "X-Agent-Id: ai:claude" \
|
|
323
|
+
https://wiki.team.com/api/agent/files/notes.md | jq
|
|
324
|
+
|
|
325
|
+
# 5. Mutate. `by` must equal `X-Agent-Id`. Idempotency-Key is required.
|
|
326
|
+
curl -s -X POST \
|
|
327
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
328
|
+
-H "X-Agent-Id: ai:claude" \
|
|
329
|
+
-H "Content-Type: application/json" \
|
|
330
|
+
-H "Idempotency-Key: req-$(cat /proc/sys/kernel/random/uuid)" \
|
|
331
|
+
-d '{"baseRevision":7,"by":"ai:claude",
|
|
332
|
+
"ops":[{"type":"block.append","markdown":"From your agent."}]}' \
|
|
333
|
+
https://wiki.team.com/api/agent/files/notes.md
|
|
334
|
+
|
|
335
|
+
# 6. Poll events to see human comments, suggestion accepts, external edits
|
|
336
|
+
curl -s -H "Authorization: Bearer $TOKEN" -H "X-Agent-Id: ai:claude" \
|
|
337
|
+
"https://wiki.team.com/api/agent/events/notes.md?after=0" | jq
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Response codes to handle:
|
|
341
|
+
|
|
342
|
+
- `401 UNAUTHORIZED` — bad token or `X-Agent-Id`.
|
|
343
|
+
- `403 FORBIDDEN` — out of scope or `by` mismatches identity.
|
|
344
|
+
- `409 STALE_REVISION` — refetch and retry. Response includes a fresh snapshot.
|
|
345
|
+
- `409 BLOCK_NOT_FOUND` — the ref no longer exists.
|
|
346
|
+
- `409 IDEMPOTENCY_KEY_REUSED` — same key, different body.
|
|
347
|
+
- `429 RATE_LIMITED` — honor `Retry-After`. Default 60 ops/minute per agent.
|
|
348
|
+
|
|
349
|
+
### Agent rate limit override
|
|
350
|
+
|
|
351
|
+
```bash
|
|
352
|
+
export AGENT_RATE_LIMIT=120
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Note: `AGENT_BEARER_TOKEN` (legacy single-secret mode) does nothing now. The server logs a one-time warning if it is set. Remove it.
|
|
148
356
|
|
|
149
357
|
---
|
|
150
358
|
|
|
151
|
-
##
|
|
359
|
+
## Dev setup
|
|
152
360
|
|
|
153
|
-
|
|
361
|
+
### Prerequisites
|
|
154
362
|
|
|
155
|
-
|
|
363
|
+
- **Node.js** ≥ 18
|
|
364
|
+
- **pnpm** — `npm install -g pnpm`
|
|
365
|
+
|
|
366
|
+
### Run from source
|
|
156
367
|
|
|
157
368
|
```bash
|
|
158
|
-
# 1. Clone & install
|
|
159
369
|
git clone https://github.com/anh-chu/wiki-viewer.git
|
|
160
370
|
cd wiki-viewer
|
|
161
371
|
pnpm install
|
|
372
|
+
ROOT_DIR=~/notes pnpm dev
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
The dev server supports hot reload.
|
|
376
|
+
|
|
377
|
+
### Scripts
|
|
378
|
+
|
|
379
|
+
| Command | Description |
|
|
380
|
+
| ---------------- | -------------------------------------- |
|
|
381
|
+
| `pnpm dev` | Next.js development server |
|
|
382
|
+
| `pnpm dev:https` | Dev server with experimental HTTPS |
|
|
383
|
+
| `pnpm build` | Production build |
|
|
384
|
+
| `pnpm start` | Production server (after `build`) |
|
|
385
|
+
| `pnpm wiki` | CLI entry point (after `build`) |
|
|
386
|
+
| `pnpm test` | Run the proof + auth test suite (180+) |
|
|
387
|
+
|
|
388
|
+
### All environment variables
|
|
389
|
+
|
|
390
|
+
| Variable | Description | Default |
|
|
391
|
+
| ---------------------- | --------------------------------------------------------------------------------- | --------------------- |
|
|
392
|
+
| `ROOT_DIR` | Directory to serve | `~/wiki-viewer-files` |
|
|
393
|
+
| `PORT` | Port to listen on | `3000` |
|
|
394
|
+
| `HOSTNAME` | Host / interface to bind | `localhost` |
|
|
395
|
+
| `BETTER_AUTH_URL` | Public origin (required in production, must be `https://`) | unset |
|
|
396
|
+
| `BETTER_AUTH_SECRET` | Override for the auto-generated session signing secret | file-stored |
|
|
397
|
+
| `GOOGLE_CLIENT_ID` | Enable Google OAuth button | unset |
|
|
398
|
+
| `GOOGLE_CLIENT_SECRET` | Enable Google OAuth button | unset |
|
|
399
|
+
| `AUTH_ALLOWED_EMAILS` | csv: only these emails can sign up (overridden by UI allowlist if set) | unset (open) |
|
|
400
|
+
| `AUTH_ALLOWED_DOMAIN` | csv: only emails on these domains can sign up (overridden by UI allowlist if set) | unset (open) |
|
|
401
|
+
| `WIKI_OWNER_HOSTS` | csv: extra hostnames trusted for CSRF Origin check | `localhost,127.0.0.1` |
|
|
402
|
+
| `WIKI_ALLOW_INSECURE` | Set to `1` to bypass the prod-https guard (dev / CI only) | unset |
|
|
403
|
+
| `AGENT_RATE_LIMIT` | Max mutation ops per minute per agent identity | `60` |
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
## Self-hosted deployment
|
|
162
408
|
|
|
163
|
-
|
|
409
|
+
### Option A — Build and run directly
|
|
410
|
+
|
|
411
|
+
```bash
|
|
412
|
+
git clone https://github.com/anh-chu/wiki-viewer.git
|
|
413
|
+
cd wiki-viewer
|
|
414
|
+
pnpm install
|
|
164
415
|
pnpm build
|
|
165
416
|
|
|
166
|
-
#
|
|
417
|
+
# Static assets into the standalone output
|
|
167
418
|
cp -r .next/static .next/standalone/.next/static
|
|
168
419
|
cp -r public .next/standalone/public
|
|
169
420
|
|
|
170
|
-
#
|
|
171
|
-
ROOT_DIR=/
|
|
421
|
+
# Start
|
|
422
|
+
ROOT_DIR=/srv/notes BETTER_AUTH_URL=https://wiki.team.com \
|
|
423
|
+
AUTH_ALLOWED_DOMAIN=team.com \
|
|
424
|
+
node .next/standalone/server.js
|
|
172
425
|
```
|
|
173
426
|
|
|
174
|
-
Or use the CLI wrapper
|
|
427
|
+
Or use the CLI wrapper, which handles the static-asset copy:
|
|
175
428
|
|
|
176
429
|
```bash
|
|
177
|
-
node bin/wiki-viewer.js /
|
|
430
|
+
node bin/wiki-viewer.js /srv/notes
|
|
178
431
|
```
|
|
179
432
|
|
|
180
|
-
### Option B —
|
|
433
|
+
### Option B — PM2
|
|
181
434
|
|
|
182
435
|
```bash
|
|
183
436
|
npm install -g pm2
|
|
184
437
|
|
|
185
|
-
# Start and name the process
|
|
186
438
|
pm2 start bin/wiki-viewer.js \
|
|
187
439
|
--name wiki-viewer \
|
|
188
|
-
--
|
|
189
|
-
-- /path/to/your/files --port 3000
|
|
440
|
+
-- /srv/notes --port 3000
|
|
190
441
|
|
|
191
|
-
# Save so it auto-starts on reboot
|
|
192
442
|
pm2 save
|
|
193
|
-
pm2 startup
|
|
443
|
+
pm2 startup # follow printed instructions
|
|
194
444
|
```
|
|
195
445
|
|
|
196
|
-
### Option C — systemd
|
|
446
|
+
### Option C — systemd
|
|
197
447
|
|
|
198
|
-
|
|
448
|
+
`/etc/systemd/system/wiki-viewer.service`:
|
|
199
449
|
|
|
200
450
|
```ini
|
|
201
451
|
[Unit]
|
|
@@ -206,44 +456,44 @@ After=network.target
|
|
|
206
456
|
Type=simple
|
|
207
457
|
User=YOUR_USER
|
|
208
458
|
WorkingDirectory=/home/YOUR_USER/wiki-viewer
|
|
209
|
-
ExecStart=/usr/bin/node bin/wiki-viewer.js /
|
|
459
|
+
ExecStart=/usr/bin/node bin/wiki-viewer.js /srv/notes --port 3000 --host 0.0.0.0
|
|
210
460
|
Restart=on-failure
|
|
211
461
|
Environment=NODE_ENV=production
|
|
462
|
+
Environment=BETTER_AUTH_URL=https://wiki.team.com
|
|
463
|
+
Environment=AUTH_ALLOWED_DOMAIN=team.com
|
|
464
|
+
Environment=WIKI_OWNER_HOSTS=wiki.team.com
|
|
212
465
|
|
|
213
466
|
[Install]
|
|
214
467
|
WantedBy=multi-user.target
|
|
215
468
|
```
|
|
216
469
|
|
|
217
|
-
Then enable and start it:
|
|
218
|
-
|
|
219
470
|
```bash
|
|
220
471
|
sudo systemctl daemon-reload
|
|
221
472
|
sudo systemctl enable wiki-viewer
|
|
222
473
|
sudo systemctl start wiki-viewer
|
|
223
|
-
sudo
|
|
474
|
+
sudo journalctl -u wiki-viewer -f
|
|
224
475
|
```
|
|
225
476
|
|
|
226
|
-
### HTTPS
|
|
227
|
-
|
|
228
|
-
> ⚠️ **HTTPS is required when wiki-viewer is not on `localhost`.** Browsers restrict several APIs (service workers, PDF.js, and other [secure-context](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts) features) to HTTPS-only origins. Accessing wiki-viewer over plain HTTP on a remote host will silently break parts of the UI.
|
|
229
|
-
|
|
230
|
-
**How it works under the hood:** `--https` does not make the Next.js server itself speak TLS. Instead it:
|
|
477
|
+
### HTTPS
|
|
231
478
|
|
|
232
|
-
|
|
233
|
-
2. Starts an HTTPS reverse proxy on the user-facing port that forwards all traffic to the internal server
|
|
479
|
+
`--https` runs an HTTPS reverse proxy in front of the internal HTTP server. mkcert is used when available, otherwise OpenSSL self-signed.
|
|
234
480
|
|
|
235
|
-
|
|
481
|
+
For real deployments, run wiki-viewer on plain HTTP behind nginx or Caddy with a Let's Encrypt cert. Configure the proxy to:
|
|
236
482
|
|
|
237
|
-
|
|
483
|
+
- Terminate TLS.
|
|
484
|
+
- Preserve the original `Host` header (`proxy_set_header Host $host;` in nginx; Caddy does this by default).
|
|
485
|
+
- Forward all paths.
|
|
238
486
|
|
|
239
|
-
|
|
240
|
-
- Otherwise → OpenSSL self-signed cert (browser warns once — click through)
|
|
241
|
-
|
|
242
|
-
```bash
|
|
243
|
-
node bin/wiki-viewer.js /path/to/your/files --https --port 443 --host 0.0.0.0
|
|
244
|
-
```
|
|
487
|
+
### Production deployment checklist
|
|
245
488
|
|
|
246
|
-
|
|
489
|
+
- [ ] `BETTER_AUTH_URL=https://your-domain` exported in the service environment.
|
|
490
|
+
- [ ] `AUTH_ALLOWED_DOMAIN` or `AUTH_ALLOWED_EMAILS` set before opening the server to anyone.
|
|
491
|
+
- [ ] `WIKI_OWNER_HOSTS` includes every hostname your users browse from.
|
|
492
|
+
- [ ] TLS handled by your reverse proxy or `--https`. Plain HTTP rejects in prod.
|
|
493
|
+
- [ ] `~/.wiki-viewer/` on local disk only. SQLite WAL is not safe on NFS or shared between replicas.
|
|
494
|
+
- [ ] Single host. If you cluster, you also need a shared lock service. Out of scope today.
|
|
495
|
+
- [ ] OAuth redirect URI registered with Google: `https://your-domain/api/auth/callback/google`.
|
|
496
|
+
- [ ] If you ran an older version: legacy agents in `agents.json` without `ownerUserId` are visible to and revocable by any signed-in user. Either edit the file to add `"ownerUserId": "<your user id>"` to each, or revoke and re-register them.
|
|
247
497
|
|
|
248
498
|
---
|
|
249
499
|
|
|
@@ -251,16 +501,32 @@ node bin/wiki-viewer.js /path/to/your/files --https --port 443 --host 0.0.0.0
|
|
|
251
501
|
|
|
252
502
|
```
|
|
253
503
|
wiki-viewer/
|
|
504
|
+
├── agents/ Installable Agent Skill + bootstrap prompt
|
|
505
|
+
│ ├── wiki-viewer-skill/ SKILL.md and assets
|
|
506
|
+
│ └── bootstrap-prompt.md One-paragraph prompt for any chat agent
|
|
254
507
|
├── bin/
|
|
255
|
-
│ └── wiki-viewer.js
|
|
508
|
+
│ └── wiki-viewer.js CLI entry point
|
|
509
|
+
├── docs/
|
|
510
|
+
│ ├── agent-collab-plan.md Full v1 spec for the agent HTTP protocol
|
|
511
|
+
│ └── agent-collab-v2-plan.md Reference for a future Yjs / multi-tenant pivot
|
|
256
512
|
├── src/
|
|
257
|
-
│ ├── app/
|
|
258
|
-
│ ├──
|
|
259
|
-
│ ├──
|
|
260
|
-
│ ├──
|
|
261
|
-
│
|
|
513
|
+
│ ├── app/
|
|
514
|
+
│ │ ├── api/agent/ Agent HTTP API
|
|
515
|
+
│ │ ├── api/agents/ Public install endpoints
|
|
516
|
+
│ │ ├── api/auth/ Better Auth handler
|
|
517
|
+
│ │ ├── api/wiki/ File browser API (session-gated)
|
|
518
|
+
│ │ ├── api/system/ System config API (session-gated)
|
|
519
|
+
│ │ └── signin/ Sign-in page
|
|
520
|
+
│ ├── components/
|
|
521
|
+
│ │ ├── editor/ TipTap editor + proof-span + comment-pip + suggestion-card
|
|
522
|
+
│ │ └── ai-panel/ Right-side AI panel (agents, activity, install)
|
|
523
|
+
│ ├── lib/
|
|
524
|
+
│ │ ├── auth/ Better Auth server + client + allowlist + CSRF
|
|
525
|
+
│ │ └── proof/ Agent protocol core (ops-applier, registry, file-lock)
|
|
526
|
+
│ ├── stores/ Zustand state
|
|
527
|
+
│ ├── tests/proof/ Node test runner suite (180+ tests)
|
|
528
|
+
│ └── middleware.ts Cookie-presence gate for UI routes
|
|
262
529
|
├── public/
|
|
263
|
-
│ └── logo.svg
|
|
264
530
|
├── next.config.ts
|
|
265
531
|
└── package.json
|
|
266
532
|
```
|
|
@@ -269,10 +535,10 @@ wiki-viewer/
|
|
|
269
535
|
|
|
270
536
|
## Contributing
|
|
271
537
|
|
|
272
|
-
1. Fork
|
|
273
|
-
2.
|
|
274
|
-
3.
|
|
275
|
-
4. Open a
|
|
538
|
+
1. Fork and branch: `git checkout -b my-feature`
|
|
539
|
+
2. `pnpm install && pnpm dev`
|
|
540
|
+
3. Run tests: `pnpm test`
|
|
541
|
+
4. Open a PR.
|
|
276
542
|
|
|
277
543
|
Bug reports and feature requests welcome via [GitHub Issues](https://github.com/anh-chu/wiki-viewer/issues).
|
|
278
544
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
You are connecting to a running wiki-viewer instance at $WIKI_URL (e.g. `http://localhost:3000`). Fetch `$WIKI_URL/api/agents/install`and follow the instructions there to register, wait for human approval, then read and edit markdown files via its HTTP API. Set`basis`and`basisDetail`on every content op so the human can see where your changes came from. Prefer`suggestion.add` over direct block ops unless told otherwise.
|