rtfx.pro

Documentation

Publish it, control who opens it, keep every version.

rtfx.pro hosts the HTML pages and multi-file artifacts that come out of an AI session — from Claude Code, Hermes, your terminal or your browser — behind real access control instead of an unlisted URL.

What rtfx.pro is

An artifact is one publishable thing: a single HTML file, or a folder/zip with its own assets. Publishing gives it a slug, a version and an owner. From then on the artifact has a stable link, a history, and an access list — the three things an unlisted URL on a static host never gives you.

  • Private by default. A new artifact is restricted to its owner until they share it.
  • Owned. The person who published it manages it; nobody else can, however they were shared with.
  • Versioned. Re-publishing creates the next version at the same address.
  • Observable. The owner sees every view: person, time, country, version.

Who uses it, and for what

Made for the work that comes out of an AI session: a finished page, a dashboard, a prototype, a report — something real, that needs a link today and shouldn't be on the open web.

Developers

Ship an agent's output without a pipeline

Claude Code just produced a working page. Publish it straight from the session — no repo, no build, no CDN config — and send the link before you lose the context.

Consultants & agencies

Client-ready links that stay off the open web

Share a deliverable with exactly the people on the account, watch who actually opened it, and roll back the moment a revision lands badly.

Product & data teams

An internal home for dashboards and prototypes

Stop mailing HTML attachments and unlisted URLs. Publish once, grant the team, and let the version history be the changelog.

Publishing

Three ways in, one behaviour. A file, a directory or a zip all work; a bundle keeps its relative paths, so ./assets/app.js resolves the way it did locally.

From the terminal

The CLI ships in the project repository — there is no npm package yet, so you run it from a checkout (or from the Claude Code plugin below, which needs no checkout at all).

$ git clone https://github.com/yogevgab/artifacts-server
$ cd artifacts-server && npm install

$ export ARTIFACTS_URL=https://rtfx.pro
$ export RTFX_API_TOKEN=rtfx_…    # dashboard → Integrations

$ node cli/artifacts.mjs publish ./index.html --slug q3-report --title "Q3 Report"
$ node cli/artifacts.mjs publish ./site --slug q3-report --note "revised charts"   # next version
$ node cli/artifacts.mjs grant q3-report alex@example.com
$ node cli/artifacts.mjs views q3-report
$ node cli/artifacts.mjs list

From the dashboard

Drop a file or zip into the publish panel under Artifacts, set a title, and it's live at its slug. Each artifact then has its own page, holding version history, sharing and the view log.

Over HTTP

The upload field decides how the file is read, not its extension: a zip goes in bundle, a single HTML document in file. A bundle needs index.html at its root.

$ export RTFX_API_TOKEN=rtfx_…              # dashboard → Integrations
$ export CF_ACCESS_CLIENT_ID=…              # Access service token (see below)
$ export CF_ACCESS_CLIENT_SECRET=…

# a zip — zip the folder first over HTTP → bundle
$ curl -X POST https://rtfx.pro/api/artifacts \
    -H "Authorization: Bearer $RTFX_API_TOKEN" \
    -H "CF-Access-Client-Id: $CF_ACCESS_CLIENT_ID" \
    -H "CF-Access-Client-Secret: $CF_ACCESS_CLIENT_SECRET" \
    -F slug=q3-report -F title="Q3 Report" -F bundle=@./dist.zip

# one HTML document → file
$ curl -X POST https://rtfx.pro/api/artifacts \
    -H "Authorization: Bearer $RTFX_API_TOKEN" \
    -H "CF-Access-Client-Id: $CF_ACCESS_CLIENT_ID" \
    -H "CF-Access-Client-Secret: $CF_ACCESS_CLIENT_SECRET" \
    -F slug=q3-report -F title="Q3 Report" -F file=@./index.html

