hooks
hooks
¶
Post-success hook execution for concert orchestration.
Executes hooks after successful job completion, enabling job chaining and concert orchestration where jobs can spawn other jobs.
Security Note:¶
This module intentionally supports shell command execution via run_command hooks. This is a DESIGN DECISION because: 1. Commands come from user-authored YAML config files (not user input at runtime) 2. Users explicitly opt-in by adding on_success hooks to their config 3. Shell features (pipes, redirects, env vars) are needed for real-world hooks 4. Marianne runs with the same permissions as the user who invokes it
The run_script hook type uses subprocess_exec (no shell) for cases where shell features aren't needed.
Classes¶
HookResult
dataclass
¶
HookResult(hook_type, description, success, exit_code=None, error_message=None, duration_seconds=0.0, output=None, chained_job_path=None, chained_job_workspace=None, log_path=None, chained_job_info=None)
Result of executing a single hook.
ConcertContext
dataclass
¶
ConcertContext(concert_id, chain_depth=0, parent_job_id=None, root_workspace=None, started_at=(lambda: now(UTC))(), total_jobs_run=0, total_sheets_completed=0, jobs_in_chain=list())
Context passed through concert job chains.
Tracks the concert's progress across multiple jobs to enforce safety limits and enable coordinated logging.
HookExecutor
¶
Executes post-success hooks and manages concert orchestration.
Responsible for: - Executing hooks after successful job completion - Managing job chaining (run_job hooks) - Enforcing concert safety limits - Logging hook execution
Hook execution runs in Marianne's Python process, not inside Claude CLI. This allows hooks to trigger new Marianne runs without recursion issues.
Source code in src/marianne/execution/hooks.py
Functions¶
execute_hooks
async
¶
Execute all configured on_success hooks.
Returns list of HookResults for each hook executed. Stops early if a hook fails and on_failure="abort".
Source code in src/marianne/execution/hooks.py
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | |
get_next_job_to_chain
¶
Get the next job to chain from successful run_job hooks.
Returns (job_path, workspace) for the first successful run_job hook, or None if no chaining should occur.
Note: This is for the synchronous chaining mode where Marianne itself manages the concert. For async/background chaining, hooks execute the jobs directly.
Source code in src/marianne/execution/hooks.py
Functions¶
get_hook_log_path
¶
Construct log path for a hook execution.
Creates a timestamped log file in {workspace}/hooks/ for capturing detached hook output that would otherwise go to /dev/null.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
workspace
|
str | Path | None
|
Job workspace directory. Returns None if not set. |
required |
hook_type
|
str
|
Hook type identifier used in filename (e.g., "chain", "command"). |
required |
Returns:
| Type | Description |
|---|---|
Path | None
|
Path to the log file, or None if workspace is not available. |
Source code in src/marianne/execution/hooks.py
expand_hook_variables
¶
Expand template variables in hook paths/commands.
Shared utility used by both HookExecutor (runner-side) and the daemon's _execute_hooks_task (daemon-side).
Known variables: {workspace}, {job_id}, {sheet_count}. Warns on unrecognized {var} patterns that remain after expansion.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
template
|
str
|
Template string with {variable} placeholders. |
required |
workspace
|
str | Path
|
Workspace path to substitute. |
required |
job_id
|
str
|
Job identifier to substitute. |
required |
sheet_count
|
int | None
|
Optional sheet count to substitute. |
None
|
for_shell
|
bool
|
When True, apply shlex.quote() to variable values before substitution. Use this when the expanded result will be passed to create_subprocess_shell. Do NOT use when the result will be used as a filesystem path (e.g., run_job hook's job_path). |
False
|