关于 ArtifactSmith
ArtifactSmith 是面向自行运行 AI Agent 用户的开源制品服务。Agent 可创建、编辑、导出和分享带版本的网页与文档;制品默认私有,分享链接可随时撤销。
主要功能
- 01创建和编辑 Agent 制品
- 02导出 HTML、Markdown、PDF、DOCX 和 XLSX
- 03文档版本管理与私有预览
- 04分享指定版本并撤销访问
- 05发布现有 Markdown 或 HTML
适用场景
- 01将 Agent 研究整理为格式化报告
- 02把内容导出为 PDF、Word 或 Excel 文件
- 03分享前预览私有制品
- 04撤销对已分享版本的访问
MCP 相关
Agent 通过 MCP API 创建、编辑、发布、分享和管理制品。自托管实例的接口需要 bearer token;托管服务支持 OAuth。
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://artifactsmith.neuralami.ai/mcpclaude mcp add --transport http vrijsinghani-artifactsmith https://artifactsmith.neuralami.ai/mcp{"mcpServers":{"vrijsinghani-artifactsmith":{"type":"http","url":"https://artifactsmith.neuralami.ai/mcp"}}}在 Cursor 中打开{"servers":{"vrijsinghani-artifactsmith":{"type":"http","url":"https://artifactsmith.neuralami.ai/mcp"}}}在 VS Code 中打开{"mcpServers":{"vrijsinghani-artifactsmith":{"type":"http","url":"https://artifactsmith.neuralami.ai/mcp"}}}{"mcpServers":{"vrijsinghani-artifactsmith":{"serverUrl":"https://artifactsmith.neuralami.ai/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
https://artifactsmith.neuralami.ai/mcp需要授权工具
详细介绍
ArtifactSmith
ArtifactSmith 是一个面向 AI Agent 的开源制品服务。

示例
基于从公开来源(Ready.gov 和美国劳工统计局)托管的副本构建。会议记录为虚构内容。无需注册即可打开。
- 网页:飓风防灾清单,内容依据 Ready.gov 指引。
- 图表报告:美国就业报告图表,涵盖 2024 年 1 月至 2026 年 9 月的失业率和工资就业人数,数据来自 BLS。
- PDF:美国劳动力市场简报,一页,2026 年 9 月,数据来自 BLS。
- Word 文档:启动会议记录,内容关于一个虚构的图书馆网站项目。下载为 .docx。
- Excel 工作簿:2024 至 2026 年失业率和工资就业人数,包含按月数据和来源工作表。下载为 .xlsx。
Agent 可调用它将工作成果转化为文档:网页、PDF、Word 文件、电子表格和 Markdown。每个制品都有版本记录,在分享前始终保持私密;共享链接也可以随时撤销。
它面向自行运行 Agent、希望在自己的服务器上获得类似 Muse 制品的人。
安装前先试用:https://artifactsmith.neuralami.ai/try。我运行了一个副本,你可以将 MCP 客户端指向它。Claude.ai、Claude Desktop、Claude Code 和 Cursor 可使用你的电子邮件通过 OAuth 登录;粘贴令牌也可以。它最多支持 20 次构建,并运行在我的服务器上。
功能
ArtifactSmith 为 Agent 提供创建、编辑、导出(PDF、Word、Excel、Markdown)、分享和撤销文档的工具。它适用于任何兼容 OpenAI 的模型端点。其灵感来自 Meta 的 Muse 制品。

