@catheadowl/ukp 0.2.6 → 0.3.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
@@ -12,6 +12,10 @@ memorize, no provider-specific commands to relearn.
12
12
  > [!NOTE]
13
13
  > Early-stage CLI (MVP) — commands and behavior may still change.
14
14
 
15
+ ```bash
16
+ npm install -g @catheadowl/ukp # or: bun add -g @catheadowl/ukp
17
+ ```
18
+
15
19
  ```bash
16
20
  $ ukp init service --name notes && ukp register
17
21
  initialized Service: notes
@@ -27,11 +31,15 @@ $ ukp read ukp://notes/2026/q3-plan.md # read straight from the reference
27
31
  # Q3 Plan
28
32
  Goals for Q3: ship the knowledge plane.
29
33
 
30
- $ echo '[capabilities.propose]' >> .ukp/service.toml # the write face is opt-in: declare propose
34
+ $ echo '[capabilities.propose]' >> .ukp/service.toml # the write path is opt-in: declare propose
35
+ $ echo '# typo fix' > typo-fix.md # a proposal is any Markdown draft
31
36
  $ ukp propose --endpoint notes --id typo-fix --file typo-fix.md
32
37
  proposal typo-fix created (revision 1)
33
38
  ```
34
39
 
40
+ A `ukp://` reference is not a web link — it names a registered endpoint
41
+ (local or remote); open one with `ukp read <uri>`.
42
+
35
43
  ## Why UKP
36
44
 
37
45
  Knowledge work starts in folders, but repeated use needs stable names,
@@ -50,8 +58,9 @@ predictable scope, and a single command surface. Use UKP when:
50
58
 
51
59
  - Register local folders as named knowledge endpoints — a registered folder
52
60
  is a *Service*, addressed by its endpoint name.
53
- - `ukp inspect` shows which endpoints the current scope selects — see what a
54
- command will touch before running it.
61
+ - `ukp inspect` shows which endpoints the current scope selects (the
62
+ nearest `.ukp/client.toml`; every registered endpoint when there is
63
+ none) — see what a command will touch before running it.
55
64
  - Navigate the Markdown structure of an endpoint — folders, descriptions,
56
65
  depth — with zero provider dependency.
57
66
  - Read endpoint files through the built-in `read/file` capability — if a
@@ -78,7 +87,8 @@ predictable scope, and a single command surface. Use UKP when:
78
87
  `[capabilities]` table still registers one (derived `read`/`nav` only).
79
88
  - Give agents JSON output (`--json`; `ukp read` uses `--format json`),
80
89
  reference sidecars, docid handoff keys, and durable `ukp://` references
81
- when they need machine-readable results.
90
+ when they need machine-readable results; every `ukp://` reference opens
91
+ with `ukp read <uri>`.
82
92
 
83
93
  UKP owns endpoint names, Registry bindings, scope, and output shape; the
84
94
  provider owns collection setup, indexes, ranking, and maintenance. UKP
@@ -126,14 +136,17 @@ endpoint without it; `propose` works wherever it's declared.
126
136
 
127
137
  An agent can carry out the same flow on your behalf.
128
138
 
129
- For workspace defaults, use `ukp guide client` and `.ukp/client.toml`.
139
+ For workspace defaults, run `ukp use <endpoint>` (see `ukp guide client`) —
140
+ it writes `.ukp/client.toml` and keeps it committable in one step.
130
141
 
131
142
  ## Commands
132
143
 
133
- Grouping below follows `ukp --help`; every command stays a flat
134
- `ukp <verb>`. `--endpoint <name>` is the canonical endpoint selector
135
- (`ukp unregister <name>` still takes the endpoint as a positional legacy
136
- form); `-g` selects the full local Host Registry where supported.
144
+ Grouping below follows `ukp --help`; primary capability commands stay a flat
145
+ `ukp <verb>`, while multi-verb capability families appear as object command
146
+ groups (`ukp init service`, `ukp guide <topic>`). `--endpoint <name>`
147
+ is the canonical endpoint selector (`ukp unregister <name>` still takes the
148
+ endpoint as a positional legacy form); `-g` selects the full local Host
149
+ Registry where supported.
137
150
 
