Appearance
Logging
An executing workflow records visited nodes and ports in one output directory, together with visit artifacts and failure tracebacks. In VS Code, use Verdog: Open Run Output to inspect a run's files. Preparation errors, such as invalid workflow input, can occur before a directory is allocated.
Run directory
Runs started from VS Code create a distinct directory below .verdog/runs/<workflow>/, where <workflow> is the selected local workflow ID:
text
.verdog/runs/main/20260901T102030Z-a1b2c3d4/The directory name contains the UTC start time and a random suffix. When using the runtime API, pass an absent or empty path as output_dir:
python
from pathlib import Path
result = dispatcher.run(
definition,
input,
output_dir=Path("artifacts/countdown"),
)Verdog rejects a path that denotes a file or a non-empty directory. See the programmatic API to enable checkpointing.
Sensitive output
Run output may contain prompts, responses, authored diagnostics, and stack traces. Exclude .verdog/ and any custom output paths from version control, and review artifacts before sharing them.
Visit directories
The runtime creates a numbered directory for every node or control port reached. The root graph writes directly beneath the run directory:
text
<run>/
├── trace.log
├── enter/000001/
├── <node-id>/
│ ├── 000001/
│ └── 000002/
└── exit/000001/Visit numbers are padded to six digits and advance independently for each node within its containing output directory. The first visit starts at 000001 when no previous output exists. Repeated visits, including retries after interruption, receive unused numbers and preserve earlier output.
Graph activation directories
A called graph writes its nodes directly beneath the call node's visit directory. Both Subroutine calls and Workflow calls use the same layout:
text
<run>/call_child/000001/
├── enter/000001/
├── <node-id>/000001/
├── call_grandchild/000001/
│ ├── enter/000001/
│ ├── <grandchild-node>/000001/
│ └── exit/000001/
└── exit/000001/If an interrupted call must start its child again, it reuses the call's output scope. Each child node advances past its existing visit directories before writing output. For example, a repeated child entry gets enter/000002/:
text
<run>/call_child/000001/
└── enter/
├── 000001/
└── 000002/Resuming a child continues its recorded output directory and workflow state. Once the child's result is recorded, replay evaluates only the call adapter. Revisiting the call node in a later loop iteration creates a new numbered call visit, where child counters start at 000001 again. Child visits are recorded in the same run-level trace.log.
The generated config.md and statistics tables describe execution within each scope. Numbered node outputs and trace events retain its history; previous versions of these summary reports are not archived separately.
The parent config.md and stats.md link to child reports. Paths grow with nesting depth and remain subject to operating-system path limits. Verdog preserves existing artifact paths during resume; see Run files for checkpoint compatibility and file rules.
Statistics reports
Runtime requirement
The usage columns and report navigation described here require verdog-runtime 0.1.5 or later.
Each graph invocation writes stats.md. Its Summary table groups visits by node type and includes a total row; Nodes gives the corresponding totals for individual nodes. Both tables include Visits and Seconds, followed by:
- Agent calls: recorded agent invocation attempts. Failed and interrupted attempts count; replaying a journaled response does not add another call.
- Input tokens: total input tokens, including cached input.
- Cached input: the cached subset of input tokens. Do not add this column to
Input tokens. - Output tokens: output tokens, including reasoning tokens when reported by the provider.
- Est. USD: the estimated cost of the recorded usage in US dollars.
Token and cost cells use — when the metric does not apply: Python, Feature, enter, exit, and failure rows. Agent, Subroutine call, Workflow call, and Total rows use 0 for applicable metrics with no usage. Agent calls is always numeric, including zero for nodes that do not invoke agents.
Missing measurements are tracked separately for each applicable metric. unknown means that no measurement is available; a number followed by + ? is a known subtotal with unmeasured attempts. An unavailable cost does not make known token counts unavailable.
An Agent node's row includes its own invocations. A call node's row includes usage from its child graph and descendants, so the parent's total covers the whole invocation without adding a second copy of each child row. Child reports provide the detailed breakdown. Failed or repeated provider attempts remain in usage totals even when resume restores an earlier workflow state.
The Calls list links to child reports. At the top of a child stats.md, ← Previous call, ↑ Parent, and Next call → link to the surrounding reports. Previous and next refer to calls made by the same parent invocation, in execution order, including calls from different nodes or repeated calls to the same graph. Older output without recorded order uses its existing call list, or directory order when that list is unavailable. Links appear only when the target report exists and refresh when execution finishes, fails, or is interrupted. Resuming updates the same reports and preserves their paths.
Token and cost sources
The built-in Codex and Claude invokers capture provider usage in usage.json beside each invocation's other artifacts. This file retains the measurement and estimation basis; events.jsonl retains the provider output. Custom invokers without usage measurements still contribute to Agent calls, with unknown token counts and cost.
Codex cost estimates use dated, bundled rates for a recognized configured or reported model, assuming standard service and short-context pricing. The usage artifact records these assumptions; tool charges and long-context or regional uplifts are excluded. If the model or applicable rate is unknown, Est. USD remains unavailable. Claude uses its reported cost and per-model usage. Claude's session counters can include earlier invocations, depending on the CLI version; a continuation is attributed only when the runtime can establish which usage belongs to the current attempt.
Costs are estimates of usage, not invoices, subscription charges, or remaining subscription quota. A subscription-backed invocation can therefore have a nonzero estimated cost without an additional charge of that amount. See Claude Code's cost documentation for the meaning of its provider-reported estimate.
Writing visit output
Every authored visit receives context.output_dir, an existing absolute pathlib.Path dedicated to that visit. Ordinary Python, Agent, and Feature visits may write logs and other artifacts beneath it:
python
(context.output_dir / "decision.txt").write_text(
"accepted\n",
encoding="utf-8",
)The runtime does not change the process working directory around a visit, so a relative path does not implicitly resolve below context.output_dir. A Feature visit that initializes state receives the same output-directory access as any other visit.
A synchronous call adapter may be evaluated more than once while Verdog runs or resumes its journaled child invocation. It must therefore not write to output_dir or perform any other unjournaled side effect. Put that work in an ordinary node or in the child graph; their output directories remain durable and completed child work is not repeated by adapter replay.
Checkpointed files are durable outputs: after publication, do not edit or delete them. Later visits write their own numbered outputs. Checkpoints record references to those files rather than copies, while resume leaves files from uncommitted attempts in place.
An Agent node's workspace is a separate choice; Verdog does not select or automatically delete it. For a disposable workspace, use context.output_dir / ".verdog" / "workspace". Rebuild it from durable inputs before every invocation, including repairs and replay, then remove it in finally. Publish any resulting candidates or evidence needed later outside .verdog before returning. All .verdog directories are private and excluded from checkpoint artifact inventories, so their contents must not be carried as durable inputs to subsequent visits.
Runtime-generated files
| Path | Contents |
|---|---|
config.md | Parameters supplied to this graph invocation and links to its child configurations. |
stats.md | Summary and per-node timing, agent usage, and estimated cost, with parent, sibling, and child report links. |
trace.log | Timestamped START and END events with run-relative visit paths. END includes status and duration; START alone does not imply successful completion. Older runs retain their trace filename. |
<agent-visit>/invocations/000001/ | One directory per agent invocation after request validation, numbered within its visit. |
<invocation>/prompt.txt | The prompt passed to the agent. |
<invocation>/response.txt | The successful text response. |
<invocation>/metadata.json | Built-in provider, model, workspace, access mode, session, timing, and status metadata. |
<invocation>/usage.json | Invocation usage, estimated cost, and their measurement or pricing basis, including unavailable fields. |
<invocation>/events.jsonl | Standard output from the built-in provider process. |
<invocation>/stderr.txt | Standard error from the built-in provider process. |
<invocation>/reasoning.txt | Reasoning text, when returned and extracted by the built-in invoker. |
<failure-visit>/stacktrace.txt | The formatted Python traceback written when an exception reaches a graph's failure boundary. |