CHANGELOG.md
Rama main · réplica de lectura del repositorio original.
# Changelog
All notable changes to Crewship are documented in this file.
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
Pre-1.0 releases may introduce breaking changes in minor versions
(`0.x.0`); patch releases (`0.x.y`) are backwards-compatible fixes.
## [Unreleased]
- **Routine run logs show when a step waits for an occupied agent (#5290).** The journal records when waiting begins and whether the agent becomes available, the wait times out, or the run is cancelled. The outcome includes elapsed wait time.
- ⚠️ **Behaviour change: routine budgets include costs reported by every agent attempt.** Reported costs from empty responses, failed attempts, and attempts preceding cancellation during backoff now count toward the run total. A routine close to its configured cost cap can stop earlier.
- ⚠️ **Behaviour change: Claude Code routine attempts use a 20-turn limit.** The routine runner now passes the existing unattended-run limit to Claude Code. Other CLI adapters use the execution timeout.
- **Routine validation rejects unsupported step controls.** Definitions with `permissions` or `max_turns` on a step now identify the offending field during validation.
- **Dependency updates keep the frontend, document editor and Go runtime libraries current (#5280).** Integrates the pending Dependabot updates and refreshes version-scoped license notices for packages that ship no license text. ⚠️ **Behaviour change:** authentication now explicitly requires compact JWE tokens, matching the tokens Crewship issues; JSON-serialized JWE messages are rejected.
- **The CLI says when a profile overrides an exported `CREWSHIP_SERVER` (#5245).** Run outside a directory bound to a profile, a command went to the `server use` default instead of the exported server, and that server's answers looked like faults of the intended one (on crewship-dev, an intermittent `503 Docs are not enabled on this server` from a slot without Docs). The precedence is unchanged; the CLI now prints one warning line on stderr naming the profile and the server it dials. An explicit `--profile` or `CREWSHIP_PROFILE` prints nothing.
- **Canvas cards name mentioned people as the Page does (#5197).** A card resolves a mention through the same reader-scoped people lookup as the Page editor, so it shows a name only for someone who can read the document, and only to its readers; anyone else stays **@Unknown member**. The Canvas no longer uses the workspace member list.
- **Docs presence is one entry per person (#5166).** A person with several tabs on a document is now one peer with a `tabs` count and the caret of the tab that moved last, instead of one caret per tab. A tab also no longer answers a selection update that did not move its caret with an extra heartbeat, and no longer redraws the other people's carets when a reply did not change, so it stays at one heartbeat a second while idle.
- **Docs presence is one entry per person (#5166).** A person with several tabs on a document is now one peer with a `tabs` count and the caret of the tab that moved last, instead of one caret per tab; a tab without a caret (such as `crewship doc presence`) never hides a tab that has one. A tab also no longer answers a selection update that did not move its caret with an extra heartbeat, so it stays at one heartbeat a second while idle.
- **The Design Library shows themes instead of `-dark` swatches (#5145, behind `NEXT_PUBLIC_ARTIFACT_DESIGN_SYSTEM`).** `design-system.json` schema 2 adds `themes`, per-theme colour values with a usage note, `{name}` aliases and type groups; schema 1 files are read unchanged and a newer schema is named instead of shown in part. The Library has a theme switch for swatches and component previews, the WCAG contrast of each swatch, usage notes, grouped text styles and a note when the system carries no font files. The Template Crewship Design System mirror now uses its two real themes.
- **A full storage quota no longer blocks saving a Word or Sheet document for the rest of the session (#5124).** After a refused save the editor keeps the changes and says they are not yet saved on the server; **Uložit znovu** in the alert or Ctrl+S sends them again, and once space is freed they are saved as a new version. Autosave still never retries a quota refusal by itself, and no version is deleted. The status line now tells 95 % (*historie je téměř plná*) and a full history apart from 80 %.
- **Releasing a saved Word or Sheet document no longer shows an unsaved draft (#5089).** A final capture with the exact bytes of the last confirmed save now counts as that version, so the status stays honest, the leave guard releases and no copy waits in the browser to be offered later.
- **Deleting an agent stops its runs whose container is already gone (#5050).** A protected host run in a removed container stayed pending and held on to its work; it now counts as stopped. Any other inspect failure still reports an error.
- ⚠️ **Behaviour change: only OWNER or ADMIN can change the governance model credential (#5024).** PATCH, rotate, escalation answers, OAuth completion and internal token writes refuse a bound credential for narrower roles, and `credential.rotate` no longer reaches it. Binding now needs an active credential.
- **A delayed sign-out no longer removes unsent chat proposals (#5026).** If a tab learns of a sign-out after its person signed back in, it now keeps their chat recovery. A real sign-out still removes it, even when saving drafts fails.
- ⚠️ **Behaviour change: invalid native version reads now return exit code 2 instead of 1 (#4930).** `crewship craft version` classifies non-positive, non-canonical and overflowing version numbers as validation errors before authentication or any HTTP request. Scripts must now expect process exit 2 and `error.exit_code: 2` in machine-readable errors. Negative positional versions are passed after `--` so they reach version validation.
- **A Design comment sent to an agent no longer produces a duplicate version (#4527).** The task prompts from the Design editor, `crewship page design comment --send-to-agent --wait` and the chat bridge told the agent to call `design_snapshot` after `design_apply`. A successful `design_apply` already saves the version and answers the comment, so the agent saved the same canvas twice. The prompts now say not to snapshot afterwards, matching the `crewship-design` skill, and the PRD acceptance test requires exactly one agent version and no `design_snapshot` call.
- **A failed release or handoff in Word and Sheet can be tried again (#5028).** A network error during the transfer used to leave the other person blocked until the holder closed the tab.
- **Accepting an agent proposal in Word no longer goes stale when nothing was edited (#4699).** Word rewrites a document into its normalized form when it opens it, so the save before accepting, handing over or releasing the editor wrote that rewrite as a new version and every proposal over the opened version became stale. The native editor host now passes the engine's revision state right after bootstrap (`loaded.mountedState`). The save coordinator treats an export as the loaded version only when no edit was reported and the engine's own revision is still the bootstrapped one, so a change whose `changed` event arrives late is still saved. Nothing is sent and the action continues on the loaded version, and an untouched final capture no longer leaves a local draft to offer on the next open. Edits and a native Ctrl+S still save. Sheet, whose engine reports no revision state, and hosts that do not pass the state keep the earlier behaviour.
- **A tab whose draft save failed during a sign-out keeps following later sign-outs (#4714).** The sign-out and expiry listeners used a sticky flag, reset by hand on each path where the tab stays. After a failed draft drain followed by a refresh from a still-mounted component, the flag stayed set and every later sign-out or expiry was ignored, so a shared browser kept the previous person's editors open. The listeners now compare against the refresh generation: any newer refresh or settle re-arms them. A sign-out superseded by a refresh during its drain, and an expiry during a re-settle (exactly one navigation), are now covered by tests.
- **Design canvases can be played as prototypes (#4449, default off).** With `NEXT_PUBLIC_ARTIFACTS_DESIGN_PROTOTYPE=true` (on top of `NEXT_PUBLIC_ARTIFACTS_DESIGN`), an editor links a layer to a screen in **Properties → Link to screen**, and anyone who can open the Design clicks **Play** to move between linked screens with mouse or keyboard, **Back** and **Esc**. Playback is local and never changes the canvas; a link to a deleted screen stays inert with a hint. The link is the optional node field `linkTo`, set through the existing live sync, `page design apply` and agent `design_apply`; no new endpoint or migration. The server now accepts `linkTo` (string, at most 128 characters), so deploy the server before enabling the UI variable.
- **A tab that stayed signed in after a sign-out elsewhere still follows later sign-outs (#4705).** When a delayed sign-out message from another tab found the session still live, the tab stayed but then ignored every later sign-out and session expiry, keeping the person's editors open on a shared browser until its next refresh. It now keeps listening.
- **Text typed before the session check answers is no longer wiped (#4706).** Since #4628 every session check that changed the local draft identity remounted the whole app, including the first one after a page load and signing in from a signed-out page, so a Share ID on `/shared-chat`, sign-up fields or the bootstrap step entered meanwhile disappeared. The app now remounts only when it leaves a signed-in person (another person, or signed out), which still retires that person's local draft writers; refreshing the same person never remounts.
- **Normal CLI chat turns can write their enabled memory again.** Each host-authorized turn now owns a fenced work-ledger attempt before execution, using the existing serial capacity limits and rechecking the original human authority at process creation. Ended or stale turns still cannot write; an unknown execution outcome keeps custody until protected exit evidence is recovered (#2762).
- **Memory audit keeps running when a directory cannot be watched (#4568).** A per-directory watch failure (an unreadable directory, or an exhausted `fs.inotify.max_user_watches`) is logged and skipped instead of disabling memory audit until restart, and if the file watcher cannot start the audit continues on polling alone. The audit watcher now applies its documented 30 s poll fallback, which production previously left off, so `memory_versions` and `memory.updated` keep recording writes.
- **Truncated multibyte text stays valid UTF-8 (#4566).** Hook messages and output, HTTP hook errors, the backup flush-hook detail and TUI dashboard cells no longer cut a character in half (shown as U+FFFD and rejected by strict JSON consumers); dashboard cells now count characters rather than bytes.
- **Native Craft agent tasks now respect the workspace agent artifact policy (#4681).** The policy is the ceiling for agent work on artifacts and already gated Projects, Design, Documents and Mooring, but `crewship craft task start` admitted a Word or Sheet task for an agent whose crew was not listed, or under a disabled policy, once the owner gave whole-document consent. Task admission now refuses it (`403`, nothing queued), and every agent write rechecks the policy (a policy change already retired running tasks through the authority generation; the explicit check keeps that independent of the trigger).
- **Accepting a Craft proposal no longer goes stale when a concurrent save repeated the same bytes, and the proposals migration now moves the schema version (#4669).** A save that landed between choosing the acceptance base and publishing, with content identical to the base, used to retire the proposal permanently; acceptance now re-reads the head, retries on it when the content is unchanged and goes stale only when the content really changed. A no-op migration `20261031100000_craft_native_proposals_frontier` is added because `craft_native_proposals` (20261029165715) was numbered below the previous newest migration, so a rollback to the old binary passed the version-skew guard and its backup left out the table. The applied migration is untouched and databases keep all data.
- **Craft access rechecks and native agent edits: four backend fixes (#4670).** The `page.access_recheck` fan-out is now registered as background work, bounded to four running plus 64 waiting fan-outs (further ones are dropped; the 30 s poll covers them) and gives up after 5 s against a hub that stopped draining. A native agent `apply`/`propose` refused at storage admission (`ErrStorageBusy`/quota) no longer burns its request ID, so the same retry runs the engine instead of failing with 422. The lease-renewal goroutine no longer shares its context variable with the request goroutine (data race). Legacy document, Slides and restore writes remain bounded by the SQL storage triggers; the free-disk probe is not on those paths (follow-up).
- **Artifacts docs and agent skills corrected after the #4527 review (#4527).** The `crewship-design` skill (1.0.1) now says that the workspace artifact policy must be enabled and list the agent's crew; the `crewship-craft` skill (1.0.1) states the 32 KiB cell-input limit and that a corrected edit needs a new `request_id`. The embedded `crewship ai` skill notes that Design `restore` takes no `--base-version`. The guides now state that creating an artifact at the page cap answers `422` `pages_limit` (not `413`), that a never-written Dashboard collection is not listed, that "Design capacity is full" also covers a used-up storage budget, and give the Design policy prerequisite, plus smaller corrections to the library, Project, Slides and Docs pages.
- **The page cap is now a setting, and Design / artifact project create at the cap give the real reason (#4664).** Instance administrators read and set the maximum pages per workspace (default 100, range 10-10000; `GET`/`PUT /api/v1/admin/instance/page-limit`, CLI `crewship admin instance page-limit get|set`, audited as `instance.page_limit_set`); lowering it never deletes pages. Every create path now uses one check, and creating a Design or an artifact project at the cap answers `422` `pages_limit` with the limit stated, instead of `413` "Design capacity is full" or `artifact_history_quota`; the new-artifact dialog, the artifact client and the agent artifact tool pass that message on. Mooring, agent Documents and GridCraft create at the cap also answer `422` `pages_limit` (previously `409`). Test items still count toward the cap (follow-up).
- **A retained agent run whose ownership cannot be verified no longer stays RUNNING forever (#4700).** When the controller recovers a run's retained output after a restart and finds its recorded workspace or agent conflicting with the trace's journal start or terminal entries, disagreeing with the agent, missing, or differing from its work attempt, it still projects nothing, but once the execution has verifiably ended it settles the run state to `error` with the reason (`unprojected`) and stops retrying, so the `retained output pending projection` warning no longer repeats every 30 s. For a journal conflict the run's own row in `GET /api/v1/agents/{id}/runs` ends as `FAILED` with "retained run output withheld: its trace has conflicting journal ownership", written only under the workspace and agent that the run state, the agent and the run's own `run.started` all agree on, with no output or exit code; rows of the conflicting owner and work attempts are never written. A run whose own recorded ownership disagrees with its agent, is missing, or differs from its work attempt settles its run state only, and its retained output stays on disk.
- **Craft hands over and releases an unchanged native editor again (#4693).** Taking the Word or Sheet editor and then choosing "Předat uživateli …" or "Uvolnit úpravy" without editing was refused with "Výsledek akce nebyl potvrzen" since unchanged content stopped being saved as a new version (#4657, #4661). The editor now transfers custody when its final capture equals the confirmed server version; edited content is still saved and acknowledged first.
- **Craft no longer saves unchanged content as a new version when a freshly opened editor is released (#4661).** The save coordinator now seeds its confirmed baseline from the loaded server snapshot (version and SHA-256 of the loaded bytes), so after an outage, reload or reopening a release flush or autosave of identical bytes creates no version, in Word and Sheet. A restored local draft, normalized content or any edit hashes differently and is still saved; an explicit Ctrl+S ticket always transmits.
- **Nullable API fields no longer publish unsupported null types in OpenAPI 3.0.** Artifact and Design origins and Page folders retain null values and their existing object constraints using OpenAPI 3.0 nullable alternatives. Arbitrary JSON payload and preference arrays also retain nested null values.
- **Craft no longer saves byte-identical content as a new version on editor release or after a reconciled lost acknowledgement (#4657).** The single-editor save coordinator now records the confirmed baseline for every application (Sheet included, not only Word) and skips the upload of an autosave or a release/transfer flush whose bytes, native state and base version match it. Native Ctrl+S still saves. Versions and quota are no longer spent on a duplicate.
- **Artifact storage budget: configurable limits, counter recompute and a clear refusal in the collaborative editors (#4648).** Instance administrators read and set the workspace limit (default 32 GiB) and instance limit (default 64 GiB) with `crewship admin instance artifact-storage get|set` (`GET`/`PUT /api/v1/admin/instance/artifact-storage`); defaults are unchanged until set, lowering a limit never deletes data, and each change is audited. `crewship admin instance artifact-storage recompute [--dry-run]` (`POST /api/v1/admin/instance/artifact-storage/recompute`) rebuilds the usage counters from the stored artifacts in one transaction and reports the drift per workspace; it is idempotent and writes only the derived counters. A Mooring command write that hits the budget now answers `413` `artifact_storage_quota` instead of "command not confirmed", and a WordCraft collaboration socket is closed with code 4009 before the session ends. Both editors show "Kapacita úložiště neumožňuje další uložení" and keep the unsaved work in the browser.
- **Craft preview rechecks no longer slow grant changes and also follow membership changes (follow-up to #4652).** The `page.access_recheck` signals are sent after the commit from a bounded background goroutine, in batches, and skip suspended and restricted accounts. Removing a workspace member or changing their role sends that member alone an empty `page.access_recheck`, which makes open shared previews re-read at once.
- **A revoked Craft shared preview removes its content within seconds, not up to 30 s (#4652).** When a Read or Comment grant on a Word or Sheet page is removed, the server sends the affected person alone a `page.access_recheck` signal with the page id only (on their own `user:{id}` channel; no content, no other users). The open shared preview repeats its authorised read at once and shows "Sdílený náhled není dostupný" on 403/404. The 30 s poll and the focus/online rereads remain as the fallback, and the PRD row `A.craft.read-revoked` now expects removal within about 5 s.
- **Craft names the editor address when the page is opened on another origin (#4649).** If the browser blocks the editor frame because the page is not on the configured editor origin (`CREWSHIP_PAGE_STUDIO_ORIGIN`), the editor now says at once "Editor je dostupný jen na adrese <origin>. Otevřete stránku tam." with a link, instead of waiting 20 seconds for a generic connection error. The local draft is kept, and the Content-Security-Policy is unchanged.
- **Seven review findings in the CLI, the orchestrator and the PRD harness are fixed (#4667).** `crewship page enable|disable` now serialise on a lock file next to the compiler image record, and `disable` re-reads the record after its confirmation, so an enable that finishes meanwhile is no longer dropped; the record writer refuses to write more than the 64 KiB the server reads (it used to turn Pages Apps off for every version). A legacy run whose container is removed while its stop confirmation is pending now releases admission, capacity, HOME and credential holds. `chat room messages --follow` subscribes before its first read (and before each catch-up), so a message committed in between is printed. `page artifact reconcile` no longer reports "save not applied" for a 404 on a version an Edit user cannot read; it says the outcome is unknown unless the latest version is not newer than the base. Artifact and Design comment lists return the newest 500 comments (oldest first), so `--wait` finds a comment created beyond 500. The PRD acceptance session files are namespaced by origin, output directory and account, so concurrent runs no longer share an identity.
- **Routine saves honor machine output formats.** `routine save --format json|yaml|ndjson` returns the saved routine identity and trigger metadata without progress text; the human receipt stays unchanged (#4621).
- **Chat no longer offers Project creation to an agent whose crew the workspace policy excludes.** The composer asks `GET /api/v1/pages/artifacts/availability?agent_id=...` (CLI: `crewship page artifact availability --agent <id>`), which now returns `can_create` and, when refused, `code` `artifact_crew_not_allowed`. If a send is refused anyway, the chat shows "This agent's crew is not allowed to create artifact projects in this workspace", keeps the typed message and starts no run, instead of "failed to save message".
- **Agent peer-card errors no longer expose server internals.** When reading or deleting an agent's peer cards fails inside the server, the API now answers `Internal server error` and logs the cause, instead of returning database driver text or a host file path.
- **Artifact MCP tools advertise the inputs they accept.** Tool descriptions now name the Slides/data flag dependencies and explain mandate, version conflict and quota behavior; version schemas require the positive values already enforced by the host.
- ⚠️ **Behaviour change: workspace webhook destinations are visible only to channel administrators.** Channel lists omit a workspace webhook URL for roles below ADMIN/OWNER while retaining its metadata and personal destinations owned by the caller. Delivery configuration and signing secrets are unchanged.
- **New artifact can create a blank Sheet.** When the server advertises `gridcraft_native` (see `crewship doc status`), **Sheet** is offered in the Artifacts New artifact dialog and opens the native GridCraft editor; without the profile it stays listed under Coming. It reuses the existing page and craft initialize endpoints, so no new API or CLI command (#4635).
- **A skipped schedule no longer blames a routine disabled afterwards.** When a schedule's last fire was skipped with nothing counted as missed, the Triggers tab now always shows "skipped: previous run busy or routine inactive". Before, a routine that skipped a tick because its previous run was still going and was disabled later showed "skipped: routine inactive", reading today's state into a past fire.
- **`crewship page enable` installs the Page compiler on a server whose page project storage is already configured (part 1 of #3108).** Prerequisite: `CREWSHIP_PAGE_PROJECTS_PATH` (or `storage.page_projects_path`) is set and the server was started with it; `page enable` does not configure storage and refuses to run without it. A default storage location and enabling Pages Apps on a fresh install without configuration or restart are not part of this release (#3108 stays open). `crewship page enable` builds the Page compiler image from the binary itself (no source checkout), tags it `crewship-pages-build:<fingerprint prefix>`, labels it with a fingerprint of its whole build context (Dockerfile and base image digest included) and records its exact image ID in `<CREWSHIP_PAGE_PROJECTS_PATH>/pages-build-image.json` (mode 0600); run it on the Docker host as the server's account, with the server's configuration. The server uses only the recorded image, and only while it keeps that ID, tag and label — never an image found by its label alone, since crew images built `FROM` a labelled base inherit it — for Pages and Artifacts Project builds alike, within seconds and without a restart once storage is configured; a missing or non-verifying record fails closed. `crewship page disable` removes this version from the record and then its image (`--all`: every recorded version), deleting only images that still verify. `CREWSHIP_PAGE_BUILD_IMAGE` stays an optional override that wins when set; Docker Compose deployments and air-gapped hosts use it with `crewship page enable --image-only`. A local installation with Studio on `http://localhost:<port>` no longer needs `CREWSHIP_PAGE_RUNTIME_ORIGIN`: the server derives `http://127.0.0.1:<server port>`, a separate browser site, used only for browsers that reach the server directly on a loopback host — not through a proxy (`Forwarded`, `X-Forwarded-*` or `X-Real-IP`) — and never for the same-host editor. After upgrading the binary, run `crewship page enable` again; older images stay recorded for rollback. ⚠️ **Behaviour change:** while Pages Apps are not enabled, `GET /api/v1/pages/{slug}/project/preview` for a Page without a draft answers 503 `page_apps_not_enabled` instead of 404, and the Page build, check, publish and application 503s now carry `code` `page_apps_not_enabled` or `page_runtime_origin_missing`. See [Operate Pages applications](docs/guides/pages-apps-operations.mdx).
- **Craft reconnects an interrupted metadata stream.** Recovery checks current authority for the same admission, allows exponential backoff while an old server stream is still held after transport loss, and stops after bounded retries; saves and custody changes are never replayed.
- **Artifact API reference explains version and access rules.** OpenAPI summaries and descriptions now document artifact manifests, comments, Design and native Craft tasks, including conflict, quota and visibility behavior; routes and schemas are unchanged.
- **Native Word and Sheet proposals have a separate retained storage allowance.** Every retained candidate counts toward a 64 MiB default budget, including rejected and superseded proposals. Concurrent proposals cannot exceed it, and filling it leaves the human’s available history allowance intact. Reads and saves no longer scan proposal payloads. A refusal preserves existing work and history.
- **Native Word and Sheet proposals survive backup and fork restore.** A fork keeps each candidate on its new document with an identifier the editor and CLI can open; backups preserve the exact candidate bytes and content hash.
- **Native agent proposals are idempotent within their authenticated run.** Two runs of the same agent can reuse a request identifier without adopting each other’s proposal. Apply and propose share the run’s change request limit; proposals cannot bypass an unresolved save. Exact retries reuse the recorded candidate without running the engine again, including after the document advances.
- **Design keeps work visible when saved history is full.** A clear message replaces the saved status and offers a draft download containing the local canvas and unsent feedback, or an explicit copy of the canvas into a new Design with fresh history. The original editor, unsent feedback and retained versions stay intact. Copy creation checks current source and create permissions atomically and is never automatically replayed.
- ⚠️ **Design readers and commenters see only the shared version.** Private saved and live changes are withheld from REST and websocket readers, and comments target the displayed shared snapshot. Workspace administrators read and edit every Design, with foreign access recorded atomically in the audit log and keyed journal, and edits using the existing locks and versions.
- Add an original-human and immutable-Page bound key-recovery primitive for private browser drafts, checked against current read authority. Browser retention and sign-out integration remain separate.
- **A Word or Sheet save whose reply was lost in a long outage is still confirmed.** Reconciling the exact attempted version no longer needs a live editing lease, so an outage longer than the lease no longer leaves an already saved draft offered for recovery; the expired lease still cannot save.
- **The chat's side viewer lies over the chat on a tablet.** With chat artifact projects on, below the large breakpoint an open artifact or saved document covers 78% of the chat from the right instead of squeezing the conversation into a narrow column. Wide screens keep the shared row; phones keep the full-screen viewer.
- **Chat starts a project from "+" › New artifact.** With chat artifact projects on, the composer's "+" menu offers Project next to Word. Picking a starter sets the same explicit creation consent as before, and the chosen kind shows as one removable chip ("New Project") in place of the two text buttons, so the toolbar fits on a phone.
- **A Page opens with its content inside Artifacts.** Its application or panels show in the library detail with the same views Pages uses, read by the page's immutable ID; the detail no longer sends you to Pages.
- **New `crewship` commands for API operations the CLI reached only with another method.** `crew member set-role` (or `--clear`), `agent learning`, `agent files --container`, `persona suggest`, `checkpoint get`, `notifychannel update` and `nuke keeper-requests`; `workspace member capabilities list` without a user id lists every member in one request, and `workflow get` reads a template by id before falling back to a name lookup. `GET /api/v1/workflow-templates` now creates the built-in templates on a fresh workspace, as `/api/v1/templates` already did, so `crewship workflow list` is no longer empty there. Built-in workflow templates are now read-only through `/api/v1/workflow-templates` too (`403` on update or delete, as on `/api/v1/templates`), since listing would otherwise recreate a deleted one and duplicate a renamed one. The `docs-inventory -strict` CLI-parity gate now compares HTTP method and path rather than path alone, and calls made only by `crewship seed` no longer count as coverage (#4510).
- **Every artifact in the Artifacts library has its own address.** Opening one goes to `/artifacts/<id>` (its immutable page ID), so Back returns to the list it was opened from, and a reload or a shared link opens it again. Links from before, `/artifacts?item=<slug>`, open by slug and move to the new address; an ID address never falls back to a slug another artifact may hold now.
- **Home's Artifacts card opens Artifacts.** With the Artifacts library on, *All artifacts* goes to `/artifacts` and each recent item to its own `/artifacts/<id>` address instead of Pages. Without the flag nothing changes.
- **Design System artifacts get an opt-in token preview.** An artifact project with a `design-system.json` file (colors, typography, spacing, radii and an optional component list) opens as a read-only sheet of swatches, type scale, spacing and radii when the web UI is built with `NEXT_PUBLIC_ARTIFACT_DESIGN_SYSTEM=true`. Agents and the CLI create and version it through the existing `page artifact create/publish/restore` commands; no new endpoint or storage. Default off.
- **Recovered HTTP panic reports identify the route without request details.** Crash reports and local panic logs use the registered route pattern and panic type; unmatched requests use a fixed label.
- ⚠️ **Behaviour change: notification channel URLs are checked more strictly.** The delivery library (shoutrrr 0.22.1) rejects a channel URL that could never send when a channel is created from the provider form or tested, and at send time for raw URLs: Gotify needs a real application token (15 characters starting with `A`, or a Gotify 3 `gtfya.` token), Google Chat needs both `key` and `token`, Mattermost needs a host, and ntfy topics follow ntfy's naming rule. Saved channels are never checked at startup or when listed; a Google Chat channel saved without `key` or `token` now reports a delivery error. SQLite driver updated to modernc.org/sqlite 1.61.0.
- **Artifact history warns before it is full and previews a retention rule.** Artifact and native document reads now return `quota.level` (`none`, `near` from 80%, `critical` from 95%, `full` at the limit) next to the existing `warning`. The owner snapshot, also printed by `crewship page artifact versions`, adds `retention_preview`: a dry run of "keep every version from the last 14 days, then the newest per day, plus latest, shared, named and restored versions" listing what it would thin. Nothing is deleted; retention stays keep-all. A `QuotaBanner` component for the Artifacts library is included but not yet wired.
- **Agents prepare a proposal when a person is editing a Word or Sheet document.** Instead of a bare refusal, the agent's `craft_propose` records a complete candidate over the version it read; the document stays unchanged. The person holding the editor can compare it, accept it as their own save (rights, lease and current version are re-checked in one transaction; a proposal over an older version becomes stale) or reject it. Any co-editor with write rights can reject without holding the editor. Open proposals over a version the document has moved past are marked stale when the agent proposes again, so they no longer count toward the limit of 16 open proposals per document. Also available as `crewship craft connect` actions. The agent's task then succeeds with outcome `proposal` and the proposal id (shown by `crewship craft task status`) instead of failing without a receipt; only a proposal recorded by that run counts.
- **An agent runtime is no longer held busy by another crew's interrupted run.** A run recovered without a container but recorded for a different crew no longer blocks refreshing this crew's runtime; a run with an unknown crew still blocks it (#4486).
- **A Read-only Design viewer can no longer stall every database write or lock an editor out.** Answering a Design websocket sync request no longer runs the Yjs engine while holding the server-wide writer lock, and a flood of sync requests closes the socket (4429). An update the engine refuses now closes with 4400 "Design update rejected" instead of 1008 "permissions changed", which sent the browser into an endless re-admission loop; 1008 is used only for changed authority. Another person claiming an editor's presence ID is ignored instead of closing the editor, and the same person reconnecting replaces their stale connection.
- **`crewship feature-flag` help explains roles, outputs and the Artifacts flags.** Every subcommand now has a description and an example; the help lists the Artifacts workspace flags with their defaults, dependencies and the web build switches their screens need, says that creating, updating and deleting a flag needs an instance administrator, and notes that `update`, `delete`, `enable`, `disable` and `inherit` print only a confirmation line (`create` honours `-f json`). Command behaviour is unchanged.
- **Deleting a workspace closes its public Page links.** Deletion revokes the links in the same transaction, and public reads also refuse previously deleted workspaces.
- **A preference no longer carries over to the next account signed in to the same browser.** The browser's copy of each preference (recently opened artifacts, favorites, panel sizes) now belongs to one signed-in user, so the next account no longer sees the previous account's values on first paint or uploads them, private artifact slugs included, into its own preferences. Nothing is read from the browser until the session is known, the older shared copy is dropped, and a change not yet saved for one account is sent only when that account signs in again.
- **Chat opens saved items in Artifacts.** With the Artifacts library on, the chat viewer has *Open in Artifacts*, and saved-document cards, the document access panel and page provenance link to the item's own `/artifacts/<id>` address instead of Pages. Without the library flag the links stay as they were.
- **Pages can hand its overview to the Artifacts library.** With `NEXT_PUBLIC_PAGES_OPEN_ARTIFACTS` and the library flag both on, `/pages` opens `/artifacts` in the same workspace. Reference links, restricted members' catalogs and single pages stay on Pages. Off by default.
- **The built-in `crewship` agent skill now covers Artifacts.** The guide an agent reads through the CLI explains when to use artifact projects, Design canvases and native Craft documents, which flags and switches each needs, who may write, how to reply to comments and hold the Craft lease, and what to do on a version conflict (409), full storage (413) or an uncertain 503 without retrying blindly. Command behaviour is unchanged.
- **Artifacts is the single home for a page and its Word or Sheet.** Behind the same two flags, `/pages/<slug>` resolves the page's immutable ID and opens `/artifacts/<id>` in the same workspace for a Page, a native Word or Sheet or a versioned project. Reference links, pinned versions, edit addresses, restricted members and any page whose ID cannot be resolved stay on Pages. A native Word or Sheet is edited inside its Artifacts detail in the single Craft editor with its lease (who edits now, ask for the handoff) when the server confirms the editor is available; otherwise the detail says editing is not available and keeps the saved preview. Off by default.
- **Shared artifact commenters can post feedback in the preview.** Comments stay anchored to the shared version without granting editing or agent execution rights; changing accounts, workspace or permissions retires an unfinished selection.
- ⚠️ **Behaviour change: a Comment grant can no longer queue agent work on an artifact project.** The Artifacts detail now offers Select and Save comment to Comment-level readers, as `/pages/<slug>?artifact=1` already did. `POST /artifact/comments` with `send_to_agent:true` returns `403` and stores nothing unless the author has Edit, matching Design comments. An agent run whose intent names no comment may answer feedback only with a version it published, never with `needs_clarification`, and no run may answer a task another run holds.
- **Workspace identity erasure also clears Mooring human attribution.** Collaboration edits keep their exact saved history while losing the erased person's ID; generic Mooring mandates keep their preconditions and revocation state and can no longer authorize that person's agent. Other people and workspaces remain unchanged.
- **Project source edits survive a lost save reply and a closed tab.** If the save reply is lost, the editor confirms the exact next version instead of reporting a false conflict, and an unsaved source draft is kept in the browser and offered back until it is saved or discarded.
- **Agents gain bundled Design and native Craft playbooks.** They explain scoped mandates, retained Design versions, session-bound leases and confirmed native saves. Design tool descriptions clarify version and conflict handling.
- **`crewship slides` and `crewship doc` help describes the real commands.** The generic "Slides <op>" and "Document <op>" texts are replaced with descriptions and examples, the `doc draft` subcommands get a summary, and native decks and documents are no longer presented as living in Pages. Command behaviour is unchanged.
- **Private artifact and document drafts survive expired sign-in.** Recovery requires the same identity and a fresh Page-read check. Failed local capture keeps the editor open behind a recovery warning; explicit sign-out asks before removing persistent copies and preserves newer revisions. New local payloads are encrypted; legacy plaintext from other identities is removed before identity admission, and confirmed read revocation removes reachable copies (#4606).
- **Artifact and Design drafts are no longer lost or left behind in the browser.** Edit source no longer overwrites a source draft kept after a crash, a successful save keeps edits typed after it was submitted, and a failed browser-storage read no longer deletes the stored comment draft.
- **The Artifacts detail no longer sends you to Pages where Pages opens nothing.** Behind `NEXT_PUBLIC_PAGES_OPEN_ARTIFACTS`, a native Word or Sheet whose editor is unavailable shows its saved version without an Edit that opened the same unavailable editor on Pages, and its preview error no longer points to Pages. An old-editor Word keeps Open in Pages only while its saved document can be read, because Pages opens it with the same read. Off by default.
- **Test Design canvases can be identified in the library.** Human canvas creation now retains the explicit test-item marker for catalog filtering.
- ⚠️ **Behaviour change: `journal priority` and `memory export` honour `--format`.** With `--format json` (or `yaml`/`ndjson`), `crewship journal priority` prints the server's answer as an object with `id`, `priority` and `previous`, and `crewship memory export` writes the bundle as before and then prints `out`, `documents` and `skipped` instead of the prose listing. With the default table or `quiet` output both keep their human-readable line. `memory export` help now states that it requires OWNER or ADMIN.
- Add human Comment grants for shared artifact feedback without edit or agent execution rights, explicit QA item markers and catalog filters, and confirmed archive and folder-move previews with live access checks. Access reports include effective capabilities and their sources; existing content, history and grants remain intact.
- **`--format json` now prints what the server sent for routines, skills and workspaces, and mutation commands answer in JSON.** `routine list/get` decoded the response into a CLI struct before printing it, so JSON lost the pending draft and its test result, `files` and `manifest`; `routine versions` lost each version's `test_result`; `skill get/list` lost `lifecycle_state`, `needs_credentials`, usage and missing credentials; `workspace get/list` lost `kind`, `personal_owner_id` and `guest_routine_max_run_minutes`. Machine formats retain every server field and preserve the explicit empty routine keys existing scripts received. Deleted-crew IDs remain usable for inbox history, unreadable successful crew-delete responses still produce a JSON receipt, and memory file reads are capped locally at 128 KiB. The human views gain a `Draft:` line and a TESTED column on routines, Lifecycle / Needs credentials / Uses 7d/30d on `skill get`, a LIFECYCLE column and `--lifecycle` filter on `skill list`, and Kind / Personal owner / Guest routine max run on workspaces. `agent stop/delete`, `crew delete`, `routine replay`, `policy set`, `skill archive/restore`, `workspace logo set/remove`, `routine pending cancel` and routine folder/template delete print the server's outcome under `-f json` instead of nothing; human output is unchanged. `admin instance backups overview` reports `crewless_workspaces`. New `crewship memory initialize` (first-write memory provisioning) and `crewship feedback peer-card` (read your own peer card). `feedback preferences` commands accept an agent slug, show the preference VALUE, check `--reason` against catalogue v1 and print JSON receipts. `inbox list --crew` accepts a slug, and `inbox list --deadline today` / `inbox counts` send your local end of day like the web inbox (`--day-end` overrides) (#4508).
- **An unsent artifact comment survives a crash.** The chat and library artifact viewer keeps the comment text in this browser for the same person and Page, and offers it again after reopening; the place has to be selected again.
- **Artifact comments reach agents as fenced data.** `artifact_comments` and `artifact_versions` now wrap comment text, the quoted element label and every reply in the same nonce-delimited `<untrusted source="artifact_comment">` block used for issue text, so a reader with only a Comment grant cannot write instructions into the owner's run. Selectors and code file content stay exact for anchoring and republishing.
- **Artifact saves are confirmed after an interrupted success response.** The CLI reads the exact successor version without repeating the publish request, preserves definitive refusals, and rejects duplicate-path matches. Craft errors redact session tokens before truncating their display.
- **`crewship page artifact comment --send-to-agent` no longer leaves the task stuck at "pending".** The task only starts when the artifact's source chat receives a message carrying its purpose, which the viewer sends and the CLI never did. `--wait` on `page artifact comment` and `page design comment` now sends it, confirms the host saved it and waits for the agent's answer or clarification; `crewship run --chat <chat> --artifact-target <file>` sends the same purpose by hand, including a "Describe it" creation (#4505).
- ⚠️ **Behaviour change: a busy agent exits `9`, a full artifact history exits `2`.** A message bounced because the agent already has a live run now exits `9` (was `1`) for `crewship run` and the new `--wait` commands; nothing was sent or stored. A full artifact version history (HTTP 413 `artifact_history_quota`) now exits `2` (was `1`) and says nothing was saved, your `--file` is unchanged and every version is retained (#4505).
- **`crewship craft` shows why the server refused.** Refusals printed only `native HTTP 409` and exited `1`. They now carry the server's text with the session token removed, exit with the usual codes (`5` conflict, `2` validation, `7` server, `8` network) and fill the `--format json` error envelope; a lease conflict names who holds the lease, and a proposal refusal says whether it was stale. Agent `task` commands still print status only (#4505).
- **`crewship page artifact publish` confirms a save whose reply was lost.** After a transport error, a 5xx or a 409, it reads version base+1 once and reports the save as done when that version holds exactly your manifest; otherwise the original error stands. `crewship page artifact reconcile` does the same check by hand (#4505).
- **More Design and Mooring operations from the CLI.** `page design create --test-item`, `page design watch --authority-revision`, `mooring command-session` and `mooring session --reauthorize` (#4505).
- **Home-installed agent CLIs remain visible during startup checks.** Offline qualification uses a separate temporary home while preserving read-only executable paths from the immutable image.
- **Mooring connect help now explains streaming and refusal conditions.** It documents output formats, the 256 KiB frame limit, agent-token refusal and rejected connections; the Design and Craft task reference covers versions, lease generations and uncertain saves.
- **Design artifacts gain an opt-in collaborative canvas.** People and agents can edit frames, shapes, text and images through Yjs, with live presence and normal artifact version history. Agents can address their selected canvas by its immutable ID. Disabled by default. Long-running cookie sessions renew only their collaborative transport after fresh authority checks, retaining unsaved work. Restoring saved canvases preserves prototype-named node IDs and their original contents.
- A shared dev release now switches one checked-in build profile (`CREWSHIP_BUILD_PROFILE` in `.env.production`); the flag tests and the phone browser contract verify the main and the release profile, and main must keep the main profile.
- **CLI stop confirms the caller’s cancelled run.** Waiting for a stop and signal handling require a private request-correlated completion (`cancel_accepted`, then `cancel_result`); another member’s terminal event, an agent stop or a server shutdown cannot report success. Repeated requests for the same run — on one socket or from several of the same user’s sockets — share its outcome, and the server answers `cancelled:false` with a reason after a 90 s deadline. **Requires a server from this release:** against an older server `chat stop --wait` and a Ctrl-C/SIGTERM-stopped `run` report “run ended; cancellation not confirmed by server (server too old?)” and exit 10 once the run’s `done` arrives, instead of waiting out the timeout. Chat retry selects the caller’s authored turn rather than another member’s latest message; an unattributed legacy turn is retried only in the caller’s own private chat (`GET /api/v1/agents/{id}/chats` now reports `visibility` and `created_by_caller`).
- ⚠️ **Behaviour change: `crewship run` stops a run on SIGTERM and only says `[cancelled]` once the server confirms it.** SIGTERM — what `timeout`, CI runners and supervisors send — used to kill the CLI and leave the run going server-side; it now sends the same stop as Ctrl-C. Both print `[stopping…]` and keep reading until the run's own terminal event, then `[cancelled]`; a stop not confirmed within 30 s exits non-zero, and a second signal still exits at once. `--no-stream` runs are stoppable the same way. New `crewship chat stop <chat-id> [--wait]` stops a run you started from another terminal or the browser (#4504).
- **`crewship run` and `crewship ask` can send what the web composer sends.** `--attach <file>` (repeatable) uploads into the chat and names the paths in the message with the composer's exact wording; `--page <slug>` attaches a Page snapshot; `run --chat <id> --ask-form <form> --var name=value` submits an agent's ask form with the envelope the server re-checks, printing `[form delivered]` or exiting non-zero with the refusal; `run --create-document` sends the composer's "Create document" intent. `run` also prints the run summary (`[summary] $… · tokens · turns`) and delegation, escalation and port-exposure progress (#4504).
- **New chat commands for what only the browser could do.** `crewship chat <id> --parts` shows thinking, tool calls and results, and group-chat authors; `chat export <id> -o file.md` writes the Export dialog's Markdown; `chat retry` and `chat edit -m` are Regenerate and Edit-and-resend; `--watch` on `chat refs`, `chat decision list` and `chat proposal list` re-prints on change, and `chat room messages --follow` tails a room. `chat stream` now renders the user's line, the run summary, busy/build/refusal notices and broadcasts instead of dropping them. Smaller: `conversation search --chat --from --has --after --before` (client-side, marked partial like the search box), `chat list --counts` (per-kind totals) and `crew peer-conversations --offset` (#4504).
- **`crewship chat stream` shows which assignment, escalation or exposed port an event is about.** Session broadcasts that are not chat events (`assignment_*`, `escalation_*`, `peer_query_*`, `port_expose_created`) reached the NDJSON run stream as a bare type name; the WebSocket delivered the same frame with its payload. The stream now carries the payload as `metadata`, cost-redacted like every other frame (#4504).
- **`crewship chat <id>` shows message times again, and `--since` filters.** The transcript read each message's `created_at`, which the messages endpoint never sends — it sends `ts` — so every header printed without a time and `--since` kept every message. It now reads `ts` (#4504).
- **"Send to agent" on Design and Project comments reports delivery correctly.** A delivered comment no longer turns into "Retry when the source chat is connected" after 15 seconds, and a busy agent is reported at once instead of after a timeout.
- **Native Craft editing can continue past access-token expiry.** The browser refreshes its cookie before admitting or renewing the same editing connection and replaces only its authenticated metadata stream. Unsaved work, the lease generation and in-flight saves remain in place; document mutations are never replayed.
- **Read-only Craft viewers saw editing controls.** Native Craft previews now show edit actions only when the server confirms current edit access. Comment viewers can open an explicitly published native preview without acquiring an editor lock or reading private drafts. The CLI exposes the same shared preview and publication paths. ⚠️ **Behaviour change:** admitted native CLI actions and shared preview reads reject HTTP redirects.
- **Workspace backups now preserve experimental workbooks.** Encrypted portable restore and forks retain snapshots, published audience and immutable mutation receipts; recovery fences unfinished edits and requires fresh editor sessions and run permissions.
- **Full document history now says what happens and what you can do.** Word and Sheet editors stop saving, state that every version is kept and the unsaved work stays in the browser, and offer the draft as a download. Projects keep their preview and source draft at full quota. Neither promises more storage.
- Add a disabled dashboard dataset storage foundation with atomic document version checks, bounded JSON batches, server attribution, portable backups and Page lifetime cleanup; code versions remain in the existing artifact VersionStore.
- Accept valid near-limit Dashboard data batches by counting their exact metadata and original value bytes, preserving document limits and atomic version conflicts.
- Add default-off Dashboard collection reads and atomic JSON document batches through authenticated Page API, CLI and original-run MCP tools. Shared readers use the current shared code manifest; data changes preserve code history and document conflicts never overwrite newer data.
- Classify Dashboard artifacts from the authorized code manifest in Page lists and detail: owners use the latest code, shared readers use the current shared pin. The disabled Dashboard data flag preserves the ordinary Project classification.
- Require actual Chromium execution of native document privacy regressions in frontend CI while preserving the strict browser-dialog guard.
- Add an opt-in Artifacts library at `/artifacts` (`NEXT_PUBLIC_ARTIFACTS_LIBRARY`): a gallery or table of projects, Word, Sheet, Slides and dashboards with kind and shared version, a project detail on its version history and the edit lock of a native Word; the Pages list reports `artifact_kind` and `artifact_shared_version`.
- Rebuild the opt-in Artifacts library on the Harbor 2 panel: Home, Mine, Favorites, Clean up, Test items, Empty and Archive views kept in the URL, a colour and drawn thumbnail per kind, folder icons, J/K navigation, and one New artifact dialog that offers only kinds this workspace can create, including Slides through an agent. Share with Read, Comment or Edit inside the workspace, an Access tab that says why each person can open an item, folder settings, and Move, Share, Archive and Unarchive on a selection, each confirmed after a preview of who gains or loses access; archiving hides and never deletes. `NEXT_PUBLIC_ARTIFACTS_SHARING_MOCK` runs sharing in the browser until the backend routes ship. New Doc and New artifact create Word documents through one shared hook.
- Add opt-in inert Dashboard previews (`NEXT_PUBLIC_ARTIFACT_DASHBOARDS`): authorized collection data refreshes numbers, tables and native meter charts without publishing new code; shared readers stay on their shared manifest and data has source and freshness labels.
- **Every Dashboard number shows where it came from.** With `NEXT_PUBLIC_ARTIFACT_DASHBOARDS` on, hovering or keyboard-focusing a bound value in a Dashboard preview shows its dataset, row and field, its producer (`You`, `Contributor` or `Agent`) and its last update time in UTC; the same text is the value's accessible description and appears in the Data sources list. Values whose producer is unknown, or whose document is not loaded, are marked "Source not stated" and drawn with a dashed underline instead of looking authoritative. The provenance comes from the reader-safe fields the data API already returns; no API or storage change.
- **A Design created from the Artifacts New dialog opens.** The dialog handed the new page's slug to the detail as if it were an ID, so a fresh Design landed on "This artifact is not available". It now opens the created artifact by its slug.
- Add Preview, History and Comments tabs to the opt-in Artifacts library; sending an anchored comment starts the source agent, with delivery confirmation and retry of the saved task.
- Add a bounded Slides artifact import adapter for a closed `deck.json` and authored HTML profile, reusing the existing slide schema and static comment anchors without enabling a new editor or preview.
- Open backend-typed artifacts in their versioned viewer from library links and ordinary Page URLs, preserving workspace and selected versions without falling back to an empty panels view.
- **Artifact comments could report that the agent did not start after it answered.** Persisted chat acknowledgements now confirm the exact artifact request, and verified task progress clears stale delivery warnings and their retry action.
- Show agent artifact project steps in chat as cards with kind, version, Draft/Shared state and a running "Creating version n…" step that settles into "vn ready · Restore"; off by default behind `NEXT_PUBLIC_CHAT_ARTIFACT_PROJECTS`.
- Chat artifact cards wear the same coloured kind tile and kind label as the Artifacts library (from the shared kind registry), show `Shared vN` and the server-reported `Agent working…` as status pills, say "Can’t show this version here" instead of guessing a type, and the running step says the current version stays as it is, or that nothing was saved when it fails; still behind `NEXT_PUBLIC_CHAT_ARTIFACT_PROJECTS`.
- **Saved artifact comments could lose Retry when their viewer was closed.** Reopening now offers Retry for an undelivered task, rereads its current delivery state and reuses the same saved comment; accepted or running tasks are not sent again.
- Add an opt-in private native-document draft journal and whole-snapshot save coordinator. Recovery offers compare or copy, stale generations cannot replay drafts, and only an exact durable receipt confirms a save. Existing editor profiles remain unchanged.
- **Native Sheet documents can use the full GridCraft editor.** The experimental, default-off native profile now initializes qualified Grid workbooks with the same edit lease, local draft and confirmed whole-document save flow as Word.
- Open an artifact card in a side viewer (full screen on phones) with screens, element select and anchored comments, the agent comment queue, version history and restore; off by default behind `NEXT_PUBLIC_CHAT_ARTIFACT_PROJECTS`.
- Add a default-off typed artifact Slides preview (`NEXT_PUBLIC_ARTIFACT_SLIDES`) with existing slide canvases, thumbnails, presentation, authored comment anchors and authorized PDF download; requires the backend Slides capability.
- Show the Craft edit-lock bar, agent proposal cards (Compare / Accept / Reject) and recovered local drafts in chat, and a "+ New artifact" composer menu offering only kinds with a backend; off by default behind `NEXT_PUBLIC_CHAT_CRAFT_LEASE` and `NEXT_PUBLIC_CHAT_ARTIFACT_PROJECTS`.
- **Opening a new conversation logged three 404s.** A draft session no longer requests its execution profile, messages or participants before the first send creates it.
- **`crewship workspace artifact-policy show|set` work with a workspace chosen by slug.** The slug from `--workspace`/`-w`, `CREWSHIP_WORKSPACE` or the config is now resolved to the workspace ID before the request, as other workspace commands do, instead of being put raw into `/workspaces/{id}/` and answered with 404; a slug that does not resolve fails rather than falling back. `set` without either `--crew-id` or `--clear-crews` now says one of them is required instead of `not both`.
- **Project Edit grants could return 403 instead of allowing changes.** Human editors can read and save the latest complete project with version conflict checks and their own attribution. Read and Comment stay on the shared version; publishing a shared pin, restoring history and agent execution keep separate owner permissions.
- **Artifacts CLI help now explains data, Slides, archive and creation policy commands.** The help includes required flags and examples, and agent refusal text names artifact and Design operations. Command behavior is unchanged.
- **Artifact authoring clients support complete project versions.** Add pilot MCP tools and `page artifact` commands for atomic manifests, explicit version conflicts, restore and anchored feedback on servers that enable the artifact project backend.
- Artifact project feedback exposes verified human/agent attribution, occupied addresses have a distinct error, and authoring tools require stable selection IDs.
- Add default-off authored Slides projections and vector PDF export with explicit version pins and current Page/run authority rechecked after rendering. Existing artifact history and comments remain authoritative.
- Add authenticated artifact project creation and workspace availability endpoints behind the disabled artifact projects flag.
- Artifact creation and publication tools now request stable element IDs so generated screens support precise element comments.
- Version the bundled Project, Dashboard and Slides authoring packages and preserve their release in agent skill files, with immutable compiled type metadata and unchanged content versions.
- **Page catalogs filter and page on the server.** Search names and slugs, combine kind (including Design), privacy, version, owner, folder and empty-item filters, and choose stable ordering through the existing API and `page list` CLI. The Artifacts library can page its All view on the server behind the default-off `NEXT_PUBLIC_ARTIFACTS_SERVER_CATALOG` flag. Totals and page windows include only authorized matching items; existing unpaged callers retain their array response.
- Clear copied-command feedback timers when onboarding unmounts.
- **Saved Slides pages could look empty.** Page detail and list responses now include native Slides presence and schema metadata, allowing the existing opt-in Slides viewer to recognize saved presentations.
- Add a standalone, bounded Slides-to-PDF foundation with a fixed embedded font, vector shapes and tables, and explicit text overflow errors; product export entrypoints are not enabled yet.
- **Native single-editor documents gain a default-off edit lease boundary.** SQL-backed holder generations fence expired, handed-off and revoked writers; workspace erasure and user deletion remove retained holder identities while preserving the fence. Lease acknowledgements recheck authority after SQL; recovery retires source holders while retaining generations, and portable replacement refuses issued target fences. A target-local workspace issuance marker preserves restore protection after Page deletion. Runtime editor and version-store wiring remain disabled.
- Expose a default-off native Craft human session and edit-lease HTTP API with Page-scoped availability, named holders, requested handoff and live connection renewal. Original credentials and current Page rights fence every action; existing document profiles are unchanged.
- Add a bounded host adapter for original Word/Sheet engine edits and reads: pinned executables, private files and a closed command allowlist. Agent authority remains in the separately guarded native task and edit-lease boundary.
- Add separately opt-in native Word/Sheet agent tasks with explicit original-human consent, confirmed run identity, shared edit leases, original-engine edits and receipt-backed whole-document saves. Human holders are refused; the original human can inspect actual task outcomes and stop the agent without lending a human editor session.
- Allow native Craft editors to copy to the clipboard while keeping clipboard reads and opaque-frame isolation restricted.
- Add a default-off whole-native WordCraft/GridCraft version store with immutable compatibility pins, engine validation, lease and CAS fencing, exact snapshot receipts and portable profile backups. Its visible 16 GiB history budget preserves versions on exhaustion; editor activation remains separate.
- Create vendored WordCraft numeric test fixtures exclusively so a competing output file cannot be truncated.
- Execute a flat WordCraft editor package with a real WASM snippet import in the packaging regression, checking the original ABI identity and manifest hashes.
- Keep an idle native WordCraft read alive when typing starts, ignoring its obsolete projection without resending the command.
- **Taking over a native document no longer ignores the first click during refresh.** Lease controls wait for a newer read-only editor snapshot to finish opening before accepting custody actions.
- Explain when a browser cannot support the isolated WordCraft command editor, including iPhone browsers.
- Allow the 72 generated fixture-qualified WordCraft commands in the default-off C1 backend test profile, with closed parameters and a new exact catalog identity.
- Keep native selection receipts valid when a WordCraft command also returns command-specific metadata.
- Add a disabled native WordCraft command HTTP controller with immutable viewer fences, confirmed SQL-only projections and bounded current-rights delivery; product startup registration remains separate.
- Validate private C1 checkpoints and quoted RPC frames with their existing 4MiB/32MiB byte bounds and a fixed bounded JCS structure profile, preserving the legacy command-envelope limits.
- Preserve bounded native C1 command selection in the original immutable staged operation receipt and atomic SQL outcome, without adding a shared peer caret or inferring selection from input.
- Add a disabled command-document runtime lifecycle that initializes only new documents, restores confirmed SQL state, and retains existing owner fencing without falling back to the legacy adapter.
- Bound the native C1 host's live generation history across repeated restores, preserving pending candidates and handles when replacement capacity is refused.
- Add a separate opt-in C1 renderer source recipe and actual native WASM registry/codec harness, with confirmed selection checks and explicit pending-input refusal; it does not enable product UI, preserve rapid input or change the legacy SDK.
- Add a default-off private inherited-FD WordCraft command host that pins its native helper and stages immutable checkpoints for trusted SQL confirmation, without exposing a public commit endpoint.
- Keep private native WordCraft agent commands and outcome lookups bound to their original confirmed chat mandate and current Page permissions.
- Add an opt-in private native command port with pinned engine identity, bounded correlated process messages, opaque staged handles, and SQL-authoritative recovery without command replay.
- Keep the opt-in WordCraft command host candidate separate from confirmed state until a trusted host SQL-success callback, retaining participant undo and committed operation receipts across checkpoint recovery.
- Preserve new command-document formats and immutable engine pins while legacy collaboration adapters refuse their payloads, including when command support is disabled.
- Add a separately disabled SQL interface for new WordCraft command documents, with current-rights checks, atomic checkpoints and operation receipts, and reconciliation without replay after uncertain outcomes.
- Keep idle WordCraft editors connected through standard WebSocket ping/pong while preserving the existing response and inactivity limits.
- Show the Crewship page name in attached WordCraft chrome and hide its standalone Discord, Share and Zotero controls.
- **Native document exports did not download.** Word and spreadsheet export copies now download through the host browser while retaining the isolated editor and separate server save confirmation.
- **New Doc was unavailable with only the native Word profile enabled.** The qualified, default-off native profile now offers Word creation through the existing whole-document initializer and opens the full editor after releasing creation custody. Ambiguous initialization never creates another Page or blindly retries a write.
- Open document links in their accessible workspace before requesting document content, preserving unsaved-work navigation guards.
- **WordCraft documents can be created from Pages.** When native collaboration is enabled, choose WordCraft in New Doc to open a blank document in the editor without setup scripts.
- **Create native Sheets from New Doc.** The Sheet choice appears only for a qualified GridCraft release, initializes its original engine model, and reopens saved native Sheets in the full editor.
- **Native Sheet documents can use the full GridCraft editor.** The experimental, default-off native profile now initializes qualified Grid workbooks with the same edit lease, local draft and confirmed whole-document save flow as Word.
- **New Doc was unavailable with only the native Word profile enabled.** The qualified, default-off native profile now offers Word creation through the existing whole-document initializer and opens the full editor after releasing creation custody. Ambiguous initialization never creates another Page or blindly retries a write.
- **One departing or expired collaborator could disconnect everyone.** Keep late lease replies scoped to the original closed participant and finish an already reserved reply before that participant leaves, preserving the other collaborators' session.
- **Opening large collaborative documents could time out.** Avoid repeated checkpoint validation in incompatible message variants and scan the existing base64 schema vocabulary directly, preserving checkpoint integrity and the five-second startup deadline.
- Bind document-agent task registration and partial-result policy to the original admitted human task before native submission.
- Add bounded native document pages to the original task's `doc_read` tool, preserving one immutable revision, complete application data and current read authorization across continuations and physical delivery.
- Allow an explicit read-only native document task through the existing original-message flow, preserving its attached read intent across admission, native grants, renewal and retirement while rejecting submissions. Default tasks retain their original write mode.
- Qualify Mooring startup metadata and complete targets from one checked owned WordCraft document, preserving checkpoint integrity and final owner checks without changing runtime deadlines.
- Replay contiguous committed Mooring native deltas after recipient reopen or a delivery gap, checking current reader rights for every frame without creating a new snapshot or source authority.
- Show recorded native agent edits separately from current document grants and tasks, with independently authorized source-chat backlinks. Historical references grant no rights and do not claim artifact creation or complete version history.
- Package the optional Mooring runtime and isolated WordCraft editor from pinned public sources, with embedded asset integrity checks and disabled-by-default runtime configuration.
- Bound Mooring session admission request and response I/O, flush buffered responses under the original ingress lease, and retain the read deadline through HTTP body cleanup.
- Rust-backed Mooring saves retain immutable original human/agent task attribution in the same transaction as each new saved atomic change. Rejections, failed commits and known retries do not create another edit record; this does not yet provide artifact creation, version browsing or live chat acceptance.
- **Document access in chat:** distinguish the agent's current document grants from verified active task permissions. Hide inaccessible document metadata, expire unverified views, and identify unknown output provenance explicitly.
- Preserve original task authority and private-run ownership through the existing Mooring agent dispatcher and confirmed-attempt chain. This prerequisite does not enable an agent route or qualify a private execution environment.
- Mooring sessions retain a Pending notification and its matching terminal receipt separately while delivery is blocked, preserving each until its own completion.
- WordCraft documents expose existing authorized sharing from their header and list menu without replacing the running editor. Opening access rechecks the current viewer and keeps document sharing separate from agent task permissions.
- Run the complete catalog of actual Mooring Rust/SQL integration tests in hosted CI using freshly built public-source fixtures; reject missing, skipped or failed execution evidence.
- Grade the actual Mooring session response and optional editor DTOs against their OpenAPI schema without increasing the ungraded-response budget.
- Keep the participant stalled-write regression tied to its unchanged physical/context deadline even when the network poller wakes before the context timer callback.
- Document the default-off Mooring session request/response and bodyless WebSocket upgrade, with exact conditional-route checks and CLI/configuration contracts.
- WordCraft explains restricted undo/redo refusals without closing the editor or changing its save state; deletion undo and changes overlapping another author's deletion remain refused.
- Mooring CLI streams honor JSON/NDJSON and YAML output; unsupported quiet output is rejected before opening input or connecting. Original submitted packets remain unchanged. Literal HTTP registrations expose the existing authenticated session and WebSocket paths to route inventories.
- Account for both Mooring FIFO lifecycle goroutines during API teardown, and make the file-download classification guard ignore braces inside Go literals and comments.
- Isolate Mooring Page-grant revocation to the affected participant while rechecking unaffected writers against current rights. Retain bounded old-gate output until its original provenance and current delivery gate are both verified, and decline a revoked pending ticket without inventing a replacement grant.
- Connect default-off Mooring human submissions to immutable live originals, same-writer public receipts, and SQL-backed per-atomic peer updates. Bootstrap requires the actual native human and complete-origin-inventory capabilities; restart recovery and agent writing remain separate qualifications.
- Add a default-off authenticated Mooring HTTP/WebSocket controller with one-use human joins and current SQL-gated checkpoint delivery. Raw editing remains refused until the native human prepare capability is integrated; in-process backup restore requires disabling the controller and restarting.
- Retain bounded original human proposals only after authenticated admission commits, and require their immutable publication proof before any sealed outcome lookup or dependency rejection. Missing or uncertain originals remain nonterminal; this does not enable raw editing.
- Mooring SDK recovery refuses incomplete full snapshots even when Yrs reports no missing updates, preserving every original unsaved draft instead of accepting silently omitted history.
- **Mooring agent reads:** an inactive session checkpoint reader retains the original agent mandate and confirmed attempt under the existing immutable authority; it grants no write or external delivery access.
- **Independent collaboration authors:** dormant admission callbacks distinguish original author generations from broad delivery invalidation, so another user's grant revocation does not reject an unaffected original author. Current source and Page policy remain required; missing tracking or schema drift stays nonterminal, and no content path is enabled.
- **Collaboration revocation metadata:** prepare persistent author-relevant generations from canonical policy mutations, separate from broad delivery invalidation. Portable restore preserves target tombstones. Admission integration remains unqualified and disabled.
- **Mooring ingress groundwork:** an inactive bounded host registry retains original operation membership and authenticated author proofs after admission COMMIT. Session transport remains disabled pending independent review and mixed-author revocation qualification.
- **Mooring session groundwork:** inactive queued commits retain their exact owner and original author proofs; uncertain authorization cannot become a durable refusal. No session transport or agent execution is enabled.
- **Mooring recovery groundwork:** inactive human admissions can retain their original identity and authority across a verified Rust-only replacement. Old store bindings and join tickets cannot follow the new process; issued delivery gates remain recorded until blocked or expired.
- **Mooring ownership groundwork:** a host can voluntarily release its exact current owner lease, preserving its generation and every issued delivery expiry. Replacement ownership does not acknowledge pending delivery gates.
- **Mooring admission groundwork:** an inactive human registry preserves original Page authority, burns bounded join tickets once and opens current SQL delivery gates. Its store wrapper holds the restore fence through the complete operation.
- **Mooring authorization groundwork:** an inactive human Page authority adapter checks current canonical grants, folder scope and original credential inside the protected writer transaction.
- **Mooring admission preserves the original human credential.** Authenticated chat receipts retain the original user revocation fence and exact credential through run admission and retries; legacy receipts remain unfenced and cannot authorize the new Mooring admission path.
- Conversation transcript appends stay inside their configured storage root even when an existing transcript path is a symbolic link.
- Adapt WordCraft C-E acceptance to actual HTTP commit receipts and passive native queue observations, keeping separate visual evidence, authenticated peers and participant undo requirements.
- **[Resource Access v1](docs/security/rbac.mdx#resource-access-v1)** delivers Guest/restricted mode, per-object agent/routine/project sharing, crew View/Use presets and trusted Manage with ordinary membership controls, existing Pages ACL, Publish in UI/API/CLI, and atomic chained audit with sealed keyring, rotation, verification and alerts. Credential grants, crew/workspace recipients, the complete inherited Access card/grid, universal GET/stream/query-count guards, unified Pages grants and Guest published-routine execution remain deferred to v1.1; the documented absence of a universal leak guard is an accepted release limitation.
- **Explicit crew managers can use ordinary member controls.** A live trusted Manage share enables adding and removing ordinary crew members in Settings. Role editing and removal of explicit crew roles remain administrator controls. Failed access checks and context switches withdraw grant-based controls.
- **Crew sharing can create explicit trusted Manage grants.** The crew Share dialog and person Access editor offer Manage to trusted MEMBER/MANAGER recipients, preserves account mode and other grants, and keeps inactive shares visible for revocation after role changes. Guest shares remain View/Use; Manage does not assign roles or expose credentials.
- **The opt-in WordCraft command editor can show silent connection loss without losing its draft.** A separate connection indicator stops claiming “Uloženo” after its configured server-silence limit and waits for authoritative server state on recovery, without replaying commands. The command host must explicitly wire this component before it affects an editor.
- **Idle work polling avoids unnecessary writer transactions.** Empty or not-yet-eligible queues use a fresh read hint; capacity, deadlines and attempt ownership remain checked in the claiming transaction when work is present.
- **Trusted members can receive explicit crew management shares.** Administrators can grant crew Manage to trusted MEMBER/MANAGER recipients through the member-policy API and CLI, permitting crew profile/configuration and membership changes without explicit crew role overrides. Role assignment, crew deletion, private-network opt-in, budgets and workspace administration retain their existing guards. Account conversion requires deliberate revocation of trusted-only shares first; writes and audit remain atomic. Existing Access editors preserve and display these shares.
- ⚠️ **Behaviour change: Host lifecycle hooks require instance administration.** Creating, editing or enabling host commands now requires an instance administrator and appropriate token scope. Existing host hooks are retained but disabled for explicit review after upgrade; restored hooks also require local review. UI and CLI explain how an administrator can review and re-enable them. Live host-hook changes commit atomically with their authorization audit. Shell output capture is bounded while retaining the existing truncation and exit-result behavior. Container hooks and the default lifecycle pause are unchanged.
- **Guest agent access can inherit from an explicit crew share.** Administrators can share a crew with View or Use through the member-policy API and CLI. View discovers current crew agents; Use also permits Chat and Run, without Delegate or credential access. Revocation, crew retirement and agent moves fence existing attempts. Access screens preserve and display saved crew shares.
- **Guest runs of published routines are deferred from the v1 contract.** Guests retain explicitly shared View, Results, Edit and Publish rights; publication never starts execution. Team members and crew triggers initiate routine runs under their existing authorization rules. Guest execution requires a separately qualified private runtime: a default install returns `503 restricted_runtime_unavailable` without creating or queuing work. Existing optional runtime code and configured qualifications are unchanged.
- **Restricted text workers have an independent release producer.** A main-only manual workflow can publish scanned, signed immutable `responses_text` candidates with source, binary and license provenance. Pull requests and publication test the real production worker against synthetic data; signing requires the exact candidate digest to pass. Image approval, host qualification and Guest runtime acceptance remain separate steps.
- **Restricted native scratch tools can fail on noatime-backed Docker storage.** The native image rebuilds bubblewrap with an atime-preserving remount fix while retaining the inner workspace sandbox and unchanged container security policies.
- **Guests can read explicitly shared crews.** Crew View/Use now opens filtered crew list/detail with identities, agent counts and current agent statuses, while configuration, credentials, membership and activity stay hidden. `crewship crew access` explains the actor’s current Guest share; Use remains conditional on agent authority and runtime preflight. Revocation, crew retirement and issuer authority apply immediately to subsequent requests.
- **Administrative security operations explicitly opt in to emergency audit fallback.** Only single/all-session revocation can use this fallback in the session handler; unlock remains chained-only, and unknown internal operations are rejected before any account or audit mutation. Web password changes and resets continue to fail closed on a broken audit chain.
- **CLI object sharing accepts routine Publish.** `crewship share` and `unshare` now accept `--operation publish`, matching the Share dialog. The server still requires Edit in the resulting policy; unrelated grants and issuer provenance are preserved, and conflicts are never retried.
- **An open workbook could remain active after its editor grant was removed.** Revocation now closes the persisted editor session in the grant transaction, sends a targeted `session_closed` control immediately, and drops queued protected frames while keeping other workbook subscriptions alive. A bounded fallback catches membership and ownership changes.
- **An agent could save a result calculated from cells that had already changed.** Workbook commands now carry cell and range read preconditions, including the range structure revision, and reject changed inputs with a visible reason. Older agent clients conservatively require an unchanged base revision.
- **A full workbook history could silently erase earlier revisions.** Writes now fail visibly with `quota_exceeded` when history or checkpoint capacity is exhausted, preserving the confirmed workbook and every previous revision.
- **An unavailable embedded editor offered no direct retry.** A failed startup now explains the availability problem and offers “Retry editor” after the existing connection deadline, creating a fresh isolated frame. Connected editors retain their current draft and pending changes.
- **A confirmed application edit could remain stuck on “Saving…” during a live update.** The editor host now waits for an in-flight snapshot read and its queued fresh read before acknowledging the durable receipt, while retaining the same mutation for a failed-read retry.
- **Mooring activity was missing from journal filters.** Creation, confirmed edits and agent mandate changes now use registered event types and appear in the Artifact activity group with matching icons.
- **Selecting a workspace could leave the rest of the application unclickable.** Workspace rows now allow the menu to dismiss normally after selection, releasing its modal pointer lock before returning to Artifacts or another workspace screen.
- **Application editors can share a small TypeScript protocol SDK.** The pilot adds a manifest-driven editor surface and a non-Rust reference editor with separate local drafts, live confirmed state and durable receipt status; GridCraft retains its existing conflict recovery on the shared capability channel.
- Workbook publication, custody requests, explicit ownership transfers and orphan deletion now append their authorization audit atomically; failed audit writes roll back the access change.
- Workbook conflict notices and save status keep the editor frame stationary, preserving rapid input during refusals, including on narrow screens.
- ⚠️ **Shared workbooks no longer accept direct agent mandates.** The experimental post-publication exception bypassed the required proposal path. New admissions and legacy mandate use now fail closed with `proposal_required`; proposal delivery remains unavailable. Private workbook mandates are unchanged.
- **Workbook previews now explain why editing is unavailable.** A disabled workspace, unsupported browser, failed availability check or invalid editor configuration has a visible reason and next step. Failed availability checks can be retried without reloading the page.
- **Workbook editor: edits saved during a reload no longer stay "Saving…".** When the workbook was reloaded (pruned history or an import) while a saved edit waited for earlier revisions, the editor was never told it was saved and kept showing it as unsaved, hiding later changes to that cell. Such an edit is now confirmed right after the reload, a repeated send gets the same confirmation without a second write, and a reload never takes the editor back behind a revision it already shows.
- **Workbook editor: a refused edit never loses cells.** A refused multi-cell edit (a paste, a fill) keeps every cell on the Page, marks which ones another writer changed, and waits for a decision: **Keep mine** writes all of its cells again, **Take theirs** keeps the other writer's values only for the cells they changed and still saves the rest, and **Discard mine** drops an edit with no such cell. Every refusal (also an unconfirmed edit or one whose recalculation could not be confirmed) stays open until decided, survives a workbook reload, and holds the status at not saved and the leave prompt; deciding one never clears another. Each notice row names its cells for screen readers, announces itself politely, disables its buttons while the choice is saved and moves focus to the next decision or the editor. Taking theirs on a session that expired unnoticed reopens the session instead of closing the editor.
- **Workbook editor: clearer bundle failures and same-cell conflicts.** An editor bundle that does not match the approved version is now reported as such instead of as a protocol break. When another writer changes a cell you are editing, the host warns at once (when the editor reports its open drafts) and keeps your draft; a commit refused because of that change shows both values with Keep mine or Take theirs instead of only an error. Take theirs sends nothing; once no other refused change is shown and nothing else is unsent, the status returns to no unsaved changes and the editor reloads the head so its own refusal notice clears. Conflict notices also clear whenever the editor loads a fresh snapshot.
- **Experimental embedded workbook editor host (off by default).** With the workspace flag `gridcraft_editor` and a server editor session, a workbook Page frames the editor from its own origin with exactly `sandbox="allow-scripts"`, `credentialless` and no referrer, checks the handshake (frame window, opaque origin, bundle digest), and ends the session and removes the frame on any later load of the frame. **Saved** appears only after a durable server receipt; an answer without one is retried a bounded number of times and then reported as not saved, without holding back later edits. A failed workbook read at open, a handshake that does not finish within 15 seconds, the editor being turned off or its bundle withdrawn while open, and an expired session all remove the frame and fall back to the read-only preview with a notice. Leaving with unconfirmed edits asks first. Otherwise the read-only preview stays.
- **The embedded workbook editor needs no extra hostname and no configured origin.** With the editor enabled and no `CREWSHIP_EDITOR_RUNTIME_ORIGIN`, Crewship serves it on the Studio origin under `/_editor/b/<digest>/`, with no DNS record, certificate or proxy route, and without any origin setting: the editor's policy and Studio's `frame-src` follow the origin each request reached (its `Host`, and the scheme by the trusted-proxy rule), and the host page frames the editor by path. `CREWSHIP_PAGE_STUDIO_ORIGIN`, when set, becomes the only origin the editor answers on (other hosts get `421`). The editor still runs in an opaque, CSP-sandboxed origin. Its policy sources and Studio's `frame-src` name only the bundle path, so it cannot call the Studio API or navigate itself onto a Studio page. That path scoping holds only while nothing in front of Crewship redirects or rewrites `/_editor/`; with the mandatory iframe attributes (`sandbox="allow-scripts"` and `credentialless`) the frame stays opaque and without cookies either way. The server learns the public origin from signed-in browser requests (or uses the configured one) and checks it for such a proxy, recognising a traversal that reaches Crewship outside the editor by its `X-Crewship-Route` header; a confirmed redirect, path rewrite or stripped `X-Crewship-Route` disables the editor on that exact origin until three consecutive checks pass again. Because those request headers are under any signed-in user's control, learning is bounded: `https` only (plain `http` only for loopback on a server bound to loopback), never link-local, cloud-metadata, unspecified or multicast addresses (the self-check also refuses to connect to them), one origin per user, at most four, forgotten after 24 hours unused, and an administrator's origin always gets a slot. Until a browser has used Studio the check is `pending`. The public `/healthz` shows only `ok`, `pending`, `failed` or `disabled`, counting only the configured origin and origins an administrator used; instance administrators see origins, causes and which user taught each origin with `crewship admin instance workbook-editor`, and `crewship doctor` repeats the check from outside for origins on the `--server` host and warns while the server's own check has not passed. The docs list the proxy rules (path unchanged, `Host` forwarded, no redirect, no SSO gate), which are reverse-proxy defaults. It answers `403` to requests that carry Crewship's own session, refresh or CSRF cookies, so it never loads without `credentialless`, while cookies a load balancer or CDN sets (for example ALB stickiness or `__cf_bm`) do not stop it from reopening in the same tab. It also refuses Studio pages loading its code. Editor responses send Studio's exact HSTS value, assets are `Cache-Control: private` so shared caches never store them, Studio documents get `private` added to their `Cache-Control` while their policy names the request's origin, and the editor policy carries `webrtc 'block'`; because Chromium does not enforce that directive yet, bundles that reference the WebRTC API are refused at load in both modes. A dedicated editor origin remains optional hardening. Same-host mode is refused with a cleartext non-loopback configured Studio origin, with a Page runtime on the Studio origin, and when `null` is a trusted origin.
- **Default-off workbook editor origin.** Operators can configure a dedicated HTTPS origin that serves only digest-pinned, manifest-verified editor bundles (pinned by the manifest digest) under a fixed server-set policy: the document is CSP-sandboxed into an opaque origin (no cookies, storage, top navigation or popups) and must be framed with `sandbox="allow-scripts"` plus `credentialless`, assets load cross-origin without credentials, manifests are decoded strictly, inline scripts run only by hash, `'wasm-unsafe-eval'` applies only there and `frame-ancestors` is limited to the Studio origin. The configuration refuses an editor host shared with or parent of Studio or the Page runtime, apex and trailing-dot hosts, and trusted API origins; Studio frames it while enabled.
- **Experimental offline workbook operations** add a default-off GridCraft Artifact adapter, native-file imports and scoped agent cell edits with durable receipts, retry recovery and bounded worker admission. Runtime activation requires a qualified persistent digest-pinned worker reached over a private authenticated socket. Embedded editing, collaboration and portable workbook backup/restore are unavailable; affected workspace backups fail explicitly.
- **Guest access explanations match the supported resource policy.** Member settings name agents, routines and projects; CLI help explains the runtime prerequisites, and Edit explains the separate Publish share instead of claiming publication always needs a trusted reviewer.
- **Skill repository imports use verified, pinned HTTPS connections.** Redirects and inherited Git/proxy/credential configuration are disabled. Administrators can allow exact private Git hosts with `skills.private_hosts`; loopback and metadata targets stay blocked. Imported `SKILL.md` files are read within the chosen import root, with bounded regular-file reads.
- **Backup inspection reads metadata and reports that integrity has not been verified.** Restore, verification, recovery and conversion use operator-configured decoder, work, output, metadata, time and admission limits. Defaults allow one million logical entries and 256 MiB of cumulative path/link names across all passes. Large operations can fail with an explicit resource allowance error; operators can tune the documented capacity settings.
- **LLM stream accounting avoids redundant JSON decoding.** The sidecar decodes valid SSE usage envelopes once while retaining existing token accounting and malformed-root fallback.
- Mooring SDK recovery refuses incomplete full snapshots even when Yrs reports no missing updates, preserving every original unsaved draft instead of accepting silently omitted history.
- **Ask form patterns are checked by the server before a submitted answer is saved.** Author patterns no longer run in the browser's native regular-expression engine, including in message previews. The server uses the chat agent's stored definition and the same answer validator as CLI preview; a refused answer stays in the open form with its field error. ⚠️ **Behaviour change:** Go-only patterns such as `(?i)` are now enforced where older browsers silently skipped them. Legacy stored patterns Go cannot compile remain unenforced, while saving a new or updated definition with an invalid pattern is still refused. Invalid or stale submission envelopes are rejected rather than saved as ordinary messages. Restricted text-only chats refuse ask forms instead of discarding their validation metadata. Deferred submissions recheck the current form and Page access after an environment build; refusals are private and correlated with the original submission.
- ⚠️ **Behaviour change: routine expression inputs stay data.** CEL and expr code now receive typed inputs and prior step outputs instead of rendered program text. Simple legacy `{{ inputs.x }}` references, including a whole quoted reference, translate at runtime without rewriting saved definitions. Embedded or complex templates are rejected on save and fail closed for historical definitions; use typed selectors directly. Complete JSON step outputs retain their JSON types, missing selectors fail explicitly, and nested selectors walk each path segment. `crewship routine validate` reports the same migration guidance.
- ⚠️ **Behaviour change:** Public Pages password checks have configurable process-wide and per-link concurrency limits. Busy checks return 429 with Retry-After immediately; existing per-link rate limits and password refusal responses remain in force.
- **Native WordCraft and GridCraft editors stay connected through unrelated workspace changes.** Creating another Page, changing a grant on another Page or adding a workspace member no longer disconnects every open native editor with "Editor odpojen" and a 403 on the next save. A native editing session now ends only when a change can affect that person or that Page, including a revoked and restored grant, membership loss or a revoked credential.
- **Open Design canvases stay connected through unrelated workspace changes.** Creating another Page, changing a grant on another Page or adding a workspace member no longer closes every open Design websocket in the workspace, which could drop unconfirmed edits on large canvases. A Design connection now closes only when a change can affect that person or that Design Page, including a revoked and restored grant, membership loss or a revoked credential.
- ⚠️ **Behaviour change:** Routine-version and consolidation diff previews share configurable byte, line and concurrency budgets. Oversized previews return 413 and busy comparisons return 429 with Retry-After immediately; the UI and CLI show an explicit refusal. Accepted comparisons keep their existing hunks and stored definitions are unchanged.
- **Audit history damage is detected without operator requests.** Full instance and workspace verification now runs at startup and hourly outside writer transactions; post-upgrade defects and unchained fallback records alert instance admins. Delivery receipts commit with the inbox notice and survive inbox purge/retention, so handled security notices are not repeatedly restored or resent.
- **Crews pick up a new sidecar after an upgrade without `crewship crew restart-agents`.** A crew container keeps running the `crewship-sidecar` it was created with, so after an upgrade agents silently lacked whatever the new sidecar adds (such as new MCP tools) until an operator recycled the crew. Crew containers are now stamped with the hash of their sidecar (`crewship.sidecar-hash`); at a crew's next start a container with a different or missing stamp is recreated when it is stopped or idle, keeping its volumes, workspace data and credentials wiring, and a `sidecar.recreated` journal entry records the old and new hash. A container with an active run is never interrupted: the run keeps the existing `sidecar.stale` signal and the container is replaced at its next idle start. Runs that start together recreate it at most once. ⚠️ The first start of each idle crew after upgrading to this version recreates its container once, because existing containers carry no stamp yet.
- ⚠️ **Downgrade boundary: saved preset choices are per version.** After migration `20261022114610`, a routine can carry both a v1 and a v2 preset choice. Earlier builds cannot handle that and are refused at start by the version-skew guard. Downgrade by restoring the pre-upgrade snapshot (see Upgrades → Rollback / downgrade), never by deleting migration records.
- Guests with separate View, Edit and Publish shares can save, structurally validate and publish an exact shared draft from the web editor. Publication never starts a run; conflicts require explicit reload. Routine Share and the person's Access card expose Publish with its Edit dependency. The new immutable v2 preset (levels None, Edit, **Edit + Publish**) preserves separate View, Results and Run shares and revokes Publish through the same reviewed preview; v1 stays unchanged, and saved preset choices are now kept per preset version so applying v2 no longer overwrites a v1 record. A refused publication or structure check (422) shows the server's reason. Publishing a routine that other saved routines reach through `call_pipeline` is refused with 422. Bounded execution remains a separate runtime slice.
- **A staged audit key rotation is installed at start only if its audit entry vouches for it.** A `crewship audit rotate-key` interrupted after its audit commit is finished at the next start only when the entry is the newest rotation, names the staged active key and that key is not yet in the keyring; a stale or replayed `audit-keyring.json.pending-*` file is kept aside as `.discarded-<entry id>` (never overwriting an earlier copy) and the start continues with a warning instead of installing it.
- **Content scanners skip regex work when required literals are absent (#3995).** Conservative per-rule prefilters preserve Unicode case folding, custom and registered-secret rules, stream boundaries, normalization, findings and existing limits.
- **Agent MCP configuration values no longer reach the audit log, and agent privilege changes roll back when their audit fails.** Updating an agent used to copy the request body, including `mcp_config_json` with any API keys in its `env` or headers, into `audit_logs` and the journal, after the change had committed. The update is now one transaction with its hash-chained audit, which records previous and current tool profile, crew, role and MCP servers (server names, transport, command name and env/header key names only); temporary hire, rehire and release are chained the same way. Rows written by earlier versions are not rewritten: rotate credentials that were set in an agent's MCP configuration. A MANAGER's credential folder move is now checked against the folder's policy as it stands in the update's own transaction.
- **Optional qualified runtime: Guest-published routine execution (deferred from v1).** `crewship routine run <slug> --wait` starts a bounded manual run of a Guest-published routine on its recorded agents and `responses_text`/`native_api_key` profiles. Logging out does not stop it; revoking a used grant, removing or suspending the member, an administrator revoking the user's sessions (recorded durably, so this works after the user logged out), a grant issuer losing authority, rotating an agent's credential, or withdrawing the routine stops it before the next step, as does a 30-minute run limit. Delayed start is refused for published routines. Start and stop (with its reason) are recorded in the chained audit journal. Schedules, webhooks, nested calls and Page actions still refuse published routines.
- **Withdraw a Guest publication and set the Guest run limit.** `crewship routine unpublish <routine>` (Publish holder or workspace OWNER/ADMIN) withdraws a Guest-published routine: new runs are refused and running ones stop before their next step, with the change audited; republishing makes it runnable again. OWNER/ADMIN set the hard limit for one Guest-published run with `crewship workspace update --guest-routine-max-run-minutes N` (1-240, default 30).
- **Project checkpoints allocate less memory (#3993).** Pack creation reuses compression state between objects while preserving independent completed zlib streams and Git pack verification.
- **The audit signing keyring is encrypted at rest, and `crewship audit rotate-key` rotates it.** `<data-dir>/audit-keyring.json` held the audit HMAC keys as plaintext JSON. It is now sealed with AES-256-GCM under a key derived (HKDF) from the current master key; an existing plaintext keyring is sealed at the next start, and a master-key rotation re-wraps it at the restart the rotation already requires (keep earlier `ENCRYPTION_KEY_V<N>` until then). A keyring that does not open with the configured master key stops the start instead of being replaced. `crewship audit rotate-key` (`POST /api/v1/admin/audit/signing-keys/rotate`, instance OWNER with `instance:admin`) adds a new active key, keeps the old ones for verification, records `audit.signing_key_rotated`, and takes effect at the next start. A keyring configured outside the data directory is read but never rewritten. ⚠️ **Behaviour change:** builds before this one cannot read the sealed keyring; before rolling back, export it with `crewship audit export-keyring --plaintext` (see the audit security page).
- **Crew links, the artifact creation policy, credential folder policy and routine origin clears roll back when their audit fails.** These access changes used to be recorded only in the unchained Settings Audit log, some of them after the change had already committed; each now appends the hash-chained journal in the same transaction, with previous and current values, and still writes the Settings Audit row. Refused waitpoint decisions are chained the same way without naming the callback token. The crew runtime privilege audit now also records `init` and mounts, alongside `privileged` and added capabilities.
- ⚠️ **Behaviour change: first-run Setup is refused for MEMBER.** `POST /api/v1/onboarding/setup` now requires the OWNER, ADMIN or MANAGER role in the workspace; a MEMBER (or VIEWER) gets 403 Forbidden instead of creating the first crew. Ask a workspace owner or admin to run Setup, or to raise your role first.
- **Managed native executable verification avoids whole-file Go buffers (#3994).** Hashing and ELF inspection retain the same open descriptor and existing static-ELF acceptance. Unix image capture uses private, immediately unlinked temporary storage; Windows retains the existing buffered archive path.
- ⚠️ **Behaviour change: a password reset now revokes the account's CLI tokens.** Redeeming an emailed reset link and `crewship admin reset-password` used to revoke only browser sessions, so a CLI token minted under the old (possibly stolen) password kept working. Both now revoke every live CLI token of the account in the same transaction as the new password, the revoked sessions and the `auth.password_reset` audit entry (which now counts `cli_tokens_revoked`); after the emailed reset, open streams using those tokens close. Scripts and other machines need a fresh `crewship login` after a reset.
- **`crewship recover --force` works on a data directory that already booted.** Recovery restored the database and then refused because the directory's own audit keyring differed from the bundle's, stopping before `secrets.env` was written. It now checks the keyring before changing anything, replaces it with the bundle's atomically and keeps the old one as `audit-keyring.json.replaced-<UTC time>`.
- **Forked workspace restores keep Artifact comments dispatchable to agents.** `--as-workspace` and `--as-crew` gave each send-to-agent task a new id but left the comment's `task_id` on the old one, so pending feedback vanished from the hand-off list and could not be sent. The comment now follows its task.
- **`crewship admin reset-password` signs with the target instance's audit keyring.** With `DATABASE_URL` it used the default `~/.crewship` keyring, creating one if absent, so its audit entry could not be verified by the server owning that database. It now uses the keyring beside the database or in the named data directory, never creates one, and says which `CREWSHIP_AUDIT_KEYRING_PATH` to set when it cannot tell.
- **Audited writes no longer slow down as the audit history grows.** Appending to a workspace journal or the instance audit chain now checks only the chain tail and the new rows instead of re-verifying the whole history inside the write transaction (one append against 100,000 rows: about 1.4 s before, 0.3 ms after). Older defects no longer make every audited write fail with HTTP 500 after an upgrade; `crewship journal verify` and the new `crewship admin instance audit verify` (`GET /api/v1/admin/instance/audit/verify`) report them as `historical_invalid` / `historical_unverified` (rows from before the keyring upgrade or the last reseal) or `post_upgrade_invalid` (keyring-signed rows). A tail that does not authenticate, or whose predecessor vanished without a compaction checkpoint, still refuses. Revoking CLI tokens or sessions, suspending an account and local `crewship admin reset-password` recovery still succeed when the instance chain tail is broken, recording an audit row marked as an unchained fallback; access-granting actions, including password change and web password reset (now a clear 503), stay refused.
- **Instance admins are told when an audit chain breaks or is resealed.** A refused append, a failed check in the instance audit log or a defect found by `crewship journal verify` or `crewship admin instance audit verify` (including `post_upgrade_invalid`) record an `audit.chain_break_detected` instance audit event and put **Audit chain needs attention** in each instance admin's inbox (category security); every reseal records an instance event and sends **Audit chain resealed**. Background journal entries refused by a broken workspace chain are now held and retried every 30 seconds (up to 10,000) instead of being dropped, and other workspaces keep writing meanwhile.
- A Document or Slides page with edits the server has not accepted now asks before an in-app link leaves it (Keep editing or Leave anyway); the link used to do nothing and say nothing.
- Replaying a Document creation submission after a lost reply no longer adds a duplicate human message or starts another run.
- **A MANAGER's agent delete is re-checked against their current role, and agent-created agents name the calling run in the audit.** The delete's authorization is now decided again inside the delete transaction, so a demotion, removal or ownership change that lands meanwhile refuses it (403). The `agent.created` audit records the workspace and crew the caller's internal token is bound to and, for a valid run token, the run and agent; an invalid one is flagged, never trusted. The redacted MCP audit records a server command's executable only when it is a plain program name, so a quoted value split by spaces is no longer recorded in its place.
- **Creating and deleting an agent now roll back if their audit fails.** Agent create, delete and agent-initiated (internal) create used to be audited best effort after commit. They are now chained in the same transaction and record the agent's crew, role, tool profile and MCP servers (redacted). A removal after a failed review hold is chained too, and it completes even if the client disconnects. The MCP audit no longer records `NAME=value` assignments that come before the executable in a server command.
- Enter in a Document acts where the caret is shown: after a quick keyboard caret move such as Ctrl+End, it no longer splits the document where the caret was a moment before.
- Explicitly update an existing personal Document from its private chat with `run --document-target`, retaining the original human purpose and revision through agent drafting.
- New Documents retain their initial confirmed version in history, so it remains readable after later edits.
- Build releases with Go 1.27.3 to fix the reachable crypto/x509 certificate verification vulnerability GO-2026-6809.
- Fix Document formatting updates with bounded position-history metadata and aligned browser/service editor dependencies (#3855).
- **Chat says Stopping until the stop is confirmed.** After Stop on a live reply, the Stop button reads **Stopping…** and does nothing more until the server reports how the turn ended; pressing it again sends no second cancel. The partial reply stays on screen, and a turn that did not complete ends with one line in words: **Stopped**, **Interrupted** or **The run failed**, each noting that the reply above is partial or may be incomplete (or that it ended before any reply); the line stays after a reload. Applies to chats on the versioned event stream; older streams still return to ready at once.
- **New Doc states who can open the document.** The dialog no longer calls a new Doc private: it says **Who can open it — you, and workspace owners and admins; others only after you share it**, which is what the server enforces for a Doc created there. The Pages guide says the same and notes that such a Doc is not listed in **My space**, which holds only Documents whose audience is you alone.
- **Copy on a chat reply says what happened.** The reply's Copy button turns into a check and screen readers hear **Copied to clipboard** only after the browser confirmed the copy; when the clipboard refuses (permission, an insecure dev host without the fallback), it says **Copy failed. Select the text and copy it with your keyboard.** instead of failing silently. The same confirmed copy is used in the onboarding setup chat.
- **Saved documents in chat say who can open them, and empty documents say how to start.** A document card in the chat adds **Private to its owner and workspace owners**, which is what the server enforces for documents created from a chat. An empty document no longer shows a blank area: the editor says **This document is empty. Start writing below, or ask an agent in a chat to draft it.**, and the document panel in the chat points to **Edit here**. A document that only holds an inserted heading, list or table is not called empty.
- **Copy on a chat reply says what happened.** The reply's Copy button turns into a check and screen readers hear **Copied to clipboard** only after the browser confirmed the copy; when the browser refuses both the clipboard and the fallback copy, it says **Copy failed. Select the text and copy it with your keyboard.** instead of failing silently. The same confirmed copy is used in the onboarding setup chat.
- **A stopped reply stays in the chat.** A turn stopped (or failed) before any reply no longer disappears when the chat reloads its history; it stays below the message it answered with its **Stopped** line. A page reload still shows only the message, because the server keeps no record of such a turn.
- **Undo and Redo on the Document toolbar.** The editor's toolbar has **Undo** and **Redo**, so a phone or tablet without a keyboard shortcut can take back an edit. Undo only ever takes back your own edits in this editor: a paragraph another person saved in the meantime stays, and cannot be undone from your editor.
- **Chat says Stopping until the stop is confirmed.** After Stop on a live reply, the Stop button reads **Stopping…** and does nothing more until the server reports how the turn ended; pressing it again sends no second cancel. The partial reply stays on screen, and a turn that did not complete ends with one line in words: **Stopped**, **Interrupted** or **The run failed**, each noting that the reply above is partial or may be incomplete (or that it ended before any reply); the line stays after a reload for a turn the server saved. Applies to chats on the versioned event stream; older streams still return to ready at once.
- **New agents can save Documents in a running crew.** Authorized creation and drafting no longer fail because the shared container's startup roster lacks the new agent's label; current run and human permissions are still checked by the host.
- **Backup downloads stop after access is revoked.** Bundle downloads recheck credential, account and live role before each chunk. Browser streams also observe session revocations persisted by a separate local recovery process. Private Page custodians retain versions, exports, documents, projects and chat context when restricted elsewhere; access by another workspace OWNER remains audited before output.
- **Access changes and their audit commit together.** Workspace/crew settings, crew deletion and admin session/lockout changes roll back if audit fails. Private membership and invitation snapshots retain old rights without exposing them through public feeds or search; provisioning records non-secret account/setup facts.
- **First-run Setup records crew membership atomically.** Setup requires current crew-creation authority (MANAGER, ADMIN or OWNER); stale, suspended and globally restricted accounts cannot create a crew through onboarding.
- **Guests can publish an exact shared routine draft through API and CLI.** Validation is structural only; publication checks live explicit rights and commits immutable authority plus audit without starting a run. Stale/busy snapshots return 409, existing triggers 422 and null descriptions 400. Generic callers and triggers cannot use bounded publication authority; manual execution remains a separate slice.
- **Routine Publish is an explicit share.** Member policies, invitations and provisioning accept `publish` only together with `edit` for the same routine; otherwise they return 422 without writes. View and Run stay separate. Preset changes preserve this dependency. Bounded publication archives retain their authority across backup/restore and cannot enter generic runs or triggers.
- **Harbor 2: the rail on one axis.** Every icon, the workspace mark, Search, the Crewship sail and your avatar are centred on the same line in the folded and the open rail; icons are 18 px, and the workspace, the sail and you are all 28 px. Search is an icon like any other row in the folded rail and a borderless field in the open one. The open workspace card shows your role under the name. The app list scrolls between a fixed top and foot with a fade at the edge, and groups (Work, Build) fold in the open rail and stay folded on this device. The sail stays Crewship blue in every style.
- **The Crewship sail is always in the rail.** It ends the rail, just above the footer's rule, in its own lit blue tile, and stays when the rail folds to icons; the top of the rail is the workspace switcher and Search. It opens **About Crewship**: what Crewship is, the edition and build, and links to the documentation, what's new and reporting a problem.
- **Linked issues appear in a new chat without a reload.** After the first message of a new conversation, the chat used to show a bare **Unavailable** line and no linked issue, proposal or decision cards until the page was reloaded; it now checks access as soon as the conversation exists.
- **A chat you cannot use says so.** Opening someone else's private chat by its address shows an empty composer, as before (the address alone does not reveal whether it exists). The first send is refused, and the chat now keeps a notice in place: **This conversation isn't available to you**, with **Start a new chat**. Your draft stays in the box. A refused send no longer blames your connection, and **Prepare project inputs** is not offered there.
- **Harbor 2 on a phone: Inbox and Settings pilot.** On a phone an Inbox item's header is Back, the item's name in two lines and a ⋯ with Previous, Next, Archive and Mark unread; Back returns to the list with its search, filters and scroll — also after the browser's Back or a reload — and after a direct link it goes to the Inbox, never out of the app. A workspace switch starts the list clean. Active filters get **Clear filters** beside their chips; a search that finds nothing says what and where; a failed load shows Retry in the list. A Settings section is a step in the browser history, so Back returns to the section list and asks first when a form has unsaved edits. Save bars dock on every phone width and ride above the on-screen keyboard; the tab bar steps aside while you type; toasts sit above both. Header buttons are real 44 × 44 targets on touch screens. On the approval detail the decision note sits above the buttons, Approve keeps its size while it works, run steps no longer wrap letter by letter, and denying an approval shows "Denied · <routine> stopped" instead of a red failure.
- **Animated Voxel avatars, the new default (#3789).** The avatar picker offers DiceBear's **Voxel Bot** and **Voxel Art**, marked New, and new agents start on Voxel Bot — from the dashboard, the CLI, the API or a template. Drawn at 32 px or larger they blink and stretch now and then; smaller ones stay still, and so do all of them with Reduce motion On, with the new **Settings → Appearance → Animated avatars** switch off (on by default, synced with the other appearance choices; per viewer, so a workspace default never sets it), or when the operating system asks for reduced motion. The picker says so in one line when an animated style is chosen. **Existing agents keep their face:** upgrading pins every agent that was drawn with the old default to Bottts Neutral by name (the picker now shows it as Bottts Neutral rather than "Follow the crew"); agents with their own style or a styled crew are untouched. The voxel styles come from DiceBear 10, loaded beside 9.4 only for them (CC0 1.0); the other 25 styles stay on 9.4. Voxel avatars are always drawn live, never stored, and **Store missing avatars** counts them as such. `crewship agent create|update --avatar-style` and `crewship crew apply-avatar-style --style` accept `voxel-bot` and `voxel-art` and list every style in `--help`. ⚠️ **Behaviour change:** an unknown avatar style slug is now refused — `400` from the API, an error from the CLI before anything is sent — instead of being stored and drawn as the default.
- **Composer artifact context and conversation library, behind the same flag.** An attached item needs an explicit create, update or reply-only choice, shows executor, location and the real audience before sending, and blocks on an ambiguous target. The library lists only explicitly linked items, with restricted links shown anonymously. Updating an attached document from chat stays disabled until the server confirms the chat's audience (no such signal exists yet); a reply-only or plain message is unaffected.
- **Composer artifact context and conversation library, behind the same flag.** An attached item needs an explicit create, update or reply-only choice, shows executor, location and the real audience before sending, and blocks on an ambiguous target. The library lists only explicitly linked items, with restricted links shown anonymously. Updating an attached document from chat stays disabled until the server confirms the chat's audience (no such signal exists yet); a reply-only or plain message is unaffected.
- **Chat result cards and viewer switching, behind `NEXT_PUBLIC_CHAT_ARTIFACT_CONTEXT` (off by default).** Result cards report server run state, saved content and freshness separately, and give revoked access, lost connection, unknown result, conflict, stopped run, missing runtime and broken preview each their own next action. The side viewer header switches only between accessible conversation links and keeps an exact revision distinct from an explicit latest. These components are not mounted in this change and no backend serves their endpoints yet.
- Stop pending Document journal writers before erasing browser drafts on sign-out or account change, so delayed writes cannot restore private copies.
- **Composer artifact context and conversation library, behind the same flag.** An attached item needs an explicit create, update or reply-only choice, shows executor, location and the real audience before sending, and blocks on an ambiguous target. The library lists only explicitly linked items, with restricted links shown anonymously. Updating an attached document from chat stays disabled until the server confirms the chat's audience (no such signal exists yet); a reply-only or plain message is unaffected.
- **Chat result cards and viewer switching, behind `NEXT_PUBLIC_CHAT_ARTIFACT_CONTEXT` (off by default).** Result cards report server run state, saved content and freshness separately, and give revoked access, lost connection, unknown result, conflict, stopped run, missing runtime and broken preview each their own next action. The side viewer header switches only between accessible conversation links and keeps an exact revision distinct from an explicit latest. These components are not mounted in this change and no backend serves their endpoints yet.
- Stop pending Document journal writers before erasing browser drafts on sign-out or account change, so delayed writes cannot restore private copies.
- ⚠️ **Behaviour change: GDPR erasure anonymizes retired credential creators.** Retired credentials no longer require a live custodian; their creator attribution becomes NULL while IDs and audit history remain. Active credentials retain the existing custody requirement, and creatorless tombstones cannot be reactivated. Workspace restore/fork preserves nullable retired creators.
- Retain original human authority for targeted Document runs and refuse missing or superseded intent bindings; the chat update entry point remains disabled.
- ⚠️ **Behaviour change: credential retirement irreversibly erases vault material.** Existing and newly retired credentials retain their IDs and audit history, while secret/refresh values, account metadata, custom fields and pending OAuth state are cleared, including historical restore/fork imports. Active credentials remain unchanged. Integration removal now rolls back if credential retirement or its audit cannot be completed.
- **Chat shows the model the chat is configured to use.** The composer's model control read a path the server never served and always offered a built-in list, silently treating its first entry as selected. It now shows the model the chat run preview reports, lists the provider's models from the server labelled as live or curated, says plainly when the list cannot be loaded, and states that a listed model is not proof of access or of what a run will use. Choosing a model from the list is not offered yet.
- **Audit signing keys survive vault-key rotation and instance recovery.** New audit rows identify their signing key; retained keys verify history without rewriting it. The encrypted recovery kit retains the keyring. An explicit OWNER `crewship audit reseal` checkpoint can start a verified continuation while preserving the unverified status of history whose key is missing.
- **Slides says a local draft is not saved, in the same words as Document.** With `NEXT_PUBLIC_SLIDES_EDITOR` on, an edited deck reads **Not stored in this browser or on the server · keep this tab open**, and **Saved** with **Confirmed by server** appears only after a receipt for the change that was sent. Document and Slides now share one save lifecycle (save states, a write queue that waits for the receipt and retries the same change, and the leave prompt); Document's save words are unchanged, and nothing changes with the flag off. When access to a Document is removed while edits are unsent, it now says **Your latest edits were not saved: access to this document was removed.** (the unsent edits are still not kept) (#3889).
- Preserve Claude Code tool result text and error details in chat and run traces when the CLI returns structured content blocks.
- Reject unsupported Document revision selectors instead of silently returning the latest content. Saved checkpoints remain available through their explicit reader.
- **Edit a chat's saved document without leaving the chat.** The document panel opened from a result card now has **Edit here**: the body becomes the document's own editor, with its save state and recovery, and **Done editing** shows the saved result. Leaving editing or closing the panel with unsent edits asks first; **Open full editor** still opens the Page in a new tab (#3886).
- **The Document save status separates "saved locally" from "confirmed by server".** While work is unsent the header says whether the browser has kept a copy, is still writing it, or could not store it; only a server receipt shows "Confirmed by server".
- **Unconfirmed Document edits survive browser reloads.** Pending human edits are retained privately per signed-in user and document before transmission; reopening offers explicit recovery after current access is checked. Unavailable browser storage prevents editing, and restored drafts never replay an old write grant automatically. The browser copy is deleted when access to the document is lost (401, 403, 404) and on sign-out, session expiry or a change of signed-in user, so a shared browser keeps no private text.
- **Native Slides can be initialized and read with `crewship slides` when `CREWSHIP_SLIDES_ENABLED` is enabled.** Current custodians can save a schema-1 deck on an empty private Page; exact retries retain the original receipt. Reads check live private access and audit another workspace OWNER before releasing content. Private Pages remain indistinguishable from missing Pages even for malformed requests. The adapter remains disabled by default.
- Prepare a client-side mirror of the strict native Slides operation contract (hashes, validation, atomic batch apply and diff-to-patch) with a flagged save client contract; no editor or save route is exposed yet.
- Prepare a static App preview boundary with scripts, navigation and external resources disabled, pinned revisions and immediate removal on access loss; it is not mounted in app routes and stays behind `NEXT_PUBLIC_STATIC_APP_PREVIEW` until a Page endpoint serves publication HTML.
- **Document history can compare revisions and revert one change; agent proposals can be reviewed.** Compare any retained revision with the last saved version by labelled blocks (unsent edits are not included) (including link and formatting changes), revert a single change as a separate action from restore, and accept or reject a proposal. Compare is always available; revert and proposals stay off behind `NEXT_PUBLIC_DOCUMENT_REVIEW_ACTIONS` until the server endpoints exist.
- **Chat search with filters.** The chat sidebar has a search dialog (Ctrl/Cmd+Shift+F) with This chat / All chats / Files tabs and `from:`, `in:`, `has:`, `after:`, `before:` filters. Results open the exact message; `from:` matches only the message's author (agent or an agent's own replies; `from:me` waits for the server to return the author), a full page of 50 says more may exist, a full page narrowed on the client, an unavailable source or an error is shown as such and never as a clean zero. The Ctrl/Cmd+Shift+F shortcut is on for everyone but never fires inside text fields. Files search and room/DM search wait for backend support.
- **Chat sidebar views (behind `NEXT_PUBLIC_CHAT_SIDEBAR_VIEWS`, default off).** With the flag on, the chat sidebar has Unreads and Agents running views, and lists hold still under the pointer or keyboard focus: background updates change rows in place and a Refresh button applies new order, while your own actions (search, favourites, opening a row) apply at once. The open chat stays listed, marked "Open chat", when a view would filter it out. Mentions, Threads, Saved, Drafts, Waiting for you and Review are sample-data previews behind `NEXT_PUBLIC_CHAT_SIDEBAR_SMART_SECTIONS`.
- Prepare the native Slides editor interactions: select (Shift for several), drag, resize and keyboard-nudge elements, layer commands, undo/redo, empty/loading/error/conflict states and a read-only phone preview. The editor is not mounted yet and edits stay a local draft until the Slides save route exists.
- Read and initialize native Slides through the server's `GET .../slides` and `POST .../slides/initialize` contract (behind `CREWSHIP_SLIDES_ENABLED`): the read must name the requested Page in `deck.deck_id` and carry exactly the five documented fields, and an initialize receipt is checked field by field. The Pages route mounts the editor behind `NEXT_PUBLIC_SLIDES_EDITOR`; edits are a labelled local draft because the server has no save route yet.
- Prepare a client-side mirror of the strict native Slides operation contract (hashes, validation, atomic batch apply and diff-to-patch) with a proposed save client contract; no editor or save route is exposed yet.
- **The Document save status separates "saved locally" from "confirmed by server".** While work is unsent the header says whether the browser has kept a copy, is still writing it, or could not store it; only a server receipt shows "Confirmed by server".
- **Unconfirmed Document edits survive browser reloads.** Pending human edits are retained privately per signed-in user and document before transmission; reopening offers explicit recovery after current access is checked. Unavailable browser storage prevents editing, and restored drafts never replay an old write grant automatically. The browser copy is deleted when access to the document is lost (401, 403, 404) and on sign-out, session expiry or a change of signed-in user, so a shared browser keeps no private text.
- Prepare the native Slides editor interactions: select (Shift for several), drag, resize and keyboard-nudge elements, layer commands, undo/redo, empty/loading/error/conflict states and a read-only phone preview. The editor is not mounted yet and edits stay a local draft until the Slides save route exists.
- Read and initialize native Slides through the server's `GET .../slides` and `POST .../slides/initialize` contract (behind `CREWSHIP_SLIDES_ENABLED`): the read must name the requested Page in `deck.deck_id` and carry exactly the five documented fields, and an initialize receipt is checked field by field. The Pages route mounts the editor behind `NEXT_PUBLIC_SLIDES_EDITOR`; edits are a labelled local draft because the server has no save route yet.
- Prepare a client-side mirror of the strict native Slides operation contract (hashes, validation, atomic batch apply and diff-to-patch) with a proposed save client contract; no editor or save route is exposed yet.
- Prepare a static App preview boundary with scripts, navigation and external resources disabled, pinned revisions and immediate removal on access loss; it is not mounted in app routes and stays behind `NEXT_PUBLIC_STATIC_APP_PREVIEW` until a Page endpoint serves publication HTML.
- **Password changes, HTTP and local CLI password resets, workspace/folder deletion and folder ACL changes fail atomically when their required chained audit cannot be recorded.** Passwords, reset-proof consumption and session/token revocations commit together; existing CLI commands retain their request shapes. Session disconnects are notified only after commit. Workspace deletion and workspace member removal recheck current authority inside the writer transaction.
- **Routine schedules say how their last fire ended.** Each schedule in a routine's Triggers tab now ends with "last fire <time> · <outcome>": "queued for capacity" when a full routine queued it, "skipped: capacity or catch-up" when a waiting occurrence or catch-up after downtime dropped it, and "skipped: routine inactive" (or "previous run busy or routine inactive" for an active routine) when nothing was counted as missed. The schedule does not record which cause applied, so the label names both. The scheduling, routines and manifest guides now describe capacity queueing, catch-up alerts and replay with edited inputs and metadata.
- **Terminal and restricted text streams stop at credential loss.** CLI terminal tickets use the shared source-token registry; revocation, suspension and original expiry close open shells. Source-credential checks remain in memory. Terminals additionally recheck live resource authority with one SQL query per PTY data/control frame and check idle shells on the 30-second watcher. Resource queries configure a five-second context deadline, but native SQLite busy handling can outlast it; no hard maximum closure time is guaranteed. This security fallback does not complete the H1 zero-SQL goal.
- **Filter My space.** The private Document catalog can be narrowed by type, scope, owner and state; groups that cannot vary on the list are hidden. Counts only reflect items the server returned.
- Move to a working folder (who gains content and history, same ID, a result per item) and Duplicate are built behind `NEXT_PUBLIC_ARTIFACT_COPY_MOVE` and stay hidden until the server routes exist.
- Show a personal view of private Documents and display the private creation audience before sending a chat request.
- **Tool activity in chat no longer shows failures as success.** A group of tool steps says "Worked" only when every step succeeded; a failed step is labelled, opens the group and is never green, and parallel tool calls are matched to their own results. A finished reply with steps that have no recorded result reads "Finished" rather than success. A reasoning block shows its approved safe summary line next to the recorded time.
- Prepare a strict Document-to-DOCX converter for validated saved content; export delivery and Microsoft 365 compatibility remain unqualified.
- **Workspace default look.** An owner or admin can set a default style, accent and theme for the workspace (Settings › Appearance › Workspace default, `crewship workspace update --appearance-default`, `PATCH /api/v1/workspaces/{id}` field `appearance_default`). Members inherit every value they have not chosen themselves; Appearance shows which is which and offers Use workspace default. Appearance sync now saves only values you changed, instead of your whole look. Personal appearance changes save as you make them and the last one can be undone from the toast that follows.
- **Harbor 2: Settings details.** Appearance › Sidebar now uses the rail's own names (Expanded, Expand on hover, Collapsed). An old `/settings?tab=audit` link opened by a Member or Manager lands on the Audit log page, which says who may read it, instead of silently showing Profile. The Account security page for restricted sessions uses the same 820 px column as the rest of Settings. The CLI calls behind Members, Crew links and the journal check are now covered by acceptance tests.
- **One name: Artifacts.** The command palette, the Dashboard strip, the Artifacts overview card and the Activity filter now say Artifacts where they said Pages (addresses and commands are unchanged).
- **Command palette: the empty state follows the design.** Opening ⌘K shows Recent, Quick actions, Go to and Switch workspace; the list of settings pages appears once you type, like the other results.
- **Sidebar modes have one set of names.** The rail menu now says Pinned open, Rail · expand on hover and Rail, as Settings › Appearance does.
- **Crews: the icon you pick is the icon you get** (#3767). The icon dialogs and the New/Edit crew identity tile preview the crew as the header draws it (solid colour tile, white glyph). Settings ends with the Danger zone; the image card says what "current" is compared against.
- **Crews: New crew opens the crew it created** (#3762). After Create crew, /crews kept the crew it had auto-opened on load on the canvas; it now opens the new one.
- **Dashboard sparklines for Success and P95.** `GET /api/v1/metrics/timeseries` accepts `metric=success_rate` and `metric=p95_duration_ms` (per bucket, from the same rules as the run insights); a bucket in which no run finished has no value. `crewship metrics --series` now sends `--window` and `--bucket` (the old `--range` was never read by the server and still works as the window).
- **Calendar: agents and .ics.** Every event of `GET /api/v1/workspaces/{id}/pipelines/calendar` now lists the `agents` its routine's steps run (for the Agents view and the agent filter), and `GET .../pipelines/calendar.ics` (`crewship routine calendar --ics`) returns the same window as an iCalendar file. A signed subscription URL that calendar apps can poll is not part of this.
- **Crew monthly budget and Release now.** `GET/PUT/DELETE /api/v1/crews/{id}/budget` and `crewship crew budget get|set|clear` set a crew's monthly spend limit (Admin and above; tiered by default: warn from 80 %, stop new runs at 100 %). `POST /api/v1/agents/{id}/release` and `crewship release` end a temporary hire before its expiry; it becomes an expired hire and Rehire brings it back. ⚠️ A hard or tiered limit makes admission refuse unmetered legacy proxy traffic for that crew.
- **Crews needing a rebuild on the Dashboard.** New `GET /api/v1/crews/provisioning-summary` and `crewship crew provision summary` list, in one request, the crews whose image build failed or that have no built image yet. The Dashboard shows them as a "N crews need a rebuild" tile after capacity (it used to say "Nothing needs you" while the Crews panel listed those crews under Needs you).
- **Harbor 2: Crews defects against the v67 wireframe.** The Delete crew dialog now names what the crew holds ("3 agents · 2 routines · container running"). The agent Skills card has **Add skill** (no detour through Manage skills). The crew options menu has **View as YAML** and **Download crewship.yaml**. The command rows in crew and agent Settings carry a line of description and a Copy button; the crew card adds `crewship apply --file <slug>.yaml`, and the agent card lists `agent update --llm-model` and `logs --follow`. Agent Settings shows a static **Hooks** card with a CLI hint; it says plainly that hooks are paused on the server and do not fire yet.
- **Harbor 2: skill Activity.** The Activity action on a skill page now opens Activity filtered to that skill (it used to switch to the Used by tab), and it is also available on a phone.
- **Harbor 2: skill Activity.** The Activity action on a skill page is also available on a phone. It opens the skill's Recent uses under Used by until Activity can filter by skill.
- **A shorter style picker.** Settings › Appearance › Style shows one live preview of the chosen style, with its description, above category chips and a compact grid of colour palettes, six to a row on a desk. Pointing at a palette previews it; clicking chooses it. (#3757)
- **Harbor 2: every wireframe style in Settings > Appearance.** The style gallery now carries 28 more styles (44 in all), so each colour style in the design has exactly one counterpart under a neutral name: Terracotta, Beacon, Carbon, Meadow, Heather, Aubergine, Lagoon, Parchment, Coral, Iris, Twilight, Marigold, Cobalt, Studio, Mulberry, Console, Bluebell, Regal, Cerulean, Denim, Sandstone, Frost, Pebble, Wisteria, Pane, Dove, Tangerine and Skyline. A new **System** section groups the seven desktop and mobile looks. Each style brings its own accent colour (41 hidden accents, not offered in the accent picker). Every style passes the same contrast checks as Harbor; where a dark ground was lighter than the accents allow, it is a little deeper than in the design.
- **Harbor 2: Activity says who and what by name.** A change row is titled with the issue, artifact, agent or crew it changed, and names the person who made it instead of "A person" (the journal lookup now lists the workspace's people by name, never by email; `crewship journal lookup` prints them too). Statuses read "Backlog → Todo", an assignment says who it went to, and the change group is called Artifacts.
- **Harbor 2: the Issues panel's six views.** Views now lists My work, Needs my reply, Agents working, Waiting for my review, Blocked and All issues, each with an exact count from the server. `GET /issues` gained `owner_id`, `delegate_id`, `work_mode`, `mine`, `working`, `needs=reply|review` and `blocked`, and `crewship issue list` the matching `--owner`, `--delegate`, `--work-mode`, `--mine`, `--working`, `--needs`, `--blocked`. A project's bar in the panel now shows done over total issues and is not drawn for an empty project. The issue page's ⋯ menu has Duplicate issue.
- **Harbor 2: a routine folder has its own menu.** Each folder heading in the Routines panel has a **⋯** menu: **Rename…**, **Icon and colour…**, **New subfolder**, **Move to…** and **Delete folder…** (its routines are kept and become unfiled; its subfolders move up a level). Folders nest up to three levels and show their icon. API: `icon` and `parent_id` on `pipeline-folders` (create and PATCH; a cycle or a fourth level is refused); CLI: `crewship routine folders create/update --icon --parent`. Sharing a folder is not offered: a routine folder still grants no access (#3768).
- **`crewship seed --ui-tour`.** A new additive seed profile for reviewing the product with realistic data: on top of the default demo (on dev slots after `crew reset --yes`) it adds scheduled routines in routine folders (Daily operations, Customer care, Finance, Reports) with run history — completed, waiting for a person and failed — so Calendar shows upcoming fires, plus a 22-issue board and the inbox items and activity those produce. Idempotent and needs no provider credentials. See `docs/cli/seed.mdx`.
- **Harbor 2: Routines overview, panel and folders.** The overview opens with a page head (Routines, "7 routines · 4 need you · next run today 09:30"); the top bar no longer repeats the counts. Card titles are never cut off (Next 24 hours links to **Calendar**). Health lists a routine quietly when it is fine (no dashes, no $0.00, no "All good" on every row) and a **Checkup across routines** card lists only the routines that have something to fix. Health now reads each routine's last 20 runs, success rate and 30-day spend from the new `GET .../pipeline-health` (`crewship routine health`). The Routines panel groups by **Folder** once one exists: **New folder** in the toolbar, **Move** when selecting several (`crewship routine folders ...`, new `pipeline-folders` API); a folder only organises, it grants no access. Panel search also finds a routine by the text of its steps (`GET .../pipelines?q=`, `crewship routine list --search`). The Checkup card shows the server's checklist (`GET .../pipelines/{slug}/checkup`, `crewship routine checkup`). A draft and the versions that hold a tested definition show their **Test run passed/failed** (kept per definition hash). New routine limits offer **Skip the new start** (`concurrency_policy: skip`: a schedule records Skipped, a webhook answers 200 SKIPPED). `crewship routine schedules preview --when "every weekday at 8:30"` turns words into a cron on the server. Routine templates: `crewship routine templates` and the `pipeline-templates` API (using one saves a draft). A routine step can **create a page** (`page.create`). Fixed: turning a schedule back on after the circuit breaker said the failure count resets after the next successful run; it restarts from zero immediately. ⚠️ **Behaviour change:** the panel's default grouping is Folder (it falls back to Crew while there are no folders); the "What it does" hint reads "Written from the definition by the server, not by a model."
- **Harbor 2: Skills and Integrations, the parts that needed the server.** Skills show the last **30 days** (Library column "Uses · 30 d", the skill page's "Last 30 days" card with its errors, and `uses_30d` / `errors_30d` in the API and `crewship skill list`). Managers can **archive and restore** skills by hand: Archive / Restore in a skill's ⋯ menu and in the Library's selection bar (Restore in the Archived view), `POST /workspaces/{id}/skills/{skillId}/archive|restore` and `crewship skill archive|restore`; built-in skills cannot be archived, and a restored skill that no agent holds is still judged by the keeper's sweep. A skill's **Activity** button opens Activity narrowed to the work whose agents called that skill: Activity has a **Skill** filter (chip, `?skill=`, Filter facet), fed by the new `skills` / `skill_count` on `GET /chains` (matched on the agent and the assignment's time window, since calls are not recorded against a run). Triggers: an **agent trigger shows its call count** (`GET /workspaces/{id}/webhook-deliveries/summary`, `crewship work deliveries summary`); a routine trigger's Mapping tab has **Test mapping**, which shows the inputs a sample call would give the routine and whether it would accept them without running anything (`POST /pipeline-webhooks/{id}/test`, `crewship routine webhooks test`); and **rotating a routine trigger's secret can keep the old one valid for 1 hour, 24 hours or 7 days** (`rotate_grace_seconds`, `crewship routine webhooks update --rotate-secret --grace 24h`). ⚠️ **Behaviour change:** the skill page's Activity button is now a link to Activity instead of switching to Used by (Recent uses stays in Used by).
- **Harbor 2: skill Activity.** The Activity action on a skill page opens Activity filtered to that skill, also on a phone.
- **Vault: folders.** Secrets can be filed in folders (two levels), shown under Views in the Vault panel; picking a folder filters the list, the panel's + creates one, and Add secret and the secret's Protection card choose or change the folder. A folder can limit who reveals its values (owners and admins, or nobody), set the lowest Keeper tier and a default tier for new secrets, and remind you to replace a secret after N days; secrets past their reminder appear under Needs attention. `crewship credential folder list|create|update|delete`, `--folder` on `credential create|update|list`, and `GET|POST|PATCH|DELETE /api/v1/credential-folders`. ⚠️ **Behaviour change:** none for existing secrets (unfiled); a folder's reveal policy only tightens the workspace reveal gate. Folder sharing (Can use / Can manage) is not part of this change.
- **Vault folders keep their protection when they move or tighten (#3706).** Moving a folder (to the top level or under another parent) that would loosen its effective reveal policy or tier floor now needs an owner or admin; a manager gets 403 and nothing changes. Raising a folder's lowest tier, moving a folder under a stricter parent, or filing a secret into a stricter folder lifts the secrets concerned to the floor in the same write, and Keeper always gates at the higher of a secret's tier and its folder's floor. The Vault panel gains Edit folder for the open folder (name, who can reveal, lowest tier, replace reminder). ⚠️ **Behaviour change:** a raised floor raises existing secrets (it used to leave them below it), and `PATCH /credentials/{id}` with only `folder_id` into a stricter folder raises the tier instead of returning 400.
- **Vault: API key spend.** An AI provider account that is an API key shows "$ this month" (the calendar month so far, UTC) on its card; subscription seats still show no price. New `GET /api/v1/paymaster/credential-spend` (OWNER/ADMIN; `range=month`) and `crewship paymaster credential-spend`.
- **Harbor 2: the Issues panel's six views.** Views now lists My work, Needs my reply, Agents working, Waiting for my review, Blocked and All issues, each with an exact count from the server. `GET /issues` gained `owner_id`, `delegate_id`, `work_mode`, `mine`, `working`, `needs=reply|review` and `blocked`, and `crewship issue list` the matching `--owner`, `--delegate`, `--work-mode`, `--mine`, `--working`, `--needs`, `--blocked`. A project's bar in the panel now shows done over total issues and is not drawn for an empty project. The issue page's ⋯ menu has Duplicate issue. ⚠️ **Behaviour change:** Waiting for my review is for the person who asked for the work (not the owner) and only when client acceptance is on; Needs my reply also counts a failed session and an execution that needs a person; Agents working includes a stale session. The New issue dialog has an Owner and a Delegate picker instead of one Assignee, and `POST /issues` takes `owner_user_id` and `delegate_agent_id` together (`crewship issue create --owner --delegate`).
- **Clear screens when a session ends, and when the server is restarting (#3787).** The app now shows a full screen with the Crewship sail in place of the bare login form, and **Sign in** opens the form. After **Log out**, "You're signed out" says "See you next time." and offers **Sign in again** and **Back to crewship.ai**. An expired session shows "Your session expired" with the account that was signed in and **Use another account**; if you had an unsent chat message it says the message is kept on this device, and after signing in you return to the same address. A session ended elsewhere (another device, an admin, a suspended account) shows "Signed out on this device". When the server cannot be reached while the app is opening, the app shows "Crewship is restarting" with "Next try in N s · Try now" and keeps trying on its own. Before, it showed a skeleton for about 8 seconds and then a login form that could not work. ⚠️ **Behaviour change:** the login page's "Your session expired. Please sign in again." banner is gone (the screen replaces it). A Log out the server did not confirm still goes to the plain login page. A cold load with the server down no longer counts as signed out.
- **A lost realtime connection is reported quietly, and the app keeps reconnecting (#3783).** A backend restart no longer shows a yellow **Disconnected** bar and a red **Disconnected** pill in the chat header from the first second. A drop shorter than 4 s shows nothing; a longer one shows a neutral "Reconnecting…" bar (with "· N messages queued" when there are any), or "Crewship is restarting · reconnecting…" when the server says it is restarting (close code 1012 or 1001). Only after about two minutes of failed attempts does it warn — "Can't reach Crewship · retrying every 30 s" with **Retry now** — and it keeps trying every 30 s instead of stopping until the page is reloaded; it also tries at once when the network comes back, the tab becomes visible or the window regains focus. With the browser offline it says "You're offline · Crewship will reconnect when you're back" and waits for the network. One bar per screen: the chat's bar steps aside for the app's, and the chat header no longer has its own connection pill. ⚠️ **Behaviour change:** the bar simply disappears when the connection is back (no "Reconnected"); the System status pill stays amber ("Reconnecting") while the connection is being retried and turns red only once Crewship cannot be reached; the realtime banner and the dashboard's and Issues' offline state wait 4 s instead of 3 s; a page whose document cannot be saved says "Reconnecting… · changes are unsaved" instead of "Disconnected".
- **Afterglow theme and theme packs.** Settings → Appearance → Style has a new **Gaming** group with **Afterglow**: a dark night-indigo theme with a sunset gradient, neon pink and an amber primary action; page titles and big numbers are set in Big Shoulders Display, the rest in Manrope (both bundled, and loaded only while Afterglow is in use). It is dark only, keeps the Crewship sail blue and meets 4.5:1 text contrast. A workspace can set it as its default look. New themes are one file in `lib/theme-packs/` plus a registry line; see [Theme packs](docs/guides/theme-packs.mdx). (#3790)
- **Design canvas peer names are readable on every presence colour.** The canvas now darkens any collaborator colour behind the white initials and cursor name labels until the text meets WCAG AA contrast (4.5:1): the earlier green and orange show one shade darker, and colours from other clients are adjusted the same way when they are drawn.
- **Harbor 2: app-wide states.** Opening the app no longer shows a full-page spinner: for a second there is just the background, then the app frame as a skeleton; if your workspaces cannot load, the frame shows the error with Retry and Log out stays available. A link opened while signed out now brings you back to it after login. An unknown address shows "This page doesn't exist" inside the app (with Go to Dashboard and Search) when you are signed in. Crash pages use the same error card with the error id and **Copy details**, and the last-resort crash page follows your light or dark theme instead of always being white. Restricted accounts see the screen named as in the navigation (Vault, not Credentials) with one way on. An unavailable workspace is a blocking dialog without a close button, listing the other workspaces with your role. The app banners (reconnecting, Docker not running, update available) share one look and show **one at a time**; the reconnecting banner says since when the data is old and offers **Retry now**, and a page's own offline banner no longer appears next to it. ⚠️ **Behaviour change:** realtime failure toasts ("Scout couldn't finish the run", routine and mission failures) stay until closed and repeated failures fold into one toast with ×N; an escalation no longer toasts while you are on the Inbox and now offers Open; "Mission started" no longer toasts.
- **Harbor 2: Dashboard in the new layout.** The 24h / 7d / 30d window moved from the page's own sticky bar into the top bar, and the page opens with a greeting and one live line ("2 things need you · 3 agents running · next routine in 18 min"). What needs you is shown as up to four number tiles (decisions, failed runs, issues for review, crews waiting for capacity, missed schedules) with the rest named on one line; it says "Nothing needs you" only when the inbox answered. Results & review has four views (All / For review / In progress / Finished — running work is part of In progress), Up next, Your crews (a two-column grid of crews and their state), the run summary, Run volume and Pages use one card style, and an empty card is one line. A card whose data failed to load says so with Retry instead of looking empty. A workspace without crews shows one "Your workspace is ready" state, and the post-onboarding checklist is a "Get started" card. On tablets the tiles and figures are 2 × 2. ⚠️ **Behaviour change:** on phones the window is not offered (the page reports 24 h); the Spend figure reads "unavailable" rather than "not metered" while the ledger has not answered; who can see Spend is unchanged.
- **Harbor 2: the rest of the issue page.** `/issues/<id>` now shows the Issues panel beside the issue, and its top bar has Previous / Next issue (through the list you came from), a ⋯ menu with Copy link, Move to project, Cancel issue and Delete issue, and Back to list. Runs are a segment of the issue's timeline (All / Comments / Activity / Runs) instead of a separate card. Add relation and Attach PR open titled popovers at their field; Add relation searches the workspace for the issue. Owner can be changed on the issue page. A project's Files tab can upload a file (or its next revision) and retire one. The peek puts focus on its content, so Enter right after opening it opens the full page. The Issues filter opens inside the panel instead of a floating menu, and List / Board and Display options use the shared segmented control. ⚠️ **Behaviour change:** the filter facets fold and show at most six values with "All N…" for the rest.
- **Harbor 2: the issue page, the project page and the rest of Issues.** An issue's own page is now two columns: the title, a session block that says who is working on it and what you can do next (nobody, delegated but not started, working, awaiting input, ready for review, needs a person, accepted, or a person holds it), the brief, sub-issues, relations, pull requests, runs and one timeline of comments and activity; beside it a Work & control card (who holds the work and at which revision, Take over, Hand off, Submit result, Stop, Start work, Lead review, and client acceptance as a switch that explains why it is locked once work has started), then the properties with Owner and Delegate shown separately. Hand off, Delegate, Submit result and Request changes open dialogs; Stop asks whether to stop after the current step or now. A project opens with a hero and Overview, Tree, Issues, Files and Settings tabs (the tab is kept in the link); project files can be downloaded from Files, and admins can delete a project from Settings. A board card can be moved with the keyboard through its Move to menu, and the + on a status group or column opens New issue in that status. ⚠️ **Behaviour change:** a link to a project that no longer exists shows "This project doesn't exist" instead of silently opening the list; old `/orchestration/projects/<id>` links open that project; the workflow buttons moved from the issue's header into the session block and the Work & control card. Fixed: links that open Issues filtered to a crew or an agent (for example an agent's "Open filtered" link) used parameter names the page never read and showed every issue.
- **Harbor 2: the Issues page.** The left panel now holds Views (My work, All issues), Projects (with health and progress) and Saved views — the current filters can be saved there by name — plus one Filter menu with Status, Priority, Delegate, Owner, Who holds the work, Labels and Crew; active filters show as removable chips and live in the URL, so a filtered list can be shared. The list is one 38 px row per issue, grouped by status, project, delegate or priority, with Display options (⇧V) for the order and which fields a row shows. The board has Backlog, Todo, In progress, In review, Done and Failed columns, and a card can be dragged to another column. Selected issues get a bar at the bottom for Status, Priority and Project. Clicking an issue opens a side peek (J/K next, Enter for the full page); on a phone it opens the full page. Keys 1–9 switch views, C creates an issue, `/` searches, Esc clears filters. ⚠️ **Behaviour change:** new users start on the list (a saved Board choice is kept); `/issues?issue=<id>` opens the peek, and editing happens on the issue's own page; the Activity/Runs/Changes/Comments/Spec/Docker drawer is no longer on the Issues page (Activity and the issue page carry that information); Cancelled and Duplicate issues appear in the list, not as board columns. Bulk "Done" now sends the status the server accepts (the old value was silently skipped), the bulk bar says when only some of the selected issues changed, and Done issues show in the board's Done column again.
- **Inbox paging, search and filters run on the server.** `GET /api/v1/inbox` takes `cursor` (keyset paging; the response carries `next_cursor`), `q`, `space`, `unread`, `attention`, `deadline`, `crew` and `agent`; `GET /api/v1/inbox/counts` takes the same filters and adds `by_attention` and `by_deadline`, so a count is the number of rows the list returns. `crewship inbox list` gains `--cursor`, `--query` and the matching filter flags (`--all` follows the cursor), and `inbox counts` the same filters.
- **Inbox: Load more, server search, server facet counts.** History past the newest page is reachable with a "Load more" at the end of the list; the search box sends its text to the server (after a short pause) instead of filtering only the loaded rows; and the type, attention, deadline and unread facet counts come from `/api/v1/inbox/counts`. A server without these keeps the previous behaviour.
- **Inbox no longer walks resolved history.** When the server offers `GET /api/v1/inbox/counts`, the Inbox loads the newest page, then only the active items, and takes the history figure from the server ("Showing the latest N of M in history"); an older server is walked in full as before.
- **Harbor 2: the Inbox.** The list is the 272 px side panel with search, Filter facets inside the panel (State, Attention — Decision, Input needed, Review, Repair — Source type and Crew), Sort (urgency first, newest or by crew; remembered), the To handle / Updates / History spaces (keys 1–3), an Overview row and Select several (Mark read, Archive). Every item opens in one layout — sender and attention, title, message, then the decision with its buttons at the bottom right — followed by where it came from, run steps and context. The top bar shows Inbox › kind, the position (4 / 16), Previous/Next (K/J), Archive (E) and the message menu; after a decision a receipt offers View record and Next to review. Wide screens add a sender column with earlier items. ⚠️ **Behaviour change:** opening the Inbox no longer previews the first row — the pane shows "Your inbox, at a glance" until you pick one; Archive stays disabled on an undecided approval; the decision buttons are ordered with the primary last (right-most); irreversible card actions confirm in the shared dialog; an unknown item link says "No longer in your inbox". Dashboard `?attention=` links, `?view=`, `?kind=`, `?item=`, `?agent=` and `?filter=` keep working.
- **Harbor 2: Activity is one list.** The overview cards and the Issues / Agents / Routines lens pages are replaced by one table of work and changes — routine runs, agent work on issues, and changes to issues, routines, pages, crews and access — grouped by Active now / Today / Yesterday / day, with repeated completed runs of one routine on one day folded into one row. The left panel holds search, Filter and the views Everything, Needs a person, Running and Could not finish (keys 1–4) with counts for the chosen time range. The top bar has a new time-range control (step shorter or longer, presets, calendar, From / To, time zone) and CSV export. A row (or J / K) opens a side Peek with how the work connects, details, earlier runs of the routine, related objects, and Stop / Run again where your role allows; Open run still leads to the run's own page. ⚠️ **Behaviour change:** the default range is the last 7 days (was 24 hours); agent work started outside routines is listed again; issue, routine, agent and crew drill-down pages now open as a filtered list. Old links (`?lens=`, `?status=`, `?mission=`, `?pipeline=`, `?run=`, `?walk=`, `?entry=`) still land. The Journal stays a separate admin page.
- **Harbor 2: Activity, finished.** Several updates to one issue or one page on one day now show as one row ("CRW-142 · 4 updates — Todo → In progress → In review") with a Peek that lists them in the order they happened; Display › Group repeated runs turns it off, and work that is still running or needs a person never folds. A `?run=` link to work outside the chosen time range widens the range so the run is in the list, not only in the Peek. Run and record pages keep exactly one page heading while they load and after. **Spend** (owners and admins) is laid out as in the design: Spend · 24 h, Spend this month, Model calls · 24 h and the most expensive piece of work, spend by crew this month as bars, the most expensive work of the last 24 hours, and a note that on subscription plans the cost is an estimate. Links that still pointed at the old Journal — crews, the agent inbox banner, the hooks page, issue and chat links, and ⌘K — open Activity directly; Activity accepts an agent or crew slug and an issue identifier in its links. The panel's Filter opens its facets inside the panel, under the search, with at most six values per facet and **All N…** for the rest, instead of a floating popover. ⚠️ **Behaviour change:** Spend no longer has its own 24 h / 7 d / 30 d picker, the spend-over-time chart and the by-agent table; the ⌘K **Journal** row is gone (typing "journal" finds Activity) and **Runs** opens Activity's runs and agent work.
- **Harbor 2: the Journal is part of Activity.** Workspace owners and admins find the Journal's timeline as **Technical log** and its runs tab as **Fleet runs** under Ledgers in the Activity panel, and Spend as the **Activity / Spend** switch in the Activity top bar — with the same filters, saved views and live tail as before. Who may see them is unchanged: owners and admins only. Every old link still works: `/journal…` and `/runs` open the same view with the same filters (`time`, `from`, `to`, `crew_id`, `agent_id`, `trace_id`, `mission_id`, `severity`, `mute`, `q`, `run_window`, `run_status`, `run_trigger`, `run_page`). ⚠️ **Behaviour change:** members, managers and viewers who open a Journal link no longer see the "kept for workspace admins" page; they land on the Activity list narrowed by what the link said (time range, crew, agent, issue, run, search, run status and trigger), and a Spend link opens plain Activity. The command palette names the views Technical log, Fleet runs and Spend under Activity and offers them to owners and admins only.
- **Harbor 2: Activity is one list.** The overview cards and the Issues / Agents / Routines lens pages are replaced by one table of work and changes — routine runs, agent work on issues, and changes to issues, routines, pages, crews and access — grouped by Active now / Today / Yesterday / day, with repeated completed runs of one routine on one day folded into one row. The left panel holds search, Filter and the views Everything, Needs a person, Running and Could not finish (keys 1–4) with counts for the chosen time range. The top bar has a new time-range control (step shorter or longer, presets, calendar, From / To, time zone) and CSV export. A row (or J / K) opens a side Peek with how the work connects, details, earlier runs of the routine, related objects, and Stop / Run again where your role allows; Open run still leads to the run's own page. ⚠️ **Behaviour change:** the default range is the last 7 days (was 24 hours); agent work started outside routines is listed again; issue, routine, agent and crew drill-down pages now open as a filtered list. Old links (`?lens=`, `?status=`, `?mission=`, `?pipeline=`, `?run=`, `?walk=`, `?entry=`) still land.
- **Admin sub-pages need an instance administrator.** People, Security and Backups under Admin now show the same "no access" page as the Admin console to anyone who is not an instance administrator, instead of drawing the page.
- **Harbor 2: Admin on the new layout.** Each Admin section opens with a short head (icon, title, one sentence) and uses the Settings cards and rows. Overview shows the build, six check tiles, one capacity strip and the cards three to a row; Runtime and Notifications open with a strip of figures; Notifications explains the one instance-wide switch and links to Channels; Limits filters to the changed ones and resets with one icon; Data retention applies to all workspaces or the chosen ones and keeps that choice in the link. On a phone Admin opens on its list of sections and a section has Back. Someone who is not an instance administrator now sees a "no access" page instead of being sent home. Removing orphaned containers, removing every crew runtime (typed word), switching off a service that channels use, signing a person out everywhere, suspending, removing access, transferring and deleting a workspace, removing empty personal accounts and replacing a workspace from a backup (typed slug) all ask through the shared confirmation, which now stays open when the server refuses; a retention change whose preview went stale keeps its dialog with a fresh preview.
- **Settings › Audit log link for a non-admin.** An old `/settings?tab=audit` link opened by someone below Admin now ends on the Audit log page's "no access" sentence instead of silently opening Profile.
- **Harbor 2: Settings on the new layout.** Every Settings section opens with a short head (icon, title, one sentence) and uses the same cards and rows: the rule or hint under each label, a lock that says who may change a value, and the control on the right, dropping under the label on a phone. On a phone `/settings` is the list of sections; a section opens with a Back to the list. Sessions & tokens is now two cards, Browsers & devices and CLI tokens. Change password is a form (Enter submits, a refusal shows under its field, success shows in the same dialog), and clicking your email copies it. Deleting the workspace, revoking a CLI token, signing out everywhere else and unlinking two crews use the shared confirmation, which waits for the server and stays open if it refuses. Access & Secrets shows its classification and placement as counts that open the Vault. Members can reissue (a new link, valid 7 days) or revoke a pending invitation. The audit log can verify the journal's hash chain on request. Failed loads show an error with Retry. ⚠️ **Behaviour change:** the ⌘K "Create CLI token" row now opens Settings › Sessions & tokens; the per-crew breakdown and credential links on Access & Secrets are replaced by counts; the CLI token form offers one checkbox per scope (each resource has a single scope today).
- **Harbor 2: Skills.** The Skills page has the new layout: a panel with the views Library, On agents, Not on any agent, Needs attention, Proposed by agents and Archived (keys 1–6) and the filters Source, Domain, Trust, Status and Used by crew; one library table with sort (Most used, Recently updated, Name), grouping by source or domain, 50 rows at a time and **Give to crew** for several skills at once; rows instead of a table on a phone. A skill's page has Overview, SKILL.md (Preview / Source), Used by (per crew, give to the whole crew), Security and Version. **Add skill** replaces Import and New skill: pick a repository, see which skills it has and which licences are refused, then choose the crews that get them — or paste a SKILL.md, describe it or write it. A **Command line** dialog lists the matching `crewship skill` commands. ⚠️ **Behaviour change:** the card grid is gone; trust reads Verified / Not reviewed / Flagged; Proposed by agents shows only to owners and admins (the roles whose approval the server accepts); removing a skill asks for confirmation and is in the ⋯ menu; the Activity tab moved into Used by as Recent uses; the Maturity and Needs a credential filters are gone (Needs attention lists missing credentials). Old `?view=` and `?tab=` links keep working.
- **Harbor 2: Integrations in four spaces.** Integrations is now split by who starts and who receives: **Tools** (apps your agents act in through Composio), **Triggers** (URLs other systems call to start a routine, an agent or an artifact), **Channels** (chat apps, email, push and incident tools that reach people) and **Webhooks** (signed JSON to your own systems). Each space has its views in the side panel, one primary action in the top bar (Connect an app, New trigger, Add channel, Add webhook), a short health strip and a table that becomes rows on a phone; keys 1–4 switch spaces. Opening a channel, webhook, trigger or connected app gives it its own page with tabs and a shareable `?id=` link. **Add channel** is three steps (App, Where it posts, What it sends) with a message preview, and Add webhook is the same dialog from step two; a webhook's or trigger's one-time secret now stays on screen until you press Done. Composio access is set per agent on each app's Access tab. Removing the Composio key, removing a channel, rotating or deleting a trigger secret and disconnecting an account ask first and stay open if the server refuses. ⚠️ **Behaviour change:** `/integrations` opens Tools (or the space you used last) instead of notification connections; "Add integration" is replaced by each space's own action; personal notification settings are under Channels › My notifications and the delivery log under Channels › Deliveries; the admin "Everyone's connections" switch is now Whose › Everyone's personal in the Channels panel. Old `?tab=…§ion=…` links keep working.
- **Harbor 2: Crews.** `/crews` opens straight on a crew (the last one you looked at) instead of a catalogue grid; on a phone it opens the list. The side panel lists Views (All crews, Needs you, Working, Idle, Temporary hires; keys 1–5), the crews grouped by status or A–Z, the open crew's agents with the lead's star and a hire's time left, and the agents without a crew. The top bar carries Activity, Terminal, Chat with the lead, a crew menu (Restart agents, Copy CLI command, Copy link, Delete crew…) and one New menu (New crew, Crew from a template, Import crewship.yaml, New agent, Hire a temporary agent; keys C and A). A crew page has one head (status, lead, size, autonomy, image and container) and the tabs Overview, Team, Tools and access, Environment, Memory, Settings; an agent page has a link back to its crew and the tabs Overview, Instructions, Model and limits, Tools and access, Memory, Settings. The tab is part of the link (`?tab=`), and older links (`?tab=work`, `skills`, `credentials`, `settings`) land on the matching tab. ⚠️ **Behaviour change:** the Edit crew, Crew administration and Edit agent dialogs are gone; their fields are on the Environment, Settings, Instructions and Model and limits tabs and save through one save bar. The dock offers only Terminal and Files (plus Logs for an agent), and the terminal now also opens for a crew in `/crew/shared`; Messages, YAML and Docker moved out (peer messages to the agent's Overview, containers to Environment). The Team tab shows temporary hires with Approve, time left and Rehire, and a Hire a temporary agent dialog. New crew picks icon and colour inline and starts from Suggest a team (the lead proposes agents you can rename or remove), a template, a crewship.yaml or an empty crew. The panel's Role, Model, Runtime, Hire, Activity and Health filters are gone.
- **Harbor 2: Crews, second pass.** New agent is a four-step wizard (Who, Model, Access, Instructions): start from a blank agent, a template or a copy of an existing agent, pick the account it pays with and its skills, and both are assigned right after the agent is created (anything refused is named, the agent stays). A crew's Environment tab shows separate cards for Container (Start / Stop container, Restart agents, Open terminal), Image (Change, image updates, Rebuild… with a cached or a clean build, build history), Tools and versions, Features (Add a tool / Add a feature), Network (with the Private network switch for admins), Resources, Services, Preview links (Revoke), Environment variables, Security and Folders, filtered by a segment. Crew Memory shows CREW.md with its last author and version history and every agent's AGENT.md; agent Memory has Remember between runs as a switch, what the agent knows about you (Forget asks first) and AGENT.md with History and Export. The agent's Instructions tab says where its instructions come from, lists their history, resets them to the crew default after a confirm and edits the crew default. The agent Overview gets Messages from teammates. Switching tabs with unsaved edits now asks first. ⚠️ **Behaviour change:** the runtime and security blocks, the integrations list and the container restart button left crew Settings (they are on Environment and Tools and access); Memory between sessions moved from Instructions to the agent's Memory tab.
- **Harbor 2: the Vault's AI providers.** The AI providers space (owners and admins) now has a health strip (accounts, need a new sign-in, pay for nothing, people with an account), account cards or a list (the default from 13 accounts) grouped by provider, owner or account group, the views *Needs attention*, *Not paying for anything* and *My accounts*, and a page per provider (`?provider=`) with how it signs in, its runners, how agents get it and the workspace default. Account groups have their own page (`?pool=`) with Accounts, Order and Settings; a change someone else saved meanwhile is reported instead of overwritten. An account's **Pays for** tab lists the agents that can use it, by crew, with a switch each, plus *Pay for the whole crew* and *Use as workspace default*. **Add AI provider** is its own dialog (Provider → Connect → Pays for) and can put the new account in a group; **Sign in again** reopens it at Connect with the name locked. A secret's **Give to agents** now assigns it to agents, crews or the whole workspace under a variable name. Keys **1** and **2** switch between Secrets and AI providers, and `/credentials` reopens the space you were last in. Usage bars appear only once the server reports usage ("No usage data yet" until then). ⚠️ **Behaviour change:** the account groups dialog, the Providers list with its *Assign* button and the *Assign to agent* dialog are replaced by the pages above; *Re-login* is now *Sign in again*, and *Revoke* moved from the account's header to its Settings tab.
- **Harbor 2: the Vault.** `/credentials` now lists secrets in a table (service, who holds it, last use, tier and classification, state) 50 rows at a time, with a health strip for rejected, soon-expiring and unused secrets, views and filters in the panel (Type, Service, Used by crew, Classification, Scope, Tag, Keeper tier), and bulk **Change tier** and **Delete**. The address carries the view and filters, so `/credentials?crew=<crew>` and `/credentials?class=SEALED` land on a filtered list and survive a reload; `?tab=providers` still opens AI providers. A secret opens as a page with tabs — Overview, Access, Value history, Activity, Settings (`?tab=`). Pasting a key in Add secret recognises the service in the browser. ⚠️ **Behaviour change:** the Edit dialog is gone — details are edited on the Settings tab with the page's save bar; **Replace value** now keeps the old value working for a grace period you pick (24 hours by default; *No grace* for the previous behaviour) and the grace can be ended early; Reveal is a single **Reveal for 30 s** button with the reason checked at the field; bulk delete says which agents and routines are affected and stays open when a delete fails; the overview dashboard and the list in the left rail are replaced by the table. Folders, sharing, external vaults, import and Workspace keys are not shown until the server supports them.
- ⚠️ **Behaviour change: approvals are decided in the Inbox only.** The separate Approvals page, its card list and side sheet are gone; `/approvals` now opens the Inbox at the decisions waiting (`/inbox?attention=approvals`), `?status=decided` or `?status=all` opens Inbox History, and `?agent_id=` is carried along, so links in older emails, Slack messages and `crewship open approvals` keep working. The command palette lists approvals once, as **Decisions waiting**. Who may decide and every decision endpoint are unchanged.
- **Routines: turning a tripped schedule back on.** The notice and the confirmation now say the failure count is back to zero as soon as you turn it on, not "after the next successful run".
- **Routines: the rest of Harbor 2.** The panel's **Filter** opens inside the panel, with a new **Trigger** facet; **View** groups by trigger and sorts by next run or spend; **Select several** turns off routines (Owner and Admin) or runs the ones that need no answer. The overview opens with four figures, **Needs you** (approve a plain decision in place), **Running now** (Stop for Owner and Admin) and **Next 24 hours**; **How routines work** explains routines, also under the empty state. **Run** offers **Run now · Test run · Later** in one dialog (Later plans a one-time start, pinned or following the live version). The run page lists the steps with an inspector (Output, Input, Log, Details), a step opens as its own screen on a phone, and runs open a peek from All runs and from the runs panel. ⚠️ **Behaviour changes:** **Triggers** no longer repeats schedules, webhooks, one-time starts and automations in cards below the list — each row is edited where it is listed; the overview's attention strip, outcome tiles, Up next and Drafts to publish are replaced by the figures, Needs you, Running now and Next 24 hours; **Test** opens the run dialog on Test run instead of starting at once; the run page's step map is gone (Steps or Timeline). A preference changed just before a reload (for example **Full detail**) is no longer lost.
- **The routine page is the editor.** A routine opens with its state in words — Live, Not live yet, Changes not live — and tabs Overview · Steps · Triggers · Settings (Versions with **Full detail**, which is remembered). Test, Run and the ⋯ menu sit in the top bar. **Steps › Edit steps** adds, removes and reorders steps and edits prompts and decision forms; **Settings** covers name, inputs, limits, the chat command, access and budget; both save a draft through one save bar, and nothing goes live until it is published. **Triggers** lists schedules, webhooks, the chat command, events and the Run button in one list, with Add trigger (next five starts previewed) and the webhook delivery log. The run page gains Copy for AI, figures, previous runs with a peek (J / K) and a timeline. Older `?view=` links open the matching tab. ⚠️ **Behaviour changes:** the menu's **Copy** became **Duplicate as draft** (it no longer puts an untested copy live); **Import** now saves a draft in the crew you pick instead of publishing; **Stop** on the run page is shown to Owner and Admin only, matching the server; Owner and Admin can now **Delete** a routine from the web; disabling, rejecting, deleting and discarding ask in the app's confirmation dialog instead of the browser's; **Restore as draft** is not offered on the Versions tab for now.
- **`crewship routine draft publish` accepts the file that `routine draft get` or `save` printed.** The CLI used to re-sort the definition's keys and HTML-escape its text when printing a draft, so publishing that file was refused with 422 "save_token invalid", which hit every draft saved in the browser. Draft envelopes are now printed byte-exact (only whitespace changes), and the draft GET/save API responses no longer HTML-escape `&`, `<` and `>`; JSON consumers read the same values. `routine approve`, `reject`, `disable` and `enable` honour `-f json|yaml|ndjson`, and a role refusal names the role the verb needs while keeping exit code 4.
- **Create a routine in the web app.** **New routine** is now a five-step wizard — Basics, When, Steps, Limits, Test and save — with a summary beside it. Pick the crew, start it manually, on a schedule (with the next three starts previewed) or once, add agent tasks, approvals, notifications, waits, issue actions, web calls or another routine as steps, set a cost limit, test it without side effects and turn it on. A routine that calls the web or uses credentials is saved for a Manager review instead. **Save as draft** keeps it unpublished; copying a routine brings its steps and limits but not its triggers; **Describe it** hands your own words to the crew lead in chat. ⚠️ **Behaviour change:** New routine and Import are available to Manager and above only (the server already refused the rest); Members see them disabled with the reason, and `C` does nothing for them.
- **Routines on the Harbor 2 layout.** The top bar shows Routines › view or Routines › crew › routine and holds New routine and Import; the in-page "Back to routines" bar is gone (the breadcrumb leads back). The panel lists Views first — Overview, Needs you, Running now, All runs, Drafts, switchable with keys 1–5 and kept in `?view=` — then the routines grouped by crew, each with one status pill and a pencil when it has changes that are not live. Filter by Status, Last run and Crew; group by crew or not and sort by last run or name. An empty workspace shows New routine with the CLI hint, and a load error offers Retry.
- **Sign-in screens keep the sails.** Sign in, create account, password reset, first-run setup and invitation acceptance draw the form beside the animated sail panel again (a short banner above the form on tablets and phones); the panel stands still with Reduce motion. Password fields gain a show/hide button and a "Caps Lock is on" line, new passwords tick "At least 8 characters" as you type, first run shows its place in setup (Account · Workspace · Model · Crew), and sign-in fills from password managers as a username. ⚠️ **Behaviour change:** a successful password reset counts down 5 s to sign-in (was a silent 2 s) and shows a Sign in button; a rate-limited sign-in says how long to wait; with sign-up switched off, sign-in says to ask an administrator for an invitation and a refused sign-up shows "Sign-up is closed" instead of the server's configuration hint.
- **Sign-in says where you return to.** A sign-in link that carries a page to return to (`/login?redirect=…`) now names that page under the title — "You'll return to Issues." — by its name in the navigation, never the raw path. A target the sign-in would refuse names nothing; where you land after signing in is unchanged.
- **Harbor 2: sign-in and public pages.** Sign in, create account, password reset, first-run setup and invitation acceptance now share one card: the logo above it, a short title and description, the fields, and one primary button at the bottom right (full width and pinned to the bottom on a phone). A wrong value is shown under its field, a refusal from the server in one band above the buttons, and "account created" / "session expired" as a banner inside the card. Shared artifacts (`/p/…`) and the shared-chat reader get a minimal top bar with only the logo and what you are looking at. Requests, redirects and the deliberately non-committal messages are unchanged. ⚠️ **Behaviour change:** accepting a Guest invitation now needs the "I understand this applies to the whole account" box ticked first; a `/join` link without its token says so instead of showing a disabled button; button labels read Sign in, Create account and Continue.
- **Calendar: Filter opens inside the panel, and Repeating says why it is off.** The Calendar's Filter button now opens its Status facet inside the side panel, under the search, instead of a floating popover, so the dates stay in view while you narrow them. In Schedule a start, Repeating is a disabled choice with its reason ("Managers and above can add repeating schedules.") for anyone who may not add schedules, instead of a choice that opened a form with no button.
- **Calendar page.** `/calendar` shows the workspace's routine starts and runs in Week, Agenda (the phone default) and Month views, with Mine / Workspace, crew and status filters, a "Need you soon" strip for runs that wait for someone or failed today, and a peek with the action each date needs: Open routine, Run now, Cancel start, Open run or Decide. **Add a date › A routine start** plans a one-time start, or — for Managers and above and members allowed to create schedules — a repeating schedule with its next three starts previewed. The command palette and the Dashboard's "Up next" now open Calendar; Routines › Calendar keeps working and links to it. Issue due dates, milestones and decision deadlines are not shown yet.
- **Harbor 2: first-run setup as one card.** `/onboarding` is now a single card under the Crewship lockup: the step's title, the shared step bar (Workspace · Model · Crew), the step, and a footer with Back, Skip setup and Continue / Launch (⌘↵ / Ctrl↵ continues). The crew step widens to put the Guide chat beside "Built so far"; templates show their agents and what they need. Loading shows the card's skeleton instead of a spinner, a failed restore shows an error card with Retry, the Docker check and CLI pairing states read as status pills and notes, and finished steps can be clicked to go back. A saved token reads *Token saved* with Replace. Every request, the save order and the redirects after Skip and Launch are unchanged. ⚠️ **Behaviour change:** the live preview pane is gone, the runtime re-check button reads **Check again**, an expired pairing code offers **New code**, and the template link reads **Pick a template instead**.
- **Harbor 2: one dialog shell.** Thirty-five create, edit and form dialogs across routines, crews, issues, integrations, credentials, skills, settings and admin now share the same surface: four fixed widths (480/640/800/960 px), the same header with a close button, a bottom sheet on phones, and ⌘↵ / Ctrl↵ to confirm. Confirmations ("Stop this run?", rotating a webhook secret) use the shared confirmation dialog in place of an ad-hoc one or the browser's `confirm()`. Fields, validation and submit behaviour are unchanged. ⚠️ **Behaviour change:** Create mission and the account-group editor now ask before discarding typed input; the Approve button in an approval request uses the standard primary colour.
- **One status pill.** Issues, routines, activity, crews, inbox, integrations, approvals, admin security and the journal now show every status and severity with the same pill and colours, so a failure, a pause or a review reads the same on every screen. Statuses that used to appear as raw values (`ALLOW`, `pending`, `SEALED`, `goal_met`, a run's `completed`) now read as words (Allow, Pending, Sealed, Goal met, Done). Counts and neutral labels use a plain badge.
- **Error toasts stay until you close them.** Success and info toasts still leave after 4 s and at most three show at once; an error now waits for its close button so the message cannot vanish before it is read. Chat and Pages keep the old timing in five places until their teams switch over.
- **Leaving an editor with unsaved changes asks in the page.** Following a link, the command palette, a bell or Back from a routine or Page editor with unsaved changes now opens the shared confirmation (Leave / Keep editing) instead of the browser's `confirm()`; Leave continues to where you were going. Reload and closing the tab still use the browser's own prompt.
- **Inbox totals come from the server.** `GET /api/v1/inbox/counts` and `crewship inbox counts` return the items you can see per space (to handle, updates, history) and per kind in one request, with the list's visibility, so a client no longer walks every page just to label its tabs.
- **Harbor 2 look, first step.** New light and dark palette (white content on a grey sidebar ground, corrected text greys that meet WCAG AA everywhere, opaque accent selection), Inter bundled with the app, 10 px cards and flat primary buttons. ⚠️ **Behaviour change:** a new device starts at Small text (13 px) and the System theme; devices and accounts that already have a text size or theme keep it, and Text size now reads Small / Standard / Large. On touch screens every control is at least 44 px. Appearance gains a separate `appearance.style` preference (only Harbor today) and shows **Not synced · Retry** if the server refuses a write.
- **Harbor 2 shell.** A 240 px sidebar (a 56 px rail on tablets) with the workspace, Search ⌘K, the sections, Settings, Admin and your profile at the bottom; one 48 px top bar with the area's breadcrumb, the page's title and its one primary action, and the Activity and Inbox bells; each page's header now sits in that top bar instead of a separate strip, with view tabs kept on the page. Phones get a bottom tab bar with More. ⚠️ **Behaviour change:** the profile menu moved from the top bar to the bottom of the sidebar (in More on a phone).
- **Harbor 2 kit, filters and panels.** Filters open inside a page's side panel, under its Filter button, with at most six values per facet and "All N…" for the rest; on a tablet the side panel starts closed and opens over the page from the top bar. Wizards show every step done when finished, and confirmation lists name what is lost, kept or at risk in words for screen readers. ⚠️ **Behaviour change:** at 768–1279 px the side panel no longer takes a column; open it with the panel button in the top bar.
- **CLI token changes are auditable.** Creation and revocation now commit together with instance-level, keyed audit records; administrators can see per-entry integrity without exposing token values or inventing proofs for legacy history.
- **One attachment queue for the chat composer.** Picked, dropped, pasted and camera files now share one queue per conversation and upload one at a time. A chip says Waiting, Uploading, Failed or Cancelled in words; a queued or running upload can be cancelled and retried without removing the chip, and files past a provisional client limit (10 per message, 25 MB each; not server-approved) are refused with a reason. Pasted files are now attached instead of being silently held back. A failed or cancelled file keeps Send off with a visible reason and Retry/Remove on the chip; uploads are kept per person and workspace, continue while you switch to another chat, and stop when you leave the chat page.
- **Crew sharing is available from the web controls.** Workspace administrators can share View/Use from crew Settings or select Crew in a person’s resource Access editor. The dialog explains the current/future agent audience, conditional execution and the exclusion of Delegate, credential visibility and crew administration. Existing API/CLI authorization, issuer provenance, revision conflicts and account modes are preserved.
- **Crew View/Use shares support explicit presets.** Administrators can preview and confirm None, View or Use in person Access or the existing API/CLI flow. Preview explains the current/future agent audience; unrelated grants, original issuers and older preset selections are preserved. Crew presets grant neither Delegate, credential visibility nor administration.
### Upgrade and recovery notes
- Preserve the configured v1 audit/journal root in encrypted instance recovery kits after secret re-encryption; successful envelope conversion does not authorize retiring that root. ⚠️ **Behaviour change:** Instance backup now rejects an invalid `ENCRYPTION_KEY` instead of producing a recovery kit with an unusable audit root.
- Before downgrading across the durable routine-start migration, stop incoming triggers and drain queued and in-flight starts. Otherwise use a forward fix; downgrading with outstanding work and upgrading again can repeat accepted work.
- Resuming a routine body provides at-least-once execution: an interrupted step can repeat external effects. This is not an exactly-once guarantee. An uncertain interrupted setup hook remains visible as interrupted rather than being automatically repeated.
- If durable start recovery fails at startup, the server refuses to start. Resolve the reported recovery/storage error before restarting; do not bypass recovery.
### Fixed
- API responses now match the published contract on 23 operations: empty lists answer `[]` instead of `null`, a new agent reports its restricted profile, and the OpenAPI document describes the real shapes, nullable fields and both error envelopes.
- **An identical Mooring create retry no longer returns a private document after its author loses access.** The existing transaction-local author check now runs before looking up the saved result as well as before committing a new document.
- **Workbook creation now rechecks the original author’s current rights in its transaction.** Lost membership, restricted access or removed Page-create rights refuse both creation and identical retries; a rights change during insertion rolls back the staged Page.
- Revoke every matching Page grant when a reference identifies both a current subject and a departed stored ID, without changing unrelated grants. ⚠️ References matching multiple live subjects now return 400 instead of selecting one arbitrarily. Creation and reissue also verify that other subjects' grants remain unchanged. Losing issuer authority during the audit commit returns 403 and rolls back the change; database failures remain server errors.
- **Old `/paymaster` links open Spend instead of Not found.** The page moved into the Journal's Spend tab; `/paymaster` now redirects there, and spend links built by the app point at it directly.
- **Harbor 2: Spend respects the role.** The dashboard no longer asks for the cost ledger or draws the Spend tile below ADMIN, and Activity › Spend shows "Spend is unavailable: only workspace owners and admins can see costs." instead of failed-load cards if the server answers 403 (#3662 on the new layout).
### Fixed
- Prepare a strict Document-to-DOCX converter for validated saved content; export delivery and Microsoft 365 compatibility remain unqualified.
### Fixed
- ⚠️ **Behaviour change: cost figures are readable by workspace OWNER and ADMIN only.** `GET /api/v1/paymaster/spend/by-crew`, `spend/by-agent/{crewId}`, `spend/by-mission/{missionId}`, `top-spenders` and `GET /api/v1/journal/spend` (and so `crewship cost`, `crewship paymaster` and `crewship spend`) now answer `403` to MANAGER, MEMBER, VIEWER and GUEST; before, the web app hid Spend but any member could read it from the API. An empty window returns `"rows": []` instead of `null`. The dashboard and Activity no longer ask for, or show, spend for other roles.
- Preserve captured run completion timestamps across retained-output recovery and terminal replay; legacy records retain their original replay identity.
- Restore a confirmed Document checkpoint as a new version after explicit human confirmation; exact retries preserve the receipt and older write mandates remain fenced.
- Keep newly added members’ canonical initial rights out of automation previews, matching and inputs. ⚠️ **Behaviour change:** `member.added` free-text journal search now matches summary only, including historical events; canonical audit payloads and keyed hashes are retained.
- Workspace member addition and account provisioning now commit their chained audit atomically, recheck live administrator authority, and keep initial rights and setup material out of public journal frames.
- Crew member additions, removals and role override changes now commit with their old/new membership audit or roll back, with notifications only after commit.
- Record the first workspace OWNER as the dedicated `member.owner_created` event atomically with workspace creation, personal signup and bootstrap; failed audit writes roll back creation, while public feeds and automation previews, predicates and templates omit the stored membership snapshot. ⚠️ **Behaviour change:** Guest `POST /api/v1/workspaces` returns 403 without creating a workspace. All `member.owner_created` and `member.access_changed` events now search summary only, including historical rows and formerly public payload fields; canonical audit payloads remain unchanged.
- Keep private authorization audit snapshots out of automation previews, matching and template inputs as well as shared journal feeds; retain the canonical keyed audit unchanged. ⚠️ **Behaviour change:** Protected authorization events now search summary only (including historical rows and formerly public payload fields); exact transactional audit readback refuses post-insert deletion or tampering.
- Dispatch due manual backups reliably across fractional-second timestamp boundaries, while keeping future busy retries queued until their exact deadline.
- Wait for provider sign-in recovery to release its database connection before server shutdown finishes.
- Accepted routine webhooks keep a durable run identity while waiting for capacity or recovering after restart. Webhook capacity waits expire after 24 hours; uncertain deduplicated starts stay visible for inspection instead of linking a nonexistent run.
- Record routine starts before setup hooks, so interrupted setup remains visible and cannot be mistaken for work that never started.
- Keep private Document output private in its source conversation, live delivery and agent diagnostics; audit foreign OWNER inspection before returning copied data.
- Refuse workspace replacement and forced recovery that would discard newer private conversation classification while retaining diagnostic log copies.
- Retain private artifact conversation classification across recovery and result deletion; refuse restores that would lose its original audience.
- Keep private Page grant administration and production limited to the custodian and workspace OWNER, including when legacy grants exist.
- Commit Page grant creation, reissue and revocation with their chained audit records; failed audits leave permissions unchanged and publish no change notification.
- **Guest Page catalogs keep working when private chat Documents exist.** Unauthorized private entries are omitted without failing the listing; private editing, OWNER access and the Guest route allowlist remain separate checks.
- Audit private Document reads against the custodian authorized by the fenced read, and withhold content when the required audit cannot be recorded.
- Audit OWNER reads of another human’s private Page export, version history and access report atomically before disclosure; ignored or removed audit rows withhold the response. Ordinary Page reads retain a read-only snapshot without taking the SQLite writer lock.
- Clear saved Document previews and chat-result titles on page deletion, and ignore responses started before the deletion.
- Rate-limited shared issue searches no longer fill workspace capacity with unused project buckets or refresh their idle lifetime.
- Workspace role updates now commit with a chained audit event and the existing Settings audit record or roll back. Capability audit events retain the previous and resulting effective sets while keeping those values out of the general journal feed.
- Isolate stream admission revocation epochs by credential and user, so another user's logout cannot reject valid requests; repeated signout of an already revoked session no longer sends another revocation notification.
- Open saved Document cards in the native editor with an immutable Page reference. Every read retains the original identity and current access checks, so reusing a deleted document's address cannot open a replacement. Query-only navigation follows the new reference.
- Document reads and initialization retries reject unsupported saved schemas before returning content, while preserving their confirmed data and authorization checks.
- ⚠️ **Behaviour change: cost figures are readable by workspace OWNER and ADMIN only.** `GET /api/v1/paymaster/spend/by-crew`, `spend/by-agent/{crewId}`, `spend/by-mission/{missionId}`, `top-spenders` and `GET /api/v1/journal/spend` (and so `crewship cost`, `crewship paymaster` and `crewship spend`) now answer `403` to MANAGER, MEMBER, VIEWER and GUEST; before, the web app hid Spend but any member could read it from the API. An empty window returns `"rows": []` instead of `null`. `GET /api/v1/metrics/timeseries?metric=cost_usd` answers `403` the same way. Every other endpoint that carried a cost next to data members may read now leaves the cost out below ADMIN (the field is absent, not `0`): routine runs, run records, run tree and run results, routine budgets (`has_budget` / `over_budget` stay), the journal list, entry and SSE stream (payload amounts and `$…` in summaries), agent runs and chat message metadata, the chat run preflight, the agent inbox, missions and mission metrics, work items, eval runs, the run NDJSON stream and WebSocket frames. `crewship routine budget`, `routine runs-all`, `routine records`, `routine tree`, `work get` and `routine run` print `—` or the budget state instead of `$0.00` when amounts are withheld. The dashboard and Activity no longer ask for, or show, spend for other roles; the routine screens, run pages and chat preflight show the budget state or leave the cost out instead of `$0.00`. The Routines Health table (`GET /workspaces/{ws}/pipeline-health`, `crewship routine health`) leaves out `spend_usd` the same way; the CLI prints `—`.
- ⚠️ **Behaviour change: private chat Documents are visible only to their human owner and workspace OWNER.** Other roles receive 404 and no catalog title; OWNER access to another human's document is audited before disclosure. Legacy sharing cannot silently widen private audiences, and OWNER selects an explicit successor before removal of a private artifact's custodian.
- ⚠️ **Privacy change: folder moves no longer expose private Page identities in workspace events, journal feeds, automation previews or automation inputs.** Canonical audit targets remain intact. Historical folder-move entries without a valid classification, including ordinary Pages, now use a generic public projection and are excluded from full-text search; newly classified ordinary Page events retain their metadata.
- **Agent details now show the configured provider and model** in table, JSON and YAML output; these settings remain distinct from evidence of the model serving a run.
- ⚠️ **Behaviour change: credential revocation ends open client streams.** Browser and CLI WebSockets, journal SSE and run NDJSON stop authorizing frames after logout, session/token revocation or credential expiry. Request a fresh ticket and reconnect with a valid credential; running routines retain their separate grant/account authority.
- **Credential history survives retirement and name reuse.** Integration cleanup and failed credential proposals retain tombstones instead of deleting audit history. Reusing a retired name creates a new ID and adds a recoverable ID suffix to the old historical label; audit references now prevent accidental hard deletion. ⚠️ Workspace replacement now refuses changes that would orphan out-of-scope legacy audit history instead of silently erasing it.
- Scheduled routines retain at most one waiting occurrence per schedule when capacity is full. Later capacity-blocked occurrences are recorded as skipped/missed, without failure alerts or circuit-breaker trips.
### Added
- **Replay captured routine runs with corrected inputs, tags and metadata.** Omitted values inherit the source; empty objects and arrays clear inherited values. Changed inputs are validated against the selected routine version. (#3592)
- Prepare scoped native Slides initialization with atomic receipts and caller-owned transactions; API and editor activation follow separately.
- Open saved Documents beside their conversation with fresh human read checks; mobile back navigation and desktop dismissal preserve the unsent chat message. Modified clicks retain native page links.
- Added scoped, read-only resolution of saved Documents for the chat preview; panel integration remains separate.
- Add controlled native Slides editor and presentation components with explicit unsaved state and a schema-1-only rendering boundary. Persistence and application integration remain separate.
- Add strict native Slides operation contracts and atomic in-memory candidates for future transactional presentation writers.
- Browse retained Document checkpoints in a separate read-only history view without replacing the live draft or editor. Every API and CLI history read rechecks current human access.
- Add a scoped document viewer shell with explicit unavailable states, keyboard dismissal and focus restoration. Chat integration remains separate.
- Prepare a shared read-only saved Document and checkpoint renderer that rejects non-Document roots and handles serialization failures without retaining stale content; production history and panel wiring remain separate.
- Read retained Document checkpoint lists and exact saved bodies through the API and `doc checkpoints` / `doc checkpoint`, without restoring or changing the current draft.
- Record member capability changes and workspace member removals in the chained journal atomically with their mutations. Audit failures roll back the change; capability values remain restricted to the existing administration endpoint.
- Select Create document in the chat composer to request a private saved document using Czech or English prose, with explicit per-message consent.
- Document drafting commands honor JSON, YAML and NDJSON output formats while preserving exact revision and checkpoint identities.
- **Workspace owners can control document creation by agents.** The workspace policy API and CLI expose an explicit creation switch, disabled by default; run authority remains bound to the requesting human and current permissions.
- **Documents can be created and edited with durable save feedback.** When document support is enabled, create an empty document in the UI or CLI, edit it and reopen the confirmed saved content. Opening saved content does not add a paragraph or trigger a write.
- Render versioned chat progress with stable replay identities, explicit partial and tool outcomes, permitted reasoning summaries and persisted timing. Keep provider accounting separate from confirmed completion and clear protected transcript state on identity changes.
- Read versioned chat source references through the existing authorized agent-session and workspace-room message APIs and CLI, preserving original identities without sending messages.
- Protect run-admission restore targets and bundle callbacks, including generated reserved metadata columns and distinct FilesOnly destinations.
- Refuse unsupported run-admission payloads in raw dump restore before opening the write transaction or invoking callbacks.
- Add byte-preserving canonical validation for routine run-admission envelopes and their outer identity tuple. This storage prerequisite does not create admissions or enable execution.
- Document a review proposal for crew and credential sharing with explicit human audiences; no access behavior changes.
- Archive only verified native legacy routine heads during upgrade, preserving exact content, origins and integer pins without reconstructing historical versions. Verify each persisted archive before recording the cutover.
- Await final host-capture fixture writes before removing temporary directories.
- Preserve distinct routine version authority identities and legacy history without enabling Guest publication or runtime.
- Decode exact publication identities and capture nonsecret provider declarations without enabling publication or provider execution.
- Define a host-only canonical publication identity that binds exact grants, actors, source origins and selected child versions without enabling publication or runtime.
- Preserve genuine archived identities in API history, upsert, and resurrection test fixtures.
- Seed pipeline API smoke tests through the migrated database and real archived routine store.
- Prepare host-only exact grant provenance for bounded routine publication: selected grant and publisher/issuer membership identities survive unrelated policy saves but cannot be replaced by trusted-mode bypass or reissued shares. No publication endpoint, permission or runtime is enabled.
- Invalidate protected editor reads and pending saves when switching members or resources, so returning to a cached scope requires a fresh read.
- Clear reviewed member preset consent on access loss and ignore late mutation responses from an older verified policy read.
- Settings resource access offers explicit immutable presets for existing Guest resources, with exact previews and confirmation. Saved intent stays separate from live grant authority; conflicts and uncertain writes require reloading before new consent.
- Clarify that resource preset preview, confirmed application and the Settings selector are available; remove obsolete foundation-only descriptions without changing access behavior.
- The CLI can apply an explicitly confirmed resource-preset selection with one write, exact JSON/YAML field names and no automatic consent refresh or retry.
- Transactional audit appends reject ignored journal inserts and withhold notifications so the owning business transaction can roll back.
- Applying a resource preset preserves every unrelated canonical grant row, including inactive historical grants whose resources are unavailable; ordinary complete-document policy updates retain their existing validation.
- Preset CLI document decoding shares the existing bounded, strict file/stdin contract without changing supported consent fields or refreshing revisions.
- OpenAPI administrative member-policy reads and replacements reuse a named complete policy document; accepted fields, CAS requirements and permissions are unchanged.
- Explicit resource-preset application in the API recomputes reviewed consent atomically with canonical grants, audit and saved selection. Retained issuers and unrelated rights are preserved; stale consent requires a new preview and never triggers automatic reissue.
- Read-only resource-preset previews in the administrative API and CLI show exact managed changes, retained provenance, Results disclosure and independent destructive consequences. Confirmation digests bind live state without granting authority or changing permissions.
- Internal transactional recorder for explicit preset selection intent, fenced to live administrator authority and matching canonical managed grants. The helper does not enable a public apply route or change permissions.
- Prepare nullable durable routine identities and start phases; dispatch behavior is unchanged.
- Deferred routine receipts expose stable waiting reasons in API, CLI and Plan, including neutral legacy causes and recovery attention.
### Added
- Administrative member-access reads include server-computed preset selection provenance. Saved intent remains separate from effective permissions; manual edits cannot forge selections and personal access responses omit this metadata. The new selection fields keep their API names in CLI YAML. OpenAPI reuses the existing grant-provenance shape without changing authority.
### Changed
- Reduce workspace and entity WebSocket delivery authorization to one current SQL snapshot per frame, retaining immediate account, membership and restricted-profile revocation checks, including the private-page owner or workspace OWNER audience.
- OpenAPI administrative member-access documents share the unchanged project/routine variants and complete resource-right union. Primitive operations remain independent; no preset or permission behavior changes.
### Changed
- OpenAPI administrative member-access documents reuse the existing agent-right shape as a named schema. Accepted operations and runtime permissions are unchanged.
### Added
- Administrative API and CLI catalog for immutable v1 project and routine access presets. Listing preserves API field names in structured formats and does not grant permissions or enable preset application.
- **Admitted runs can create a saved document through `crewship doc create`.** The requesting human owns the populated document, and retrying after a lost confirmation returns the same result. Document support and creation policy must be enabled.
- **Document creation runs can save confirmed draft checkpoints.** An original drafting request permits guarded edits only to its new document in the same live run. Exact retries preserve saved work; a human edit or replacement run never silently extends the permission.
- Index preset selection ownership, resources and selectors for parent cleanup and scoped backup lookups.
- **Revoked project data stays hidden during connection errors.** Shared project details, milestones and issue deletion previews require a fresh successful read after access is refused; cached responses and late saves cannot restore the old view.
- Guests with explicit project Read+Manage can open a known-project management link without List. The screen reuses reviewed metadata/milestone forms, preserves drafts during temporary workspace-directory loss, and optionally previews a known issue for confirmed deletion with the separate Delete issues share, without issue discovery or broader grants.
- **Participants can start a conversation in an empty shared chat.** A current authorized execution profile confirms the existing chat without a creator-only create request; every send still rechecks access and refused sends keep the draft.
- **Proposal comments address the chat agent explicitly.** “Send comment to agent” now includes its canonical mention so shared chats trigger the requested reply; rejected sends keep the comment draft.
- **Guests can connect their CLI from the account menu.** Connect CLI now opens the existing browser pairing dialog for Guest accounts after access loads, retaining their current grants. Guest menus also avoid an unavailable system-version request.
- **Issue editor links and images use a URL dialog instead of the browser prompt.** Inserting or editing a link, and inserting an image from the toolbar or the `/image` command, opens a dialog that pre-fills the current link, accepts only `http://` and `https://` URLs (an empty value removes a link), shows the error under the field and returns focus to the same place in the editor. Cancel and Esc change nothing.
- ⚠️ **Behaviour change: enabling privileged runtime access requires an instance administrator.** Workspace OWNER/ADMIN rights alone no longer enable `allow_privileged_credentials`. Scoped CLI tokens also need `instance:admin`. Workspace administrators may still disable the opt-in; existing privileged containers require separate review and recreation.
- **Protected chat runs wait for confirmed execution results after their observer disconnects.** Chat preserves partial replies and leaves the run admitted for retained-output reconciliation instead of recording a false failure or cancellation.
- **Human-owned content can be handed over explicitly.** Workspace administrators can review eligible readers and transfer custody while preserving content and grants. Private content requires a human successor before its owner leaves; ordinary Pages retain their existing succession behavior.
- **Guest CLI pairing accepts verified browser sessions.** Pairing start and poll now pass the restricted route gate only for interactive sessions. CLI bearer callers remain forbidden; redemption retains the same current Guest grants as browser CLI token creation and rejects logout, revocation or suspension.
- Chat shows advisory configured-model payer, budget and gate details above the composer after a current viewer/chat profile check.
- **Crews can opt into whole-run approval before agent execution.** The existing policy API and `crewship policy set --whole-run-approval` enable a real `agent_run` rule. Chat preflight and runtime use the same crew-scoped rule, while default behavior and autonomy modes remain unchanged.
- **Decision drafts retain focus during access rechecks.** Typing and caret position survive temporary verification outages; sending waits for verified access and explicit source-version review, while uncertain submitted responses remain locked for exact retry.
- **Withdrawn chat approval sources cannot be rejected through a stale Inbox ID.** Canonical decisions now retain the original chat generation and current operator audience; authorized refusal still works when only the original requester loses access.
- **Chat decision answers preserve the Inbox token scope.** Narrowly scoped CLI tokens cannot answer through chat; the same existing workspace administration scope is required, including retries. Read-only role demotion still permits an authorized completed retry.
- **Routine runs distinguish fresh chat invocation from inherited recipe authority.** Verified direct-human calls retain their exact source run privately; legacy and scheduled execution continue without a guessed question. Explicit invalid run credentials are refused before creating a run.
- **Guest intake changes and deletion preserve active routine work.** Queued, running and waiting runs still block changes after their issue execution becomes superseded; completed runs do not. Rejected deletion keeps the issue and execution intact.
- **Shared routine results retain private provenance.** Replays preserve their source and trusted caller origins; issue runs, ambiguous legacy origins and malformed authority evidence stay hidden. Final outputs receive the same credential scrubbing as step outputs, including historical shared reads. Oversized selected results return 413.
- **Guests can inspect explicitly shared routine history and outputs.** A new Results share with View exposes run metadata and selected outputs in UI and CLI, without execution authority or transcripts. Inputs are not shown directly; outputs may contain them. Existing View/Run shares retain their previous scope; inherited private conversation audiences still constrain results.
- **Shared issue searches visit only projects with live List grants.** Search and counts resolve current grant authority before reading issues, avoiding scans of hidden workspace issues. Issuer demotion/suspension and Read/Contribute without List return no list results.
- **Guests can search shared issue titles and identifiers in UI and CLI.** Filtering and total counts retain live project grants; hidden descriptions, comments and unrelated projects are excluded. A new search starts from the first page in the UI. Creation confirmation remains visible when the filter hides the new issue.
- **Shared issue searches explain temporary rate limits.** The browser keeps results and search drafts, pauses search polling and disables repeated requests until the retry interval ends. A definitive access denial discards old results so later throttled retries cannot restore them. CLI commands print retry guidance, exit 6 and require an explicit retry.
- **Reloading a shared routine draft now discards local edits even when its saved revision has not changed.** A failed reload retains the local edits, and background refreshes of the same revision keep them.
- **Agent images and charts appear in chat.** Authorized PNG, JPEG and WebP outputs from the reply’s run render inline with a filename caption, alt text and byte version. Access rechecks remove unavailable images; SVG and disguised active content stay outside the viewer.
- **Decision reply drafts remain scoped to their viewer and source.** Reload restores an uncertain reply with its original retry key; definitive access loss removes protected recovery, and paginated source lists reconcile as complete snapshots.
- **Chat can answer verified information requests from the same source as Inbox.** TEXT escalation cards use live access and deadline checks, reviewed source versions and stable retry keys; terminal receipts retain the actual human actor. Credential requests stay in the existing protected Inbox flow.
- **Escalation requests retain their verified execution source.** New run-authenticated requests keep the original agent run ID for accurate chat decision anchoring. Older service requests remain unanchored and retain their existing Inbox resolution.
- **Decision cards gain a typed response view.** Source-defined workflow actions retain their identity, terminal decisions show read-only receipts, and uncertain replies keep the same operation key for retry. Integration with live decision sources follows separately.
- ⚠️ **Behaviour change: CLI pairing follows its source browser session.** Suspended accounts and missing, logged-out, revoked or expired source sessions cannot redeem codes. Request a fresh browser code for older pairings without session provenance; CLI-token authentication cannot start pairing.
- **Dependency updates now build and package together.** Refresh the frontend, Go and CI dependencies, explicitly declare lockfile version changes, and retain the version-scoped license inventory.
- ⚠️ **Behaviour change: crash reporting uses Sentry v11.** Self-hosted Sentry must be 26.4.2 or newer. Browser, Node and Edge initialization disable collection of user identifiers, request metadata, AI content and other payload data. Browser release-health sessions stay off and telemetry consent remains required.
### Fixed
- Isolate shared issue-search limiter capacity to 256 accounts and 2048 audience buckets per workspace while retaining global bounds. Ordered idle expiry avoids scanning active buckets on capacity refusal and preserves their rate budgets; global saturation can still refuse new buckets.
- Waitpoint decision confirmations and CLI errors no longer repeat approval capabilities; transport failures retain their existing error type and exit code.
- **Agent questions stay connected across chat and Work.** Authorized decision forms appear beside their run and in “Waiting for you”; opening one uses the same source in the Work panel or a full-screen phone panel. Inbox answers refresh the card to a read-only receipt. Uncertain replies retain their original operation key across reload; temporary failures preserve drafts, while access denial clears the source and recovery data.
- **Chat can project existing synchronous whole-run approvals.** Verified human run sources share the canonical Inbox decision and source retry metadata. Newly host-correlated blocking approvals enforce expiry and live operator/requester checks before commit; per-tool, async and legacy paths retain their existing behavior.
- **Chat can project existing synchronous whole-run approvals.** Verified human run sources share the canonical Inbox decision and source retry metadata. Newly host-correlated blocking approvals enforce expiry and live operator checks before commit, with live requester admission required for approval; authorized refusal can still settle withdrawn requests; per-tool, async and legacy paths retain their existing behavior.
- Chat pull-request cards label their data as stored metadata, including empty lists; live CI remains unavailable. The credential diagnostic runbook distinguishes a local missing credential (412) from a forge failure.
- **Issue proposals are interactive in their originating chat.** Review and edit the proposed selection, confirm or discard the reviewed version, and open the same proposal in Work or a full-screen phone panel. Card and panel drafts stay separate; uncertain writes retain their retry key. Temporary access-check failures preserve drafts with writes disabled, while explicit access loss and sign-out clear protected recovery data.
- **Chat can inspect the current payer and budget before work.** The read-only run preflight reports Paymaster remaining balances and predicted whole-run gate for the configured agent model, with an explicit unknown price and current provider admission constraints. It reserves no funds and grants no approval.
- **Whole-run approvals follow the actual gate mode.** Nonblocking async reviews now allow the run to continue even when reward history changed a configured synchronous gate. Approval metadata records the effective mode and trusted run provenance; unknown adapter modes continue to block pending work. Direct human approvals recheck the recorded requester after the wait; delegated and legacy runs retain their existing paths. Legacy approval reads keep new internal chat/run references private.
- **Personal memory withdrawal stays inside its workspace.** A guest invitation or restricted-membership change no longer erases saved preferences in another workspace. Local withdrawn preferences remain forgotten; previously erased values cannot be reconstructed. Clearing all preferences also works for agents without a crew.
- **Chat drafts survive temporary access-check outages.** Network errors and server failures keep the last verified cards mounted as rechecking with writes disabled. Explicit access denial still clears protected data and cannot be undone by another failed check.
- ⚠️ **Upgrade: restart agent containers after updating the backend and sidecar.** Coordinate an idle window and use `crewship crew restart-agents` so existing containers receive the matching sidecar; old sidecars can fail issue writes. Follow [the execution-authority rollout](RELEASING.md#execution-authority-rollout-3068), including the read-only `doctor execution-origins` audit against the actual stage/production database before upgrade.
- **Chat issue drafts survive saving and access rechecks.** Field and comment drafts clear independently; editors retain focus during successful refreshes. Unknown writes retain their original retry key across panel close and reload, and conflicts reload current values alongside the draft.
- **Chat issue hints stay within their conversation.** Showing an issue refreshes only the originating chat; issue changes refresh revisions without announcing activity in another chat. Card-only viewers subscribe to a dedicated hint channel, avoiding run-stream traffic. Streaming observers recheck current access before receiving frames, and deletion, relation and review-policy changes refresh cards.
- **Chat table previews rejected ordinary spreadsheets and legacy CSV text.** Hyperlinks are ignored without fetching, chart tabs are skipped while worksheets remain visible, invalid dates are labelled, and UTF-16/Windows-1250 CSV text is decoded locally. Both shipped worker acceptance checks now run in CI.
- Chat Artifacts includes supported files in the canonical per-run output folder while retaining internal, hidden-directory and attachment filters.
- **Mobile table selections return to Chat without covering the draft.** Asking about selected rows closes the artifact overlay and preserves existing draft text. Switching between Chat, Work and Artifacts keeps previews within the selected panel and retains their tabs.
- **Chat issue references stay scoped to the current viewer (#3068).** Reconciliation replaces complete snapshots, clears protected projections after a denied access check, and preserves durable run anchors. Uncertain human writes retain the same revision and idempotency key through recovery, including a denied retry after a lost acknowledgement.
- Chat CSV/TSV artifacts gain bounded local-worker previews with sorting, filtering, virtual rows and source-preserving selection. Ask about selection appends a versioned reference to the draft without sending it. Access denial clears displayed artifact bytes.
- Chat XLSX artifacts gain bounded local worksheet previews, saved formula results and source-preserving draft selection. Corrupt, encrypted, macro-enabled and oversized workbooks, and those with external data connections, retain an explicit download fallback. Macro-enabled `.xlsm` outputs remain discoverable for download only.
- **Issues created in chat stay with their conversation turn (#3068).** Viewer-authorized cards survive reload and failed runs, open an existing Issue detail panel, and support permitted field edits and comments with conflict and uncertain-write recovery. Access loss hides protected card and panel data; phone and keyboard flows use the same controls. Direct work execution remains on the canonical Issue page.
- **Chat issue cards can refresh sooner after successful writes.** Authorized chat sessions now receive content-free reference/revision invalidation hints; reference snapshots include `contract_version: 1`. Queued session delivery also rejects suspended users and deleted chat agents/workspaces.
- **Suspended accounts stop receiving realtime updates.** Channel subscriptions and queued WebSocket delivery now recheck the active account, including global and identity feeds and protocol control messages.
- Issue cards in chat can show linked pull requests on demand, using authorized stored provider metadata. Cards distinguish failed or missing synchronization and explicitly mark CI as unknown; no private source or diff is fetched.
- Guests with explicit routine View and Edit draft shares can change collaborative drafts through UI and CLI with revision/base conflicts and atomic audit. Published recipes, execution authority and trusted testing/review gates remain intact; direct Guest publication is still separate work.
- Guest project managers can create and edit milestones with reviewed versions and atomic audit. Empty-only removal preserves linked issue work; UI and CLI enforce current action flags and conflict review.
- Guests can remove reviewed Backlog/Cancelled issues through an explicit Delete issues share, with Read/Manage, current snapshots, active-work guards and atomic audit/chat receipts.
- ⚠️ **Behaviour change:** Page shares become inactive when their issuer is suspended or restricted as a Guest anywhere. Existing share metadata remains visible to Page administrators with an account-status explanation.
- ⚠️ Tokens with limited scopes can no longer create successor tokens or pairing codes. Use an interactive sign-in to create credentials; trusted full-role token creation remains available.
- Internal foundations preserve explicit versioned resource-preset choice provenance through backup and fork restore. Existing grants remain unchanged and no preset selector/API/CLI is enabled yet; immutable v1 bundles, managed-edit invalidation and empty migration state prepare #3271.
- Internal preset planning reads one live-authority snapshot and explains exact bundle changes, preserved issuers and independent consequences without changing any grants. Empty grant collections remain JSON arrays; unavailable unrelated historical resource grants remain preserved without granting authority. Confirmation checksums do not authorize access; public preview and application remain disabled pending the next #3271 slices.
- Guests with an explicit routine View share can inspect its definition without an execution runtime or agent Run grants. Stored Run grants retain their existing invocation-only disclosure; View does not expose another person’s private runs. UI, CLI and access explanations use the same live issuer policy.
- Guests with explicit project Read and Manage shares can edit shared project names and descriptions. UI and CLI preserve review snapshots and refuse conflicting saves; private project metadata and unrelated operations remain inaccessible.
- **Agent chat transcripts survive workspace and crew backups (#3109).** Encrypted bundles include scoped structured history, remapped fork identities and stable message/run anchors. Damaged lines produce per-chat completeness warnings instead of blocking all backups. Collection only fences file pinning; restore fences publication and commit, preserving existing histories unless replacement is explicit. Cross-workspace chat collisions are refused. The search/feedback mirror and atomic hard-crash recovery across filesystem/DB publication remain separate limitations.
- **Agents can remember explicitly stated feedback preferences.** Optional future preferences on thumbs feedback now have scoped, source-tracked storage, asynchronous status, CLI self-service edits and deletion, and private-session recall with consent checks. Bare thumbs remain feedback only.
- **Choose what an agent should remember from feedback.** Thumbs now offer optional explicit future preferences with verified memory status, and the chat Memory panel lets you inspect sources, change or forget preferences, and control personal memory.
- Pages folder and page menus now follow caller-specific server ACL decisions: readers see no mutation controls, folder editors can arrange, and page owners retain move access.
- Guest accounts can complete CLI login by creating their own token from a verified interactive session. Minted tokens retain Guest restrictions; bearer credentials cannot remint a wider successor.
- Guest project contributors can submit Backlog requests, post explicitly shared comments and arrange intake work. Administrators choose the project intake crew; historical staff comments stay private and shared threads stay bound to their original project. UI and CLI cover the same operations.
- **Share routines and projects from their detail cards.** Workspace administrators can inspect Guest shares, preserve unrelated rights and issuer provenance, revoke individual operations or explicitly reissue inactive shares. Conflicting saves require a fresh review. Routine sharing offers Run; project sharing offers independent List and Read.
- **Share individual routines and projects from the CLI.** `share`, `share list` and `unshare` preserve unrelated rights and issuer provenance, expose inactive shares and require explicit `--reissue` to move authority. Stale policy saves fail without retry.
- **Guests can understand their own access.** Settings shows named resources and execution prerequisites; `workspace access me` and the workspace `access/me` API expose the same self-scoped explanation. Temporary refresh errors preserve the last good result, while access loss clears it. Concurrent resource deletion becomes an unavailable row.
- Policy saves and explicit grant reissues record previous and new issuers and rights atomically. Member access CLI supports `--reissue` and shows inactive shares; Settings displays issuer names when available.
- **Editing one Guest share preserves other administrators’ grants.** Unchanged rights retain their issuer and creation time, and inactive grants require an explicit reissue. Administrative policy shows issuer and active status; changes to already inactive issuers no longer stop newly authorized work.
- ⚠️ **Behaviour change: resource shares follow current administrator authority.** Guest discovery, Issues, chat and routine execution stop using a grant when its issuer leaves, is demoted or suspended, or becomes a Guest. Stored shares are preserved; restoring the issuer does not revive previously admitted runs.
- Guest accounts cannot acquire ADMIN or OWNER in any workspace; a database invariant protects both directions of the account-wide restriction. Guest Page actions retain Pages ACL checks and also require explicit routine Run and agent grants; existing capabilities are not backfilled.
- Native Guest runtime candidates use a patched Debian 13 userspace while preserving the exact pinned bubblewrap 0.8 and Codex sandbox contract. Candidate publication still requires a passing vulnerability scan, signature verification and live acceptance before installation.
- **Audit chart selections clear when the same bar is selected again (#3094).** The chart and table retain the chosen time-window anchor while activity loads or filters change, so incoming samples no longer shift a relative bucket beneath the selection.
- Fix Settings reloads while account access loads, Guest chat regeneration controls and restricted resource path segments. Add CLI Guest invitation policy/consent flags and binary acceptance coverage.
- ⚠️ **Behaviour change:** Guest invitations, provisioning and resource policy changes refuse accounts that own or administer any workspace. Stale Guest invitation signup returns a typed conflict. Automation rules recheck the active routine author's membership in that workspace, and any non-NULL suspension blocks instance administration.
- ⚠️ **Behaviour change: only workspace owners may provision ADMIN accounts.** The setup-link flow now applies the same role assignment rule as membership updates and invitations. Workspace administrators can still provision MANAGER, MEMBER and VIEWER accounts; refused requests preserve existing accounts and setup links.
- ⚠️ **Behaviour change: guests run only routines explicitly shared with them.** Routine run grants now combine with every required agent grant, without a workspace-wide routine capability. Existing restricted members need routine grants added; pending private work is invalidated on upgrade. Settings › Members can select individual routines.
- **Guests can be added with initial shares and inspect project Issues.** Guest invitations install initial shares atomically with acceptance, including signup redemption. Existing accounts explicitly accept the account-wide restriction; direct provisioning cannot silently restrict a claimed account. Project list/read grants expose a filtered, read-only Issues catalog and detail without shared activity or related-resource data. Settings and `workspace member access explain` describe saved grants and blocked execution prerequisites.
- **Suspending a human routine author stops unattended triggers.** Schedule, webhook, wake-check, nested calls and automation rules recheck the author’s live account; promoting a Guest to administrator requires explicitly restoring trusted access.
- **Access refusals explain what remains available.** Restricted screens show Crewship branding, administrator guidance and links to the member’s available sections. Discover-only agents no longer offer sending messages, and the Pages rail hides folder creation when creation is unavailable.
- **Workspace recovery keeps account and administration usable.** Workspace selections are stored separately per account; a stale preference recovers on login. Directory outages preserve active drafts while account and instance API requests remain available. Remaining chat and output-file path identifiers reject dot segments before dispatch. Private workflow suspension matches login’s NULL-only active-account rule.
- **A temporarily missing workspace no longer silently switches context or discards a draft (#3083).** Retry preserves the selected workspace and local draft while content and workspace requests remain unavailable; choosing another workspace uses the existing unsaved-change confirmation.
- **Memory file access remains inside its configured storage root during directory replacement.** Sidecar fallback reads and writes, indexing, restores and proposed-skill reads use pinned directory handles and reject symlinked path components. Local sidecar fallback requires an explicit trusted storage root; ordinary crew launches configure it automatically. Custom sidecars without one retain the host bridge but refuse unsafe local fallback.
- Invitation creation, reissue, withdrawal and acceptance record non-secret workspace activity atomically with their state changes (#3084).
- **Private workflow dispatch follows current account status.** Queued and recovered work retains its existing resource, role and execution safety checks.
- **Restricted routine failures retain their meaning.** Missing graph dependencies return the existing opaque unavailable response, while storage failures remain temporary service errors; unsupported declarations still report a request error.
- **Pages creation and import controls follow current workspace permissions (#3081).** Readers keep access to existing content; authorized roles and explicit `page.create` grants retain authoring. An open draft survives permission loss while submission is disabled.
- **Members never shows another workspace's roster while loading.** Switching workspaces clears the previous roster immediately, including when the new request fails; refreshing the same workspace keeps an open invitation's setup link visible and refreshes capability grants too. A member whose grants have not loaded cannot have them overwritten by an edit. Reopening backup setup also selects the current instance plan instead of retaining a plan from an earlier opening.
- **A password change can revoke CLI tokens too.** `POST /api/v1/users/me/password` accepts `revoke_cli_tokens: true` and reports `cli_tokens_revoked`; `crewship auth passwd --revoke-cli-tokens` and an "Also revoke all CLI tokens" checkbox in the web dialog send it. Without it nothing changes: browser sessions are signed out, CLI tokens keep working.
- **A workspace's security page reads at a glance.** Admin › Security › a workspace opens with five tiles — Watchdog, Findings, Four-eyes, Leases, Judge — each with its icon, whether it is on and how, and a click to its card. The cards say less: the long explanations are behind an ⓘ beside each setting (and read out to a screen reader), what to flag is a row of toggles with an icon each, own rules are folded until there are some, and the review rate, the DENY alert threshold and the lease length offer the usual values one click away beside the field that still takes any other.
- **Backups lead you through the first setup.** Until there is a backup key and an enabled plan, Admin › Backups opens with **Set up backups**, and *Back up now* opens it instead of failing with "recipient_ids is required". Step one makes the backup key in the browser (Web Crypto X25519, encoded as age: the private key is shown once to download or copy and never sent; the server keeps the `age1…` public half) or takes a pasted one; step two creates the Complete recovery plan (nightly, a year of copies, on this server); step three runs the first backup. Only an enabled plan of everything on the whole instance counts; a plan for some workspaces does not finish the setup.
- **Admin › Backups is built like People & workspaces and Security.** The panel switches between Overview, Runs and Restore and lists the plans, every workspace with its newest backup, and the instance settings (Storage, Keys & alerts); the four groups of run filters are gone from it. A tick beside each workspace (and *All workspaces*) picks what Overview, Runs, a new restore and **Back up now** cover — several at once, none being the whole instance — and the name opens the workspace. **Runs** is built like the Audit log — the time range in the sub-bar, the Crew Journal's chart of runs by result (a bar or a dragged span narrows the table), and Scope, Result, Kind and Proof filters above the table — and ticked runs are pinned, unpinned or downloaded from the green selection bar. A workspace opens its own backups (`?workspace=`): newest backup and proof, its plan, Needs attention, nights and last runs, with Back up now and Restore. The Overview is the whole instance, adds a table of workspaces, answers the five questions as a checklist, and its Needs attention says High / Medium like every other page. Restore puts New restore, History and Drills above the wizard. On a phone the sub-bar keeps icons only and the views are a switch, not a select.
- **Admin › Security is built like People & workspaces.** The panel switches between Overview, Workspaces and Activity, and lists the instance settings (Credential judge, Decision rules, Background checks, New workspaces), the activity streams with their counts and every workspace with how it is watched; a search finds a workspace. The list of workspaces to tick at the top of the panel is gone. What is set per workspace is no longer four sections: the **Workspaces** view is one table — watchdog, review rate, DENY alert, enforced four-eyes, lease, judge, then what a new workspace starts with — whose rows open a **workspace profile** with all its settings, and ticked rows change together from the green selection bar (Watchdog, Alerts, Lease, Judge), still previewed workspace by workspace before anything is written. The Overview shows the same table under Needs attention; Activity narrows to one workspace. Old `?section=watchdog&ws=…` links open that workspace's profile. Workspaces show their logo there and in People & workspaces' chips, access grid and person profile; the instance Keeper responses carry `workspace_logo_url`.
- **A change of the log level is on record.** Admin › Runtime › Logging and `crewship system log-level set` write each change to the instance audit (`instance.log_level_changed`: who, from, to, for how long), and the server's return to the baseline when the time runs out as `instance.log_level_reverted`; the card lists the last three. Fixed: switching to `error` silenced the server log line that reported the switch. The card says the baseline comes from `CREWSHIP_LOG_LEVEL` on the server, and *Drop back after* is offered only for a level other than the baseline.
- **Top bar, user menu and Settings › Appearance redesigned.** The status pill shows one message in one tone, the worst state winning: an icon only while healthy, otherwise "N agent errors", "N queued", "No agents", "Connecting", "Reconnecting" or "Offline". Clicking it opens System status with the agents in error. The user menu links its header to Profile and states your role and workspace. It has a compact theme switch, a sounds on/off switch, Notification preferences, "Sessions & CLI tokens" with the active-session count, **Connect CLI…** (the onboarding's device-code pairing, now available any time), a Help & resources submenu and the build label. Accent moved to the new **Settings › Appearance**, alongside theme, density (Compact), reduce motion and "Sync across devices", which stores the choice under the `appearance` key of `/api/v1/me/preferences`. **Sessions & tokens** is now its own Settings section instead of the bottom of Profile. The workspace switcher adds Workspace settings and Invite members, and replaces the placeholder workspace in the phone navigation sheet. The Activity bell has Live / Recent / Failed filters. The Inbox bell filters by kind and offers Approve / Deny in the row for plain routine approvals. Appearance also offers a **Team colour** accent derived from the workspace's brand colour (General › Pages appearance), with each shade's lightness adjusted to stay WCAG AA. Notification sounds are now saved with the user per workspace (`notification-sounds.<workspace-id>` in `/api/v1/me/preferences`) instead of only in the browser. Appearance adds three accents (Sky, Fuchsia, Pink), shown as a row of large swatches with a live preview, Text size (Small / Default / Large) and the Sidebar mode, all saved with the user; ⚠️ **Behaviour change:** the default Pages palette is now the **Crewship** palette (brand blue on the product's dark ground) instead of mint, for every workspace that never customised it — including the Page starter's CSS fallbacks. Pages appearance offers Crewship, Crewship light, Midnight, Paper or Custom, one compact colour list with AA badges, a larger live sample and *Reset to Crewship default*; it stacks on phones and tablets. Nested pages (Settings › Crew links and Audit log, Admin › People & workspaces, Security and Backups) show the way back once, as a bordered "← Settings" / "← Admin" button on the sub-bar next to the page name and description, instead of repeating the path at the top of their side panel. In light, the left rail is now white like the section panels, on a quiet grey page ground. Settings › Members is a nested page too (`/settings/members`). It starts with **Needs attention** — who can reveal secrets in plaintext, Members or Viewers holding skills or credentials, invitations that have expired or are about to — each with a button that lists or opens them. The roster is grouped by role (or A–Z), and what each person may do reads as up to three chips — Routines, Content, Secrets, with "n/m" when only part of an area is held, a red "Secrets · reveal" and "Chat only" — instead of a dot per capability. The side panel filters by role, by area, by "needs a look" and lists pending invitations with when each runs out. A row opens the person in a side panel: role, a preset (Chat only / Power user / Builder — the server's `chat` / `power` / `admin`) with what differs from it, each ability as a switch grouped by area, crews and agents, removal, and a warning with "Turn … off" / "Make Manager" when the role and the access disagree. Tick rows to set a preset, grant or revoke for many people at once — all as drafts that only Save in the page's save bar commits (Discard drops them); high-stakes grants ask first. Drafts belong to their workspace: switching workspaces with unsaved changes on any page with the save bar asks first, as leaving does, and nothing is editable until the server has said what each person holds. Every role and ability wears the product's icon for it (Routines' scroll, an issue's dot, Pages, Memory, Skills, Credentials), and Manager, Member and Viewer have icons of their own. **Add member** takes the role as cards and what the person may do — the role's default or a preset — and applies the preset right after the account is created; Add and Remove share one dialog style. The person panel shows whether Reveal is switched on for the workspace, and Settings › Access & Secrets no longer keeps its own editable list of who may reveal: it says how many people hold it (with the recommendation of two) and links to Members, where the "Can reveal secrets" view shows the workspace switch and grants reveal like any other change; on a phone that page no longer runs off the right edge. Old `/settings?tab=members&member=…` links open the same person there. The space sign-up creates for someone who has no invitation ("<Name>'s Workspace") is now their **personal account**, and "workspace" means only a place people share. The workspace switcher shows it first, under *Personal account*, with the person's name, then *Workspaces*. Admin › People & workspaces lists personal accounts under People — a *Personal accounts* view that a search narrows (by the owner's name too), with *Remove N empty* — and never among the Workspaces; people's chips read "Personal account". A workspace's page renames it and turns it into a personal account or back, for an instance admin who is not a member. `GET /api/v1/workspaces` and the workspace responses carry `kind` (`team` | `personal`) and, for a personal account, `personal_owner_id` — whose it is (its longest-standing owner), so someone who joins another person's personal account as an owner sees it under Workspaces, not as their own. The Access grid lists only workspaces. `crewship seed` names the demo workspace *Acme Company* on a fresh database instead of "Demo User's Workspace". The page opens with **Needs attention** — locked accounts (Unlock), unfinished sign-ups, people in no workspace, empty personal accounts — each facet has an icon, ticked people can be added to a workspace with a role or suspended at once (the bar over ticked rows — here, in Settings › Members and on Credentials — is green like the save bar, so it is not overlooked; so is the stand-alone Save bar a section draws outside such a page), and Add person / New workspace pick roles as icons (New workspace can add people right away). Settings › Audit log takes its time range from the sub-bar — the Crew Journal's picker (Last hour to Last 90 days, All time) with the month calendar behind *Custom…* — instead of the side panel. Its chart is the Crew Journal's — events stacked by severity across the picked range, where a click picks a bar and a drag picks a span; that slice narrows the table (and shows as a filter chip) without changing the range. Each category wears the product's icon for what it records. People in the side panel show their photo and a bar for their share, busiest first, with those who did nothing in the range folded into one line; the table shows photos too. The Journal's *Custom…* no longer closes the moment it opens. Fixed: the frontend's `admin` preset lacked `credentials:reveal`, which the server grants; a sheet opened from state in a dev build closed the moment it opened (React StrictMode's double mount spent its back-button history entry). ⚠️ **Behaviour change: lifecycle hooks are paused.** The feature is unfinished — a webhook gets the raw event JSON, which Slack, Teams or PagerDuty do not accept without a relay, and the subagent handler was never wired — so it is switched off rather than offered: hooks do not fire, every `/api/v1/hooks` endpoint answers `503` with the reason, `crewship hooks` is hidden, and Settings no longer lists it (`/settings/hooks` says it is paused). Rows in `hooks_config` are kept. `CREWSHIP_HOOKS_ENABLED=1` on the server turns hooks back on for development.
- **Deferred and resumed human routine runs follow current account status (#3079).** Autonomous triggers and dry-run validation retain their existing behavior.
- ⚠️ **Behaviour change:** Signup invitation handoff requires the matching invitation link; existing accounts can explicitly accept after signing in or through `workspace invite accept`. Invitation listings retain metadata without redemption tokens; pending links can be reissued or revoked. Legacy unaccepted invitation links stored as raw tokens are invalidated on upgrade; an authorized inviter must create a new invitation or reissue the pending invitation. Accepted invitation history is preserved. New proofs are stored hashed, and browser/CLI handoff avoids putting proof in redirect URLs or command arguments (#3071).
- **Restricted navigation follows each member’s grants (#3072).** Chat, Routines and Pages appear only when the selected workspace membership can access their catalog; account security remains available. Switching workspaces no longer borrows another membership’s screens. A missing execution runtime does not hide otherwise authorized navigation. Open screens recheck changed access through the existing foreground polling interval.
- ⚠️ **Behaviour change:** Manual schedule runs record the requesting operator and follow their current workspace execution authority (#3070).
- **Assignments use durable work admission (#3057).** Ordinary assignments, mentions, channel requests and mission planning share fenced claims and run identities with scheduled and webhook work. Cancellation is durable before execution creation, results and mission completion retry safely after restart, and current assignment attempts can use run-bound memory. Legacy running assignments continue to hold capacity; an upgrade refuses ambiguous queued rows that still name an exec.
- ⚠️ **Behaviour change: assignment concurrency now shares the server-wide work caps (#3057).** Assignments are admitted by the same dispatcher as scheduled and webhook work, so they count against its server-wide limits: 8 executions in total, at most 6 of them background, and one execution at a time per agent. Before, only the per-crew budget limited assignments. That crew budget (`max_concurrent_agents`, or else the crew container memory divided by `runtime.agent_min_memory_mb`, which is 2 for the default 4096 MB / 2048 MB) now applies to every work item that carries a crew, including scheduled routines, webhooks and chat-class Pages tasks. A setup that ran more than 8 assignments at once, or relied on routines and webhooks bypassing the crew budget, now queues the excess instead of starting it.
- **Finished assignments always complete their projection (#3057).** A queued follow-up that can never be dispatched (target agent deleted, comment author removed, crews disconnected, the requester's authority no longer valid, or a gate declining) is recorded on the delivery as refused, and the human author gets an inbox notice. Agent-declared deliverables that are missing, escape the crew's shared directory, are not regular files or have a disallowed type are skipped and logged; escaping symlinks are still never read. Only host faults retry the projection, and a settled assignment awaiting projection no longer holds an execution slot.
- **Local Linux Docker runs retain output across controller loss (#2845).** A private host helper keeps the actual CLI execution and redacted output independent of its reader. Recovery projects output and terminal results with durable acknowledgements, preserves work-generation ownership, and refuses duplicate launches. Capture has per-run and aggregate bounds and acknowledgement-based retention. Unsupported providers keep the existing transport; uncertain forced stops retain reconciliation rather than report completion.
- **⌘K finds every place in the app (#3045).** As you type, the search box finds:
- every Settings card, opening the tab and scrolling to the card; `/settings?tab=…&card=<slug>` links to one
- the tabs and sections of Integrations, Inbox, Activity, Journal and Routines
- actions that live behind a button: Create issue, Invite member, Create CLI token, Change password, Store missing avatars
- the Admin console, for instance administrators
- missions, routine schedules and automations, each crew tool on its own row, and your other workspaces to switch to
Several words now match in any order. Every row is gated the way its page is. See [Search (⌘K)](docs/guides/search.mdx).
- **Agent Issue actions produce durable chat references (#3068).** Typed MCP tools create, update, comment on and show issues with host-verified requester authority and stable retry keys. `crewship chat refs` reads authorized replacement snapshots; `crewship operation get` exposes sanitized metadata. Issue responses include state-aware viewer actions and revisions, including work policy. Reference pages batch current card data. Human PATCH supports revision preconditions, and PATCH/comments support stable retry keys; deletion retains minimal authorized receipts. Interactive frontend cards, proposals and dedicated entity WebSocket events remain follow-ups. Limited CLI tokens cannot acquire unrestricted chat authority; existing WebSocket tickets must be refreshed after this update.
- **Issue work preserves authenticated web/API requesters (#3068).** Public issue creation, starting or handing work to an agent, recurring issues and comment mentions retain a revocable requester admission. Unrelated chat audience changes do not revoke web admissions; revoked recurring templates leave the due queue and notify a current member. Verified live runs can escalate even when their requester grant is blocked. Human and agent Issue creation, PATCH/comments, bulk status/priority/assignment edits, attachments and code-link changes commit audit intents with their mutations. Bulk label/project audit and remaining relation/workflow/Inbox mutation doors are tracked separately (#3105). Mention delivery survives disconnect/restart, queued receipts prevent duplicate dispatch, and failed deliveries have bounded retries, private terminal notices and admin API/CLI diagnostics. Completed delivery payloads are cleared and receipts expire after seven days; unchanged labels leave the issue revision unchanged. Scoped CLI tokens retain ordinary CRUD without gaining execution authority. Unverified recurring occurrences retain explicit unavailable provenance and notify an eligible owner once, so missing legacy creator attribution cannot turn them into autonomous work. Scoped execution edits cannot reuse another person’s template authority; labels and disable retain the existing origin, same-person edits retain a valid grant, and full-session content edits capture the editor’s own admission. Scoped explicit re-enable is refused unchanged. Plain comments now emit `mission.comment` for existing notification preferences and automation rules; audit-only traces do not appear as automation run IDs. Restored memberships receive a fresh web execution epoch; old web-origin work requires authenticated re-admission. Failed-delivery payload retention, journal recovery and restore/fork mention reconciliation remain follow-ups (#3103, #3104).
- **Execution authorization boundaries (#3068).** Routine agent steps now have durable `ROUTINE` admissions and publish agent RUNNING state. Restricted accounts cannot use the human Issue PATCH/comment paths, and narrow CLI token scopes cannot be widened into a standing human execution grant. Unknown legacy unfinished assignments, pipeline runs and pending work remain blocked until fresh authenticated admission; review the affected queue before rollout. `crewship doctor execution-origins` provides a read-only local inventory with record IDs, workspace counts and explicit uncertain cases; it does not authorize execution or certify rollout. Existing history and standing routine definitions remain preserved.
- **Execution-authority upgrade steps (#3068).** Before each stage or production upgrade, run the read-only execution-origins doctor against that target's actual database; the production owner performs the production audit. After deploying matching backend/sidecar artifacts, recycle retained crew containers with `crewship crew restart-agents <slug-or-id>` only in a coordinated idle window; the command removes the container and can interrupt active work. Restored web-origin recurring templates pause until reviewed and saved/re-enabled through a fresh full authenticated session. See the [rollout procedure](RELEASING.md#execution-authority-rollout-3068).
- ⚠️ **Behaviour change:** Chat-requested issue writes keep the original requester’s authority through delegation and deferred routines (#3068). Upgrade recovers unique durable human receipts and positively admitted machine roots; legacy queued work without such proof requires a fresh authorized request, including historical UI/cron work with missing evidence. Records are preserved. OWNER/ADMIN operators can auditably clear a stale routine head and selected schedule origins without changing pinned versions or already admitted work. Restoring or forking data does not grant copied human work autonomous rights.
- **The Crews sidebar has Status, Filter and View, like Routines and Skills (#3043).** Status counts agents (Needs you, Working, Idle, Expired hires) and lists the ones you pick. Filter narrows by role, model, runtime, hire type, activity and crew health, with removable chips. View groups by crew, by status or not at all and sorts by crew size, name or last active. Leads come first with a crown; rows show each agent's role and when it last worked, and each crew's running missions or last activity. Hover adds Chat on an agent and Add agent on a crew, and the collapsed sidebar keeps the crew icons with an attention dot. Status, filters and view are kept in the URL (`?status=needs&role=lead&group=status`).
- **Security: the server image's docker CLI is Docker's static 29.9.0 build (#3047).** Alpine's `docker-cli` package in alpine:3.24 was built with go1.26.8, so the image carried the critical net/http advisories GO-2026-6612 and GO-2026-6604 that #3039 fixed for Crewship's own binaries, and the image scan failed on every build. The Dockerfile now downloads the static docker CLI for the target architecture, checks it against a pinned SHA-256 and copies only the `docker` binary.
- **Explicit skill authoring grants now allow imports.** Trusted workspace members holding `skill.create` can import SKILL.md content or URLs, matching generation. Revocation is checked on each request; Guest restrictions, CLI scopes and import validation remain enforced.
- **Skills has the same explorer as Routines and Issues, and can be filtered by agent (#3033).** The left panel lists View buckets (All, On agents, Not assigned, Needs a look, Proposed by agents), the workspace's crews with their agents and how many skills each holds, and the domains in use; source, trust, maturity and "needs a credential" sit in the Filter popover. Each card shows one trust word (Verified, Unverified, Not scanned, Flagged), the credentials the skill needs, the agents that hold it and its uses in the last 7 days. A strip at the top names what needs a person: a flagged skill on agents, a proposal waiting for review, an agent missing a credential a skill needs. A skill opens beside the explorer with Overview, Agents (one switch per agent, applied at once, or a whole crew), SKILL.md (download) and Activity; built-in skills cannot be deleted and say so. The Overview lays the SKILL.md out (when to use it, steps, what it hands back, guardrails) with agents, uses per day, needs and source in a rail; the SKILL.md tab has an outline, the frontmatter as a table and a Source view. Every skill shows its own icon. New skill either has Claude write it or lets you write it, with an icon and domain picked up front; Edit and Duplicate as new skill save through the importer, which re-runs the scan and refuses to change built-ins. Proposals are approved or rejected on the page. On a phone the explorer is a drawer behind Filters. `/skills/<id>` links open the same view. The Runtime facet (every skill is instructions-only), the always-zero install count and the Browse / Installed / Generated tabs are gone.
- ⚠️ **Behaviour change:** **Skill holders are scoped to your workspace (#3032).** The skills catalog is shared across workspaces, but the agents listed on a skill (`installed_on`), the `?installed=1` / `installed_for_agent_id` filters and a skill's `agent_count` counted agents of every workspace, so a member could see other workspaces' agent names and crews. They now only see the caller's workspace. Skills also report this workspace's usage (`usage`: uses in 7 days, errors, total, last used), `lifecycle_state`, `needs_credentials` and, per agent, the required credentials it is missing; `GET /agents/{id}/skills` carries the same. `crewship skill list` gains AGENTS and USES 7D columns, and `crewship agent skills` prints the skill name and category it showed blank before.
- ⚠️ **Behaviour change:** **Skill holders are scoped to your workspace (#3032).** The skills catalog is shared across workspaces, but the agents listed on a skill (`installed_on`), the `?installed=1` / `installed_for_agent_id` filters and a skill's `agent_count` counted agents of every workspace, so a member could see other workspaces' agent names and crews. They now only see the caller's workspace. Skills also report this workspace's usage (`usage`: uses in 7 days, errors, total, last used), `lifecycle_state`, `needs_credentials` and, per agent, the required credentials it is missing; `GET /agents/{id}/skills` carries the same. `crewship skill list` gains AGENTS and USES 7D columns, and `crewship agent skills` prints the skill name and category it showed blank before.
- **Settings › Members marks restricted members (#2878).** A restricted member's row shows a Restricted chip next to the role chip, and the expanded panel names the access mode; saving a changed mode in Edit resource access updates the roster. `GET /workspaces/{id}/members` returns `access_mode` to a trusted OWNER/ADMIN (the same gate as a member's access policy) and omits it for everyone else; `crewship workspace member list` has an ACCESS column (`-` when withheld).
- **Cancelling a run parked at an approval can no longer race its resume (#2910).** If an approval, signal or event resumed the run at the same moment, the API could report the cancellation while the resumed run went on to execute its next steps. Exactly one side now wins: either the resume is refused and the run stays cancelled, or the resumed run is stopped before its next step and records `cancelled` (instead of `interrupted`). The response carries `"parked": true` only when the cancel recorded the row itself.
- **A model call refused by the sidecar says why (#2899).** Every admission failure used to read as 403 "hard-budget traffic requires the restricted broker", even on a workspace with no budget. Only a host decision is still a 403 (a hard budget, or a refused agent, crew or credential scope); an unreachable host, a rejected sidecar credential, an unavailable budget store or a missing binding is a 503, and an unreadable host answer a 502. Each message names its kind. The troubleshooting guide lists what each one means.
- **A taken or reserved agent slug is shown under the Slug field (#2862).** Creating or renaming an agent onto a slug in use used to toast the raw JSON body, and a rename onto a taken slug failed with a 500. The API now answers `409` with a machine-readable `code` (`agent_slug_taken`, `agent_slug_reserved`, `crew_lead_exists`) and the `field` it concerns, next to the unchanged sentence; the agent dialog shows it under Slug (or Role), and the crew and agent canvases, model configuration and crew dialog show the server's sentence instead of JSON. A race between two new LEAD agents is reported as `crew_lead_exists` instead of a taken slug.
- **Routine runs show reported usage, not spend (#2193).** A run's `cost_usd` is what the agent CLIs reported, priced at list rates; under a subscription nothing is billed per call. Routine run detail, the crew bottom panel and the workspace digest now say "reported usage" with an approximate `~$` figure; `routine records` and `routine runs-all` call the column REPORTED USAGE. The `cost_usd` field is unchanged.
- **Restricted members see only what they can use (#2861).** For a restricted account, `GET /api/v1/workspaces` now returns `restricted_session` and `restricted_surfaces` (`chat`, `routines`, `pages`, `account_security`). The server derives the list from its route allowlist. The sidebar, phone menu and phone tab bar show only those screens. Any other URL shows "Not available with your access" without loading the screen, and `/` opens Chat. Settings shows only account security (password, sessions, revoking CLI tokens).
- **Background sweepers no longer fire in lockstep after a restart (#1891).** The sub-hour periodic loops each wait a random offset within their own period before their ticker starts. That covers the harbormaster timeout, waitpoint, pending-run, ephemeral-agent, assignment queue/running/lease, OAuth and provider-login refresh, presence, episodic-index and port-exposure sweepers. A deploy used to line up their phases so the 30-second sweepers hit the database on the same second. Loops that run once at boot still do so immediately. The daily jobs scheduled by wall-clock hour are unchanged.
- **The first message of a new conversation can be sent again (#2898).** Opening an agent with no saved conversation left Send disabled: the draft has no row yet, so its execution profile stayed pending, realtime stayed off and the composer waited for a connection that only the first send would start. Send is now offered once the profile check has answered. The send creates the conversation, resolves its profile, waits for the connection a trusted chat needs, and only then goes; a refused profile, a failed create or a connection that does not open leaves the message in the box with a toast. The same applies to a `?prompt=` handoff.
- **`crewship backup verify` catches a workspace bundle that left rows behind (#2009).** A workspace backup now checks, in the same database snapshot, every row the schema ties to the workspace (its own `workspace_id`, or a foreign key into an exported workspace row) against what the backup's scope filters exported. The result is recorded in the manifest as `contents.scope_reconciliation`. `verify` reports `INVALID` with `table: N of M workspace row(s) in the source were not exported` for a bundle that recorded a shortfall, including an encrypted one. The verify API returns the list as `scope_shortfalls`.
- **Private routines and Page actions say why nothing is listed (#2877).** A restricted member on a server without private execution sees "Private execution isn't installed on this server — ask an administrator" instead of "catalog unavailable" and "nothing available" at once. Loading, empty, unavailable and not-installed are now one state each. The routine and Page catalogs, routine runs and restricted Page actions answer `503` with code `restricted_runtime_unavailable` to restricted members only; every access refusal stays an opaque `404`.
- **A tool switched off on an MCP integration is refused by the crew sidecar's gateway (#2178).** `crewship integration tools disable` and the per-tool switch now also stop the sidecar's `/mcp/call` from calling the tool and hide it from `/mcp/tools`, from the sidecar's next start. Agent CLIs that connect to an HTTP MCP server directly are not gated per tool yet.
- **A repeated webhook delivery gets its receipt even while the first one is running (#2964).** If the acceptance write could not commit in time, for example because the original delivery's run held the database, a duplicate was answered `503 acceptance unavailable`. It now gets `202` with the original work and its current state; only new work is refused.
- **Security: Go 1.27.2 and golang.org/x/net v0.60.0 (#3039).** Fixes the net/http and HTTP/2 advisories GO-2026-6599, 6600, 6603–6605 and 6607–6613, and GO-2026-6617, that `govulncheck` reports as reachable on 1.27.1 / x/net v0.59.0. The release image builds with `golang:1.27.2-alpine`.
- **The Work queue and Webhook deliveries look like Activity (#3017).** Opening either one keeps the rail and switches it, with a slide, to the ledger's own rows:
- status in Activity's words — the Waiting and Expired filters, which nothing ever filled, are gone;
- agents with their avatars, and whether their queue moves;
- event families.
Each row narrows the page. The Work queue gives:
- a summary sentence and a flow from Arrived to Done;
- **Needs you**, where work with an unknown outcome is settled with **Retry**, **Mark as failed** or **Mark as done**, and the card says how many items wait behind it;
- failures grouped by cause;
- one lane per agent, with its crew's colour;
- the latest work, one sentence each.
Deliveries show each endpoint's health (an endpoint with nothing in a day reads quiet), arrivals per event family, and what each delivery became, with a detail panel that opens its work. Each narrowing shows as a removable chip, so a filter whose row left the window can still be cleared. On a phone the rail starts closed and work and deliveries open in a sheet. Retry's dialog says when the input cannot run again and does not run it. The pages read their whole window plus all unfinished work, so stuck work stays in Needs you; a routine's endpoint is named as such, not as a deleted agent. The 7 d lane axis on these pages and on Activity's home marks every day; it skipped one before.
- **The work queue and webhook deliveries name who, what and how it ended (#3012).** `GET …/work-items` items carry `agent` (name, slug, avatar, stored `avatar_url`, `deleted`), `crew` (name, colour, icon, `deleted`), `event_type`, `duration_ms` and `cost_usd`; `GET …/webhook-deliveries` carries `agent` and the resulting `work_state`. `crewship work list` shows the agent's name and the event instead of the agent id and capacity class, and `crewship work deliveries list` shows the agent and the work state. Both lists take `since=` (a time window; pages run oldest first) and the work list `open=true` (unfinished work however old), with `--since` and `--open` in the CLI. A replay names its original's event, a deleted crew says so, and duration and cost are given only when known. `crewship work list` no longer has the CLASS column; it is in `-f json`.
- **Activity's rail follows source and severity filters too (#3007).** With a source, severity or telemetry filter, the rail lists only the runs the matching events belong to, and is empty when none match. It no longer keeps listing every run beside an empty column. Agent work started outside a routine is hidden in Activity for now; the index and CLI still list it.
- **A crew, agent, issue or routine filter keeps Activity's home, narrowed (#3002).** The column used to swap the home for the raw journal list ("morgan runs claude --print …"). It now shows the same cards for the chains the rail shows, titled with the filter. Source, severity and telemetry filters keep the event list. `GET …/pipeline-runs` returns each run's `chain_origin`.
- **Activity's Filter narrows the rail too (#3000).** With a crew, agent, issue or routine picked, the rail kept listing every run beside a column that showed only the filtered ones. The facets now narrow the chain list that every surface reads. The rail's routine focus slides in and out like the column beside it.
- **Activity's rail can focus one routine, and says what each row is (#2998).** Picking a routine's row narrows the rail to that routine and lists its runs by day with time and outcome. The status rows and time range apply to those runs, and a run opens beside the list. Every row now leads with **Routine**, **Issue** or **Agent** before what started it.
- **Agent work started outside a routine is in Activity (#2993).** A delegation from a chat, an issue mention or lead planning was missing from the chain index. A root assignment is now a chain of its own (`kind: assignment`, grouped by the stored `chain_origin`), with outcome counts, its agents and the issue it was for. It is listed only for people who may read the chat it came from, or, for issue work, for trusted members. Activity shows it as a row titled by its task and opens a work page with its delegations and asks; `crewship chain list` shows `work: <task>`. The chain index also attaches issues through `assignments.mission_id` for routine chains.
- **The Activity Bar speaks the rail's words, and ↑/↓ step between runs (#2988).** The toolbar dropdown says *waiting for you*, opens the run (**Decide →**, **Open run**) instead of the routine or a "trace", and lists cancelled and interrupted runs under Recent in grey with their own word. Cancel is offered only to OWNER/ADMIN, and the footer opens the waiting bucket when something waits. On a run's page, ↑/↓ move to the previous or next run in the rail.
- **The chain walk no longer shows inbox items outside the caller's audience (#2986).** `GET /api/v1/chains/{anchor}` returned every inbox item a run produced, including titles of items targeted at a higher role or another person. Inbox nodes now follow the `/inbox` rule. A hidden anchor is a 404, and the response declares that items were withheld without naming them.
- **The chain walk follows links it missed (#2986).** These are issue ↔ assignment through `assignments.mission_id`, issue → run through `issue_executions`, run → the issue it created (`missions.author_run_id`), and `run_needs_human` asks for routine runs and issue work. Activity's run page lists created issues from the walk, with no five-ref cap. The link contract is `docs/specs/activity-links.md`.
- **Activity's issue page shows the issue's whole history (#2983).** Events, comments and runs are read directly by issue, each with its own paging, and merged newest first with Load older — instead of being derived from the loaded page of chains and their five capped issue refs. `GET …/issues/{identifier}/events` gains `before_seq` + `limit` for backward pages (`crewship issue events --before-seq --limit`), and the issue endpoints also accept the issue's id.
- **Cancelled and interrupted runs no longer read as finished (#2981).** The chain index (`GET /api/v1/chains`, `crewship chain list`) counts `completed_runs`, `cancelled_runs` and `interrupted_runs`. Activity has a **Stopped** status row, and a run's page says Cancelled or Interrupted; a stopped branch never hides running or waiting work. The CLI's STATUS column reads `waiting`, `FAILED`, `running`, `cancelled` / `interrupted` / `stopped` or `ok` instead of `ok` for everything that had not failed.
- **Activity reads like Issues and Routines and is about runs (#2979).** The tab strip above the page is gone; Work queue and Webhook deliveries are rail rows. The rail lists every run under the Routines status rows, titled by routine name, with Group by in place of the lens tabs. A row opens the run: status, Retry / Stop, the approval or why it failed, its steps with attempts, what it caused, what it is linked to and changed, and its routine's previous runs. The home is built from runs: what needs you (decidable for plain approvals), what is live and next, every run on its routine's lane, recurring failures, outcomes and the latest runs. The Inbox digest links into Activity.
- ⚠️ **Behaviour change: the Journal page is shown to workspace OWNER and ADMIN only (#2979).** Other roles are sent to Activity. The journal API is unchanged.
- **Journal streams stop after access is revoked.** Replay and live delivery recheck account suspension, workspace membership and the account-wide Guest boundary before sending entries; deleted workspaces no longer keep an existing journal stream active.
- **Stopping an idle agent succeeds instead of failing with `runtime stop not confirmed` (#2879).** `POST /api/v1/agents/{id}/stop` answers `200` with `outcome: "already_stopped"` when the server establishes nothing is running (no invocation owned by the daemon, a readable run store, and no non-terminal run record for the agent), and `outcome: "stopped"` when it ended a run. A refusal is still `502` and now carries a stable `code`: `stop_not_confirmed` when a process may still be live, `runtime_unavailable` when the runtime could not be read. `crewship agent stop` prints `was not running; nothing to stop` for the first and a next step for each refusal; the web Stop buttons word the refusal by its code and the agent page says "Agent was not running".
- **An agent's restricted client execution can be changed in the web app again (#3028).** Edit agent › Model and execution has the Restricted client execution field; the change is part of the dialog's draft and applies on Save, after the agent. It had no UI since #3008. The unused Admin memory-configuration card is removed: Admin › Data retention › Memory versions edits the same setting.
- **Opening chat, a crew or an agent no longer writes the agents' avatars (#2876).** Viewing an agent without a stored avatar render used to send `PUT /api/v1/agents/{id}/avatar` from the viewer's browser — refused for viewers, members and restricted members, noise in access logs for everyone, and whoever looked first decided the stored face. Rendering is now read-only. The render is stored when an agent is created or edited in the dashboard (the agent editor, the avatar picker, a crew's avatar style, a crew created from a template). ⚠️ **Behaviour change:** existing agents and agents created through the CLI, API or Captain no longer fill in on their own; store them with **Settings › General › Agent avatars › Store missing avatars** (admins) or the same button beside a crew's **Avatar style** (managers and up). Until then they are drawn from their seed, as before.
- **Settings and Admin read as one product (#3022).** A refused switch in Access & Secrets or Hooks flips back and says why in the bottom-right toast instead of a line in the card. Every field, select and picker has the same size as its neighbours; supporting text (row descriptions, hints, empty states) is 12px instead of 11px and nothing is set below 11px; every table uses one header, cell and row style; person status, Keeper decisions, "No owner" and "Off" are status pills.
- **Open-source license capacity showed inactive limits.** The license API, administration and CLI now report unlimited crews, members and agents, including when a signed license contains historical caps. Signed claims and enforcement hooks remain available for future releases; administration explains that resource licensing may change.
- **A workspace can have a logo (#3005).** Settings › General › Identity has a Workspace logo row (Upload, Change, Remove; PNG, JPEG or WebP up to 2MB, the same rules as a profile picture), and `crewship workspace logo set <file>` / `remove` do the same. The workspace switcher and Admin › People draw the logo instead of the initial. API: `POST`/`DELETE`/`GET /api/v1/workspaces/{workspaceId}/logo`; setting or removing it is `ADMIN+` and audited.
- **A project's detail saves through the page's floating Save bar, and a bulk status or priority change asks first (#2984).** Name, status, priority, health, lead, dates, icon and colour are held as a draft until Save sends them in one request; clicking away from the name keeps it, and stepping through dates no longer writes each day. Setting several issues to a status or priority from the list now confirms, naming the change and that automations reacting to a status change may run.
- **The Pages editor saves through the floating Save bar (#2984).** The Content card (name, description, icon and colour) is a draft until the bar's Save; its own Save button is gone, a refused save is a corner toast that keeps what was typed, and leaving the editor with edits still asks once — Discard now drops the draft too. The Panels document, Access grants and publishing keep their own explicit actions.
- **Editing an agent no longer changes who pays for it or how it learns behind your back (#2984).** In the agent Edit dialog the provider account ("Pays with") and the learning posture were written the moment they were picked; they are now part of the draft, count as unsaved changes, and are applied when you choose Save changes, after the agent itself. Closing without saving leaves both as they were. The unused save-per-field editor that duplicated the dialog's sections was removed.
- **Issue edits wait for the Save bar (#2984).** On the issues page and /issues/<id>, changing a title, description, status, priority, assignee, date, estimate, project, milestone, routine or labels no longer saves on the spot: the floating bar counts the changes and one Save sends them together. A status of Done, Cancelled, Duplicate or Review, or a new assignee, asks first and names the automations it starts; the description no longer saves itself while you type, and a title edit is kept when you click away. Opening another issue with edits pending asks first.
- **Admin › Backups no longer lists every empty personal workspace as a problem (#2990).** Workspaces that hold no crew are summed up in one Needs attention item ("4 workspaces without crews have no backup") instead of two rows each, get no coverage row, and the summary counts them apart. The overview response carries `crewless_workspaces`.
- **Integrations: a connector's command, URL and environment wait for Save (#2984).** Editing an MCP server's name, command, arguments, URL, transport or environment variables no longer saves on blur; the edits join the page's floating Save bar and one Save sends them together. Collapsing the connector with edits pending asks first. Tool switches, webhook and notification toggles still apply at once.
- **An invited person no longer gets an empty workspace of their own at signup (#3006).** Signup redeems the address's live invitations first; when it joins at least one workspace, no "<name>'s Workspace" is created, and the person lands in the inviting workspace. A signup with nothing to redeem, or only invitations to deleted workspaces, still gets its own workspace. Existing workspaces are untouched.
- **Admin › Backups: the side panel shows only what applies to the page (#2990).** The scope appears where it changes what is listed (Overview, Backup history, a new restore), the workspace list only once Selected workspaces is picked, and the run filters (result, kind, proof, when, each with the rows it opens) only on Backup history; below them sits the navigation. Workspaces without crews, such as the one every signup gets, fold behind "Show N without crews", and a workspace shows its logo when it has one (`GET /admin/workspaces` now returns `logo_url`).
- **Restore checks and the restore itself judge a target by one rule (#2990).** The checks used to approve targets the restore then refused — a crew target for a workspace backup, replacing a workspace from a custom or crew backup, an empty server or drill for a non-instance backup — and neither looked at the new name. Both now share `ValidateRestoreTarget`: a new workspace or crew name must be a valid slug and free on this server, deleted workspaces included; a taken name is refused before anything is written (`409` from the restore). `restore/checks` and `crewship admin instance backups restore-checks` take the new name (`as_workspace` / `as_crew`, `--as-workspace` / `--as-crew`).
- **A backup plan over several workspaces no longer reports success while one of them failed (#2990).** The plan's `failed` and `stale` incidents clear, and the heartbeat is pinged, only once every run of that due time (or manual start) has finished and none failed, was interrupted or was skipped. Before, the first workspace to finish well resolved the incident and pinged the heartbeat, hiding a failure in another workspace or pinging while it still ran.
- **Admin › Backups no longer shows a partial restore as finished (#2989).** Recovery now shows the server's own verdict and names what did not land: missing attachments, crew files, rows short per table, incomplete items, clamped credentials and dropped columns, and says when crew files still have to be brought back into the containers.
- **Settings and Admin save through one floating bar (#2984).** Edits on any card add up in a bar at the bottom of the page ("3 unsaved changes · Discard · Save", ⌘S / Ctrl+S) instead of a Save button per card. Leaving the page or switching section with edits pending asks first, and a failed save is a toast in the bottom-right corner that keeps the edits and offers Retry. Switches still save at once; changes across several workspaces still go through their preview.
- **Routine HTTP results now redact injected credentials, including JSON and URL-escaped values.** Redaction applies before response bodies and request errors reach step results, run history or broadcasts.
- **Generated clients described incorrect crew provisioning responses.** OpenAPI now matches the status fields, managed tool/launch artifact metadata and optional build progress, documents provision/rebuild success as 202, and includes rebuild admission errors and conflict diagnostics. ⚠️ **Specification correction:** generated clients no longer expose `crew_id`, `phase`, `updated_at` or trigger `success`, which these handlers never returned; regenerate clients to adopt the corrected contract. HTTP behavior is unchanged (#2897).
- **Page rejections show their reason in the web app and CLI.** A 422 page rejection (for example a payload over the size cap) now also carries an `error` field with the same sentence as `message`, so the web app shows that sentence instead of "Request failed (HTTP 422)" and the CLI prints `API error (422): <sentence>` instead of the raw JSON body. The existing `rejected`, `kind`, `detail` and `message` fields are unchanged.
- ⚠️ **Behaviour change: routine authoring and validation now reject unsupported transform expressions, including skipped branches.** Existing definitions must be corrected before re-saving or draft testing; there is no automatic rewrite. Running an existing definition still skips inactive branches, while unsupported expressions reached at runtime fail. Use code for arithmetic or pipes. Whitespace around array indices remains supported.
- **Approval waits now honor the documented `wait.timeout_sec` setting.** A positive step-level `timeout_seconds` takes precedence; parked waits keep their recorded deadlines.
- **Webhook deliveries with invalid form inputs now return `400` before acceptance.** Malformed target definitions return `409`. Corrected retries can use the same delivery key. Signed, rate-limited validation failures count toward webhook delivery failure health and can aler