138
151
  The same five commands — search, read, nav, rg, propose — work on local and
139
152
  remote endpoints; consuming a remote endpoint is a one-command gesture
@@ -143,7 +156,7 @@ Endpoint commands:
143
156
 
144
157
  | Command | What it does |
145
158
  |---|---|
146
- | `ukp search` | Indexed search through the endpoint's provider (QMD today); `--recursive` expands the manifest's declared `dependencies`. Results hand off via docid session keys and verified `ukp://` references. |
159
+ | `ukp search` | Indexed search through the endpoint's provider (QMD today); `--recursive` expands the manifest's declared `dependencies`. Results hand off a docid handoff key and verified `ukp://` references. |
147
160
  | `ukp read` | Reads an endpoint-scoped resource — exact path, `ukp://` URI, or a `docid` handed off by search results. |
148
161
  | `ukp nav` | Markdown outline of an endpoint (`--depth`, respects `.gitignore`); on by default, configurable via `[capabilities.nav]`. |
149
162
  | `ukp rg` | Lexical grep (ripgrep) across endpoint files — provider-free, on by default; `--files` enumerates them instead of searching. Results become `read`-ready `ukp://` references. A missing rg binary skips the endpoint with a warning. |
@@ -153,9 +166,14 @@ Registry commands:
153
166
 
154
167
  | Command | What it does |
155
168
  |---|---|
156
- | `ukp init service` | Creates a minimal `.ukp/service.toml`. |
157
- | `ukp register` / `ukp unregister --endpoint <name>` | Manages Host Registry bindings — local folders and remote endpoints alike (`ukp register --url`, see Remote in 60 seconds). `--name <handle>` disambiguates collisions: `notes` vs `ali-notes`. |
158
- | `ukp list` | Lists registered endpoints with their declared capabilities. New endpoints on a host door show as a stderr note (`door <origin>: N unimported endpoint(s) …`) — importing stays an explicit gesture. |
169
+ | `ukp init service` | Creates a minimal `.ukp/service.toml`. The `.ukp/.gitignore` it drops ignores machine-local state only (the instance identity; the serve TLS identity lives in `~/.ukp/tls/`) — `service.toml` and `client.toml` are pure declarations and committable by design (a fresh clone re-registers in one `ukp register`). |
170
+ | `ukp use <endpoint> [endpoint...]` | One-step consumer gesture: sets this workspace's `default_endpoints` (`.ukp/client.toml`, explicit replace, idempotent — every name must be registered) and keeps the config version-visible in the same step. `ukp inspect` confirms the active scope. |
171
+ | `ukp register` / `ukp unregister --endpoint <name>` | Manages Host Registry bindings — local folders and remote endpoints alike (`ukp register --url`, see Remote in 60 seconds). `--name <handle>` disambiguates collisions: `notes` vs `ali-notes`. A folder that moved re-binds in one step: `ukp register --rebind` from the new location (local bindings). |
172
+ | `ukp list` | Lists endpoint bindings and capabilities under the **workspace scope** by default (nearest `.ukp/client.toml`; every registered endpoint when there is none); `-g` lists the full Host Registry without reading the client config. `--json` emits the offline machine snapshot (`ukp.list.v1`) riding the same scope — stable field names, the same data core as the text listing, zero network (remote bindings are registry facts only, so their capability fields are `null`); pin `-g` for the full snapshot. New endpoints on a host door show as a stderr note (`door <origin>: N unimported endpoint(s) …`) — importing stays an explicit gesture. |
173
+
174
+ A legacy `.ukp/.gitignore` (the retired `*` self-ignore template) migrates
175
+ to this posture in passing whenever `ukp register` (local folders) or
176
+ `ukp use` meets one.
159
177
 
