Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b89ed55
feat(agents): bundle native monitoring tools
johnmatthewtennant Aug 26, 2026
e74b4ed
style: format native monitor changes
johnmatthewtennant Aug 26, 2026
f009d40
fix(berdctl): attribute created sessions
johnmatthewtennant Aug 28, 2026
f982eb7
fix(monitor): bound unterminated output records
johnmatthewtennant Aug 28, 2026
1201f01
fix(chat): retain Berd message provenance
johnmatthewtennant Aug 28, 2026
006cd24
fix(monitor): keep stop requests responsive
johnmatthewtennant Aug 28, 2026
dc22c92
fix(monitor): replace pending output atomically
johnmatthewtennant Aug 28, 2026
8b2fc63
fix(monitor): stabilize cross-platform formatting
johnmatthewtennant Aug 28, 2026
abf9cf4
fix(monitor): terminate timed-out launches
johnmatthewtennant Aug 28, 2026
e698da2
fix(monitor): clean up producers on errors
johnmatthewtennant Aug 28, 2026
9ac883f
fix(monitor): bound delivery subprocesses
johnmatthewtennant Aug 28, 2026
92ff33c
fix(monitor): deduplicate retried deliveries
johnmatthewtennant Aug 28, 2026
edda53e
fix(monitor): stabilize CI test formatting
johnmatthewtennant Aug 28, 2026
748a6b0
fix(berdctl): preserve queued delivery ids
johnmatthewtennant Aug 28, 2026
c9295c8
fix(berdctl): serialize delivery admission
johnmatthewtennant Aug 28, 2026
571ae7d
fix(monitor): sanitize nul output bytes
johnmatthewtennant Aug 28, 2026
8271666
fix(monitor): preserve fresh stop requests
johnmatthewtennant Aug 28, 2026
2935acd
fix(chat): clear delivery metadata on manual edits
johnmatthewtennant Aug 28, 2026
e3f2025
fix(monitor): surface stdout capture failures
johnmatthewtennant Aug 28, 2026
9744ca2
fix(berdctl): deduplicate hydrated deliveries
johnmatthewtennant Aug 28, 2026
52c271d
fix(berdctl): deduplicate recovered queue deliveries
johnmatthewtennant Aug 28, 2026
0ddd195
fix(monitor): disarm producer cleanup
johnmatthewtennant Aug 28, 2026
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
52 changes: 52 additions & 0 deletions distro/skills/berd-monitor/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
name: berd-monitor
description: >-
Run a long-lived command outside the current Berd turn and wake the owning
session with actionable stdout. Use for builds, tests, reviews, deployments,
polling, watchers, and other external waits.
metadata:
berdBundled: true
---

# Berd Monitor

Use `berd-monitor` when a command may outlive the current turn. It detaches the
producer from Berd and the agent harness, buffers output across delivery
failures, and sends complete stdout lines to the exact originating session.

Run short, bounded commands normally. Do not hold a turn open with `sleep`,
polling, log tailing, or a foreground timeout.

## Start

```bash
berd-monitor run \
--state-key <stable-key> \
--label '<concise source name>' \
--instructions '<short event-handling guidance>' \
-- <producer-command> [args...]
```

`AGENT_SESSION_ID` selects the current session. Use `--session-id` only for
another positively identified session; never infer a session from the working
directory. The command prints the detached monitor PID. After checking the
monitor's `watcher.log` under the printed state directory when diagnosis is
needed, continue other work or end the turn—never wait on the detached PID.

The producer's stdout is the event API:

- emit concise, newline-terminated milestones and flush promptly;
- put verbose output and diagnostics in durable logs or stderr;
- avoid NUL bytes and emit a final summary when practical.

Default `--if-running steer` adds an event to an active run or starts a new
turn. Use `--if-running queue` only when the active run must not be steered.
Pending events retry without being dropped, and a trailing partial line is
delivered when the producer exits.

Delivered messages are visibly labeled as coming from `berd-monitor`. Stop a
monitor with:

```bash
berd-monitor stop --state-key <stable-key>
```
29 changes: 29 additions & 0 deletions distro/skills/berd-orchestrator/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
name: berd-orchestrator
description: >-
Coordinate work across Berd sessions while keeping one conversation
available to the user. Use for a long-lived orchestration session.
metadata:
berdBundled: true
---

# Berd Orchestrator

Keep this session available for conversation. Use `berdctl session list`,
`get`, `create`, and `send` to delegate substantial work to other sessions
instead of doing it here.

Prefer an existing session that owns the relevant context. Create one when
work has no owner, and give it a complete task. Do not approve, merge, or
archive work without the user's direction.

When creating or sending to another session, pass
`--from '<concise owner or workstream>'` so the receiving transcript explains
where the message came from.

Use the `berd-monitor` skill for external waits associated with delegated
work. End the turn after starting a monitor; do not poll in the foreground.

Stay quiet while work is progressing. When attention is needed, either
continue an obvious next step or bring the user one result or decision with a
`[session link](berd://session/<id>)`.
8 changes: 5 additions & 3 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -498,16 +498,18 @@ dev:
export VITE_APP_VERSION="$BERD_APP_VERSION_RICH"
echo "Using app version: ${BERD_APP_VERSION} (${BERD_APP_VERSION_RICH})"

# tauri dev only builds the root package; the berdctl CLI workspace
# member needs an explicit build, resolved at runtime via BERDCTL_BIN
# because tauri.dev.conf.json blanks externalBin.
# tauri dev only builds the root package; the agent-facing CLI workspace
# members need explicit builds because tauri.dev.conf.json blanks externalBin.
BERDCTL_FEATURES=()
[[ "${VITE_FEEDBACK:-0}" == "1" ]] && BERDCTL_FEATURES+=(--features block-feedback)
# ${arr[@]+...} guards the empty-array expansion, which bash 3.2 (stock
# macOS) treats as an unbound variable under `set -u`.
(cd src-tauri && cargo build -p berdctl ${BERDCTL_FEATURES[@]+"${BERDCTL_FEATURES[@]}"})
(cd src-tauri && cargo build -p berd-monitor)
export BERDCTL_BIN="${CARGO_TARGET_DIR}/debug/berdctl"
export BERD_MONITOR_BIN="${CARGO_TARGET_DIR}/debug/berd-monitor"
echo "Using berdctl CLI: ${BERDCTL_BIN}"
echo "Using berd-monitor CLI: ${BERD_MONITOR_BIN}"

if [[ "${VITE_AGENT_TOOLS:-0}" == "1" ]]; then
./scripts/prepare-bb-cli-resource.sh
Expand Down
27 changes: 22 additions & 5 deletions scripts/prepare-berdctl-sidecar.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Build and stage the berdctl CLI for Tauri's externalBin bundling.
# Build and stage the berdctl and berd-monitor CLIs for Tauri externalBin bundling.
#
# Tauri expects external binaries to be present at build time with the target
# triple appended to the configured stem. For config
Expand All @@ -13,8 +13,9 @@ usage() {
cat <<'USAGE'
Usage: scripts/prepare-berdctl-sidecar.sh [target-triple]

Builds the berdctl workspace crate in release mode and copies the binary
into src-tauri/binaries with the target triple suffix required by Tauri.
Builds the berdctl and berd-monitor workspace crates in release mode and
copies both binaries into src-tauri/binaries with the target triple suffix
required by Tauri.

The triple defaults to the rustc host. Pass it explicitly (or set
BERDCTL_TRIPLE) when the Tauri build itself uses an explicit --target, so
Expand All @@ -29,9 +30,9 @@ if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
fi

EXPLICIT_TRIPLE="${1:-${BERDCTL_TRIPLE:-}}"
CARGO_ARGS=(build -p berdctl --release)
CARGO_ARGS=(build -p berdctl -p berd-monitor --release)
if [[ "${VITE_FEEDBACK:-0}" == "1" ]]; then
CARGO_ARGS+=(--features block-feedback)
CARGO_ARGS+=(--features berdctl/block-feedback)
fi
if [[ -n "$EXPLICIT_TRIPLE" ]]; then
TRIPLE="$EXPLICIT_TRIPLE"
Expand Down Expand Up @@ -75,3 +76,19 @@ mkdir -p "$OUT_DIR"
cp "$BUILT" "$OUT"
chmod +x "$OUT"
echo "Staged berdctl sidecar: $OUT"

if [[ -n "$EXPLICIT_TRIPLE" ]]; then
MONITOR_BUILT="$TARGET_DIR/$TRIPLE/release/berd-monitor"
else
MONITOR_BUILT="$TARGET_DIR/release/berd-monitor"
fi

if [[ ! -x "$MONITOR_BUILT" ]]; then
echo "Built berd-monitor binary not found at: $MONITOR_BUILT" >&2
exit 1
fi

MONITOR_OUT="$OUT_DIR/berd-monitor-$TRIPLE"
cp "$MONITOR_BUILT" "$MONITOR_OUT"
chmod +x "$MONITOR_OUT"
echo "Staged berd-monitor sidecar: $MONITOR_OUT"
7 changes: 7 additions & 0 deletions scripts/windows/Dev-Windows.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,13 @@ if (-not (Test-Path $env:BERDCTL_BIN -PathType Leaf)) {
}
Write-WindowsDevInfo "Using berdctl CLI: $env:BERDCTL_BIN"

Invoke-CheckedCommand -FilePath "cargo" -ArgumentList @("build", "-p", "berd-monitor") -WorkingDirectory (Join-Path (Get-BerdRepoRoot) "src-tauri") -Label "cargo build berd-monitor"
$env:BERD_MONITOR_BIN = Join-Path (Join-Path $env:CARGO_TARGET_DIR "debug") "berd-monitor.exe"
if (-not (Test-Path $env:BERD_MONITOR_BIN -PathType Leaf)) {
throw "Expected berd-monitor.exe at $env:BERD_MONITOR_BIN after cargo build."
}
Write-WindowsDevInfo "Using berd-monitor CLI: $env:BERD_MONITOR_BIN"

if ([string]::IsNullOrWhiteSpace($env:GOOSE_BIN)) {
$env:GOOSE_BUILD_PROFILE = "debug"
$result = Invoke-EnsureLocalGoose -Action Check
Expand Down
11 changes: 8 additions & 3 deletions scripts/windows/Stage-Sidecar-Windows.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ Write-WindowsDevInfo "Staged Goose sidecar: $staged"
$tauriTargetDir = Get-TauriCargoTargetDir
$env:CARGO_TARGET_DIR = $tauriTargetDir
$hostTriple = Get-RustHostTriple
$cargoArgs = @("build", "-p", "berdctl", "--release")
$cargoArgs = @("build", "-p", "berdctl", "-p", "berd-monitor", "--release")
if ($env:VITE_FEEDBACK -eq "1") {
$cargoArgs += @("--features", "block-feedback")
$cargoArgs += @("--features", "berdctl/block-feedback")
}
if (-not [string]::IsNullOrWhiteSpace($hostTriple) -and $Triple -ne $hostTriple) {
$cargoArgs += @("--target", $Triple)
Expand All @@ -82,10 +82,15 @@ if (-not [string]::IsNullOrWhiteSpace($hostTriple) -and $Triple -ne $hostTriple)
$berdctlReleaseDir = Join-Path $tauriTargetDir "release"
}
Invoke-CheckedCommand -FilePath "cargo" -ArgumentList $cargoArgs `
-WorkingDirectory (Join-Path (Get-BerdRepoRoot) "src-tauri") -Label "cargo build -p berdctl --release"
-WorkingDirectory (Join-Path (Get-BerdRepoRoot) "src-tauri") -Label "cargo build -p berdctl -p berd-monitor --release"
$berdctlSource = Join-Path $berdctlReleaseDir (Get-WindowsExeName "berdctl")
$staged = Stage-WindowsSidecar -SourcePath $berdctlSource -Triple $Triple -Stem "berdctl" -BinDir $binDir
Write-WindowsDevInfo "Staged berdctl sidecar: $staged"

# ── berd-monitor ─────────────────────────────────────────────
$monitorSource = Join-Path $berdctlReleaseDir (Get-WindowsExeName "berd-monitor")
$staged = Stage-WindowsSidecar -SourcePath $monitorSource -Triple $Triple -Stem "berd-monitor" -BinDir $binDir
Write-WindowsDevInfo "Staged berd-monitor sidecar: $staged"

# Catch is deliberately not staged on Windows (see header).
Write-WindowsDevInfo "Skipping Catch sidecar: unsupported on Windows (excluded from externalBin)."
2 changes: 2 additions & 0 deletions scripts/windows/Test-WindowsDev.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ try {
$windowsExternalBin = @(Get-ObjectValue (Get-ObjectValue $windowsConf "bundle") "externalBin")
Assert-Equal "Windows externalBin stages goosed" ($windowsExternalBin -contains "binaries/goosed") $true
Assert-Equal "Windows externalBin stages berdctl" ($windowsExternalBin -contains "binaries/berdctl") $true
Assert-Equal "Windows externalBin stages berd-monitor" ($windowsExternalBin -contains "binaries/berd-monitor") $true
Assert-Equal "Windows externalBin excludes catch" ($windowsExternalBin -contains "binaries/catch") $false

# Tauri merges platform overlays into the base config with json_patch (RFC
Expand All @@ -454,6 +455,7 @@ try {
$mergedExternalBin = if ($null -ne $windowsExternalBin) { $windowsExternalBin } else { $baseExternalBin }
Assert-Equal "merged Windows externalBin stages goosed" ($mergedExternalBin -contains "binaries/goosed") $true
Assert-Equal "merged Windows externalBin stages berdctl" ($mergedExternalBin -contains "binaries/berdctl") $true
Assert-Equal "merged Windows externalBin stages berd-monitor" ($mergedExternalBin -contains "binaries/berd-monitor") $true
Assert-Equal "merged Windows externalBin drops catch" ($mergedExternalBin -contains "binaries/catch") $false

# ── Windows bundle recipes route through native staging ──────
Expand Down
33 changes: 33 additions & 0 deletions src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ crate-type = ["staticlib", "cdylib", "rlib"]
# <plugin> --features ...` only works for workspace members. app-test-driver
# stays excluded (a plain path dependency, as before this workspace existed).
[workspace]
members = ["crates/berd-voice", "crates/berdctl", "plugins/berdctl"]
members = [
"crates/berd-monitor",
"crates/berd-voice",
"crates/berdctl",
"plugins/berdctl",
]
exclude = ["plugins/app-test-driver"]

[build-dependencies]
Expand Down
23 changes: 23 additions & 0 deletions src-tauri/crates/berd-monitor/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[package]
name = "berd-monitor"
version = "0.6.2"
description = "Detached command monitor for Berd sessions"
authors = ["Block, Inc."]
edition = "2021"

[dependencies]
clap = { version = "4", features = ["derive", "env"] }
fs2 = "0.4"

[target.'cfg(unix)'.dependencies]
libc = "0.2"

[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.59", features = [
"Win32_Foundation",
"Win32_Security",
"Win32_Storage_FileSystem",
"Win32_System_Diagnostics_ToolHelp",
"Win32_System_JobObjects",
"Win32_System_Threading",
] }
Loading