Add deployment guidelines, assets/attachments spec, and humans-and-permissions plan
Document local-trusted vs cloud-hosted deployment scenarios in PRODUCT.md. Spec out assets and issue_attachments tables with storage provider abstraction and attachment API endpoints. Draft comprehensive plan for human users, memberships, invites, permissions, and agent-to-human task delegation across both deployment modes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ Paperclip is the control plane for autonomous AI companies. One instance of Pape
|
||||
### Company
|
||||
|
||||
A company has:
|
||||
|
||||
- A **goal** — the reason it exists ("Create the #1 AI note-taking app that does $1M MRR within 3 months")
|
||||
- **Employees** — every employee is an AI agent
|
||||
- **Org structure** — who reports to whom
|
||||
@@ -20,6 +21,7 @@ A company has:
|
||||
Every employee is an agent. When you create a company, you start by defining the CEO, then build out from there.
|
||||
|
||||
Each employee has:
|
||||
|
||||
- **Adapter type + config** — how this agent runs and what defines its identity/behavior. This is adapter-specific (e.g., an OpenClaw agent might use SOUL.md and HEARTBEAT.md files; a Claude Code agent might use CLAUDE.md; a bare script might use CLI args). Paperclip doesn't prescribe the format — the adapter does.
|
||||
- **Role & reporting** — their title, who they report to, who reports to them
|
||||
- **Capabilities description** — a short paragraph on what this agent does and when they're relevant (helps other agents discover who can help with what)
|
||||
@@ -80,6 +82,13 @@ More detailed task structure TBD.
|
||||
6. Set budgets, define initial strategic tasks
|
||||
7. Hit go — agents start their heartbeats and the company runs
|
||||
|
||||
## Guidelines
|
||||
|
||||
There are two deployment scenarios that need to be maintained:
|
||||
|
||||
- a single user, local trusted deployment - this should be easy to install with a single `npx paperclip run` command and the environment is trusted and self-contained on a local machine (e.g. local files, agents, embedded db, easy to use)
|
||||
- multi-user cloud deployment - allows for a hosted deploy (remote deployment, user logins, hosted db, scalable)
|
||||
|
||||
## Further Detail
|
||||
|
||||
See [SPEC.md](./SPEC.md) for the full technical specification and [TASKS.md](./TASKS.md) for the task management data model.
|
||||
|
||||
@@ -95,6 +95,9 @@ V1 implementation extends this baseline into a company-centric, governance-aware
|
||||
- Local default: embedded PostgreSQL at `~/.paperclip/instances/default/db`
|
||||
- Optional local prod-like: Docker Postgres
|
||||
- Optional hosted: Supabase/Postgres-compatible
|
||||
- File/object storage:
|
||||
- local default: `~/.paperclip/instances/default/data/storage` (`local_disk`)
|
||||
- cloud: S3-compatible object storage (`s3`)
|
||||
|
||||
## 6.3 Background Processing
|
||||
|
||||
@@ -302,9 +305,32 @@ Operational policy:
|
||||
- `heartbeat_runs(company_id, agent_id, started_at desc)`
|
||||
- `approvals(company_id, status, type)`
|
||||
- `activity_log(company_id, created_at desc)`
|
||||
- `assets(company_id, created_at desc)`
|
||||
- `assets(company_id, object_key)` unique
|
||||
- `issue_attachments(company_id, issue_id)`
|
||||
- `company_secrets(company_id, name)` unique
|
||||
- `company_secret_versions(secret_id, version)` unique
|
||||
|
||||
## 7.14 `assets` + `issue_attachments`
|
||||
|
||||
- `assets` stores provider-backed object metadata (not inline bytes):
|
||||
- `id` uuid pk
|
||||
- `company_id` uuid fk not null
|
||||
- `provider` enum/text (`local_disk | s3`)
|
||||
- `object_key` text not null
|
||||
- `content_type` text not null
|
||||
- `byte_size` int not null
|
||||
- `sha256` text not null
|
||||
- `original_filename` text null
|
||||
- `created_by_agent_id` uuid fk null
|
||||
- `created_by_user_id` uuid/text fk null
|
||||
- `issue_attachments` links assets to issues/comments:
|
||||
- `id` uuid pk
|
||||
- `company_id` uuid fk not null
|
||||
- `issue_id` uuid fk not null
|
||||
- `asset_id` uuid fk not null
|
||||
- `issue_comment_id` uuid fk null
|
||||
|
||||
## 8. State Machines
|
||||
|
||||
## 8.1 Agent Status
|
||||
@@ -420,6 +446,10 @@ All endpoints are under `/api` and return JSON.
|
||||
- `POST /issues/:issueId/release`
|
||||
- `POST /issues/:issueId/comments`
|
||||
- `GET /issues/:issueId/comments`
|
||||
- `POST /companies/:companyId/issues/:issueId/attachments` (multipart upload)
|
||||
- `GET /issues/:issueId/attachments`
|
||||
- `GET /attachments/:attachmentId/content`
|
||||
- `DELETE /attachments/:attachmentId`
|
||||
|
||||
### 10.4.1 Atomic Checkout Contract
|
||||
|
||||
|
||||
234
doc/plan/humans-and-permissions.md
Normal file
234
doc/plan/humans-and-permissions.md
Normal file
@@ -0,0 +1,234 @@
|
||||
# Humans and Permissions Plan
|
||||
|
||||
Status: Draft
|
||||
Date: 2026-02-20
|
||||
Owner: Server + UI + Shared + DB
|
||||
|
||||
## Goal
|
||||
|
||||
Add first-class human users and permissions while preserving two deployment modes:
|
||||
|
||||
- local trusted single-user mode with no login friction
|
||||
- cloud-hosted multi-user mode with mandatory authentication and authorization
|
||||
|
||||
## Why this plan
|
||||
|
||||
Current V1 assumptions are centered on one board operator. We now need:
|
||||
|
||||
- multi-human collaboration with per-user permissions
|
||||
- safe cloud deployment defaults (no accidental loginless production)
|
||||
- local mode that still feels instant (`npx paperclip run` and go)
|
||||
- agent-to-human task delegation, including a human inbox
|
||||
|
||||
## Product constraints
|
||||
|
||||
1. Keep company scoping strict for every new table, endpoint, and permission check.
|
||||
2. Preserve existing control-plane invariants:
|
||||
- single-assignee task model
|
||||
- approval gates
|
||||
- budget hard-stop behavior
|
||||
- mutation activity logging
|
||||
3. Keep local mode easy and trusted, but prevent unsafe cloud posture.
|
||||
|
||||
## Deployment modes
|
||||
|
||||
## Mode A: `local_trusted`
|
||||
|
||||
Behavior:
|
||||
|
||||
- no login UI
|
||||
- browser opens directly into board context
|
||||
- embedded DB and local storage defaults remain
|
||||
- a local implicit human actor exists for attribution
|
||||
|
||||
Guardrails:
|
||||
|
||||
- server binds to loopback by default
|
||||
- refuse startup if mode is `local_trusted` with non-loopback bind, unless explicit `--allow-unsafe-local-network`
|
||||
- UI shows a persistent "Local trusted mode" badge
|
||||
|
||||
## Mode B: `cloud_hosted`
|
||||
|
||||
Behavior:
|
||||
|
||||
- login required for all human endpoints
|
||||
- hosted DB and remote deployment supported
|
||||
- multi-user sessions and role/permission enforcement
|
||||
|
||||
Guardrails:
|
||||
|
||||
- fail startup if auth provider/session config is missing
|
||||
- fail startup if insecure auth bypass flag is set
|
||||
- health payload includes mode and auth readiness
|
||||
|
||||
## Auth and actor model
|
||||
|
||||
Unify request actors into a single model:
|
||||
|
||||
- `user` (authenticated human)
|
||||
- `agent` (API key)
|
||||
- `local_board_implicit` (local trusted mode only)
|
||||
|
||||
Rules:
|
||||
|
||||
- in `cloud_hosted`, only `user` and `agent` are valid actors
|
||||
- in `local_trusted`, unauthenticated browser/API requests resolve to `local_board_implicit`
|
||||
- all mutating actions continue writing `activity_log` with actor type/id
|
||||
|
||||
## Data model additions
|
||||
|
||||
## New tables
|
||||
|
||||
1. `users`
|
||||
- identity record for human users (email-based)
|
||||
|
||||
2. `company_memberships`
|
||||
- `company_id`, `user_id`, status, role metadata
|
||||
- stores effective permissions and optional org scope constraints
|
||||
|
||||
3. `invites`
|
||||
- `company_id`, invite email, token hash, expires_at, invited_by, revoked_at, accepted_at
|
||||
- optional default permissions payload at invite time
|
||||
|
||||
4. `user_permission_grants` (or JSON grant blob in membership)
|
||||
- explicit grants such as `agents:create`
|
||||
- includes scope payload for chain-of-command limits
|
||||
|
||||
5. `issues` extension
|
||||
- add `assignee_user_id` nullable
|
||||
- preserve single-assignee invariant with XOR check:
|
||||
- exactly zero or one of `assignee_agent_id` / `assignee_user_id`
|
||||
|
||||
## Compatibility
|
||||
|
||||
- existing `created_by_user_id` / `author_user_id` fields remain and become fully active
|
||||
- agent API key model remains unchanged, still company-scoped
|
||||
|
||||
## Permission model (initial set)
|
||||
|
||||
Core grants:
|
||||
|
||||
1. `agents:create`
|
||||
2. `users:invite`
|
||||
3. `users:manage_permissions`
|
||||
4. `tasks:assign`
|
||||
5. `tasks:assign_scope` (org-constrained delegation)
|
||||
|
||||
Additional behavioral rules:
|
||||
|
||||
- board-level users can manage all grants
|
||||
- non-board users can only act within explicit grants
|
||||
- assignment checks apply to both agent and human assignees
|
||||
|
||||
## Chain-of-command scope design
|
||||
|
||||
Initial approach:
|
||||
|
||||
- represent assignment scope as an allow rule over org hierarchy
|
||||
- examples:
|
||||
- `subtree:<agentId>` (can assign into that manager subtree)
|
||||
- `exclude:<agentId>` (cannot assign to protected roles, e.g., CEO)
|
||||
|
||||
Enforcement:
|
||||
|
||||
- resolve target assignee org position
|
||||
- evaluate allow/deny scope rules before assignment mutation
|
||||
- return `403` for out-of-scope assignments
|
||||
|
||||
## Invite and signup flow
|
||||
|
||||
1. Authorized user creates invite with email + grants + optional expiry.
|
||||
2. System sends invite URL containing one-time token.
|
||||
3. Invitee signs up/logs in.
|
||||
4. Email on authenticated account must match invite email.
|
||||
5. Accepting invite creates active `company_membership` and permission grants.
|
||||
6. Inviter/admin can revoke invite before acceptance.
|
||||
|
||||
Security rules:
|
||||
|
||||
- store invite token hashed at rest
|
||||
- one-time use token with short expiry
|
||||
- all invite lifecycle events logged in `activity_log`
|
||||
|
||||
## Human inbox and agent-to-human delegation
|
||||
|
||||
Behavior:
|
||||
|
||||
- agents can assign tasks to humans when policy permits
|
||||
- humans see assigned tasks in inbox view (including in local trusted mode)
|
||||
- comment and status transitions follow same issue lifecycle guards
|
||||
|
||||
API additions (proposed):
|
||||
|
||||
- `GET /companies/:companyId/inbox` (human actor scoped to self)
|
||||
- `POST /companies/:companyId/issues/:issueId/assign-user`
|
||||
- `POST /companies/:companyId/invites`
|
||||
- `POST /invites/:token/accept`
|
||||
- `POST /invites/:inviteId/revoke`
|
||||
- `GET /companies/:companyId/members`
|
||||
- `PATCH /companies/:companyId/members/:userId/permissions`
|
||||
|
||||
## Local mode UX policy
|
||||
|
||||
- no login prompt or account setup required
|
||||
- local implicit board user is auto-provisioned for audit attribution
|
||||
- invite/multi-user screens can be hidden or marked unavailable in local mode
|
||||
- if operator wants collaboration, they must switch to `cloud_hosted`
|
||||
|
||||
## Cloud agents in this model
|
||||
|
||||
- cloud agents continue authenticating through `agent_api_keys`
|
||||
- same-company boundary checks remain mandatory
|
||||
- agent ability to assign human tasks is permission-gated, not implicit
|
||||
|
||||
## Implementation phases
|
||||
|
||||
## Phase 1: Mode and guardrails
|
||||
|
||||
- add explicit deployment mode config (`local_trusted | cloud_hosted`)
|
||||
- enforce startup safety checks and health visibility
|
||||
- implement actor resolution for local implicit board
|
||||
|
||||
## Phase 2: Human identity and memberships
|
||||
|
||||
- add schema + migrations for users/memberships/invites
|
||||
- wire auth middleware for cloud mode
|
||||
- add membership lookup and company access checks
|
||||
|
||||
## Phase 3: Permissions and assignment scope
|
||||
|
||||
- add grant model and enforcement helpers
|
||||
- add chain-of-command scope checks for assignment APIs
|
||||
- add tests for forbidden assignment (for example, cannot assign to CEO)
|
||||
|
||||
## Phase 4: Invite workflow
|
||||
|
||||
- invite create/send/accept/revoke endpoints
|
||||
- email-match enforcement and token security
|
||||
- UI for invite management and membership permissions
|
||||
|
||||
## Phase 5: Human inbox + task assignment updates
|
||||
|
||||
- extend issue assignee model for human users
|
||||
- inbox API and UI
|
||||
- agent-to-human assignment flow with policy checks
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
1. `local_trusted` starts with no login and shows board UI immediately.
|
||||
2. `cloud_hosted` cannot start without auth configured.
|
||||
3. No request in `cloud_hosted` can mutate data without authenticated actor.
|
||||
4. Humans can be invited by email, accepted with matching email, and revoked.
|
||||
5. Permissions can be granted/revoked per company member.
|
||||
6. Assignment scope prevents out-of-hierarchy or protected-role assignments.
|
||||
7. Agents can assign tasks to humans only when allowed.
|
||||
8. Humans can view assigned tasks in inbox and act on them per permissions.
|
||||
9. All new mutations are company-scoped and logged in `activity_log`.
|
||||
|
||||
## Open decisions
|
||||
|
||||
1. Auth provider choice for cloud mode (Auth.js vs hosted provider).
|
||||
2. Whether local mode supports optional login in addition to implicit board.
|
||||
3. Exact representation of permission grants (normalized table vs JSON schema).
|
||||
4. Whether a user can belong to multiple companies in initial release.
|
||||
5. Whether invite email delivery is built-in or webhook/provider integration only.
|
||||
Reference in New Issue
Block a user