Two credentials, two jobs. Cloudflare Access gates the edge; the bearer token authenticates you to the app. While /api sits inside the Access application — the posture rtfx.pro runs — a call from a machine has to satisfy both, so it sends the service-token headers and the API token. The headers get the request through Access and grant nothing inside the app; the API token decides who you are and what you may do. Mint the service token in Cloudflare Zero Trust, keep both halves in environment variables, and drop the two CF-Access-* headers only on an instance whose operator has excluded /api from Access. The CLI and the MCP server send the same pair automatically when CF_ACCESS_CLIENT_ID and CF_ACCESS_CLIENT_SECRET are set.

Claude Code, MCP & Hermes

Agents publish through exactly the same CLI and API a human uses — there is no separate, weaker agent path. Mint an API token in the dashboard, scope it to publish, and hand it to the session:

# in a Claude Code session, with the plugin installed
/rtfx:publish ./out client-demo

# or from any shell — Claude Code, Hermes, CI — in a checkout of the project
$ node cli/artifacts.mjs publish ./out --slug client-demo --title "Checkout prototype"
$ node cli/artifacts.mjs grant client-demo teammate@example.com

The Claude Code plugin

Installing the plugin turns that into ordinary conversation: say publish this and the session picks the build output, versions it under a slug and hands back the link. It ships a skill, five slash commands, and a dependency-free publisher — no checkout and no package install, since the plugin brings its own copy of the publisher.

/plugin marketplace add yogevgab/artifacts-server
/plugin install rtfx@rtfx

/rtfx:setup       # check the token reaches your instance
/rtfx:publish     # publish what the session just built
/rtfx:versions    # history · /rtfx:rollback to go back

The MCP server

The same plugin ships a native MCP server, for a client with no shell to run a command in — Claude Desktop, or anything else that speaks MCP. Installing the plugin registers it; it publishes, lists versions and rolls back as tool calls, holding the same scoped token and applying the same credential filters as the CLI. To wire it up by hand instead, point a client at the server file inside the installed plugin (or inside a checkout) — it needs Node and nothing else:

{ "mcpServers": { "rtfx": {
    "command": "node",
    "args": ["/path/to/plugins/rtfx/scripts/rtfx-mcp.mjs"],
    "env": { "RTFX_API_TOKEN": "rtfx_…" } } } }

tools: publish · list_artifacts · get_versions · rollback · doctor

Why a token, not your login. An API token is bound to its owner, carries only the scopes you give it (read, publish, manage), and can be revoked on its own. An agent holding one can publish as you — it can never become you, manage other people, or reach anyone else's artifacts.

Access & privacy model

There are two independent layers, and both must say yes.

  1. Who may sign in at all. Cloudflare Access is the identity provider; the people list is managed in the dashboard. Sign-in is passwordless — a one-time code by email. Access to rtfx.pro is by invitation.
  2. Who may open a given artifact. Either restricted (the owner plus the people they name) or everyone signed in. Sharing one artifact never widens who can sign in, and never exposes anything else you own.

An unauthorized request and a request for something that doesn't exist get the identical 404, so a link can't be used to confirm that a page exists. Artifact content is served from a dedicated origin that hosts files only — never the dashboard or the API — so uploaded HTML can't reach the app it was published from.

Worth being precise about what that origin does and doesn't do: it separates published content from rtfx.pro, and all artifacts share it. It is not a per-artifact browser sandbox, so two pages published by people who don't trust each other are kept apart by the access list — who may open what — rather than by the browser's origin boundary. Publish only what you're willing to run in the same origin as your other artifacts.

None of it is crawlable: artifacts, the dashboard and the API are excluded in robots.txt, marked noindex, and served with an X-Robots-Tag: noindex header. The only indexable pages are this one, the landing page, the sign-in page and the two legal pages.

What rtfx.pro itself stores about you — and the fact that it runs no analytics, advertising or third-party tracking — is set out in the privacy policy. What you agree to by publishing here is in the terms of use.

Versions & view logs

