Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
02197b5
docs(cli): add agent skills setup to the CLI overview (#9417)
waleedlatif1 Oct 28, 2026
8563d25
fix(ci): predict the promoted app digest instead of trusting a read r…
waleedlatif1 Oct 28, 2026
fb74b4b
fix(billing): withhold the free allowance from Gmail aliases of an ex…
waleedlatif1 Oct 28, 2026
7f72c6d
fix(desktop): hold the GitHub credential check open while the e2e ass…
waleedlatif1 Oct 28, 2026
80be6e3
chore(deps): dependency hygiene cleanup (#9422)
waleedlatif1 Oct 28, 2026
54bb500
chore(deps): replace deprecated OpenTelemetry trace SDK packages with…
waleedlatif1 Oct 28, 2026
5b49429
fix(library): merge duplicate sections and FAQs in the ecommerce and …
waleedlatif1 Oct 28, 2026
94de080
chore(ci): authenticate Trigger.dev deploys with per-environment API …
waleedlatif1 Oct 28, 2026
f2401ac
perf(db): cut hot-path database work and close copilot cleanup gaps (…
waleedlatif1 Oct 28, 2026
17f35ef
feat(db): seal account tokens by default and backfill them during mig…
waleedlatif1 Oct 29, 2026
e05cf89
fix(files): cap how long a room delivery waits for its refetches (#9427)
waleedlatif1 Oct 29, 2026
a34e2e7
fix(ci): fail the promote wait on a digest lookup error instead of re…
waleedlatif1 Oct 29, 2026
336ed5a
chore(deps): drop the stray bun tag hunk from the zod patch (#9432)
waleedlatif1 Oct 29, 2026
77dfe17
fix(billing): serialize Gmail inbox allowance decisions so racing ali…
waleedlatif1 Oct 29, 2026
31f7529
fix(scim): harden directory lifecycle and clarify group mappings (#9429)
waleedlatif1 Oct 29, 2026
70724d0
perf(db): index a workspace's live files in upload order (#9434)
waleedlatif1 Oct 29, 2026
19b8d53
fix(cleanup): keep shared chat files, sweep inline images by prefix, …
waleedlatif1 Oct 29, 2026
fffa150
feat(files): page, search, look up and roll up workspace files over t…
waleedlatif1 Oct 29, 2026
70c8231
perf(files): page the Files browser and resolve files without listing…
waleedlatif1 Oct 29, 2026
59bbfd5
perf(audit-logs): index organization-level rows and read them as two …
waleedlatif1 Oct 29, 2026
8a14967
fix(audit-logs): list an organization's audit log through its single …
waleedlatif1 Oct 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/scripts/get-ecr-image-digest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ if [ -n "$ALLOW_MISSING" ] && [ "$ALLOW_MISSING" != '--allow-missing' ]; then
exit 1
fi
export AWS_PAGER=''
aws ecr batch-get-image --repository-name "$REPOSITORY" --image-ids imageTag="$TAG" --output json |
aws --cli-connect-timeout 10 --cli-read-timeout 20 ecr batch-get-image --repository-name "$REPOSITORY" --image-ids imageTag="$TAG" --output json |
ALLOW_MISSING="$ALLOW_MISSING" python3 -c '
import json, os, re, sys
response = json.load(sys.stdin)
Expand Down
18 changes: 17 additions & 1 deletion .github/scripts/promote-app-image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,25 @@ RELEASE_TAG="${5:-}"
: "${GITHUB_OUTPUT:?GitHub output file required}"
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
PREVIOUS=$(bash "$SCRIPT_DIR/get-ecr-image-digest.sh" "$REPOSITORY" "$DEPLOY_TAG" --allow-missing)
# A tag read straight after the move can still return the previous image, which
# reports a moved tag as unchanged. The dry run prints the exact manifest the
# move pushes (plus a trailing newline), so its hash is the digest the tag will
# point at, known before the move.
MANIFEST=$(docker buildx imagetools create --dry-run -t "$REGISTRY/$REPOSITORY:$DEPLOY_TAG" "$REGISTRY/$REPOSITORY:$SOURCE_TAG")
DIGEST="sha256:$(printf '%s' "$MANIFEST" | sha256sum | cut -d' ' -f1)"
EPOCH=$(date +%s)
bash "$SCRIPT_DIR/promote-image.sh" "$REGISTRY" "$REPOSITORY" "$SOURCE_TAG" "$DEPLOY_TAG" "$RELEASE_TAG"
DIGEST=$(bash "$SCRIPT_DIR/get-ecr-image-digest.sh" "$REPOSITORY" "$DEPLOY_TAG")
deadline=$(( $(date +%s) + 60 ))
while true; do
# Assigned, not tested in the loop condition, so a failed lookup stops the script under set -e.
CURRENT=$(bash "$SCRIPT_DIR/get-ecr-image-digest.sh" "$REPOSITORY" "$DEPLOY_TAG" --allow-missing)
[ "$CURRENT" = "$DIGEST" ] && break
if [ "$(date +%s)" -ge "$deadline" ]; then
echo "ERROR: $DEPLOY_TAG did not resolve to the pushed $DIGEST within 60s; cutover cannot be correlated" >&2
exit 1
fi
sleep 3
done
CHANGED=true
if [ "$DIGEST" = "$PREVIOUS" ]; then CHANGED=false; fi
{
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -273,21 +273,21 @@ jobs:
id: deploy
working-directory: ./apps/sim
env:
TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}
TRIGGER_ACCESS_TOKEN: ${{ (steps.target.outputs.environment == 'prod' && secrets.TRIGGER_ACCESS_TOKEN_PROD) || (steps.target.outputs.environment == 'staging' && secrets.TRIGGER_ACCESS_TOKEN_STAGING) || secrets.TRIGGER_ACCESS_TOKEN }}
TRIGGER_PROJECT_ID: ${{ secrets.TRIGGER_PROJECT_ID }}
TRIGGER_ENV: ${{ steps.target.outputs.environment }}
TRIGGER_BRANCH: ${{ steps.target.outputs.preview_branch }}
run: |
set -eo pipefail
if [ -z "$TRIGGER_ACCESS_TOKEN" ] || [ -z "$TRIGGER_PROJECT_ID" ]; then
echo "ERROR: TRIGGER_ACCESS_TOKEN and TRIGGER_PROJECT_ID repo secrets must both be set" >&2
echo "ERROR: TRIGGER_PROJECT_ID and a Trigger.dev access token (TRIGGER_ACCESS_TOKEN_${TRIGGER_ENV^^} or TRIGGER_ACCESS_TOKEN) repo secrets must be set" >&2
exit 1
fi
TARGET_ARGS=(--env "$TRIGGER_ENV")
if [ -n "$TRIGGER_BRANCH" ]; then
TARGET_ARGS+=(--branch "$TRIGGER_BRANCH")
fi
bunx trigger.dev@4.5.16 deploy "${TARGET_ARGS[@]}" --skip-promotion
bunx trigger.dev@4.7.6 deploy "${TARGET_ARGS[@]}" --skip-promotion
- name: Validate deployment version output
env:
Expand Down Expand Up @@ -618,15 +618,15 @@ jobs:
- name: Promote Trigger.dev version
working-directory: ./apps/sim
env:
TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}
TRIGGER_ACCESS_TOKEN: ${{ (needs.trigger-upload.outputs.environment == 'prod' && secrets.TRIGGER_ACCESS_TOKEN_PROD) || (needs.trigger-upload.outputs.environment == 'staging' && secrets.TRIGGER_ACCESS_TOKEN_STAGING) || secrets.TRIGGER_ACCESS_TOKEN }}
TRIGGER_PROJECT_ID: ${{ secrets.TRIGGER_PROJECT_ID }}
TRIGGER_ENV: ${{ needs.trigger-upload.outputs.environment }}
TRIGGER_BRANCH: ${{ needs.trigger-upload.outputs.preview_branch }}
VERSION: ${{ needs.trigger-upload.outputs.version }}
run: |
set -eo pipefail
if [ -z "$TRIGGER_ACCESS_TOKEN" ] || [ -z "$TRIGGER_PROJECT_ID" ]; then
echo "ERROR: TRIGGER_ACCESS_TOKEN and TRIGGER_PROJECT_ID repo secrets must both be set" >&2
echo "ERROR: TRIGGER_PROJECT_ID and a Trigger.dev access token (TRIGGER_ACCESS_TOKEN_${TRIGGER_ENV^^} or TRIGGER_ACCESS_TOKEN) repo secrets must be set" >&2
exit 1
fi
if [ -z "$VERSION" ]; then
Expand All @@ -638,7 +638,7 @@ jobs:
if [ -n "$TRIGGER_BRANCH" ]; then
TARGET_ARGS+=(--branch "$TRIGGER_BRANCH")
fi
bunx trigger.dev@4.5.16 promote "$VERSION" "${TARGET_ARGS[@]}"
bunx trigger.dev@4.7.6 promote "$VERSION" "${TARGET_ARGS[@]}"
# Production only, once the new app serves traffic: submit the library and comparison URLs this
# push changed to IndexNow. Best effort: nothing depends on it, and a failure never fails the run.
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/desktop-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,11 @@ jobs:
- name: Install dependencies
run: bun install --frozen-lockfile

# The bunfig age gate would resolve `latest` to the newest week-old release; the canary
# exists to test the release that just shipped. Already-locked packages stay locked.
- name: Switch to electron@latest
working-directory: apps/desktop
run: bun add --no-save -d electron@latest
run: bun add --no-save -d --minimum-release-age=0 electron@latest

- name: Bundle main and preload
working-directory: apps/desktop
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/trigger-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,19 @@ jobs:
id: deploy
working-directory: ./apps/sim
env:
TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}
TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN_PREVIEW || secrets.TRIGGER_ACCESS_TOKEN }}
TRIGGER_PROJECT_ID: ${{ secrets.TRIGGER_PROJECT_ID }}
run: |
set -euo pipefail
: "${TRIGGER_ACCESS_TOKEN:?TRIGGER_ACCESS_TOKEN must be configured}"
: "${TRIGGER_ACCESS_TOKEN:?TRIGGER_ACCESS_TOKEN_PREVIEW or TRIGGER_ACCESS_TOKEN must be configured}"
: "${TRIGGER_PROJECT_ID:?TRIGGER_PROJECT_ID must be configured}"
bunx trigger.dev@4.5.16 deploy --env preview --branch dev-sim --skip-promotion
bunx trigger.dev@4.7.6 deploy --env preview --branch dev-sim --skip-promotion
- name: Promote current dev preview
working-directory: ./apps/sim
env:
GH_TOKEN: ${{ github.token }}
TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}
TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN_PREVIEW || secrets.TRIGGER_ACCESS_TOKEN }}
TRIGGER_PROJECT_ID: ${{ secrets.TRIGGER_PROJECT_ID }}
VERSION: ${{ steps.deploy.outputs.deploymentVersion }}
run: |
Expand All @@ -61,4 +61,4 @@ jobs:
echo "::notice::Skipping superseded dev task version $VERSION"
exit 0
fi
bunx trigger.dev@4.5.16 promote "$VERSION" --env preview --branch dev-sim
bunx trigger.dev@4.7.6 promote "$VERSION" --env preview --branch dev-sim
24 changes: 17 additions & 7 deletions apps/desktop/e2e/source-connect.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ test('source authorization returns to its desktop screen and refreshes live', as
const githubStartSessions: string[] = []
const githubInventorySessions: string[] = []
let nativeCredentialVisible = false
let githubInventoryHold: Promise<void> | undefined
let installed = false
let holdSlackStart = false
let canceledSlackRequests = 0
Expand Down Expand Up @@ -304,7 +305,7 @@ test('source authorization returns to its desktop screen and refreshes live', as
}
if (path === '/api/organization-credentials/oauth') {
githubInventorySessions.push(session)
await sleep(500)
await githubInventoryHold
json({
credentials: nativeCredentialVisible
? [
Expand Down Expand Up @@ -545,12 +546,21 @@ test('source authorization returns to its desktop screen and refreshes live', as
await expect(page.getByLabel('GitHub error')).toContainText('not available')
await expect(page.getByLabel('GitHub credential')).toHaveText('')
nativeCredentialVisible = true
await page.getByRole('button', { name: 'Connect GitHub' }).click()
await expect.poll(async () => (await opened()).length).toBe(6)
await external.goto((await opened())[5])
await external.getByRole('link', { name: 'Authorize GitHub' }).click()
await expect.poll(() => githubInventorySessions.length).toBe(2)
await expect(page.getByLabel('GitHub pending')).toHaveText('true')
let releaseGithubInventory = () => {}
githubInventoryHold = new Promise<void>((resolve) => {
releaseGithubInventory = resolve
})
try {
await page.getByRole('button', { name: 'Connect GitHub' }).click()
await expect.poll(async () => (await opened()).length).toBe(6)
await external.goto((await opened())[5])
await external.getByRole('link', { name: 'Authorize GitHub' }).click()
await expect.poll(() => githubInventorySessions.length).toBe(2)
await expect(page.getByLabel('GitHub pending')).toHaveText('true')
} finally {
githubInventoryHold = undefined
releaseGithubInventory()
}
await expect(page.getByLabel('GitHub credential')).toHaveText('fixture-github-credential')
expect(githubStartSessions).toEqual(['browser-fixture', 'browser-fixture'])
expect(githubInventorySessions).toEqual(['desktop-fixture', 'desktop-fixture'])
Expand Down
33 changes: 33 additions & 0 deletions apps/docs/content/docs/cli/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,39 @@ sim tables rows query --help

The [command overview](/cli/commands) lists global options and root commands. The [complete reference](/cli/reference) contains every subcommand, argument, and option on one page. Both are generated from the CLI.

## Agent skills

The [Sim skills](https://github.com/simstudioai/skills) teach coding agents such as Claude Code and Codex to build and operate Sim through the CLI. Install them with the standard Agent Skills installer:

```bash
bunx skills add simstudioai/skills --global
```

To install one skill for one agent without prompting:

```bash
bunx skills add simstudioai/skills \
--skill build-workflow \
--agent codex \
--global \
--yes
```

| Skill | What it covers |
| --- | --- |
| `build-workflow` | Discover blocks and author a draft graph with atomic workflow operations |
| `run-workflow` | Test saved state, exercise triggers, resume from a block, and diagnose runs |
| `deploy-workflow` | Publish and manage workflows as APIs, chats, or MCP tools |
| `files` | Organize workspace files and folders, read and search text, and apply targeted edits |
| `sync-workspaces` | Import portable workflows with bindings, fork workspaces, and preview, apply, and reconcile push/pull sync |
| `table` | Design typed tables, load and query rows, import data, and run workflow groups |
| `knowledge-base` | Ingest and index documents, configure connectors and tags, and verify retrieval |
| `run-tool` | Call one integration tool directly with Sim-managed credentials |

The repository is also a native Claude Code and Codex plugin, which exposes the same skills under the `sim` namespace (`sim:build-workflow`, `sim:run-workflow`, and so on).

The skills assume `sim` is installed and signed in, so complete [Your first command](#your-first-command) first. They never store or print API keys. These agent skills are separate from the workspace skills you manage with [`sim skills`](/cli/skills).

## Related docs

- [Authentication](/cli/authentication)
Expand Down
15 changes: 10 additions & 5 deletions apps/docs/content/docs/platform/enterprise/scim/entra.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Use a non-gallery enterprise application in Microsoft Entra ID to create, update

## Before you start

- Use an Enterprise organization in Sim and an organization owner or admin account.
- On Sim Cloud, use an Enterprise organization. Use an organization owner or admin account to configure provisioning.
- [Verify each provisioned email domain](/platform/enterprise/verified-domains).
- Use an Entra administrator who can create enterprise applications and manage provisioning.
- Make Sim reachable by Entra over HTTPS. Self-hosted deployments must meet the [SCIM rollout requirements](/platform/enterprise/scim#deployment-and-upgrades).
Expand All @@ -20,6 +20,8 @@ Automated user provisioning is available with Entra ID Free. Group provisioning

Start with dedicated test accounts. Provisioned members use a seat and receive workspace access through mappings or existing grants.

An existing SAML or OIDC sign-in setup can remain in place. Use the same account email for authentication and provisioning, and review app assignments if they use separate enterprise applications. See [Plan membership and access](/platform/enterprise/scim#plan-membership-and-access) for the distinction between sign-in, organization membership, workspace access, and permission policy.

## Connect Entra to Sim

<Steps>
Expand Down Expand Up @@ -101,12 +103,13 @@ Sim deactivation suspends access while retaining membership, ownership, and the

## Provision groups and verify access

With P1 or higher, create a security group with **Assigned** membership and add test accounts as direct members. Assign it under **Users and groups**. Review **Attribute mapping** and keep group provisioning enabled.
With P1 or higher, create a security group with **Assigned** membership and add test accounts as direct members. Assign it under **Users and groups**. Review **Attribute mapping** and keep group provisioning enabled. Create the target workspace and a dedicated permission group in Sim, configuring that policy's restrictions and workspace scope before mapping it.

1. Run **Provision on demand** for one group and select up to five test members, or wait for a scheduled cycle. Nested membership is unsupported; see [Microsoft group assignment](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/assign-user-or-group-access-portal).
2. Once the group appears under **Single sign-on → Provisioning → Group mappings** in Sim, map it to a workspace, permission group, or organization admin role. Start with a workspace mapping and confirm access.
3. Remove a test member from the group while retaining a separate direct app assignment. After synchronization, confirm the directory workspace grant is withdrawn while the account remains active.
4. Add the member back and verify access returns.
2. Once the group appears under **Single sign-on → Provisioning → Group mappings** in Sim, add a **Workspace** mapping and a **Permission group** mapping to the policy created above. Confirm both workspace access and policy restrictions. A permission-group mapping alone does not grant workspace access; an organization-admin mapping is a separate privilege.
3. For automatic policy matching, enable **Provisioning rules → Manage rules → Match permission groups by name**. Names must match an existing non-default Sim permission group exactly, including case. Select **Reconcile now** for groups already synced. Sim does not create the permission group.
4. Remove a test member from the group while retaining a separate direct app assignment. After synchronization, confirm the directory workspace grant is withdrawn while the account remains active. Check the [fallback policy](/platform/enterprise/scim#how-access-is-withdrawn) on any workspace the person can still access.
5. Add the member back and verify access and restrictions return.

Read [How access is withdrawn](/platform/enterprise/scim#how-access-is-withdrawn) before mapping groups that overlap manual access.

Expand All @@ -133,6 +136,8 @@ Issue a replacement token in Sim while the current one remains active. In Entra'
| Disablement or deletion has not reached Sim | Inspect the scheduled log, `IsSoftDeleted` mapping to `active`, enabled **Update** actions, and accidental deletion protection. Confirm **Skip out of scope deletions** is disabled. A connection test does not verify lifecycle changes. |
| Group assignment is unavailable | Check licensing. Free supports individual assignment; group assignment and provisioning require an upgrade. |
| Member has no workspace access | Provision the directory group and add a Sim workspace mapping. User provisioning adds organization membership. |
| Member has access but the expected policy does not apply | Check **Group mappings** for unassigned members. Resolve overlapping membership or workspace scope under **Permission groups**, then select **Reconcile now**. For name matching, also check the exact group name. |
| A removed mapping returns | Turn off name matching or use different names before removing a same-name mapping. See [mapping behavior](/platform/enterprise/scim#map-directory-groups). |
| A disabled member still uses a seat | Deactivation suspends access; organization removal is separate. |

Use Entra's **Provisioning logs** and Sim's **Provisioning → Activity**. Invalid or revoked tokens appear only in Entra because Sim cannot associate them with a connection.
Expand Down
Loading
Loading