server@0.89.0
Minor Changes
-
82869db: Distribute observability hooks through a pinned, checksum-verified Go binary bootstrapper. The one-time binary install is capped at 45 seconds and runs in the background wherever the agent supports asynchronous hooks. When the binary can't be installed on a developer machine, the outcome follows the org's "Fail Open During Outages" setting: fail open lets hook events pass, the fail-closed default blocks per provider semantics. The binary downloads from your Speakeasy server domain — the same domain hooks already send telemetry to — so restricted or sandboxed developer environments only ever need that one domain allowed.
-
999c323: Environment entries can now be marked non-secret so their values stay readable after save. Secret entries keep today's encrypt-and-redact behavior; flipping a secret entry to non-secret requires supplying a new value, while flipping a non-secret entry to secret encrypts the stored value in place. Callers that never send the new is_secret flag behave exactly as before (entries default to secret).
-
52aaf58: Add the org-level
hooks_fail_openproduct feature and removeobservability_mode(DNO-497): org admins choose whether agent hooks fail open or fail closed (the default) when the Speakeasy control plane is unreachable or erroring and no policy verdict can be obtained. The setting is delivered to hook senders as anorg_settingsentry in every authenticatedhooks.ingestresponse's effects map, and toggling it records anorganization:hooks_fail_open_enabled|disabledaudit event. The speakeasy-hooks binary caches the last server-confirmed value next to its credential cache and consults it only on the unreachable/5xx branch of verdict resolution — explicit denies, 4xx responses, and the 401/403 credential ratchet keep failing closed regardless. The cached posture expires after 14 days without server confirmation (reverting to fail closed), and successful exchanges re-stamp an unchanged value daily so actively syncing machines never age out.Observability mode is removed outright — fail-open supersedes it (observability mode was equivalent to fail-open plus not creating blocking policies, while also swallowing explicit denies). Generated hook plugins no longer carry a nonblocking variant (
hooksGeneratorVersionbumped, so connected repos republish), and the binary treats a legacy bakednonblockingflag as the fail-open posture so stale plugins keep outage tolerance without bypassing deny decisions. -
1275b21: Add a project-scoped API for manually managing the Skills registry with immutable canonical versions. Project-bound API keys can no longer select a different project through the project header.
-
3edf806: Plugin assignments: organizations using the Speakeasy device agent can now choose which principals receive each plugin. From a plugin's detail page, admins assign an org-wide default (everyone), specific roles, individual members, or email addresses, and the device agent (
agent.getPlugins) delivers each plugin only to its resolved recipients (email, user, and RBAC role membership). New plugins — including the auto-provisioned Default plugin — default to everyone, so nothing stops being delivered; admins can narrow the audience afterward. The assignments section is shown only for device-agent organizations; marketplace installs (Claude, Cursor, Codex) continue to receive every published plugin regardless of assignment. -
f4786b5: Show the currently live (published) plugin version on the plugin detail page.
getPublishStatusnow reportslive_version— the version stamped into the
published plugin.json manifests, read back from the marketplace repo via a
single Contents API call and cached briefly — and the dashboard displays it
next to the publish freshness indicator, so it can be compared directly
against the version plugin clients like Claude Code report for installed
plugins when debugging sync lag.
Patch Changes
- b6f3467: Classify Claude sessions authenticated by company credentials (an API key, gateway/proxy, Bedrock, or Vertex) as
teamfor the account-type cost breakdown. These sessions emit nouser.account_uuid(only a personal Claude subscription, which signs in via OAuth, does), so account attribution previously no-op'd and their entire spend fell into the(unset)bucket. Attribution now always classifies and stampsaccount_type, and these sessions also teach the device-owner bridge (keyed on the per-device id, not the account UUID) so a personal account later seen on the same device can be attributed to its employee; only theuser_accountsentity and billing mode, which key on the absent UUID, are skipped. - dae476c: Persist hook-captured chat messages at their original occurred_at and order transcripts by (created_at, seq) (DNO-536). Previously chat_messages rows were stamped at insert time and read back in insertion order, so downtime backlog replayed from a device's offline spool sorted AFTER the newer live event that triggered the drain — the latest message appeared before older ones. The ingest handler now writes the event's occurred_at (clamped to arrival time so a skewed device clock cannot sort a row into the future) as created_at, and every transcript reader — full lists, keyset pages, risk/search windows — orders by (created_at, seq) with seq as the stable tiebreak. Keyset cursors keep their public seq shape; the anchor row's position is resolved server-side. Non-hook writers (playground, assistants, imports) leave created_at unset and the message store stamps each batch with one shared write-time value, so their ordering semantics are unchanged.
- 2fef155: Add a (chat_id, generation, created_at, seq) index on chat_messages so the DNO-536 transcript ordering — (created_at, seq) within a generation — is served by an ordered index scan and keyset pagination keeps its LIMIT early-stop instead of sorting the generation's full row set per page.
- cb75e1c: Scope the device agent's managed marketplaces to the org's default project plus any project the caller has an assignment in.
agent.getPluginspreviously returned every published marketplace in the org — each synthesizing its always-on observability plugin independent of assignments — so an org with many published projects flooded the device agent with onespeakeasy-observabilityper project. The default project still always surfaces as the org-wide baseline; a non-default project now appears only when the caller has a matching plugin assignment there. - cc8791e: Add project-selectable read and write permissions for skills to RBAC role management.
- a98cbcd: Gate the Skills page by organization entitlement and provision default Skills grants for RBAC-enabled organizations.
- 6429a07: Expand the
hooks.event.durationmetric for DNO-539 dashboard coverage: the unified/rpc/hooks.ingestendpoint now records it (it previously emitted no duration/throughput metric at all, leaving the plugin ingest path invisible to the hooks monitors), and every hooks endpoint now tags the metric with agram.hook.decisionattribute (allow/deny/ask, or none when the endpoint errored before producing a verdict) so allow/deny rates can be charted independently of the processing outcome. Ingest also distinguishes a newunauthenticatedoutcome (keyless requests acknowledged without processing) from the hard-401unauthorizedone. - 49a4aac: Data migration translating organizations still on the removed
observability_modeproduct feature tohooks_fail_open(DNO-497): the new fail-open row preserves the outage tolerance those orgs opted into, and the retired observability_mode rows are soft-deleted. - cbf965c: Accept replayed hook events on hooks.ingest: an optional X-Gram-Replayed header marks deliveries redelivered from a device's offline spool after control-plane downtime. Replayed deliveries claim the idempotency guard for 15 days (covering the devices' 14-day spool retention) (instead of the 10-minute retry-burst window) so competing drain triggers dedupe, and their telemetry rows carry gram.hook.replayed so dashboards can separate backdated backlog from live traffic.
- 7ff9141: Persist the replayed flag on captured chat messages and surface it on risk results: messages redelivered from a device's offline spool after control-plane downtime (X-Gram-Replayed) now carry chat_messages.replayed, and findings produced by scanning them return replayed on the RiskResult type so retroactive findings are distinguishable from live ones.
- 1275b21: Skill version responses now include a
frontmatterfield with every top-level field parsed from the SKILL.md manifest, so spec fields likelicenseand tool-specific extensions likeargument-hintare visible without re-parsing the raw content. - f96b6fb: Unfurl Gram dashboard links shared in Slack with the Speakeasy logo (the dashboard favicon) and a humanized page title. The generated Slack app manifest now registers the dashboard as an unfurl domain and grants links:write, and the trigger webhook answers link_shared events with chat.unfurl.