Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6133882
docs(openspec): plan operator web UI and hot reload
magix022 Jul 31, 2026
0de3be9
feat(operator): retain historical run topology and agent details
magix022 Jul 31, 2026
d5ab121
Publish revisioned operator catalog reloads
magix022 Jul 31, 2026
204b3eb
Add in-process gRPC-Web listener
magix022 Jul 31, 2026
d4a97dc
Wire operator web listener controls
magix022 Jul 31, 2026
1e7d876
Build the operator React interface
magix022 Jul 31, 2026
40d59fe
Expose versioned agent run metadata
magix022 Jul 31, 2026
c5a3049
Cover operator browser behavior
magix022 Jul 31, 2026
50743ea
Document the local operator web UI
magix022 Jul 31, 2026
dbd1e5f
Restyle operator web UI with light neutrals
magix022 Jul 31, 2026
8288903
feat(tui): add operator web interface
magix022 Aug 3, 2026
0679a89
perf(operator): define bounded browser hydration contract
magix022 Aug 3, 2026
4730f8a
perf(operator): bound browser data hydration
magix022 Aug 3, 2026
5220d89
perf(operator): bound browser rendering
magix022 Aug 3, 2026
6b2d77f
fix(operator): preserve live browser state
magix022 Aug 3, 2026
9d60d15
feat(operator): add lifecycle logging
magix022 Aug 3, 2026
8d78eb3
checkpoint: panel runs & square arrows
magix022 Aug 4, 2026
f7f8345
feat(web): add resizable run-wide log pane
magix022 Aug 4, 2026
fa2e631
feat: tailwind setup
magix022 Aug 4, 2026
38f490b
basic success/error node styling
magix022 Aug 4, 2026
631e56e
feat: dag nodes work, zoom, style
magix022 Aug 4, 2026
aad9535
feat: various small feat, ready for v0.1
magix022 Aug 4, 2026
9d9b4dc
fix(operator): harden web UI run lifecycle
magix022 Aug 5, 2026
852c2df
ci: run browser benchmark with Chrome v2
magix022 Aug 5, 2026
6ce454d
chore: remove OpenSpec planning artifacts
magix022 Aug 5, 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
22 changes: 22 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,28 @@ jobs:
env:
PYTHONFAULTHANDLER: "1"

web:
name: Browser UI
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
- uses: pnpm/action-setup@v4
with:
version: 10.17.1
- run: uv sync --all-extras
- run: pnpm install --frozen-lockfile
working-directory: web/operator
- run: make web-proto
- run: make web-test
- run: make web-build
- uses: browser-actions/setup-chrome@v2
id: chrome
- run: make web-bench
env:
CHROME_BIN: ${{ steps.chrome.outputs.chrome-path }}
- run: git diff --exit-code -- src/runtime/operator/proto web/operator/src/generated src/runtime/operator/web_assets

ray:
name: Ray tests
runs-on: ubuntu-latest
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,5 @@ trampoline_ai_transform
presentation_artifacts/
examples/customer_feedback_review/artifacts/
__marimo__

.vite
4 changes: 2 additions & 2 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ only for the selected run. Control requests travel back through the provider.

The operator exposes these main RPCs through `OperatorService`:

- `ListFlows` returns discovered flows.
- `GetCatalog` returns discovered workflows and scan-target metadata.
- `StartRun` starts a new workflow run; caller-owned IDs are limited to 256
UTF-8 bytes so retained summaries stay bounded.
- `CancelRun` requests cancellation for a run.
Expand All @@ -429,7 +429,7 @@ The operator exposes these main RPCs through `OperatorService`:
operator-assigned retention cursor; source-local event sequences remain in
the fetched detail body.
- `ReadTrace` and `ReadDetail` stream bounded chunks for immutable detail bodies.
- `StreamRunUpdates` replays typed changes under an operator-instance epoch.
- `StreamOperatorUpdates` replays typed changes under an operator-instance epoch.
Stale cursors, restarts, and slow-consumer overflow require an explicit
structural reset.

Expand Down
47 changes: 47 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,53 @@

## Unreleased

### Operator web interface

