Skip to content

Aggregate one .basou/ across multiple source repos - #44

Merged
takashi-matsuyama merged 1 commit into
mainfrom
import/multi-root-source-roots
Jun 7, 2026
Merged

takashi-matsuyama merged 1 commit into
mainfrom
import/multi-root-source-roots

Conversation

@takashi-matsuyama

Copy link
Copy Markdown
Member

Summary

Let one .basou/ workspace aggregate the native logs of multiple source
repositories
. A single logical project often spans several checkouts (an
implementation repo, a planning repo, and a shared working directory the AI is
launched from). Each session is recorded under whichever directory the AI ran
in, but the provenance belongs to one workspace. Import discovery previously
keyed on a single exact source path, so a multi-repo project captured only the
slice whose cwd matched the workspace's own repo root and silently dropped the
rest.

Why

This is a real coverage gap for any monorepo-of-repos / workspace layout. The
fix is vendor-neutral (both the claude-code and codex importers) and matches
the project's stance that cross-tool, cross-checkout capture is the point.

What changed

Applied symmetrically to basou import claude-code, basou import codex, and
basou refresh:

  • Repeatable --project <path> — each path is a source root; several paths
    union their sessions into the current workspace, de-duplicated (a root listed
    twice, or equal to the repo root, is scanned once).
  • manifest.import.source_roots — an optional, ordered list of roots
    relative to the repository root (e.g. [".", "../basou-workspace"]), so
    basou refresh with no arguments aggregates every listed repo. The list is
    complete: include "." to keep the host repo. Absent means the host repo only
    (prior behaviour, unchanged). A regex validates entries (rejects absolute
    paths, ~-expansion, backslashes, drive letters) and is emitted into the JSON
    Schema pattern, so cross-language validators enforce it too.
  • basou init --source-root <path> (repeatable) seeds source_roots for a
    new workspace, normalizing each value to a repo-root-relative path.

Resolution precedence: explicit --project flags, else the manifest's
source_roots, else the repository root alone.

Notes on correctness

  • The path sanitizer is unchanged: each session is sanitized against its own
    working_directory, so aggregating siblings never relativizes a path across
    repositories or leaks an absolute host path beyond the existing pathless
    contract.
  • basou view's project field no longer pre-fills the repo root, so a GUI
    refresh honors source_roots instead of silently overriding them.

Testing

  • pnpm -r build && pnpm typecheck && pnpm test && pnpm lint all green
    (core 743, sdk 17, cli 433; lint 0 errors).
  • New tests: multi-root union, manifest-vs-flag precedence, manifest roots
    resolved relative to the repo root, de-dup, partial presence (one absent
    root), --session across roots, "not found in any root" errors, schema
    rejection of absolute/~/backslash/drive-letter/empty source roots,
    init --source-root normalization, and a refresh manifest aggregation case.
  • Regenerated @basou/core JSON Schema artifacts; the drift-guard test passes.

Out of scope

Capture currency / automation (a refresh --watch / cron / editor hooks),
per-source-root session tagging, and the --session + --all mutual-exclusion
guard are intentionally left as follow-ups.

A single logical project often spans several checkouts -- an
implementation repo, a planning repo, and a shared working directory the
AI is launched from. Each AI session is recorded under whichever
directory it ran in (Codex keys each rollout by its session cwd; Claude
Code stores transcripts per project directory), but the provenance
belongs to one workspace. Until now import discovery keyed on a single
exact source path, so a multi-repo project captured only the slice whose
cwd matched the workspace's own repo root and silently dropped the rest.

Let one .basou/ aggregate the native logs of multiple source roots,
applied symmetrically to the claude-code and codex importers and to
basou refresh:

- --project <path> is now repeatable on import claude-code, import
  codex, and refresh. Each path is a source root; several paths union
  their sessions into the workspace, de-duplicated (a root listed twice,
  or equal to the repo root, is scanned once).
- manifest.import.source_roots: an optional, ordered list of roots
  relative to the repository root (e.g. ["." , "../basou-workspace"]), so
  refresh with no arguments aggregates every listed repo. The list is
  complete -- include "." to keep the host repo. Absent means the host
  repo only (prior behaviour, unchanged). Entries are validated by a
  regex that rejects absolute paths, '~' expansion, backslashes, and
  drive letters, so the committed manifest stays path-clean and portable;
  the constraint is emitted into the JSON Schema 'pattern' too.
- init --source-root <path> (repeatable) seeds source_roots for a new
  workspace, normalizing each value to a repo-root-relative path.

Resolution precedence: explicit --project flags, else the manifest's
source_roots, else the repository root alone. The path sanitizer is
unchanged: each session is sanitized against its own working_directory,
so aggregating siblings never relativizes a path across repositories or
leaks an absolute host path. The basou view project field no longer
pre-fills the repo root, so a GUI refresh honors source_roots instead of
overriding them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@takashi-matsuyama
takashi-matsuyama force-pushed the import/multi-root-source-roots branch from c4abee1 to 721672a Compare June 7, 2026 03:13
@takashi-matsuyama
takashi-matsuyama merged commit e2a7379 into main Jun 7, 2026
7 checks passed
@takashi-matsuyama
takashi-matsuyama deleted the import/multi-root-source-roots branch June 7, 2026 03:20
takashi-matsuyama added a commit that referenced this pull request Jun 7, 2026
Import is a pull, so the corpus only advances when 'basou refresh' runs.
After multi-root capture (#44) fixed which repos are scanned, this closes
the currency half: keep the workspace current without a manual step.

'basou refresh --watch [--interval <seconds>]' runs a catch-up refresh on
start, then polls the native-log stores (~/.codex/sessions,
~/.claude/projects) and re-imports + regenerates only when they have
settled (unchanged since the previous poll, so nothing is captured
mid-write) AND changed since the last import. Handoff / decisions
regenerate only when something was imported, so AI work in unrelated
projects never rewrites this workspace's files. Polling is dependency-free
and cross-platform; latency is the interval (default 30s, min 5, max
86400), not real-time. Ctrl-C / SIGTERM stops after the in-flight cycle.
--watch rejects --dry-run / --json / --force.

The baseline scan is taken before the initial import so a session that
appears during the import window is not missed; a pending-regenerate flag
retries a failed regeneration; scan errors are pathless and a missing /
non-directory root contributes nothing; the abortable sleep leaves no
listener behind. A session active at start-up or resumed after settling is
recorded only up to that point -- 'basou refresh --force' rebuilds those.
Event-driven watching and vendor hooks are deferred.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
takashi-matsuyama added a commit that referenced this pull request Jun 8, 2026
Promote the Unreleased changelog to 0.7.0 and bump @basou/core,
@basou/cli, @basou/sdk, and the bare `basou` installer to 0.7.0 in
lockstep. Publishes two dogfood-proven features already on main plus
two folded-in fixes.

Features since 0.6.0:
- Multi-root capture: one .basou/ workspace can aggregate the native
  logs of several sibling repositories (#44).
- `basou refresh --watch`: keep the workspace current automatically by
  polling the native-log stores and re-importing only settled, changed
  sessions (#45).

Fixes:
- Reject --session combined with --all on import (both adapters).
- Drop a reference to a nonexistent `basou session export` from the
  session-import JSON Schema.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant