Source commit: 309831e1e021f962c118452336776fd9a94025f9 Public tree identity: sha256:6fa95c1745579bd6256dbeb3d476db0b07c2f24aa9213b0f7783ce1adfc8aca5
4.3 KiB
Disasmer Operator Panel Notes
Disasmer programs should be able to expose a small human-facing UI through the coordinator web page.
This is useful for long-running build systems, repo watchers, task dashboards, and manual controls.
Core idea
Disasmer program renders UI state
Coordinator displays it in a webpage
Human clicks/types/selects
Coordinator sends typed events back to the program
Program reacts by spawning, stopping, restarting, or debugging tasks
The browser is only a view. The Disasmer program owns the state and logic.
Terminology
Operator Panel
A small immediate-mode UI exposed by a virtual process.
Widget
A built-in UI element such as a button, textbox, dropdown, progress bar, or task table.
UI Event
A typed event sent from the coordinator webpage back into the virtual process.
Example use case
A long-running build program can expose:
repo picker
branch dropdown
parallelism input
start/stop buttons
running task table
progress bars
log tail
artifact links
debug/restart/cancel buttons per task
This makes the build system controllable without external YAML, dashboards, or proprietary CI UI.
Rust sketch
use disasmer::prelude::*;
#[disasmer::main]
async fn main() -> Result<()> {
let panel = ui::panel("Repo builder").await?;
let mut cfg = BuildConfig {
repo: None,
branch: "main".into(),
parallelism: 4,
};
let mut builds = BuildState::load().await?;
loop {
let action = panel.draw(|ui| {
ui.heading("Repo builder");
cfg.repo = ui.git_repo_picker("Repository", cfg.repo.clone());
cfg.branch = ui.git_branch_dropdown("Branch", cfg.repo.as_ref(), &cfg.branch);
cfg.parallelism = ui.number("Parallel builds", cfg.parallelism);
if ui.button("Start watcher").clicked() {
ui.emit(Action::Start(cfg.clone()));
}
if ui.button("Stop").clicked() {
ui.emit(Action::Stop);
}
ui.progress("Current build", builds.current_progress());
ui.task_table("Running tasks", builds.running_tasks());
ui.log_tail("Recent output", builds.log_stream());
}).await?;
match action {
Some(Action::Start(cfg)) => builds.start_watcher(cfg).await?,
Some(Action::Stop) => builds.stop_watcher().await?,
Some(Action::RestartTask(id)) => builds.restart_task(id).await?,
Some(Action::CancelTask(id)) => builds.cancel_task(id).await?,
None => {}
}
builds.poll().await?;
}
}
What this proves
A Disasmer build system can be expressed as one normal program containing:
build logic
repo watching
branch selection
parallel task spawning
human controls
progress reporting
logs
artifact links
debug hooks
The build loop is just normal program logic. Build tasks are virtual threads.
Task controls
A task table should support simple per-task actions:
Debug
Restart
Cancel
View logs
Open artifacts
Example row:
commit abc123 | linux-x64 | running | 72% | Debug | Restart | Cancel
Debugging behavior
When the virtual process is running:
operator panel is interactive
button clicks become UI events
program handles events normally
When the virtual process is stopped in a debugger:
panel shows last rendered state
program-level UI events are disabled or queued
control-plane actions may remain available
For the MVP, prefer:
running process -> interactive panel
stopped process -> read-only panel plus control-plane actions
This avoids executing program code while the debugger says the process is stopped.
MVP widget set
Start with:
text
heading
button
textbox
number input
checkbox
dropdown
progress bar
task table
log tail
artifact link
git repo picker
git branch picker
Avoid initially:
custom HTML
custom JavaScript
complex layout
live charts
drag/drop workflow editors
browser-side business logic
Design rule
The operator panel should stay boring, typed, and immediate-mode.
One source file can define:
distributed execution
build orchestration
environment selection
filesystem/artifact behavior
debugging behavior
human operator UI