- Added an opt-in local React operator interface (`ava operator --web`) with
workflow discovery, live DAG replacement, immutable historical run canvases,
launch/cancel controls, logs, and demand-loaded agent evidence.
- Added a same-process binary gRPC-Web listener and packaged browser assets.
Loopback remains the default; non-loopback binding requires the explicit
`--web-trusted-proxy` acknowledgement.
- Run topology now retains only versioned agent input/output field schemas,
while bounded trace descriptors expose stable PredictRLM header, usage, and
telemetry metadata without embedding declaration instructions or complete
trace bodies in structural snapshots.
- Unchanged discovery results no longer advance catalog revisions, and the web UI
retains workflow/run navigation on narrow viewports with accessible input and
repeated-node labels plus WCAG AA secondary-text contrast.
- Workflow cards now show contained typed field lists while declarations remain in the inspector.
Canvases retain depth-aware edge routing, live durations, stronger execution states, and `Run`
labels.
- Agent steps now use an explicit DAG-card label and accent, including historical
runs classified from their retained agent field schemas.
- Successful and failed nodes retain their neutral borders; only their titles
and status labels use the corresponding outcome color.
- The current workflow canvas uses React Flow's neutral dotted blueprint field;
historical run canvases retain their separate neutral presentation.
- Run logs now render bounded ANSI SGR color and text-style sequences without
interpreting log content as HTML.
- Node-scoped run logs now retain canonical node IDs, including repeated-node
suffixes, so selecting a log node preserves its filtered records.
- Starting a workflow now navigates directly to its retained run snapshot as
soon as the operator publishes the run ID.
- Agent steps now default PredictRLM to quiet execution; workflows and
individual steps can explicitly opt into verbose trace logs.
- Zoomed-out run nodes center their titles while preserving a larger,
card-corner duration label.
- Failed DAG cards now show status only; inspect their retained logs for error detail.
- Retained run canvases now include a `Current workflow` control that returns
directly to the live workflow view.
- Explorer collapse and restore controls now stay at the pane edge, and Explorer and inspector
panes are independently resizable. Retained inputs, outputs, and traces use bounded progressive
JSON with content-sized key columns, while logs use a record-separated continuous-text view
without hidden unbounded DOM.
- Large-run hydration is now summary-first, cancellable, incrementally paged, and
bounded across browser queues, descriptor windows, detail caches, and virtualized
DOM rendering. `make web-bench` covers 10,000 retained runs in real Chromium.
- Added `ava operator --log-level` and explicit source-watcher and hot-reload
lifecycle logs for successful, unchanged, and failed catalog refreshes.

### Operator transport

- Operator streams now replay bounded, typed run updates under an instance epoch
Expand Down
18 changes: 17 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: test test-cov test-cov-html lint format precommit-check check smoke-test tui-bench proto brand install clean
.PHONY: test test-cov test-cov-html lint format precommit-check check smoke-test tui-bench proto brand install clean web-bench

# Run tests with every supported executor/storage extra installed.
test:
Expand Down Expand Up @@ -43,6 +43,22 @@ proto:
perl -pi -e 's/^import operator_pb2 as operator__pb2$$/from . import operator_pb2 as operator__pb2/' \
src/runtime/operator/proto/operator_pb2_grpc.py

# Regenerate the checked-in TypeScript operator client.
web-proto:
cd web/operator && pnpm generate

# Build the packaged browser interface.
web-build:
cd web/operator && pnpm build

# Run browser projection and component tests.
web-test:
cd web/operator && pnpm test

# Run the Vitest volume gate followed by the Node-managed real-Chromium virtualizer gate.
web-bench:
cd web/operator && pnpm benchmark

