Skip to content

re.py in the OpenCode tmp folder shadows Python's standard re module #132

Closed

Description

@dezren39

Summary

A file named re.py sits in the shared OpenCode temp folder ~/.local/share/opencode/tmp/opencode/. Python puts the working directory (for python -c and -m) and the script's own directory on sys.path, so any Python process started from that folder imports this file as the standard re module and fails at startup.

Reproduction

Observed on macOS with nix Python 3.14.7 (/nix/store/...-python3-3.14.7):

cd ~/.local/share/opencode/tmp/opencode
python3 -c "import json"

Result (abridged):

File ".../opencode/re.py", line 25, in <module>
    import logging
...
AttributeError: module 're' has no attribute 'escape' (consider renaming '.../opencode/re.py' since it has the same name as the standard library module named 're' and prevents importing that standard library module)

uv run with a script inside that folder fails the same way, because the script's directory is put first on sys.path.

The file

  • Path: ~/.local/share/opencode/tmp/opencode/re.py, 8,357 bytes, modified 2026-10-18 02:04.
  • Contents: an Alembic helper module from the operations-portal repository (its docstring describes helpers for Alembic revisions). It is not an OpenCode file. How it got into the shared temp folder is unknown.

Impact

One command in an affected session failed before it ran. The error looked like a broken Python install until the traceback named the file.

Workaround

python3 -I (isolated mode) keeps the working directory and the script directory off sys.path. Running from another directory also works. The file was left in place because it is not ours to delete.

Requests

  1. Find what writes module-named files (re.py, or any other standard library module name) into the shared tmp root, and stop it.
  2. Keep the shared tmp root free of Python modules. A per-session or per-tool subdirectory is enough.
  3. Document python3 -I for tools that run Python from the tmp folder.

Environment

  • macOS (darwin), uv, nix Python 3.14.7
  • OpenCode tmp folder: ~/.local/share/opencode/tmp/opencode (pre-created, approved for external access)

Acceptance criteria

  • The writer of stdlib-named files (re.py) into the shared tmp root is identified and stopped, or proven external and a guard/cleanup is in place.
  • The shared tmp root contains no Python modules named after standard-library modules.
  • Verification: python3 -c "import json" run from inside the tmp root succeeds.

