Repository navigation
Releases: SpicyDaemon/OpsMender-AI
Release list
v1.2.0
[1.2.0] - 2026-10-17
Fixed
- With several app instances behind a load balancer, or scheduler replicas
in distributed mode, a due audit schedule ran once per process and every
process probed every SLA target. A due audit schedule is now claimed with
one row update before it runs, a claim lasts one interval and the run
releases it; each SLA target's poll is claimed the same way, so every
job runs once across all processes and a process that dies mid-run hands
its job to another after the interval. The admin guide says how many
replicas may run (any number; SQLite serves one process).
Security
- AI Sessions now mark alert text, incident descriptions and tool output as
data in every prompt that carries them, with one plain rule that such text
is never an instruction. Credential-shaped strings in tool output (keys,
tokens, private keys,password=values) are redacted before the model,
the session record and any ticket see them. An alert whose text addresses
the assistant ("ignore your instructions", "as the AI, run") is flagged on
the incident and in the audit log at intake and never acted on; what a
session may do is still decided by the tier gate alone. A corpus of
injected alerts proves the gate blocks or asks for approval at every tier. - A model config whose saved key setting is not a variable name (a key
pasted before such values were refused) is now listed without it, for
every role, with anot a variable name: edit this confignote on the
Models page; the server logs the config ids at startup, never the values. - Skill Studio no longer suggests
safefor a tool whose name starts with
explain: anEXPLAIN ANALYZEruns the statement it explains, so such a
tool is suggested ascautionfor review. - An identity provider that publishes a single bare key instead of a key
set no longer ends a sign-in as a server error when that key does not fit
the id token; the sign-in is refused like any other bad token. - A model's key setting must now be the provider's own variable
(ANTHROPIC_API_KEY,OPENAI_API_KEY,AZURE_OPENAI_API_KEY) or one the
server operator lists inOPSMENDER_MODEL_KEY_VARS, and the providers with
a fixed host (anthropic,openai,azure_openai) refuse a base URL
anywhere else. Before, an admin could name any variable the server holds,
the token signing secret included, and pair it with any URL, so a model
setting could send that value to a host of their choosing. The free-URL
providers (ollama,openai_compatible) keep any URL but may only use
listed keys. Model configs saved before this change keep working until
edited. - A local (stdio) MCP server now receives only PATH, the OS basics and the
variables its own configuration names. Before, it received every variable
of the app, so a server (and through it an admin) could read the token
signing secret or the database URL. A server saved before this change
keeps receiving everything until an admin saves it again, which the MCP
page points out; a server defined inOPSMENDER_MCP_SERVERS_JSONinherits
only with"inherit_env": true. A server that needsKUBECONFIGor
AWS_PROFILEgets it named in its variables.
Changed
- The MCP SDK moves to 1.30.0, and CI's audit no longer ignores its
advisory. A remote (SSE or HTTP) MCP server is now followed through a
redirect only within its own scheme, host and port; any other redirect
fails the connection with a message naming the other origin, so an
admin enters that URL if it is the server they mean. - Every workflow runs on the Node 24 releases of its actions (checkout v7,
setup-python v7, setup-node v7, upload-artifact v7, download-artifact v8,
action-gh-release v3, codeql-action v4, setup-uv v10.3.0 (it publishes no
moving major tag), upload-pages-artifact
v5, deploy-pages v5, setup-buildx-action v4, build-push-action v7, and
trivy-action 0.36.0 whose own steps run on Node 24), and the repository
carries.nvmrc(24) beside the frontend'senginesfield, so Node 24
is the minimum everywhere.
v1.1.2
[1.1.2] - 2026-10-16
Security
- While a person's temporary password must still change (a new account an
admin created, or a temporary password an admin set), their session can
only read their own profile, change the password and use MFA. Every other
API call from that session, creating an API token included, answers 403
withpassword_change_required, their live streams are refused, and an
open dashboard tab goes to the password change page. Before, only the web
app asked for the change, and the API served that session in full,
including creating API tokens. - Listing the Rosters a person leaves on demotion or deactivation now checks
that the person belongs to your workspace, like the other People routes
(404 otherwise). Before, it answered for a person of another workspace;
one instance runs one workspace, so this only mattered if a second
workspace row existed. - Model discovery (
GET /models) now accepts connection settings (a base
URL, a key variable, an API version, a region, a profile, a project or a
location) only from admins; every other role, and their API tokens, gets
403before anything is read or called. Before, any signed-in user, a
Viewer included, could name an environment variable and a URL, and
OpsMender sent that variable's value to the URL as a bearer key, which
could expose the token signing secret, the database URL or a provider key.
A model's key setting must now be written like an environment variable
name (letters, digits and underscores, not starting with a digit);
discovery and the model save routes refuse anything else with400
before reading or storing it, without repeating it. Settings saved before
this change are not rewritten. An unknown provider in discovery answers
400instead of a server error. - The generic command guard now also catches common runner names:
terminal,
console,tty,pty,shellexec,bash_tool,invoke_expression,
subprocess,popen,os_system,sudo,su,docker,podman,
nerdctl,crictlandsystemctl, names that start withbash_,
powershell_,pwsh_,sh_,terminal_,console_,sudo_,docker_
orsubprocess_, and names that end with_terminal,_console,_bash,
_powershell,_pwsh,_subprocessor_cypher, in any case or separator
style (Terminal,BashTool,bash-tool,PowerShellExecute). It also
catches the runner tools of common MCP servers, such askubectl_generic,
call_kubectl,call_aws,execute_kubectl,ssh_execute,
start_process,execute_code,browser_run_code_unsafeand
explain_sql_statement(which runs the statement when it analyzes it); the
MCP Skills page lists all of them and the bounded tools to classify in a
Skill instead. Before,terminal,
shellexec,bash_tooland the like were ordinary tools, so a Skill entry
or glob that allowed one let it run at Tier 0, without approval at Tier 1,
and in environment scans. Now they are blocked at Tier 0 and Tier 2 and in
environment scans. At Tier 1 they ask for operator approval, and run once
approved, even where the Skill blocks them: the guard is checked before a
tool's own tier policy, so a T1 policy ofblockedoradvisory, or no
entry for the tool, no longer refuses it. To block one at every tier, add it
to the Skill's deny-list withdeny: true. A narrowly scoped tool that a
new prefix or suffix catches, such asdocker_logs,console_url,
get_consoleoraws_console, needs an entry with its exact name and
allow_generic: trueto run under its own tier policies again. Skill
Studio's Generate from tools and AI assist now mark these names as generic
and pre-set them to deny, as they already did for the older runner names. - OIDC sign-in and Teams actions now name the signature algorithms they
accept. An identity provider's id token must be signed with an asymmetric
algorithm that its discovery document lists (RS256 when it lists none), and
a Teams action with RS256, the algorithm Bot Framework signs with. Before,
both checks used whatever algorithm the token named (python-jose advisory
GHSA-3qf3-8w2g-rqmx), and a token naming HS256 ornonecaused a server
error instead of a refusal. An identity provider set to sign id tokens with
HS256 (the client secret), or with an RSASSA-PSS algorithm (PS256 and up)
that the token library cannot verify, is now refused with a clear message;
set it to RS256 or ES256. Both checks also try only the published keys
that can verify the token (only those with its key id when any key has
it), so a key set that lists an EC key before the RSA key, or holds a key
that cannot be used, no longer refuses a valid token. - The web app is now built with Next.js 16.4.1 (from 16.2.3) and tested with
Vitest 4.1.11 (from 3.2.4), which carry the fixes for the published
advisories against both, including three Next.js advisories from
2026-10-14 that 16.4.0 does not fix. None reached a running OpsMender: it
serves a static export with no Next.js server or image optimizer. The
locked Mako moves to 1.4.3. - Every pull request and release now audits dependencies: the web app's
runtime npm packages fail the check on a high or critical advisory, and
the installed Python packages fail it on any known advisory (checked
against OSV). Three advisories are ignored because they do not apply:
GHSA-3qf3-8w2g-rqmx in python-jose (every token check names its
algorithms), GHSA-wj6h-64fc-37mp in ecdsa (it affects signing, which
OpsMender never does with ecdsa) and GHSA-84m7-p3x7-pcfv in the MCP SDK
(it affects MCP servers; OpsMender only connects to them as a client).
Fixed
- Assigning an incident to someone else, and bulk reassign or bulk
acknowledge for someone else, now refuse the change when the incident's
owner changed after the request was checked, naming the current owner if
there is one (409, or that incident's failure in a bulk action); nothing
is written. Before, an assignment that arrived a moment after someone took
the incident replaced them without a note or an Inbox notice. An
assignment that arrives as the incident is resolved or merged is refused
the same way; before, it answered a server error or reported success. - Alert intake refuses a body whose objects and arrays nest more than 64
levels deep with400and opens no incident; the token's delivery log keeps
a short row naming the limit, never the body. Every other route refuses a
JSON body nested more than 64 levels with400before the route acts on
it, and the Teams, Discord, Slack and ticket webhooks, which read their own
bodies, refuse one too deep to read with their usual400. A token nested
too deeply to read (a session, an MFA challenge, an SSO or bot sign-in
state, a voice link or a Teams token) is refused like any bad token.
Before, intake accepted and stored deeply nested bodies and failed with a
server error on the deepest, and a deeply nested body or token sent to
other routes, such as saving My Routing settings, failed with a server
error, sometimes after the value was saved. - On SQLite, the standalone binary's local database, identical alerts that
arrive at the same moment now open one incident and page once: the app takes
incoming alerts one at a time inside its process. Before, each alert could
open its own incident and page again. Run one app process per SQLite
database; several processes need PostgreSQL. - Inbox quiet hours and My Routing quiet hours are now saved separately, and
saving one page never changes the other. Before, both pages wrote one
shared setting: saving the Inbox notification preferences, even just a
category mute, turned off the quiet hours that hold back P1 pages, saving
My Routing turned off Inbox quiet hours, and after any Inbox save, Save
routing failed with "[object Object]". A save the server refuses as
invalid now shows the reason, in My Routing and the other pages. Through
the API, Inbox quiet hours are underrouting.in_app.quiet_hoursof
/users/me/notification-preferences, and itsquiet_hoursis My
Routing's only. Upgrading moves saved Inbox quiet hours to their new
place; SQLite evaluation databases are not migrated, so set Inbox quiet
hours again there. - Reloading the Reliability page, or following a link out of the app, while
it is still loading no longer logs "Failed to load reliability data" in the
browser console: the browser cancels the page's requests then, and a
cancelled or aborted request is not a failure. A load that really fails is
still logged, also after you move to another page of the app. - Saving My Routing through the API with only one of the Inbox settings
underrouting.in_app(a category mute, say) no longer drops the other
(the Inbox quiet hours); the settings are merged with what is saved. The
My Routing page never sends them, so this only affected API calls.
Changed
- The People guide now says what a Viewer sees: in the web app the Dashboard,
the incident list and each incident's summary, the On Call Schedule,
Activity, their Inbox and their own profile; through the API also the lists
of Escalation Chains, Rosters, teams, services, memories and more, but not
incident timelines or comments, reports or analytics. A Viewer can't list or
open AI sessions or read their chat history, but sees each session's tool
calls in Activity and its proposed actions in the approval list, can read
which memories a session used, and can follow a running session's live
stream, chat included, if they know its id. What a Viewer can open is
unchanged; tests now hold the sidebar, the page guard, these API answers and
the session content a Viewer reads to it. Before, the Auth guide said
Viewers could read sessions and the People guide didn't say what a Viewer
could open. - The two quiet-hours settings now s...
v1.1.1
[1.1.1] - 2026-10-10
Security
- Authorizing an HTTP MCP server no longer puts the PKCE verifier or the
client secret in the authorization link: its state is now a random,
single-use reference to the request, which stays on the server and
expires after 10 minutes. A restart during consent means starting the
authorization again. - When several globs in an MCP Skill match a tool, the strictest one now sets
its policy whatever order they are written in; before, the first listed
won, so a broad allow written first let a narrower blocked tool run. The
generic command guard also catches runner names in any case or separator
style (run-command,kubectl-exec,ExecuteCommand) andpython_repland
code_interpreter. Review skills that relied on a broad glob listed first. - SAML and OIDC sign-in now refuse a deactivated account before signing it
in, and change nothing about it. Before, the sign-in issued a token that
was refused only on its first use. - WeCom and Weixin updates are checked against their signature before
OpsMender decrypts or reads them, and a malformed body gets 400 instead of
a server error. Before, WeCom updates were decrypted without checking the
signature. - The Inbox and notification settings refuse API tokens, like the other
personal settings. - Open live streams of an AI session or the Inbox now close within about 15
seconds after their account is deactivated or its password changes, and a
session stream serves only sessions in your own workspace. Before, a
stream checked the account only when it opened. - Starting an AI session with no incident is now for admins only, including
through API tokens; operators got it before. Forcing a session past its
model's limit stays with the incident's owner and admins. - Viewers and viewer API tokens no longer receive credential values from SLA
probe targets or model configurations: probe URLs and model base URLs show
without user names, passwords, query strings or fragments, and probe
headers, bodies and other settings are left out. Exporting the Activity log
as CSV is now for admins and operators; Viewers still read the Activity
page, which the dashboard now opens to them (before, it said access denied
while the API answered). If a probe URL or model endpoint carried a token,
rotate it. - Workspace settings, invite and People routes now check that the workspace
and person named in the request are your own workspace and its members
(404 otherwise), and OpsMender never creates a second workspace. Before,
an admin could read and change any workspace or person by id, including
reset links and temporary passwords; one instance runs one workspace, so
this only mattered if a second workspace row existed. - Nobody can change their own role or deactivate their own account, including
through their API tokens; another admin can. Before, the only admin could
demote or deactivate themselves and leave nobody able to sign in as admin. - A password change now revokes every API token the person created: their own
change, an admin's temporary password and a reset link. The tokens return
401 at once and show as revoked, each with an Activity entry. Before, a
reset account kept working through its tokens. Create new tokens after a
password change, including for automation an admin set up. - Intake refuses alert bodies over 1 MiB with
413before reading them in
full, including bodies sent without a length; set
OPSMENDER_INGEST_MAX_BODY_BYTESto change the limit. Before, a body of any
size was read and stored whole in the ingest log. The token's delivery log
keeps a short row with the size and the limit, never the body. - MCP server credentials are now shown to admins only. Before this change
every signed-in account and API token, Viewers included, could read each
saved MCP server's command, arguments, URL and environment values, and the
last connection error, from the server list; Operators could also read the
launch details of servers configured in the environment from Settings.
Others now see the name, transport, state and environment variable names.
Rotate any credential stored in an MCP server's environment values,
arguments or URL, since any account could read it.
Added
- Operators can create, see and revoke their own Operator API tokens from
Profile. Admins still create any role from Settings and see everyone's. - Operators can open the Memories page. It lists global memories and their
teams' memories, with a Team column (Global for global memories) and a team
filter; operators edit or delete only their teams' memories. - Hand several incidents to another team at once from the incident list
(Actions > Hand off to team), with one required note. Each incident keeps
its service and gets the note on its timeline; if any can't be handed off,
none move. - Operators can ask someone from another team to join an incident as a
responder. The person gets an Inbox notice and an email naming who asked,
and only they accept or decline from the incident page. A pending request
holds one of the three responder slots until it is answered, expires after
30 minutes or the incident closes, and the requester learns the outcome.
Removed
- Memory feedback: the thumbs on the Memories page and in a session's
Memories used panel,POST /memories/{id}/feedback, and the
helpful_countandunhelpful_countfields of memory responses. Recall
ranking and eviction no longer weigh old feedback; pinned memories are
still never evicted.
Fixed
- The API's OpenAPI document now reports the installed version (
1.1.1), the
same oneopsmender --versionprints; it said0.2.0whatever the release. - The models and the database migrations now describe the same schema. On
PostgreSQL, the names of ingest tokens, MCP servers, model configurations,
skills, SLA targets and workflow profiles are unique per workspace, as the
models already said, and the models declare the JSONB columns and indexes
the migrations create. Saved data doesn't change. CI now fails a change
whose models and migrations disagree. - Scheduled reports keep their day and local time. A monthly report set
for the 31st runs on the last day of shorter months and returns to the 31st
(before, it moved to the 28th for good after February), and a weekly 09:00
report stays at 09:00 in its time zone when the clocks change (before, it
ran at a fixed UTC time and moved an hour). Existing schedules keep their
next run's day and time, in UTC. - Identical alerts that arrive at the same moment now all get a normal
answer and open one incident; before, all but one could fail with a server
error on PostgreSQL. Two Takes at the same moment on an incident without
an Escalation Chain now leave one owner and give the other the usual 409
instead of a server error. - An operator's Maintenance Window now lasts at most 24 hours, tells the
admins and the covered teams in their Inbox when it becomes active, and can
be edited, ended early (End now) or deleted by the operator who created
it; other operators can't, and only an admin changes what it covers. Before,
it could last years, told nobody, and its creator couldn't end it. - Taking someone off a Roster no longer moves everyone else's shifts. Removing,
deactivating or demoting a member to Viewer now keeps their place in the
rotation, and its shifts go to the next member. Before, the rotation was
recounted, so other people's shifts moved, the current one included.
Demoting someone to Viewer now takes them off every Roster, as deactivation
does (before, they stayed on it and paging skipped them), and both
confirmations list the Rosters and who takes the current shift. - Deactivating someone or making them a Viewer now stops their remaining
notification stages at once; before, their My Routing stages kept arriving
on incidents they could no longer act on. No stage is sent to anyone who
isn't an active admin or operator. Someone paged after an incident has an
owner (a responder added later, or Escalate now while the owner keeps it)
now gets only the first stage of their plan instead of every stage. - The next Escalation Chain level no longer pages before the people the
current level paged have had all their own notification stages. A level
escalates at the later of its timeout and the end of everyone's stages plus
an answer window (the last stage's wait; none if that stage couldn't be
sent), unless someone acknowledges. Someone with no stages saved, or who is
no longer an active admin or operator, holds nothing: the level timeout
alone decides. The wait for people's stages ends at most 10 minutes after
the level paged for P0 and P1 incidents, and 20 for P2 and P3; a longer
level timeout still applies. New levels and new My Routing stages wait 3
minutes (new levels waited 5 before), so with three stages at the default
wait, levels fire 9 minutes apart. My Routing shows the last stage's wait
as the answer window and warns when a priority's stages and answer window
take longer than that priority's limit; the chain editor's Preview timeline
shows each level's earliest time. - A recovery that arrives during a Maintenance Window now closes the incident
it clears, stopping its Escalation Chain and AI session without paging
anyone. Before, the window dropped it with every other alert, so an incident
opened before the window stayed open. New alerts in the window are still
dropped. - Deleting an incident also deletes the incidents combined into it, including
ones combined into those, and Activity records each with the incident it
was combined into. The delete confirmation lists them first, on the incident
list, in bulk and on the incident page. Before, they stayed behind with no
incident to point to, and their alert was swallowed when it fired again: it
no...
v1.1.0
This release makes OpsMender useful without an MCP server, gives skill authors a proper workbench, and lets Discord users act on incidents without leaving the channel.
What's new
Sessions without MCP. A service covered by native integration connectors can now run an AI session with no MCP server configured. Integration tools pass through the same tier gate, approvals, and audit log as MCP tools. If nothing provides tools for a service, the session says so and stays advisory rather than failing.
Skill Studio for either source. Skills can bind to an MCP server or to a native connector. Start from a template, discover the tools the source offers, validate the file before saving, and see exactly which operations changed and where permissions widened. Policy you write can make a connector stricter than its baseline but never looser.
Discord incident actions. Acknowledge, resolve, escalate, or start an AI session from a Discord message. Every button press is signature verified before it is parsed, matched to a linked account and its role, checked for replays, and written to the audit log.
Also in this release
- The setup checklist and service toolset views now treat an active native integration as a valid tool source.
- Native actions refused before admission are now recorded in the audit log.
- The showcase site dropped its roadmap section and got new landing copy.
Downloads
Linux x64 and Windows x64 binaries are attached below with SHA256 checksums, along with a source archive. Both binaries report 1.1.0.
The full list of changes is in CHANGELOG.md.
v1.0.0
[1.0.0] - 2026-07-11
Added
-
MCP Skill free-form instructions. Custom Instructions now reach every
model-driven incident stage. OpsMender parses and preserves per-tier
Markdown, injects only the active tier's guidance, and keeps structured tool
policy, deny lists, approval requirements, and backend guardrails
authoritative. -
Deterministic autonomy demonstrations. The demo seed now includes
self-contained Tier 0 autonomous remediation, Tier 1 approval-gated, and
Tier 2 advisory-only sessions with persisted workflow and audit events; the
README screenshots show each policy producing a distinct outcome without a
live model or network dependency. -
Standalone SQLite evaluation.
opsmender servenow initializes a local
SQLite schema from ORM metadata, stamps it at the bundled Alembic head, and
starts in development mode for a zero-PostgreSQL product trial. The
PostgreSQL production migration path and migration-skip flag remain intact. -
Release verification gate. Added reusable pull-request and release-tag
verification for backend lint/tests, empty-Postgres migrations, frontend
lint/typecheck/tests/build, and a container health smoke test. Backend tests
now deselect live integration cases and enforce a 180-second per-test timeout. -
Platform-neutral health probes. Added dependency-free
/health/liveand
role-aware/health/readyendpoints with database and migration checks, while
retaining/healthas the backward-compatible liveness alias. -
Simplification sprint — Phase 5 Voice & SMS calling. Added admin
Settings for workspace Voice/SMS calling, with encrypted auth-token storage,
DB-over-env resolution, availability for My Routing, and disabled
Voice/SMS routing options when calling is not configured. -
Noise and analytics sprint — Phase 0 tier clarity. Approval rows now show
the requesting session tier, the demo seed separates Tier 1 approval-gated
sessions from Tier 2 advisory blocking, and team-scoped maintenance windows
mark status-page components as maintenance. -
Noise and analytics sprint — Phase 1 alert-noise intelligence. Services
now support inherited/on/off similar alert grouping, grouped Incident badges,
flapping detection with P0 safety behavior, and workspace default controls. -
Noise and analytics sprint — Phase 2 analytics. Added read-only Noise
and Response analytics APIs with CSV export plus a dashboard Analytics page
for alert volume, noise reduction, MTTA, and MTTR trends. -
Noise and analytics sprint — Phase 3 API tokens. Added named,
revocable, role-scoped REST API bearer tokens with Settings management,
one-time secret display, audit attribution, and self-service denylist
protections. -
A+ closure sprint — final audit proof. Added
scripts/live_update_proof.mjs, a Playwright two-context acceptance script
that proves the dashboard's live incident refresh updates within the
two-second budget with one notification WebSocket and no skeleton flash.
Sprint-end re-grade remains GATE PASS 0/0/0.
Changed
-
Production configuration validation. Production startup now rejects
placeholder secrets, non-PostgreSQL database URLs, weak configured bootstrap
passwords, and invalid autonomy tiers, with warnings for wildcard CORS,
missing public URLs, and enabled API documentation. -
Simplification sprint — Phase 3 Models. Services now expose their
service-specific model list as Models, backed byservices.model_config_ids,
and the session model picker is restricted to active service Models plus the
workspace default model.
Breaking
-
Explicit Skill tier policies. Every executable Skill operation must now
declare complete T0/T1/T2 behavior; underspecified runtime policies fail
closed and deny entries remain unconditional. Existing stored and imported
classification-only operations are deterministically upgraded to the prior
conservative behavior and surfaced for operator review. -
Simplification sprint — Phase 4 MCP servers. Service MCP server lists are
now strict allowlists, backed byservices.mcp_server_ids; empty service
lists and sessions without a service get no MCP tools instead of falling back
to any configured server.
Removed
-
Workspace Status Page. Removed the public/private Status Page feature
entirely — the/statuspage, the Settings section, the per-incident status
update publishing, thestatus_page_*tables and Organization columns, and
the related API. Stakeholder communication is served by scheduled reports; the
separate Atlassian Statuspage integration connector is unaffected. Migration
n1o2p3q4r5s6drops the tables and columns (downgrade recreates them). -
Simplification sprint — Phase 1 Agent Teams. Removed Agent Teams from
the API, database model, Settings, session start flow, and AI workflow
runner; sessions now use the single-agent path by design. -
Simplification sprint — Phase 2 Session workflow. Removed the Session
Profiles page and per-session profile picker; admins now manage one
workspace-wide Session workflow from Settings, and every new AI session stamps
that default workflow configuration.
Fixed
-
Session notification task lifecycle. Scheduled session chat
notifications are tracked in the application background-task registry so
shutdown can drain them cleanly and session-state transitions cannot race an
unmanaged SQLite read transaction. -
Role-aware dashboard loading. Viewer and operator dashboard routes no
longer issue requests their roles cannot make, while workspace branding is
readable by every member and protected mutations remain admin-only. -
Session audit history and approval layout. Completed and paused sessions
hydrate their event streams from persisted audit entries, the desktop work
area retains usable height as context grows, and approval actions fit within
the table at supported desktop widths. -
Integration and notification-channel brand icons. Restored the ServiceNow
mark in the integration catalog; added recognizable Microsoft Teams,
Lark/Feishu, DingTalk, and WeCom marks to the notification-platform picker;
and replaced the monochrome Slack glyph with its official four-color mark. -
A+ closure sprint — A-8 README screenshot set. The screenshot capture
helper now uses the design-audit credential pattern with environment
overrides and.envbootstrap fallback, captures the four launch README
surfaces intosite/public/screenshots/, refuses to capture an empty
approval inbox, and the README now embeds the current screenshots with
product captions. Skill parsing now fails closed on non-mapping YAML roots so
malformed skill records cannot 500 session-tier resolution. -
A+ closure sprint — A-9 motion micro-polish. Toasts now ease in with a
short fade/rise and fade out before removal, shared modals open with a
conservative backdrop fade plus panel fade/scale, andglobals.cssnow has
a globalprefers-reduced-motion: reducekill-switch for existing and new
animations/transitions. -
A+ closure sprint — A-6 command-palette incident search. Cmd/Ctrl+K now
debounces incident search throughlistIncidents({ q, limit: 5 }), renders
an Incidents section with severity badges and relative created times, drops
stale responses, fails silently, and lets keyboard selection traverse static
nav/actions plus incident hits as one list. -
A+ closure sprint — A-5 memory severity tags. Incident memory severity
tags now canonicalize toseverity-<level>across recall derivation, LLM
writeback, manual memory create/update, and postmortem memory extraction;
an Alembic data migration normalizes existingincident_memories.tagsrows
while preserving order and deduping duplicates. -
A+ closure sprint — A-4 Activity grouping. Activity now defaults to
collapsible session groups with short session IDs, View session links, time
spans, entry counts, blocked-count chips, grouped Search/Type/Tier/Status
filters, and a toggle that restores the previous flat DataTable with its
date range, column picker, expansion, and CSV behavior intact. -
A+ closure sprint — A-3 mobile approvals. Pending approvals now use
thumb-sized, full-width Approve, Reject, and Redirect actions belowsmon
the session-detail card and Approvals page; action JSON collapses behind an
accessible disclosure on mobile while reason and expiry stay visible, and
the Approvals page renders stacked mobile cards instead of the desktop
table. -
A+ closure sprint — A-2 dashboard onboarding. The first-run setup
checklist now lives only on the Dashboard, has a slim progress bar and
explicit "N of 5 steps" status, refreshes on focus/live events, silently
hides when unavailable or complete, and no longer duplicates itself on the
Incidents page. -
A+ closure sprint — A-1 live updates. Dashboard, Approvals,
Orchestration, Incidents, the notification Inbox bell, and the sidebar
Approvals badge now share one live notification WebSocket with
category-filtered, debounced subscribers; manual and fire-test incident
creation emitincident.createdin-app events so existing silent refreshers
update without loading flashes. -
UI/UX Polish sprint (design-audit remediation) — Phase C: Reliability
maintenance polish (P-15). Maintenance windows now cross-link to Paging
maintenance windows, explicitly note that they suppress paging too, and
populate the Targets column with "All Targets" or scoped target badges. -
UI/UX Polish sprint (design-audit remediation) — Phase C:
Settings/Profile (P-20). Settings now uses a compact pointer row for
Models, MCP Servers, and Notification Channels; Organization save is
bottom-right in its card, and the profile page is titled "My profile." -
**UI/UX Polish sprint (design-audit remediation) — Phase D...