with span only when a
temporary block is clearer than a named function.
Multi-agent
When one logical task involves multiple cooperating agents (a Reviewer, a TestRunner, a GitHub-poster), each agent gets its own context, spans, and attributed work. They all share one Voyage, so the dashboard shows one trace for the full background agent workload.role= is the optional cohort taxonomy (“reviewer”,
“test_runner”, “source_control”, “executor”). The dashboard groups runs by
name and offers role as a categorical filter. Pass slug= (advanced) to pin
the attribution key across display renames.
Sailbox exec attribution and .wait()
Sailbox commands run as first-class Voyage evidence when they happen inside a
Voyage. Keep the agent context active around the call so the dashboard can show
which participant owned the command:
sb.exec(...) returns immediately with a request handle. For foreground
commands, call .wait() to observe completion, return code, and output tails.
If there is no active span, Sail creates an auto-span for the exec. For
foreground commands, that span closes when .wait() observes the result.
Use explicit spans for steps you want named in the product. Let auto-spans cover
low-level calls when you are migrating an existing harness and only need
attribution with minimal code changes.
Child-process attach
When the controller spawns subprocesses (e.g., a parallel test runner), the subprocess should attach to the parent’s Voyage rather than create its own. The parent exportsSAIL_VOYAGE_ID. The child calls
sail.voyage.attach(), which reads it:
child_env() returns the handoff env (SAIL_VOYAGE_ID, plus the active
agent context as the child’s SAIL_AGENT_* defaults). It returns {} when
telemetry is disabled, so the same code runs keyless.
Common cross-pattern pitfalls
- Do not complete the Voyage from inside an agent block. Call
voyage.complete()at the top level, after all agent contexts have exited. - Do not reuse a Voyage across logical tasks. One Voyage per task. If the agent does N tasks, record N Voyages.
- Do not put secrets in event payloads. Sail applies server-side redaction, but the safest pattern is to summarize or hash sensitive values before recording them.
- Do not open more than one Voyage per controller process unless you intentionally have parallel-independent tasks. The SDK has a process- global “current Voyage.” Multiple Voyages confuse implicit attribution.