Repository navigation
Let agents organize credentials and groups in one approved batch #162
Description
Goal
Add an MCP tool organize_credentials that applies a batch of group operations (move credentials, create, rename and delete groups) as one frozen write with one approval and one system authentication.
Context
- The maintainer wants agents to help tidy the credential library. Each agent write needs its own approval and system authentication (ADR 0002), so moving credentials one by one through
modify_credentialwould mean one Touch ID per credential. - Builds on the metadata writes, catalog
groupfield and ADR 0010 from Let agents set usage instructions and groups when they write credentials #161. Let agents set usage instructions and groups when they write credentials #161 merged as PR Let agents propose credential instructions and groups through approved writes #163 (01431c9). Reuse its patterns: group resolution and transactional group commit inVault+AgentWriteFreeze.swiftandVaultStore+AgentWrites.swift, and the operation-specific approval presentation inSources/AskKeyAppKit/App/FrozenWriteSummaryContent.swift, where unchanged fields appear once and Approve/Deny stay within the 680-point budget. BrokerApprovalOperationRequestbinds an approval to a single credential and target. A batch spans many credentials and the group list, so the approval shape needs a design decision (Step 1).
Executor: Codex · high. risk:security.
Decisions
- Operations, at most 64 per batch, applied in order:
{"move": {"credential": "<name>", "group": "<name>" | null}},{"create_group": "<name>"},{"rename_group": {"from": "<name>", "to": "<name>"}},{"delete_group": "<name>"}. Credentials are identified by their visible name, as inrun. - The whole batch is validated before it is frozen and commits in one transaction. If any operation is invalid, or any affected credential changes, expires or becomes Hidden before commit, nothing is applied.
- The catalog gains a top-level
groupslist: empty groups and groups with at least one visible member. A group whose members are all Hidden, or only recycled, is not listed, and agents get the generic not-found error for it. - Renaming a group moves all its members, including ones agents cannot see. Deleting a group ungroups all its members, as the App does, and deletes no credential. For both, the approval card states the affected count, for example "4 credentials, 1 not visible to agents". Renaming onto an existing group name is rejected; agents merge groups with moves.
- The approval card lists every operation in order: moves as "name: from → to", created groups, and renames and deletions with their member counts. Approval, digest, retransmission, expiry and cancellation behave as for other agent writes.
- Agents cannot change permissions or delete credentials through this tool.
Approved design (Step 1 gate, 2026-10-08)
- New
.organizeapproval operation.BrokerApprovalOperationRequestgains an optional sorted, uniqueorganizationCredentialIDsbinding (affected credentials, including Hidden and recycled members of renamed or deleted groups); single-credential requests require it nil. Organize uses an emptycredentialIDand the targetcredential-library. There is one ticket per batch and no per-member tickets. Equality and consumption include the binding, andcancelPendingmatches any member. The binding and every affected name or count stay App-side and never appear in any response to the agent. - Expiry: only credentials explicitly moved by the batch must be unexpired, and only their expiry can shorten the request deadline. Members affected only by a group rename or delete, Hidden or recycled ones included, neither block the batch nor shorten its deadline. Expiry-triggered cancellation uses a separate Broker
cancelPendingForExpiry(credentialID:). It still cancels reads and single-credential writes, but keeps an organize batch whose own deadline, derived only from moved credentials, is still valid. Only the expiry-triggered calls inVault+CredentialDelivery.swiftandVault+AgentWriteFreeze.swiftswitch to it, with no run or delivery behavior change. OrdinarycancelPendingstill matches every batch member when a credential actually changes. - The approval digest binds the ordered operations, caller data, the before and after state of affected records, and the state of the groups the batch names. It does not bind the whole group list, so unrelated App group edits do not invalidate a pending batch. One SQL transaction re-validates that state and writes records, groups and the existing idempotency receipt.
- Moves need a destination that is visible or created earlier in the batch. Renaming onto any occupied name, including a group agents cannot see, fails with the generic error. Rename and delete include recycled members, matching App group management, and the card counts them as not visible to agents.
- Access records: one
.modifyevent per affected credential, Hidden included, plus one credential-less.modifyevent for a group-only batch. Denial uses the same binding. - Card: the existing 300-point prompt with caller, details and expiry; every numbered operation in a height-capped scroll area (moves as
name: from → to, created groups, renames and deletes with total and not-visible member counts); no material reveal; Approve Organization and Deny within 680 points in English and Simplified Chinese.
Scope
May change: helper MCP definitions, parsing and guide; broker action, approval operation and summary types; vault freeze and commit for the batch; the approval card and its strings; ADR 0010 (append the approval shape); docs/features.md; the CI screenshot scenario in Tests/AskKeyE2ETests/ScreenshotE2ETests.swift, its synthetic MCP write in Tests/AskKeyTestSupport/E2EBrokerScenario.swift, and its entry in the scripts/e2e-report.py allowlist; tests in Tests/AskKeyBrokerTests/, Tests/AskKeyVaultTests/, Tests/AskKeyAppTests/.
Must not touch: run and delivery; permissions; the App's own group management UI; BrokerProtocolVersion.
Steps
- Design gate. Propose how a multi-credential write is represented in
BrokerApprovalOperationRequest, the request store and the access records, with the approval-card layout. Send it to the coordinator as an Orca question and wait for approval before writing code. - Broker types and the catalog
groupslist. - Vault: validate, freeze and commit the batch atomically.
- Helper: the
organize_credentialsschema, parsing and guide text. - App: the approval card and strings.
Acceptance
swift build
swift test --filter <changed suites>
python3 scripts/check_hygiene.py && python3 scripts/check_module_deps.py- Tests: mixed batch commits all-or-nothing; one invalid operation rejects the batch; a stale, expired or newly Hidden member fails the commit; rename to an existing name is rejected; renaming or deleting a group that includes Hidden members applies to them and the summary counts them; deleting a group deletes no credential; a hidden-only group is absent from
groupsand unknown to agents; the 64-operation limit; one approval and one authentication per batch; Allow and timed allowances do not skip approval. - CI
build-and-testandbasic-ui-flowsgreen, and the approval-card screenshot from CI is linked in the PR. The screenshot step iscontinue-on-error, so report the screenshot test's own result as well as the job result.
Blocked by
#161 (agent metadata writes).
Activity