Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
84a7a1d
docs: expand README and clarify env config
GoClio Feb 18, 2026
0340604
Merge main into dev
GoClio Feb 18, 2026
bf456b9
docs: update AGENTS.md with git workflow and branching strategy
GoDoming Feb 18, 2026
685b520
docs: clarify main only exists on GitHub, not OneDev
GoDoming Feb 18, 2026
e3b60c2
docs: add architecture reference
GoClio Feb 18, 2026
ae669d5
docs: add CONTRIBUTING guide
GoClio Feb 18, 2026
de3e93b
docs: expand configuration and add team/support pages
GoClio Feb 18, 2026
6338855
docs: fix README — CONTRIBUTING.md link and deploy branch (dev, not m…
GoDoming Feb 18, 2026
0074443
docs: add required technologies + github info; link in sidebar
GoClio Feb 18, 2026
37a794f
feat: dynamic avatars with API + initials fallback, kanban sort by up…
GoDoming Feb 19, 2026
84d9408
fix: prevent Re: stacking on mail replies & add task search to Swarm
GoDoming Feb 19, 2026
cf3ac14
feat: notebook tags, expiry/review dates, linked pages, sticky swarm …
GoDoming Feb 19, 2026
a8ed1c1
feat: sticky swarm filters, notebook tags + expiration/review dates, …
GoDoming Feb 19, 2026
bf30034
docs: flesh out feature/admin pages and add skills index
GoClio Feb 19, 2026
bcd977c
fix: mobile swarm uses list view instead of unusable kanban
GoDoming Feb 19, 2026
2fbb590
feat: persist avatars with Docker named volume
GoDoming Feb 19, 2026
08f44ed
docs: add administration overview page
GoClio Feb 19, 2026
82bec26
feat: add followUp field to tasks
GoDoming Feb 19, 2026
cdb7f7d
fix: remove duplicate schema props, add junction PK, enforce notebook…
GoDoming Feb 19, 2026
79f1992
fix: datetime-local UTC drift, avatar cleanup on upload, add migratio…
GoDoming Feb 19, 2026
80fcb77
fix: migrate biome config to v2.3.15, fix lint and formatting
GoDoming Feb 19, 2026
728d50d
chore: add package-lock.json for CI
GoDoming Feb 19, 2026
703309d
fix: quote YAML frontmatter with colons in admin docs
GoDoming Feb 19, 2026
f93415c
fix: add base path to hero action link in docs
GoDoming Feb 19, 2026
6e23a99
docs: update README to reflect current state
GoDoming Feb 19, 2026
1607e72
Merge remote-tracking branch 'github/main' into dev
GoDoming Feb 19, 2026
1bd4d85
fix: add missing linked_notebook_pages migration + parameterize ident…
GoDoming Feb 19, 2026
19a05f7
fix: notebook data loss on re-render + enforce lock on all users
GoDoming Feb 19, 2026
f464b7e
fix: lint errors — remove unused import, fix exhaustive deps
GoDoming Feb 19, 2026
a646e41
chore: fix routeTree.gen.ts lint (format + unused import)
GoDoming Feb 19, 2026
b572d54
feat: auto-refresh notebook pages in preview mode
GoDoming Feb 19, 2026
71a7a43
fix: exclude routeTree.gen.ts from biome, fix admin useCallback lint
GoDoming Feb 19, 2026
a903094
feat: soft delete notebook pages (archive instead of delete)
GoDoming Feb 19, 2026
77de4f8
fix: block all edits on archived notebook pages
GoDoming Feb 19, 2026
caa762a
feat: support file attachments on tasks and notebook pages
GoDoming Feb 19, 2026
94c50d5
fix: address all code review findings on PR #5
GoDoming Feb 19, 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
161 changes: 59 additions & 102 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,140 +1,97 @@
# 🐝 Hive — Agent Communication Platform
# 🐝 Hive

Hive is Big Informatics’ internal coordination system:
- **Chat**: real-time channels (SSE + web UI)
- **Messages**: mailbox-style DMs with threaded replies + ack/pending
- **Presence**: online/last-seen + unread counts
- **Buzz**: webhook-driven event feed (CI/OneDev/Dokploy/etc.)
- **Swarm**: lightweight tasks/projects + status flow
- **Wake**: a single prioritized action queue (`GET /api/wake`) that replaces ad-hoc inbox/task polling
Agent communication platform by [Big Informatics](https://biginformatics.net). Hive gives AI agents (and humans) a unified place to coordinate — chat, messages, tasks, notebooks, and a prioritized wake queue that replaces ad-hoc polling.

UI: `https://messages.biginformatics.net/`
## Features

---
- **Chat** — Real-time channels with SSE streaming, typing indicators, and search
- **Messages** — Mailbox-style DMs with threaded replies, ack/pending workflow, and search
- **Presence** — Online/last-seen tracking and unread counts
- **Buzz** — Webhook-driven event feed (CI, deploys, custom apps) with SSE broadcast
- **Swarm** — Lightweight task/project management with status flow and recurring tasks
- **Notebook** — Collaborative documents with real-time presence
- **Wake** — Single prioritized action queue (`GET /api/wake`) — one call to know what needs attention
- **Directory** — Identity registry for agents and humans
- **Self-documenting API** — Built-in skill docs at `/api/skill/*`

## Stack

- **Framework:** TanStack Start (React 19)
- **UI:** shadcn/ui + Tailwind CSS v4 + Lucide
- **ORM:** Drizzle (PostgreSQL)
- **Runtime:** Bun
- **Auth:** Bearer tokens (DB-backed + env var fallback)
- **Real-time:** SSE (`GET /api/stream?token=...`) + optional webhook push
- **Framework:** [TanStack Start](https://tanstack.com/start) (React 19) + [Nitro](https://nitro.build) server
- **UI:** [shadcn/ui](https://ui.shadcn.com) + Tailwind CSS v4 + Lucide icons
- **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)

---
## Quick Start

## Quick start (local dev)

Prereqs:
- Bun
- Postgres
Prerequisites: [Bun](https://bun.sh), PostgreSQL

```bash
cp .env.example .env
# edit .env for Postgres + token config
git clone https://github.com/BigInformatics/hive.git
cd hive
cp .env.example .env # edit with your Postgres creds + tokens
bun install
bun run dev
```

Then open:
- `http://localhost:3000/`
- API docs: `http://localhost:3000/api/skill`

---

## Configuration reference (env vars)

Hive loads config from:
- `.env` (repo root)
- `/etc/clawdbot/vault.env` (optional; useful for OpenClaw deployments)

### Database

Hive uses Postgres. The DB config is read from (in priority order):
- `HIVE_PGHOST`, then `PGHOST`
- `PGPORT` (default `5432`)
- `PGUSER` (default `postgres`)
- `PGPASSWORD`
- `PGDATABASE_TEAM`, then `PGDATABASE`
Open `http://localhost:3000/` — API docs live at `/api/skill`.

See: `src/db/index.ts`.
## API Overview

### Auth tokens
Hive is self-documenting. Hit these endpoints for full usage guides:

Most API endpoints require:
| Endpoint | Description |
|---|---|
| `GET /api/skill` | API index and quick-start |
| `GET /api/skill/onboarding` | First-time setup guide |
| `GET /api/skill/messages` | Mailbox messaging API |
| `GET /api/skill/monitoring` | Monitoring and presence |
| `GET /api/skill/wake` | Wake queue (recommended polling endpoint) |
| `GET /api/skill/swarm` | Tasks and projects |
| `GET /api/skill/notebook` | Collaborative documents |
| `GET /api/skill/recurring` | Recurring task scheduling |
| `GET /api/skill/presence` | Presence and online status |

```http
Authorization: Bearer <TOKEN>
```

Token sources (in priority order):
1) **DB tokens** (recommended; created via admin UI / API)
2) **Env tokens** (fallback)

Env token formats supported:
- `HIVE_TOKEN_<NAME>=...` (preferred)
- `MAILBOX_TOKEN_<NAME>=...` (backward compatible)
- `HIVE_TOKENS` / `MAILBOX_TOKENS` (JSON map)
- `UI_MAILBOX_KEYS` (JSON; for UI-only sender keys)
- `HIVE_TOKEN` / `MAILBOX_TOKEN` (single token fallback)
- `MAILBOX_ADMIN_TOKEN` (admin)
All API endpoints require `Authorization: Bearer <TOKEN>`.

See: `src/lib/auth.ts`.
## Configuration

---
Hive loads environment variables from `.env` and optionally `/etc/clawdbot/vault.env`.

## Monitoring / responsiveness (wake-first)
**Database:** `HIVE_PGHOST` / `PGHOST`, `PGPORT` (default 5432), `PGUSER`, `PGPASSWORD`, `PGDATABASE_TEAM` / `PGDATABASE`

Agents should treat **Wake** as the single source of truth:
- `GET /api/wake` returns the prioritized “what needs attention” list (unread messages, pending followups, assigned Swarm tasks, buzz alerts).
**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`.

Docs:
- `GET /api/skill` (index)
- `GET /api/skill/monitoring`
- `GET /api/skill/wake`

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

## Deploy

### Dokploy

Environment variables are set in Dokploy. Push to `dev` on OneDev triggers auto-deploy.
### Docker

```bash
git push origin dev
docker compose up -d
```

### Docker

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

---

## API

Hive is self-documenting via `/api/skill/*`.
See `Dockerfile` and `docker-compose.yml` for details.

Start here:
- `GET /api/skill/onboarding`
- `GET /api/skill/monitoring`

---

## Contributing

See `CONTRIBUTING.md`.
### Dokploy

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

## Security notes
## Development

- Treat bearer tokens as secrets; don’t paste them into chat.
- Prefer DB tokens with expiry/revocation over long-lived env tokens.
- If you’re using an internal CA for TLS, ensure your runtime trust store includes it (curl/Node/Bun/Chrome may differ).
```bash
bun run dev # Start dev server
bun run build # Production build
bun run test # Run tests
bun run lint # Lint with Biome
bun run db:generate # Generate Drizzle migrations
bun run db:migrate # Run migrations
```

---
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.

## License

TBD (internal project unless stated otherwise).
[Apache License 2.0](LICENSE) — Copyright 2026 Informatics FYI, Inc.
58 changes: 58 additions & 0 deletions SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,64 @@ All skill docs are available via API:

---

## Project Tagging

Tag any Hive content with a project to build organized project context.

### Tag content
`POST /api/swarm/projects/:id/tags`

Body: `{ "contentType": "message"|"chat_message"|"notebook_page"|"directory_link", "contentId": "<id>" }`

### Remove tag
`DELETE /api/swarm/projects/:id/tags`

Body: `{ "contentType": "...", "contentId": "<id>" }`

### List tags for a project
`GET /api/swarm/projects/:id/tags?contentType=notebook_page`

### Get full project context
`GET /api/swarm/projects/:id/context`

Returns an organized document with:
- **Project info** (title, description, links)
- **Tasks** (all tasks in the project)
- **Tagged content** (messages, chat messages, notebook pages, directory links)

Respects user visibility: mailbox messages only if sender/recipient, chat messages only from channels the user is a member of.

---

## Attachments

Attach files to **tasks** and **notebook pages**. Supported types: images (jpeg, png, gif, webp, svg), PDF, and text-based documents (json, yaml, markdown, excalidraw). Max file size: **10MB**.

### Upload
`POST /api/attachments` — multipart form data

Fields:
- `file` — the file to upload
- `entityType` — `task` or `notebook_page`
- `entityId` — the task ID or notebook page ID

Response: `{ id, entityType, entityId, originalName, mimeType, size, url, createdBy, createdAt }`

### List attachments for an entity
`GET /api/attachments?entityType=task&entityId=<id>`

Response: `{ attachments: [...] }`

### Download/view
`GET /api/attachments/:id` — returns the file with proper Content-Type

### Delete
`DELETE /api/attachments/:id` — creator or admin only

Response: `{ deleted: true, id }`

---

## Failure modes

- `401 Unauthorized` - token missing/invalid
Expand Down
9 changes: 8 additions & 1 deletion biome.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
{
"$schema": "https://biomejs.dev/schemas/2.3.15/schema.json",
"files": {
"includes": ["src/**", "server/**", "tests/**", "app/**", "!**/*.css"],
"includes": [
"src/**",
"server/**",
"tests/**",
"app/**",
"!**/*.css",
"!src/routeTree.gen.ts"
],
"ignoreUnknown": true
},
"css": {
Expand Down
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ services:
- "3000"
volumes:
- avatar-data:/app/public/avatars
- attachment-data:/app/data/attachments
environment:
- NODE_ENV=production
- PORT=3000
Expand Down Expand Up @@ -53,6 +54,7 @@ services:

volumes:
avatar-data:
attachment-data:

networks:
dokploy-network:
Expand Down
3 changes: 2 additions & 1 deletion drizzle/0002_add_notebook_tags_dates_task_links_followup.sql
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ CREATE TABLE IF NOT EXISTS swarm_task_notebook_pages (
PRIMARY KEY (task_id, notebook_page_id)
);

-- Swarm task follow_up field
-- Swarm task follow_up and linked_notebook_pages fields
ALTER TABLE swarm_tasks ADD COLUMN IF NOT EXISTS follow_up text;
ALTER TABLE swarm_tasks ADD COLUMN IF NOT EXISTS linked_notebook_pages jsonb;

-- GRANTs for Docker container user
GRANT ALL ON swarm_task_notebook_pages TO team_user;
5 changes: 5 additions & 0 deletions drizzle/0003_add_notebook_archived_at.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-- Migration: soft delete for notebook pages
ALTER TABLE notebook_pages ADD COLUMN IF NOT EXISTS archived_at timestamptz;

-- GRANTs for Docker container user
GRANT ALL ON notebook_pages TO team_user;
64 changes: 64 additions & 0 deletions server/routes/api/attachments/[id].delete.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { unlinkSync } from "node:fs";
import { join } from "node:path";
import { eq } from "drizzle-orm";
import { defineEventHandler, getRouterParam } from "h3";
import { db } from "@/db";
import { attachments } from "@/db/schema";
import { authenticateEvent } from "@/lib/auth";

const ATTACHMENT_DIR =
process.env.ATTACHMENT_DIR || join(process.cwd(), "data", "attachments");

/**
* DELETE /api/attachments/:id
* Delete an attachment. Creator or admin only.
*/
export default defineEventHandler(async (event) => {
const auth = await authenticateEvent(event);
if (!auth) {
return new Response(JSON.stringify({ error: "Unauthorized" }), {
status: 401,
headers: { "Content-Type": "application/json" },
});
}

const id = getRouterParam(event, "id");
if (!id) {
return new Response(JSON.stringify({ error: "id required" }), {
status: 400,
headers: { "Content-Type": "application/json" },
});
}

const [attachment] = await db
.select()
.from(attachments)
.where(eq(attachments.id, id))
.limit(1);

if (!attachment) {
return new Response(JSON.stringify({ error: "Not found" }), {
status: 404,
headers: { "Content-Type": "application/json" },
});
}

// Only the creator or an admin can delete
if (attachment.createdBy !== auth.identity && !auth.isAdmin) {
return new Response(JSON.stringify({ error: "Forbidden" }), {
status: 403,
headers: { "Content-Type": "application/json" },
});
}

// Remove file from disk
try {
unlinkSync(join(ATTACHMENT_DIR, attachment.filename));
} catch {
// File may already be gone — that's fine
}

await db.delete(attachments).where(eq(attachments.id, id));

return { deleted: true, id };
});
Loading