Feature
Add minimal token authentication plus role-gated subscriber permissions for multi-client ACP sessions.
Motivation
Once acp-mux is used from a phone, browser, remote desktop, or other companion client, every attached peer should not automatically have full control. The mux should distinguish watching, prompting, approving tool permissions, and administrative cancellation.
This is a better Hermes-first priority than broad fs/* / terminal/* compatibility because Hermes already executes tools inside the agent process. For Hermes users, the real risk is accidental or overprivileged session control from secondary clients.
Proposed roles
Suggested initial roles:
| Role |
Can view stream |
Can prompt |
Can answer permission requests |
Can cancel active turn / admin actions |
observer |
yes |
no |
no |
no |
driver |
yes |
yes |
no |
own turn only, if implemented |
approver |
yes |
no |
yes |
no |
admin |
yes |
yes |
yes |
yes |
Keep this intentionally small. More roles can come later if real clients need them.
Proposed auth shape
Prefer token-derived roles over trusting the role= query parameter.
One possible config:
{
"tokens": [
{ "name": "desktop", "token": "REPLACE_WITH_RANDOM_TOKEN", "role": "admin" },
{ "name": "phone", "token": "REPLACE_WITH_RANDOM_TOKEN", "role": "driver" },
{ "name": "wallboard", "token": "REPLACE_WITH_RANDOM_TOKEN", "role": "observer" }
]
}
Possible flag:
amux --auth-file ~/.config/acp-mux/auth.json --agent-cmd 'hermes acp'
Transport:
- Prefer
Authorization: Bearer <token> where the client can set headers.
- Allow
?token=<token> as a browser/WebSocket fallback if needed, but redact tokens from logs and debug endpoints.
- The authenticated token assigns the effective role. The query
role= value can remain a display/client hint only, or be ignored when auth is enabled.
Enforcement points
observer cannot send session/prompt or any mutating subscriber -> agent request.
driver can send session/prompt but cannot answer session/request_permission unless also allowed by policy.
approver can answer mux-fanned-out permission requests but cannot prompt.
admin can prompt, approve, and call amux/cancel_active_turn.
- Unauthorized requests receive a JSON-RPC error with a stable code/message and are not forwarded upstream.
/debug/sessions must not expose raw tokens.
Non-goals
- No OAuth.
- No user database.
- No cross-host identity/federation.
- No browser UI in this issue.
Acceptance criteria
- Tests cover missing/invalid token rejection when auth is enabled.
- Tests cover token-derived role assignment and prove a client cannot escalate by changing
role= in the URL.
- Tests prove
observer cannot prompt.
- Tests prove
driver can prompt but cannot approve a permission request.
- Tests prove
approver can approve/deny a permission request but cannot prompt.
- Tests prove
admin can call amux/cancel_active_turn.
- Logs and
/debug/sessions redact or omit token values.
- README documents auth setup with placeholder tokens only.
Feature
Add minimal token authentication plus role-gated subscriber permissions for multi-client ACP sessions.
Motivation
Once
acp-muxis used from a phone, browser, remote desktop, or other companion client, every attached peer should not automatically have full control. The mux should distinguish watching, prompting, approving tool permissions, and administrative cancellation.This is a better Hermes-first priority than broad
fs/*/terminal/*compatibility because Hermes already executes tools inside the agent process. For Hermes users, the real risk is accidental or overprivileged session control from secondary clients.Proposed roles
Suggested initial roles:
observerdriverapproveradminKeep this intentionally small. More roles can come later if real clients need them.
Proposed auth shape
Prefer token-derived roles over trusting the
role=query parameter.One possible config:
{ "tokens": [ { "name": "desktop", "token": "REPLACE_WITH_RANDOM_TOKEN", "role": "admin" }, { "name": "phone", "token": "REPLACE_WITH_RANDOM_TOKEN", "role": "driver" }, { "name": "wallboard", "token": "REPLACE_WITH_RANDOM_TOKEN", "role": "observer" } ] }Possible flag:
Transport:
Authorization: Bearer <token>where the client can set headers.?token=<token>as a browser/WebSocket fallback if needed, but redact tokens from logs and debug endpoints.role=value can remain a display/client hint only, or be ignored when auth is enabled.Enforcement points
observercannot sendsession/promptor any mutating subscriber -> agent request.drivercan sendsession/promptbut cannot answersession/request_permissionunless also allowed by policy.approvercan answer mux-fanned-out permission requests but cannot prompt.admincan prompt, approve, and callamux/cancel_active_turn./debug/sessionsmust not expose raw tokens.Non-goals
Acceptance criteria
role=in the URL.observercannot prompt.drivercan prompt but cannot approve a permission request.approvercan approve/deny a permission request but cannot prompt.admincan callamux/cancel_active_turn./debug/sessionsredact or omit token values.