- In-app update notice: a new
/api/v1/runtime/updateendpoint compares the running runtime against the latest published GitHub Release, and the console shows an update action beside the version number. A collapsed sidebar shows a marker on the app icon so a pending release is never hidden. - Automatic checks on macOS: the desktop app now checks shortly after launch and daily thereafter, where previously it checked only when the menu item was opened. A check that finds nothing stays silent, and each version is offered once.
- Relaunch after install: installing a package replaces the app bundle while the running window keeps the previous code. Enkstein detects that and offers to relaunch. Windows gains
Ctrl+Rto match the existing macOSCmd+R.
- Release publication: v0.8.1 never published because both architectures built serially on one runner with amd64 emulated, exceeding the job timeout. Each platform now builds on its own native runner and the manifest list is verified to contain both, so a missing architecture fails the release rather than shipping.
- Windows download link: the documented Windows installer link returned 404 because no release had completed since v0.8.0.
- Update checks read only public release metadata. The repository is validated before any request, and the endpoint is never given a caller-supplied URL.
- Existing installs at v0.8.3 and earlier have no notifier and must update once manually; v0.8.4 is the first release that announces its successor.
- Complete connected CoreOS coverage: prompts, writes, and commands evaluate every active policy across Global, Module, Connector, and Identity scopes while retaining priority order and first-match enforcement. Coverage counts are returned and written into the audit evidence.
- Complete private policy identity: the builder reads the numbered private policy modules directly, preserving all 60 IDs, names, severities, risk scores, and scopes. The current source produces 228 local rules without placing their expressions in the public repository.
- Safe correlation: policy IDs, fixed labels, lengths, and SHA-256 digests provide audit correlation without sending raw prompt, file content, command arguments, paths, or working directories to Trust Fabric.
- Signal-map fields cannot override tenant, actor, action, risk, classification, digest, or authentication context derived by the server.
- Private regex fallbacks were measured against the real source tree; LLM-context-dependent rules remain prompt-only, and deterministic credential/key families alone extend file and command scanning.
- Private policy packs: licensed detection content can be generated locally into
~/.enkstein/policy-packswith owner-only permissions. The public plugin contains the loader and policy contract, never the private expressions. - Prompt governance: the
UserPromptSubmithook stops detected credentials and sensitive records before they enter the model provider's conversation history. - Mask and continue: mask rules use the agent's supported
updatedInputchannel for file writes and commands, replacing the sensitive value while preserving paths, structure, and unrelated content. - Measured rule conversion: the private-pack builder can measure detections against real source trees, keeping prose-oriented rules out of file scanning when they would interrupt normal development.
- Built-in and private decisions combine with strictest-wins semantics; loading a pack cannot weaken Enkstein's local protections.
- A prompt cannot be rewritten by current agent hook APIs, so a prompt-scoped mask finding is held for approval instead of claiming the raw value was removed.
- Malformed packs and unavailable connected services do not brick the coding agent, while built-in scanning remains active.
- Enkstein Guard for Claude Code and Codex CLI: a plugin that enforces Enkstein policy inside the coding agent you already use. It runs before every file write and shell command, so an AWS key headed into a config file, a
curl … | sh, a recursive delete of a protected path, a force push, or a read of~/.aws/credentialsnever executes. The agent is told why and corrects itself. Installs with two commands and runs entirely locally — no account, no backend, no Docker. - Restraint is part of the design:
rm -rf ./build,git push --force-with-lease, and placeholder credentials in an.env.examplepass without comment. A guardrail that interrupts ordinary work gets uninstalled, so the pack deliberately declines to flag things that only resemble danger. - Local and server policy combine, strictest wins: setting
ENKSTEIN_API_URLadds tenant policy, approvals, and the console audit trail on top of local scanning rather than replacing it, so connecting a server can only ever increase enforcement. Blocked calls arrive in Events attributed to the agent and project that attempted them. - Findings never echo the secret: a blocked AWS key is reported as
AKIA3Z…OPAS— enough to locate it in the file, not enough to leak it into a transcript, a log, or the model's context.
- Empty databases are initialized before migrations run: the Alembic baseline revision is a no-op that assumes the schema already exists. On an empty database,
alembic upgrade headreached the first revision containing real DDL and failed, no migration version was recorded, and the seed scripts then ran without tables. The runtime now creates the schema first when the database is empty and stamps the migration state, allowing first-launch seeding to complete. - Failed requests no longer look like empty data: Policies, Connectors, Workflows, and Policy Packs now distinguish an API failure from a successful response with no records. Their empty states also no longer tell desktop users to run
docker compose execseeding commands by hand.
- Turns survive navigation: a governed turn is owned above the router rather than by the page showing it, so switching conversations or workspaces leaves it running. The sidebar lists what is still in flight with a live indicator whose shape reflects the stage the runtime actually reported, and each entry links back to its conversation.
- Every Brain's answer is kept: a Multi-Brain Swarm used to discard every answer but the winning one. Each Brain that answered now keeps its own card, with the one that became the reply marked as such, stored under the same encryption as the reply itself.
- Connector control scope: a connector now answers two separate questions from one binding — which controls it could ever produce evidence for, and which of those passed, failed, or were never assessed in this tenant. The second cannot live in a docs site, because only the deployment knows it.
- Remediation reflects assessment: the autonomous remediation view is synchronized with control assessment rather than maintaining a separate idea of what needs fixing.
- Cowork executors explain themselves: both executors report unavailable in two quite different situations — no project is open, or the open project has no approved folder — and both were described with the same sentence, blaming a project that in one case had not been selected. The two now read differently, the state is visible before a turn is sent rather than only while one runs, and approving a folder is offered as the fix where a folder is genuinely what is missing.
- A crash waiting in the Cowork runner: the Brain progress callback called a function that did not exist anywhere in the codebase. It only ran when a Brain reported progress, so it reached a release as a latent failure on real jobs. Progress is now buffered and recorded once the turn returns, matching how file progress already worked, and the runner is checked for unresolvable names rather than for one path.
- Drawers stopped rendering as embedded panels: Liquid Glass gives every card a backdrop filter, which silently makes that card the containing block for anything fixed inside it — so a drawer collapsed to the card's bounds instead of covering the page. Overlays now render against the document.
- Local folder status follows the conversation: it was keyed to the sidebar's project picker, so an open conversation belonging to another project could be described by the wrong folder.
- Liquid Glass has real depth: surfaces are layered rather than uniformly translucent, so what is above the page reads as above it.
- Longer Brains are given longer: one timeout covered hosted APIs, local models, and subscription CLIs alike, which cut off the slower two mid-answer. Each now gets a budget that matches how it actually works.
- The two unavailable states now read differently: with nothing open, Cowork asks for a project rather than blaming one. With a project open but no folder approved, it names the remedy instead of only the problem.
- Executor state is visible before a turn is sent: the Brain and Executor panel previously rendered only while a turn was already running, so there was nothing to read at the moment the choice is actually made. It now sits above the composer, with a Connect folder control that opens the same approval dialog — hidden when the desktop runtime itself is down, since approving a folder cannot help there.
- Auto is no longer presented as healthy when nothing can run: it is marked unavailable alongside the executors it would have selected.
- Local folder status follows the conversation, not the sidebar: it was keyed to the project picker, so an open conversation belonging to another project could be described by the wrong folder — the same class of mismatch already corrected for the file panel.
- Six backend tests covering both unavailable states, the actionable reason carried through Auto, and a down runtime still reported as a runtime problem rather than a folder one.
- Three interface tests covering the explanation, the offered fix, and its absence when a folder cannot help.
- All nine were confirmed to fail without the change, and all three states were reproduced against a live workspace before and after.
- Turns survive navigation: a governed turn is now owned above the router rather than by the page showing it, so switching conversations, switching workspaces, or moving to Security leaves it running.
- Running-elsewhere tray: the sidebar lists every turn still in flight with a live orb whose shape encodes the stage the runtime actually reported — waiting on a Brain looks different from writing files. Each entry links straight back to its conversation and can be stopped from there.
- Markers on the workspace switch: Chat, Cowork, and Security each carry their own marker: a pulsing dot while one of their turns is running, and a green dot once a reply is waiting. The marker clears when the conversation is opened, so a reply that arrived while you were away is never missed.
- A finishing turn no longer drags you back: the completion path unconditionally set the active conversation and pushed its URL, so a turn settling after you had moved on pulled you out of whatever you switched to. The transcript now updates only while you are still viewing that conversation; otherwise the tray reports it and the reply loads when you choose to return.
- A turn is started, the operator switches conversations mid-flight, the turn settles while they are elsewhere, and the persisted reply is still there on return — with exactly one governed submission, proving navigation never replayed it.
- The tray is absent when nothing is running, and stopping a background turn removes it.
- All three were confirmed to fail without the change.
MARCELLUS_CHANGES heading and an empty array printed underneath, after six of eight Brains reported themselves timed out. Three separate defects were involved.- Enkstein told the Brain to be brief while asking it to write a file: every local and API Brain shared one system prompt instructing it to “return a concise answer.” On a turn carrying the file-output protocol that is a direct contradiction, and models resolved it by declining to write the file and explaining the content was too long for a short reply — the exact wording seen on screen. File-authoring turns now get their own instruction stating that length is not a constraint and that a smaller number of complete files is always preferred over truncating one.
- The protocol block leaked into the visible answer: Enkstein recognized its change protocol as a fenced
marcellus_changesblock or as a bare label followed directly by JSON, but not as a label followed by an ordinary code fence — which is how providers commonly answer it. That form was treated as prose, so the heading and its array were shown verbatim. The label form now accepts an optional surrounding fence, and its real file entries extract normally. - Locally executed Brains were cut off too early: one 60-second budget covered hosted API calls, local Ollama profiles, and CLI-driven Codex/Claude subscriptions alike. A local model generating file content from a large project capsule routinely needs longer, so most of a swarm reported itself as timed out and the answer fell back to whichever Brain finished first. Locally executed Brains now get their own budget, still bounded below the outer turn deadline so a timeout is always reported rather than swallowed.
- Leak coverage: three label-and-fence variants must leave no protocol text in the reply, a fenced variant must still yield its real file changes, and ordinary prose naming the protocol must be left untouched.
- Prompt coverage: a reasoning turn keeps the concise instruction; a file-authoring turn never receives it.
- Timeout coverage: local profiles and CLI subscriptions must exceed the hosted-API budget, browser sessions must exceed both, and every budget must stay under its outer streaming deadline.
- All eight new tests were confirmed to fail against the prior code.
- Per-Brain answer cards: every Brain that answered now gets its own card under the reply. Cards open one at a time, render Markdown and code the same way the reply does, and each has its own copy button.
- Which one was used: the Brain whose text became the reply is labelled directly, so the relationship between the swarm and the answer on screen is explicit rather than inferred.
- Durable: the alternate answers are stored inside the same encrypted blob as the reply, so they are still there when the conversation is reopened and never sit at a weaker protection level than the answer itself. Brains that failed or were never reached are left out, and a single-Brain turn shows no cards at all.
- Backend: a swarm turn keeps each counted Brain’s own answer, flags the primary, drops Brains that never answered, and survives a conversation reload. A single-Brain turn stores nothing. Both confirmed to fail against the prior code.
- Interface: an end-to-end test asserts a discarded answer is hidden until its card is opened, then fully readable, and that opening a second card closes the first.
- Live: verified against the running app with three real Brains — a local Ollama model, a ChatGPT browser session, and a Claude subscription — and confirmed all three answers persisted and reloaded.
- Root cause: starting a new conversation's first turn created the conversation, then immediately pushed the URL to include its ID. That URL resolves to a different Next.js page file than the one already on screen, so the push unmounted the entire workspace mid-request. The backend kept working and persisted the reply correctly; every callback that would have shown it on screen was firing against a component that no longer existed.
- Fix: the URL now updates only after the turn settles — on success, on failure, and on a stopped turn — so the workspace stays mounted for the entire request and the reply always renders.
- Scope: affected the first message on every brand-new Chat conversation, every unfiled and project-scoped Cowork conversation, Auto Brain, Multi-Brain Swarm, a manually built swarm, and the native Codex agent path alike. A second message in an already-open conversation was never affected.
- Regression coverage: a new test opens a mode with no conversation selected, sends a message, and asserts the URL stays put while the turn is in flight and only changes once the reply is visible. Confirmed to fail against the prior code and pass against the fix.
- Mock persistence: the shared workspace test double previously always answered a conversation re-fetch with an empty message list, which made this exact bug indistinguishable from correct behavior in a mocked test. The double now persists messages the way the real backend does.
- Embedded overlays: a
position: fixedoverlay is clamped to any ancestor carryingbackdrop-filter. Liquid Glass gives every card that property, so a drawer opened from a connector card collapsed to the card's bounds. Overlays now render through a portal ondocument.body, so no ancestor can contain them. - All overlays covered: the same fix is applied to the connector configure modal, control scope drawer, policy and workflow editors, Swarm and Mission creation, and the Chat/Cowork research, confirm, and swarm-picker dialogs.
- Overlay depth: because every other surface in this theme is see-through, overlays now darken the scrim past the shared
bg-black/40and carry a defined edge with a deeper drop shadow. The panel stays opaque; a translucent treatment was measured and rejected because page text read through it.
- WebKit coverage: the packaged desktop app is WKWebView, and WebKit enforces the containing-block rule that Blink ignores, so this defect measured as correct under Chromium while being broken for every user. Playwright now runs a WebKit project over
@webkit-tagged specs, with overlay geometry and containment assertions that fail when the portal is removed.
- Gemini could never submit: the send-button search required a real
<button>element, but Gemini's composer is built from Angular Material custom elements, so nothing matched. The prompt was typed into the page and left sitting there. Send controls are now matched by role rather than element type, and the selector set no longer assumes an English interface. - No submit fallback existed: when the send control could not be found, the companion threw before any alternative was tried. It now falls back to a synthetic Enter key press, and reports which path failed when neither works.
- Unknown sites were treated as Gemini: any host that was not ChatGPT or Claude was assumed to be Gemini, so an unrelated tab would run Gemini's selectors and report a confusing selector error instead of naming the real problem. Provider detection is now explicit.
- Sessions dropped while still signed in: readiness expired after 50 seconds, but Chromium clamps the extension's wake-up alarm to 30 seconds and Edge to 60, so a suspended service worker could not check in before expiry. A healthy, still-open tab reported as disconnected within a minute of being left alone. The window now clears the slowest browser's floor with room for cold-start jitter.
- Long generations looked dead: the companion stopped checking in entirely while a turn was in flight, leaving readiness dependent on observable streaming. A provider that paused to think long enough would be marked stale mid-turn. It now sends a keepalive that refreshes readiness without leasing new work or disturbing the running task.
- Workspace crash on older history: a provenance manifest saved before citations were added would take down the entire Chat and Cowork surface on load, because the citation count was read without a guard. Older manifests now render as having no citations rather than throwing.
- Stage-aware activity indicators: a running turn showed one rotating spinner for every stage, which said only that something was happening. The timeline now draws an animation whose shape encodes the stage actually reported — planning, gathering context, waiting on a Brain, receiving tokens, writing files, verifying, or comparing Brain results. The distinction that matters most is waiting versus receiving: a browser Brain that accepted the prompt and went quiet no longer looks identical to one that is streaming.
- Honest by construction: the stage comes from the step the runtime reported, never from a guess, and only genuinely active steps animate. Finished and skipped steps keep their terminal icons.
- Revertible without a rebuild: a control on the timeline header switches back to the original spinner, and the choice persists. Nothing about the governed turn changes with this setting; the step labels are identical either way.
- Accessibility: a reduced-motion preference freezes the indicator on a single frame rather than removing it, since the stage it encodes is still information.
- Both launch screens: the native macOS splash appears first and holds through the entire container start, so replacing only the web loader would have left the longest part of startup on the old spinner. The AppKit splash now draws the same planning animation as the web screen, at a matching size, and a test pins the two figures together so they cannot drift apart.
- Brain Connections: the ready-Brain count now carries a constellation that wires itself together, which is what the page is about. It depicts the connections rather than work in progress, so it runs whether or not a turn is in flight — but it is hidden at a count of zero, since a live network above an empty number would claim connections that do not exist.
- Cards read as glass, not as outlines: panels carried a flat slate stroke and a single shadow, which read as a drawn border rather than a lit edge. They now carry a white rim, a top specular highlight, a bottom counter-edge, an inner glow, and a tight contact shadow beneath the ambient one. Measured contrast improved in the WebKit worst case rather than degrading.
- Scales with the transparency level: the denser Subtle setting takes a weaker edge, and the Clear setting takes a stronger one, since at high transparency the edge is most of what carries the shape.
- Reduced transparency: the specular treatment is dropped entirely and the rim returns to a solid stroke, so the surface stays legible when the system asks for less transparency.
- Glass was disabled entirely on Windows: the theme's blur rules were written with both the standard and the
-webkit-property names. Authoring both makes the build drop the standard one and ship only the prefixed alias, which Chromium does not support — so Liquid Glass had no blur at all in the Windows WebView2 host while looking correct in the packaged macOS WKWebView. The rules now declare the standard property alone and let the build emit the alias, and a test fails if the manual prefix returns.
- Autonomous Remediation: the page fetched only the action queue, so a node reporting open violations still showed an empty console. Failing controls from the latest assessment are now listed, with an explicit proposal action that still passes Trust Fabric and the approval gate.
- Recommendation-only controls: a failing control with no executable action is listed separately with its reason, instead of offering a button that cannot act.
- Liquid Glass: the panel and border rules matched any rounded, bordered box, which repainted every button with the neutral panel surface and erased the colour distinguishing Approve from Block. Controls are excluded and keep their own glass treatment.
- Liquid Glass colours: dark-console state colours are remapped for light translucent panels so status text and tints stay legible.
API error 500 is fixed.- See controls: each connector opens a drawer showing in-scope, passing, failing, and not-assessed counts with the individual controls and their reasons.
- Evidence collectors: the drawer names each bound collector, whether it can run now, and which alternative connectors also satisfy it.
- Control scope API:
/controls/connector-scopeand/controls/connector-scope/{type}resolve adapter aliases, so a tenant configured forazure_adsees the same scope asentra_id.
- Connector coverage: 39 connectors with working read adapters were bound to no evidence collector, so each looked functional while proving no control. Every reporting adapter now has a collector, and a test prevents a new one shipping unbound.
- Unevaluated nodes: Attack Path, Automation, Compliance, Threat Intelligence, Threat Analysis, Release, Vendor Risk, and Recovery Readiness had a baseline control with no evaluator, leaving them permanently unassessable.
- Baseline install: installing the control pack now binds its collectors in the same operation, so a fresh deployment is assessable instead of reporting empty scopes.
- Non-assessing connectors: Brain providers and notification channels state that they carry no control posture instead of implying a missing collector.
- AI advisory: the API server's five-second keep-alive closed idle sockets the console proxy had already reused, so a request the backend answered with
200reached the browser asAPI error 500. The keep-alive window now outlives the proxy's reuse window. - Console requests: read-only calls retry once when a recycled connection is lost. Writes are never replayed.
- Installer links: the download buttons name the current release instead of resolving to a missing asset.
- Capability Nodes: production scans no longer substitute sample findings for an environment without a verified source.
- Connector Health: records a successful read-only provider test before showing Verified; configured and approved connectors still needing a test are explicit.
- Controls and AI advisories: use tenant-scoped live evidence only. Demo and unknown origins cannot affect verdicts or remediation candidates.
- Identity Security: inventory, risk events, and privileged approvals are tenant-owned and foreign records resolve as not found.
- Brain Bridge: the loopback listener specified its port twice, which macOS rejected with
EINVAL, crash-looping the bridge under launchd. - Diagnostics: bridge startup failures report the underlying error instead of a generic configuration message.
- Sidebar: Security Arms start collapsed; the group owning the current page opens automatically and manual choices persist.
- Windows: the launcher now compiles against the .NET Framework compiler used by the installer build.
- Workspace: Chat, Cowork, and Security are the only initial sidebar modes.
- Security: Arms and nested nodes stay hidden until their disclosure section is opened.
- Branding: dark mode uses the white octopus on a dark rounded tile.
- Startup: Docker Desktop is checked before governed services start, with actionable recovery controls.
- Detection: macOS and Windows distinguish healthy, installed-but-stopped, missing, unhealthy, and unavailable Docker states.
- Startup: installed Docker Desktop opens automatically and
docker infois polled with bounded progress before Compose runs. - Installation: missing Docker opens only the official Docker Desktop flow and never bypasses its installer, licensing, administrator, or reboot steps.
- Recovery: the native prerequisite screen exposes Retry, Open Docker, Install Docker, and startup-log actions instead of a generic launch error.
- Packaging: the helper scripts ship inside both native installers, with mocked state and Compose-ordering tests.
- Icon: the red/orange octopus sits on a white rounded-square tile with transparent outer corners.
- Windows: Start Menu and Desktop shortcuts reference the canonical ICO directly instead of relying on executable icon extraction.
- Validation: every 16px through 256px ICO frame is checked for alpha transparency and correct geometry.
- Packaging: native Windows and macOS package validation remains covered by CI.
- macOS: native vibrancy samples the desktop through the WebKit shell and honors Reduce Transparency.
- Windows: the desktop host embeds WebView2 and requests Acrylic through DWM on supported Windows 11 systems, with a safe opaque fallback.
- Theme bridge: the web layer reports theme changes to each native host; Liquid Glass alone enables native transparency.
- Startup: native hosts consume the runtime's dynamic UI URL instead of opening a second browser tab.
- macOS vibrancy: the transparent WebKit shell uses an
NSVisualEffectViewbehind the app content so the system desktop material can show through. - Theme bridge: the web UI reports its active theme to the native shell; vibrancy is enabled only for Liquid Glass.
- Fallback safety: dark and light modes restore an opaque window, and browser sessions retain the CSS glass fallback.
- Visible depth: neutral frosted-gray canvas, translucent surfaces, stronger separation, and restrained blur make the active theme unmistakable.
- Clear theme state: the sidebar control shows the active theme and the next available transition.
- Neutral controls: Liquid Glass uses slate accents rather than cyan or green browser-style highlights.
- Full-console glass surfaces: dashboard canvases, navigation, cards, tables, forms, dialogs, inputs, and runtime surfaces now share the translucent glass treatment.
- Neutral palette: the glass theme uses clear white, gray, and slate layers without the previous blue-green cast.
- Theme-specific branding: dark and light modes use the transparent octopus logo; only Liquid Glass uses the glass logo asset and frame.
- Accessibility: readable contrast, stable borders, restrained blur, and solid code surfaces are preserved for security-console scanning.
Changelog
Every feature shipped, integration added, and fix landed — in order. New features are published here when they're tested and ready.
AI analysis existed behind the Zero Trust control drawer, but a user opening Cloud, Identity, Endpoint, Dev, or another Security Arm could see findings without any explanation layer beside them. The new shared advisory surface is now present on every scan-backed Arm.
- AI analysis and remediation plan appears on all 23 scan-backed Security Arm pages. It shows the summary, root-cause analysis, ordered remediation steps, provider/model, evidence counts, and honest clean or unavailable states.
- The Brain remains advisory. Deterministic controls, verdicts, scores, and remediation gates are never changed by generated prose.
- Liquid Glass is now the third persisted theme after Dark and Light. The final treatment uses neutral clear glass and slate accents rather than saturated blue or green.
- Brand assets match the theme. The clear-glass Enkstein icon is used by the portal, browser companion, and future macOS/Windows packaging builds.
Verification. Frontend ESLint, production build, node advisory wiring, and diff checks pass. This release changes presentation and advisory visibility; the Trust Fabric and deterministic assessment boundary remain unchanged.
The Channel Gateway and the Execution Channels were the last two record sets with no owner. They are also the highest-consequence pair in the product: one runs shell commands, drives browsers, brokers credentials and gates production, and the other is the unauthenticated ingress that feeds it. Any authenticated caller could read another tenant’s inbound messages, approve their pending execution, or list their credential broker entries.
- Execution requests, production gates and broker entries are scoped end to end — list, detail, approve, reject, execute, rollback, rotate and statistics. A foreign record answers 404 rather than 403, so an identifier cannot be used to probe what exists in another tenant, and an already-approved foreign request still refuses to run.
- Channel messages, identities and configs are scoped too. A channel config holds a webhook URL and a signing secret, so it was a credential surface listed to everyone. Outbound replies are now matched to a config in the message’s own tenant, which means one tenant’s response can no longer be delivered through another tenant’s webhook.
- Ingress cannot name its own tenant. Slack, Teams, webhook, email and CLI arrive unauthenticated, so ownership is taken from the channel config an operator registered rather than from the payload. A message on an unregistered channel stays unowned and visible only to an administrator, instead of defaulting into a tenant. A
tenant_idsupplied in an identity upsert no longer adopts or elevates an existing mapping. - Two global uniqueness constraints were themselves the leak. A channel id and a credential name were unique across the whole install, so the first tenant to register a name locked every other tenant out of it and the insert conflict revealed the name existed somewhere else. Both are now per-tenant.
- Control Center counters stop mixing tenants. Channel volume, blocked traffic, pending replies and pending execution approvals were counted across the entire install.
Verification. Twelve new adversarial checks assert the foreign-record behaviour directly, including that an approved request of another tenant is still not executed. Migration 0011 was run on PostgreSQL 16 through a full upgrade → downgrade → upgrade cycle against a schema clone, resolving the existing constraint by inspection because its generated name differs between deployments. 1,303 backend tests pass.
The repository had newer commits than the latest downloadable release, and the macOS download button pointed to an asset that was not attached. This release aligns the application version, Git tag, release assets, and download links at v0.5.12.
- Windows startup waits for the actual Docker Linux engine. It now detects both system-wide and per-user Docker Desktop installations, waits for the named pipe to become usable, validates the engine again immediately before Compose, and retries container startup when Docker is still settling.
- Installer links point to this release. macOS and Windows buttons, the native installer documentation, the browser companion version, and package metadata all use v0.5.12.
- Failure messages are actionable. If Docker Desktop cannot become ready, Enkstein reports that directly and opens the launcher log instead of surfacing an opaque Compose pipe error.
Requirement. Docker Desktop remains required for this installer path. Enkstein starts it when installed, but Windows must still have Docker Desktop installed and allowed to run.
Running a node produced verdicts and a score, and stopped there. Reading which of 324 controls failed, working out which failures shared a cause, and deciding what to do first was left entirely to the operator. Not one of the 26 node scans reached a Brain — AI existed only as a cross-node correlation on a separate page.
- Explain this assessment now sits under the verdicts for every Security Arm. It reads the failing controls, the open findings, the remediations that can execute, and the ones that need a human, and returns a summary, the themes connecting the failures, and ordered remediation steps citing the control IDs they resolve.
- Controls that were never assessed are reported alongside the failures. A high pass rate over a third of a profile is not a good posture, and the summary is given the coverage gap so it cannot describe one as the other.
- The narration cannot change the assessment. Verdicts and scores stay deterministic, and the model only ever reads the finished result. Two reasons hold that line: a control that moves between pass and fail because a model phrased itself differently makes a compliance posture unauditable, and every finding string arrives from a third-party connector, so it is framed as untrusted data — a successful injection yields misleading prose rather than a forged pass.
- A clean node skips the model entirely rather than paying for a call to say nothing is wrong, and when no Brain is reachable the assessment is reported as complete and unaffected instead of showing an empty panel.
Found while building this. The summary was reading control rows from a key the evaluation service does not return, and remediation proposals from another. Left as it was, every node would have reported “no failing controls” no matter how many had failed. Both contracts are now pinned by tests.
Windows does not run the shell installer — it drives Docker Compose directly. Every fix made to the installer had therefore been missing Windows entirely, including the prebuilt images from the previous release.
- A port already in use no longer stops the launch. Ports 3000 and 8000 were claimed unconditionally, so anything else holding either one made startup abort with nothing on screen but “Container startup failed”. Both platforms now keep the familiar port when it is free and quietly move to the next one when it is not, and the browser opens on the port actually chosen. The two port settings were also absent from the environment file, so they were ignored even when set by hand.
- Windows generates its own owner password. It previously kept the placeholder from the example environment file, meaning every Windows installation shared the same known credential. Existing installations still holding the placeholder are given a fresh one.
- Windows downloads the runtime instead of compiling it, matching macOS, with the same fallback to building when the download is unavailable.
- A failed launch opens the log rather than printing a folder path and leaving you to find it.
Honest limitation. The port and version helpers were executed and verified, and the launcher parses cleanly, but this was developed without a Windows machine. The installer itself has not been run end to end on Windows.
Every new user was building the runtime on their own machine before they could see anything. The backend image is 3.47 GB, and 2.22 GB of that is Prowler’s dependency tree — that compile is what made first launch take minutes.
- Runtime images are now published for each release, built for both Apple silicon and x86, so installation is a download rather than a build.
- Building still works when the download cannot. An offline machine, an unreachable registry, or a source checkout falls back to building locally and says so. Set
ENKSTEIN_FORCE_BUILD=trueto always build. - The download is time-bounded, and that is not a precaution. A pull against a tag that does not exist yet does not fail — it hangs indefinitely. Unbounded, that would have left first launch waiting forever with nothing on screen. It now gives up and builds instead.
- Published images exclude local development state. The build previously included the virtual environment and installed packages from the machine that built it, which bloats the image and risks carrying a local environment file into a public artifact.
Running entirely without Docker, and a Docker-free installer variant, remain under consideration; this release makes the existing path fast rather than replacing it.
The previous release page listed enkstein-0.5.7.tar.gz beside three wheels named for the predecessor project, which reads like two unrelated downloads.
- Renamed to
enkstein-cli,enkstein-core, andenkstein-mcp, with matching import names and anenksteinconsole command. None were published to a package index, so no existing installation is affected. - Fixed the references that would have broken the build. The release workflow builds the core package by directory name, and the packaging check watches that path; both still pointed at the old directory.
Verification. All three were built and installed into a clean virtual environment: from enkstein_core import ... imports and enkstein --help runs, which is exactly what the documentation now instructs.
The project is now wcoreiron-rgb/enkstein, and the leftover names were doing real damage rather than merely looking untidy.
- “Check for Updates” would have stopped working. The macOS app reads its repository out of
Info.plistand queries the GitHub releases API with it. That value still named the old repository, so every installed copy would have failed to find a release — quietly. It now names the current repository, and the app still accepts the old package filename so existing installs can update to this build. - The build badge was showing another repository’s status. Its link had been repointed but the badge image had not, so the README reported a different project’s build result as though it were this one.
- Downloads carry the product name. Self-hosted bundles were still
marcellus-VERSION; they are nowenkstein-VERSION, along with the macOS packaging path that consumes that directory. - The documentation site is published at its own address and no longer borrows the predecessor project’s. Old links continue to resolve.
Deliberately unchanged. Anything a rename would break for an existing install stays as it is: the API route segments, the Brain Bridge and external-agent request headers, the Compose project and database names, and the application support directory holding your database and bridge secret. Renaming those would orphan working installations for no visible benefit.
Three things were quietly making Enkstein untestable by anyone who had not cloned the repository.
- The companion is now a download, not a Finder reveal. The button opened a folder inside a local checkout, so anyone running the notarized package had no way to obtain the extension files. Brain Connections now serves the extension as a zip, resolved from the packaged layout or a source checkout, with dotfiles omitted because Chrome rejects an unpacked load that contains them. The instructions on the page name each step: unzip, open Extensions, enable Developer mode, Load unpacked, then Pair browser.
- The Windows installer now bundles the companion too. It had never been copied into the Windows runtime, which would have made the fix macOS-only.
- A missing Authenticode certificate no longer kills the Windows build. Signing was a hard gate on a repository with no signing secrets, so every Windows artifact failed before it was produced. It now warns and publishes unsigned, and still fails loudly if signing is configured and genuinely breaks. The resulting SmartScreen prompt is documented rather than left as a surprise.
- New Testing Guide. Which connectors work without a paid account, what a passing connector test does and does not prove, how to distinguish live findings from demonstration data, and the known gaps — written for someone evaluating this for the first time.
Verification. A real browser click downloaded the zip and it passed an integrity check with every extension file present. The Windows packaging script and release workflow were both validated by their own parsers.
The Brain picker in Chat and Cowork listed three near-identical Ollama rows and offered only three Claude models.
- Internal profiles no longer appear as operator choices. Cowork file authoring and workspace scanning are pinned by the runtime, not chosen; they rendered as extra “Ollama” rows that behaved differently from the general local Brain. Routing and policy are unchanged.
- The label reflects what is actually selectable. It named one model when the whole installed set is available, and named the wrong one when the profile’s configured default was not installed — showing gemma2:9b for a profile configured as qwen2.5:14b-instruct, purely because gemma2 sorted first. Providers offering a live choice now show their count.
- Claude offers the models this account is entitled to, read from Claude Code’s own state rather than three hardcoded aliases that never changed with your plan. The aliases remain available, and remain the fallback if that state cannot be read.
Verification. Measured against the running console and the real Claude session: three Ollama rows became one reading “9 models”, and Claude went from 3 models to 8.
Every provider read “Unknown” — including the Mock backend that cannot fail, and a local Ollama that was running with nine models installed. The internal status map was declared and read, but nothing ever wrote to it.
- Providers are probed rather than assumed. Ollama is checked for real reachability and reports its installed model count; cloud providers report whether a usable credential exists.
- Readiness matches what a routed call would actually do, so the strip cannot show healthy where the call would fail on a missing key. Azure requires both an endpoint and a key, since either one missing fails the request.
- Keys added through the Connector Marketplace count. Reading only environment variables reported providers as unconfigured while their routed calls succeeded.
- Each status explains itself, so “No key” names the connector to configure instead of leaving you to guess.
Verification. Measured against the running stack, not asserted from source. This surfaces a real gap the old display hid: Public, Internal and Confidential currently route to providers with no credential configured.
Claude Subscription showed “Needs setup” on hosts where claude auth status reports a live session, and Brain Connections printed model lists as one long run of text.
- Claude now detects your real login. Enkstein runs vendor CLIs under a deliberately minimal environment, and that environment omitted
USER. The Claude CLI resolves its session through your Keychain and needs it, so under the bridge it genuinely saw a signed-out machine. It is now passed, and nothing else about the environment changed. - Model lists collapse behind a count and open on demand, so Codex’s 44 models no longer make one card taller than the other seven combined.
- API providers show their model names instead of only a number with no way to see what is behind it.
- Counts come from live discovery where it returned anything, rather than a static catalogue that disagreed with it, and the Discovered Models tile now includes subscription models instead of ignoring all 47.
Verification. Measured against the real Claude session and the running console, not asserted from the source. Claude moved from authenticated=false to Ready, and all nine installed Ollama models render.
Two live Entra findings — any user can create tenants, any user can register applications — were open in the console while Identity and Privileged Access both reported 100% passing. Four faults had to line up for that, and all four are fixed.
- A control created from a finding now inherits an evaluator from the connector that produced it. Without one it read as advisory forever, so a live violation could never fail its own control.
- Controls created before this fix are repaired in place on the next scan, instead of needing the catalog rebuilt by hand.
- A re-scan that changes nothing still commits catalog repairs. The commit was gated on new or updated findings, so an unchanged scan silently rolled the repair back and the control never gained its evaluator.
- Nodes that share an adapter now both see the shared control. Identity and Access share the Entra collector, so the control was visible only to whichever node registered it first and passed silently on the other.
Verification. Measured against the running stack with real Entra credentials. Identity and Privileged Access each moved from a reported 100% to 50%, with both genuine violations failing on both nodes.
Zero Trust Control Coverage shipped with dark slate colours written directly into the markup rather than read from the theme, so it stayed dark and washed-out when the rest of the console was in light mode.
- Surfaces, text, borders and hover states now read from the shared theme variables the other pages already use, so the page switches with the console instead of ignoring it.
- Card corners, toolbar buttons and table rows match the surrounding design system, rather than using their own slightly different radius and treatment.
- Verdict and pillar accent colours were re-picked for contrast on a light background, so pass, fail and recommendation stay legible either way.
Verification. Rendered and inspected in both light and dark mode against the running console, not asserted from the stylesheet.
Enkstein could list what was wrong. It could not say what was right, which meant it could not answer the question an operator actually asks: how many controls do I have, and how many are failing? This release adds the control catalog, the profiles that make coverage meaningful, and the verdicts that make a score honest.
- 1,426 controls, from three sources. The NIST SP 800-53 Rev 5 OSCAL catalog (324), Prowler's check catalog for AWS, Azure, GCP, Kubernetes and GitHub (1,038), and Enkstein's own node objectives, TerraClaw rules and ArcClaw patterns (64). Only factual fields are imported — identifier, severity, service, remediation reference — never framework prose.
- Every Security Arm gets its own denominator. A catalog is not a profile. Showing all 1,426 controls under every node would claim Identity Security is accountable for physical facility access. Each Arm now declares the NIST families it can plausibly produce evidence for and inherits only those, so coverage means something.
- A control only passes when something looked at it. Silence is never success: PASS requires a collector to have actually run and returned no violation. Demonstration data can no longer produce a compliance verdict, and evidence older than seven days downgrades to NOT ASSESSED rather than standing as a stale pass. The pass rate is scored only over controls that were genuinely assessed; the rest are reported as the coverage gap they are.
- Failing controls propose the fix they declare. A control that can only report FAIL is an alert. Failing controls now route their declared remediation through the existing governed engine, which keeps its own risk classification and approval gate — a medium-risk action still waits for a human. Enkstein never infers a destructive action from a finding's text, and an executed action is not treated as proof the control now passes; verification is a fresh evaluation after a rescan.
- Prowler is a real dependency now, not a plan. It ships in the backend image in its own virtual environment so its dependency tree cannot collide with the backend's, and it runs read-only: no shell, allowlisted executables, credentials passed through the child environment rather than argv, bounded timeouts and capped output. A non-zero exit without parseable results is a failure, never a clean scan. When it is absent, readiness says so.
- Saved state stopped freezing shipped capabilities. A persisted model profile replaced its built-in wholesale, so a policy change in a release never reached a deployment that already had state on disk. Operator-tunable fields are still restored from disk; the policy allow-lists are owned by the code again.
Verification. Confirmed against the running stack rather than by reading code. All five Prowler providers execute and fail closed with genuine credential errors instead of reporting a clean scan. A live finding drove the full loop end to end: FAIL verdict, actionable proposal, a governed force_mfa_reset correctly held at pending approval, and re-verification. Cross-node AI analysis ran over 40 findings from 14 Security Arms on the local Brain with no cloud key configured, and a Swarm investigation across 8 Arms returned a critical verdict at 0.88 confidence, correctly requiring approval. 1,225 backend tests pass.
Every Microsoft connector reported “did not accept these credentials” after a successful sign-in. The credentials were fine; the test was wrong, and it was wrong in a way that hid two separate defects.
- A connector was tested by asking it for findings. That conflates three different outcomes — a rejected credential, a healthy tenant with nothing to report, and a token missing one optional scope — and reports all three as a credential failure. A Microsoft sign-in is now verified against an identity endpoint covered by the base scope every sign-in grants, so an empty tenant tests as connected. The probe is matched to the audience the connector actually signed in for, because a Microsoft Graph token cannot verify an Azure Resource Manager connector and the reverse is equally untrue.
- Entra ID read only Identity Protection. That endpoint needs an Entra ID P2 licence and an additional scope, so a correctly connected tenant without one produced no findings at all — which the test above then read as a bad credential. Entra now also reads directory defaults and standing privileged-role membership, each degrading on its own, so a licensed tenant gains checks rather than losing them.
- The Configure form and six adapters disagreed on field names. Okta stored
domainwhile its adapter readorg_url, so a correctly filled form failed before it ever reached Okta. Splunk, CrowdStrike, GCP and AWS had the same drift. Stored credentials are now reconciled through an alias layer, so connectors configured before this release keep working without being re-entered, and the fields those adapters genuinely need were added to the form. - An unreachable host was reported as a rejected credential. A network failure, a provider that returned nothing, and a refused token now read as three different messages, because they call for three different fixes.
Verification. Confirmed against a live Microsoft tenant, not by reading code: Entra ID and Sentinel now pass their connector test and Entra returns real findings on the directory's default user permissions. A new contract test asserts that every field a hand-written adapter reads is either on the Configure form or derived from it, and that a provider returning no findings tests as connected rather than as a failure — so this class of mismatch cannot return silently. 1,158 backend tests pass.
Four paths reported real-looking results for work that never executed. Each is now honest about what happened.
- Remediation recorded success for actions it never ran. With no credentials configured, a shared helper returned
success=truewith a “Simulated:” message, so the engine marked the action completed and wrote a matching audit event. An operator reviewing the queue saw a disabled account or an isolated host that had never been touched, and the audit trail agreed with them. All twenty call sites across identity, cloud, endpoint, code and ticketing now fail withprovider_not_configuredinstead. - Agent runs returned a fixed scenario per Capability Node. The AI Security agent always “found” one prompt injection and one DLP violation whether or not a connector existed, and parked approval actions for targets that were not real. A run now executes the node's own governed scan — the same path the console uses — and reports the findings that scan actually persisted, including none. Remediation is proposed only for connector-backed findings, so the approval queue cannot contain an action against demonstration data.
- Workflow gates approved everything. A policy check returned PASS unconditionally with a “(simulated)” note, so a workflow's guardrail waved through every branch it was asked about. Gates now evaluate against real workflow context, and a gate that cannot be evaluated fails rather than passing. An agent step whose agent did not exist reported completed; it now fails, and steps without a bespoke intel path run the node's real scan.
- Two Capability Nodes reported unconfigured providers as successful scans. Cloud and Endpoint returned
status: successalongsidesimulated: true, and omitted themodefield that callers use to tell demonstration data from a connector result.
Production data policy. A new REQUIRE_LIVE_DATA setting makes every Capability Node return nothing rather than demonstration findings, so everything on screen came from an authenticated connector. It defaults to off, which keeps a fresh install explorable; set it to true for a real deployment.
Verification. Confirmed against a running stack, not by reading code: an agent run that previously invented two findings now reports an honest zero, and with the policy enabled Cloud and Identity return mode: empty with an explanation instead of a fabricated estate. One existing test asserted that a Jira ticket “completed” without any Jira credential; it now asserts the failure. 1,084 backend tests pass and all twenty-nine console surfaces still load.
All twenty-nine navigation entries were walked against a running backend rather than reviewed by reading code. Four were broken.
- Findings returned a server error on any upgraded install. Startup creates missing tables but cannot alter existing ones, so a column added to a model after first run was simply absent from the database while the migration revision still read as current — and the first query selecting it failed. Because a local database outlives every upgrade, this would have hit every existing operator. Startup now reconciles additive column drift before anything queries it, adding only columns the models declare and never dropping, renaming or retyping.
- Mission Control was taken down by one stale row. The listing decrypted each objective inline, so a single mission written under a previous runtime key raised and returned a server error for the entire page. Unreadable rows are now listed and labelled as such, which keeps the page working and makes the bad row visible enough to remove.
- Remediation could not reach the backend from the packaged app. It bypassed the shared API client and called an absolute
localhost:8000URL with no bearer token, so requests were blocked cross-origin. It now uses the same-origin proxy and the operator's session. Approvals also posted a hardcodedadminidentity; the backend already derives the approver from the token, and the client no longer claims otherwise. - The connector list fetched vendor logos from a third-party CDN. Every render told an outside service which connectors an operator was viewing, and eleven brands had been removed upstream so those requests 404'd permanently. Seventeen marks are now bundled locally and the rest use the existing initials badge. Nothing about the connector inventory leaves the machine.
Verification. A new end-to-end sweep walks all twenty-nine routes and fails on a server error, a render crash, or an uncaught exception. Running it against deliberately truncated responses found four more pages that would white-screen on a payload from a version-skewed backend; those now degrade or report an error instead. 1,076 backend tests pass, including new coverage for schema reconciliation and unreadable encrypted rows.
Two things that looked finished but were not.
- Microsoft browser sign-in could never have worked. Every Microsoft connector offered “Sign in with your browser,” which borrowed the Azure CLI public client and sent it a loopback callback path that client does not register — so Entra rejected the request with
AADSTS50011before any consent screen appeared. Browser auth is no longer offered for Microsoft; the device-code flow, which needs no registered redirect, now covers all nine Microsoft connector types including Purview and Azure Resource Manager. GitHub, GitLab, Okta and the rest keep browser sign-in unchanged. - An agent run recorded a tally, not a result. A completed run stored how many findings it had produced but not the findings themselves, so the only way to see what an agent actually found was to correlate the Events feed by run id. The run log now carries each finding, and the run history panel lists them by severity. Separately, a run parked in “Awaiting Approval” had no way to be approved or rejected — the endpoint and the client call both existed but nothing in the console used them. Each pending action now shows its type and target with Approve and Reject beside it.
Verification. Agent runs had no test coverage at all, which is how the missing output survived; two now assert that a completed run records what it found and that a parked action carries enough detail to decide on. The Microsoft change is covered by an assertion that all nine connector types decline browser auth and name a device provider instead. 1,072 backend tests pass.
Known limitation. Built-in agents still run scenario data rather than querying a live tenant. The plumbing above is what surfaces a result once real scan logic is attached.
0.4.1 stopped the workspace grabbing the first project in the list, but two other paths still decided where you landed.
- A plain open is a fresh start. Both the workspace and the blade restored the last remembered project from local storage, and the workspace then loaded the most recent conversation and rewrote the URL to point at it — so there was no way to reach an empty page. Opening
/marcellus/chator/marcellus/coworknow stays put with nothing selected. Deep links to a specific project or conversation resolve exactly as before, and earlier threads remain one click away in the blade. - The file panel appears only when it has something to show. Cowork rendered its right-hand rail on every open, including when no project was bound, spending roughly a third of the width on an empty “No project selected” placeholder. It now appears once a project is actually bound, and the composer takes the full width until then.
- Mission Control is reachable from the navigation. It renders at the top of the Security workspace but had no entry in the blade, so it could only be found by switching modes. It is now the first item under Cortex & Hearts.
Verification. The end-to-end test that previously asserted a base route would adopt a conversation now asserts the opposite — that the route stays clean, no file panel renders without a project, and a deep link still resolves to its exact conversation. 1,070 backend tests pass; the workspace suite is 14 of 15 with the one failure a pre-existing flake that passes in isolation.
The sign-in screen showed no version, so confirming which build was actually installed meant unlocking the console first. The running version now appears quietly beneath the sign-in card, read from the same unauthenticated runtime endpoint the console sidebar uses — the locked screen cannot report a different build than the application behind it. When the runtime is unreachable it says so rather than showing a stale or assumed number.
Three things that made the workspace feel like it was deciding for you.
- No project is selected on open. Both the workspace and the sidebar fell back to the first project in the list when nothing was remembered, silently scoping everything to a folder you never chose and hiding every conversation outside it. Both now rest on no selection, so a fresh open shows all threads including unfiled ones. Cowork no longer refuses to start a conversation without a project either — file writes are project-scoped and the backend already skips them when a conversation has none, so thinking through a problem before binding a folder is a supported path rather than a blocked one.
- Claude subscription readiness was structurally unable to work. The native bridge treated a zero exit code from
claude auth statusas proof of sign-in, but that command exits 0 whether or not a session exists — a signed-out host returns success with{"loggedIn": false}. No amount of re-authenticating in a terminal could have changed the result. Readiness now reads the reported login flag, with a text fallback for older builds that do not emit JSON. - Local Brains are named. Several profiles share the Ollama provider — a general, an authoring and a scanner profile — and all three rendered as an identical “Ollama” row in both the Brain picker and the swarm builder, with no way to tell which engine you were choosing. Each row now carries its model, so the choice reads as
Ollama · qwen2.5:14b-instructrather than three indistinguishable entries.
Verification. 1,070 backend tests pass, including a new guard that fails if Claude readiness regresses to an exit-code check. The workspace suite is 14 of 15, with the one failure a pre-existing flake that passes in isolation. Four end-to-end tests encoded the old auto-selection behaviour and were updated to select a project explicitly.
Red was doing two contradictory jobs. It marked critical findings, failed checks and destructive actions — but it also coloured the Send button, folder icons, the Brain Connections header, the login password field and the “Agent tools” toggle. In a security console that trade is a bad one: when ordinary chrome shouts as loudly as a critical CVE, the eye learns to stop listening, and the loudest signal is spent before anything is actually wrong.
- Severity keeps red. Open findings, KEV badges, failure icons, blocked actions, policy denials and destructive-intent controls are unchanged. The Codex “Approve once” control also stays red, because authorising an agent action genuinely is consequential.
- Brand chrome moves to its own token. A new
--rc-brandpair carries navigation icons, primary actions and product marks. It is tuned to the octopus logo rather than fighting it, so the workspace reads as one product instead of a permanent alert state. - Two more undefined tokens fixed.
--rc-accent-violetwas referenced eleven times in Custom Capability and never defined, so those chips and buttons rendered with no colour at all — the same class of defect as the--rc-bggap closed in 0.4.1. Two Release Governance controls also paired an indigo background with red text. Both now resolve. - Consistent across both themes. The new tokens are defined for light and dark, so primary actions, the sidebar and Cowork no longer drift apart when the theme changes.
How this was checked. Brain Connections and Cowork were rendered and inspected rather than assumed. A diff of the severity surfaces — Findings, Threat Intelligence and the shared stat card — confirms no colour changes landed there at all. Typecheck, lint and the 66-route build pass; the workspace suite is 14 of 15, with the one failure being a pre-existing flake that passes in isolation.
Previous releases established that the platform's parts existed. This one drives them: every node, connector, platform route and execution control is executed against the running application, and three real defects surfaced that no amount of code review had caught.
- SSRF guard was bypassable. The connector URL check blocked
127.0.0.1but allowedlocalhost, and never resolved hostnames at all — so any attacker-controlled domain pointing at the cloud metadata address passed straight through. Hostnames are now resolved and rejected when they land on loopback, private, link-local, reserved, multicast or unspecified space. This guard protects every self-hosted connector URL and the entire Custom Capability surface. - Authenticated fetches were not tagged. Twenty connectors returned findings without a data-origin stamp, leaving the console unable to distinguish tenant data from demonstration data. Provenance is now applied where authentication actually happens, so no call site can emit untagged results.
- One malformed row killed an entire connector. Parsers written against documented vendor shapes crashed on real-world deviations, discarding every valid row alongside the bad one. Row parsing is now contained, and a summarizer failure raises a named error identifying the endpoint.
- Execution channels were never exercised end to end. The shell, browser, credential and production channels opened their own session for the policy call, so every test attempt failed closed at 503 and the real decision path went unverified. It is now driven directly: production shell commands are held for approval, destructive commands are not auto-approved, a self-asserted
caller_rolecannot escalate a decision, and Trust Fabric evaluates and flags every request. - Complete node surface. Custom Capability gained the
/findingsand/providersroutes it was missing, so all 26 nodes expose an identical contract. The four collapsed sidebar arms now open by default, making every node visible on load rather than only the nine under Protection. - AWS Security Hub is honest about its limits. It was registered as a native adapter but could not sign requests, returning an empty list indistinguishable from a clean account. It now raises with an explanation.
- Workspace UI. The
--rc-bgtoken was referenced in eleven places and never defined, so Cowork inputs and search fields rendered with no background — the root cause of that surface looking unfinished next to Chat and Security. Panel headers, hover states, file-tree density, context selection and the active-conversation indicator now follow one shared vocabulary in both light and dark themes.
What is verified and what is not. 26 of 26 nodes answer every operator call, 57 of 57 connectors complete a full fetch and correctly reject bad credentials, 189 platform routes load on an empty tenant, and 98 adversarial checks hold. Connectors are still exercised against responses shaped like vendor documentation; GitHub, VirusTotal and CISA KEV remain the only three confirmed against a live tenant.
Security mode previously had twelve provider names that could be configured but had no adapter behind them. That is now a build-breaking condition rather than a hidden product gap.
- All declared provider types are live-capable. Veracode, Orca, Jenkins, Code42, DTEX, Fortinet, OneTrust, Transcend, Google Workspace, Salesforce, Exabeam, and Securonix now have read-only adapters with matching configure forms, bounded outbound calls, Trust Fabric-gated credentials, provenance tagging, and explicit failure states.
- No partial Capability Nodes. Application Security, Attack Path Analysis, Security Automation, Insider Risk, Network Security, Privacy Governance, SaaS Security, and User Risk no longer contain a provider that silently has no execution path. A coverage test now rejects any mapped provider without an adapter.
- Special nodes scan what they actually own. Identity Security now uses the shared live connector scan path. AI Security aggregates governed AI-event telemetry. Release Governance evaluates the tenant deployment posture and control catalog. Custom Capability has a bounded root scan across configured definitions, with SSRF validation on every custom endpoint.
- Adapter failures are honest. The registry no longer converts an adapter error into a false successful empty response. Failed calls are reported as failures and the node keeps clearly labelled demonstration data instead of claiming a clean live scan.
Operational validation still matters. The adapters are complete in the product contract, but a vendor can change endpoint details or response envelopes. Enkstein fails closed to labelled demo data when that happens. The next production step is tenant-by-tenant connector verification through the now-real credential test rather than accepting a generic reachability result.
Auditing every connector's authentication path surfaced a contradiction: a connector could offer “Sign in with Microsoft” and still show Client ID and Client Secret fields directly underneath, which makes signing in look pointless.
- The credential form is now the fallback. Where browser sign-in is available the key fields collapse behind “Or enter API credentials manually”, and say plainly that they are only needed when you cannot sign in — an unattended service principal, for example. Connectors with no sign-in path are unchanged.
- Snyk and PagerDuty gain browser sign-in, bringing the total to 18 of 63 connectors: 6 that need no setup at all, and 12 that need a one-time OAuth client ID.
Why the remaining 45 stay key-based. Tenable, Qualys, CrowdStrike, Splunk, Wiz and the rest publish no OAuth authorization endpoint; their documented integration path is an API token. Converting a logged-in browser session into API access would mean reading session cookies or driving the vendor's pages, which breaks on any UI change and is the wrong trade for a tool holding production credentials. When those vendors ship OAuth, adding them is a table entry.
Interactive sign-in previously reached four connectors, because it used the device grant (RFC 8628) and few vendors publish a device endpoint. Enkstein is a desktop application, so it now uses the flow desktop applications are actually meant to use: an OAuth authorization code grant with PKCE, redirected to a loopback address only this machine can receive.
- Approve in a browser, no app registration. Microsoft connectors — Entra ID, Azure, Defender, Sentinel, Purview — sign in with one approval and no client secret, because Azure CLI publishes a loopback-registered public client. GitHub, GitLab, Google Cloud, Okta, Slack, Jira, ServiceNow, Auth0, and Datadog are supported once a client ID is supplied.
- You do not copy a code. Enkstein listens on
127.0.0.1for the provider's redirect, so approving in the browser completes the connection. The listener starts only while a sign-in is in flight and never logs the authorization code. - A connector says what it needs. Vendors that publish no shared public client ask for a one-time OAuth client ID and show the exact redirect URI to register. A connector with no OAuth endpoint at all does not offer a button that could only fail.
- Tokens keep working. Refresh tokens renew transparently through the same path adapters already use, so a scheduled scan does not stop an hour after sign-in.
What this is not. No cookies are read, no page is driven, and no vendor session is reused. Enkstein opens the provider's own consent screen; the grant is visible and revocable there. PKCE means no client secret is embedded in the distributed application. Sign-in passes the same Trust Fabric gate as manual credential configuration, a sign-in request is single-use, and a code issued for one connector cannot be redeemed into another.
A marketplace of 56 connectors is only worth having if a stranger can configure one and trust what it tells them. This release closes the three gaps between "the connector is listed" and "the connector works".
- Connected now means the credential was accepted. Previously most connectors were tested by reachability, so an unauthenticated 200 from a vendor's login page reported success and told an operator nothing. Every connector is now verified by calling the provider with the stored credential through the connector's own adapter. Local Terraform tooling is the one honest exception, and it says so.
- The configure form asks for the right fields. Security Hub and Defender for Cloud were asking for a bare API key that no AWS or Azure credential can satisfy. Adapter requirements and form fields are now reconciled, and a test fails the build if a connector ever requires a field the form does not collect.
- Vendor Risk is no longer inert. It was the one Capability Node where every provider it referenced lacked an adapter, so it could only ever show demonstration data. SecurityScorecard, Bitsight, and UpGuard adapters are added, and a test now asserts that no Capability Node is left without a live path.
- CISA KEV works with no credential at all. Threat Intelligence referenced the Known Exploited Vulnerabilities catalog but had no adapter for it. It is a free public feed, verified here against the live catalog: 1,653 real exploited vulnerabilities parsing correctly. ThreatFox and MISP adapters are added alongside it.
- Provider pills say when a credential would not help. A provider with no adapter used to look merely unconfigured, so an operator could connect a key and reasonably conclude the product was broken when the node kept showing sample data. Those providers now read "no live adapter yet" and are visually distinct from ones that are simply not connected. The pill was duplicated across 21 Capability Node pages and is now one shared component.
Honest limitation. The declarative adapters are written from vendor API documentation, not verified against live tenants. Some endpoint paths and field names will be wrong on first contact. The framework fails safe: a provider error falls back to clearly labelled demonstration data rather than inventing findings. GitHub, VirusTotal, and CISA KEV are the connectors confirmed against real responses so far.
Several Capability Nodes shipped with working provider adapters that their own scan route never called, and connecting a connector could make a module look broken. Both are fixed, and Microsoft connectors gain one-approval sign-in.
- Adapters are actually invoked. Privileged Access now calls its Entra and Okta adapters and Security Telemetry calls Splunk, taking the platform from five connector-backed Capability Nodes to seven. Nineteen nodes now share one scan path so behaviour cannot drift apart again.
- A configured connector no longer empties a module. Previously, connecting a credential to a node with no live adapter hid its demonstration findings and showed nothing, which reads as a broken scan. Those nodes now keep showing clearly labelled demonstration data and say why: "Connector configured, but no live adapter is available yet." A connector that errors keeps its demonstration data too, and reports the failure rather than silently showing an empty list.
- Interactive sign-in for Microsoft. Entra ID, Azure, Defender, and Sentinel connectors can be connected with the OAuth device grant: Enkstein shows a code, you approve once in a browser, and it receives a refresh token. No app registration and no client secret. This is a documented provider flow — no cookies, page automation, or vendor session tokens are involved, and the grant is revocable from the provider's own consent screen. Device sign-in passes the same Trust Fabric gate as manual credential configuration.
- Tokens refresh on their own. Adapters accept a device-code token in place of client credentials and renew it transparently when it expires, so scheduled scans do not quietly stop after an hour. GitHub device sign-in is present but stays disabled until a deployment supplies its own OAuth client ID, because GitHub offers no first-party public client; PAT configuration is unaffected.
The blocker for beta testing Security mode was that a tenant with one live connector still saw hundreds of demonstration findings with no way to tell them apart. Findings now carry a data origin.
- Origin on every finding. A new
data_originfield recordslive,simulated, orunknown, alongsidesource_connectornaming the connector behind a live result. Provider adapters tag their own output: the authenticated path reports live, the fallback path reports simulated. - Fails toward honesty. The finding pipeline constrains whatever an adapter sends to a known vocabulary and defaults to
unknownrather thanlive, so an untagged or unrecognised adapter can never be presented as verified customer data. A rescan that omits the origin cannot downgrade a finding already confirmed live. - Filter and see it. The findings console gains a data-origin filter, a per-row badge, a live-of-total count in the stats bar, and connector attribution in the detail drawer. The API accepts
?data_origin=and/findings/statsreturns aby_originbreakdown. - Migration
0004. Adds both columns and an origin index. Existing rows backfill tounknown, neverlive, so nothing already stored can be mistaken for real estate data.
Three gaps closed ahead of release, each with regression coverage.
- LLM02 — binary output handling. Provider-generated downloads introduced in v0.3.38 were opaque bytes, so a credential inside a generated script or workbook could reach the project folder unexamined. Downloads are now unpacked (including compressed OOXML/ZIP members) and DLP-scanned before they can become a governed change; a sensitive file is dropped and named in the reply instead of written.
- LLM04 — AI denial of service. Governed turn, streaming, and research endpoints are rate limited per authenticated identity. The key is the identity rather than the client IP, because every desktop request arrives from the same loopback address and an IP bucket would let one runaway conversation throttle the whole tenant. Tunable via
AI_RATE_LIMIT_WINDOW_SECONDSandAI_RATE_LIMIT_MAX_REQUESTS. - LLM09 — overreliance. Lowering a detected data classification is the direction that can route restricted content to a cloud provider, so it now requires an explicit
override_reason. The audit entry retains both the detected and the asserted level. Raising a classification stays frictionless, so operators are not nudged into leaving it unset.
When a provider runs its own tooling it produces a genuine document, spreadsheet, or archive — better than anything reconstructed from prose. Enkstein now asks for those files first, collects them from the visible completed turn, and writes them into the project folder byte for byte. Local rendering remains the automatic fallback.
- Downloads are read in the provider page's own session; no cookie, token, or credential is read, copied, or forwarded, and nothing is persisted to the broker journal.
- A provider file supersedes any text-derived change with the same filename, and inherits the directory the response chose, so it lands beside its siblings rather than at the project root.
- Attachments are bounded and re-validated at every boundary — extension, native broker, and backend — for name shape, count, and decoded size; traversal names and malformed payloads are rejected.
- Plain-text files (code, config, markdown) continue through the normal governed manifest, so a turn mixing scripts and documents applies completely.
A Brain can only return text, so a requested .docx or .pptx previously reached the folder as markdown under an Office extension — a file Word and PowerPoint refuse to open. Enkstein now renders the real Office binary locally from the Brain's markdown and mirrors that through the same governed write boundary.
.docx,.pptx, and.xlsxare rendered in the backend; headings, bullets, page breaks, code blocks, and markdown/CSV tables are preserved, and each#/##heading starts a new slide.- Binary content travels to the approved host root base64-encoded through the native broker, which applies the same containment, allowlist, and size checks as text writes.
- A document that cannot be rendered is skipped rather than written as broken text, so an unopenable file is never reported as applied.
- The Cowork project/review panel can be dragged wider (or maximized) up to 900px, with the width persisted; wide panels show full-height diffs and larger editor type for reading scripts before approval.
The governed Cowork execution contract now explicitly allows batching. When a change set is too large for a single response, the Brain delivers a coherent subset of complete files and names what remains, and Enkstein applies each governed batch as it arrives.
- The strict (smart) contract no longer implies emitting every file twice — file content is included once, inside the
marcellus_changesarray. - Partial or truncated files are still never accepted; only complete files are applied, and the automatic recovery retry uses the same batch-friendly instruction.
The interface now renders in Inter — self-hosted at build time with native SF Pro, Segoe UI, and Roboto fallbacks — for higher-contrast, more readable UI and chat text.
- Assistant Markdown gets a taller body rhythm, clearer heading hierarchy (with an underlined H1 and small-caps H5/H6), and roomier list spacing.
- Tables use tabular figures, zebra striping, and cleaner row rules; fenced code renders slightly smaller in a dedicated monospace stack with ligatures disabled for exact alignment.
Completed Cowork turns now retain an expandable Files changed ledger beside their governed context and Brain provenance.
- Every row identifies the relative project path, create/update/delete operation, and actual applied, proposed, skipped, or blocked result.
- The ledger is content-free, tenant-scoped governance metadata and remains visible when a conversation is reopened.
- Assistant output continues to render as sanitized Markdown with readable tables, labeled copyable code blocks, and Mermaid diagram labeling.
Cowork now accepts an exact standalone marcellus_changes label followed by a JSON array even when a Browser Brain omits Markdown fences. The array is removed from chat, validated, and routed through the existing governed proposal or Auto-apply writer.
- Every operation and relative path still passes the existing schema, protected-directory, project-root, and Trust Fabric checks.
- Output DLP no longer mistakes JSON-escaped framework decorators such as
\n@routes.routefor email addresses; real email addresses remain redacted.
Once a browser task has started, transient host-bridge status failures no longer terminate the turn. Enkstein reports a reconnecting state and continues polling until the task completes or reaches the existing governed browser deadline.
- The 890-second Brain bound and 900-second workspace bound remain unchanged.
- A focused regression test covers status failure, reconnection, streaming, and successful completion.
Browser turns are now allowed to wait for the same bounded 15-minute deadline enforced by the governed backend. This prevents a desktop WebKit/proxy heartbeat gap from turning a still-running ChatGPT task into a false UI failure.
- Local and API turns retain the short 75-second dead-stream guard.
- Browser tasks remain bounded by Trust Fabric and the backend deadline; this does not create unbounded background execution.
ChatGPT streams by replacing text nodes inside an existing assistant container. The Companion now records text and descendant mutations against that assistant message, allowing the stable completed answer to be correlated and returned to Enkstein.
- Reloading the extension can recover a pending task from its session metadata without persisting prompts, responses, cookies, or account tokens.
- Browser task lifecycle remains visible as queued, submitted, streaming, and completed; provider DOM content is still never journaled.
The dedicated local Qwen file author now runs after a plan-only response from either a Browser Companion or a Hybrid/local profile. Cowork no longer treats an Ollama architecture answer as a reason to skip implementation.
- The author receives its configured Ollama output budget, avoiding the short default reply that cut multi-file manifests off mid-generation.
- Complete entries in a truncated ordinary JSON fence are recovered, validated, and governed; the incomplete trailing entry is discarded.
- Live verification used the installed
qwen2.5:7bruntime to produce a parsedREADME.md,.env.example, andapp.pymanifest.
Browser Brains now act as advisors for Cowork implementation requests. When they return a plan rather than Enkstein’s governed file manifest, Cowork hands a bounded copy of that answer to the local Qwen file author.
- The local author produces a project-relative create/update/delete manifest, which is still checked by Trust Fabric and written only through the connected project-root bridge.
- Auto-apply writes each file individually; approval-first keeps the exact same changes reviewable. The live timeline now shows Browser plan handoff, local file author work, and each resulting write instead of presenting a plan as completed execution.
- Browser credentials, cookies, and sessions remain outside Enkstein. The local author receives only the user request and a bounded, redacted browser answer.
This release completes two provider compatibility paths that prevented the deterministic local writer from receiving an otherwise valid change request.
- Browser handoffs now use a bounded continuity capsule rather than inserting the full prior transcript into ChatGPT, avoiding contenteditable normalization failures on large conversations while preserving recent task context.
- Local-model JSON fences are normalized when they use common field names such as
typeandfile_path, including JSON-encoded object entries. They still pass the exact same project-relative path, protected-directory, Trust Fabric, and approved-folder checks as Enkstein-native manifests.
Cowork previously accepted a browser response such as “the files were already staged” even when the response contained no file contents. That could leave a connected local project unchanged while the answer sounded as though implementation had happened.
- File requests now require complete project-relative file output in the current response. The provider is explicitly told not to substitute a plan or refer to an earlier answer.
- If no parseable files arrive, Cowork makes one bounded governed retry in the same Brain session for the actual file manifest. It only writes after the normal Trust Fabric and local-folder checks pass, and otherwise says plainly that no local files were created.
The installer copied the new runtime correctly, but its frontend image could not build because an unrelated lockfile dependency had been changed to a nonexistent registry release during version stamping. The lock now retains the package's real published version, and a clean install and production build were completed before this replacement installer was signed.
The generic Next.js API rewrite can buffer or end a long-lived SSE response even when the FastAPI backend is emitting regular heartbeats. That made Enkstein's 45-second client watchdog report a failed turn while the Browser Companion continued to stream and ultimately completed the provider answer.
- Cortex turns now use a dedicated Node.js streaming route with a 15-minute maximum duration and explicit no-buffer headers. Provider progress and backend heartbeats reach the desktop UI as they arrive.
- The desktop idle guard now allows 75 seconds for a genuine network or WebKit scheduling delay, while the backend remains responsible for the 15-minute governed browser-turn deadline.
Long browser generations now keep their Companion connection live for their entire observed lifecycle. Previously, the extension correctly reported a submitted or streaming task, but the native bridge only refreshed readiness when it was idle and polling for new work. After its 50-second idle threshold, Enkstein could wrongly say it could not reach ChatGPT while the same signed-in tab was still actively producing the requested answer.
- A successful prompt submission, live streaming update, or completed browser task now acts as a verified Companion heartbeat for that provider.
- Subsequent turns and Brain Connections status stay ready while a large ChatGPT/Claude/Gemini response is in progress, without creating a second browser task or weakening pairing boundaries.
A request that legitimately took several minutes for a browser Brain to answer (for example, generating a full application scaffold) could still fail with "the governed turn stream stalled," even after the 0.3.20 timeout increase, and even though the browser session went on to complete the answer correctly. Root-caused by watching a real live 6-minute request: the governed turn's own request was being wrongly treated as disconnected by the client partway through, rolling the turn back before the Brain's answer could be persisted, while the browser task kept running to completion with nobody left to receive it.
- The turn stream previously checked
request.is_disconnected()once per heartbeat (every 10s by default). That call internally reads the same raw ASGI receive channel uvicorn itself uses; polling it repeatedly for the several minutes a long browser generation can take is a known false-positive source, and it is what was silently tearing the connection down mid-turn. - The stream now watches for a real client disconnect exactly once, in a single dedicated background task for the life of the turn, instead of repeatedly polling the same channel. Verified against a live 6-minute end-to-end reproduction through the real Docker/Next.js stack with no false disconnect and a clean completion.
Codex/Claude subscription and browser session detection could keep showing "needs setup" after a real, successful CLI login, and package updates could appear to install with no effect at all. The cause was not the detection logic -- it was that the native Brain Bridge (a separate always-on background process from the desktop app) could end up detached from launchd's supervision and never actually exit when the launcher tried to restart it. A brand new, correctly updated process would then repeatedly fail to bind its port behind the stuck old one and crash-loop forever, while the stale process from an earlier install kept answering every request with outdated code and stale Brain readiness.
- The Brain Bridge now installs real SIGTERM/SIGINT handlers, so a normal stop request always releases its port immediately instead of potentially being ignored.
- The launcher now verifies the port is actually free after asking the bridge to stop, force-killing whatever still holds it if it does not exit in time, and confirms a fresh process is genuinely listening before treating the restart as successful -- rather than assuming a requested stop/start always worked.
- The installer's postinstall step now also restarts the Brain Bridge service itself (previously it only relaunched the desktop app), so a package update takes effect immediately without requiring a manual process kill or reboot.
A large multi-file/full-app request could legitimately take a browser session (ChatGPT, Claude, Gemini) several minutes to generate. Every layer of the request budget -- the outer turn stream deadline, the per-Brain wait, the native bridge's own wait, and the bridge HTTP client's own timeout -- was sized for a normal chat answer, not a long generation, so the turn was silently abandoned partway through even though the provider tab went on to finish the answer.
- The outer streamed-turn deadline for browser sources raised from 210s to 900s (15 minutes).
- The per-Brain browser wait in the Cortex Gateway raised from 170s to 890s, staying inside the new outer deadline.
- The native Brain Bridge's own browser wait raised from 180s to 900s to match.
- The bridge's internal HTTP client timeout, previously fixed at 180s for every call, now accepts a per-call override so the (fallback) blocking browser invocation is no longer cut off underneath the bridge's own longer wait.
The native Brain Bridge already tracked real browser-session states (queued, leased, submitted, streaming) internally, but those states were discarded at the bridge boundary -- the backend only ever saw one final response after up to 170 seconds of silence. Cowork's file-apply step also only ever reported one summary count, never which files actually changed.
- The native bridge now exposes non-blocking
/v1/browser-invoke/startand/v1/browser-invoke/statusendpoints alongside the existing blocking call, so a ChatGPT/Claude/Gemini browser turn's real lifecycle state is polled and forwarded live instead of only surfacing after the fact. Older bridge builds without these endpoints fall back to the original blocking call automatically. - Cowork's auto-apply writer now reports each file's write/delete outcome individually as it happens, instead of a single end-of-batch count.
- The in-flight activity feed is now a real two-layer execution timeline: Enkstein's own pipeline stages (context compiled, sent, files written) apply to every Brain, including a fully local Ollama turn that has nothing else to show; a separate Brain-native layer surfaces the answering Brain's own real states only when that source actually reports one -- a browser turn now genuinely shows "waiting for ChatGPT to respond" / "ChatGPT is streaming" rather than a single opaque "Cortex is working" badge, and nothing is invented for sources that have no native state.
- The browser companion extension's manifest version now tracks the desktop app version on every release (starting here at 0.3.19) instead of its own separate counter, and it ships the same octopus mark as the desktop app icon instead of the browser's default puzzle-piece icon.
Opening a conversation from a different Cowork project than whatever the sidebar's project picker had selected could leave the previous project's files showing in the right-hand file panel -- and selectable for a new turn -- because artifact loading was handled ad hoc in several different code paths, each only covering its own trigger.
- One project (the project of whichever conversation is actually open) now exclusively owns the file panel's contents, replacing the scattered per-action refreshes that could each individually forget to update.
- The file panel header now names the project it's showing, and the sidebar's own project selector is kept in lockstep with it, so the two blades can no longer disagree about which project is active.
- Creating a file, adding files, and syncing a local folder now always target the project that's actually open, not whatever the sidebar dropdown happens to show.
A Brain could correctly produce a full project scaffold (for example, a nested layout staged with .keep files), yet Cowork failed to create it locally.
- The native writer rejected any file whose extension was not on a fixed allowlist. Extensionless dev markers like
.keep/.gitkeepand common source types such as.swiftwere refused, so an Apple-app scaffold could never be written. The writer now accepts these, matched by full name for extensionless files, while backend path validation still blocks secret files and protected directories. - Agent-turn extraction silently capped at 10 changes, truncating larger scaffolds. The cap now matches the manual batch ceiling (100), so a real multi-directory layout is applied in full.
A browser turn could reach ChatGPT and produce a visible answer, yet Enkstein never captured it back — the companion waited on the provider's stop/streaming control to clear, and if that control lingered in the DOM or its selector drifted, the finished answer sat unread until the invoke timeout.
- The companion now accepts a completion when the visible answer has been non-empty and unchanged for a short stall window, even if the streaming indicator still reads active.
- The normal fast path (finish the instant streaming stops) is unchanged; this only adds a fallback so selector drift can no longer strand a rendered answer.
- Browser Companion bumped to 0.1.12 — reload it in your browser's extensions page to pick up the fix.
Cowork agent mode previously only wrote files when a Brain emitted a strict marcellus_changes JSON block, which browser chat models (ChatGPT/Gemini/Claude web) rarely produce — so "build me an app" gave structure in the reply but created nothing on disk.
- Structure modes: Smart (strict JSON protocol), Fast (scrape filename-labelled code fences), and Auto (try the protocol, fall back to code fences) — chosen from the Cowork composer.
- Auto-apply: when enabled and a local folder is connected, extracted changes write straight into the folder through the existing Trust Fabric path and become active file versions; with no folder connected it safely degrades to pending review.
- The Brain now receives format guidance it can actually follow, and the file tree refreshes automatically after applied changes.
- Safe Markdown: headings, paragraphs, lists, tables, links, inline code, blockquotes, and citations render through a sanitized renderer (no raw HTML; dangerous URL protocols stripped; links carry
rel="noopener noreferrer"). - Code blocks: fenced code shows a language label, readable light/dark styling, exact whitespace with horizontal scrolling for long PowerShell/Python/Terraform, and an accessible Copy button with tooltip and copied state.
- Operational blocks: change proposals, Codex approvals, and terminal failed/timeout/interrupted turns render as compact professional blocks instead of raw JSON.
- Retry & Continue: terminal failed/timeout/interrupted normal turns offer Retry (replays the preserved message as a fresh turn — safe because the turn rolled back server-side) and Continue (returns the message to the composer), preserving draft and conversation without duplicate submission.
- Response provenance: a compact record shows source/provider/model, runtime group, policy outcome, latency, confidence, input/output redaction, and fallback reason.
- Heartbeats: while a governed turn is still running the SSE stream emits a periodic heartbeat (configurable via
WORKSPACE_STREAM_HEARTBEAT_SECONDS) so proxies and browsers never see an idle connection during long turns. - Hard deadline: a turn that outruns
WORKSPACE_STREAM_DEADLINE_SECONDSis cancelled, its transaction rolled back, and a terminalturn_timeoutevent delivered — the stream can never run indefinitely. - Guaranteed terminal state: every stream ends in exactly one of
turn_completed,turn_failed, orturn_timeout; failures carry a bounded non-leaking detail rather than raw exception text. - Client-disconnect release: if the client goes away mid-turn the governed work is cancelled and the transaction released instead of streaming into a dead socket.
- Preserved chunk integrity: the persisted permitted assistant output is re-chunked into bounded deltas that reconstruct long multiline scripts byte-for-byte, and the web client now enforces its own idle-read watchdog so a dead stream cannot hang the UI.
- Connection dropping with the tab still open: Chrome suspends the extension's MV3 background service worker when idle, silently stopping its plain interval-based check-in, and only wakes it back up on its own scheduled alarm -- which has a 30-second floor. The native bridge previously only considered a companion connected for 15 seconds since its last check-in, a window shorter than that floor, so a perfectly healthy, still-open tab was guaranteed to be reported as disconnected between wake-ups. The bridge now allows 50 seconds, and the extension additionally re-checks in immediately whenever a tab is activated, a window regains focus, or a provider tab finishes loading, instead of only on its regular schedule.
- Sign in button for CLI subscriptions: Codex and Claude Code CLI cards on Brain Connections now have a Sign in button. CLI login is an interactive OAuth device-flow that cannot be completed silently, so this opens Terminal.app running the exact resolved CLI binary's login command instead of requiring the user to find and type it manually (macOS only in this release).
- Explicit Markdown formatting guidance: every Brain now receives guidance to use GitHub-flavored Markdown -- bold key terms and section titles, tables for comparisons, numbered/bulleted lists for steps, fenced code blocks with a language tag -- matching the default formatting style of ChatGPT, Claude, and Kimi, instead of defaulting to flat prose. The renderer (SafeMarkdown) already supported all of this; only the guidance was missing.
- Lost context on Brain switch: a Browser Companion turn (ChatGPT/Claude/Gemini tab) sends only the current message by design, on the assumption that the paired provider tab already holds every prior turn -- but that assumption breaks the moment a different Brain starts answering. Enkstein now compares the previous reply's actual answering source against the current turn's target Brain; when they differ, the newly addressed Brain receives the full bounded conversation transcript instead of only the latest message, so switching engines mid-conversation no longer causes the new Brain to respond as if the conversation just started.
- Browser Companion in Auto Brain's fallback order: Chat mode's "Auto Brain" now falls back to the ChatGPT, then Claude, then Gemini browser sessions (in that order) when the Codex/Claude CLI subscriptions are unavailable or unauthenticated, before falling back further to configured API profiles and finally the local Ollama boundary -- so a host without an authenticated CLI subscription but with a signed-in ChatGPT tab still gets a real answer through Auto Brain instead of skipping straight to a weaker fallback.
- Silent truncation on long single inserts: the browser's native
execCommand('insertText')can silently truncate a large single call while still reporting success, and the previous Gemini-specific line-by-line fallback only verified the result once, after every line had already been attempted -- so a truncation partway through was invisible until the very end, and the last-resort recovery was an equally unverified blind retry. Prompt insertion for every contenteditable provider now writes in small chunks and re-reads the editor's real content after each one, so a truncation is caught at the exact point it happens; if a pass fails, it retries with a smaller chunk size instead of guessing.
- Folder-picking accumulation: when no Cowork project was active, picking a folder that happened to share a name with an older, unrelated project silently rebound that old project (with all its history) instead of starting fresh -- the actual cause of "keeps adding on top of old projects/folders." Both the native-folder-picker handler and the plain-file-input fallback now always create a brand-new project in that case; the name-matching lookup is removed entirely.
- Scope leaks fixed while making this change: native-workspace-status and artifact-loading effects were reachable for any project regardless of mode, so a Chat project could trigger folder-sync/artifact fetches it has no business making; both are now explicitly Cowork-only.
- Pick a folder from New Project: the left blade's "New Project" form can now open the native folder picker directly instead of only accepting a typed name, using the same proven folder-picker mechanism Cowork's "Import folder" already relies on.
- Separate Chat projects: Chat now has its own lightweight project/folder concept for organizing conversations, walled off from Cowork's projects -- different list, different dropdown, different remembered selection, and the same name can be reused in both without colliding. Chat's project is sidebar-organizational only (no local folder binding, no URL segment) and is optional.
- VS Code-style folder tree: Cowork's file panel groups artifacts into real, independently collapsible folder nodes instead of indentation on a flat list. Folders default expanded per project and newly-appeared folders (e.g. after a sync) auto-expand without re-collapsing folders the operator already closed by hand.
- Copy a message or the whole chat: every message (user or assistant) gets a hover-revealed copy-to-clipboard control, and the conversation header gets a "copy whole chat" button that copies the full transcript labeled by role, in order.
- Local folder switching: connecting a different local folder to the same Cowork project kept showing files from every previously-connected folder, since a sync only ever added or updated files and never removed one that disappeared from the bound folder. Every sync now marks a previously native-synced artifact deleted (recoverable) once its path is no longer present, while files created or uploaded directly in Enkstein are never touched by this.
- Browser Companion change protocol: a ChatGPT/Claude/Gemini browser tab in Cowork agent mode was never told it could propose a governed file write, so a request like "create that script in this project folder" always failed with "I cannot place it into the project folder" even though the response parser already knew how to handle exactly that kind of reply. The browser-turn prompt now includes the same governed change protocol the direct-API path already sends.
- Custom Brain swarm builder: a new "Build a Swarm…" option in the existing Brain source picker (Chat, Cowork, and Security all share it) opens a checklist of every ready Browser Companion session, subscription CLI/desktop app, and API/local profile. Pick any mix, set how many must agree, and the turn runs them concurrently through the existing consensus/vote mechanism. The selection is remembered locally and can be reopened from a compact toolbar button.
- Local scanner Brain: a bounded, local-only Ollama Gemma profile (
gemma_scanner) pre-summarizes a Cowork project's files into a compact index before a heavier Brain sees them, engaging only once a project has enough files to make navigation worthwhile and never on an already-local turn. - RTK-style token hygiene: a pure, deterministic compactor strips terminal noise, collapses long runs of duplicate lines, and folds log-shaped info/debug spam into an omission count while preserving every error/warning line verbatim — applied ahead of the existing size caps on native Codex output and fetched research pages.
- Lost long browser responses: Browser Companion sessions (ChatGPT/Claude/Gemini tabs) were cut off by a uniform 60-second timeout well before the native bridge's own 180-second patience window elapsed, silently discarding an in-progress long response. Browser sources now get a dedicated, longer budget; every other source kind is unchanged.
- Stream deadline awareness: the turn-stream route's overall deadline now extends automatically whenever any requested source — direct or inside a custom swarm — is a browser session, instead of applying the same tight ceiling regardless of what was requested.
- Truncated file-change recovery: when an agent-mode response proposing file changes was cut off mid-generation, the change block never closed and every proposed change was silently dropped. A truncation-tolerant recovery pass now salvages whichever individual changes completed before the cutoff and reports the truncation clearly instead of showing zero changes with no explanation.
- Stale Cowork file panel: switching Cowork projects while a slower request for the previous project's files was still in flight could let that stale response land last and show the wrong project's files. The load effect now guards against this the same way the rest of its lifecycle already does.
- Effective classification: governed workspace and native Codex paths use the highest request, conversation, Project, and included-artifact classification; restricted/top-secret paths fail closed without an approved local Brain.
- Safe Codex output: agent deltas, plans, diffs, command approvals, and reasons are bounded, DLP-scanned, secret-redacted, injection-checked, and stripped of absolute native paths before client delivery.
- Browser reliability: response identity replaces count-based correlation; delayed ChatGPT/Gemini SPA URLs are sanitized, persisted, and restored; durable journal errors use bounded codes only.
- Task attribution: Project ids are server-resolved and owner/tenant checked; requester, orchestrator, specialist, classification, and dependency evidence ids reach policy and audit records.
- Final provenance: context manifests are reconciled with actual ordered adapter attempts, policy outcomes, selected provider/model, fallback reason, effective classification, redaction, digests, and citations.
- Denied-call audit: explicit and consensus subscription Brains rejected by the restricted-data boundary now write a durable blocked model-call record without invoking the provider.
- Known limits: task-graph timeouts and dependency skipping are implemented, but provider-side cancellation is not claimed; provenance records runtime adapter attempts, not vendor-side prompt retention.
- Workspace isolation: Chat never loads Cowork Projects/files, Cowork state remounts independently, and conversation/project/folder changes appear immediately.
- Governed runtime groups: Local fails closed at the local profile boundary, Hybrid is local-first, Cloud excludes local/desktop/browser fallbacks, and covered restricted workspace requests are pinned local.
- Live Brain readiness: status discovery passes through Trust Fabric, forced refresh bypasses stale failures, and installed-but-unauthenticated CLIs remain Needs setup.
- Safe CLI bridges: Claude Code is preferred; Codex and Claude prompts use stdin with read-only/tool-disabled execution. Claude Browser hides only while Claude CLI is healthy.
- Native Codex agent: connected Cowork projects use one resumable, root-scoped official Codex App Server thread with bounded streamed events, governed one-shot command/file approvals, deny-only permission expansion, cancellation, and recovery.
- Bounded task graph: explicit specialist DAGs use the existing Cortex Gateway with graph and peer-message policy checks, ordered fallback, isolated bounded concurrency, timeouts, dependency skipping, and per-node attempt provenance.
- Known limits: runtime groups and role presets are not persisted per conversation/Project; native agent output is transient rather than conversation history; hardware-aware model recommendations/confirmed pulls and additional provider adapters remain planned.
- Tenant-bound Cortex: profile reads, model-call history, direct Brain invocation, consensus, and compatibility routing reject cross-tenant access.
- Operator-owned configuration: model profile mutation requires a runtime operator or administrator identity.
- Bounded Multi-Brain execution: per-tenant and per-source concurrency limits prevent one workload from saturating every Brain.
- Safe timeout behavior: slow Brains return an explicit unavailable vote without exposing provider details or blocking the remaining consensus.
- Architecture preserved: Chat, Cowork, Security, local Ollama, subscription bridges, browser sessions, and deterministic consensus retain their existing contracts.
- Unified presentation: navigation, operational pages, Swarm participants, schedules, policies, notifications, and current documentation use Enkstein capability names.
- Compatibility preserved: existing
/api/v1/*clawroutes, database fields, task contracts, and module imports are unchanged. - Safe translation: only known legacy module names are translated; external products such as OpenClaw and literal compatibility paths remain intact.
- Correct hierarchy: Security Arms identify domain pillars and Capability Nodes identify individual workers.
- Ollama discovery: the Model Cortex reads the live provider-status endpoint instead of a connector-record route with an overlapping path.
- Local model selection: a healthy Ollama runtime and its installed models now appear ready in Chat and Cowork.
- Controlled editors: paste-aware and provider-specific insertion keeps vendor application state synchronized.
- Gemini multiline prompts: paragraph-aware insertion prevents the governance preamble from displacing the actual question.
- Regression coverage: backend provider readiness and three browser editor behaviors are tested directly.
- Editor compatibility: the companion waits for provider state synchronization before using compatibility fallbacks.
- Complete content checks: line endings, non-breaking spaces, and invisible editor markers are normalized without accepting truncated prompts.
- Large input support: controlled editors can receive long workspace context through bounded native insertion chunks.
- Useful errors: Cortex now returns the specific provider failure instead of replacing it with a generic no-Brain message.
- Controlled-editor support: contenteditable prompts use browser-native text insertion so provider application state receives the complete prompt.
- Provider-specific Send detection: the companion waits for an enabled ChatGPT, Claude, or Gemini Send control before clicking it.
- Submission verification: Enkstein confirms the composer cleared or changed; a prompt left sitting in the message box now fails clearly instead of waiting for a response that will never arrive.
- Large-prompt regression: automated browser coverage verifies that a complete PowerShell script is inserted, submitted, and returned to Enkstein.
- Complete Cowork attachments: explicitly selected text files are sent in full up to 100,000 characters; oversized selections fail clearly instead of sending partial code.
- Current-turn browser prompts: persistent provider threads receive only the current governed turn, avoiding repeated history and preserving full attachment capacity.
- Durable thread recovery: local provider conversation URLs reopen the same ChatGPT, Claude, or Gemini thread after a tab or browser restart without storing authentication tokens.
- Enkstein desktop: the visible app, login, workspace, dashboard, native shell, and browser companion use the new Enkstein identity.
- Safe migration: existing Enkstein API routes, bundle identifier, encrypted data path, credentials, projects, and conversations remain compatible.
- Conversation affinity: the first turn opens a provider tab and subsequent turns reuse that exact tab.
- Clear boundaries: new and branched Enkstein conversations receive separate provider threads.
- Opaque identity: tenant and conversation identifiers are hashed before reaching the native bridge or companion.
- Recovery: closing a bound provider tab clears its mapping and the next turn opens a replacement thread.
- Browser companion: one-time loopback pairing, exact provider-origin access, visible page controls, and no cookie or account-token extraction.
- Honest readiness: only an open signed-in tab with a compatible message field is reported ready; changed or unsupported provider pages fail closed.
- Governed routing: Trust Fabric decisions, data-classification blocking, prompt redaction, output scanning, tenant checks, and model-call audit remain mandatory.
- Multiple paths: Codex CLI, Claude host runtime, compatible desktop sessions, browser sessions, approved APIs, and local Ollama Brains can participate in explicit consensus.
- Resilient broker: browser work is serialized by provider, pairing rotates the local token, and timed-out work is removed without accepting stale completions.
- Live selection: profile defaults, preferred models, security-tuned models, and general fallbacks are matched against Ollama's live inventory.
- Alias support: names such as
llama3.2correctly match an installedllama3.2:latesttag. - Fail closed: an explicit missing model is rejected rather than silently replaced.
- Provenance: the actual local model used remains visible in the governed response.
- Tool-using Cortex: streaming turns, review-before-write proposals, and parallel multi-Brain consensus.
- Governed research: bounded browser and workspace tools, injection and sensitive-data scans, citations, and encrypted artifacts.
- Persistent Missions: scheduled bounded Swarms with pause, resume, run-now, fixed read/analyze/recommend authority, and Trust Fabric enforcement.
- Memory Heart: encrypted Mission intent and observations, operator approval before reuse, tenant isolation, and overnight intelligence.
- Mission Control: Cortex health, active Missions, material changes, decisions, running Arms, Reflex metadata, and blocked activity.
- Reliable organization: in-app archive and move dialogs replace unsupported browser confirmations in the desktop shell.
- Native folder grants: the macOS picker creates a protected opaque grant and synchronizes only bounded text files.
- Real file operations: create, edit, rename, move, resync, and recoverably trash files in the approved folder.
- Defense in depth: Trust Fabric authorization, encrypted bindings, tenant checks, traversal and symlink rejection, and a recoverable `.marcellus-trash` path.
- Persistent file context: up to 20 active project files are automatically attached to bounded Cowork turns unless the operator clears them.
- Project editor: create files by path, edit encrypted content, save new versions, and delete active files from the Cowork pane.
- Conversation organization: delete active chats or move them into a selected Cowork project from the header or left blade.
- Policy enforcement: file writes, file deletes, chat deletes, and project moves are tenant-scoped and Trust Fabric authorized.
- Codex models: model choices are read from the authenticated host Codex model cache and passed through the governed subscription bridge.
- Claude models: subscription-default, Sonnet, Opus, and Haiku choices appear when the Claude host runtime is installed and authenticated.
- Provider readiness: unavailable subscription, API, and local Brains are visibly disabled instead of failing only after submission.
- Provider models: verified NVIDIA, Gemini, and installed Ollama model inventories drive the model picker.
- Native folders: Cowork uses the macOS folder panel and explicitly imports selected text files into its encrypted artifact store.
- Quieter workspace: outer frames, response borders, and composer edges were removed from Chat and Cowork.
- Chat blade: new conversation, search, encrypted history, message counts, and active-chat selection.
- Cowork blade: project creation and selection, project-scoped conversations, search, and active-work indicators.
- Security blade: Cortex & Hearts, Capability Studio, and every Security Arm remain isolated to Security mode.
- Unified workspace: the duplicate nested conversation rail was removed so the main canvas has more room.
- Persistent mode switch: direct Chat, Cowork, and Security destinations remain visible beneath the logo, including collapsed-sidebar mode.
- Runtime fingerprint: the desktop launcher compares packaged content as well as the version before reusing an installed runtime.
- Reliable relaunch: package updates close the stale desktop process and open the newly installed application automatically.
- Persistent workspace: encrypted tenant-scoped conversations, search, archive, branching, and redacted titles.
- Cowork Projects: explicit folder/file import into an encrypted, versioned, path-bounded artifact store.
- Adaptive Brains: mode-aware routing with candidate, attempt, selection, and policy provenance.
- Gemini: approved Gemini API connector/profile with real credential verification; no desktop OAuth extraction.
- Security handoff: approval-gated Swarm creation from a tenant-bound encrypted conversation reference; bounded context is decrypted and redacted only during task execution.
- Workspace: top-level Chat, Cowork, and Security modes with selectable subscription, API, local, automatic, and consensus Brains.
- Cortex Gateway: full-conversation DLP, prompt-injection audit, Trust Fabric decision per source, output scan, and call metadata audit.
- Data boundary: automatic restricted and top-secret requests remain local; explicit subscription requests with those classifications are blocked.
- Swarm Judge: summary synthesis now uses the real Cortex Gateway and preserves deterministic fallback.
- Codex Subscription Bridge: official ChatGPT login detection and ephemeral read-only reasoning invocation through a signed native host helper.
- Claude host bridge: explicit official runtime and account status with tool-disabled prompt execution when available.
- Browser Session Bridge: explicit ChatGPT, Claude, and Gemini browser-session routing through a narrowly scoped companion that uses visible page controls, never reads cookies or account tokens, and fails closed when a provider page is incompatible.
- Consensus: concurrent subscription, API, and local votes with unavailable and policy-denied sources excluded from confidence.
- Zero Trust boundary: per-install bridge secret, local peer restriction, Trust Fabric decision per source, tenant/profile checks, output re-scan, and call audit.
- Operator UI: Model Cortex now shows native Brain readiness, source selection, agreement, confidence, provenance, and fallback reasons.
- First-run security: local owner password creation, Authenticator QR enrollment, TOTP confirmation, and ten one-time recovery codes.
- Owner login: password plus replay-protected TOTP; password-only native owner bypass removed.
- Console lock: session-scoped tokens, 30-minute inactivity lock, and explicit menu-bar lock control.
- Always-on operation: closing or quitting the console leaves monitoring, schedules, Swarms, and governed Reflexes running.
- Supply-chain hardening: frontend upgraded to patched Next.js 16 with a zero-vulnerability production npm audit.
- Plexus: encrypted payloads, Ed25519-signed envelopes, TTL, replay protection, policy decisions, participant-only payload reads, approval, and acknowledgement.
- Reflexes: typed event conditions, authority ceilings, cooldown/rate budgets, event deduplication, Trust Fabric enforcement, and Ring Policy approval gates.
- Regeneration: secret-free encrypted checkpoints, signature and digest verification, quarantine, six restoration stages, and health-gated logical runtime rejoin.
- Operator console: live Plexus, Reflex, checkpoint, approval, and regenerated-runtime controls at
/marcellus. - Security: exact tenant-scoped approval lookups, self-approval defense in depth, atomic approval claims, and restricted decrypted-message access.
- Brand: the supplied red octopus artwork replaces inherited application logo assets.
- Desktop packaging: one-click
Enkstein-VERSION-macos.pkgandEnkstein-VERSION-windows-x64-setup.exelaunchers use isolated app IDs, state paths, shortcuts, and the Enkstein icon. - Native macOS shell: a universal Intel/Apple Silicon WebKit app owns the Enkstein window, shows first-launch progress, keeps local navigation in-app, and opens only external links in the system browser.
- Startup readiness: the frontend waits for backend health, while the launcher verifies backend and UI endpoints before displaying the operator console.
- Capability navigation: the operator sidebar presents Security Arms and Capability Nodes by function while retaining compatibility routes behind the UI.
- Release bundles: build scripts produce
.tar.gzand.zippackages containing the backend, frontend, production Compose model, installer, and deployment documentation. - Secure installer:
install.shvalidates prerequisites and generates unique application, PostgreSQL, and Redis secrets without replacing an existing environment file. - Persistent runtime: the release Compose model uses named volumes for PostgreSQL, encrypted connector credentials, and runtime state instead of development source mounts.
- Python artifacts: tagged releases build CLI, governance-core, and MCP wheel/source packages.
- macOS: builds
/Applications/Enkstein.appinside a Developer ID-signed, notarized, and stapled.pkg; installation launches Enkstein for the signed-in user. - Windows: builds a per-user Inno Setup executable with Start Menu/desktop shortcuts, Docker startup, secure environment initialization, and optional Authenticode signing.
- Integrity: every published asset is covered by
SHA256SUMS.
- Terraform MCP provider: Terraform Governance now reports Terraform MCP as a provider surface and maps the
terraform_mcpconnector to Terraform Governance. - MCP tools: the Enkstein MCP server exposes
terraclaw_generate_secure_terraform,terraclaw_review_hcl, andterraclaw_analyze_plan. - Agent response contract:
/api/v1/terraclaw/generatereturns MCP mode, agent trace, output artifacts, applied controls, framework metadata, and next actions. - Cloud coverage: added a secure GCP Cloud SQL PostgreSQL template with private networking, encrypted storage, backups, SSL-only connections, and deletion protection.
- Generate UI: the Terraform Governance Generate tab now behaves like a chat-style agent surface with Review and Plan handoff buttons.
http://localhost:3000.
- Frontend container: switched Docker runtime from
next devto productionnpm run build+npm run start. - Compose mounts: removed frontend bind mounts that could shadow the baked
.nextbuild output and cause missing manifest errors. - API proxy: bakes
INTERNAL_API_URL=http://backend:8000into the frontend image so browser/api/v1/*calls route correctly inside Docker. - Root route:
/now renders the dashboard directly instead of relying on a server redirect shell. - Verification: confirmed
/,/dashboard,/control-center, and/api/v1/dashboard/control-center-summaryreturn HTTP 200 locally.
- Build endpoint: added
POST /api/v1/terraclaw/buildfor natural-language Terraform module generation. - AI Security safety scan: build requests run prompt-injection and sensitive-pattern checks before module generation.
- Secure module output: generated modules include secure-by-default controls such as private networking, encryption, diagnostics, managed identity, and secret generation where applicable.
- Build UI: Terraform Governance page now starts on a Build tab with intent summary, generated module, security controls, review findings, and deploy steps.
- Terraform HCL review: Trust Fabric-gated review for public exposure, weak data protection, excessive IAM, hardcoded secrets, missing diagnostics, and risky Kubernetes control plane settings.
- Secure Terraform generation: generates security-first Terraform templates and immediately runs the Terraform Governance rule review on generated code.
- Plan risk analysis: analyzes Terraform plan changes before apply and returns APPROVE / WARN / BLOCK decisions with risky-change details.
- Provider surfaces: exposes Terraform Cloud, tfsec/Trivy, Checkov, and Infracost connector status with scan-path registration.
- Swarm support: adds
POST /api/v1/terraclaw/task, Swarm dispatcher routing, connector-state metadata, and normalized 0-100 risk scores for Findings and task output. - Docs: README, technical docs, landing page, maturity matrix, production deployment guide, and changelog now describe Terraform Governance consistently.
- Universal deployment contract: deployment preflight normalizes source, environment, app, change ref, deployment type, mode, artifacts, execution plan, rollback plan, model profile, and classification.
- Adapter catalog: GitHub Actions, GitLab CI, Jenkins, Azure DevOps, ArgoCD, Terraform Cloud, AWS/Azure/GCP CLI, Kubernetes, Helm, Docker, Docker Compose, Bash, PowerShell, Python, Node, Ansible, webhook, and custom paths are represented as governed handoff adapters.
- Trust Fabric gating: preflight, approval, and execution handoff are policy-governed and audited; self-approval is blocked.
- Evidence bundle: deployment gates include required controls, Capability Node coverage, blockers, warnings, policy decision, handoff metadata, and SHA-256 chain-of-custody hash.
- UI: Release Governance page added to the Infrastructure blade with templates, adapters, preflight form, approval, execute handoff, recent gates, and evidence hash visibility.
- Backend focused tests:
cd backend && .venv/bin/python -m pytest tests/test_releaseclaw.py tests/test_claw_task_endpoints.py tests/test_swarm.py -q→ 36 passed. - Backend full suite:
cd backend && .venv/bin/python -m pytest -q→ 286 passed, 3 skipped, 7 xfailed, 2 xpassed. - Frontend:
cd frontend && npm run lintandcd frontend && npm run buildboth passed.
- Provenance completion: added
data_source/connector_stateto remaining focused task handlers (Intel, Privacy, Vendor, Insider, User, SaaS, Custom). - Regression expansion: dispatcher routing provenance tests now cover all currently swarm-routed capability nodes.
- Log hardening: Cloud Security and Endpoint Security provider scan failures now log sanitized provider context without embedding raw exception payloads.
- MCP scan hardening: AGT adapter now resolves relative paths from repo root, rejects empty paths, and blocks traversal/absolute outside-repo inputs.
- Regression coverage: trust-fabric tests added for traversal block, absolute-path block, empty-path rejection, and valid repo-relative path handling.
- Provenance expansion:
data_source/connector_statenow surfaced for Data/Net/Log/Config/AttackPath/App/Compliance/Recovery/Automation focused task responses. - Error-surface hardening: additional API routes now return sanitized validation errors without raw exception payloads.
- Dispatch gate: remote dispatch now blocks when
last_seenis stale beyond TTL. - Dispatch gate: remote dispatch now blocks when trust score is below minimum threshold.
- New endpoint:
GET /api/v1/remote-agents/healthreturns healthy/stale counts and per-agent dispatchability. - Regression coverage: tests added for stale heartbeat, low trust score, and health endpoint response shape.
- Evidence export: added
POST /api/v1/complianceclaw/evidence/exportfor audit-ready JSON bundles. - Trust Fabric gate: evidence export can be denied by policy before findings or audit logs are returned.
- Chain of custody: export responses include per-framework rollups and a SHA-256 bundle hash.
- Production guide: added
docs/production-deployment.mdwith TLS, secrets, database, Redis, CI security, and backup/restore expectations.
- Backend tests:
cd backend && .venv/bin/pytest tests/test_compliance_evidence_export.py -q→ 2 passed.
- Update preview: added
POST /api/v1/skill-packs/{id}/preview-updateto show skill, connector, Capability Node, and scope-permission diffs before applying a pack upgrade. - Installed-pack upgrade: added
POST /api/v1/skill-packs/{id}/upgradewith bounded previous-version snapshots stored in manifest lifecycle metadata. - Rollback: added
POST /api/v1/skill-packs/{id}/rollbackwith rollback actor and reason metadata. - Operator visibility: pack responses now expose
rollback_availableso the UI/API can show whether a pack can be restored.
- Backend tests:
cd backend && .venv/bin/pytest tests/test_skill_packs.py -q→ 4 passed.
- Runtime memory context: Swarm dispatcher now injects short, redacted tenant/incident memory into task input when relevant memory exists.
- Task provenance: task outputs include
memory_context_loadedfor audit/operator visibility. - Memory proposals: high-risk Swarm Judge results create proposed
IncidentMemoryentries linked to the swarm job. - Safety scan: memory writes are blocked when summaries resemble secrets or prompt-injection payloads.
- Backend tests:
cd backend && .venv/bin/pytest tests/test_swarm.py -q→ 13 passed.
- Enrollment token endpoint: added
POST /api/v1/remote-agents/enrollment-tokenwith signed tenant/owner/scope metadata and expiry. - Registration guardrails: remote-agent registration can validate enrollment token tenant, owner, allowed actions, allowed Capability Nodes, and allowed connectors.
- Key rotation endpoint: added
POST /api/v1/remote-agents/{agent_id}/rotate-keywith duplicate-key rejection and rotation audit metadata. - Capability inventory: registration and heartbeat can now persist remote-agent capabilities for operator and dispatch context.
- Backend tests:
cd backend && .venv/bin/pytest tests/test_remote_control.py -q→ 24 passed.
- New preset:
POST /api/v1/swarm/jobs/presets/microsoft-identity-incidentlaunches Identity, Cloud, Endpoint, Log, Threat, Compliance, and Automation tasks. - Connector preference metadata: preset input declares Entra ID, Azure Defender, Defender Endpoint, and Microsoft Sentinel as preferred connector families.
- Identity Security task upgrade:
POST /api/v1/identityclaw/tasknow attempts Entra-backed findings through configured connector credentials before falling back to persisted or seeded data. - Swarm UI: incident preset controls now include a Microsoft Incident quick-launch action.
- Backend tests:
cd backend && .venv/bin/pytest tests/test_claw_task_endpoints.py tests/test_swarm.py::test_microsoft_identity_incident_preset_creates_connector_oriented_job -q→ 17 passed. - Frontend lint:
cd frontend && npm run lint→ pass.
- Update preview: Skill Packs page can call
POST /api/v1/skill-packs/{id}/preview-updateand show added/removed skill counts. - Upgrade: installed packs can be upgraded from the UI using edited target version and manifest JSON.
- Rollback: installed packs expose rollback availability and a rollback action wired to
POST /api/v1/skill-packs/{id}/rollback. - Install scan path: install still supports optional gateway
scan_pathand shows policy/gateway results.
- Backend tests:
cd backend && .venv/bin/python -m pytest tests/test_skill_packs.py→ 4 passed. - Frontend lint:
cd frontend && npm run lint→ pass.
- Proposal queue:
GET /api/v1/memory/proposalslists Swarm-created incident memory awaiting review. - Review actions:
POST /api/v1/memory/proposals/{id}/approveand/rejectpreserve reviewer/reason in the incident timeline. - Rollback:
POST /api/v1/memory/incidents/{id}/rollbackexcludes stale or incorrect memory from runtime use without deleting the audit trail. - UI: Memory page now shows pending proposals and adds rollback control on expanded incident rows.
- Backend tests:
cd backend && .venv/bin/python -m pytest tests/test_memory_proposals.py tests/test_swarm.py::test_swarm_high_risk_judgement_proposes_incident_memory→ 3 passed. - Frontend lint:
cd frontend && npm run lint→ pass.
- Threaded Slack replies: inbound Slack
ts/thread_tsvalues are carried into outbound reply payloads when available. - Approval card metadata: approval-required commands now generate Slack Block Kit action blocks and Teams MessageCard actions for approve/reject workflows.
- Persisted delivery context: message detail exposes
outbound_deliveryandoutbound_cardfacts alongsideresponse_sent. - Control Center reply health:
GET /api/v1/dashboard/control-center-summarynow includes 24-hour replies-sent and replies-pending-config counters.
- Backend tests:
cd backend && .venv/bin/python -m pytest tests/test_channel_gateway_commands.py tests/test_control_center_summary.py→ 12 passed.
- Outbound delivery: Slack/Teams channel responses are posted through configured
ChannelConfig.webhook_urlvalues when available. - Explicit status: ingress responses now include
outbound_delivery.statusassent,failed, orskipped. - Persisted signal:
ChannelMessage.response_sentis updated after successful outbound delivery. - UI visibility: Channel Gateway message rows and detail panels show whether the response was delivered or not configured.
- Backend tests:
cd backend && .venv/bin/pytest tests/test_channel_gateway_commands.py -q→ 10 passed. - Frontend lint:
cd frontend && npm run lint→ pass.
- New endpoints:
POST /api/v1/intelclaw/taskandPOST /api/v1/recoveryclaw/task. - Dispatcher routing:
backend/app/core/swarm/dispatcher.pynow routes Threat Intelligence and Recovery Readiness tasks through real handlers. - Regression updates: dispatcher routing test matrix now includes intel and recovery capability nodes.
- Control Center summary API: added
GET /api/v1/dashboard/control-center-summaryfor pending commands, swarm pressure, remote-agent health, schedule load, channel pressure, and execution-gate status. - Control Center v2 UI: frontend control center now renders live summary cards from the new backend endpoint.
- Channel chat-ops review: channel messages now support
approve <command_id>andreject <command_id>/deny <command_id>with the same command policy workflow used by direct APIs. - Test-mode session routing: channel review path now reuses dependency-overridden async DB session in pytest to avoid bypassing the request test database.
- Backend tests:
cd backend && .venv/bin/pytest tests/test_control_center_summary.py tests/test_channel_gateway_commands.py -q→ passing.
- Timeline actions: Channel Gateway timeline panel now supports copy JSON and download JSON actions.
- Backend filter validation: regression test now verifies
outcome-filtered timeline responses.
- Timeline API filters:
GET /api/v1/commands/{command_id}/timelinenow acceptsaction_containsandoutcome. - Channel Gateway controls: timeline panel includes quick filters for All, Approvals, and Rejections.
- Regression coverage: backend test validates approval-only timeline filtering behavior.
- Status endpoint enrichment:
GET /api/v1/commands/{command_id}/statusnow returnsapproval_auditwith latest approver and rejection metadata. - Channel Gateway UX: expanded status strip in timeline panel now shows last approver for faster review.
- Regression tests: added status-level approval audit assertions in
test_remote_control.py.
- Single-command approve:
approved_bynow always records JWT principal; request-bodyapproveris display-only. - Bulk approve: duplicate-approver checks now key off JWT principal instead of user-supplied display value.
- Reject metadata: rejection principal stored as authenticated id, with separate display field for UI.
- New tests: spoofed display-name duplicate attempts are blocked for both single and bulk approval flows.
- Backend regression:
pytest -q tests/test_remote_control.py tests/test_channel_gateway_commands.py→ passing.
- Bulk payload guardrail:
POST /api/v1/commands/bulk-reviewnow rejects duplicatecommand_ids. - Bulk response shape: response now includes
requestedcount in addition to processed/approved/rejected/errors. - Partial-failure visibility: Channel Gateway now surfaces bulk-review result summary and top per-command errors.
- Regression coverage: added duplicate-id rejection and partial-error-path tests for bulk review.
- Backend tests:
pytest -q tests/test_remote_control.py tests/test_channel_gateway_commands.py→ 22 passed. - Frontend lint:
cd frontend && npm run lint→ pass. - Playwright:
npx playwright test e2e/channel-gateway-bulk-review.spec.ts→ 1 passed.
- Remediation validation hardening for
create_jira_ticket: requireprovider=jira, requiretarget_type=ticket, uppercase/alphanumeric project key guardrail, plus minimum summary/description length checks. - Policy outcome assertions expanded in regression tests for low-risk ticket handoff behavior and output metadata.
- New Playwright E2E:
frontend/e2e/channel-gateway-bulk-review.spec.tsverifies select-visible + bulk approve flow on Channel Gateway.
- Backend regression: targeted platform + command suite run → 23 passed.
- Frontend lint:
cd frontend && npm run lint→ pass. - Playwright E2E:
npx playwright test e2e/channel-gateway-bulk-review.spec.ts→ 1 passed.
- New endpoint:
POST /api/v1/commands/bulk-reviewwithdecision=approve|rejectand command id list. - Guardrails preserved: self-approval and duplicate-approver checks still apply per command during bulk approve.
- Channel Gateway Commands tab: row multi-select, select-visible toggle, and bulk approve/reject actions.
- API client support:
bulkReviewPendingCommands()helper added.
- Backend regression:
DEBUG=true .venv/bin/pytest -q tests/test_remote_control.py tests/test_channel_gateway_commands.py→ 20 passed. - Frontend lint:
cd frontend && npm run lint→ pass.
- New endpoint:
POST /api/v1/commands/{command_id}/approval-policyupdates required approvals (1-4) for pending commands. - Guardrail enforcement: required approvals cannot be set below approvals already recorded for that command.
- Channel Gateway command rows now include an inline approval-threshold selector for operator delegation.
- API client support adds
updateCommandApprovalPolicy()helper.
- Backend tests add approval-policy update and guardrail coverage in
test_remote_control.py. - Regression run:
pytest -q tests/test_remote_control.py tests/test_channel_gateway_commands.py→ 18 passed. - Frontend lint:
cd frontend && npm run lint→ pass.
- Pending filters added to
GET /api/v1/commands/pending:source,requester, andmin_risk. - New endpoint:
GET /api/v1/commands/{command_id}/statusreturns latest outcome, source/requester context, and approval-state summary. - Channel Gateway Commands tab now includes search, source filter, min-risk filter, and inline status preview for timeline-expanded rows.
- API client updates add
getCommandStatus()and filterable pending-command calls.
- Backend tests add pending-filter and status-endpoint coverage.
- Regression run:
pytest -q tests/test_remote_control.py tests/test_channel_gateway_commands.py→ 16 passed. - Frontend lint:
cd frontend && npm run lint→ pass.
- New endpoint:
GET /api/v1/commands/{command_id}/timelinereturns command-linked lifecycle events and metadata. - Channel Gateway commands UI adds a
Timelineaction that expands inline event history for each pending command. - API client support adds
getCommandTimeline()helper for frontend consumption. - Pending review visibility improves operator context for multi-step approval decisions.
- Backend tests include timeline endpoint coverage in
test_remote_control.py. - Regression run:
pytest -q tests/test_remote_control.py tests/test_channel_gateway_commands.py→ 15 passed. - Frontend lint:
cd frontend && npm run lint→ pass.
- New endpoint:
POST /api/v1/commands/{command_id}/rejectmarks pending commands as blocked and records rejection reason. - Approval-state persistence now records rejection metadata (
rejected_by,rejected_at,reject_reason). - Channel Gateway UX now includes both
ApproveandRejectactions for pending command rows. - API client surface adds
rejectPendingCommand()helper for frontend integration.
- Backend tests now include deterministic reject flow coverage in
test_remote_control.py. - Regression run:
pytest -q tests/test_remote_control.py tests/test_channel_gateway_commands.py→ 14 passed. - Frontend lint:
cd frontend && npm run lint→ pass.
- Approval progress state persists in command event metadata with required approvals and step history.
- Pending command API enrichment now returns
approvals_received,required_approvals, andapproval_status. - Self-approval prevention blocks requesters from approving their own command.
- Duplicate-approver prevention blocks repeated approvals from the same operator.
- Two-step finalization behavior keeps outcome pending until required approvals are met, then marks final allow.
- Channel Gateway commands table now displays approval progress counters for pending items.
- Backend tests validate pending listing, self-approval rejection, duplicate rejection, partial approval state, and final approval transition.
- Regression run:
pytest -q tests/test_remote_control.py tests/test_channel_gateway_commands.py→ 13 passed. - Frontend lint:
cd frontend && npm run lint→ pass.
- Pending Commands tab on
/channel-gatewaylistsGET /api/v1/commands/pendingoutput and supports one-click approval viaPOST /api/v1/commands/{command_id}/approve. - Quick ingress test controls added for CLI, Webhook, and Email adapters using the new channel ingress endpoints.
- Message detail panel now includes normalized
command_resultmetadata for traceability. - API client updates include typed helpers for webhook/email/CLI ingest and command pending/approve operations.
- Frontend lint:
cd frontend && npm run lint→ pass. - Backend regression set for these APIs remains green (
13 passedin remote control + channel gateway tests).
- CLI ingress endpoint added:
POST /api/v1/channel-gateway/cli/command, routing terminal commands into the same normalized command path. - Pending command listing added:
GET /api/v1/commands/pending. - Manual approval action added:
POST /api/v1/commands/{command_id}/approve, including approval metadata persistence. - Shared ingestion refactor now unifies Slack/Teams/message/webhook/email/CLI normalization behavior.
- Remote control tests expanded with pending/approve coverage.
- Channel gateway tests expanded with CLI ingress coverage.
- Test run:
pytest -q tests/test_remote_control.py tests/test_channel_gateway_commands.py→ 13 passed.
- New ingress endpoint:
POST /api/v1/channel-gateway/webhookfor generic webhook command messages. - New ingress endpoint:
POST /api/v1/channel-gateway/email/inboundfor email-triggered command messages. - Shared processing path now handles Slack, Teams, generic message, webhook, and email consistently via normalized command execution and response metadata.
- Live/simulate parity preserved: both persistent and simulated channel flows return
command_result.
- Channel tests now include webhook and email ingress command-contract coverage.
- Combined regression run:
pytest -q tests/test_channel_gateway_commands.py tests/test_remote_control.py→ 11 passed.
- Remote dispatch enforcement now blocks tenant mismatch, kill-switch active agents, and intents outside agent
allowed_actions. - Dispatch payload guard now rejects mismatched
remote_agent_idbetween path and request body. - Command ID validation now returns explicit
422for invalid remote agent IDs. - Simulation parity adds command normalization + policy outcome metadata to
POST /api/v1/channel-gateway/simulate.
- Remote control tests expanded with tenant mismatch, disallowed intent, and path/body mismatch coverage.
- Channel tests expanded to validate
/simulatecommand result behavior. - Test run:
pytest -q tests/test_remote_control.py tests/test_channel_gateway_commands.py→ 9 passed.
- Channel normalization added for
/channel-gateway/slack/events,/channel-gateway/teams/webhook, and/channel-gateway/messageinto Command request shape. - Unified policy path now executes normalized channel commands through the same guarded contract as
POST /api/v1/commands. - Response traceability now includes
command_resultin channel message responses. - Graceful fallback returns
outcome: unavailablewhen async command backend is unreachable, without breaking channel ingestion.
- New tests in
backend/tests/test_channel_gateway_commands.pyvalidate normalization and blocked-path behavior. - Command route regressions continue to pass in
backend/tests/test_remote_control.py. - Test run:
pytest -q tests/test_channel_gateway_commands.py tests/test_remote_control.py→ 5 passed.
- SSE provenance payload:
task_completedstream events now includeexecution_modeandfallback_reasonwhen available. - Backend stream regression: new Swarm tests assert provenance is present for both real-handler and simulated fallback task completions.
- E2E UI coverage: added
frontend/e2e/swarm-execution-provenance.spec.tsto validate task execution badges and fallback reason rendering in Swarm detail.
pytest -q tests/test_swarm.py tests/test_swarm_dispatcher_routing.pypassed.npx playwright test e2e/swarm-execution-provenance.spec.tspassed.npm run lintpassed.
- Swarm task table execution column now shows
real handlervssimulated fallbackbadges. - Fallback reason surfaced in task detail row when simulation path is used.
- Frontend API typing improved with a typed
SwarmTaskcontract forgetSwarmTasks().
- Custom Capability task endpoint: added
POST /api/v1/customclaw/taskreturning standardized Swarm Task Contract fields. - Dispatcher wiring:
customclawnow executes through its real task handler instead of fallback simulation. - Fallback regression updated: unsupported-module fallback now validates against
unknownclaw.
- Swarm tests:
pytest -q tests/test_swarm_dispatcher_routing.py tests/test_swarm.pypassed. - Control-plane regressions:
pytest -q tests/test_remote_control.py tests/test_channel_gateway_commands.pypassed.
- New focused task routes added for
attackpathclaw,automationclaw,configclaw, andexposureclaw. - Dispatcher routing expanded for the above modules plus prior additions (
saasclaw,privacyclaw,userclaw,insiderclaw,vendorclaw). - Swarm fallback reduced to only unsupported edge modules, preserving deterministic behavior where real handlers are not yet available.
- Swarm routing tests updated to validate all newly routed capability nodes and fallback behavior on unsupported modules.
- Test runs:
pytest -q tests/test_swarm_dispatcher_routing.py tests/test_swarm.pyandpytest -q tests/test_remote_control.py tests/test_channel_gateway_commands.pypassed.
- Fail-closed execution requests:
/api/v1/exec/shell,/api/v1/exec/browser, and execute paths now return503 trust_fabric_unavailablewhen policy evaluation cannot run. - Production-gate identity enforcement: approve/reject actor is always sourced from JWT identity; request body identity fields are ignored.
- Production-gate self-approval block: requester cannot approve their own production gate.
- Production execute re-check:
/api/v1/exec/production-gates/{id}/executeperforms a pre-execution Trust Fabric authorization and fails closed on gateway error. - Remediation approve fail-closed: remediation approval now returns governed deny when Trust Fabric evaluation is unavailable.
- Platform regressions: new tests cover fail-closed behavior for exec create/execute, production-gate execute, and remediation approve.
- Identity regressions: tests confirm production-gate approve/reject uses JWT principal and blocks self-approval.
- Smoke:
pytest -q tests/test_platform_regressions.pytargeted slices +tests/test_remote_control.py tests/test_channel_gateway_commands.pypassed.
- Swarm detail ticket handoff posts the live ticket draft to
POST /api/v1/remediation/triggerusing acreate_jira_ticketaction spec. - Ticket payload validation now enforces required ticket fields:
project_key,summary, anddescription. - Compliance rollup context is included in the remediation handoff payload.
- Playwright E2E harness added under
frontend/e2e/withnpm run test:e2e.
- Backend regression tests assert invalid ticket payloads fail and valid ticket handoffs remain low-risk/non-approval actions.
- Frontend lint passes for Swarm detail and API client changes.
- E2E note: local execution requires Playwright to start the Next.js server on
127.0.0.1:3100; this sandbox blocks local port binding.
- Preset endpoint added:
POST /api/v1/swarm/jobs/presets/suspicious-identity. - Preset participants include Identity Security, Threat Analysis, Cloud Security, Data Security, Compliance Assurance, and Security Automation.
- Approval-gated launch is enabled by default for this preset.
- Swarm list UI adds a quick-launch card for the preset workflow.
- Swarm detail UI now shows judge
root_cause,blast_radius, andnext_stepswhen available.
- Swarm tests validate preset creation, participant set, approval gate, and approve path.
- Frontend lint passes for updated Swarm pages and API client.
- Trigger actions now support
start_swarm/fire_swarmexecution paths with optional pre-execution approval gating. - Schedule swarm execution now supports notes
typevalues ofSWARM_JOB,START_SWARM, andFIRE_SWARM. - Swarm approval flow now supports both modes: pre-execution approve-to-run and post-judge approve-to-complete.
- Profile defaults now apply automatically for trigger/schedule swarm launches
(
FAST_TRIAGE,DEEP_INVESTIGATION,INCIDENT_RESPONSE,AUTONOMOUS_LOW_RISK,EMERGENCY_CONTAINMENT). - UI wiring added so Triggers can configure swarm actions directly and Schedules can route run actions to
/run-swarm.
- Platform regression tests cover trigger->swarm launch, schedule->swarm launch, approval-gated pre-execution launches, and profile-default behavior.
- Frontend lint passes for updated Triggers/Schedules/API client files.
- Bounded parallel swarm execution shipped for background jobs (Semaphore + gather) instead of sequential loops.
- Real claw task routing in dispatcher now targets
/task-equivalent handlers for Identity Security, Cloud Security, Threat Analysis, and AI Security with deterministic fallback for unsupported capability nodes. - Live swarm stream endpoint added:
GET /api/v1/swarm/jobs/{id}/stream(SSE events for job/task lifecycle). - Model Cortex scaffold added with governed route/profile/provider/call-audit APIs under
/api/v1/modelclaw/*. - Swarm Judge synthesis now uses Model Cortex via dedicated
swarm_judge_profileand falls back to deterministic summary when policy blocks or profile constraints apply.
- Swarm parallelism tests added to verify bounded concurrency.
- Capability Node task contract tests added for the four shipped
/taskcapability nodes. - Dispatcher routing tests added for both real-handler and fallback paths.
- Swarm SSE test added to verify stream events and terminal lifecycle completion behavior.
- Model Cortex + Swarm Judge tests added for allow and denied/fallback synthesis paths.
- Trust Fabric UI now includes a live
MCP Security Scanpanel wired toPOST /api/v1/trust-fabric/mcp/scan. - Swarm UI now shows per-task secure channel state on
/swarm/[id]and adds participants/runtime columns on/swarm. - Swarm tests now verify
AGT_ENABLE_E2E_MESSAGINGbehavior for both disabled and enabled modes.
- Policy packs stats route shadowing fixed for
GET /api/v1/policy-packs/stats. - Schedule delete no longer fails on linked runs; related
agent_runs.schedule_idis cleared first. - Autonomy emergency mode endpoints now accept object JSON payloads used by the UI.
- Run replay now supports
GET /api/v1/orchestrations/run-replay/{run_id}. - Capability Node contract consistency added missing compatibility endpoints for AI Security and Identity Security findings/providers.
- Auth deadlock resolved — login endpoint no longer requires a JWT to issue a JWT. Public paths exempt from global dependency.
- DEBUG=false default —
docker-compose.ymlnow uses${DEBUG:-false}. Auth bypass no longer ships on. - Port isolation — backend, PostgreSQL, Redis all bind to
127.0.0.1. Not reachable from host network.
- Dual-approval enforced — shell/browser exec channels require 2 different approvers. Self-approval blocked.
- approved_by from JWT — approval identity pulled from token sub, never from client-supplied body field.
- SSRF blocklist — connector tester blocks RFC1918, loopback, and cloud metadata IPs (
169.254.169.254). - AI Security chat auth — Next.js proxy route now forwards
Authorizationheader to backend. - SECRET_KEY guard — startup rejects known insecure default keys when
DEBUG=false.
- PyJWT 2.9.0 — replaced unmaintained
python-jose. Mandatory claim enforcement on decode. - bcrypt SHA-256 prehash — eliminates silent 72-char truncation.
python-multipart→ 0.0.12 (ReDoS fix). - .secrets/ permissions — chmod 600/700 enforced on every write. Key and ciphertext now restricted.
- Rate limiting — 10 req/min per IP on
/auth/token. Brute-force protected. - Security headers —
X-Content-Type-Options,X-Frame-Options,Referrer-Policy, HSTS (prod only). - Env var credentials — all docker-compose secrets use
${VAR:-default}substitution.
- Execution Ring Policy — ring0 (blocked) → ring3 (auto-allow). 32/32 tests. Wired into exec channels + remediation.
- Connector Provenance — SHA-256 + Ed25519 signature verification at skill pack install. 10 provenance tests.
- OWASP LLM + ASI Top 10 — honest self-assessment, one automated test per ASI category, test anchors in docs.
- Tenant isolation audit — 13 tests documenting isolation model with honest xfail markers for known gaps.
- SRE Engine — circuit breaker, error budget, SLO primitives for all governed modules.
- NVIDIA NIM connector added to Connector Marketplace — configure an NVIDIA API key in 4 steps.
- Security Copilot auto-activates when a ready provider is detected on page load.
- Live model list fetched from the NIM API on each page load — only models confirmed to support tool calling are shown.
- 8 tool-capable models available: Llama 3.3 70B (recommended), Llama 3.1 70B, Nemotron 70B, Nemotron Super 49B, Mistral Large 2, Mistral Nemo, Qwen 2.5 72B, Llama 3.1 8B.
- In-chat "Open Connector Marketplace" button appears when a key is missing — one click to configure.
- Connector modal now advances through all 4 steps (Credentials → Policy Check → Test → Done) without closing mid-flow.
- Next.js proxy timeout bypassed via a dedicated route handler with
maxDuration=300— long LLM tool chains no longer drop withECONNRESET. - Connector type mapping fixed —
nvidiaprovider now resolves tonvidia_nimconnector correctly. - Body stream error in Security Copilot resolved — response body read once as text, then JSON-parsed.
- Agent timeout raised from 60 s → 120 s for multi-step tool chains.
- Review NVIDIA's current API free-tier terms and obtain a key at build.nvidia.com/models.
- Open Enkstein → Connectors → search NVIDIA NIM → click Configure.
- Paste your key → complete the 4-step flow → done.
- Navigate to AI Security → Security Copilot auto-activates with NVIDIA NIM selected.
- 5 built-in playbooks: compromised credential, exposed secret, endpoint compromise, privilege escalation, data exfiltration.
- Human approval queue — high-risk actions (quarantine, account suspend) require sign-off before execution.
- One-click rollback — every executed action stores rollback data so it can be reversed instantly.
- Provider integrations: Okta, Entra ID, AWS IAM, CrowdStrike, Defender, SentinelOne, GitHub, Jira, PagerDuty, Slack.
- Remediation page at
/remediation— approval queue, action history, playbook grid, stats. - Finding pipeline integration — critical/high findings automatically trigger playbook matching.
- 24 Capability Node modules — AI Security (AI), Cloud Security, Endpoint Security, Identity Security, Exposure Management, Threat Analysis, and 18 more.
- Trust Fabric — central policy evaluation, risk scoring, and audit for every action.
- Security Copilot (AI Security) — AI agent with live tool calling: CVEs, MITRE ATT&CK, findings, scans, workflow triggers.
- AI Governance — prompt injection detection (12-vector AGT audit), PII/secret redaction, risk scoring, full audit log.
- Connector Marketplace — 100+ connectors, Fernet-encrypted credentials stored locally, never in the cloud.
- Policy Engine — define allow/block/alert rules scoped to any connector, user, or module.
- Workflows — multi-step automation with branching, conditions, and remediation steps.
- FastAPI + SQLAlchemy async + PostgreSQL + Redis + Next.js 14 stack.