feat(claudewatcher): exclude whole project directories from ingestion
CLAUDE_INGEST_SKIP_PROJECTS takes filepath.Match globs tested against the project directory NAME, and a matching directory is skipped during the directory WALK — so its files are never opened and their content never enters the process. That is a stronger property than filtering after reading, and the difference is observable: without SkipDir, WalkDir lists the directory's entries, and an unreadable one aborts the entire walk, silently stopping ingestion for every other project. Globs rather than exact names because a project directory is derived from the session's working directory, so a git worktree yields an ephemeral name no exact-match list could keep up with. An unparseable pattern refuses to run. filepath.Match returns an error ALONGSIDE a false match, so a bad pattern checked per-file would ingest the directory while the log complained — the failure nobody notices. Validated once, up front, in both entry points. This complements the client-name scrubber rather than replacing it. The scrubber drops individual turns whose content matches a client identity; this excludes whole workspaces whose content is confidential in ways no pattern reliably recognises. Learnings from excluded sessions are captured deliberately through the session-close ritual instead. Recorded caveat: the project directory reflects the session's working directory, NOT the repositories it touches. A session run from ~/dev that reads an excluded repo is not excluded by this. The scrubber remains the control for content; this is a control for workspaces. A mutation test earned the strongest assertion here: the original tests could not distinguish SkipDir from filtering after the walk, because neither opens files. The unreadable-directory test can. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,29 @@
|
||||
"supervisor": {
|
||||
"url": "http://localhost:3200/mcp",
|
||||
"description": "Hyperguild SDO — skill workers (tdd, retrospective), brain tools (brain_query, brain_write), session logging, tier detection"
|
||||
},
|
||||
"brain": {
|
||||
"type": "http",
|
||||
"url": "https://koala.tail30472e.ts.net:8443/mcp",
|
||||
"headers": {
|
||||
"Authorization": "Bearer ${BRAIN_MCP_TOKEN}"
|
||||
}
|
||||
},
|
||||
"gitea": {
|
||||
"_comment": "gitea-mcp authenticates by PASS-THROUGH: the bearer is a Gitea PAT it validates against Gitea and then acts as. GITEA_MCP_TOKEN -- which this entry used until 2026-09-08 -- 401s against it, so every harness synced from this file had a dead gitea server and no signal saying so. Probed 2026-09-08: GITEA_MCP_TOKEN 401, DMABE_GITEA_API_TOKEN 200, on both the public and the Serve URL.",
|
||||
"type": "http",
|
||||
"url": "https://koala.tail30472e.ts.net:8446/mcp",
|
||||
"headers": {
|
||||
"Authorization": "Bearer ${DMABE_GITEA_API_TOKEN}"
|
||||
}
|
||||
},
|
||||
"infra": {
|
||||
"_comment": "The bearer is belt-and-braces: this endpoint answers 200 with or without it, since Serve already limits reach to the tailnet. Sending it anyway means the day the server starts enforcing is not the day every harness breaks.",
|
||||
"type": "http",
|
||||
"url": "https://koala.tail30472e.ts.net:8444/mcp",
|
||||
"headers": {
|
||||
"Authorization": "Bearer ${INFRA_MCP_TOKEN}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user