要求:Docker Engine 和 Compose 插件。构建页面需要模型密钥(兼容 OpenAI 的 API 或本地端点);发布现成的 Markdown 或 HTML 则无需密钥。
快速开始
Cline 请参阅 llms-install.md。
cp .env.example .env
# Set OPENAI_API_KEY (or AM_LLM_KEY). Change AM_LLM_BASE / AM_DEFAULT_MODEL
# only if you are not using the default OpenAI host and model.
# Object-store keys: leave them empty and run ./scripts/ensure-local-env.sh,
# or paste your own AM_STORE_KEY and AM_STORE_SECRET.
./scripts/ensure-local-env.sh
docker compose up -d --build
# Create a token (prints the raw value once; only its hash is stored).
# --workspace is a label that scopes every artifact the token can see
# (e.g. alpha, team-a). Tokens cannot cross workspaces.
docker compose exec server artifactsmith token add --name agent --workspace alpha
publish 会存储你已编写的页面,不会调用模型,因此密钥为空时也可以执行下一步。粘贴上方打印的令牌,然后运行此命令。它会打印一个共享 URL。
export AM_TOKEN='paste-the-token'
docker compose exec -T -e AM_TOKEN server python - <<'PY'
import asyncio
import json
import os
from datetime import timedelta
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
URL = "http://127.0.0.1:8780/mcp"
PAGE = """# Pilot store brief
The pilot store code is HARBOR-17. It is the identifier used on inventory, support, and rollout reports.
"""
def parse(result):
if result.structuredContent is not None:
return result.structuredContent
return json.loads(result.content[0].text)
async def main():
headers = {"Authorization": "Bearer " + os.environ["AM_TOKEN"]}
async with streamablehttp_client(URL, headers=headers) as (read, write, _session):
async with ClientSession(read, write) as session:
await session.initialize()
created = parse(
await session.call_tool(
"publish",
{"display_name": "Pilot store brief", "markdown": PAGE},
read_timeout_seconds=timedelta(seconds=120),
)
)
done = parse(
await session.call_tool(
"status",
{"job_id": created["job_id"], "wait": 90},
read_timeout_seconds=timedelta(seconds=120),
)
)
if done.get("status") != "done":
raise SystemExit(json.dumps(done))
shared = parse(
await session.call_tool(
"share",
{"artifact_id": created["artifact_id"]},
read_timeout_seconds=timedelta(seconds=120),
)
)
print(shared["url"])
asyncio.run(main())
PY
服务会从 .env 读取 AM_LLM_BASE、AM_LLM_KEY 或 OPENAI_API_KEY,以及 AM_DEFAULT_MODEL。默认基础 URL 为 https://api.openai.com。基础 URL 末尾可以带 /v1;客户端会自行附加 /v1/chat/completions。create 需要密钥或本地兼容 OpenAI 的端点。密钥为空时,create 失败会提示 OPENAI_API_KEY / AM_LLM_KEY 为空。再次运行 docker compose up -d 以使更改生效。
主机端口绑定到 127.0.0.1:
http://127.0.0.1:8780/mcp是 MCP API(需要 bearer token)http://127.0.0.1:8780/app/是“我的页面”(粘贴相同的令牌;浏览器会获取会话 cookie)http://127.0.0.1:8781/是无 cookie 的预览和分享源站(/p/…、/s/…)
使用已发布的镜像
每次发布都会提供适用于 linux/amd64 的 ghcr.io/vrijsinghani/artifactsmith:0.1.0。默认方式仍然是从源代码构建(使用上述 Compose 步骤)。
连接客户端
Claude.ai:选择 Customize → Connectors → + Add → Add custom connector。粘贴 https://artifactsmith.neuralami.ai/mcp,选择 Connect,然后使用邮箱登录。之后,该连接器也可在 Claude 桌面应用和手机应用中使用。免费方案允许添加一个自定义连接器。在 Team 和 Enterprise 方案中,需由所有者先添加。
github.com/vrijsinghani/Artifactsmith 是供你自行运行的副本。在托管副本上,Claude Desktop、Claude Code 和 Cursor 通过 OAuth 在 https://artifactsmith.neuralami.ai/mcp 登录。在你自己的副本上,它们使用令牌。这台机器上的 MCP 端点是 http://127.0.0.1:8780/mcp。将 artifactsmith token add 输出的令牌作为 Authorization: Bearer YOUR_TOKEN 发送。标头值以 Bearer 开头。
ChatGPT Free、Go 和 Plus 无法添加自定义 MCP 服务。Pro 可以添加一个,但仅支持读取和获取,因此无法创建页面。ChatGPT Business、Enterprise 或 Edu 的管理员可以在网页端添加;它通过 OAuth 登录。
ChatGPT 用户也可以改用 OpenAI 的 Codex CLI:运行 codex mcp add artifactsmith --url https://artifactsmith.neuralami.ai/mcp,然后运行 codex mcp login artifactsmith,并使用邮箱登录。
Claude Desktop 将配置保存在 claude_desktop_config.json(Settings → Developer → Edit Config)中。此代码片段会运行 npx 和 mcp-remote,这需要 Node.js。保存后重启 Claude Desktop。
{
"mcpServers": {
"artifactsmith": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://127.0.0.1:8780/mcp", "--header", "Authorization:${AUTH_HEADER}"],
"env": { "AUTH_HEADER": "Bearer YOUR_TOKEN" }
}
}
}
Claude Code 将配置保存在 .mcp.json 中,或者运行:
claude mcp add --transport http artifactsmith http://127.0.0.1:8780/mcp --header "Authorization: Bearer YOUR_TOKEN"
{
"mcpServers": {
"artifactsmith": {
"type": "http",
"url": "http://127.0.0.1:8780/mcp",
"headers": { "Authorization": "Bearer YOUR_TOKEN" }
}
}
}
Cursor 将配置保存在 ~/.cursor/mcp.json 中,或者保存在项目中的 .cursor/mcp.json。
{
"mcpServers": {
"artifactsmith": {
"url": "http://127.0.0.1:8780/mcp",
"headers": { "Authorization": "Bearer YOUR_TOKEN" }
}
}
}
提示词示例:创建一份名为 Pilot store brief 的单页简报。将以下内容作为 source_content 传入:试点门店代码为 HARBOR-17。它是在库存、支持和上线报告中使用的标识符。
artifactsmith stdio 可以在标准输入和标准输出上列出工具,但不会监听。它无法使用对象存储或模型,因此无法创建或发布页面。
在网络中或代理后提供服务
Compose 会在 AM_BIND_ADDRESS 上发布 API(8780)和预览/分享服务(8781)(默认值为 127.0.0.1)。卡片和链接使用 AM_API_URL、AM_PREVIEW_URL 和 AM_SHARE_URL(空的 AM_SHARE_URL 会回退到 AM_PREVIEW_URL)。不使用 TLS 直接公开端口,会导致承载令牌和制品内容的流量以明文传输。
局域网访问
绑定到所有网络接口(或特定网卡 IP),并将公开 URL 变量指向客户端要访问的地址:
# .env (192.0.2.10 is documentation-range; substitute your LAN IP)
AM_BIND_ADDRESS=0.0.0.0
AM_API_URL=http://192.0.2.10:8780
AM_PREVIEW_URL=http://192.0.2.10:8781
AM_SHARE_URL=http://192.0.2.10:8781
AM_ALLOWED_HOSTS=192.0.2.10:8780,127.0.0.1:8780,localhost:8780
然后运行 docker compose up -d --build。客户端访问 http://192.0.2.10:8780/mcp,预览/分享链接使用 192.0.2.10,而不是 127.0.0.1。基于浏览器的 MCP 客户端还需要设置 AM_ALLOWED_ORIGINS,使其指向页面来源。
服务器返回分享和预览 URL 时,会根据 AM_SHARE_URL / AM_PREVIEW_URL 生成这些 URL。切换到局域网服务之前复制的链接仍会使用旧的基础主机;更改这些设置后,请再次调用 share(或从 inspect / status 复制 URL)。
使用 TLS 的反向代理
将主机绑定地址保留为环回地址,并在 nginx 或 Caddy 上终止 TLS。将公开 URL 和允许列表设置为外部主机名:
# .env
AM_BIND_ADDRESS=127.0.0.1
AM_API_URL=https://artifacts.example.com
AM_PREVIEW_URL=https://preview.artifacts.example.com
AM_SHARE_URL=https://preview.artifacts.example.com
AM_ALLOWED_HOSTS=artifacts.example.com
AM_ALLOWED_ORIGINS=https://artifacts.example.com
最简 Caddy 示例(API 使用 443 端口,预览使用另一个主机名):
artifacts.example.com {
reverse_proxy 127.0.0.1:8780
}
preview.artifacts.example.com {
reverse_proxy 127.0.0.1:8781
}
API 主机的最简 nginx 片段:
server {
listen 443 ssl;
server_name artifacts.example.com;
# ssl_certificate / ssl_certificate_key omitted
location / {
proxy_pass http://127.0.0.1:8780;
proxy_set_header Host $host;
proxy_set_header Authorization $http_authorization;
# status wait can be up to 90s; nginx defaults cut at 60s.
proxy_read_timeout 120s;
proxy_send_timeout 120s;
}
}
当 AM_ALLOWED_HOSTS 仅列出公开主机名时,本地执行 curl http://127.0.0.1:8780/mcp 会收到 HTTP 421(DNS 重绑定防护)。请将客户端指向代理主机名。基于浏览器的 MCP 客户端会发送 Origin 标头;请将 AM_ALLOWED_ORIGINS 设置为该来源,否则请求会被拒绝。
位于另一台机器上的 MCP 客户端
将客户端指向 {AM_API_URL}/mcp,并将令牌作为 Authorization: Bearer <token> 发送(该令牌由 artifactsmith token add 输出,且只显示一次)。标头值以 Bearer 开头。artifactsmith stdio 可以在标准输入和标准输出上列出工具,但不会监听。它无法使用对象存储或模型,因此无法创建或发布页面。示例:
URL: http://192.0.2.10:8780/mcp
Header: Authorization: Bearer asmb_…
工作原理
Agent 通过 MCP 与 ArtifactSmith 通信。它们将用户请求作为 verbatim_request 传递,并将任何研究内容作为 source_content 或 source_files 传递。create 会启动私有构建,不会发布分享链接。想要样式化的页面?将 Markdown 传给 publish,它会自动应用样式(传入 markdown 且不传 html 时可省略 format;默认使用站点样式,在打开页面时应用)。你仍然可以传入 format=markdown。或者调用 create 并传入 source_content。publish 中的原始 HTML 仅用于你自行设计的页面,并且会按原样显示。
服务会调用一个兼容 OpenAI 的端点(检查失败时最多尝试两次)。模型负责编写内容。固定渲染器会将内容转换为 HTML、Markdown、PDF、DOCX 或 XLSX。publish 会跳过模型,执行相同的检查并使用相同的渲染器。调用 status(或等待最多 90 秒的 wait)即可获取私有预览。
share 会为某个确切版本创建公开链接。unshare 会使该链接返回 404。令牌仅属于一个工作区,并携带一组权限。
文档可以引用公开的 http(s) 来源,并将其显示为可点击链接。服务会移除脚本、拒绝指向私有链接的主机和疑似机密内容,并将图片、CSS、字体和 iframe 保持为自包含内容,确保下载的文件可离线打开且不会向外部发送请求。存在大小限制。此流程不会向任何地方发送使用数据。
输出格式
| 格式 | create(..., format=) | 主要文件 | 渲染器 |
|---|---|---|---|
| HTML | html(默认) | index.html | 清理,然后存储 |
| Markdown | markdown | document.md | UTF-8 文本 |
pdf | document.pdf | WeasyPrint(HTML/CSS 转 PDF) | |
| DOCX | docx | document.docx | python-docx |
| XLSX | xlsx | document.xlsx | openpyxl |
HTML 使用视觉样式(默认采用站点样式),并存储完整页面。其他格式会让模型生成 Markdown,再由渲染器进行转换。publish 接受已完成的 HTML 或 Markdown,并使用相同的渲染器。PDF、DOCX 和 XLSX 也会存储 content.md,以便后续编辑时有文本作为基础。
PDF 通过 WeasyPrint 生成,它需要 Pango 和 Cairo。Docker 镜像不包含 Chromium。详情请参阅 docs/formats.md。
样式
create 和 edit 可为 HTML 指定可选的 style:house、bold、editorial、playful、terminal 或 swiss。默认值为 AM_DEFAULT_STYLE(通常是 house)。对于 Markdown、PDF、DOCX 和 XLSX,模型提示词不会采用该视觉样式。打开已发布的 Markdown 页面时,页面仍会以记录的样式显示。在 edit 中省略 style 可保留上次使用的样式。
create 还接受 mode:full(默认值 AM_BUILD_MODE)会让模型编写 HTML;fast 会让模型编写 Markdown,再由服务按该样式渲染。fast 仅适用于首次构建 HTML。编辑和其他格式仍走完整流程。AM_FAST_STYLES(默认为空)列出省略 mode 时采用 fast 的样式;显式指定的 mode 优先。如果源内容中包含完整的 HTML 文档,或者请求原样发布该 HTML,那么在省略 mode 时仍会采用 full。在“保持不变”旁提及 HTML 则不会。
house:简洁静谧的当代页面——白色、单一强调色,只在一处使用粗体。bold:深海军蓝到紫罗兰色的主视觉区、巨大的白色标题、饱和色卡片和标签。