Activity

  1. dezren39 commented on Oct 24, 2026

    @dezren39
    Author

    Triage update (issue-sweep-rotating, 2026-10-24, on main bca2f2e):

    Investigated request 1 (find what writes module-named files into the shared tmp root):

    • No in-repo writer exists. git grep over the repo finds no code that writes re.py or any Python module into the tmp root. The only tmp writers in core are specifically named temp files (e.g. persistent-pty/binary.bun.ts writes opencode-pty.<pid>.<uuid>.tmp; plugin/vcs/git.ts uses os.tmpdir()/opencode-untracked-<uuid>).
    • The tmp root is shared by design, and agents are directed to it: packages/core/src/instructions/builtins.ts tells the model "Prefer ${global.tmp} over generic system temporary directories... it is pre-created and approved for external access", packages/core/src/filesystem.ts (write path) notes clients stage files in "the server tmp directory, which the model is already told to prefer and permitted to access", and packages/core/src/shell.ts points child TMPDIR/TMP/TEMP at the same directory when OPENCODE_TMPDIR is set.
    • The file itself, per the issue, is an Alembic helper from the operations-portal repository — not an OpenCode artifact. The most consistent explanation is that an agent or tool working in some session wrote it into the advertised scratch directory; OpenCode code did not.

    So there is no in-repo bug to fix for request 1. The remaining requests are a product decision: moving to per-session/per-tool subdirectories (request 2) would change the documented shared-tmp contract above, and request 3 (document python3 -I) only matters for tools run from that directory. Keeping this OPEN for that decision rather than closing it as not-a-bug, so the trade-off is recorded here.

  2. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    source/humanFiled directly by a human
    priority/lowNice to have; do when convenient
    effort/sSmall: expected under 2 hours of work
    area/infraInfrastructure, deployment, and operations
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    on Oct 26, 2026
  3. dezren39 commented on Oct 26, 2026

    @dezren39
    Author

    🤖 Intake review — fleet monitor, 2026-10-26 run

    Still live: no related issue or fix found this run; the file described in the body is an Alembic helper from the operations-portal repo — not an OpenCode file — so the writer is likely tooling that copies/syncs a working tree into the shared tmp root.
    Related: none filed; the workaround (python3 -I, or running from another directory) is recorded in the body.
    Notes / risks: impact so far is one failed command and a misleading traceback, hence priority/low; the risk is recurrence with a worse module name (os.py, json.py).
    Suggested approach: grep session/tooling code paths that write into the tmp root, check mcpx/session scratch handling, and consider a startup sweep that warns on stdlib-named .py files in the tmp root.

  4. added
    queue/claimedA queue worker has claimed the task for this item
    work/assignedAn agent holds this item via the queue (claimed task)
    and removed on Oct 28, 2026
  5. dezren39 commented on Oct 28, 2026

    @dezren39
    Author

    Triage verdict: exposure confirmed, writer external — guard routed (queue task 2071)

    Re-verified on current main b0633cc697760085022fb5656ed92fac9ce49b9c (2026-10-28), updating the 2026-10-24 triage (main bca2f2ecb7), whose no-in-repo-writer conclusion still holds:

    • The exposure is live and by design. packages/core/src/instructions/builtins.ts:43 still directs the model: prefer ${global.tmp} over system temp directories, pre-created and approved. packages/core/src/shell.ts:273 exports that root as TMPDIR/TMP/TEMP to shell commands when OPENCODE_TMPDIR is set. The only other core reference (messaging/vars.ts:218) just returns the path.
    • No in-repo writer, still. Nothing in core writes .py files — or arbitrary-named files — into the tmp root, and no stdlib-collision guard exists (git grep stdlib in packages/core/src: no relevant hits). The re.py in the report is an operations-portal Alembic helper (per the issue body), i.e. external tooling/agent scratch, exactly as the 2026-10-24 triage concluded.
    • That satisfies the first acceptance branch's 'proven external' half; the guard half was missing, so:

    Routing: follow-up small_fix enqueued as queue task 2611 — a warn-only sweep at tmp-root initialization/session start: top-level *.py files whose stem collides with a Python stdlib module name produce a log warning naming the file, the shadowing risk, and the python3 -I workaround; files are never deleted or moved (they may belong to another project). It also adds the python3 -I hint to the builtins tmp guidance (request 3). Tests pin detection (stdlib hit warns, non-stdlib/non-.py/empty root quiet).

  6. 8 remaining items

  7. dezren39 commented on Oct 28, 2026

    @dezren39
    Author

    🤖 Agent note · fix implemented, PR open, parked on CI

    • Agent: repo-worker-opencode (Lane B, job repo-queue-worker-shift-opencode-b)
    • Session / ID: task 2611, shift 2026-10-28 14:21 CDT
    • Outcome: PR fix(core): warn on stdlib-named .py files in the shared tmp root (#132) #748 — fix(core): warn on stdlib-named .py files in the shared tmp root (#132), branch queue/2611-132-stdlib-warn at base b0633cc697.
    • What it does: new packages/core/src/tmp-guard.ts — top-level-only scan of the shared tmp root for .py files whose stem is a Python stdlib module name (CPython 3.14 list); Effect.logWarning naming the file(s), the directory, the shadowing risk, and the python3 -I workaround, once per process per collision set; files are never deleted, moved, or modified. Hooked into InstructionBuiltIns.load() at session start. The builtins tmp guidance now also carries the python3 -I hint (issue request 3), with the pinned expectation in builtins.test.ts updated.
    • Verification (laptop worktree, before push): bun test ./test/tmp-guard.test.ts ./test/instructions/builtins.test.ts from packages/core — 9 pass / 0 fail; bun typecheck from packages/core — clean; oxlint on the 4 changed files — 0 warnings / 0 errors. One test caught a real bug during development (Effect.sync does not catch the readdirSync throw on a missing root; warn now uses Effect.try).
    • State: task 2611 parked until 2026-10-28T20:13Z for PR fix(core): warn on stdlib-named .py files in the shared tmp root (#132) #748 CI; resume brief is on the task. If CI is green, merge per the standing directive and complete the task.
    • Links: PR fix(core): warn on stdlib-named .py files in the shared tmp root (#132) #748 · issue re.py in the OpenCode tmp folder shadows Python's standard re module #132
  8. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    and removed
    queue/claimedA queue worker has claimed the task for this item
    on Oct 28, 2026
  9. dezren39 commented on Oct 28, 2026

    @dezren39
    Author

    Done: implemented, tested, and opened PR #751 (targets main, not merged).

    What changed (all in packages/core):

    • New packages/core/src/tmp-stdlib.ts: top-level-only (never recursive) scan of the tmp root against the stdlib module list; warns via Effect.logWarning naming the file(s) plus the python3 -I workaround; warn-once per tmp root per process; never deletes, moves, or edits files; quiet on clean/missing/unreadable roots.
    • Session.create runs the sweep first (first session use); Global.node added to the Session node deps (yield hoisted to the layer constructor so the create interface is unchanged).
    • Builtins tmp guidance now tells the model to prefer python3 -I when running Python with the tmp root as cwd.
    • Tests: packages/core/test/tmp-stdlib.test.ts (12 tests: stdlib hit, non-stdlib .py ignored, non-.py ignored, top-level-only, empty-root quiet, warn/quiet behaviour, warn-once, files left untouched); builtins expectation updated.

    Test results (packages/core, this machine):

    • bun typecheck (tsgo -b tsconfig.json tsconfig.tests.json): clean.
    • bun test test/tmp-stdlib.test.ts test/instructions/builtins.test.ts: 15 pass, 0 fail.
    • bun test test/session-create.test.ts: 42 pass, 2 fail — both are 5s-timeout flakes in shell-spawning live tests that fail identically on the pristine base tree (verified via stash), unrelated to this change.

    PR: #751

  10. dezren39 commented on Oct 28, 2026

    @dezren39
    Author

    Implemented and opened PR #751 (not merging, per task scope).

    What changed (all in packages/core):

    • New packages/core/src/tmp-stdlib.ts: top-level-only (never recursive) scan of the tmp root against the stdlib module list (194 names from sys.stdlib_module_names); Effect.logWarning names the offending file(s) and points at the python3 -I workaround; warn-once per tmp root per process; never deletes, moves, or edits files; quiet on clean/missing/unreadable roots.
    • Session.create runs TmpStdlib.checkOnce(global.tmp) first (first session use); Global.node added to the Session node deps (service resolved in the layer constructor so the create interface is unchanged).
    • Builtins tmp guidance now tells the model to prefer python3 -I when running Python with the tmp root as cwd.
    • Tests in packages/core/test/tmp-stdlib.test.ts: stdlib-name hit, non-stdlib .py ignored, non-.py ignored, top-level-only scan, empty-root quiet, warn names file + workaround, warn-once, clean-root quiet, and files left untouched. Updated the builtins expectation for the new guidance text.

    Test results (packages/core on this machine):

    • bun typecheck (tsgo -b tsconfig.json tsconfig.tests.json): clean.
    • bun test test/tmp-stdlib.test.ts test/instructions/builtins.test.ts: 15 pass, 0 fail.
    • bun test test/session-create.test.ts test/shell-tmpdir.test.ts: 43 pass, 2 fail — both are 5s-timeout flakes in shell-spawning live tests; I stashed my changes and re-ran on the clean base tree, where the same tests flake, so this is environmental and unrelated.

    PR: #751 (targets main, fixes #132, ready for review, not merged).

  11. dezren39 commented on Oct 28, 2026

    @dezren39
    Author

    Dedupe note (operator, 2026-10-28): two PRs were opened for this issue — lane PR #748 and session PR #751 — from the dispatcher/lane binding gap. Verified overlapping implementations (shared surface: instructions/builtins.ts + test). Closed #751 as the duplicate; PR #748 is canonical (queue-bound lane PR).

  12. added a commit that references this issue on Oct 28, 2026
  13. dezren39 commented on Oct 28, 2026

    @dezren39
    Author

    agent-note:v1 — task 2611 (repo-health-opencode-pilot, lane A, agent repo-queue-worker-shift-opencode)

    The guard branch is landed: PR #748 merged this shift (merge commit ec310fc). PR #751 was the parallel duplicate and stays closed per the operator dedupe note; #748 is canonical.

    Verification before merging: on the laptop at the PR head (5fc0d9c), bun test test/tmp-guard.test.ts test/instructions/builtins.test.ts — 9 pass / 0 fail. CI: typecheck, nix-eval, build (linux/windows) and affected-packages green; unit (linux)/unit (windows) fail only on the two standing TUI input-scope permission tests (log-checked — the same failure on merged PRs #745/#741/#740); the test workflow's e2e jobs were still queued in the runner backlog at merge time.

    All five packet acceptance criteria are met by the merged change (warn-only top-level sweep at session start via InstructionBuiltIns.load, files never touched, quiet on clean roots, python3 -I in the builtins tmp guidance, tests pinning detection). This issue stays open for the two reporter-machine items no repo change can settle: the stray external re.py still sitting in that machine's tmp root (acceptance: tmp root contains no stdlib-named modules) and the python3 -c "import json" verification run from inside that folder.

  14. removed
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    work/assignedAn agent holds this item via the queue (claimed task)
    on Oct 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/infraInfrastructure, deployment, and operationseffort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)meta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/lowNice to have; do when convenientsource/humanFiled directly by a humanstatus:done

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions