feat(cron): add per-job profile support#25917
Conversation
|
Overlaps significantly with #19958 (fix(cron): honor per-job profile during scheduler runs) and #14703 (restore cron profile binding). This PR adds CLI/tool plumbing and create/update-time validation on top of the scheduler-only runtime scoping. Related: #11470 (profile job model resolution), #20622 (multi-profile dashboard), #25295 (profile fragmentation). |
|
Would be awesome! |
Agree there’s overlap. This PR covers the E2E flow: checks the profile when jobs are created or edited, supports profiles in the cron CLI/tooling, and keeps existing jobs working the same way. |
There was a problem hiding this comment.
Pull request overview
Adds per-cron-job Hermes profile pinning so scheduled jobs can run under a specific profile’s config/scripts/memory paths while preserving legacy behavior when profile is unset.
Changes:
- Adds an optional
profilefield to cron job storage + validation, plus CLI/tool plumbing for create/edit/update/list flows. - Introduces a context-local
HERMES_HOMEoverride (ContextVar-based) and bridges it into subprocess environments. - Updates scheduler execution to apply per-job profile context and to serialize profile/workdir jobs; adds targeted regression tests.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
hermes_constants.py |
Introduces ContextVar-based Hermes home override helpers and makes subprocess HOME resolution honor the override. |
cron/jobs.py |
Adds profile field normalization/validation at create/update time and normalizes the stored record shape. |
cron/scheduler.py |
Adds per-job profile execution context, runs profile/workdir jobs sequentially, and wires profile into script subprocess env. |
tools/environments/local.py |
Bridges context-local Hermes home override into subprocess env for terminal/background tool execution. |
tools/cronjob_tools.py |
Exposes profile on the cronjob tool (formatting, create/update plumbing, schema). |
hermes_cli/main.py |
Adds --profile flags to hermes cron create and hermes cron edit. |
hermes_cli/cron.py |
Plumbs profile through CLI create/edit calls and prints profile on list/create/edit output. |
tests/cron/test_cron_profile.py |
Adds end-to-end tests covering validation/storage, tool wiring, scheduler scoping, and tick serialization. |
tests/test_subprocess_home_isolation.py |
Adds tests for thread-local override semantics and env-bridging into run/background subprocess env. |
tests/hermes_cli/test_cron.py |
Updates CLI tests to cover setting and clearing per-job profile via edit/create. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
austinpickett
left a comment
There was a problem hiding this comment.
Use PULL_REQUEST_TEMPLATE.md, address Copilot comments.
|
@daimon-nous can you make a proper reproduction environment as well as review? |
There was a problem hiding this comment.
Review: feat(cron): add per-job profile support
Good PR — the ContextVar-based architecture is well-designed. Profile scoping via set_hermes_home_override() + sequential serialization for profile jobs + os.environ snapshot/restore covers the full isolation surface. Tests are comprehensive (406 lines covering validation, runtime scoping, env restoration, subprocess bridging, tick partitioning, and thread isolation). E2E verified: profile override, env restore, subprocess bridging all work against a real isolated HERMES_HOME.
Competing PR #19958 takes a simpler RLock approach but is incomplete — scheduler-only, no CLI --profile, no tool schema update, no subprocess HERMES_HOME bridging. This PR is the right one to land.
See inline comments for specific observations. Nothing blocking — these are follow-up improvements.
Salvage note: AUTHOR_MAP in scripts/release.py is missing an entry for 52470719+gianfrancopiana@users.noreply.github.com → gianfrancopiana. CI will block on unmapped emails during release.
|
Merged via PR #28124 — your 3 commits were cherry-picked onto current main with authorship preserved in git log. Follow-up fixes added on top: AUTHOR_MAP entry, delta-based env restore (idea from #19958), graceful fallback on deleted profiles (idea from #19958), profile+workdir combined test. Thank you @gianfrancopiana! |
What does this PR do?
Adds per-cron-job Hermes profile pinning so scheduled jobs can run under a specific profile’s config, scripts, and runtime paths without changing behavior for jobs that do not set
profile.This approach keeps the scheduler profile as the storage/scheduling owner, then applies the selected profile only while that job runs via context-local Hermes home scoping, subprocess
HERMES_HOMEbridging, and profile.envsnapshot/restore.Related Issue
Related: #19958, #14703, #11470, #20622, #25295.
No dedicated issue.
Type of Change
Changes Made
cron/jobs.py: stores and validates optionalprofilevalues on create/update.cron/scheduler.py: runs profile-pinned jobs under context-local profile scope, restores temporary profile.envmutations after each run, and serializes profile/workdir jobs.tools/cronjob_tools.py: exposesprofilein the cronjob tool schema and create/update plumbing with an accurate runtime contract.hermes_cli/cron.pyandhermes_cli/main.py: add profile support to cron create/edit/list CLI flows.hermes_constants.pyandtools/environments/local.py: bridge profile-scoped Hermes home into subprocess environments.tests/cron/test_cron_profile.pyandtests/test_subprocess_home_isolation.py: cover validation, runtime scoping,.envrestoration, subprocess bridging, and tick serialization.How to Test
venv/bin/python -m pytest -o 'addopts=' -q tests/cron/test_cron_profile.pyvenv/bin/python -m pytest -o 'addopts=' -q tests/cron/test_cron_profile.py tests/cron/test_cron_workdir.py tests/hermes_cli/test_cron.py tests/tools/test_cronjob_tools.py tests/test_subprocess_home_isolation.py tests/tools/test_local_env_blocklist.py tests/tools/test_env_passthrough.pyvenv/bin/python -m compileall -q cron/scheduler.py tools/cronjob_tools.py tests/cron/test_cron_profile.pygit diff --checkFocused result:
126 passed.Full-suite note: a previous full-suite smoke run was attempted, but
origin/mainalready failed ontests/acp/test_approval_isolation.py::TestAcpExecAskGate::test_interactive_env_var_routes_to_callback, so the full-suite failure appears pre-existing.Checklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests passDocumentation & Housekeeping
docs/, docstrings) — or N/Acli-config.yaml.exampleif I added/changed config keys — or N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/AFor New Skills
N/A — this PR does not add a skill.
Screenshots / Logs
Warnings are existing thread-drain warnings from
tests/tools/test_local_env_blocklist.py; the focused test set passed.