Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/dwarves

crates/dwarves-web-client/proto/dwarf.proto

// dwarf.proto — a TRIMMED copy of dwarves' `Dwarf` per-run-report read surface.
//
// This is the thin backend-(2) client's ONLY proto: the read RPCs an embed pane
// needs to render a LIVE forge run — `History` (pick the newest run when no id is
// pinned) and `GetRunReport` (the parent RunRow + a BuildRow per step, with the
// step's `needs` DAG edges). Field numbers, message names, and the `dwarf.v1`
// package MUST match `crates/dwarves/proto/dwarf.proto` exactly (the gRPC method
// paths are `/dwarf.v1.Dwarf/History` and `/dwarf.v1.Dwarf/GetRunReport`), so this
// client talks to a live `dwarves-server` WITHOUT linking the `dwarves` server
// feature (which would build the whole tonic router + skidbladnir lifecycle) — and
// with NO `nornir` dep (that would be a cycle: nornir → dwarves already).
//
// Auth: both RPCs carry `authorization: Bearer <DWARVES_SERVER_TOKEN>` in their grpc
// metadata (enforced by the server's shared nornir-service interceptor).

syntax = "proto3";

package dwarf.v1;

// A historized pipeline run summary (the wire twin of PipelineRunRow). Field
// numbers mirror the server's `RunRow` exactly.
message RunRow {
  string run_id = 1;
  string pipeline = 2;
  string project = 3;
  string trigger = 4;
  string status = 5;
  uint32 steps = 6;
  uint32 passed = 7;
  uint64 duration_ms = 8;
  string finished_at = 9;
}

// `pipeline` (when set) narrows the runs to that pipeline's.
message HistoryRequest { uint32 limit = 1; string pipeline = 2; }
message HistoryReply { repeated RunRow runs = 1; }

// One step's log, by its run and its row's index in the run (`seq`). `tail` = the last
// N lines (0 = the whole log, its end, at most 20000 lines).
message StepLogRequest { string run_id = 1; uint32 seq = 2; uint32 tail = 3; }
message StepLogReply {
  repeated string lines = 1;
  uint64 total = 2;   // lines the log holds
  bool found = 3;     // false = the step kept no log
}

// One REGISTERED pipeline on the forge (the wire twin of the server's `PipelineInfo`).
// Field numbers mirror `crates/dwarves/proto/dwarf.proto` exactly.
message PipelineInfo {
  string project = 1;
  string name = 2;
  uint32 steps = 3;
}

// The forge's render-ready dump: the REGISTERED pipeline roster + the recent runs, in
// ONE round trip. This pair is exactly what a status BOARD needs — a pipeline that has
// never run still belongs on the board (as a grey "unknown" chip), and `History` alone
// can never name one, because a pipeline with no run contributes no row.
message ShowReply {
  repeated PipelineInfo pipelines = 1;
  repeated RunRow recent_runs = 2;
}

// Ask for one run's full report by id (the server reuses `RunStatusRequest`).
message RunStatusRequest { string run_id = 1; }

// One executed step's wire record + its DAG `needs` edges (mirrors the server's
// `BuildRow`). Enough to reconstruct BOTH the RunReport rows and the build DAG.
message BuildRow {
  string run_id = 1;
  string step = 2;
  string stage = 3;
  string backend = 4;
  string matrix = 5;
  string status = 6;
  string summary = 7;
  string artifact_id = 8;
  string job_ref = 9;
  uint64 duration_ms = 10;
  string finished_at = 11;
  repeated string needs = 12;
  // A Runa `BuildWorkspace` step's units (dwarves `run_units::StepUnits` as JSON:
  // counts, per repo, failed units + their errors); empty for every other step.
  string units_json = 13;
}

// The full per-run report: parent RunRow + a BuildRow per step (mirrors the
// server's `RunReport`).
message RunReport {
  RunRow run = 1;
  repeated BuildRow steps = 2;
  // a release run's state, statement, artifacts and signing command (JSON)
  string release_json = 3;
}

// An empty request (the wire twin of the server's `Empty`) — AgentPool takes no args.
message Empty {}

// Queue a run (`release`/`release-build` with `request`: a release request, TOML).
message TriggerRequest {
  string project = 1;
  string pipeline = 2;
  string trigger = 3;
  string request = 4;
}
message TriggerReply {
  string run_id = 1;
  string status = 2;
}

