Skip to content

Get started ​

OpenAct runs on your own Cloudflare account. You need a Cloudflare account and a Resend account for sign-in emails.

Deploy to Cloudflare

Deploy with one click ​

  1. Click Deploy to Cloudflare.
  2. Sign in to Cloudflare. Connect GitHub or GitLab. Cloudflare copies this repository to your account.
  3. Cloudflare creates the D1 database, the R2 bucket and the Vectorize index for you.
  4. Fill in the form:
    • RESEND_API_KEY: your Resend API key.
    • AUTH_SECRET: a long random string. Make one with openssl rand -hex 32.
    • EMAIL_FROM: the sender, for example OpenAct <no-reply@yourdomain.com>.
  5. Click Deploy. The deploy script applies the database migrations, then deploys the Worker.

After the first deploy:

  1. In Resend, verify the domain that you use in EMAIL_FROM. Without this step, sign-in emails do not arrive.
  2. In the Cloudflare dashboard, go to AI > AI Gateway and make a gateway named openact. If the gateway does not exist, AI requests still work, but without gateway logs and limits.
  3. Open your Worker URL. Type your email. The first person can always sign up.
  4. Search by meaning needs a Vectorize index with 768 dimensions and a project_id metadata index. If search shows "Search by words" only, run npm run search:setup once from a copy of the repository. Search by words works without it.

Deploy by hand ​

You need Node.js 20 or later and a Cloudflare account.

sh
git clone https://github.com/marketgrowth/openact.git
cd openact
npm install
npx wrangler login

# Make the database. Copy the database_id from the output into wrangler.jsonc, under d1_databases.
npx wrangler d1 create openact

# Make the file bucket.
npx wrangler r2 bucket create openact-files

# Make the search index (768 dimensions, cosine, with a project_id metadata index).
npm run search:setup

# Add the secrets.
npx wrangler secret put RESEND_API_KEY
npx wrangler secret put AUTH_SECRET

# Set EMAIL_FROM and the other settings in wrangler.jsonc under "vars". Then build and deploy.
npm run build
npm run deploy

npm run deploy applies new migrations, checks the search index, then deploys. Use it for every update.

Run it on your computer ​

sh
npm install
cp .dev.vars.example .dev.vars   # optional
npm run dev

Open http://localhost:8787.

  • Without RESEND_API_KEY, OpenAct does not send email. It prints each sign-in code in the terminal.
  • npm run dev runs fully local, so AI assist and search by meaning are off. Search by words still works. To use AI on your computer, run npx wrangler login, then npm run dev:ai.
  • For hot reload of the web app, run npx wrangler dev --local in one terminal and npm run dev:ui in a second terminal. Then open http://localhost:5173.

Other commands:

CommandWhat it does
npm run typecheckChecks the types of the Worker and the web app
npm testRuns the unit tests
npm run test:searchRuns the search pipeline test: real migrations in SQLite, with fake Vectorize and Workers AI
npm run search:setupCreates the Vectorize index and its metadata index. Safe to run again.
npm run buildBuilds the web app into dist/client
npm run db:migrate:localApplies migrations to the local database
npm run db:migrate:remoteApplies migrations to the Cloudflare database

Settings ​

Set these under vars in wrangler.jsonc, or in the Cloudflare dashboard.

NameDefaultWhat it does
APP_NAMEOpenActThe default name in the app and in emails. A super admin can change it in Site settings.
SUPER_ADMIN_EMAILSemptyA comma-separated list of the emails that can change the app name, the logo and which apps are on for the site. Empty means nobody can.
APP_URLemptyThe public URL used in email links. Empty means the URL of the request.
EMAIL_FROMOpenAct <no-reply@example.com>The sender address. The domain must be verified in Resend.
SIGNUP_MODEopenopen: anyone can sign up. invite: only invited people can sign up.
ALLOWED_EMAIL_DOMAINSemptyA comma-separated list of domains that can sign up, for example example.com,example.org
AI_PROVIDERworkers-aiworkers-ai, anthropic or openai. This is the deploy default. A company owner can choose Claude with their own key. Read The AI provider of a company.
AI_MODEL@cf/meta/llama-3.3-70b-instruct-fp8-fastThe model ID for the provider
AI_EMBED_MODEL@cf/baai/bge-base-en-v1.5The Workers AI model for search embeddings. It must make 768-dimension vectors.
AI_SCOPE_MODEL(empty)A small, fast model for the topic check. Empty uses @cf/meta/llama-3.1-8b-instruct-fast, claude-haiku-5-5 or gpt-4.1-mini, by provider.
AI_GATEWAY_IDopenactThe AI Gateway name. Empty turns the gateway off.
CF_ACCOUNT_IDemptyYour account ID. Needed for anthropic and openai.
TYPESAFE_MODELjev-1.14.0The Jev release for the topic check. Pinned, because the thresholds are set for it.
TYPESAFE_BASE_URLhttps://api.typesafe.aiAnother URL for the TypeSafe API, such as a gateway

Set these secrets with npx wrangler secret put NAME:

SecretNeededWhat it does
RESEND_API_KEYYesSends sign-in codes and invitations
AUTH_SECRETYesProtects stored sign-in codes, the encrypted AI keys of companies and the saved Docs share links. Use 32 or more random characters. If you change it, company owners must paste their AI keys again. Old share links still open, but editors must make a new link to copy one again.
ANTHROPIC_API_KEYFor anthropicAnthropic API key, sent through AI Gateway
OPENAI_API_KEYFor openaiOpenAI API key, sent through AI Gateway
AI_GATEWAY_TOKENNoNeeded only if your AI Gateway uses authentication
TYPESAFE_API_KEYNoTurns on Jev for the topic check. Get a key from TypeSafe.

The first person to sign in can always make an account, even in invite mode. An invitation always lets that email sign up, even when ALLOWED_EMAIL_DOMAINS does not include its domain.

Durable Objects ​

wrangler.jsonc binds two Durable Object classes. Wrangler makes them on the first deploy.

BindingClassWhat it does
PROJECT_ROOMSProjectRoomLive updates for projects and docs lists. Without it, pages check for changes every few seconds.
DOCS_ROOMSDocsRoomLive editing in Docs. Without it, Docs saves the usual way.

Site name, logo and apps ​

A super admin sets the name and logo that everyone on the site sees, and can turn an app off for the whole site.

  1. Add your email to SUPER_ADMIN_EMAILS in wrangler.jsonc, then deploy.

  2. Sign in. Open your menu at the bottom of the app rail, then choose Site settings.

  3. Type the app name, then choose Save name. Leave it empty to use APP_NAME again.

  4. Choose Upload logo. Use a PNG, JPEG or WebP image, up to 1 MB. A square image looks best.

  5. Under Apps, turn an app off to hide it in every company. Its data stays. Companies cannot turn it on again until a super admin does.

The name shows on the sign-in page, in the browser tab, in the company menu and in emails. The logo shows on the sign-in page and as the browser tab icon. Without a logo, the OpenAct mark shows.

A super admin is not a company role. Super admins change only the site settings. They get no access to company data.

An app that is off for the site is off in every company: its pages, its API and its public links stop working. You cannot turn every app off. Keep at least one on.

Each Worker keeps the settings for up to 30 seconds. After a change, other open pages show it when they load again.

Security headers ​

The file public/_headers sets the security headers for the web app. Cloudflare sends them with index.html and every static file.

  • Content-Security-Policy lets the page load scripts, styles, images and data only from your own site. Fonts can also come from Google Fonts. Other sites cannot show the app in a frame.
  • Strict-Transport-Security tells browsers to use only HTTPS for one year.
  • The public build has no source maps. The Worker's source maps go only to Cloudflare, for error stack traces.

If an app loads files from another site, add that site to the matching directive in public/_headers. For example, add https://images.example.com to img-src.

Delete an account ​

A person can delete their own account. They open Account from their menu, choose Delete account, then type their email to confirm.

  • They leave every company, and their sessions end.
  • Projects, tasks and files that they made stay with the company. Their name leaves them: assignments and "created by" fields become empty.
  • The only owner of a company cannot delete their account. They must make another person an owner, or delete the company, first.

How sign-in works ​

  1. A person types their email. OpenAct makes a random 6-digit code and sends it with Resend.
  2. The code works for 10 minutes and for 5 tries. Only the newest code works.
  3. When the code is correct, OpenAct sets a session cookie for 30 days. The cookie is HttpOnly and SameSite=Lax, and Secure on HTTPS.
  4. Pending project and company invitations for that email become memberships. If a company claimed the email's domain, the person joins it as a member.

OpenAct stores only SHA-256 hashes of codes and session tokens. It limits code requests to 5 for each email in 15 minutes and 30 for each IP address in one hour. A daily cron job deletes old codes and sessions.

Apache License 2.0. Made by MarketGrowth.