artifacty
by raeseoklee
README.md
# Artifacty
English | [한국어](README.ko.md)
[Documentation](docs/README.md)
[](https://github.com/raeseoklee/artifacty/actions/workflows/publish.yml)
[](https://www.npmjs.com/package/artifacty)
[](LICENSE)
[](package.json)
Artifacty stores AI-generated artifacts locally so agents can share them. Claude, Codex, Gemini, GitHub Copilot, Cursor, and other MCP tools can publish artifacts to the same store. Other agents can find, read, and update them without copying content through chat.

## See it in action
These screenshots show the English interface with example data.
**Find artifacts across agents.** Browse a shared catalog, search by text, and narrow results with filters and saved views.

**View diagrams in the browser.** Render Mermaid source as a diagram alongside version history and artifact details.

**Review changes between versions.** Compare an artifact created by one agent and updated by another. Added and removed lines appear together.

Follow the [browser user guide](docs/user-guide.md) for step-by-step instructions and checks.
The next release adds collection pages with a table of contents, personal and team categories, and separate records for each version’s authoring tool and model. These repository changes are not included in published version 0.16.1. See [organizing artifacts and author history](docs/organizing-artifacts.md).
## Why MCP
Artifacts make session output available as pages that you can share and version. Artifacty keeps those pages local and makes them available across agents. The browser server renders artifacts for people. The MCP stdio server gives agents a common tool interface.
## Installation
Artifacty requires Node.js 22.12.0 or newer. Node 24 is recommended. On Node 22.12, enable its experimental SQLite support with `NODE_OPTIONS=--experimental-sqlite`.
The optional React renderer uses Babel 8. Its supported Node.js versions are
`^22.18.0 || >=24.11.0`. Use a compatible version if you enable that renderer.
The browser renderer uses Mermaid 12.2.0. Use a current browser with ES2024 support, such as Safari 17.4 or newer. Mermaid keeps the `classic` look, `dagre` layout, and `default` theme.
Install the CLI globally from npm:
```bash
npm install -g artifacty
artifacty --help
```
Run it without a global install:
```bash
npx artifacty@latest serve --foreground
```
Start the local dashboard in the background:
```bash
artifacty serve
```
Open the `url` in the JSON response. By default, Artifacty tries `http://127.0.0.1:8787`. If that port is busy and you did not configure a port, Artifacty uses the next available local port. It records the actual URL for CLI and MCP responses.
Manage the background server:
```bash
artifacty status
artifacty stop
```
`artifacty start` and `artifacty serve --detach` use the same lifecycle path as `artifacty serve`. Artifacty writes logs under `~/.artifacty/logs/`.
These commands use Node's detached process support on macOS, Linux, and Windows. `artifacty stop` uses process-group signals on macOS and Linux. On Windows, it uses `taskkill`. If Windows requires forceful termination, it retries with `/F`.
To debug with the server attached to your terminal, run:
```bash
artifacty serve --foreground
npm start
```
To protect HTTP API and browser write routes, generate an API token at startup:
```bash
artifacty serve --generate-token
artifacty serve --host 0.0.0.0 --share-mode lan --generate-token
artifacty serve --foreground --generate-token
```
Background `serve` returns the generated token and ready-to-open `/new?token=...` and `/import?token=...` URLs in JSON. Foreground `serve` prints the same values to stderr. For scripts or long-running services that need a stable token, generate one first:
```bash
artifacty token
artifacty start --api-token "$(artifacty token --raw)"
```
Install MCP configuration for local agents:
```bash
artifacty install claude
artifacty install codex
artifacty install gemini
artifacty install copilot
artifacty install cursor
artifacty install all
artifacty check
```
Choose the command for your agent, or use `artifacty install all` to install all supported configurations. Add `--dry-run` to preview changes without writing configuration files.
For a central internal server, enable the HTTP MCP endpoint on the server and
let users issue personal MCP/API tokens from the account page:
```bash
ARTIFACTY_BOOTSTRAP_TOKEN="$(artifacty token --raw)"
artifacty serve --host 10.0.0.50 --share-mode team --api-token "$ARTIFACTY_BOOTSTRAP_TOKEN" --mcp-http --foreground
```
Open `http://10.0.0.50:8787/login` to create the first administrator, then issue a personal token at `/account`. Keep the server terminal running. In a Bash terminal on each client machine, read that token without echoing it and install the client configuration:
```bash
read -r -s -p "Personal API token: " ARTIFACTY_PERSONAL_TOKEN
printf '\n'
artifacty install all --mcp-url http://10.0.0.50:8787/mcp --api-token "$ARTIFACTY_PERSONAL_TOKEN"
```
When running the central server as a Linux `systemctl --user` service, enable
lingering for the service account so Artifacty stays up after logout:
`sudo loginctl enable-linger $USER`.
Administrators can create users individually at `/admin/users` or import them
from CSV. Use `email,name,role,password,password_reset_required` headers. If
`password` is empty, Artifacty generates a temporary password, shows it once in
the import result, and requires the user to change it on first sign-in.
```csv
email,name,role
user@example.com,User,user
admin2@example.com,Admin Two,admin
```
```bash
artifacty users import --file users.csv
```
Run diagnostics for the local runtime, store, server, service definitions, and MCP discovery:
```bash
artifacty doctor
artifacty doctor --skip-mcp
```
Use `artifacty install codex --timeout 30000` or
`artifacty install gemini --timeout 30000` to tune supported MCP client timeouts.
See [docs/integrations.md](docs/integrations.md) for Claude Code, Codex, Gemini CLI, GitHub Copilot in VS Code, and Cursor setup.
## Update Artifacty
On any supported CLI platform, check for a release without changing the installation or store:
```bash
artifacty update --check
```
Administrators can also open **Administration → Server update** (`/admin/update`). Select **Check for updates** to check the latest release. If this server supports browser updates, confirm the displayed version and select **Back up and update**. The server briefly stops during the update. Keep the page open to reconnect and read the result. Opening the page does not check npm or start an update.
On Linux, the updater can install a release and restart the systemd user service `com.artifacty.server`:
```bash
artifacty update
```
`artifacty upgrade` is an alias. With no artifact ID, `update` updates the application. The existing `artifacty update <id>` command still updates artifact content. Use `--target-version <version>` to select an exact release. Use `--home /path/to/store` to select the store. Automatic updates refuse root execution and downgrades. If `latest` is older than the installed service, the updater keeps the newer installation.
For installed versions before 0.14.0, bootstrap the updater with:
```bash
npx --yes artifacty@latest update && export PATH="$HOME/.local/bin:$PATH"
```
This POSIX Linux shell command puts the user-owned launcher first for the current session after a successful update. For future sessions, add `~/.local/bin` to your shell's `PATH`.
The updater stages releases in the user's `~/.local/share/artifacty/releases` directory. It preserves the service's arguments and environment through a systemd drop-in. It creates and verifies a store snapshot before switching releases. If switching or startup fails, it attempts to roll back the changed code, service configuration, and store. Failures before the switch leave the running release in place.
Before stopping an active service, the updater checks its current health. If its bind address or network policy blocks that check, the update stops before downtime. The service stops during the update. Stop other clients that use the same store first. A store rollback discards writes made after the snapshot.
This automatic update path supports the Linux systemd user service only. It does not update macOS, Windows, foreground servers, or detached background servers automatically. A root-owned global installation remains in place. Add `~/.local/bin` to `PATH` if needed to use the user-owned launchers. If another command takes precedence, use the absolute `nextCommand` returned by the updater. It does not change shell configuration. An abrupt process or host shutdown can leave an update lock or a stopped service; inspect recovery before retrying. See [update operations and recovery](docs/upgrade-backups.md) for prerequisites and limits.
## Quick Start
Create an artifact in the browser:
```text
http://127.0.0.1:8787/new
```
For local development from a checkout:
```bash
npm install
npm test
npm start
```
Run the production-readiness check:
```bash
npm run release:check
```
Replace example IDs and paths with your own values. Values in angle brackets, such as `<artifact-id>`, are placeholders; replace the entire value before running a command.
Publish from the CLI:
```bash
artifacty publish --title "handoff note" --format markdown --source codex --content "# Next step
Review the API plan."
```
Import an artifact produced by another agent and convert it to Artifacty format:
```bash
artifacty import --agent claude --file ./deploy-failures.html --tag review
artifacty import --agent gemini --content '{"title":"Plan","returnDisplay":"# Plan\n- Ship it"}'
artifacty import --agent codex --content '{"agent":"codex","title":"Implementation Handoff","goal":"Continue Phase 3","changedFiles":[{"path":"src/lib/render.js","status":"modified"}],"nextSteps":["Add CodeMirror read-only viewer"]}'
artifacty import --agent copilot --content '{"agent":"github-copilot","title":"PR Review","findings":[{"severity":"medium","file":"src/app.js","line":42,"title":"Handle missing state"}]}'
artifacty import --agent cursor --content '{"sourceAgent":"cursor","title":"Cursor Handoff","summary":"Editor pass complete.","nextSteps":["Run visual QA."]}'
```
Codex, GitHub Copilot, and Cursor structured payloads can become `handoff`,
`bundle`, `diff-walkthrough`, `code-review`, or `test-report` artifacts when
the payload explicitly identifies the agent through `agent` or `sourceAgent`.
Plain Markdown from these agents stays a normal
`document` unless you pass an explicit `artifactType`.
When `format` is omitted, Artifacty infers common formats from filename,
content type, and content. HTML files and HTML fragments such as
`<section>...</section>` are stored as `html` so the browser viewer renders
them as HTML instead of plain text.
## Agent Handoff Example
One agent publishes a handoff artifact. Another agent finds it, reads the context, and appends the next version.
Codex publishes the handoff:
```bash
artifacty import --agent codex --tag handoff --content '{
"agent": "codex",
"title": "Release Handoff",
"goal": "Prepare Artifacty for an npm release",
"changedFiles": [
{ "path": "src/lib/converters.js", "status": "modified", "summary": "Normalize agent outputs" }
],
"commands": [
{ "command": "npm run release:check", "status": "passed" }
],
"nextSteps": [
"Review README",
"Publish package"
]
}'
```
Claude or Gemini finds the handoff and continues from the same artifact: Replace `release-handoff-abc12345` in the following commands with the ID returned by the import or list command.
```bash
artifacty list --tag handoff
artifacty show release-handoff-abc12345 --raw
artifacty update release-handoff-abc12345 \
--format markdown \
--source claude \
--tag handoff \
--content "# Release Handoff
Reviewed README and prepared publish notes."
```
List artifacts:
```bash
artifacty list
artifacty list --query review --limit 20 --offset 20
```
Run the MCP server:
```bash
artifacty-mcp
ARTIFACTY_MCP_MODE=bridge ARTIFACTY_MCP_URL=http://10.0.0.50:8787/mcp ARTIFACTY_API_TOKEN=... artifacty-mcp
```
MCP clients can create artifacts with `artifacty_create`. `artifacty_publish` remains as a backwards-compatible alias.
MCP clients that support resources or prompts can also read `artifacty://recent`,
`artifacty://artifacts/{id}`, `artifacty://artifacts/{id}/raw{?version}`, and
`artifacty://schema/v1`, or use prompt templates such as `artifacty_handoff`,
`artifacty_review`, and `artifacty_release_notes`.
Operational commands:
```bash
artifacty audit --limit 20
artifacty doctor
artifacty index rebuild
artifacty integrity
artifacty backup
artifacty backup --full
artifacty export --file ./artifacty-backup.json
artifacty export --file ./artifacty-backup-full.json --full
artifacty import-store --file ./artifacty-backup.json
artifacty import-store --file ./artifacty-backup-full.json --confirm replace-all
artifacty start
artifacty status
artifacty stop
artifacty service install --dry-run
artifacty service unit --dry-run
artifacty service task --dry-run
```
If you run from a source checkout without a global installation, replace `artifacty` with `node src/cli.js` and `artifacty-mcp` with `node src/mcp-server.js`.
## Storage
By default, Artifacty stores files under `~/.artifacty`.
```bash
ARTIFACTY_HOME=/path/to/shared/store artifacty serve
```
Artifacty stores metadata in `artifacty.sqlite`. Normal create and update operations append version files under `artifacts/`. Administrators can repair or delete individual versions from the browser. The audit log records these exceptions.
Artifacty writes the current browser server URL to `server.json`. MCP tools use this URL to return correct links when the server selects another port. On first access, Artifacty automatically migrates existing `index.json` stores.
Every artifact row has a `visibility` (`private`/`team`/`public`, default `team`) and an `ownerUserId`. During migration, Artifacty fills the owner field from the artifact's `publisherUserId`. See the Security Model section below for the access rules these enforce.
Administrators can download and restore backups from `/admin/backup`. The
default `artifacts` scope contains artifact metadata and version contents,
but not users, sessions, API token records, audit logs, comments, relations, or sharing grants. Restoring an
artifacts-scope bundle replaces the target server's artifact records and
prunes unreferenced version files, leaving users, tokens, and audit history
untouched. If the target contains comments, relations, or sharing grants, restore refuses unless you pass `--confirm replace-all` (API: `confirm: "replace-all"`). This confirmation permits deleting those records without restoring them. Use a `full` backup when you need to preserve them.
A `full`-scope backup (`artifacty backup --full`, `?scope=full` on the
download, or the scope selector on `/admin/backup`) additionally includes
users (with password hashes), API tokens (hashed, never the raw token),
audit log entries, artifact relations, and webhooks. Webhook secrets are
never exported. Restored webhooks are disabled and need a new secret. Sessions are never exported. Restoring a `full` bundle
requires explicit confirmation (`confirm: "replace-all"` over the API,
`--confirm replace-all` on the CLI, or the confirm checkbox in the browser)
and refuses to run when the target store already has users unless
`forceUsers`/`--force-users` is also set, since that would silently merge or
overwrite existing accounts. Restoring a bundle written before this feature
(no `bundleVersion`/`scope` header) is still supported and is always treated
as artifacts-only. For large migrations or scripted server moves, use
`artifacty backup --full` and
`artifacty import-store --file ./artifacty-backup.json --confirm replace-all`.
If the local Node SQLite build supports FTS5, search uses a SQLite FTS5 index. It covers the latest version body, title, tags, source agent, artifact type, format, and metadata summary. If FTS5 is unavailable, Artifacty uses metadata search. To rebuild or check the store, run:
```bash
artifacty index rebuild
artifacty integrity
```
### Upgrade Snapshots
Before migrating an existing store to a new schema, Artifacty creates and verifies a mandatory local snapshot. The snapshot includes the raw SQLite database, referenced version files, and legacy index. If snapshot verification fails, migration stops.
Set `ARTIFACTY_BACKUP_ON_UPDATE=true` to also snapshot application-version changes. If an existing store has no recorded application version, its first open with this setting creates a baseline snapshot. `ARTIFACTY_UPGRADE_BACKUP_KEEP` retains the latest three automatic snapshots by default (valid range: 1–1000).
Use `artifacty backups list`, `artifacty backups verify <id>`, and `artifacty backups restore <id> --confirm restore-store`. Stop every server and MCP process before an upgrade or restore. Restore creates a recovery snapshot before replacing the store. It also restores credentials and security state. As a result, previously revoked sessions, tokens, and links can become valid again.
These local snapshots are separate from portable `artifacty backup`/`export` JSON bundles. See [upgrade snapshots and recovery](docs/upgrade-backups.md) for verification, corrupt-store recovery, and interrupted-restore procedures.
### Semantic Search
The bundled ONNX model and `artifacty embeddings` commands are changes for the next release, not yet included in npm `0.16.1`.
Artifacty includes a quantized ONNX `multilingual-e5-small` model for local semantic search. It runs as CPU WebAssembly in a server-side Node.js worker without an API key or inference-time downloads. Document text and queries stay on the server when the local provider is selected. The model adds about 118 MB of weights plus tokenizer and runtime files to the installation.
- `keyword` searches with FTS5 or metadata.
- `semantic` compares the meaning of the query with indexed artifacts.
- `hybrid` combines keyword and semantic rankings and is the default for a nonempty search query.
Use `?mode=keyword|semantic|hybrid` on `GET /api/artifacts`, `artifacty list --mode`, or the MCP `artifacty_list` tool. Search permissions and filters apply in every mode. If the selected provider fails or embeddings are disabled, semantic and hybrid requests fall back to keyword search; the response reports `search.fallback: true`.
```bash
artifacty embeddings info
artifacty embeddings check
artifacty index rebuild --embeddings
```
The check command runs inference with the selected provider. Rebuild indexes existing artifacts; newly created or updated artifacts are indexed in the background. After changing models, rebuild embeddings using the same environment and store as the server.
Set `ARTIFACTY_EMBEDDINGS_PROVIDER=disabled` to use keyword search only. Other choices are `local`, `command`, and `openai-compatible`. Without an explicit provider, an existing command configuration takes precedence over an existing URL configuration; otherwise Artifacty uses the bundled model. Custom local models use `ARTIFACTY_EMBEDDINGS_LOCAL_PATH`. See [local models and semantic search](docs/embeddings.md) for model selection, privacy, licenses, and verification.
### Relations
Use typed, directional relations to connect a handoff, its review, and follow-up work:
- Relation names are a closed set for v1: `derived-from`, `supersedes`, `reviews`, `references`, `part-of`.
- Every relation has a computed inverse (`derived-from` ↔ `derives`, `supersedes` ↔ `superseded-by`, `reviews` ↔ `reviewed-by`, `references` ↔ `referenced-by`, `part-of` ↔ `contains`) shown automatically on the other side.
- `POST`/`GET`/`DELETE /api/artifacts/:id/relations` manage links over HTTP; `GET /api/artifacts` accepts `relatedTo` and `relation` filters.
- `artifacty_create` and `artifacty_update` accept a `relations` array so an agent can link an artifact when publishing it. `artifacty_get` responses include `relations: { outgoing, incoming }`.
- A relation whose target was deleted is reported with `missing: true` instead of being omitted.
```bash
artifacty link "<from-id>" derived-from "<to-id>"
artifacty relations "<artifact-id>"
artifacty show "<artifact-id>" --relations
artifacty unlink "<from-id>" derived-from "<to-id>"
```
### Automatic application of preferences
Language and page-size selections apply immediately. Advanced dashboard filters apply when a selection changes or an edited field loses focus. To run a text search, press Enter or select Search. Changes to permissions, server settings, and artifact content still require an explicit save. If JavaScript is unavailable, the Apply buttons remain available.
### Comments and review status
Review status is optional. Use it to record whether a team has reviewed an artifact or requested changes. For example, mark an AI-generated release plan as `pending`, use `changes-requested` when it needs revision, and set `approved` after review. Leave personal notes or other material that does not need review at the default, `none`.
| Status | Purpose |
| --- | --- |
| `none` | No review status assigned. This is the default. |
| `pending` | Waiting for review |
| `changes-requested` | Needs revision |
| `approved` | Approved after review |
When user accounts exist, only the artifact owner or an administrator can change this status. Use it in dashboard filters and saved views. It does not enforce a sequence of approval steps, change visibility or read/write permissions, or block publication. Resolving comments does not automatically approve an artifact.
Appending a version after approval resets the status to `pending` for another review. The retention policy's **automatic archiving** excludes `approved` artifacts. Approval does not prevent manual deletion or all retention operations.
Add feedback to a specific version without publishing a new version or a separate review artifact:
- Comments use the same sanitized Markdown renderer as artifact content. Each comment has a 16 KB limit. The optional `anchor` field provides a display hint: `{ line: 42 }` for text, `{ path: "$.runs[0].results[3]" }` for JSON/SARIF, or `{ row: 7 }` for CSV. Artifacty does not validate the hint against the content.
- Threads are one level deep: `parentId` on a new comment must point to a root comment (one with no `parentId` of its own).
- Deleting a comment is a soft delete: it disappears from `artifacty comments`/`GET .../comments` but its audit-log entry is kept. Pass `--include-deleted`/`includeDeleted=true` to include deleted comments. Authenticated non-administrators can see only their own deleted comments; administrators and trusted local calls can see all deleted comments for the artifact.
- Each artifact has a `reviewStatus`: `none`, `pending`, `changes-requested`, or `approved`. Set the status explicitly. If you append a version to an approved artifact, Artifacty resets the status to `pending`. The update's audit metadata records this change.
- `GET`/`POST /api/artifacts/:id/comments`, `POST /api/artifacts/:id/comments/:commentId/resolve`, `DELETE /api/artifacts/:id/comments/:commentId`, and `POST /api/artifacts/:id/review-status` manage comments and review status over HTTP.
- `artifacty_comment`, `artifacty_resolve_comment`, and `artifacty_set_review_status` provide the same operations through MCP. `artifacty_get` accepts `includeComments: true` to return the requested version's open comments alongside the artifact.
- The browser artifact page shows a comments panel grouped by version, with a reply form, a resolve button, and (for the artifact's owner or an admin) a review-status selector. Line-anchored comments are shown as plain text (e.g. "line 42") rather than a CodeMirror gutter marker.
```bash
artifacty comment release-handoff-abc12345 --body "Looks good, one nit" --line 42
artifacty comments release-handoff-abc12345
artifacty resolve-comment release-handoff-abc12345 "<comment-id>"
artifacty review-status release-handoff-abc12345 approved
```
### Diff
`artifacty diff <id> [--from N] [--to M] [--structured] [--json]` compares two artifact versions. By default, `--to` selects the latest version and `--from` selects `--to - 1`.
JSON, SARIF, CSV, notebook, and bundle artifacts use a structured diff by default. The output contains JSON paths, CSV rows and cells, or bundle files. Other formats use a line diff. To request a structured diff for any format, use `--structured`. Text lines include word highlights. To print machine-readable output instead of unified text, use `--json`.
```bash
artifacty diff release-handoff-abc12345
artifacty diff release-handoff-abc12345 --from 1 --to 3 --json
```
### Retention
By default, Artifacty does not limit retained artifacts, audit rows, or events. Administrators can set a retention policy at `/admin/retention` or with `artifacty retention set`. Artifacty stores the policy in the `meta` table:
- `archiveAfterDays` (a default plus optional per-artifact-type overrides) auto-archives artifacts that have not been updated within the window, unless the artifact carries a tag in `keepTags` or has `reviewStatus: "approved"`.
- `purgeArchivedAfterDays` hard-deletes artifacts that have been archived longer than the window, including their version files, dependent rows that cascade via foreign keys (comments, relations, embeddings), and their `events`/search-index rows. Audit log rows for the artifact are deliberately kept (see `auditRetentionDays` below) as the historical record that the purge happened, even though the artifact itself is gone. This is the only retention action that permanently deletes artifact content. It is refused unless the operator has set `ARTIFACTY_RETENTION_ALLOW_PURGE=true` in the server environment. With that environment variable enabled, scheduled sweeps and CLI runs can purge eligible artifacts even without `--allow-purge`. Browser and HTTP API runs additionally require `allowPurge: true`. Neither the CLI flag nor the request field sets the environment variable. Always dry-run first (`artifacty retention run --dry-run`, or the report on `/admin/retention`) to review what would be purged.
- `auditRetentionDays` prunes old audit log rows, except `version-repair`, `version-delete`, `retention-purge`, `retention-policy-update`, and `owner-change`, which are kept indefinitely.
- `eventRetentionRows` caps how many rows the `events` change-notification table keeps.
The HTTP server runs a background sweep every `ARTIFACTY_RETENTION_INTERVAL_MS` (default one hour). Each sweep checks the current policy. The timer starts even if no policy is set. A later policy change takes effect on the next sweep without a restart.
If a purge is interrupted, `artifacty integrity`/`checkStoreIntegrity` reports files left behind. `artifacty doctor` reports the current retention policy summary.
```bash
artifacty retention show
artifacty retention set --archive-after-days 90 --archive-after-days-for test-report=30 --purge-archived-after-days 180 --audit-retention-days 365 --event-retention-rows 10000 --keep-tag pinned
artifacty retention run --dry-run
ARTIFACTY_RETENTION_ALLOW_PURGE=true artifacty retention run --allow-purge
```
The retention screen groups artifact archive/purge settings, history limits, and protected tags. Review the preview before running cleanup.
### Dashboard Filters and Saved Views
`listArtifactsPage` and its callers (the `/` dashboard, `GET /api/artifacts`, `artifacty list`, and `artifacty_list`) accept these filters in addition to `q`/`tag`/`sourceAgent`/`relatedTo`/`relation`/`includeArchived`:
- `artifactType` — exact match against the artifact's type.
- `publisher` — matches `publisherId`, `publisherUserId`, or `ownerUserId`.
- `createdAfter` / `createdBefore` — ISO date or date-time bounds on `createdAt`. An unparseable value returns a `400` with `code: "invalid_filter"`.
- `reviewStatus` — the artifact-level review status: `none`, `pending`, `changes-requested`, or `approved`.
A frequently used filter combination can be saved as a **view**:
- `POST /api/views` with `{ name, filters, shared }` creates a view. `GET /api/views` lists views visible to the caller. `DELETE /api/views/:id` removes a view. `filters` is validated against an allowlist (`query`, `tag`, `sourceAgent`, `artifactType`, `publisher`, `createdAfter`, `createdBefore`, `reviewStatus`, `relatedTo`, `relation`, `includeArchived`, `mode`) and rejects any other key with `code: "invalid_filter"`.
- In single-user mode (no user accounts) views are global. In team mode a view belongs to its creator and is visible only to them unless `shared: true`, in which case every user sees it.
- `?view=<name-or-id>` on `/` or `GET /api/artifacts` expands the saved filters first; any other query parameter passed alongside `view` overrides that one filter. `artifacty_list` and `artifacty list --view <name-or-id>` work the same way.
- In the main dashboard, open **Saved views** to find the view list, delete buttons, and "Save current filters" form. **Advanced filters** and **Saved views** start collapsed. Search stays visible. Collapsing these sections preserves the selected filters. `artifacty views`, `artifacty views save <name> [--shared] [filters...]`, and `artifacty views delete <id>` manage them from the CLI.
- `groupBy=artifactType|sourceAgent|day` (dashboard query param, `--group-by` on the CLI) renders the already-fetched page grouped under section headers. This changes only the presentation. It does not change which artifacts are fetched or their sort order.
```bash
artifacty list --type handoff --review-status pending --created-after 2025-01-01
artifacty views save open-handoffs --type handoff --review-status pending --shared
artifacty list --view open-handoffs --group-by sourceAgent
artifacty views delete "<view-id>"
```
## Events
Every mutation (`artifact.created`, `artifact.updated`, `artifact.archived`, `artifact.restored`, `artifact.relation.added`, `artifact.version.repaired`, `artifact.version.deleted`) publishes an event agents can react to instead of polling `artifacty_list`.
**Watch from a shell:**
```bash
artifacty watch --tag handoff --type artifact.updated --json
artifacty watch --artifact release-handoff-abc12345 --exec "./on-change.sh"
artifacty watch --once # exits 0 after the first match
```
`--exec` runs the command with the event JSON on stdin and `ARTIFACTY_EVENT_TYPE`, `ARTIFACTY_EVENT_ARTIFACT_ID`, `ARTIFACTY_EVENT_VERSION` environment variables. `watch` reconnects automatically with `Last-Event-ID` if the connection drops.
**Server-Sent Events:**
```bash
curl -N -H "x-artifacty-token: $ARTIFACTY_API_TOKEN" \
"http://127.0.0.1:8787/api/events?tag=handoff"
```
Filters: `type`, `tag`, `artifactId`, `sourceAgent`. Send `Last-Event-ID` (a request header, matching the `id:` field of the last event you saw) to replay missed events after a reconnect. Without `Accept: text/event-stream`, `GET /api/events?since=<seq>` returns one JSON page of events instead (useful for polling or tests). The server sends a heartbeat comment every 25 seconds and caps concurrent streams at `ARTIFACTY_SSE_MAX_CLIENTS` (default 64; excess connections get `503`).
**Webhooks** deliver the same events to an external HTTP endpoint:
```bash
curl -s -X POST http://127.0.0.1:8787/api/webhooks \
-H 'content-type: application/json' \
-H "x-artifacty-token: $ARTIFACTY_API_TOKEN" \
-d '{ "url": "https://example.com/hooks/artifacty", "eventTypes": ["artifact.updated"] }'
```
Save `secret` from the response. Artifacty returns it only once. Each delivery sends JSON with `POST` and these headers: `X-Artifacty-Event`, `X-Artifacty-Delivery`, and `X-Artifacty-Signature: sha256=<hmac>`. Failed deliveries retry up to three times, after 2, 10, and 60 seconds. After 20 consecutive failures, Artifacty disables the webhook.
Manage webhooks at `/admin/webhooks` in the browser. The API provides `GET/POST /api/webhooks`, `DELETE /api/webhooks/:id`, and `POST /api/webhooks/:id/test`. See [docs/threat-model.md](docs/threat-model.md) for the signature scheme and SSRF guard.
**MCP:** `resources/subscribe` on `artifacty://artifacts/{id}` or `artifacty://recent` delivers `notifications/resources/updated` over the stdio transport. The `artifacty_wait` tool (`{ artifactId?, tag?, type?, timeoutMs }`, max 120000ms) is a long-poll alternative that works over any transport, including the stateless `/mcp` HTTP transport where `resources/subscribe` cannot push notifications. See [docs/mcp-public-api.md](docs/mcp-public-api.md).
## API Example
Start a protected server with a reusable shell token:
```bash
export ARTIFACTY_API_TOKEN="$(artifacty token --raw)"
artifacty serve --api-token "$ARTIFACTY_API_TOKEN"
```
```bash
curl -s http://127.0.0.1:8787/api/artifacts \
-H 'content-type: application/json' \
-H "x-artifacty-token: $ARTIFACTY_API_TOKEN" \
-d '{
"title": "PR review dashboard",
"content": "<h1>Review</h1>",
"format": "html",
"sourceAgent": "claude",
"tags": ["review"]
}'
```
Convert-and-save an external agent artifact:
```bash
curl -s http://127.0.0.1:8787/api/import \
-H 'content-type: application/json' \
-H "x-artifacty-token: $ARTIFACTY_API_TOKEN" \
-d '{
"agent": "claude",
"fileName": "deploy-failures.html",
"content": "<html><head><title>Deploy failures</title></head><body>...</body></html>",
"tags": ["review"]
}'
```
On desktop, use the navigation rail. Use its collapse button to switch to an icon rail; the browser saves this choice as `artifacty_sidebar`. On narrower screens, open **Menu**. **Artifacts** and **Inbox** lead to your work; **New** and **Import** create or bring in content. Administrators use **Administration** for Access (`/admin/access`), Users (`/admin/users`), Backup (`/admin/backup`), Retention (`/admin/retention`), Webhooks (`/admin/webhooks`), and Server update (`/admin/update`). **Account** contains Account & API tokens (`/account`), password changes (`/account/password`), and sign-out. API docs and language selection are also in the navigation.
The bottom pager offers 10, 25, 50, or 100 items per page; the default is 50. Changing the page size returns to the first page and preserves filters and language.
Browser routes:
- `/`: list artifacts with search, tag, and source filters.
- `/new`: create an Artifacty-native artifact with the CodeMirror editor.
- `/import`: paste an external agent artifact and convert it with automatic editor mode detection.
- `/artifacts/:id/edit`: save a new version with Markdown, HTML, JSON, text, code, SVG, Mermaid, React, SARIF, CSV, image, or video syntax support. Browser edits that do not change the artifact are recorded as `update-noop` audit events without creating a version.
- `/artifacts/:id/diff?from=&to=&view=structured|lines`: compare versions. `structured` is the default view for JSON-like formats (`json`, `sarif`, `csv`, `notebook`, bundle artifacts) and shows JSON path, CSV row/cell, or bundle per-file changes; other formats default to the line view with word-level highlighting on changed lines.
- `/api/artifacts/:id/diff?from=&to=&view=`: the same diff as structured JSON.
- `/admin/artifacts/:id/versions`: administrator-only repair/delete screen for individual versions.
- `/admin/backup`: administrator-only backup download and restore screen, with an `artifacts`/`full` scope selector.
- `/api/admin/backup?scope=artifacts|full`: administrator-only backup JSON download.
- `/api/admin/backup/import`: administrator-only backup restore. Accepts the raw bundle or `{ bundle, confirm, forceUsers }`.
- `/api/audit`: list audit events.
- `/openapi.json`: machine-readable OpenAPI 3.1 document for every `/api/*` route and `/mcp`; `/docs/api`: server-rendered human-readable reference for the same routes. Both require no authentication. The API reference groups endpoints in expandable sections, with search, request/response examples, and copyable curl commands generated from OpenAPI. It is read-only and has no live “Try it” execution. It uses the same saved browser theme as the dashboard.
List APIs support pagination with `limit` and `offset`. Responses keep the top-level `artifacts` array and include `pagination` and `search` metadata:
```bash
curl -s "http://127.0.0.1:8787/api/artifacts?q=handoff&limit=20&offset=0" \
-H "x-artifacty-token: $ARTIFACTY_API_TOKEN"
```
### Optimistic Concurrency
Every artifact response carries `latestVersion` and an `etag` (`"<id>:<latestVersion>"`). When two agents read the same version and both try to save a new one, the second write can replace the latest content without incorporating the first agent's changes. To avoid that, pass back the version you read as `expectedVersion` in the update body, or send it as an `If-Match` header (a weak `W/"..."` prefix is accepted):
```bash
curl -s "http://127.0.0.1:8787/api/artifacts/<id>" \
-H 'content-type: application/json' \
-H "x-artifacty-token: $ARTIFACTY_API_TOKEN" \
-H 'If-Match: "<id>:3"' \
-d '{ "content": "updated content" }'
```
If the artifact's `latestVersion` no longer matches, the update is rejected with `409 Version conflict`:
```json
{ "error": "Version conflict", "code": "version_conflict", "details": { "latestVersion": 4 } }
```
`GET /api/artifacts/:id` sets an `ETag` header. If the request's `If-None-Match` matches the current version, the server returns `304 Not Modified`. The optional `expectedVersion` field preserves compatibility with clients that omit it.
The browser editor includes a hidden `expectedVersion` field. If another agent updated the artifact first, the editor shows a conflict banner with a link to the diff view.
## User administration and email
At `/admin/users`, administrators can change a user's role inline. The last active administrator cannot be demoted. After demotion, existing tokens cannot retain effective administrator access through an old `admin` scope.
Password reset generates a temporary password, forces a change at the next login, and revokes sessions. API tokens remain valid subject to current permissions. Configure optional reset emails at `/admin/email`; see [SMTP and password reset](docs/smtp.md). Back up `secrets/smtp.key` separately: neither JSON backups nor upgrade snapshots include it.
### Artifact visibility
In public server mode, `public` artifacts allow anonymous read-only access. `team` artifacts require authentication, and `private` artifacts remain restricted to the owner and administrators. In private server mode, explicit sharing rules apply; choosing `public` or `team` does not grant anonymous access. The default remains `team`. Existing team artifacts no longer allow anonymous browsing; select `public` explicitly if that is intended.
The Access preview shows anonymous read-only access without saving configuration. Preview results do not change the access policy.
## Interface Language
English and Korean are built in. Administrators can enable installed languages and choose the default at **Administration → Languages** (`/admin/languages`). Import custom JSON packs or download the template there. The selector displays native language names. Partial packs use English for missing messages. See [language packs](docs/language-packs.md) for validation, limits, and backup behavior.
The browser uses enabled choices in this order: explicit `?lang=<locale>`, its one-year language cookie, then the saved administrator default. Disabled choices are ignored. Before settings are saved, `ARTIFACTY_LOCALE=en` or `ko` supplies the initial default; otherwise it is English. `Accept-Language` is ignored. Selecting enabled English explicitly overrides a Korean preference. Clearing the browser-specific cookie returns to the current default.
Translations cover navigation, authentication, accounts, administration, backup, version repair, and CSV/SARIF controls. Commands, API/MCP identifiers, and stored artifact content are unchanged. Guides are available in [English](docs/README.md) and [Korean](docs/ko/README.md).
The monitor, sun, and moon buttons select System, Light, and Dark themes. Each icon has an accessible label. The browser stores the choice as `artifacty_theme`. System follows the operating system preference.
UI controls use selectively compiled Bootstrap 5.3.8 forms, buttons, and button groups, with Tabler 3.49 icons. Assets are served locally without a CDN. Bootstrap, Tabler, and Sass are development dependencies; rebuild the generated assets with `npm run build:ui`. The application keeps its server-rendered UI.
Schema and storage:
- Metadata lives in SQLite with `schemaVersion: 1`, `artifactType`, `publisherId`, and `archivedAt`.
- Archive hides artifacts from default lists without deleting versions. Admin version repair/delete is available for correcting accidental or sensitive historical versions and records `version-repair` or `version-delete` audit events.
- Bundle artifacts store multiple files or base64 assets as portable JSON. A `files` entry can also carry a binary document (PDF, DOCX, XLSX, or ZIP, base64-encoded, 32 MB per file) served at `GET /artifacts/:id/raw?file=<path>`; PDFs render in a sandboxed viewer iframe and other document types show a download link.
- Supported formats are `html`, `markdown`, `text`, `json`, `code`, `svg`, `mermaid`, `react`, `sarif`, `csv`, `image`, `video`, and `notebook`.
- Native create/import paths infer `html` from HTML documents or fragments when no explicit format is supplied.
- The next release distinguishes authoring tools from providers and models. Exact tool aliases such as `Claude Code` and `codex-cli` become `claude-code` and `codex`. Ambiguous values such as `Claude`, `GPT`, or `OpenAI` do not identify a tool. Each version records separate provenance, and `createdBy` preserves the initial author. Earlier releases combined some names; information already lost through that normalization cannot be recovered. See [author history](docs/organizing-artifacts.md#read-author-history).
- Diagram, component, source snippet, analysis report, table, and media assets use `diagram`, `component`, `snippet`, `analysis-report`, `table`, and `asset` artifact types.
- Copilot/Cursor examples cover PR reviews, screenshots, demo recordings, and visual evidence bundles.
- See [docs/artifact-schema-v1.md](docs/artifact-schema-v1.md).
- See [docs/mcp-public-api.md](docs/mcp-public-api.md) for MCP tools, resources, prompts, and compatibility notes.
- See [docs/central-team-deployment-design.md](docs/central-team-deployment-design.md) for central team deployment.
- See [docs/sarif-csv-artifact-plan.md](docs/sarif-csv-artifact-plan.md) for the SARIF/CSV output artifact roadmap.
- See [docs/roadmap-design.md](docs/roadmap-design.md) for the original designs of relations, change notifications, optimistic concurrency, comments, semantic search, visibility, token scopes, and retention. The document distinguishes implemented features from later proposals.
## Public and Private Access Modes
This feature upgrades the SQLite store to version 10. Older builds reject the
upgraded store rather than ignoring its access policy.
Administrators can open **Administration → Access** (`/admin/access`) to change the
server's access mode without restarting it. Existing installations default to
**public** mode. Explicitly public artifacts permit anonymous read-only access. Team artifacts require authentication.
Artifacts marked private remain restricted to their owner and administrators.
API authentication and write protection still apply in public mode.
In **private** mode, browser visitors must sign in. An artifact is readable only
by its owner, an administrator, or users explicitly granted access, directly or
through a team. The existing `team` visibility value does not grant all users
access in this mode. Sharing grants support **read**, **comment**, and **edit**.
Commenters can add feedback and resolve their own comments. Editors can also
append versions. The strongest direct or team grant applies. Ownership, sharing,
archiving, and review-status control remain with owners and administrators.
Administrators can access existing unowned artifacts. They can assign ownership
or share those artifacts.
Create teams on `/admin/access`. Select the members for each team.
To grant artifact access:
1. Open the artifact as its owner or an administrator.
2. Open **Sharing**.
3. Select the allowed users and teams.
4. Select their permission levels.
5. Save the sharing settings.
The **Effective access** report shows each
user's actual permission and why it applies, anonymous access, and the global IP
condition. Removing a grant or team membership takes effect on subsequent reads,
search results, and change notifications. Personal API tokens carry the same
user permissions through HTTP and MCP. Shared server tokens have no user
identity and cannot read or create artifacts through ordinary artifact routes in
private mode. Trusted local CLI/store access remains an administrative
filesystem capability.
The same admin page accepts an optional IP/CIDR allowlist, one address or network
per line (for example `192.168.10.0/24` or `2001:db8:1234::/48`). If the list is empty,
all source addresses are allowed. If the list has entries, it restricts **all HTTP routes**
in both modes. This includes login, raw downloads, API routes, and HTTP MCP.
An allowed IP address does not replace user or artifact permissions. Artifacty rejects a list that
excludes the administrator's current connection address. Browser
changes are provisional for **120 seconds**: confirm that access still works to
keep the change, or roll it back. Unconfirmed changes revert before the next
policy check after the deadline, even across server restarts. A second change is
blocked while confirmation is pending. Mode changes offer a preview of how many
artifacts will become anonymously readable before you apply them.
Address checks use the actual TCP peer, including IPv4-mapped IPv6 addresses;
`X-Forwarded-For` and `Forwarded` are not trusted. Behind a reverse proxy, the
peer is the proxy: enforce end-user IP restrictions at that proxy. Local stdio
MCP and CLI operations do not have an HTTP source IP and are not covered by the
network allowlist.
Full backups include modes, network settings, teams, memberships, sharing grants,
and inbox entries. Pending network confirmation state and share-link tokens are
not exported. Artifact-only restores do not restore grants. If they replace existing grants,
they require confirmation. Restoring a full backup into a private server
keeps it private even if the backup was public, and an existing network policy
is preserved.
If you switch back to public mode, anonymous visitors can read explicitly public
artifacts. Team artifacts still require authentication. Artifacty retains explicit sharing grants for a later return
to private mode.
## Share Links and Inbox
Owners and administrators can create a read-only link from an artifact's
**Sharing** page:
1. Choose the latest version or pin a particular version.
2. Set an expiration (seven days by default).
3. Copy the URL when it is first shown.
Artifacty stores only a hash, so it cannot show the complete URL again. Links can be
revoked individually and are permanently revoked on ownership transfer.
Archived artifacts and deleted versions cannot be read through their links.
Links grant access to the selected artifact without an account, so private mode
requires an administrator to enable **Allow share links in private mode** at
`/admin/access`. Disabling this policy also disables existing links while the
server is private. Every link request still obeys the network allowlist. Links
do not expose the dashboard, history, comments, or editing controls. Public HTML
previews are static: scripts and external resources are disabled. React,
Mermaid, SVG and notebook shares show source instead of running active content.
The **Inbox** (`/inbox`) lists newly shared artifacts, comments, review requests,
and new versions for the signed-in user. Events caused by the same user are
excluded. Read individual notifications or mark all as read. Revoking artifact
access also hides its notifications and removes them from unread counts.
## Sample Manuals
Install four English sample artifacts: **Start here**, **Feature guide**,
**Architecture**, and **Handoff exercise**. Administrators can use the sample
controls on `/admin/access`; local CLI users can run:
```bash
artifacty samples install
artifacty samples remove
```
Installation is idempotent within the installing account (or local CLI scope).
Reinstalling restores archived samples without overwriting edits. Removal
archives managed samples and preserves their versions. It does not delete other
artifacts with similar names or tags. In private mode, share the installed
manuals with the intended users or teams from each artifact's Sharing page.
## Security Model
- The HTTP server binds to `127.0.0.1` by default.
- If `ARTIFACTY_API_TOKEN` is set, HTTP API routes require `Authorization: Bearer <token>` or `x-artifacty-token`; scripts should prefer headers over `?token=...` URLs.
- When users exist, personal API tokens issued from `/account` also authenticate HTTP API and MCP requests. Created artifacts record the token owner's email as `publisherId`, and audit logs record the same identity as `actor`.
- API token checks use timing-safe digest comparison.
- Personal API tokens support `read`, `write`, and `admin` scopes. The default is `read`+`write`. Select scopes when creating a token at `/account`. Only administrator tokens can receive `admin`. Each `/api/*` route requires the matching token scope. The shared `ARTIFACTY_API_TOKEN` and browser sessions have full scopes.
If a scope check fails, the server returns `403` with `code: "scope_denied"`. It also writes a rate-limited `token-scope-denied` audit row. For HTTP MCP or bridge tokens without `write`, `tools/list` omits tools that change data. Calls to those tools return `structuredContent.code: "scope_denied"`. Trusted local stdio does not enforce token scopes; it still applies the resolved user’s artifact permissions.
- Once any user account exists, artifacts use `visibility` (`public`, `team`, or `private`, default `team`) and `ownerUserId`. In public server mode, `public` allows anonymous read-only access; `team` requires authentication; `private` permits only the owner or administrator. Writes and owner-management operations remain permission-checked. In private mode, explicit sharing controls access. Restricted reads return 404 to avoid disclosing existence. The no-account single-user mode remains a separate local behavior. Change visibility or ownership through `POST /api/artifacts/:id/visibility`, `POST /api/artifacts/:id/owner`, `artifacty visibility <id> private|team|public`, or `artifacty_set_visibility`.
- HTTP and MCP-over-HTTP requests are rate limited per `(token or user or remote address, bucket)` in fixed one-minute windows: `write` (mutating routes, default 120/min, `ARTIFACTY_RATE_WRITE_PER_MIN`), `auth` (`/login`, default 10/min per address, `ARTIFACTY_RATE_AUTH_PER_MIN`), and `search` (`GET /api/artifacts?q=`, default 300/min, `ARTIFACTY_RATE_SEARCH_PER_MIN`). Rate limiting is disabled on a loopback bind unless `ARTIFACTY_RATE_LIMIT=always`, and always disabled with `ARTIFACTY_RATE_LIMIT=off`. Exceeding a limit returns `429` with a `Retry-After` header, `code: "rate_limited"`, and a rate-limited `rate-limited` audit row.
- To bind outside localhost, set `ARTIFACTY_SHARE_MODE=lan` or `team` and also set `ARTIFACTY_API_TOKEN`.
- Non-local sharing is intended for trusted LAN or VPN sessions. Prefer a specific interface IP over `0.0.0.0`, keep React rendering disabled, and see [docs/network-sharing.md](docs/network-sharing.md).
- Non-local binding prints a startup warning because Artifacty does not terminate TLS.
- Before storing artifact content, Artifacty scans it for common API keys and private keys. Use `--allow-secrets` or `ARTIFACTY_ALLOW_SECRETS=true` only for intentional exceptions.
- Creates, updates, reads, imports, archives, restores, no-op browser edits, and admin version repair/delete actions write audit events to SQLite. Legacy artifacts without a stored publisher are best-effort backfilled from their first `create` or `import` audit actor.
- CodeMirror editor/viewer and renderer assets are served from local npm dependencies through a package allowlist, not from a public CDN. JavaScript asset routes answer `Origin: null` requests with `Access-Control-Allow-Origin: null` so sandboxed renderer iframes can import local ESM without `allow-same-origin`.
- Mutating HTTP routes reject non-local browser origins.
- HTML artifacts render in a sandboxed iframe.
- SVG artifacts render in a scriptless sandboxed iframe and are sanitized for `<script>`, `on*` attributes, and `javascript:` links in the viewer. The raw source remains unchanged.
- Mermaid artifacts render with the vendored local Mermaid package in a sandboxed iframe without `allow-same-origin`.
- React artifacts are source-only by default. Set `ARTIFACTY_ENABLE_REACT_RENDERER=true` to execute them in a sandboxed frame with a frame-scoped CSP that permits JSX transformation.
- SARIF artifacts render a bounded findings summary and keep the full formatted JSON behind a raw-source details panel. The viewer adds client-side level filter chips (error/warning/note), a rule id text filter, and sort-by-level/rule/location over the rendered set, all as progressive enhancement (the server output is already correct without JS).
- CSV artifacts render as an escaped table with size limits. `/raw` preserves the original text. The viewer adds client-side numeric-aware column sort (click a header) and a per-column contains filter, with a visible row count.
- `GET /artifacts/:id/export?format=csv&sort=<col>&dir=asc|desc&filter=<col>:<text>[,...]` and `GET /artifacts/:id/export?format=sarif&level=error,warning&rule=<text>` re-parse the stored original (never `/raw` itself), apply the filter/sort, and stream a fresh file with `Content-Disposition: attachment`, capped at the max artifact byte size. Invalid parameters return 400 with `code: "invalid_export"`.
- Image and video artifacts store base64 media inline, render safe previews, and decode bytes through `/raw`.
- Markdown artifacts render fenced code blocks with CodeMirror read-only syntax highlighting client-side (the server output stays plain escaped HTML, so no-JS contexts still work), render ```mermaid``` fences through the same sandboxed Mermaid iframe as whole-document Mermaid artifacts (one lazily created iframe per diagram, capped by `ARTIFACTY_MAX_INLINE_DIAGRAMS`, default 20; extra diagrams stay as escaped code), render task lists as disabled checkboxes, and wrap tables in a horizontally scrolling container. Inline HTML in Markdown is always escaped.
- Notebook (`.ipynb`) artifacts store the original notebook JSON unchanged. The viewer renders cells in order (Markdown cells through the same embedded Markdown pipeline, code cells as highlighted escaped source with their execution count), with outputs limited to `text/plain`, `text/markdown`, `image/png`, `image/jpeg`, `image/svg+xml` (scriptless sandboxed iframe), and `text/html` (sandboxed iframe); other output MIME types show a placeholder. Outputs over 2 MB are replaced with a truncation notice. Rendering is limited to the first 500 cells.
- Treat artifact content as untrusted. Use the raw view when handing content back to an agent.
- npm releases are published with GitHub Actions OIDC Trusted Publishing after lint, test, and smoke checks pass.
See [SECURITY.md](SECURITY.md), [docs/threat-model.md](docs/threat-model.md), and [docs/release-checklist.md](docs/release-checklist.md) before publishing or running a shared instance.
## Environment Variables
The table lists every `ARTIFACTY_*` variable that Artifacty reads. `node src/cli.js help` prints the same list.
| Variable | Purpose | Default |
| --- | --- | --- |
| `ARTIFACTY_HOME` | Storage directory | `~/.artifacty` |
| `ARTIFACTY_BACKUP_ON_UPDATE` | Snapshot existing stores before application-version changes; schema-migration snapshots are always required | `false` |
| `ARTIFACTY_UPGRADE_BACKUP_KEEP` | Automatic upgrade snapshots to retain; integer from 1 to 1000 | `3` |
| `ARTIFACTY_URL` | Public URL override; otherwise CLI/MCP read the last running server URL | — |
| `ARTIFACTY_HOST` | Bind host for the HTTP server | `127.0.0.1` |
| `ARTIFACTY_PORT` | Bind port for the HTTP server | `8787` |
| `ARTIFACTY_MCP_URL` | Central MCP HTTP endpoint used by bridge mode | — |
| `ARTIFACTY_MCP_MODE` | `local` or `bridge`; `bridge` forwards stdio MCP to `ARTIFACTY_MCP_URL` | `local` |
| `ARTIFACTY_MCP_HTTP` | Set `true` to also expose MCP over HTTP on the running server | `false` |
| `ARTIFACTY_MCP_TIMEOUT_MS` | Bridge-mode MCP HTTP request timeout | `30000` |
| `ARTIFACTY_API_TOKEN` | Shared token required for HTTP API and LAN/team sharing | — |
| `ARTIFACTY_LOCALE` | Initial UI default (`en` or `ko`) before administrator language settings are saved | `en` |
| `ARTIFACTY_EMBEDDINGS_PROVIDER` | `local`, `command`, `openai-compatible`, or `disabled`; when unset, command → URL → bundled local model | automatic |
| `ARTIFACTY_EMBEDDINGS_LOCAL_PATH` | Custom ONNX model directory containing `embedding-model.json` | bundled model |
| `ARTIFACTY_EMBEDDINGS_URL` | Base URL of an external OpenAI-compatible embeddings API | — |
| `ARTIFACTY_EMBEDDINGS_MODEL` | Model name for the external API or command provider | provider default |
| `ARTIFACTY_EMBEDDINGS_API_KEY` | API key for the openai-compatible provider; never logged or stored | — |
| `ARTIFACTY_EMBEDDINGS_COMMAND` | Local command that reads JSON lines on stdin and writes vectors on stdout | — |
| `ARTIFACTY_EMBEDDINGS_MAX_CHARS` | Max content characters embedded per artifact | `8000` |
| `ARTIFACTY_EMBEDDINGS_TIMEOUT_MS` | Timeout for the local embeddings command | `30000` |
| `ARTIFACTY_EMBEDDINGS_MAX_CANDIDATES` | Max embedding rows scored per semantic/hybrid search query | `20000` |
| `ARTIFACTY_EMBEDDINGS_SYNC` | Set `true` to index embeddings synchronously instead of in the background (used by tests) | `false` |
| `ARTIFACTY_SHARE_MODE` | `lan` or `team`, required before binding outside localhost | — |
| `ARTIFACTY_TEAM_WRITE` | Set `owner` to restrict writes on `team`-visibility artifacts to the owner or an admin | — |
| `ARTIFACTY_ALLOW_SECRETS` | Set `true` only to intentionally store content that matches a detected secret pattern | `false` |
| `ARTIFACTY_ENABLE_REACT_RENDERER` | Set `true` to execute React artifacts in a sandboxed frame instead of source-only | `false` |
| `ARTIFACTY_RETENTION_INTERVAL_MS` | Background retention sweep interval | `3600000` (1 hour) |
| `ARTIFACTY_RETENTION_ALLOW_PURGE` | Set `true` to allow retention sweeps to hard-delete archived artifacts | `false` |
| `ARTIFACTY_WEBHOOK_TIMEOUT_MS` | Per-attempt webhook delivery timeout | `10000` |
| `ARTIFACTY_WEBHOOK_ALLOW_PRIVATE` | Set `true` to allow webhook URLs that resolve to private/loopback addresses | `false` |
| `ARTIFACTY_EVENT_POLL_MS` | SSE poll interval for new events | `1000` |
| `ARTIFACTY_EVENT_HISTORY` | Max in-memory event history retained for replay | `10000` |
| `ARTIFACTY_SSE_MAX_CLIENTS` | Max concurrent SSE connections | `64` |
| `ARTIFACTY_MAX_WAITS` | Max concurrent `artifacty_wait` MCP long-polls | `64` |
| `ARTIFACTY_MAX_DIFF_ENTRIES` | Max diff entries computed per `artifacty diff` | `5000` |
| `ARTIFACTY_MAX_INLINE_DIAGRAMS` | Max inline Mermaid diagrams rendered per Markdown artifact | `20` |
| `ARTIFACTY_MAX_COMMENTS_PER_ARTIFACT` | Max comments retained per artifact | `2000` |
| `ARTIFACTY_MAX_SAVED_VIEWS_PER_USER` | Max saved views retained per user | `100` |
| `ARTIFACTY_RATE_LIMIT` | `always` or `off`; overrides the default (disabled on loopback, enabled otherwise) | — |
| `ARTIFACTY_RATE_WRITE_PER_MIN` | Rate limit for mutating routes | `120`/min |
| `ARTIFACTY_RATE_AUTH_PER_MIN` | Rate limit for `/login` per address | `10`/min |
| `ARTIFACTY_RATE_SEARCH_PER_MIN` | Rate limit for `GET /api/artifacts?q=` searches | `300`/min |
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues