Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/skills/update-docs/.last-updated
Original file line number Diff line number Diff line change
@@ -1 +1 @@
e1c2c35866ee53ea1009dd86ea15c3710b3ef090
e8d6f38b307472c2a79d615a1cfc081755f7b16f
2 changes: 1 addition & 1 deletion .claude/skills/update-manpages/.last-updated
Original file line number Diff line number Diff line change
@@ -1 +1 @@
e1c2c35866ee53ea1009dd86ea15c3710b3ef090
e8d6f38b307472c2a79d615a1cfc081755f7b16f
2 changes: 1 addition & 1 deletion .claude/skills/update-readme/.last-updated
Original file line number Diff line number Diff line change
@@ -1 +1 @@
e1c2c35866ee53ea1009dd86ea15c3710b3ef090
e8d6f38b307472c2a79d615a1cfc081755f7b16f
2 changes: 1 addition & 1 deletion .claude/skills/update-website/.last-updated
Original file line number Diff line number Diff line change
@@ -1 +1 @@
e1c2c35866ee53ea1009dd86ea15c3710b3ef090
e8d6f38b307472c2a79d615a1cfc081755f7b16f
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,42 @@ let output = AgentBuilder::new()
println!("{}", output.result.unwrap_or_default());
```

#### Live event streaming

`AgentBuilder` can opt in to session logging and live event callbacks, so
programmatic consumers see the same structured stream as `zag listen`
without shelling out to the CLI:

```rust
use zag::builder::AgentBuilder;
use zag::listen::ListenFormat;

// Tail every event to stderr (same formatter as `zag listen`).
let output = AgentBuilder::new()
.provider("claude")
.stream_events_to_stderr(ListenFormat::Text)
.stream_show_thinking(false)
.exec("refactor this module")
.await?;

// Or register your own callback for fine-grained handling.
let output = AgentBuilder::new()
.provider("claude")
.on_log_event(|event| {
eprintln!("{}: {:?}", event.session_id, event.kind);
})
.exec("refactor this module")
.await?;

// The written JSONL path is available on the output once logging is on.
println!("log: {:?}", output.log_path);
```

Both helpers implicitly enable `SessionLogMode::Auto`; use
`.session_log(SessionLogMode::Disabled | Auto | External(coord))` for
explicit control (e.g. when an outer caller already owns a
`SessionLogCoordinator`).

See the [`zag-agent` crate](zag-agent/) for the full API including JSON schema validation, custom progress handlers, and interactive sessions. Library-level primitives for `review`, `plan`, `discover`, manpages, and agent-to-agent messaging are re-exported from `zag_agent` and `zag_orch` so downstream programs can drive these flows without shelling out to the CLI.

### Language bindings
Expand Down
38 changes: 37 additions & 1 deletion docs/events-and-logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ Every agent session produces an `AgentOutput` structure:
"output_tokens": 800
},
"model": "claude-sonnet-4-5-20250929",
"provider": "claude"
"provider": "claude",
"log_path": "/home/you/.zag/projects/.../sessions/<id>.jsonl"
}
```

Expand All @@ -40,6 +41,7 @@ Access this with `zag exec -o json` or `zag exec -o json-pretty`.
| `usage` | Usage? | Aggregated token usage for the session. |
| `model` | string? | Concrete model reported by the provider (e.g. `claude-sonnet-4-5-20250929`). |
| `provider` | string? | Effective provider after any tier-list downgrade (see `providers.md#provider-downgrade`). |
| `log_path` | string? | Absolute path to the JSONL session log on disk, populated when the builder ran with session logging enabled (`AgentBuilder::enable_session_log(true)` or via `on_log_event` / `stream_events_to_stderr`). Omitted from JSON when `null`. |

`exec` exits with a non-zero status when `is_error == true`; pass `--exit-on-failure` to force the CLI to propagate provider failure as an exit code 1 even when the session technically completed.

Expand Down Expand Up @@ -308,6 +310,40 @@ zag subscribe --json
zag subscribe --tag batch --json | jq 'select(.type == "session_ended")'
```

### Live event streaming from the builder (Rust)

Rust callers using `AgentBuilder` can subscribe to per-step session log
events without shelling out to `zag listen`. Opting in starts a
`SessionLogCoordinator` for the terminal method's lifetime and invokes a
callback (or tails events to stderr) as each event is written:

```rust
use zag::{AgentBuilder, listen::ListenFormat};

// Register a typed callback
let output = AgentBuilder::new()
.provider("claude")
.on_log_event(|event| {
eprintln!("event: {:?}", event.kind);
})
.exec("analyze the code")
.await?;

println!("log on disk: {:?}", output.log_path);

// Or tail a pre-formatted event stream to stderr
let output = AgentBuilder::new()
.provider("claude")
.stream_events_to_stderr(ListenFormat::RichText)
.stream_show_thinking(true)
.exec("analyze the code")
.await?;
```

Both setters implicitly enable session logging. Use
`.enable_session_log(true)` or `.session_log(SessionLogMode::Auto)` when
you want the JSONL log on disk but no live callback.

## Filesystem event markers

For external orchestrators that prefer filesystem notifications over polling, zag writes lifecycle markers to `~/.zag/events/`:
Expand Down
4 changes: 4 additions & 0 deletions docs/language-bindings.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ All bindings support the same set of builder methods (naming follows each langua
| `replay_user_messages` | Claude-only: replay stdin user messages on stdout |
| `include_partial_messages` | Claude-only: emit per-chunk assistant messages |
| `bin` / `ZAG_BIN` | Override the `zag` CLI binary used by the binding |
| `enable_session_log` / `session_log` | Rust-only: start a `SessionLogCoordinator` for the terminal method. Populates `AgentOutput.log_path` with the JSONL path on disk. |
| `on_log_event` | Rust-only: register a callback fired for every `AgentLogEvent` while the terminal method runs. Implicitly enables session logging. |
| `stream_events_to_stderr` | Rust-only: tail the session log to stderr in the same formats as `zag listen` (`Text`, `Json`, `RichText`). Implicitly enables session logging. |
| `stream_show_thinking` | Rust-only: include `Reasoning` events in the stderr stream when `stream_events_to_stderr` is active. |

> **Capability-aware errors**: feature-gated builder options
> (`exec_streaming` / `streaming_input`, `worktree`, `sandbox`,
Expand Down
6 changes: 3 additions & 3 deletions website/src/data/sourceData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export interface ConfigSection {

// --- Data ---

export const version = "0.14.1";
export const version = "0.14.2";

export const providerCount = 5;

Expand Down Expand Up @@ -951,12 +951,12 @@ export const bindings: BindingData[] = [
{
"language": "Swift",
"directory": "swift",
"installCommand": ".package(url: \"https://github.com/niclaslindstedt/zag\", from: \"0.14.1\")"
"installCommand": ".package(url: \"https://github.com/niclaslindstedt/zag\", from: \"0.14.2\")"
},
{
"language": "Java",
"directory": "java",
"installCommand": "io.zag:zag:0.14.1"
"installCommand": "io.zag:zag:0.14.2"
},
{
"language": "Kotlin",
Expand Down