# ADR-017: Hub-first role definitions (database, not files) - **Status**: Accepted - **Date**: 2026-05-26 - **Deciders**: alkdev ## Context The original architecture (from agent-roles.md) defined a three-phase role system: 1. **Phase 1 (current)**: Roles defined in `.opencode/agents/*.md` markdown files 2. **Phase 2**: A `roles.sync` operation that ingests `.opencode/agents/*.md` files into a `roles` table 3. **Phase 3**: Database-authoritative roles, with markdown files only for version control editing This phased approach was designed around opencode's convention of file-based agent definitions. With ADR-015 (dev spoke instead of opencode integration), opencode is no longer a core dependency. The hub manages its own roles. ## Decision The hub is database-first for roles from day one. There is no Phase 1 or Phase 2 transition from files to database. Roles are defined in the `roles` table in Postgres, seeded by migrations for the built-in roles (architect, decomposer, coordinator, implementation-specialist, code-reviewer, architecture-reviewer, research-specialist, poc-specialist). ### Built-in roles The hub's migration files seed the standard SDD roles: | Role | Mode | Key Permission Pattern | |------|------|----------------------| | architect | primary | read, write, webSearch — no bash | | architecture-reviewer | subagent | read, grep — read-only | | code-reviewer | subagent | read, grep, bash (read-only) | | coordinator | primary | read, worktree_*, bash (limited) — no implementation | | decomposer | primary | read, taskgraph — no bash | | implementation-specialist | primary | read, write, edit, bash, webSearch — scoped to worktree | | poc-specialist | primary | read, write, edit, bash, webSearch — scoped to research worktree | | research-specialist | subagent | webSearch, read, write — no bash | ### Role API Roles are managed via hub operations: - `hub.listRoles` — list available roles - `hub.getRole` — get role definition by name - `hub.createRole` — create a custom role (requires admin scope) - `hub.updateRole` — update role definition (requires admin scope) Custom roles can be created at runtime via `hub.createRole`. No file sync is needed. ### Opencode agent mapping When importing opencode sessions (if an opencode-spoke is built later), the mapping from opencode's `agent` field to the hub's `roleName` is: | Opencode `agent` | Hub `roleName` | |-------------------|----------------| | `"build"` | `"implementation-specialist"` | | `"plan"` | `"decomposer"` | | `"general"` | `"coordinator"` | | `"explore"` | `"research-specialist"` | This mapping is a compat concern in the import tool, not a core architecture concern. ## Consequences **Positive**: No file-based role sync system to build. No `.opencode/agents/` directory dependency. Roles are queryable, type-safe, and managed through the hub's operation interface. Custom roles can be created programmatically. The hub doesn't need a `roles.sync` operation. **Negative**: Role definitions can't be easily version-controlled in markdown files alongside the code. Role creation requires the hub API (or seeding via migrations). If role editing in a text editor is desired later, a `roles.export`/`roles.import` operation can be built, but this is not a v1 concern. ### Open questions resolved by this decision | OQ | Resolution | |----|-----------| | OQ-26 | No `roles.sync` from `.opencode/agents/*.md` needed. Hub is database-first. Role definitions are seeded by migrations. | | OQ-28 | No `Agent.generate()` equivalent needed for v1. Custom roles are created via `hub.createRole`. | | OQ-51 | No file→DB migration needed. Hub started in the database-first state. | ### Open questions narrowed by this decision | OQ | Narrowing | |----|-----------| | OQ-04 | Service account provisioning is now a generalized question: `hub.createAccount` operation for programmatic creation. For v1, manual creation with keypal CLI is sufficient. LLM-specific email conventions (like `glm-5.1@alk.dev`) are deployment-specific, not core architecture. | | OQ-05 | SSO with Gitea is out of scope for a generalized hub. Git provider integration (Gitea, GitHub, etc.) is a spoke concern via operations, not through SSO. For v1, Gitea is accessed via the dev spoke's git operations, not via shared auth. |