Files
hub/docs/decisions/ADR-012-agent-vs-role-vs-account.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

84 lines
4.9 KiB
Markdown

# ADR-012: Agent vs Role vs Account Terminology
## Status
Proposed
## Context
The codebase and documentation use "agent" in multiple overlapping senses:
1. **OpenCode "agent"**: A behavioral specification defining what tools, permissions, model, and prompt an LLM session uses. OpenCode's `.opencode/agents/*.md` files define these.
2. **Philosophical "agency"**: An ill-defined notion of autonomy or self-direction.
3. **Principal-agent "agent"**: In the legal sense, an entity that acts on behalf of a principal.
4. **MCP/LLM "agent"**: A general term for an LLM-powered system that takes actions.
Meanwhile, our `accounts` table has a `role` column with values `admin`, `user`, `service` — which is a _different_ "role" concept (access level, not behavioral specification).
This creates confusion:
- When we say "agent permissions," do we mean the behavioral spec (OpenCode sense) or the access level (account sense)?
- When an LLM creates a Gitea commit, who is the "agent"? The LLM? The human who delegated? The account the LLM uses?
- When we import OpenCode sessions, their `agent` field maps to... what in our model?
## Decision
We adopt the following terminology:
| Term | Definition | Storage |
|------|-----------|---------|
| **Account** | An identity in the system (human, service, or LLM). Owns resources, authenticates. | `accounts` table |
| **Role** | A behavioral specification that any account can fill. Defines permissions, tools, model params. | `roles` table (future), currently `.opencode/agents/*.md` |
| **Session** | A unit of work where an account fills a role. Binds account + role for a duration. | `sessions` table |
### Specific naming changes:
1. **`sessions.agentName`** → **`sessions.roleName`**
- The field stores which behavioral role is active, not which account
- OpenCode's `agent` field on messages maps to our `roleName`
2. **`accounts.role`** → **`accounts.accessLevel`**
- Renamed to avoid confusion with behavioral roles
- Values remain: `admin`, `user`, `service`
- This is a different concept from the behavioral role
3. **`organization_members.role`** → **`organization_members.membershipLevel`**
- Yet another "role" concept — org membership level
- Values remain: `owner`, `admin`, `member`
- Renamed for the same reason: avoid collision with behavioral roles
4. **New term**: When we need to say "an LLM acting autonomously", we say **"LLM in a role"** or **"session with an LLM account"**, not "agent"
5. **OpenCode import mapping**: OpenCode's `session.agent` → our `sessions.roleName`
### Rationale
- **"Role" is what you fill, not what you are**. A human can fill the implementer role. An LLM can fill the implementer role. The role defines behavior, not identity.
- **"Account" provides accountability**. Every session, API call, and audit entry traces back to an account. Whether that account is human or LLM is indicated by `accounts.accessLevel: "service"`.
- **"Agent" is ambiguous**. The philosophical and legal senses conflict. The OpenCode sense conflates behavior with identity. Avoiding it removes confusion.
- **The principal-agent framework maps naturally**. When a coordinator (principal) delegates to an implementer (agent), both have accounts. The accountability flows through the accounts, not through some notion of "agency."
- **Permission intersection makes sense**. `Session permissions = Role.permissions ∩ Account.scopes ∩ SpokeType.trustLevel` reads clearly. `Agent.permissions ∩ ...` would be unclear.
## Consequences
### Positive
- Clear separation between identity (account) and behavior (role)
- Unambiguous accountability trail (every action → account)
- Natural mapping of OpenCode's `agent` field → `roleName`
- No philosophical confusion about "agency"
### Negative
- Three columns renamed: `sessions.agentName``sessions.roleName`, `accounts.role``accounts.accessLevel`, `organization_members.role``organization_members.membershipLevel`
- Need to be consistent about this in all new documentation and code
- OpenCode's `.opencode/agents/` directory name stays (it's their convention), but we refer to the contents as "role specs" not "agent specs"
- Migration needed for existing code/docs that use the old column names
### Terminology Summary
| Old/Ambiguous Term | Canonical Term | Storage Location | Values |
|---|---|---|---|
| `accounts.role` | `accounts.accessLevel` | `accounts.accessLevel` | admin, user, service |
| `sessions.agentName` | `sessions.roleName` | `sessions.roleName` | architect, implementation-specialist, ... |
| `organization_members.role` | `organization_members.membershipLevel` | `organization_members.membershipLevel` | owner, admin, member |
| behavioral "agent" (OpenCode) | role | `roles` table (planned) | architect, implementation-specialist, ... |
### Neutral
- OpenCode import just maps `agent``roleName` — this is a data mapping, not a semantic conflict