Skip to content

Headless sessions leave smoke-test files in /tmp #23

Closed

Description

@JacobStephens2

What happened

In the vacation#5 acceptance run (#12), the implement session smoke-tested the built jar by writing a fixture docs dir and a server log to /tmp:

java -jar target/vacation-0.1.0-SNAPSHOT.jar --server.port=18085 --vacation.docs-dir=../../../../../tmp/vac5docs > /tmp/vac5.log 2>&1 ...

thirdshift removed the worktree afterwards, but /tmp/vac5docs/ and /tmp/vac5.log were left behind. The Run's cleanup can't catch these because the session made them outside the worktree.

Log: ~/.thirdshift/logs/JacobStephens2-vacation-issue-5-20260925T123845Z-implement.jsonl

Possible fix

Have the implement skill/prompt tell the session to put scratch files under a git-ignored dir inside the worktree, or give the session a per-Run temp dir (e.g. TMPDIR) that thirdshift removes along with the worktree.

Activity

  1. JacobStephens2 commented on Sep 25, 2026

    @JacobStephens2
    OwnerAuthor

    This was generated by AI during triage.

    Agent Brief

    Category: enhancement
    Summary: Give every Run's agent sessions their own temp directory, removed when the Run ends, and tell the sessions to put scratch files there instead of /tmp

    Current behavior:
    Agent sessions start from session::run with thirdshift's own environment, so TMPDIR is whatever the user has (usually unset, which means /tmp). No prompt or Factory skill says where scratch files belong. Sessions write smoke-test fixtures, server logs and PR body drafts straight to /tmp (for example, /tmp/vac5docs/, /tmp/vac5.log and /tmp/pr5-body.md from the vacation#5 Run). Cleanup removes only the worktree, the local Issue branch and the temporary plugin directory, so those files stay behind. The README's "What sessions leave behind" section calls this "by design".

    Desired behavior:

    • Each Run creates one temp directory for its agent sessions, under thirdshift's own temp location (honoring the TMPDIR thirdshift was started with), with a recognizable prefix such as thirdshift-tmp-.
    • Every agent session in the Run (implement, continuation, conflict Repair, CI-fix Repair) runs with TMPDIR set to that directory.
    • The directory is outside the worktree. The Failed run path commits everything in the worktree, so scratch files must never land there.
    • The directory and everything in it are removed when the Run ends, on every path the plugin directory is removed on: success, Failed run, and interrupt.
    • Each session is told, through the prompts or the Factory skills (whichever fits better), to put temporary and scratch files (fixtures, logs, drafts, downloaded one-off tools) under $TMPDIR and never write to /tmp directly. The skills are namespaced plugin copies (ADR-0001), so an instruction in them must hold up for headless sessions.
    • The README's "What sessions leave behind" section describes the new behavior: scratch files go to a per-Run temp directory that cleanup removes. This is best-effort, because auto mode can't stop an agent from writing elsewhere. Anything written outside it, such as toolchains installed under ~, still stays.

    Key interfaces:

    • session::run(kind, worktree, plugin_dir, prompt, log): needs the Run's temp directory (a new parameter, or a small struct bundling the Run's session environment) and sets TMPDIR on the claude command.
    • A per-Run temp directory owner shaped like Plugin (a tempfile::TempDir that is removed on drop), created alongside the plugin where sessions are set up.
    • The prompt builders in the prompt module (fresh, continuation, conflict_repair, ci_fix_repair), or the Factory implement skill, carry the scratch-file instruction.

    Acceptance criteria:

    • An integration test (using the fake claude in tests/fakes/) in which the fake session writes a file into $TMPDIR shows that $TMPDIR is not the thirdshift process's own TMPDIR and not inside the worktree, and that the file and its directory are gone after a successful Run (assert_cleaned_up still passes).
    • The same holds for a Failed run, and the scratch file is not in the commit pushed by the Failed run path.
    • Repair sessions get the same TMPDIR as the implement session in the same Run.
    • Every prompt an agent session is started with (or the skill it invokes) tells the session to use $TMPDIR for scratch files and not /tmp; a test asserts this for the prompts, if the instruction lives there.
    • The README's "What sessions leave behind" section is updated as described above.
    • cargo test and cargo clippy pass.

    Out of scope:

    • Stopping sessions from installing toolchains or writing under ~ (for example, ~/.local/jdk/). That stays documented as by design.
    • Sandboxing or blocking writes to /tmp (for example, with namespaces or permission rules).
    • Cleaning up files earlier Runs left in /tmp.
    • A git-ignored scratch directory inside the worktree (rejected: the Failed run path would commit it).
  2. added
    enhancementNew feature or request
    ready-for-agentFully specified, ready for an AFK agent
    and removed
    needs-triageMaintainer needs to evaluate this issue
    on Sep 25, 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

    enhancementNew feature or requestready-for-agentFully specified, ready for an AFK agent

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions