cloudflare-os
Applicationcloudflare/cloudflare-os
AI-powered workspace for building documents and apps with agents.
Overview
Cloudflare OS is an agentic productivity environment with a chat UI, sandboxed app development, and the Gatekeepers security framework. Users create documents and custom mini-apps using AI agents, each running in private, sandboxed instances with human-in-the-loop approvals.
README Preview
# Cloudflare OS: An AI productivity environment\n\nCloudflare OS is an "operating system" for AI productivity originally developed for use inside Cloudflare. A large portion of Cloudflare's workforce -- from engineering to sales and everything in between -- uses Cloudflare OS every day to help them do their jobs.\n\n\n\nThis is not a traditional computer operating system. We use the term "operating system" in two senses:\n\n* An operating system for *the company* to be productive with AI, in a way that is safe, so that the security team can sleep at night.\n* An operating system for AI workloads, analogous to the sense in which a traditional operating system manages compute workloads.\n\nCloudflare OS provides three things in particular:\n\n1. An agent chat UI where you can ask agents to do tasks, preloaded with knowledge about how your company operates.\n2. Sandboxed application development, so that you can ask agents to build "gadgets" (small personal apps) and safely share what you've built with others.\n3. A security framework, called Gatekeepers, that applies guardrails to both agents and apps such that non-technical users can safely "go nuts" and nothing bad will happen.\n\nWe are making Cloudflare OS open source so that others can copy it and customize it for their own company. The idea is not that your company uses Cloudflare OS, but rather that you make it "*Your Company* OS".\n\n## Quick Start\n\nTo quickly run Cloudflare OS locally, [install pnpm](https://pnpm.io/), then do:\n\n pnpm run-local\n\nThen visit: http://localhost:8787\n\nThis runs the whole stack locally on wrangler and workerd. This is not meant for production use, but is a quick way to see what the product does.\n\nAlternatively, you can [deploy to your Cloudflare account](https://os.cloudflare.app/deploy).\n\n(More options at the end of this readme.)\n\n### What to try\n\nTry prompts like:\n\n* "Make slides for my upcoming meeting with a customer." (This will use the built-in slides blue
FAQ (5)
TroubleshootingHow do I fix GitHub gatekeeper connections failing with "Bad credentials" exactly 8 hours after connecting?
This affects new GitHub OAuth apps because GitHub now issues access tokens that expire after 8 hours and provides a refresh token. Older gatekeeper-github versions stored only the access token and discarded refresh_token, causing calls to fail after expiry.
Immediate workaround:
1. In GitHub, go to **Settings → Developer settings → OAuth Apps → select your app → Optional features**.
2. Opt out of **expiring user tokens**.
3. Have each affected user **Disconnect** and then **Connect** their GitHub account once. Tokens issued before the opt-out still expire.
Permanent fix: upgrade gatekeeper-github to a release containing the fix for issue #641. The fix persists refresh_token and token expiry, refreshes before expiration using POST https://github.com/login/oauth/access_token with grant_type=refresh_token, atomically stores GitHub's rotated token pair, serializes concurrent refreshes, and prompts reconnect when GitHub returns bad_refresh_token. OAuth apps without expires_in retain the previous non-expiring behavior.
TroubleshootingHow do I fix “Failed to find executable rm” when running workshop-frontend build or pnpm lint on Windows?
The Vite+ clean:dist task invokes the POSIX-only rm binary directly, so Windows cannot find it. In packages/workshop-frontend/vite.config.ts, replace command: 'rm -rf dist' with Node's built-in filesystem removal:
'clean:dist': {
command: `node -e "require('node:fs').rmSync('dist', { recursive: true, force: true })"`,
cache: false,
}
Alternatively, update to a revision containing PR #373 (c0ccaa1), which uses fs.rmSync(..., { recursive: true, force: true }). Then rerun pnpm exec vp run -F @gadgets/workshop-frontend --no-cache build or pnpm lint.
TroubleshootingHow do I fix bundled blueprint test failures on Windows where expected paths use '/' but actual paths use '\'?
The implementation is correct; the tests hard-code POSIX path separators. On Windows, Node's readlinkSync() and path.relative() return backslash-separated paths. Fix scripts/build-bundled-blueprints.test.ts by making assertions platform-aware: compare the symlink target with path.normalize("../NOTES.md"), and change the error-message regexes to match either separator, for example /ignored by Git: example[\\/]files[\\/]dist[\\/]client\.js/ and /ignored by Git: example[\\/]blueprint\.json/. Then run pnpm --filter @gadgets/scripts test. This is the fix in PR #653, verified on Windows 11 and Ubuntu/WSL with Node 24.18.0. As a temporary workaround, run the tests under WSL. The separate gatekeeper-google failures are unrelated and are caused by Git for Windows checking out symlinks as plain files when core.symlinks=false.
TroubleshootingWhy does the Confluence gatekeeper show "Credentials expired" after one hour even though the refresh token works?
The Confluence gatekeeper records the short-lived Atlassian access token's one-hour expiry as the overall credential expiry. After that time, the UI marks the account expired even though getAccessToken() can transparently use the rotating refresh token. To fix it, edit packages/gatekeeper-confluence/src/confluence.ts and remove the expiresAt/new Date(grant.expiresAt) argument from callback.complete(), callback.reconnectComplete(), and callback.credentialsRestored(). Rely on the normal refresh path and the explicit credentialsExpired() signal sent only when refresh actually fails. Until patched, using an existing Confluence binding triggers a refresh and temporarily clears the expired state; reconnecting also works but the message returns after one hour.
TroubleshootingHow do I fix 'GitLab OAuth token response was incomplete' when connecting a self-hosted GitLab older than 15.0?
This happens with self-hosted GitLab versions before 15.0, such as GitLab 13.3, because non-expiring OAuth tokens omit expires_in. The GitLab gatekeeper must not treat that field as required.
Fix the token exchange handling so expires_in is optional; when it is missing, leave expiresAt empty/undefined, which the credentials kit treats as a token that never needs refreshing:
if (typeof tokenResponse.expires_in === "number") {
credentials.expiresAt = new Date(
Date.now() + tokenResponse.expires_in * 1000
).toISOString();
} else {
credentials.expiresAt = undefined; // GitLab < 15.0: token does not expire
}
Only access_token should be required. Rebuild and redeploy Cloudflare OS, remove the failed GitLab connection if necessary, and reconnect through OAuth. Alternatively, upgrade GitLab to 15.0 or newer, or use a release containing the referenced fix.