feat(sources): #344 LocalDirectorySourceAdapter — capture decisions beyond the IDE#347
Merged
Merged
Conversation
…eyond the IDE Closes #344 (planning/brainstorming workflows weren't being auto-captured because SessionEnd hooks only fire during IDE sessions). Partial step on #337 (multi-source decision capture pipeline) — adds a third adapter to the events/sources/ registry after Granola. Workflow: operator drops a planning/brainstorm output into a configured directory (e.g. ~/.bicameral/captured-notes/); next bicameral-mcp sync-and-brief ingests it. No SessionEnd hook required, no IDE coupling, no remote auth flow. Design (per plan-344 + qor-judge PASS at L1 + audit advisories A1-A3): - Implements SourceAdapter protocol; reuses existing two-phase-commit plumbing in cli/sync_and_brief_cli.py::_run_source. - Non-recursive iterdir(); subdirs ignored; hidden files (.-prefix) ignored; symlinks inside the dir not followed. - Extension allow-list defaults to [.md, .txt, .json]; configurable. - File-size cap mirrors context._DEFAULT_INGEST_MAX_BYTES (1 MiB). Oversized files skipped with stderr warning; mtime NOT added to watermark candidates so future runs retry after shrinkage. - Watermark stores max ISO 8601 mtime; advances only after confirm() (two-phase commit). Corrupt watermark treated as missing. - Graceful empty-return on config errors (missing path, not a dir, unreadable); never raises to the CLI caller. Tests (21 new sociable unit tests against real filesystem via tmp_path, no mocks): registry conformance, protocol conformance, config error handling (missing/nonexistent/file-not-dir), happy-path pull, watermark filtering, extension filter (default + custom), hidden files, subdirs, oversized files (with correct watermark behavior), confirm advances to max mtime, no-new-items-no-watermark-file, source_type_label override (operator can tag content), corrupt watermark, stable span_id from path sha256, parametrized content preservation across multi-line/emoji/markdown. Regression: 11 Granola unit tests still pass; tests/test_sync_and_brief_cli.py all pass (CLI integration unchanged). Docs: docs/policies/sources-config.md gets a new "local_directory source" section + updated source-type table + roadmap entry flipped from "P2 follow-up" to "shipped". Scope honesty: closes #344 fully; partial step on #337 (the Slack / PR review / Linear / git-commit-convention / transcript-dir adapters are separate sub-cycles). Plan: plan-344-local-directory-source-adapter.md (qor-judge PASS at L1) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
9 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #344 (P2 — planning/brainstorming workflows weren't being auto-captured because SessionEnd hooks only fire during IDE sessions). Partial step on BicameralAI/bicameral-daemon#3 (P3 umbrella — multi-source decision capture pipeline); adds a third adapter to
events/sources/after Granola.Workflow
Operator drops a planning/brainstorm output into a configured directory (e.g.
~/.bicameral/captured-notes/2026-05-14-auth-design.md); nextbicameral-mcp sync-and-briefingests it. No SessionEnd hook required, no IDE coupling, no remote auth flow.Design (per plan-344 + qor-judge PASS at L1)
SourceAdapterprotocol; reuses existing two-phase-commit plumbing incli/sync_and_brief_cli.py::_run_source.iterdir(); subdirs ignored; hidden files (.-prefix) ignored; symlinks inside the dir not followed.[.md, .txt, .json]; configurable per source.context._DEFAULT_INGEST_MAX_BYTES(1 MiB). Oversized files skipped with stderr warning; mtime not added to watermark candidates so future runs retry after shrinkage.confirm_watermark()(two-phase commit). Corrupt watermark treated as missing (mirrors Granola precedent)._run_sourcediscipline).Test plan
tmp_path— no mocks. Cover registry conformance, protocol conformance, config errors, watermark filtering, extension filter (default + custom), hidden files, subdirs, oversized files, confirm advance, no-items-no-file,source_type_labeloverride, corrupt watermark, stable span_id from path sha256, parametrized content preservationruff format+ruff checkcleanDocs
docs/policies/sources-config.mdgets a new "local_directorysource" section with config example, behavior summary, workflow example, and what-this-doesn't-do calloutslocal_directoryScope honesty
Plan
plan-344-local-directory-source-adapter.md(qor-judge PASS at L1 with 3 advisory clarifications, all folded into the implementation)🤖 Generated with Claude Code