intentframe.org
In practice

Use cases

Six deployments where agents already run in production, and what changes when the request between them carries structure rather than prose.

Each follows the same shape: the system, the failure mode it has today, and what the frame forecloses.

1Conversational and customer support agents

The system. A customer writes in. One agent reads the ticket and the account history and drafts a reply. A second agent checks the draft before it is sent. If the reply involves a refund or a policy exception, a human approves it.

The failure mode. The drafting agent holds the full account record: address, payment details, prior complaints. The prompt instructs it not to disclose personal information beyond what the customer already knows, and it usually complies. Occasionally a draft quotes the last four digits of a card, or surfaces another customer's name that arrived through a merged ticket. Detection is a complaint.

The reviewing agent is a second prompt, authored by a different engineer six months later. It evaluates tone and length. It has never evaluated the thing that actually fails.

What the frame adds. The rules governing customer-facing text stop being prompt guidance and become criteria evaluated on every draft:

frame = (aif.request("support.draft_reply")
         .objective("Draft a reply to the customer's refund question.")
         .artifact("ticket", "TCK-88213")
         .artifact("account", "ACC-40021")
         .input(tone="apologetic", channel="email")
         .output("customer_reply", sections=["Greeting", "Answer", "Next steps"])
         .require_sections()
         .max_tokens(220)
         .no_pii()                       # checked on the draft, not asked of the model
         .criterion("must_include_phrases", phrases=["TCK-88213"])
         .criterion("must_exclude_patterns", patterns=["credit_card"],
                    label="card numbers", advertise=False)
         .review(["support.compliance_check"])
         .retries(2)
         .build())
flowchart TD
    T["Ticket + account record"] --> DR["support.draft_reply"]
    DR --> SC{"Output scan"}
    SC -- "card number found" --> RP["Repair note<br/>back to the model"]
    RP --> DR
    SC -- "no PII found" --> CR{"Contract"}
    CR -- "section missing" --> RP
    CR -- passes --> RV["support.compliance_check"]
    RV --> OUT["Sent to the customer"]
    class T context
    class DR model
    class SC,CR check
    class RP orchestrate
    class RV enforce
    class OUT ok
The scan runs before the reviewer, not afterA draft carrying a card number never reaches the reviewing agent. It returns to the drafting model with the specific violation, so the compliance step only ever sees drafts that already passed the mechanical checks.

A draft leaking a card number never reaches the customer, and never reaches the reviewing agent either. It returns to the drafting model carrying the specific violation, and the second attempt typically clears.

The enterprise angle

At support volume these agents execute thousands of times daily. At that scale a compliance rate is a forecast of incident count, not a question of whether incidents occur. Relocating the check into code converts a rate into a zero.

2DevOps and SRE agents

The system. An alert fires. A triage agent reads the alert, the recent deploys, and the dashboards, and proposes what is wrong. A second agent proposes a fix. Depending on the fix, something either applies it or pages a human.

The failure mode. This is where prompt-only constraints are most dangerous, because the agents hold real credentials. The triage agent is nominally read-only and its prompt says so, but it shares a Kubernetes client with the remediation agent because that was simpler to wire. Nothing but prompt wording separates "investigate this alert" from a production rollback at 03:00.

The uncomfortable question: if the triage agent elected to restart a deployment right now, what would prevent it? On most systems the honest answer is that nothing would — it was asked not to.

What the frame adds. Read and write become distinct intent types with distinct tool grants, enforced at admission:

# Investigation: read-only, and the runtime enforces it
triage = (aif.request("sre.triage")
          .objective("Explain why checkout latency alerted at 02:14.")
          .artifact("alert", "ALT-99120")
          .input(service="checkout", window_minutes=45)
          .output("triage_note", sections=["What changed", "Likely cause", "Evidence"])
          .require_sections()
          .limits(tools=["metrics.read", "deploys.read", "logs.read"])
          .min_confidence(0.7)
          .build())

# Remediation: a different job, and only a trusted one may hold write tools
fix = (aif.inform("sre.remediate")
       .objective("Roll back checkout to the previous release.")
       .input(service="checkout", target_release="v2026.31.4")
       .output("action_receipt", sections=["action", "result"])
       .require_json(["action", "result"])
       .limits(tools=["k8s.write"])
       .build())
flowchart TD
    AL["Alert fires"] --> TR["sre.triage<br/>intent: request"]
    AL --> RM["sre.remediate<br/>intent: inform"]
    TR --> TG{"Privileged?"}
    RM --> RG{"Privileged?"}
    TG -- "no · asked for k8s.write" --> RF["TOOL_ESCALATION<br/>0 attempts · $0 spent"]
    TG -- "yes · read tools only" --> TOK["metrics.read<br/>deploys.read · logs.read"]
    RG -- "yes · on the privileged list" --> ROK["k8s.write granted"]
    TOK --> AN["Triage note<br/>confidence floor 0.7"]
    AN -- "below floor" --> HU["Escalate to on-call human"]
    AN -- "at or above floor" --> RM
    class AL context
    class TR,RM route
    class TG,RG enforce
    class RF refusal
    class TOK,ROK orchestrate
    class AN check
    class HU model
