Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
77abaf3
feat(knowledge): resolve connector tokens through one service-account…
waleedlatif1 Sep 4, 2026
d21f661
feat(knowledge): map Google Drive permissions to document access tokens
waleedlatif1 Sep 4, 2026
a73add1
feat(knowledge): write mirrored document ACLs without re-embedding
waleedlatif1 Sep 4, 2026
4c0e817
feat(knowledge): crawl Google Drive as an administrator and mirror it…
waleedlatif1 Sep 4, 2026
0fd6df2
fix(knowledge): make one email address mean one account
waleedlatif1 Sep 4, 2026
140c772
feat(knowledge): resolve directory groups so mirrored grants reach th…
waleedlatif1 Sep 4, 2026
64053e8
feat(knowledge): let a connector be put into administrator mode
waleedlatif1 Sep 4, 2026
3053ec4
fix(knowledge): gate mirrored access on its own feature, not on Crede…
waleedlatif1 Sep 4, 2026
faab96f
refactor(knowledge): drop directory-group columns nothing reads
waleedlatif1 Sep 4, 2026
972422f
feat(knowledge): mirror Confluence space permissions and page restric…
waleedlatif1 Sep 4, 2026
de993af
feat(knowledge): refresh mirrored directories on their own clock
waleedlatif1 Sep 4, 2026
9e68ad3
fix(knowledge): close two admin-mode gaps found in an architecture audit
waleedlatif1 Sep 4, 2026
8932ca2
fix(knowledge): read shared-drive permissions, and finish a pending s…
waleedlatif1 Sep 4, 2026
7ecdc94
docs(knowledge): state why the ACL ceiling exists rather than where t…
waleedlatif1 Sep 4, 2026
822625b
chore(knowledge): register the directory-sync cron, and collapse the …
waleedlatif1 Sep 4, 2026
8ca4ff1
refactor(auth): one email fold, in SQL and TypeScript, and no reads o…
waleedlatif1 Sep 4, 2026
cc92806
fix(knowledge): Drive field mask named a permission field that does n…
waleedlatif1 Sep 4, 2026
2c86087
fix(knowledge): close the audit findings on administrator access
waleedlatif1 Sep 4, 2026
6f204a0
refactor(knowledge): tighten administrator access after the mechanics…
waleedlatif1 Sep 4, 2026
399149c
refactor(knowledge): collapse the access-mode vocabulary and the dupl…
waleedlatif1 Sep 4, 2026
6e07a0c
Merge remote-tracking branch 'origin/staging' into feat/connector-ser…
icecrasher321 Sep 5, 2026
6b9ecfb
Merge remote-tracking branch 'origin/staging' into feat/connector-ser…
icecrasher321 Sep 5, 2026
caf82ac
feat(search): unify source access and scale indexing
icecrasher321 Sep 5, 2026
30ce06e
fix(ci): align search cleanup checks and chart version
icecrasher321 Sep 5, 2026
0689c67
fix(search): clean up source access and directory refresh
waleedlatif1 Sep 5, 2026
cbfe70d
improvement(search): remove Answer with Sim action
waleedlatif1 Sep 5, 2026
9507aa0
Merge remote-tracking branch 'origin/staging' into feat/connector-ser…
icecrasher321 Sep 5, 2026
27d7796
improvement(search): simplify source setup and preserve account handoffs
waleedlatif1 Sep 5, 2026
ca68b75
feat(assistant): use canonical search and personal integration accounts
icecrasher321 Sep 5, 2026
ee7ab5a
Merge remote-tracking branch 'origin/feat/connector-service-account-a…
icecrasher321 Sep 5, 2026
3a3d38a
improvement(search): simplify connection setup and merge staging
waleedlatif1 Sep 5, 2026
93fc4d7
merge: preserve latest assistant and personal account changes
waleedlatif1 Sep 5, 2026
9a1821a
merge: bring in latest staging parsing fixes
waleedlatif1 Sep 5, 2026
a6616d5
Merge remote-tracking branch 'origin/staging' into feat/connector-ser…
icecrasher321 Sep 5, 2026
8f687a3
feat(assistant): connect personal accounts in chat and reuse desktop …
icecrasher321 Sep 5, 2026
f15777d
Merge remote-tracking branch 'origin/feat/connector-service-account-a…
icecrasher321 Sep 5, 2026
b0857a3
fix(slack): keep channel listing independent of credential storage
icecrasher321 Sep 5, 2026
c65cc33
improvement(assistant): streamline account checks and bound catalog c…
icecrasher321 Sep 5, 2026
febebf4
Merge remote-tracking branch 'origin/staging' into feat/connector-ser…
icecrasher321 Sep 5, 2026
066ecb5
improvement(search): unify source setup and member connection actions
waleedlatif1 Sep 5, 2026
4356872
Merge remote-tracking branch 'origin/feat/connector-service-account-a…
waleedlatif1 Sep 5, 2026
fd6fc44
improvement(search): clarify setup requirements and focus account con…
waleedlatif1 Sep 5, 2026
015948a
feat(search): add Gmail, Jira, GitHub and Calendar sources
waleedlatif1 Sep 5, 2026
b939801
Merge remote-tracking branch 'origin/staging' into codex/pr-7477
waleedlatif1 Sep 5, 2026
4770c98
feat(search): document connector setup and harden source access
waleedlatif1 Sep 6, 2026
6e12f9e
Merge remote-tracking branch 'origin/staging' into codex/pr-7477
waleedlatif1 Sep 6, 2026
9810f1f
feat(org): organization surface, app entry, and shared rail chrome
emir-karabeg Sep 6, 2026
987eb2b
fix(search): support GitHub App grants and verify connector ACLs
waleedlatif1 Sep 6, 2026
1bc27a7
fix(search): deny revoked Atlassian grants and bound provider requests
waleedlatif1 Sep 6, 2026
149eb03
Merge remote-tracking branch 'origin/staging' into codex/pr-7477
waleedlatif1 Sep 6, 2026
7e5a792
test(search): verify unchanged document indexing recovery
waleedlatif1 Sep 6, 2026
179d80c
fix(search): harden connector recovery and file lifecycle
waleedlatif1 Sep 6, 2026
90b5bd8
Merge remote-tracking branch 'origin/staging' into codex/pr-7477
waleedlatif1 Sep 6, 2026
4f1e635
feat(org): home composer, page shell, and completion blue
emir-karabeg Sep 7, 2026
c996233
Merge remote-tracking branch 'origin/feat/org' into codex/pr-7477
waleedlatif1 Sep 7, 2026
cc128f1
Merge remote-tracking branch 'origin/staging' into codex/pr-7477
waleedlatif1 Sep 7, 2026
3b63c42
feat(search): integrate organization sources and private assistant
waleedlatif1 Sep 7, 2026
72d067c
Merge remote-tracking branch 'origin/staging' into codex/pr-7477
waleedlatif1 Sep 7, 2026
5f69ee0
fix(org): clarify membership navigation and role-aware settings
waleedlatif1 Sep 7, 2026
b3524ec
Merge remote-tracking branch 'origin/staging' into codex/pr-7477
waleedlatif1 Sep 7, 2026
46fd0cb
fix(ui): align organization and workspace sidebar interactions
waleedlatif1 Sep 7, 2026
715de0d
Merge staging into enterprise organization search
waleedlatif1 Sep 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .claude/rules/emcn-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ The menu surface intentionally diverges from the pill: `dropdown-menu.tsx` items
- **`ChipDatePicker`** — chip-styled date field.
- **`ChipTimePicker`** — minute-granular time sibling of `ChipDatePicker`, a `ChipInput` that leniently parses typed input (`9:47`, `947`, `2:05pm`, `14:30`), commits on Enter/blur, and re-renders the canonical `9:47 AM` label.
- **`DropdownMenu`** — the canonical context/action menu (Radix-backed). Not a chip, but the standard menu for command/action lists; reach for it instead of a hand-rolled popover. Its surface intentionally diverges from the chip pill (`text-small`, `gap-2`) — keep them distinct. For a pill that opens a value picker, use `ChipDropdown`/`ChipSelect` instead.
- **`useScrollEdges` + `scrollFadeClass` / `scrollFadeAttributes`** — the canonical scroll-region edge treatment. The hook reports which edges hide content (tracking scroll and resizes; pass the element itself, held in state, when the region mounts after its owner, e.g. inside a Radix portal); the class and attributes fade a fixed 12px band at an active edge only, so a list that fits or sits at its top is never fogged. A floating control over the top edge sets `--scroll-fade-inset` to its height. A region that scrolls sideways (a tab row, a chip strip) uses `useScrollEdges(ref, { axis: 'x' })` with `scrollFadeXClass`; the attributes helper is shared. Any divider beside the region belongs to the neighboring block (`border-b` above, `border-t` below), never to the masked element, and shows only while that edge is active. Never hand-roll a `mask-image` gradient for a scroll region.
- **`OverflowText`** — the canonical single-line overflow treatment for read-only human labels and titles. It owns `min-w-0`, fade-only clipping (never an ellipsis), the conditional 18px edge mask, and the full-value floating tooltip; consumers pass only layout/typography through `className`. `overflowTextClipClass` and `overflowTextFadeClass` are the complete base/faded treatments for the rare component that must own measurement itself; never pair either with `truncate`, `text-ellipsis`, or hover-time mask removal. Use `DropdownMenuItemLabel` for a menu label beside icons, checks, or actions. A non-editable `Combobox` passes the full visual value through `overlayLabel`; the combobox owns the visual overlay's fade and keeps its one accessible tooltip on the interactive layer. Keep ordinary `truncate` only for editable values, code/log/path content, dense or virtualized grids, and rich composite content that cannot supply a plain tooltip label. Multiline copy uses an intentional `line-clamp-*` treatment instead.

## Modal keyboard defaults
Expand Down
6 changes: 5 additions & 1 deletion .claude/rules/sim-styling.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ Use `DropdownMenuItemLabel` for a human label beside menu icons, checks, shortcu

Do not apply the fade universally to editable or mirrored input values, code, logs, paths, filenames that use intentional middle truncation, dense or virtualized grids, or a composite container that also holds icons/actions. Those keep their purpose-built overflow behavior. Multiline copy uses an intentional `line-clamp-*` treatment.

## Scroll Edges

A scroll region that can hide rows past an edge uses `useScrollEdges` with `scrollFadeClass` + `scrollFadeAttributes` from `@sim/emcn`: a 12px fade at an edge only while content is hidden beyond it, never at rest. The region's baseline padding lives on the scroll box itself (so rows pass through it under the fade), and the divider at that edge is drawn by the neighboring block, conditional on the same edge. Never hand-roll a `mask-image` gradient or a `scrollTop > 0` effect for this.

## Font Weight

Three steps, Tailwind's stock scale, nothing else: **`font-normal` (400)**, **`font-medium` (500)**, **`font-semibold` (600)**. 400 is the document default, so body text, chip labels, sidebar items, and headings carry **no weight class at all** — they inherit. Reach for a class only to step *up* from body.
Expand All @@ -70,7 +74,7 @@ Headings inherit their weight. Tailwind preflight resets `h1`–`h6` to `font-we

## Color Tokens

Value text `--text-body`; muted/placeholder/labels `--text-muted`; icons `--text-icon`; neutral borders and dividers `--border` (`--border-1` and `--border-muted` are legacy aliases resolving to it; `--divider` is retired); surfaces `--surface-5` (light) / `--surface-4` (dark); active row `--surface-active`; error `--text-error`. No focus rings on chip surfaces.
Value text `--text-body`; muted/placeholder/labels `--text-muted`; icons `--text-icon`; progress and completion (a checked step, a done state) `--brand-blue` — `--selection` stays the interactive highlight; neutral borders and dividers `--border` (`--border-1` and `--border-muted` are legacy aliases resolving to it; `--divider` is retired); surfaces `--surface-5` (light) / `--surface-4` (dark); active row `--surface-active`; error `--text-error`. No focus rings on chip surfaces.

### Line weight

Expand Down
6 changes: 3 additions & 3 deletions apps/desktop/e2e/smoke.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { _electron as electron, expect, test } from '@playwright/test'
const DESKTOP_DIR = fileURLToPath(new URL('..', import.meta.url))

const PAGES: Record<string, string> = {
'/workspace': `<!doctype html><html><head><title>Sim Fixture</title></head><body>
'/home': `<!doctype html><html><head><title>Sim Fixture</title></head><body>
<h1 id="app">fixture-app</h1>
<button id="internal-blank" onclick="window.open('/workspace/two', '_blank')">internal</button>
<button id="external-blank" onclick="window.open('https://docs.sim.ai/x', '_blank')">external</button>
Expand Down Expand Up @@ -82,7 +82,7 @@ test.describe('desktop shell smoke', () => {
app = await launchApp(origin)
const window = await app.firstWindow()
await expect(window.locator('#app')).toHaveText('fixture-app')
expect(window.url()).toBe(`${origin}/workspace`)
expect(window.url()).toBe(`${origin}/home`)
})

test('internal window.open creates an independent full Sim window', async () => {
Expand Down Expand Up @@ -150,7 +150,7 @@ test.describe('desktop shell smoke', () => {
app.evaluate(() => (globalThis as { __openedExternal?: string[] }).__openedExternal)
)
.toEqual(['https://docs.sim.ai/navigation'])
expect(window.url()).toBe(`${origin}/workspace`)
expect(window.url()).toBe(`${origin}/home`)
})

test('unreachable origin shows the bundled offline page', async () => {
Expand Down
12 changes: 6 additions & 6 deletions apps/desktop/src/main/app-routes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ describe('app routes', () => {
it('derives the new-chat route from the last workspace route', () => {
expect(newChatRoute('/workspace/ws1/w/wf2')).toBe('/workspace/ws1/home')
expect(newChatRoute('/workspace/ws1/home?resource=r1')).toBe('/workspace/ws1/home')
expect(newChatRoute('/account')).toBe('/workspace')
expect(newChatRoute(undefined)).toBe('/workspace')
expect(newChatRoute('//evil.example')).toBe('/workspace')
expect(newChatRoute('/account')).toBe('/home')
expect(newChatRoute(undefined)).toBe('/home')
expect(newChatRoute('//evil.example')).toBe('/home')
})

it('derives the settings route from the last workspace route', () => {
expect(settingsRoute('/workspace/ws1/w/wf2')).toBe('/workspace/ws1/settings/desktop')
expect(settingsRoute('/account')).toBe('/workspace')
expect(settingsRoute(undefined)).toBe('/workspace')
expect(settingsRoute('//evil.example')).toBe('/workspace')
expect(settingsRoute('/account')).toBe('/home')
expect(settingsRoute(undefined)).toBe('/home')
expect(settingsRoute('//evil.example')).toBe('/home')
})
})
16 changes: 11 additions & 5 deletions apps/desktop/src/main/app-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ import { isSafeInternalPath } from '@/main/config'
* do with the tray, and the tray can be absent entirely.
*/

/**
* The web app's signed-in entry. It resolves to the organization the user belongs
* to, or to their workspaces, so the shell never has to know which applies.
*/
export const APP_ENTRY_ROUTE = '/home'

/** Workspace id from the last visited route, or null when it carries none. */
function workspaceIdFromRoute(lastRoute: string | undefined): string | null {
if (isSafeInternalPath(lastRoute)) {
Expand All @@ -23,19 +29,19 @@ function workspaceIdFromRoute(lastRoute: string | undefined): string | null {

/**
* Route for "New Chat": the home (chat) surface of the workspace the user was
* last in, falling back to the workspace picker redirect when the last route
* carries no workspace.
* last in, falling back to the app entry when the last route carries no
* workspace.
*/
export function newChatRoute(lastRoute: string | undefined): string {
const workspaceId = workspaceIdFromRoute(lastRoute)
return workspaceId ? `/workspace/${workspaceId}/home` : '/workspace'
return workspaceId ? `/workspace/${workspaceId}/home` : APP_ENTRY_ROUTE
}

/**
* Route for "Settings…": the Sim app's settings surface for the workspace the
* user was last in, falling back to the workspace picker redirect.
* user was last in, falling back to the app entry.
*/
export function settingsRoute(lastRoute: string | undefined): string {
const workspaceId = workspaceIdFromRoute(lastRoute)
return workspaceId ? `/workspace/${workspaceId}/settings/desktop` : '/workspace'
return workspaceId ? `/workspace/${workspaceId}/settings/desktop` : APP_ENTRY_ROUTE
}
10 changes: 5 additions & 5 deletions apps/desktop/src/main/session-lifecycle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ describe('decideStartRoute', () => {
})

it('falls back to /workspace for missing, unsafe, or auth-surface last routes', () => {
expect(decideStartRoute(undefined)).toBe('/workspace')
expect(decideStartRoute('//evil.example')).toBe('/workspace')
expect(decideStartRoute('/login')).toBe('/workspace')
expect(decideStartRoute(undefined)).toBe('/home')
expect(decideStartRoute('//evil.example')).toBe('/home')
expect(decideStartRoute('/login')).toBe('/home')
})
})

Expand All @@ -94,11 +94,11 @@ describe('resolveStartRoute', () => {
)
})

it('falls back to the workspace picker after confirmed access denial', async () => {
it('falls back to the app entry after confirmed access denial', async () => {
const session = sessionWithResponse(403, { error: 'Workspace access denied' })

await expect(resolveStartRoute(session, APP, '/workspace/revoked/chat/c1')).resolves.toBe(
'/workspace'
'/home'
)
})

Expand Down
9 changes: 5 additions & 4 deletions apps/desktop/src/main/session-lifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
completeAccountDataTeardown,
waitForAccountDataMutations,
} from '@/main/account-data-generation'
import { APP_ENTRY_ROUTE } from '@/main/app-routes'
import { isSafeInternalPath } from '@/main/config'
import { isAuthSurfacePath, openExternalSafe } from '@/main/navigation'
import type { EventRecorder } from '@/main/observability'
Expand Down Expand Up @@ -60,14 +61,14 @@ export function isLogoutNavigation(rawUrl: string, appOrigin: string): boolean {

/**
* Picks the route to load at launch: the last visited route (when safe and
* not itself an auth surface), falling back to /workspace. A signed-out
* not itself an auth surface), falling back to the app entry. A signed-out
* partition is handled by the web app's own login redirect.
*/
export function decideStartRoute(lastRoute: string | undefined): string {
if (lastRoute && isSafeInternalPath(lastRoute) && !isAuthSurfacePath(lastRoute)) {
return lastRoute
}
return '/workspace'
return APP_ENTRY_ROUTE
}

function workspaceIdFromRoute(route: string): string | null {
Expand Down Expand Up @@ -110,8 +111,8 @@ export async function resolveStartRoute(
}
)
if (response.status === 403) {
logger.info('Saved workspace route is no longer accessible; opening workspace picker')
return '/workspace'
logger.info('Saved workspace route is no longer accessible; opening the app entry')
return APP_ENTRY_ROUTE
}
return route
} catch {
Expand Down
1 change: 1 addition & 0 deletions apps/docs/content/docs/cli/credentials.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ Update Credential (OAuth login or personal API key required)
| `--service-account-json <value>` | No | Write-only Google service-account JSON key. |
| `--api-token <value>` | No | Write-only provider API token. |
| `--domain <value>` | No | Provider account domain. |
| `--atlassian-product <value>` | No | Atlassian product to verify; defaults to Jira on create and preserves the saved product on reconnect. Accepted values: `jira`, `confluence`. |
| `--signing-secret <value>` | No | Write-only webhook signing secret. |
| `--bot-token <value>` | No | Write-only bot token. |
| `--client-id <value>` | No | OAuth client identifier. |
Expand Down
1 change: 1 addition & 0 deletions apps/docs/content/docs/cli/reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,7 @@ sim credentials update <credentialId> [options]
| `--service-account-json <value>` | No | Write-only Google service-account JSON key. |
| `--api-token <value>` | No | Write-only provider API token. |
| `--domain <value>` | No | Provider account domain. |
| `--atlassian-product <value>` | No | Atlassian product to verify; defaults to Jira on create and preserves the saved product on reconnect. Accepted values: `jira`, `confluence`. |
| `--signing-secret <value>` | No | Write-only webhook signing secret. |
| `--bot-token <value>` | No | Write-only bot token. |
| `--client-id <value>` | No | OAuth client identifier. |
Expand Down
10 changes: 5 additions & 5 deletions apps/docs/content/docs/integrations/slack.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -956,15 +956,15 @@ Rename the Slack agent session associated with a thread.

### Slack List Channels

List up to 10,000 accessible Slack conversations across as many cursor pages as Slack supplies, capped at 200 provider pages. Credential-group user tokens also return one-to-one and group direct messages.
List up to 10,000 accessible public and private Slack channels across as many cursor pages as Slack supplies, capped at 200 provider pages.

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `authMethod` | string | No | Authentication method: oauth or bot_token |
| `botToken` | string | No | Bot token for Custom Bot |
| `includePrivate` | boolean | No | Include private channels the bot is a member of \(default: true\) |
| `includePrivate` | boolean | No | Include private channels the connected account can access \(default: true\) |
| `excludeArchived` | boolean | No | Exclude archived channels \(default: true\) |
| `limit` | number | No | Conversations to request per Slack page \(default: 100, max: 200\) |
| `cursor` | string | No | Pagination cursor from a previous response.nextCursor to resume from |
Expand All @@ -974,7 +974,7 @@ List up to 10,000 accessible Slack conversations across as many cursor pages as

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `channels` | array | Up to 10,000 accessible public and private channels, plus direct and group DMs for credential-group user tokens |
| `channels` | array | Up to 10,000 accessible public and private channels |
| ↳ `id` | string | Conversation ID \(for example, C123, D123, or G123\) |
| ↳ `name` | string | Channel or group-DM name; omitted for one-to-one direct messages |
| ↳ `is_channel` | boolean | Whether this is a channel |
Expand All @@ -998,8 +998,8 @@ List up to 10,000 accessible Slack conversations across as many cursor pages as
| ↳ `is_user_deleted` | boolean | Whether the other participant in a direct message is deactivated |
| ↳ `is_open` | boolean | Whether a direct or group-direct-message conversation is open |
| ↳ `priority` | number | Slack sidebar sort priority |
| `ids` | array | Conversation IDs for every returned channel or DM |
| `names` | array | Names of returned channels and group DMs; one-to-one DMs have no name |
| `ids` | array | Conversation IDs for every returned channel |
| `names` | array | Names of returned channels |
| `count` | number | Total number of conversations returned across all fetched pages, up to 10,000 |
| `hasMore` | boolean | Whether more Slack conversation pages remain beyond the fetched window |
| `nextCursor` | string | Cursor to fetch the next page; null when there are no more pages |
Expand Down
2 changes: 2 additions & 0 deletions apps/docs/content/docs/knowledgebase/connectors.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { Step, Steps } from 'fumadocs-ui/components/steps'
import { Image } from '@/components/ui/image'
import { FAQ } from '@/components/ui/faq'

For workspace Search with each person's source permissions, use the [Search connector guides](/search). This page covers connectors inside general knowledge bases.

Connectors continuously sync documents from external services into your knowledge base, so you never have to upload files manually. New content is added, changed content is re-processed, and deleted content is removed — all automatically.

## Available Connectors
Expand Down
1 change: 1 addition & 0 deletions apps/docs/content/docs/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"workflows",
"agents",
"---Workspace---",
"search",
"knowledgebase",
"tables",
"files",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Point cron at an **internal** address where possible (the in-cluster Service, or
| Workspace file search dispatch | `/api/cron/workspace-file-search-dispatch` | `*/1 * * * *` | Dispatches indexing work for workspace file search |
| Connector sync | `/api/knowledge/connectors/sync` | `*/5 * * * *` | Knowledge base connector syncs |
| Connector member sync | `/api/knowledge/connectors/member-sync` | `*/5 * * * *` | Per-member access sync for permission-aware connectors |
| Connector directory sync | `/api/knowledge/connectors/directory-sync` | `*/5 * * * *` | Refreshes the directory groups administrator-mode connectors mirror, so a membership change takes effect without waiting for a content sync |
| Workspace events poll | `/api/workspace-events/poll` | `*/15 * * * *` | Workspace event triggers |
| Table row TTL cleanup | `/api/cron/cleanup-table-row-ttl` | `*/15 * * * *` | Deletes table rows whose TTL column has expired |
| OAuth token cleanup | `/api/cron/cleanup-oauth-tokens` | `0 * * * *` | Deletes access and refresh tokens after the retention tail |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,18 @@ One app registration in [Entra ID](https://entra.microsoft.com) covers all of th

The same variables also power "Sign in with Microsoft".

### GitHub Search

Register a [GitHub App](https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/registering-a-github-app) with repository **Contents: read-only**, **Metadata: read-only**, and account **Email addresses: read-only** permissions. Keep user access token expiration enabled so Sim can rotate access and refresh tokens.

| Environment variables | Provider ID |
|---|---|
| `GITHUB_APP_CLIENT_ID`<br />`GITHUB_APP_CLIENT_SECRET` | `github-repositories` |

Register `https://<your-domain>/api/auth/oauth2/callback/github-repositories` as the callback. These App OAuth client credentials are separate from `GITHUB_CLIENT_ID` and `GITHUB_CLIENT_SECRET` used for Sim sign-in. Sim does not require an App private key.

A repository or organization administrator installs the App on the repositories to search. Each member connects their own GitHub account, with a verified email matching their Sim account. Search indexes repository files that both the member and the installed App can access. GitHub workflow blocks and existing knowledge-base token connections continue to use personal access tokens.

### Everything else

| Service | Environment variables | Provider ID |
Expand Down
Loading
Loading