* feat(managed-agents): add Claude Managed Agents workflow block
* improvement(managed-agents): complete session inputs/outputs; trim block templates
- add memory instructions + file mount_path inputs; bound metadata (16 pairs)
- surface cumulative token usage (inputTokens/outputTokens) as outputs
- validate the full session-create schema against live docs
- remove BlockMeta templates
* improvement(managed-agents): select a Claude Platform credential instead of BYOK
- register Claude Platform as a token-paste service-account credential (descriptor + validator)
- add no-OAuth OAUTH_PROVIDERS entry; generalize the shared credential picker with a 'service-account' kind
- block: oauth-input credential picker + dependsOn dropdowns; list route resolves the key server-side (audit-logged)
- run via directExecution with the executor-injected key; drop the internal run route
- remove the interim claude-platform BYOK provider
* fix(managed-agents): harden reconnect loop; fix credential-picker regression
- drive completion off terminal events + authoritative session status (drop the fragile busy-clock)
- drain full event history so a long session's tail is never cut off
- skip idless events in catch-up; require an id before replying to custom_tool_use
- gate the shared credential-selector service-account lookup on credentialKind and use the non-throwing helper (was crashing multi-service OAuth pickers)
- audit-log the list route's credential access; refresh stale tool docs
* fix(managed-agents): address review round 2
- don't complete on idle status while a requires_action is still outstanding
- vaults: combobox → dropdown so multiSelect actually attaches multiple vaults
- auto-select a freshly-pasted service-account credential (onCreated through the connect modal)
* fix(managed-agents): propagate cancellation, fix reconnect ordering, classify advanced fields
- Thread the executor abort signal into directExecution (additive ToolConfig
change) so a cancelled workflow stops the session immediately; best-effort
user.interrupt releases the Anthropic session past cancel/wall-clock cap
- Recompute the requires_action pending state from the chronological history
so an older agent.message recovered on catch-up can't clear a newer pause
- Retry a custom-tool error reply that failed to send instead of stranding the
session (mark the event seen only once handled)
- Mark optional fields (vaults, memory, files, metadata) mode: advanced
- Title the session with the workflow id for Claude-console traceability
* fix(managed-agents): stop leaked sessions on all give-up paths; harden event ordering and normalizers
- Interrupt on sendUserMessage failure and on the reconnect-cap exit, matching
the abort/wall-clock paths, so no give-up path leaves a session running
- Order the events list by processed_at (list page order isn't guaranteed
chronological) so catch-up accumulates text and reads the latest lifecycle
event correctly regardless of API sort
- Don't reset reconnect backoff on a failing custom-tool reply (stays unseen
for retry) — prevents a no-delay reconnect storm
- Treat only end_turn as a complete status_idle event; an unspecified idle
defers to the sawActivity-gated status check (no empty completion pre-turn)
- normalizeFiles parses a JSON-stringified table instead of dropping it;
normalizeStringList returns [] on malformed JSON; metadata keeps scalar values
- Declare the injected accessToken as a hidden param for convention parity
* fix(managed-agents): interrupt the session on a mid-run stream/API failure
The non-abort error catch path returned without stopping the session, so a
mid-run network/API failure could leave the Anthropic session running against
the workspace key. Interrupt on that path too — completing the invariant that
every give-up exit (abort, cap, send failure, reconnect cap, stream error)
stops the session. Still fails fast; no retry added.
* fix(managed-agents): skip idless stream previews; resolve service-account provider icons
- Skip idless events in the live SSE handler (mirroring catch-up). event_start/
event_delta previews carry no id, are never deduped, and final text always
arrives as a persisted id-bearing agent.message — so appending previews could
double the block's content output
- Map serviceAccountProviderId to its base provider in PROVIDER_ID_TO_BASE_PROVIDER
so parseProvider resolves 'claude-platform-service-account' to 'claude-platform'
(a two-segment base the hyphen split can't recover), fixing the credential-row
icon falling back to the generic external-link glyph
* fix(managed-agents): keep idless terminals and preserve live pending state
Refine the round-6 idless-event fix, which was too broad:
- Process idless events again (revert the blanket stream skip) so an idless
session.status_idle(end_turn)/session.error delivered only on the live stream
still registers as terminal instead of reconnecting to a timeout. Only the
agent.message TEXT append is now id-gated, so preview text still can't double
- When catch-up history has no lifecycle event, restore the live-observed
requires_action state instead of trusting a stale older agent.message that
cleared it — prevents a false completion with partial output while a tool
result is still pending
* fix(managed-agents): route memory via metadata on self-hosted environments
Live API testing revealed self-hosted environments reject the `resources`
array with a 400 ("resources are not supported with self-hosted
environments"), so the prior universal-resources[] payload would have failed
any self-hosted session that attached a memory store or files.
Restore env-type-aware routing: resolve the environment's config.type via a new
getEnvironmentType() before session create, and for self_hosted send the memory
store through metadata.memory_store_ids/memory_access (the worker consumes it)
and drop file attachments. Cloud environments keep resources[]. Verified end-to-
end against the live Managed Agents API (cloud resources[] 200, self-hosted
metadata 200, self-hosted resources[] 400).
* feat(managed-agents): environment-type selector; hide cloud-only fields on self-hosted
Collapse what #5769 split into two blocks into one, natively:
- Add an Environment type selector (Cloud / Self-hosted) that filters the
environment list to the matching type and gates cloud-only fields
- Memory store, memory access/instructions, and files are cloud-only (self-
hosted rejects the resources[] attach — verified live, 400) and are now hidden
on self-hosted instead of silently dropped. A self-hosted worker that uses a
memory store reads its id from a Metadata key the author sets explicitly
- Expose each environment's config.type on the list options so the picker can
filter by mode; pass the selected type as a routing hint (server still re-
resolves the authoritative type via getEnvironmentType)
* fix(managed-agents): track requires_action by processed_at, not history position
Persisted history can lag the live stream, so the last lifecycle event in the
history array may be OLDER than a requires_action the stream already observed.
Deriving the pending state from history position (findLastLifecycleEvent) could
then clear a newer pause and let an idle snapshot complete a still-waiting
session with partial text.
Track requires_action from the NEWEST lifecycle event by processed_at across
both the live stream and catch-up, so an older/lagging event can never override
a newer pause. Removes the pendingBeforeCatchup snapshot and history-position
recompute. New test covers lagging history holding only an older running event.
* fix(managed-agents): treat missing processed_at as oldest, not newest
A lifecycle event without processed_at mapped to +Infinity, poisoning the
high-water mark: once seen, no later timestamped event could update the pending
state (at >= Infinity always false), stranding a pause or clearing one wrongly.
Map missing/unparseable processed_at to -Infinity so an untimestamped lifecycle
event can never outrank a timestamped one in either direction — it neither
blocks later real events nor clears a timestamped requires_action. Persisted
lifecycle events always carry processed_at; this is purely defensive. New test
covers a stray untimestamped running not clearing a timestamped pause.
A workspace to build, deploy and manage AI agents and workflows.
Quickstart
Cloud-hosted: sim.ai
Self-hosted
npx simstudio
Docker must be installed and running. Use -p, --port <port> to run Sim on a different port, or --no-pull to skip pulling the latest Docker images.
Capabilities
- Connect 1,000+ integrations and every major LLM
- Add Slack, Notion, HubSpot, Salesforce, databases, and more
- Build agents visually, conversationally, or with code
- Ingest files, knowledge bases, and structured table data
- Monitor runs, logs, schedules, and workflow activity
One workspace, every surface
Chat and workflows are just the start — tables, files, knowledge, and scheduled tasks all live in the same workspace.
Tables — a database, built in |
Files — one store for your team and every agent |
Knowledge — your agents' memory |
Scheduled tasks — runs on your schedule |
Self-hosting
Docker Compose
git clone https://github.com/simstudioai/sim.git && cd sim
docker compose -f docker-compose.prod.yml up -d
Sim also supports local models via Ollama and vLLM. See the Docker self-hosting docs for setup details.
Manual Setup
Requirements: Bun, Node.js v20+, PostgreSQL 12+ with pgvector
- Clone and install:
git clone https://github.com/simstudioai/sim.git
cd sim
bun install
bun run prepare # Set up pre-commit hooks
- Set up PostgreSQL with pgvector:
docker run --name simstudio-db -e POSTGRES_PASSWORD=your_password -e POSTGRES_DB=simstudio -p 5432:5432 -d pgvector/pgvector:pg17
Or install manually via the pgvector guide.
- Configure environment:
cp apps/sim/.env.example apps/sim/.env
# Create your secrets
perl -i -pe "s/your_encryption_key/$(openssl rand -hex 32)/" apps/sim/.env
perl -i -pe "s/your_internal_api_secret/$(openssl rand -hex 32)/" apps/sim/.env
perl -i -pe "s/your_api_encryption_key/$(openssl rand -hex 32)/" apps/sim/.env
# DB configs for migration
cp packages/db/.env.example packages/db/.env
# Edit both .env files to set DATABASE_URL="postgresql://postgres:your_password@localhost:5432/simstudio"
- Run migrations:
cd packages/db && bun run db:migrate
- Start development servers:
bun run dev:full # Starts Next.js app and realtime socket server
Or run separately: bun run dev (Next.js) and cd apps/sim && bun run dev:sockets (realtime).
Chat API Keys
Chat is a Sim-managed service. To use Chat on a self-hosted instance:
- Go to https://sim.ai → Settings → Chat keys and generate a Chat API key
- Set
COPILOT_API_KEYenvironment variable in your self-hosted apps/sim/.env file to that value
Environment Variables
See the environment variables reference for the full list, or apps/sim/.env.example for defaults.
Tech Stack
Next.js · Bun · PostgreSQL · Drizzle · Better Auth · Tailwind — and the rest of the stack
- Framework: Next.js (App Router)
- Runtime: Bun
- Database: PostgreSQL with Drizzle ORM
- Authentication: Better Auth
- Schema Validation: Zod
- UI: Shadcn, Tailwind CSS
- Streaming Markdown: Streamdown
- State Management: Zustand, TanStack Query
- Flow Editor: ReactFlow
- Docs: Fumadocs
- Monorepo: Turborepo
- Realtime: Socket.io
- Background Jobs: Trigger.dev
- Remote Code Execution: E2B
- Isolated Code Execution: isolated-vm
Contributing
We welcome contributions! Please see our Contributing Guide for details.
License
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.





