Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
dd9062c
refactor: SUPERUSER_TOKEN model — users.isAdmin as source of truth, d…
GoDoming Feb 22, 2026
a3c60c5
chore: rename dev service hive → hivetest in docker-compose.dev.yml
GoDoming Feb 22, 2026
8f71e6b
chore: revert dev service name to hive, add docker-compose.test.yml (…
GoDoming Feb 22, 2026
b760e32
feat: auto-migrate on startup + first-run setup UI + fix docs
GoDoming Feb 22, 2026
5d17925
fix: task detail dialog scrolls content, pins status buttons at bottom
GoDoming Feb 22, 2026
909bf44
fix: widen task detail and compose dialogs to 90vw
GoDoming Feb 22, 2026
781ce97
fix: remove drizzle from .dockerignore so migrations are available in…
GoDoming Feb 22, 2026
720dd68
fix: rewrite startup migration plugin to use postgres client directly
GoDoming Feb 22, 2026
7a58b27
revert: remove startup migration plugin (crashing container on start)
GoDoming Feb 22, 2026
0335efc
fix: use definePlugin from nitro (not undefined defineNitroPlugin)
GoDoming Feb 22, 2026
80cd572
fix: move auto-migration to module-level call in health route
GoDoming Feb 22, 2026
e3f65f2
fix: use !max-w-[90vw] to override shadcn DialogContent base sm:max-w-md
GoDoming Feb 22, 2026
d5373d8
fix: add missing users table migration
GoDoming Feb 22, 2026
0dda604
fix: remove all hardcoded domain and team-specific references
GoDoming Feb 22, 2026
2abd0e8
fix: use safe defaults for HIVE_HOSTNAME and HIVE_TLS_CERTRESOLVER
GoDoming Feb 22, 2026
af04334
fix: show error message when task save fails (was silent 502)
GoDoming Feb 22, 2026
1ebc008
feat: add docker-compose.local-ca.yml for private CA cert trust
GoDoming Feb 22, 2026
9b49a26
feat: add Closed task status + chat unread badge on Presence nav
GoDoming Feb 22, 2026
3338e6e
ux: improve first-time setup experience
GoDoming Feb 22, 2026
a902ea1
ux: comprehensive first-time experience improvements
GoDoming Feb 22, 2026
11cc56b
ux: hide 'None' connection label when no delivery method configured
GoDoming Feb 22, 2026
f408f81
feat: onboarding improvements (4 tasks complete)
GoDoming Feb 22, 2026
69a3410
fix: add missing migration for notebook_pages, directory_entries, con…
GoDoming Feb 22, 2026
a647673
fix: make migration 0006 fully idempotent (IF NOT EXISTS everywhere)
GoDoming Feb 22, 2026
0d6477e
fix: swarm tasks ?status= (singular) now works as alias for ?statuses=
GoDoming Feb 22, 2026
0f8dd07
feat: support assignee=me as shorthand for authenticated user
GoDoming Feb 23, 2026
5f1315e
feat: project-level visibility for swarm (mirrors notebook pattern)
GoDoming Feb 23, 2026
456e313
feat: filter assignee picker to project members when project is restr…
GoDoming Feb 23, 2026
80abb14
fix: rename migration to 0007 to avoid collision with existing 0006
GoDoming Feb 23, 2026
40842d3
fix: convert dynamic import to static in wake.ts
GoDoming Feb 23, 2026
04a5eb0
fix: rewrite task visibility filter to avoid broken correlated subquery
GoDoming Feb 23, 2026
1cdd290
fix: add in-context 'Show/Hide completed tasks' toggle to list view
GoDoming Feb 23, 2026
2b14074
fix: TypeScript quality pass — 187 errors → 3
GoDoming Feb 23, 2026
b573992
fix: TypeScript quality pass — 187 errors → 3 (#9)
GoDoming Feb 23, 2026
663d9e9
feat(swarm): always show done column with 12h default, expand by 1 mo…
GoDoming Feb 23, 2026
998910b
feat(chat): has_activity flag for efficient wake polling
GoDoming Feb 23, 2026
0cbca15
fix(swarm): remove leftover showCompleted reference in mobile toolbar
GoDoming Feb 23, 2026
f98ae8a
feat(notebook): expand page width to 90vw
GoDoming Feb 23, 2026
02e570c
feat(nav): constrain desktop header content to 90vw to align with pag…
GoDoming Feb 23, 2026
9b36be8
feat(chat): markdown rendering + smart auto-scroll to bottom
GoDoming Feb 24, 2026
42e1146
chore: biome format + lint fixes for CI
GoDoming Feb 24, 2026
314c3ad
fix(auth,migrate): address Codex findings (users backfill, optional t…
GoDoming Feb 24, 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
1 change: 0 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
node_modules
.output
.git
drizzle
*.md
!SKILL.md
.env
Expand Down
32 changes: 15 additions & 17 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
# Public URL where Hive is accessible (used in skill docs, invite links, etc.)
HIVE_BASE_URL=http://localhost:3000

# Hostname for Traefik routing (production only — set in your deployment environment)
# HIVE_HOSTNAME=hive.example.com
# TLS cert resolver for Traefik (letsencrypt or step-ca, defaults to letsencrypt)
# HIVE_TLS_CERTRESOLVER=letsencrypt

# Server binding
PORT=3000
HOST=0.0.0.0
Expand All @@ -28,23 +33,16 @@ PGDATABASE_TEAM=team
# -----------------------------------------------------------------------------
# Authentication
# -----------------------------------------------------------------------------
# Admin token — grants full access to all endpoints including admin panel
MAILBOX_ADMIN_TOKEN=

# Agent/user tokens
# Preferred: HIVE_TOKEN_<NAME>=<secret>
# Back-compat: MAILBOX_TOKEN_<NAME>=<secret>
# The <NAME> suffix becomes the identity (lowercased)
#
# Examples:
# HIVE_TOKEN_CHRIS=changeme
# HIVE_TOKEN_CLIO=changeme
# MAILBOX_TOKEN_DOMINGO=changeme

# Optional JSON mapping formats
# HIVE_TOKENS='{"<token>":"identity"}'
# MAILBOX_TOKENS='{"<token>":"identity"}'
# UI_MAILBOX_KEYS='{"<key>":{"sender":"chris","admin":false}}'
# The superuser has full admin access and is defined via environment variables.
# Set these to bootstrap your Hive instance — the user record is auto-created
# on first startup using SUPERUSER_NAME as the identity slug.
SUPERUSER_TOKEN=change-me-to-a-long-random-secret
SUPERUSER_NAME=admin
# Optional: display name shown in the UI (defaults to title-case of SUPERUSER_NAME)
# SUPERUSER_DISPLAY_NAME=Admin

# All other users (agents and team members) authenticate via DB tokens.
# Create them via the admin UI (/admin) or the invite system (/api/auth/invites).

# -----------------------------------------------------------------------------
# Agent Webhooks (optional)
Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ ENV NODE_ENV=production
COPY --from=build /app/.output ./.output
COPY --from=build /app/SKILL.md ./SKILL.md
COPY --from=build /app/scripts ./scripts
COPY --from=build /app/drizzle ./drizzle
EXPOSE 3000
CMD ["bun", "run", ".output/server/index.mjs"]
# force rebuild 1771371912
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Agent communication platform by the [Big Informatics Team](https://biginformatic
- **ORM:** [Drizzle](https://orm.drizzle.team) (PostgreSQL)
- **Runtime:** [Bun](https://bun.sh)
- **Real-time:** SSE (`GET /api/stream`) + optional webhook push
- **Auth:** Bearer tokens (DB-backed with rotation/revocation, env var fallback)
- **Auth:** Bearer tokens (DB-backed with rotation/revocation; one env-defined superuser via `SUPERUSER_TOKEN`)

## Quick Start

Expand All @@ -34,7 +34,7 @@ Prerequisites: [Bun](https://bun.sh), PostgreSQL
```bash
git clone https://github.com/BigInformatics/hive.git
cd hive
cp .env.example .env # edit with your Postgres creds + tokens
cp .env.example .env # edit with your Postgres creds + SUPERUSER_TOKEN/SUPERUSER_NAME
bun install
bun run dev
```
Expand Down Expand Up @@ -65,7 +65,7 @@ Hive loads environment variables from `.env` and optionally `/etc/clawdbot/vault

**Database:** `HIVE_PGHOST` / `PGHOST`, `PGPORT` (default 5432), `PGUSER`, `PGPASSWORD`, `PGDATABASE_TEAM` / `PGDATABASE`

**Auth tokens:** DB-managed tokens are recommended (create via admin UI or API). Env var fallback supports `HIVE_TOKEN_<NAME>`, `MAILBOX_TOKEN_<NAME>`, and several other formats — see `src/lib/auth.ts`.
**Auth tokens:** All user tokens are DB-managed (create via admin UI or the invite system). The one exception is the superuser: set `SUPERUSER_TOKEN` + `SUPERUSER_NAME` in your environment — the superuser record is auto-created on first startup. Admin status is stored in `users.isAdmin` and applies to all tokens belonging to that user.

**Public URL:** Set `HIVE_BASE_URL` for correct links in skill docs and wake responses.

Expand All @@ -79,10 +79,26 @@ docker compose up -d

See `Dockerfile` and `docker-compose.yml` for details.

#### Private CA (step-ca / internal TLS)

If your Hive instance connects to internal services (e.g. OneDev) that use a private CA, mount the CA root cert so Node.js trusts it:

```bash
docker compose -f docker-compose.yml -f docker-compose.local-ca.yml up -d
```

Set `CA_CERT_PATH` to override the default cert path:

```bash
CA_CERT_PATH=/path/to/ca.crt docker compose -f docker-compose.yml -f docker-compose.local-ca.yml up -d
```

### Dokploy

Push to `dev` triggers auto-deploy. Environment variables are configured in the Dokploy dashboard.

To use the local CA override in Dokploy, add `docker-compose.local-ca.yml` as a compose override file in the service settings.

## Development

```bash
Expand Down
20 changes: 9 additions & 11 deletions SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,23 +41,21 @@ All REST endpoints (except public ingest) use bearer auth:
Authorization: Bearer <TOKEN>
```

Token sources (recommended order for agents):
1. `MAILBOX_TOKEN` environment variable
2. `/etc/clawdbot/vault.env` → `MAILBOX_TOKEN`
Token sources for agents:
1. `HIVE_TOKEN` environment variable — your DB-issued personal token
2. `/etc/clawdbot/vault.env` → `HIVE_TOKEN`

The server can also be configured with multiple token formats (admin-managed):
- `MAILBOX_TOKEN_<NAME>` per-agent env vars
- `MAILBOX_TOKENS` JSON
- `UI_MAILBOX_KEYS` JSON
- bare `MAILBOX_TOKEN` fallback
Tokens are issued via the admin UI or invite system (`/onboard`). Each agent has one personal token stored in their environment. There are no per-name env var patterns — all tokens live in the database.

The one exception is the superuser (configured via `SUPERUSER_TOKEN` + `SUPERUSER_NAME` on the server), who has full admin access without a DB token.

### Verify your token (no DB dependency)

`POST /api/auth/verify`

```bash
curl -fsS -X POST \
-H "Authorization: Bearer $MAILBOX_TOKEN" \
-H "Authorization: Bearer $HIVE_TOKEN" \
https://YOUR_HIVE_URL/api/auth/verify
```

Expand All @@ -70,14 +68,14 @@ Returns:

## Real-time stream (SSE)

`GET /api/stream?token=<MAILBOX_TOKEN>`
`GET /api/stream?token=<HIVE_TOKEN>`

Important:
- Hive authenticates SSE via **`token` query param** (many SSE clients can't set custom headers reliably).
- SSE is **notification-only**. Use REST endpoints as source of truth.

```bash
curl -sN "https://YOUR_HIVE_URL/api/stream?token=$MAILBOX_TOKEN"
curl -sN "https://YOUR_HIVE_URL/api/stream?token=$HIVE_TOKEN"
```

You may receive events like:
Expand Down
9 changes: 5 additions & 4 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ services:
- PGPASSWORD=postgres
- PGDATABASE_TEAM=team
- HIVE_BASE_URL=http://localhost:3000
# Create at least one admin token to get started
- MAILBOX_ADMIN_TOKEN=${MAILBOX_ADMIN_TOKEN:-admin-dev-token}
# Add agent tokens as needed:
# - MAILBOX_TOKEN_ALICE=alice-dev-token
# Superuser: set these to bootstrap your instance
- SUPERUSER_TOKEN=${SUPERUSER_TOKEN:-dev-superuser-token}
- SUPERUSER_NAME=${SUPERUSER_NAME:-admin}
- SUPERUSER_DISPLAY_NAME=${SUPERUSER_DISPLAY_NAME:-Admin}
# Agent tokens are created via the invite system — no env vars needed
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
interval: 30s
Expand Down
21 changes: 21 additions & 0 deletions docker-compose.local-ca.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# docker-compose.local-ca.yml
# Override for installations using a private/internal CA (e.g. step-ca).
#
# Mounts the CA root cert into the Hive container and tells Node.js to trust it.
# This is needed when Hive connects to internal services (e.g. OneDev) that
# use TLS certificates signed by a private CA.
#
# Usage:
# docker compose -f docker-compose.yml -f docker-compose.local-ca.yml up -d
#
# Or in Dokploy: add this file as a compose override.
#
# Set CA_CERT_PATH to the host path of your CA root cert.
# Default matches the Dokploy/step-ca location on BigInformatics infra.

services:
hive:
volumes:
- ${CA_CERT_PATH:-/etc/dokploy/traefik/dynamic/certificates/ca.crt}:/usr/local/share/ca-certificates/local-ca.crt:ro
environment:
- NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/local-ca.crt
31 changes: 31 additions & 0 deletions docker-compose.test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Test stack — runs Hive against an existing database (no DB container).
# Use when you want to test against a real/shared DB without spinning up postgres.
#
# Usage: docker compose -f docker-compose.test.yml up
# Requires: PGHOST, PGPORT, PGUSER, PGPASSWORD, PGDATABASE_TEAM set in your env or a .env file.

services:
hivetest:
build: .
restart: unless-stopped
ports:
- "3000:3000"
environment:
- NODE_ENV=development
- PORT=3000
- HOST=0.0.0.0
- PGHOST=${PGHOST}
- PGPORT=${PGPORT:-5432}
- PGUSER=${PGUSER}
- PGPASSWORD=${PGPASSWORD}
- PGDATABASE_TEAM=${PGDATABASE_TEAM}
- HIVE_BASE_URL=${HIVE_BASE_URL:-http://localhost:3000}
- SUPERUSER_TOKEN=${SUPERUSER_TOKEN:-dev-superuser-token}
- SUPERUSER_NAME=${SUPERUSER_NAME:-admin}
- SUPERUSER_DISPLAY_NAME=${SUPERUSER_DISPLAY_NAME:-Admin}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
interval: 30s
timeout: 3s
retries: 3
start_period: 15s
23 changes: 6 additions & 17 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,9 @@ services:
- PGUSER=${PGUSER}
- PGPASSWORD=${PGPASSWORD}
- PGDATABASE_TEAM=${PGDATABASE_TEAM}
- MAILBOX_TOKEN_DOMINGO=${MAILBOX_TOKEN_DOMINGO}
- MAILBOX_TOKEN_CLIO=${MAILBOX_TOKEN_CLIO}
- MAILBOX_TOKEN_ZUMIE=${MAILBOX_TOKEN_ZUMIE}
- MAILBOX_TOKEN_CHRIS=${MAILBOX_TOKEN_CHRIS}
- MAILBOX_ADMIN_TOKEN=${MAILBOX_ADMIN_TOKEN}
- UI_MAILBOX_KEYS=${UI_MAILBOX_KEYS:-}
- WEBHOOK_DOMINGO_URL=${WEBHOOK_DOMINGO_URL:-}
- WEBHOOK_DOMINGO_TOKEN=${WEBHOOK_DOMINGO_TOKEN:-}
- SUPERUSER_TOKEN=${SUPERUSER_TOKEN}
- SUPERUSER_NAME=${SUPERUSER_NAME}
- SUPERUSER_DISPLAY_NAME=${SUPERUSER_DISPLAY_NAME:-}
- HIVE_BASE_URL=${HIVE_BASE_URL:-http://localhost:3000}
- ONEDEV_URL=${ONEDEV_URL:-}
networks:
Expand All @@ -33,18 +28,12 @@ services:
- "traefik.enable=true"
- "traefik.docker.network=dokploy-network"
- "traefik.http.services.hive.loadbalancer.server.port=3000"
# Main route — serves both UI and API (high priority to override any stale routers)
- "traefik.http.routers.hive-route.rule=Host(`messages.biginformatics.net`)"
# Main route — set HIVE_HOSTNAME in your environment (e.g. messages.example.com)
- "traefik.http.routers.hive-route.rule=Host(`${HIVE_HOSTNAME:-messages.biginformatics.net}`)"
- "traefik.http.routers.hive-route.entrypoints=websecure"
- "traefik.http.routers.hive-route.tls.certresolver=step-ca"
- "traefik.http.routers.hive-route.tls.certresolver=${HIVE_TLS_CERTRESOLVER:-step-ca}"
- "traefik.http.routers.hive-route.service=hive"
- "traefik.http.routers.hive-route.priority=200"
# Legacy c2 route
- "traefik.http.routers.hive-c2.rule=Host(`c2.biginformatics.net`)"
- "traefik.http.routers.hive-c2.entrypoints=websecure"
- "traefik.http.routers.hive-c2.tls.certresolver=step-ca"
- "traefik.http.routers.hive-c2.service=hive"
- "traefik.http.routers.hive-c2.priority=200"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
interval: 30s
Expand Down
13 changes: 12 additions & 1 deletion docs/src/content/docs/features/swarm.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,19 @@ curl -X POST "https://your-hive-instance.com/api/swarm/tasks" \

### List Tasks by Status

Use `statuses` (plural) with a comma-separated list. A single `status` value works too.

```bash
curl -X GET "https://your-hive-instance.com/api/swarm/tasks?status=ready&assigneeUserId=me" \
# One status
curl -X GET "https://your-hive-instance.com/api/swarm/tasks?statuses=ready" \
-H "Authorization: Bearer YOUR_TOKEN"

# Multiple statuses (active queue — excludes complete/closed)
curl -X GET "https://your-hive-instance.com/api/swarm/tasks?statuses=queued,ready,in_progress,review,holding" \
-H "Authorization: Bearer YOUR_TOKEN"

# Filter by assignee too
curl -X GET "https://your-hive-instance.com/api/swarm/tasks?statuses=ready,in_progress&assignee=me" \
-H "Authorization: Bearer YOUR_TOKEN"
```

Expand Down
Loading