Read and write are different capabilitiesThe triage path cannot acquire write tools regardless of what its frame requests, because sre.triage is absent from the privileged set. The confidence floor is the second gate: a note the model holds at 40% never becomes the basis for a rollback.

A triage frame listing k8s.write is refused with TOOL_ESCALATION before any model is invoked — not because the model behaved well, but because sre.triage is absent from the set of privileged capabilities.

The confidence threshold matters here too. A triage note the model holds at 40% confidence should not silently become the basis for a rollback; it fails its criterion and escalates to a human.

The enterprise angle

This is the deployment that gets agent programmes cancelled after one bad night. Evidence that write access was structurally unavailable to the investigating agent is frequently the difference between a security review that passes and one that does not.

3Code review and engineering agents

The system. A pull request opens. One agent summarises the change. Another reviews it against the team's standards. A third may write tests.

The failure mode. The reviewing agent is frequently the same model at the same settings that produced the code. It is grading its own output and approves accordingly. Teams observe that reviews are uniformly agreeable and stop reading them, at which point the agent costs money and contributes nothing.

Nor is there any record of what the review was meant to cover. "Review this PR" yields whatever the model finds salient that day.

What the frame adds. Review is a verify frame, which the runtime dispatches differently: an independent model, temperature pinned to zero, no tool grant, and a strict validation pipeline.

review = (aif.verify("eng.review_pr")
          .objective("Review this change against the team's standards.")
          .input(diff=diff_text, pr_number=4471)
          .artifact("standards", "eng-standards-v4")
          .output("review", sections=["verdict", "blocking", "non_blocking", "evidence"])
          .require_json(["verdict", "blocking", "non_blocking", "evidence"])
          .criterion("max_assumptions", limit=2)
          .limits(cost_usd=0.05)
          .build())

A review returning without evidence, or carrying unresolved assumptions past the declared limit, fails validation and retries against the finding. And because the standards live in an artifact rather than a prompt, revising them is a single change every subsequent review picks up.

4Regulated document generation

The system. Banking, insurance, healthcare, legal. An agent drafts something that will be read by a client, a regulator, or a patient: a suitability letter, a claims summary, a discharge note.

The failure mode. These teams frequently cannot ship agents at all, and the blocker is not model quality. It is that the compliance questions have no answer. Was the source data classified? Who reviewed the output? What was the model given? For this specific document produced eight months ago, which controls were in force?

A prompt log answers none of these convincingly, because it is an undifferentiated body of English in which the controls were never separable from the request.

What the frame adds. Classification becomes a field with consequences. Marking material Confidential causes the runtime to require a named reviewer, refuse external upload, and record both:

letter = (aif.request("advice.suitability_letter")
          .objective("Draft a suitability letter for the recommended portfolio change.")
          .artifact("client_profile", "CLI-3391")
          .artifact("policy", "suitability-rules-2026-q2")
          .classify("Confidential")          # triggers mandatory review
          .output("suitability_letter",
                  sections=["Recommendation", "Why it suits you", "Risks", "Costs"])
          .require_sections()
          .criterion("must_include_phrases", phrases=["capital at risk"])
          .no_pii(patterns=["ssn", "credit_card"])
          .min_confidence(0.85)
          .review(["compliance.review", "advisor.signoff"])
          .retries(1)
          .build())

A Confidential frame naming no reviewer is refused with REVIEW_REQUIRED. The result frame carries which criteria ran, which passed, how many attempts were required, and which policy artifact was in force. That record is the audit trail, produced as a by-product of execution rather than reconstructed afterwards from logs.

The enterprise angle

In regulated industries the question is rarely whether the model can write the document. It is whether you can evidence how it was written. Structured requests make that evidencable, which is frequently what unblocks the programme.

5Data and analytics agents

The system. Someone asks a question in plain English. An agent writes SQL, runs it, and explains the result.

The failure mode. Two, both expensive. The agent emits a query scanning a year of event data at a cost of several hundred dollars, because nothing capped it. Or it connects with write-capable credentials and a generated statement does something unintended.

A subtler failure also recurs: the agent answers confidently from a table deprecated last quarter, and nobody notices because the answer is plausible.

What the frame adds. Budgets and tool grants are enforced before the query is generated, rather than discovered on the invoice:

query = (aif.request("analytics.answer")
         .objective("Which regions missed their delivery SLA last month?")
         .artifact("schema", "warehouse-schema-v12")
         .input(question=user_question, max_rows=5000)
         .output("analysis", sections=["Answer", "Query used", "Caveats"])
         .require_sections()
         .limits(cost_usd=0.25, tools=["warehouse.read"])
         .criterion("must_exclude_patterns",
                    patterns=[r"DROP|DELETE|UPDATE|INSERT"],
                    label="write statements", advertise=False)
         .min_confidence(0.7)
         .build())

