artifacty 0.11.1 → 0.13.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.
@@ -1,7 +1,7 @@
1
1
  # Threat Model
2
2
 
3
- Artifacty is a local artifact exchange for LLM agents. It is designed for one
4
- operator, one local store, and trusted local MCP clients by default.
3
+ Artifacty is a local artifact exchange for LLM agents. Its default deployment
4
+ uses one operator, one local store, and trusted local MCP clients.
5
5
 
6
6
  ## Assets
7
7
 
@@ -14,8 +14,8 @@ operator, one local store, and trusted local MCP clients by default.
14
14
 
15
15
  ## Trust Boundaries
16
16
 
17
- - **HTTP browser server**: local by default, optionally reachable on LAN/team
18
- networks when explicitly configured.
17
+ - **HTTP browser server**: local by default. An operator can configure access
18
+ from LAN or team networks.
19
19
  - **MCP stdio server**: local process launched by an MCP client. It inherits the
20
20
  local user account's filesystem permissions. In bridge mode, it forwards
21
21
  JSON-RPC to a configured central `/mcp` endpoint instead of touching local
@@ -58,8 +58,11 @@ Controls:
58
58
  - Personal API tokens are stored only as hashes.
59
59
  - Browser sessions use `HttpOnly` and `SameSite=Lax` cookies.
60
60
 
61
- Guidance: rotate tokens after sharing sessions, prefer header-based tokens for
62
- scripts, and use generated startup tokens only for temporary interactive shares.
61
+ Guidance:
62
+
63
+ - Rotate tokens after sharing sessions.
64
+ - Use token headers in scripts.
65
+ - Use generated startup tokens only for temporary interactive shares.
63
66
 
64
67
  ### Cross-Site Request Forgery
65
68
 
@@ -97,12 +100,12 @@ Risk: agents may accidentally publish API keys or private keys into artifacts.
97
100
 
98
101
  Controls:
99
102
 
100
- - Common API key and private key patterns are scanned before storage.
103
+ - Artifacty scans common API key and private key patterns before storage.
101
104
  - Writes fail unless `allowSecrets` or `ARTIFACTY_ALLOW_SECRETS=true` is set.
102
- - Stored scan status is recorded in version metadata.
105
+ - Artifacty records the scan status in version metadata.
103
106
 
104
- Limitations: pattern scanning is best-effort and does not prove content is free
105
- of sensitive data.
107
+ Limitation: pattern scanning can miss sensitive data. A successful scan does
108
+ not prove that content is safe to share.
106
109
 
107
110
  ### MCP Tool Abuse
108
111
 
@@ -120,23 +123,25 @@ Controls:
120
123
  - MCP writes go through the same secret scan and audit paths as CLI/HTTP writes.
121
124
  - MCP resources are read-only.
122
125
 
123
- Guidance: install Artifacty MCP only in clients and workspaces you trust. For
124
- central deployments, prefer TLS through a reverse proxy and rotate shared tokens
125
- after team changes.
126
+ Guidance:
127
+
128
+ - Install Artifacty MCP only in trusted clients and workspaces.
129
+ - For central deployments, use TLS through a reverse proxy.
130
+ - Rotate shared tokens after team changes.
126
131
 
127
132
  ### Personal API Token Scopes
128
133
 
129
- Risk: a personal API token leaked from one integration (e.g. a read-only
130
- reporting bot) should not also let the leaker create, modify, or delete
131
- artifacts or reach admin-only routes (backup, webhooks).
134
+ Risk: an attacker can use a leaked personal API token. A read-only reporting
135
+ token should not permit artifact changes or access to admin routes, such as
136
+ backup and webhooks.
132
137
 
133
138
  Controls:
134
139
 
135
140
  - Each personal token carries a `scopes_json` list drawn from `read`,
136
141
  `write`, `admin` (default `["read", "write"]` for both new tokens and
137
142
  tokens created before scopes existed).
138
- - `admin` can only be requested for a token owned by a user with the admin
139
- role; `createApiToken` rejects the request otherwise.
143
+ - Only a user with the admin role can own a token with the `admin` scope.
144
+ `createApiToken` rejects other requests for this scope.
140
145
  - `requireScope` (`src/lib/security.js`) is called on every `/api/*` HTTP
141
146
  route: read routes need `read`, mutating routes need `write`, and
142
147
  admin-only routes (`/api/webhooks*`, `/api/admin/backup*`) need `admin` in
