Capka v0.38.0 πΎ
·
135 commits
to master
since this release
Added
scripts/release-gate.shchecks a tree beforenpm run release(migrations generated, journal timestamps increasing, locale parity, typecheck, lint); run it by hand, it is not wired into the release script.- The worker reports any
note_claims/vault_edgesdivergence every six hours as avault contains parity divergedwarning per space; it never repairs. - The assistant edits a memory file in place (replace a passage, insert a paragraph, rename it) instead of rewriting the whole file.
- Topic sections (You / Topics / Areas / People); the assistant records what it learns as short topic files during the chat.
- A turn that wrote memory lists each saved item on its activity rail with one-click undo, and the rail header shows the count.
- When a fact the assistant saved contradicts one already stored, the memory page shows both side by side and one click keeps either or both.
- The assistant can write and update project notes, and link them to each other; links are stored as ids, so renaming a note updates every reference.
- The assistant can file a saved fact or note under a topic.
memory_openlets the assistant read one saved item in full by its handle.- The assistant now saves facts to memory immediately, with no confirmation step; everything it saves appears on the memory page with one-click undo.
- Vault tool results are capped per call and per turn (50,000 bytes across all memory and document tools), so prompt cost stays flat as the vault grows.
- Topic membership is now written to
vault_edgesalongsidenote_claims; existing memberships are back-filled at boot, a parity check runs on every write outside production, andPOST /api/admin/vault/reindexreports it ascontainsParity. - Notes are searchable by the assistant:
memory_searchnow returns note rows beside facts, filtered by the note's own trust class. - Notes now store their body in immutable revisions (
vault_note_versions); the backfill runs at boot and needs no operator action. - New admin-only
POST /api/admin/vault/reindex(body{"spaceId": "..."}) rebuilds one space's memory search index. - The memory search index is now written with every fact and topic it projects; the boot migration back-fills every existing space.
- Memory search is now full-text plus trigram. The boot migration runs
CREATE EXTENSION pg_trgm; the database role must be allowed to create extensions or the migration fails. - New
vault_nodes/vault_edgestables; applied automatically at boot, no operator action. - Every vault claim, note and document now has a
vault_nodesrow; the backfill runs in the boot migration. - Vault claims carry a server-assigned trust class and a generated
prompt_accesschannel; existing claims are mapped fromreview_statusby the boot migration. - Vault data foundation (content-addressed blob store; sources/versions/fragments/citations schema) β groundwork for project knowledge.
- Facts can now be deleted from the memory page, including sensitive ones the assistant is not allowed to read.
- The memory page now says how a fact gets saved β by telling the assistant in a chat β and why the set-aside list is waiting.
- A "forget everything" control on the memory page removes every recorded fact and every set-aside candidate across the user's own memory and all their projects; the audit trail of the reset is kept.
- Facts the assistant recorded but could not activate can now be kept or discarded on the memory page, with the wording editable first.
Changed
- Similar topics are not merged automatically yet; the assistant edits the existing file instead of opening a second one.
- Opening an existing chat shows a quiet transcript skeleton until its history arrives, instead of an empty pane.
- Images in replies load into a reserved box and fade in; a broken image shows a labelled chip instead of disappearing.
- Markdown tables in replies drop the grey header band, take their content width, use tabular digits, and show their copy/download controls on hover.
- On wide screens the first column of a wide markdown table stays pinned while the rest scrolls sideways, with a seam that appears only once scrolled; phones pan the whole table.
- On wide screens a markdown table fills the text column, and one wider than the column grows into both margins before it has to scroll.
- A markdown table's fullscreen view uses the same styling as the transcript instead of a boxed default, with an opaque sticky header.
- The reasoning spoiler's label fades when it changes from the live stopwatch to the final duration instead of snapping.
- The memory page is a list of topic files grouped by section, each opening to its text, its trust tag and the facts filed under it; a file can be deleted with one click and put back from the toast.
- Streamed replies fade in word by word and no longer re-render the whole message when the turn ends; the caret blinks only while the model pauses.
- Chats longer than twenty messages fold the older ones out of layout once the transcript settles; scrolling back renders them in place at their measured size.
- The chat navigator highlights the hovered or active turn with one pill that glides between rows, and a single-choice question marks the chosen option the same way.
- Activity-rail rows and the controls under a finished reply rise in with a short cascade, and the line between steps is drawn in rather than present from the start.
- The memory page lists everything the assistant saved, each row tagged with where it came from; the old review queue becomes a read-only "Earlier suggestions" archive that expires 30 days after this release.
- Facts found by post-turn extraction are saved directly instead of waiting in a review queue; legacy memory documents migrate as assistant conclusions, not as confirmed facts.
- The person card and the capability rule dialog use hairline rows instead of boxed items; the Allow / Ask / Deny switch is the shared segmented control and no longer stretches across the dialog.
- Text fields carry the same edge weight as buttons, and every grey well in Settings (segmented switches, code and command boxes, category chips) is recessed again instead of rendering as a white pill on the page.
- Settings: every page is built from one set of blocks (page title, section with its one action on the title line, rows divided by hairlines straight on the page instead of cards, radio choice, note), with three type sizes for page, section and row; the tab/filter switcher is the same control on every page.
- Settings: the sidebar search field is gone; the app sidebar's search button (βK) already finds every setting. The people, analytics and activity switchers, the key-mode picker and the sign-in page now use the shared controls.
- Settings β Providers: the model-filter limits are rows with the value read back in words; "Add provider" sits on the section title. Settings β Security: the encryption-key section now shows its status as a row instead of a heading over nothing.
- Settings β Agent and Keys & limits: Save appears only once something differs from what is stored, instead of a permanently greyed-out button. The empty "User tiers" section was removed from Keys & limits.
- The assistant can undo a memory write it made in the same turn; anything older is still removable only by the owner on the memory page.
- Chat UI: one accent colour (ink-blue) for the focus ring and the unread dot only; hover/active surfaces and hairlines are a full step stronger, so the current chat and the hovered row are visible at a glance.
- The model and thinking controls now live in the composer footer on every screen; the floating pill under the greeting and the copy in the chat header are gone.
- The new-chat screen drops the "Recent" list (it duplicated the sidebar) and the drag-a-file hint; the greeting and mark are smaller.
- Tool steps render as a single bordered list β one row per step, details behind the chevron β instead of a timeline with ringed nodes and a "Done" cap.
- Sidebar rows are 15px; the chat search is a quiet borderless field; settings section labels are sentence-case.
- The interface palette is now graphite: a warm near-achromatic ramp with no accent hue, so colour is reserved for error, warning and success. Links are ink and permanently underlined; audit-log category badges are no longer colour-coded.
- Input fields are a white raised well with a mid-grey border instead of a sunken grey fill, so a field no longer looks like a disabled control.
--popoveragain shares--card's value. - A correction the assistant cannot prove came from the user is stored beside the existing fact as a conflict rather than replacing it.
memory_searchnow takes several query wordings per call and returns short run-local handles instead of[id@revision]addresses.- Memory topics now fold by normalized title inside a space, enforced by
uniq_vnotes_topic_title; naming an existing subject reuses it instead of creating a second topic. - Two pre-existing memory topics in one space whose titles differ only in case or spacing block that migration: it retries and the schema stays at
0065until they are merged, while the app keeps serving without the constraint. The first[db] auto-migration failedlog line names the space and the title; later retries name only the index. - Claim trust classes are now minted by one module (
src/lib/vault/grounding.ts); no other code path can state asource_class. - Memory search now matches by full text and trigram similarity instead of substring, so a misspelling or a different word order still finds the fact.
- The
withheldcountmemory_searchreturns now includes sensitive facts still awaiting confirmation, not only kept ones. - A proposed fact that duplicates one
memory_searchcan already find β including a fact still awaiting confirmation β is answered "already known" and writes nothing, so the review queue no longer fills with duplicates. - Agent memory is now a structured vault: facts with provenance, quarantine for web/tool-derived facts, full audit trail; existing memory documents migrate automatically at boot. The old memory editor is read-only until the new memory page ships.
- The memory page now shows topics, each fact's source conversation and what it replaced, and the facts set aside awaiting the user's confirmation (migration 0057).
- The memory page's topic rail is replaced by one searchable list of every approved fact, newest first (server-side search on
GET /api/memory?q=, 200 rows per scope). No database change: topic rows stay as they are and the prompt manifest still lists topics. - Settings search keywords moved into the message catalogs (
settings.search.*), so each locale ships its own synonym list instead of one hardcoded bilingual string. - Files carried into a project when a chat is moved land in an English subdir (
From chat "β¦"), which stays stable across an interface-language change so a retry replaces rather than duplicates the copy. - Web citations redesigned: [N] markers render as raised number pills with a hover card (title, domain, date), and the "Sources" footer is a grid of source tiles with domain monograms, one tile per URL, collapsing beyond six.
- The memory page shows a sensitive fact's text to its owner, blurred behind a per-row reveal control, instead of withholding it; the manifest and
memory_searchstill withhold it from the model. - A memory row's source line links to the conversation it came from, and a conflicting one names the fact it would replace.
- Conflicts raised by the assistant's own
memory_updatenow name the fact they contest, like extraction-raised ones already did. - The assistant can no longer save, correct or delete a memory fact on its own: every fact it records waits on the memory page until the user keeps it, and
memory_forgetrefuses outright. - Memory documents from the old system now migrate into the review queue instead of straight into memory, so the user keeps their carried-over facts once.
- A memory step in the chat timeline is labelled by what was attempted ("Memory proposal") rather than by a success that may not have happened.
- Facts no longer merge automatically: two facts about the same thing accumulate as duplicates and the user resolves them on the memory page (
vault_claims.slot_keyis a display hint;uniq_vclaims_active_slotdropped in migration 0058).
Fixed
- Reverting or editing a memory file the owner already deleted is refused instead of writing a hidden new revision onto it.
- A
str_replacewhose text overlaps itself in the file is refused as ambiguous instead of editing the leftmost occurrence. memory_note_writerejectstopicon astr_replace,insertorrenameinstead of silently ignoring it.- Reading memory no longer counts as reading outside content: the assistant can edit an existing memory file in a chat that searched memory first.
- An in-place edit of a memory file can no longer cut a link in half or duplicate one, and a rename onto a topic title that already exists is refused instead of failing the write.
- Undo in the chat's "saved to memory" notice now reverts an edit the turn made to an existing topic file, instead of deleting the file and its whole history; the notice says how many files were updated apart from what was saved.
- A fact deleted on the memory page can be put back from the toast, and the per-fact delete no longer asks for confirmation first.
- A topic file linking a sensitive fact no longer prints that fact's words on the memory page, and a link to a fact that has since been replaced no longer shows the old wording.
- A topic file that links to a sensitive file no longer shows that file's title on the memory page.
- Undoing an edit from the chat's "saved to memory" notice refuses with a clear message if the file changed in the meantime, instead of dropping that later change.
- Empty topic containers no longer appear on the memory page as rows with a title and a date and nothing else.
- The unfiled list on the memory page now says how many facts it is showing of how many.
- A topic file the owner deleted and the assistant then re-used keeps the facts filed under it visible to the parity check, instead of reading as a divergence that blocks the next write into that topic.
- A topic file's row preview no longer skips a paragraph that merely starts with a hash ("#1 priority is β¦").
- Updating a note without naming a topic no longer re-files it under General.
- The "jump to end" pill no longer flickers while a reply streams.
- The greeting's composer and starter hints stagger in as designed; the delay never applied before.
- A fact the assistant saves with
memory_fact_writenow names the conversation it came from on the memory page, instead of reading "the conversation is no longer available". - Keeping a correction on the memory page now actually replaces the fact it names, instead of leaving both facts live and asserting each to the assistant; if that fact was already replaced by something else in the meantime, the correction is saved beside it and nothing is superseded.
- Keeping a correction whose wording the memory already holds no longer records that wording a second time: the fact it contests is removed and the existing one is kept.
- Memory topics are identified by a stable key instead of their displayed title, so renaming one no longer forks it into two the assistant counts twice.
- Deleting a project now closes its memory for good: a post-turn fact extraction still running when the project is deleted no longer writes into the deleted project's memory (
spaces.retired_at, migration 0056). - Memory tool calls read as memory in the chat timeline instead of "Searched the web" with a globe β
memory_searchwas matching the web-search name heuristic. - A forked or cloned chat is named in the interface language β the "(copy)" suffix was hardcoded Ukrainian for everyone.
- Inline citation pills actually render in the web chat β the markdown sanitizer strips the attribute the previous CSS styling targeted, so markers showed as plain blue numbers and a
[1, 9]group read as "19". - A reply's [N] markers no longer resolve against a different message's sources (markdown processor cache collision on anonymous plugins).
- A chat whose first turn goes through an approval or "Ask" prompt is now auto-titled instead of keeping the placeholder name for good.
- The step timeline no longer opens an empty thought row for a reasoning part carrying only a line break, which some models emit between tool calls.
- A fact stated while answering an assistant question is now attributed to the user instead of waiting for confirmation.
- Keeping a set-aside fact whose slot a sensitive fact holds now works instead of failing with "try again" on every attempt.
- A sensitive fact quoted in a conflict line, or opened for editing, is blurred like every other sensitive statement on the memory page.
- The memory page no longer quotes an unverified claim as the fact a conflict would replace.
- The memory page's search no longer lets a slower, older request overwrite a faster, newer one's results, and a stale request failing after a newer one succeeded no longer blanks the whole page with a load-error panel.
Security
- The assistant cannot create a new memory topic in a turn that read a document, a web page or a connector result; the item is filed under General and the assistant is told. Existing topics still take filings.
- A turn that has read untrusted content (a tool result, a provider-side search, an attachment, or a compaction summary of any of those) can no longer replace a fact the user stated; the correction is recorded as a conflict instead. The mark is stored on
messages.untrusted_ingressand survives compaction and approval continuations. - Forking or cloning a chat now carries each message's untrusted-content mark, and an imported conversation's messages are marked untrusted, so a copied history no longer reads as if the user authored it.
- A memory fact that looks like a credential is stored sensitive whatever wrote it, so it is never re-injected into a prompt and never returned by memory search.
- The boot-time memory migration logs only the error message on failure, so a failing statement's bound parameters no longer reach the log.
- Memory audit events (
audit_events) no longer carry a fact's slot key or a forget reason, so no memory text survives a project delete;memory_forgetaccordingly no longer takes areason. - An unmigrated memory document is no longer sent to the model: the prompt's raw legacy fallback is removed, so an old document holding a credential cannot be disclosed on every turn while its migration fails.
- Lexical overlap with the user's own message no longer authorizes a memory write, so a fetched web page cannot rewrite or erase a fact the user merely mentioned.
- A credential straddling the 500/120-character truncation boundary is now flagged: the screen classifies the text as given as well as the text as stored.
- The boot migration's audit event no longer carries a document hash or character count, which together allowed a deleted document's text to be recovered by dictionary attack.
- The credential screen is now shape-based only (a long opaque run) and is documented as an advisory flag rather than a boundary; its English-only word list is removed, since it flagged
password: β¦and missed the same sentence in every other language. - A memory confirmation can no longer land on a fact that was superseded while the user was deciding;
vault_claims.approved_at/approved_by_user_idrecord who approved each fact (migration 0058).
Removed
- The unused
chats.kindcolumn and itsuniq_chats_memoryindex are dropped (migration 0070); they shipped for a memory-page composer that was cancelled and nothing read them. - Removed
memory_proposeandmemory_update; the assistant writes facts directly and records corrections as conflicts.
Full changelog: https://github.com/LyoSU/capka/blob/master/CHANGELOG.md