Skip to content

Design (parked): team mode — a shared server behind the local daemon, with RBAC #248

Description

@piwi3910

Not scheduled. This is a design record, parked deliberately so the local
daemon in #117 can ship without it and without being redone because of it.
Nothing here is implemented and nothing here is committed to; the decisions
below are where the discussion of 2026-08-28 landed, not a promise.

Team mode is the third tier of the service design in #117: hooks talk to a local
daemon, and the daemon — never the hook — talks to a shared team server.

 procoder (client) ──socket──▶ procoder daemon ──HTTPS+token──▶ team server
                                                                 many users
                                                                 many repos

The daemon still runs every check on the local checkout. The team server has
nobody's files and can never run gofmt; asking it to would mean shipping
working trees over the network or silently running fewer checks in team mode
than locally. Both are worse than the problem.

The scope ladder gains a rung

internal/gate/adoption.go already decides between Universal (only what is
true regardless of house style) and Adopted (everything, because this
repository asked). Team mode is the third rung — Adopted plus a policy floor
set centrally
. A repo may tighten the floor. It may not weaken it. That is the
one place D-OVERRIDE changes: the repo file still wins, but only upward.

Ownership moves; files do not

Team-owned artifacts still materialise as files under .procoder/, committed to
git. The daemon syncs them down and records the team version in a manifest. Every
domain that reads them today reads them unchanged, pull requests still show them,
CI and a fresh clone still work.

What changes is who may write them. A local edit to a team-owned file is a
drift finding at the gate, not an accepted change — the same shape as the
agent-layer drift check that already exists.

This is why #117's D7 survives contact with team mode. Git still holds the
content. The server holds the authority over it.

What is owned where

Artifact Local mode Team mode
config.toml, security/RULES.md, docs/RULES.md, github templates repo file wins (D-OVERRIDE) team baseline is a floor; repo may tighten only
specs repo, in git team-owned
backlog: milestones, epics, stories repo team-owned — a story can span repos
sprints repo team-owned — multi-person by definition
ask decisions and answers repo team-owned — an answered question is answered everywhere
lessons, glossary repo team-owned — cross-repo by nature
ADRs repo scoped — org ADRs from the team, repo ADRs stay local
claims, release versions, changelog repo / gitignored team-owned — coordination is meaningless with one person
plans repo stays repo — how this repo implements a story
todo repo stays repo
index, dispatch, handoff, bench baselines local stays local — derived or machine-specific
learn timings local local, aggregated to the team

Where each check and gate runs

Checks are unchanged in both modes: they exec real tools against the working
tree, on the machine that holds it.

Local mode Team mode
format, lint, secrets, SAST, deps, complexity, debt, tests local daemon local daemon, team policy floor, verdict recorded team-side
audit / full-repo scan local, on demand runs local (it needs the tree), results aggregated team-side
commit gate local verdict, final local verdict + team leg; no team verdict, no green
todo close local local
story / epic close local team — requires approve on backlog
sprint open / close local team — requires approve on sprint
spec approve local team — requires approve on spec
release / version local team — version reserved centrally, changelog assembled team-side, requires approve on release
PR merge local (gh) team — consults the recorded team verdict

RBAC

Resources: spec, backlog, sprint, adr, policy, release, lesson,
decision. Verbs: read, propose, approve, admin.

Role Gets
viewer read everything, propose nothing
contributor read all; propose specs, stories, ADRs, decisions; close todos
maintainer approve specs, stories and ADRs; open and close sprints; release
admin policy, membership, repo registration

Per-repo overrides: maintainer in one repo, viewer in another.

The client cannot enforce any of this, and this design does not pretend
otherwise.
Anyone can edit a file locally or set mode = "off". What the
server enforces is whether an edit becomes team truth and whether the team gate
says yes; the local gate reports the divergence as drift. It is a boundary
against accident and a record of authority, not a wall against a determined
local user — the same stance internal/dispatch takes about parallelism claims.

Which is why RBAC works through propose/approve rather than client-side
refusal. "Cannot create a spec" does not mean the binary refuses. It means the
write lands server-side as proposed and someone holding approve promotes it.
That is P-CONTROL one tier up: procoder records, a person decides.

Decisions of 2026-08-28

# Decision
T1 Team mode is the third rung of the scope ladder: Adopted plus a policy floor a repo may tighten but never weaken.
T2 Ownership moves, location does not. Team-owned artifacts materialise as files in .procoder/, committed to git, with a sync manifest recording which team version each came from.
T3 Checks never move to the server. Team mode supplies their policy and receives their evidence.
T4 Every write to a team-owned artifact lands server-side as proposed; a role holding approve promotes it. RBAC is enforced by the server and never by the client.
T5 RBAC is resources × verbs with four default roles and per-repo overrides — not a permission per command.
T6 In team mode the commit gate needs a team verdict to report green. Local legs still run and report; the overall verdict is NOT green without the team leg.
T7 All four tiers are team-owned by default when a repo joins a team: policy, planning, knowledge, coordination.
T8 Per-user identity is required. A single shared bearer token is not identity — every decision, lesson, answer and claim needs an author.

Risks this design carries

  • A team-server outage stops the team committing (T6). Deliberate — the team
    floor is not optional — but it makes the server's availability a hard
    dependency for everyone who joined a team.
  • Approval queues can starve. T7 puts machine-written knowledge through
    approval too: an answer recorded by procoder ask, a lesson harvested from a
    copilot leak, a claim taken when work starts. If claims need approval, nobody
    starts work while a maintainer is asleep. A direct-write carve-out for the
    coordination tier is the most likely correction to this design.
  • Drift becomes a routine finding. Every stale sync shows up at the gate. Too
    noisy and people learn to ignore the gate, which is worse than not having the
    check.

Open questions

  • How does a repo join a team, and who may do it? procoder init --team <name>
    needs an admin on the other end registering the repo.
  • Where do per-user identities come from — procoder-issued tokens, or OIDC
    against whatever the team already uses?
  • Conflict handling when the same story is edited team-side and locally in the
    same window. The drift finding is the detection; the resolution path is
    undefined.
  • Does the approval queue need a carve-out for machine-written coordination
    writes, claims especially? See the risks above.
  • What happens to an in-flight release when the team server goes down midway —
    is a reserved version released back, or held?
  • Team-server schema and migrations: who owns the storage, and how does a version
    upgrade land for a team that cannot restart everybody at once?
  • novamem as the knowledge backing store — a separate question once this tier
    exists.

Blocked on #117.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions