Publish a folder to a company-private URL.
An organization installs Up once in its Cloudflare account. Employees and coding agents can then publish small internal apps without creating a repository, deployment pipeline, database, credentials, or authentication flow for each app.
folder + name → verified upload → atomic activation → company-private URL
Dogfood: https://up.ax.cloudflare.dev · Version: 0.0.1
Browser:
Open Up → choose folder → choose name → publish
CLI:
bunx github:acoyfellow/up init
bunx github:acoyfellow/up deploy ./dist lunch-voteAuthenticated · 3 files ready
Uploading 3/3 style.css
Published
https://lunch-vote.up.example.com
Access: your organization
Both clients use the same manifest, upload, and activation API. A copied URL does not grant access; Up verifies a company session before returning content.
Every site can import one same-origin module:
import { up } from '/_up/client.js';
const viewer = await up.identity.current();
const votes = up.db.collection('votes');
await votes.create({ choice: 'Tacos', voter: viewer.email });
await up.files.put('menu.txt', new Blob(['Tacos · Pizza · Salad']));
const result = await up.ai.chat([
{ role: 'user', content: 'Summarize today’s vote' }
]);
const room = up.realtime.channel('votes');
room.on('vote', renderVote);
room.send('vote', { choice: 'Tacos' });Browser code receives no Cloudflare credentials or resource identifiers.
| API | Cloudflare mechanism |
|---|---|
up.identity |
Access-backed Up session |
up.db |
site-named SQLite Durable Object |
up.files |
site-prefixed private R2 objects |
up.ai |
Workers AI with a fixed model and limits |
up.realtime |
site-and-channel Durable Object WebSockets |
Lunch Vote ↗ is a live, employee-protected app using all five fixed APIs. Its three-file source is plain HTML, CSS, and JavaScript with no _worker.js, credentials, framework, or infrastructure configuration. Browse it from the documentation’s compact examples page.
Up uses Cloudflare OAuth. The current operator path is:
export UP_OAUTH_CLIENT_ID=<client-id>
bun run oauth:connect
export CLOUDFLARE_ACCOUNT_ID=<account-id>
export UP_CONTROL_HOST=up.example.com
export UP_PARENT_ZONE=example.com
export UP_ALLOWED_DOMAIN=example.com
bun run setupThe installer creates customer-owned resources:
Cloudflare Access
↓
Up Worker + SvelteKit assets
├── private R2
├── Registry Durable Object
├── Database Durable Object namespace
├── Realtime Durable Object namespace
└── Workers AI
The Worker, Access application, DNS, R2, and Durable Objects remain visible in the customer account. workers.dev and preview URLs stay disabled.
Alchemy v2 was tested and omitted from this revision because it cannot yet express Workers AI and Access without custom provider code. See receipts/2026-06-19-alchemy-v2-decision.md.
- Every new site is company-private.
- The site hostname selects scope only after Up verifies identity.
- Site A cannot address Site B’s database, files, or realtime room.
- Browser code never receives AI or storage credentials.
- Deployment files stay pending until every path, size, and SHA-256 digest passes verification.
- Activation changes one pointer, so visitors receive a complete old or complete new deployment.
- Anonymous probes receive Access before uploaded bytes.
Read SECURITY.md for the exact contracts.
src/core-backend.ts deploy protocol and site request routing
src/capabilities.ts fixed browser API and site scoping
src/site-database.ts document collections
src/site-realtime.ts authenticated channel WebSockets
src/auth.ts Access JWT verification
cli/up.ts init and deploy
skills/up/ agent instructions and client types
examples/lunch-vote/ complete framework-free proof
tests/up.test.ts runtime, capability, and isolation proof
wrangler.jsonc installation graph
The source contract is captured in docs/0.0.1-source-brief.md.
bun install
bun run check
bun run test:e2eThe suite uses the real Workers runtime, SQLite Durable Objects, R2, WebSockets, SvelteKit SSR, and Access/session logic. It does not use application mocks.
MIT © Jordan Coeyman