ANTIGRAVITY LABJP
Articles/Agents & Manager
Agents & Manager/2026-04-26Advanced

Designing Antigravity Agent Traces That Tell You Why It Failed — Observability in Practice

Run Antigravity agents long enough and unreadable failure logs pile up fast. This piece walks span structure, attribute design, failure tagging, dashboards, cost visibility, and retry policy — backed by six months of production metrics — so you can cut post-incident debugging time in half.

Antigravity322agents124observability17tracing3operations22OpenTelemetry

Premium Article

It took six months of running Antigravity agents in production for the first piece of operational debt to show: failure traces I could not read. Early on I sprinkled console.log calls across the agent loop, and when execution volume was a few dozen runs per day I could scroll. Once it crossed a few thousand runs per month, errors were happening but I could no longer tell which step of which cycle had broken.

After six months of investing in observability I am at the point where three lines of a trace usually point at the cause. Mean time to resolution (MTTR) for incidents dropped from 47 minutes pre-instrumentation to 11 minutes today. This article shares the trace design I run against my own Antigravity agents — span structure, attributes, failure tagging, dashboards, and retry policy — at a level of detail you can copy into your own repo.

Having shipped mobile apps since 2014, I remember it taking three months on my first wallpaper app to make production crash reports actually readable. Instrumenting agents was the same job in a new costume.

Why agents fall into the "I cannot tell why it failed" hole

The patterns I have observed cluster into three causes.

First, fuzzy step boundaries. Agents cycle through "tool call → LLM inference → state update," and without logging that boundary you cannot tell which step of which cycle blew up. Time-stamped flat logs hide the cycle structure.

Second, opaque inputs and outputs. Teams log "what happened inside the LLM call" but not the context passed in or the raw response returned. Failures collapse into "the LLM said something weird" and become unreproducible.

Third, no failure taxonomy. Errors are logged, but you cannot tell after the fact whether the failure was retryable, deserved a user notification, or was a plain code bug. That triggers alert fatigue and broken retry policies.

Observability design is about wiring structure for these three up front.

The base unit of a trace — pick a span structure

I align with OpenTelemetry semantics and represent agent execution like this. The shape is generic, not Antigravity-specific, but inserting a "cycle" level matters.

- agent.run               (root span — one full agent execution)
  - agent.cycle           (a single reasoning + execution cycle)
    - agent.plan          (LLM picks next action)
    - agent.tool_call     (tool execution — separate span per call)
    - agent.observe       (folding the tool result back into context)
  - agent.cycle
    - ...

Making agent.cycle its own span is the load-bearing decision. When an agent runs eight cycles and fails on the fifth, without cycle-level spans a human has to walk the log to recover the fact that "cycle five hit a tool error."

Implementing this is just wrapping the cycle in tracer.start_as_current_span("agent.cycle"). In Python:

from opentelemetry import trace
from opentelemetry.trace import Status, StatusCode
 
tracer = trace.get_tracer("antigravity.agent")
 
def run_agent(task):
    with tracer.start_as_current_span("agent.run") as run_span:
        run_span.set_attribute("task.id", task.id)
        run_span.set_attribute("task.kind", task.kind)
        run_span.set_attribute("agent.policy", task.policy_name)
        run_span.set_attribute("agent.tools_available", list(task.tools))
 
        for cycle_idx in range(MAX_CYCLES):
            with tracer.start_as_current_span("agent.cycle") as cycle_span:
                cycle_span.set_attribute("cycle.index", cycle_idx)
 
                try:
                    action = plan_next_action(task)
                    if action is None:
                        cycle_span.set_attribute("cycle.terminated", True)
                        run_span.set_attribute("result.status", "success")
                        return success(task)
 
                    result = execute_tool(action)
                    observe(task, result)
                    cycle_span.set_attribute("cycle.action_type", action.kind)
                except AgentError as e:
                    cycle_span.set_status(Status(StatusCode.ERROR, str(e)))
                    cycle_span.set_attribute("result.failure_class", e.failure_class)
                    run_span.set_attribute("result.status", "failure")
                    run_span.set_attribute("result.failure_class", e.failure_class)
                    raise

In TypeScript (Node.js) with @opentelemetry/api the same structure looks like:

import { trace, SpanStatusCode } from "@opentelemetry/api";
 
const tracer = trace.getTracer("antigravity.agent");
 
export async function runAgent(task: Task): Promise<Result> {
  return await tracer.startActiveSpan("agent.run", async (runSpan) => {
    runSpan.setAttribute("task.id", task.id);
    runSpan.setAttribute("task.kind", task.kind);
    runSpan.setAttribute("agent.policy", task.policyName);
 
    try {
      for (let cycleIdx = 0; cycleIdx < MAX_CYCLES; cycleIdx++) {
        const done = await tracer.startActiveSpan(
          "agent.cycle",
          async (cycleSpan) => {
            cycleSpan.setAttribute("cycle.index", cycleIdx);
            const action = await planNextAction(task);
            if (action === null) {
              cycleSpan.setAttribute("cycle.terminated", true);
              return true;
            }
            cycleSpan.setAttribute("cycle.action_type", action.kind);
            const result = await executeTool(action);
            observe(task, result);
            cycleSpan.end();
            return false;
          }
        );
        if (done) {
          runSpan.setAttribute("result.status", "success");
          return success(task);
        }
      }
    } catch (e) {
      runSpan.setStatus({ code: SpanStatusCode.ERROR, message: String(e) });
      runSpan.setAttribute("result.failure_class", classify(e));
      throw e;
    } finally {
      runSpan.end();
    }
  });
}

One catch: always set cycle.index on agent.cycle. You will end up writing the query "show me what happened in the third cycle."

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
OpenTelemetry-aligned four-level span structure (agent.run / agent.cycle / agent.plan / agent.tool_call) with copy-pasteable Python and TypeScript implementations
An eight-class failure_class taxonomy paired with a retry-policy and user-notification matrix you can drop into your repo today
Real production numbers from six months of operation — average cycle count 4.2 → 2.8, token consumption down 35%, MTTR 47 min → 11 min — plus three dashboard query examples
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

Agents & Manager2026-06-28
Treating Built-in Guide Skills as Design Assets, Not Throwaway Prompts
Antigravity v2.2.1 added built-in Guide skills. Here is a concrete structure and set of judgment calls for running them as version-controlled, shared design assets instead of one-off instructions.
Agents & Manager2026-06-27
Keep a Tamper-Evident Audit Log of Your Autonomous Agent's Actions
To record the decisions and actions an Antigravity agent takes autonomously in a form you can trace and verify later, design an append-only audit log whose hash chain detects tampering. Includes the implementation.
Agents & Manager2026-06-17
Tracing Parallel Agents After the Fact: Observability with Structured Logs and Spans
Running multiple agents in parallel on the Antigravity 2.0 desktop makes it impossible to tell which one is doing what. I share an observability design that drops tangled print debugging for run_ids and spans you can trace afterward, with a solo-operator implementation and numbers.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →