Docs menu

Guard on Traza Cloud

Guard is the engine’s run fuses, running on your project’s cell. This page covers what Traza Cloud adds around them; the model itself (runs, usage, verdicts, what is durable) is in the engine’s run fuses guide.

Policies

A policy holds the runs of one service to a set of limits. Create, list and delete them with a full key, or in the console’s Guard tab:

curl -s https://api.trazadb.com/v1/fuses/policies \
  -H "Authorization: Bearer $TRAZA_API_KEY" \
  -d '{"name": "support", "match": {"service": "support-agent"},
       "limits": {"max_cost_usd": 2.0, "max_steps": 40, "max_repeats": 4, "max_error_streak": 3},
       "action": "stop"}'

A run gets the policy whose match.service is the service of its first span; else your project’s policy named default, which takes no match; else the cell’s global policy. Create a default policy so no run of yours depends on the cell’s defaults. Limits do not inherit: set every limit you want on the policy you mean.

max_cost_usd counts cost your spans carry in llm.cost_usd (or gen_ai.usage.cost). If your instrumentation does not meter cost, hold runs to max_tokens instead.

Predictive limits

A policy may also hold a run to its odds: min_success_odds stops (or warns) a run whose path has historically failed, judged by the upper bound of a 95% interval over at least 30 earlier runs of its agent that took the same path. See Foresight on Traza Cloud. And max_handoff_cycles stops a run whose agents keep handing control straight back to each other; see Steer.

Ask before each step

The check is the only surface that refuses a step before it runs. Call it from your agent loop, a framework hook or a tool wrapper, with an estimate of the next step if you have one. Any key can ask, ingest included.

import os, httpx

def may_continue(run_id: str, est_cost_usd: float = 0.0, tool: str | None = None) -> bool:
    nxt = {"est_cost_usd": est_cost_usd} | ({"tool": tool} if tool else {})
    r = httpx.post(
        "https://api.trazadb.com/v1/fuses/check",
        headers={"Authorization": f"Bearer {os.environ['TRAZA_API_KEY']}"},
        json={"run": run_id, "next": nxt},
        timeout=5,
    )
    r.raise_for_status()  # an error is not a verdict: decide whether to fail open or closed
    verdict = r.json()
    if verdict["verdict"] == "stop":
        raise RuntimeError("; ".join(verdict["reasons"]))
    return True

A stop is a 200: the verdict is the answer. An error response means Guard could not decide (for example, a very long run it could only partly rebuild), so choose deliberately whether your agent stops or proceeds.

A check that names the next step ("next": {...}) also delivers the run’s pending nudges, once, in its nudges field: words a person queued for the agent, or a block that answers stop. Hand them to your agent; see Steer.

Stop and approve

  • Kill switch: POST /v1/fuses/runs/{run}/trip with an optional {"reason": "…"} stops a run at once, whatever its usage. The console’s Guard tab and Mission Control have it on every run, and so do push notifications and Slack alerts.
  • Approve to continue: POST /v1/fuses/runs/{run}/reset clears a stop. It does not refill cumulative usage, so a run over its cost limit stops again; pass {"grant": {"max_cost_usd": 5}} to raise that run’s limits.

Both need a full key. A run id containing / travels as %2F.

Alerts

In the console, under Alerts, add destinations and rules.

Event When
fuse.stop A policy stopped a run
fuse.warn A run entered warn (80% of a limit, or a limit under a warn policy)
fuse.manual_stop Someone pulled the kill switch
quota.warning The organization used 80% of its period’s spans
quota.capped The organization reached its cap and ingest paused
billing.payment_failed A payment failed

A rule can cover every project or one. Destinations depend on the plan (see pricing): email and push to your own devices on every plan, Slack and webhooks from Pro. Rules can also follow a run’s foresight reaching likely_failure (Foresight). Send test on a destination delivers a sample at once, and the delivery history lists it with what the destination answered. Failed deliveries are retried with exponential backoff, from 30 seconds up to six hours apart, for up to ten attempts.

Each event is delivered once per rule, and a rule is unique per event, project and destination; an organization can have up to 200 rules. If 1,000 deliveries are already waiting for an organization (a destination that is down or slow while many runs stop), new fuse alerts for it are skipped until the queue drains; quota and billing alerts are always sent. The delivery history keeps 30 days, up to the newest 10,000 deliveries.

Email carries the run, the verdict and a link to it in the console. Push notifications carry Approve, Kill and Open, each with a one-time token that expires after 15 minutes; see Steer. Slack messages carry the run, verdict, reasons and usage, with Approve, Kill and Nudge… buttons once the Traza app is installed; see Steer.

Webhooks

A webhook delivery is a JSON POST:

{"id": "dlv_…", "type": "fuse.stop", "created_at": …, "org": …, "project": …, "data": {…}}

type is the event from the table above and data carries the event: for a fuse event, the run, its verdict, reasons and usage.

Each delivery carries a Traza-Signature: t=<unix seconds>,v1=<hex> header, where v1 is the HMAC-SHA256, keyed with the destination’s secret, of the timestamp, a ., and the raw body. Verify it before trusting the payload:

import hashlib, hmac, time

def verify(secret: str, header: str, body: bytes, tolerance_s: int = 300) -> bool:
    fields = dict(part.split("=", 1) for part in header.split(","))
    t, sig = fields.get("t", ""), fields.get("v1", "")
    if not t.isdigit() or abs(time.time() - int(t)) > tolerance_s:
        return False
    want = hmac.new(secret.encode(), t.encode() + b"." + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(want, sig)

Webhook and Slack URLs must be HTTPS and may not resolve to private, loopback or link-local addresses.

Claude Code

The engine’s hook pack turns every Claude Code tool call into a guarded step. See Claude Code.