Compiled entirely from public activity on meta.discourse.org, X, and GitHub.
💬 meta.discourse.org
This week Sam was focused on small but user-visible fixes and follow-ups on Meta. He shipped an update addressing the request to display all users who liked or reacted to a post, and he responded to a survey-editing bug report by routing it to the appropriate maintainer for investigation.
🐦 On social
On social, the week centered on hands-on AI tooling: term-llm widgets, Jarvis building prototypes, gpt-realtime-2 access, and interest in testing cyber models against real codebases like Discourse. There were also sharp takes on phishing detection, open-source AI coding harnesses, and model preferences, with replies often functioning as live debugging notes or lightweight commentary from active experimentation.
- 12 posts and 12 replies captured in the last 7 days
- Top by engagement: It is shameful that @gmail is not automatically flaggi…, https:// aider.chat was really first here in exploring…, gpt 5.5 cyber
Most engaged tweets:
- post — It is shameful that @gmail is not automatically flagging this kind of phishing as spam. We can boil entire oceans with our datacenters but can not figure out a phishing 101 email?
0 likes · 0 reposts · 0 replies - post — https:// aider.chat was really first here in exploring the limits of ai coding, gets very little credit … unfairly
0 likes · 0 reposts · 0 replies - reply to @reach_vb — gpt 5.5 cyber
0 likes · 0 reposts · 0 replies - reply to @gdb — would love access so I can run it on the code running the OpenAI community , filled in the persona last week
0 likes · 0 reposts · 0 replies - post — Crazy, Jarvis coded a full working prototype of gpt realtime 2 as a Jarvis supervisor, I then mounted the widget and got it to close a pr, all on my mobile phone
0 likes · 0 reposts · 0 replies
🛠️ GitHub — Sam’s Commits
samsaffron/term-llm
Over the last 7 days, Sam focused on making term-llm’s serve and web UI experience faster, more reliable, and smoother: paginated session history, cached model/asset metadata, gzip/ETag improvements, and fixes for stale stream updates, drafts, tool rendering, and WebRTC gating. He also pushed deeper agent/LLM capabilities, including provider-neutral tool schemas, developer subagent delegation, agent-specific skills directories, parallel tool limits, and in-progress model swapping. Overall, the work looks aimed at scaling interactive agent sessions while reducing UI friction and backend latency.
Key commits:
8007cfb— perf(serve): paginate session history and cache model listsc0bffbb— fix(serveui): cache rendered assets and preserve tool args6eac108— perf: lazily load skills metadataca7d656— fix(serveui): improve text direction detection44d86f8— fix(serve): gzip JSON responses over http
discourse/discourse
Sam focused heavily on security and privacy hardening across Discourse, closing multiple information-leak and authorization gaps around hidden tags, private posts/bookmarks, topic metadata, username renames, publish timers, and Data Explorer results. He also advanced Discourse AI capabilities, adding safe document-to-text extraction for uploaded files so LLM prompts can work with DOCX/RTF/XLS/XLSX-style content, plus a smaller fix for AI bot streaming behavior. On the product side, he improved authoring workflows with inline policy editing in the rich editor, making policy creation and editing more integrated and user-friendly.
Key commits:
a20a6a4— FEATURE: Inline policy editing in rich editor (#39820)e8e3f01— FIX: Unescaped username regex lets self-service rename rewrite other users’ mentions (#39821)e3f7118— FIX: Data Explorer post relations expose private post excerpts to group report users (#39819)14a1fb7— FIX: topic_map exposes hidden-post URLs and titles through public topic details (#39815)1fd56c7— FIX: Tag settings can reassign hidden synonym tags by ID (#39778)
discourse/dv
Sam focused on making dv more flexible for real-world Discourse development workflows: adding support for private Discourse forks, custom HTTPS hostnames in the local proxy, and targeted updates of a single agent inside a container. He also refreshed the Charm TUI dependency stack and adjusted related configuration/agent UI code, suggesting maintenance work to keep the developer experience current while expanding deployment and local-dev capabilities.
Key commits:
b3f6457— FEATURE: support private discourse forks4b43bd5— feat(local-proxy): support custom HTTPS hostnames59c77d2— chore(deps): upgrade charm TUI stackc6ff2f0— FEATURE: allow just updating a single agent in the container
discourse/discourse_docker
Sam made a small but purposeful update to the Discourse Docker base image, adding catdoc and antiword so containers can better support legacy Word document extraction. The work appears focused on improving document-processing capabilities while avoiding a more complex sandboxing addition (bubblewrap) that proved impractical inside the container environment.
Key commits:
1a13a7b— FEATURE: add antiword and catdoc (#1051)
🤖 Jarvis — Public Repo Work
Agent-authored public commits, typically guided by Sam during implementation work.
SamSaffron/term-llm
Over the last 7 days, Sam-directed Jarvis work in SamSaffron/term-llm focused heavily on performance and responsiveness, especially streaming, sidebar rendering, startup waterfalls, SSE handling, session/message caching, and reducing unnecessary DOM, filesystem, git, SQLite, and provider/model work. A second theme was agent/product capability expansion, notably adding proxied widgets and improving tool/client behavior, while also tightening reliability around jobs, memory search, file reads, Gemini streaming tools, image uploads, MCP shutdown, and clearer timeout errors. In total, there were 52 Sam-directed Jarvis-authored commits, mostly touching internal/, cmd/, and docs-site/.
Key commits:
5b554da— feat: allow responses clients to append tools (#610)1564cb8— perf: incremental sidebar render — reuse DOM nodes, skip no-op renders (#549)3678b27— perf: avoid full-tree glob scans (#604)35b367c— fix: Template context always spawns two git subprocesses even when prompts do not use git variables (#602)d8e10e0— fix: Skills setup does a full multi-path skill discovery and metadata parse on every startup (#600)
sam-saffron-jarvis/jarvis-browser-proxy
In the last 7 days, Sam-directed Jarvis work focused on making jarvis-browser-proxy recover more reliably from browser lifecycle failures. The main change hardened Chrome/DevTools startup and shutdown handling: browser processes now run in their own process group, stale or unrelated PIDs are detected more carefully, failed startups surface recent browser logs, and stuck launches are killed cleanly. Tests were expanded around these lifecycle paths, suggesting the intent was operational robustness rather than new user-facing features.
Key commits:
3492a2c— Fix browser lifecycle recovery
⤴️ GitHub — Pull Requests
53 PRs this week:
- ✅ SamSaffron/term-llm#554 (diff) — perf: skip redundant turn action panel sync on streaming chunks after first plac closed
Skip
syncTurnActionPanelForAssistanton every streaming chunk after the turn action panel has been placed once. ```js // Before — called on every SSE chunk (potentially 50+/sec) syncTurnActionPanelForAssistant(message.id); // After — called only un… - ✅ SamSaffron/term-llm#563 (diff) — perf: cache RenderManifest and RenderServiceWorker with sync.Once closed
Cache the output of
RenderManifest()andRenderServiceWorker()inserveuiusingsync.Once, following the same pattern as the existingassetVersionOncecache forAssetVersion(). Both functions are called on every request for `manifest.webm… - ✅ SamSaffron/term-llm#576 (diff) — perf: replace O(n²) JSON.parse guard in tool-arg delta handler with argumentsFin closed
In
response.function_call_arguments.delta, the handler previously calledJSON.parse(entry.arguments)on every delta to detect whether the arguments string had already been finalized (a guard for stream replay scenarios). This is O(n) per delta, m… - ✅ SamSaffron/term-llm#582 (diff) — perf: skip buildArgsNode for done tools with existing args in updateToolGroupNod closed
In
updateToolGroupNode, skip callingbuildArgsNodefor tool entries that are alreadydoneand already have an args node in the DOM. ```js // before: always rebuilds the args DOM node const existingArgs = entry.querySelector(’.tool-entry-args’);… - ✅ SamSaffron/term-llm#589 (diff) — perf: hoist early-return guard in scheduleAssistantStreamRender before closure a closed
Hoist the “already scheduled” guard to the top of
scheduleAssistantStreamRender, before the work that the old code did unconditionally. ```js // before const scheduleAssistantStreamRender = (streamState) => { if (!streamState) return; const ren… - ✅ SamSaffron/term-llm#594 (diff) — perf: write SSE event data bytes directly, reduce fmt.Fprintf calls closed
Collapse
writeStoredResponseEventfrom threefmt.Fprintfcalls into onefmt.Fprintffor the structured prefix, a directw.Write(ev.Data)for the JSON payload, and anio.WriteStringfor the trailing"\n\n".writeStoredResponseEventis ca… - ✅ SamSaffron/term-llm#605 (diff) — fix: Switching to a lazy-loaded session fetches the same message history twice closed
- track when
switchToSession()has already successfully preloaded messages for a lazy-loaded (_serverOnly) session - passskipMessagesFetchintosyncActiveSessionFromServer()only when that preload succeeded, so the session switch path avoids…
- track when
- ✅ SamSaffron/term-llm#606 (diff) — fix: /v1/models has no cache and can block initial /chat startup on upstream pro closed
- make
/v1/modelsprefer already-available local model lists (providers.*.models, configured default model, curated built-in lists) before attempting upstreamListModels- add a small in-memory cache for upstreamListModelsresponses when `/v…
- make
- ✅ SamSaffron/term-llm#607 (diff) — fix: Session history loads the entire transcript, inlines image blobs, and retur closed
- paginate
/v1/sessions/{id}/messageswith a bounded page size andhas_more/next_offsetmetadata instead of returning one unbounded response - materialize stored inline image blobs into served/images/files so session history JSON no longe…
- paginate
- ✅ SamSaffron/term-llm#608 (diff) — test: avoid zombie waits in handover cancellation test closed
Make the handover cancellation test’s process-exit wait zombie-aware on Linux.
TestRunHandoverScript_CancelKillsProcessGroupwaits for a background child process to disappear after canceling the handover script. On Linux, a killed child can remain … - ✅ SamSaffron/term-llm#609 (diff) — perf: amortize response run replay compaction closed
Amortize response run replay-window compaction by tracking a logical
eventStartoffset and reclaiming the dropped prefix in batches instead of copying the entire retained replay window on every streamed event after the replay limit. This keeps reco… - ✅ SamSaffron/term-llm#557 (diff) — perf: add preload hints for large first-party scripts closed
Add
<link rel="preload" as="script">hints in<head>for the four largest first-party JS files: | File | Size (uncompressed) | |——|——————-| |app-stream.js| 119 KB | |app-render.js| 57 KB | |app-core.js| 47 KB | | `app-… - ✅ SamSaffron/term-llm#579 (diff) — perf: run session state sync in parallel with messages fetch during startup hydr closed
hydrateActiveSessionAfterStartupruns two network requests sequentially: 1.loadServerSessionMessages— fetches the session’s message history 2.syncActiveSessionFromServer— fetches/v1/sessions/{id}/stateto determine if a response is activ… - ✅ SamSaffron/term-llm#545 (diff) — perf: cache plain text stream checks closed
- Adds an incremental plain-text eligibility check for assistant stream tails. - Reuses the previous plain-text scan result while streamed content grows by ordinary prose characters. - Falls back to the full markdown/math scanner when punctuation or …
- ✅ SamSaffron/term-llm#558 (diff) — perf: cache message node in streamState to skip DOM lookups per stream chunk closed
In
enqueueAssistantStreamUpdate, add a fast path that skips two DOM lookups whenstreamStatealready exists for the message. Before: every SSE streaming chunk called: 1.findMessageElement(message.id)— `querySelector(’[data-message-id="…… - ✅ SamSaffron/term-llm#553 (diff) — perf: replace O(n²) session.find loops with Map/Set lookups in status poll closed
Replace two O(n²)
Array.findloops in the sidebar status poll hot path with O(n)Map/Setlookups.app-render.js—updateSidebarStatus: ```js // Before — O(n) find per entry × m entries = O(n·m) per poll tick const local = state.sessions… - ✅ SamSaffron/term-llm#564 (diff) — perf: incremental renderMessages — skip full DOM rebuild on same-session message closed
renderMessagespreviously didelements.messages.innerHTML = ''followed by a fullcreateMessageNodeloop on every call — even when the active session hadn’t changed and only new messages were appended. This PR adds an incremental fast path: whe… - ✅ SamSaffron/term-llm#566 (diff) — perf: fast path for response.output_text.delta SSE events closed
Two Go-side optimizations on the SSE streaming hot path, targeting the
response.output_text.deltaevent that fires ~100x/sec during token streaming. Previously, every text delta token required: - Allocating `map[string]any{“output_index”: …, “del… - ✅ SamSaffron/term-llm#599 (diff) — fix: Skills initialization does a full multi-path skill catalog scan before ever closed
- make
internal/skills.NewSetupstop callingregistry.List()eagerly during setup - add a fastRegistry.HasAnySkill()probe so startup only confirms that skills exist before enabling the system - lazily generate<available_skills>metadata vi…
- make
- ✅ SamSaffron/term-llm#583 (diff) — perf: eliminate String coercion and trim in isSessionVisible hot path closed
isSessionVisibleis called once per streaming token (~100×/sec) to guard DOM updates to the currently visible session. The previous implementation allocated a trimmed string on every call: ```js // before const isSessionVisible = (session) => { c… - ✅ SamSaffron/term-llm#603 (diff) — perf: cache tool registry specs closed
Cache
ToolRegistry.AllSpecs()results in deterministic name order and invalidate the cache when tools are registered or unregistered. This keeps the returned slice/top-levelToolSpecvalues independent while documenting the existing immutability … - ✅ SamSaffron/term-llm#593 (diff) — perf: replace O(n) regex match in directionForText with early-exit charCodeAt sc closed
Replace the O(n)
text.match(/.../g)scan indirectionForTextwith an early-exitcharCodeAtloop.directionForTextis called on every RAF frame during streaming viaperformAssistantStreamRender, and also when rendering static messages. The o… - 🟢 discourse/discourse#39842 (diff) — FIX: Wiki edits can silence the original author through AI spam scans opened
under rare conditions spam scanning can be mis-attributed and apply to author when an editor edited it.
- ✅ SamSaffron/term-llm#550 (diff) — perf: gzip-compress JSON responses for startup-path API endpoints closed
Add
writeJSONGzip, a helper that transparently gzip-compresses JSON API responses when the client sendsAccept-Encoding: gzipand the payload exceeds 512 bytes. Apply it to the three endpoints the web UI calls on every page load: | Endpoint | Typ… - 🟢 discourse/discourse#39840 (diff) — DEV: rename staff_logins report to admin_logins opened
The report was already titled “Admin Logins” and only displayed admin login data, but was named
staff_loginsand accessible to all staff. Rename it to match its actual contents and restrict access to admins only by adding it toADMIN_ONLY_REPORTS… - 🟢 discourse/discourse#39839 (diff) — FIX: Persona-level
allowed_group_idsis not enforced when executing modes openedsome security hardening, ensure server side is aligned with behavior of client.
- 🟢 discourse/discourse#39838 (diff) — FIX: Full names are exposed when name display is disabled opened
Hide full names when site disables names
- 🟢 discourse/discourse#39837 (diff) — UX: Auto-resize the AI bot docked composer with content opened
Adds an
@autoResizemode to the sharedDockedComposerso the input grows with its content up to a viewport-bounded max height instead of requiring a manual resize handle. The textarea path uses CSSfield-sizing: content(with a JS fallback for … - ✅ SamSaffron/term-llm#552 (diff) — perf: omit app-webrtc.js from page load when WebRTC is disabled closed
Omit
app-webrtc.jsfrom the page and service worker when WebRTC is not enabled. - Strip the<script src="app-webrtc.js?v=...">tag from the renderedindex.html- Remove'./app-webrtc.js?v=...'from the service worker’sSHELL_ASSETSlist Web… - ✅ SamSaffron/term-llm#581 (diff) — perf: scope refreshRelativeTimes to messages container instead of full document closed
refreshRelativeTimesruns every 60 seconds and on everyrenderMessagescall. It usesdocument.querySelectorAll('[data-created]')which traverses the entire document DOM tree each time. The[data-created]attribute is only set on<span>node… - ✅ SamSaffron/term-llm#562 (diff) — perf: cache gzip-compressed static assets to avoid re-compression closed
Add
uiCachedGzip: compress an embedded static asset once, store the result in a package-levelsync.Map(keyed by SHA-256 of the raw bytes), and return the cached slice on all subsequent calls. Replace the inlinegzip.NewWriterblock in `serveEm… - ✅ SamSaffron/term-llm#560 (diff) — perf: cache rendered index HTML with sync.Once closed
Wrap
renderIndexHTML()insync.Onceso the rendered HTML is computed once and reused for every subsequent request.renderIndexHTML()rebuilds the same ~19 KB byte slice on every page navigation: - MarshalsbasePath, asset version, sidebar con… - ✅ SamSaffron/term-llm#546 (diff) — perf: cache gzipped UI assets closed
- Caches gzip-compressed embedded UI asset bodies by the uncompressed body ETag. - Reuses cached compressed bytes for repeated
Accept-Encoding: gziprequests. - Keeps existing cache-control, ETag, conditional request, and HEAD behavior unchanged. T…
- Caches gzip-compressed embedded UI asset bodies by the uncompressed body ETag. - Reuses cached compressed bytes for repeated
- ✅ SamSaffron/term-llm#573 (diff) — fix: Status-line token estimation rescans the whole conversation on the render h closed
Cache the streaming status-line context-token estimate in the chat model instead of recomputing it from the full conversation on every render. - store the latest streaming context estimate alongside the in-progress streaming snapshot - refresh that c…
- ✅ SamSaffron/term-llm#574 (diff) — fix: Chat smooth-buffer streaming still processes one Bubble Tea cycle per incom closed
- defer the next chat stream read when a text event has already scheduled a smooth render tick - let
ui.SmoothTickMsgresume the blocked stream read after the frame, matching the existing ask-mode behavior - update the chat regression test to cover…
- defer the next chat stream read when a text event has already scheduled a smooth render tick - let
- ✅ SamSaffron/term-llm#569 (diff) — fix: Smooth-buffered streaming still triggers one full Bubble Tea cycle per prov closed
- defer the next blocking stream read when a text delta has already scheduled a smooth rendering tick - let
ui.SmoothTickMsgresume provider ingestion after releasing buffered words - update the chat perf test to cover the deferred-read behavior Th…
- defer the next blocking stream read when a text delta has already scheduled a smooth rendering tick - let
- ✅ discourse/discourse#39820 (diff) — FEATURE: Inline policy editing in rich editor merged
Policy nodes in the rich editor now display a summary of their attributes (groups, version, renew, accept, etc.) and expose an edit button that opens the policy builder modal pre-populated with the current values. Changes are applied directly to t…
- ✅ discourse/discourse#39821 (diff) — FIX: Unescaped username regex lets self-service rename rewrite other users’ ment merged
Mention update should regex escape username cause username can have . in it which needs escaping.
- ✅ discourse/discourse#39819 (diff) — FIX: Data Explorer post relations expose private post excerpts to group report u merged
A non obvious issue in data explorer is that it can return sideloaded data (topic/user/post) ensure side loaded data runs through security rules for account viewing it. Can easily be bypassed by amending the query so it will have minimal impact.
- ✅ SamSaffron/term-llm#532 (diff) — fix: tool persistence callbacks run synchronously on the tool-dispatch hot path closed
- move the blocking session-persistence work in
ask,serve_runtime, andspawn_runneroff the engine callback hot path by enqueueing callback work onto a per-run async queue - refresh callback contexts when queued work actually runs so persisten…
- move the blocking session-persistence work in
- ✅ SamSaffron/term-llm#528 (diff) — fix: read_file keeps scanning to EOF after hitting output limits closed
- stop
read_fileas soon asstreamLineNumberedRangehitsMaxLinesorMaxBytes- only include an exact total-line count in the truncation footer when EOF was actually reached - add coverage that verifies truncation no longer consumes the entir…
- stop
- ✅ SamSaffron/term-llm#529 (diff) — fix: parallel tool execution launches an unbounded goroutine per tool call closed
Bound parallel tool execution in
Engine.executeToolCallswith a small worker pool instead of launching one goroutine per tool call. Also adds a regression test that verifies parallel tool execution stays concurrent while respecting the configured w… - ✅ discourse/discourse#39815 (diff) — FIX: topic_map exposes hidden-post URLs and titles through public topic details merged
If topic map links to a hidden / whisper post it shows it in the list of links which can be confusing to end users anyway.
- ✅ SamSaffron/term-llm#527 (diff) — feat: add codegen benchmark harness closed
Adds a repo-local execution-based code generation benchmark under
benchmarks/codegen. The benchmark: - runs against any term-llm provider via-provider provider[:model]- defaults toclaude-bin- supports-concurrency 2and-budget 4hout o… - ✅ discourse/discourse#39778 (diff) — FIX: Tag settings can reassign hidden synonym tags by ID merged
Hidden tags (via groups) are pretty rare, hidden tag synonyms are even more rare. The seals a small edge case where users who were not allowed access to a synonym got access.
- ✅ discourse/discourse#39817 (diff) — FIX: tags_descriptions exposes PM tag metadata when PM tags are hidden merged
Defense in depth, in rare cases where serializer is called with superfluous data ensure it is not exposed.
- ✅ SamSaffron/term-llm#531 (diff) — fix: parallel tool execution has no global concurrency limit closed
Cap parallel tool execution in
Engine.executeToolCallswith a small worker pool instead of launching one goroutine per tool call. Also add a regression test that proves a response with more tool calls than the limit does not start more than the con… - ✅ SamSaffron/term-llm#539 (diff) — fix: Memory mining reloads the full fragment corpus for the same agent on every closed
Cache the per-agent memory fragment taxonomy during a mining run instead of reloading the full fragment corpus for every candidate session. - Switch the mining loop to load fragment paths once per agent via
ListFragmentPaths- Reuse a cached taxono… - ✅ SamSaffron/term-llm#540 (diff) — fix: Memory vector search does a full embedding-table scan, JSON decode, and ful closed
- add a memory_embeddings index on
(provider, model, dimensions, fragment_id)so vector lookups stop scanning the whole embeddings table before scoring - changeStore.VectorSearchto stream matching embeddings, keep only the current top-k hits in…
- add a memory_embeddings index on
- ✅ discourse/discourse#39816 (diff) — FIX: Duration-based publish timers bypass destination category authorization merged
Small moderator edge case, was allowed publishing in rare cases to categories it could not access.
- ✅ discourse/discourse#39777 (diff) — FIX: Moderators can receive another user’s private bookmark content merged
Security hardening, disallow mods from seeing bookmarks on random users
- ✅ discourse/discourse#39779 (diff) — FIX: Tag info leaks hidden synonym tag names and descriptions merged
Similar to https://github.com/discourse/discourse/pull/39778 protect hidden tag synonyms
- ✅ discourse/discourse#39776 (diff) — FIX: security hardening form
codes_to_imgmergedOut of the box only admins can create categories, the emoji field there is not XSS protected. This introduces defense in depth for this field.
🐛 GitHub — Issues
No issue activity this week.
👀 GitHub — Reviews
1 reviews this week:
- discourse/discourse#39823 — FIX: Chat channel creation skips category posting permission check for mods approved