# Build checked-in brand image artifacts from the Three.js source HTML.
brand:
node docs/assets/brand/source/export-brand-assets.mjs
Expand Down
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,29 @@ ava operator --flows path/to/flows --port 7433
ava tui --connect localhost:7433
```

For a browser interface backed by the same operator, enable the loopback web
listener:

```bash
ava operator --flows path/to/flows --web
# Open http://127.0.0.1:7435
```

Add `--log-level INFO` to either operator launch command to show listener startup,
source-watcher startup and shutdown, changed files, successful catalog revision
transitions, unchanged rescans, and reload failures. The default is `WARNING`;
accepted levels are `DEBUG`, `INFO`, `WARNING`, and `ERROR`.

The browser shows the live workflow catalog, current definitions, immutable
per-run topology, run controls, logs, and retained agent trace evidence. Source
changes replace only the current-definition canvas; earlier runs keep their
topology and agent input/output field schemas without retaining instruction
bodies or execution configuration. The browser listener is loopback-only by
default. `--web-trusted-proxy` permits a
non-loopback bind only when a trusted, authenticated proxy supplies the missing
security boundary.


The TUI is a client of the operator; it does not import or execute workflow files
itself. To explore the interface without an operator, start mock mode:

Expand Down
7 changes: 6 additions & 1 deletion docs/agent-steps.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,10 @@ PredictRLM skills.

Workflow-scoped defaults configure shared PredictRLM execution policy:

Agent steps are quiet by default (`verbose=False`); set `verbose=True` on an
individual `@ava.agent_step` or in `agent_defaults` when live PredictRLM trace
output is needed.

```python
@ava.workflow(
input=PreparedInputs,
Expand All @@ -264,7 +268,8 @@ async def expensive_audit(..., *, agent: ava.Agent):
Resolution order:

```text
agent-step runtime kwargs > workflow agent_defaults > PredictRLM defaults
agent-step runtime kwargs > workflow agent_defaults > Avalanche agent defaults >
PredictRLM defaults
```

Workflow defaults cannot configure `signature`, `skills`, or `tools`; those are
Expand Down
20 changes: 20 additions & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ To run them separately, start the operator in one terminal:
uv run ava operator --flows examples --port 7433
```

Operator terminal logging defaults to `WARNING`. Add `--log-level INFO` to see
service and source-watcher startup, each hot-reload attempt, successful revision
transitions, unchanged rescans, reload failures, and watcher shutdown. The flag
also works with the `python -m avalanche.operator` entry point.

Start a discovered flow from another terminal with the CLI:

```bash
Expand All @@ -136,6 +141,21 @@ Alternatively, connect the TUI and start runs interactively:
uv run ava tui --connect localhost:7433
```

Or enable the operator's browser interface:

```bash
uv run ava operator --flows examples --web
```

Open `http://127.0.0.1:7435`. The browser receives the same ordered operator
updates as the TUI, including live catalog replacement when watched workflow
sources change. Current definitions update in place; historical run canvases
retain the topology and agent declarations captured for that run. The browser
listener defaults to loopback and has no built-in authentication. Use
`--web-trusted-proxy` with a non-loopback `--web-host` only behind a trusted,
authenticated proxy.


The TUI gets flows from the operator over gRPC. It does not import files from the
examples directory directly.

Expand Down
36 changes: 36 additions & 0 deletions src/ava_cli/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,28 @@ def _build_parser() -> argparse.ArgumentParser:
operator.add_argument(
"--webhook-port", type=int, default=7434, help="loopback webhook HTTP port"
)
operator.add_argument("--web", action="store_true", help="serve the local browser UI")
operator.add_argument(
"--web-host",
default="127.0.0.1",
help="browser UI listen host (default: loopback)",
)
operator.add_argument("--web-port", type=int, default=7435, help="browser UI HTTP port")
operator.add_argument(
"--web-trusted-proxy",
action="store_true",
help=(
"confirm non-loopback browser traffic is protected by an external trusted "
"and authenticated boundary"
),
)
operator.add_argument(
"--log-level",
type=str.upper,
choices=("DEBUG", "INFO", "WARNING", "ERROR"),
default="WARNING",
help="terminal log level (default: WARNING)",
)
operator.add_argument("--ray", action="store_true", help="use the Ray executor")
operator.set_defaults(handler=_run_operator)

Expand Down Expand Up @@ -215,7 +237,21 @@ def _run_operator(args: argparse.Namespace) -> int:
str(args.port),
"--webhook-port",
str(args.webhook_port),
"--log-level",
args.log_level,
]
if args.web:
runtime_args.extend(
[
"--web",
"--web-host",
args.web_host,
"--web-port",
str(args.web_port),
]
)
if args.web_trusted_proxy:
runtime_args.append("--web-trusted-proxy")
if args.ray:
runtime_args.append("--ray")
return _operator_main(runtime_args)
Expand Down
Loading
Loading