@lightupai/polaris 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +38 -0
- package/.mcp.json +12 -0
- package/LICENSE +201 -0
- package/Makefile +38 -0
- package/PLAN.md +438 -0
- package/docker-compose.yml +14 -0
- package/docs/README.md +377 -0
- package/hooks/capture.sh +19 -0
- package/hooks/statusline.sh +30 -0
- package/package.json +22 -0
- package/scripts/setup-google-oauth.sh +111 -0
- package/scripts/setup-slack-app.sh +115 -0
- package/skills/polaris/SKILL.md +29 -0
- package/src/cli/cli.ts +294 -0
- package/src/client/client.ts +245 -0
- package/src/daemon/daemon.ts +275 -0
- package/src/service/auth.ts +45 -0
- package/src/service/db.ts +275 -0
- package/src/service/server.ts +406 -0
- package/src/slack/system.ts +107 -0
- package/src/types.ts +108 -0
- package/src/web/app.ts +397 -0
- package/src/web/fixtures.ts +121 -0
- package/src/web/layout.ts +68 -0
- package/src/web/pages.ts +156 -0
- package/src/web/serve.ts +13 -0
- package/src/web/views.ts +356 -0
- package/tests/auth.test.ts +37 -0
- package/tests/client.test.ts +187 -0
- package/tests/daemon.test.ts +220 -0
- package/tests/db.test.ts +282 -0
- package/tests/e2e.test.ts +415 -0
- package/tests/service.test.ts +365 -0
- package/tests/types.test.ts +240 -0
- package/tests/web.test.ts +420 -0
- package/tsconfig.json +16 -0
package/PLAN.md
ADDED
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
# Polaris: Bidirectional Coding Agent Session Bridge
|
|
2
|
+
|
|
3
|
+
## Context
|
|
4
|
+
|
|
5
|
+
We're building the first feature for the Lightup project — a system that **captures every interaction** in a coding agent session (user messages, agent responses, tool calls, tool results) and **injects external messages** into the session. This enables multiplayer collaboration where teammates and external systems can observe and participate in coding agent sessions. The system is model-agnostic — it works with any coding agent (e.g., Claude Code, Cursor, Windsurf).
|
|
6
|
+
|
|
7
|
+
Polaris is a **SaaS service**. Organizations sign up, connect their Slack workspace, and team members authenticate via SSO. The cloud service is the central broker and system of record.
|
|
8
|
+
|
|
9
|
+
## Organization & Auth
|
|
10
|
+
|
|
11
|
+
### Org Signup (Admin, web app at polaris.dev)
|
|
12
|
+
|
|
13
|
+
1. Admin visits `polaris.dev`, signs up with **Google SSO**
|
|
14
|
+
2. Creates an **organization** (e.g., `lightup`)
|
|
15
|
+
3. Admin dashboard:
|
|
16
|
+
- **Connect Slack workspace** — OAuth flow, polaris gets a bot token
|
|
17
|
+
- **Invite team members** — by email, or auto-join by email domain
|
|
18
|
+
- **Manage projects** — create, archive, view activity
|
|
19
|
+
|
|
20
|
+
### Slack Connection (Admin, web app)
|
|
21
|
+
|
|
22
|
+
Admin clicks "Connect Slack" → Slack OAuth → polaris receives bot token + workspace user list (with emails). The **Slack bridge is server-side** — managed by the SaaS, not deployed by the user. One bridge per org.
|
|
23
|
+
|
|
24
|
+
### User Auth (each team member, one-time per machine)
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
npx @lightup/polaris login
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Opens browser → Google SSO (same provider as the org) → callback stores a token in `~/.polaris/credentials.json`.
|
|
31
|
+
|
|
32
|
+
The token carries:
|
|
33
|
+
- **User identity** — derived from Google profile (e.g., `user:manu`)
|
|
34
|
+
- **Org membership** — which org this user belongs to
|
|
35
|
+
- **Service URL** — the polaris SaaS endpoint
|
|
36
|
+
|
|
37
|
+
The `login` command also installs:
|
|
38
|
+
- Local daemon (as a persistent service — launchd on Mac, systemd on Linux)
|
|
39
|
+
- MCP server config → `~/.claude/` (global, works in every project and Claude Desktop)
|
|
40
|
+
- Hook config → `~/.claude/settings.json`
|
|
41
|
+
- Status line config → `~/.claude/settings.json`
|
|
42
|
+
- `/polaris` skill → `~/.claude/skills/polaris/SKILL.md`
|
|
43
|
+
|
|
44
|
+
**One command sets up everything.**
|
|
45
|
+
|
|
46
|
+
### Identity Mapping (Slack ↔ Polaris)
|
|
47
|
+
|
|
48
|
+
The user's **email is the common key** between Google SSO and Slack:
|
|
49
|
+
|
|
50
|
+
- When admin connects Slack (OAuth), polaris gets the workspace user list with emails
|
|
51
|
+
- When a user logs in via Google SSO, polaris has their email
|
|
52
|
+
- **Automatic match**: polaris user `user:manu` (manu@lightup.com) ↔ Slack user `@manu` (manu@lightup.com)
|
|
53
|
+
|
|
54
|
+
When a polaris event is posted to Slack, it shows the user's Slack identity (avatar, display name). When someone posts in Slack, the bridge resolves Slack user → email → polaris identity.
|
|
55
|
+
|
|
56
|
+
**Edge cases:**
|
|
57
|
+
- **Email mismatch** (different Google vs Slack emails) — admin dashboard has manual override to link accounts
|
|
58
|
+
- **No Slack account** — polaris posts as the bot with attribution: `polaris-bot: [user:manu] built the auth middleware`
|
|
59
|
+
- **Slack-only advisor** (no polaris account) — Slack display name used as identity: `slack:krishna`
|
|
60
|
+
|
|
61
|
+
## Participants: Humans and Agents
|
|
62
|
+
|
|
63
|
+
Every participant in polaris — whether human or AI agent — has an **identity** with a type prefix:
|
|
64
|
+
|
|
65
|
+
- `user:manu`, `user:krishna`, `user:priya` — humans (identity from SSO)
|
|
66
|
+
- `agent:test-writer`, `agent:security-reviewer` — agents
|
|
67
|
+
- `slack:someone` — Slack-only participants without a polaris account
|
|
68
|
+
|
|
69
|
+
Agents are **first-class participants**. They can be drivers or advisors, same as humans. Polaris treats them identically — the cloud service doesn't distinguish between human and agent clients.
|
|
70
|
+
|
|
71
|
+
**Spawning**: humans create sessions and start agents out of band (not managed by polaris in v1).
|
|
72
|
+
|
|
73
|
+
**Privileges & HITL**: agent permissions, approval flows, and escalation paths are configured outside polaris. Polaris's job is context pooling, capture, injection, and broadcast — not authorization.
|
|
74
|
+
|
|
75
|
+
**Addressed messaging**: every injection specifies a **target** — a specific session within the project. No blind broadcast into all sessions.
|
|
76
|
+
|
|
77
|
+
## Data Model: Projects, Sessions, Drivers, Advisors
|
|
78
|
+
|
|
79
|
+
### Organizations
|
|
80
|
+
|
|
81
|
+
An **organization** is the top-level account. Created via signup on `polaris.dev`. All projects, users, and integrations are scoped to an org.
|
|
82
|
+
|
|
83
|
+
### Projects
|
|
84
|
+
|
|
85
|
+
A **project** is the context container within an org. All context is pooled at the project level. A project has a flat, human-readable name (e.g., `pj`). One Slack channel per project (`#pj`).
|
|
86
|
+
|
|
87
|
+
### Sessions
|
|
88
|
+
|
|
89
|
+
A project contains one or more **sessions**, each representing a concurrent workstream (e.g., feature, bugfix). Sessions have names scoped to their project (e.g., `fxm`, `fxk`).
|
|
90
|
+
|
|
91
|
+
### Drivers
|
|
92
|
+
|
|
93
|
+
Each session has **one driver** — a human or agent actively building in a coding agent (e.g., Claude Code). Multiple sessions in a project can have concurrent drivers (one per session). A driver's activity (prompts, agent responses, tool calls) is captured and broadcast.
|
|
94
|
+
|
|
95
|
+
### Advisors
|
|
96
|
+
|
|
97
|
+
**Advisors** (human or agent) contribute context via Slack or another client. Advisory messages are injected into a **specific target session's** driver. Multiple advisors can participate simultaneously. Every injection must specify its target session.
|
|
98
|
+
|
|
99
|
+
### Context Pooling
|
|
100
|
+
|
|
101
|
+
All events across all sessions in a project are persisted together as the project's shared context. This means:
|
|
102
|
+
|
|
103
|
+
- **Real-time**: advisors' messages are injected into the target driver's session immediately
|
|
104
|
+
- **Sibling activity**: events from other sessions (e.g., Krishna's `fxk` work) are available on-demand to a driver (e.g., Manu on `fxm`) but not auto-injected to avoid noise
|
|
105
|
+
- **Handoff/new session**: when a driver takes over or starts a new session, they can be seeded with full project context
|
|
106
|
+
|
|
107
|
+
### Handoff
|
|
108
|
+
|
|
109
|
+
The driver role on a session can transfer from one person to another:
|
|
110
|
+
|
|
111
|
+
1. Current driver releases (via command or API)
|
|
112
|
+
2. Session goes to "open" state (no driver)
|
|
113
|
+
3. New driver claims the session, connects their coding agent CLI
|
|
114
|
+
4. New driver's session is seeded with context from project history
|
|
115
|
+
5. Slack channel shows the transition
|
|
116
|
+
|
|
117
|
+
## Setup Flow
|
|
118
|
+
|
|
119
|
+
### Step 1: Admin signs up org (once)
|
|
120
|
+
|
|
121
|
+
On `polaris.dev`:
|
|
122
|
+
1. Google SSO → org created
|
|
123
|
+
2. Connect Slack workspace → OAuth
|
|
124
|
+
3. Invite team (or set auto-join by email domain)
|
|
125
|
+
|
|
126
|
+
### Step 2: User sets up machine (once per machine)
|
|
127
|
+
|
|
128
|
+
```sh
|
|
129
|
+
npx @lightup/polaris login
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Browser opens → Google SSO → token stored → daemon installed → MCP/hooks/skill/status line configured in `~/.claude/`. Done.
|
|
133
|
+
|
|
134
|
+
### Step 3: User connects to a session (each time)
|
|
135
|
+
|
|
136
|
+
Inside any coding agent:
|
|
137
|
+
```
|
|
138
|
+
/polaris join my-project fxm
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Project is scoped to the user's org (from token). User identity is from SSO. Session is created if it doesn't exist, or joined if it does. The Slack channel `#my-project` is auto-created by the server-side bridge if this is the first session in this project.
|
|
142
|
+
|
|
143
|
+
That's the complete flow: **one web signup, one CLI command, one slash command.**
|
|
144
|
+
|
|
145
|
+
## Example: Project `pj` with Humans + Agents
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
Project pj (org: lightup)
|
|
149
|
+
├── session fxm driver: user:manu auth middleware
|
|
150
|
+
├── session fxk driver: user:krishna database schema
|
|
151
|
+
├── session tests driver: agent:test-writer tests for fxm + fxk
|
|
152
|
+
│
|
|
153
|
+
├── advisor: agent:security-reviewer (watches project, advises sessions)
|
|
154
|
+
└── advisor: user:priya (via Slack)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
1. **Manu** creates project `pj` with session `fxm`, connects as driver
|
|
158
|
+
2. **Krishna** creates session `fxk`, connects as driver
|
|
159
|
+
3. `agent:test-writer` is started out of band, drives session `tests`
|
|
160
|
+
4. `agent:security-reviewer` connects as an advisor, watching project events
|
|
161
|
+
5. Slack `#pj` shows an interleaved, attributed log:
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
[user:manu/fxm → agent] "Let's implement the auth middleware"
|
|
165
|
+
[agent → user:manu/fxm] "I'll create src/middleware/auth.ts..."
|
|
166
|
+
[user:krishna/fxk → agent] "Set up the database schema for users"
|
|
167
|
+
[agent → user:krishna/fxk] "Creating migrations/001_users.sql..."
|
|
168
|
+
[user:priya → fxk] "Remember we need GDPR compliance on the users table"
|
|
169
|
+
[agent → user:krishna/fxk] "Good point from Priya. Adding data retention fields..."
|
|
170
|
+
[agent:security-reviewer → fxm] "This auth endpoint needs rate limiting"
|
|
171
|
+
[agent → user:manu/fxm] "Adding rate limiting middleware..."
|
|
172
|
+
[agent:test-writer/tests → agent] "Writing integration tests for auth middleware"
|
|
173
|
+
[agent → agent:test-writer/tests] "Created tests/auth.test.ts..."
|
|
174
|
+
[user:manu/fxm → agent] "What has Krishna done on fxk so far?"
|
|
175
|
+
[agent → user:manu/fxm] "Krishna has set up the users schema with GDPR fields..."
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
6. Manu finishes `fxm`, hands off `fxk` to himself to continue Krishna's work
|
|
179
|
+
7. The Slack log is continuous and complete — humans, agents, handoffs, all in one stream
|
|
180
|
+
|
|
181
|
+
## Architecture
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
┌───────────────────────────────────────────────────────────────┐
|
|
185
|
+
│ Polaris SaaS (polaris.dev) │
|
|
186
|
+
│ │
|
|
187
|
+
│ Web App: │
|
|
188
|
+
│ Signup (Google SSO) | Org dashboard | Slack OAuth │
|
|
189
|
+
│ │
|
|
190
|
+
│ Cloud Service (Broker / System of Record): │
|
|
191
|
+
│ REST API (all endpoints authenticated via token) │
|
|
192
|
+
│ POST /projects create │
|
|
193
|
+
│ GET /projects/:proj metadata │
|
|
194
|
+
│ GET /projects/:proj/messages full history │
|
|
195
|
+
│ GET /projects/:proj/events SSE (all) │
|
|
196
|
+
│ POST /projects/:proj/sessions create session │
|
|
197
|
+
│ GET /projects/:proj/sessions/:sess metadata │
|
|
198
|
+
│ POST /projects/:proj/sessions/:sess/events push │
|
|
199
|
+
│ GET /projects/:proj/sessions/:sess/events SSE │
|
|
200
|
+
│ POST /projects/:proj/sessions/:sess/inject inject │
|
|
201
|
+
│ GET /projects/:proj/sessions/:sess/messages history │
|
|
202
|
+
│ POST /projects/:proj/sessions/:sess/handoff release │
|
|
203
|
+
│ POST /projects/:proj/sessions/:sess/driver claim │
|
|
204
|
+
│ │
|
|
205
|
+
│ WebSocket (authenticated): │
|
|
206
|
+
│ /projects/:proj/ws project-level │
|
|
207
|
+
│ /projects/:proj/sessions/:sess/ws session-level │
|
|
208
|
+
│ │
|
|
209
|
+
│ Slack Bridge (server-side, managed per org): │
|
|
210
|
+
│ project ↔ Slack channel (auto-created) │
|
|
211
|
+
│ Email-based identity mapping (SSO ↔ Slack) │
|
|
212
|
+
│ │
|
|
213
|
+
│ Persistence: Postgres (Hetzner VPS) │
|
|
214
|
+
└────────┬──────────────────────────────────────────────────────┘
|
|
215
|
+
│
|
|
216
|
+
│ authenticated WebSocket + REST
|
|
217
|
+
│
|
|
218
|
+
┌────────┴──────────────────────────────────────────────────────┐
|
|
219
|
+
│ User's Machine │
|
|
220
|
+
│ │
|
|
221
|
+
│ Daemon (port 4321, one per machine): │
|
|
222
|
+
│ Routes hook events by CC session_id │
|
|
223
|
+
│ Manages WS connections to cloud (one per polaris session) │
|
|
224
|
+
│ Auth token from ~/.polaris/credentials.json │
|
|
225
|
+
│ │
|
|
226
|
+
│ MCP Server (one per coding agent session, stdio): │
|
|
227
|
+
│ Registers with daemon on startup │
|
|
228
|
+
│ polaris_connect | polaris_reply | polaris_context tools │
|
|
229
|
+
│ claude/channel capability for advisor injection │
|
|
230
|
+
│ │
|
|
231
|
+
│ Hooks (capture.sh → POST localhost:4321/events) │
|
|
232
|
+
│ Status Line (queries daemon for connection state) │
|
|
233
|
+
│ /polaris Skill (slash command UX) │
|
|
234
|
+
└───────────────────────────────────────────────────────────────┘
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## File Structure
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
src/
|
|
241
|
+
types.ts # Shared event types + zod schemas
|
|
242
|
+
service/
|
|
243
|
+
server.ts # Cloud service: HTTP + WebSocket + persistence
|
|
244
|
+
db.ts # Postgres persistence layer
|
|
245
|
+
auth.ts # Token validation, Google SSO, org scoping
|
|
246
|
+
daemon/
|
|
247
|
+
daemon.ts # Local daemon: hook routing, WS management
|
|
248
|
+
client/
|
|
249
|
+
client.ts # MCP channel server (stdio only)
|
|
250
|
+
slack/
|
|
251
|
+
bridge.ts # Slack ↔ cloud bridge (server-side, Socket Mode)
|
|
252
|
+
format.ts # Event → Slack mrkdwn formatting
|
|
253
|
+
identity.ts # Email-based Slack ↔ polaris user mapping
|
|
254
|
+
cli/
|
|
255
|
+
cli.ts # CLI: login, daemon, status
|
|
256
|
+
web/
|
|
257
|
+
app.ts # Web app: signup, dashboard, Slack OAuth
|
|
258
|
+
hooks/
|
|
259
|
+
capture.sh # Shell script: reads hook JSON stdin, POSTs to daemon
|
|
260
|
+
statusline.sh # Status line script: queries daemon, formats output
|
|
261
|
+
skills/
|
|
262
|
+
polaris/SKILL.md # /polaris slash command skill definition
|
|
263
|
+
tests/
|
|
264
|
+
types.test.ts # Schema validation tests
|
|
265
|
+
db.test.ts # Persistence layer tests
|
|
266
|
+
service.test.ts # Cloud service API tests
|
|
267
|
+
auth.test.ts # Auth + org scoping tests
|
|
268
|
+
daemon.test.ts # Daemon routing tests
|
|
269
|
+
client.test.ts # MCP client tests
|
|
270
|
+
slack.test.ts # Slack bridge tests
|
|
271
|
+
format.test.ts # Formatting tests
|
|
272
|
+
identity.test.ts # Identity mapping tests
|
|
273
|
+
capture.test.ts # Hook script test
|
|
274
|
+
tsconfig.json
|
|
275
|
+
.mcp.json # MCP server registration
|
|
276
|
+
docker-compose.yml # Local dev (Postgres)
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## Implementation Phases
|
|
280
|
+
|
|
281
|
+
### Phase 1: Types + Persistence ✓
|
|
282
|
+
- `src/types.ts` — zod schemas for participant IDs, hook payloads, inject/reply messages, event envelope, project/session models
|
|
283
|
+
- `src/service/db.ts` — Postgres persistence layer
|
|
284
|
+
- Tests, deps, tsconfig
|
|
285
|
+
|
|
286
|
+
### Phase 2: Cloud Service ✓
|
|
287
|
+
- `src/service/server.ts` — Bun HTTP + WebSocket server with full REST API
|
|
288
|
+
- Project and session endpoints, WebSocket at project and session levels
|
|
289
|
+
- Tests
|
|
290
|
+
|
|
291
|
+
### Phase 3: Local Client + Hooks ✓ (v1, pre-daemon)
|
|
292
|
+
- `src/client/client.ts` — MCP channel server + HTTP relay + WS connection
|
|
293
|
+
- `hooks/capture.sh` — hook event relay
|
|
294
|
+
- Tests
|
|
295
|
+
|
|
296
|
+
### Phase 4: Auth + Org Model
|
|
297
|
+
- `src/service/auth.ts` — Google SSO, token issuance/validation, org scoping
|
|
298
|
+
- `src/web/app.ts` — web app: signup flow, dashboard, Slack OAuth
|
|
299
|
+
- Add org + user tables to Postgres schema
|
|
300
|
+
- All API endpoints require auth, scope to org
|
|
301
|
+
- `src/cli/cli.ts` — `polaris login` command (browser SSO flow + local setup)
|
|
302
|
+
|
|
303
|
+
### Phase 5: Local Daemon + `/polaris` Skill + Status Line
|
|
304
|
+
|
|
305
|
+
The local architecture uses a **single daemon per machine** that routes between multiple concurrent coding agent sessions. Users interact through the `/polaris` slash command.
|
|
306
|
+
|
|
307
|
+
#### `/polaris` Slash Command (Skill)
|
|
308
|
+
|
|
309
|
+
`skills/polaris/SKILL.md` — the primary UX. Installed to `~/.claude/skills/polaris/` by `polaris login`.
|
|
310
|
+
|
|
311
|
+
- `/polaris join <project> <session>` — connects the current coding agent session to a polaris session. Creates the session if it doesn't exist. Project scoped to user's org (from token). User identity from SSO.
|
|
312
|
+
- `/polaris` (no args) — shows status: connected project/session/user, or "not connected".
|
|
313
|
+
- `/polaris disconnect` — disconnects from the current session.
|
|
314
|
+
|
|
315
|
+
Example:
|
|
316
|
+
```
|
|
317
|
+
/polaris join pj fxm ← connect to project pj, session fxm
|
|
318
|
+
/polaris ← check status
|
|
319
|
+
/polaris join pj fxk ← switch to different session
|
|
320
|
+
/polaris disconnect ← disconnect
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
#### Status Line
|
|
324
|
+
|
|
325
|
+
Persistent bar at the bottom of the coding agent CLI. Always visible, updates after every turn.
|
|
326
|
+
|
|
327
|
+
When connected:
|
|
328
|
+
```
|
|
329
|
+
polaris: pj/fxm (user:manu) ● connected
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
When disconnected:
|
|
333
|
+
```
|
|
334
|
+
polaris: not connected
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
- `hooks/statusline.sh` — queries daemon's `GET /status/:cc-session-id`, formats output
|
|
338
|
+
- Installed to `~/.claude/settings.json` by `polaris login`
|
|
339
|
+
|
|
340
|
+
#### Daemon
|
|
341
|
+
|
|
342
|
+
`src/daemon/daemon.ts` — persistent process on port 4321 (one per machine):
|
|
343
|
+
- `POST /events` ← hooks POST here (routes via `session_id` in hook JSON)
|
|
344
|
+
- `POST /register` ← MCP servers register their CC session → polaris session mapping on startup
|
|
345
|
+
- `POST /connect` ← `/polaris join` triggers this to bind a CC session to a polaris session
|
|
346
|
+
- `POST /disconnect` ← `/polaris disconnect` triggers this
|
|
347
|
+
- `GET /status/:cc-session-id` ← status line script queries this
|
|
348
|
+
- Auth token from `~/.polaris/credentials.json` for all cloud API calls
|
|
349
|
+
- Manages WebSocket connections to cloud service (one per active polaris session)
|
|
350
|
+
- Routes advisor messages from cloud to the correct MCP server instance
|
|
351
|
+
|
|
352
|
+
#### MCP Client
|
|
353
|
+
|
|
354
|
+
`src/client/client.ts` — MCP channel server (stdio only, no HTTP):
|
|
355
|
+
- Registers with daemon on startup (sends CC session_id)
|
|
356
|
+
- Exposes tools: `polaris_connect`, `polaris_disconnect`, `polaris_status`, `polaris_reply`, `polaris_context`
|
|
357
|
+
- `claude/channel` capability for injecting advisor messages
|
|
358
|
+
- Receives advisor messages from daemon via IPC
|
|
359
|
+
|
|
360
|
+
#### CLI
|
|
361
|
+
|
|
362
|
+
`src/cli/cli.ts`:
|
|
363
|
+
- `polaris login` — browser SSO → token stored → daemon + MCP + hooks + skill + status line installed
|
|
364
|
+
- `polaris daemon` — starts the daemon (normally auto-started)
|
|
365
|
+
- `polaris status` — shows all active sessions and daemon health
|
|
366
|
+
- `polaris logout` — removes token and local config
|
|
367
|
+
|
|
368
|
+
### Phase 6: Slack Bridge (Floor, server-side)
|
|
369
|
+
|
|
370
|
+
The Slack bridge runs server-side as part of the SaaS — not deployed by the user.
|
|
371
|
+
|
|
372
|
+
#### Slack Channel Lifecycle
|
|
373
|
+
|
|
374
|
+
- **Channel name = project name** — project `pj` → Slack `#pj`
|
|
375
|
+
- **Created automatically** when the first session is created in a project (if Slack is connected for the org)
|
|
376
|
+
- **Channel ID stored in the project record** on the cloud service
|
|
377
|
+
- Users never manually create or configure the Slack channel
|
|
378
|
+
|
|
379
|
+
#### Bridge
|
|
380
|
+
|
|
381
|
+
`src/slack/bridge.ts` — runs server-side, one instance per org:
|
|
382
|
+
- Connects to Slack via Socket Mode
|
|
383
|
+
- Watches all projects in the org via project-level WebSocket connections
|
|
384
|
+
- **Project → Slack**: session events → attributed, formatted Slack posts. `UserPromptSubmit` and `Stop` events posted; tool calls skipped or collapsed.
|
|
385
|
+
- **Slack → Project**: advisor messages → injected into target session (must specify target, e.g., `@fxm use RS256`)
|
|
386
|
+
- **Handoff events** → Slack notification showing the transition
|
|
387
|
+
|
|
388
|
+
#### Identity Mapping
|
|
389
|
+
|
|
390
|
+
`src/slack/identity.ts` — email-based Slack ↔ polaris user mapping:
|
|
391
|
+
- Automatic match via shared email between Google SSO and Slack workspace
|
|
392
|
+
- Admin override in dashboard for email mismatches
|
|
393
|
+
- Slack-only participants get `slack:displayname` identity
|
|
394
|
+
|
|
395
|
+
#### Formatter
|
|
396
|
+
|
|
397
|
+
`src/slack/format.ts` — event → Slack mrkdwn conversion:
|
|
398
|
+
- Attribution: `[user:manu/fxm → agent]`, `[agent:security-reviewer → fxm]`
|
|
399
|
+
- Markdown → Slack mrkdwn (different bold/italic/link syntax)
|
|
400
|
+
- Long messages truncated with "see full message" link
|
|
401
|
+
|
|
402
|
+
#### Slack App Requirements
|
|
403
|
+
|
|
404
|
+
- Socket Mode enabled
|
|
405
|
+
- Bot token scopes: `channels:manage`, `channels:join`, `chat:write`, `channels:read`, `users:read`, `users:read.email`
|
|
406
|
+
- Tokens stored per org in the database (from the Slack OAuth flow in the dashboard)
|
|
407
|
+
|
|
408
|
+
## Key Design Decisions
|
|
409
|
+
|
|
410
|
+
1. **SaaS with SSO** — organizations sign up on polaris.dev, users authenticate via Google SSO. No self-hosted setup for end users.
|
|
411
|
+
2. **Email-based identity mapping** — Google SSO email = Slack email. Automatic, no manual mapping. Admin override for mismatches.
|
|
412
|
+
3. **One command machine setup** — `polaris login` installs everything: daemon, MCP, hooks, skill, status line.
|
|
413
|
+
4. **One slash command to connect** — `/polaris join project session` from inside any coding agent. No terminal switching.
|
|
414
|
+
5. **Agents are first-class** — same identity model as humans (`agent:name` vs `user:name`). Spawned out of band. Privileges/HITL managed externally.
|
|
415
|
+
6. **Addressed messaging** — every injection targets a specific session. No blind broadcasts.
|
|
416
|
+
7. **Project-level context pooling** — all events persisted under the project. Sibling activity on-demand, not auto-injected.
|
|
417
|
+
8. **One driver per session, multiple sessions per project** — concurrent human and agent drivers.
|
|
418
|
+
9. **Status line** — persistent polaris connection indicator in the coding agent CLI. Queries daemon, updates every turn.
|
|
419
|
+
10. **Single daemon per machine** — routes hook events and cloud messages between multiple concurrent coding agent sessions.
|
|
420
|
+
11. **Server-side Slack bridge** — managed by the SaaS, not by the user. Auto-creates channels. Email-based identity mapping.
|
|
421
|
+
12. **`/polaris` slash command** — single entry point: join, disconnect, status.
|
|
422
|
+
13. **Postgres on Hetzner** — persistent, production-ready from day one.
|
|
423
|
+
14. **Flat names** — project names unique within an org, session names unique within a project.
|
|
424
|
+
|
|
425
|
+
## Verification
|
|
426
|
+
|
|
427
|
+
- `bun test` covers all unit + integration tests
|
|
428
|
+
- Manual end-to-end test:
|
|
429
|
+
1. Sign up org on polaris.dev, connect Slack
|
|
430
|
+
2. `npx @lightup/polaris login` — authenticate, install local components
|
|
431
|
+
3. Open coding agent, `/polaris join pj fxm` — verify status line shows connected
|
|
432
|
+
4. Send a prompt → verify it appears in Slack `#pj` attributed to `user:manu/fxm`
|
|
433
|
+
5. Another user: `/polaris join pj fxk` — verify both sessions broadcast to `#pj`
|
|
434
|
+
6. Post in Slack targeting `fxk` → verify it appears in Krishna's session
|
|
435
|
+
7. Manu asks "what has Krishna done?" → `polaris_context` fetches `fxk` history
|
|
436
|
+
8. Handoff `fxm` from Manu → Krishna → verify transition in Slack
|
|
437
|
+
9. Verify Slack identity mapping (polaris user shows as correct Slack profile)
|
|
438
|
+
- CI gate: GitHub Actions runs `bun test` on PRs
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
services:
|
|
2
|
+
polaris-postgres:
|
|
3
|
+
image: postgres:17
|
|
4
|
+
environment:
|
|
5
|
+
POSTGRES_USER: polaris
|
|
6
|
+
POSTGRES_PASSWORD: polaris
|
|
7
|
+
POSTGRES_DB: polaris
|
|
8
|
+
ports:
|
|
9
|
+
- "5432:5432"
|
|
10
|
+
volumes:
|
|
11
|
+
- polaris-pgdata:/var/lib/postgresql/data
|
|
12
|
+
|
|
13
|
+
volumes:
|
|
14
|
+
polaris-pgdata:
|