Skip to content

Allow external callers to configure the hook directory - #951

Merged
podkidyshev merged 3 commits into
NVIDIA:mainfrom
shreyaskommuri:fix/configurable-hook-directory
Jul 29, 2026
Merged

Allow external callers to configure the hook directory#951
podkidyshev merged 3 commits into
NVIDIA:mainfrom
shreyaskommuri:fix/configurable-hook-directory

Conversation

@shreyaskommuri

@shreyaskommuri shreyaskommuri commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #952.

  • Add an optional --hook-dir argument to the shared scenario command options used by run, dry-run, install, uninstall, and generate-report.
  • Pass the selected hook directory into Parser instead of always resolving hooks from conf/hook relative to the process working directory.
  • Preserve conf/hook as the default for existing in-repository workflows.
  • Add CLI and parser regression coverage for the configurable hook directory.

CloudAI Autotune exposed this while validating CloudAI's supplied NCCL scenario from outside the CloudAI checkout. Autotune already passed absolute paths for the scenario, system config, tests, and output directory:

autotune smoke-cloudai \
  ../cloudai/conf/common/test_scenario/nccl_test.toml \
  --cloudai-bin ../cloudai/.venv/bin/cloudai \
  --system-config ../cloudai/conf/common/system/example_slurm_cluster.toml \
  --tests-dir ../cloudai/conf/common/test \
  --runs-dir runs/integration \
  --timeout-sec 60

CloudAI still resolved hooks from conf/hook under Autotune's working directory and exited with:

[ERROR] Pre-test hook 'nccl_test' not found in hook mapping. A corresponding hook should exist under 'conf/hook'. Ensure that a proper hook directory is set under the working directory.

Changing the caller's working directory would make output and orchestration behavior depend on where CloudAI was launched. This change instead makes the remaining configuration root explicit, consistent with --system-config, --tests-dir, and --test-scenario.

Test Plan

Testing environment:

  • macOS local development environment
  • Python managed through the repository's uv environment
  • CloudAI dry-run mode; no Slurm cluster was available
  • Invocation performed from the sibling CloudAI-Autotune repository, not the CloudAI working directory

Regression and repository checks:

uv run pytest tests/test_cli.py tests/test_parser.py tests/test_handlers.py -q
# 60 passed

uv run pytest -q
# 1636 passed, 4 skipped, 490 deselected

uv run pytest -q -m ci_only
# 490 passed, 1640 deselected

uv run pytest --dead-fixtures
# Cool, every declared fixture is being used.

uv run pre-commit run --all-files
# All hooks passed, including pyright, ruff, vulture, import-linter, and taplo.

The original NCCL dry-run was then repeated from the Autotune working directory with the new option:

PYTHONPATH=/Users/shreyas/cloudai/src ../cloudai/.venv/bin/cloudai dry-run \
  --test-scenario /Users/shreyas/cloudai/conf/common/test_scenario/nccl_test.toml \
  --system-config /Users/shreyas/cloudai/conf/common/system/example_slurm_cluster.toml \
  --tests-dir /Users/shreyas/cloudai/conf/common/test \
  --hook-dir /Users/shreyas/cloudai/conf/hook \
  --output-dir /tmp/cloudai-hook-dir-validation

Result:

[INFO] Test Scenario Name: nccl-test
[INFO] Starting test: Tests.all_reduce
[INFO] Starting test: Tests.all_gather
[INFO] All jobs are complete.
exit code: 0

The dry run emitted expected local warnings for unavailable Slurm commands, but hook discovery succeeded and the complete NCCL scenario was generated.

Additional Notes

  • Live NCCL execution on a Slurm cluster was not tested.
  • AI was used only for context and guidance.

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds an optional --hook-dir argument to five CloudAI commands. The value is passed through command namespaces and handlers into Parser, which now uses configurable hook and hook-test directories when loading TOML configuration.

Changes

Hook directory configuration

