A Repository is the main handle for grit-lib. It carries the absolute git_dir path, an optional work_tree for non-bare repos, an Odb for object reads and writes, and the Environment used to discover or open it.
Environment
Environment holds discovery and config variables (GIT_DIR, GIT_WORK_TREE, GIT_CEILING_DIRECTORIES, GIT_CONFIG_*, home paths, cwd, and related fields) without reading the process environment inside the library. Construct one with Environment::empty() (defaults only) or Environment::from_vars() (parse an iterator of (key, value) pairs plus an explicit working directory). See Environment.
The grit CLI builds an environment from the process in grit-cli and passes it into discovery. Embedders should do the same: snapshot the variables you care about once, then call Repository::discover_with or Repository::open_with with RepositoryOptions.
Repository::discover and Repository::open remain convenience entry points that use Environment::empty() (no overrides beyond cwd = ".").
ConfigSet::load takes &Environment as its first argument and always parses the cascade from disk (no process-global cache). Repository-scoped memoization lives on each open handle: Repository::config returns Arc<ConfigSet> backed by RepoCaches (config cascade, gitattributes stacks, filter-process drivers, precompose flags, and related state).
Command runner
Hooks, clean/smudge filters, credential helpers, signing, SSH transport, and similar features spawn subprocesses through a CommandRunner stored on the repository (via RepositoryOptions::command_runner). The default is SystemCommandRunner, which is the only non-test code path that calls std::process::Command. Tests and embedders can install RecordingRunner or a custom runner to assert argv, environment, and stdin without executing real programs. Hook failures surface as HookError; shell filter subprocess failures use FilterError.
Discover vs open
Call Repository::discover_with when you have a working directory and want Git-style upward search. Call Repository::open_with when you already know the git directory and optionally the work tree path. See Repository.
Bare repositories have work_tree: None. Linked worktrees and gitfile indirection are handled during discovery so git_dir always points at the directory that contains objects/.
Config
Repository::config returns a lazily loaded snapshot of the merged cascade (system / global / local / worktree / environment overrides). Prefer it on hot paths instead of calling ConfigSet::load repeatedly. Keys use Git’s dotted names (user.name, core.bare, …).
Errors
Library operations return grit_lib::error::Result. The Error enum covers I/O, missing objects, bad repository layout, and invalid user input. Match on variants in application code; the grit CLI maps them to exit codes and messages separately.