Every publish to a slug creates the next immutable version. The public link always points at the current one; each older version keeps its own preview URL for whoever manages the artifact, and rollback is a single action. Nothing is overwritten, so a bad revision is a click to undo rather than a re-run of whatever produced it.

The view log answers the question client work always ends with: who opened it, when, from where, and which version they saw. Views are recorded for signed-in people opening a page — not for asset requests or machine tokens.

Why rtfx.pro

Several tools now host the page an AI session just produced, and they mostly agree on the basics. So the useful question is not "does it host HTML" — it is what happens on the second day, when the link is out, the client asks who has seen it, and a revision lands badly. Here is the split, written so you can decide in one screen.

Table stakes

Present here, and expected of anything in this category. Nobody should pick a tool for these.

  • Publishing with no build step. A single HTML file, a folder or a zip goes up as it is; relative paths keep working.
  • A stable link. One slug, one URL, for as long as the artifact exists.
  • Re-publishing to the same address. The link you already sent keeps working after an update.
  • A dashboard. Drag-and-drop publishing, an inventory, and the state of each artifact in one place.
  • Some idea of who looked. Counts at minimum.

What actually makes it different

These are the reasons to choose rtfx.pro over a general "share your AI output" tool.

  • Agent-native publishing, not an upload form with an API bolted on. Claude Code, a native MCP server, a Hermes run, the CLI and the HTTP API all take the same path a human takes — there is no separate, weaker agent route. An agent holds a scoped, owner-bound, revocable token, so it can publish as you and can never become you.
  • Access is an identity, not a secret URL. Every artifact is restricted until you name someone. An unauthorized request and a request for something that doesn't exist return the identical 404, so a leaked link can't even confirm the page is real. Sharing is revocable, per artifact, and never widens who can sign in.
  • Immutable versions with one-click rollback. Every publish is a new version with its own preview URL. Nothing you have already shared is overwritten, so a bad revision is an undo rather than a re-run of whatever produced it.
  • A view log that names a person and a version. Not a hit counter: who opened it, when, from which country, and which version they saw — the question every client project ends with.
  • Workspace governance. Artifacts belong to a workspace, not to one shared login. Members carry a role — owner, admin, member or viewer — and instance privilege is re-derived from configuration on every request, so no database write can escalate anyone.
  • Uploaded HTML runs somewhere it can't reach us. Artifact files are served from a dedicated content origin that hosts files and nothing else — no dashboard, no API, no admin — so a page you publish can never touch the app that published it. Artifacts share that one content origin, so it isolates published content from rtfx.pro rather than artifacts from each other.
  • Nothing watches the visitor. No analytics, advertising or third-party tracking anywhere on this site, and none injected into what you publish. The view log is ours to show you, not a product we resell.

Not here yet

Listed so you know they are deliberate gaps rather than things you failed to find. If a project needs one of these today, this is the honest place to find that out.

  • Per-link secrets. A shared code on the link itself, for handing something to someone who will never have an account. Today the answer is an invitation and an access list.
  • Link expiry. Access is revoked by hand, not on a timer. API tokens do carry an optional expiry.
  • Custom domains. Serving artifacts from your own hostname. Content already runs on its own origin, which is the hard part.
  • Comments, approvals and polls. rtfx.pro publishes and controls the artifact; it is not the review tool around it.

Why not a generic static host?

You could put this on any bucket or edge host. Here's what you'd then have to build yourself.

What you needGeneric static hostingrtfx.pro
PrivacyPublic by default; an unlisted URL is the whole defence — anyone with the link is in.Private by default. Access is per artifact, per person, and revocable.
IdentityBring your own auth, or bolt on a password everyone shares.Passwordless sign-in through Cloudflare Access, with a managed people list.
VersionsA deploy overwrites the last one; rollback means a rebuild.Every publish is an immutable version with its own preview and one-click rollback.
AuditRaw request logs, if you wire up analytics.A per-artifact view log: person, time, country, version.
Agent workflowGit push, build, wait, configure.One command, or one API call, from inside the session that made the page.

