Brand consistency agent
This page explains how a brand consistency agent reads your website, help center, social profiles, marketplace listings, or CMS drafts under a read-only grant, checks cross-channel consistency against a versioned glossary and claims rules, and returns a sourced diff list. After reading it, you will understand which modules this scenario needs, how the permission boundary narrows, and where terminology rules and patrol baselines each belong.
Use case
Marketing, content, and product teams need to check multiple pages before release or on a recurring basis for brand consistency. Brand language is spread across the website, social channels, store pages, and the help center, each maintained by a different team — terminology drift and stale claims are hard to catch manually, and differences keep accumulating after channel redesigns.
Typical triggers:
- The brand glossary or claims wording changes, and existing language across all channels must be swept.
- A recurring brand patrol needs consistency spot-checks on the website, social channels, and store pages.
- A channel page is redesigned, and the changes must be verified against brand guidelines.
Engineering challenges
- Channels are scattered and evolve independently: the website, social channels, store pages, and help center are maintained by different teams, terminology drifts gradually, and manual spot checks only see single-page snapshots — never the full cross-channel picture.
- Diffs need evidence, not impressions: "this page's tone feels off" drives no rewrite; every diff must land on a concrete page, a concrete phrase, and the concrete rule it violates, or content owners have nothing to act on.
- The consistency baseline itself keeps changing: the glossary and claims wording are continuously updated, so patrol conclusions must bind to a rule version and baselines must be archived by version — otherwise two patrol cycles cannot be compared, and no one can tell new drift from an old issue.
Module composition
| Module | Role | Notes |
|---|---|---|
| GenAuth | Core | Read-only delegation, revocation, and the audit chain for CMS and channel back offices; recurring patrols run on freshly issued credentials per trigger. |
| Web Agent | Core | Controlled sessions extract text, CTAs, and visual context page by page with sources; key pages can be watched continuously with Track — change detection is driven by deterministic rules, not by model phrasing. |
| GUMem | Not used | The glossary and claims rules are versioned configuration — keep them in your policy store and inject them per version. Patrol baselines and diff conclusions are business state — archive them to your structured storage. This scenario has no user long-term preferences that belong in Memory. |
Permission and delegation boundaries
The Agent holds no inherent permissions. The effective authority for each patrol task is the intersection of three sets: what the user actually holds ∩ what was explicitly delegated for this task ∩ what the enterprise has approved. Applied to this scenario:
- The delegated scope covers only "read the selected sites, CMS collections, and channel pages" — no content editing, page publishing, or listing changes.
- Delegation credentials are short-lived; minute-level validity is recommended for a single patrol run, and recurring watches run on freshly issued credentials per trigger.
- The user or an administrator can revoke the grant at any time; new page-read requests fail immediately after revocation.
- Out-of-scope attempts (for example, a workspace outside the delegated list) are rejected and recorded — the audit chain covers all attempts, not just successful actions.
Note: the SDK example requests product-level scopes (such as webagent.do_anything:read). Fine-grained boundaries — site lists, CMS collection ranges, action whitelists — are enforced by the GenAuth Agent Profile or your policy layer, not by the task prompt; that configuration is not shown on this page. See Delegate token and attenuation for the full semantics.
Workflow
The user selects the sites, channels, or page lists to check, plus the patrol dimensions (terminology, tone, claims), and confirms the interactive authorization in Qoni Console.
GenAuth issues a least-privilege, read-only delegation credential for this task.
Your app loads the current version of the glossary, brand voice, and claims rules from the policy store and injects them into the task.
Web Agent extracts text, CTAs, and visual context from each channel page, keeping source URLs and screenshots.
Checkpoint: When a channel back office or CMS preview hits a login wall, CAPTCHA, or risk-control page, the Web Agent should escalate to a human instead of silently bypassing it.
The Agent compares channel language against the rules, flagging terminology drift, tone deviations, and stale claims, each with a page source and the triggered rule ID.
Your app validates the output contract — diffs missing a page source or rule ID are dropped — and archives this cycle's patrol baseline to your structured storage by policy version.
For key pages that need ongoing watching, Track is configured to monitor future changes by deterministic rules.
The Agent returns a diff list, rewrite suggestions, and a source list, with the policy version and an audit id.
Checkpoint: Every inconsistency in the diff list should trace back to a concrete page source; conclusions without evidence should not enter the deliverable.
Example code
The example below wires this scenario into your backend with the official Qoni SDK (@qoniai/qoni): interactive delegation (with the full callback) → load glossary and claims rules from your policy store → one doAnything.run() consumed through the events() stream → parse and validate the diff list.
import { Qoni, QoniScopes } from '@qoniai/qoni'
const qoni = new Qoni({
accessKey: process.env.QONI_ACCESS_KEY!,
secretKey: process.env.QONI_SECRET_KEY!,
})
// 1. Interactive delegation: channel back offices and CMS sign-in
// are involved — the user confirms in Qoni Console
export async function startBrandPatrol(userId: string, taskId: string) {
const { data: authorization } = await qoni.delegateToken({
mode: 'interactive',
agent: 'brand-consistency',
scopes: [QoniScopes.DO_ANYTHING_READ, QoniScopes.DO_ANYTHING_MANAGE],
redirectUri: 'https://app.example.com/qoni/callback',
state: taskId,
user: { id: userId },
expiresIn: 900, // minute-level validity for a single patrol run
})
redirectUserTo(authorization.authorizationUrl)
}
// GET /qoni/callback — after the user approves, exchange for the grant
// server-side and continue the task
export async function handleQoniCallback(request: Request) {
const query = new URL(request.url).searchParams
const { data: grant } = await qoni.completeDelegateToken({
grantId: query.get('grantId')!,
code: query.get('code')!,
state: query.get('state')!,
})
return runPatrol(grant, await loadPatrolTask(query.get('state')!))
}
async function runPatrol(
grant: { token: string; auditId: string; grantedScopes: string[] },
task: { channelPages: string[] },
) {
// 2. Before the run: load the current glossary and claims rules
// from YOUR policy store (versioned policy, not Memory)
const policy = await loadBrandConsistencyPolicy() // e.g. { version: '2026-08', glossary: [...], claimRules: [...] }
// 3. Start the cross-channel patrol: compare page by page, diff list only
const run = await qoni.doAnything.run({
token: grant.token,
prompt: `
Patrol the following channel pages: ${task.channelPages.join(', ')}.
Extract each page's text, CTAs and visual context, compare them against
the brand policy below, and return diffs as a JSON array of
{ page, diff, quote, ruleId, sourceUrl } objects.
Report only — never edit, publish or change listings.
Brand policy (version ${policy.version}):
${JSON.stringify(policy)}
`,
capture: { screenshots: true },
})
// 4. Consume the run through the event stream: forward progress and
// screenshots, escalate login walls to a human
let output = ''
for await (const event of run.events()) {
if (event.type === 'progress') appendTrace(event.data)
if (event.type === 'screenshot') broadcastScreenshot(event.image)
if (event.type === 'interaction') notifyUserActionRequired(event.data) // login walls / CAPTCHAs → human
if (event.type === 'done') output = event.data.output
}
// 5. Validate the output contract on the app side: diffs missing
// a source or rule ID are dropped
const diffs = parseDiffs(output).filter((d) => d.sourceUrl && d.ruleId)
// Archive the patrol baseline to YOUR structured storage (not Memory)
await archivePatrolBaseline(diffs, policy.version)
return {
diffs,
policyVersion: policy.version,
audit: { auditId: grant.auditId, permissionBoundary: grant.grantedScopes },
}
}The output structure is a contract set by the task prompt: here it is an array of { page, diff, quote, ruleId, sourceUrl }, parsed and validated by parseDiffs on the app side, and any entry missing sourceUrl or ruleId is dropped. The SDK itself returns the generic RunResult (runId, status, output, artifacts, and so on); event type constants for events() are in QoniEventTypes.
Data and memory boundaries
This scenario touches four kinds of data; none of them needs GUMem:
- Versioned rules: the glossary, brand voice, and claims rules — managed by version in your policy store, with every diff citing a rule version.
- Business state: patrol baselines, diff lists, page screenshots — archived by policy version to your structured storage for cross-cycle comparison and traceability.
- Audit records: the delegation and behavior chain formed by
grantIdandauditId— maintained by GenAuth. - User Memory (optional): this scenario neither recalls nor writes back by default; if a genuine cross-task user preference emerges later, evaluate GUMem then.
Failure handling
| Situation | Recommended handling |
|---|---|
| Channel back-office login state expires | Suspend the task, notify the user to sign in again, and resume from the checkpoint. |
| Page structure changes break extraction | Treat it as a failure and replay the session recording; never emit diffs without evidence. |
| Request for a workspace outside the delegated scope | Reject and record it; the attempted access remains visible in the audit chain. |
| A diff lacks a page source or rule ID | App-side validation drops the entry and the diff list notes how many were dropped. |
Production notes
Do not overwrite published content automatically. Content owners should approve bulk changes. The Agent only produces diff lists and suggestions and never edits live content on any channel; diff lists should carry the policy version, and old baselines are not retroactively re-judged after the glossary changes. Patrol frequency against external channel pages should be capped to avoid load on those sites.
Next steps
- Read the Quickstart to run the shortest path for Agent identity and delegation.
- Read Authorization and browser sandbox for the security boundaries of controlled sessions.
- Continue with the Localization messaging agent for an adjacent scenario.