Reorganize docs and add implementation spec
Move GOAL.md, PRODUCT.md, SPEC.md from repo root into doc/. Add AGENTS.md (contributor guidance), doc/DEVELOPING.md (dev setup), doc/SPEC-implementation.md (V1 implementation contract), and doc/specs/ui.md (UI design spec). Update ClipHub doc. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
143
AGENTS.md
Normal file
143
AGENTS.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# AGENTS.md
|
||||
|
||||
Guidance for human and AI contributors working in this repository.
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
Paperclip is a control plane for AI-agent companies.
|
||||
The current implementation target is V1 and is defined in `doc/SPEC-implementation.md`.
|
||||
|
||||
## 2. Read This First
|
||||
|
||||
Before making changes, read in this order:
|
||||
|
||||
1. `doc/GOAL.md`
|
||||
2. `doc/PRODUCT.md`
|
||||
3. `doc/SPEC-implementation.md`
|
||||
4. `doc/DEVELOPING.md`
|
||||
5. `doc/DATABASE.md`
|
||||
|
||||
`doc/SPEC.md` is long-horizon product context.
|
||||
`doc/SPEC-implementation.md` is the concrete V1 build contract.
|
||||
|
||||
## 3. Repo Map
|
||||
|
||||
- `server/`: Express REST API and orchestration services
|
||||
- `ui/`: React + Vite board UI
|
||||
- `packages/db/`: Drizzle schema, migrations, DB clients
|
||||
- `packages/shared/`: shared types, constants, validators, API path constants
|
||||
- `doc/`: operational and product docs
|
||||
|
||||
## 4. Dev Setup (Auto DB)
|
||||
|
||||
Use embedded PGlite in dev by leaving `DATABASE_URL` unset.
|
||||
|
||||
```sh
|
||||
pnpm install
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
This starts:
|
||||
|
||||
- API: `http://localhost:3100`
|
||||
- UI: `http://localhost:5173`
|
||||
|
||||
Quick checks:
|
||||
|
||||
```sh
|
||||
curl http://localhost:3100/api/health
|
||||
curl http://localhost:3100/api/companies
|
||||
```
|
||||
|
||||
Reset local dev DB:
|
||||
|
||||
```sh
|
||||
rm -rf data/pglite
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
## 5. Core Engineering Rules
|
||||
|
||||
1. Keep changes company-scoped.
|
||||
Every domain entity should be scoped to a company and company boundaries must be enforced in routes/services.
|
||||
|
||||
2. Keep contracts synchronized.
|
||||
If you change schema/API behavior, update all impacted layers:
|
||||
- `packages/db` schema and exports
|
||||
- `packages/shared` types/constants/validators
|
||||
- `server` routes/services
|
||||
- `ui` API clients and pages
|
||||
|
||||
3. Preserve control-plane invariants.
|
||||
- Single-assignee task model
|
||||
- Atomic issue checkout semantics
|
||||
- Approval gates for governed actions
|
||||
- Budget hard-stop auto-pause behavior
|
||||
- Activity logging for mutating actions
|
||||
|
||||
4. Do not replace strategic docs wholesale unless asked.
|
||||
Prefer additive updates. Keep `doc/SPEC.md` and `doc/SPEC-implementation.md` aligned.
|
||||
|
||||
## 6. Database Change Workflow
|
||||
|
||||
When changing data model:
|
||||
|
||||
1. Edit `packages/db/src/schema/*.ts`
|
||||
2. Ensure new tables are exported from `packages/db/src/schema/index.ts`
|
||||
3. Generate migration:
|
||||
|
||||
```sh
|
||||
pnpm db:generate
|
||||
```
|
||||
|
||||
4. Validate compile:
|
||||
|
||||
```sh
|
||||
pnpm -r typecheck
|
||||
```
|
||||
|
||||
Notes:
|
||||
- `packages/db/drizzle.config.ts` reads compiled schema from `dist/schema/*.js`
|
||||
- `pnpm db:generate` compiles `packages/db` first
|
||||
|
||||
## 7. Verification Before Hand-off
|
||||
|
||||
Run this full check before claiming done:
|
||||
|
||||
```sh
|
||||
pnpm -r typecheck
|
||||
pnpm test:run
|
||||
pnpm build
|
||||
```
|
||||
|
||||
If anything cannot be run, explicitly report what was not run and why.
|
||||
|
||||
## 8. API and Auth Expectations
|
||||
|
||||
- Base path: `/api`
|
||||
- Board access is treated as full-control operator context
|
||||
- Agent access uses bearer API keys (`agent_api_keys`), hashed at rest
|
||||
- Agent keys must not access other companies
|
||||
|
||||
When adding endpoints:
|
||||
|
||||
- apply company access checks
|
||||
- enforce actor permissions (board vs agent)
|
||||
- write activity log entries for mutations
|
||||
- return consistent HTTP errors (`400/401/403/404/409/422/500`)
|
||||
|
||||
## 9. UI Expectations
|
||||
|
||||
- Keep routes and nav aligned with available API surface
|
||||
- Use company selection context for company-scoped pages
|
||||
- Surface failures clearly; do not silently ignore API errors
|
||||
|
||||
## 10. Definition of Done
|
||||
|
||||
A change is done when all are true:
|
||||
|
||||
1. Behavior matches `doc/SPEC-implementation.md`
|
||||
2. Typecheck, tests, and build pass
|
||||
3. Contracts are synced across db/shared/server/ui
|
||||
4. Docs updated when behavior or commands change
|
||||
|
||||
@@ -8,7 +8,7 @@ ClipHub is the public registry where people share, discover, and download Paperc
|
||||
|
||||
## What It Is
|
||||
|
||||
ClipHub is to Paperclip what a package registry is to a programming language. Paperclip already supports exportable org configs (see SPEC.md §2). ClipHub is the public directory where those exports live.
|
||||
ClipHub is to Paperclip what a package registry is to a programming language. Paperclip already supports exportable org configs (see [SPEC.md](./SPEC.md) §2). ClipHub is the public directory where those exports live.
|
||||
|
||||
A user builds a working company in Paperclip — a dev shop, a marketing agency, a research lab, a content studio — exports the template, and publishes it to ClipHub. Anyone can browse, search, download, and spin up that company on their own Paperclip instance.
|
||||
|
||||
|
||||
58
doc/DEVELOPING.md
Normal file
58
doc/DEVELOPING.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Developing
|
||||
|
||||
This project can run fully in local dev without setting up PostgreSQL manually.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Node.js 20+
|
||||
- pnpm 9+
|
||||
|
||||
## Start Dev
|
||||
|
||||
From repo root:
|
||||
|
||||
```sh
|
||||
pnpm install
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
This starts:
|
||||
|
||||
- API server: `http://localhost:3100`
|
||||
- UI: `http://localhost:5173`
|
||||
|
||||
## Database in Dev (Auto-Handled)
|
||||
|
||||
For local development, leave `DATABASE_URL` unset.
|
||||
The server will automatically use embedded PGlite and persist data at:
|
||||
|
||||
- `./data/pglite`
|
||||
|
||||
No Docker or external database is required for this mode.
|
||||
|
||||
## Quick Health Checks
|
||||
|
||||
In another terminal:
|
||||
|
||||
```sh
|
||||
curl http://localhost:3100/api/health
|
||||
curl http://localhost:3100/api/companies
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- `/api/health` returns `{"status":"ok"}`
|
||||
- `/api/companies` returns a JSON array
|
||||
|
||||
## Reset Local Dev Database
|
||||
|
||||
To wipe local dev data and start fresh:
|
||||
|
||||
```sh
|
||||
rm -rf data/pglite
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
## Optional: Use External Postgres
|
||||
|
||||
If you set `DATABASE_URL`, the server will use that instead of embedded PGlite.
|
||||
@@ -82,4 +82,4 @@ More detailed task structure TBD.
|
||||
|
||||
## Further Detail
|
||||
|
||||
See [SPEC.md](./SPEC.md) for the full technical specification and [doc/TASKS.md](./doc/TASKS.md) for the task management data model.
|
||||
See [SPEC.md](./SPEC.md) for the full technical specification and [TASKS.md](./TASKS.md) for the task management data model.
|
||||
765
doc/SPEC-implementation.md
Normal file
765
doc/SPEC-implementation.md
Normal file
@@ -0,0 +1,765 @@
|
||||
# Paperclip V1 Implementation Spec
|
||||
|
||||
Status: Implementation contract for first release (V1)
|
||||
Date: 2026-02-17
|
||||
Audience: Product, engineering, and agent-integration authors
|
||||
Source inputs: `GOAL.md`, `PRODUCT.md`, `SPEC.md`, `DATABASE.md`, current monorepo code
|
||||
|
||||
## 1. Document Role
|
||||
|
||||
`SPEC.md` remains the long-horizon product spec.
|
||||
This document is the concrete, build-ready V1 contract.
|
||||
When there is a conflict, `SPEC-implementation.md` controls V1 behavior.
|
||||
|
||||
## 2. V1 Outcomes
|
||||
|
||||
Paperclip V1 must provide a full control-plane loop for autonomous agents:
|
||||
|
||||
1. A human board creates a company and defines goals.
|
||||
2. The board creates and manages agents in an org tree.
|
||||
3. Agents receive and execute tasks via heartbeat invocations.
|
||||
4. All work is tracked through tasks/comments with audit visibility.
|
||||
5. Token/cost usage is reported and budget limits can stop work.
|
||||
6. The board can intervene anywhere (pause agents/tasks, override decisions).
|
||||
|
||||
Success means one operator can run a small AI-native company end-to-end with clear visibility and control.
|
||||
|
||||
## 3. Explicit V1 Product Decisions
|
||||
|
||||
These decisions close open questions from `SPEC.md` for V1.
|
||||
|
||||
| Topic | V1 Decision |
|
||||
|---|---|
|
||||
| Tenancy | Single-tenant deployment, multi-company data model |
|
||||
| Company model | Company is first-order; all business entities are company-scoped |
|
||||
| Board | Single human board operator per deployment |
|
||||
| Org graph | Strict tree (`reports_to` nullable root); no multi-manager reporting |
|
||||
| Visibility | Full visibility to board and all agents in same company |
|
||||
| Communication | Tasks + comments only (no separate chat system) |
|
||||
| Task ownership | Single assignee; atomic checkout required for `in_progress` transition |
|
||||
| Recovery | No automatic reassignment; stale work is surfaced, not silently fixed |
|
||||
| Agent adapters | Built-in `process` and `http` adapters |
|
||||
| Auth | Session auth for board, API keys for agents |
|
||||
| Budget period | Monthly UTC calendar window |
|
||||
| Budget enforcement | Soft alerts + hard limit auto-pause |
|
||||
| Deployment modes | Embedded PGlite default; Docker/hosted Postgres supported |
|
||||
|
||||
## 4. Current Baseline (Repo Snapshot)
|
||||
|
||||
As of 2026-02-17, the repo already includes:
|
||||
|
||||
- Node + TypeScript backend with REST CRUD for `agents`, `projects`, `goals`, `issues`, `activity`
|
||||
- React UI pages for dashboard/agents/projects/goals/issues lists
|
||||
- PostgreSQL schema via Drizzle with embedded PGlite fallback when `DATABASE_URL` is unset
|
||||
|
||||
V1 implementation extends this baseline into a company-centric, governance-aware control plane.
|
||||
|
||||
## 5. V1 Scope
|
||||
|
||||
## 5.1 In Scope
|
||||
|
||||
- Company lifecycle (create/list/get/update/archive)
|
||||
- Goal hierarchy linked to company mission
|
||||
- Agent lifecycle with org structure and adapter configuration
|
||||
- Task lifecycle with parent/child hierarchy and comments
|
||||
- Atomic task checkout and explicit task status transitions
|
||||
- Board approvals for hires and CEO strategy proposal
|
||||
- Heartbeat invocation, status tracking, and cancellation
|
||||
- Cost event ingestion and rollups (agent/task/project/company)
|
||||
- Budget settings and hard-stop enforcement
|
||||
- Board web UI for dashboard, org chart, tasks, agents, approvals, costs
|
||||
- Agent-facing API contract (task read/write, heartbeat report, cost report)
|
||||
- Auditable activity log for all mutating actions
|
||||
|
||||
## 5.2 Out of Scope (V1)
|
||||
|
||||
- Plugin framework and third-party extension SDK
|
||||
- Revenue/expense accounting beyond model/token costs
|
||||
- Knowledge base subsystem
|
||||
- Public marketplace (ClipHub)
|
||||
- Multi-board governance or role-based human permission granularity
|
||||
- Automatic self-healing orchestration (auto-reassign/retry planners)
|
||||
|
||||
## 6. Architecture
|
||||
|
||||
## 6.1 Runtime Components
|
||||
|
||||
- `server/`: REST API, auth, orchestration services
|
||||
- `ui/`: Board operator interface
|
||||
- `packages/db/`: Drizzle schema, migrations, DB clients (Postgres and PGlite)
|
||||
- `packages/shared/`: Shared API types, validators, constants
|
||||
|
||||
## 6.2 Data Stores
|
||||
|
||||
- Primary: PostgreSQL
|
||||
- Local default: embedded PGlite at `./data/pglite`
|
||||
- Optional local prod-like: Docker Postgres
|
||||
- Optional hosted: Supabase/Postgres-compatible
|
||||
|
||||
## 6.3 Background Processing
|
||||
|
||||
A lightweight scheduler/worker in the server process handles:
|
||||
|
||||
- heartbeat trigger checks
|
||||
- stuck run detection
|
||||
- budget threshold checks
|
||||
- stale task reporting generation
|
||||
|
||||
Separate queue infrastructure is not required for V1.
|
||||
|
||||
## 7. Canonical Data Model (V1)
|
||||
|
||||
All core tables include `id`, `created_at`, `updated_at` unless noted.
|
||||
|
||||
## 7.0 Auth Tables
|
||||
|
||||
Human auth tables (`users`, `sessions`, and provider-specific auth artifacts) are managed by the selected auth library. This spec treats them as required dependencies and references `users.id` where user attribution is needed.
|
||||
|
||||
## 7.1 `companies`
|
||||
|
||||
- `id` uuid pk
|
||||
- `name` text not null
|
||||
- `description` text null
|
||||
- `status` enum: `active | paused | archived`
|
||||
|
||||
Invariant: every business record belongs to exactly one company.
|
||||
|
||||
## 7.2 `agents`
|
||||
|
||||
- `id` uuid pk
|
||||
- `company_id` uuid fk `companies.id` not null
|
||||
- `name` text not null
|
||||
- `role` text not null
|
||||
- `title` text null
|
||||
- `status` enum: `active | paused | idle | running | error | terminated`
|
||||
- `reports_to` uuid fk `agents.id` null
|
||||
- `capabilities` text null
|
||||
- `adapter_type` enum: `process | http`
|
||||
- `adapter_config` jsonb not null
|
||||
- `context_mode` enum: `thin | fat` default `thin`
|
||||
- `budget_monthly_cents` int not null default 0
|
||||
- `spent_monthly_cents` int not null default 0
|
||||
- `last_heartbeat_at` timestamptz null
|
||||
|
||||
Invariants:
|
||||
|
||||
- agent and manager must be in same company
|
||||
- no cycles in reporting tree
|
||||
- `terminated` agents cannot be resumed
|
||||
|
||||
## 7.3 `agent_api_keys`
|
||||
|
||||
- `id` uuid pk
|
||||
- `agent_id` uuid fk `agents.id` not null
|
||||
- `company_id` uuid fk `companies.id` not null
|
||||
- `name` text not null
|
||||
- `key_hash` text not null
|
||||
- `last_used_at` timestamptz null
|
||||
- `revoked_at` timestamptz null
|
||||
|
||||
Invariant: plaintext key shown once at creation; only hash stored.
|
||||
|
||||
## 7.4 `goals`
|
||||
|
||||
- `id` uuid pk
|
||||
- `company_id` uuid fk not null
|
||||
- `title` text not null
|
||||
- `description` text null
|
||||
- `level` enum: `company | team | agent | task`
|
||||
- `parent_id` uuid fk `goals.id` null
|
||||
- `owner_agent_id` uuid fk `agents.id` null
|
||||
- `status` enum: `planned | active | achieved | cancelled`
|
||||
|
||||
Invariant: at least one root `company` level goal per company.
|
||||
|
||||
## 7.5 `projects`
|
||||
|
||||
- `id` uuid pk
|
||||
- `company_id` uuid fk not null
|
||||
- `goal_id` uuid fk `goals.id` null
|
||||
- `name` text not null
|
||||
- `description` text null
|
||||
- `status` enum: `backlog | planned | in_progress | completed | cancelled`
|
||||
- `lead_agent_id` uuid fk `agents.id` null
|
||||
- `target_date` date null
|
||||
|
||||
## 7.6 `issues` (core task entity)
|
||||
|
||||
- `id` uuid pk
|
||||
- `company_id` uuid fk not null
|
||||
- `project_id` uuid fk `projects.id` null
|
||||
- `goal_id` uuid fk `goals.id` null
|
||||
- `parent_id` uuid fk `issues.id` null
|
||||
- `title` text not null
|
||||
- `description` text null
|
||||
- `status` enum: `backlog | todo | in_progress | in_review | done | blocked | cancelled`
|
||||
- `priority` enum: `critical | high | medium | low`
|
||||
- `assignee_agent_id` uuid fk `agents.id` null
|
||||
- `created_by_agent_id` uuid fk `agents.id` null
|
||||
- `created_by_user_id` uuid fk `users.id` null
|
||||
- `request_depth` int not null default 0
|
||||
- `billing_code` text null
|
||||
- `started_at` timestamptz null
|
||||
- `completed_at` timestamptz null
|
||||
- `cancelled_at` timestamptz null
|
||||
|
||||
Invariants:
|
||||
|
||||
- single assignee only
|
||||
- task must trace to company goal chain via `goal_id`, `parent_id`, or project-goal linkage
|
||||
- `in_progress` requires assignee
|
||||
- terminal states: `done | cancelled`
|
||||
|
||||
## 7.7 `issue_comments`
|
||||
|
||||
- `id` uuid pk
|
||||
- `company_id` uuid fk not null
|
||||
- `issue_id` uuid fk `issues.id` not null
|
||||
- `author_agent_id` uuid fk `agents.id` null
|
||||
- `author_user_id` uuid fk `users.id` null
|
||||
- `body` text not null
|
||||
|
||||
## 7.8 `heartbeat_runs`
|
||||
|
||||
- `id` uuid pk
|
||||
- `company_id` uuid fk not null
|
||||
- `agent_id` uuid fk not null
|
||||
- `invocation_source` enum: `scheduler | manual | callback`
|
||||
- `status` enum: `queued | running | succeeded | failed | cancelled | timed_out`
|
||||
- `started_at` timestamptz null
|
||||
- `finished_at` timestamptz null
|
||||
- `error` text null
|
||||
- `external_run_id` text null
|
||||
- `context_snapshot` jsonb null
|
||||
|
||||
## 7.9 `cost_events`
|
||||
|
||||
- `id` uuid pk
|
||||
- `company_id` uuid fk not null
|
||||
- `agent_id` uuid fk `agents.id` not null
|
||||
- `issue_id` uuid fk `issues.id` null
|
||||
- `project_id` uuid fk `projects.id` null
|
||||
- `goal_id` uuid fk `goals.id` null
|
||||
- `billing_code` text null
|
||||
- `provider` text not null
|
||||
- `model` text not null
|
||||
- `input_tokens` int not null default 0
|
||||
- `output_tokens` int not null default 0
|
||||
- `cost_cents` int not null
|
||||
- `occurred_at` timestamptz not null
|
||||
|
||||
Invariant: each event must attach to agent and company; rollups are aggregation, never manually edited.
|
||||
|
||||
## 7.10 `approvals`
|
||||
|
||||
- `id` uuid pk
|
||||
- `company_id` uuid fk not null
|
||||
- `type` enum: `hire_agent | approve_ceo_strategy`
|
||||
- `requested_by_agent_id` uuid fk `agents.id` null
|
||||
- `requested_by_user_id` uuid fk `users.id` null
|
||||
- `status` enum: `pending | approved | rejected | cancelled`
|
||||
- `payload` jsonb not null
|
||||
- `decision_note` text null
|
||||
- `decided_by_user_id` uuid fk `users.id` null
|
||||
- `decided_at` timestamptz null
|
||||
|
||||
## 7.11 `activity_log`
|
||||
|
||||
- `id` uuid pk
|
||||
- `company_id` uuid fk not null
|
||||
- `actor_type` enum: `agent | user | system`
|
||||
- `actor_id` uuid/text not null
|
||||
- `action` text not null
|
||||
- `entity_type` text not null
|
||||
- `entity_id` uuid/text not null
|
||||
- `details` jsonb null
|
||||
- `created_at` timestamptz not null default now()
|
||||
|
||||
## 7.12 Required Indexes
|
||||
|
||||
- `agents(company_id, status)`
|
||||
- `agents(company_id, reports_to)`
|
||||
- `issues(company_id, status)`
|
||||
- `issues(company_id, assignee_agent_id, status)`
|
||||
- `issues(company_id, parent_id)`
|
||||
- `issues(company_id, project_id)`
|
||||
- `cost_events(company_id, occurred_at)`
|
||||
- `cost_events(company_id, agent_id, occurred_at)`
|
||||
- `heartbeat_runs(company_id, agent_id, started_at desc)`
|
||||
- `approvals(company_id, status, type)`
|
||||
- `activity_log(company_id, created_at desc)`
|
||||
|
||||
## 8. State Machines
|
||||
|
||||
## 8.1 Agent Status
|
||||
|
||||
Allowed transitions:
|
||||
|
||||
- `idle -> running`
|
||||
- `running -> idle`
|
||||
- `running -> error`
|
||||
- `error -> idle`
|
||||
- `idle -> paused`
|
||||
- `running -> paused` (requires cancel flow)
|
||||
- `paused -> idle`
|
||||
- `* -> terminated` (board only, irreversible)
|
||||
|
||||
## 8.2 Issue Status
|
||||
|
||||
Allowed transitions:
|
||||
|
||||
- `backlog -> todo | cancelled`
|
||||
- `todo -> in_progress | blocked | cancelled`
|
||||
- `in_progress -> in_review | blocked | done | cancelled`
|
||||
- `in_review -> in_progress | done | cancelled`
|
||||
- `blocked -> todo | in_progress | cancelled`
|
||||
- terminal: `done`, `cancelled`
|
||||
|
||||
Side effects:
|
||||
|
||||
- entering `in_progress` sets `started_at` if null
|
||||
- entering `done` sets `completed_at`
|
||||
- entering `cancelled` sets `cancelled_at`
|
||||
|
||||
## 8.3 Approval Status
|
||||
|
||||
- `pending -> approved | rejected | cancelled`
|
||||
- terminal after decision
|
||||
|
||||
## 9. Auth and Permissions
|
||||
|
||||
## 9.1 Board Auth
|
||||
|
||||
- Session-based auth for human operator
|
||||
- Board has full read/write across all companies in deployment
|
||||
- Every board mutation writes to `activity_log`
|
||||
|
||||
## 9.2 Agent Auth
|
||||
|
||||
- Bearer API key mapped to one agent and company
|
||||
- Agent key scope:
|
||||
- read org/task/company context for own company
|
||||
- read/write own assigned tasks and comments
|
||||
- create tasks/comments for delegation
|
||||
- report heartbeat status
|
||||
- report cost events
|
||||
- Agent cannot:
|
||||
- bypass approval gates
|
||||
- modify company-wide budgets directly
|
||||
- mutate auth/keys
|
||||
|
||||
## 9.3 Permission Matrix (V1)
|
||||
|
||||
| Action | Board | Agent |
|
||||
|---|---|---|
|
||||
| Create company | yes | no |
|
||||
| Hire/create agent | yes (direct) | request via approval |
|
||||
| Pause/resume agent | yes | no |
|
||||
| Create/update task | yes | yes |
|
||||
| Force reassign task | yes | limited |
|
||||
| Approve strategy/hire requests | yes | no |
|
||||
| Report cost | yes | yes |
|
||||
| Set company budget | yes | no |
|
||||
| Set subordinate budget | yes | yes (manager subtree only) |
|
||||
|
||||
## 10. API Contract (REST)
|
||||
|
||||
All endpoints are under `/api` and return JSON.
|
||||
|
||||
## 10.1 Companies
|
||||
|
||||
- `GET /companies`
|
||||
- `POST /companies`
|
||||
- `GET /companies/:companyId`
|
||||
- `PATCH /companies/:companyId`
|
||||
- `POST /companies/:companyId/archive`
|
||||
|
||||
## 10.2 Goals
|
||||
|
||||
- `GET /companies/:companyId/goals`
|
||||
- `POST /companies/:companyId/goals`
|
||||
- `GET /goals/:goalId`
|
||||
- `PATCH /goals/:goalId`
|
||||
- `DELETE /goals/:goalId` (soft delete optional, hard delete board-only)
|
||||
|
||||
## 10.3 Agents
|
||||
|
||||
- `GET /companies/:companyId/agents`
|
||||
- `POST /companies/:companyId/agents`
|
||||
- `GET /agents/:agentId`
|
||||
- `PATCH /agents/:agentId`
|
||||
- `POST /agents/:agentId/pause`
|
||||
- `POST /agents/:agentId/resume`
|
||||
- `POST /agents/:agentId/terminate`
|
||||
- `POST /agents/:agentId/keys` (create API key)
|
||||
- `POST /agents/:agentId/heartbeat/invoke`
|
||||
|
||||
## 10.4 Tasks (Issues)
|
||||
|
||||
- `GET /companies/:companyId/issues`
|
||||
- `POST /companies/:companyId/issues`
|
||||
- `GET /issues/:issueId`
|
||||
- `PATCH /issues/:issueId`
|
||||
- `POST /issues/:issueId/checkout`
|
||||
- `POST /issues/:issueId/release`
|
||||
- `POST /issues/:issueId/comments`
|
||||
- `GET /issues/:issueId/comments`
|
||||
|
||||
### 10.4.1 Atomic Checkout Contract
|
||||
|
||||
`POST /issues/:issueId/checkout` request:
|
||||
|
||||
```json
|
||||
{
|
||||
"agentId": "uuid",
|
||||
"expectedStatuses": ["todo", "backlog", "blocked"]
|
||||
}
|
||||
```
|
||||
|
||||
Server behavior:
|
||||
|
||||
1. single SQL update with `WHERE id = ? AND status IN (?) AND (assignee_agent_id IS NULL OR assignee_agent_id = :agentId)`
|
||||
2. if updated row count is 0, return `409` with current owner/status
|
||||
3. successful checkout sets `assignee_agent_id`, `status = in_progress`, and `started_at`
|
||||
|
||||
## 10.5 Projects
|
||||
|
||||
- `GET /companies/:companyId/projects`
|
||||
- `POST /companies/:companyId/projects`
|
||||
- `GET /projects/:projectId`
|
||||
- `PATCH /projects/:projectId`
|
||||
|
||||
## 10.6 Approvals
|
||||
|
||||
- `GET /companies/:companyId/approvals?status=pending`
|
||||
- `POST /companies/:companyId/approvals`
|
||||
- `POST /approvals/:approvalId/approve`
|
||||
- `POST /approvals/:approvalId/reject`
|
||||
|
||||
## 10.7 Cost and Budgets
|
||||
|
||||
- `POST /companies/:companyId/cost-events`
|
||||
- `GET /companies/:companyId/costs/summary`
|
||||
- `GET /companies/:companyId/costs/by-agent`
|
||||
- `GET /companies/:companyId/costs/by-project`
|
||||
- `PATCH /companies/:companyId/budgets`
|
||||
- `PATCH /agents/:agentId/budgets`
|
||||
|
||||
## 10.8 Activity and Dashboard
|
||||
|
||||
- `GET /companies/:companyId/activity`
|
||||
- `GET /companies/:companyId/dashboard`
|
||||
|
||||
Dashboard payload must include:
|
||||
|
||||
- active/running/paused/error agent counts
|
||||
- open/in-progress/blocked/done issue counts
|
||||
- month-to-date spend and budget utilization
|
||||
- pending approvals count
|
||||
- stale task count
|
||||
|
||||
## 10.9 Error Semantics
|
||||
|
||||
- `400` validation error
|
||||
- `401` unauthenticated
|
||||
- `403` unauthorized
|
||||
- `404` not found
|
||||
- `409` state conflict (checkout conflict, invalid transition)
|
||||
- `422` semantic rule violation
|
||||
- `500` server error
|
||||
|
||||
## 11. Heartbeat and Adapter Contract
|
||||
|
||||
## 11.1 Adapter Interface
|
||||
|
||||
```ts
|
||||
interface AgentAdapter {
|
||||
invoke(agent: Agent, context: InvocationContext): Promise<InvokeResult>;
|
||||
status(run: HeartbeatRun): Promise<RunStatus>;
|
||||
cancel(run: HeartbeatRun): Promise<void>;
|
||||
}
|
||||
```
|
||||
|
||||
## 11.2 Process Adapter
|
||||
|
||||
Config shape:
|
||||
|
||||
```json
|
||||
{
|
||||
"command": "string",
|
||||
"args": ["string"],
|
||||
"cwd": "string",
|
||||
"env": {"KEY": "VALUE"},
|
||||
"timeoutSec": 900,
|
||||
"graceSec": 15
|
||||
}
|
||||
```
|
||||
|
||||
Behavior:
|
||||
|
||||
- spawn child process
|
||||
- stream stdout/stderr to run logs
|
||||
- mark run status on exit code/timeout
|
||||
- cancel sends SIGTERM then SIGKILL after grace
|
||||
|
||||
## 11.3 HTTP Adapter
|
||||
|
||||
Config shape:
|
||||
|
||||
```json
|
||||
{
|
||||
"url": "https://...",
|
||||
"method": "POST",
|
||||
"headers": {"Authorization": "Bearer ..."},
|
||||
"timeoutMs": 15000,
|
||||
"payloadTemplate": {"agentId": "{{agent.id}}", "runId": "{{run.id}}"}
|
||||
}
|
||||
```
|
||||
|
||||
Behavior:
|
||||
|
||||
- invoke by outbound HTTP request
|
||||
- 2xx means accepted
|
||||
- non-2xx marks failed invocation
|
||||
- optional callback endpoint allows asynchronous completion updates
|
||||
|
||||
## 11.4 Context Delivery
|
||||
|
||||
- `thin`: send IDs and pointers only; agent fetches context via API
|
||||
- `fat`: include current assignments, goal summary, budget snapshot, and recent comments
|
||||
|
||||
## 11.5 Scheduler Rules
|
||||
|
||||
Per-agent schedule fields in `adapter_config`:
|
||||
|
||||
- `enabled` boolean
|
||||
- `intervalSec` integer (minimum 30)
|
||||
- `maxConcurrentRuns` fixed at `1` for V1
|
||||
|
||||
Scheduler must skip invocation when:
|
||||
|
||||
- agent is paused/terminated
|
||||
- an existing run is active
|
||||
- hard budget limit has been hit
|
||||
|
||||
## 12. Governance and Approval Flows
|
||||
|
||||
## 12.1 Hiring
|
||||
|
||||
1. Agent or board creates `approval(type=hire_agent, status=pending, payload=agent draft)`.
|
||||
2. Board approves or rejects.
|
||||
3. On approval, server creates agent row and initial API key (optional).
|
||||
4. Decision is logged in `activity_log`.
|
||||
|
||||
Board can bypass request flow and create agents directly via UI; direct create is still logged as a governance action.
|
||||
|
||||
## 12.2 CEO Strategy Approval
|
||||
|
||||
1. CEO posts strategy proposal as `approval(type=approve_ceo_strategy)`.
|
||||
2. Board reviews payload (plan text, initial structure, high-level tasks).
|
||||
3. Approval unlocks execution state for CEO-created delegated work.
|
||||
|
||||
Before first strategy approval, CEO may only draft tasks, not transition them to active execution states.
|
||||
|
||||
## 12.3 Board Override
|
||||
|
||||
Board can at any time:
|
||||
|
||||
- pause/resume/terminate any agent
|
||||
- reassign or cancel any task
|
||||
- edit budgets and limits
|
||||
- approve/reject/cancel pending approvals
|
||||
|
||||
## 13. Cost and Budget System
|
||||
|
||||
## 13.1 Budget Layers
|
||||
|
||||
- company monthly budget
|
||||
- agent monthly budget
|
||||
- optional project budget (if configured)
|
||||
|
||||
## 13.2 Enforcement Rules
|
||||
|
||||
- soft alert default threshold: 80%
|
||||
- hard limit: at 100%, trigger:
|
||||
- set agent status to `paused`
|
||||
- block new checkout/invocation for that agent
|
||||
- emit high-priority activity event
|
||||
|
||||
Board may override by raising budget or explicitly resuming agent.
|
||||
|
||||
## 13.3 Cost Event Ingestion
|
||||
|
||||
`POST /companies/:companyId/cost-events` body:
|
||||
|
||||
```json
|
||||
{
|
||||
"agentId": "uuid",
|
||||
"issueId": "uuid",
|
||||
"provider": "openai",
|
||||
"model": "gpt-5",
|
||||
"inputTokens": 1234,
|
||||
"outputTokens": 567,
|
||||
"costCents": 89,
|
||||
"occurredAt": "2026-02-17T20:25:00Z",
|
||||
"billingCode": "optional"
|
||||
}
|
||||
```
|
||||
|
||||
Validation:
|
||||
|
||||
- non-negative token counts
|
||||
- `costCents >= 0`
|
||||
- company ownership checks for all linked entities
|
||||
|
||||
## 13.4 Rollups
|
||||
|
||||
Read-time aggregate queries are acceptable for V1.
|
||||
Materialized rollups can be added later if query latency exceeds targets.
|
||||
|
||||
## 14. UI Requirements (Board App)
|
||||
|
||||
V1 UI routes:
|
||||
|
||||
- `/` dashboard
|
||||
- `/companies` company list/create
|
||||
- `/companies/:id/org` org chart and agent status
|
||||
- `/companies/:id/tasks` task list/kanban
|
||||
- `/companies/:id/agents/:agentId` agent detail
|
||||
- `/companies/:id/costs` cost and budget dashboard
|
||||
- `/companies/:id/approvals` pending/history approvals
|
||||
- `/companies/:id/activity` audit/event stream
|
||||
|
||||
Required UX behaviors:
|
||||
|
||||
- global company selector
|
||||
- quick actions: pause/resume agent, create task, approve/reject request
|
||||
- conflict toasts on atomic checkout failure
|
||||
- clear stale-task indicators
|
||||
- no silent background failures; every failed run visible in UI
|
||||
|
||||
## 15. Operational Requirements
|
||||
|
||||
## 15.1 Environment
|
||||
|
||||
- Node 20+
|
||||
- `DATABASE_URL` optional
|
||||
- if unset, auto-use PGlite and push schema
|
||||
|
||||
## 15.2 Migrations
|
||||
|
||||
- Drizzle migrations are source of truth
|
||||
- no destructive migration in-place for V1 upgrade path
|
||||
- provide migration script from existing minimal tables to company-scoped schema
|
||||
|
||||
## 15.3 Logging and Audit
|
||||
|
||||
- structured logs (JSON in production)
|
||||
- request ID per API call
|
||||
- every mutation writes `activity_log`
|
||||
|
||||
## 15.4 Reliability Targets
|
||||
|
||||
- API p95 latency under 250 ms for standard CRUD at 1k tasks/company
|
||||
- heartbeat invoke acknowledgement under 2 s for process adapter
|
||||
- no lost approval decisions (transactional writes)
|
||||
|
||||
## 16. Security Requirements
|
||||
|
||||
- store only hashed agent API keys
|
||||
- redact secrets in logs (`adapter_config`, auth headers, env vars)
|
||||
- CSRF protection for board session endpoints
|
||||
- rate limit auth and key-management endpoints
|
||||
- strict company boundary checks on every entity fetch/mutation
|
||||
|
||||
## 17. Testing Strategy
|
||||
|
||||
## 17.1 Unit Tests
|
||||
|
||||
- state transition guards (agent, issue, approval)
|
||||
- budget enforcement rules
|
||||
- adapter invocation/cancel semantics
|
||||
|
||||
## 17.2 Integration Tests
|
||||
|
||||
- atomic checkout conflict behavior
|
||||
- approval-to-agent creation flow
|
||||
- cost ingestion and rollup correctness
|
||||
- pause while run is active (graceful cancel then force kill)
|
||||
|
||||
## 17.3 End-to-End Tests
|
||||
|
||||
- board creates company -> hires CEO -> approves strategy -> CEO receives work
|
||||
- agent reports cost -> budget threshold reached -> auto-pause occurs
|
||||
- task delegation across teams with request depth increment
|
||||
|
||||
## 17.4 Regression Suite Minimum
|
||||
|
||||
A release candidate is blocked unless these pass:
|
||||
|
||||
1. auth boundary tests
|
||||
2. checkout race test
|
||||
3. hard budget stop test
|
||||
4. agent pause/resume test
|
||||
5. dashboard summary consistency test
|
||||
|
||||
## 18. Delivery Plan
|
||||
|
||||
## Milestone 1: Company Core and Auth
|
||||
|
||||
- add `companies` and company scoping to existing entities
|
||||
- add board session auth and agent API keys
|
||||
- migrate existing API routes to company-aware paths
|
||||
|
||||
## Milestone 2: Task and Governance Semantics
|
||||
|
||||
- implement atomic checkout endpoint
|
||||
- implement issue comments and lifecycle guards
|
||||
- implement approvals table and hire/strategy workflows
|
||||
|
||||
## Milestone 3: Heartbeat and Adapter Runtime
|
||||
|
||||
- implement adapter interface
|
||||
- ship `process` adapter with cancel semantics
|
||||
- ship `http` adapter with timeout/error handling
|
||||
- persist heartbeat runs and statuses
|
||||
|
||||
## Milestone 4: Cost and Budget Controls
|
||||
|
||||
- implement cost events ingestion
|
||||
- implement monthly rollups and dashboards
|
||||
- enforce hard limit auto-pause
|
||||
|
||||
## Milestone 5: Board UI Completion
|
||||
|
||||
- add company selector and org chart view
|
||||
- add approvals and cost pages
|
||||
- add operational dashboard and stale-task surfacing
|
||||
|
||||
## Milestone 6: Hardening and Release
|
||||
|
||||
- full integration/e2e suite
|
||||
- seed/demo company templates for local testing
|
||||
- release checklist and docs update
|
||||
|
||||
## 19. Acceptance Criteria (Release Gate)
|
||||
|
||||
V1 is complete only when all criteria are true:
|
||||
|
||||
1. A board user can create multiple companies and switch between them.
|
||||
2. A company can run at least one active heartbeat-enabled agent.
|
||||
3. Task checkout is conflict-safe with `409` on concurrent claims.
|
||||
4. Agents can update tasks/comments and report costs with API keys only.
|
||||
5. Board can approve/reject hire and CEO strategy requests in UI.
|
||||
6. Budget hard limit auto-pauses an agent and prevents new invocations.
|
||||
7. Dashboard shows accurate counts/spend from live DB data.
|
||||
8. Every mutation is auditable in activity log.
|
||||
9. App runs with embedded PGlite by default and with external Postgres via `DATABASE_URL`.
|
||||
|
||||
## 20. Post-V1 Backlog (Explicitly Deferred)
|
||||
|
||||
- plugin architecture
|
||||
- richer workflow-state customization per team
|
||||
- milestones/labels/dependency graph depth beyond V1 minimum
|
||||
- realtime transport optimization (SSE/WebSockets)
|
||||
- public template marketplace integration (ClipHub)
|
||||
1001
doc/specs/ui.md
Normal file
1001
doc/specs/ui.md
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user