Conversation
Add optional `environmentId` field to the Environment config interface. Update `validateCredentials` to call `/whoami` instead of `assets.list`, which both validates credentials and retrieves the Mux environment ID in a single request. The ID is persisted to the config on login. Existing configs without `environmentId` remain valid (field is optional). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewrite the webhook events store to use bun:sqlite instead of a JSON file. Key changes: - Schema: events(id PK, type, timestamp, environment_id, payload) - Indexes on timestamp and type for efficient queries - WAL mode for safe concurrent access from multiple CLI sessions - INSERT OR IGNORE for deduplication (replaces manual array check) - No event cap (previously limited to 100) - Operations are now synchronous (bun:sqlite is sync) Database stored at ~/.local/share/mux/events.db (XDG data dir). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use environmentId from config when storing events, falling back to the environment name for backwards compatibility with pre-migration configs. Remove unnecessary await since SQLite operations are synchronous. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Make environmentId a required parameter on listEvents, getAllEvents, and getEventById — the CLI always has an environment context. The events list and replay commands resolve the current environment and pass its ID to scope all queries. Falls back to environment name for configs predating the environmentId field. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add `mux webhooks events browse` command with an interactive terminal UI for exploring stored webhook events. Features: - Browse events with keyboard navigation - Filter events by type (f to filter, c to clear) - View full event payload - Copy payload or event ID to clipboard - Forward/replay events to a local URL (--forward-to) Uses the same TUI components (SelectList, ActionMenu) as assets manage. Adds getEventTypes and listEventsByType queries to the events store. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Store the last-used --forward-to URL in the environment config so it doesn't need to be re-entered on every invocation. Auto-recall applies to browse and replay commands. Listen always requires --forward-to explicitly but saves it for the other commands to use. Add updateEnvironment helper for partial config updates and forwardUrl field to the Environment interface. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Primary key missing environment_id breaks environment scoping
- Updated the events schema to use a composite primary key of (id, environment_id), allowing identical event IDs across environments while preserving per-environment deduplication.
Or push these changes by commenting:
@cursor push 2ce65a3978
Preview (2ce65a3978)
diff --git a/src/lib/events-store.test.ts b/src/lib/events-store.test.ts
--- a/src/lib/events-store.test.ts
+++ b/src/lib/events-store.test.ts
@@ -74,6 +74,16 @@
expect(events).toHaveLength(1);
});
+ test('appendEvent allows same event ID in different environments', () => {
+ appendEvent(makeEvent('evt_shared', 'video.asset.ready', 'env-aaa'));
+ appendEvent(makeEvent('evt_shared', 'video.asset.ready', 'env-bbb'));
+
+ expect(getEventById('evt_shared', 'env-aaa')).toBeDefined();
+ expect(getEventById('evt_shared', 'env-bbb')).toBeDefined();
+ expect(listEvents('env-aaa')).toHaveLength(1);
+ expect(listEvents('env-bbb')).toHaveLength(1);
+ });
+
test('appendEvent does not cap at 100 events', () => {
for (let i = 0; i < 150; i++) {
appendEvent(makeEvent(`evt_${i}`));
diff --git a/src/lib/events-store.ts b/src/lib/events-store.ts
--- a/src/lib/events-store.ts
+++ b/src/lib/events-store.ts
@@ -23,11 +23,12 @@
db.run('PRAGMA journal_mode = WAL');
db.run(`
CREATE TABLE IF NOT EXISTS events (
- id TEXT PRIMARY KEY,
+ id TEXT NOT NULL,
type TEXT NOT NULL,
timestamp TEXT NOT NULL,
environment_id TEXT NOT NULL,
- payload TEXT NOT NULL
+ payload TEXT NOT NULL,
+ PRIMARY KEY (id, environment_id)
)
`);
db.run(This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.
| environment_id TEXT NOT NULL, | ||
| payload TEXT NOT NULL | ||
| ) | ||
| `); |
There was a problem hiding this comment.
Primary key missing environment_id breaks environment scoping
Medium Severity
The table uses id TEXT PRIMARY KEY but every query filters by environment_id, and getEventById requires both id and environmentId. The INSERT OR IGNORE silently drops an event if a different environment already stored an event with the same id. That second environment's queries will then never find the event. The primary key needs to be the composite (id, environment_id) to match the scoping model.
Additional Locations (1)
There was a problem hiding this comment.
There will not be any case where the same event ID exists between two environments. So I think we don't need the composite primary key



Summary
bun:sqlite(built into the binary, no dependencies)environmentIdfrom Mux/whoamiduring login. All event queries are scoped to the current environment. This will gracefully handle if environments are renamed because we are no longer using the name as the primary keymux webhooks events browse)**: Browse, filter by event type, and replay stored events in a terminal UI. Side-by-side detail view shows actions alongside the JSON payload.--forward-topersistence:browseandreplayremember the last--forward-toURL per environment.listensaves the URL but requires it explicitly each run. This makes replaying easier b/c you don't have to explicitly pass the forward URLScreen.Recording.2026-03-19.at.11.37.39.AM.mov
Test plan
pnpm run checkpassespnpm run testpasses (666 tests)tsc --noEmitpassesmux webhooks listen --forward-to http://localhost:3000/webhookscaptures eventsmux webhooks events browseshows events, filters, and replays workmux webhooks events replay --allforwards stored events--forward-toURL is remembered acrossbrowse/replayinvocations🤖 Generated with Claude Code
Note
Medium Risk
Medium risk due to a full rewrite of local webhook event persistence (JSON→SQLite) and updated environment-scoped querying, which could affect event capture/replay behavior and existing stored data migration expectations.
Overview
Switches local webhook event storage from a capped
events.jsonfile to an indexed SQLite DB (events.db, WAL) and updates the events API to be environment-scoped (environmentIdrequired for list/get/all, plus new type-filter helpers andcloseDbfor tests).Updates login/validation to fetch and persist the Mux
environmentId(via/system/v1/whoami), and extends config withenvironmentId+ a per-environment persistedforwardUrlplusupdateEnvironment().Adds
mux webhooks events browse, an interactive TUI to list events, filter by type, inspect payloads, and optionally replay/forward events;events list,events replay, andwebhooks listenare updated to use the new environment-scoped store and to remember--forward-toper environment.Written by Cursor Bugbot for commit cf89051. This will update automatically on new commits. Configure here.