160
178
  Operations commands:
161
179
 
@@ -181,9 +199,11 @@ Help commands:
181
199
  ## Remote in 60 seconds
182
200
 
183
201
  `ukp serve` exposes an endpoint over HTTP. Authentication is deny-by-default:
184
- serving with a `--host` beyond loopback requires `UKP_SERVE_TOKEN` (tokenless
185
- serving needs an explicit `--allow-anonymous` and is refused off loopback).
186
- The two fastest paths — each block notes where its commands run:
202
+ serving with a `--host` beyond loopback requires a credential — the
203
+ `UKP_SERVE_TOKEN` env token (full power) or a labeled key issued into
204
+ the `~/.ukp/tokens` file (tokenless serving needs an explicit
205
+ `--allow-anonymous` and is refused off loopback). The two fastest
206
+ paths — each block notes where its commands run:
187
207
 
188
208
  ```bash
189
209
  # From the consumer machine — SSH between two personal machines; the door is
@@ -199,6 +219,21 @@ UKP_SERVE_TOKEN=<token> ukp serve --endpoint <name> --host 0.0.0.0 --port 8570 -
199
219
  ukp register --url https://<ip>:8570 --endpoint <name> --token <token>
200
220
  ```
201
221
 
222
+ Handing a second machine or an agent a narrower key? Issue labeled, scoped,
223
+ revocable keys instead of sharing the env token (ON THE HOST):
224
+
225
+ ```bash
226
+ ukp serve token add liku "notes:ro,cad:rw" # prints the raw key ONCE
227
+ ukp serve token list # labels, key ids, scopes
228
+ ukp serve token revoke liku # next request is a 401
229
+ ```
230
+
231
+ Scopes are `name:ro|rw` comma-separated (full power is the explicit `*:rw`);
232
+ the file stores hashes only, and the door re-reads it on every request —
233
+ deleting a line revokes without a restart. A scoped key sees only its own
234
+ endpoints: out-of-scope names answer exactly like nonexistent ones. While
235
+ `UKP_SERVE_TOKEN` is set it takes precedence and the file is not consulted.
236
+
202
237
  NAT/EIP cloud host (public IP on no NIC)? Name it with
203
238
  `ukp serve --tls --tls-san <public-ip>` — the persisted certificate re-signs
204
239
  over the same key, so the pin (and every registration) survives; details in
@@ -219,6 +254,36 @@ registry), Caddy and Tailscale fronting, the certificate pinning lifecycle,
219
254
  and the hardening posture — lives in the
