Skip to content

Command logs: each command keeps a file of what it printed, in a log tree under logs.dir #259

Closed

Description

@JacobStephens2

This was generated by AI from a design session.

Problem Statement

What a thirdshift command prints on stderr and stdout lives only in the terminal it ran in, or in whatever file a crontab line redirects it to. When a Spec run started by hand ended in a Failed run (could not start the Run for #248: No such file or directory), there was no file holding its output to look back at: only the Session logs, which are agent transcripts and say nothing about thirdshift's own steps.

The cron recipes make it worse in two ways. A crontab line's redirect is the only record of a scheduled pass, so a line that breaks before thirdshift starts loses everything, and one shared log file per line mixes every pass together with no date on its lines. And the Session logs sit flat in ~/.thirdshift/logs/ with UTC stamps, so matching a log to when something happened means converting from UTC by hand, and there is no easy way to show another engineer "this is what a Pickup run looks like" or answer "what has my Pickup run been doing lately?".

Solution

Every Run, Spec run, Architect run and Pickup run keeps a Command log: one file holding everything it printed, stderr and stdout in the order they were printed, written by thirdshift itself while the terminal still shows everything.

logs.dir (default ~/.thirdshift/logs) becomes the root of a log tree:

~/.thirdshift/logs/
├── sessions/                 Session logs, flat
└── commands/
    ├── architect/            <owner>-<repo>-<stamp>.log
    ├── pickup/               <owner>-<repo>-issue-<n>-<stamp>.log
    └── issue/                <owner>-<repo>-issue-<n>-<stamp>.log

The folder is the command that was typed: thirdshift architect, thirdshift pickup, or thirdshift <Issue URL> (a Run or a Spec run). Stamps are in local time with the UTC offset, such as 20261003T120000-0400, for Command logs and Session logs alike. A command and every Session log under it share one stamp, so they can be found from each other.

A command's first progress line names the date and offset, so a crontab line's own catch-all log (now commands/<kind>/cron.log in the README recipes, #316) reads as a dated list of passes.

User Stories

  1. As a thirdshift user, I want each Run I start by hand to keep a file of everything it printed, so that I can read what happened after the terminal is gone.
  2. As a thirdshift user, I want a Spec run's Command log to include its Tickets' relayed lines, so that one file tells the whole Spec run.
  3. As a thirdshift user, I want a Pickup run's Command log to cover the Run or Spec run it dispatched, so that one pass is one file.
  4. As a thirdshift user, I want an Architect run's Command log to cover the run its plan was dispatched as, so that one night is one file.
  5. As a thirdshift user, I want a Base fix's lines in the Command log of the Run that started it, so that I don't hunt for a second file.
  6. As a thirdshift user, I want a Pickup run or Architect run that was skipped before doing any work to keep no Command log, so that the commands/ folders list only passes that did something.
  7. As a thirdshift user, I want Command logs sorted into a folder per command, so that I can show another engineer what each kind of command looks like.
  8. As a thirdshift user, I want ls -t ~/.thirdshift/logs/commands/pickup | head to list the recent passes that took an issue, so that I can see what my scheduled Pickup run has been doing.
  9. As a thirdshift user, I want the file names in local time with the UTC offset, so that I can tell when a command ran without converting from UTC, even on the night the clocks go back.
  10. As a thirdshift user, I want the time zone to be the machine's, overridable with TZ, so that thirdshift agrees with date, ls -l and the cron journal.
  11. As a thirdshift user, I want a command's Command log and its Session logs to share one stamp, so that I can find a pass's transcripts from its Command log and back.
  12. As a thirdshift user, I want Session logs in sessions/ with the same local stamp, so that the whole tree uses one convention.
  13. As a thirdshift user, I want lines printed before a Command log's name is known (a Pickup run's "passed over" lines, before it takes an issue) to be in the file, so that the file starts at the command's first line.
  14. As a thirdshift user, I want a progress line logging this command to <path>, so that I know where the Command log is while the command runs.
  15. As a thirdshift user, I want a Failed run's output to end with the Command log's path next to its most recent Session log's, so that I know where to start reading.
  16. As a thirdshift user, I want a Command log: line in the Run notification, so that the email points straight at what happened.
  17. As a thirdshift user, I want a command's first progress line to name the date and offset, so that a crontab line's catch-all log can be read across days.
  18. As a thirdshift user, I want a Command log that can't be written to be a warning: line and nothing more, so that logging can never fail a Run.
  19. As a thirdshift user, I want logs.dir to stay my one log setting, now the root of the tree, so that one line in the User config moves all of it.
  20. As a thirdshift user, I want my existing flat Session logs left where they are, so that an update never moves or deletes my files.
  21. As a thirdshift user, I want setup, email-test, update, version and help to keep no Command log, so that only the commands that do work leave a record.

Implementation Decisions

  • The command's start stamp is made once and given to everything under it: the Command log's name, and every Session log's, including those of a Run or Spec run a Pickup run or Architect run dispatches, and of a child Run (a Ticket's Run in a Spec run, a Base fix), which today takes its own. Format: %Y%m%dT%H%M%S%z in local time. The existing UTC ...Z stamp goes.
  • The Logs type that names Session logs puts them under <logs.dir>/sessions/, created if missing.
  • One Command log per top-level command. The process the user or cron started writes it. A child thirdshift (a Ticket's Run, a Base fix) writes none: its lines already reach the parent's stderr through the relay, and from there the parent's Command log. A dispatched Run or Spec run runs inside the Pickup run's or Architect run's process and writes to that command's file.
  • What goes in: every line thirdshift writes to stderr through the progress module, relayed child lines included, and what it writes to stdout (the pull request URL), in the order written. The terminal output is unchanged.
  • When the file is created: as soon as its name is known. A Run or Spec run knows at once. A Pickup run knows once it has taken an issue, and an Architect run once it is past its skip checks. Lines printed before then are held in memory and written first. A command that ends skipped before then never creates the file.
  • Naming: commands/issue/<owner>-<repo>-issue-<n>-<stamp>.log for thirdshift <Issue URL>, commands/pickup/<owner>-<repo>-issue-<n>-<stamp>.log for a Pickup run that took issue n, commands/architect/<owner>-<repo>-<stamp>.log for an Architect run. The repository is in the name because one logs.dir serves every repository on the machine.
  • The dated first line: a command's first progress line carries the date and offset, such as thirdshift: 12:00:01 Pickup run starting, 2026-10-03 -0400. Later lines keep the HH:MM:SS stamp they have now. The first line is the same whether or not a Command log is kept.
  • Where the path is shown: a progress line logging this command to <path> once the file is created; after a Failed run's last lines, beside the most recent Session log's path; and a Command log: line in the Run notification body, beside Session log:.
  • Failure to write (the folder can't be created, the disk is full) is one warning: line on stderr. The command carries on with the same outcome, stdout and exit code, as a Run notification that can't be sent does today. Later lines don't repeat the warning.
  • logs.dir keeps its validation and meaning of "where logs go". Its comment in the User config written by setup, and its help text, say it is the root of sessions/ and commands/.
  • Docs: the README's Logs section shows the new tree and names, and the Run notification body list gains the Command log: line. CONTEXT.md already defines Session log and Command log (A whole sample crontab, with a log folder per command #316); keep them true. No note about moving from the old layout: thirdshift has one user, who moves their own files.

Testing Decisions

  • One seam: the real thirdshift binary run by the test Scenario, with fake gh and claude and a temporary HOME, as the existing integration tests do. Tests assert on files under the temporary logs.dir, on stderr and stdout, and on the email the fake Resend receives. No new seam inside the code.
  • Tests set TZ to a fixed zone so stamps and offsets are exact, including a negative offset.
  • Good tests assert what a user would see: which files exist and their names, that a Command log's contents equal what the command printed in order, that the notification carries the path. Not how the output is captured.
  • Cases to cover: a hand-started Run; a Spec run with Tickets, whose Ticket lines appear in the Spec run's Command log and whose Ticket Runs keep none; a Pickup run that takes an issue (its "passed over" lines before the take are in the file); a skipped Pickup run and a skipped Architect run (no Command log); an Architect run that dispatches a run; Session logs under sessions/ sharing the command's stamp; the logging this command to line; a Failed run's ending naming the Command log; the Command log: line in a Run notification; the dated first line; an unwritable commands/ folder giving one warning: and an unchanged outcome and exit code.
  • Prior art: the integration tests on Pickup runs, Architect runs, Spec runs, Failed runs, Run notifications and progress lines, and the logs.dir tests on the User config.

Out of Scope

  • Moving or renaming existing Session logs, or any migration note.
  • Deleting or rotating old logs.
  • A thirdshift log command for listing recent passes.
  • A time-zone setting in the User config: the zone is the machine's, or TZ.
  • Separate settings for the sessions/ and commands/ folders.
  • Changing the crontab recipes, which A whole sample crontab, with a log folder per command #316 does.
  • Timestamps inside a Session log's transcript.

Further Notes

Design settled in a grilling session on 2026-10-02/03. Related: #303 (a Pickup run that takes a finished Spec on every pass) is the kind of thing a Pickup run's folder makes visible at a glance.

Activity

  1. changed the title [-]log stderr and stdout from thirdshift run into .thirdshift/logs[/-] [+]Command logs: each command keeps a file of what it printed, in a log tree under logs.dir[/+] on Oct 3, 2026
  2. added
    ready-for-agentFully specified, ready for an AFK agent
    in-progressA Claim: thirdshift has taken this issue
    and removed
    ready-for-agentFully specified, ready for an AFK agent
    on Oct 3, 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 request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions