Repository navigation
Issue map: how the open issues relate, and what blocks what #168
Description
Rebuilt 2026-08-13 over 182 open issues and 38 open pull requests. CLAUDE.md
makes reading this a precondition for filing, and it was a title with an empty body
from 2026-08-04 until now — #683 is the issue about that, and this is the answer to
it.
How to use it
Before filing, find the cluster your defect belongs to below and name at least one
issue from it in the body. "Checked, nothing related" is a fine answer; silence is
not. Then come back and add your number to the cluster, and to the spine if it blocks
something.
Two commands before you write a word — the map is a snapshot and the repository is not:
gh issue list --state open --limit 300 --search "<the words in your title>"
gh issue list --state closed --limit 100 --search "<the same words>"Search the closed ones too. #659 was filed, worked and merged this week as half of
#437, which had been closed unfixed six days earlier — that is what #687 is about, and
it is the single most expensive mistake this map exists to prevent. A closed issue in
this repository is often closed by hand, with the evidence in a comment and no
closing pull request, so Closes/Refs in a footer is not a reliable signal either
way.
Every issue below appears exactly once, in the cluster that owns it. 48 of the 182
have a pull request in flight — those are marked, and picking one up is duplicated
work.
The clusters
A refusal that quotes the vendor
- Stop logging expected refusals as application errors #19
mediumStop logging expected refusals as application errors - Make an audit write failure loud, and type record_audit #20
mediumMake an audit write failure loud, and type record_audit - Refuse a malformed sealed payload without naming its contents #21
mediumRefuse a malformed sealed payload without naming its contents - PiiRedactionFilter redacts nothing: it is on the root logger, and the worker never installs it #440
highPiiRedactionFilter redacts nothing: it is on the root logger, and the worker never installs it - Dashboard error frame sends str(e) of a provider exception to the client #659
mediumDashboard error frame sends str(e) of a provider exception to the client — PR fix(chat): stop sending a provider's own text to the chat panel #675 - A failed agent run still stores the model client's exception text on the run row #676
mediumA failed agent run still stores the model client's exception text on the run row — PR fix(agents): store the refusal on a failed run, not the provider #691 - The chat tool_result frame relays a search provider's exception text to the client #681
mediumThe chat tool_result frame relays a search provider's exception text to the client — PR Name the tool that failed, not the search provider's error #694 - MCP OAuth refusals interpolate an httpx error, so a request URL can reach the user #686
highMCP OAuth refusals interpolate an httpx error, so a request URL can reach the user — PR fix(mcp): stop OAuth refusals quoting the upstream client #693 - The run transcript stores a search provider's exception text on a tool-call row #695
mediumThe run transcript stores a search provider's exception text on a tool-call row - A delegated run's row still stores the subagent library's exception text #699
mediumA delegated run's row still stores the subagent library's exception text — PR fix(agents): compose a delegated run's stored error, never store the library's #816 - check_task and wait_tasks hand a delegate's provider text to the parent's transcript #819
mediumcheck_task and wait_tasks hand a delegate's provider text to the parent's transcript — PR fix(agents): keep a delegate's provider text out of a status answer #832
Who may do what
-
An app admin can suspend, demote and delete their own account, unguarded at both layers #941
mediumsecurityAn app admin can suspend, demote and delete their own account - no guard at either layer, and two of the three take one click with no confirmation. Same family as change_role can mint a second Owner, bypassing transfer_ownership #672 and change_role lets an Admin demote a peer Admin that remove refuses to remove #700 -
Impersonation mints a bearer token onto the clipboard, and nothing it does is attributable to the admin #943
mediumsecurityImpersonation mints a bearer token onto the clipboard, carries no actor claim, and cannot be ended - so nothing done with it is attributable to the admin -
Impersonation should be an endable session, not a token on the clipboard #1044
enhancementsecurityImpersonation as an endable session, not a token on the clipboard — the flow half of Impersonation mints a bearer token onto the clipboard, and nothing it does is attributable to the admin #943 — PR feat(admin): make impersonation an endable session, not a token on the clipboard #1435 -
An open WebSocket outlives the revocation of the session that opened it #1437
mediumsecurityAn open WebSocket outlives the revocation of the session that opened it — found reviewing Impersonation should be an endable session, not a token on the clipboard #1044 -
chat: a normal (non-impersonation) session's WebSocket is not closed by sign-out-everywhere (no sid bind) #1501
mediumsecurityA normal (non-impersonation) session's WebSocket is not closed by sign-out-everywhere — nosidbinds an ordinary access token to a session row, so it hangs onis_activealone — found implementing An open WebSocket outlives the revocation of the session that opened it #1437 -
Identity-binding routes are allowed while impersonating, so an admin can attach their own chat identity to somebody's account #1438
mediumsecurityIdentity-binding routes (channel link, MCP OAuth) are allowed while impersonating — found reviewing Impersonation should be an endable session, not a token on the clipboard #1044 -
Organization MCP OAuth starts are allowed while impersonating, binding an admin grant as a member #1490
mediumsecurityThe organization MCP OAuth starts are the org half of Identity-binding routes are allowed while impersonating, so an admin can attach their own chat identity to somebody's account #1438, left open by its personal-only fix — found fixing Identity-binding routes are allowed while impersonating, so an admin can attach their own chat identity to somebody's account #1438 -
Manual personal MCP token entry is allowed while impersonating, storing an admin token as a member's #1492
mediumsecurityManual personal MCP token entry is unguarded under impersonation — the manual-token half of Identity-binding routes are allowed while impersonating, so an admin can attach their own chat identity to somebody's account #1438 — found fixing Identity-binding routes are allowed while impersonating, so an admin can attach their own chat identity to somebody's account #1438 -
Manual org MCP token entry is neither refused nor fully audited while impersonating #1521
mediumsecurityManual organization MCP token entry is neither refused nor fully audited under impersonation — the org manual-token corner alongside Organization MCP OAuth starts are allowed while impersonating, binding an admin grant as a member #1490/Manual personal MCP token entry is allowed while impersonating, storing an admin token as a member's #1492 — found fixing Manual personal MCP token entry is allowed while impersonating, storing an admin token as a member's #1492 -
Changing a password from Settings does not revoke the account's other sessions #1439
mediumsecurityChanging a password from Settings does not revoke the other sessions; only the email reset does — found reviewing Impersonation should be an endable session, not a token on the clipboard #1044 -
auth: refresh-token rotation has no reuse/replay detection (kill-family on a spent token) #1519
enhancementsecuritypriority:lowRefresh-token rotation has no reuse/replay detection (kill-family when a spent token returns) — a defense-in-depth pattern the project never had, orthogonal to chat: a normal (non-impersonation) session's WebSocket is not closed by sign-out-everywhere (no sid bind) #1501, not a regression — found implementing chat: a normal (non-impersonation) session's WebSocket is not closed by sign-out-everywhere (no sid bind) #1501 -
PATCH /users/me with {"password": null} returns 500 instead of a 4xx #1497
lowMalformed{"password": null}onPATCH /users/mereturns 500, not a 4xx — found fixing Changing a password from Settings does not revoke the account's other sessions #1439, pre-existing input-validation defect in the same branch -
Sharing a conversation outside the organization is accepted and unreadable #930
mediumSharing a conversation outside the organization is accepted and unreadable - the share resolves any deployment user, the read refuses on the tenant first (found reading the path for The Share conversation dialog: a member picker instead of an email box, room to breathe, and icons on view/edit #931) -
Access-check spec.skill_ids at publish, like every other reference #6
highAccess-check spec.skill_ids at publish, like every other reference -
OAuth sign-in drops the ?returnTo= deep link #135 OAuth sign-in drops the ?returnTo= deep link
-
Invitations never reach EXPIRED: the sweep has no caller, and a timed-out one is marked revoked #456
lowInvitations never reach EXPIRED: the sweep has no caller, and a timed-out one is marked revoked — PR Expire a stale invitation instead of leaving it pending #667 -
InviteLinkCreate.role is unvalidated — an Owner can mint an owner-granting share link #551
mediumInviteLinkCreate.role is unvalidated — an Owner can mint an owner-granting share link — PR Validate the role an invite link offers #671 -
Agent draft can't be published by a builder who can't add a model #591
mediumAgent draft can't be published by a builder who can't add a model — PR feat(onboarding): first-run tour, guided flows #624 -
change_role can mint a second Owner, bypassing transfer_ownership #672
mediumchange_role can mint a second Owner, bypassing transfer_ownership — PR fix(permissions): stop change_role handing out the owner role #697 -
Invitation role ceiling is keyed on the literal 'admin', so only built-in Admins are capped #696
mediumInvitation role ceiling is keyed on the literal 'admin', so only built-in Admins are capped — PR fix(permissions): cap the invitable role by what the requester holds #1019, merged -
The role pickers offer roles the caller cannot assign, and the service refuses them after the fact #1028
lowfrontendThe role pickers offer roles the caller cannot assign, and the service refuses them after the fact — the client half of Invitation role ceiling is keyed on the literal 'admin', so only built-in Admins are capped #696 and change_role lets an Admin demote a peer Admin that remove refuses to remove #700, found reviewing fix(permissions): cap the invitable role by what the requester holds #1019 -
change_role lets an Admin demote a peer Admin that remove refuses to remove #700
lowchange_role lets an Admin demote a peer Admin that remove refuses to remove -
invite_only cannot honour a shareable link with no address or domain #916
lowinvite_only cannot honour a shareable link with no address or domain: the register request carries no token, so the policy can only match an invitation against the submitted address (found reviewing fix(builder): configure an agent in one place, and stop guessing at what a reader sees #914, which added the sign-up policy) -
ASK_ALL is not restored on resume, so a rejected tool call can execute #1326
highsecurityASK_ALLis not restored when a parked run resumes, so a tool gated only by the conversation's approval mode and then rejected can reach its handler (found reviewing feat(approvals): a per-conversation approval mode in the chat #1295, which added the mode) -
A conversation cannot be shared past the first page of members #1335
highfrontendA conversation cannot be shared past the first page of members: the picker The Share conversation dialog: a member picker instead of an email box, room to breathe, and icons on view/edit #931 made the only path fetches one page of 50 and Sharing a conversation outside the organization is accepted and unreadable #930's tightening removed the address field that used to be the escape hatch
Channels and bots
-
Surface parity: what /chat offers that the raw WebSocket and the Public API do not #936 Surface parity: what
/chatoffers that the raw WebSocket and the Public API do not - the API cannot attach a file and never fillsparked, the socket has noenvironment_id, noask_userand no compaction notice. Deliverable is a parity table indocs/channels.mdthat a test holds true -
Refuse a Telegram webhook that carries no secret #4
highRefuse a Telegram webhook that carries no secret -
Other channels setup (websocket, frontend, etc.) #39 Other channels setup (websocket, frontend, etc.) — PR feat(channels): surface parity, the socket as an integration, and a hosted chat page #634
-
Telegram setup #42 Telegram setup
-
Slack setup #43 Slack setup
-
Workspaces: a user-scoped workspace from Slack or Telegram is invisible to the linked account #131 Workspaces: a user-scoped workspace from Slack or Telegram is invisible to the linked account
-
Offer the widget's WebSocket as an integration, not only as documentation #516 Offer the widget's WebSocket as an integration, not only as documentation — PR feat(channels): surface parity, the socket as an integration, and a hosted chat page #634
-
A hosted chat page: reach an agent by link, with no login and no site of your own #517 A hosted chat page: reach an agent by link, with no login and no site of your own — PR feat(channels): surface parity, the socket as an integration, and a hosted chat page #634
-
Visual map: four directions around the agent, and a node per subagent #518 Visual map: four directions around the agent, and a node per subagent
-
Telegram polling and Mattermost webhook bypass parse_incoming, dropping attachments #547
highTelegram polling and Mattermost webhook bypass parse_incoming, dropping attachments — PR fix(channels): parse every inbound transport with one parser #698 -
Three channel webhook routes drift on a missing secret: 500 (Slack) vs 403 (others) #555
mediumThree channel webhook routes drift on a missing secret: 500 (Slack) vs 403 (others) -
chat_type vocabulary differs per adapter, so the column holds mixed vocabularies #556
mediumchat_type vocabulary differs per adapter, so the column holds mixed vocabularies -
Lift the channel transport boilerplate into base.py helpers #565
lowLift the channel transport boilerplate into base.py helpers -
A widget update sending theme: null answers 500 on a NOT NULL column #637
lowA widget update sending theme: null answers 500 on a NOT NULL column — PR feat(channels): surface parity, the socket as an integration, and a hosted chat page #634 -
A channel bot past 200 messages is reminded of the thread's first 200, not its last #638
mediumA channel bot past 200 messages is reminded of the thread's first 200, not its last — PR feat(channels): surface parity, the socket as an integration, and a hosted chat page #634 -
A group channel refuses every sender who never linked an account, and require_link decides nothing #639 A group channel refuses every sender who never linked an account, and require_link decides nothing — PR feat(channels): surface parity, the socket as an integration, and a hosted chat page #634
-
Two copies of "an anonymous surface runs as its publisher": embed_session and channels/mentions #640 Two copies of "an anonymous surface runs as its publisher": embed_session and channels/mentions — PR feat(channels): surface parity, the socket as an integration, and a hosted chat page #634
-
A channel thread stays visible to somebody removed from the channel #641 A channel thread stays visible to somebody removed from the channel
-
The cookie banner covers Send on a hosted page, and its copy is untrue there #644
mediumThe cookie banner covers Send on a hosted page, and its copy is untrue there — PR feat(channels): surface parity, the socket as an integration, and a hosted chat page #634 -
Every agenticos cmd channel-* command fails: the CLI builds ChannelBotService with no organization, and three of them report it as "Bot not found" #1350
highEveryagenticos cmd channel-*command fails - the CLI builds ChannelBotService with no organization, and three of the five report it as "Bot not found" (found setting a Slack bot up from scratch) -
A Slack bot whose Socket Mode connection never starts looks healthy on /channels - the only evidence is a log line #1351
mediumfrontendA Slack bot whose Socket Mode connection never starts looks healthy on /channels - the only evidence is a log line. Narrowed by PR docs: rebuild the site, add the galleries, and close eleven issues #1344, which badges an absentxapp-token; a present-but-rejected one is still silent -
slack-sdk is declared without the [socket-mode] extra, so Socket Mode works only while aiohttp arrives transitively #1352
lowdependenciesslack-sdk is declared without the[socket-mode]extra, so Socket Mode works only while aiohttp arrives transitively - and the guarded import means no test would catch its removal -
A bot mentioned in a thread it has no record of answers as if the thread were empty - nothing backfills the earlier turns #1353
mediumA bot mentioned in a thread it has no record of answers as if the thread were empty - nothing backfills the earlier turns, andread_channel_historyis bound to the channel rather than the thread (found verifying PR docs: rebuild the site, add the galleries, and close eleven issues #1344 in a real workspace) -
Mattermost webhook transport answers every post, unlike the stream transport #662
mediumMattermost webhook transport answers every post, unlike the stream transport — PR fix(channels): gate a Mattermost webhook post the way the stream is #685 -
A Mattermost webhook bot has no server URL, so its attachments cannot be fetched #692
mediumA Mattermost webhook bot has no server URL, so its attachments cannot be fetched -
Refuse a deactivated member's channel turn instead of running it at their old role #1427
highsecurityRefuse a deactivated member's channel turn instead of running it at their old role -_membership_contextreads the role offmember_repo.getwherepublisher_contextwas hardened toget_active; not fixed by PR feat(spec)!: an MCP binding says whose account it speaks through #1392, land after it (2026-09-03 channels audit) -
Bound the router's chat-lock and rate-bucket maps, which grow per Slack message #1428
mediumBound the router's_chat_locks/_rate_buckets, which grow per top-level Slack message and were named in Add row locks to four check-then-act races #17 but never evicted (2026-09-03 channels audit) -
Render a channel chart off the event loop #1429
mediumRender a channel chart off the event loop -drawn_chart→ Pillowrender_chart_pngruns synchronously in the async turn (2026-09-03 channels audit) -
One supervised reconnect loop for the three adapters; Telegram retries a bad token forever #1430
mediumOne supervised reconnect loop for the three adapters; Telegram has no config-error branch and retries a bad token forever (2026-09-03 channels audit) -
Re-stamp the Telegram polling heartbeat so a quiet bot does not read unknown #1431
lowRe-stamp the Telegram polling heartbeat - the Telegram half A Slack bot whose Socket Mode connection never starts looks healthy on /channels - the only evidence is a log line #1351 named but did not do (2026-09-03 channels audit) -
Make the channel chart dispatch exhaustive over ChartType, and fix the skill's claim that the renderer is gone #1432
lowAnareachart renders as a line chart in channels, and the channel-bot skill sayschart_png.pyis gone (2026-09-03 channels audit) -
Couple jwt_linked to require_link, or retire the mode value that decides nothing #1433
lowCouplejwt_linkedtorequire_link, or retire the mode value that decides nothing since A group channel refuses every sender who never linked an account, and require_link decides nothing #639 (2026-09-03 channels audit) -
Channels hygiene: seven small items from the 2026-09-03 audit #1434
lowChannels hygiene: seven small items from the 2026-09-03 audit (Slack payload-URL fetch,router.pyAny, deadlist_platforms, client lifecycle,getattrsetup hooks,encode_untrustedparity, two duplicated router shapes) -
Gate /new, /project and /unlink on the same link admission as a turn #1455
severity:lowGate /new, /project and /unlink on the same link admission as a turn - pre-existing since A group channel refuses every sender who never linked an account, and require_link decides nothing #639, found reviewing fix(channels): make the jwt_linked mode require a link on its own #1454 -
Refuse a deactivated linked sender before attachments are stored and transcribed #1456
severity:lowsecurityRefuse a deactivated linked sender before attachments are stored and transcribed - moves fix(channels): refuse a deactivated member's channel turn #1436's run-level refusal earlier, found reviewing fix(channels): make the jwt_linked mode require a link on its own #1454 -
A crashed channel turn leaves its attachments orphaned in chat_files #1503
lowA crashed channel turn leaves its attachments orphaned inchat_files— found unifying the router turn paths (Unify the mention and default turn paths' refusal-and-crash handling in the channel router #1459), same A successful channel turn never links its ChatFile rows to a message #690 class -
Thread backfill under jwt_linked quotes unlinked authors into the prompt #1457
severity:lowThread backfill under jwt_linked quotes unlinked authors into the prompt - generalises the whitelist backfill filter, found reviewing fix(channels): make the jwt_linked mode require a link on its own #1454 -
Unify the mention and default turn paths' refusal-and-crash handling in the channel router #1459
enhancementUnify the mention and default turn paths' refusal-and-crash handling - the try/except half split out of Channels hygiene: seven small items from the 2026-09-03 audit #1434 (2026-09-03 channels audit) -
A room thread nobody linked an account in is writable by any member #701
lowA room thread nobody linked an account in is writable by any member
Files a turn writes
- One file viewer, not four: the chat file dialog is the poorest of them #136 One file viewer, not four: the chat file dialog is the poorest of them
- Workspaces: an owner column, a link to the conversation, and Open into a skills-style browser #137 Workspaces: an owner column, a link to the conversation, and Open into a skills-style browser
- All files: no search, no sort, six icons and no preview #138 All files: no search, no sort, six icons and no preview — PR feat(chat): search, sort and previews on the All files grid #828
- A file card shows no thumbnail for an image #827 A file card shows no thumbnail for an image — the half of All files: no search, no sort, six icons and no preview #138 that costs a request per tile — PR feat(chat): search, sort and previews on the All files grid #828, alongside All files: no search, no sort, six icons and no preview #138: the listing carries a scaled
data:URI, so it costs no request at all - Chat uploads are capped at a hardcoded 10MB while every setting says 50 #498
mediumChat uploads are capped at a hardcoded 10MB while every setting says 50 - A workspace file has no modified time, so the file viewer's header cannot show one #500 A workspace file has no modified time, so the file viewer's header cannot show one
- An answered ask_user question leaves no trace in the transcript #502
mediumAn answered ask_user question leaves no trace in the transcript - A non-mention channel message with attachments stores every file twice #660
mediumA non-mention channel message with attachments stores every file twice — PR fix(channels): fetch a message's attachments once, not per path #684 - A channel turn refused before the run orphans its ChatFile rows #661
lowA channel turn refused before the run orphans its ChatFile rows — PR Delete the files a refused channel turn stored #689 - A successful channel turn never links its ChatFile rows to a message #690
lowA successful channel turn never links its ChatFile rows to a message — PR Link a channel turn's files to the message it wrote #703 - A caption-less image on a workspace-less agent records no user turn #704
lowA caption-less image on a workspace-less agent records no user turn - A chat turn can link another user's file to its own message #706
mediumA chat turn can link another user's file to its own message - An attachment the router cannot read is silence to the model, so the agent denies the file #746
lowAn attachment the router cannot read is silence to the model, so the agent denies the file (found working A caption-less image on a workspace-less agent records no user turn #704) - A malformed file id off the socket reads as a server error, not a refusal #749
lowA malformed file id off the socket reads as a server error, not a refusal (found working A chat turn can link another user's file to its own message #706) - A blank user turn is still written by the streaming socket when files arrive with no words #750
lowA blank user turn is still written by the streaming socket when files arrive with no words (found reviewing fix(chat): name a caption-less turn's files in its user message #747, the A caption-less image on a workspace-less agent records no user turn #704 fix) — PR Name a blank streaming turn's files in its user message #751, stacked on fix(chat): name a caption-less turn's files in its user message #747
The frontend's own API surface
- Encode the avatar proxy's path segment #13
highEncode the avatar proxy's path segment - Encode every interpolated segment in the hand-rolled proxies #30
mediumEncode every interpolated segment in the hand-rolled proxies - Proxy routes discard the backend's refusal reason, showing a generic 'Backend API error' #546
highProxy routes discard the backend's refusal reason, showing a generic 'Backend API error' — PR fix(api): answer a refusal with the backend's reason, not a generic #668 - The backendFetch route family omits no-store, so a refetch-after-write can be served stale #553
mediumThe backendFetch route family omits no-store, so a refetch-after-write can be served stale - rating-buttons hand-rolls two fetch calls instead of a lib client and a hook #563
mediumrating-buttons hand-rolls two fetch calls instead of a lib client and a hook - Collapse the backendFetch forwarder family (~40 routes) into platformProxy #564
lowCollapse the backendFetch forwarder family (~40 routes) into platformProxy - Toast layer still reads .message off ApiError at ~25 sites, bypassing BFF code resolution #655
lowToast layer still reads .message off ApiError at ~25 sites, bypassing BFF code resolution - Three proxy routes echo the backend's content type, and one of them can serve HTML #702
highThree proxy routes echo the backend's content type, and one of them can serve HTML - Frontend: NEXT_PUBLIC_* are baked at build time, so a published frontend image cannot exist #1544
enhancementfrontendNEXT_PUBLIC_*are build arguments, so one frontend image carries one deployment's hostnames - readPUBLIC_API_URL,PUBLIC_WS_URL,PUBLIC_SITE_URL,CHAT_MAX_UPLOAD_SIZE_MBandOAUTH_PROVIDERSat runtime through a context, the wayBrandingProviderdoes;NEXT_PUBLIC_RAG_ENABLEDis read by nothing. Blocks Publish the backend and frontend images to GHCR on every release, and make docker compose up pull them #1545
English in every locale
- DOM keyboard constants parked in en.json — a translator can silently break Enter-to-submit #549
highDOM keyboard constants parked in en.json — a translator can silently break Enter-to-submit — PR fix(chat): compare DOM key literals, not catalog values #669 - BFF route payloads and the workspace step detail reach the toast in English #603
lowBFF route payloads and the workspace step detail reach the toast in English — PR fix(i18n): resolve BFF refusal codes and step details in the locale #654 - fix(frontend): Polish diacritics fall back to the system font — vendored subsets are latin only #606
lowfix(frontend): Polish diacritics fall back to the system font — vendored subsets are latin only — PR fix(frontend): render Polish diacritics in the brand fonts #652 - Twelve local next-intl mocks model t but not t.rich #612
lowTwelve local next-intl mocks model t but not t.rich - A Polish page still declares itself English: <html lang> is hard-coded #619
lowA Polish page still declares itself English: is hard-coded — PR fix(i18n): declare <html lang> from the active locale #646 - timeAgo formats a date older than a week as en-US in every locale #621
lowtimeAgo formats a date older than a week as en-US in every locale — PR fix(i18n): format timeAgo's date fallback in the active locale #651 - The Builder is untranslated under pl: agents is 0 of 508 keys #643 The Builder is untranslated under pl: agents is 0 of 508 keys
- formatDate, formatDateTime and formatCurrency still format as en-US in every locale #649
lowformatDate, formatDateTime and formatCurrency still format as en-US in every locale — PR Format an absolute date in the active locale #673 - check-i18n misses prose whose first word is hyphenated ("Sign-in failed") #656
lowcheck-i18n misses prose whose first word is hyphenated ("Sign-in failed") — PR fix(i18n): read a hyphenated first word as prose, not a label #677 - check-i18n misses prose whose first word is an acronym ("API keys are stored in the vault") #678
lowcheck-i18n misses prose whose first word is an acronym ("API keys are stored in the vault") — PR fix(frontend): detect prose after leading acronyms #688
Ingestion and retrieval
-
Sync source credentials are pasted into a JSONB column, encrypted by the one second mechanism the vault was meant to replace #937
securitySync source credentials are pasted intosync_sources.configand encrypted byapp/core/crypto.py- the one second mechanism the vault was meant to replace, surviving becauseorganization_idis nullable. Blocks Which sync connectors after Google Drive and S3 - decide the list and the order #938 -
Which sync connectors after Google Drive and S3 - decide the list and the order #938 Which sync connectors after Google Drive and S3 - decided, PR docs(rag): decide which sync connectors follow Drive and S3 #989: the list is cut to Sync connector: import and synchronize websites and sitemaps #984 → Sync connector: synchronize SharePoint and OneDrive #985 → Sync connector: Confluence spaces #986 → Sync connector: import and synchronize Git documentation #987, then Generalize S3Connector to an object store, before Azure Blob and GCS #988; Notion, Slack and email are decided against. The cross-connector permissions answer is in
docs/file-processing.md, and A sync source's wizard never says who will be able to read what it ingests #982/A sync source is created, repointed and deleted with no audit entry #983 are what it still owes -
A connector sync ignores sync_mode and duplicates every document on every run #990highA connector sync ignoredsync_modeentirely and inserted a duplicate of every document on every run - done, 0.0.216. Review of the fix found the basename collision inexisting_document, the delete-before-insert replacement order and the missingupdatedcount -
Documents ingested by a connector sync are invisible to every per-document surface #992highA connector sync created norag_documentsrow, so its documents were searchable and invisible - done, 0.0.217. Review found the delete that did not delete (delete_document's optionalingestion_service, reachable today for an uploaded document from the Documents tab), the row written after the ingest,app-scoped collections skipped by an equality test, and both models unrecorded -
A synced file's error row is never retired by the sync that succeeds #996
lowA synced file's error row is never retired by the sync that succeeds - retirement matchesvector_document_idand a failed parse writes none. Needs asource_pathcolumn onrag_documents: matching by filename would delete the other row when a bucket holds two keys of one basename, which is the collision A connector sync ignores sync_mode and duplicates every document on every run #990 removed on the vector side. The column also lets the Documents tab say where a document came from (found reviewing fix(rag): record a document row for what a connector sync ingests #995) -
The local-directory sync writes its document row after indexing, and only on success #997
lowThe local-directory sync writes its document row after indexing and only on success, so it keeps the exposure Documents ingested by a connector sync are invisible to every per-document surface #992 removed from the connector path and a file that failed to parse leaves no row and no reason (found reviewing fix(rag): record a document row for what a connector sync ingests #995) -
Sync connector: import and synchronize websites and sitemaps #984 A web crawler connector, from a root URL or a sitemap - no credential, first of the five; inherits validate_webhook_url claims DNS-rebinding protection its callers undo by re-resolving #840/MCP OAuth discovery URLs are remote-chosen, and the validated address is not pinned #860's pinned client and makes Paginate GET /rag/documents, and stop full-scanning on ingest #27 matter sooner
-
Sync connector: synchronize SharePoint and OneDrive #985 SharePoint and OneDrive, on a new
SecretKindfor an Entra app - the largest gap on the list, and the sharpest case of A sync source's wizard never says who will be able to read what it ingests #982's question (tenant-wide consent) -
Sync connector: Confluence spaces #986 Confluence spaces, on a page's
version.numberas the change signal -
Sync connector: import and synchronize Git documentation #987 A git repository's documentation - the commit sha makes incremental sync exact; inherits validate_webhook_url claims DNS-rebinding protection its callers undo by re-resolving #840/MCP OAuth discovery URLs are remote-chosen, and the validated address is not pinned #860 for the clone URL
-
rag: a document listed by two sync sources is removed when either one drops it #1879
lowA document two sync sources both list belongs to whichever ingested it last (rag_documents.sync_source_idholds one source), so either dropping it removes it - needs a claims table (found reviewing feat(rag): sync a knowledge base from a website #1868) -
Generalize S3Connector to an object store, before Azure Blob and GCS #988 Generalize
S3Connectorto an object store before writing Azure Blob and GCS - the condition Which sync connectors after Google Drive and S3 - decide the list and the order #938 attached to them -
A sync source's wizard never says who will be able to read what it ingests #982
frontendThe sync-source wizard never says who will be able to read what a source ingests - the model is written down in Which sync connectors after Google Drive and S3 - decide the list and the order #938, and this is the sentence that states it where the collection is chosen -
A sync source is created, repointed and deleted with no audit entry #983
securityA sync source is created, repointed and deleted with no audit entry, so "who bound this credential to this collection" has no answer after the fact (found deciding Which sync connectors after Google Drive and S3 - decide the list and the order #938) -
Tabs for the RAG pages: Reusable integrations as /rag's third tab, and a knowledge base's three sections as three #939Tabs for the RAG pages - done, 0.0.213 -
The RAG dialogs: a markdown editor for the image prompt, one width scale, and a mark on the parser choices #940
lowThe RAG dialogs:MarkdownEditorfor the image prompt, one width scale (the same form gets 512px in create and 768px elsewhere), and a mark on the parser choices -
Move blocking file work off the request event loop #25mediumMove blocking file work off the request event loop - done (offloadedsave/loadand the worker's hash/stat;deletewas missed, now rag: LocalFileStorage.delete blocks the event loop during bulk teardown #1294) -
Paginate GET /rag/documents, and stop full-scanning on ingest #27
mediumPaginate GET /rag/documents, and stop full-scanning on ingest -
Add a real reranker to RAG retrieval #142 Add a real reranker to RAG retrieval — PR feat(rag): add a real reranker to RAG retrieval #911
-
rag: binding an embedding secret skips the caller's secret-view check #912
mediumsecurityrag: binding an embedding secret skips the caller's secret-view check — found reviewing Add a real reranker to RAG retrieval #142 -
rag: per-collection resolution picks a KB by non-unique collection_name #913
mediumsecurityrag: per-collection resolution picks a KB by non-unique collection_name — found reviewing Add a real reranker to RAG retrieval #142 -
rag: chunk_count is never recorded, so every document claims 0 chunks #147
mediumrag: chunk_count is never recorded, so every document claims 0 chunks — PR feat(rag): chunk with our own splitters and drop the langchain tree #834 -
rag: KB stats count status "completed", but ingestion writes "done", so indexed_count is always 0 #148
mediumrag: KB stats count status "completed", but ingestion writes "done", so indexed_count is always 0 — PR fix(rag): count the status the pipeline writes, not one nothing writes #957, which introducesDocumentStatusso the writer and the reader name one member -
The ingestion flow's _update_status has a branch nothing can reach, and a status parameter with one value #956
lowThe ingestion flow's_update_statushas an unreachabledonebranch and a status parameter all four callers pass one value to — found fixing rag: KB stats count status "completed", but ingestion writes "done", so indexed_count is always 0 #148 -
Replace langchain-text-splitters with our own, and drop the langchain tree #158 Replace langchain-text-splitters with our own, and drop the langchain tree — PR feat(rag): chunk with our own splitters and drop the langchain tree #834, with rag: chunk_count is never recorded, so every document claims 0 chunks #147 in the same branch
-
Two RAG document-lookup helpers disagree on precedence; get_documents has no ORDER BY #548
highTwo RAG document-lookup helpers disagree on precedence; get_documents has no ORDER BY — PR Give RAG document lookup one precedence and a stable order #670 -
PyMuPDF OCR fallback nests an event loop, so a scanned PDF indexes empty #550
highPyMuPDF OCR fallback nests an event loop, so a scanned PDF indexes empty — PR fix(rag): await the OCR describer instead of nesting an event loop #666 -
One RAG document-lookup helper; collapse the 3-4 full-collection scans per ingest #566
lowOne RAG document-lookup helper; collapse the 3-4 full-collection scans per ingest -
rag-source-add writes an unvalidated, unowned collection name from the CLI #707
mediumrag-source-add writes an unvalidated, unowned collection name from the CLI -
Dispose the vector store's engine, or stop building one per ingested document #948
highThe ingestion worker builds a pooled vector-store engine per document and disposes none, so a large batch reachesmax_connections— PR fix(rag): dispose the vector store each ingestion flow builds #960 -
Insert a document's chunks in one statement, not one per chunk #950
mediumA document's chunks are inserted one statement each, so a 200-page PDF is one to three thousand round trips — PR perf(rag): write a document's chunks in batches, not one statement each #962 -
A document's embeddings are all held in memory at once, so a long PDF is hundreds of megabytes in the worker #963
lowA document's embeddings are all held in memory at once, so a long PDF is hundreds of megabytes in the worker — found reviewing PR perf(rag): write a document's chunks in batches, not one statement each #962 -
The in-process RAG fallback handlers have no caller, and each leaks the store #948 fixed #959
lowThe in-process RAG fallback handlers have no caller and each carries Dispose the vector store's engine, or stop building one per ingested document #948's undisposed store — found fixing Dispose the vector store's engine, or stop building one per ingested document #948 -
rag: teardown unlinks stored files before the request commits #1293
mediumrag: teardown unlinks stored files before the request commits, so a failed commit leaves rows pointing at missing uploads — found reviewing fix(rag): unlink a dropped collection's stored uploads #1284 (PR for DELETE /rag/collections/{name} orphans the stored upload files #1265) -
rag: LocalFileStorage.delete blocks the event loop during bulk teardown #1294
mediumrag:LocalFileStorage.deleteblocks the event loop, and bulk teardown deletes every file in one turn — found reviewing fix(rag): unlink a dropped collection's stored uploads #1284; thedeletecase Move blocking file work off the request event loop #25 missed -
rag: delete paths drop vector tables and remove vectors before the request commits #1347
mediumrag: delete paths drop vector tables and remove vectors before the request commits — same rollback class as rag: teardown unlinks stored files before the request commits #1293, on the store's own engine; found finishing rag: teardown unlinks stored files before the request commits #1293 -
rag: deferred teardown file unlinks are in-process, not durable across a restart #1349
lowrag: deferred teardown file unlinks are in-process (spawn_after_commit), so a worker restart mid-drain orphans files — recoverable leak, the durable (Prefect) half of rag: teardown unlinks stored files before the request commits #1293; sibling of Org-teardown cleanup is lost if the process dies after commit (spawn_after_commit is not durable) #1274 -
rag: an app-scoped collection can be created but can never index or search #1631
mediumrag: an app-scoped collection can be created but can never index or search - it belongs to no organization, so it has no vault to hold the embedding key feat(rag)!: drop the deployment embedding key; add data-protection docs #1604 made the only one; needs a deployment-level credential or a refusal at creation. Caused by feat(rag)!: drop the deployment embedding key; add data-protection docs #1604 (for Document and implement the data-protection deployment controls for FA-108 #1596), found reviewing it; the rows Documents ingested by a connector sync are invisible to every per-document surface #992 and rag: per-collection resolution picks a KB by non-unique collection_name #913 already treat specially -
rag: a self-hosted embedding provider, so a knowledge base can stay on the deployment's own hardware #1632 rag: a self-hosted embedding provider in the catalog, so a knowledge base can stay on the deployment's own hardware - the one hop
docs/data-protection.mdcannot make local today; named there as untracked until this (Document and implement the data-protection deployment controls for FA-108 #1596, feat(rag)!: drop the deployment embedding key; add data-protection docs #1604). Beside Add a real reranker to RAG retrieval #142 -
rag/org-teardown: collection drop's reference re-check is not serialized with collection claims (TOCTOU) #1355
mediumrag: the teardown collection-drop'slist_by_collection_namere-check is not serialized with collection claims (TOCTOU) — the drop can still delete a name reclaimed between the re-read and theDROP TABLE; found reviewing rag: delete paths drop vector tables and remove vectors before the request commits #1347, pre-existing in Org-teardown cleanup is lost if the process dies after commit (spawn_after_commit is not durable) #1274's org-purge too; needs an advisory lock across both drops and thePOST /rag/collections/{name}claim path; rooted in rag: per-collection resolution picks a KB by non-unique collection_name #913 -
rag: two in-request collection-drop paths bypass the durable locked teardown #1359
mediumrag: two in-request collection-drop paths bypass the durable locked teardown —DELETE /rag/collections/{name}(no rag: per-collection resolution picks a KB by non-unique collection_name #913 re-check, no lock) and_purge_personal_collections(re-check, no lock), both dropping the table before the request commits; found reviewing rag/org-teardown: collection drop's reference re-check is not serialized with collection claims (TOCTOU) #1355, which locked the durable path but not these; siblings of rag: delete paths drop vector tables and remove vectors before the request commits #1347/rag: deferred teardown file unlinks are in-process, not durable across a restart #1349/rag/org-teardown: collection drop's reference re-check is not serialized with collection claims (TOCTOU) #1355/rag: per-collection resolution picks a KB by non-unique collection_name #913 -
rag: deferred vector-table drop leaks across tenants via name reuse (and a default-KB clear regression) #1362
highsecurityrag: the whole deferred-drop arc (rag: delete paths drop vector tables and remove vectors before the request commits #1347/rag: deferred teardown file unlinks are in-process, not durable across a restart #1349/rag/org-teardown: collection drop's reference re-check is not serialized with collection claims (TOCTOU) #1355/rag: two in-request collection-drop paths bypass the durable locked teardown #1359) frees a collection name before the DROP runs, so an attacker re-creating the same explicit name in the commit-to-drop window hasCREATE TABLE IF NOT EXISTSadopt the victim's populated table and reads its chunks; the rag/org-teardown: collection drop's reference re-check is not serialized with collection claims (TOCTOU) #1355 lock only serializes, it doesn't stop the claim winning the race. Also folds the default-KB clear regression. Needs a tombstone/generation (a mechanism decision, like Org-teardown cleanup is lost if the process dies after commit (spawn_after_commit is not durable) #1274). Found by codex on fix(rag): route the last two in-request collection drops through the durable teardown #1361; the arc's merge should hold until this is decided -
rag: teardown reservations need a stuck-tombstone sweep, and the default-clear has an ingest window #1364
lowrag: teardown reservations (rag: deferred vector-table drop leaks across tenants via name reuse (and a default-KB clear regression) #1362) have no stuck-tombstone sweep — a name whose drop permanently fails is blocked for good — and the default-KB clear has a same-tenant ingest-vs-drop window; both fail-safe, found reviewing rag: deferred vector-table drop leaks across tenants via name reuse (and a default-KB clear regression) #1362 -
rag: serialise teardown against concurrent writes (upload, sync) end to end #1382
lowrag: teardown is not fully serialised against concurrent writes - the worker sync/retry ingestion paths don't consult the reservation (reachable for a default+sync clear, latent while nothing sets is_default), the reservation is created after the row delete so the upload guard is best-effort, and that guard drops its lock to avoid inverting delete's lock order; found reviewing fix(rag): reap stuck teardown reservations, guard uploads, and clear a dropped default #1378 (the rag: teardown reservations need a stuck-tombstone sweep, and the default-clear has an ingest window #1364 PR) -
rag: claim and org purge take the teardown and organizations locks in opposite order (ABBA deadlock) #1387
lowrag:claimand orgpurgetake the teardown lock and theorganizationsrow lock in opposite order — a KB create naming an existing collection, racing a purge of that collection's org, deadlocks (ABBA); pre-existing since rag: deferred vector-table drop leaks across tenants via name reuse (and a default-KB clear regression) #1362's claim lock, split from rag: serialise teardown against concurrent writes (upload, sync) end to end #1382, found reviewing fix(rag): reap stuck teardown reservations, guard uploads, and clear a dropped default #1378 -
rag: teardown lock-ordering residuals (gap-collection D↔K, user-delete U↔T) need a serialization point #1389
lowrag: teardown lock-ordering residuals surviving rag: claim and org purge take the teardown and organizations locks in opposite order (ABBA deadlock) #1387's fix — a gap collection born betweenpurge's snapshot and its org lock can D↔K-deadlock with a concurrent KB delete/drop and is dropped-but-not-reserved (rag: deferred vector-table drop leaks across tenants via name reuse (and a default-KB clear regression) #1362 window reopened for that subset); and user-delete'susersFOR UPDATE inverts against a personal-KB create's teardown lock (U↔T); both narrow and self-resolving, both need a serialization point/outbox; split from rag: serialise teardown against concurrent writes (upload, sync) end to end #1382, found in rag: claim and org purge take the teardown and organizations locks in opposite order (ABBA deadlock) #1387's adversarial review
Unattended runs
- Drain background work before tearing the process down #11
highDrain background work before tearing the process down - Agent Schedules & Triggers: set up and manage unattended runs from the UI #44 Agent Schedules & Triggers: set up and manage unattended runs from the UI — PR feat(agents): heartbeat & agent triggers #537
- Scheduled trigger fire() drops last_run_id and fails the flow on a model error #588
mediumScheduled trigger fire() drops last_run_id and fails the flow on a model error — PR fix(triggers): record a model-errored fire instead of failing the flow #589 - Stitch the parallel W3 features into one product: triggers dashboard widget, triggers onboarding, unified naming #594 Stitch schedules/triggers + dashboard customization + onboarding together on main
- run_now executes the agent synchronously in the HTTP request (504 + double-fire on slow runs) #658
mediumrun_now executes the agent synchronously in the HTTP request (504 + double-fire on slow runs) — PR Dispatch a manual trigger fire instead of running it in the request #679 - test_flow_starts_after_commit's spawn probe flakes on a 250ms grace under make test #680
lowtest_flow_starts_after_commit's spawn probe flakes on a 250ms grace under make test — PR Wait on the dispatched task instead of a 250ms grace #705 - A sandbox's activity log lives in the service's memory: 200 entries, gone on restart #1061
mediumThe sandbox activity log lives only in the service's 200-entry ring buffer, so a restart loses it — PR feat(agents): heartbeat & agent triggers #537 - Gmail as a connected account, and delete the email relay webhook it stands in for #1068 Gmail as a connected account, and delete the email relay webhook it stands in for — PR feat(agents): heartbeat & agent triggers #537
- The trigger create dialog: a fixed 90vh height, markless template cards, unreadable presets #1069
lowThe trigger create dialog: a fixed 90vh height, markless template cards, unreadable presets — PR feat(agents): heartbeat & agent triggers #537 - A trigger's Environment picker hides the default's name, so an environment reads as missing #1070
lowA trigger's Environment picker hides the default's name, so an environment reads as missing — PR feat(agents): heartbeat & agent triggers #537 - The API trigger is a ghost button in the toolbar, not a tile beside the portals #1071
lowThe API trigger is a ghost button in the toolbar, not a tile beside the portals — PR feat(agents): heartbeat & agent triggers #537 - GitHub triggers should be a GitHub App, not an OAuth App with admin:repo_hook #1072 GitHub triggers should be a GitHub App, not an OAuth App with admin:repo_hook — found reviewing feat(agents): heartbeat & agent triggers #537, blocked on nothing but changes the delivery contract every portal shares
- An approval alert cannot reach its request past the first queue page #1336
mediumfrontendAn approval alert cannot reach its request past the first queue page -list_approvalsreturns the 50 oldest and the tab has no pagination, so the newly parked run the email is about is the one row the reader cannot get to (found reviewing fix(approvals): send the parked-run alert to the queue, not the Builder #1202)
What a run costs
- Commit the run row so a failed run is still accounted #3
highCommit the run row so a failed run is still accounted - Exclude a resumed run's own spend from its budget baseline #15
mediumExclude a resumed run's own spend from its budget baseline - Default a new organization's budget to $100 #785 Default a new organization's budget to $100 (the budget existing by default, not measuring against it)
- spend_by_provider and spend_by_key cannot attribute a delegation's vendor or key #194 spend_by_provider and spend_by_key cannot attribute a delegation's vendor or key
- A failed terminal commit replaces the cancellation that ended the run #235
lowA failed terminal commit replaces the cancellation that ended the run - Per-person spend card under-counts vs By agent, with nothing explaining the gap #539 Per-person spend card under-counts vs By agent, with nothing explaining the gap
- The "could not be priced" caveat misses a tree that straddles the start of the window #620
lowThe "could not be priced" caveat misses a tree that straddles the start of the window — PR fix(budgets): count an unpriced tree that straddles the window start #650 - A message shows a cost with no sign that it is partial, and a conversation shows no total #772
mediumA message shows a cost with no sign that it is partial, and a conversation shows no total — split out of Add Context manager #49, same point as Improve the Activity page (/runs) — plan + mockup first #45 - Per-message cost is web-chat only, so a channel or API thread totals nothing #776
lowPer-message cost is web-chat only, so a channel or API thread totals nothing — found building A message shows a cost with no sign that it is partial, and a conversation shows no total #772 - Persist a model profile's context length, so compaction stops trusting a registry that is wrong #773 Persist a model profile's context length, so compaction stops trusting a registry that is wrong — split out of Add Context manager #49
Secrets at rest
- Make the vault master key explicit and rotatable #8
highMake the vault master key explicit and rotatable - Stop putting tokens in the OAuth redirect URL #14
highStop putting tokens in the OAuth redirect URL - Require a freshness claim on an embed token #23
mediumRequire a freshness claim on an embed token - Vault 'seal N fields under one version' is hand-rolled at 4 models; agent_embed has no key-version column #552
mediumVault 'seal N fields under one version' is hand-rolled at 4 models; agent_embed has no key-version column - The observability secret is validated at run time; the factory docstring claims publish refuses it #561
mediumThe observability secret is validated at run time; the factory docstring claims publish refuses it
The database underneath
- Reconcile the delete cascades with the CHECK constraints #9
highReconcile the delete cascades with the CHECK constraints - Stop holding a pooled DB connection across slow work #12
highStop holding a pooled DB connection across slow work- Reap runs a dead process left durably running #1078
mediumReap runs a dead process left durably running — the crash-orphan remainder of Stop holding a pooled DB connection across slow work #12's early commit - Knowledge singleton's pooled engine can cross worker event loops #1079
mediumKnowledge singleton's pooled engine can cross worker event loops — pre-existing, found reviewing Stop holding a pooled DB connection across slow work #12 - Dev-stack watchdog kills a healthy reloaded server and leaves nothing serving #1080
mediumDev-stack watchdog kills a healthy reloaded server — found standing up Stop holding a pooled DB connection across slow work #12's smoke stack
- Reap runs a dead process left durably running #1078
- Add row locks to four check-then-act races #17
mediumAdd row locks to four check-then-act races - Return the five repository-calling routes to the service layer #28
mediumReturn the five repository-calling routes to the service layer - A session can be in the sessions page and not in its total #1337
lowA session can be in the sessions page and not in its total: The admin drawer reports "Never signed in" for anyone who has signed out #1256'sopenpredicate evaluates its ownnow()per statement, so a session expiring between the page query and the count query is counted by one and not the other
Middleware written and never registered
- Actually apply the rate limiter #7
highActually apply the rate limiter - Register SecurityHeadersMiddleware #18
mediumRegister SecurityHeadersMiddleware
The product's surfaces and shells
- Add onboarding #53 Add onboarding — PR feat(onboarding): first-run tour, guided flows #624
- Default avatars for orgs, profiles and agents #60 Default avatars for orgs, profiles and agents
- Secrets 'Added by' avatar seeds on email, not user id (hue inconsistent) #799 Secrets 'Added by' avatar hue inconsistent with member lists (found implementing Default avatars for orgs, profiles and agents #60)
- Mobile View #120 Mobile View
- Add default system prompt #124 Add default system prompt
- Pre-enable a default set of tools when creating an agent #786 Pre-enable a default set of tools when creating an agent (same shape as Add default system prompt #124, tool list TBD)
- Fix Agent Builder frontend #127 Fix Agent Builder frontend
- Improve "Alerts" in Limits section (agent builder) #128 Improve "Alerts" in Limits section (agent builder)
- Model picker says the org has no models when the profiles read failed #863
lowModel picker says the org has no models when the profiles read failed — same defect one element from Agent draft can't be published by a builder who can't add a model #591, found reviewing PR fix(builder): warn up front when an agent draft can never get a model #846 — closed; the sibling case is in Six answers to "what models and providers exist", and none of them is the authority #923 - Chat composer: a long paste should attach, and attachments should look like files #133 Chat composer: a long paste should attach, and attachments should look like files
- A per-conversation approval mode in /chat: follow the agent, approve everything, or ask about everything #925 A per-conversation approval mode in /chat - follow the agent, approve everything, or ask about everything. Loosens what a spec gated, so it is gated on
approvals:decide, ceilinged by the organization, and every waived call still writes its row - Chat's temperature and thinking-effort overrides are sent on every turn and read by nothing #924
mediumChat'stemperatureandthinking_effortoverrides are sent on every turn and read by nothing - the reader left with the general-assistant path inb56ba1feand the popover did not (found scoping A per-conversation approval mode in /chat: follow the agent, approve everything, or ask about everything #925) - The chat's Model tab opens empty, so it never says which model the conversation runs on #926
lowThe chat's Model tab opens empty, so it never says which model the conversation runs on - the published profile is already loaded forcontext_window_tokensand only the window is kept - Composer attachments wrap into rows: twenty files is ~850px of composer, and it should be a carousel #927 Composer attachments wrap into rows: twenty files is ~850px of composer. One scrolled row and a compact
FileCardvariant - the sequel to Chat composer: a long paste should attach, and attachments should look like files #133, under One file viewer, not four: the chat file dialog is the poorest of them #136's one-card constraint - Rating a message spins both thumbs: the spinner is keyed on the current rating, not the button clicked #928
lowRating a message spins both thumbs - the spinner is keyed oncurrentRating, which is null on every unrated message, rather than on the button clicked. Same file as rating-buttons hand-rolls two fetch calls instead of a lib client and a hook #563 - Favourite a conversation: a starred band at the top of the chat sidebar #929 Favourite a conversation: a starred band at the top of the chat sidebar, on top of /chat: search, sort and an agent filter on the conversation list #159's controls
- The Share conversation dialog: a member picker instead of an email box, room to breathe, and icons on view/edit #931 The Share conversation dialog:
MemberPickerinstead of an email box, room to breathe, and icons on view/edit - Dashboard pages have no bottom padding: it is declared on the flex-column scroll container, where it is not painted #933
lowDashboard pages have no bottom padding -maindeclarespb-20 lg:pb-16on a flex-column scroll container, which does not paint it once the page overflows; four surfaces have re-added it inside the content at three different values - The admin user drawer: four facts, no memberships, no last-seen, and three privileged actions that look alike #942 The admin user drawer: four facts, no memberships, no last-seen, and three privileged actions that look alike (the piece of Admin redesign #63 worth doing alone)
- Active sessions: paging blanks the card and jumps the scroll - the query has no keepPreviousData #944
lowActive sessions paging blanks the card and jumps the scroll - the one paged query with nokeepPreviousData, whichquery-freshness.tsalready diagnoses in writing - The run detail panel survives a tab switch on /runs, and below lg it hides the tab you switched to #934
lowThe run detail panel survives a tab switch on /runs, and belowlgit hides the tab you switched to - the panel is page state, the tab is uncontrolled, so nothing clears the focus. Blocks The approval email links to the agent's Builder page, which has no approvals queue #935 - The approval email links to the agent's Builder page, which has no approvals queue #935
mediumThe approval email links to/agents/{id}, which has no approvals queue - there is no URL for the Approvals tab to link to (found scoping The run detail panel survives a tab switch on /runs, and below lg it hides the tab you switched to #934) - The approval alert is mailed to people who may not decide, and the page just has no queue for them #1203
mediumThe approval alert is mailed to people who may not decide -builderandmemberhold noapprovals:decide, so the initiator the default audience names follows Review the request to a page with no Approvals tab at all (found by the reviewer on PR fix(approvals): send the parked-run alert to the queue, not the Builder #1202) - Alert emails name no organization, so they open whichever one the reader last used #1204
mediumAlert emails name no organization, so they open whichever one the reader last used - all four notification URLs are organization-agnostic whileactiveOrgIddecides what the page acts on;run.organization_idis in scope and discarded. Same class as The members page judges permissions from the active organization while acting on the one in the URL #1032 (found by the reviewer on PR fix(approvals): send the parked-run alert to the queue, not the Builder #1202) - Notification bell badge and mark-all-read cap at 500 unread with no continuation #1761
severity:lowThe notification bell badge and mark-all-read both cap at 500 unread candidates with no continuation - an account past that count sees a wrong badge and a partial mark-all-read, silently (found by the reviewer on PR feat(notifications): the write path and the four inbox routes (#1598) #1692, notification center Add role-targeted in-app notifications, delivery channels and app-admin announcements #1598) - A rate-limited mandatory security_event/configuration_changed is dropped with no coalesced fallback #1762
severity:mediumsecurityA rate-limited mandatorysecurity_event/configuration_changednotification is dropped with no coalesced fallback - the audit entry still lands, only the alert is silently lost (found by the reviewer on PR feat(notifications): notify on a security event or a settings change #1711, notification center Add role-targeted in-app notifications, delivery channels and app-admin announcements #1598) - ABBA lock hazard: audit-chain lock vs. admin-delete's app-admin row locks #1763
severity:mediumABBA lock hazard: the audit-chain lock (impersonation start) vs. admin-delete's app-admin row locks (FOR UPDATE) - same class as rag: claim and org purge take the teardown and organizations locks in opposite order (ABBA deadlock) #1387/rag: teardown lock-ordering residuals (gap-collection D↔K, user-delete U↔T) need a serialization point #1389, can silently drop a mandatory notification when the deadlock victim is the survivor's savepoint rather than the whole transaction (found by the reviewer on PR feat(notifications): notify on a security event or a settings change #1711, notification center Add role-targeted in-app notifications, delivery channels and app-admin announcements #1598) - Environments: pin a version from the environment, not only from the version #134 Environments: pin a version from the environment, not only from the version
- One table primitive, with sortable headers and filters, everywhere #139 One table primitive, with sortable headers and filters, everywhere — closed
- Sandboxes: split connections from what is running, into tabs #140 Sandboxes: split connections from what is running, into tabs
- A sandbox's activity log lives in the service's memory: 200 entries, gone on restart #1061 A sandbox's activity log lives in the sandbox service's memory: 200 entries per session, gone on restart, and nothing on our side ever saw them. Record each operation as it happens, then the log is a query rather than a window and paginating it means something.
Later(found finishing the Running tab in Sandboxes, runtimes and workspaces: an attachment that never reaches the workspace, a CSP that blocks every PDF, and seven things nothing explains #1039; the truncation notice is on that branch) - Migrate the sandbox onto Pydantic AI workspaces (pydantic-ai-backend breaking release) #2003
dependenciesMove the sandbox onto Pydantic AI workspaces (ctx.workspace) via pydantic-ai-backend'sSandboxdWorkspaceandConsoleCapability(use_workspace=True)- library side is feat(workspaces)!: replace the backend protocol with Pydantic AI workspaces pydantic-ai-backend#112; changes what feeds A sandbox's activity log lives in the service's memory: 200 entries, gone on restart #1061's operation record - web_search and create_chart render as raw JSON: the frontend matches tool names the backend stopped emitting #144
mediumweb_search and create_chart render as raw JSON: the frontend matches tool names the backend stopped emitting - run_python: collapse the code once the output arrives, and show it while it runs #145 run_python: collapse the code once the output arrives, and show it while it runs
- /chat: search, sort and an agent filter on the conversation list #159 /chat: search, sort and an agent filter on the conversation list
- A new conversation shows no agent until the page is reloaded #909
lowA new conversation shows no agent until the page is reloaded — the listing is fetched before the first answer exists - Let a person arrange their own dashboard: pick widgets, order and width #213 Let a person arrange their own dashboard: pick widgets, order and width — closed (PR feat(dashboard): let a person arrange their own dashboard layout #587), which is what makes Does /admin "Overview" earn a page? Six figures and three links that all exist elsewhere #922 answerable
- Skills are always available: drop the 'Ready-made skills' install step, one Skills list #281 Skills are always available: drop the 'Ready-made skills' install step, one Skills list
- A consistent list-page shell (container, pagination, filter bar) across resource pages #282 A consistent list-page shell (container, pagination, filter bar) across resource pages — closed
- Every wrong-method request answers 500 instead of 405 #917
mediumEvery wrong-method request answers 500 instead of 405: OpenTelemetry's FastAPI instrumentation reads.pathoff_IncludedRouter, which FastAPI 0.141 has none of (found reviewing fix(builder): configure an agent in one place, and stop guessing at what a reader sees #914; pre-existing, reachable on every route) - Remove the Refresh button from /admin #283 Remove the Refresh button from /admin — closed
- Standardise the admin pages (users and tabs) to the shared table and list-page shell #284 Standardise the admin pages (users and tabs) to the shared table and list-page shell — closed, and /admin/organizations has no search, sort, filter or pagination - the route behind it answers none #921 is what it left behind
- /admin/organizations has no search, sort, filter or pagination - the route behind it answers none #921
/admin/organizationshas no search, sort, filter or pagination, and the route behind it answers none - the one page Standardise the admin pages (users and tabs) to the shared table and list-page shell #284's chain left with the shell and none of the controls - Does /admin "Overview" earn a page? Six figures and three links that all exist elsewhere #922 Does
/admin"Overview" earn a page? Six figures and three links that all exist elsewhere - theplatformdashboard widget reads the same/admin/stats, and the three links repeat three of the five tabs above them - mcp-server-list still uses native confirm(): no busy-guard, so a double-click can double-DELETE #554
mediummcp-server-list still uses native confirm(): no busy-guard, so a double-click can double-DELETE - Onboarding steps on the MCP page vanish when the server catalog is empty #592
lowOnboarding steps on the MCP page vanish when the server catalog is empty — PR feat(onboarding): first-run tour, guided flows #624 - Onboarding tour leaves Settings and the workspace file browser unexplained #593 Onboarding tour leaves Settings and the workspace file browser unexplained — PR feat(onboarding): first-run tour, guided flows #624
- A still-parked run says nothing about waiting once the page is reloaded #601
lowA still-parked run says nothing about waiting once the page is reloaded — PR fix(chat): keep a parked run saying it waits after a reload #653 - Every baked MCP logo is keyed on a brand domain the lookup never asks for #614
lowEvery baked MCP logo is keyed on a brand domain the lookup never asks for — PR fix(mcp): key baked logos on the URL host the lookup asks with #648 - MCP OAuth callback outcome is read by nothing - no toast after the provider redirect #657
mediumMCP OAuth callback outcome is read by nothing - no toast after the provider redirect — PR Announce the MCP OAuth outcome after the provider redirect #682 - Activity: a date-range picker owned by the page, windowing all three tabs and the export #760 Activity: a date-range picker owned by the page, windowing all three tabs and the export — PR Frontend standardisation: one table, one shell, admin on both, skills without install, map in four directions #759
- Activity: an icon per run surface — Slack, Telegram and Mattermost get their marks #761 Activity: an icon per run surface — Slack, Telegram and Mattermost get their marks — PR Frontend standardisation: one table, one shell, admin on both, skills without install, map in four directions #759
- Activity: expose the filters the backend already answers — rated up, person, agent, version #762 Activity: expose the filters the backend already answers — rated up, person, agent, version — PR Frontend standardisation: one table, one shell, admin on both, skills without install, map in four directions #759
- Run export drops the on-screen status/surface/rating filters it claims to carry #763
mediumRun export drops the on-screen status/surface/rating filters it claims to carry — PR Frontend standardisation: one table, one shell, admin on both, skills without install, map in four directions #759 - Activity: paginate the run history — the page shows fifty rows and says nothing about the rest #764 Activity: paginate the run history — the page shows fifty rows and says nothing about the rest — PR Frontend standardisation: one table, one shell, admin on both, skills without install, map in four directions #759
- Activity: open the conversation behind a run — the id is there and nothing links it #765 Activity: open the conversation behind a run — the id is there and nothing links it — PR Frontend standardisation: one table, one shell, admin on both, skills without install, map in four directions #759
- Activity: one control grammar and an observability-grade look across Approvals, Runs and Spend #766 Activity: one control grammar and an observability-grade look across Approvals, Runs and Spend — PR Frontend standardisation: one table, one shell, admin on both, skills without install, map in four directions #759
- Activity's filters are local state, so no dashboard slice can hand over to the runs behind it #768 Activity's filters are local state, so no dashboard slice can link to the runs behind it — found reviewing PR feat(dashboard): let a person arrange their own dashboard layout #587
- Web chat never rehydrates a conversation's history, so a reopened thread runs with no context #771
highWeb chat never rehydrates a conversation's history, so a reopened thread runs with no context — found scoping Add Context manager #49 - A turn cancelled by a closed tab is unrecoverable, and its spend is not #781 A turn cancelled by a closed tab is unrecoverable, and its spend is not — found adding Add Context manager #49's progress notice
- Show how full the context window is, beside what the turn cost #774 Show how full the context window is, beside what the turn cost — split out of Add Context manager #49
Models and providers
- Six answers to "what models and providers exist", and none of them is the authority #923 Six answers to "what models and providers exist", and none of them is the authority -
PROVIDERS(27),model_listings.json(20),model_fallbacks.json(7, and not about fallbacks), thegenai_pricessnapshot,image_models.jsonand two hand-written tables indocs/models.md, over a run-time authority that is Pydantic AI's own inference. Seven providers answer an empty picker today.
Performance and security (audit 2026-08-19)
The sweep behind these is Audit agenticos 2026-08-19 performance and security. #947 is
the one that is not like the others: it is a live, unauthenticated denial of service.
- Rate-limit the auth surface, and take bcrypt off the event loop #947
criticalsecurityRate-limit the auth surface, and take bcrypt off the event loop - 171 ms measured percheckpw, no limit on any route inauth.py, so ~6 req/s saturate a worker. Also an enumeration timing oracle and an unlimited mail amplifier. Supersedes the auth half of Actually apply the rate limiter #7 - Dispose the vector store's engine, or stop building one per ingested document #948
highThe ingestion worker creates and abandons a pooled engine per document -aclose()has one caller in the repo;get_worker_db_contextdoes the opposite deliberately one module away - Collapse the dashboard's fifteen sequential aggregates into a handful #949 Collapse the dashboard's fifteen sequential aggregates into a handful - ten scans of one window; not
gather, because Two gated tool calls in one model step race the request's AsyncSession #169 - #950 Insert a document's chunks in one statement, not one per chunk
- #951 Stream bodies through the BFF proxy instead of buffering them - 50 MB buffered twice on upload, TTFB = whole transfer on download
- #952 One HTTP client per channel adapter, not one per call - ~30 TLS handshakes per streamed turn at
EDIT_INTERVAL = 1.0 - #953 Two listings query per row where the code beside them batches
- #954 Resolve a spec's references in one query - six loops, one of them on every run
- #955 Stop shipping the whole brand-glyph table to the sign-in page - 89 marks to draw three
CI, the suite and the tools
- #33
lowCode health clean-up: nine small items from the 2026-08-01 audit - #109 TypeScript 7 and ESLint 10 are blocked, each by a different plugin
- #1820
dependenciessecurityeffort:mmcpis capped below 2.0 because 2.0 moves the SDK tohttpx2:PinnedAsyncClientis anhttpxclient and cannot send thehttpx2.Requestthe OAuth helpers now build, the discovery refusals catch the wrong library'sInvalidURL(#889 again), and the streamable transport renamed itself and dropped itsheadersargument. Migrating the pin is the change; a shim would put the SSRF check and the request in different libraries - found reviewing PR #1804, which Dependabot had widened the cap in - #130 E2E: the vault rotation spec fails intermittently before the secret is created
- #154 e2e: sharing and skills specs fail when a mutation's refetch lands stale
- #1474
lowe2e:journey.specflakes reading the hosted link after publish - the same class, in the one spec #154 did not cover; the reload before the read narrows the window rather than closing it - found on PR #1383, which touches none of it - #155 Backend dependencies: fastapi-cache2 is initialised and caches nothing, plus four more that are imported nowhere — PR #831
- #156 Frontend dependencies: date-fns is unused and three icon libraries answer one question — PR #835
- #836
gen:mcp-logoswrites an unformatted file, somake lintfails until the commit hook rewrites it — found writing #156's generator, which solves it — PR #835, alongside #156 - #829
highThe Resend email provider imports an SDK declared nowhere — found by thedeptrygate #831 adds, and what keeps DEP001 switched off until it is answered — PR #842; the provider was never reachable and is deleted, so #843 records what bringing Resend back would cost - #830 Recorded: why
google-api-python-clientand every model-provider extra stay in the image — the two questions #155 deliberately excluded from its own PR — closed as recorded, both answers still hold - #843 Resend as an email provider, properly, or not at all — closed, not planned: SMTP is the one way this platform sends mail
- #833 ty relaxations are justified by libraries this project does not have — langgraph and deepagents never were, langchain stopped being one in #158 — PR #842
- #162 e2e: the cost journey spec flakes on main after passing on the PR
- #855
lowmake auditfails the required Security Scan job on a single pypi.org timeout — one request per locked distribution, no retry; the network half of the same problem #154 records for e2e - #203
lowyamlfmt, zizmor and the pre-commit basics read only changed files, and no gate reads the tree - #311
highThe ai-review reviewer has produced nothing since 2026-08-05, and reports success - #317 CI burns ~8,900 billed Actions minutes a week, a fifth of it on runs nothing cancels
- #618 Three frontend tests hand-roll the same source-tree walker — PR #645
- #635 check_comments.py descends into every .claude worktree, so a commit waits ~7 minutes — PR #647
- #663 Bring app/services/embed_session.py into the 100% coverage + ty gate — PR #674
- #862
lowtest-frontendgoes red on a 5stestTimeoutcoverage instrumentation cannot meet — a different spec each run, each passing alone; the vitest half of the timing-flake pair #154 and #162 record for e2e — found reviewing PR #624 - #915
mediumFrontend coverage gate red on Node 26: the built-insessionStorageshadows jsdom's in vitest, soresume.ts's catch loses coverage while every test passes - the sessionStorage half of the localStorage normalizationvitest.setup.tsalready does; pre-existing from PR #624, found running the gate for #537's trigger-wizard restyle - #1075
lowfrontendlayout.test.tsxreaches the network - the root layout's unmockedreadBranding()makes the spec depend on what is listening on :8000, so it hangs against a container that accepts connections without answering; green on CI and against a healthy backend, which is why nobody had seen it - #1338
lowciFlaky:test_lifespan_drain.py::test_the_lifespan_waits_for_in_flight_background_workfails under xdist withRuntimeError: Event loop is closedand passes on a plain re-run - the test that guards the drain #1137 and #1274 depend on — root cause is the module-globalmodel_catalog._listing_clientclosed on a dead loop; mitigated in PR #1378 (the drain test stubs the close), the conftest reset that fully fixes it stays open; found working #1364 (duplicate #1381 folded in) - #1545
enhancementciPublishagenticos-backendandagenticos-frontendto GHCR on everyv*tag (andedgefrommain);docker compose uppulls them, a clone keeps building throughdocker-compose.override.yml, the quickstart needs only Docker. Blocked by #1544. Neighbours #1512 (GHCR package visibility), #1415 (SBOM per release), #143 (thedockerjob leavesci.yml) - #1830
higheffort:sValkey 8 cannot read the RDBredis:7-alpineleft inredis_data, so the first deploy after #1638 to reach a host carrying that volume crash-loops redis, leavesappinCreatedand serves 404 while the migrations have already run — confirmed on production 2026-09-21 deploying 0.0.477 - #1831
mediumeffort:sThe compose healthchecks have nostart_period, so a container that crashed carries its staleunhealthyinto the nextupand fails a deploy that would otherwise pass — the message is identical to #1830's, so a fix that worked reads as one that did not; found redeploying after #1830 - #1832
highcieffort:mA Deploy run waiting at theproductionapproval gate holdsconcurrency: deploy-production, so every later run sitspendingwith no jobs and is cancelled by the next one — thirteen days of merges never reached the server and nothing said so. Neighbours #317 (runs nothing cancels) and #1545 (what the deploy pulls)
Documentation
- #29
mediumCorrect three documentation claims that describe behaviour that does not exist - #840
mediumvalidate_webhook_urlclaims DNS-rebinding protection its callers undo by re-resolving — same shape as #29 and #561; the claim is narrowed rather than delivered — PR #842- #860
highMCP OAuth discovery URLs are remote-chosen, and the validated address is not pinned (found reviewing PR #842 — #840's "an operator typed it" reasoning covers the connection URL and thecdp_url, but notmcp_oauth._send, whose every hop the remote server names; this is the delivery half #840 declined) — PR #875- #889
lowAn MCP discovery URL with a bad port answers 500 rather than the refusal —httpx.InvalidURLis not anhttpx.HTTPError, so the flow's three catches miss it and #872's fix cannot reach it (pre-existing, found mergingmaininto PR #875)
- #889
- #861
mediumA blocked MCP server URL answers a generic 500 instead of naming the refusal —SSRFBlockedErroris aValueError, which no handler maps (pre-existing, found reading the same path) — PR #872- #873
mediumImporting a spec YAML answers a generic 500 for every kind of mistake in it — a raw pydanticValidationErroris not aRequestValidationError, so no field error reaches the person who edited the file (found sweeping the same defect in PR #872) - #874
lowAn ingestion override with too large achunk_overlapanswers a 500 rather than the form its own docstring says it refuses to (same sweep) — PR #881- #882
lowA per-field refusal answers withdetails.errors, which the form cannot mark — the frontend readsdetails.fields, so all four call sites of that idiom show a sentence and highlight nothing (found fixing #874; #873 added the fourth) — PR #892- #891
lowThe same defect in a third shape: seventeen refusals name one field with a singulardetails.fieldand the envelope's message, which no form reads either (deliberately left out of #882 — converging one of eighteen would make it disagree with its siblings) — PR #900- #897
lowA connector's per-field refusal is flattened to a sentence byvalidate_config's(bool, str)protocol, so the sync-source wizard marks nothing — the one place #891 could not reach (found fixing #891) - #898
lowA refused model id is posted back indetails={"model": model}— the caller's own submission, serialized and logged — and still marks no input (found fixing #891)
- #897
- #891
- #882
- #873
- #860
- #122 Improve README.md
- #212
lowdocs/testing.md documents three fixtures and a layout the suite does not have - #664 Stale docs: governance.md claims deployment-wide rate limiting; SECURITY.md describes RoleChecker/UserRole — PR #665
- #783 README: badges, star tracker and product graphics, styled like pydantic-ai / FastAPI (follow-up to the empty-bodied, closed #122)
- #784 Docs: a readability and visual pass, modelled on pydantic-ai / FastAPI (presentation, not content-correctness like #29/#664)
- #1912
lowdocs/channels.mdsays Allowed origins; the console field is Allowed sites (found building the use-case library, #1909)
The roadmap
- #46 Add Guardrails
- #1900
highsecurityOutput guardrails redact the final answer after every streaming surface has sent the raw text — the harness guard sees only final output (found building the use-case library, follow-up to #1895) - #1901 PII redaction has no phone-number detector — the harness ships email, IBAN, card and SSN only (same source)
- #2000
securityOutput guardrails do not screen streamed tool arguments or a delegate's streamed answer — the paths left after #1900's stream screen (follow-up to #1900)
- #1900
- #47 Add Planning
- #48 Add Context
- #49 Add Context manager — PR #775, which also closes #771, #772, #773 and #774
- #50 Add Tool Search
- #51 Improve WebSearch and WebFetch capabilities — PR #839 adds the
web_fetchcapability (SSRF-guarded, ownweb:fetchscope); search-provider spend metering decided against and recorded on the issue, which found #840- #857 Native web search escapes the approval gate, the way native fetch did (found reviewing #839, which fixed the
web_fetchhalf)
- #857 Native web search escapes the approval gate, the way native fetch did (found reviewing #839, which fixed the
- #52 Agents evaluation & authoring assistant — plan first
- #1897 An internal LLM wiki agents maintain, web version only — design first; nearest existing mechanism is #1470's memory files
- #54 Add realtime models + transcription
- #55 Add media
- #56 Add Dynamic workflows
- n8n-parity review of the editor and the tables (2026-09-29), all in the Workflows + Virtual Tables milestone:
- Workflows
- #1932
highseparate Manual and API triggers, and run a manual workflow from the editor - #1933
highshow a run live on the canvas - each step's status, tries and output - #1934
higha step's input and output data in its settings (JSON, table and schema views) - #1935
hightest a single step with the data its upstream steps produced - #1936
midpin a step's output as test data - #1937
midmap fields by dragging values from the Input pane - #1938
midtemplate fields that mix text with values from earlier steps - #1939
midrename a step, add a note to it, and switch it off without deleting it - #1940
lowsticky notes on the canvas - #1941
midcanvas ergonomics - insert on a connection, tidy up, minimap and shortcuts - #1942
highsearch, sort and manage workflows from the list, and rename one in the editor - #1943
highrun history you can debug - filters, open a past run on the canvas, retry from the failed step - #1944
midworkflow settings - timezone, execution timeout, error workflow and what runs to keep - #1945
midan error workflow that runs when another workflow fails - #1946
midcall another workflow as a step - #1947
highSwitch, Wait, Filter and more Merge modes - #1948
middata transformation steps - Edit fields, Sort, Limit, Remove duplicates, Aggregate, Split out, Date & time - #1949
midwebhook test URL, listen for a test event, and respond to the caller - #1950
midcreate a credential from a step without leaving the editor - #1951
midHTTP request - import cURL, authentication from the vault, pagination - #1952
mida real code editor for the Python and JavaScript steps, with a test run - #1953
midimport and export a workflow, and a template gallery - #1954
lowcompare two versions of a workflow - #1955
midtest a chat-triggered workflow in a chat panel inside the editor - #1956
highactivate and pause a published workflow from the editor header - #1957
highstep settings that stay short - optional settings on demand and quieter validation
- #1932
- Virtual Tables
- #1958
highadd records from the console - #1959
highedit cells in place in the grid - #1960
highdelete records, one or many - #1961
highimport a CSV and export a table - #1962
midfilter and search records in the grid, saved with a view - #1963
midmanage columns from the grid header - #1964
lowlarge tables - virtualised scrolling and counts
- #1958
- #57 Add Overflowing tool output (harness module renamed to
tool_output_limits; reference refreshed)- #803 Prune
tool_output_limitsspills at run end on non-run-scoped workspaces (found reviewing #57)
- #803 Prune
- #787 Add System Reminders: re-inject steering guidance mid-run against instruction fade (harness
system_reminders) - #788 Add a Memory capability: persist and recall facts across runs — plan first
- #1470 Reshape it into two capabilities a builder picks (
memory_files,memory_mem0) and drop the operator console; the native fact store, theorigintrust tier and the Memory tab went with it. #1384, #1385 and #1386 were closed as superseded by the same reshape - #1077 A plan does not survive to the conversation's next turn, and the agent denies it exists (found adding the chat plan strip; the same question as #788 about state that outlives a run)
- #1902
memory_filesis refused in scheduled and triggered runs by design, and the docs do not say so — two tutorials hit it at run time (found building the use-case library) - #2027
securityLet a trigger run as its creator (opt-in), so a scheduled run can reach their memory, personal connections and conversation search - the product half #1902 left out of scope; also carries the Builder hint and the sandboxuser-scope inconsistency (found working #1902)
- #1470 Reshape it into two capabilities a builder picks (
- #789 Add a Conversations Search capability: search past transcripts mid-run — plan first (a tool, unlike #159's UI list search). Shipped on #788's branch (#1383) rather than its own: it needs the same run-level fact — who will hear this run — and a second derivation of that is the thing to avoid
- #58 Add Image Generation
- #59 Add Browseruse
- #62 Agents redesign
- #63 Admin redesign
- #64 MCP redesign
- #65 Knowledge Base redesign
- #66 Vault redesign
- #67 Chat redesign
- #68 Organizations redesign
- #69 Skills redesign
- #1911
mediumGallery skills cannot be loaded reliably - their title-case names are deferred-capability ids the model guesses as slugs, and a second wrong guess ends the turn (found building the use-case library, #1909)
- #1911
- #70 Artefakty — needs a definition before it can be scoped
- #71 Deep Research mode — blocked on #47, #51
- #72 Seed Agents
- #73 Seed Skills
- #150 A first-class public API: organization API keys, so everything the UI does is doable without it
- #1903
docs/api.mdsaysX-Organization-Idis required;get_active_organizationfalls back to the personal organization — docs fix or require it for API keys (found writing the agent-API tutorial) - #2121
bugA provider refusal onPOST /agents/{id}/runanswers500without the run id; mirrorresume'sRunExecutionError(found verifying #1796) - #2122
enhancementMulti-turn conversations for keys: no conversation to open, history never sent to the model, so the default sandbox scope refuses every key-made run (found verifying #1796)
- #1903
- #151 A global assistant in the UI, running the platform through its own API — blocked on #150
- #276 Render the delegation tree recursively on the agent map
Artifacts: from published pages to live pages (2026-09-30)
Origin #70. Gap analysis and Q&A 2026-09-30; W8 items need nothing unmerged, W10 items wait on #56.
- #1965
bugA staging run republishes the production page - environment in the identity - #1966 Restore a kept version as the current one
- #1967 Filter the list by the publishing agent
- #1968
bugA script-drawn page's thumbnail is empty - #1969
securityLinks inside a page open through the viewer after a confirmation - #1970 The agent reads its page back and edits part of it
- #1971
securityA pinned library set served to pages, and a bundled skill - #1972
securityPublic link settings: expiry, pinned version, password, view counts - #1973
securityEmbed a public artifact on allowlisted sites - #1974 Live data: bind a page to a saved view - blocked by #56, #1783
- #1975
securityLive data on a public link behind an organization switch - blocked by #1974 - #1976
securityActions through workflows - blocked by #56, #1792, #1974 - #1977 Follow a page and be notified of a new version - blocked by #56
Microsoft 365: Teams, Outlook and the Graph (2026-09-30)
Epic #1989. Builds on Entra sign-in (#1419) and the SharePoint/OneDrive sync (#985); copies the Google account and Gmail trigger (#1068).
- #1983
securityConnect a Microsoft account for delegated Graph access - blocks #1984, #1986, #1988 - #1984 Outlook mail trigger - blocked by #1983
- #1986 Outlook calendar trigger - blocked by #1983
- #1985
securityTeams channel bot, approvals as Adaptive Cards - #1987 Work IQ MCP servers in the catalog (needs a templated catalog URL)
- #1988
securityDeliver results to Teams and Outlook - blocked by #1983, #1985
Audit clean-up bags
- #545
lowBackend duplication & quality cleanup (audit 2026-08-10) - #557
mediumuseKBDetail holds server data in useState off React Query; two registered query keys are dead - #558
mediumAdmin query-key factories type params as unknown; admin.ratings is keyed three ways - #559
mediumThe ratings-by-day shape is declared four times under two confusable names - #560
mediumTwo upload routes serialize the same schema differently (response_model_exclude_none) #562mediumType the dict[str, Any] service contracts in sandbox and connectors - done, 0.0.214- #567
lowExtract the runner's duplicated prompt-flatten and terminal-state assembly - #568
lowUnify the two backend-schema form renderers (SchemaForm vs ConfigureStep)- #1093
lowConverge the backend connector config schema onto JSON Schema (dropConnectorConfigField) - the L, higher-risk half #568 deferred; #568 unified the renderer, this unifies the wire shape
- #1093
- #569
lowFrontend duplication & quality cleanup (audit 2026-08-10)
Bookkeeping
- #168 Issue map: how the open issues relate, and what blocks what
- #683 The issue map (#168) has an empty body, so the filing rule that depends on it cannot be followed
- #687 24 issues closed with no closing PR since Aug 5; at least two are still broken on main
The spine — what blocks what
Ordered by how much it unblocks. Everything not named here is independent.
1. #440 blocks the whole refusal cluster, and it was closed in error.
Reopened today after verifying on main: PiiRedactionFilter is attached to the root
logger at app/core/logging.py:73, where it never sees a record from a module
logger, and setup_logging has exactly one caller — app/main.py:217 — so the Prefect
worker never installs it at all. Every fix in that cluster works the same way: stop
putting the vendor's text in the response, keep it in the logger.exception beside the
raise. That remedy is only sound if the log is scrubbed, and it is not. #676, #681,
#686, #695, #699 and #659 all inherit the assumption; app/services/rag/failures.py:19
states the failure in the present tense and cites the number.
2. #311 is why the sweeps keep finding things. The automated reviewer has produced
nothing since 2026-08-05 while reporting success; eleven pull requests merged on a
sentence that read like a verdict. Until it is fixed the only review before a merge is
a human one. Not a formal blocker on anything — but it is the reason clusters like
"the frontend's own API surface" are found in audits rather than in review.
3. #564 is the structural fix for five symptoms. #13, #30, #546, #553 and #702 are
all the same ~40 hand-rolled backendFetch handlers under src/app/api/**: one
unencoded and unauthenticated (#13), eighteen unencoded (#30), the family swallowing
the backend's refusal reason (#546), omitting no-store (#553), and three echoing the
backend's content type (#702). Collapsing them into platformProxy removes the class.
Decide this before PR #668 merges — it already touches about forty of those files
for #546 alone.
4. #150 → #151 and #47 + #51 → #71, both stated in the blocked issue's own
title. #151 (a global assistant driving the platform through its own API) cannot start
before organization API keys exist; #71 (deep research) needs planning and the web
capabilities first.
5. #139 → #282 → #284. One table primitive, then the list-page shell built on it,
then the admin pages standardised onto both. Doing them in the other order means
writing the admin pages twice. Same shape in #136 → #138, #500: one file viewer
before the files page and the header field it needs.
6. #44 + #213 + #53 → #594. Three feature branches — PR #537 (triggers), PR #587
(dashboard layout), PR #624 (onboarding) — that each land alone and then have to agree
with each other on main. #594 is that reconciliation and cannot start until all three
merge.
7. #3, #7 and #12 are acceptance criteria of #39, and PR #634 says Closes #39.
#39's "Done when" list is four items: every surface records a run identically (#3),
EmbedSession takes a session factory rather than a session (#12), rate limits apply
to the public surfaces (#7), and docs/channels.md describes what exists. Three of
those are separate open issues. Either the footer should be Refs #39 with the
checkboxes ticked as they land, or #39 should be re-scoped to what #634 actually
finishes. Closes only when the change genuinely finishes it.
Pairs that want one pull request, not two: #7 + #18 (both are one
app.add_middleware line in create_app), #147 + #148 (adjacent lines of one
aggregation in repositories/rag_document.py:188-189), #548 → #566 (fix the
disagreement, then collapse the two helpers into one).
8. The connector chain, decided in #938. #984 (a web crawler) is first because it needs no credential and waits on nothing; #985 needs a new SecretKind for an Entra app that nothing else wants yet; #988 blocks Azure Blob and GCS and is the condition #938 attached to them - generalize S3Connector before writing either, not alongside. #990 came before all four and is done (0.0.216), which is what makes a change signal worth naming at all. #982 and #983 are not blockers but every connector on the chain inherits them, so they are worth having before the third one rather than after.
- #1544 (runtime frontend config) → #1545 (published images): no frontend image until the hostnames leave the build
The duplicate register — already adjudicated
Recorded so nobody re-litigates them, and so the next filer can see what "the same
bug" has looked like here.
| Filed more than once | Survivor | What happened |
|---|---|---|
| #636 · #638 · #642 | #638 | One defect at one line, channels/router.py:728, filed three times in eight days. #642 closed 2026-08-12, #636 closed 2026-08-13. |
| #554 · #611 | #554 | mcp-server-list.tsx:360 using window.confirm(), filed twice by the same author eleven days apart from two different sweeps. #611's three unique findings copied onto #554 before closing. |
| #437 → #659 · #676 | — | #437 closed COMPLETED with neither half fixed; both halves re-filed by people who could not find it. #659 is the socket half (PR #675), #676 the run-row half (PR #691). #437 now carries a comment naming them. |
| #422 → #707 | — | Closed for its first finding while a second, live one sat in a comment. #707 is that finding: rag-source-add writing an unvalidated, unowned collection name. |
| #452 → #451 | — | Superseded before it was closed; both now closed. |
| #617 | — | Withdrawn by its author into PR #587 rather than fixed separately. |
Pairs that look like duplicates and are not — checked, keep both:
- #13 / #30 — #30 is the sweep over eighteen unencoded segments; #13 is the one
instance that is also unauthenticated, which is why it isseverity:highwhere the
sweep ismedium. #13 must be in #30's fix, and #30 must not close without it. - #7 / #18 — two different middlewares, both written and never registered. One
call site, two fixes, two sets of acceptance criteria. - #147 / #148 — both make one stats row lie; the fixes are independent and each
body says so. #147 landed in #834 rather than alone, because #158 could not
measure its own before/after while the only stored chunk count was a constant 0. - #656 / #678 — two shapes the i18n guard misses (hyphen, acronym), two pull
requests (#677, #688). - #48 / #49 — context injection against context compaction. Different
capabilities, adjacent names.
What has no scope yet
- #70 Artefakty — says so in its own title. Needs a definition before it can be
estimated. - #122, #124, #127, #128 have empty bodies. All four sit on
W1 · Aug 3–7, a
milestone eight days past, and are unactionable as written: "Fix Agent Builder
frontend" names no defect and has no acceptance criterion. #168 was the fifth
empty body and is fixed by this rebuild; these four are not. Either write them or
close them — leaving them is what makes the open count untrustworthy. - #52 carries
plan firstin its title deliberately. - #1897 (LLM wiki) is filed to schedule a design: what "web only" covers, who may write and how it relates to context and memory files are all open.
Known-stale references
An issue body's cross-references were true when written. About 78 of the open bodies
cite at least one number that has since closed — mostly the roadmap family citing #16
(un-metered embeddings), which is done. The one that changes a decision is #39's
second checkbox, which describes #16 as live; it is not.
Do not chase the rest. Check a referenced number's state before acting on it:
gh issue view <n> --json state,stateReason,titleTriage state, 2026-08-13
Every open issue now has a type, a milestone, an effort:* label and a row on the
VstormOS board. Before today, 84 had no type and 26 — #456 and the whole
2026-08-10 audit batch, #545–#569 — were on no project at all, which made them
invisible to every view the board is read through.
Re-deriving this
gh issue list --state open --limit 300 --json number,title,body,labels,milestone
gh pr list --state open --limit 100 --json number,title,body # then grep the footersPass --limit. It defaults to 30 and caps at 100; under a hundred open issues it
silently drops the lowest numbers, which is how #2–#7 once read as closed and a blocker
chain read as already done.
Refs #683, #687.
Filed 2026-08-28, merging the W4 backlog
Thirty pull requests were merged and released as 0.0.316-0.0.343 in one pass. The
five issues above with 13xx numbers came out of that: four from reviewer findings
on branches that were merged anyway, and one flake. Each is in its cluster.
One pull request was not merged: #1128 (#1079, the knowledge retrieval
store crossing worker event loops). Its fix builds a store with its own pool,
which #948 and #12 removed from main, so a mechanical merge either re-adds the
second pool or stops fixing the bug. #1079 stays open with the new shape written
down on it.
Filed 2026-08-29, from the MCP redesign
Three came out of one branch (docs/site-improvements), all in the #64 MCP
redesign cluster and all in the same thread of work:
-
#1339
mediumA Mattermost conversation was one channel, not one thread — the agent read every thread in a channel as one conversation -
#1340
mediumStarting OAuth from the catalog answered 404 -
#1341
mediumThe Builder picker keyed its rows on the catalog entry, so an organization with several connections to one server could bind only one of them — one card per server with an account select, and per-binding personal substitution- #1342
featureA member holding two accounts on one service cannot say which an agent speaks as — #1341 declines to guess, and nothing records the choice - #1343
lowA resumed direct-message run stops speaking as the member who started it —agent_runsrecords the surface but not whether the conversation held one person
- #1342
-
#1391
featureAn MCP binding is either the organization's account or each person's own — a kind, not a flag. Supersedes #1341's per-binding substitution and #1343'sprivate_to_user; builds on #1342's nomination of a default account. Filed 2026-09-04 — PR #1392- #1442
mediumPublish and run time each decide MCP prefix collisions, and only publish says so - #1443
lowownAccountStatusre-implements the server's account rule on the client, and they disagree onunauthorized - #1444
lowThe personal-service briefing builds a frontend URL in the runner, which a locale-prefixed deployment breaks - #1445
lowAn API run authenticated with a user's own JWT is told nobody is signed in
All four found reviewing PR #1392 before merge; none blocks 0.0.356.
- #1442
Security programme (milestone W6 and W7 · Sep 7–18, planned 2026-09-05)
The theme for W6 and W7: a client's security review answered in writing, a mechanism and a test behind every row of a controls matrix (HIPAA §164.312, SOC 2 CC6–CC8), an issue behind every gap. #1424 is the epic and the four-area status; docs/security.md (#1412) is the deliverable the rest feeds.
- #1424
securitymetaSecurity programme - the epic - #1412
documentationsecuritydocs/security.md: threat model, data flows, what is encrypted where, the controls matrix - #1413
securityTraces sent to Logfire carry full prompts and outputs - a content mode onAgentSpec.observability(same card as #561) - #1414
lowsecurityfrontendCodeQL alert #20 inoauth-return.ts- validate or dismiss with a reason (#135 added the path) - #1415
cisecurityCodeQL on pull requests, a frontend dependency audit, an SBOM per release (parity via #143) - #1416
securityfrontendA real Content-Security-Policy; the widget and hosted page are the framing exception (#702 family) - #1417
cisecurityAsecuritypytest marker naming every refusal test, reported per release - #1418
securityEncrypted connections to Postgres and Redis, and a doctor line - #1419
securityGeneric OIDC sign-in beside Google; honours the sign-up policy (#914). SAML/SCIM and TOTP are in the roadmap note, unfiled - #1420
securityPer-organization data retention with an audit floor - #1421
securityErasure and export of one person's data - whatUserService.deleteleaves (#941 neighbour) - #1422
securityAudit trail export and a hash chain (#20, #983 neighbours) - #1423
securityS3-compatible file storage with server-side encryption beside the local disk - #1448
securityA HIPAA deployment profile and adoctor --profile hipaacheck that proves a running deployment matches it - the configuration half of #1412
Existing security issues scheduled under the same theme rather than moved here: #943 and #1044 (impersonation),
#913, #1047, #1066, #1245, #555, #1072 and #150. Bartek's 2026-09-05 sweep added #1427 (a deactivated member's
channel turn), #1437 (a WebSocket outliving its session), #1438 (identity binding while impersonating) and #1439
(a password change that revokes nothing) — the same theme, filed independently.
W6 and W7 are one milestone as of 2026-09-05, and everything schedulable was drained out of Later into it.
Seven issues stayed behind: #52 and #56 (themes planned in the roadmap note), #70 (unscoped), #71 and #151
(blocked), #54 (needs an architectural decision for the realtime half), #985 (needs the tenant-consent answer).
Filed 2026-10-12, from pydantic-ai-harness
Five capabilities adopted from pydantic-ai-harness (we lock 0.54.0), chosen by the maintainer after comparing the harness's capability list with what AgenticOS already ships. All five are in Later, unassigned:
- #2105
effort:sRepair malformed tool-call arguments before validation - fewer paid retries, mostly for open-weight and local models - #2106
effort:mA run reviewer: a second model that steers a run while it goes - complements #52 (evaluation after a run) and #2086 (the deterministic loop guard) - #2107
effort:lCode mode: call many tools from one sandboxed script - must keep the approval gate, budgets and permissions on calls made from code - #2108
effort:mBackground tools: keep working while a slow tool runs - needs answers for budget reservation, cancellation and durable resume - #2109
effort:sDetect prompt-cache busts per agent and model - feeds #2088 (metrics export)
#2086 (tool-call loops) was checked against the harness the same day: nothing upstream detects loops, so it stays, built on our SystemReminders port. Not adopted, with the reason: the MCP-backed integrations (covered by the MCP catalog), the developer tools (coder, localstack, macroscope, aws_lambda), capability_creation (an agent writing its own capabilities at run time contradicts "code defines, configuration composes"), advisor, prompt_injection_defender and dynamic_workflow.
Filed 2026-10-12, the Self improving milestone
#52 is now the parent of a milestone of its own, Self improving, with its design settled in a Q&A from the plan in #1111: evals first, the authoring assistant on top. #1801 was folded into #52 and closed. #2102 (structured outputs) was closed as covered by workflow model steps (#1925). Children, all for Bartosz Ochnik, in dependency order:
- #2110 Datasets → #2111 scoring → #2112 per-environment connections → #2113 eval runs (needs the three before it)
- #2114 generated cases (needs #2110) · #2115 suites and triggers (needs #2113) → #2116 promotion gate
- #2117 the authoring assistant from #1111, checked by evals (needs #2113)
- #2118 more proposal targets (context, model, capabilities...) and #2119 knowledge gaps (both after #2117)
#52's body is the single description of the whole milestone: the loop, the target matrix, principles and what is out of scope.
Related elsewhere: #2106 (run reviewer) shares the judge with #2111; #2086 (loop guard) and the workflow step evals of #1925 share the check vocabulary.
Filed 2026-10-12, from client feedback (Henning, Antoni)
Built in PR #2062 (milestone W11 · Oct 12–16):
- #2124 folders with access for Apps, Skills, Context and Knowledge bases - extends #2072's audiences to folders.
- #2125 any number of accounts of one MCP server on one agent - extends #2073.
- #2126 rename Agent files to Documents.
- Browser: #2127 one capability on browser-use (removes the step-by-step browser; unblocks #801) → #2128 ask the person / take over, #2129 a saved signed-in session per person, #2130 stealth browser in the sandbox plus proxy or external browser. #2128-#2130 build on #2127; #2129 also on #2128 (signing in happens in the takeover view). Related: #2094.
- #2131 discoverability of Availability, personal MCP accounts and Documents - related to #2063, #2075.
- Public API follow-ups from #1796: #2121 (done in #2062), #2122.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsBacklog
Activity
[-]Issue map: how the 110 open issues relate, and what blocks what[/-][+]Issue map: how the open issues relate, and what blocks what[/+]DEENUU1 commentedon Aug 5, 2026
Delegation (#40) has landed, so here is its cluster in one place.
Closed by the work: #40 itself, and #166 (a delegate's own collections never reached the
running delegate, so knowledge search always came back empty — fixed on the branch, the
assertion lives at the deps a delegation actually runs with).
Found while building it, all pre-existing, none caused by the branch:
agent_session.pycarries the whole chat wire format and is in neither thecoverage nor the
tygate. 31% covered,process_messageentirely uncovered. Same class asweb_search and create_chart render as raw JSON: the frontend matches tool names the backend stopped emitting #144.
AsyncSession.pydantic-ai runs tool calls from one response concurrently; the approval row write is a
flushon the shared session. Nothing to do with delegation, which merely made it obvious.spend_by_provider,spend_by_keyand the organization usage report never gotthe
parent_run_id IS NULLfiltersum_cost_sinceis careful about, so all threedouble-count a delegated run.
agent_runner._runrecords a cancelled run asFAILEDand never commits;agent_chatgets both right.bootstrapis idempotent by adopting any existing model profile rather thanensuring the one it names, so four E2E specs fail on a used database, and two of them leak a
profile that poisons the next run.
include_general_purposecannot produce a usable delegate at all. Removed fromthis deployment's configuration surface on the branch; the upstream defect is open, since the
library still defaults it on for every other consumer.
resumemarks a runRUNNINGbefore building its spec, so any spec that stopsbuilding leaves a parked run unfinishable. Retitled: it was filed against
max_depth, whichis one route in rather than the problem.
Caused by the work, narrowed rather than hidden: #175 — a specialist kept by
create_agentdoes not survive a second approval park, because the library's registry belongsto the built agent rather than the run.
Follow-up: #177 — promote a specialist to a draft agent. It is what makes "a dynamic
specialist is never persisted" a design rather than an obstacle; without it the workaround is a
person copying instructions out of a chat log.
Blocked chain worth noting: #71 (Deep Research mode) named #40 as one of its blockers. That
half is now unblocked.
docs: require a new issue to say where it sits, via the map in #168
DEENUU1 commentedon Aug 5, 2026
#186 filed - the residual of #179 (
skill_idswas the one spec reference publish never validated). #179 closes the publish gate; #186 is about the versions frozen before it existed, which a run resolves from the frozen spec and does not re-check.Edges for the map:
DEENUU1 commentedon Aug 5, 2026
#189 filed -
tests/integration'senginefixture drops and recreates every table per test against a fixed database name, so two worktrees running the suite at once break each other. Cluster: Tests, CI, dependencies, beside #154 and #143/#165 - the same family of "the suite's answer is not about your change", one layer down (two local runs sharing one database rather than a CI gate). Found running the suite for #179; not caused by it.DEENUU1 commentedon Aug 5, 2026
Two filed while implementing #182 (PR #193), both in Agents, spec, capabilities:
option answer_subagent is offered to every delegating agent and can never be used #182 named and fix(capabilities): stop offering a delegation tool nothing can reach #193 declined; it is a feature rather than a repair, and it does
not on its own make
answer_subagentreachable (a sync question is answered by aperson through
ask_user, never through that tool). Sits with Add subagents-pydantic-ai #40, A specialist create_agent kept does not survive the approval park that created it #175 and include_general_purpose=True cannot produce a usable delegate #174 — thelast because opening it for a pinned delegate needs the same upstream change include_general_purpose=True cannot produce a usable delegate #174 does.
mode="sync"whose delegates override nothing. Generalises answer_subagent is offered to every delegating agent and can never be used #182's fix under a condition that has to be
computed per run.
Edges to add:
#182 ──▶ #184(#184 is what removes #182's filter) and#182 ──▶ #185(same defect class, wider scope). Neither is on the spine — both are parallelisable, and
both are behind #40 in the delegation chain.
DEENUU1 commentedon Aug 5, 2026
Three issues filed out of #181 (run history could not tell a delegated run from
one somebody started). Adding them here so they are not unlinked, per this
issue's own rule.
All three are pre-existing and were found reading around the change, not caused
by it.
Cluster 3 — the shared table primitive (#139)
{entry.run_count} runsin Activity's two spend breakdowns isEnglish-only pluralisation, which
.claude/rules/frontend.mdrefuses. The moreuseful half:
scripts/check_i18n.pypasses it, so the guard whose job thisis has a blind spot for
{expr} wordin a JSX text node. Both lists eventuallymove into One table primitive, with sortable headers and filters, everywhere #139's primitive, so a fix here should not be a rewrite.
A new pair, both about the run-history read path — nearest existing issue is #170
GET /runsandGET /runs/{id}callagent_run_repodirectly fromthe route, which the layering rule forbids outright. Every other handler in the
same file goes through a service. Run history cannot tell a delegated run from one somebody started: the columns exist and nothing reads them #181 had to thread two more parameters through
the violation.
counts the calendar month, so the two invite a comparison that is wrong by
however old the deployment is. A windowed count belongs with the aggregates in
Three spend aggregates double-count a delegated run: by_provider, by_key and the org usage report #170. Run history cannot tell a delegated run from one somebody started: the columns exist and nothing reads them #181 fixed the other half of the same card: it counted delegated rows the
money excluded, and rendered
runs.lengthof a page of fifty rather thantotal.Not a new cluster — #170, #197 and #198 are all "the numbers Activity prints and
where they come from", and #181 is the surface half of the same thing. Worth
folding into the spine as one chain if anybody redraws it, with #197 first: a
windowed count wants a service to live in.
DEENUU1 commentedon Aug 5, 2026
Four issues filed out of #181 (run history could not tell a delegated run from
one somebody started). Adding them here so they are not unlinked, per this
issue's own rule.
All four are pre-existing and were found reading around the change, not caused
by it.
Cluster 3 — the shared table primitive (#139)
{entry.run_count} runsin Activity's two spend breakdowns isEnglish-only pluralisation, which
.claude/rules/frontend.mdrefuses. The moreuseful half:
scripts/check_i18n.pypasses it, so the guard whose job thisis has a blind spot for
{expr} wordin a JSX text node. Both lists eventuallymove into One table primitive, with sortable headers and filters, everywhere #139's primitive, so a fix here should not be a rewrite.
A new pair, both about the run-history read path — nearest existing issue is #170
GET /runsandGET /runs/{id}callagent_run_repodirectly fromthe route, which the layering rule forbids outright. Every other handler in the
same file goes through a service. Run history cannot tell a delegated run from one somebody started: the columns exist and nothing reads them #181 had to thread two more parameters through
the violation.
counts the calendar month, so the two invite a comparison that is wrong by
however old the deployment is. A windowed count belongs with the aggregates in
Three spend aggregates double-count a delegated run: by_provider, by_key and the org usage report #170. Run history cannot tell a delegated run from one somebody started: the columns exist and nothing reads them #181 fixed the other half of the same card: it counted delegated rows the
money excluded, and rendered
runs.lengthof a page of fifty rather thantotal.Not a new cluster — #170, #197 and #198 are all "the numbers Activity prints and
where they come from", and #181 is the surface half of the same thing. Worth
folding into the spine as one chain if anybody redraws it, with #197 first: a
windowed count wants a service to live in.
With #154, the e2e flakes
seed.setup.ts › a provider key is storedflakes, and because it isin the
[seed]project it takes every journey behind it down: the job reports"1 failed, 7 passed" and no product spec ran at all. That is worse than e2e: sharing and skills specs fail when a mutation's refetch lands stale #154,
which fails one spec. It may be the same root cause as e2e: sharing and skills specs fail when a mutation's refetch lands stale #154 (a mutation's
invalidation refetch landing stale) — e2e: the seed step storing a provider key flakes, and hides every journey behind it #201 says which log line would decide it
on the next occurrence, and the two should merge if so.
Anyone reading a red
e2eshould check for this one before believing their diffcaused it. The evidence in #201 is three runs on one branch where the only
failure landed on a commit that reordered a paragraph of Markdown.
test(chat): put the chat wire format behind the gate at 100% (#196)
docs(review): write down the CodeQL half, and adjudicate its blind sp…
121 remaining items
DEENUU1 commentedon Sep 8, 2026
pet.mp4
docs: put Amigo on the README, and say the desktop app is an add-on
DEENUU1 commentedon Sep 8, 2026
Desktop shell (#1531): #1532 is the OAuth handoff the shell needs (system browser + one-time exchange code); it sits with #1419 and #1414 on the sign-in chain.
DEENUU1 commentedon Sep 12, 2026
Docs cluster, from #1599 (multilingual documentation):
code-review.mdopen on an issue number at column zero and Python-Markdown renders them as<h1>. Pre-existing; found while Translate and maintain AgenticOS documentation in Polish, German and Spanish #1599's translation guard had to reproduce the anchor rule a build uses. Independent of Translate and maintain AgenticOS documentation in Polish, German and Spanish #1599 and safe to fix alone.#1599 itself belongs with the documentation cluster rather than the tender chain: it adds
scripts/check_docs_i18n.pytomake lint, so every future docs change owes three translations. Nothing blocks it and it blocks nothing.Lock the tool-contract cache build and stop caching a transient failu…
DEENUU1 commentedon Sep 15, 2026
Docs cluster update: #1599 is closed - the site publishes English, Polish, German and Spanish, and
scripts/check_docs_i18n.pyruns inmake lint, so every docs change from here on owes three translations. #1605 is closed too.What the cluster still carries is the part #1599 explicitly excluded: SD-002's client-specific administrator manual, where backup/recovery and troubleshooting are each one section today. Not yet filed.
DEENUU1 commentedon Oct 1, 2026
demo-chat-sfx.mp4
DEENUU1 commentedon Oct 1, 2026
Updated README demo: removed 00:30–00:39 from the original recording. The video now runs for 37.5 seconds with sound.
Watch the shortened MP4
The silent GIF is a 2× preview; the linked MP4 plays at normal speed. Both assets are hosted in the repository. README updates: #1999.
DEENUU1 commentedon Oct 1, 2026
demo-chat-short.mp4
DEENUU1 commentedon Oct 5, 2026
agenticos-intro-16x9-4k.mp4
DEENUU1 commentedon Oct 10, 2026
New issues, 2026-10-10:
#2098-#2101 are being done in #2062.