220
255
  [deployment guide](https://github.com/CatheadOwl/ukp/blob/main/docs/remote-deployment.md).
221
256
 
257
+ ## Security
258
+
259
+ UKP is local-first: nothing listens on the network until you run
260
+ `ukp serve`. When you do, the surface is deny-by-default — serving beyond
261
+ loopback without a credential is refused, and anonymous serving is an
262
+ explicit flag that only works on loopback. Credentials come in two forms:
263
+ the `UKP_SERVE_TOKEN` env token (full power, takes precedence while set)
264
+ and labeled keys in the 0600 `~/.ukp/tokens` file (hash-only storage,
265
+ required per-key scopes, revocation by deleting the line — effective on
266
+ the next request). Transport is `https://`, pinned
267
+ automatically at registration (a certificate that renews on the same key
268
+ re-pins silently; a different key hard-blocks with both fingerprints), or
269
+ `ssh://`, where SSH carries both encryption and authentication. A
270
+ `--select` door neither routes, declares, nor lists unselected endpoints —
271
+ excluded and unknown names return byte-identical 404s, and a scoped key's
272
+ out-of-scope endpoints answer the same way.
273
+
274
+ Accepted tradeoffs, disclosed rather than hidden: tokens are long-lived
275
+ static bearer secrets stored client-side in the 0600 registry file or an
276
+ environment variable (the same tradeoff as `~/.aws/credentials`); the
277
+ Windows door generator (`ukp serve --print-task`) embeds the token in a
278
+ 0600 `start-door.cmd` it never prints; identity pinning is
279
+ trust-on-first-use (an SSH-style first-connect window). Hardening
280
+ guidance — token strength, reverse proxies and their same-machine
281
+ blind spot, firewalls — is in the
282
+ [deployment guide](https://github.com/CatheadOwl/ukp/blob/main/docs/remote-deployment.md).
283
+
284
+ Found something? Report it privately — see [SECURITY.md](SECURITY.md);
285
+ please don't use public issues for security reports.
286
+
222
287
  ## Not Yet
223
288
 
224
289
  - remote operation of `update`, and a formally specified network protocol
@@ -231,6 +296,8 @@ and the hardening posture — lives in the
231
296
  ## Documentation
232
297
 
233
298
  - [Remote deployment](https://github.com/CatheadOwl/ukp/blob/main/docs/remote-deployment.md) — serving endpoints across machines: the full guide.
299
+ Also ships inside the npm package (`docs/remote-deployment.md` in the
300
+ installed package); the other docs live in the GitHub repository.
234
301
  - [Contributing](https://github.com/CatheadOwl/ukp/blob/main/CONTRIBUTING.md) — development setup and release packaging.
235
302
  - [Changelog](https://github.com/CatheadOwl/ukp/blob/main/CHANGELOG.md) — what changed per release.
236
303
  - Repository: https://github.com/CatheadOwl/ukp ·
package/SECURITY.md ADDED
@@ -0,0 +1,69 @@
1
+ # Security Policy
2
+
3
+ ## Reporting a vulnerability
4
+
5
+ Report privately using GitHub security advisories:
6
+
7
+ https://github.com/CatheadOwl/ukp/security/advisories/new
8
+
9
+ Please do not open public issues for security reports. We follow
10
+ coordinated vulnerability disclosure (the CERT process, with the 90-day
11
+ convention as the default clock) and credit reporters unless they prefer
12
+ to stay anonymous. Good-faith research on your own deployments is welcome.
13
+
14
+ ## Supported versions
15
+
16
+ Only the latest published release line receives security fixes.
17
+
18
+ ## Scope
19
+
20
+ In scope:
21
+
22
+ - the `ukp` CLI runtime: local capability commands, `ukp serve`
23
+ (transport, authentication, TLS identity, door routing), the generated
24
+ door artifacts (`ukp serve --print-task`), and credential handling on
25
+ consumer machines;
26
+ - the published package supply chain (npm tarball, GitHub repository).
27
+
28
+ Out of scope:
29
+
30
+ - hardening of your own host, SSH daemon, or reverse proxy — deployment
31
+ guidance exists, but operator-side misconfiguration is not a UKP
32
+ vulnerability;
33
+ - private working materials that are not part of the published package.
34
+
35
+ ## Posture summary
36
+
37
+ - Local-first: no network listener exists until you run `ukp serve`.
38
+ - Deny-by-default serving: serving beyond loopback without
39
+ `UKP_SERVE_TOKEN` is refused; anonymous serving is an explicit flag and
40
+ loopback-only.
41
+ - Transport: `https://` with registration-time pinning (self-signed
42
+ certificates are pinned by SPKI; a renewal on the same key re-pins
43
+ transparently, a different key hard-blocks) or `ssh://`, where SSH
44
+ carries both encryption and authentication.
45
+ - Door scoping: a `--select` door neither routes, declares, nor lists
46
+ unselected endpoints; excluded and unknown names return byte-identical
47
+ 404s.
48
+
49
+ Deployment hardening (token strength, reverse proxies, firewalls,
50
+ systemd) is covered in the
51
+ [deployment guide](https://github.com/CatheadOwl/ukp/blob/main/docs/remote-deployment.md).
52
+
53
+ ## Known, accepted tradeoffs
54
+
55
+ Disclosed rather than hidden; each has a documented trigger for change:
56
+
57
+ - Tokens are long-lived static bearer secrets. OAuth flows are deferred
58
+ until a multi-tenant or hosted scenario exists.
59
+ - Read and write use the same token today; separation becomes mandatory
60
+ with the first remote content-write capability.
61
+ - Client-side tokens live in the 0600 registry file or an environment
62
+ variable, in plaintext — the same tradeoff as `~/.aws/credentials`.
63
+ - The Windows door artifact embeds the token in a 0600 `start-door.cmd`
64
+ and never prints it; a file that ever left the machine burns the token.
65
+ - Identity pinning is trust-on-first-use, with the SSH-style
66
+ first-connect window that implies.
67
+ - npm provenance attestations prove where and how a package was built,
68
+ not that the code is safe — verify with `npm audit signatures` and
69
+ treat provenance as one signal among several.
package/bin/ukp.js CHANGED
@@ -56,28 +56,52 @@ function bunCandidates() {
56
56
  return candidates;
57
57
  }
58
58
 
59
- function fail(detail) {
59
+ function fail(detail, hint = "") {
60
60
  process.stderr.write(
61
61
  "ukp: no bun executable found (" + detail + ").\n"
62
62
  + "ukp runs on bun — install it (https://bun.sh), or point UKP_BUN at the\n"
63
63
  + "bun executable. Standard install locations (~/.bun/bin and the npm\n"
64
- + "global prefix) are checked before PATH.\n",
64
+ + "global prefix) are checked before PATH.\n"
65
+ + hint,
65
66
  );
66
67
  process.exit(1);
67
68
  }
68
69
 
70
+ /** Windows-only diagnosis for a UKP_BUN that the user's shell accepts but
71
+ * existsSync rejects: name the shape mismatch instead of implying the file
72
+ * is absent. Two real shapes (0.3.0 release review): Git Bash converts an
73
+ * exported MSYS path (/c/.../bun) to a native form WITHOUT the .exe
74
+ * extension before this launcher sees it, so the .exe sibling exists while
75
+ * the named path does not; and a variable set outside a converting shell
76
+ * (cmd/PowerShell) reaches us as the raw /c/... or /cygdrive/... form,
77
+ * which Windows file APIs cannot resolve at all. */
78
+ function ukpBunHint() {
79
+ const value = process.env.UKP_BUN;
80
+ if (!isWindows || typeof value !== "string") return "";
81
+ if (/^\/(?:[a-z]|cygdrive\/[a-z])\//i.test(value)) {
82
+ return "ukp: UKP_BUN looks like an MSYS-style path; Windows needs a native "
83
+ + "form like C:/path/to/bun.exe\n";
84
+ }
85
+ if (!/\.exe$/i.test(value) && existsSync(value + ".exe")) {
86
+ return "ukp: UKP_BUN omits the .exe extension (the executable sits next to "
87
+ + "it); use its full name, e.g. C:/path/to/bun.exe\n";
88
+ }
89
+ return "";
90
+ }
91
+
69
92
  const bunPath = bunCandidates().find((candidate) => existsSync(candidate));
70
93
  if (bunPath === undefined) {
71
- fail("looked at UKP_BUN, the standard install locations, and PATH");
94
+ fail("looked at UKP_BUN, the standard install locations, and PATH", ukpBunHint());
72
95
  }
73
96
 
74
97
  // In-process handoff when this launcher already runs under bun (bun's own
75
98
  // bin links and `bunx`): importing the CLI keeps it in THIS process, where
76
- // stdout/stderr keep their real TTY identity (columns, isTTY) — a spawnSync
99
+ // stdout/stderr keep their real TTY identity (isTTY) — a spawnSync
77
100
  // grandchild re-inherits duplicated handles, and on some hosts that layer
78
- // degraded TTY detection (the third dogfood round: progress/wrap silently
79
- // skipped while a direct run on the same console had both). One process
80
- // also starts faster. The node-interpreted path (npm shims) keeps spawning.
101
+ // degraded TTY detection (the third dogfood round: progress frames
102
+ // silently skipped while a direct run on the same console had them). One
103
+ // process also starts faster. The node-interpreted path (npm shims) keeps
104
+ // spawning.
81
105
  if (runningUnderBun) {
82
106
  const { runCli } = await import(pathToFileURL(cli).href);
83
107
  const exit = runCli(process.argv.slice(2));
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: Operational recipes for serving UKP endpoints remotely — ssh wake, native TLS, Windows resident door, socket activation, fronting proxies, scoped keys, and hardening posture
3
+ ---
4
+
1
5
  # Remote deployment
2
6
 
3
7
  Operational guide for exposing UKP endpoints over the network. For the
@@ -28,6 +32,17 @@ the same host forwards from the public side to the loopback bind, so proxied
28
32
  deployments treat the token as mandatory (serve cannot see past its own bind
29
33
  address).
30
34
 
35
+ The complete route list (ukp-remote v1) — what a client or a fronting proxy's
36
+ path allowlist must account for: `GET /.well-known/ukp.json` (the public
37
+ discovery document — the door's roster document in host door mode, where each
38
+ endpoint also serves its own at `/e/<name>/.well-known/ukp.json`), the read
39
+ face — `POST /v1/search`, `GET /v1/read`, `GET /v1/nav`, `GET /v1/rg` (each
40
+ prefixed `/e/<name>` at a door) — and the one write route, `PUT
41
+ /v1/propose/<id>` (`PUT /e/<name>/v1/propose/<id>` at a door): the proposal
42
+ upsert. Propose needs the endpoint to declare the capability, and a scoped
43
+ key must carry that endpoint at `rw` (`ro` keys reach the read face only —
44
+ see Scoped keys below).
45
+
31
46
  ## Via SSH (two personal machines — zero extra components, zero ceremony)
32
47
 
33
48
  The `ssh://` URL scheme makes the transport transparent AND wakes the door
@@ -80,9 +95,12 @@ supported (its `-c` quoting drops the wake form).
80
95
 
81
96
  ## Native TLS (bare IP, no domain — zero extra components)
82
97
 
83
- `--tls` self-signs on first start (identity = keypair, persisted under the
84
- Service folder's `.ukp/tls/`; SAN covers the host's addresses). Clients pin
85
- the certificate automatically at registration — same command as any other
98
+ `--tls` self-signs on first start (identity = keypair, persisted in the
99
+ machine home beside the host registry — `~/.ukp/tls/<endpoint-name>/` for a
100
+ single endpoint, `~/.ukp/tls/` for a host door; SAN covers the host's
101
+ addresses, so the identity never travels with the knowledge folder and a
102
+ re-cloned endpoint on the same host keeps its pin). Clients pin the
103
+ certificate automatically at registration — same command as any other
86
104
  remote, no flags added:
87
105
 
88
106
  ```bash
@@ -115,6 +133,57 @@ only grows: the re-sign keeps everything the certificate already carried
115
133
  narrower requests reuse the certificate untouched. Explicit `--tls-cert` certificates carry their own SAN, so
116
134
  `--tls-san` next to them is a usage error, not a no-op.
117
135
 
136
+ ## Scoped keys (second machines, agents — labeled, revocable)
137
+
138
+ `UKP_SERVE_TOKEN` is the full-power shortcut: any listed token reaches every
139
+ endpoint and the write face. When you hand access to a second machine or an
140
+ agent, issue a **labeled, scoped key** instead — the issuance face is a serve
141
+ subcommand, and the credential store is a plain file you can audit:
142
+
143
+ ```bash
144
+ # ON THE HOST (run without UKP_SERVE_TOKEN set — while the env token is
145
+ # present it takes precedence and the file is not consulted at all):
146
+ ukp serve token add liku "notes:ro,cad:rw"
147
+ # issued key for 'liku' (scopes: notes:ro,cad:rw)
148
+ # ukp_liku_3f9c...TQ <- the raw key, shown ONCE, never stored
149
+ # stored in ~/.ukp/tokens (0600, hash-only)...
150
+
151
+ # serve the door with NO env token — the key file arms the gate:
152
+ ukp serve --host 0.0.0.0 --tls
153
+
154
+ # consumer machine registers with the raw key as the token:
155
+ ukp register --url https://<ip>:8570 --token ukp_liku_...
156
+ ```
157
+
158
+ How the pieces behave:
159
+
160
+ - **Scopes** are `name:ro|rw`, comma-separated (Docker-registry style); full
161
+ power is the explicit `*:rw` — a key with no scopes is a usage error, not a
162
+ wildcard. `rw` adds the propose route; `ro` keys get read/search/nav/rg
163
+ only. An endpoint outside the key's scope answers exactly like a name that
164
+ does not exist (same 404, same roster) — the key cannot even learn what it
165
+ cannot see.
166
+ - **The file** is `~/.ukp/tokens`, one line per key (`label key-id sha256$
167
+ hash scopes`), 0600, hash-only — a leaked file is not a leaked credential.
168
+ On POSIX, group/other permissions make the file unusable (machine refusal,
169
+ OpenSSH-style); Windows relies on the %USERPROFILE% ACLs instead.
170
+ - **Revocation is deleting the line.** `ukp serve token revoke <label>`
171
+ removes every key carrying that label; the running door re-reads the file
172
+ on every request, so the next call is a 401 — no restart, no deploy step.
173
+ Hand-editing (deleting or `#`-commenting a line) works too.
174
+ - **Rotation** is zero-downtime: `token add` with an existing label keeps the
175
+ old key active; hand out the new one, then revoke the label when the old
176
+ key's last consumer has switched. `ukp serve token list` shows labels, key
177
+ ids, and scopes (never hashes).
178
+ - **Chain order**: while `UKP_SERVE_TOKEN` is set, the env token wins and the
179
+ file is ignored — the env is the shortcut form of the same gate (the same
180
+ order as `AWS_*` env vars over `~/.aws/credentials`, or `GH_TOKEN` over the
181
+ stored gh login). An env var set to an empty value counts as unset.
182
+
183
+ The Windows resident form (`--print-task --write`) interpolates the env token
184
+ into `start-door.cmd`; a file-key door instead wants the cmd's `set
185
+ "UKP_SERVE_TOKEN=..."` line removed so the key file arms the gate.
186
+
118
187
  ## Windows host (https — resident form)
119
188
 
120
189
  Windows has no socket-activation equivalent, so the https path on a
@@ -219,6 +288,13 @@ Pitfalls the verification run caught:
219
288
  - `rg` on the host is the host's business — no ripgrep installed means
220
289
  the remote `rg` capability reports unavailable (everything else works).
221
290
 
291
+ `ukp diagnose --door` is the read-only health check for this resident form:
292
+ for every door it reports the task state, the wscript->cmd->bun process tree,
293
+ the port (and who holds it), and the door.log tail — and exits 1 when a door
294
+ is down (a host with no doors is healthy). Each finding names its repair;
295
+ removal and restart moves live in the `ukp serve --print-task` §5 checklist
296
+ (the three-level teardown below) and the pitfalls above.
297
+
222
298
  To remove the door — the inverse of steps 4–0, in three levels (stopping
223
299
  is not disabling, and disabling is not erasing; `ukp serve --print-task`
224
300
  prints this checklist as its §5):
@@ -237,11 +313,13 @@ prints this checklist as its §5):
237
313
  plaintext** — deleting it destroys this copy; if it ever left the
238
314
  machine, treat the token as burned), `start-door-hidden.vbs`, and
239
315
  `door.log`, plus the certificate material: your `--tls-cert` /
240
- `--tls-key` paths, or — with `--tls` — the identity in the served
241
- folder's `.ukp\tls\` (single-endpoint door: *inside* the KB folder,
242
- so git or cloud sync carries the private key out;
243
- `ukp init service` drops a self-ignoring `.ukp\.gitignore` there) or
244
- beside the host registry (host door). The endpoints stay registered
316
+ `--tls-key` paths, or — with `--tls` — the self-signed identity beside
317
+ the host registry: `%USERPROFILE%\.ukp\tls\<endpoint-name>\` for a
318
+ single-endpoint door, `%USERPROFILE%\.ukp\tls\` for a host door (it
319
+ never lives inside the knowledge folder, so git or cloud sync cannot
320
+ carry the private key out; `ukp unregister` leaves it in place on
321
+ purpose — a re-registered endpoint keeps its pin — so delete it by
322
+ hand when you are done). The endpoints stay registered
245
323
  on the host for local use — `ukp unregister --endpoint <name>` per
246
324
  endpoint only if you are done with them; and every consumer that
247
325
  registered holds the token in plaintext in its own registry —
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@catheadowl/ukp",
3
- "version": "0.2.6",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "bun": ">=1.3.14"
@@ -18,10 +18,12 @@
18
18
  "keywords": [
19
19
  "knowledge",
20
20
  "cli",
21
- "bun",
22
- "qmd",
23
21
  "search",
24
- "agent"
22
+ "agent",
23
+ "ai-agents",
24
+ "knowledge-base",
25
+ "local-first",
26
+ "self-hosted"
25
27
  ],
26
28
  "bin": {
27
29
  "ukp": "bin/ukp.js"
@@ -30,16 +32,19 @@
30
32
  "bin",
31
33
  "src",
32
34
  "docs",
35
+ "skills/ukp/SKILL.md",
33
36
  "README.md",
34
- "LICENSE",
35
- "package.json"
37
+ "SECURITY.md",
38
+ "LICENSE"
36
39
  ],
37
40
  "scripts": {
38
41
  "dev": "bun run src/cli.ts",
42
+ "prepack": "bun ./scripts/pack-audit.mjs",
39
43
  "test": "bun test",
40
44
  "typecheck": "tsc --noEmit"
41
45
  },
42
46
  "dependencies": {
47
+ "@any-nav/scan": "^0.2.0",
43
48
  "commander": "15.0.0",
44
49
  "smol-toml": "1.7.1",
45
50
  "zod": "4.4.3"
@@ -0,0 +1,32 @@
1
+ ---
2
+ name: ukp
3
+ description: "ukp — a CLI tool for named knowledge endpoints(registered local or remote folders)"
4
+ ---
5
+
6
+ # ukp
7
+
8
+ A CLI tool for knowledge endpoints: register any local or remote folder
9
+ as a named endpoint, then address knowledge by name through one stable
10
+ command surface.
11
+
12
+ ## Entry
13
+
14
+ Run `ukp --help` — the command surface teaches itself: grouped help,
15
+ per-command `--help` for exact grammar, `ukp guide <topic>` for
16
+ role-based walkthroughs, `ukp list` for the registered endpoints.
17
+
18
+ ## Handoff: ukp:// references
19
+
20
+ Knowledge you got from ukp is handed off as
21
+ `ukp://<endpoint>/<path>` — name-addressed, so folders can move while
22
+ references stay valid.
23
+
24
+ `ukp read <uri>` opens one as-is, replayable in
25
+ any session. The cross-repo `{name}:path` shorthand resolves the same
26
+ way.
27
+
28
+ ## Writes: propose
29
+
30
+ Endpoints are read-only by default. Changes go through `ukp propose` —
31
+ an idempotent suggestion box (created / unchanged / updated; a revision
32
+ bumps only on updated) that the endpoint owner adjudicates.