Platform Platform
System
ConceptsEnginePolicy as codeDeclarationsSafe changeGatewaysIntegrationsObservabilityAdministrationSecurityHuman reviewAudit and evidenceData retentionSecrets and data classification
Controls
Registries and documentationAuthentication and authorizationInjection detectionData redactionCode fingerprintingRole and judge checksContent classificationSpend and loop limitsBusiness rules
Solutions Solutions
By what you do
Sell into the enterpriseControl the AI you run
By industry
Financial servicesDigital assetsInsuranceHealthcareLegalUser-generated content
By discipline
AI governanceTrust and safetyRisk and compliance
Cases Cases Embedded control planeSource-code leakTrading agents over MCPLive firehoseRefund assistant
Compare Compare LiteLLMNVIDIA NeMo GuardrailsOPAROOSTAgent Governance Toolkit
Resources Resources
Guides
Enterprise review questionsPrompt injectionAgent and control layerAgent architecturesDecision system mapAI control maturity model
Standards
Standards OWASP Agent Control StandardEU AI ActPMI AI standardNIST AI RMFERC-8004
Book a demo
Platform · Controls

The agent that cannot stop, and the invoice that follows.

A rule counts what each agent calls and spends, and acts when it reaches the limit you set.

You write these as rules. A changed rule goes live when you promote it, without redeploying Swiftward.

The whole control

YAML, versioned, backtestable
# Without exists, an undeclared ceiling reads as zero and refuses everyone.
rules:
  record_agent_spend:
    all:
      - path: "event.type"
        op: eq
        value: "llm.completed"
      - path: "event.data.cost_nano"
        op: exists
      - path: "event.data.agent.id"
        op: exists        # no agent, no bucket to add it to
    effects:
      verdict: approved
      priority: 1
      state_changes:
        agent:
          change_buckets:
            spent_hour: "{{ event.data.cost_nano }}"
            spent_day: "{{ event.data.cost_nano }}"

  agent_spend_ceiling_day:
    all:
      - path: "event.type"
        op: eq
        value: "llm.input"
      - path: "event.data.agent"
        op: exists
      - path: "event.data.agent.ceiling_day"
        op: exists
      - path: "state.agent.buckets.spent_day"
        op: gte
        value: "{{ event.data.agent.ceiling_day }}"
    effects:
      verdict: rejected
      priority: 100
      response:
        reason: "Refused. This agent has reached the ceiling declared for it today."

The numbers are not in the rule. The ceiling is set on the agent record, because it differs per agent, changes from week to week, and is set by someone in finance or security. So changing one agent's budget needs no new ruleset version.

The rule is named and versioned. You can backtest it and run it in shadow, and every decision it makes is recorded. The limit can differ for each customer. A hundred lines of gateway code gives you none of that.

What you can count

You choose what is counted, and per what: calls per agent per hour, dollars per tenant per day, tool calls per task, retries against the same failing endpoint.

The limit does not have to be a hard stop: slow the agent down, route the next call to a person, drop to a cheaper model, or refuse. One agent can carry several limits: warn at half, hand to a human at three quarters, stop at the ceiling.

How the accounting works

The counter sits in the path of every call, so a ceiling stops the next one. A call already running completes, and its cost is recorded when it closes.

Where the calling code names its own agent and you do not control that code, this is a spend control over a caller who cooperates, not a security control over a hostile one. For a hostile caller the control is authorization.

Why the loop is the dangerous half

A runaway agent is rarely one expensive call. It is a cheap call repeated faster than anyone is watching, and what usually ends it is the bill, or a downstream service that starts refusing. A counter on a dashboard someone reads on Monday is too late.

Related: business rules · agents that trade
Book a demo