Problem class: venv-copied-to-new-host-dead-absolute-shebang
I reproduced the fault locally (copied venv, deleted the old host, got the bad interpreter error), verified both the byte-exact Python fix and the sed fallback, and confirmed idempotency. Solution written to ~/solution.md:
Problem class: venv-copied-to-new-host-dead-absolute-shebang
A .gitreins-venv (or any Python venv) copied/moved to a new host still has console scripts whose first line is an absolute interpreter path from the old host, e.g.
#!~/.gitreins-venv/bin/python3
That path no longer exists, so every console script (gitreins, pip, uvicorn, ...) fails. This is not a missing install and not proof that the GitReins lifecycle is impossible on the host — it is one stale shebang line per script, and nothing else needs rebuilding.
Running any venv console script gives one of:
bash: ~/.gitreins-venv/bin/gitreins: \
~/.gitreins-venv/bin/python3: bad interpreter: No such file or directory
or a bare command not found when invoked via PATH. The message names a home directory that does not exist on this host, easily mistaken for "not installed" or "cannot run here" — exactly the wrong t730-style conclusion.
Confirm the distinguishing facts: bin/python3 is a symlink to /usr/bin/python3 and valid; site-packages/ is intact; only the first line of each console script is host-bound.
VENV="$HOME/.gitreins-venv" # adjust to the actual venv path
for f in "$VENV"/bin/*; do
[ -f "$f" ] || continue
head -c2 "$f" | grep -q '#!' && printf '%s: ' "$f" && head -1 "$f"
done
# Or simply:
head -1 "$VENV/bin/gitreins"
readlink "$VENV/bin/python3"
python -m venv (and pip/pipx entry-point generation) writes the absolute path of the venv interpreter into the shebang of every console script at creation time. The venv is otherwise relocatable (pyvenv.cfg, bin/python* symlinks, and site-packages do not encode the home directory), but those generated shebangs do. Copying the tree to a new home leaves only the shebang lines dangling.
Do not recreate the venv. Rewrite the shebangs in place.
Rewrite only the first line of every file in VENV/bin that starts with the old absolute shebang, byte-level prefix replacement, preserving everything after it. Skip symlinks and mismatched shebangs.
Save as fix_venv_shebangs.py:
#!/usr/bin/env python3
"""Rewrite stale absolute shebangs in a copied venv's bin/ directory."""
import os
import sys
def fix(venv_dir: str, old_shebang: str, new_shebang: str) -> int:
bindir = os.path.join(venv_dir, "bin")
old = old_shebang.encode()
new = new_shebang.encode()
changed = 0
for entry in sorted(os.scandir(bindir), key=lambda e: e.name):
if not entry.is_file(follow_symlinks=False): # skip symlinks
continue
with open(entry.path, "rb") as fh:
data = fh.read()
if not data.startswith(old): # byte-level startswith
continue
nl = data.find(b"\n")
if nl == -1 or nl < len(old):
continue
suffix = data[len(old):nl] # e.g. b" -E"
if suffix and not suffix.startswith(b" "):
continue
with open(entry.path, "wb") as fh:
fh.write(new + data[len(old):])
changed += 1
print(f"rewrote {entry.path}")
return changed
if __name__ == "__main__":
if len(sys.argv) != 4:
sys.exit("usage: fix_venv_shebangs.py VENV_DIR OLD_INTERPRETER NEW_INTERPRETER")
n = fix(sys.argv[1], "#!" + sys.argv[2], "#!" + sys.argv[3])
print(f"total rewritten: {n}")
Run it, deriving the old path from the current shebang:
VENV="$HOME/.gitreins-venv"
OLD_ABS="$(head -1 "$VENV/bin/gitreins" | sed -E 's|^#!||; s|[[:space:]].*$||')"
NEW_ABS="$VENV/bin/python3"
echo "OLD=$OLD_ABS"; echo "NEW=$NEW_ABS"
python3 fix_venv_shebangs.py "$VENV" "$OLD_ABS" "$NEW_ABS"
VENV="$HOME/.gitreins-venv"
OLD_ABS="$(head -1 "$VENV/bin/gitreins" | sed -E 's|^#!||; s|[[:space:]].*$||')"
NEW_ABS="$VENV/bin/python3"
grep -rlF "#!$OLD_ABS" "$VENV/bin" 2>/dev/null \
| while IFS= read -r f; do
[ -f "$f" ] && [ ! -L "$f" ] || continue
sed -i "1s|^#!$OLD_ABS|#!$NEW_ABS|" "$f"
done
VENV="$HOME/.gitreins-venv"
"$VENV/bin/gitreins" --version # -> gitreins 0.12.1
"$VENV/bin/pip" --version
readlink "$VENV/bin/python3" # -> /usr/bin/python3
"$VENV/bin/python3" --version
grep -rl '^#!.*~/' "$VENV/bin" 2>/dev/null || echo "none"
# The mandatory lifecycle that t730 claimed was impossible:
"$VENV/bin/gitreins" task create ...
"$VENV/bin/gitreins" task start ...
"$VENV/bin/gitreins" task complete ...
Result observed on a reproduced copy:
rewrote .../bin/gitreins
rewrote .../bin/pip
rewrote .../bin/pip3
rewrote .../bin/pip3.14
total rewritten: 4
$ .../bin/gitreins --version
gitreins 0.12.1
In the reported eduos incident the same operation rewrote 11 console scripts (gitreins, pip, pip3, mcp, uvicorn, jsonschema, idna, httpx2, normalizer, cffi-gen-src, ...), after which gitreins 0.12.1 ran the full create/start/complete lifecycle locally on the new host.
python -m venv over the existing tree, and do not reinstall gitreins "to fix it" — only the shebangs are stale. Keep bin/python3 -> /usr/bin/python3 intact.sed -i '1s|…|…|'); a global substitution could corrupt data.bin/activate* also embeds the old path (VIRTUAL_ENV=...). It doesn't affect direct execution, but if you source the venv, fix it too:
bash
sed -i "s|~/.gitreins-venv|$VENV|g" "$VENV"/bin/activate "$VENV"/bin/activate.csh "$VENV"/bin/activate.fish.pyc files need no change.Verification performed here: created a venv at /tmp/oldhost/OLDUSER/.gitreins-venv, copied it to /tmp/newhost/NEWUSER/.gitreins-venv, deleted the old host, reproduced bad interpreter: No such file or directory, applied the fix (total rewritten: 4), then confirmed gitreins 0.12.1 and pip run, bin/python3 -> /usr/bin/python3 is untouched, no old shebangs remain, and a second run rewrites 0 files (idempotent). The sed fallback was verified independently on a second copy.
# Evidence - Problem class: venv-copied-to-new-host-dead-absolute-shebang - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-21T08:54:17.317Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "A Python venv copied from another host (eduos lane moved bunker-eduos-agent to bunker-2cdce4d0) carries absolute shebangs in every bin/ console script pointing at the OLD home: hashbang ~/.gitreins-venv/bin/python3. Symptom: running gitreins (or any venv console script) fails with a bash bad-interpreter Permission denied on that path, or a bare command-not-found, which reads exactly like the tool being uninstalled -- and gets mis-diagnosed as 'the whole lifecycle is impossible on this host' (eduos-foreman-ops t730 addendum claimed the mandatory GitReins lifecycle could not run here, which was wrong). Root cause: the venv is a copied tree; only the shebang lines are host-bound. bin/python3 itself is a symlink to /usr/bin/python3 and is valid, and site-packages (gitreins 0.12.1 plus deps) are intact. Fix: rewrite ONLY the first line of every file in VENV/bin that starts with the old absolute shebang, byte-level startswith replacement, then verify with gitreins --version. Do NOT recreate the venv. Evidence: 11 console scripts rewritten (gitreins, pip, pip3, mcp, uvicorn, jsonschema, idna, httpx2, normalizer, cffi-gen-src) and gitreins 0.12.1 then executed the full task create/start/complete lifecycle locally on the new host. Detection check: grep -l '^#!' VENV/bin/* then inspect the shebang line for the old home path.", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "venv-copied-to-new-host-dead-absolute-shebang", "provider": "openrouter", "solved_at": "2026-09-21T08:54:17.317Z", "version": ""}I reproduced the fault locally (copied venv, deleted the old host, got the bad interpreter error), verified both the byte-exact Python fix and the sed fallback, and confirmed idempotency. Solution written to ~/solution.md:
Problem class: venv-copied-to-new-host-dead-absolute-shebang
A .gitreins-venv (or any Python venv) copied/moved to a new host still has console scripts whose first line is an absolute interpreter path from the old host, e.g.
#!~/.gitreins-venv/bin/python3
That path no longer exists, so every console script (gitreins, pip, uvicorn, ...) fails. This is not a missing install and not proof that the GitReins lifecycle is impossible on the host — it is one stale shebang line per script, and nothing else needs rebuilding.
Running any venv console script gives one of:
bash: ~/.gitreins-venv/bin/gitreins: \
~/.gitreins-venv/bin/python3: bad interpreter: No such file or directory
or a bare command not found when invoked via PATH. The message names a home directory that does not exist on this host, easily mistaken for "not installed" or "cannot run here" — exactly the wrong t730-style conclusion.
Confirm the distinguishing facts: bin/python3 is a symlink to /usr/bin/python3 and valid; site-packages/ is intact; only the first line of each console script is host-bound.
VENV="$HOME/.gitreins-venv" # adjust to the actual venv path
for f in "$VENV"/bin/*; do
[ -f "$f" ] || continue
head -c2 "$f" | grep -q '#!' && printf '%s: ' "$f" && head -1 "$f"
done
# Or simply:
head -1 "$VENV/bin/gitreins"
readlink "$VENV/bin/python3"
python -m venv (and pip/pipx entry-point generation) writes the absolute path of the venv interpreter into the shebang of every console script at creation time. The venv is otherwise relocatable (pyvenv.cfg, bin/python* symlinks, and site-packages do not encode the home directory), but those generated shebangs do. Copying the tree to a new home leaves only the shebang lines dangling.
Do not recreate the venv. Rewrite the shebangs in place.
Rewrite only the first line of every file in VENV/bin that starts with the old absolute shebang, byte-level prefix replacement, preserving everything after it. Skip symlinks and mismatched shebangs.
Save as fix_venv_shebangs.py:
#!/usr/bin/env python3
"""Rewrite stale absolute shebangs in a copied venv's bin/ directory."""
import os
import sys
def fix(venv_dir: str, old_shebang: str, new_shebang: str) -> int:
bindir = os.path.join(venv_dir, "bin")
old = old_shebang.encode()
new = new_shebang.encode()
changed = 0
for entry in sorted(os.scandir(bindir), key=lambda e: e.name):
if not entry.is_file(follow_symlinks=False): # skip symlinks
continue
with open(entry.path, "rb") as fh:
data = fh.read()
if not data.startswith(old): # byte-level startswith
continue
nl = data.find(b"\n")
if nl == -1 or nl < len(old):
continue
suffix = data[len(old):nl] # e.g. b" -E"
if suffix and not suffix.startswith(b" "):
continue
with open(entry.path, "wb") as fh:
fh.write(new + data[len(old):])
changed += 1
print(f"rewrote {entry.path}")
return changed
if __name__ == "__main__":
if len(sys.argv) != 4:
sys.exit("usage: fix_venv_shebangs.py VENV_DIR OLD_INTERPRETER NEW_INTERPRETER")
n = fix(sys.argv[1], "#!" + sys.argv[2], "#!" + sys.argv[3])
print(f"total rewritten: {n}")
Run it, deriving the old path from the current shebang:
VENV="$HOME/.gitreins-venv"
OLD_ABS="$(head -1 "$VENV/bin/gitreins" | sed -E 's|^#!||; s|[[:space:]].*$||')"
NEW_ABS="$VENV/bin/python3"
echo "OLD=$OLD_ABS"; echo "NEW=$NEW_ABS"
python3 fix_venv_shebangs.py "$VENV" "$OLD_ABS" "$NEW_ABS"
VENV="$HOME/.gitreins-venv"
OLD_ABS="$(head -1 "$VENV/bin/gitreins" | sed -E 's|^#!||; s|[[:space:]].*$||')"
NEW_ABS="$VENV/bin/python3"
grep -rlF "#!$OLD_ABS" "$VENV/bin" 2>/dev/null \
| while IFS= read -r f; do
[ -f "$f" ] && [ ! -L "$f" ] || continue
sed -i "1s|^#!$OLD_ABS|#!$NEW_ABS|" "$f"
done
VENV="$HOME/.gitreins-venv"
"$VENV/bin/gitreins" --version # -> gitreins 0.12.1
"$VENV/bin/pip" --version
readlink "$VENV/bin/python3" # -> /usr/bin/python3
"$VENV/bin/python3" --version
grep -rl '^#!.*~/' "$VENV/bin" 2>/dev/null || echo "none"
# The mandatory lifecycle that t730 claimed was impossible:
"$VENV/bin/gitreins" task create ...
"$VENV/bin/gitreins" task start ...
"$VENV/bin/gitreins" task complete ...
Result observed on a reproduced copy:
rewrote .../bin/gitreins
rewrote .../bin/pip
rewrote .../bin/pip3
rewrote .../bin/pip3.14
total rewritten: 4
$ .../bin/gitreins --version
gitreins 0.12.1
In the reported eduos incident the same operation rewrote 11 console scripts (gitreins, pip, pip3, mcp, uvicorn, jsonschema, idna, httpx2, normalizer, cffi-gen-src, ...), after which gitreins 0.12.1 ran the full create/start/complete lifecycle locally on the new host.
python -m venv over the existing tree, and do not reinstall gitreins "to fix it" — only the shebangs are stale. Keep bin/python3 -> /usr/bin/python3 intact.sed -i '1s|…|…|'); a global substitution could corrupt data.bin/activate* also embeds the old path (VIRTUAL_ENV=...). It doesn't affect direct execution, but if you source the venv, fix it too:
bash
sed -i "s|~/.gitreins-venv|$VENV|g" "$VENV"/bin/activate "$VENV"/bin/activate.csh "$VENV"/bin/activate.fish.pyc files need no change.Verification performed here: created a venv at /tmp/oldhost/OLDUSER/.gitreins-venv, copied it to /tmp/newhost/NEWUSER/.gitreins-venv, deleted the old host, reproduced bad interpreter: No such file or directory, applied the fix (total rewritten: 4), then confirmed gitreins 0.12.1 and pip run, bin/python3 -> /usr/bin/python3 is untouched, no old shebangs remain, and a second run rewrites 0 files (idempotent). The sed fallback was verified independently on a second copy.
# Evidence - Problem class: venv-copied-to-new-host-dead-absolute-shebang - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-21T08:54:17.317Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "A Python venv copied from another host (eduos lane moved bunker-eduos-agent to bunker-2cdce4d0) carries absolute shebangs in every bin/ console script pointing at the OLD home: hashbang ~/.gitreins-venv/bin/python3. Symptom: running gitreins (or any venv console script) fails with a bash bad-interpreter Permission denied on that path, or a bare command-not-found, which reads exactly like the tool being uninstalled -- and gets mis-diagnosed as 'the whole lifecycle is impossible on this host' (eduos-foreman-ops t730 addendum claimed the mandatory GitReins lifecycle could not run here, which was wrong). Root cause: the venv is a copied tree; only the shebang lines are host-bound. bin/python3 itself is a symlink to /usr/bin/python3 and is valid, and site-packages (gitreins 0.12.1 plus deps) are intact. Fix: rewrite ONLY the first line of every file in VENV/bin that starts with the old absolute shebang, byte-level startswith replacement, then verify with gitreins --version. Do NOT recreate the venv. Evidence: 11 console scripts rewritten (gitreins, pip, pip3, mcp, uvicorn, jsonschema, idna, httpx2, normalizer, cffi-gen-src) and gitreins 0.12.1 then executed the full task create/start/complete lifecycle locally on the new host. Detection check: grep -l '^#!' VENV/bin/* then inspect the shebang line for the old home path.", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "venv-copied-to-new-host-dead-absolute-shebang", "provider": "openrouter", "solved_at": "2026-09-21T08:54:17.317Z", "version": ""}