SurfSense/plans/git-native-kb/02-git-working-tree-backend.md

2.8 KiB

Phase 2 — Git-working-tree backend

Build after Phase 1. Umbrella: 00-umbrella-plan.md. Replaces the read-side fake (KBPostgresBackend) with a backend over the real git tree. Agent tools are unchanged.

Objective

A GitTreeBackend implementing deepagents' BackendProtocol over the Phase-1 GitRepoService, so the agent's ls/read/write/edit/mv/rm/glob/grep operate on real files in the workspace git repo instead of faked-over-Postgres rows.

Locked model

  • Same tool interface, new backend. Implement the exact BackendProtocol surface KBPostgresBackend implements: als_info, aread, awrite, aedit, aglob_info, agrep_raw, alist_tree_listing (return the upstream WriteResult/EditResult/FileInfo/GrepMatch shapes — no extra fields).
  • Reads hit git; writes stage in the working tree (commit happens at end of turn — Phase 3). Reuse the same staging/Command.update pattern the current wrappers use, but backed by the working tree rather than the files cache + Postgres.
  • path_resolver retires for flagged workspaces — virtual /documents/... paths become real repo paths. Keep DOCUMENTS_ROOT as the repo-relative prefix for continuity.
  • Selected via the resolver behind KB_GIT_ENABLED.

Work items

  1. New .../filesystem/backends/git_tree.pyGitTreeBackend(workspace_id, runtime) implementing BackendProtocol over GitRepoService.
    • Map protocol calls → GitRepoService primitives (areadread_file, aglob_infolist_tree+fnmatch, agrep_raw→tree scan, etc.).
    • Preserve read rendering behavior the agent expects (document text/XML view) so reads never regress.
  2. Wire into .../filesystem/backends/resolver.py::build_backend_resolver: when KB_GIT_ENABLED and workspace_id is not None, return GitTreeBackend(workspace_id, runtime) instead of KBPostgresBackend.
  3. Gate path_resolver/kb_postgres usage behind the flag (keep both paths compilable during rollout).

Tests

  • For a seeded repo, ls/read/glob/grep return results identical to KBPostgresBackend for the same content (golden comparison).
  • read of a nested path returns file content; glob("**/*.md") lists the tree; grep respects the existing match caps.
  • Resolver returns GitTreeBackend only when the flag is on; falls back to KBPostgresBackend/StateBackend otherwise.

Out of scope

  • End-of-turn commit → Phase 3. Index refresh → Phase 4.
  • Desktop-local (MultiRootLocalFolderBackend) path — unchanged.

Open questions

  1. Read rendering: serve raw markdown from git vs. reproduce the current rendered-document view (citations). Confirm what the agent contract needs.
  2. Whether grep/glob scan the working tree directly or use git plumbing (git grep semantics via dulwich) for large repos.