Skip to content

Releases: caliban-ai/prospero

v0.5.0 — dashboard v2 + honest k8s outcomes

Choose a tag to compare

@johnford2002 johnford2002 released this 22 Aug 20:37
52c63b5

Replaces the dashboard. The hand-written vanilla-JS page is superseded by a
Rust → WASM single-page app that shares the server's own types, and it now
serves /; the old page remains at /v1, deprecated. Everything an operator
previously needed v1 for — launching, killing, replying to an interactive
agent, editing a workspace's config, watching a live stream — is in v2, along
with things v1 never had: a per-agent timeline with a tool-call inspector, and
fleet-wide spend, turns, and outcome charts over a selectable window.

The other half of this release is the k8s fleet telling the truth about what it
ran. Terminal outcomes were structurally invisible under PROSPERO_FLEET=k8s:
the watch loop derived agent status from the CalibanTask phase, and the
operator never advances that past Running, so the new outcome charts read a
permanent zero — including for runs that had demonstrably failed. Outcomes are
now taken from the pod, recorded once per agent, and survive a restart.

Upgrade note. GET / now serves dashboard v2 rather than v1, and
GET /app.js is gone — v1's script moved to /v1/app.js along with the page.
/v2 remains a permanent alias for the new dashboard, so existing links to it
keep working.

Added

  • Dashboard v2 — a Rust → WASM single-page app, and now the dashboard. A
    Dioxus SPA in crates/dashboard, compiled to wasm32-unknown-unknown and
    embedded in prosperod, replacing the hand-written vanilla-JS page. The read
    model and the control-plane DTOs are the same Rust types the server uses, so
    the client cannot drift from the API the way a hand-maintained JS copy did.
    The crate sits outside the cargo workspace on purpose (a wasm-only crate would
    break the host-target build and sink the coverage floor) and has its own CI
    job; its built bundle is committed and include_bytes!'d, so an ordinary
    cargo build still needs no wasm toolchain and one binary still ships the UI
    (#97).
  • Full operator control from the dashboard. Launch, kill, remove, respawn,
    interactive input, end-input, and workspace removal — every action gated on
    /api/capabilities, so the UI never offers an operation the active backend
    would answer with a 405
    (#173).
  • Workspace registration and configuration from the dashboard, with two form
    shapes chosen at runtime: the local single-provider/env form, and the k8s
    Workspace-CR editor with sources, named providers, and Secret references,
    plus the reconciliation-status pill and a provider picker on launch. This also
    fixed a lossy read: GET /api/workspaces was projecting the CR's source spec
    down and dropping the git remote and ref, so editing a k8s workspace meant
    retyping every remote from memory
    (#175).
  • Live agent stream viewer — replay history from the store, then tail over
    SSE. A reconnect resumes at last_seq + 1 and anything at or below the
    high-water mark is dropped, which is the defence against the v1 reconnect
    storm that duplicated the timeline unboundedly (#105); a close after
    AgentFinished reads as "finished" rather than an error, so a healthy
    completed run does not sit there retrying
    (#178).
  • Per-agent timeline with a tool-call inspector. Tool calls pair start with
    finish into a collapsible entry, consecutive output coalesces, and the opening
    context and final accounting become a header and a summary. Pairing is on the
    tool id and never the name — caliban's ToolCallEnd carries the id but leaves
    the name empty, which is what left every tool stuck "running" in v1 (#106)
    (#179).
  • GET /api/usage — cost, turns, and terminal outcomes aggregated per
    workspace per UTC day
    over a window (since/until, or days). Computed
    by the store rather than by replaying the log, with identical semantics across
    the JSONL, SQLite, and Postgres backends, held there by a shared conformance
    suite (#180).
  • Fleet overview charts for spend, turns, and outcomes over a selectable
    24h / 7d / 30d window. Outcomes are faceted rather than stacked: measured
    against the real tokens, no ordering of a four-way stack is separable in light
    mode, so one single-hue chart per outcome is the fix rather than a mitigation.
    Hand-rolled SVG with native <title> tooltips — the page is served under
    default-src 'none', so there is no script and nothing for the CSP to refuse
    (#181).
  • An explicit theme setting (System / Light / Dark), persisted in
    localStorage, replacing "whatever prefers-color-scheme says". The explicit
    choice wins in both directions, and the theme is applied before first paint so
    there is no flash of the wrong one
    (#183).

Changed

  • The control-plane DTOs moved to prospero-types and now carry both
    Serialize and Deserialize. They previously lived in prospero-api, which
    pulls axum and tokio and so compiles for no wasm target, and each carried only
    the server's half of the contract — so a WASM client would have had to
    hand-duplicate all eight, reintroducing exactly the drift Rust/WASM was chosen
    to avoid. They are re-exported from their original paths and the serde output
    is unchanged, so this is additive for existing consumers
    (#172).
  • Dashboard v2 is now the default surface. GET / serves the Dioxus/WASM
    dashboard; /v2 stays mounted as a permanent alias, since the bundle's own
    asset URLs are absolute /v2/... and existing links point there. The scaffold
    deliberately parked v2 at /v2 so / stayed untouched while epic #95 landed —
    that transition is complete
    (#191).

Deprecated

  • The v1 dashboard has moved to /v1 and is deprecated. It renders a notice
    pointing at /, and its script now lives at /v1/app.js (GET /app.js is
    gone). It is kept rather than removed so an operator hitting a v2 regression
    has somewhere to land, but it receives no further work and carries defects v2
    was built to fix — most visibly #106, where a tool call whose finish frame has
    a blank name stays "running" forever. Removal is a follow-up once v2 has a
    release of real-world use (#191).

Fixed

  • Restarting prosperod no longer re-counts outcomes it already recorded. A
    fresh process starts with an empty view of the fleet and re-derives the
    terminal transition it had already written before the restart, so every
    outcome facet doubled on each restart — measured on a live cluster as
    3 done / 3 failed becoming 6 / 6 with nothing having run. The watch loop now
    checks the durable log (which outlives the process) before recording an
    agent's outcome, so an agent that finished once is counted once
    (#196).

  • Terminal outcomes are now derived from the pod, not the CalibanTask phase.
    #190 made the watch loop persist the transitions it observed, but it observed
    status.phase, and the operator never advances that past Running — CRs whose
    agents finished a day earlier still read Running, so no terminal transition
    ever occurred and the outcome facets stayed at zero on a real cluster. The loop
    now applies the same pod-caliband overlay snapshot() has always used, so the
    component that emits events and the one that renders them finally agree. Pod
    dials are bounded and concurrent, and an agent is consulted only until it is
    observed terminal (#194).

  • An unreachable pod can no longer stall fleet observation. The status
    overlay dialled each pod sequentially with no deadline. A pod that black-holes
    its SYN (rather than refusing it) blocked until the OS connect timeout, which
    was survivable when only GET /api/fleet did this and is not now that the
    watch loop depends on it. Dials are concurrent and bounded; a miss retries on
    the next poll (#194).

  • Terminal outcomes are now recorded under PROSPERO_FLEET=k8s. The usage
    aggregate counts done/failed/killed/crashed from persisted
    status_changed events. The local arm has always emitted them, but the k8s
    watch loop computed the identical transition diff and only broadcast it
    in-memory — so on k8s every outcome facet in the dashboard read zero,
    including for agents that had demonstrably failed. The loop now persists the
    transition it observes, elected by a single-writer observer lease so replicas
    don't multiply the counts
    (#190).

  • The dashboard's usage panel refreshes on its own. It fetched once per
    window selection and never again, so a finished agent's spend could sit
    invisible until the operator toggled the window by hand. It now refetches when
    the fleet poll observes an agent appear, change status, or disappear, and on a
    one-minute heartbeat — without re-running a 30-day store aggregate on every
    five-second poll (#190).

  • A k8s workspace's provider base URL survives an edit. The v2 editor had no
    base-URL input and ProviderInfo did not carry the field, so reopening the
    editor showed a blank box and saving wrote it back — a routine model edit
    silently unpicked a self-hosted provider, after which agents died instantly
    with a ProviderError against localhost
    ([#188](https://github.com/caliban-ai/prospero/issues...

Read more

v0.4.0 — interactive agents under the k8s fleet

Choose a tag to compare

@johnford2002 johnford2002 released this 28 Jul 01:24
e5c7acd

Makes the PROSPERO_FLEET=k8s fleet interactive. Since 0.3.0 a k8s agent
could be launched from the dashboard but never talked to: the reply box renders
only for an agent that is both interactive and idle, and under the k8s
backend neither could ever be true. Closing that took a field on the
authoritative CRD (caliban-operator#28) plus both halves of the round-trip here,
and turned up a second defect — 0.3.3's agent-id decoupling had quietly broken
reply delivery and the 0.3.2 status overlay. Local behavior is unchanged.

Deploy note: requires the caliban-crds chart at >= 0.2.1. Older CRDs
have no spec.task.interactive, so the API server prunes the field at admission
and the flag never reaches the pod.

Added

  • Interactive agents under PROSPERO_FLEET=k8s. The dashboard's
    interactive: true now survives the CR round-trip: build_calibantask
    writes spec.task.interactive (the field caliban-operator#28 added to the
    authoritative CRD) and spawn_spec_from_task reads it back into the
    SpawnSpec sent to the pod's caliband. Previously the flag was silently
    dropped at the CR boundary and the spawn spec hardcoded interactive: false,
    so a k8s agent could never await input and the dashboard reply box
    (interactive && idle) could never appear. Requires the caliban-crds chart
    at >= 0.2.1, or the API server prunes the field at admission
    (#163).

Fixed

  • Operator replies and the interactive/idle overlay now target caliband's own
    agent id.
    #159 decoupled the agent id caliband assigns from prospero's CR
    name, but send_input still attached by CR name (404, reply lost) and
    overlay_pod_status still looked records up by id (silent miss, regressing
    #130's reply box). send_input now resolves the pod's agent via
    ensure_pod_agent, and the overlay matches each pod's record by endpoint
    rather than by id. The pre-existing tests used one string for both ids, so
    they passed while the real path was broken; the new tests use distinct ids
    (#163).

v0.3.3

Choose a tag to compare

@johnford2002 johnford2002 released this 19 Jul 15:54
fb29e42

Completes the PROSPERO_FLEET=k8s control plane so a spawned agent actually runs: the previous two fixes (v0.3.2) let the caliband pod bind and decoupled spawn from reconcile, but nothing ever started the agent inside the pod. Local behavior is unchanged.

Fixed

  • k8s agents now actually start (and stream). Under the k8s backend, spawning created the CalibanTask CR and a caliband pod but never started the LLM run — caliband is a passive supervisor that begins an agent only on CtlRequest::Spawn, and prospero's session plane only attached, so the attach looped forever on agent not found. prospero now spawns the agent in the pod's caliband (list-or-spawn, one agent per pod) from the CalibanTask prompt, then attaches — idempotent across poll cycles and replicas (ownership-lease-gated). Because caliband assigns the agent id itself, the attach id is decoupled from prospero's stream key (the CR name) so output still streams to the dashboard under the identity /stream expects (#159) (#160).

Image: ghcr.io/caliban-ai/prospero:0.3.3

v0.3.1

Choose a tag to compare

@johnford2002 johnford2002 released this 15 Jul 02:27
13193d8

Bug-fix follow-up to the 0.3.0 Kubernetes config plane, closing the four issues
surfaced in k8s smoke testing on a fresh 0.3.0 deploy. The PROSPERO_FLEET=k8s
fleet now stays Ready through a schema-skewed custom resource, surfaces the
registered Workspace CRs it manages (instead of a synthetic phantom), and
rejects an unregisterable workspace up front. Local behavior is unchanged.

Fixed

  • A single un-deserializable CalibanTask no longer wedges the whole fleet.
    K8sFleet's watch/readiness path listed CalibanTasks strictly, so one CR
    that failed to deserialize (e.g. a stale task predating the now-required
    workspaceRef field) failed the entire poll — the fleet never populated,
    /readyz stuck at 503, and the pod never became Ready. The list is now
    decoded per-item, skipping and logging the bad CRs
    (#148)
    (#152).
  • The k8s fleet snapshot reconciles with the Workspace registry.
    GET /api/fleet synthesized a single phantom k8s workspace and never read
    the registered Workspace CRs, so a registered workspace was invisible in the
    dashboard while the synthetic k8s entry reported workspace not registered.
    The snapshot now surfaces the registered Workspace CRs (agents grouped by the
    workspace they reference), so /api/fleet and /api/workspaces agree and a
    fresh deploy shows no phantom
    (#149,
    #151)
    (#153).
  • Add-workspace rejects an invalid workspace as 400, not a raw apiserver
    422.
    The dashboard's + add workspace posted a Workspace with empty
    providers/sources, which the CRD (minItems: 1 on both) rejected — so a
    workspace could never be registered from the dashboard. The config plane now
    validates at least one well-formed source and provider before apply (add and
    edit paths), and the form validates the same client-side
    (#150)
    (#154).

v0.3.0 — Kubernetes config plane

Choose a tag to compare

@johnford2002 johnford2002 released this 12 Jul 19:26
e142ff8

The Kubernetes config plane: deploying with PROSPERO_FLEET=k8s is now a
real control plane — create and configure workspaces, and launch provider-bound
agents, from the dashboard — instead of a read-only viewer that returned
405 Method Not Allowed on Save. Workspaces are first-class Workspace custom
resources reconciled by caliban-operator, and the dashboard is backend-aware.
Local behavior is unchanged.

Added

  • Kubernetes config plane (core + API). Under PROSPERO_FLEET=k8s,
    K8sFleet now wires a FleetAdmin over operator-owned Workspace custom
    resources, so POST / PUT / DELETE on /api/workspaces persist and
    manage real configuration — multi-source workspaces, a named-provider list,
    and per-provider credentials referenced by Kubernetes Secret name (prospero
    never reads the Secret) — instead of returning 405. A backend-neutral
    WorkspaceConfig DTO lets one API serve both backends (local projects its
    single-provider subset, unchanged); GET /api/workspaces returns the real
    Workspace CRs with reconciliation status; async workspace writes answer
    202 Accepted; and a spawned agent binds a named provider via providerRef
    (#142)
    (#144,
    #145).
  • Backend-aware dashboard. The dashboard fetches GET /api/capabilities and
    adapts. On k8s it renders a workspace editor (git sources + a named-provider
    list with secretName / key Secret references and a default marker),
    reconciliation status pills (pending / reconciling / ready / failed
    with the failure message on hover), and a launch-modal provider picker; on
    local it is byte-for-byte unchanged
    (#143)
    (#146).
  • GET /api/capabilities — a backend capability seam the dashboard gates its
    controls on (#99)
    (#101).
  • Frontmatter / agent-template support through spawn — a spawn can forward an
    agent-template markdown file to caliband's SpawnSpec.frontmatter_path
    (#6)
    (#102).
  • Guiding Principles & Invariants guide page synthesizing ADRs 0002–0009
    (#74)
    (#104).

Changed

  • The CalibanTask CRD mirror moved from an inline workspace to a
    workspaceRef (plus an operator-pinned status.resolvedWorkspace), matching
    caliban-operator's frozen v1alpha1 contract. Pre-v1; existing cluster CRs
    are recreated under the new schema.

v0.2.0

Choose a tag to compare

@johnford2002 johnford2002 released this 12 Jul 00:33
71552d6

Kubernetes high-availability, a reworked dashboard, and a full QA sweep. A
second QA pass over the real prospero/caliband stack filed 23 findings; all
are fixed here, alongside first-class leader election for the k8s fleet backend
and a new agent-timeline dashboard.

Added

  • Leader election + attach lifecycle for the K8sFleet backend. The
    session-plane attach — the one path that writes an agent's events to the shared
    store/bus — is now gated on a per-agent ownership lease, so with 2+ prosperod
    replicas exactly one replica owns, attaches to, and emits each agent (no more
    duplicate SSE events or racing per-stream seq allocation). Standalone is
    unchanged (SelfOwnsAll); a clustered deploy builds a LeasedOwnership lease
    plus heartbeat. Attach tasks are now promptly torn down on stop/remove/restart,
    and any agent observed Running — including operator- or peer-created ones —
    is streamed by the lease owner
    (#108,
    #112,
    #113)
    (#138).
  • Dashboard agent timeline, tool-call inspector, and run header — a folded
    event timeline with expandable tool-call segments and a per-run turns/outcome
    header (#5)
    (#96).
  • prospero-types crate — the normalized FleetEvent/model DTOs extracted
    into a small, wasm-compatible serde-only crate the WASM dashboard can share
    (#98)
    (#100).

Changed

  • Under PROSPERO_FLEET=k8s, prosperod no longer builds a local
    FleetManager/poll loop; the k8s backend serves directly over the shared
    store/bus (#83)
    (#92).
  • /readyz now reports workspaces_total/workspaces_healthy/
    workspaces_unreachable (was repos_*), and user-facing error wording says
    "workspace" not "repo", matching the vocabulary used everywhere else
    (#116,
    #117)
    (#135).

Fixed

  • Dashboard. Terminal-agent SSE streams no longer reconnect-storm into an
    unbounded, duplicated timeline with runaway memory
    (#105)
    (#128); tool calls resolve
    ok/fail instead of showing "running" forever (paired by tool_use_id)
    (#106)
    (#131); the fleet summary
    shows the workspace count, the misleading $0.0000 cost is gone, and a favicon
    is served (#115,
    #109,
    #119)
    (#134).
  • API. Duplicate workspace registration returns 409 Conflict, not a
    misleading 503 (#111)
    (#139); an unknown agent's
    events endpoint returns 404 instead of 200 []
    (#118)
    (#135); api_key_from_env
    on a keyless provider is rejected at config-set time, and rm no longer races
    a just-spawned agent or lags the fleet view
    (#120,
    #122,
    #123)
    (#137).
  • k8s hardening. The session-plane bearer token is never sent over plaintext
    (#107)
    (#133); unrecognized
    CalibanTask phases map to a terminal state, calibandEndpoint is validated,
    lock poisoning can't wedge the fleet view, the token compare is constant-time,
    and --fleet-backend k8s on a non-k8s build fails before any side effects
    (#114,
    #121,
    #125,
    #126,
    #127)
    (#136).
  • Tests. De-flaked the distributed_bus PG suite under parallel shared-DB
    load (#110)
    (#129) and
    cli_drives_the_full_stack (#85)
    (#94).

v0.1.1

Choose a tag to compare

@johnford2002 johnford2002 released this 06 Jul 00:41
fd948bb

First image built with --features k8s (#90) — PROSPERO_FLEET=k8s now works. Image: ghcr.io/caliban-ai/prospero:0.1.1 (multi-arch). Unblocks the prospero k8s-fleet Helm chart support (helm-charts#17).

v0.1.0 — prosperod container image

Choose a tag to compare

@johnford2002 johnford2002 released this 04 Jul 01:07
35e58c4

Initial release. First containerized and licensed release of the prospero control plane as part of the P0 Kubernetes deployment (epic caliban-ai/caliban#274).

Image

  • `ghcr.io/caliban-ai/prospero:0.1.0` — multi-arch (linux/amd64 + linux/arm64), non-root, prosperod REST/SSE/dashboard on 7878.
  • Also tagged `:latest` and `:sha-`.

Deploy

Helm chart `charts/prospero` in caliban-ai/helm-charts — renders standalone (sqlite + PVC) or clustered (external Postgres, N replicas) from one `topology` value.

Notes

  • This repository is now licensed AGPL-3.0-only, matching its sibling projects.