Skip to content

fix: detect .git-only stale workdir; wire run_external repo cloning#293

Merged
wwind123 merged 2 commits into
mainfrom
feat/stale-workdir-git-only
Jun 12, 2026
Merged

fix: detect .git-only stale workdir; wire run_external repo cloning#293
wwind123 merged 2 commits into
mainfrom
feat/stale-workdir-git-only

Conversation

@wwind123

Copy link
Copy Markdown
Owner

Summary

  • _is_stale_default_workdir extended (config.py): previously returned False as soon as .git/ existed, so a workdir with .git/ but no source files (e.g. after accidental wipe leaving only response storage at .git/agent-loop/) was never detected as stale. Now also flags the case where .git is present but the working tree contains no non-artifact files.

  • run_external.py now validates/re-clones the workdir (run_external.py, skill_runner.py): run_external was being called with --workdir but never called ensure_temp_checkout, so it would fail silently if the workdir was absent or stale. Added --repo OWNER/REPO; when provided, run_external calls ensure_temp_checkout with the real repo before launching the agent. skill_runner now passes --repo on every run_external invocation.

  • Fixed a misleading comment in skill_runner.py that claimed cloning was handled by --workdir (it wasn't).

Test plan

  • tests/test_agent_loop.py -k stale — three tests, including new test_stale_default_workdir_git_only_is_recreated
  • tests/test_skill_helpers.py — 22 tests unchanged

🤖 Generated with Claude Code

-- Anthropic Claude

Two gaps that caused Gemini's workdir to become an empty checkout
(only .git/ present, no source files), making Gemini fail with
'path not in workspace' errors:

1. _is_stale_default_workdir previously returned False whenever .git
   existed, so a workdir with .git/ but no source files was never
   detected as stale and never re-cloned.  Extend the check: if .git
   is present but the working tree has no non-artifact files, treat it
   as stale and recreate.

2. run_external.py never called ensure_temp_checkout before launching
   the agent, so even if the workdir was deleted the agent would fail
   to start.  Add --repo (OWNER/REPO); when provided, run_external
   calls ensure_temp_checkout with the real repo before starting the
   agent.  skill_runner passes --repo on every run_external call.

Also fix the misleading comment in skill_runner.py that claimed
run_external handles cloning via --workdir (it didn't).

Related to #291.
@wwind123

Copy link
Copy Markdown
Owner Author

Review verdict: Blocking

The PR correctly extends stale workdir detection to handle .git-only directories and wires up repository cloning in run_external.py. However, it fails to handle completely empty directories as stale, which causes skill_runner.py to fail on first run because it pre-creates the workdir.

Blocking issues

  • _is_stale_default_workdir in src/coding_review_agent_loop/config.py still requires the directory to be non-empty (via bool(contents)) to be considered stale in the non-git case. This blocks auto-cloning when helpers/skill_runner.py creates an empty directory before calling run_external.py, as ensure_temp_checkout will find the directory exists but is not stale, skipping the clone and failing later with a 'not a git checkout' error.

Same-PR follow-ups

  • Import AgentName in helpers/run_external.py and remove the type: ignore[arg-type] on the ensure_temp_checkout call to maintain type safety.

-- Google Gemini

- _is_stale_default_workdir: remove bool(contents) guard so an empty
  directory (no .git, no files) is also treated as stale.  Discovered
  when the Codex workdir was an empty dir: ensure_temp_checkout skipped
  the clone and crashed in _sync_base_branch.
- run_external.py: annotate agent_name as AgentName (cast from argparse
  str) and remove all type: ignore[arg-type] comments on the config and
  ensure_temp_checkout calls.
- Add test_stale_default_workdir_empty_is_recreated.

Related to #291.
@wwind123

Copy link
Copy Markdown
Owner Author

Change summary (round 1 feedback)

Gemini blocking item (real bug, fixed): _is_stale_default_workdir required bool(contents) to be true in the no-.git branch, so an empty directory was never flagged as stale. When ensure_temp_checkout found an empty-but-existing Codex workdir, it skipped the clone and crashed in _sync_base_branch. Fixed by removing the bool(contents) guard — an empty directory with no git checkout is always stale.

Gemini same-PR followup (fixed): run_external.py now declares agent_name: AgentName (cast from the argparse string, which is always valid) and removes all three type: ignore[arg-type] annotations.

Added test_stale_default_workdir_empty_is_recreated covering the empty-dir case. All 4 stale workdir tests pass.

-- Anthropic Claude

@wwind123

Copy link
Copy Markdown
Owner Author

Review verdict: Approved

The PR successfully addresses the prior review items and improves the robustness of workdir management in run_external. _is_stale_default_workdir now correctly identifies empty or .git-only directories as stale, triggering a re-clone when necessary. The addition of --repo to run_external ensures that it can autonomously manage the checkout state. Type safety is also improved by properly importing and using AgentName.

Prior unresolved item dispositions

  • [item-1] Blocking issue from Google Gemini, round 1: _is_stale_default_workdir in src/coding_review_agent_loop/config.py still requires the direct... -> resolved
  • [item-2] Same-PR follow-up from Google Gemini, round 1: Import AgentName in helpers/run_external.py and remove the type: ignore[arg-type] on the `e... -> resolved

-- Google Gemini

@wwind123

Copy link
Copy Markdown
Owner Author

Review verdict: Approved

Approved. The stale workdir detection now covers empty and .git-only default workdirs, and run_external is wired to validate or re-clone when skill_runner supplies the repo.

Prior unresolved item dispositions

  • [item-1] Blocking issue from Google Gemini, round 1: _is_stale_default_workdir in src/coding_review_agent_loop/config.py still requires the direct... -> resolved
  • [item-2] Same-PR follow-up from Google Gemini, round 1: Import AgentName in helpers/run_external.py and remove the type: ignore[arg-type] on the `e... -> resolved

-- OpenAI Codex

@wwind123 wwind123 merged commit 283126f into main Jun 12, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant