Skip to content

Commit fd1a900

Browse files
feat(chat-keys): standalone manage page, drop from settings nav, refresh README
- Add /account/settings/chat-keys — a linkable page to view, create, and revoke Chat API keys - Remove Chat keys from the settings sidebar (account + unified nav) and its render branches - README: replace Docker Compose + Manual Setup with the bun run setup wizard; drop the manual COPILOT_API_KEY step, point to the manage page
1 parent c5a6607 commit fd1a900

11 files changed

Lines changed: 52 additions & 98 deletions

File tree

README.md

Lines changed: 9 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -75,71 +75,27 @@ Docker must be installed and running. Use `-p, --port <port>` to run Sim on a di
7575

7676
## Self-hosting
7777

78-
### Docker Compose
78+
**Requirements:** [Bun](https://bun.sh/) and [Docker](https://www.docker.com/).
7979

8080
```bash
8181
git clone https://github.com/simstudioai/sim.git && cd sim
82-
docker compose -f docker-compose.prod.yml up -d
83-
```
84-
85-
Open [http://localhost:3000](http://localhost:3000)
86-
87-
Sim also supports local models via [Ollama](https://ollama.ai) and [vLLM](https://docs.vllm.ai/). See the [Docker self-hosting docs](https://docs.sim.ai/self-hosting/docker) for setup details.
88-
89-
### Manual Setup
90-
91-
**Requirements:** [Bun](https://bun.sh/), [Node.js](https://nodejs.org/) v20+, PostgreSQL 12+ with [pgvector](https://github.com/pgvector/pgvector)
92-
93-
1. Clone and install:
94-
95-
```bash
96-
git clone https://github.com/simstudioai/sim.git
97-
cd sim
9882
bun install
99-
bun run prepare # Set up pre-commit hooks
100-
```
101-
102-
2. Set up PostgreSQL with pgvector:
103-
104-
```bash
105-
docker run --name simstudio-db -e POSTGRES_PASSWORD=your_password -e POSTGRES_DB=simstudio -p 5432:5432 -d pgvector/pgvector:pg17
106-
```
107-
108-
Or install manually via the [pgvector guide](https://github.com/pgvector/pgvector#installation).
109-
110-
3. Configure environment:
111-
112-
```bash
113-
cp apps/sim/.env.example apps/sim/.env
114-
# Create your secrets
115-
perl -i -pe "s/your_encryption_key/$(openssl rand -hex 32)/" apps/sim/.env
116-
perl -i -pe "s/your_internal_api_secret/$(openssl rand -hex 32)/" apps/sim/.env
117-
perl -i -pe "s/your_api_encryption_key/$(openssl rand -hex 32)/" apps/sim/.env
118-
# DB configs for migration
119-
cp packages/db/.env.example packages/db/.env
120-
# Edit both .env files to set DATABASE_URL="postgresql://postgres:your_password@localhost:5432/simstudio"
83+
bun run setup
12184
```
12285

123-
4. Run migrations:
86+
`bun run setup` is an interactive wizard: it provisions the database, generates secrets, writes your `.env` files, connects a Chat API key, and starts Sim the way you choose:
12487

125-
```bash
126-
cd packages/db && bun run db:migrate
127-
```
128-
129-
5. Start development servers:
88+
- **Local dev** — run from source to contribute or hack on Sim
89+
- **Docker Compose** — a self-contained instance for testing self-hosting
90+
- **Kubernetes (Helm)** — deploy to a local cluster
13091

131-
```bash
132-
bun run dev:full # Starts Next.js app and realtime socket server
133-
```
92+
When it finishes, open [http://localhost:3000](http://localhost:3000).
13493

135-
Or run separately: `bun run dev` (Next.js) and `cd apps/sim && bun run dev:sockets` (realtime).
94+
Sim also supports local models via [Ollama](https://ollama.ai) and [vLLM](https://docs.vllm.ai/). See the [self-hosting docs](https://docs.sim.ai/self-hosting/docker) for details.
13695

13796
## Chat API Keys
13897

139-
Chat is a Sim-managed service. To use Chat on a self-hosted instance:
140-
141-
- Go to https://sim.ai → Settings → Chat keys and generate a Chat API key
142-
- Set `COPILOT_API_KEY` environment variable in your self-hosted apps/sim/.env file to that value
98+
Chat is a Sim-managed service. `bun run setup` connects a Chat API key for you — sign in when it opens your browser and the key is stored automatically. To view, create, or revoke keys later, go to [sim.ai/account/settings/chat-keys](https://sim.ai/account/settings/chat-keys).
14399

144100
## Environment Variables
145101

apps/sim/app/account/settings/[section]/page.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
parseSettingsPathSection,
1111
} from '@/components/settings/navigation'
1212
import { getSession } from '@/lib/auth'
13-
import { isBillingEnabled, isHosted } from '@/lib/core/config/env-flags'
13+
import { isBillingEnabled } from '@/lib/core/config/env-flags'
1414
import { isPlatformAdmin } from '@/lib/permissions/super-user'
1515

1616
interface AccountSettingsSectionPageProps {
@@ -46,7 +46,6 @@ export default async function AccountSettingsSectionPage({
4646
})
4747
if (!parsed) notFound()
4848
if (parsed === 'billing' && !isBillingEnabled) redirect(getAccountSettingsHref('general'))
49-
if (parsed === 'copilot' && !isHosted) redirect(getAccountSettingsHref('general'))
5049
if (parsed === 'admin' || parsed === 'mothership') {
5150
const isSuperUser = await isPlatformAdmin(session.user.id)
5251
if (!isSuperUser) notFound()

apps/sim/app/workspace/[workspaceId]/settings/components/copilot/copilot.tsx renamed to apps/sim/app/account/settings/chat-keys/chat-keys-view.tsx

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@ import {
1212
ChipModalHeader,
1313
SecretReveal,
1414
} from '@sim/emcn'
15+
import { ArrowLeft } from '@sim/emcn/icons'
1516
import { createLogger } from '@sim/logger'
1617
import { formatDate } from '@sim/utils/formatting'
1718
import { Plus } from 'lucide-react'
19+
import { useRouter } from 'next/navigation'
20+
import { getAccountSettingsHref } from '@/components/settings/navigation'
1821
import { SettingsEmptyState } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state'
1922
import type { SettingsAction } from '@/app/workspace/[workspaceId]/settings/components/settings-header/settings-header'
2023
import { SettingsPanel } from '@/app/workspace/[workspaceId]/settings/components/settings-panel'
@@ -26,7 +29,7 @@ import {
2629
useGenerateCopilotKey,
2730
} from '@/hooks/queries/copilot-keys'
2831

29-
const logger = createLogger('CopilotSettings')
32+
const logger = createLogger('ChatKeysSettings')
3033

3134
/** Formats a key's last-used timestamp, falling back to "Never" when unset. */
3235
function formatLastUsed(dateString?: string | null): string {
@@ -35,10 +38,11 @@ function formatLastUsed(dateString?: string | null): string {
3538
}
3639

3740
/**
38-
* Copilot Keys management component for handling API keys used with the Copilot feature.
39-
* Provides functionality to create, view, and delete copilot API keys.
41+
* Standalone page for managing the Chat API keys used with the Chat feature.
42+
* Provides functionality to create, view, and delete Chat API keys.
4043
*/
41-
export function Copilot() {
44+
export function ChatKeysView() {
45+
const router = useRouter()
4246
const { data: keys = [], isLoading } = useCopilotKeys()
4347
const generateKey = useGenerateCopilotKey()
4448
const deleteKeyMutation = useDeleteCopilotKey()
@@ -84,7 +88,7 @@ export function Copilot() {
8488
setIsCreateDialogOpen(false)
8589
}
8690
} catch (error) {
87-
logger.error('Failed to generate copilot API key', { error })
91+
logger.error('Failed to generate Chat API key', { error })
8892
setCreateError('Failed to create API key. Please check your connection and try again.')
8993
}
9094
}
@@ -98,7 +102,7 @@ export function Copilot() {
98102

99103
await deleteKeyMutation.mutateAsync({ keyId: keyToDelete.id })
100104
} catch (error) {
101-
logger.error('Failed to delete copilot API key', { error })
105+
logger.error('Failed to delete Chat API key', { error })
102106
}
103107
}
104108

@@ -122,12 +126,19 @@ export function Copilot() {
122126
return (
123127
<>
124128
<SettingsPanel
129+
back={{
130+
text: 'Account',
131+
icon: ArrowLeft,
132+
onSelect: () => router.push(getAccountSettingsHref('general')),
133+
}}
125134
search={{
126135
value: searchTerm,
127136
onChange: setSearchTerm,
128137
placeholder: 'Search API keys...',
129138
}}
130139
actions={actions}
140+
title='Chat keys'
141+
description='Create and manage the API keys that power Chat.'
131142
>
132143
{isLoading ? null : showEmptyState ? (
133144
<SettingsEmptyState>Click "Create API key" above to get started</SettingsEmptyState>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Suspense } from 'react'
2+
import type { Metadata } from 'next'
3+
import { redirect } from 'next/navigation'
4+
import { getAccountSettingsHref } from '@/components/settings/navigation'
5+
import { getSession } from '@/lib/auth'
6+
import { isHosted } from '@/lib/core/config/env-flags'
7+
import { ChatKeysView } from '@/app/account/settings/chat-keys/chat-keys-view'
8+
9+
export const metadata: Metadata = {
10+
title: 'Chat keys - Account settings',
11+
}
12+
13+
export default async function AccountChatKeysPage() {
14+
const session = await getSession()
15+
if (!session?.user) redirect('/login')
16+
if (!isHosted) redirect(getAccountSettingsHref('general'))
17+
18+
return (
19+
<Suspense fallback={null}>
20+
<ChatKeysView />
21+
</Suspense>
22+
)
23+
}

apps/sim/app/workspace/[workspaceId]/settings/[section]/settings.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ const ApiKeys = dynamic(() =>
2525
const BYOK = dynamic(() =>
2626
import('@/app/workspace/[workspaceId]/settings/components/byok/byok').then((m) => m.BYOK)
2727
)
28-
const Copilot = dynamic(() =>
29-
import('@/app/workspace/[workspaceId]/settings/components/copilot/copilot').then((m) => m.Copilot)
30-
)
3128
const Forks = dynamic(() => import('@/ee/workspace-forking/components/forks').then((m) => m.Forks))
3229
const Secrets = dynamic(() =>
3330
import('@/app/workspace/[workspaceId]/settings/components/secrets/secrets').then((m) => m.Secrets)
@@ -182,7 +179,6 @@ export function SettingsPage({ section }: SettingsPageProps) {
182179
<WhitelabelingSettings organizationId={organizationId} />
183180
)}
184181
{effectiveSection === 'byok' && <BYOK />}
185-
{effectiveSection === 'copilot' && <Copilot />}
186182
{effectiveSection === 'mcp' && <MCP />}
187183
{effectiveSection === 'forks' && <Forks />}
188184
{effectiveSection === 'custom-tools' && <CustomTools />}

apps/sim/app/workspace/[workspaceId]/settings/components/copilot/index.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

apps/sim/app/workspace/[workspaceId]/settings/navigation.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ describe('unified settings navigation', () => {
3535
{ id: 'apikeys', label: 'Sim API keys', section: 'system' },
3636
{ id: 'workflow-mcp-servers', label: 'MCP servers', section: 'system' },
3737
{ id: 'byok', label: 'BYOK', section: 'system' },
38-
{ id: 'copilot', label: 'Chat keys', section: 'system' },
3938
{ id: 'inbox', label: 'Sim mailer', section: 'system' },
4039
{ id: 'recently-deleted', label: 'Recently deleted', section: 'system' },
4140
{ id: 'sso', label: 'Single sign-on', section: 'enterprise' },

apps/sim/components/settings/account-settings-renderer.tsx

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,6 @@ const ApiKeys = dynamic(() =>
1717
(module) => module.ApiKeys
1818
)
1919
)
20-
const Copilot = dynamic(() =>
21-
import('@/app/workspace/[workspaceId]/settings/components/copilot/copilot').then(
22-
(module) => module.Copilot
23-
)
24-
)
2520
const Admin = dynamic(() =>
2621
import('@/app/workspace/[workspaceId]/settings/components/admin/admin').then(
2722
(module) => module.Admin
@@ -47,7 +42,6 @@ export function AccountSettingsRenderer({ section }: AccountSettingsRendererProp
4742
if (section === 'general') return <General />
4843
if (section === 'billing') return <Billing scope='account' />
4944
if (section === 'api-keys') return <ApiKeys scope='personal' />
50-
if (section === 'copilot') return <Copilot />
5145
if (section === 'admin') return <Admin />
5246
return <Mothership />
5347
}

apps/sim/components/settings/navigation.test.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ describe('settings navigation boundaries', () => {
3838
'apikeys',
3939
'workflow-mcp-servers',
4040
'byok',
41-
'copilot',
4241
'inbox',
4342
'recently-deleted',
4443
'sso',
@@ -55,7 +54,6 @@ describe('settings navigation boundaries', () => {
5554
'general',
5655
'billing',
5756
'api-keys',
58-
'copilot',
5957
'admin',
6058
'mothership',
6159
])

apps/sim/components/settings/navigation.ts

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,7 @@ import { isHosted } from '@/lib/core/config/env-flags'
2929

3030
export type SettingsPlane = 'account' | 'organization' | 'workspace'
3131

32-
export type AccountSettingsSection =
33-
| 'general'
34-
| 'billing'
35-
| 'api-keys'
36-
| 'copilot'
37-
| 'admin'
38-
| 'mothership'
32+
export type AccountSettingsSection = 'general' | 'billing' | 'api-keys' | 'admin' | 'mothership'
3933

4034
export type OrganizationSettingsSection =
4135
| 'members'
@@ -92,7 +86,6 @@ export type UnifiedSettingsSection =
9286
| 'sso'
9387
| 'domains'
9488
| 'whitelabeling'
95-
| 'copilot'
9689
| 'forks'
9790
| 'mcp'
9891
| 'custom-tools'
@@ -487,19 +480,6 @@ export const SETTINGS_SECTION_REGISTRY: readonly SettingsSectionRegistryEntry[]
487480
workspace: { id: 'byok', group: 'workspace', order: 2 },
488481
},
489482
},
490-
{
491-
label: 'Chat keys',
492-
icon: HexSimple,
493-
unified: {
494-
id: 'copilot',
495-
description: 'Manage the model-provider keys that power Chat.',
496-
group: 'system',
497-
requiresHosted: true,
498-
},
499-
planes: {
500-
account: { id: 'copilot', group: 'developer', order: 3 },
501-
},
502-
},
503483
{
504484
label: 'Sim mailer',
505485
icon: Send,

0 commit comments

Comments
 (0)