Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ In a sandbox or SSH session, replace `login` with `login --device-code`. Keep
that process running and approve its displayed URL and code in your own
browser, then run `npx @zaks-io/agent-paste whoami --json` before publishing.
Device login needs network access to WorkOS and the API, but no browser in the
sandbox. See the [remote login guide](apps/cli/README.md#remote-login).
sandbox. See the [remote login guide](apps/cli/README.md#agent-quick-path).

Expected output:

Expand Down
80 changes: 33 additions & 47 deletions apps/apex/src/agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,73 +3,63 @@ import { API_BASE_URL, APP_BASE_URL, MCP_BASE_URL, SKILL_INSTALL_CMD } from "./c

export const AGENTS_MD = `# agent-paste for agents

Agent Paste turns a file or directory into a top-level website. Use it when the
next step should be a URL instead of a deploy, repository, zip, screenshot, or
local server.
agent-paste publishes a file or directory as a website and returns one URL that
opens without login. Use it when the next step should be a link instead of a
deploy, zip, screenshot, or local server.

Every publish returns one no-login \`url\` on the Artifact's own capability
subdomain. There is no iframe, viewer wrapper, or second sharing step. Revising
the same Artifact keeps the URL.
Default to the CLI. Use MCP only when the host cannot run commands.

Default to the CLI. Use MCP only when the host can connect to remote MCP but
cannot run commands.

## Install the skill
## Skill

\`\`\`sh
${SKILL_INSTALL_CMD}
\`\`\`

## CLI

Check authentication first:

\`\`\`sh
npx @zaks-io/agent-paste whoami --json
\`\`\`

\`whoami\` exits 0 when signed out; inspect \`authenticated: false\`.
Use \`npx @zaks-io/agent-paste login\` locally or add \`--device-code\` in a
sandbox. Keep device login running while the user approves the URL and code
from stderr, then check \`whoami\` again. Existing credentials, including an
injected \`AGENT_PASTE_API_KEY\`, work without another login.
\`whoami\` exits 0 even when signed out, so check \`authenticated\`. If it is
false, run \`login\` where a browser is available or \`login --device-code\` in a
sandbox. Device login prints a URL and code on stderr; keep it running until the
user approves, then run \`whoami\` again. An \`AGENT_PASTE_API_KEY\` env var also
authenticates and takes precedence over stored credentials.

Publish a file or directory:
Publish:

\`\`\`sh
npx @zaks-io/agent-paste publish ./path --json
\`\`\`

Return \`url\` to the user.

Revise the Artifact at the same URL:
Revise at the same URL:

\`\`\`sh
npx @zaks-io/agent-paste publish ./path --artifact-id 01234-56789-abcde-fghjd --json
\`\`\`

Use the artifact ID with \`--artifact-id\`, \`pull\`, or \`edit\`.
Full URLs also work. Updates require Workspace access.
The artifact ID is the first label of the URL hostname. \`--artifact-id\`,
\`pull\`, and \`edit\` accept that ID, the \`art_...\` \`artifact_id\` from JSON
output, or the full URL.

If login is unavailable and static accountless output satisfies the task, or
the user explicitly asks for accountless publish:
When login is unavailable, or the user asks for accountless publishing:

\`\`\`sh
npx @zaks-io/agent-paste publish ./path --ephemeral --json
\`\`\`

Return \`url\`. Return \`claim_url\` too when the human wants to keep and own the
upload. Unclaimed ephemeral Artifacts expire after 24 hours and render with
scripts, connections, forms, frames, objects, and workers blocked. Claiming
promotes the same Artifact URL to the claimed execution policy.

If copied instructions include \`--claim-code <clm_...>\`, preserve it on the
ephemeral publish command. It is attribution, not part of the Artifact URL.
Return \`url\`. Also return \`claim_url\` if the user wants to keep the Artifact.
Unclaimed ephemeral Artifacts expire in 24 hours and serve static HTML only:
scripts, fetch, forms, frames, and workers are blocked. Claiming keeps the URL
and lifts those blocks. If the instructions you were given include
\`--claim-code <clm_...>\`, keep it on the command.

Directory publish preserves relative paths. Entrypoint inference is
\`index.html\`, \`index.md\`, \`README.md\`, then the only file. Otherwise pass
\`--entrypoint <path>\`. Folder publishing excludes \`.git/\`, \`node_modules/\`,
\`.DS_Store\`, \`.env\`, and \`.env.*\`.
Directory publish keeps relative paths and skips \`.git\`, \`node_modules\`,
\`.DS_Store\`, and \`.env*\`. The entrypoint is \`index.html\`, \`index.md\`,
\`README.md\`, or the only file; otherwise pass \`--entrypoint <path>\`.

## Result

Expand All @@ -84,35 +74,31 @@ Directory publish preserves relative paths. Entrypoint inference is
}
\`\`\`

The URL is an unguessable bearer locator with at least 95 bits of entropy. It opens without login and
serves the latest Published Revision. Authenticated publishes can use inline
scripts, external HTTPS dependencies, root-relative assets, fetch, secure
WebSockets, and dedicated workers. Service workers are blocked on every
Artifact host.
Claimed Artifacts run as ordinary top-level pages: inline scripts, external
HTTPS dependencies, fetch, WebSockets, and dedicated workers all work. Service
workers are blocked everywhere.

## MCP

Connect to \`${MCP_BASE_URL}\`, complete OAuth, and call \`whoami\`.
Connect to \`${MCP_BASE_URL}\` with OAuth and call \`whoami\`.

- Create: \`publish_artifact\`
- Revise: \`add_revision\` or \`multi_edit\`
- Revise: \`add_revision\` (whole file) or \`multi_edit\` (literal find/replace)
- Read: \`list_artifacts\`, \`read_artifact\`, \`read_file\`, \`list_revisions\`
- Manage: \`delete_artifact\`, \`update_display_metadata\`

Use the artifact ID in \`artifact_id\`; full URLs also work.
MCP and CLI publishing return the same \`url\` contract.
MCP publishes text only; folders and binary files need the CLI. \`artifact_id\`
accepts the ID or the full URL.

## Reading this site

Every page on https://agent-paste.sh answers \`Accept: text/markdown\` with a clean
Markdown twin of that page. Each twin also has a direct address: /index.md,
Every page answers \`Accept: text/markdown\` and has a \`.md\` twin: /index.md,
/docs.md, /docs/{slug}.md, /about.md, /how-it-works.md, /terms.md, /privacy.md.

## Links

- Dashboard: ${APP_BASE_URL}
- API auth metadata: ${API_BASE_URL}/auth.md
- Human docs: https://agent-paste.sh/docs
- Markdown docs: https://agent-paste.sh/docs.md
- Docs: https://agent-paste.sh/docs.md
- Full corpus: https://agent-paste.sh/llms-full.txt
`;
14 changes: 7 additions & 7 deletions apps/apex/src/docs/pages/artifact-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ export const ARTIFACT_MODEL_DOC: DocsPage = {
columns: ["Object", "Meaning"],
rows: [
["Workspace", "Tenant that owns Artifacts, members, policy, and Audit Events."],
["Artifact", "Durable folder-like package containing one or more files."],
["Artifact", "Folder-like package of one or more files."],
["Revision", "Immutable saved state of an Artifact."],
["Published Revision", "Revision currently visible at the Artifact URL."],
["Artifact URL", "Unguessable top-level capability website returned by publish."],
["Artifact Console", "Login-walled management page at `/artifacts/<id>`; never returned by publish."],
["Published Revision", "Revision currently served at the Artifact URL."],
["Artifact URL", "Unguessable website returned by publish."],
["Artifact Console", "Login-walled management page at `/artifacts/<id>`."],
["Agent View", "Machine-readable Artifact and Revision metadata with per-file URLs."],
["Bundle", "Downloadable archive of a complete Revision tree."],
["Bundle", "Downloadable archive of a complete Revision."],
],
},
],
Expand All @@ -32,7 +32,7 @@ export const ARTIFACT_MODEL_DOC: DocsPage = {
blocks: [
{
kind: "paragraph",
text: "Artifact and Revision IDs are management identities. The Artifact URL uses an independent random capability ID, so it does not expose either management ID.",
text: "Artifact and Revision IDs are management identities. The Artifact URL uses a separate random capability ID, so it exposes neither.",
},
{
kind: "code",
Expand All @@ -47,7 +47,7 @@ export const ARTIFACT_MODEL_DOC: DocsPage = {
blocks: [
{
kind: "paragraph",
text: "Publishing to an existing Artifact creates a new Published Revision and rewrites the capability manifest in place. The URL stays unchanged. Draft Revisions are never served there.",
text: "Publishing to an existing Artifact creates a new Published Revision at the same URL. Draft Revisions are never served.",
},
],
},
Expand Down
16 changes: 6 additions & 10 deletions apps/apex/src/docs/pages/billing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export const BILLING_DOC: DocsPage = {
slug: "billing",
title: "Billing and Plans",
shortTitle: "Billing",
summary: "Hosted billing is enabled: your Plan sets write allowance, retention, and caps.",
summary: "Your Plan sets write allowance, retention, and caps. Reads are always free.",
sections: [
{
id: "plans",
Expand All @@ -18,7 +18,7 @@ export const BILLING_DOC: DocsPage = {
},
{
kind: "paragraph",
text: "Shared caps: 100 files per Revision, 100 lifetime published Revisions per Artifact, 60 actor requests per minute, and 300 Workspace burst requests per minute.",
text: "Shared caps: 100 files per Revision, 100 published Revisions per Artifact, 60 requests per minute per actor, 300 per minute per Workspace.",
},
],
},
Expand All @@ -28,11 +28,7 @@ export const BILLING_DOC: DocsPage = {
blocks: [
{
kind: "paragraph",
text: "Open `/billing` in the dashboard and choose the Pro interval. The dashboard creates a Stripe Checkout session and redirects you to Stripe.",
},
{
kind: "paragraph",
text: "After a successful Checkout return, the dashboard activates Pro synchronously, refreshes the billing cache, and shows the updated Plan. Stripe webhooks and daily reconciliation keep local entitlement state converged after that.",
text: "Open `/billing` in the dashboard and choose a Pro interval. Checkout runs on Stripe; Pro activates as soon as you return, and webhooks plus daily reconciliation keep it in sync after that.",
},
],
},
Expand All @@ -42,11 +38,11 @@ export const BILLING_DOC: DocsPage = {
blocks: [
{
kind: "paragraph",
text: "The billing page can open Stripe Customer Portal for subscription management and cancellation. It also lists Stripe invoices with hosted invoice and PDF links when Stripe provides them.",
text: "The billing page opens the Stripe Customer Portal for changes and cancellation, and lists invoices with hosted and PDF links.",
},
{
kind: "paragraph",
text: "Reads are always free. Billing changes write allowance and feature limits; it does not meter recipients opening an Artifact URL.",
text: "Billing changes write allowance and limits only. Recipients opening an Artifact URL are never metered.",
},
],
},
Expand All @@ -56,7 +52,7 @@ export const BILLING_DOC: DocsPage = {
blocks: [
{
kind: "paragraph",
text: "Stripe `active`, `trialing`, and `past_due` subscriptions map to Pro. Canceled, unpaid, incomplete, expired, paused, or missing subscriptions map to Free.",
text: "Stripe `active`, `trialing`, and `past_due` map to Pro. Everything else, including no subscription, maps to Free.",
},
],
},
Expand Down
28 changes: 11 additions & 17 deletions apps/apex/src/docs/pages/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,21 @@ export const CLI_DOC: DocsPage = {
kind: "table",
columns: ["Command", "Purpose"],
rows: [
["`agent-paste login`", "Authenticate through browser OAuth."],
["`agent-paste login --device-code`", "Authenticate from a sandbox with approval in your own browser."],
["`agent-paste login`", "Authenticate through the browser."],
["`agent-paste login --device-code`", "Authenticate from a sandbox; approve in your own browser."],
["`agent-paste logout`", "Revoke and remove the stored credential."],
["`agent-paste whoami --json`", "Report authentication, Workspace, actor, and scopes."],
["`agent-paste publish <path>`", "Publish a file or folder and return one top-level `url`."],
["`agent-paste publish <path>`", "Publish a file or folder and return `url`."],
["`agent-paste pull <artifact-id> <path>`", "Read one stored file."],
["`agent-paste edit <artifact-id> <path>`", "Apply literal edits and publish a Revision."],
["`agent-paste version`", "Print the CLI version."],
["`agent-paste upgrade`", "Update a standalone binary install."],
],
},
{
kind: "paragraph",
text: "`--json` writes one object to stdout with `schema_version`; progress and errors go to stderr. Exit codes: 0 success, 1 generic, 2 authentication, 3 quota, 4 validation, 5 not found, 6 network or server. `agent-paste help publish` and `help pull` list flags and JSON fields.",
},
],
},
{
Expand All @@ -38,11 +42,7 @@ export const CLI_DOC: DocsPage = {
},
{
kind: "paragraph",
text: "Keep device login running while the user approves the URL and code from stderr in their browser, then check whoami again. Device login needs access to WorkOS and the API, but no local browser.",
},
{
kind: "paragraph",
text: "Existing credentials work without another login. AGENT_PASTE_API_KEY takes precedence over stored credentials. If authentication is unavailable, use --ephemeral for accountless static output or report the blocker.",
text: "`whoami` exits 0 even when signed out, so check `authenticated`. Device login prints a URL and code on stderr and needs network access to WorkOS and the API but no local browser. Keep it running until the user approves, then run `whoami` again. An `AGENT_PASTE_API_KEY` env var also authenticates and takes precedence over stored credentials.",
},
],
},
Expand All @@ -57,22 +57,16 @@ export const CLI_DOC: DocsPage = {
},
{
kind: "paragraph",
text: "Publish returns a URL that opens without login. Use its artifact ID with `--artifact-id`, `pull`, or `edit`. Full URLs also work. Updates keep the same URL and require Workspace access.",
text: "The returned `url` opens without login and stays the same across updates. Its artifact ID is the first label of the hostname; `--artifact-id`, `pull`, and `edit` accept that ID, the `art_...` `artifact_id` from JSON output, or the full URL. Updates require Workspace access.",
},
{
kind: "code",
language: "text",
code: '✓ Published "report"\n\n View https://01234-56789-abcde-fghjd.agent-paste.link/\n Expires <expiration date>\n\n Update agent-paste publish ./report --artifact-id 01234-56789-abcde-fghjd\n\n → open https://01234-56789-abcde-fghjd.agent-paste.link/',
},
],
},
{
id: "ephemeral",
title: "Accountless publish",
blocks: [
{
kind: "paragraph",
text: "Run `whoami --json` first. When login is unavailable and static accountless output meets the task, or when explicitly requested, use `publish <path> --ephemeral --json`. Return `url`; return `claim_url` too when the human wants to keep the upload. Ephemeral HTML is static until claimed.",
text: "When login is unavailable, `publish <path> --ephemeral --json` publishes without an account. See [Ephemeral](/docs/ephemeral).",
},
],
},
Expand All @@ -82,7 +76,7 @@ export const CLI_DOC: DocsPage = {
blocks: [
{
kind: "paragraph",
text: "Directory publish preserves relative paths and skips `.git`, `node_modules`, `.DS_Store`, and `.env*`. Entrypoint inference is `index.html`, `index.md`, `README.md`, then the only file. Otherwise pass `--entrypoint <path>`.",
text: "Directory publish keeps relative paths and skips `.git`, `node_modules`, `.DS_Store`, and `.env*`. The entrypoint is `index.html`, `index.md`, `README.md`, or the only file; otherwise pass `--entrypoint <path>`. Pass `--render-mode html|markdown|text|image|audio|video` only when inference is wrong.",
},
],
},
Expand Down
17 changes: 7 additions & 10 deletions apps/apex/src/docs/pages/dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ export const DASHBOARD_DOC: DocsPage = {
slug: "dashboard",
title: "Dashboard",
shortTitle: "Dashboard",
summary: "The dashboard is the human control plane for Workspaces, Artifacts, billing, and settings.",
summary: "The human control plane for Workspaces, Artifacts, billing, and settings.",
sections: [
{
id: "sign-in",
title: "Sign in",
blocks: [
{
kind: "paragraph",
text: "Open [app.agent-paste.sh](https://app.agent-paste.sh) or run `agent-paste login`. Both use WorkOS authentication. For a CLI in a sandbox or SSH session, use `agent-paste login --device-code` and approve from your own browser. See [remote login](/docs/cli#remote-login).",
text: "Open [app.agent-paste.sh](https://app.agent-paste.sh) or run `agent-paste login`. From a sandbox or SSH session, use `agent-paste login --device-code` and approve in your own browser. See [remote login](/docs/cli#remote-login).",
},
],
},
Expand All @@ -26,13 +26,10 @@ export const DASHBOARD_DOC: DocsPage = {
rows: [
["`/dashboard`", "Workspace overview, Usage Policy, recent Artifacts, and recent Audit Events."],
["`/artifacts`", "Artifact list with status, pinning, Bundle state, URL, and last publish time."],
[
"`/artifacts/{artifactId}`",
"Artifact detail, capability URL, Revisions, Bundle state, warnings, and delete action.",
],
["`/keys`", "Dashboard member credential list, create, and revoke controls."],
["`/audit`", "Workspace Audit Event list."],
["`/settings`", "Workspace name and default retention settings."],
["`/artifacts/{artifactId}`", "Artifact detail, URL, Revisions, Bundle state, warnings, and delete."],
["`/keys`", "Create and revoke member credentials."],
["`/audit`", "Workspace Audit Events."],
["`/settings`", "Workspace name and default retention."],
["`/billing`", "Plan, remaining writes, Checkout, Portal, and invoices."],
],
},
Expand All @@ -44,7 +41,7 @@ export const DASHBOARD_DOC: DocsPage = {
blocks: [
{
kind: "paragraph",
text: "The claim page accepts `/claim#<token>`. It requires a signed-in human and promotes the Ephemeral Workspace's Artifact into that member's Personal Workspace.",
text: "`/claim#<token>` requires a signed-in human and moves the ephemeral Artifact into that member's Personal Workspace.",
},
],
},
Expand Down
Loading