Artifacty — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Artifacty (Agent Skill) and scored it 96/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 1 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
English | 한국어
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.
Artifacty overview showing multiple AI agents sharing artifacts through a local exchange
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.
English dashboard with artifacts from Claude, Codex, Gemini, and Cursor
View diagrams in the browser. Render Mermaid source as a diagram alongside version history and artifact details.
English artifact viewer rendering a Mermaid diagram of an agent workflow
Review changes between versions. Compare an artifact created by one agent and updated by another. Added and removed lines appear together.
English version comparison showing additions and removals in a release checklist
Follow the browser user guide for step-by-step instructions and checks.
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.
Artifacty requires Node.js 22.12.0 or newer.
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:
npm install -g artifacty
artifacty --helpRun it without a global install:
npx artifacty@latest serve --foregroundStart the local dashboard in the background:
artifacty serveOpen 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:
artifacty status
artifacty stopartifacty 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:
artifacty serve --foreground
npm startTo protect HTTP API and browser write routes, generate an API token at startup:
artifacty serve --generate-token
artifacty serve --host 0.0.0.0 --share-mode lan --generate-token
artifacty serve --foreground --generate-tokenBackground 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:
artifacty token
artifacty start --api-token "$(artifacty token --raw)"Install MCP configuration for local agents:
artifacty install claude
artifacty install codex
artifacty install gemini
artifacty install copilot
artifacty install cursor
artifacty install all
artifacty checkChoose 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:
ARTIFACTY_BOOTSTRAP_TOKEN="$(artifacty token --raw)"
artifacty serve --host 10.0.0.50 --share-mode team --api-token "$ARTIFACTY_BOOTSTRAP_TOKEN" --mcp-http --foregroundOpen 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:
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.
email,name,role
[email protected],User,user
[email protected],Admin Two,adminartifacty users import --file users.csvRun diagnostics for the local runtime, store, server, service definitions, and MCP discovery:
artifacty doctor
artifacty doctor --skip-mcpUse artifacty install codex --timeout 30000 or artifacty install gemini --timeout 30000 to tune supported MCP client timeouts.
See docs/integrations.md for Claude Code, Codex, Gemini CLI, GitHub Copilot in VS Code, and Cursor setup.
On any supported CLI platform, check for a release without changing the installation or store:
artifacty update --checkAdministrators 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:
artifacty updateartifacty 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:
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 for prerequisites and limits.
Create an artifact in the browser:
http://127.0.0.1:8787/newFor local development from a checkout:
npm install
npm test
npm startRun the production-readiness check:
npm run release:checkReplace 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:
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:
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.
One agent publishes a handoff artifact. Another agent finds it, reads the context, and appends the next version.
Codex publishes the handoff:
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.
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:
artifacty list
artifacty list --query review --limit 20 --offset 20Run the MCP server:
artifacty-mcp
ARTIFACTY_MCP_MODE=bridge ARTIFACTY_MCP_URL=http://10.0.0.50:8787/mcp ARTIFACTY_API_TOKEN=... artifacty-mcpMCP 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:
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-runIf 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.
By default, Artifacty stores files under ~/.artifacty.
ARTIFACTY_HOME=/path/to/shared/store artifacty serveArtifacty 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:
artifacty index rebuild
artifacty integrityBefore 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 for verification, corrupt-store recovery, and interrupted-restore procedures.
?mode=keyword|semantic|hybrid on GET /api/artifacts, the dashboard, artifacty list --mode, and the MCP artifacty_list tool add optional natural-language search on top of FTS5, without a bundled model or a required dependency:
keyword is the existing FTS5/metadata path.semantic embeds the query and ranks artifacts by cosine similarity over stored vectors.hybrid (the default once a provider is configured and q/query is set) merges keyword and semantic rankings with reciprocal rank fusion.If no embedding provider is configured, semantic/hybrid requests fall back to keyword and the response's search.fallback is true. Configure one provider through the environment:
# openai-compatible: POSTs { model, input } to <url>/embeddings
export ARTIFACTY_EMBEDDINGS_URL=https://api.openai.com/v1
export ARTIFACTY_EMBEDDINGS_MODEL=text-embedding-3-small
export ARTIFACTY_EMBEDDINGS_API_KEY=sk-...
# or: command, a local executable reading/writing JSON lines on stdin/stdout
# (wire in Ollama or any local model without an Artifacty dependency)
export ARTIFACTY_EMBEDDINGS_COMMAND="python3 embed.py"Artifacty reads the API key only from the environment. It does not log the key, return it in errors, or save it to the store. artifacty doctor reports the provider and model with the key redacted. After a create or update, Artifacty generates embeddings in the background. To generate or refresh embeddings for existing artifacts in batches of 16, run:
artifacty index rebuild --embeddingsUse typed, directional relations to connect a handoff, its review, and follow-up work:
derived-from, supersedes, reviews, references, part-of.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 }.missing: true instead of being omitted.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>"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.
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:
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.parentId on a new comment must point to a root comment (one with no parentId of its own).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.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.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 approvedartifacty 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.
artifacty diff release-handoff-abc12345
artifacty diff release-handoff-abc12345 --from 1 --to 3 --jsonBy 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.
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-purgeThe retention screen groups artifact archive/purge settings, history limits, and protected tags. Review the preview before running cleanup.
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".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.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.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>"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:
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:
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:
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 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.
Start a protected server with a reusable shell token:
export ARTIFACTY_API_TOKEN="$(artifacty token --raw)"
artifacty serve --api-token "$ARTIFACTY_API_TOKEN"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:
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:
curl -s "http://127.0.0.1:8787/api/artifacts?q=handoff&limit=20&offset=0" \
-H "x-artifacty-token: $ARTIFACTY_API_TOKEN"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):
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:
{ "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.
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. Back up secrets/smtp.key separately: neither JSON backups nor upgrade snapshots include it.
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.
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 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 and Korean.
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:
schemaVersion: 1, artifactType, publisherId, and archivedAt.version-repair or version-delete audit events.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.html, markdown, text, json, code, svg, mermaid, react, sarif, csv, image, video, and notebook.html from HTML documents or fragments when no explicit format is supplied.sourceAgent is canonicalized before storage. Aliases such as claude-code, Claude Code, github-copilot, and gemini-cli are stored as claude, copilot, and gemini; legacy unknown rows are backfilled only when version metadata, audit data, or source-agent tags provide a known agent.diagram, component, snippet, analysis-report, table, and asset artifact types.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:
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.
Owners and administrators can create a read-only link from an artifact's Sharing page:
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.
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:
artifacty samples install
artifacty samples removeInstallation 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.
127.0.0.1 by default.ARTIFACTY_API_TOKEN is set, HTTP API routes require Authorization: Bearer <token> or x-artifacty-token; scripts should prefer headers over ?token=... URLs./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.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.
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.(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.ARTIFACTY_SHARE_MODE=lan or team and also set ARTIFACTY_API_TOKEN.0.0.0.0, keep React rendering disabled, and see docs/network-sharing.md.--allow-secrets or ARTIFACTY_ALLOW_SECRETS=true only for intentional exceptions.create or import audit actor.Origin: null requests with Access-Control-Allow-Origin: null so sandboxed renderer iframes can import local ESM without allow-same-origin.<script>, on* attributes, and javascript: links in the viewer. The raw source remains unchanged.allow-same-origin.ARTIFACTY_ENABLE_REACT_RENDERER=true to execute them in a sandboxed frame with a frame-scoped CSP that permits JSX transformation./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"./raw.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..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.See SECURITY.md, docs/threat-model.md, and docs/release-checklist.md before publishing or running a shared instance.
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_URL | openai-compatible embeddings endpoint base URL; enables semantic/hybrid search | — |
ARTIFACTY_EMBEDDINGS_MODEL | Embeddings model name | 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 |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.