@@ -145,22 +150,20 @@ Controls:
145
150
  throttled to one per token per minute.
146
151
  - The shared `ARTIFACTY_API_TOKEN` and browser sessions always have full
147
152
  scopes — scoping only narrows a *personal* token.
148
- - Over MCP, `tools/list` omits every tool without a `readOnlyHint`
149
- annotation (create, publish, import, update, archive, restore, link,
150
- unlink) when the connection's token lacks `write`; calling one of those
151
- tools directly anyway returns an `isError` tool result with
152
- `structuredContent.code: "scope_denied"` instead of executing it. This
153
- only applies to the streamable-HTTP MCP transport, where the connection is
154
- tied to an authenticated token — local stdio MCP connections are treated
155
- as fully trusted, matching every other local write path.
156
-
157
- Guidance: issue read-only tokens to reporting/analytics integrations, and
158
- reserve `admin` scope tokens for operator tooling only.
153
+ - For HTTP MCP, `tools/list` omits write tools when the token lacks `write`.
154
+ A direct call to one of these tools returns an `isError` result with
155
+ `structuredContent.code: "scope_denied"`. The tool does not execute.
156
+ - Local stdio is a trusted local process and does not enforce token scopes.
157
+ If its configured token identifies a personal account, artifact access rules
158
+ still apply to that account. Private site mode requires that personal identity.
159
+
160
+ Guidance: issue read-only tokens to reporting and analytics integrations.
161
+ Reserve tokens with the `admin` scope for operator tools.
159
162
 
160
163
  ### HTTP and MCP Rate Limiting
161
164
 
162
- Risk: a compromised or misbehaving token/client could flood the server with
163
- writes or searches, or brute-force `/login`.
165
+ Risk: a compromised or faulty client could send excessive writes or searches.
166
+ An attacker could also send repeated password guesses to `/login`.
164
167
 
165
168
  Controls:
166
169
 
@@ -184,29 +187,28 @@ Controls:
184
187
  - The limiter is in-memory and per-process; it resets on restart and does
185
188
  not coordinate across multiple server processes sharing one store.
186
189
 
187
- Guidance: raise the `*_PER_MIN` env vars for legitimate high-throughput
188
- integrations rather than disabling rate limiting outright on a
189
- non-loopback bind.
190
+ Guidance: increase the `*_PER_MIN` environment variables for integrations that
191
+ need higher throughput. Keep rate limiting enabled on non-loopback interfaces.
190
192
 
191
193
  ### Request and Content Size Limits
192
194
 
193
- Artifacty enforces the following byte limits, all in-process and independent
194
- of any reverse proxy's own limits:
195
+ Artifacty enforces the following byte limits in its server process. These
196
+ limits are independent of reverse proxy limits:
195
197
 
196
198
  | Limit | Value | Constant / env |
197
199
  | --- | --- | --- |
198
200
  | Artifact version content | 16 MiB | `MAX_ARTIFACT_BYTES` (`src/lib/storage.js`) |
199
201
  | Backup import body | see `src/lib/backup.js` | `MAX_BACKUP_BYTES` |
200
- | Comment body (reserved; no comments feature yet) | 16 KiB | `MAX_COMMENT_BYTES` (`src/lib/storage.js`) |
202
+ | Comment body | 16 KiB | `MAX_COMMENT_BYTES` (`src/lib/storage.js`) |
201
203
  | Generic JSON/form request body | `MAX_ARTIFACT_BYTES + 1024` | default `limitBytes` in `readJsonBody`/`readFormBody` (`src/server.js`) |
202
204
 
203
- A request body over its limit is rejected with `413` before being parsed.
205
+ Artifacty rejects a request body over its limit with `413` before parsing it.
204
206
 
205
207
  ### Webhook SSRF and Secret Handling
206
208
 
207
- Risk: a webhook target URL is an attacker-influenceable outbound HTTP request
208
- from the Artifacty server's network position; a leaked webhook secret would let
209
- an attacker forge signed deliveries.
209
+ Risk: an attacker who controls a webhook URL can influence outbound HTTP
210
+ requests from the Artifacty server. A leaked webhook secret lets an attacker
211
+ forge signed deliveries.
210
212
 
211
213
  Controls:
212
214
 
@@ -234,9 +236,8 @@ Controls:
234
236
  records changed after the webhook was created) is not caught by this
235
237
  control. Treat webhook creation as an admin-only, trusted-input operation,
236
238
  not as safe to expose to untrusted callers.
237
- - Deliveries use `redirect: "manual"` and never follow a redirect, so a
238
- webhook target cannot use a 3xx response to retarget delivery at an
239
- otherwise-blocked address.
239
+ - Deliveries use `redirect: "manual"` and never follow redirects. A webhook
240
+ target cannot use a 3xx response to send delivery to a blocked address.
240
241
  - The webhook secret is shown once, in the create response, and never stored
241
242
  or returned again in plaintext. What is persisted is `secretHash =
242
243
  sha256(secret)`, and every delivery is signed as
@@ -249,74 +250,97 @@ Controls:
249
250
  single-user mode (no accounts configured) it is available to whoever holds
250
251
  the configured API token, matching every other write route's trust
251
252
  boundary.
252
- - After 20 consecutive delivery failures a webhook is automatically disabled
253
- and a `webhook-deliver-failed` audit row is written; it stays disabled
254
- until deleted and recreated.
253
+ - After 20 consecutive delivery failures, Artifacty disables the webhook and
254
+ writes a `webhook-deliver-failed` audit row. The webhook stays disabled until
255
+ an administrator deletes and recreates it.
256
+
257
+ Guidance:
255
258
 
256
- Guidance: only register webhook endpoints you control or trust, prefer HTTPS
257
- targets, and treat a leaked webhook secret as a credential (delete and
258
- recreate the webhook if you suspect exposure — that also rotates the
259
- `secretHash` used for signing).
259
+ - Register only webhook endpoints that you control or trust.
260
+ - Prefer HTTPS targets.
261
+ - If you suspect secret exposure, delete the webhook.
262
+ - Recreate the webhook with a new secret. This also rotates its signing
263
+ `secretHash`.
260
264
 
261
265
  ### Artifact Visibility and Ownership
262
266
 
263
- Risk: in team mode, any authenticated user could read or modify any other
264
- user's artifacts, including sensitive drafts or work-in-progress content
265
- that was never meant to be shared server-wide.
267
+ Risk: one user could read or change another user's artifacts without permission.
268
+ This includes sensitive drafts that the owner did not intend to share.
269
+
270
+ Controls:
271
+
272
+ - Administrators select public or private site mode at `/admin/access`.
273
+ - In public mode, every artifact has `visibility` (`private` or `team`, default
274
+ `team`) and an `ownerUserId`. Only the owner or an administrator can read or
275
+ write `private` artifacts through normal artifact routes. Anonymous browser
276
+ visitors can read `team` artifacts. Authenticated principals can write them.
277
+ API authentication requirements still apply. `ARTIFACTY_TEAM_WRITE=owner` restricts these writes to owners and
278
+ administrators.
279
+ - Private site mode requires a personal identity. Owners and administrators
280
+ retain access. Other users need a direct or team grant. Grants permit
281
+ reading, commenting, or editing. Artifacty applies the strongest matching
282
+ grant. Token scopes impose an additional restriction.
283
+ - Archiving, restoring, sharing, and changes to visibility or ownership require
284
+ the owner or an administrator. These rules apply in both site modes.
285
+ - If a caller cannot read an artifact, the server returns
286
+ `404`/`ARTIFACT_NOT_FOUND`. This prevents disclosure of the artifact's
287
+ existence. If the caller can read it but lacks the required write or management
288
+ permission, the server returns `403` with `code: "forbidden"`.
289
+ - List queries apply access checks in SQL for both metadata and FTS search.
290
+ Relations to unreadable targets return `{ restricted: true }` without the
291
+ target summary.
292
+ - A shared `ARTIFACTY_API_TOKEN` has no personal identity. In public mode, it can
293
+ read and write `team` artifacts but cannot see `private` artifacts. In private
294
+ mode, it cannot read or create artifacts. Its administrative privileges on
295
+ other server routes do not grant a personal artifact identity.
296
+ - In public mode with no user accounts, user access checks do not apply.
297
+
298
+ Guidance: use separate stores for mutually untrusted parties. Administrators can
299
+ read, write, and reassign any artifact in their store.
300
+
301
+ ### Public Share Links and Network Restrictions
302
+
303
+ Risk: a copied share link can disclose an artifact to anyone who holds the link.
304
+ An incorrect network policy can either expose the server or lock out its
305
+ administrator.
266
306
 
