Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 12 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
node_modules
dist
.git
.env
.env.*
!.env.example
data
artifacts
RESEARCH.md
docs
*.sqlite*
*.db*
50 changes: 50 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# OpenDots template: the UI opens in setup state until these fields are configured.
HOST=127.0.0.1
PORT=4310
DATABASE_PATH=data/opendots.sqlite
# Keep OWNER_ID stable: it owns the persistent Intelligence conversations.
OWNER_ID=opendots-owner
# npm run dev allows http://127.0.0.1:5173; override for a different exact origin.
# APP_ORIGIN=http://127.0.0.1:5173
# Required for an external HOST binding (24+ characters); enables local login too.
# OWNER_TOKEN=

INTELLIGENCE_API_KEY=
# INTELLIGENCE_API_URL=
# INTELLIGENCE_WS_URL=
OPENAI_API_KEY=
OPENAI_BASE_URL=https://api.openai.com/v1
OPENAI_MODEL=

# Optional isolated read-only public-page browser. No search service is bundled.
BROWSER_URL=http://127.0.0.1:4311
BROWSER_SECRET=
BROWSER_HOST=127.0.0.1
BROWSER_PORT=4311
# Use the same random 24+ character secret in app/browser. All redirects are blocked.
# Supply canonical public URLs. Use the separate browser container for isolation.

# Optional realtime speech; compute uses the same configured Intelligence thread.
VOICE_API_KEY=
VOICE_MODEL=
VOICE_NAME=marin

# Optional managed Slack channel; see docs/SETUP.md#slack.
# Match the managed declaration name, not a Slack #conversation name.
# OpenTag calls this INTELLIGENCE_CHANNEL_NAME; OpenDots uses SLACK_CHANNEL_NAME.
# Allowlist both the Slack workspace and explicit Slack user IDs.
SLACK_CHANNEL_NAME=
SLACK_TEAM_ID=
SLACK_USER_IDS=
# SLACK_DOT_ID= (defaults to the initial Dot)

# Optional persistent computers, one per Dot, using OpenBot services.
# See docs/COMPUTERS.md. Keep these two different random secrets on the server.
COMPUTER_SUPERVISOR_URL=
COMPUTER_SUPERVISOR_TOKEN=
COMPUTER_TOKEN=
# Keep stable: the namespace identifies existing containers and persistent volumes.
COMPUTER_NAMESPACE=opendots
# COMPUTER_MEMORY_BYTES=2147483648
# COMPUTER_RUNTIME=runsc
# ENGINE_SOCKET=/var/run/docker.sock
22 changes: 22 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: CI
on:
push:
pull_request:
permissions:
contents: read
jobs:
check:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '24'
cache: npm
- run: npm ci
- run: npm run check-format
- run: npm run lint
- run: npm run typecheck
- run: npm test
- run: npm run build
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,11 @@ test-results/
docs/superpowers/
RESEARCH.md
.DS_Store

data/
*.sqlite
*.sqlite-shm
*.sqlite-wal

# Local hosted-project selection
.copilotkit/
5 changes: 5 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
dist
package-lock.json
RESEARCH.md
docs/superpowers
1 change: 1 addition & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "singleQuote": true, "trailingComma": "all" }
26 changes: 26 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
FROM node:24-bookworm-slim AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:24-bookworm-slim AS app
ENV NODE_ENV=production HOST=0.0.0.0 PORT=4310 DATABASE_PATH=/data/opendots.sqlite
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev && mkdir -p /data && chown node:node /data
COPY --from=build /app/dist ./dist
USER node
EXPOSE 4310
CMD ["node", "dist/server/server/index.js"]

FROM node:24-bookworm-slim AS browser
ENV NODE_ENV=production BROWSER_HOST=0.0.0.0 BROWSER_PORT=4311 PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev && npx playwright install --with-deps chromium && chmod -R a+rX /ms-playwright
COPY --from=build /app/dist/server ./dist/server
USER node
EXPOSE 4311
CMD ["node", "dist/server/browser/index.js"]
85 changes: 61 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,43 +8,59 @@

Spaces, specialist agents, and conversations that move between text, calls, and Slack.

[Overview](#overview) · [Architecture](#architecture) · [Status](#development-status) · [Contributing](CONTRIBUTING.md)
[Get started](#get-started) · [Overview](#overview) · [Architecture](#architecture) · [Status](#development-status) · [Contributing](CONTRIBUTING.md)

</div>

---

![Live specialist conversation](docs/demos/specialist-chat.gif)

_A live conversation with Scout, with the updated Dot avatars and separate Dots, Spaces, and recent chats. [Watch the MP4](docs/demos/specialist-chat.mp4)._

## Overview

OpenDots is a starting point for building your own agent workspace. Clone it, define your Dots, connect your services, and adapt the interface and tools to your needs.

**A template, not a hosted product.** You run the application and configure its infrastructure. The template is under development; the status table below separates implemented work from planned integrations.
**A template, not a hosted product.** You run the application and configure its infrastructure. The template is in early development; the status table below distinguishes local verification from connected-service testing.

### Spaces

Group related Dots, conversations, sources, and results in a Space. Keep each area of work organized without losing the context of its conversations.
A Space is a home for working documents. Dots appear separately in navigation and can be granted access to multiple Spaces in their settings. Each Dot has a default destination for saved pages; existing installations retain their original Space access. Browse pages in a searchable library, switch between grid and list views, and organize documents as nested subpages. Open a page in a focused visual editor with formatting, slash commands, and undo/redo. Write directly, save a conversation as a page, or ask a specialist to create and revise content.

Pages stay in the local workspace database. Their conversations use CopilotKit Threads, with a separate conversation for each page and specialist. Page links connect the document workspace to Dot chat. Manual editing works before you configure conversation services. Autosave reports its progress, failed saves retain your draft, and revision checks prevent stale edits from overwriting newer content. Markdown source mode remains available.

![Navigate Spaces and ask a specialist about a page](docs/demos/spaces-page-chat.gif)

_Open a Space, navigate to its launch brief, ask Scout about the saved page, and continue in Dot chat. This recording uses live page chat and example launch content. [Watch the MP4](docs/demos/spaces-page-chat.mp4)._

### Specialist Dots

Give each Dot a name, role, instructions, and permitted tools. A researcher can investigate a topic; a writer can turn findings into a draft. Inspect their work and control what they can do.

### Dot computers

Each Dot can have its own computer, using [OpenBot](https://github.com/CopilotKit/OpenBot)'s container supervisor and computer service. Its browser profile and workspace files persist across stop/start. The Computer panel exposes browser control, human takeover, files, terminal output, and activity, with browser, file, and shell permissions set per Dot. The application keeps service credentials on the server and derives a different computer credential for each Dot.

See [Computer setup](docs/COMPUTERS.md) to build the pinned services and connect your deployment. Computer tools require those services; an unconfigured template does not execute commands on your host.

### Text and calls

A continuous conversation keeps the Dot's avatar and status above the messages, with text and call controls close at hand. Work updates, source links, and call receipts appear in the timeline; a side panel shows results or the agent's computer.

Calls pair realtime speech with a separate compute agent, so the conversation can continue while longer work runs. Both use the same conversation context and tool permissions. Voice integration is still in progress.
Calls pair realtime speech with a separate compute agent, so the conversation can continue while longer work runs. Both use the same conversation context and tool permissions. Voice needs separate provider configuration.

### Slack

Message a Dot through a managed Slack connection using Channels SDK. Explicit identity and Space mappings determine which conversations and tools a Slack user can access.
Mention a Dot through a managed Slack connection using Channels SDK, then continue in its thread. The integration follows [OpenTag](https://github.com/CopilotKit/OpenTag), with an explicit workspace/user allowlist and a selected specialist. See [Slack setup](docs/SETUP.md#slack) to connect your deployment.

## Architecture

The template uses CopilotKit's React SDK and runtime, Intelligence for durable Threads, and Channels SDK for Slack. Application metadata and background-work state are stored separately from conversation history.
The template uses CopilotKit's React SDK and runtime, Intelligence for durable Threads, and Channels SDK for Slack. Pages, application metadata, and background-work state are stored separately from conversation history.

```mermaid
flowchart TB
Web["Web app: Spaces, Dots, chat"] --> Runtime[CopilotKit runtime]
Web["Web app: pages, Spaces, Dots, chat"] --> Runtime[CopilotKit runtime]
Slack[Slack] <--> Managed[Managed channel connection]
Managed <--> Channels[Channels SDK]
Channels --> Agents[Specialist compute agents]
Expand All @@ -57,35 +73,55 @@ flowchart TB
Agents --> Controls[Tool permissions]
Controls --> Computer[Isolated browser / workspace]
Agents --> Jobs[Background work]
Runtime --> Metadata[(Spaces, Dots, work metadata)]
Runtime --> Metadata[(Pages, Spaces, Dots, work metadata)]
```

You configure the Intelligence project, model provider, and channel connection for your deployment; calls also need a speech provider. Credentials stay on the server. Missing configuration should produce a clear setup state, and test fixtures should remain visibly separate from live integrations.

[OpenMuse](https://github.com/CopilotKit/OpenMuse) and [OpenBot](https://github.com/CopilotKit/openbot) are code references for persistent work, agent computers, and execution controls. OpenDots can be adapted to your own workflows and deployment choices.

## Get started

Use **Node.js 24** and **npm**:

```sh
git clone https://github.com/CopilotKit/OpenDots.git
cd OpenDots
npm ci
cp .env.example .env
npm run dev
```

Open **http://127.0.0.1:5173**. You can create Spaces, write pages, and configure Dots before connecting services. Add your conversation and model settings to `.env` to start chatting.

See [Setup](docs/SETUP.md) for configuration, Slack, calls, the browser service, and Docker.

## Development status

A local research prototype includes persistent tasks, scheduling, memory controls, a separate read-only browser, and a responsive companion UI. That work is being integrated into the template's conversation architecture.
| Area | Included |
| -------------------------- | ------------------------------------------------------------------------------------------------- |
| Spaces and Specialist Dots | Saved names, role instructions, and per-Dot research and memory permissions |
| Pages | Searchable library, visual editor, slash commands, autosave, and revision checks |
| Conversations | React SDK chat and Threads integration, page-specific conversations, and source links |
| Slack | Managed Channels SDK declaration with workspace and user allowlists |
| Calls | WebRTC speech, delegated compute, bounded sessions, hangup, and timeline receipts |
| Background work | Scheduled server-side turns in their original conversation, with pause and retry controls |
| Browser | Separate read-only public-page service with page capture and navigation limits |
| Dot computers | Per-Dot browser profiles, files, shell, takeover, permissions, and action records through OpenBot |
| Memory | User-managed preferences that permitted Dots can use |
| Deployment | Local Node setup and separate application/browser containers |

| Area | Status |
| ------------------------------------------------- | ------------------------------------------------------- |
| Research tasks, scheduling, and browser isolation | Implemented in the local prototype; integration pending |
| Intelligence runtime and Threads | Integration in progress |
| Spaces and Specialist Dots | Implementation in progress |
| Conversation layout and text streaming | Implementation in progress |
| Slack | Integration in progress |
| Realtime calls and compute delegation | Integration in progress |
| Connected-service verification | Pending deployment configuration |
Local checks cover setup, persistence, permissions, SDK failure handling, and browser isolation. Automated tests use service fixtures. **Live Intelligence, model responses, and page-context chat were verified on September 29, 2026.** Slack, voice, and Dot-computer verification still require their own deployment configuration. See [recording notes](docs/demos/README.md) for the demonstrated flows and limits.

This initial repository milestone contains documentation. Application source and reproducible setup instructions will follow with the implementation.
This is a single-owner starting point. Shared editing, invitations, file uploads, and interactive page embeds are not included. Schedules are recurring instructions, not a complete goal or event-trigger system. Specialist Dots have separate roles and conversations; multi-Dot group conversations and automatic delegation are further work.

### Next steps
### Extending the template

- Finish conversation persistence and Space/Dot configuration.
- Connect text, Slack, and calls to the same authorized agent tools.
- Verify background execution, cancellation, reconnects, and service failures.
- Document local setup and container deployment.
- Add identity, Space membership, and shared page editing for multi-user deployments.
- Add file attachments and richer page content.
- Add event triggers and a persistent responsibility lifecycle.
- Extend tools and approval flows for your own workflows.
- Add richer artifacts, connected-app context, and specialist coordination.

## Contributing

Expand All @@ -97,6 +133,7 @@ See [Contributing](CONTRIBUTING.md) for development guidance and [Security](SECU
- [Channels SDK](https://github.com/CopilotKit/channels-sdk)
- [OpenMuse](https://github.com/CopilotKit/OpenMuse)
- [OpenBot](https://github.com/CopilotKit/openbot)
- [OpenTag](https://github.com/CopilotKit/OpenTag) — Channels SDK integration reference

## License

Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ OpenDots is an application template under development, not a hosted service. The
- Treat page text, uploaded content, and model output as untrusted data, not authorization to change permissions.
- Authorize every Space, Dot, and thread operation on the server. Map Slack actors explicitly; never treat a display name or client-supplied user ID as proof of identity.
- Voice sessions must use scoped, short-lived credentials and route compute actions through the same permissions as text and Slack.
- The initial research prototype is read-only. Adding external writes requires a separate authorization and review design.
- Research browsing is read-only. Page tools can edit local documents in the executing Dot’s Space; those writes use revision checks. Adding external writes requires a separate authorization and review design.

Recurring work requires an available server. A sample run is not evidence that a live provider or deployment is safe or configured correctly. Review results before using them for important decisions.

Expand Down
18 changes: 18 additions & 0 deletions compose.computers-app.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Overlay for an app running in Compose instead of on the host.
# Use with compose.yml and compose.computers.yml, in that order.
services:
app:
environment:
COMPUTER_SUPERVISOR_URL: http://computer-supervisor:4300
COMPUTER_SUPERVISOR_TOKEN: ${COMPUTER_SUPERVISOR_TOKEN:?Set COMPUTER_SUPERVISOR_TOKEN in .env}
COMPUTER_TOKEN: ${COMPUTER_TOKEN:?Set COMPUTER_TOKEN in .env}
COMPUTER_NAMESPACE: ${COMPUTER_NAMESPACE:-opendots}
networks:
- computer-control
- computers
computer-supervisor:
environment:
COMPUTER_NETWORK: ${COMPUTER_NAMESPACE:-opendots}-computers
networks:
computers:
name: ${COMPUTER_NAMESPACE:-opendots}-computers
53 changes: 53 additions & 0 deletions compose.computers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# OpenBot services pinned to the source revision reviewed for this template.
# Build both images; only the supervisor is started directly. It creates one
# computer per Dot, with separate named volumes for files and browser profiles.
services:
computer-image:
profiles: [build-computers]
image: opendots-computer:b6932d3
build:
context: https://github.com/CopilotKit/OpenBot.git#b6932d31a8d6e7896c15139dfc27a6c6911deb27
dockerfile: agent-computer/Dockerfile
command: ['true']
computer-supervisor:
image: opendots-supervisor:b6932d3-dot-auth
build:
context: .
dockerfile: deployment/computers/supervisor.Dockerfile
additional_contexts:
openbot: https://github.com/CopilotKit/OpenBot.git#b6932d31a8d6e7896c15139dfc27a6c6911deb27
ports:
- '127.0.0.1:4312:4300'
environment:
PORT: '4300'
SUPERVISOR_TOKEN: ${COMPUTER_SUPERVISOR_TOKEN:?Set COMPUTER_SUPERVISOR_TOKEN in .env}
COMPUTER_TOKEN: ${COMPUTER_TOKEN:?Set COMPUTER_TOKEN in .env}
COMPUTER_NAMESPACE: ${COMPUTER_NAMESPACE:-opendots}
COMPUTER_IMAGE: opendots-computer:b6932d3
COMPUTER_BROWSER_MODE: headless
COMPUTER_NETWORK: ''
COMPUTER_MEMORY_BYTES: ${COMPUTER_MEMORY_BYTES:-2147483648}
COMPUTER_RUNTIME: ${COMPUTER_RUNTIME:-}
volumes:
- ${ENGINE_SOCKET:-/var/run/docker.sock}:/var/run/docker.sock
networks:
- computer-control
init: true
restart: unless-stopped
security_opt:
- no-new-privileges:true
cap_drop: [ALL]
healthcheck:
test:
[
'CMD',
'bun',
'-e',
"const r = await fetch('http://localhost:4300/health'); const j = await r.json(); process.exit(r.ok && j.docker ? 0 : 1)",
]
interval: 10s
timeout: 5s
retries: 3
networks:
computer-control:
internal: true
Loading
Loading