contrib: devbox-aware scheduler templates (host-side, docker exec)

On hosts running a long-lived opencode-devbox (or equivalent)
container, mempalace-session lives INSIDE the container, not on
the host. The existing contrib/* templates install a scheduler on
the machine that runs the tool; for the devbox case the scheduler
has to live on the host and reach into the container via
'docker exec'. This was noted in passing in contrib/README.md but
no templates were actually shipped for it.

Adds parallel *-devbox templates for systemd and cron:

contrib/systemd/mempalace-session-devbox.service
  - Type=oneshot, same 2h TimeoutStartSec + low Nice as the direct
    variant.
  - Two Environment knobs (CONTAINER, CONTAINER_USER) default to
    opencode-devbox/developer, overrideable via
    'systemctl --user edit'.
  - ExecCondition checks 'docker ps --filter name= --filter
    status=running' so the unit no-ops cleanly when the container
    is currently down. systemd reports this as a successful
    'condition failed' state — no alert noise across dev cycles
    of teardown/rebuild.
  - ExecStart is plain /usr/bin/docker exec with no shell; systemd
    does the env-var expansion.
  - Stdout/stderr go to journalctl --user -u <unit> (nothing to
    redirect, since docker exec surfaces container output to the
    calling process).

contrib/systemd/mempalace-session-devbox.timer
  - Mon 03:00 Persistent=true RandomizedDelaySec=30m, mirrors the
    direct timer.

contrib/cron/mempalace-session-devbox.cron
  - Equivalent shell-wrapped form for hosts using cron instead of
    systemd. 'docker ps | grep -q .' short-circuits if the container
    isn't running. Log goes to $HOME/.cache/mempalace-session/
    cron-devbox.log on the HOST (outside the container) so it's
    inspectable without dropping into the devbox.

contrib/README.md:
  - Replaces the two-paragraph 'Running inside a container' note
    with a proper section: preconditions, install recipes for both
    the systemd and cron devbox variants, verify/uninstall commands,
    customization via 'systemctl --user edit', behaviour when the
    container is down.
  - Chooser table gains a dedicated row pointing devbox users at
    the *-devbox templates, and mentions the systemd vs cron pick
    for that case.
  - New 'When to pick devbox variants vs direct ones' table covers
    the rare both-installed case (host mempalace AND in-container
    mempalace see separate palaces — they don't cross-pollinate).

Top-level README.md 'Keeping it fresh' subsection gains a quick-start
block for the devbox variant alongside the existing Linux/macOS
quick-starts.

Tested: all four systemd units parse cleanly as INI via
configparser (sections + key=value pairs); validated file sizes
and locations match the layout described in docs. Runtime
validation (systemctl --user enable; actual docker exec) requires
a host with docker + an opencode-devbox container up — deferred
to the user's Mac/Linux boxes.
This commit is contained in:
Joakim Persson
2026-04-30 14:09:15 +00:00
parent 4dcd2959ec
commit 46bcce5a67
5 changed files with 204 additions and 11 deletions
@@ -0,0 +1,38 @@
# Sample crontab entry for mempalace-session inside a long-running
# opencode-devbox container, scheduled from the DOCKER HOST (not inside
# the container — containers typically don't run cron).
#
# Host-side cron runs `docker exec` against the running container once a
# week. Requires:
# - Container is long-lived (compose up, restart: unless-stopped, etc.)
# - User running cron has rights to talk to the docker socket
# (usually means being in the `docker` group, or on macOS having
# Docker Desktop running for the current login session)
# - `mempalace-session` is already installed inside the container
# (opencode-devbox bakes it in via cli_utils → mempalace-toolkit)
#
# Install:
# # Replace CONTAINER / USER / HOST_USER to match your setup, then:
# (crontab -l 2>/dev/null; cat contrib/cron/mempalace-session-devbox.cron) | crontab -
#
# Adjust CONTAINER and USER below before installing.
#
# Design notes:
# - `docker ps --filter name=... --filter status=running` makes the job a
# no-op if the container is down, so the timer is harmless on machines
# where the devbox is currently stopped. No mail/warning/noise.
# - Exec runs as `developer` (the opencode-devbox user). Change `-u`
# if you named your user something else.
# - Output is captured in a log under the HOST user's home, not inside
# the container — so you can inspect it from outside.
CONTAINER=opencode-devbox
CONTAINER_USER=developer
# HOST_USER is used only to anchor the log path. Replace with your host
# username (or leave the $HOME substitution if your cron implementation
# expands it — most do).
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# m h dom mon dow command
0 3 * * 1 /bin/sh -c 'docker ps --filter "name=^/${CONTAINER}$" --filter "status=running" -q | grep -q . && docker exec -u "${CONTAINER_USER}" "${CONTAINER}" mempalace-session >> "$HOME/.cache/mempalace-session/cron-devbox.log" 2>&1'