Skip to content

Commit ce7a6f5

Browse files
committed
feat(coda): add permission-aware knowledge connector
1 parent 59a364a commit ce7a6f5

24 files changed

Lines changed: 2350 additions & 6 deletions

File tree

‎apps/docs/content/docs/knowledgebase/connectors.mdx‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ Connectors continuously sync documents from external services into your knowledg
1616

1717
<Image src="/static/connectors/connectors-sources.png" alt="The current Connect Source picker showing searchable connectors including Airtable, Asana, Ashby, Azure DevOps, Bitbucket, Box, and ClickUp" width={750} height={680} className="mx-auto h-auto w-full max-w-md" />
1818

19-
Sim ships with 64 built-in connectors:
19+
Sim ships with 66 built-in connectors:
2020

2121
| Category | Connectors |
2222
|----------|-----------|
23-
| **Productivity** | Notion, Confluence, Asana, Linear, Jira, Jira Service Management, Monday, Trello, ClickUp, Google Calendar, Google Sheets, Google Forms, Microsoft Excel, Typeform |
23+
| **Productivity** | Coda, Notion, Confluence, Asana, Linear, Jira, Jira Service Management, Monday, Trello, ClickUp, Google Calendar, Google Sheets, Google Forms, Microsoft Excel, Typeform |
2424
| **Cloud Storage** | Google Drive, Dropbox, OneDrive, SharePoint, Box, Amazon S3, SFTP |
2525
| **Documents** | Google Docs, Google Slides, Mintlify, WordPress, Webflow, DocuSign |
2626
| **Development** | GitHub, GitLab, Bitbucket, Azure DevOps, Sentry |
@@ -31,7 +31,7 @@ Sim ships with 64 built-in connectors:
3131
| **Incident Management** | incident.io, Rootly, PagerDuty |
3232
| **Data** | Airtable, Databricks |
3333
| **Note-taking** | Obsidian |
34-
| **Meetings** | Zoom, Google Meet, Gong, Grain, Granola, Fathom, Fireflies |
34+
| **Meetings** | Zoom, Google Meet, Gong, Grain, Granola, Fathom, Fireflies, Circleback |
3535
| **Recruiting** | Greenhouse, Ashby |
3636
| **HR** | Workday Help |
3737
| **Compliance** | Google Vault |
@@ -52,6 +52,7 @@ Other connectors use **API keys** or **personal access tokens** instead. The set
5252
| Connector | Where to get the key |
5353
|-----------|---------------------|
5454
| **Obsidian** | Install the [Local REST API](https://github.com/coddingtonbear/obsidian-local-rest-api) plugin, then copy the key from its settings |
55+
| **Coda** | API token from Account settings → API connections, saved as a Coda service account credential |
5556
| **Fireflies** | Generate from the Integrations page in your Fireflies account |
5657
| **Typeform** | Personal access token from your Typeform account settings |
5758
| **Azure DevOps** | Personal access token with Wiki (Read), Work Items (Read), and Code (Read) scopes |
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
---
2+
title: Coda
3+
description: Index Coda pages and tables with each teammate's source permissions
4+
---
5+
6+
import { Callout } from 'fumadocs-ui/components/callout'
7+
8+
An organization admin connects a Coda API token. Sim indexes the selected documents and matches their sharing permissions to teammates' verified Sim email addresses. Teammates do not need a personal OAuth connection for this source.
9+
10+
## Set up the source
11+
12+
1. In Coda, open **Account settings → API connections** and generate an API token for the account that will index your documents. Coda's current app may be labeled **Superhuman Docs**. The account must be able to read the documents and their sharing permissions.
13+
2. In Sim, open **Settings → Sources → Add source → Coda**. Add or select a Coda service account credential and paste the API token when prompted.
14+
3. Select **Documents**, or use the switch beside that field to enter **Document IDs**, separated by commas. In a Coda URL such as `https://coda.io/d/_dAbCDeFGH`, the document ID is `AbCDeFGH`. Select up to 100 documents per source. The picker shows documents the token owner can access and has opened; use IDs for other Enterprise organization documents.
15+
4. Leave **Enterprise organization ID** empty for ordinary token-based access. For organization-wide access, use an Enterprise organization administrator's token and enter the organization ID returned by Coda's [Admin API](https://coda.io/developers/apis/admin/v1).
16+
5. Select **Connect & Sync**. Open the source's **Documents** and **Sync history** to check its progress.
17+
18+
API tokens do not refresh automatically. When rotating a token, add the replacement credential, update the source, and verify a sync before revoking the old token. Indexing only reads Coda content; a broadly authorized token may allow other operations in Coda.
19+
20+
## Document selection and content
21+
22+
Explicit document IDs provide the clearest sync scope and include accessible documents the token owner has not opened. If IDs are empty, ordinary discovery includes only accessible documents the token owner has previously opened. Enterprise discovery uses the organization's document list.
23+
24+
Discovery pages can change order while syncing. Sim therefore does not delete existing indexed content solely because it disappears from a discovery listing. Use explicit document IDs when reliable deletion reconciliation is required. Discovery runs may report incomplete reconciliation; this does not mean their returned content failed to index.
25+
26+
| Connection | Indexed content |
27+
| --- | --- |
28+
| Ordinary API token | Visible canvas page text and base tables, including all listed columns and rows. Hidden pages, embedded pages, synced pages, and duplicate table views are excluded. |
29+
| Enterprise organization | Page content returned by the Admin API's `LossyPlainText` format. Tables are represented only to the extent included in that export; they are not separately read through the public table API. |
30+
31+
Comments, attachments, images, and arbitrary embedded applications are not extracted. The connector stops with an error rather than indexing truncated content when a provider response, document, or pagination limit is exceeded. If the Enterprise API omits a document revision timestamp, Sim refreshes that document on each crawl.
32+
33+
Document edits invalidate the pages and tables within that document. A full resync also refreshes rendered content whose dependencies may have changed without changing the document revision. This costs more API calls and processing than a regular sync. Ordinary unchanged documents retain their indexed content while their permissions are refreshed.
34+
35+
## How teammate access works
36+
37+
| Coda permission | Ordinary token | Enterprise organization |
38+
| --- | --- | --- |
39+
| Owner or direct email share | Matches the verified Sim email | Matches active users in the organization directory |
40+
| Group share | Excluded | Resolves group members through the Admin API |
41+
| Workspace share | Excluded | Resolves that Coda workspace's members |
42+
| Domain share | Excluded | Matches active organization-directory users in that exact domain |
43+
| Anyone with the link | Does not grant Search access | Does not grant Search access |
44+
45+
Enterprise mode excludes deactivated or deleted organization users. Directly shared external guests absent from the organization directory are also excluded. A guest explicitly returned in a group's or workspace's membership can receive that group's or workspace's access, unless the organization directory marks them inactive.
46+
47+
Ordinary token mode cannot independently check organization-level Coda account deactivation. Manage the person's Sim membership as well, or use Enterprise directory synchronization when that check is required.
48+
49+
Unknown permission types never become broad access. Sim admin status does not override Coda permissions, and a workspace API key does not inherit an individual's Coda access. A source created in **workspace access** mode inside an ordinary knowledge base intentionally shares its indexed content with that workspace; organization Search requires source permissions.
50+
51+
<Callout type="info">
52+
Permission changes take effect after synchronization. Each sync reads sharing again, including for unchanged content. If sharing or directory data cannot be completely verified, the connector fails closed through Sim's permission-sync handling. A verified Sim email must match the address Coda reports; aliases are not inferred.
53+
</Callout>
54+
55+
## Troubleshooting
56+
57+
| Problem | What to check |
58+
| --- | --- |
59+
| No documents found | Open the documents as the token owner or enter their IDs explicitly. |
60+
| Enterprise setup fails | Confirm the account is an Enterprise organization administrator and the organization ID is correct. An ordinary workspace admin token is insufficient. |
61+
| Content exists but a teammate cannot search it | Check the verified Sim email, Coda share, selected scope, and sync history. Ordinary mode cannot resolve group, domain, or workspace-only shares. |
62+
| Cross-domain sharing is prohibited | Coda's organization policy blocks that share. Use a permitted test account or an existing workspace that permits the intended share. |
63+
| New document temporarily unavailable | Coda may return `409` while initializing its API snapshot. The connector retries; retry the sync if initialization takes longer. |
64+
| Oversized or malformed response | The sync preserves its failure state instead of treating a partial response as complete. Narrow the scope or contact your operator. |
65+
66+
The connector uses Coda's [public API](https://coda.io/developers/apis/v1) and optional [Enterprise Admin API](https://coda.io/developers/apis/admin/v1). It needs no additional OAuth app configuration on self-hosted Sim.

‎apps/docs/content/docs/search/connect-your-account.mdx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ For a source configured inside a workspace, join that workspace and connect thro
6060
| GitHub App installation | Connect GitHub once for this Sim organization. The App handles indexing; your account establishes which repositories you may search. |
6161
| Confluence service account | Connect Confluence to verify your identity; the service account handles the crawl. |
6262
| Google Workspace service account (Gmail, Calendar, Drive) | No personal connection is needed for that source. Your verified Sim email identifies your mailbox and calendar view, or is matched to Drive permissions. |
63+
| [Coda](/search/coda) | No personal connection is needed. Your verified Sim email must match a supported Coda sharing grant. |
6364
| GitLab | No personal connection is needed. For an administrator token, your verified Sim email must match your confirmed primary GitLab email. For a non-admin token, it must match the uploaded user mapping and have a project grant. |
6465

6566
Gmail, Calendar, and Drive are separate Search sources. Connecting one Google service does not connect all of them. Central Google and GitLab sources remain searchable without a personal account connection.

‎apps/docs/content/docs/search/meta.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"pages": [
44
"connect-your-account",
55
"mcp",
6+
"coda",
67
"confluence",
78
"github",
89
"gitlab",

‎apps/sim/connectors/coda/README.md‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Coda connector decisions and verification
2+
3+
## Precedent and authentication
4+
5+
[Glean](https://www.glean.com/connectors/coda) supports Coda document/page search with source permissions. [Onyx's connector](https://github.com/onyx-dot-app/onyx/blob/main/backend/onyx/connectors/coda/connector.py) reads page text and table rows using a Coda API token; its content connector is not evidence that ordinary tokens expose an organization directory.
6+
7+
This connector reuses Sim's existing `coda-service-account` token credential and its selector. The metadata's `oauth` discriminator means “use a stored credential” in the shared connector framework. The actual credential is an API token, with no OAuth authorization or refresh flow. Personal credential-group enrollment is not exposed because that flow currently requires OAuth. Admin indexing matches provider-reported grants to verified Sim emails instead.
8+
9+
## Access tradeoffs
10+
11+
- Without an organization ID, only ownership and direct email grants establish individual access. Workspace, domain, group, and unknown principals are not expanded. Link possession never grants Search access. The public API does not provide organization account status; this mode cannot independently detect organization-level deactivation while a direct grant remains. Sim membership lifecycle must also be managed.
12+
- With an Enterprise organization ID, the Admin API supplies organization discovery and directory membership. Direct users and domains use synthetic groups so deactivated/deleted organization users cannot resolve grants. External direct-share guests absent from the organization directory are conservatively excluded. Explicit group/workspace guests remain eligible unless the directory reports them inactive.
13+
- Opaque group/workspace IDs are hex encoded before shared case-folding. Tenant IDs remain source-exact. This avoids merging case-sensitive Coda IDs.
14+
- Every listed document's complete ACL is read on every sync, independently of content hashes. Partial/failed ACLs are omitted so the shared engine fails closed. Directory snapshots are collected under the shared directory lease and never reported complete after a truncated response.
15+
- Permission freshness, query authorization, and directory persistence remain in the existing shared engines. Workspace access mode deliberately grants workspace-wide access and is separate from organization Search.
16+
17+
## Content and pagination tradeoffs
18+
19+
The [public API](https://coda.io/developers/apis/v1) exposes canvas plaintext and base-table rows; the [Admin API](https://coda.io/developers/apis/admin/v1) exposes `LossyPlainText` page exports. Admin exports are not equivalent to independently fetching every table. Hidden/embed/synced pages are excluded on the public path; the Admin API does not expose those public page-type flags. Neither path extracts arbitrary attachments or remote embeds.
20+
21+
Admin document reads use the current workspace-qualified endpoints, resolving the workspace with the documented organization `docIds` filter. Metadata queries request `fetchPermissionsMode=none`; permissions come only from the complete paginated ACL endpoint.
22+
23+
Listing defers content and retains only the current parent document metadata in the per-run context, avoiding one redundant parent fetch per child. Resource content and permissions are still read from the provider; ACLs never use that metadata cache. Discovery fetches ten parent documents at a time. Compound cursors persist that bounded queue, the current document, child phase, and provider token for durable replay, under the shared 512 KiB cursor limit. Only `pageToken` is sent on continuation requests, as Coda requires. No response URL or redirect receives the credential. Responses, text, list lengths, ACLs, directory entries, and pagination loops are bounded and fail rather than silently truncating. Responses are limited to 4 MiB, indexed text to 12 MiB, and hydration concurrency to two. The stubs advertise the text bound to the shared byte-budget scheduler. Directory entries are limited to 100,000, email lengths to 254, and document permissions to 5,000. Domain memberships are indexed once instead of scanning every user for every domain.
24+
25+
Hashes use the parent document revision because table-list references do not guarantee a row-sensitive timestamp. A document edit invalidates all its children, trading extra reads for correctness. Explicit full resyncs also refresh rendered dependencies. When the Admin API omits its optional revision timestamp, the shared durable sync-generation ID forces one refresh per crawl, following the Slack/GitLab pattern. It remains stable across retries within that generation.
26+
27+
Discovery order is mutable and the public list omits never-opened documents. Discovery is therefore non-authoritative for deletion reconciliation. Explicit document IDs provide authoritative scope; confirmed 404/410 documents reconcile, while 403s remain errors. Up to 100 explicit IDs are supported per source. Setup probes one document and one ACL page to keep request latency bounded; sync checks the remaining scope.
28+
29+
## Reproducible checks
30+
31+
From `apps/sim`:
32+
33+
```sh
34+
bunx vitest run connectors/coda/coda.test.ts connectors/coda/permissions.test.ts lib/selectors/server/providers/coda.test.ts lib/credentials/token-service-accounts/validators/coda.test.ts lib/selectors/manifest.test.ts
35+
CODA_CONNECTOR_LIVE_TOKEN_FILE=/path/to/token bunx vitest run connectors/coda/coda.live.test.ts
36+
```
37+
38+
The provider test creates and deletes its own document. `CODA_CONNECTOR_LIVE_ORGANIZATION_ID` enables additional Enterprise export/ACL/directory checks against that fixture when the token belongs to an Enterprise organization. Set `CODA_CONNECTOR_LIVE_FIXTURE_FILE=/path/to/fixture.json` to retain it for the application test, then from the repository root:
39+
40+
```sh
41+
CODA_CONNECTOR_LIVE_TOKEN_FILE=/path/to/token \
42+
CODA_CONNECTOR_LIVE_FIXTURE_FILE=/path/to/fixture.json \
43+
CODA_CONNECTOR_LIVE_SECOND_EMAIL=second-user@example.com \
44+
bun scripts/test-knowledge-acls.ts coda-live.integration.ts
45+
```
46+
47+
The application test uses disposable PostgreSQL/Redis, real credentials, Coda, source creation, ingestion, storage, and authorization. Set `CODA_CONNECTOR_LIVE_SCOPE=organization` to exercise organization credential creation and organization Search instead of a workspace knowledge base. Only embeddings are deterministic substitutes. It changes only the retained fixture's share, with notifications suppressed, and removes that share afterward. `CODA_CONNECTOR_LIVE_ALLOW_SHARING=false` explicitly skips the live grant/revoke cases when source policy prohibits sharing. `CODA_CONNECTOR_LIVE_UI_FIXTURE_FILE` optionally retains isolated rows and writes a temporary signed session for browser verification; use only with the runner's disposable-database retention options and remove both afterward.
48+
49+
## Verification coverage
50+
51+
- Focused connector, selector, credential, navigation, configuration, and integration-availability tests passed. App and deployment-config type checks, Biome, and the strict API-contract audit passed.
52+
- Live provider tests cover page/table hydration, page edits, and row edits. Coda's real initialization `409` led to an explicit retry path.
53+
- Real application setup and ingestion passed in both workspace and organization scope (the live sharing cases require a workspace that allows the intended cross-domain share). Organization scope creates the token credential through the authorized application use case. Owner search/chunks were allowed; another verified user, unverified owner, and workspace API key were denied. Embeddings were substituted, so external embedding-provider behavior was not tested.
54+
- Sim's browser showed the Coda source Active, both indexed documents, the live document picker, the saved organization credential, and preserved selection across connection/input modes. Browser checks caught and fixed missing Search URL registration, scope loss when switching modes, and deployment metadata rejecting Coda's token credential. Coda's official browser app showed the fixture content.
55+
- Live sharing to the requested second account was rejected by the source policy: “Cross domain sharing is prohibited.” Grant/revoke tests remain unverified live, with unit coverage for ACL changes and incomplete responses.
56+
- The available test account returned no Enterprise organizations; the official UI offers sales-assisted Enterprise setup rather than a self-service trial. Admin API behavior is checked against published schemas and mocked responses; organization-wide crawling, deactivation, and group/workspace/domain permission parity still require an Enterprise tenant test before being considered release-verified.
57+
58+
These remaining provider prerequisites prevent claiming complete live verification.

0 commit comments

Comments
 (0)