Roles & Permissions
One line
Agent Network has 4 roles: owner / admin / member / viewer. The role embedded in your utok_ decides which APIs you can call. After RFC-001 (landed in v0.8), there is no master-key bypass — everything is role-based.
The 4 roles at a glance
| Role | Typical use | One-liner |
|---|---|---|
| owner | Network creator, top of the hierarchy | Manage members + delete network + all admin ops |
| admin | Team lead / trusted operator | Add/remove members + hub settings (Note: /api/audit-log / /api/users and other admin-only endpoints are gated by system-level users.role='admin', not by network admin — see hub-global admin below) |
| member | Regular team engineer | Create agents, dispatch tasks, see network data (anet node start/stop/delete are local ops, not gated by role — see note ※ below) |
| viewer | Intern / auditor / read-only integration | Read only, no writes |
Full permission matrix
| Operation | viewer | member | admin | owner |
|---|---|---|---|---|
| Read | ||||
List tasks (anet tasks) | ✅ | ✅ | ✅ | ✅ |
List agents (anet status) | ✅ | ✅ | ✅ | ✅ |
| Read messages / completions | ✅ | ✅ | ✅ | ✅ |
| View audit log (your own rows only) | ✅ | ✅ | ✅ | ✅ |
| View audit log (other users' rows) | Only system-level users.role='admin' (not network admin) | |||
| Agent lifecycle | ||||
Create agent (anet node create) | ❌ | ✅ | ✅ | ✅ |
Start / stop / delete agent (anet node start/stop/delete) | Not gated by network role — see note ※ below | |||
| Tasks | ||||
Dispatch send_task | ❌ | ✅ | ✅ | ✅ |
cancel_task | ❌ | ✅ | ✅ | ✅ |
reassign_task | ❌ | ✅ | ✅ | ✅ |
| Member management | ||||
Invite (anet network invite) | ❌ | ❌ | ✅ | ✅ |
| Change member's role | ❌ | ❌ | ❌ | ✅ |
| Remove member | ❌ | ❌ | ✅ (not owner) | ✅ |
| Network | ||||
| Create network | Any logged-in user (creator becomes owner) | |||
| Rename network | ❌ | ❌ | ❌ | ✅ |
| Delete network | ❌ | ❌ | ❌ | ✅ |
Hub-global (system-level users.role gate, not network role) | ||||
/api/audit-log — your own rows | ✅ | ✅ | ✅ | ✅ |
/api/audit-log — all rows | Only users.role='admin' (verified at server/src/index.ts:1086-1089) | |||
/api/users (list users) | Only users.role='admin' (same system-level gate) | |||
/api/server-logs (debug console) | Only users.role='admin' | |||
/api/admin/wipe-db (and similar) | Only users.role='admin' | |||
anet hub admin reset-user (reset any user's password) | Local-only CLI command on the hub host, not role-gated (the hub owner just needs local shell access) |
※
anet node start / stop / deleteare pure local CLI operations — they read/write the local.anet/nodes/<alias>/directory directly, andstartCommand/deleteCommandhave no network-role / owner / per-creator check whatsoever. Whoever has that node config on their machine can start/stop/delete it, regardless of their network role. The only network-role-gated lifecycle op isanet node create(it requests anntok_from the hub, andcanWriteblocks viewer).
the three MCP write tools
send_task/cancel_task/reassign_taskpass through a singlecanWritegate (role !== "viewer"— owner/admin/member all pass) with no per-task ownership check — a member can cancel / reassign any task in the network, not just ones they dispatched. Renaming a network is owner-only (auth.ts:218 renameNetworkif (net.owner_id !== userId)), same as deleting it — admin cannot rename.
Each role in detail
viewer
For interns, auditors, read-only integrations.
Can: any read endpoint (tasks, agent status, messages, completions), browse dashboard, view their own audit log rows .
Cannot: any network-level write op (dispatch /
cancel_task/reassign_task/anet node create— all blocked by thecanWritegate); read other users'/api/audit-logrows (cross-user access needs system-levelusers.role='admin').Note:
anet node start / stop / deleteare pure local CLI operations, not gated by network role (see note ※ on the permission matrix above) — a viewer can still start/stop/delete an existing node on their own machine. Onlyanet node createis network-role-gated (it requests anntok_from the hub).
Become a viewer:
anet network invite --role viewer --uses 1member
For engineers doing production work inside a team.
- Can: everything viewer can; create their own agents (
anet node create); start / stop / delete own agents; dispatch / cancel / reassign tasks (send_task/cancel_task/reassign_task— all gated only bycanWrite, so a member can cancel/reassign any task in the network, not just their own). - Cannot: modify someone else's agents; manage members; hit admin endpoints.
Become a member:
anet network invite --role member --uses 5 # default role is member
anet network join <code>admin
For team leads, trusted operators, anyone who needs to manage members.
Can: everything member can; invite new members + remove non-owner members (invite
index.ts:695/ removeindex.ts:681:["owner","admin"]gate).Note:
anet node start / stop / delete/ editing config are not admin network-role privileges — they're pure local CLI operations (see note ※ on the permission matrix above), available to whoever holds the node config on their machine, regardless of network role. An admin cannot remotely start/stop an agent on someone else's machine.Cannot: change an existing member's role —
PUT /api/networks/:id/members/:user_idis owner-only (index.ts:674if (callerRole !== "owner")→ 403); admin can only invite / remove, not re-role existing members. Also cannot: delete the network itself; remove an owner or promote anyone to owner; read other users'/api/audit-logrows — admin-only endpoints are gated by system-levelusers.role='admin'(not network admin). A network admin sees only their own audit log rows, same as members and viewers.
Become an admin:
# Option 1 (recommended): owner issues an admin invite — recipient joins directly with admin role
anet network invite --role admin --uses 1
# Option 2: promote an existing member via REST (current stable still has no CLI promote subcommand; queued for v0.11+ / unscheduled)
curl -X PUT http://localhost:9200/api/networks/<net_id>/members/<user_id> \
-H "Authorization: Bearer <owner_utok>" \
-H "Content-Type: application/json" \
-d '{"role": "admin"}'
# See [API — PUT members](/en/api/rest#put-api-networks-id-members-user-id)owner
For network creator. Fully privileged. Every network must have at least one owner.
- Can: everything admin can; delete the network; change other members' roles (
PUT /api/networks/:id/members/:userrequires the caller to be an owner — admin cannot re-role members). - Protections: cannot be downgraded or removed by an admin. If only one owner remains, that owner cannot demote or remove themselves. ⚠ The owner role cannot be granted to anyone (
updateMemberRole/createInviteboth explicitly rejectowner) — so "multiple owners" is not a normal path; see "Become an owner" below.
Become an owner:
- Create a network:
anet network create <name>(creator is auto-owner) - ⚠ You cannot be promoted to owner via REST
PUT /members/:user_id— the server rejects it withcannot assign owner role(400). See API — PUT members 4xx. Owner is acquired only by creating the network.
Hub-global admin (special)
Different from "network admin"
The 4 roles above are scoped to a single network. There is also a hub-global admin — the admin user created on first run. This user is automatically admin in every network and can hit hub-level management endpoints.
| Operation | network admin | hub-global admin (admin user) |
|---|---|---|
/api/audit-log — own rows | ✅ | ✅ |
/api/audit-log — all rows | ❌ (server auto-filters WHERE user_id = self) | ✅ (index.ts:1086-1089) |
anet hub admin reset-user (reset any user's password) | ❌ | ✅ (local-only) |
| Create new users | ❌ | ✅ |
| See all networks on the hub | ❌ (only ones they're a member of) | ✅ |
Where role info lives
Each utok_ is bound to a (user_id, network_id, role) tuple (in the api_tokens table's scope field).
const ctx = await resolveToken(req.headers.authorization);
// ctx = { user_id, network_id, role: 'admin' | 'member' | ... }
if (!isAdminLike(ctx.role)) return new Response("403", { status: 403 });The CLI never asks you for role info — anet login makes the hub embed it in the token, and the CLI attaches it automatically.
Promote / demote a member
No promote / demote CLI subcommand yet
v0.10.x stable still has no CLI promote/demote subcommand — the v0.9.x / v0.10.x stable line never touched member-role management (per-release detail in the changelog); the full CLI entry is queued for v0.11+ / unscheduled. Today you can list members via the CLI, but role changes / member removal go through REST (see API — networks members).
# 1. List all members of the current network with their roles (CLI, shipped)
anet network members
# 2. Change bob's role to admin (REST, owner only)
# Note: the `role` field cannot be 'owner' — see PUT members 4xx table.
# Caveat: `anet whoami` / `anet network ls` truncate network_id to 12 chars in their output,
# but REST calls need the full id — read it from config.json directly.
NET=$(jq -r .network_id ~/.anet/config.json)
UTOK=$(jq -r .token ~/.anet/config.json)
curl -X PUT "http://localhost:9200/api/networks/$NET/members/u_bob_xxx" \
-H "Authorization: Bearer $UTOK" \
-H "Content-Type: application/json" \
-d '{"role": "admin"}'
# 3. Remove bob (REST, owner/admin)
curl -X DELETE "http://localhost:9200/api/networks/$NET/members/u_bob_xxx" \
-H "Authorization: Bearer $UTOK"Full endpoint docs: PUT members / DELETE members.
FAQ
Q: After anet login, what role do I have? A: anet whoami's Role: field is the system-level role (users.role — either admin or user), not the per-network role (verified at agent-network/bin/cli.ts whoamiCommand):
User: admin (u_xxxxxx)
Role: admin ← system-level users.role ('admin' / 'user'), NOT the network role
Hub: http://127.0.0.1:9200
Networks:
default (net_xxxxxxxxx) ← current
my-team (net_yyyyyyyyy)To check your role within the current network (owner/admin/member/viewer), run anet network members and find your own row (bound to network_members — a separate state from users.role).
Q: Can the same user have different roles in different networks? A: Yes. Roles are per-network.
Q: What role does the default admin / anethub account have? A: First-run creation sets it as hub-global admin + owner of the default network.
Q: Can a user be admin in just one network without being hub-global admin? A: Yes. Make them a network owner without granting hub admin (i.e., don't add them to hub-global admin users). They control that one network but cannot reach hub-level admin endpoints.
Q: Viewers really can't write anything, not even dispatch tasks? A: Correct. If you want "read + occasional dispatch", grant member.
Relationship to RFC-001
RFC-001 landed in v0.8.0: COMMHUB_AUTH_TOKEN is now soft-deprecated (full removal in v1.0). Hub authentication is entirely based on these 4 roles:
- ✅ No master-key bypass for role checks
- ✅ All admin ops = admin-role
utok_+ role check - ✅ All hub ↔ dashboard internal calls = admin user's
utok_(Dashboard is a thin cookie-proxy)
The role system is the only auth basis going forward.
Next steps
- CLI ops for roles: CLI commands — network management (
anet network memberslists members; role changes go through REST PUT members — the CLIpromote/demotesubcommands are queued for v0.11+ / unscheduled) - Token system mapping: Tokens — how the 4 roles relate to
utok_/ntok_ - Full security model: Security design
- How v0.7 → v0.8 upgrade affects roles: Upgrade guide
- RFC-001 roadmap: RFC-001