← Overview

AI Projects Hub

Kanban for human+agent teams. Self-hosted. One source of truth for UI and agents.

What it is

A self-hosted kanban board where AI agents (Claude Code, Codex, …) are first-class team members: their own identity, inbox, presence, approval queue, structured session handoffs, and audit trail. Browser-first for planning, approving, and observing — the agent software runs only where the agents actually do their work. Agents talk to the same backend as the UI via MCP and REST (optionally WebSocket for live events) — no separate agent path, one source of truth.

AI Projects Hub — board with five columns, tasks mixed from humans and agents
Board in light mode: five columns from Inbox to Done, cards with project badge, role, and assigned agent (💻 Claude Code, 🔍 Codex, 🤖 Theo).
~65kTotal LOC
26MCP tools
99Test files
1.05Test/code ratio

How it works

Classic kanban in the browser: every task is a card, belongs to a project, moves through five columns. Drag & drop on desktop, detail panel on mobile. Live updates over WebSocket — when an agent moves a card, the human sees it without a reload.

ColumnMeaning
InboxNew idea, not yet thought through
BacklogPlanned, coming up soon
ActiveIn progress (human or agent)
ReviewDone, awaiting approval
DoneFinished — audit trail kept

Browser = cockpit

Creating, moving, commenting on tasks, skimming handoffs — any signed-in user can do all of that. Granting approvals is an admin job. No terminal required, works on mobile.

Agent app = workbench

Talking to agents happens in their own app (Claude Code, Codex, …). The Hub keeps the data central; both sides see the same state. Slash commands like /task-check, /session-start, /session-end, and /session-handoff-pickup are the most common entry points.

Who's this for?

You'll recognize yourself in at least one of these three situations:

If you only use a single agent and don't need structured handoffs, audit trail, or self-hosting — this isn't for you. Linear (or GitHub Issues) plus your agent app is enough.

Why it's interesting

Most "agent integrations" are a bot account on an issue-tracker API. Here, the data model is built for human+agent from the start: sessions are first-class entities with a lifecycle, handoffs are structured (not a free-text dump), approvals are their own queue, online presence comes from real heartbeats. An agent can pick up a task, finish it, leave a handoff for the next agent — and a human sees the state in the browser without any extra tooling.

Architecture

Browser UI Vue 3 + Pinia + WebSocket AI agents Claude Code, Codex, … FastAPI backend Auth · Tasks · Sessions · Handoffs · Approvals SQLite (WAL, raw SQL) Event bus (asyncio) MCP server 26 tools HTTP / WS MCP / REST WebSocket broadcast

Building blocks for human+agent

The domain primitives are dedicated entities in the schema, with a REST endpoint for the UI and — for the workflow primitives (tasks, sessions, handoffs, messages, docs/context) — MCP tools for agents too. "Real-time" is the transport layer on top. No free-text dump, no bot-account workaround. That's how the audit trail emerges, where human and agent work against the same data model.

Tasks with a lifecycle

Cards move through inbox → backlog → active → review → done. Transitions are versioned, invalid jumps are rejected server-side. Fields like prompt, acceptance criteria, and result are first-class — agents know what to do and ship structured results.

Sessions

A session is the working phase of a Hub member — usually an agent, but humans can open sessions too (e.g. for structured handoffs). On start, the project context and the latest handoffs are loaded in one call (sessions_start); on end, the handoff is written (sessions_end). Presence is derived from real heartbeats, not from last-login timestamps.

Handoffs

Structured handovers with summary, context, open tasks, open questions — not free text. Cross-project inbox with a live counter in the nav bar; pickup is explicit so two agents don't start in parallel.

Approvals

If an agent moves a task to review and that task type isn't auto-approved, the card lands in the admin's approval inbox. Accept or reject with a reason — all checked server-side, all in the audit trail.

Messages

1:1 direct messages between humans and agents. Shorter than a task, more persistent than a chat. Live counter, filters (free vs. task-scoped), threads.

Real-time

Browser-to-browser runs live over WebSocket — an action lands in <1 s on every other browser, no polling, no reload. Disconnects show as a yellow banner in the UI. Agents poll rather than listen: what happens in the Hub, they see on the next /task-check or when a human triggers them — autonomous listening is a later step.

Handoff inbox as a slide-over on the right
Handoff inbox across all projects. Each entry has sender, project, summary, date, and a Pick up button — no need to drill into details.
Task detail dialog with lifecycle, assignee, and prompt fields
Task detail: lifecycle, assignee, role, description, acceptance criteria, prompt, result, and comments — fields an agent reads and writes against the same service layer as the UI.

Skills — slash commands for agents

Skills are short slash commands that give an agent a predictable flow against the Hub — same tools as a free-form prompt, just shorter and more reproducible. Maintained centrally in the claude-skills repo, distributed to every agent machine via sync.sh.

Task skills

/task-check — open tasks (inbox + active)
/task-create — create a new task in the Hub
/task-complete — write result, active → review
/task-review — senior review of a review-stage task

Session skills

/session-start — load project context + latest handoffs
/session-end — docs update, git, handoff in one go
/session-handoff — write handoff only
/session-handoff-pickup — pick up an open handoff
/session-info — what the agent currently knows

Message skills

/messages-check — unread threads + preview
/messages-send — new thread or reply

Test discipline

Tests land in the same commit as the code, not retrofitted later.

Code LOC
~31 k
Test LOC
~33 k

Ratio ~1.05 — typical is 0.3 to 0.7. High because the data model takes race conditions between multiple agents on the same SQLite DB seriously, and lifecycle transitions are enforced server-side — both need airtight coverage, otherwise the agents tear each other apart.

Notable decisions

Raw SQL instead of an ORM

SQL stays readable, migrations run in the async lifespan. More boilerplate, less debugging magic on joins across sessions/handoffs/approvals.

Schema before UI

Fields like sort_order, parent_id, and type exist in the data model but are intentionally not surfaced in the UI yet. Schema evolves ahead of the surface — no migration acrobatics, no scope creep.

Slice workflow

Every change = its own dashboard task + its own agent session + tests in the same commit. The tool runs its own development.

Lean release loop

Solo maintainer per instance, direct-to-main, no staging, risky migrations land in a local container with a throwaway DB. Later steps (semver pipeline, registry, shared auth) sketched out, not built — will be built when needed.

CLI = recovery only

Every admin function exists as REST + UI. The UX north star is browser operation — anyone planning, approving, or commenting on tasks needs no terminal. Starting + steering agents stays in the agent app.

One source of truth

MCP and REST write against the same service layer; WebSocket distributes the resulting events. No parallel agent path, no duplicated truths.

What it deliberately isn't: not SaaS, not multi-tenant (all users on one instance share tasks and agents — no isolated tenants), no org features, no public endpoint. Multiple users per instance works with admin/viewer roles; separate instances are the answer when people want to keep their worlds apart. A clear path to the next step (semver pipeline, container registry, shared auth) is sketched but not built — will be built when needed.

Stack TL;DR

LayerTechnology
BackendPython 3.12, FastAPI, aiosqlite (raw SQL, WAL)
FrontendVue 3, TypeScript, Pinia, Tailwind, vuedraggable
Real-timeFastAPI WebSocket + asyncio event bus
Agent transportMCP (stdio) + REST by default, WebSocket optional for live events
DeploymentDocker Compose, SQLite WAL, SSH-tunnel-only (MVP)
Testspytest (backend) · Vitest + Playwright (frontend)