Repository navigation
Releases: ncecere/pi-durable-platform
Release list
Pi Durable Platform v0.3.0
Images
The platform (the Go server with the web UI):
ghcr.io/ncecere/pi-durable-platform:v0.3.0
ghcr.io/ncecere/pi-durable-platform@sha256:01972d4f8cf6dfa2e79f2834f2643590d2aca43ba705a347aa0d39040d198a36
The agent runtime (one agent per container; the platform starts it):
ghcr.io/ncecere/pi-durable-platform-runtime:v0.3.0
ghcr.io/ncecere/pi-durable-platform-runtime@sha256:c4e967f0ff40df422971303e72bddc3f2225876f55029716f4300ca3126da4a5
Deploy by digest. Verify the signatures with cosign v3 or newer (keyless, GitHub Actions OIDC):
cosign verify ghcr.io/ncecere/pi-durable-platform@sha256:01972d4f8cf6dfa2e79f2834f2643590d2aca43ba705a347aa0d39040d198a36 \
--certificate-identity https://github.com/ncecere/pi-durable-platform/.github/workflows/image.yml@refs/tags/v0.3.0 \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
cosign verify ghcr.io/ncecere/pi-durable-platform-runtime@sha256:c4e967f0ff40df422971303e72bddc3f2225876f55029716f4300ca3126da4a5 \
--certificate-identity https://github.com/ncecere/pi-durable-platform/.github/workflows/image.yml@refs/tags/v0.3.0 \
--certificate-oidc-issuer https://token.actions.githubusercontent.comRelease assets
<image>-v0.3.0-<os>-<arch>.sbom.spdx.json: each image's SBOM (SPDX JSON) for each platform, as attached to the image.<image>-v0.3.0.digest.txt: each image's reference by digest.checksums.txt: SHA-256 of the files above (sha256sum -c checksums.txt).
The SBOM and build provenance are also attached to the images as attestations:
docker buildx imagetools inspect ghcr.io/ncecere/pi-durable-platform@sha256:01972d4f8cf6dfa2e79f2834f2643590d2aca43ba705a347aa0d39040d198a36 --format '{{ json .SBOM }}'.
Pi Durable Platform v0.3.0
"Apps at scale" (2026-10-20), on top of v0.2.0. Apps built on the platform can page and search long lists,
follow conversations with small event streams instead of whole views, steer a reply in progress, create agents safely
on retries, move agents between teams, and serve many people through one connection. It includes database migrations
00018 to 00020: read Upgrading first.
What changed
For apps
- Paging and title search (#8).
GET /v1/agents/{id}/threadstakeslimit, an opaquecursor(the reply's
nextCursor) andq, a case-insensitive title substring; newest activity first. Withoutlimitthe reply is exactly
what it was. A conversation pages backwards withGET …/threads/{thread}?limit=&before=(the reply's
earlierCursor). - Incremental event streams (#9).
GET …/threads/{thread}/events?format=delta&v=1sends asnapshot, then
numbered changes:message.addedandmessage.updated, partial text (partial.set,partial.appended,
partial.cleared), tools (tool.started,tool.updatedwith elapsed time,tool.finished,tool.removed,
tools.set) and the run's state (run). After a reconnect,Last-Event-IDresumes, or a new snapshot comes. Traffic
follows the new tokens, not the conversation's length. Withoutformatthe stream is unchanged. - Steering (#10).
whenBusy: "steer"onPOST …/messagesjoins the reply in progress (after its current tool
round);followUp, the default, queues behind it. - Safe agent creation (#11). An
Idempotency-Keyheader onPOST /v1/teams/{team}/agents: the same key and request
within 24 hours return the first agent (Idempotent-Replayed: true), a different request with the key is 422
idempotency_key_reused, and concurrent retries create one agent.PUT …/agents/by-key/{key}now also works for a
person in their own personal workspace (with a session, a personal API key or an app they connected), so an app can
keep one agent per purpose for each person; those agents are the person's, not service-managed. In shared teams it
stays for service accounts. - OAuth Connect for apps with many people (#12).
prompt=nonereconnects without a page, or returnslogin_required,consent_requiredor
interaction_required.login_hintnames the account the app expects: a different signed-in account is never
connected silently.- A read-only scope,
agents:read(reads only; anything else is 403insufficient_scope). - App secrets (
pdpcs_…): a platform admin issues one to a trusted app (Admin › Settings › Trusted apps; shown
once, at most two). With it, the app follows everyone who connected it on one stream,GET /v1/app/events, and
reads their usage,GET /v1/app/usage. People appear there only as the app's ownsubjectfor them (returned in
the token response and in/v1/me), never by user ID, email or name.
- Usage for several agents (#24). A repeatable
agentId(up to 100) andgroupBy=agent,dayon usage reports.
In the console
- The test chat pages and searches its threads, loads earlier messages, follows the conversation with the delta stream,
offers Steer while a reply runs, and Enter queues a follow-up. - An agent's Settings has Move, with the dry run's summary before confirming (#13): what the target team must offer,
how many shared threads become visible to whom, and what stops applying. Service-managed agents don't move. - Team › Usage groups by agent and day; Admin › Usage filters by connected app; Admin › Settings issues and deletes app
secrets.
MCP
- Tools an MCP server's app keeps for its own interface (
_meta.ui.visibilitywithout"model", the MCP Apps
extension) are never offered to the model. Tool lists stored before this release are read again in the background when
the platform starts. Showing apps' interfaces is roadmap item #51.
Fixed and hardened (the result of an independent review of this release; none was known to be exploited)
- A v0.2 replica serving requests during a rolling upgrade could create keyed agents that weren't service-managed, so
the team's people could read an app's users' conversations. The database now enforces that a keyed agent in a team
that isn't a personal workspace is service-managed (migration00020, which also fixes such rows). - A runtime start always uses the agent's current configuration: a request in flight during a move can't restart the
agent with the old team's model key or MCP servers, and an agent turned off isn't started by a request authorized while
it was on. Thread MCP servers set during a move don't survive it. prompt=noneno longer tells an app whether the browser is signed in as thelogin_hintaccount, unless the person
connected the app or it is trusted.- The app-level event stream names people only by the app's subjects.
- Removing an app from the trusted list deletes its app secrets (audited); trusting it again needs new ones.
qwith NUL or invalid UTF-8 is 400invalid_queryinstead of 500.
Upgrading from v0.2.0
- Back up the platform database.
- Replace both images (the platform and the runtime, by digest) and restart. The platform applies migrations
00018
(agents'service_managedflag, idempotency keys, agent moves),00019(OAuth scopes, app secrets, per-app
subjects, usage attributed to apps) and00020(the database enforces that keyed agents in shared teams are
service-managed) when it starts.- Existing keyed agents (all made by service accounts in shared teams) are marked service-managed: nothing changes for
them. - With several replicas, a rolling upgrade is safe: a v0.2 replica that creates a keyed agent after the migrations
still gets a service-managed one (the database sets it).
- Existing keyed agents (all made by service accounts in shared teams) are marked service-managed: nothing changes for
- Agents upgrade as they wake. Conversation paging, delta streams and steering are served by the agent's runtime.
An agent that was running when you upgraded keeps its old runtime until it hibernates; until then it ignoreslimit
andbefore(the whole conversation comes back),format=delta(whole-view events) andwhenBusy(a follow-up).
Thread list paging and search work at once (the platform serves them). - MCP tool lists are read again once, in the background, for every server registered before this release; a server
that can't be reached keeps its list until the next start. - Apps using OAuth Connect keep working unchanged. To use the new features: store the
subjectfrom the token
response, useprompt=nonewithlogin_hintfor silent reconnects, and ask a platform admin for an app secret to
use the app-level stream and usage. - No new settings.
Rolling back. Going back to v0.2.0's images works with the schema at 00020: v0.2 ignores the new columns and
tables (idempotency keys, app secrets, per-app subjects), treats every keyed agent as service-managed again (so a person's
keyed agents in their personal workspace become service-managed for them: they keep them but can't read them until you
upgrade again), and its by-key inserts get the trigger's protection.
Known limitations
Unchanged from v0.2.0, except these, which this release resolves: no paging, whole-view
events, messages always queue, by-key agents for service accounts only, no idempotency on agent creation, OAuth
Connect without login_hint and prompt=none, and no agent transfer. New or remaining:
- Usage of a shared team agent used through two apps at once is attributed to neither app (usage counts for an app
only when it's unambiguous which app's person the agent is answering). - During a move, the running-agents limit is checked against the old team for a start already under way.
- Delta streams keep a copy of the view per open stream, and the number of open streams per person isn't limited.
- Conversation paging needs the agent's runtime to be v0.3 (see Upgrading).
- The [roadmap]...
Pi Durable Platform v0.2.0
Images
The platform (the Go server with the web UI):
ghcr.io/ncecere/pi-durable-platform:v0.2.0
ghcr.io/ncecere/pi-durable-platform@sha256:3f988afa89eadec2b4f38b132cc34016300e10d11e7c08c0258a6546b195222d
The agent runtime (one agent per container; the platform starts it):
ghcr.io/ncecere/pi-durable-platform-runtime:v0.2.0
ghcr.io/ncecere/pi-durable-platform-runtime@sha256:11a098887c13377c985dae169d7dbbaedc854717b1d277e3cdf5aec45602ce8e
Deploy by digest. Verify the signatures with cosign v3 or newer (keyless, GitHub Actions OIDC):
cosign verify ghcr.io/ncecere/pi-durable-platform@sha256:3f988afa89eadec2b4f38b132cc34016300e10d11e7c08c0258a6546b195222d \
--certificate-identity https://github.com/ncecere/pi-durable-platform/.github/workflows/image.yml@refs/tags/v0.2.0 \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
cosign verify ghcr.io/ncecere/pi-durable-platform-runtime@sha256:11a098887c13377c985dae169d7dbbaedc854717b1d277e3cdf5aec45602ce8e \
--certificate-identity https://github.com/ncecere/pi-durable-platform/.github/workflows/image.yml@refs/tags/v0.2.0 \
--certificate-oidc-issuer https://token.actions.githubusercontent.comRelease assets
<image>-v0.2.0-<os>-<arch>.sbom.spdx.json: each image's SBOM (SPDX JSON) for each platform, as attached to the image.<image>-v0.2.0.digest.txt: each image's reference by digest.checksums.txt: SHA-256 of the files above (sha256sum -c checksums.txt).
The SBOM and build provenance are also attached to the images as attestations:
docker buildx imagetools inspect ghcr.io/ncecere/pi-durable-platform@sha256:3f988afa89eadec2b4f38b132cc34016300e10d11e7c08c0258a6546b195222d --format '{{ json .SBOM }}'.
Pi Durable Platform v0.2.0
"Run it anywhere, safely" (2026-10-19), on top of v0.1.2. The platform now ships deployment manifests, runs
as several replicas, exports metrics and traces, can re-encrypt its secrets, and closes the safety gaps the v0.1.0 notes
listed, plus the findings of an independent review of this release. It includes database migration 00017: read
Upgrading first.
What changed
Deploying
- A Helm chart and a Kustomize base (
deploy/) with RBAC, NetworkPolicies (and a Cilium flavour), Pod Security
restricted, the Kubernetes and Agent Sandbox launchers, an Ingress, a PodDisruptionBudget and a ResourceQuota. The
chart is the source of truth: the Kustomize base is generated from it, and CI checks that the two render the same
objects, with Helm 3 and Helm 4. The chart is published, signed with cosign, to
oci://ghcr.io/ncecere/charts/pi-durable-platformon release tags. CI installs it into a kind cluster with two
replicas and checks the isolation (an agent reaches only its database, the gateway and DNS), using the images built for
the commit under test (#1). - Several platform replicas (#2). Set
replicaCount: 2(the Kustomize componentcomponents/replicas; the chart
adds rolling updates that leave none missing, spreading over nodes and zones and, if you turn it on, a
PodDisruptionBudget). The runtime reports its open streams and its work, the reaper believes that report, only one
replica reaps at a time and starting an agent is serialised across replicas, so no replica can hibernate an agent whose
stream is open on another. Sessions, sign-in and OAuth state, rate limits and thread events were already shared through
PostgreSQL. The design and the inventory of what is per replica are indocs/replicas.md. - Metrics and tracing (#3).
/metricson its own listener (METRICS_ADDR; the chart enables it on port 9090 and
allows nobody to reach it until you say who may), with requests by route pattern, agent wakes (cold, warm pool or
already running), hibernations, model and MCP proxies, OAuth, sign-ins, rate limits, background loops, group re-checks
and database pools. Labels are values the platform defines; no id, email, team name or URL is ever a label. Optional
traces over OTLP/HTTP (OTEL_EXPORTER_OTLP_ENDPOINT). A Grafana dashboard and example alerts are indeploy/grafana/,
and the chart can create a ServiceMonitor, the NetworkPolicy for your scraper and the dashboard ConfigMap.
Operating
pi-durable-platform rekey(#4) re-seals every stored secret (agent credentials, model providers, MCP servers
and the stored identity provider tokens) under the currentENCRYPTION_KEY;--dry-runshows what it would do and
doctorcounts the values still under the previous key. Once it reports none,ENCRYPTION_KEY_PREVIOUScan go. A
test fails for any sealed column it doesn't cover.- A configuration reference (#23).
.env.examplelists every setting, and a test keeps it complete. - The agents database is harder to interfere with (#7). An agent's ownership is a row in its own schema, taken over
only when the owning database session is gone, so another agent's role can't block it. New commandsprune-rolesand
prune-agent-storage.doctorreports agent roles that belong to no agent, and warns when PUBLIC may connect to the
platform database. - Vulnerability checks in CI:
govulncheckand audits of the web app's and the runtime's production dependencies,
weekly and whenever a dependency file changes.
For apps and people
- Platform-chosen thread IDs (#5).
POST /v1/agents/{id}/threadsreturns a new random thread ID. MCP servers are set
only on a thread that exists or that the samePUTcreates (the caller becomes its creator; sendvisibilityon the
PUTfor a private thread). Use thePOSTand your threads can't be pre-seeded. - IdP group re-checks (#6). With
OIDC_ALLOWED_GROUPS, the platform asks the identity provider every 15
minutes (OIDC_GROUP_RECHECK_INTERVAL) whether each recently active person is still in an allowed group. When not,
their sessions, API keys and connected apps stop working, open event streams close, and Admin › People shows "Group
access ended"; signing in again restores access. If the provider can't answer, access lasts a grace period
(OIDC_GROUP_RECHECK_GRACE, 24 hours). It needs the refresh token of the person's sign-in, so theoffline_access
scope. A person without a stored token is never re-checked: this is logged, counted and shown bydoctor.
Fixed and hardened (the result of an independent review of this release; none was known to be exploited)
- The reaper reads a runtime's
/statusthrough a 64 KiB limit; an agent could otherwise send a reply large enough to
exhaust the platform's memory. - Agents whose database role created large objects or stray tables can be deleted;
prune-rolesremoves such leftovers. - An agent's role can no longer block platform start-up by holding the agents database's prepare lock.
- A client's
traceparentno longer forces a request to be traced. - Open event streams re-check access every 30 seconds, so a person who is suspended, denied or removed from a team stops
receiving events. - MCP servers set on a reserved thread ID don't reach another person's first message.
- A stored identity provider token that can't be opened ends access after the grace period instead of exempting the
person; a rotated refresh token survives a restart in the middle of a check; people in more than 200 groups are matched
on the full list. - A status report from an agent's runtime that arrived after a thread was deleted brought the thread back, as a shared
record carrying the deleted thread's title, even for a private thread (in v0.1.x too). A single report now only
updates a thread the platform has; the runtime's list at start-up still adopts threads the platform doesn't know. - A reserved thread (no message yet) can be deleted; the runtime has no conversation for it, so the delete returned 404.
golang.org/x/net0.60.0 fixes four HTTP/2 advisories (GO-2026-6603, -6611, -6612, -6617) thatgovulncheckreports
as reachable. v0.1.2 and earlier are affected.
Upgrading from v0.1.2
-
Back up the platform database (the migration is forward-only in practice: see rolling back).
-
Replace both images (the platform and the runtime, by digest) and restart. The platform applies migration
00017
when it starts.- It deletes MCP servers that were set on a thread nobody had started (earlier releases accepted them, and a later
private thread with that ID would have inherited them) and makes a thread's servers belong to its record from then on. - It adds the tables for group re-checks. Nobody is re-checked until they sign in again, so nobody is locked out by the
upgrade. - With several replicas, a rolling upgrade runs both versions for a while: until every replica is upgraded, a request
to set MCP servers on an unrecorded thread can fail against the new reference. Apps that use
POST /v1/agents/{id}/threadsare unaffected.
- It deletes MCP servers that were set on a thread nobody had started (earlier releases accepted them, and a later
-
Agents upgrade as they wake. An agent that was already running keeps its old runtime until it hibernates; until
then it doesn't reportopenStreams, so the reaper judges it by the streams of the replica it is on. An agent database
from v0.1.x opens with the new runtime without any step. -
Keep agents' roles out of the platform database. Run
pi-durable-platform doctor. If it warns that PUBLIC may
connect, run on the server (as the platform database's owner):REVOKE CONNECT ON DATABASE <platform database> FROM PUBLIC; GRANT CONNECT ON DATABASE <platform database> TO <the platform's role>;
and the same
REVOKEfor the other databases on that server that agents must not reach, or limit agent roles to the
agents database inpg_hba.conf(a rule is in [`deploy/examples/cloudnative-pg/...
Pi Durable Platform v0.1.2
Images
The platform (the Go server with the web UI):
ghcr.io/ncecere/pi-durable-platform:v0.1.2
ghcr.io/ncecere/pi-durable-platform@sha256:c20916ab720cc5353e17d8ad5d7c12a50fd637b9cbedc1e453f1a99ca6db6deb
The agent runtime (one agent per container; the platform starts it):
ghcr.io/ncecere/pi-durable-platform-runtime:v0.1.2
ghcr.io/ncecere/pi-durable-platform-runtime@sha256:7b61a2af7b1c4aafec78ec0c5af4e9ae8e6978c1bfd375d9fea9f0b52e32c983
Deploy by digest. Verify the signatures with cosign v3 or newer (keyless, GitHub Actions OIDC):
cosign verify ghcr.io/ncecere/pi-durable-platform@sha256:c20916ab720cc5353e17d8ad5d7c12a50fd637b9cbedc1e453f1a99ca6db6deb \
--certificate-identity https://github.com/ncecere/pi-durable-platform/.github/workflows/image.yml@refs/tags/v0.1.2 \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
cosign verify ghcr.io/ncecere/pi-durable-platform-runtime@sha256:7b61a2af7b1c4aafec78ec0c5af4e9ae8e6978c1bfd375d9fea9f0b52e32c983 \
--certificate-identity https://github.com/ncecere/pi-durable-platform/.github/workflows/image.yml@refs/tags/v0.1.2 \
--certificate-oidc-issuer https://token.actions.githubusercontent.comRelease assets
<image>-v0.1.2-<os>-<arch>.sbom.spdx.json: each image's SBOM (SPDX JSON) for each platform, as attached to the image.<image>-v0.1.2.digest.txt: each image's reference by digest.checksums.txt: SHA-256 of the files above (sha256sum -c checksums.txt).
The SBOM and build provenance are also attached to the images as attestations:
docker buildx imagetools inspect ghcr.io/ncecere/pi-durable-platform@sha256:c20916ab720cc5353e17d8ad5d7c12a50fd637b9cbedc1e453f1a99ca6db6deb --format '{{ json .SBOM }}'.
Pi Durable Platform v0.1.2
A fix release (2026-10-19) on top of v0.1.1: two console fixes. No database migrations (still 00016), no
configuration changes.
What changed
Fixed
- A connecting app's logo shows. An app that connects with OAuth Connect can publish a logo. The approval screen,
Account › Connected apps and a person's admin page showed a broken image, because the console's
Content-Security-Policy allows images only from the platform itself. The platform now fetches the logo (public
addresses only, https only, no redirects, at most 256 KiB, PNG, JPEG, GIF or WebP verified by their bytes, never SVG),
caches it for an hour and serves it from its own origin atGET /v1/oauth/client-logo?client_id=…(signed-in people
only, rate limited). The request never carries a URL, so it can't be used to fetch arbitrary addresses (#25). - The agent page's status badge follows the agent. After a message woke a hibernated agent from another session or an
app, the badge kept saying "Hibernating" until the next poll or a reload. The page now follows the agent's events
(#27).
Upgrading from v0.1.1
Replace both images (the platform and the runtime, by digest) and restart. There are no migrations and no new settings.
Known limitations
Unchanged from v0.1.0. The roadmap plans each one, and each has a GitHub
issue with the roadmap label.
Images
| Image | What |
|---|---|
ghcr.io/ncecere/pi-durable-platform |
The platform (distroless, UID 65532, read-only root filesystem) |
ghcr.io/ncecere/pi-durable-platform-runtime |
The agent runtime (Node 22, UID 10001, read-only root filesystem with a writable /tmp) |
Both are tagged v0.1.2 and latest, for linux/amd64 and linux/arm64. Deploy by digest. The digests are in the GitHub
Release, its <image>-v0.1.2.digest.txt assets and the workflow's job summary.
Verifying the images
Verify the signatures with cosign v3.0 or newer
(keyless, GitHub Actions OIDC):
cosign verify ghcr.io/ncecere/pi-durable-platform@sha256:<digest> \
--certificate-identity https://github.com/ncecere/pi-durable-platform/.github/workflows/image.yml@refs/tags/v0.1.2 \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
cosign verify ghcr.io/ncecere/pi-durable-platform-runtime@sha256:<digest> \
--certificate-identity https://github.com/ncecere/pi-durable-platform/.github/workflows/image.yml@refs/tags/v0.1.2 \
--certificate-oidc-issuer https://token.actions.githubusercontent.comThe SBOM (SPDX) and build provenance are attached to each image as attestations, and the Release carries each image's
SBOM per platform with checksums.txt. pi-durable-platform version prints pi-durable-platform 0.1.2 (<commit>);
the runtime image is labelled org.opencontainers.image.version=0.1.2.
Reporting problems
Open an issue at https://github.com/ncecere/pi-durable-platform/issues. Report security problems privately as
SECURITY.md describes.
Pi Durable Platform v0.1.1
Images
The platform (the Go server with the web UI):
ghcr.io/ncecere/pi-durable-platform:v0.1.1
ghcr.io/ncecere/pi-durable-platform@sha256:ef046ad6534aa056adf0f10b1a9e41d5e93793e17e911b8cefab750dd909b147
The agent runtime (one agent per container; the platform starts it):
ghcr.io/ncecere/pi-durable-platform-runtime:v0.1.1
ghcr.io/ncecere/pi-durable-platform-runtime@sha256:a7adb0c5f7913ff2f2ffd7783301f81d23caeeceb8d68abd48838e178d9d1168
Deploy by digest. Verify the signatures with cosign v3 or newer (keyless, GitHub Actions OIDC):
cosign verify ghcr.io/ncecere/pi-durable-platform@sha256:ef046ad6534aa056adf0f10b1a9e41d5e93793e17e911b8cefab750dd909b147 \
--certificate-identity https://github.com/ncecere/pi-durable-platform/.github/workflows/image.yml@refs/tags/v0.1.1 \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
cosign verify ghcr.io/ncecere/pi-durable-platform-runtime@sha256:a7adb0c5f7913ff2f2ffd7783301f81d23caeeceb8d68abd48838e178d9d1168 \
--certificate-identity https://github.com/ncecere/pi-durable-platform/.github/workflows/image.yml@refs/tags/v0.1.1 \
--certificate-oidc-issuer https://token.actions.githubusercontent.comRelease assets
<image>-v0.1.1-<os>-<arch>.sbom.spdx.json: each image's SBOM (SPDX JSON) for each platform, as attached to the image.<image>-v0.1.1.digest.txt: each image's reference by digest.checksums.txt: SHA-256 of the files above (sha256sum -c checksums.txt).
The SBOM and build provenance are also attached to the images as attestations:
docker buildx imagetools inspect ghcr.io/ncecere/pi-durable-platform@sha256:ef046ad6534aa056adf0f10b1a9e41d5e93793e17e911b8cefab750dd909b147 --format '{{ json .SBOM }}'.
Pi Durable Platform v0.1.1
A fix release (2026-10-18) on top of v0.1.0: small console fixes found while preparing the documentation
and screenshots, doctor checking the agents database, a read-only console path for platform staff to any team's
agents, and the product's logo. No database migrations (still 00016), no configuration changes.
What changed
Added
doctorchecks the agents database. It connects toAGENTS_DATABASE_URLand checks that its role can provision
agents (CREATEROLE, andCREATEon the database, on PostgreSQL 16 or later). Skipped without an agents database;
reported as info whenAGENTS_CREATE_DATABASEwill create it.- Platform staff read any team's agents. Platform admins and auditors see every team's agents read-only
(GET /v1/teams/{team}/agents,GET /v1/agents/{id}), not only personal workspaces'. Admin › Teams › a team has an
Agents tab linking to each agent's page: Overview and Settings, Conversations for platform admins (reading one still
takes a reason), and no Test. - The product's logo, "Wake". The sidebar, the sign-in page and the session-unavailable page show Pi Durable
Platform's mark when the instance has no logo of its own (UI_LOGO_URLstill replaces it); the favicon is the mark,
with afavicon.icoand anapple-touch-icon.png.
Changed
- Staff can't hibernate other teams' agents. In v0.1.0 platform staff could hibernate a personal workspace's agent
(POST /v1/agents/{id}/hibernate); now only the agent's team can, and staff get 403. Staff access to agents is
read-only everywhere.
Fixed
- Sign-in: the "Help signing in" link uses the app's link colour.
- Home: the Agents card no longer shows an empty strip (it links to All agents and the Catalog).
- Admin › Models and MCP servers: the Owner filter's chevron no longer overlaps its text (every small select).
- Admin › Templates: the review queue and the full list each have a heading, and the queue's table a name.
- Admin › Settings › Private networks: the example placeholder shows only while no network is listed.
- Audit log: every action the platform records has a label, with areas in the filter and target type names.
- Platform admins' conversation list says "Title hidden" for a withheld title instead of "Private conversation";
Visibility says who sees the thread. - Agent Test chat: the header's Shared icon stays on the line with its word.
Upgrading from v0.1.0
Replace both images (the platform and the runtime, by digest) and restart. There are no migrations and no new
settings. Run pi-durable-platform doctor afterwards: it now also checks the agents database.
Known limitations
Unchanged from v0.1.0. The roadmap plans each one, and each has a GitHub
issue with the roadmap label.
Images
| Image | What |
|---|---|
ghcr.io/ncecere/pi-durable-platform |
The platform (distroless, UID 65532, read-only root filesystem) |
ghcr.io/ncecere/pi-durable-platform-runtime |
The agent runtime (Node 22, UID 10001, read-only root filesystem with a writable /tmp) |
Both are tagged v0.1.1 and latest, for linux/amd64 and linux/arm64. Deploy by digest. The digests are in the GitHub
Release, its <image>-v0.1.1.digest.txt assets and the workflow's job summary.
Verifying the images
Verify the signatures with cosign v3.0 or newer
(keyless, GitHub Actions OIDC):
cosign verify ghcr.io/ncecere/pi-durable-platform@sha256:<digest> \
--certificate-identity https://github.com/ncecere/pi-durable-platform/.github/workflows/image.yml@refs/tags/v0.1.1 \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
cosign verify ghcr.io/ncecere/pi-durable-platform-runtime@sha256:<digest> \
--certificate-identity https://github.com/ncecere/pi-durable-platform/.github/workflows/image.yml@refs/tags/v0.1.1 \
--certificate-oidc-issuer https://token.actions.githubusercontent.comThe SBOM (SPDX) and build provenance are attached to each image as attestations, and the Release carries each image's
SBOM per platform with checksums.txt. pi-durable-platform version prints pi-durable-platform 0.1.1 (<commit>);
the runtime image is labelled org.opencontainers.image.version=0.1.1.
Reporting problems
Open an issue at https://github.com/ncecere/pi-durable-platform/issues. Report security problems privately as
SECURITY.md describes.
Pi Durable Platform v0.1.0
Images
The platform (the Go server with the web UI):
ghcr.io/ncecere/pi-durable-platform:v0.1.0
ghcr.io/ncecere/pi-durable-platform@sha256:15d1335db6c44d4499cef90097675320e8349a78bfc8b21b3d33e7a0588ef059
The agent runtime (one agent per container; the platform starts it):
ghcr.io/ncecere/pi-durable-platform-runtime:v0.1.0
ghcr.io/ncecere/pi-durable-platform-runtime@sha256:2621a07f708fcdab089bba4384da08932d278e350fc55a985d178a498df55b35
Deploy by digest. Verify the signatures with cosign v3 or newer (keyless, GitHub Actions OIDC):
cosign verify ghcr.io/ncecere/pi-durable-platform@sha256:15d1335db6c44d4499cef90097675320e8349a78bfc8b21b3d33e7a0588ef059 \
--certificate-identity https://github.com/ncecere/pi-durable-platform/.github/workflows/image.yml@refs/tags/v0.1.0 \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
cosign verify ghcr.io/ncecere/pi-durable-platform-runtime@sha256:2621a07f708fcdab089bba4384da08932d278e350fc55a985d178a498df55b35 \
--certificate-identity https://github.com/ncecere/pi-durable-platform/.github/workflows/image.yml@refs/tags/v0.1.0 \
--certificate-oidc-issuer https://token.actions.githubusercontent.comRelease assets
<image>-v0.1.0-<os>-<arch>.sbom.spdx.json: each image's SBOM (SPDX JSON) for each platform, as attached to the image.<image>-v0.1.0.digest.txt: each image's reference by digest.checksums.txt: SHA-256 of the files above (sha256sum -c checksums.txt).
The SBOM and build provenance are also attached to the images as attestations:
docker buildx imagetools inspect ghcr.io/ncecere/pi-durable-platform@sha256:15d1335db6c44d4499cef90097675320e8349a78bfc8b21b3d33e7a0588ef059 --format '{{ json .SBOM }}'.
Pi Durable Platform v0.1.0
This is Pi Durable Platform's first release (2026-10-18). Pi Durable Platform is a self-hosted console and API where teams deploy, test and manage agents built with Pi and its durable package. Each agent runs in its own runtime, keeps its state in its own PostgreSQL schema, and hibernates when idle. People don't chat with agents in the console: a team's own apps (a chat app, a support tool) reach its agents through the platform API. The full list of changes is in the changelog, and the design in DESIGN.md.
Pi Durable Platform is an independent project. It is not affiliated with or endorsed by Earendil.
v0.1.0 ships two images: the platform (one Go binary with the React web UI embedded, backed by PostgreSQL 17) and the agent runtime (Node, one agent per container). Migrations 00001 to 00016.
What's in it
- Teams and roles. Platform roles
platform_adminandplatform_auditor; team roles owner, admin, editor and member. Platform admins create teams and assign owners; owners and admins manage members and invites. The authorization rules are pure functions (internal/authz), and a test classifies every operation inapi/openapi.yamlfor every kind of caller. - Personal workspaces. While platform admins have them turned on, each person who signs in gets a team of kind
personalwith themselves as its only member. Personal workspaces deploy catalog templates only. Platform admins set defaults (max agents, max running, a monthly budget) and override them per workspace, and choose whether personal workspaces may add their own model providers and MCP servers (off by default). Platform admins and auditors see a workspace, its agents, usage and audit log, but not its conversations. - Templates and the reviewed catalog. Templates are versioned; each agent is pinned to a version and can move to another (upgrade or roll back), applied at its next start. Platform admins curate platform templates. Teams write their own, and submit them to the catalog; a platform admin approves or rejects the request with a note.
- Agents. Team editors deploy agents from templates and test them in the console. Each agent gets its own schema and database role in a separate agents database (
AGENTS_DATABASE_URL), and a session advisory lock on its only connection makes sure only one runtime writes for it. Service accounts create service-managed agents by external key (PUT /v1/teams/{team}/agents/by-key/{key}), for example one per user of an app. Only the team's service accounts use those; owners and admins see and delete them but don't read them.prune-agent-storageremoves storage no agent owns. - Launchers (
AGENTS_LAUNCHER).local: child processes of the platform, for development.kubernetes: one pod per agent (no service-account token, non-root, read-only root filesystem, all capabilities dropped, optionalAGENTS_RUNTIME_CLASSsuch as gVisor), with its secrets in a per-agent Secret.agent-sandbox: a Kubernetes Agent Sandbox per agent, suspended when idle; or, withAGENTS_SANDBOX_WARM_POOL, a standby runtime claimed from aSandboxWarmPooland activated as the agent (POST /activatewith the pool's activation token), so a wake skips scheduling, image pull and Node start-up. - Hibernation and wake. Agents with no work in progress, no open event streams and no recent requests hibernate after
AGENTS_IDLE_TIMEOUT(default 10 minutes): no pod, no database connection. The next request wakes them, and work in flight resumes from storage. Team members can hibernate an agent by hand (POST /v1/agents/{id}/hibernate). - Model catalog. Platform admins add providers: OpenAI (Responses API), Anthropic (Messages API), and servers compatible with OpenAI chat completions (LiteLLM, vLLM, Ollama, OpenRouter and others), the OpenAI Responses API or the Anthropic Messages API. "Discover models" lists what a provider offers. Models are published to every team, to chosen teams, and optionally to personal workspaces. Each provider is either proxy (default: agents call the platform's model gateway with their own credential, and the gateway checks the model, adds the key and records usage) or direct (agents get the URL and key). Team owners and admins add the team's own providers and models (proxy only, through the address guard, for that team alone). Models carry input and output prices. Usage reports (
GET /v1/teams/{team}/usage,GET /v1/admin/usage) sum requests and tokens per day, model, agent or team, with a cost estimate from current prices. The runtime reports usage for models the gateway doesn't see (direct providers, the default model). - MCP catalog. Platform admins add remote MCP servers (Streamable HTTP) with sealed headers and publish them. The platform reads and keeps each server's tool list. A template version gives its agents servers and all or some of their tools; tools are named
mcp__<slug>__<tool>, and more than 20 are deferred behindtool_search. Calls go through the gateway's MCP proxy by default, which adds the headers, refuses tools the version left out and logs each call. Teams add their own servers (proxy only, through the address guard). Apps may give an agent their own MCP servers for one thread (mcpServerswith a message, orPUT .../threads/{thread}/mcp-servers), for hosts inAGENTS_CLIENT_MCP_HOSTS(none by default), with headers sealed until they expire. - Threads. The platform keeps a record of each thread (
agent_threads), so listing doesn't wake the agent: title, created and updated times, busy, last reply and last error, creator and participants.GET /v1/agents/eventsstreams thread changes for every agent the caller may use;GET .../threads/{thread}/eventsstreams one conversation's view. A thread is shared or private (chosen by its first message; private threads are visible only to the person or service account that started it, and read as not found to everyone else). The platform sets each message's author, and on shared threads of shared teams the model is told who is speaking. Messages carry their time, the model, token usage, stop reason and tool timings. Platform admins can list any agent's threads and read one conversation with a stated reason (10 to 500 characters), recorded in the team's audit log before the conversation is returned. - Service accounts and personal API keys. Team service accounts with a team role and expiring keys (
pdp_sa_…, 1 to 365 days, two active at a time for rotation). Personal API keys (pdp_…) act as their person. - OAuth Connect. The platform is a small OAuth 2.1 authorization server, so an app can act as the person who connects it: discovery (RFC 8414 and RFC 9728), PKCE (S256, required), Client ID Metadata Documents or Dynamic Client Registration, a consent page, 1-hour access tokens and rotating 30-day refresh tokens with reuse detection, revocation, and trusted apps that skip consent. App tokens act as the person without their platform role, on the agent routes and a few read routes.
- Audit log. Append-only, written in the same transaction as each change. Team audit logs for editors and above, and a platform log for admins and auditors.
- Sign-in. OIDC (any provider), optionally limited to email domains or IdP groups (
OIDC_ALLOWED_GROUPS), with a bootstrap admin subject. Development personas (DEV_AUTH=true: admin, auditor, user, alex, blair and casey), refused unlessAPP_URLis a loopback address. - Operations.
pi-durable-platform doctorchecks the configuration, the production safety rules, PostgreSQL, the API key pepper and the migration state.migrateapplies migrations under an advisory lock (MIGRATE_ON_STARTdoes it at start-up)./healthzand/readyz. Rate limits are counted in PostgreSQL.
Security model
- One enforcement point. Clients reach agents only through the platform API, which authenticates, ...