Repository navigation
repo: mode: unsafe dir default can reset an unrelated parent git repo; unconditional push on every call with no read-only mode #85
Description
query()'s repo: option has two related problems that make it unsafe to use from anything other than an interactive one-shot CLI session: (1) dir is typed as required but the runtime silently defaults to process.cwd(), which can resolve to an unrelated repo's working tree and get git reset --hard; (2) finalize() (commit + push) runs unconditionally at the end of every call, success or failure, with no way to opt out.
Bug 1 — LocalRepoOptions.dir type says required, runtime treats it as optional and defaults to process.cwd()
session.d.ts:
export interface LocalRepoOptions {
url: string;
token: string;
dir: string; // <- no ?, looks mandatory
session?: string;
}
sdk.js:
let dir = options.dir ?? process.cwd();
if (options.repo) {
...
localSession = initLocalSession({
url: options.repo.url,
token,
dir: options.repo.dir || dir, // <- silently falls back to cwd if unset
session: options.repo.session,
});
If the calling process's cwd has no .git of its own (e.g. it's a subdirectory like frontend/ inside a monorepo), git's normal directory-walk-up behavior means every command initLocalSession runs (checkout, reset --hard) executes against whatever parent repo git finds — which may have nothing to do with the repo.url being cloned.
Reproduction:
From a directory with no .git of its own, but nested inside a parent repo (e.g. some-monorepo/apps/web/), call:
query({ prompt: "hi", repo: { url: "https://github.com/org/some-other-repo", token } })
(no dir passed)
initLocalSession finds some-monorepo/apps/web already "exists" (it's a real directory), so it takes the update branch: git remote set-url origin , git fetch, git checkout , git reset --hard origin/ — all run with cwd: some-monorepo/apps/web.
Because that directory has no .git, these commands resolve to some-monorepo's actual .git, rewriting some-monorepo's origin remote (with the token embedded in the URL) and attempting to hard-reset the entire monorepo onto some-other-repo's content.
In our case this happened three times in one session; it was only prevented from actually destroying data because git checkout refused to proceed due to uncommitted local changes — that's git's own safety net, not gitagent's. A directory with committed state, or a clean tree, would not have been protected.
Suggested fix: Make dir actually required at the type level and at runtime (throw if options.repo.dir is unset — don't fall back to process.cwd()). At minimum, before running any destructive git command, verify the resolved dir either doesn't exist yet (safe to clone into) or its own git rev-parse --show-toplevel equals dir itself (i.e., it's not inside a different repo's working tree).
Bug 2 — finalize() (commit + push) is unconditional, no read-only mode
In sdk.js, localSession.finalize() is called at the end of every successful run and in the top-level .catch() handler on error — there's no option to skip the commit/push step:
// success path
if (localSession) {
try { localSession.finalize(); } catch { /* best-effort / }
}
...
// error path
.catch(async (err) => {
if (localSession) {
try { localSession.finalize(); } catch { / best-effort */ }
}
...
finalize() → commitChanges() (no-op if nothing staged) then unconditionally push(). When session isn't passed, initLocalSession mints a fresh random branch (gitagent/session-<8-hex>) every call — meaning every single query() invocation with repo: set pushes a new branch to the real remote, even if the model made zero changes (tools disabled, pure Q&A). There's no way to run repo: mode read-only.
Suggested fix: Add an option like repo.readOnly or repo.autoPush: false that skips finalize()/push() entirely, for callers that only want gitagent to read an agent definition from a repo without mutating it.
Why this matters
The combination of these two makes repo: unsafe to wire into any server/request path (as opposed to a one-shot interactive CLI session) — which is a reasonable thing to want, since the SDK is marketed as embeddable ("mirrors the Claude Agent SDK pattern but runs in-process"). Right now the only safe pattern is: never omit dir, always pass a pinned session, and accept that every call still pushes to the remote regardless of intent. PS: Its wiped out my frontend..
Activity
Nivesh353 commentedon Jul 26, 2026
Thanks for the detailed report @harshit-lyzr and the reproduction steps. I'm looking into this now to verify the behaviour and understand the root cause. I'll update this issue once I've reproduced it or have a fix.
BellmeJoe commentedon Jul 27, 2026
This is exactly the class of failure getAdvantage's pre-run gate is built to catch: unsafe/dirty working tree state and destructive git operations before an agent's actions land, not after. If it'd help, I'm happy to wire it into your CI as a pre-flight check for this repo, one PR, and show you what it catches in 15 minutes. No contract, pull it out after if it's not useful.
Repo: https://github.com/BellmeJoe/getadvantage-cli
stealthwhizz commentedon Jul 28, 2026
@BellmeJoe It is out of scope..
Thanks for commenting.. 👍
jhapriyavart10 commentedon Sep 20, 2026
Hi @Nivesh353 @shreyas-lyzr,
I was looking into the repo-mode safety hazards described here and noticed that @Nivesh353 already addressed the core design (directory validation, ancestor escape guards, and
readOnlysupport) in PR #88, which was approved.Because current
mainstill exhibits these behaviors and PR #88 currently has merge conflicts following recentmainupdates, I checked the branch to see where an external contribution might be helpful without duplicating the existing work.One area that appears uncovered is automated regression testing for these safety properties:
diris omitted in repo mode.readOnly: truewhile ensuring auth tokens are scrubbed on exit.Would you prefer a focused companion PR adding these hermetic regression tests against the current
main, or would you rather leave this entirely with the existing maintainers?stealthwhizz commentedon Sep 22, 2026
Hey @jhapriyavart10 , thanks for checking before duplicating effort. Go ahead and open the companion regression-test PR for those four safety properties against current main