Skip to main content
What every setting, method and field does. If you are instrumenting for the first time, start with the guide — this page is for looking things up.

Custom agents guide

Install, instrument, the event methods, a worked example, and common problems.

Using a framework?

LangChain, CrewAI, LlamaIndex and Pydantic AI instrument themselves with one call.
Python 3.10 or newer. No runtime dependencies.

Install

The package is installed as failproofai-sdk and imported in Python as failproofai_sdk. Framework extras such as failproofai-sdk[langgraph] install the framework itself; the adapters always ship in the base wheel.

Connect the Failproof daemon

  1. Go to Admin → Keys and create a key with events:add.
  2. Connect the Failproof daemon to Cloud on the agent machine.
  3. Run one instrumented session, then find its exact ID under Observe → Events.
  4. Go to Observe → Sessions, select the same environment, and open the reconstructed trace. A custom Python agent session reconstructed as an execution graph and ordered event trace.

Configuration

Set by environment variable instead:
No commas in environment. Ingest splits that field on commas to build its filters, and skips any event whose label contains one — so a whole run silently vanishes. Write prod-eu, not prod,eu.configure(environment="prod,eu") raises so you find out immediately. AGENTEYE_ENVIRONMENT cannot raise — nothing is calling you — so it warns once and falls back to dev.
Events are queued in memory and written in the background every flush_interval seconds, with a final flush at interpreter exit. A process killed outright loses whatever had not been written yet.

Identity

Every event belongs to a session and an agent. The scopes fill both in, so you rarely pass them:
Passing session_id or agent_id explicitly still works and wins. With neither bound nor passed, the call raises TypeError rather than emitting an event Cloud would quietly discard.
Identity rides on context variables. It follows asyncio tasks automatically, but not new threads — wrap a worker in failproofai_sdk.propagate() or its events land unattached.

Event catalog

Fifteen methods. Most come in pairs — you call the opener, then the closer, and the SDK times the gap. Three stand alone: error, human_pause, human_interrupt.
Every method also takes session_id and agent_id, which the scopes fill in for you. Anything left as None is dropped rather than sent as JSON null, and every method returns None.
To mark a run as failed, outcome must be one of failed, error, timeout or rejected. Anything else — including the near-miss "failure" — counts as a success.

Pairing and duration

One rule: give the closing event the same id as its opener. That is what pairs them, and what lets the SDK time the gap. Do not pass duration_ms yourself. The SDK measures it, and passing it raises ValueError. The one exception is model_response, where only you know the real provider latency. Pass a whole number of milliseconds — a float raises, because the column is a 32-bit integer and would otherwise land empty.
  • Ids only need to be unique per kind, per session. A tool call and a hook can share one; two sessions running at once can reuse the same ids without colliding.
  • They are not scoped to an agent. A pair opened under one agent and closed under another still matches — which is the normal case in multi-agent code.
  • request_id is optional but recommended. Without it, model events pair up in the order they arrive, so two concurrent calls in the same agent can mispair.
  • A pair split across processes still matches in Cloud, but the SDK cannot time it — nothing in either process saw both halves.
  • At most 10,000 openers wait for a closer at once. Past that the oldest is dropped, so a leak cannot grow without bound.

Your own fields

Any extra keyword you pass is stored with the event:
Prefer JSON types if you want to query them later. Anything else — a UUID, a datetime, a Decimal, a set, bytes, a model object — is stored as a string.
Prefix your field names. Extras are applied last, so a field called model, tool_name or outcome silently overwrites the real one. The framework adapters use fw_; do the same and nothing can collide.This is also why a misspelled optional field never errors — it just becomes a new custom field. If a standard field is missing in Cloud, check the spelling first.
These five names are reserved and rejected outright: timestamp, session_id, agent_id, type, environment.

Deliver and verify

In Observe → Events, verify agent_start exists first and agent_end exists last. Then open Observe → Sessions and confirm model, tool, human, hook, and error events appear in the intended order. Use the session ID as the primary troubleshooting key.
If Cloud is empty, inspect $FAILPROOFAI_HOME/custom-agents/events, otherwise ~/.failproofai/custom-agents/events. JSONL files prove SDK emission; a growing spool points to daemon configuration or delivery, while an empty spool points to instrumentation or process lifetime.
Inspect the spool only when the daemon is stopped. While it runs, it collects and deletes each batch within milliseconds, so a directory listing races the collector and shows far fewer events than were emitted.

Prevent failures in a custom runtime

Use audit findings and linked traces to define the unsafe action, required evidence, and intended response. A custom enforcement integration must expose the action before execution, pass its structured input to the policy engine, and apply the resulting allow, instruct, or deny decision. Contact Failproof AI and we will help map your runtime’s model, tool and lifecycle boundaries to policy hooks, then validate the integration with you.