Compiled entirely from public activity on meta.discourse.org, X, and GitHub.
💬 meta.discourse.org
This week Sam was focused on Discourse AI chat improvements, including shipping starred AI conversations so common chats can be pinned to the top of the list. He also triaged chat UX regressions around the floating chat back button and clarified reproduction scope. On the bug-fix side, he acknowledged a TypeError in custom-content flag submissions and invited a PR while the team investigates.
🐦 On social
No X activity captured this week.
🛠️ GitHub — Sam’s Commits
discourse/discourse
Sam focused heavily on tightening privacy and permission boundaries across Discourse, especially around IP visibility, hidden post excerpts, AI bot conversations, artifact sharing, and admin/reporting surfaces. He also improved suspension handling for anonymous shadow sessions so they can outlive the master account’s suspension, suggesting work on edge-case account/session behavior. Overall, the week’s work was security- and access-control oriented, with substantial accompanying test coverage to lock down regressions.
Key commits:
d0db90e— FIX: Suspicious login IPs bypass the moderator IP-visibility setting (#40154)87ead9f— FIX: Hidden post excerpts can be returned by group activity serializers (#40217)cf59f5e— FEATURE: Anonymous shadow sessions can outlive suspension of the master account (#40156)49af022— FIX: Tighten security controls for artifact sharing (#40153)458dcfd— DEV: add learn more url to ai star feature (#40151)
SamSaffron/dotfiles
Sam Saffron focused on desktop environment maintenance in his dotfiles over the last 7 days, especially around Hyprland configuration and supporting workflow scripts. The work looks like a small post-upgrade cleanup: adjusting Hyprland settings, adding a workspace-naming helper, refreshing Neovim plugin locks, and making a minor Waybar style tweak.
Key commits:
🤖 Jarvis — Public Repo Work
No public Jarvis commits this week.
⤴️ GitHub — Pull Requests
40 PRs this week:
- ✅ SamSaffron/term-llm#715 (diff) — fix: Interrupted Telegram replies are shown to the user but not durably persiste closed
- Persist a best-effort assistant snapshot in the Telegram interrupt path when partial text was shown but no assistant message was captured by the normal callbacks yet. - Use a short detached store context (
context.WithoutCancel+ timeout) for that…
- Persist a best-effort assistant snapshot in the Telegram interrupt path when partial text was shown but no assistant message was captured by the normal callbacks yet. - Use a short detached store context (
- ✅ SamSaffron/term-llm#714 (diff) — fix: Response-run replay disables compaction forever after approvals/interjectio closed
- Kept response-run event compaction enabled even after
response.ask_user.prompt,response.approval.prompt, andresponse.interjectionso the raw replay log still respectsmaxRetainedEvents. - Preserved interactive recovery state separately fr…
- Kept response-run event compaction enabled even after
- ✅ SamSaffron/term-llm#713 (diff) — fix: Interrupted Telegram replies are only kept in RAM and are dropped from pers closed
- Persist the partial assistant reply in the Telegram interrupt path when streaming was canceled before any assistant message had been durably written. - Use a short timeout with
context.WithoutCancel(...)for that best-effort write so the interrup…
- Persist the partial assistant reply in the Telegram interrupt path when streaming was canceled before any assistant message had been durably written. - Use a short timeout with
- ✅ SamSaffron/term-llm#712 (diff) — fix: MCP server startup can hang indefinitely and leak stuck subprocesses becaus closed
- Added a manager-owned startup timeout for MCP servers so
Enableno longer depends on the caller passing a cancelable context. - Stored per-server startup cancel functions inManagerand invoked them fromDisable/StopAllso an in-flight star…
- Added a manager-owned startup timeout for MCP servers so
- ✅ SamSaffron/term-llm#710 (diff) — fix: Durable response ID lookups load and deserialize entire session histories o closed
- Added
GetLatestVisibleMessageIDto the session store interface. - Implemented it ininternal/session/sqlite.goas a targeted single-row query over themessagestable: - filters to visible continuation roles (user,assistant) - orders …
- Added
- ✅ SamSaffron/term-llm#711 (diff) — fix: Durable response-id lookups load and JSON-decode the entire session transcr closed
- Added a targeted SQLite lookup for the latest visible persisted message in a session:
GetLatestVisibleMessageID, which reads a singleuser/assistantrow ordered bysequence DESC LIMIT 1. - Updated durable response-id resolution to use that …
- Added a targeted SQLite lookup for the latest visible persisted message in a session:
- ✅ SamSaffron/term-llm#709 (diff) — fix:
recent.mdmaintenance does unlocked read-modify-write overwrites, so over closed- Added a shared
recent.mdupdate helper that acquires a per-file advisory lock before reloadingrecent.md, holds it across the LLM-based read/modify/write flow, and releases it after the write and related metadata updates complete. - Switched bo…
- Added a shared
- ✅ SamSaffron/term-llm#708 (diff) — fix: TUI chat streams ignore the model’s root cancellation context, so quit/sign closed
- Changed TUI chat streaming to derive its cancellable run context from
m.rootContext()instead ofcontext.Background(). - Applied the same root-context derivation to/compactand LLM-backed/handoverhelper operations. - Added targeted tests…
- Changed TUI chat streaming to derive its cancellable run context from
- ✅ discourse/discourse#40154 (diff) — FIX: Suspicious login IPs bypass the moderator IP-visibility setting merged
Harden implementation of suspicious login report Co-authored-by: discourse-patch-triage <272280883+discourse-patch-triage[bot]@users.noreply.github.com>
- ✅ SamSaffron/term-llm#706 (diff) — perf: cache tool schema JSON for adapters closed
Cache JSON-encoded immutable
ToolSpec.Schemamaps by schema identity and reuse the cachedjson.RawMessagewhen building tool definitions for OpenAI-compatible chat-completions adapters and Ollama. This avoids re-marshalling every tool schema on e… - ✅ SamSaffron/term-llm#705 (diff) — optimize session snapshot replacement closed
Optimize
SQLiteStore.ReplaceMessagesso full-session snapshot persistence keeps an unchanged message prefix and only deletes/reinserts the changed suffix. The fallback path still performs a full rewrite if legacy/corrupt rows have duplicate or nega… - ✅ SamSaffron/term-llm#704 (diff) — fix: The UI only dequeues one stream event per frame, creating avoidable backlog closed
- keep scheduling the next chat stream read immediately after each non-terminal stream event, even while smooth text rendering is already frame-paced - remove the now-unused deferred stream-read path from the chat TUI - update the chat perf test to a…
- ✅ SamSaffron/term-llm#703 (diff) — fix: Streaming partial markdown reparses and re-renders the entire in-progress s closed
- avoid re-rendering the full committed markdown snapshot on every flowing partial-preview tick - reuse the already-rendered committed prefix after the first partial preview for a block, and only re-render the current partial block on subsequent upda…
- ✅ SamSaffron/term-llm#702 (diff) — fix: Streaming partial markdown reparses and re-renders the entire in-progress s closed
- stop full-document markdown re-renders on every flowing partial update once a block preview is established - cache the stable rendered prefix before the active partial block and reuse it for later token updates in the same block - add a regression …
- ✅ SamSaffron/term-llm#701 (diff) — fix: Stream consumption is intentionally stalled to one event per smooth-tick, c closed
Stop deferring the next chat stream read behind a pending smooth tick. The chat TUI now keeps listening for the next provider event immediately after handling any non-terminal stream event, while still using the smooth buffer/tick path to coalesce vi…
- ✅ discourse/discourse#40217 (diff) — FIX: Hidden post excerpts can be returned by group activity serializers merged
Some spam posts that are hidden may be exposes in group listings Co-authored-by: discourse-patch-triage <272280883+discourse-patch-triage[bot]@users.noreply.github.com>
- ✅ SamSaffron/term-llm#697 (diff) — fix: unblock provider stream close during SSE reads closed
- Add a cancellable stream close hook to
newEventStreamso providers can unblock resources that were opened before the stream goroutine starts. - Use that hook to close HTTP response bodies for OpenAI-compatible, Responses API HTTP, Venice, xAI, an…
- Add a cancellable stream close hook to
- ✅ SamSaffron/term-llm#696 (diff) — perf: avoid ANSI strip allocations in markdown render closed
- Replaced hot-path
strings.TrimSpace(stripANSI(...))checks in the terminal markdown renderer with SGR-aware scanners that test visible content without materializing an ANSI-stripped copy. - KeptstripANSIfor the hard-wrap fallback that still n…
- Replaced hot-path
- ✅ SamSaffron/term-llm#694 (diff) — fix: Memory mining paginates session messages with OFFSET, causing reads to degr closed
- switch memory mining from OFFSET-based pagination to sequence-based reads via
GetMessagesFrom(..., fromSeq, limit)- teach the SQLite session store to apply an optionalLIMITwhen seeking from a sequence cursor - updatememory freshento reus…
- switch memory mining from OFFSET-based pagination to sequence-based reads via
- ✅ SamSaffron/term-llm#693 (diff) — fix: Vector memory search linearly scans and scores every embedding blob on ever closed
- add lightweight vector-search metadata columns for embeddings (prefix dimensions plus tail/full norms) and populate them on upsert - lazily backfill that metadata for older/directly-inserted rows before search - change
VectorSearchto rank candid…
- add lightweight vector-search metadata columns for embeddings (prefix dimensions plus tail/full norms) and populate them on upsert - lazily backfill that metadata for older/directly-inserted rows before search - change
- ✅ SamSaffron/term-llm#692 (diff) — fix: Vector memory search scores every stored embedding blob on every query closed
- bound
VectorSearchto a generous recent embedding window instead of rescoring every embedding blob for the provider/model on every query - order that window byembedded_at DESCand add a matching composite index so SQLite can satisfy the prefil…
- bound
- ✅ SamSaffron/term-llm#691 (diff) — fix: Memory mining paginates long sessions with OFFSET, making reads degrade tow closed
Change memory mining to load session messages from the last mined sequence with
GetMessagesFrominstead of repeatedly callingGetMessages(..., OFFSET ...)as the offset grows. Also add a regression test that verifies mining uses sequence-based re… - 🟢 discourse/discourse#40189 (diff) — FEATURE: User API key device authorization flow opened
Adds an OAuth-style device authorization flow for user API keys so applications that can’t open a browser (CLIs, headless tools, IoT clients) can request a key by displaying a short user-facing code. The client POSTs to
/user-api-key/deviceto obta… - ✅ discourse/discourse#40156 (diff) — FEATURE: Anonymous shadow sessions can outlive suspension of the master account merged
When suspending a main account also suspend anonymous shadow account. This avoids double work for moderators. Co-authored-by: discourse-patch-triage <272280883+discourse-patch-triage[bot]@users.noreply.github.com>
- ✅ SamSaffron/term-llm#683 (diff) — fix: Every shell/custom tool completion does a full /proc descendant sweep closed
- add a lightweight inherited-fd leak probe to
prepareToolCommand- only run the expensive nonce-based/procdescendant sweep when that probe shows a child survived the process-group kill - keep the existing/procfallback for detached descenda…
- add a lightweight inherited-fd leak probe to
- ✅ SamSaffron/term-llm#684 (diff) — fix: Tool dispatch waits for persistence callbacks on the hot path closed
- move runLoop assistant snapshot, response-completed, and turn-completed callbacks onto an ordered background queue - preserve callback ordering while letting tool execution start without waiting for persistence work to finish - wait for queued book…
- ✅ SamSaffron/term-llm#685 (diff) — fix: Tool execution is blocked on synchronous callback I/O before dispatch conti closed
- move agent-loop assistant snapshot, response-completed, and turn-completed callbacks onto an asynchronous ordered callback queue instead of running them inline on the hot path - keep callback ordering stable and drain the queue before the stream fu…
- ✅ SamSaffron/term-llm#686 (diff) — fix: spawn_agent timeout does not include time spent waiting for a parallelism s closed
- start the spawn_agent timeout before waiting on the MaxParallel semaphore - use the child timeout context while queued for a slot, so waiting time counts against the tool timeout - include queued time in reported duration/error results - add regres…
- ✅ discourse/discourse#40153 (diff) — FIX: Tighten security controls for artifact sharing merged
Tighted security controls around artifact sharing so they are not shared as side effects Co-authored-by: discourse-patch-triage <272280883+discourse-patch-triage[bot]@users.noreply.github.com>
- ✅ discourse/discourse#40151 (diff) — DEV: add learn more url to ai star feature merged
- ✅ discourse/discourse#40019 (diff) — FIX: Enforce can_see_ip checks across admin IP features merged
Same-IP user lookups now identify the target by user_id and ip_type rather than accepting a raw IP in params, so the IP is resolved server-side and never round-trips through clients that lack permission to see it. Additionally: - Hide the `suspicious…
- ✅ discourse/discourse#40146 (diff) — FIX: Hidden post excerpts can appear in public BestPosts rewinds merged
Exclude hidden posts from rewind Co-authored-by: discourse-patch-triage <272280883+discourse-patch-triage[bot]@users.noreply.github.com>
- ✅ SamSaffron/term-llm#682 (diff) — perf: defer skill metadata catalog loading closed
Defer the expensive skills catalog scan during
skills.NewSetup.NewSetupnow usesRegistry.HasAnySkill()as a cheap availability probe and leaves the fullRegistry.List()catalog load/parsing untilEnsurePromptMetadata()is actually called.… - ✅ SamSaffron/term-llm#681 (diff) — perf: reuse OpenAI SSE event buffers closed
Reuse an owned SSE event data buffer in the OpenAI-compatible streaming parser instead of allocating a fresh
[]bytefor everydata:event. The streaming hot path now constructs onesseEventReaderper HTTP response and reuses its data buffer for… - ✅ SamSaffron/term-llm#680 (diff) — fix: Uploaded images are fully decoded, saved, optionally resized, re-encoded, a closed
- stream base64 uploads directly to the uploads directory instead of decoding the whole image into an intermediate raw buffer first - only decode/resize large inline images after the original upload has been saved, using the saved file as the resize …
- ✅ SamSaffron/term-llm#679 (diff) — fix: Session storage writes full base64 image blobs into every message row closed
- stop session persistence from storing redundant base64 image blobs when the same image is already recoverable from a saved file path - strip persisted base64 for user image parts with
ImagePathand for tool-result image content parts with `ImageP…
- stop session persistence from storing redundant base64 image blobs when the same image is already recoverable from a saved file path - strip persisted base64 for user image parts with
- ✅ SamSaffron/term-llm#678 (diff) — fix: Web image uploads are decoded, rewritten, resized, re-encoded, and kept inl closed
Change web image upload parsing to stop retaining inline base64 payloads in memory after request parsing. Uploaded images are still saved to disk, but the model-facing bytes are now staged via
InlineImagePathand encoded lazily when a provider actu… - ✅ SamSaffron/term-llm#677 (diff) — fix: Uploaded images are decoded, saved, optionally resized, re-encoded, and ret closed
- stream base64 image uploads straight to the uploads directory instead of decoding the whole image into an intermediate raw buffer first - reuse the saved original file for the rare >1 MB resize path, so small images avoid the extra decode/write hot…
- ✅ SamSaffron/term-llm#676 (diff) — feat: require configured output tools closed
Adds an explicit required-output contract for agents that use
output_tool. Today,output_toolregisters a finishing tool and captures its value if the model calls it. But an agent can still naturally complete without calling that tool, causing `t… - ✅ discourse/discourse#40105 (diff) — DEV: make tests more robust opened
- start sequence of custom flag ids at 1000 - previously this was not reliable This reserves a proper sequence and always sets it on create. 2. fix db structure create on systems that have a “discourse” user running Previously this would explode t…
🐛 GitHub — Issues
No issue activity this week.
👀 GitHub — Reviews
7 reviews this week:
- discourse/discourse#40237 — Corrected release notes
new_version_mailerlink format in English locale approved - discourse/discourse#40189 — FEATURE: User API key device authorization flow commented
- discourse/discourse#40189 — FEATURE: User API key device authorization flow commented
- tmm1/rbtrace#108 — Fix
--interactiveirb mode not printing eval results commented - discourse/discourse#40155 — FIX: Emoji deny list with regex metacharacters crashes cooking approved
- discourse/discourse#40152 — FIX: Data explorer agent reliability for schema and plurality approved
- discourse/discourse#39891 — FEATURE: Bot only PMs filter approved