Layer / File(s) Summary
Parser hook root and parsing
src/cloudai/parser.py, tests/test_parser.py
Parser accepts and stores a configurable hook root, derives its test directory, and parses hook TOMLs from instance-specific paths. Tests cover custom-root parsing and hook scenario resolution.
CLI option and command propagation
src/cloudai/cli/cli.py
The shared Click options and install, uninstall, dry-run, run, and generate-report commands accept and forward hook_dir; the copyright year is updated.
Handler integration and regression coverage
src/cloudai/cli/handlers.py, tests/test_cli.py
Handlers pass the selected directory to Parser, and CLI tests cover help exposure of --hook-dir.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: srivatsankrishnan

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: making the hook directory configurable for external callers.
Description check ✅ Passed The description is directly related to the changeset and accurately explains the new hook-dir option and its purpose.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@shreyaskommuri
shreyaskommuri marked this pull request as ready for review June 29, 2026 17:44

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/test_cli.py`:
- Around line 49-55: The hook-dir help check only covers the dry-run command, so
it can miss regressions in other commands that should also include the shared
option. Update the test in test_hook_dir_is_available_on_run_commands to be
parameterized over the full command set covered by the common_options decorator,
including install, uninstall, run, dry-run, and generate-report, and invoke main
for each command to assert the help output still contains --hook-dir DIRECTORY.

In `@tests/test_parser.py`:
- Around line 42-47: The current test only checks Parser constructor state, so
it won’t catch regressions in path resolution inside parse(). Update
test_custom_hook_root_is_used to exercise Parser.parse() with the injected
hook_root and assert the parsed hook file resolution comes from that custom
directory, using Parser.parse and the parser.hook_root/hook_test_root setup to
verify the runtime behavior instead of just object fields.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 43241b99-55f5-4ceb-8a26-047f57f413e5

📥 Commits

Reviewing files that changed from the base of the PR and between 79f8bdb and 5d971f4.

📒 Files selected for processing (5)
  • src/cloudai/cli/cli.py
  • src/cloudai/cli/handlers.py
  • src/cloudai/parser.py
  • tests/test_cli.py
  • tests/test_parser.py

Comment thread tests/test_cli.py Outdated
Comment thread tests/test_parser.py
@podkidyshev

Copy link
Copy Markdown
Contributor

we're quite busy with release + I'll be on vacations for couple weeks. I'll respond as soon as I get some spare time 🙏

@shreyaskommuri

Copy link
Copy Markdown
Contributor Author

@podkidyshev No worries! Take your time, happy to wait but I will update branch and merge conflicts once this is active again to avoid redundant work.

Expose an optional --hook-dir across scenario commands and pass the resolved directory into Parser so tools such as CloudAI Autotune can invoke hook-bearing scenarios outside the CloudAI repository.

Constraint: Preserve conf/hook as the parser default and keep hook-free external invocations backward compatible.

Rejected: Require callers to change into the CloudAI checkout | output paths and orchestration should not depend on process working directory.

Confidence: high

Scope-risk: narrow

Directive: Keep scenario config roots explicit at the CLI boundary when external orchestration depends on them.

Tested: uv run pytest -q (1636 passed, 4 skipped); uv run pytest -q -m ci_only (490 passed); uv run pytest --dead-fixtures; uv run pre-commit run --all-files; external NCCL dry-run from CloudAI-Autotune cwd exits 0 with --hook-dir

Not-tested: Live NCCL execution on a Slurm cluster.
Signed-off-by: shreyaskommuri <shreyaskommuri@gmail.com>
Parametrize test_hook_dir_is_available_on_run_commands over all five
common_options commands (install, uninstall, dry-run, run,
generate-report) instead of only dry-run, so a regression on any one
of them is caught.

Add test_custom_hook_root_is_used_by_parse, which exercises
Parser.parse() end-to-end with a custom hook_root and asserts a hook
test placed only under that directory is actually resolved, rather
than just checking the constructor sets hook_root/hook_test_root.

Tested: python -m pytest -q (1762 passed, 18 skipped); ruff check;
ruff format --check

Signed-off-by: shreyaskommuri <shreyaskommuri@gmail.com>
Copilot AI review requested due to automatic review settings July 26, 2026 21:50
@shreyaskommuri
shreyaskommuri force-pushed the fix/configurable-hook-directory branch from 5d971f4 to e34c5b4 Compare July 26, 2026 21:50
@shreyaskommuri

Copy link
Copy Markdown
Contributor Author

Rebased onto latest main (was 186 commits behind) to keep this mergeable — no conflicts. Also addressed both CodeRabbit review notes: test_hook_dir_is_available_on_run_commands now parametrizes over all five common_options commands (install, uninstall, dry-run, run, generate-report) instead of just dry-run, and added test_custom_hook_root_is_used_by_parse, which exercises Parser.parse() end-to-end and asserts a hook test placed only under a custom hook_root is actually resolved, rather than just checking constructor state. Re-ran python -m pytest -q (1762 passed, 18 skipped), ruff check, and ruff format --check — all clean. No rush on review — hope the release + time off went well.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR makes CloudAI’s hook discovery configurable for external orchestrators by introducing an optional --hook-dir CLI option and threading the selected hook root into Parser, while preserving the existing default behavior (conf/hook relative to the working directory) for in-repo usage.

Changes:

  • Add --hook-dir to the shared scenario CLI options for run, dry-run, install, uninstall, and generate-report.
  • Extend Parser to accept a configurable hook_root and use it for hook scenario + hook test discovery.
  • Add regression tests covering the new CLI option and parser hook-root behavior.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/cloudai/cli/cli.py Adds --hook-dir to common scenario options and passes it through command argument namespaces.
src/cloudai/cli/handlers.py Instantiates Parser with the selected hook directory (or default).
src/cloudai/parser.py Introduces hook_root/hook_test_root on Parser and switches hook discovery to use them.
tests/test_cli.py Verifies --hook-dir appears in help output for the intended subcommands.
tests/test_parser.py Adds parser regression coverage for custom hook roots and hook-test discovery.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/cloudai/parser.py
Comment thread src/cloudai/parser.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/cloudai/cli/handlers.py (1)

622-623: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Avoid eagerly resolving every lazy agent while listing.

Registry.agent_names() includes unresolved entry-point names, while Registry.get_agent() calls ep.load() and can raise when an optional agent or dependency is unavailable. One broken plugin can therefore make list agents fail. List names without loading classes, or catch resolution failures and display those entries as unavailable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cloudai/cli/handlers.py` around lines 622 - 623, Update the agent-listing
loop around registry.agent_names() and registry.get_agent() so listing does not
fail when a lazy or optional agent cannot be resolved. Prefer displaying names
without calling get_agent; otherwise catch per-agent resolution failures and
mark those entries unavailable while continuing to list the remaining agents.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/test_parser.py`:
- Around line 49-65: Add a root-level hook scenario fixture alongside the
existing custom hook test data, then invoke Parser.parse with a non-None
scenario in test_custom_hook_root_is_used_by_parse. Assert the resulting
scenario resolution uses the custom hook root, exercising the parse_hooks branch
around the parser’s scenario-handling logic rather than only validating hook
file loading.

---

Outside diff comments:
In `@src/cloudai/cli/handlers.py`:
- Around line 622-623: Update the agent-listing loop around
registry.agent_names() and registry.get_agent() so listing does not fail when a
lazy or optional agent cannot be resolved. Prefer displaying names without
calling get_agent; otherwise catch per-agent resolution failures and mark those
entries unavailable while continuing to list the remaining agents.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: d044e709-77ae-4da0-b666-fcc5bdd2dc02

📥 Commits

Reviewing files that changed from the base of the PR and between 5d971f4 and e34c5b4.

📒 Files selected for processing (5)
  • src/cloudai/cli/cli.py
  • src/cloudai/cli/handlers.py
  • src/cloudai/parser.py
  • tests/test_cli.py
  • tests/test_parser.py

Comment thread tests/test_parser.py
Comment thread src/cloudai/parser.py
Comment thread src/cloudai/parser.py
- Remove unused HOOK_TEST_ROOT module constant (superseded by
  Parser.hook_test_root instance attribute).
- Extend custom hook_root test coverage to also exercise scenario-level
  hook resolution (pre_test/post_test), not just hook test toml loading.
Copilot AI review requested due to automatic review settings July 29, 2026 01:02

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/test_parser.py`:
- Around line 69-110: Extend
test_custom_hook_root_is_used_for_hook_scenario_resolution by adding post_test =
"custom_hook" to the main scenario fixture, then assert
test_scenario.test_runs[0].post_test is not None and its name is "custom_hook",
alongside the existing pre_test assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: f6f4f75e-11f3-4bf0-945a-75e5e3b1e7a4

📥 Commits

Reviewing files that changed from the base of the PR and between e34c5b4 and 2a85f25.

📒 Files selected for processing (2)
  • src/cloudai/parser.py
  • tests/test_parser.py
💤 Files with no reviewable changes (1)
  • src/cloudai/parser.py

Comment thread tests/test_parser.py
@shreyaskommuri

Copy link
Copy Markdown
Contributor Author

Pushed 2a85f256:

  • Deleted the unused HOOK_TEST_ROOT constant.
  • Left the hook_root validation and the system_config_path docstring as-is per your replies to Copilot's suggestions.
  • Added test_custom_hook_root_is_used_for_hook_scenario_resolution per CodeRabbit's note — the existing test only proved custom hook_root was used for loading hook test tomls, not for resolving hook scenarios referenced via pre_test/post_test. Verified it's a real regression test (fails with the old global-HOOK_ROOT behavior).

All green: 1777 passed, ruff/pyright clean.

@podkidyshev
podkidyshev merged commit bd8332f into NVIDIA:main Jul 29, 2026
5 checks 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.

Allow external callers to configure the hook directory

3 participants