SQLite needs write access to the repo directory to create journal files
alongside pipekit.db. Fixed by setting group pipekit + g+w on the
directory itself only (not recursive).
Driver registration now matches existing rows by kind before falling
back to name, so re-deploys update the correct row regardless of what
name was used at initial registration.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Avoids stripping write access from the developer. The service only needs
to own pipekit.db (runtime writes) and .venv (created as pipekit).
Source code stays owned by whoever ran deploy.sh.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
deploy.sh now prints each step with what it's doing, adds the invoking
user to the pipekit group automatically, uses --home-dir /nonexistent
for the system user, and passes --no-cache-dir to pip to suppress the
home directory warning.
cli.py: removed the kind-based early-exit in drivers register that was
short-circuiting before the upsert logic, so re-running deploy now
correctly updates existing driver rows rather than printing "already
registered". Also removed the now-unused --force flag.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Scheduling: cron-based group runs via a daemon thread (scheduler.py)
started at API startup. Schedules managed inline on the group edit form.
last_fired_at persisted before run to prevent double-fire on restart.
Requires croniter (added to requirements.txt); DB migration adds
last_fired_at column to schedule table.
Deploy: deploy.sh now creates the pipekit system user, chowns the repo,
builds the venv as pipekit, and installs/enables the systemd unit.
systemd/pipekit.service is now a production-ready unit (User=pipekit
uncommented). pipekit secrets set preserves existing file permissions
instead of resetting to 0600. Driver registration is now idempotent
(upsert via get_driver_by_name + update_driver).
Docs: CLAUDE.md and SPEC.md updated to reflect groups, scheduling,
scheduler-in-API-process architecture, TUI deferred (not dropped),
stop-on-failure tradeoff, jrunner as prerequisite, and deploy flow.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
The tracked launcher now checks for .venv/bin/python3 under the repo and
uses it if present, else falls back to system python3. Works pre-deploy
(no venv) and post-deploy (venv exists) without being modified. Deploy
no longer regenerates the file, so `git pull` on a deployed box won't
conflict with the launcher.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Without -H, sudo keeps HOME pointed at the invoking user, so pip running
as root tries to write to /home/<user>/.cache/pip and disables caching
with a warning. -H resets HOME to /root while -E preserves the rest.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
deploy.sh is the idempotent rollout path: venv + deps, launcher,
/etc/pipekit/secrets.env skeleton (mode 0600), schema init, and
auto-register of every JDBC driver shipped with jrunner. systemd
unit is a template, not auto-installed — user copies it when ready
to cut over.
`pipekit secrets {list,set,unset}` manages /etc/pipekit/secrets.env
with atomic 0600 writes so passwords don't need sudoedit. Prompted
input by default; positional value allowed for scripting.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>