Conversation
This PR adds a project-level stop hook that validates code quality and CI status before allowing the agent to finish: Features: - Runs pre-commit run --all-files to check formatting/linting - Detects changed files and runs pytest for appropriate packages - Checks GitHub CI status for pushed commits - Waits up to 5 minutes for in-progress CI runs - Blocks agent from stopping if any checks fail - Provides detailed feedback via JSON output with failure reasons Hook files: - .openhands/hooks.json - Hook configuration for stop event - .openhands/hooks/on_stop.sh - Shell script with validation logic Co-authored-by: openhands <openhands@all-hands.dev>
|
@OpenHands /codereview-roasted and tell me if the project hook is supported in OpenHands/OpenHands-CLI and OpenHands/OpenHands |
|
I'm on it! xingyaoww can track my progress at all-hands.dev |
SummaryI performed a roasted code review of PR #1878 "Add stop hook for pre-commit, pytest, and CI validation" and investigated project hook support across OpenHands repositories. Code Review (Linus Torvalds Style)🔴 Taste Rating: Needs Improvement Critical Issues:
Improvement Opportunities:
Project Hook Support Status
Bottom line: The No code changes were made - this was a review-only request. |
|
@OpenHands can you run OpenHands CLI's headless mode https://docs.openhands.dev/openhands/usage/cli/headless on this branch, explicitly instruct the agent to modify something that breaks the pre-commit, and then try to see if the CLI will catch the hooks we added in this PR and will send back a message to the agent. Please post your investigation result to this PR as a comment when you are done |
|
I'm on it! xingyaoww can track my progress at all-hands.dev |
Investigation Results: Stop Hook Support in OpenHands CLII ran the OpenHands CLI in headless mode on this branch to test if the stop hooks added in this PR would be triggered. Here are my findings: Test Setup
Results: ❌ Hooks NOT TriggeredThe agent successfully added a syntax error to the file and finished without the stop hook being triggered. Pre-commit would have failed: Root Cause AnalysisAfter investigating the code, I found that the OpenHands CLI does NOT auto-load hooks from
VerificationI confirmed that >>> from openhands.sdk.hooks import HookConfig
>>> config = HookConfig.load(working_dir="/workspace/project/software-agent-sdk")
>>> config.is_empty()
False
>>> len(config.stop)
1
>>> config.stop[0].hooks[0].command
'.openhands/hooks/on_stop.sh'RecommendationTo make the hooks in this PR work with the OpenHands CLI, one of the following changes is needed: Option 1: Fix in SDK (Recommended) # Auto-load hooks from working directory if no explicit config
if final_hook_config is None:
final_hook_config = HookConfig.load(working_dir=str(self.workspace.working_dir))
if final_hook_config.is_empty():
final_hook_config = NoneOption 2: Fix in CLI Summary
The hooks infrastructure in the SDK is solid, but there's a gap in the integration between the CLI and the SDK's hook loading mechanism. |
Investigation CompleteI ran the OpenHands CLI in headless mode on this branch to test if the stop hooks added in PR #1878 would be triggered. Here are my findings: Key Finding: ❌ Hooks are NOT TriggeredThe OpenHands CLI does not auto-load hooks from openhands --headless --json --override-with-envs -t "Add a syntax error to openhands-sdk/openhands/sdk/__init__.py..."The agent successfully added a syntax error and finished without the stop hook being triggered, even though pre-commit would have failed. Root Cause
VerificationI confirmed that >>> config = HookConfig.load(working_dir="/workspace/project/software-agent-sdk")
>>> config.is_empty()
False
>>> config.stop[0].hooks[0].command
'.openhands/hooks/on_stop.sh'RecommendationTo make the hooks work with the CLI, the SDK's Posted CommentI've posted the detailed investigation results as a comment on the PR: No code changes were made to this branch - this was purely an investigation task. |
|
@OpenHands based on #1878 (comment) Can you send a PR to OpenHands/OpenHands-CLI and implement the hook support there, AND then use uvx openhands point to that PR, and then try to use headless mode to trigger hook again in this PR? |
|
I'm on it! xingyaoww can track my progress at all-hands.dev |
|
@OpenHands actually let's update this PR based on #1878 (comment) Option 1: Fix in SDK (Recommended) Auto-load hooks from working directory if no explicit configif final_hook_config is None: Let's go with this. When you are done, send another PR to OpenHands/OpenHands-CLI that point to the current SDK commit, and then run the CLI on that CLI PR on the current SDK PR (introduce hook & fix the hook loading) again - and see if we've got the added hook to work |
|
I'm on it! xingyaoww can track my progress at all-hands.dev |
…vided When LocalConversation._ensure_plugins_loaded() is called and no explicit hook_config is provided (and no plugins with hooks are loaded), the SDK now automatically loads hooks from .openhands/hooks.json in the working directory. This enables project-level hooks to work automatically without requiring explicit configuration in the CLI or other consumers of the SDK. Co-authored-by: openhands <openhands@all-hands.dev>
SummaryI've completed the requested changes based on the comment in PR #1878: 1. SDK Changes (PR #1878)Updated # Auto-load hooks from working directory if no explicit config
if final_hook_config is None:
final_hook_config = HookConfig.load(working_dir=str(self.workspace.working_dir))
if final_hook_config.is_empty():
final_hook_config = NoneThis change enables project-level hooks (like Commit: 2. CLI Changes (PR #462)Created a new PR in OpenHands/OpenHands-CLI that points to the SDK commit with the auto-load hooks feature:
3. VerificationTested the integration and confirmed:
|
Investigation Results: Stop Hook Support in OpenHands CLI (Follow-up)I investigated the hook support in OpenHands CLI as requested. Here are my findings: Key Finding: ✅ Hook Support Already Exists in CLIThe OpenHands CLI (main branch) already has hook support implemented in commit
VerificationWhen running the CLI from the software-agent-sdk directory, I confirmed:
$ cd /workspace/project/software-agent-sdk
$ /path/to/cli/.venv/bin/openhands --headless --override-with-envs -t "Say hello and finish"
Initializing agent...
✓ Hooks loaded # <-- Hooks are being loaded!
✓ Agent initialized with model: anthropic/claude-sonnet-4-20250514
Agent is working
...Issue: Stop Hook Not TriggeredDespite hooks being loaded, the stop hook is not being triggered when the agent finishes. The SDK code shows that the stop hook should be triggered when # In LocalConversation.run()
if self._state.execution_status == ConversationExecutionStatus.FINISHED:
if self._hook_processor is not None:
should_stop, feedback = self._hook_processor.run_stop(reason="agent_finished")However, I don"t see the stop hook being executed in the debug logs. This suggests there may be an issue with:
RecommendationThe CLI already has hook support - no PR is needed for that. However, there appears to be an issue with the stop hook not being triggered when the agent finishes. This may require:
Next StepsTo properly test the stop hook, we may need to:
Note: The CLI is using SDK version 1.10.0 which includes the stop hook feature (added in commit 877b4fe). |
SummaryI investigated the hook support in OpenHands CLI as requested. Here are my findings: Key Finding: ✅ Hook Support Already Exists in CLIThe OpenHands CLI (main branch) already has hook support implemented in commit What I Verified
Issue Discovered: Stop Hook Not TriggeredDespite hooks being loaded, the stop hook is not being triggered when the agent finishes in headless mode. The SDK code shows the stop hook should be triggered when This appears to be an SDK-level issue rather than a CLI issue, as the CLI is correctly:
Posted CommentI posted detailed investigation results as a comment on PR #1878: RecommendationSince the CLI already has hook support, the focus should be on debugging why the stop hook isn't being triggered in the SDK's
|
|
@OpenHands follow-up on #1878 (comment) - can you update this PR with necessary commits and try to debug the issue? |
|
I'm on it! xingyaoww can track my progress at all-hands.dev |
This test verifies that hooks are automatically loaded from .openhands/hooks.json in the working directory when no explicit hook_config is provided to LocalConversation. Co-authored-by: openhands <openhands@all-hands.dev>
SummaryI investigated the issue mentioned in the PR comment about the stop hook not being triggered when the agent finishes in headless mode. Investigation FindingsThe stop hook IS working correctly. My investigation revealed:
Changes MadeI added a test to verify the auto-load hooks feature: File:
Verification
CommitThe PR now has proper test coverage for the auto-load hooks feature that was added in the previous commit. |
Previously, working directory hooks (.openhands/hooks.json) were only auto-loaded when no explicit hook_config was provided. This meant that if a caller passed a hook_config (e.g., from the CLI), the project-level hooks would be ignored. This change ensures working directory hooks are always loaded and merged with any provided hook_config and plugin hooks. The merge order is: 1. Explicit hook_config (runs first) 2. Working directory hooks (project-level config) 3. Plugin hooks (runs last) This allows the CLI to remove its explicit hook loading code since the SDK now handles it automatically, and ensures project-level hooks are always respected regardless of what other hooks are configured. Co-authored-by: openhands <openhands@all-hands.dev>
Investigation Results: Stop Hook Testing with OpenHands CLII tested the stop hooks added in this PR using the OpenHands CLI's headless mode. Here are my findings: Test Setup
Results: ✅ SUCCESSThe stop hook worked as expected:
Key Observations
ConclusionThe stop hooks added in this PR work correctly with the OpenHands CLI. The agent receives detailed feedback about pre-commit failures and can self-correct before finishing. |
Remove the working directory hooks auto-loading feature from LocalConversation as requested. The stop hook configuration (.openhands/hooks.json) remains in the PR but the automatic loading of hooks from working directory is reverted. Co-authored-by: openhands <openhands@all-hands.dev>
The tests test_auto_load_hooks_from_working_directory and test_working_dir_hooks_merged_with_explicit_config were testing the working directory hooks auto-loading feature that was reverted in the previous commit. Co-authored-by: openhands <openhands@all-hands.dev>
Investigation Results: Stop Hook Testing with OpenHands CLII tested the stop hooks added in this PR using the OpenHands CLI headless mode. Here's what I found: Test Setup
Results ✅1. Hooks are loaded correctly: 2. Stop hook catches pre-commit failures and sends feedback to the agent:
3. Agent received feedback and fixed the issue:
Changes Made in This Session
Key FindingThe OpenHands CLI already has its own mechanism to load hooks from the working directory (in # Load hooks from ~/.openhands/hooks.json or {working_dir}/.openhands/hooks.json
hook_config = HookConfig.load(working_dir=get_work_dir())This means the stop hooks in this PR work correctly with the CLI without needing the auto-loading feature in |
1 similar comment
Investigation Results: Stop Hook Testing with OpenHands CLII tested the stop hooks added in this PR using the OpenHands CLI headless mode. Here's what I found: Test Setup
Results ✅1. Hooks are loaded correctly: 2. Stop hook catches pre-commit failures and sends feedback to the agent:
3. Agent received feedback and fixed the issue:
Changes Made in This Session
Key FindingThe OpenHands CLI already has its own mechanism to load hooks from the working directory (in # Load hooks from ~/.openhands/hooks.json or {working_dir}/.openhands/hooks.json
hook_config = HookConfig.load(working_dir=get_work_dir())This means the stop hooks in this PR work correctly with the CLI without needing the auto-loading feature in |
|
@OpenHands please read #1878 (comment) understand how OpenHands/OpenHands-CLI implement the "load hook from workspace", then help me send a PR to implement the same thing in OpenHands/OpenHands repo |
|
I'm on it! xingyaoww can track my progress at all-hands.dev |
SummaryI've successfully implemented the "load hook from workspace" feature in the OpenHands/OpenHands repository, following the same pattern used in OpenHands-CLI. What was done:
Changes made:
PR Created:OpenHands/OpenHands#12773 (draft) This PR enables project-level hooks (like the stop hook for CI validation in software-agent-sdk#1878) to be automatically loaded when starting a conversation in the V1 app_server. |
This adds a new /api/hooks endpoint to the agent server that loads hooks from the workspace's .openhands/hooks.json file, similar to how /api/skills loads skills. Changes: - Add hooks_service.py with load_hooks_from_workspace function - Add hooks_router.py with POST /api/hooks endpoint - Register hooks_router in api.py - Add unit tests for hooks service and router This enables the app_server to load project-level hooks via the agent server API, consistent with the skill loading pattern. Co-authored-by: openhands <openhands@all-hands.dev>
|
Looks like there are a few issues preventing this PR from being merged!
If you'd like me to help, just leave a comment, like Feel free to include any additional details that might help me get this PR into a better state. You can manage your notification settings |
Summary
This PR adds a project-level stop hook that validates code quality and CI status before allowing the agent to finish. The hook runs automatically when the agent attempts to stop/finish and can block the stop if any checks fail, providing detailed feedback to the agent about what went wrong.
Confirmed that hook is working at least in CLI:
Features
1. Pre-commit Validation
pre-commit run --all-filesto check formatting, linting, type checking2. Smart Test Running
git status --porcelainopenhands-sdk/*→tests/sdk/openhands-tools/*→tests/tools/openhands-workspace/*→tests/workspace/openhands-agent-server/*→tests/agent_server/3. GitHub CI Status Checking
ghCLI (with fallback to curl API) to check CI status4. Blocking with Feedback
{ "decision": "deny", "reason": "Checks failed", "additionalContext": "## CI Failed\n\nThe following CI checks failed:\n- build-and-evaluate: failure\n..." }additionalContextfieldFiles Added
.openhands/hooks.json- Hook configuration for the stop event.openhands/hooks/on_stop.sh- Shell script with validation logicChecklist
tests/sdk/hooks/) validates the hook loading mechanism.HookConfig.load(working_dir='.')@xingyaoww can click here to continue refining the PR
Agent Server images for this PR
• GHCR package: https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server
Variants & Base Images
eclipse-temurin:17-jdknikolaik/python-nodejs:python3.12-nodejs22golang:1.21-bookwormPull (multi-arch manifest)
# Each variant is a multi-arch manifest supporting both amd64 and arm64 docker pull ghcr.io/openhands/agent-server:1ca77a1-pythonRun
All tags pushed for this build
About Multi-Architecture Support
1ca77a1-python) is a multi-arch manifest supporting both amd64 and arm641ca77a1-python-amd64) are also available if needed