Trust
- Your assistantAny MCP client
- MCP, after an OAuth sign-in
- Trust boundaryYour Cloudflare account
- codemode MCPThe MCP server, a Worker of its own
- Bearer token on every API call, after a PKCE sign-in
- Optical WorkerSign-in, the REST API, calendar webhooks, planning
- D1 databaseScheduling data, with calendar grants encrypted
- KVToken cache
- Fallback solverIts own Worker, running a containerService binding only, no public route
- Each person's own OAuth grant
- Google Workspace or Microsoft 365Calendar and mail APIs
Where it runs
Optical runs on Cloudflare, in a Cloudflare account your organisation holds. A TypeScript Worker handles sign-in, the API, calendar webhooks, planning and cron. The main Worker also runs the primary solver, an exact engine. The fallback is OR-Tools’ CP-SAT solver, which a second Worker, the solver Worker, runs in a Cloudflare container. By default the container steps in only when the engine can’t certify its answer; configuration can instead make the container the only solver, which takes more infrastructure management. The solver Worker has no public route; the main Worker reaches it only over an internal service binding. The database (D1), token cache (KV), DNS and Cloudflare Access are provisioned as code.
The API (/v1/*) is bearer-authenticated: a caller presents an OAuth token
minted through a PKCE sign-in. Your assistant’s caller is codemode MCP, a
separate MCP server in the same account; one codemode MCP serves the
whole organisation, and Optical itself exposes only this REST API. Admin routes need a bearer token with the
admin scope, held by a user with the admin role. The one browser-facing
admin page is gated by Cloudflare Access instead.
Some routes take no bearer token:
- Emailed plan-accept links carry a signed, time-limited token.
- Calendar webhooks carry a signed channel token.
- When the booking page or meeting polls are switched on, their public pages accept submissions without sign-in, behind a Cloudflare Turnstile challenge or a per-invitee link token.
- The OAuth revocation endpoint accepts a token to revoke without further authentication.
Your deployment, your rules
A deployment of Optical is two Workers (the main Worker, which also runs
the primary solver, and the solver Worker, which runs the fallback solver’s
container) and one D1 database, in one Cloudflare account. The operator decides who may sign in, with a
membership allow-list of addresses or whole domains; everyone admitted
shares that deployment. Every API query is scoped to the signed-in user
(owner_subject), so one person’s tasks, plans and calendar sync state
are not returned to another.
A person can choose to publish their availability through a booking page or a busy feed. People with access to the Cloudflare account itself can read the database directly.
That account is yours: every organisation deploys its own Optical, so there is no shared instance, and we have no standing access to it. We get temporary access only if you grant it because you want our help.
How your data is held
Google and Microsoft refresh tokens — the standing permission to read and write your calendar and send mail as you — are encrypted with AES-GCM before they are stored in D1. The key is a Cloudflare Worker secret, not a database value. Bearer tokens used to call the API are stored as hashes. Unless the operator sets separate keys, the encryption, hashing and signing keys all derive from one secret.
Scheduling data — tasks, projects, templates, proposed plans, calendar sync state — is keyed to its owner, and every API query is scoped to the signed-in user. People with access to the Cloudflare account can read the database directly.
Optical can capture solver inputs, which include task and event titles, to an R2 bucket in the same Cloudflare account for solver diagnostics. Capture is off in customer deployments, and off by default in the code.
Google Workspace scopes
Your organisation creates and manages its own OAuth client in its own Google Cloud project, so you control the consent screen and can revoke it at any time.
Signing in with Google grants Optical four scopes, with offline access so it keeps working when you are not signed in:
- calendar events (read/write, to place and move your blocks)
- calendar free/busy (to check attendee availability for meetings you organise)
- Gmail send (to send replan emails to you, and poll and booking emails to the people involved, from your address)
- your email address (for identity)
A deployment may enable extra diagnostic scopes. If it does, they are added to the scope list you consent to at sign-in.
Microsoft 365 scopes
Your organisation creates and manages its own application registration in its own Microsoft Entra tenant, so you control the consent and can revoke it at any time.
Signing in with Microsoft 365 grants Optical:
- your identity (openid, profile, email)
- offline access, so it keeps working when you are not signed in
- calendar read/write, which also covers free/busy
- mail send (to send replan emails to you, and poll and booking emails to the people involved, from your mailbox)
Optical does not request User.Read: your identity comes from the sign-in
token, not from a Graph profile lookup. A deployment may enable one extra
diagnostic scope. If it does, the scope is added to the permissions
requested at sign-in and needs consent like the others.
What the assistant can reach
Optical has no MCP server of its own. Your assistant connects to codemode
MCP, a separate MCP server running as its own Worker in your Cloudflare
account. It signs in to Optical like any OAuth client, with PKCE, and calls
Optical’s REST API (schema/openapi.json) with a bearer token. Through it, the assistant can:
- create, change and delete tasks, templates and projects
- ask for a plan, and accept or discard one
- adjust per-category scheduling preferences and the solver’s weights, including churn against fit
- manage your booking page and busy feeds
- create, edit, nudge, cancel or book meeting polls, which emails the invitees
A plan reaches your calendar only through an accept or commit call. Outside plans, the API changes your calendar when a task is deleted or marked done (its own blocks are removed or recoloured) and when a meeting poll books.
The API has no write operation for your business hours, your account
meeting policy or your home timezone (these are coming soon): it reads
them; the operator sets them. Done-task marking is handled within
Optical; the MCP can read task statuses through the API. The API returns
the underlying Google access token only to a client the operator has
registered with the calendar:raw-token scope (which can be disabled at
the OAuth level for security if preferred; it is used only for the
automated tests). codemode MCP is registered with scheduler:read and
scheduler:write only, so MCP calls can’t directly make arbitrary changes
to a calendar.
What's set once, by the operator
Some things are deployment configuration, not conversation:
- who may sign in (a membership allow-list)
- whether Microsoft 365 sign-in is enabled
- which optional features are on: owned meetings, the booking page, meeting polls, busy feeds
- the default business hours, 09:00–17:00 Monday to Friday unless changed; a task with no pin and no hard window is placed inside them
- the done colour (in Outlook, the done category) that a repaint has to match
The operator sets these when the deployment is stood up and changes them later. The API has no write operation for any of them.
Threat model
A full threat model exists, covering entry points, trust boundaries and mitigations. It isn’t published here — ask us and we’ll share a summary.
Ask us about this: info@optical-scheduler.com
Microsoft 365 support
Google Workspace and Microsoft 365 are both supported. The calendar provider is chosen per person, not per deployment. Microsoft 365 sign-in is switched on per deployment with a flag, once the deployment is registered in Microsoft Entra; switching it off again freezes calendar sync for existing Microsoft users until it is back on.
Known limitations:
- Cross-provider free/busy. A Google attendee on a Microsoft-organised meeting (or the reverse) can’t be read through the organiser’s API; the meeting is treated as immovable.
- Done-marking is exact-category-name coupled. Renaming or deleting the category in Outlook silently stops done-marking; un-marking clears categories added to that block by hand.
- Only meetings you organise move. Optical won’t move a meeting you’ve been allowed to edit as a guest but don’t organise. The same applies on Google.
- No rich webhook payloads. Every ping triggers a refetch.
- No PKCE on the Microsoft OAuth flow in v1. It is a confidential client; Microsoft recommends but does not require PKCE there.
- No switch-time ghost sweep. A provider switch leaves committed blocks on the old calendar and abandons the old push channel.
- Weekly channel-secret rotation is date-derived, not recorded.
Timezones
Today, a deployment runs on one instance timezone, set by the operator — that’s the clock every week is planned and committed against. A per-user home timezone exists in the data model and is honoured for where things are placed, but it’s set by the operator too; there’s no self-service way for a person to change their own yet. Self-service per-user timezones are coming.
Delegated access
Today each person sees only their own tasks and plans. Delegated access, letting an assistant see and manage an executive’s tasks and plans with their permission, is coming.