Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🤖 OS review · request changes · confidence 2/5Safe once the two P1 issues below are fixed. The MCP is appropriately constrained to pinned-site GET requests, but it is unavailable in the default compiled installation and can report incorrect breakdown comparisons when a prior row falls outside the requested top-N.
🔁 Not merge-ready and no live session owns this branch — add the |
| "args": [ | ||
| "run", | ||
| "/home/ubuntu/projects/opensession/scripts/mcp-fathom.ts" | ||
| ], |
There was a problem hiding this comment.
🔴 P1 — Ship an executable MCP path for compiled installations
This path only exists in a source checkout, while the default installation is the compiled release. scripts/build-compile.ts documents that the release archive contains the executable, native/worker sidecars, service files, deploy files, and release.json, and install.sh explicitly detects compiled releases by their lack of a scripts/ directory and does not install Bun. Consequently, a default-install user following this configuration has neither this TypeScript file nor necessarily a bun command, so MCP startup fails with ENOENT. Expose the server through a compiled-binary subcommand such as opensession fathom-mcp, or package a standalone executable sidecar and configure its installed path; keep the TypeScript invocation only as the source-install alternative.
There was a problem hiding this comment.
Fixed in de0fb3e: added an opensession fathom-mcp CLI entrypoint that is bundled into compiled releases, and changed the example and setup docs to use that stable installed command.
| this.getSite(), this.aggregation(range, fields), prior ? this.aggregation(prior, fields) : Promise.resolve(null), | ||
| ]); | ||
| const current = normalizeRanking(currentRaw, field, metric, limit); | ||
| const previous = priorRaw ? normalizeRanking(priorRaw, field, metric, limit) : []; |
There was a problem hiding this comment.
🔴 P1 — Do not treat absence from the prior top-N as zero traffic
Both aggregation requests are capped to limit, but a current row missing from the prior response is assigned prior_value: 0 and passed to delta, which labels it new. For example, with limit: 10, a page that moves from rank 11 with 90 visits to rank 10 with 100 visits is absent from the prior top ten, so this returns prior_value: 0, absolute: 100, and status: "new" instead of acknowledging that the prior value is unknown. This makes the comparison materially false. Represent an unmatched prior row with prior_value: null and pass null to delta so it becomes unavailable, or fetch enough prior data to establish the actual value and rank.
There was a problem hiding this comment.
Fixed in de0fb3e: unmatched prior top-N rows now return null prior values and unavailable deltas instead of claiming a zero baseline or new traffic. The focused comparison test covers this case.
A mention only clears when you open the exact session it was recorded on, but the workspace row's badge can sit on a row whose click opens a different sibling — so the badge could never be cleared from where it appears. Carry the mentioned member's id on the row and make the badge a click target that opens that session (clearing the mention on open).
…e006 Commit 1b4e006 swept in the Sidebar.tsx side of another session's subagent-grouping refactor (activeSubagentsForWorkspace -> activeSubagentsByWorkspace) while the new export stayed uncommitted in the shared checkout, leaving main unbuildable. This lands the matching lib half and its tests, both authored by that session, to restore a buildable main.
Vendor and enable the anti-slop Oxlint rules, resolve existing frontend findings, and expose the shared Electron bridge contract to all frontend builds.
…ends The WebSocket command outbox kept every pending command and tombstone forever. Once an Electron profile had collected enough of them, put() returned false and every mutation, including Create, failed with a generic message and no way to recover after the Reliability tab went. - tryPut() reports unavailable, full, or blocked; the composer and the reconnect toast say which and where to fix it. - Pending commands expire after 7 days; tombstones after 7 days, with shipped untimestamped ones stamped on first sight. - Preferences shows a Pending sends card with Retry, Forget and Forget all.
A long paste collapses into a "Pasted text" chip, but on send the block
was placed ahead of the typed message, so the instruction ended up
buried under the material it was about. The message now leads and each
pasted block follows it as
---
Pasted text:
<block>
so the bubble shows a visible split and the model sees where the
instruction stops. A paste sent on its own still goes out bare.
Live SDK conversations report each pi step from the usage on that step's own assistant message and stream events, keyed by Anthropic message id so the SDK's per-content-block repeats count once and an internal ToolSearch round trip is summed. The previous cumulative diff assumed the SDK result usage was a running total across tool steps. It is not: its input and cache fields describe the last request while output spans the whole turn, and the synthetic boundary result carries no usage at all. That wiped the baseline at every tool boundary, so the final step of a multi-step turn re-billed the earlier steps' output and boundary audit rows logged zero tokens. Started by Jaap Frolich in this OS session: https://os.tella.dev/session/os-01a05ed5-6c40-704a-81e6-69e597c66e12
The Socket Mode client was deleted in 966357f but the setup UI kept offering it as the default. SlackAgent only registers the HTTP routes, never reads SLACK_APP_TOKEN, and verifySlackSignature fails closed on an empty secret, so a Socket Mode save without a signing secret produced an app whose every POST got a 401. Setup now only describes what the server does: the transport toggle and xapp field are gone, the manifest always carries both request URLs with socket_mode_enabled false, SLACK_SIGNING_SECRET is unconditionally required, and a loopback webhook base shows a warning pointing at Domains and ingress instead of steering people to a client that is not there. The requiredWhen hook only existed for this case, so it and envRequired go too. A leftover SLACK_APP_TOKEN in the env file is left alone and ignored. Fixes #283 Co-authored-by: Michiel Westerbeek <happylinks@gmail.com>
A compiled `opensession server` runs opensession.ts, which binds 127.0.0.1:PORT through Bun.serve and never reads LISTEN_FDS; no ingress process ships in the release either. Rendering Requires=opensession.socket for it failed on the missing template in 0.4.52 to 0.4.55, and a socket copied in by hand took the port so the server crash-looped on EADDRINUSE. Compiled installs now render a socket-free unit that binds directly, the installer removes a stale socket unit from earlier releases or the manual workaround, start/stop/uninstall only touch the socket when its file exists, and the socket template leaves the release artefact. Closes #297. Co-authored-by: Michiel Westerbeek <happylinks@gmail.com>
A large paste used to be concatenated into the message string. It now travels as `pastedTexts` beside the prompt on every send path (REST prompt and create, the prompt, interrupt_prompt and create_session frames). The server folds each block into the model-visible prompt after the message inside a <pasted-text> fence at intake, so the queue, the steer channel, persistence and search keep carrying one string, and classifyEntry lifts the blocks back onto the entry as `pastedTexts` on the way to every client. The queue projection and the take-back path lift the same way, so a queued message shows its text and an edit restores the chips. The web bubble renders a card per paste that opens in place, with the clamped tail fetched from the full-entry endpoint; the New session palette gains the same chip as a session composer; a note folds the paste behind a divider since it has no attachment slot. The native app renders the cards and the Chrome side panel names them.
A message waiting in the queue, or held while a workspace sets up, showed only its typed text, so a paste sent beside it looked lost until the turn started. The queued row now ends with "· Pasted text +60 lines".
Settings → Providers can add a SuperGrok / X Premium account by device code, as a third pool beside Claude and ChatGPT with the same capabilities: ownership, pins, sideline-on-quota, designated list (bridge.xaiAccounts), rotation-proof sandbox copies (Docker read-only mount, scoped remote upload with refresh refusal and a host upkeep tick), usage meters, and the native app's third pool. Requests route through cli-chat-proxy.grok.com so they draw on the subscription's quota; the API-key xai provider is untouched and the runner loads no Pi extensions. Closes #276. Started by Michiel Westerbeek in this OS session: https://os.tella.dev/session/os-01a062ed-eae1-7e93-9587-090f02c052e1
Settings writes the env file through a .bak-<n> copy and an atomic .tmp rename, both created beside it, so the gateway needs write access to the directory, not just the file. A system-scope install that points OPENSESSION_ENV_FILE into /etc/opensession passes installation and then 500s on every integration save with a raw EACCES, because three root-run installers reset that directory to root:root 0700 on purpose: it holds the executor and session-kernel credentials. Catch the problem where it is cheapest: `service install --system` and deploy/deploy.sh now refuse an env file whose directory the service user cannot write, with the fix in the message. The server wraps a permission failure in EnvFileWriteError so the integrations route returns the same guidance instead of Bun's default error page, and the docs say where the file may live. Fixes #282
⌘⇧C already copies the Open Session link to what is open (session, workspace, or review). ⌘⇧G is its GitHub counterpart: the same target ⌘G opens, copied instead. The PR chip's context menu shows both chords, and the command palette gains a matching "Copy pull request link" action.
A message with more than six images failed inside delivery with a plain Error, which the prompt route turned into a 500. The browser outbox reads 5xx as transient, so the message retried every 30 seconds with no Retry, Edit or Discard control, never reached the agent, and could not be removed from the queue view. Later messages still drained around it. Share the cap through the protocol package. The route now answers 400 before delivery for a list over the cap, staging errors carry their status, and a non-retryable kernel replay of a recorded failure answers 409, so the outbox parks the message as failed with Edit and Discard. The composer stops at the cap while attaching and names what it left out, and a message brought back for editing with more is refused at send with a toast. Co-authored-by: Grant Shaddick <grant@tella.com>
The Claude Agent SDK sends the whole custom system prompt as one prompt-cache block, so any session-specific byte in it costs every new session a full cache write of the ~25k-token system+tools prefix instead of a read. Three things varied per session: the session link, requester and GitHub login in the PR attribution section, pi's trailing "Current working directory" line, and the absolute worktree paths pi stamps into project_instructions and skill locations (223 of the last 247 pi sessions ran in their own worktree). buildRunInstructions now emits only per-repo text and points at "the session context" for attribution. buildSessionContext carries the link, working directory, PR footer and assignee rule, fenced as a new "session" context source ahead of every prompt so it survives compaction and resume misses. assembleRunSystemPrompt strips pi's cwd line and makes the structural paths cwd-relative, which a new prompt section explains.
The tellahq installation hit its hourly GraphQL limit about once a day. Nearly all of the spend was pr-info's `gh pr view <branch>`: gh resolves a branch by wrapping the whole field set in `pullRequests(headRefName:, first: 30)`, and with `commits` (100 x 100 authors) GitHub prices that at 32 points. The same fields by number cost 1. CI webhook bursts made it worse: every check_run, status and workflow_run delivery dropped the detail cache and broadcast pr_updated, so open tabs re-read the PR once per delivery for as long as a pipeline ran. - pr-info: resolve the branch to a number first (bulk cache, then a memo seeded from the durable snapshot, then a one-point lookup) and view by number. A memoized number is verified against headRefName once. - pr-webhook: fold CI deliveries per branch into one refresh per 30s window, invalidating at broadcast time. PR, review, comment and push deliveries still refresh promptly. - github-budget: report the bucket as consumers' own GraphQL responses see it (rateLimit is free to request), next to a probe that resolves its token through the same service credential path. The old probe logged used=0 through every exhaustion.
A chip's text is folded into the prompt verbatim, so pasting a few megabytes put the whole block in context and the turn failed before the model saw a word of it: "Prompt is too long" on a single exchange, which compaction cannot shorten. Past 200k characters (about 50k tokens) the web composer now stages the paste as pasted-text.txt through the same upload path a dropped file takes. The agent gets the usual attached-file note and reads it with its tools; the transcript shows the file chip and a download. Below the line a paste still collapses into a chip, and a team note keeps the chip at any size because it has no file channel. Started by Michiel Westerbeek in this OS session: https://os.tella.dev/session/os-01a0671c-d75e-79c1-bd39-3f19f3713358
A distill timer used to wait in-handler on a process-wide serial queue, holding one of the shared kernel timer slots for the whole wait plus the model call. Many sessions going idle together could occupy every slot and delay scheduled prompts, agent waits, and ask escalations. The handler now tries to take the single distill slot; when it is taken it replaces its own timer 15-30s out and returns immediately.
Local main fell 20 commits behind origin/main because git pull --ff-only refuses the shared checkout as soon as one dirty file overlaps an upstream commit, and nobody may discard another session's edit. Sessions then rebased only their own commit or committed from a throwaway worktree, and the shared branch drifted for everyone; 44 of the 61 blocking files were byte-identical to origin/main, residue of edits that had already landed. scripts/shared-checkout-sync.ts fast-forwards main in place: clean paths follow upstream, edits that already landed become clean, genuine edits are three-way merged onto the new base (index and worktree separately, with a pre-merge copy under .git/shared-checkout-sync/), conflicts are left untouched and listed, and the ref moves last by compare-and-swap. AGENTS.md now makes it the only sanctioned way to move main, requires it at task start and after every push, and forbids the worktree and rebase-only workarounds.
The skill is now written against the pinned effect@4.0.0-rc.112 rather than the early v4 beta the upstream (joelhooks/effectts-skills, MIT) targeted, and it carries an Open Session-specific reference for the frontend lifecycle runtimes. Allowlist it next to the other tracked skills and ignore .agent-sources/, the source mirror it asks agents to clone for API lookups.
Add the hosted Braintrust MCP (https://api.braintrust.dev/mcp, bearer API key header) to mcp-config.example.json and the MCP-only integrations section of the setup docs. Started by Michiel Westerbeek in this OS session: https://os.tella.dev/session/os-01a06762-a6ea-70a4-a59c-c70fc533c2b1
Summary
Security
FATHOM_SITE_IDis pinned; schemas and fixed endpoint enums reject arbitrary API accessTests
bun test ./scripts/mcp-fathom.test.tsStarted by Grant Shaddick in this OS session
Created by this OS session