API

Authenticate with Authorization: Bearer <token>. Every endpoint is scoped to what the token's owner may see; an admin sees everything they administer. While /api sits behind Cloudflare Access, a machine call also carries the CF-Access-Client-Id and CF-Access-Client-Secret headers of an Access service token — see Publishing for a runnable call.

  • GET /api/artifacts — list artifacts you can manage.
  • POST /api/artifacts — publish (multipart: title, slug, and either file for one .html document or bundle for a .zip).
  • GET /api/artifacts/:slug/versions — version history.
  • POST /api/artifacts/:slug/rollback — restore a previous version.
  • POST /api/artifacts/:slug/access — set visibility and the share list.
  • DELETE /api/artifacts/:slug — delete an artifact and its versions.

The API lives behind sign-in; these paths are documented here but are not public. Full request/response detail ships with the CLI (node cli/artifacts.mjs --help in a checkout) and in the dashboard once you have access.

Frequently asked

Is anything I publish visible to the public web?

No. Every artifact is access-controlled: a visitor without a valid identity gets a 404, and so does a signed-in person who hasn't been granted access. Artifact origins send X-Robots-Tag: noindex and are excluded in robots.txt, so nothing you publish is crawled or indexed. Only the product pages — the landing page, these docs and the sign-in page — are public.

How do I publish from Claude Code, an MCP client or a Hermes run?

Give the agent a scoped API token and let it call the same CLI or HTTP API you use. The Claude Code plugin is the shortest path: install it from the project's marketplace and 'publish this' becomes the last step of an ordinary session. The same plugin ships a native MCP server, so a client with no shell — Claude Desktop, for instance — publishes as a tool call over the same path. From a terminal, run the CLI out of a checkout of the project: `node cli/artifacts.mjs publish ./out --slug client-demo` handles a single file, a folder or a zip. There is no npm package to install yet, and nothing here pretends there is. A token is bound to its owner and can be revoked at any time, so the agent never gains your account.

What happens when I publish the same slug twice?

You get a new immutable version at the same URL. Previous versions stay addressable for preview, and rollback is one click — nothing you have already shared is overwritten or lost.

Who can sign in to rtfx.pro?

Access is by invitation. Cloudflare Access is the identity provider and sign-in is passwordless — you get a one-time code by email. Request access from the landing page and we'll send an invitation.

Can someone I share an artifact with see my other artifacts?

No. A grant applies to exactly one artifact. It never confers management rights, never reveals your other work, and never widens who can sign in.

Can I put a password on a share link?

Not today, and nothing here pretends otherwise. Access is by identity instead: you name the people who may open an artifact, and everyone else — signed in or not — gets a 404. Sign-in itself is passwordless, a one-time code by email through Cloudflare Access, so there is no shared secret to leak, rotate or forget. Per-link secrets, link expiry and custom domains are planned, and they are listed as planned on this page.

How is this different from the other tools for sharing what Claude built?

Most of them start from a public link and add controls on top of it. rtfx.pro starts locked, and sharing is a deliberate act you can see and undo. The differences that survive a real project: publishing is agent-native — Claude Code, Hermes, a CLI and the HTTP API all take the same path — access is an identity-backed list rather than a secret URL, every publish is an immutable version you can roll back, the view log names the person and the version they saw, and a workspace has roles so a team is not one shared login.

Where does the uploaded HTML actually run?

On a separate content origin (a.rtfx.pro) that serves artifact files and nothing else — no dashboard, no API, no admin. Uploaded HTML therefore can never run in the same origin as the app that manages it. That boundary sits between your artifacts and rtfx.pro, not between one artifact and the next: every artifact is served from the same content origin today, so what keeps one publisher's page away from another's is the access list, not the browser. If you need two mutually distrusting publishers isolated by the browser itself, that is not what this origin split gives you.

Get an account

Access is invite-only — tell us where to send yours.