The write-statement check is withheld from the model deliberately. Instructing it not to emit DROP is the advisory version; scanning the output is the control, and it also catches the case where the model quoted a table name containing the token.

6Back-office document processing

The system. Invoices, claims, purchase orders, KYC packets. An agent reads a document and produces structured data for a downstream system.

The failure mode. These pipelines run at volume and fail quietly. The model returns near-valid JSON, hallucinates a field, or reads 1,800 as 18,000 with full confidence. Downstream systems accept it because nothing validated it. The error surfaces weeks later during reconciliation.

What the frame adds. A structural contract, plus a confidence floor routing uncertain extractions to a human queue rather than into the ledger:

extract = (aif.request("ap.extract_invoice")
           .objective("Extract the payable fields from this invoice.")
           .artifact("scan", "INV-2026-114872")
           .output("invoice_record",
                   sections=["supplier", "invoice_number", "currency",
                             "line_items", "total"])
           .require_json(["supplier", "invoice_number", "currency",
                          "line_items", "total"])
           .criterion("must_match", pattern=r"\"currency\":\s*\"[A-Z]{3}\"",
                      label="ISO currency code")
           .min_confidence(0.9)
           .retries(1, on_failure=["RouteToHumanQueue"])
           .build())

Below 90% confidence the document routes to human review rather than accounts payable. That is a business rule, and it now lives in the frame rather than in an engineer's recollection of how the pipeline is meant to behave.

At volume this also yields the metric that matters: straight-through processing rate. Segment it by supplier and the formats requiring work identify themselves.

7How this rolls out in an organisation

The technical adoption is modest. The organisational fit warrants more planning, because structured requests let three groups own three separable concerns without contention.

WhoOwnsChanges without asking anyone
Platform teamThe policy: cost ceilings, which jobs may use write tools, which classifications need reviewTighten a limit across every agent at once
Product teamsThe requests: what each job asks for and what counts as a good answerChange a prompt or a check without touching policy
Security and complianceClassification rules and required reviewersAdd a review requirement without editing any prompt
Whoever is on callNothing newReads structured refusals instead of guessing from logs
flowchart LR
    subgraph PT["Platform team"]
        P1["Cost and token ceilings"]
        P2["Privileged capabilities"]
    end
    subgraph SEC["Security and compliance"]
        S1["Classification rules"]
        S2["Mandatory reviewers"]
    end
    subgraph PD["Product teams"]
        D1["Objective and inputs"]
        D2["Acceptance criteria"]
    end
    P1 --> POL["Deployment policy"]
    P2 --> POL
    S1 --> POL
    S2 --> POL
    D1 --> FR["The frame"]
    D2 --> FR
    POL --> ADM{"Admit?"}
    FR --> ADM
    ADM --> RUN["Execution"]
    class P1,P2 enforce
    class S1,S2 context
    class D1,D2 model
    class POL enforce
    class FR route
    class ADM check
    class RUN ok
Three owners, one enforcement pointEach group changes its own column without coordinating with the others. A requirement such as "customer-facing text must never contain card numbers" becomes one check in one place, rather than a line every team adds to every prompt.

This separation is the substantive enterprise argument. Today a requirement such as "customer-facing text must never contain card numbers" propagates into every prompt owned by every team, and is verified by reading all of them. With frames it is one check in one location, and a frame omitting it can be refused outright.

7.1 A realistic first month

Week one — pick one handoff

Select the agent-to-agent boundary generating the most incidents. Express what an acceptable result looks like as typed checks. Expect to discover the question was never settled.

Week two — add limit checking

Encode your real ceilings in policy and run production traffic through the layer in report-only mode. You will surface frames that were succeeding by luck.

Week three — turn on refusals

Begin enforcing. Refusals carry typed violations, so remediation is mechanical.

Week four — look at the numbers

Retry rate by intent type, refusal rate by policy rule, cost by capability. This is typically where someone identifies a criterion failing most of the time and concludes the requirement itself was unrealistic.

8Patterns worth reusing

The same handful of patterns recur across all six.

PatternWhat it doesWhere it showed up
Read and write are different jobsAn investigating capability is structurally incapable of mutationDevOps, analytics
Hidden output scanCatches what prompt instruction cannot: content copied verbatim from the sourceSupport, regulated documents, analytics
Confidence floorRoutes low-confidence output to human review rather than downstreamBack-office, DevOps
Independent checkerA verify frame dispatches to a different model, so it is not grading its own outputCode review, support
Rules as artifactsStandards and policies are dereferenced rather than inlined, so revision is a single changeCode review, regulated documents
Classification with consequencesClassification triggers mandatory review and blocks external uploadRegulated documents

None of these require adopting all of IntentFrame. Each is worth applying independently, at a single boundary.

How to build it → · Python library → · Specification →