Permissions
The API enforces 87 permissions of the form product.resource.action: 13 in organisation scope and 74 in
program scope (program 27, evidence 13, plans 14, review 10, progress 10). The catalog is pinned in
api/app/auth/permissions.py (EXPECTED_PERMISSION_COUNT = 87), mirrored in web/lib/auth/permissions.ts
(PERMISSION_COUNT = 87) and in the table below; web/scripts/check-permissions-sync.mjs --docs compares
the three by key, scope, order and count and prints permissions in sync: 87 strings (13 org, 74 program).
Every route has exactly one permission or a documented public, authenticated, signature or run-token rule; a
missing permission answers 403 as problem+json with the key in permission.
Phase 2 added nine keys (72 -> 81), all in program scope: four for console threads, two for fetched
documents, two for agent memory and progress.agents.use. Phase 3 R3 adds six more (81 -> 87), also in
program scope and placed after program.agent_memory.manage: four for persona twins and two for hand-off
requests (PRODUCT-CONTRACT.md 11.4 and 11.7). There is still no “approve an agent write” key: approving a
proposal, whether it came from a console turn or from a twin, needs the write’s own permission, and the audit
row records it as permission_exercised (PRODUCT-CONTRACT.md 10.2). No dormant key exists: org.twins.use
(R5) and the four stage-gate keys (R4) enter the catalog with their routes.
Shape
productis one oforg,program,evidence,plans,review,progress.actioncomes from the closed setread,create,update,delete,manage,approve,link,sync,use,read_own,manage_owners.- Scope kind is
orgwhen the product segment isorg, otherwiseprogram. Org-scope permissions apply everywhere in the organisation; program-scope permissions apply inside one program. - Effective permissions are the union of direct and group role assignments; there are no deny rules.
.managecovers create, update, delete and the transitions to every status other thanapproved;.approvecovers the/approveand/decisionroutes;.usestarts agent runs, threads or tool invocations, and for twins is the person’s own consent to background runs.program.threads.readandprogram.twins.readare oversight (every thread, every twin);program.threads.read_ownandprogram.twins.read_ownare own and shared; theprogram.*.readpattern used by persona bundles matchesreadexactly, soread_ownis never absorbed by it.
Catalog
Organisation scope (org, 13)
| Permission | Scope | Description |
|---|---|---|
org.settings.read | org | Read organisation name, slug and settings |
org.settings.update | org | Update organisation settings |
org.programs.read | org | List the organisation’s programs |
org.programs.create | org | Create a program |
org.programs.manage | org | Rename, pause, complete or archive a program |
org.users.read | org | List users of the organisation |
org.users.manage | org | Invite, deactivate or update users |
org.groups.read | org | List groups |
org.groups.manage | org | Create, update or delete groups and their members |
org.roles.read | org | List organisation role assignments |
org.roles.manage | org | Assign or remove organisation roles other than owner |
org.roles.manage_owners | org | Grant or revoke the organisation owner persona |
org.audit.read | org | Read the organisation audit log |
Program scope (program, 27)
| Permission | Scope | Description |
|---|---|---|
program.settings.read | program | Read program name, description, stage and status |
program.settings.update | program | Update program settings and current stage |
program.members.read | program | List members of the program |
program.members.manage | program | Add or remove program members |
program.roles.read | program | List program role assignments |
program.roles.manage | program | Assign or remove program roles other than owner |
program.roles.manage_owners | program | Grant or revoke the program owner persona |
program.connections.read | program | List connections to external systems and their sync runs |
program.connections.manage | program | Create, update or remove connections |
program.connections.sync | program | Trigger a manual sync of a connection |
program.audit.read | program | Read the program audit log |
program.agent_runs.read | program | List agent runs and their events |
program.agent_runs.manage | program | Cancel agent runs |
program.threads.read | program | Read every console thread of the program for oversight |
program.threads.read_own | program | Read own and shared console threads |
program.threads.use | program | Start threads, send messages and resolve agent interrupts |
program.threads.manage | program | Archive or export any thread with a recorded reason |
program.documents.read | program | Read fetched documents and their chunks |
program.documents.manage | program | Fetch documents by identifier, re-fetch or archive them |
program.agent_memory.read | program | Read what the agent remembers about the program |
program.agent_memory.manage | program | Delete agent memory records |
program.twins.read | program | Read every twin of the program and its activity, for oversight |
program.twins.read_own | program | Read your own twins, duties and schedules |
program.twins.use | program | Start, pause, resume, configure or retire your own twin and approve its standing plans |
program.twins.manage | program | Pause or retire any twin and set program twin defaults, with a reason |
program.handoffs.read | program | Read hand-off requests |
program.handoffs.manage | program | Send, accept, decline, complete or withdraw hand-off requests |
Evidence (evidence, 13)
| Permission | Scope | Description |
|---|---|---|
evidence.questions.read | program | Read research questions |
evidence.questions.manage | program | Create, update or delete research questions |
evidence.sources.read | program | Read evidence sources |
evidence.sources.manage | program | Register or update evidence sources |
evidence.sources.link | program | Link a source to a question, finding or hypothesis |
evidence.findings.read | program | Read findings |
evidence.findings.manage | program | Record or update findings |
evidence.hypotheses.read | program | Read hypotheses |
evidence.hypotheses.manage | program | Propose or update hypotheses |
evidence.hypotheses.approve | program | Accept or reject a hypothesis |
evidence.gaps.read | program | Read knowledge gaps |
evidence.gaps.manage | program | Address or dismiss knowledge gaps |
evidence.agents.use | program | Start evidence agent runs (compare, gaps, hypotheses) |
Plans (plans, 14)
| Permission | Scope | Description |
|---|---|---|
plans.plans.read | program | Read research plans |
plans.plans.manage | program | Create, update or transition research plans |
plans.plans.approve | program | Approve a research plan |
plans.protocols.read | program | Read protocols |
plans.protocols.manage | program | Draft, update or transition protocols |
plans.protocols.approve | program | Approve a protocol |
plans.experiments.read | program | Read experiment records |
plans.experiments.manage | program | Create or update experiment records |
plans.reports.read | program | Read research reports |
plans.reports.manage | program | Draft, update or transition research reports |
plans.reports.approve | program | Approve a research report |
plans.tools.read | program | List approved tools and their invocations |
plans.tools.use | program | Invoke an approved analytical or design tool |
plans.agents.use | program | Start plans agent runs (draft protocol, draft report) |
Review (review, 10)
| Permission | Scope | Description |
|---|---|---|
review.sops.read | program | Read standard operating procedures and document requirements |
review.sops.manage | program | Draft, update or transition SOPs |
review.sops.approve | program | Approve an SOP |
review.checks.read | program | Read review checks |
review.findings.read | program | Read review findings |
review.findings.manage | program | Annotate review findings |
review.findings.approve | program | Decide a review finding (accept, dismiss, resolve) |
review.deviations.read | program | Read deviations |
review.deviations.manage | program | Record or update deviations |
review.agents.use | program | Start a review check (agent comparison against an SOP) |
Progress (progress, 10)
| Permission | Scope | Description |
|---|---|---|
progress.milestones.read | program | Read milestones and the program overview |
progress.milestones.manage | program | Create, update or delete milestones |
progress.dependencies.read | program | Read milestone dependencies |
progress.dependencies.manage | program | Create or delete milestone dependencies |
progress.open_items.read | program | Read open items |
progress.open_items.manage | program | Create or update open items |
progress.approvals.read | program | Read approval requests |
progress.approvals.manage | program | Request or withdraw approvals |
progress.approvals.approve | program | Decide an approval request |
progress.agents.use | program | Start progress agent runs (propose open items and milestone changes) |
Console keys and the thread rule
lets a person read the threads they
created and the threads an owner shared with the program;
adds every thread for oversight, which the composer announces with the fixed phrase “Private to you. Quality
reviewers and program leads can read this thread for review.” Sharing is an owner action, never a
manage action; covers archive and export with a
recorded reason. The same thread rule governs the run rail: events, tool calls, interrupts, snapshots and
artifacts of an agent run that belongs to a thread are returned only to a principal who may read that thread,
while alone lists such runs as metadata.
Approving an agent proposal exercises the permission of the write itself: accepting a proposed finding needs
, and the audit row of that write carries
permission_exercised = evidence.findings.manage beside the interrupt id. Agents hold no approve, sign or
notify tools, so *.approve keys are only ever exercised by people.
Twin keys and the bound-user rule
is a person’s consent to background runs in their
own name: it enables, pauses, resumes, configures and retires their own twin and approves its standing plans,
and the audit row of a standing-plan approval records permission_exercised = program.twins.use. It is held
by every program persona except the viewer. shows a
person their own twins, duties and schedules and is the one twin key the viewer holds (a viewer has no twin;
the home page says “Viewers have no twin. Nothing waits for you.”).
is oversight: every twin of the program, its activity, the names on the program board and the
decision_reminder escalations; it is held by the program owner, the program lead and the quality reviewer
only, subtracted from the other personas exactly as program.threads.read is.
lets an owner or lead pause or retire anyone’s twin with
a recorded reason and set the program’s twin defaults; it never activates a twin for someone else.
Twin proposals follow the same rule as console proposals, with one addition: interrupts on a twin run belong
to the bound person. A write approval is resolvable by the bound person or by an active delegate who holds the
write’s own permission; a standing plan only by the bound person; anyone else, whatever thread keys they
hold, gets 403 bound_user_only. is absorbed by every
program persona’s reads; sends, accepts, declines,
completes or withdraws hand-off requests, each route scoped to the party it belongs to (sender, addressee or
current persona holder). No twin holds either key as a tool that acts alone: console.propose_handoff only
proposes, and the handoff_requests row exists once the sending person approves.
Reading the table
is the permission a person needs to
accept or reject a hypothesis; at persona version 3 it is held by the program lead and owner, not the
scientist. is the one permission that
separates org_owner from org_admin. Which persona holds which key is on the
personas page.
Source: api/app/auth/permissions.py (EXPECTED_PERMISSION_COUNT = 87), api/app/auth/personas.py (PERSONA_VERSION = 3), web/lib/auth/permissions.ts (PERMISSION_COUNT = 87), web/scripts/check-permissions-sync.mjs, docs/lib/content.ts, PRODUCT-CONTRACT.md sections 10.2, 11.4 and 11.7, decisions/0021-persona-twins.md