267
307
  Controls:
268
308
 
269
- - Every artifact carries a `visibility` (`private` or `team`, default
270
- `team`) and an `ownerUserId`. `private` artifacts are readable and
271
- writable only by their owner or an admin; `team` artifacts are readable
272
- and writable by any authenticated principal, or restricted to the owner
273
- and admins for writes with `ARTIFACTY_TEAM_WRITE=owner`.
274
- - Archiving, restoring, and changing visibility or ownership always require
275
- the artifact's owner or an admin, independent of the write rule above.
276
- - A read of a `private` artifact by anyone other than its owner or an admin
277
- returns `404`/`ARTIFACT_NOT_FOUND` rather than `403`, so the artifact's
278
- existence is not leaked to callers who cannot see it. Writes and manage
279
- actions on an artifact the caller can see but does not own return `403`
280
- with `code: "forbidden"`.
281
- - The access predicate is applied at the SQL layer for list queries (both
282
- the metadata and FTS search paths), not filtered after the fact, and
283
- relation entries pointing at a target the caller cannot see are returned
284
- as `{ restricted: true }` instead of the target's summary.
285
- - A shared `ARTIFACTY_API_TOKEN` (or any request before the first user
286
- account exists) has no personal identity and is treated as an anonymous
287
- team principal: it can read and write `team` artifacts but never sees
288
- `private` ones, even though it is admin-equivalent for server
289
- administration routes elsewhere.
290
- - In single-user mode (no user accounts configured at all) every check is
291
- bypassed, matching pre-Section-10 behavior, since there is no second
292
- identity to protect against.
293
-
294
- Guidance: treat `private` as a convenience boundary between cooperating,
295
- already-authenticated users on one server, not a substitute for running
296
- separate stores for genuinely untrusted parties — an admin account can
297
- always read, write, and reassign ownership of any artifact.
309
+ - Share links provide read-only access. The owner or an administrator creates
310
+ and revokes them. A link can select the latest version or one fixed version.
311
+ - Links expire. Private site mode disables them unless an administrator enables
312
+ them. The server stores token hashes and shows the raw token only at creation.
313
+ - Share pages omit artifact ownership, tags, history, and internal artifact URLs.
314
+ They use `Referrer-Policy: no-referrer` and `Cache-Control: no-store`.
315
+ - All HTTP requests, including share links, obey the configured IP/CIDR allowlist.
316
+ The server checks the TCP peer address and ignores forwarding headers.
317
+ - A network change must include the administrator's current address. It remains
318
+ pending until confirmed. If it expires without confirmation, Artifacty restores
319
+ the previous policy. Administrators can also roll back a pending change.
320
+
321
+ Guidance: treat share links as credentials. Revoke a link if it reaches an
322
+ unintended recipient. When using a reverse proxy, account for its TCP peer
323
+ address in the network policy.
298
324
 
299
325
  ### Retention Purge Gate
300
326
 
301
- Risk: a misconfigured or overly broad retention policy (e.g. a low
302
- `purgeArchivedAfterDays` set by mistake, or applied before reviewing what it
303
- would affect) could hard-delete artifacts and their version files with no
304
- way to recover them — the only irreversible action any retention setting
305
- can trigger.
327
+ Risk: an incorrect retention policy can permanently delete artifacts and their
328
+ version files. For example, an operator could set `purgeArchivedAfterDays` too
329
+ low or apply it without reviewing the affected artifacts. Purge is the only
330
+ irreversible action that retention settings can trigger.
306
331
 
307
332
  Controls:
308
333
 
309
- - Retention policy changes (`archiveAfterDays`, `purgeArchivedAfterDays`,
310
- `auditRetentionDays`, `eventRetentionRows`, `keepTags`) themselves never
311
- delete anything; they only take effect on the next sweep or explicit
312
- `artifacty retention run`.
334
+ - Changing `archiveAfterDays`, `purgeArchivedAfterDays`, `auditRetentionDays`,
335
+ `eventRetentionRows`, or `keepTags` does not delete data. The new policy takes
336
+ effect on the next sweep or explicit `artifacty retention run`.
313
337
  - `artifacty retention run` and `POST /api/admin/retention/run` default to
314
338
  `dryRun: true`, returning a report of what would be archived/purged/pruned
315
339
  without changing the store. `/admin/retention` renders that same report so
316
340
  an admin can review it before applying anything.
