Skip to content

Add exec, config, resource limits and CLI conveniences - #8

Merged
dafioram merged 1 commit into
mainfrom
claude/upbeat-cannon-w8n2qa-features
Oct 4, 2026
Merged

dafioram merged 1 commit into
mainfrom
claude/upbeat-cannon-w8n2qa-features

Conversation

@dafioram

@dafioram dafioram commented Oct 4, 2026

Copy link
Copy Markdown
Owner

PR 2 of 3 in this round, stacked on the tests PR (#7). Merge that one first; GitHub then retargets this PR to main.

Changes

Feature Details
Default to . systemd-compose up works inside a project folder. systemd-compose <folder> <command> still works. A folder whose name matches a command needs a path: ./logs up.
-h / --help Prints a full command summary and exits 0. Previously it errored.
logs options With no options it still follows the logs. Any options are passed straight to journalctl: logs -n 200, logs --since today -f.
down keeps the venv down stops the app and removes the service. down --volumes (-v) also deletes the venv, like Docker. Unknown options are rejected before anything is removed.
exec systemd-compose exec python manage.py migrate runs a command the way the service runs the app: venv first on PATH, .env variables, inside APP_DIR. It returns the command's exit code.
config Prints the service file that run would write and says whether the installed one is out of date. Changes nothing.
Resource limits MEMORY_MAX="300M" / CPU_QUOTA="50%" in config.env become MemoryMax= / CPUQuota=. status shows the memory limit.
Stricter arguments Commands that take no options now reject extra arguments, so a typo like stop --all fails instead of being ignored.

Behaviour change: down no longer deletes the venv. Use down --volumes for the old behaviour. The README is updated.

Resource limit details

While testing I found that MemoryMax= and CPUQuota= take % literally. The %→%% escaping used for the other settings would have produced CPUQuota=50%%, which systemd silently ignores. Two things handle this:

  • Limit values are validated against strict patterns, then written without escaping.
  • A test runs systemd-analyze verify on the generated file and asserts CPUQuotaPerSecSec: 500ms.

systemd also silently ignores invalid limits, which is another reason for validating them up front. run warns when the user manager doesn't have the memory/cpu cgroup controllers, because the limit wouldn't be enforced there.

Testing

  • 19 new tests (68 total, all passing), plus ShellCheck clean.
  • Mutation check: putting the % escaping back on the limit values makes 2 tests fail.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KdsNJV9e2ktZ9gF5kmczEu


Generated by Claude Code

- The project folder is optional: `systemd-compose up` works in the
  current folder. `systemd-compose <folder> <command>` still works.
- -h/--help/help print a full usage summary and exit 0.
- logs: follows by default; extra options go straight to journalctl
  (`logs -n 200`, `logs --since today -f`).
- down keeps the venv; `down --volumes` (or -v) also deletes it.
  Unknown options are rejected before anything is removed.
- exec: run a one-off command like the service runs the app (venv
  first on PATH, .env variables, inside APP_DIR), e.g.
  `exec python manage.py migrate`. Returns the command's exit code.
- config: print the service file `run` would write and say whether the
  installed one is out of date. Changes nothing.
- MEMORY_MAX / CPU_QUOTA in config.env set MemoryMax=/CPUQuota=. Values
  are validated (systemd silently ignores invalid ones) and written
  without %-escaping, since these settings take "%" literally. `run`
  warns when the kernel can't enforce them; status shows the limit.
- Commands that take no options now reject extra arguments.
- 19 new tests (68 total), including systemd-analyze checks that the
  limits parse.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdsNJV9e2ktZ9gF5kmczEu
@dafioram
dafioram changed the base branch from claude/upbeat-cannon-w8n2qa to main October 4, 2026 10:51
@dafioram
dafioram merged commit 7917654 into main Oct 4, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants