Summary
Inside a brand-new repo with no remote (a freshly git init'd directory — e.g. the first steps of scaffolding a new project), omind guard locks the agent out of its own repo. The same-turn freshness gate (repo-work-fresh-base) demands a git fetch / git pull before any review/edit/test/commit — but a repo with no remote has nothing to fetch, so the demanded remediation is impossible:
git fetch → fatal: No remote repository specified.
git pull --ff-only → There is no tracking information for the current branch.
Only the exact string git fetch --all --prune happens to exit 0 (it iterates over zero remotes as a no-op), so the block is technically escapable via one specific incantation — but the two commands the block message actually suggests both fail, which reads as a hard deadlock.
Reproduce
mkdir /tmp/newrepo && git -C /tmp/newrepo init
cd /tmp/newrepo
# consult the git-rules note this turn (satisfies repo-work-read-git-rules), then:
# → any Write/Edit/pytest/commit is blocked with rule_id=repo-work-fresh-base
git pull --ff-only # fatal: There is no tracking information for the current branch.
git fetch # fatal: No remote repository specified.
Driving the decision engine directly:
from omind import guard
sess = "demo"
guard.record_consult(sess, kind="read", target=guard.GIT_RULES_NOTE, relevant=True)
v = guard.decide({"tool": "Write", "file_path": "/tmp/newrepo/hello.py", "session": sess})
# BEFORE: v.allow is False, v.rule_id == "repo-work-fresh-base"
Root cause
guard.decide() demands freshness for any repo-sensitive action whenever _repo_root_for_action(...) resolves a repo (i.e. a .git exists) and the per-turn freshness marker isn't set. It never checks whether the repo actually has a remote. A repo with zero configured remotes has no upstream to be stale against, so the freshness check is vacuous there — yet it's enforced, and can't be satisfied by the remediation the block message recommends.
Proposed fix
Waive the freshness demand when the repo has no configured remote (repo-work-fresh-base no longer fires); keep it exactly as-is for any repo that has a remote. The rules-note consult (repo-work-read-git-rules) still applies — this only touches freshness.
Detection must be subprocess-free (this runs on the PreToolUse hot path) and conservative: read <repo>/.git/config for a [remote "…"] stanza, and treat any doubt — a .git pointer file (linked worktree / submodule, whose remotes live in the shared config), an unreadable config, or any resolution error — as has a remote. That way freshness is only ever waived when we positively confirm zero remotes, and a repo that has a remote can never be loosened.
Scope / non-goals
- Not a loosening for real repos: a repo with a remote still requires a same-turn fetch.
- Does not touch the
git pull bare-vs---ff-only rule, the rules-note consult, or the destructive hard-blocks.
- A directory that is not a git repo at all already isn't freshness-gated (no
.git → no repo → freshness branch skipped); it only ever hits the ordinary consult-gate.
Summary
Inside a brand-new repo with no remote (a freshly
git init'd directory — e.g. the first steps of scaffolding a new project),omind guardlocks the agent out of its own repo. The same-turn freshness gate (repo-work-fresh-base) demands agit fetch/git pullbefore any review/edit/test/commit — but a repo with no remote has nothing to fetch, so the demanded remediation is impossible:git fetch→fatal: No remote repository specified.git pull --ff-only→There is no tracking information for the current branch.Only the exact string
git fetch --all --prunehappens to exit 0 (it iterates over zero remotes as a no-op), so the block is technically escapable via one specific incantation — but the two commands the block message actually suggests both fail, which reads as a hard deadlock.Reproduce
Driving the decision engine directly:
Root cause
guard.decide()demands freshness for any repo-sensitive action whenever_repo_root_for_action(...)resolves a repo (i.e. a.gitexists) and the per-turn freshness marker isn't set. It never checks whether the repo actually has a remote. A repo with zero configured remotes has no upstream to be stale against, so the freshness check is vacuous there — yet it's enforced, and can't be satisfied by the remediation the block message recommends.Proposed fix
Waive the freshness demand when the repo has no configured remote (
repo-work-fresh-baseno longer fires); keep it exactly as-is for any repo that has a remote. The rules-note consult (repo-work-read-git-rules) still applies — this only touches freshness.Detection must be subprocess-free (this runs on the PreToolUse hot path) and conservative: read
<repo>/.git/configfor a[remote "…"]stanza, and treat any doubt — a.gitpointer file (linked worktree / submodule, whose remotes live in the shared config), an unreadable config, or any resolution error — as has a remote. That way freshness is only ever waived when we positively confirm zero remotes, and a repo that has a remote can never be loosened.Scope / non-goals
git pullbare-vs---ff-onlyrule, the rules-note consult, or the destructive hard-blocks..git→ no repo → freshness branch skipped); it only ever hits the ordinary consult-gate.