Skip to main content

Agent Patterns

An agent's capability is decided entirely by the permissions on the credential it carries. Designing one is therefore mostly deciding what to grant — and that is easier against known shapes than from a blank page.

Grant a pattern's permissions and the agent can do that job and nothing else.

Two permissions are not the ones you would guess

A "read-only" agent provisioned with entity.read alone cannot count records and cannot detect duplicates, because neither operation reads an entity:

  • Counting is a statistics operation and needs statistics.read.
  • Duplicate detection runs the matching engine and needs entity.match.

Both fail closed, so the symptom is a refusal rather than a wrong answer — but it is a confusing refusal if you believed reading was all you had granted.

Choosing a pattern​

PatternAnswersChanges data
Read-only analyst"What is in here, and how good is it?"No
Duplicate triage"Are these two the same, and should they be joined?"Yes
Bulk loader"Get this batch in, and tell me what failed."Yes
Privacy responder"Someone exercised a data right — action it."Yes

The patterns compose. An agent may hold any combination; the permissions simply add up.

Read-only analyst​

Reads and reports. Cannot change anything, because none of these permissions grant a write.

OperationAnswersPermission
countEntitiesHow many records of a type existstatistics.read
searchEntitiesWhich records match this text or attributesearch.read
getEntityOne recordentity.read
getEntity360One record with its sources, history, and relationshipsentity.read
listRelationshipsHow records connectentity.relationship.read
getDqScoreThe quality score behind a recorddq.score.read
listAuditEntriesWhat changed, and who changed itaudit.read

Masking matters most here: a value the operator may not see is masked before the agent receives it, so the agent cannot report it even if asked directly.

Duplicate triage​

Works the clerical review queue — the pairs the engine scored as probable but not certain. See reviewing potential matches for what a reviewer is actually deciding.

OperationDoesPermissionClass
findDuplicatesFinds probable duplicates of one recordentity.matchRead
listPotentialMatchesReads the review queuepotential-match.readRead
getPotentialMatchReads one pair and its scoringpotential-match.readRead
confirmMatchConfirms a queued pair and joins the recordsentity.merge + potential-match.resolveEdit
rejectMatchRecords that a pair is not a matchpotential-match.resolveEdit
snoozeMatchDefers a pair without deciding itpotential-match.resolveEdit
markNotAMatchExcludes a pair from future scoringentity.read + potential-match.resolveEdit
mergeEntitiesJoins records directly, outside the queueentity.merge + entity.readDestructive
unmergeEntitiesReverses a merge, restoring what was absorbedentity.unmerge + merge-history.readDestructive

Resolving a queued pair and merging directly are different permissions. An agent can be allowed to work the queue — where the engine has already proposed the pair and a person can audit the decision — without being able to join two arbitrary records it chose itself.

Bulk loader​

Loads batches and reports on them. The load itself runs asynchronously, so the agent submits and then polls.

OperationDoesPermissionClass
createBulkJobSubmits a batchbulk-job.createDestructive
getBulkJobReports progressbulk-job.readRead
getBulkJobResultsReports what succeeded and what failedbulk-job.readRead
cancelBulkJobStops a running jobbulk-job.cancel + bulk-job.readEdit

Submitting counts as destructive because the size of the change is not apparent from the call — one submission may touch a single record or a million.

Privacy responder​

Handles data-subject requests and consent. Grant it narrowly.

OperationDoesPermissionClass
listDsrsReads outstanding requestsdsr.readRead
createDsrRecords a new requestdsr.create + entity.readEdit
updateDsrStatusMoves a request through its statesdsr.updateEdit
fulfillDsrExecutes the request, including erasuredsr.updateDestructive
listConsentRecordsReads what a subject has consented toconsent-record.readRead
withdrawConsentRecordWithdraws a consent-basis recordconsent-record.updateEdit

An erasure request revokes every consent-basis record for the subject while retaining those held under another lawful basis — a correct outcome, and not one to discover after the fact.

What every pattern shares​

BehaviourApplies to
Two calls to change anything. Every write is a preview, then a separate confirmation carrying a single-use token. The model cannot produce that token itself.All mutating operations, always
The permission is checked on the second call too. Confirming does not bypass anything.All mutating operations
getMe needs only me.read. An agent can always report its own effective permissions — including what it lacks.Every pattern
Masking is applied before the agent sees the value. There is no unmasked surface to reach for.Every pattern

The Class column is a signal to the client. Read operations change nothing. Edits are reversible. Destructive operations are flagged so a well-behaved client asks a human before proceeding — but that prompt is a client-side courtesy, and a client configured permissively may skip it.

Keep the two apart when you reason about risk. The prompt can be turned off; the two-call contract and the permission check are enforced by the endpoint and cannot be. An agent configured to approve everything is still an agent that can only do what its permissions allow.

Provisioning an agent​

StepWhat you do
1Decide the pattern, and read off the permissions its tables list
2Create a role holding exactly those, and nothing else
3Assign it to the credential the agent will carry — a person, or a system token if the agent runs unattended
4Ask the agent what it can do. getMe reports its effective permissions, so you verify the grant rather than assuming it

Step 4 catches both surprises above in a single call.

Discovering the full set​

These are representative operations, not the complete catalog. The endpoint publishes its own tool list, each entry naming what it does and the permission it requires. Query it rather than copying the operations into your own configuration.

Next​