← Chitragupta Connect

It reads the apps
you already use.

One class per source, describing itself in a record the permission layer can actually reason about — so the gate understands send:email without knowing whether the app behind it is Gmail, Apple Mail or something you wired up yourself.

The contract

A connector describes itself

The manifest is read off the class, never hand-maintained beside it. That distinction is not pedantry: it is why the declared capabilities stayed true while hand-maintained lists elsewhere drifted.

ConnectorManifest
├── connector_id · display_name · provider · version
├── auth           method, and the lifecycle state of each connection
├── capabilities   frozenset[Capability]   ← the whole security surface
├── resources      what kinds of thing it holds
├── sync           strategy · incremental · resumable · cursor kind
├── events         webhook | polling | none, and the dedup key
├── health         supported? cost?
└── limits         requests/interval · concurrency · page size
One machine-readable record per connector.
Capabilities

Verbs on resources, never app names

A capability is a verb applied to a kind of thing — read:email, send:email, read:repository. It says what can be done, not what the app is called, so one gate reasons across all of them.

tiermeanswhat the gate does
READAnswers a questionNo approval
WRITEChanges something at the vendor, reversiblyThe risk tier decides
DESTRUCTIVENo inverse existsAlways asks. Never grantable
OUTBOUNDReaches a person who is not youNeeds a permitted recipient
Outbound is separate from write on purpose: a draft writes to your own mailbox and reaches nobody.
The connectors screenEach source with its state, what it may do, and when it last synced
The gate

One chain, and only one

connector declares capability
   → action registry names the capability it needs
   → permissions.check() evaluates risk + recipient
   → approval card, or a standing grant
   → connector executes
No second permission system anywhere in the path.
Sync

Four rules bought by shipped bugs

01

The checkpoint moves after the page is committed

The other order loses a page on a crash and reports success for it. A 2,000-item sync failing at 1,900 used to restart at zero; the unit became a page, and the rule did not move.

02

A truncated listing never tombstones

Sweeping one deletes the tail of a mailbox because a sync hit its own budget. The absence of an item is not evidence it was deleted.

03

One account is not one connector

Storage once keyed on the connector alone, which baked “provider equals account” into the schema. Connections, checkpoints, identity and provenance are all per account now — two mailboxes no longer fight.

04

Retry only what retrying could fix

403, 400, 401 and 404 are each a reason not to try again. The bounded loop is what stops a rate limit becoming a ban.

Beyond the built-ins

Anything else speaks MCP

Where there is no connector there is usually a protocol, and where there is no protocol there is a browser. A tool reached over MCP is gated by the same chain as a built-in one — and it is grantable per server:tool, because that is a stable, comparable, revocable key in a way an argument blob never is.

Want it on your Mac?

Free while it is in beta. Bring your own model — or run a local one and never leave the machine.

Join the waitlist→