Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions adoption/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,26 @@ retain that expected outcome explicitly. For final retirement use
that unit. Keep its data directories. The shared MCPorter daemon is not an
owned disposable service; do not stop it to clean up another component.

Added after `v2026.09.26.2`: a daily user timer keeps the next session's
currency notice current without a check at startup.
[`stack-currency.service`](templates/systemd/stack-currency.service) runs
`python3 scripts/currency_due.py`, which runs the receipt, pin and saturation
checks and writes `${XDG_STATE_HOME:-~/.local/state}/native-agent-stack/currency-due.json`
(mode 0600) only while something is due; a SessionStart hook prints its one
line ([decision](../docs/decisions/2026-09-30-session-currency-notice.md)).
Render the service from the live clone, verify both units, enable
[the timer](templates/systemd/stack-currency.timer) and read the current report;
the service file's header covers `PATH` on another host:

```sh
sed 's#@REPOSITORY@#%h/code/native-agent-stack-live#g' adoption/templates/systemd/stack-currency.service > ~/.config/systemd/user/stack-currency.service
cp adoption/templates/systemd/stack-currency.timer ~/.config/systemd/user/
systemd-analyze --user verify ~/.config/systemd/user/stack-currency.service ~/.config/systemd/user/stack-currency.timer
systemctl --user daemon-reload
systemctl --user enable --now stack-currency.timer
python3 scripts/currency_due.py --dry-run
```

Foreground tools should close through their native exit path. For a child
started by the qualification shell, record its PID, verify its identity, send
SIGTERM if needed and `wait` for that same child. Record its exit status and
Expand Down
44 changes: 44 additions & 0 deletions adoption/templates/systemd/stack-currency.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Drafted, not run: no host has loaded, enabled or started this unit (the worktree that authored it made no host
# changes). stack-currency.timer starts it once a day. It has no [Install] section, matching this directory's
# timer-triggered oneshot convention (codex-broker-reaper.service, host-requests-workstation.service). Why a timer
# and a due-file rather than a check at session start: docs/decisions/2026-09-30-session-currency-notice.md.
#
# @REPOSITORY@ is the checkout that holds scripts/currency_due.py. On the workstation that is the live clone,
# %h/code/native-agent-stack-live, as for credential-boot-receipt.service; never the working checkout, whose
# revision moves, and never a build worktree, which a merge deletes. Substitute it before installing, as for the
# other @REPOSITORY@ templates in this directory, and verify both units together (adoption/lifecycle.md):
# sed 's#@REPOSITORY@#%h/code/native-agent-stack-live#g' adoption/templates/systemd/stack-currency.service > ~/.config/systemd/user/stack-currency.service
# cp adoption/templates/systemd/stack-currency.timer ~/.config/systemd/user/
# systemd-analyze --user verify ~/.config/systemd/user/stack-currency.service ~/.config/systemd/user/stack-currency.timer
#
# The run makes no network call and writes nothing into the checkout. scripts/currency_due.py runs
# receipt_staleness.py, adoption_status.py --pinned-versions and saturation_ledger.py --report, then writes
# $XDG_STATE_HOME/native-agent-stack/currency-due.json (~/.local/state/... when XDG_STATE_HOME is unset; mode 0600)
# when something is due and removes it otherwise. Its --network option (runtime-worker skill pins through gh api)
# stays off here. A flag added to ExecStart changes the notice: the command that ends the due-file's summary_line
# repeats --network and a non-default --sweep-cadence-days, so it names the same flags as ExecStart (tests/
# test_currency_due.py checks that), and a skill check that cannot fetch leaves an earlier due-file in place.
#
# PATH: adoption_status.py --pinned-versions finds each version probe with shutil.which, and the user manager's own
# PATH lacks the ecosystem bin directory, so without this line every probe would be reported unchecked and
# pins_behind would read 0 (on the workstation on 2026-09-30 all six exec probes of the default profile resolved
# only there). On another host, use the directories that hold its pinned tools.
# PYTHONDONTWRITEBYTECODE=1 keeps this interpreter and the three it starts from writing __pycache__ into the
# checkout; -B on ExecStart would not reach the child interpreters.
# TimeoutStartSec= covers the script's own per-check bounds (120 s + 120 s + 600 s for the version probes); a
# oneshot has no start timeout by default (systemd.service(5)). UMask=0077 and NoNewPrivileges=true follow this
# directory's other oneshots.
[Unit]
Description=Write the stack currency due-file for the next session (read-only checks, no network)

[Service]
Type=oneshot
UMask=0077
NoNewPrivileges=true
Nice=10
IOSchedulingClass=best-effort
IOSchedulingPriority=7
TimeoutStartSec=900
Environment=PATH=%h/.local/share/codex-ecosystem/bin:%h/.local/bin:/usr/local/bin:/usr/bin:/bin
Environment=PYTHONDONTWRITEBYTECODE=1
ExecStart=/usr/bin/python3 @REPOSITORY@/scripts/currency_due.py
20 changes: 20 additions & 0 deletions adoption/templates/systemd/stack-currency.timer
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Drafted, not run: see stack-currency.service in this directory for the placeholder, PATH and deployment notes
# that also apply here.
[Unit]
Description=Daily trigger for the stack currency due-file

[Timer]
# daily is *-*-* 00:00:00 local time (systemd.time(7)). Persistent=true catches up once after a day on which the
# host or the user manager was down: the service "is triggered immediately if it would have been triggered at
# least once during the time when the timer was inactive", and the setting "only has an effect on timers
# configured with OnCalendar=" (systemd.timer(5), systemd 255.4-1ubuntu8.17 on the workstation). On WSL, where the
# distribution often stops, that catch-up is what keeps the due-file at most a day old. RandomizedDelaySec=15m
# spreads the start, the catch-up run included ("Such triggering is nonetheless subject to the delay imposed by
# RandomizedDelaySec="), so it does not start together with every other catch-up at boot.
OnCalendar=daily
Persistent=true
RandomizedDelaySec=15m
Unit=stack-currency.service

[Install]
WantedBy=timers.target
Loading
Loading