// The owner's signed bundle for a release run.
message ReleaseBundleRequest {
  string run_id = 1;
  bytes bundle = 2;
}

// One registered worker agent (the wire twin of the server's `AgentRow` = a jera
// `AgentSpec` + liveness). Field numbers mirror `crates/dwarves/proto/dwarf.proto`
// exactly so this thin client reads the live `dwarves-server`'s `AgentPool` reply.
message AgentRow {
  string id = 1;
  string group = 2;
  repeated string caps = 3;   // required-capability labels the agent advertises
  uint32 cores = 4;
  uint64 mem_mb = 5;
  string state = 6;           // idle|busy|... (jera AgentState) — liveness/online
}

// The forge's worker fleet as data — every agent the scheduler dispatches to.
message AgentPoolReply {
  repeated AgentRow agents = 1;
}

// Where the server finds holger's checkout for the holger build target: a LOCAL repo
// root the server already has on disk (e.g. the side-by-side `../holger`). Empty ⇒ the
// server's default (`$DWARVES_HOLGER_REPO`, else `../holger`). Field number mirrors the
// server's `HolgerBuildRequest` exactly.
message HolgerBuildRequest {
  string holger_root = 1;
}

// One resolved holger deployment tier (the wire twin of the server's `HolgerTier` =
// brokkr::resolve::ResolvedTarget). When `resolved` is false the tier names a build
// target holger's build-space does not declare (a dropped/renamed executable) and the
// bin/package/command_line are empty. Field numbers mirror the server's exactly.
message HolgerTier {
  string tier = 1;            // the tier/variant name (embedded|mini|full)
  string step = 2;            // the pipeline step id (build-<tier>)
  bool resolved = 3;          // true iff the tier names a declared build target
  string bin = 4;             // the tier's executable name (when resolved)
  string package = 5;         // the tier's cargo package (when resolved)
  string command_line = 6;    // the materialized `cargo build …` argv (when resolved)
}

// The 3-tier resolution: a per-tier row plus the completeness verdict. `complete` is
// false when any tier is unwired; `found` is false when holger declares no build-space
// at `holger_root` (the plan is empty, NOT an error). Field numbers mirror the server's.
message HolgerBuildReply {
  repeated HolgerTier tiers = 1;
  uint32 resolved = 2;
  uint32 missing = 3;
  bool complete = 4;
  bool found = 5;
}

// The read RPCs this thin pane consumes. The full dwarves `Dwarf` service has more
// (Health/Show/Register/Trigger/Webhook/RunStatus/Badge); this client needs only these —
// list runs to pick the newest, fetch its per-step report, read the worker fleet for the
// live Jobs + Agent-fleet cockpit pane, and resolve holger's 3-tier build matrix.
service Dwarf {
  rpc History      (HistoryRequest)   returns (HistoryReply);
  rpc GetRunReport (RunStatusRequest) returns (RunReport);
  // One Runa step's log (everything the step printed), filed on its run.
  rpc StepLog (StepLogRequest) returns (StepLogReply);
  // Queue a run; a release request rides `TriggerRequest.request`.
  rpc Trigger (TriggerRequest) returns (TriggerReply);
  // The owner's signed bundle for a release run, verified before it is stored.
  rpc ReleaseBundle (ReleaseBundleRequest) returns (TriggerReply);
  // The forge's render-ready dump — registered pipelines + recent runs in ONE round
  // trip. The Status BOARD's feed: `History` alone cannot name a registered pipeline
  // that has never run, and a board that silently drops those is a board that reports
  // only on what already worked. Added 2026-09-10 when the board's fixture was deleted.
  rpc Show         (Empty)            returns (ShowReply);
  // The worker/agent roster + heartbeat/online state (the multi-machine fleet).
  rpc AgentPool    (Empty)            returns (AgentPoolReply);
  // holger's 3-tier (embedded·mini·full) build MATRIX: each tier mapped onto its build
  // target (bin · package · materialized `cargo` argv) + which resolve + completeness.
  // COMPILE-FREE (the server resolves the plan; it never builds holger in the RPC).
  rpc ResolveHolgerBuild (HolgerBuildRequest) returns (HolgerBuildReply);
}