Files
hub/docs/architecture/storage/roles.md
glm-5.1 2b63cda1c7 Setup repo: migrate architecture specs, code stubs, and tasks from alkhub_ts
Copy architecture docs, ADRs, storage domain specs, research, reviews,
and 56 storage architecture tasks from the alkhub_ts monorepo. Adapt for
standalone @alkdev/hub repo structure (src/ not packages/hub/).

Sanitize all sensitive information:
- Replace private IPs (10.0.0.1) with localhost defaults
- Remove internal server hostnames (dev1, ns528096)
- Replace /workspace/ private paths with npm package references
- Remove hardcoded credentials from examples
- Rewrite infrastructure.md without private network details

Add Deno project scaffolding: deno.json (pinned deps), .gitignore,
AGENTS.md, entry point. Migrate existing code stubs (crypto, config
types, logger) with updated import paths.
2026-05-25 10:56:32 +00:00

105 lines
5.5 KiB
Markdown

---
status: draft
last_updated: 2026-04-20
---
# Table Schemas: Roles
Behavioral role definitions. For cross-cutting reference (cascade behavior, index reference, status enums, relations), see [table-reference.md](./table-reference.md). For the full account-role-session model, see [../../agent-roles.md](../../agent-roles.md). For the terminology decision, see [ADR-012](../../../decisions/ADR-012-agent-vs-role-vs-account.md).
### `roles`
Behavioral role definitions that any account can fill during a session. Roles define what operations are available, what permissions are granted, and what scope constraints apply. Currently defined in `.opencode/agents/*.md` files; this table enables database storage and runtime permission resolution.
| Column | Type | Notes |
|--------|------|-------|
| commonCols | — | id, metadata, createdAt, updatedAt |
| name | text NOT NULL UNIQUE | Role identifier (e.g., "architect", "implementation-specialist") |
| description | text | Human-readable description |
| mode | text NOT NULL | `primary` (user-facing) or `subagent` (spawned by coordinator) |
| temperature | real | Model sampling temperature (default: 0.2 for subagents, 0.3 for primary) |
| permissions | jsonb NOT NULL DEFAULT `[]` | Permission ruleset — array of `{ action, permission, pattern }` rules, evaluated first-match |
| tools | jsonb NOT NULL DEFAULT `{}` | Tool availability map — `{ toolName: boolean }` for enabled/disabled tools |
| prompt | text | System prompt template |
| parentId | text | FK → roles.id — Parent role for inheritance. onDelete: SET NULL — deleting a parent detaches children. |
| scopes | jsonb NOT NULL DEFAULT `[]` | API key scopes this role requires (string array, used during permission resolution) |
| data | jsonb | Additional role-specific configuration (model selection, max steps, etc.) |
**Indexes**: `unq_roles_name` UNIQUE on `(name)`, `idx_roles_parent_id` on `(parentId)`, `idx_roles_mode` on `(mode)`.
**`permissions` shape**: A `Permission.Ruleset` — an ordered array of rules evaluated first-match:
```ts
type PermissionRule = {
action: "allow" | "deny" | "ask"; // What to do when this rule matches
permission: string; // e.g., "edit", "read", "bash", "webSearch"
pattern: string; // Glob pattern for path-based matching (e.g., "src/**", "*")
};
type PermissionRuleset = PermissionRule[];
```
Example for implementation-specialist:
```json
[
{ "action": "allow", "permission": "read", "pattern": "**" },
{ "action": "allow", "permission": "write", "pattern": "src/**" },
{ "action": "allow", "permission": "edit", "pattern": "src/**" },
{ "action": "allow", "permission": "bash", "pattern": "deno *" },
{ "action": "deny", "permission": "bash", "pattern": "*" },
{ "action": "allow", "permission": "webSearch", "pattern": "*" }
]
```
**`tools` shape**: A simple boolean map for which tools are available to this role:
```json
{
"read": true,
"write": true,
"edit": true,
"glob": true,
"grep": true,
"bash": true,
"webSearch": true,
"webfetch": true
}
```
**Role inheritance**: When a role has a `parentId`, the child role inherits `permissions` and `tools` from the parent, with the child's values taking priority. Specifically:
- `permissions`: The parent's ruleset is prepended before the child's ruleset. First match wins, so child rules override parent rules for the same pattern.
- `tools`: Union of parent and child tool sets. If both define a tool, the child's value takes priority.
- `temperature`, `prompt`, `model`, `scopes`: Child values override parent values entirely (no merging).
- Max inheritance depth: 3 levels. Circular inheritance is prevented at role creation time.
**`data` shape**: Additional configuration that varies by role:
```ts
type RoleData = {
model?: { // Override model selection
providerID: string; // e.g., "anthropic", "openai"
modelID: string; // e.g., "claude-opus-4-5-20250101"
};
steps?: number; // Max agentic steps per turn
topP?: number; // Top-P sampling parameter
color?: string; // Display color for UI
hidden?: boolean; // Don't show in role selection UI
source?: "builtin" | "file" | "database"; // Where this role definition came from
filePath?: string; // Source file path (for file-based roles)
};
```
**OpenCode compatibility**: When importing from `.opencode/agents/*.md`, the YAML frontmatter maps to:
- `description` → from frontmatter `description`
- `mode` → from frontmatter `mode`
- `temperature` → from frontmatter `temperature`
- `tools` → from frontmatter `tools`
- `permissions` → converted from frontmatter `permission` (OpenCode uses `Permission.Ruleset` format)
- `prompt` → from markdown body content
- `data.model` → from frontmatter `model`
- `data.steps` → from frontmatter `steps`
- `data.source``"file"`
- `data.filePath` → path relative to project root
**Migration path**: Phase 1 uses `.opencode/agents/*.md` files. Phase 2 adds a `roles.sync` operation that reads files and upserts into this table. Phase 3 makes the database authoritative with files as a version-controlled editing surface.
**Sessions reference**: `sessions.roleName` is a free-form string that references `roles.name` by convention, but there is no FK constraint. Sessions may use role names not yet in the `roles` table (e.g., file-based roles not yet synced). A FK constraint may be added in Phase 3 when the database becomes authoritative.