Status: Design-only for TICKET-005. Do not treat this document as implementation scope.
This document narrows the approval and grant UX design that follows the Agent Control Plane spec, especially sections 6.8, 11.2, 17, and 24. It does not change code, cloud relay behavior, artifact lifecycle, or adapter contracts.
The Phase 2 runtime has a durable grants schema and TypeScript grant types:
grants.grant_idsession_id- optional
run_id capabilityoperationresource_patterneffect:allowordenysource:policy,user, orsystemconstraints_jsoncreated_at_ms- optional
expires_at_ms - optional
revoked_at_ms
That schema is present, but grants are currently dormant state. There is no live insertion path for policy, user, or system grants in the merged Phase 2 runtime.
The intended meaning remains section 6.8: a grant is a recorded capability decision scoped to a session or run. Until implementation work explicitly activates grant writes, UI must not imply that Omi already has user-managed grant records.
Live ACP approval behavior is currently handled by LegacyPermissionPolicy, not by a user-facing approval queue.
When ACP sends session/request_permission, the policy selects:
- an option with kind
allow_always, if present; - otherwise
allow_once, if present; - otherwise the first supplied option;
- otherwise a synthetic fallback option id
allow.
The runtime then immediately responds to ACP with the selected option. This preserves the high-trust legacy behavior required by section 17.
The policy also creates an audit payload shaped as approval.resolved with:
policy: "legacy_high_trust"adapterId: "acp"- the ACP
requestId, when supplied optionIdoptionKindautomatic: true
That audit payload is logged, but it is not currently appended as a canonical kernel event and does not create a grant row. Therefore approval.resolved is live as policy audit behavior, not yet live as persisted ACP event state.
legacy_high_trust names the temporary policy mode that auto-resolves ACP permission prompts. It is policy identity and UX copy must not present it as an end-user trust grant.
legacy_default is a retired database provenance value, not a valid source for
new grant writes. Older runtimes may parse it only long enough to migrate an
existing row into revoked history. legacy_high_trust remains the temporary
policy mode name and does not imply a stored grant.
- Make approval state visible without claiming dormant grants are already active.
- Keep all approval decisions inside a policy module.
- Keep runtime adapters as request emitters, not approval authorities.
- Provide event shapes that fit section 11.2 without adding an approvals table.
- Avoid broad ACP trust defaults for Hermes, OpenClaw, A2A, AgentVM, or future adapters.
Approval UI should project from kernel events and policy decisions:
| State | Meaning | User action |
|---|---|---|
not_required |
The action is covered by policy and needs no user prompt. | None. |
auto_allowed_legacy |
ACP was auto-approved by legacy_high_trust. |
Optional audit details only. |
requested |
A policy module requires explicit user input. | Allow or deny. |
allowed_once |
User allowed this request for the current run or attempt. | None. |
allowed_for_session |
User allowed matching requests in this session under constraints. | May revoke later. |
denied |
User denied the request. | Retry only if the agent asks again with changed context. |
expired |
A prior allow no longer applies. | Re-prompt if needed. |
revoked |
User or system removed an existing grant. | Re-prompt if needed. |
failed |
The approval decision could not be applied or delivered. | Show retry or stop the run. |
The UI should show a compact action summary, the requesting adapter, the affected resource pattern, and the scope before asking. It should not expose raw ACP option labels as the primary copy.
Approval requests and resolutions remain events as required by section 11.2.
{
"type": "approval.requested",
"payload": {
"approvalId": "apr_...",
"policy": "default_user_approval",
"adapterId": "acp",
"capability": "filesystem",
"operation": "write",
"resourcePattern": "/Users/example/project/**",
"reason": "Agent wants to edit files in the current project.",
"options": [
{ "id": "allow_once", "effect": "allow", "scope": "run" },
{ "id": "allow_session", "effect": "allow", "scope": "session" },
{ "id": "deny", "effect": "deny", "scope": "request" }
],
"defaultOptionId": "deny",
"expiresAtMs": 1782240300000
}
}{
"type": "approval.resolved",
"payload": {
"approvalId": "apr_...",
"policy": "default_user_approval",
"adapterId": "acp",
"decision": "allow",
"selectedOptionId": "allow_once",
"grantId": "grant_...",
"automatic": false,
"resolvedBy": "user",
"resolvedAtMs": 1782240020000
}
}Legacy automatic ACP approvals should use the same event name when persisted, but with policy: "legacy_high_trust", automatic: true, resolvedBy: "policy", and no grantId.
When grant writes are pulled into implementation scope:
- only the policy module may create, renew, revoke, or consume grants;
- adapter code may describe a requested capability, but may not choose allow or deny;
- new writes must never use
legacy_default; any existing rows are migration-only history and must remain revoked; - user choices should use
source: "user"; - automatic non-legacy decisions should use
source: "policy"; - operating-system or managed-admin decisions should use
source: "system"; - every persisted grant write must have a paired
approval.resolvedevent in the same transaction.
Grant rows should be narrow by default. Use exact capability, operation, and resource pattern fields rather than storing generic "trusted adapter" state.
ACP may continue to opt into legacy_high_trust only as a named legacy policy.
Hermes, OpenClaw, A2A, AgentVM, and future adapters must not inherit ACP's legacy auto-approval behavior by default. Each adapter must explicitly choose a policy profile, and new profiles should start from explicit user approval or narrow policy grants.
This design does not implement:
- a new approvals table;
- grant persistence;
- Swift approval UI;
- runtime event persistence changes;
- cloud relay or cross-device approval sync;
- artifact lifecycle changes;
- broad capability generation for future standards.
Those remain implementation tickets. Section 24 still applies: a new user-facing approval UX is deferred until it is explicitly pulled into scope.