Skip to content

T-NS6Z-vault-git-status-service

State: planning/proposed · Impact: high · Complexity: medium

The agent-pants tree, the git panel, and version-bump suggestions all need to know whether a vault sits on uncommitted or ahead/behind work. Today VaultAspect::Git only reports that a .git/ directory exists; nothing reports what state it holds. This task adds the read side — branch, ahead/behind, and per-path status — as one platform facility every consumer subscribes to, instead of each one shelling out on its own.

LocationRole today
packages/rust/dir-aspect/src/lib.rs#AspectPresence-only detection: a .git/ directory exists or it does not; no status
solutions/determined/crates/determined-platform/src/vault_workspace.rs#aspect_fromMaps dir_aspect::Aspect to the wire VaultAspect on every vault read
solutions/determined/crates/determined-core/src/wire/mod.rs#VaultAspectWire enum {Obsidian, Git, Generic}; no per-path or per-branch shape
packages/rust/easy-git/src/query.rsis_repo, current_branch, is_clean, status_short (git status --porcelain), diff_stat, head_sha; no ahead/behind, no per-path state enum
packages/rust/fluent-git/src/cmd.rs#GitCommandThe fluent argv builder (dir/arg/args/run/check) easy-git’s queries are built on
solutions/determined/crates/determined-backup/src/git.rsThe one existing process-shelling git module; hard-codes a bare-repo --git-dir/--work-tree pairing private to the backup store, not a live vault
solutions/determined/crates/determined-platform/src/api/v1/One route module per capability (vault.rs, openers.rs, settings.rs, …); no git.rs
solutions/determined/crates/determined-core/src/ctx.rs#CtxThe per-call bundle every port method receives, documented as the place a new shared facility is added explicitly
solutions/determined/crates/determined-platform/src/vault_watch.rsCoalesces filesystem events per vault and invalidates the frontmatter index and link graph; nothing subscribes for git status
solutions/determined/packages/shell/app/composables/useVaultRegistry.tsuseVaultRegistry() caches openers and vaults per id; no useVaultGit()

determined-platform/src/api/v1/git.rs serves git_status(vault_id), gated on VaultAspect::Git: a vault without the aspect answers Invalid rather than shelling out. The result carries the current branch, ahead/behind counts against its upstream, and one entry per changed path tagged modified | staged | untracked | conflicted. It is built over easy-git/fluent-git, not over determined-backup’s bare-repo shelling, which is specific to that crate’s dotfiles pairing. Wire types live in determined-core/src/wire/mod.rs beside VaultAspect. A useVaultGit() composable in the shell package caches the result per vault id and invalidates it when that vault’s contents change, the same way useVaultRegistry() caches openers.

  1. Confirm with T-QGMQ-vault-facilities-decision whether git_status is a bare AppState surface (the vault.rs/openers.rs “no port trait” precedent, since it reads registry state) or a Ctx-registered facility; this task follows whichever it settles.
  2. Extend easy-git with a branch-plus-ahead/behind query (git status --porcelain=v2 --branch parses both in one call) and a per-path status parse, rather than layering a second parser over the existing status_short.
  3. Add GitStatus, GitFileStatus and a GitFileState enum to determined-core/src/wire/mod.rs, named and documented beside VaultAspect.
  4. Add determined-platform/src/api/v1/git.rs with git_status(vault_id) -> Result<GitStatus, AppError> and register it in api/v1/mod.rs. A vault without VaultAspect::Git returns Invalid naming the missing aspect, never a shelled-out failure.
  5. Add useVaultGit() to solutions/determined/packages/shell/app/composables/, mirroring useVaultRegistry()’s per-id cache.
  6. Wire invalidation: decide whether useVaultGit() refetches on the vault’s existing vault_watch.rs change feed or on a simpler pull (window focus, an explicit refresh action); the risk log’s “cache per watch tick” advice applies here — whichever fires must not poll.
  7. Unit-test git_status over a real tempdir git repo (branch, ahead/behind, each file state) and over a non-git vault (empty/Invalid), following vault_workspace.rs’s tempdir test style.
AreaNote
solutions/determined/crates/determined-platform/src/api/v1/git.rsgit_status op
solutions/determined/crates/determined-platform/src/api/v1/mod.rsRegister pub mod git;
solutions/determined/crates/determined-core/src/wire/mod.rsGitStatus/GitFileStatus/GitFileState
packages/rust/easy-git/src/query.rsBranch+ahead/behind and per-path status queries
solutions/determined/packages/shell/app/composables/useVaultGit.tsuseVaultGit() composable
solutions/determined/crates/determined-platform/src/vault_watch.rsInvalidation trigger the composable subscribes to (mechanism per Approach step 6)
  • AC-1: git_status on a git-aspected vault with uncommitted changes reports branch, ahead/behind, and one entry per changed path with the correct state, verified by a unit test against a real tempdir repo.
  • AC-2: git_status on a vault without VaultAspect::Git returns an Invalid error naming the missing aspect and never spawns git.
  • AC-3: useVaultGit() exists in the shell package and caches per vault id, matching useVaultRegistry()’s shape.
  • AC-4: No caller of the new op shells out to git directly; every git invocation goes through easy-git/fluent-git.

From the user’s Agent Manager planning request of 2026-09-07: git awareness as a vault facility is one of the eight areas in the brain-dump, expanded into a milestone by solutions/agent-pants/docs/vault/design/workflow-and-ux-assessment.md’s harness and workflow survey. It backs the git panel, tree/tab decorations, and version-bump-suggestion tasks in the same stage.

T-QGMQ-vault-facilities-decision


← Back to Tasks