Artifacts for AI agents, on your own domain.
OpenArtifact lets your agents publish pages, dashboards and apps for your users. Your users open them on your domain, sign in through your app, and share them like documents. It's built on AgentFGA, so every artifact has clear owners.
In development. OpenArtifact isn't released yet. This page describes the API as designed, and details may change before release.
// Your agent made a dashboard for one of your users.
const res = await fetch(`${OA_URL}/v1/artifacts`, {
method: "POST",
headers: {
Authorization: `Bearer ${OA_KEY}`,
"Content-Type": "application/json",
"OpenArtifact-User": "u_123",
"OpenArtifact-Agent": "support-bot",
},
body: JSON.stringify({
title: "Signups this week",
files: [{ path: "index.html", content: html }],
}),
});
// A link on your domain, private until they share it.
const { urls } = await res.json();
// urls.view: https://artifacts.acme.com/a/7Hk2xQp9
Plain HTTP, from your backend or your agent's runtime.
§ 01 · Why artifacts
Artifacts are how agents show their work.
Users now expect an agent to hand back something they can open, use and share: a page, a dashboard, an app. Building that yourself means hosting code a model wrote, plus sign-in, sharing, versions and embeds. OpenArtifact is that layer, as open infrastructure.
- Can viewYour team
- Can editYou
- The agentRead only
Who can see and change each artifact runs on AgentFGA.
01
Publish from any agent
Any agent, on any model, wherever it runs, publishes over HTTP or MCP. Edits send only what changed, and earlier versions are kept, so a bad change rolls back in one call.
Artifacts · Versions · MCP
02
On your domain, under your name
Artifacts open on a domain you bring, with your name and logo. Your app signs users in, and OpenArtifact keeps no passwords.
Domains · Branding · Sign-in
03
Shared like a document
Owners share with people, groups or other agents, as viewers or editors, and access can expire. A link can be private, open to anyone signed in, or public, as far as your policy allows.
Shares · General access
04
Embedded in your product
Show an artifact inline in your chat or app. Your backend gives the browser a short-lived token for one user, and the artifact itself never holds a credential.
Client tokens · Embeds
§ 02 · How it works
Your agent publishes. Your users open and share.
You set up a domain, sign-in and branding once. After that, every artifact follows the same three steps, shown here for one dashboard.
-
Your agent publishes
The agent creates an artifact for one of your users. It's private to them until they share it.
user: u_123 agent: support-bot title: Signups this week -
Your user opens it
The link is on your domain. If the user isn't signed in, your app signs them in and sends them back.
link: artifacts.acme.com/a/7Hk2xQp9 sign-in: app.acme.com/oa/sign-in -
They share it
They share it with their team. A teammate opens the same link, and OpenArtifact checks that they may view it.
share: group:org_9 → viewer viewer: u_456, in org_9 can_view: true
Where OpenArtifact fits
Your agent publishes through OpenArtifact. Your users see the result on your domain, while each artifact's code runs on an origin of its own.
When an agent acts for a user, a request goes through only if the user may do it and the agent may too. Every refusal says which of them said no.
§ 03 · Security
Code a model wrote, kept in its own box.
OpenArtifact treats every artifact as untrusted, because a model wrote it. Your users see your domain in the address bar, while the artifact's code runs somewhere it can't reach your app.
Isolation
- An origin per artifact. Each artifact runs on its own subdomain of a render domain that is never same-site with your app, so its code can't reach your cookies or storage.
- No network by default. An artifact can only call hosts on your project's allowlist, plus any its manifest adds, if you allow that.
- No credentials inside. The artifact talks to the page around it with
postMessage, and that page authorizes every call.
Permissions
- The user and the agent. When an agent acts for a user, both must be allowed. A refusal says which one wasn't.
- Nothing leaks by existing. Someone who can't view an artifact gets
404, not403. - Access that ends on time. A share can carry an end date. It's stored as an AgentFGA condition, so it ends without a cleanup job.
- Keys shown once. Keys are stored as hashes, and a revoked key stops working within a minute.
§ 04 · API
Built for agents to call.
Agents retry, race each other and get things wrong, so the API expects it. Every change names the version it was based on, every POST takes an idempotency key, and every refusal says how to fix it.
Edit by replacement
The cheapest way for an agent to change an artifact: send only the text that changed.
POST /v1/artifacts/art_1/edits
{
"base_version": "ver_03",
"edits": [{
"old_text": "<h1>Signups</h1>",
"new_text": "<h1>Signups this week</h1>"
}],
"publish": true
}
Refusals an agent can act on
If the artifact changed since the agent read it, the edit is refused, along with the fix.
409 Conflict
{
"error": {
"code": "version_conflict",
"message": "The live version is ver_04, not ver_03.",
"hint": "Read ver_04, then reapply your change.",
"live_version": "ver_04"
}
}
Over MCP
Every project gets an MCP endpoint on its own domain, such as artifacts.acme.com/mcp, under your product's name. Each tool maps onto the API.
| Tool | What it does |
|---|---|
create_artifact | Publishes a new artifact from HTML or a set of files. |
update_artifact | Publishes a new version with the files that changed, and any to delete. |
edit_artifact | Replaces text in place. Every edit applies, or none do. |
read_artifact | Reads a file from any version, a range of lines at a time. |
get_artifact, list_artifacts | Finds artifacts, with what the caller may do with each. |
share_artifact | Shares with a person, group or agent, or changes who the link is open to. |
rollback_artifact | Makes an earlier version live again, without uploading anything. |
Who calls what, with which credential
| Surface | Who calls it | Credential |
|---|---|---|
| Control API | Your admin, once at setup: domains, sign-in, branding and policy | An admin key, so a leaked agent or backend key can't change them |
| Artifact API | Your backend and agents, and your users' browsers | A secret key, an agent key, or a short-lived client token |
| Viewer | Your users, on your domain | A session cookie, set after they sign in through your app |
| Render origin | The frame that runs one artifact's code | A short-lived token for that artifact's files only, with no access to data |
| MCP | Any agent, under your product's name | An agent key |
Artifacts that keep data
An artifact can store records that outlive its versions, such as votes or a shared board. It declares each collection in an optional openartifact.json, along with who may write to it. Reads and writes go through the page around the artifact, which checks them.
{
"network": { "connect": ["https://api.acme.com"] },
"data": {
"votes": { "scope": "per_user", "write": "viewer" },
"board": { "scope": "shared", "write": "editor" }
}
}
§ 05 · Open source
Run it yourself, or let us run it for you.
OpenArtifact will be open source, like AgentFGA. Run it on your own Cloudflare account, or let OHQ run it, under the same account as AgentFGA Cloud.
| Open source | Cloud | |
|---|---|---|
| Projects | As many as you need in one deployment, managed with an admin key you set | Per account, managed in the OHQ console |
| Your domain | The API checks you own it, and you route it to your deployment | Added for you, with TLS certificates handled |
| Accounts, billing and team members | Not included | Included, shared with AgentFGA Cloud |
An OHQ product.
OHQ researches and builds the infrastructure agents run on, and releases it as open source. OpenArtifact builds on AgentFGA, OHQ's first product, which decides who may see and change each artifact.