feat(db): optional ignore-filter for sessions by cwd (MONITOR_IGNORE_CWD)#182
feat(db): optional ignore-filter for sessions by cwd (MONITOR_IGNORE_CWD)#182MarcoFPO wants to merge 1 commit into
Conversation
|
✅ All contributors have signed the CLA. Thank you! |
…CWD) Consolidation/probe sessions (e.g. `claude --print` runs with cwd=/tmp) could flood the dashboard with thousands of entries. This adds a central guard around stmts.insertSession that covers every insert path (hooks, REST POST, backfill). Opt-in via the MONITOR_IGNORE_CWD env var (default empty = disabled); set it to a path prefix to ignore matching sessions. Co-Authored-By: Claude <noreply@anthropic.com>
6a909b3 to
2d5681d
Compare
|
recheck |
There was a problem hiding this comment.
Code Review
This pull request introduces a mechanism to prevent the persistence of database sessions based on their current working directory (CWD) using the MONITOR_IGNORE_CWD environment variable. The review feedback identifies a critical issue where skipping session insertion will cause foreign key constraint violations in SQLite when related entities (such as agents or events) are subsequently inserted. Additionally, the reviewer points out that replacing stmts.insertSession with a plain object strips other Statement methods, and suggests using a Proxy to safely intercept and skip all related write statements.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| if (IGNORED_SESSION_CWDS.size > 0) { | ||
| const _origInsertSession = stmts.insertSession; | ||
| stmts.insertSession = { | ||
| run: (...args) => { | ||
| const cwd = args[3]; | ||
| if (cwd && IGNORED_SESSION_CWDS.has(cwd)) { | ||
| return { changes: 0, lastInsertRowid: 0 }; | ||
| } | ||
| return _origInsertSession.run(...args); | ||
| }, | ||
| }; | ||
| } |
There was a problem hiding this comment.
Critical Correctness Issues
-
Foreign Key Constraint Violations:
The database schema enforces foreign key constraints (FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE) onagents,events,token_usage, andworkflowstables, andforeign_keys = ONis enabled on line 127. If we skip inserting a session but subsequently attempt to insert agents, events, token usage, or workflows referencing that session ID, SQLite will throw aSqliteError: FOREIGN KEY constraint failederror, crashing the server or hook handler. -
Interface Preservation:
Replacingstmts.insertSessionwith a plain object{ run: ... }strips away all other properties and methods of the Statement object (such asget,all,iterate, etc.). Using aProxypreserves the Statement prototype and all other methods/properties, ensuring full compatibility.
Solution
Track ignored session IDs in a Set and use a Proxy to intercept all write statements referencing session_id to safely skip execution for ignored sessions.
const IGNORED_SESSION_IDS = new Set();
if (IGNORED_SESSION_CWDS.size > 0) {
const wrapStatement = (stmt, checkFn) => {
if (!stmt) return stmt;
return new Proxy(stmt, {
get(target, prop, receiver) {
if (prop === "run") {
return (...args) => {
if (checkFn(...args)) {
return { changes: 0, lastInsertRowid: 0 };
}
return target.run(...args);
};
}
const value = Reflect.get(target, prop, receiver);
return typeof value === "function" ? value.bind(target) : value;
},
});
};
stmts.insertSession = new Proxy(stmts.insertSession, {
get(target, prop, receiver) {
if (prop === "run") {
return (...args) => {
const id = args[0];
const cwd = args[3];
if (cwd && IGNORED_SESSION_CWDS.has(cwd)) {
if (id) IGNORED_SESSION_IDS.add(id);
return { changes: 0, lastInsertRowid: 0 };
}
return target.run(...args);
};
}
const value = Reflect.get(target, prop, receiver);
return typeof value === "function" ? value.bind(target) : value;
},
});
stmts.insertAgent = wrapStatement(stmts.insertAgent, (...args) => IGNORED_SESSION_IDS.has(args[1]));
stmts.insertEvent = wrapStatement(stmts.insertEvent, (...args) => IGNORED_SESSION_IDS.has(args[0]));
stmts.upsertTokenUsage = wrapStatement(stmts.upsertTokenUsage, (...args) => IGNORED_SESSION_IDS.has(args[0]));
stmts.replaceTokenUsage = wrapStatement(stmts.replaceTokenUsage, (...args) => IGNORED_SESSION_IDS.has(args[0]));
stmts.upsertWorkflow = wrapStatement(stmts.upsertWorkflow, (...args) => IGNORED_SESSION_IDS.has(args[1]));
stmts.updateSession = wrapStatement(stmts.updateSession, (...args) => IGNORED_SESSION_IDS.has(args[4]));
stmts.reactivateSession = wrapStatement(stmts.reactivateSession, (...args) => IGNORED_SESSION_IDS.has(args[0]));
stmts.updateSessionModel = wrapStatement(stmts.updateSessionModel, (...args) => IGNORED_SESSION_IDS.has(args[1]));
stmts.touchSession = wrapStatement(stmts.touchSession, (...args) => IGNORED_SESSION_IDS.has(args[0]));
stmts.setSessionTranscriptPath = wrapStatement(stmts.setSessionTranscriptPath, (...args) => IGNORED_SESSION_IDS.has(args[1]));
stmts.setSessionAwaitingInput = wrapStatement(stmts.setSessionAwaitingInput, (...args) => IGNORED_SESSION_IDS.has(args[1]));
stmts.clearSessionAwaitingInput = wrapStatement(stmts.clearSessionAwaitingInput, (...args) => IGNORED_SESSION_IDS.has(args[0]));
stmts.clearSessionAgentsAwaitingInput = wrapStatement(stmts.clearSessionAgentsAwaitingInput, (...args) => IGNORED_SESSION_IDS.has(args[0]));
stmts.insertAlertEvent = wrapStatement(stmts.insertAlertEvent, (...args) => IGNORED_SESSION_IDS.has(args[3]));
}|
I have read the CLA Document and I hereby sign the CLA |
|
recheck |
What
Adds an optional, opt-in filter that prevents sessions from being recorded based on their working directory (cwd).
Why
Short-lived helper sessions — e.g.
claude --printcalls spawned by an API wrapper, all running withcwd=/tmp— can flood the dashboard with thousands of throwaway entries, drowning out real sessions.How
stmts.insertSessioninserver/db.js, so it applies to all insert paths: hooks, the RESTPOSTendpoint, and backfill.MONITOR_IGNORE_CWD./tmp) to skip matching sessions.Notes
server/db.js, +27 lines).