317
- - Archiving (moving an artifact out of active listings) is reversible via
318
- `artifacty restore` and never deletes content, so it carries no
319
- additional gate beyond the existing owner/admin check on `archiveArtifact`.
341
+ - Archiving removes an artifact from active lists without deleting content.
342
+ `artifacty restore` reverses it. The existing owner or administrator check
343
+ on `archiveArtifact` is the only access requirement.
320
344
  - Purging is irreversible and additionally requires
321
345
  `ARTIFACTY_RETENTION_ALLOW_PURGE=true` in the server's environment. A
322
346
  policy with purge candidates but no allow-purge gate set records them as
@@ -340,11 +364,8 @@ Controls:
340
364
  ## Out of Scope
341
365
 
342
366
  - Public internet hosting without a separate TLS/auth proxy.
343
- - Multi-user browser write access.
344
- - OAuth or per-user remote MCP authorization beyond the `read`/`write`/`admin`
345
- personal API token scopes described below.
346
- - Group- or team-scoped ACLs beyond the single owner + team/private model
347
- (see Artifact Visibility and Ownership above).
367
+ - OAuth. Personal API token scopes and direct or team artifact grants are
368
+ supported, as described above.
348
369
  - Encrypted-at-rest storage.
349
370
  - Malware analysis of arbitrary artifact content.
350
371
 