editorial:杂志专题风格——米白色纸张、大号衬线标题、细分隔线和一处深红色强调。

playful:奶油色页面、糖果色圆角卡片、粗边框和错位阴影。

terminal:深色模式、等宽字体、霓虹绿和青色,各个版块呈现为仿终端窗口。

swiss:白色网格、巨大的黑色无衬线字体,仅在数字和分隔线上使用醒目的橙色。

MCP 工具
| 工具 | 权限 | 功能 |
|---|---|---|
create | create | 将私有构建加入队列。可选参数:format、style 和 mode。不会创建分享链接。 |
publish | publish | 存储 Markdown 以生成带样式的页面,或存储你自行设计的 HTML。不调用模型。 |
edit | edit | 基于最新的已完成版本创建新版本。若 base_version 已过时则拒绝操作。 |
status | read | 轮询,或等待(0 到 90 秒),直到任务完成、失败或需要输入。 |
list_artifacts | read | 列出此令牌工作区的目录。 |
inspect | read | 查看清单、历史记录和分享状态。可选参数 include_content 会返回该版本存储文本的内容,长度上限为发布字符限制。 |
export | export | 获取渲染文件的下载链接,有效期为 15 分钟。 |
share | share | 为某个确切版本创建公开链接。 |
unshare | share | 立即撤销公开链接。 |
revoke_previews | export | 使某个资源的私有 /p/ 预览链接失效(可选指定版本)。 |
delete | delete | 两步清除。首次调用会返回确认令牌。 |
create arguments
必填项:
verbatim_request:用户的原话。这就是全部范围。
至少提供 display_name 或 slug 之一(另一项会自动填充):
display_name:卡片和目录中显示的标题。设置了slug时可以不填;如果省略,默认使用slug。限制:200 个字符。示例:"Pilot store brief"。slug:工作区内唯一的 URL 键。设置了display_name时可以不填;如果省略,会根据标题生成(转换为小写、折叠重音符号,其他字符替换为连字符)。限制:2–63 个字符,仅限a-z、0-9和-,且必须以字母或数字开头。示例:"pilot-store-brief"。同一工作区中存在重复的slug时会被拒绝;请使用edit。
可选项:
kind:默认为web_static(此版本中唯一的类型)。format:html(默认)、markdown、pdf、docx或xlsx。style:house(默认)、bold、editorial、playful、terminal或swiss。HTML 构建会使用此样式。打开 Markdown 页面时,也会以此样式显示。PDF、DOCX 和 XLSX 不使用此样式。mode:full(默认)或fast。fast会进行首次 HTML 构建:输入 Markdown,输出带样式的 HTML。source_content/source_files:经调研的事实,总计 200 KB。构建器会将其视为数据。model、workspace、idempotency_key、capabilities。
可用示例(仅标题;slug 会变为 pilot-store-brief)。来源文本必须支持请求中要求的每一项事实(包括“为什么重要”):
{
"display_name": "Pilot store brief",
"verbatim_request": "One page that states the pilot store code and why it matters.",
"source_content": "The pilot store code is HARBOR-17. It matters because it is the single identifier used across inventory, support, and rollout reports for the pilot.",
"format": "html"
}
如果请求和来源中缺少所需事实,任务会以 needs_input 结束,且不会保存文件。服务器检查失败时,会再次调用模型,因此失败的构建所需报告时间约为正常构建的两倍。编辑会先请求对变更部分进行补丁。如果补丁无法应用,或未能通过相同的检查,则会在同一任务中重新构建完整文件。
publish 参数
想要将已有文本生成为带样式的页面?传入 Markdown,即可自动应用样式。传入 markdown 且不传入 html 时,可省略 format。你仍然可以传入 format=markdown。style 默认为 house,并在打开页面时应用。存储的文件仍为 Markdown。创建新产物时,如果同时传入 html,除非设置了 format,否则 html 将作为页面内容。原始 HTML 会按提供的内容原样显示,不应用 ArtifactSmith 样式。如果 HTML 几乎没有 CSS 或完全没有 CSS,结果中会包含 warning。对于 pdf、docx 或 xlsx,请传入 format。publish 不会调用模型。页面仍会经过与模型输出相同的大小限制、密钥扫描、私有链接检查、净化、渲染和最终检查。
新建产物:传入 display_name 或 slug,以及页面内容。
html:完整的 HTML 文档。当format为html时必填。markdown:完成的 Markdown。当format为markdown、pdf、docx或xlsx时必填。省略format且这是唯一的正文内容时,格式为 markdown。- 你也可以传入另一个字段。该字段会接受密钥和私有链接检查,但不会被渲染。
新建版本:传入 artifact_id 和 base_version(最新的已完成版本),以及新页面。对于 html 或 markdown 产物,如果省略 format,且传入 markdown 而未传入 html,则格式为 markdown;传入 html 而未传入 markdown,则格式为 html;两个字段都传入时,保留产物原有格式。对于 pdf、docx 或 xlsx 产物,省略 format 且新页面为 markdown 时,保留原有格式。传入 format 可选择其他受支持的格式。传入 display_name 可在此版本完成时重命名卡片。省略 display_name 且页面标题发生变化时(HTML <title> 或第一个 Markdown 标题),卡片标题也会随之更改。产物 ID 和 slug 保持不变。最新的分享页面会使用该名称作为 <title> 和 og:title。旧版本保留各自的格式。分享的 markdown 页面会以带样式的 HTML 打开;在该 URL 后添加 ?raw=1 或 document.md,即可下载存储的 Markdown。
summary 和 assumptions 是可选的卡片字段(每项最多 8000 个字符),并会像模型输出一样接受扫描。摘要或假设过长时,调用会被拒绝,并返回 metadata exceeds N characters,且不会存储任何内容。note 是可选的。Inspect 会将其显示在 Published a finished page. 旁边。过长的备注,或未通过密钥、私有链接或允许列表检查的备注,会在创建版本记录前被拒绝。对于 markdown,style 会更改打开的页面(默认为 house)。对于 HTML,会记录 style,但不会重新设置所提交页面的样式。PDF、DOCX 和 XLSX 不使用 HTML 样式表。
返回 artifact_id、version 和 job_id。调用 status,直到状态为 done 或 failed。被拒绝的页面状态为 failed,且 error 会指出未通过的检查。任务完成后,status 和 inspect 会包含 safety_changes,即对所提交页面进行的安全编辑列表。HTML 发布不会将纯 URL 转换为链接。publish 不会创建分享链接。它会计入每个令牌的构建配额,并需要 publish 权限。
export
权限:export。
参数:
artifact_id(必填):要下载的产物。version(可选):一个已完成的版本。省略时使用最新的已完成版本。
返回 download_url(有效期 15 分钟)、file、version、sha256、self_contained 和 expires_in("15m")。
{ "artifact_id": "art_example", "version": 1 }
share
权限:share。
参数:
artifact_id(必填):要发布的产物。version(可选):指定的已完成版本。省略时使用最新的已完成版本。ttl_days(可选):有效期天数。默认为AM_SHARE_TTL_DAYS。当AM_SHARE_TTL_DAYS为0时,ttl_days会被忽略,链接会一直有效,直到被撤销。否则,有效期最长为AM_SHARE_TTL_MAX_DAYS。
返回 state("shared")、url、version、expires_at、lifetime 和 reused。任何拥有该 URL 的人都可以打开该版本。
{ "artifact_id": "art_example" }
unshare
权限:share。
参数:
artifact_id(必填):要撤销共享的制品。version(可选):撤销一个版本。省略此参数或传入0,即可撤销所有版本。
返回 artifact_id、revoked_links(撤销的链接数量)和 state。当仍有公开链接有效时,state 为 "shared",并附带 url 和 follows("latest" 或 "pinned")。仅当没有剩余公开链接时,state 才为 "not_shared"。撤销一个固定版本的链接,不会影响跟随最新版本的链接。被撤销的 URL 会立即返回 404。
{ "artifact_id": "art_example" }
delete
权限:delete。
参数:
artifact_id(必填):要彻底删除的制品。confirm_token(首次调用时省略):首次响应中的令牌,有效期为 10 分钟。
首次调用不会删除任何内容。它会返回 step("confirm")、confirm_token、title、versions、expires_in("10m")和一条警告。第二次调用会彻底删除所有已存储的版本、共享链接和数据库行。它会返回 deleted(true)、artifact_id 和 purged_object_versions。
{ "artifact_id": "art_example" }
{ "artifact_id": "art_example", "confirm_token": "paste-the-token" }
配置
每项设置也有一个 NAME_FILE 变体,可从文件读取该值。
| 变量 | 默认值 | 用途 |
|---|---|---|
OPENAI_API_KEY / AM_LLM_KEY | empty | 配置的端点所需的大模型凭据。 |
AM_LLM_API | chat | chat(Chat Completions)或 responses。 |
AM_LLM_BASE | https://api.openai.com | OpenAI 兼容主机根地址。可带或不带结尾的 /v1。 |
AM_LLM_TEMPERATURE | unset | Chat Completions 温度。未设置时发送 0;设为 none 时省略此字段。 |
AM_DEFAULT_MODEL | gpt-4o-mini | 发送给大模型的模型名称。 |
AM_DEFAULT_STYLE | house | create 未指定 style 时使用的 HTML 视觉样式。 |
AM_BUILD_MODE | full | create 未指定 mode 时使用 full 或 fast。fast 仅适用于首次构建 HTML。 |
AM_FAST_STYLES | empty | 逗号分隔的样式(house、bold 等),当 create 未指定 mode 时,这些样式默认使用 fast。留空则所有样式都使用 AM_BUILD_MODE。显式指定的 mode 优先。如果提供的是已完成的 HTML 源码,或请求按原样发布该 HTML,则在未指定 mode 时仍使用 full。在“unchanged”旁提及 HTML 不适用此规则。其他格式和编辑仍使用 full。未知名称会导致启动失败。 |
AM_SHARE_TTL_DAYS | 30 | 0 表示有效期持续到撤销为止。 |
AM_SHARE_TTL_MAX_DAYS | 365 | 正数 TTL 的上限。 |
AM_SHARE_CREDIT | true | 在共享的 HTML 页面上显示不显眼的“Made with ArtifactSmith”链接。false 时隐藏。导出文件、预览和存储文件中均不包含此链接。 |
AM_STORE_ENDPOINT | (必需) | 兼容 S3 的对象存储。 |
AM_STORE_BUCKET | artifacts | 存储桶名称。 |
AM_STORE_KEY / AM_STORE_SECRET | (必需) | 对象存储凭据。 |
AM_BLOCK_PRIVATE_LINKS | true | 拒绝输出中的 localhost、RFC1918 和链路本地地址主机。 |
AM_ALLOWED_LINK_DOMAINS | empty | 如果设置,则所有剩余主机都必须匹配。 |
AM_MAX_OUTPUT_BYTES | 50 MiB | 渲染输出上限。 |
AM_RENDER_TIMEOUT | 120 | 单次渲染器调用的秒数。 |
AM_BUILD_TIMEOUT | 900 | 整个任务的秒数。 |
AM_EDIT_PATCH_TIMEOUT_S | 45 | 编辑补丁调用的秒数。超时后会回退到完整重写。 |
AM_MAX_BUILDS | 2 | 并发工作线程数。托管试用最多占用其中一个名额。 |
AM_BUILDS_PER_HOUR | 20 | 内部令牌的每小时配额。试用令牌使用 AM_TRIAL_BUILDS_PER_HOUR。 |
AM_TRIAL_ENABLED | false | 开放托管试用页面(/try,旧版为 /trial)并允许其执行构建。false 会立即关闭两者。 |
AM_TRIAL_EMAIL_VERIFY | true | 在显示令牌前发送一次性链接。false 会在提交时显示令牌,并将地址记录为未经验证。 |
AM_TRIAL_BUILD_LIMIT | 20 | 单个试用令牌的终身构建次数。 |
AM_TRIAL_FREE_NEEDS_INPUT | 5 | 每个托管令牌可免费处理的 needs_input 任务数,不消耗构建次数。超出后将消耗构建次数。 |
AM_TRIAL_BUILDS_PER_HOUR | 10 | 试用令牌的每小时上限。不影响 AM_BUILDS_PER_HOUR。 |
AM_TRIAL_DAILY_USD | 10 | 每个 UTC 日的全局试用支出上限。内部令牌不受限制。 |
AM_TRIAL_PRICE_IN / AM_TRIAL_PRICE_OUT | 0.10 / 0.50 | 每 1M 个输入/输出令牌的美元价格,用于计算预留额度。 |
AM_TRIAL_MODEL | anthropic/claude-haiku-5-5 | 所有试用构建使用的模型。忽略调用方提供的模型名称。 |
AM_TRIAL_MAX_OUTPUT_TOKENS | 16000 | 试用模型调用时发送的输出上限。 |
AM_TRIAL_SIGNUPS_PER_IP / AM_TRIAL_SIGNUP_WINDOW_S | 3 / 86400 | 每个 IPv4 地址或 IPv6 /48 网段在每个时段内的注册尝试次数。 |
AM_TRIAL_SIGNUPS_PER_DAY | 300 | 每个 UTC 日签发的注册数。达到上限后,/try 会提示今天不再签发托管令牌,并于 UTC 00:00 恢复。 |
AM_TRIAL_LINK_TTL_S | 1800 | 魔法链接的有效期,单位为秒。 |
AM_TRIAL_RETENTION_DAYS | 30 | 试用工作区在最后一次构建后经过此天数即删除。 |
AM_TRIAL_ABUSE_EMAIL | empty | 试用页面页脚中的 mailto 地址。留空则省略链接。 |
AM_SMTP_HOST / AM_SMTP_PORT / AM_SMTP_FROM | empty / 587 / empty | 魔法链接邮件。主机或发件人地址为空时将拒绝发送。 |
AM_SMTP_USER / AM_SMTP_PASSWORD | empty | SMTP 登录信息。密码可通过 AM_SMTP_PASSWORD_FILE 提供。 |
AM_SMTP_TLS | true | 发送魔法链接时启用 TLS。 |
AM_HOST | 127.0.0.1 | artifactsmith serve 的监听地址。容器内的 Compose/镜像会设置为 0.0.0.0。 |
AM_BIND_ADDRESS | 127.0.0.1 | compose.yaml 中端口 8780 和 8781 的主机发布绑定地址。 |
AM_API_PORT / AM_PREVIEW_PORT | 8780 / 8781 | 监听端口。 |
AM_API_URL / AM_PREVIEW_URL / AM_SHARE_URL | http://127.0.0.1:8780 / :8781 | 写入卡片和链接的 URL。AM_SHARE_URL 为空时使用 AM_PREVIEW_URL。API URL 为 https:// 时,My pages Cookie 会设置为 Secure。 |
AM_COOKIE_SECURE | 跟随 AM_API_URL | true 或 false 可强制设置 My pages Cookie 的 Secure 标志。使用本地 HTTP 时请勿设置。 |
AM_TRUSTED_PROXIES | empty | 逗号分隔的 IP 或 CIDR,可为 My pages 登录限额和试用注册限额设置 X-Real-IP 或 X-Forwarded-For。留空则忽略这些标头。 |
AM_LOGIN_LIMIT / AM_LOGIN_PREFIX_LIMIT / AM_LOGIN_WINDOW_S | 8 / 8 / 900 | 时间窗口(秒)内,每个 IPv4 地址或 IPv6 /64 网段以及每个哈希令牌前缀允许的失败登录次数。 |
AM_ALLOWED_HOSTS | 127.0.0.1:<api_port>,localhost:<api_port> | 用于 MCP DNS 重绑定防护的逗号分隔 Host 值(默认启用)。 |
AM_ALLOWED_ORIGINS | empty | 用于 MCP DNS 重绑定防护的逗号分隔 Origin 值。 |
AM_DATA_DIR / AM_SECRETS_DIR | /data / /secrets | SQLite 数据库和 HMAC 签名密钥。 |
复制 .env.example 作为本地文件。./scripts/ensure-local-env.sh 会填充空的 AM_STORE_KEY 和 AM_STORE_SECRET。存储镜像为 rustfs/rustfs:1.0.1(在 compose.yaml 中通过摘要固定)。 |
运行托管试用页面
设置 AM_TRIAL_ENABLED=true,并将 AM_API_URL 指向公开来源。若 AM_TRIAL_EMAIL_VERIFY 保持为 true,/try 会发送一次性链接(必须设置 AM_SMTP_HOST 和 AM_SMTP_FROM;如果其中任一项为空,注册会以失败关闭)。GET /trial 会重定向到 /try。保留 POST /trial 和 /trial/verify,以确保已打开的表单或已发送的链接仍然有效。Message-ID 域名使用 AM_SMTP_FROM 的域名。打开链接不会消耗它。“显示我的令牌”按钮会显示一次工作区令牌。设置 AM_TRIAL_EMAIL_VERIFY=false 后,提交时会显示同一页面且不发送邮件;注册记录中的 verified=0。无论哪种情况,页面都包含 Claude Desktop(mcp-remote)、Claude Code(HTTP)、Cursor 和通用 MCP 客户端的配置。Desktop 代码片段会将 bearer 值放在 AUTH_HEADER 中,避免空格被当作参数。Cursor 使用 URL 和 headers,不带命令参数。每个代码片段都写有 YOUR_TOKEN。页面还介绍 Claude Desktop 中 Customize → Connectors → Add custom connector 的配置路径,并使用相同的公开 MCP URL 和 Authorization 请求标头。标头值以 Bearer 开头。页面列出 claude_desktop_config.json、.mcp.json 和 ~/.cursor/mcp.json,以及用于该公开 MCP URL 的 claude mcp add 命令,还提供一个将笔记作为 source_content 传入的示例提示词。页面会说明 AM_TRIAL_BUILD_LIMIT 设定的构建上限。当 AM_API_URL 是公开的 https 来源时,同一页面会为 {AM_API_URL}/try 添加 Open Graph 和 Twitter 卡片。图片为 {AM_API_URL}/static/og-trial.png,无需令牌。若 AM_API_URL 是回环地址或私有地址,则不添加这些标签。页面始终设置为 noindex。每个规范化地址只能获得一个令牌。Gmail 地址会忽略点号和 +tags。拒绝一次性邮箱域名。来自同一个 IPv6 网络的注册尝试共用一个 /48。我的页面登录使用 /64。每个 UTC 日最多签发 AM_TRIAL_SIGNUPS_PER_DAY 个令牌(默认值为 300)。达到上限后,/try 会提示今天没有更多托管令牌,并告知 00:00 UTC 后恢复。
托管构建始终使用 AM_TRIAL_MODEL,且不能调用 publish。托管令牌的工具列表不包含 publish。响应中包含 builds_remaining。每个令牌最多有 AM_TRIAL_FREE_NEEDS_INPUT 个 needs_input 作业(默认值为 5)不消耗构建次数;超过后则会消耗。失败的作业仍会消耗构建次数。每日支出上限仍会计入该作业使用的模型令牌,小时限制也仍会计入此次尝试。删除构件不会返还构建次数。达到每日支出上限时,错误提示为 the hosted copy hit today's limit, back at 00:00 UTC。令牌用尽后会指向 GitHub 仓库。托管令牌的分享链接最长有效 30 天。即使页面已有的 robots 元标签没有声明 noindex,提供的页面也会添加 noindex,并附上一个链接到仓库的页脚;即使页面隐藏页脚,该页脚仍会显示。闲置的托管工作区会在 AM_TRIAL_RETENTION_DAYS 天后删除(默认值为 30)。该清理任务会在启动时运行,之后每小时运行一次。
安全性
令牌按工作区签发,并以 SHA-256 哈希形式存储。知道某个产物 ID 并不会因此获得访问权限。
权限包括 create、read、edit、publish、export、share 和 delete。
构建结果默认保持私有,直到调用 share。这会创建一个公开的 /s/… URL,指向最新的已完成版本。传入 version 或 pin,可将某个版本固定到专属 URL。unshare 会使该 URL 返回 404。使用版本参数调用 unshare 时,只会撤销对应的固定版本。共享的 HTML 页面会在页脚添加一行不显眼的文字“Made with ArtifactSmith”,并链接到 GitHub 仓库。设置 AM_SHARE_CREDIT=false 可隐藏这行文字。该文字不会写入存储的文件、预览或导出内容。
预览页和共享页使用独立端口,不发送 Cookie,并设置 CSP script-src 'none',以及 sandbox allow-popups allow-popups-to-escape-sandbox allow-top-navigation-by-user-activation。
“我的页面”(API 来源上的 /app/)是令牌所属工作区的只读目录。登录时需在表单中粘贴令牌。响应会在路径 /app 上设置 HttpOnly、SameSite=Strict 会话 Cookie,不会将令牌放入 URL。当 AM_API_URL 为 https 时(或设置了 AM_COOKIE_SECURE=true),Cookie 会设置 Secure 属性。每次请求都会重新加载令牌,因此撤销令牌后会立即终止会话。其他工作区的产物 ID 会返回 404。列表每次显示 50 个页面。时间默认使用 America/New_York,除非查看者设置了其他 IANA 时区;页面会注明所用时区。在反向代理后运行时,将 AM_TRUSTED_PROXIES 设置为该代理,以便将登录失败计入客户端(X-Real-IP 或最右侧的 X-Forwarded-For 跳)以及令牌前缀的哈希。IPv6 客户端共用一个 /64 网段。每个 IPv4 地址各自使用独立的计数桶,包括 IPv4 映射的 IPv6 地址。其他对等方无法提供这些标头。预览来源不会提供 /app/。
脚本会被移除。指向全局主机的公开 http(s) 链接会保留(在 HTML 中添加 rel="noopener noreferrer nofollow" 和 target="_blank")。页面内的 # 锚点会保留在页面内。主机检查使用 urllib 和 WHATWG 风格的近似实现;这能确保通过检查的链接不会指向私有主机,但不保证每个通过检查的链接都能被浏览器识别。仅当主机公开时,协议相对的 //host 引用才会升级为 https://;指向私有或危险目标的 // 链接会被置为无效,而不会升级。私有、回环和链路本地主机会导致构建失败,javascript:、vbscript:、data: 和 file: 也一样。远程图片 URL 在所有格式中都会变成指向该 URL 的可点击链接(以替代文本作为标签)——打开时不会加载图片。CSS url()、字体和 iframe 会保留在本地。检测到机密信息会导致构建失败。大小和时间均设有限制。
此进程不会向任何地方发送使用数据。
其余内容见 docs/threat-model.md 和 SECURITY.md。
令牌
工作区是产物的命名空间(例如 alpha 或 team-a)。每个令牌恰好属于一个工作区,且只能在该工作区内创建或读取产物。知道其他工作区的产物 ID 并不会因此获得访问权限。
artifactsmith token add --name NAME --workspace WS [--perms create,read,edit,publish,export,share,delete]
artifactsmith token list
artifactsmith token revoke --id ID | --name NAME
artifactsmith token perms --id ID | --name NAME
artifactsmith token perms --name NAME --add publish
artifactsmith token perms --name NAME --remove publish
token perms 可修改现有令牌的一项权限。令牌值保持不变。每次添加或移除权限,都会在审计日志中追加一行。列出权限则不会追加。如果名称匹配多个令牌,请传入 --id。
卸载 / 重置
# Stop containers, delete compose volumes, and remove images created for this project
# (server, storage-init, and the rustfs/rustfs pull). Requires store keys in .env like other compose commands.
docker compose down --volumes --rmi all
再次复制 .env.example,然后重新运行快速入门流程,即可从头开始。
开发
python3 -m venv .venv && source .venv/bin/activate
make install
make ci # lint, types, unit tests, denylist
运行测试
make test 使用与 CI 相同的 pytest 命令运行单元测试套件。它不会启动 Docker。
端到端测试使用 compose.test.yaml,其中添加了一个来自 tests/support/ 的模拟聊天模型。
./scripts/ensure-local-env.sh
docker compose -f compose.yaml -f compose.test.yaml up -d --build
python -m tests.e2e.test_end_to_end
python -m tests.e2e.test_formats
python -m tests.e2e.test_bind_address # AM_BIND_ADDRESS=0.0.0.0 via non-loopback IP
make smoke 使用相同的堆栈和脚本运行冒烟测试。Compose 命令需要一个设置了 AM_STORE_KEY 和 AM_STORE_SECRET 的 .env 文件(包括 docker compose down),因为 compose.yaml 需要这些变量。
docs/architecture.md、docs/operations.md、CONTRIBUTING.md。
构建方式
Artifactsmith 采用 vibe coding 的方式编写。由一名人员确定方向并做出决策,AI Agent 负责编写和检查代码:
- Grok Bot 负责运行项目。它规划工作,逐个文件审查每个拉取请求,并决定合并前必须修复哪些问题。
- Cursor 云端 Agent 编写代码、测试和文档,并修复审查发现的问题。
- Hermes Agent 进行了独立检查。其中一个以资深工程师的身份审查代码,并在每轮审查后批准。另一个从零开始安装,只遵循本 README 操作,模拟新用户的使用方式。
发布前,项目经历了以下流程:
- 多轮逐行代码审查;每轮都反复进行,直到没有遗留阻塞问题。
- 使用 Semgrep、Bandit、gitleaks、pip-audit 和 Trivy 进行独立安全审计,并编写了威胁模型。
- 对 HTML 清理器、链接处理和导出格式进行实际攻击测试。
- 使用实时模型对五种格式进行实际构建,检查链接是否仍可点击,以及打开文档时是否不会从外部加载任何内容。
- 在另一台机器上进行全新安装,包括在本地网络中向其他机器提供服务。
- 每次更改都会运行自动检查:lint、严格类型检查、Python 3.11 和 3.12 上的单元测试、Docker 构建、依赖项扫描和密钥扫描。
审计报告位于 docs/security-audit-2026-10-09.md。如果你发现我们遗漏了什么,请参阅 SECURITY.md。
许可证
MIT。House-style 写作和视觉规范改编自 Humanizer(MIT)和 Anthropic frontend-design(Apache-2.0)。致谢信息见 NOTICE;第三方许可证文本位于 licenses/。Docker 镜像会将这些文件放在 /app。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。