@@ -0,0 +1,89 @@
1
+ # Upgrade Snapshots and Recovery
2
+
3
+ Artifacty creates a local snapshot before it migrates an existing store to a newer schema. This snapshot is mandatory. If snapshot creation or verification fails, Artifacty stops before migration.
4
+
5
+ Use upgrade snapshots to recover the original store state. Use `artifacty backup` and `artifacty export` for portable JSON backups and store transfers. These are separate backup systems. `artifacty restore <id>` restores an archived artifact; it does not restore a store snapshot.
6
+
7
+ ## When Artifacty Creates a Snapshot
8
+
9
+ - **Schema migration:** Artifacty always snapshots an existing store before migration. This includes a legacy `index.json` store. A new empty store needs no snapshot.
10
+ - **Application update:** Set `ARTIFACTY_BACKUP_ON_UPDATE=true` to also snapshot an existing store when the application version changes. This setting is off by default.
11
+ - **Unknown application version:** With the update setting enabled, the first open of an existing store without an application-version marker creates a baseline snapshot. Its source application version is unknown. Later opens with the same version do not repeat it.
12
+ - **Restore:** Before replacing a store, Artifacty creates and verifies a recovery snapshot of its current state.
13
+
14
+ Stop every HTTP server and MCP process that uses the store before an upgrade or restore. This includes services, foreground servers, and local stdio MCP clients. Artifacty checks managed server PID markers, but these markers cannot identify every process with an open store.
15
+
16
+ Snapshots are stored at `ARTIFACTY_HOME/upgrade-backups/<id>/`. The default home is `~/.artifacty`.
17
+
18
+ ## Snapshot Contents
19
+
20
+ Each snapshot contains a manifest with file sizes and SHA-256 hashes. It also contains:
21
+
22
+ - A consistent raw SQLite database, including all tables and security state.
23
+ - Every version file referenced by the database or an authoritative legacy index.
24
+ - The legacy `index.json`, if it exists.
25
+
26
+ Verification checks the file hashes, SQLite integrity, and version-file references. Snapshots do not include unrelated files, process markers, logs, or the complete installation directory. Keep snapshots private: they contain credentials and security records.
27
+
28
+ `ARTIFACTY_UPGRADE_BACKUP_KEEP` controls automatic snapshot retention. The default is `3`; valid values are integers from `1` through `1000`. Artifacty prunes older automatic schema/update snapshots after a successful upgrade. It does not prune manual or recovery snapshots with this setting.
29
+
30
+ ## Inspect Snapshots
31
+
32
+ List snapshots without opening or migrating the store:
33
+
34
+ ```bash
35
+ artifacty backups list --home /path/to/store
36
+ ```
37
+
38
+ Copy an `id` from the output. Verify that snapshot:
39
+
40
+ ```bash
41
+ artifacty backups verify <id> --home /path/to/store
42
+ ```
43
+
44
+ A successful response includes `valid: true`. Listing checks manifests; it does not replace full verification. From a repository checkout, use `node src/cli.js` in place of `artifacty`.
45
+
46
+ ## Restore a Snapshot
47
+
48
+ A restore replaces the current database, version files, and legacy index. Changes made after the snapshot are no longer current. Artifacty keeps the pre-restore state in a separate recovery snapshot.
49
+
50
+ **Security state also rolls back.** Old passwords, permissions, network rules, sessions, API tokens, and share-link records can become current again. A session, token, or link revoked after the snapshot can become valid again if it has not expired. Review the restored security state before allowing users to reconnect.
51
+
52
+ 1. Stop all server, service, and MCP processes that use this store.
53
+ 2. Select a snapshot from `backups list`.
54
+ 3. Verify it with `backups verify`.
55
+ 4. Restore it with explicit confirmation:
56
+
57
+ ```bash
58
+ artifacty backups restore <id> --confirm restore-store --home /path/to/store
59
+ ```
60
+
61
+ 5. Save the returned `recoveryBackupId`.
62
+ 6. Review the restored security settings before reconnecting clients.
63
+
64
+ Restore does not migrate the selected snapshot. Opening it with the current application can trigger another protected migration. A build that does not support the restored schema rejects the store.
65
+
66
+ ## Recover When the Current Store Is Corrupt
67
+
68
+ If Artifacty cannot verify the current store for its recovery snapshot, it returns `RECOVERY_BACKUP_FAILED`. It does not overwrite the damaged store.
69
+
70
+ 1. Keep the damaged home and its snapshots unchanged.
71
+ 2. Create a new empty home directory.
72
+ 3. Copy the selected snapshot directory into the new home's `upgrade-backups/` directory. Preserve its original snapshot ID and directory contents.
73
+ 4. Run `backups verify <id> --home /path/to/new-home`.
74
+ 5. Run `backups restore <id> --confirm restore-store --home /path/to/new-home`.
75
+ 6. Review the restored data and security settings before using the new home.
76
+
77
+ Do not copy the damaged database over the new home. The selected snapshot supplies the database and referenced version files.
78
+
79
+ ## Recover an Interrupted Restore
80
+
81
+ If a `.restore-<uuid>` directory remains, Artifacty stops with `RESTORE_INCOMPLETE`.
82
+
83
+ 1. Preserve that directory and the entire affected home.
84
+ 2. Read `.restore-<uuid>/restore.json`.
85
+ 3. Find its `recoveryBackupId`. This identifies the snapshot of the state before the interrupted restore.
86
+ 4. Copy that recovery snapshot into a new empty home's `upgrade-backups/` directory.
87
+ 5. Verify and restore it there with the commands above.
88
+
89
+ Do not remove the interrupted restore directory to bypass the check. It contains recovery evidence and can contain the previous database and files.
@@ -0,0 +1,56 @@
1
+ # Documentation writing style
2
+
3
+ Artifacty uses an ASD-STE100-inspired style for English documentation. Korean documentation follows the same clarity principles with natural Korean phrasing. This is an editorial guide, not a claim of compliance with ASD-STE100.
4
+
5
+ Apply the sentence and procedure rules consistently. Use technical vocabulary where it makes the meaning more precise. Keep introductions natural. The project's “75%” target describes this balance; it is not a compliance score.
6
+
7
+ ## Sentences and terms
8
+
9
+ - Give each sentence one main idea. Split long sentences when this improves clarity.
10
+ - Name the actor when responsibility matters: the administrator, the artifact owner, the user, or the server.
11
+ - Prefer active voice. Use passive voice when the actor is unknown or does not matter.
12
+ - Use the same term for the same concept. Match UI labels, API fields, and CLI commands exactly.
13
+ - Keep established terms such as artifact, MCP, webhook, and CIDR. Explain unfamiliar terms on first use.
14
+ - Keep words that make a sentence complete. Do not turn prose into compressed notes.
15
+ - Do not enforce a fixed word limit or replace precise terms only to fit a controlled dictionary.
16
+
17
+ ## Instructions and behavior
18
+
19
+ - State prerequisites and conditions before the action.
20
+ - Give each numbered step one action. Show the command or UI control that performs it.
21
+ - State the expected result when readers need it to verify the action.
22
+ - Make defaults, permissions, exceptions, and recovery behavior explicit.
23
+ - Keep requirements and recommendations distinct. Preserve the meaning of MUST, SHOULD, and MAY in specifications.
24
+ - Preserve commands, identifiers, URLs, examples, and technical constraints when editing prose.
25
+ - Describe planned features as planned. Do not present a design proposal as current behavior.
26
+
27
+ ## Apply by document type
28
+
29
+ Use these rules most strictly in installation instructions, API references, and security documentation. Allow more connected prose in the README introduction, design rationale, and launch posts. Keep the explanation readers need; shorter text is not useful if it omits a condition or exception.
30
+
31
+ For example:
32
+
33
+ > By default, share links do not work in private mode. An administrator must enable them in Access settings.
34
+
35
+ This states the default, the responsible actor, and the setting location.
36
+
37
+ Refer to the [official ASD-STE100 overview](https://www.asd-ste100.org/about.html) for the specification's purpose and structure.
38
+
39
+ ## 한국어 문서 작성 기준
40
+
41
+ 한국어 문서에도 같은 명료성 원칙을 적용합니다. 다만 영어의 문장 구조나 어휘 규칙을 그대로 옮기지 않고, 자연스러운 한국어 어순과 흐름을 살립니다. ‘75% 강도’는 편집 방향을 뜻하며, 표준 준수율을 뜻하지 않습니다.
42
+
43
+ - 한 문장에는 하나의 핵심 내용을 담습니다. 서로 밀접한 내용은 자연스럽게 연결하고, 짧게 쓰기 위해 문장을 지나치게 끊지 않습니다.
44
+ - 조건이나 전제는 행동보다 먼저 설명합니다. 절차는 단계별로 나누고, 필요한 경우 예상 결과와 확인 방법을 덧붙입니다.
45
+ - 권한이나 책임을 구분해야 할 때는 주체를 밝힙니다. 문맥상 분명한 주어는 반복하지 않습니다.
46
+ - 번역투, 불필요한 수동 표현, 명사만 나열하는 문장을 피합니다. 예를 들어 ‘설정의 변경이 가능합니다’보다 ‘설정을 변경할 수 있습니다’로 씁니다.
47
+ - 같은 개념에는 같은 용어를 사용합니다. 화면 이름은 해당 언어의 실제 UI 표기와 맞추고, 명령어·API 필드·코드 식별자는 그대로 유지합니다.
48
+ - 익숙한 기술 용어는 억지로 번역하지 않습니다. 설명이 필요한 용어는 처음 나올 때 간단히 풀이합니다.
49
+ - 기본값, 예외, 제한, 복구 조건을 생략하지 않습니다. 필수 사항과 권장 사항도 명확히 구분합니다.
50
+ - 설명문은 ‘합니다’체를 기본으로 씁니다. 절차에서는 필요한 행동을 ‘선택하세요’, ‘실행하세요’처럼 직접 안내합니다.
51
+
52
+ 예를 들어 다음과 같이 씁니다.
53
+
54
+ > 비공개 모드에서는 기본적으로 공유 링크를 사용할 수 없습니다. 관리자가 접근 설정에서 공유 링크를 허용해야 합니다.
55
+
56
+ 설치·API·보안 문서에는 이 기준을 엄격하게 적용합니다. 소개 글과 설계 배경에서는 정확성을 유지하면서 문장이 자연스럽게 이어지도록 씁니다.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "artifacty",
3
- "version": "0.11.1",
3
+ "version": "0.13.0",
4
4
  "description": "Local artifact exchange for heterogeneous LLM agents via HTTP and MCP.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -44,6 +44,8 @@
44
44
  "docs/roadmap-design.md",
45
45
  "docs/sarif-csv-artifact-plan.md",
46
46
  "docs/threat-model.md",
47
+ "docs/upgrade-backups.md",
48
+ "docs/writing-style.md",
47
49
  "scripts/lint.mjs",
48
50
  "scripts/smoke.sh",
49
51
  "README.md",
@@ -54,7 +56,7 @@
54
56
  "CLAUDE.md"
55
57
  ],
56
58
  "engines": {
57
- "node": ">=22.5"
59
+ "node": ">=22.12"
58
60
  },
59
61
  "license": "MIT",
60
62
  "dependencies": {
@@ -63,7 +65,7 @@
63
65
  "@codemirror/lang-json": "^6.0.2",
64
66
  "@codemirror/lang-markdown": "^6.5.0",
65
67
  "codemirror": "^6.0.2",
66
- "mermaid": "^11.15.0"
68
+ "mermaid": "^12.1.0"
67
69
  },
68
70
  "optionalDependencies": {
69
71
  "@babel/standalone": "^8.0.4",