Skip to content

Conversation

@xingyaoww
Copy link
Collaborator

@xingyaoww xingyaoww commented Jan 7, 2026

Summary

This PR fixes a bug where third-party skill files like AGENTS.md, .cursorrules, CLAUDE.md, and GEMINI.md were not being loaded when the .openhands/skills or .openhands/microagents directories don't exist.

Related issue: OpenHands/OpenHands-CLI#300

Problem

The load_project_skills() function only called load_skills_from_dir() when the skills directories existed. However, the third-party file loading logic (which uses find_third_party_files()) was inside load_skills_from_dir().

This meant that if a project had an AGENTS.md file but no .openhands/skills directory, the AGENTS.md file would never be loaded.

Solution

Modified load_project_skills() to:

  1. First, load third-party skill files directly from the work directory using find_third_party_files() (which already does case-insensitive matching)
  2. Then, load skills from .openhands/skills and .openhands/microagents directories if they exist
  3. Merge all skills, avoiding duplicates

This ensures third-party skill files are always loaded, regardless of whether the skills directories exist.

Tests Added

  • test_load_project_skills_agents_md_without_skills_directory: Main bug fix test - verifies AGENTS.md is loaded even when .openhands/skills doesn't exist
  • test_load_project_skills_agents_md_case_insensitive: Verifies case-insensitive file matching
  • test_load_project_skills_multiple_third_party_files: Tests loading multiple third-party files
  • test_load_project_skills_third_party_with_skills_directory: Verifies no duplicates when both AGENTS.md and skills directory exist

@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

Variant Architectures Base Image Docs / Tags
java amd64, arm64 eclipse-temurin:17-jdk Link
python amd64, arm64 nikolaik/python-nodejs:python3.12-nodejs22 Link
golang amd64, arm64 golang:1.21-bookworm Link

Pull (multi-arch manifest)

# Each variant is a multi-arch manifest supporting both amd64 and arm64
docker pull ghcr.io/openhands/agent-server:fd873a4-python

Run

docker run -it --rm \
  -p 8000:8000 \
  --name agent-server-fd873a4-python \
  ghcr.io/openhands/agent-server:fd873a4-python

All tags pushed for this build

ghcr.io/openhands/agent-server:fd873a4-golang-amd64
ghcr.io/openhands/agent-server:fd873a4-golang_tag_1.21-bookworm-amd64
ghcr.io/openhands/agent-server:fd873a4-golang-arm64
ghcr.io/openhands/agent-server:fd873a4-golang_tag_1.21-bookworm-arm64
ghcr.io/openhands/agent-server:fd873a4-java-amd64
ghcr.io/openhands/agent-server:fd873a4-eclipse-temurin_tag_17-jdk-amd64
ghcr.io/openhands/agent-server:fd873a4-java-arm64
ghcr.io/openhands/agent-server:fd873a4-eclipse-temurin_tag_17-jdk-arm64
ghcr.io/openhands/agent-server:fd873a4-python-amd64
ghcr.io/openhands/agent-server:fd873a4-nikolaik_s_python-nodejs_tag_python3.12-nodejs22-amd64
ghcr.io/openhands/agent-server:fd873a4-python-arm64
ghcr.io/openhands/agent-server:fd873a4-nikolaik_s_python-nodejs_tag_python3.12-nodejs22-arm64
ghcr.io/openhands/agent-server:fd873a4-golang
ghcr.io/openhands/agent-server:fd873a4-java
ghcr.io/openhands/agent-server:fd873a4-python

About Multi-Architecture Support

  • Each variant tag (e.g., fd873a4-python) is a multi-arch manifest supporting both amd64 and arm64
  • Docker automatically pulls the correct architecture for your platform
  • Individual architecture tags (e.g., fd873a4-python-amd64) are also available if needed

This commit fixes a bug where third-party skill files like AGENTS.md,
.cursorrules, CLAUDE.md, and GEMINI.md were not being loaded when the
.openhands/skills or .openhands/microagents directories don't exist.

The root cause was that load_project_skills() only called
load_skills_from_dir() when the skills directories existed, but the
third-party file loading logic was inside load_skills_from_dir().

The fix modifies load_project_skills() to:
1. First, load third-party skill files directly from the work directory
   using find_third_party_files() (which already does case-insensitive
   matching)
2. Then, load skills from .openhands/skills and .openhands/microagents
   directories if they exist
3. Merge all skills, avoiding duplicates

This ensures third-party skill files are always loaded, regardless of
whether the skills directories exist.

Tests added:
- test_load_project_skills_agents_md_without_skills_directory
- test_load_project_skills_agents_md_case_insensitive
- test_load_project_skills_multiple_third_party_files
- test_load_project_skills_third_party_with_skills_directory

Co-authored-by: openhands <[email protected]>
@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

Coverage

Coverage Report •
FileStmtsMissCoverMissing
openhands-sdk/openhands/sdk/context/skills
   skill.py32424424%65, 69–70, 74–75, 79–80, 182–183, 186, 192–198, 204–208, 214–221, 252, 254–255, 257–258, 260, 274–275, 277–280, 283, 286–289, 294–297, 300–303, 305, 321–323, 326–327, 331, 333–336, 339, 342–344, 346, 372, 375, 383, 388–390, 396, 398–404, 407, 418–419, 430, 447, 449–450, 462–463, 468, 475, 485–486, 488, 494–495, 497, 506–509, 511–514, 522–524, 532–534, 557–558, 560–563, 569–571, 574–575, 580–581, 585–586, 592, 613–614, 616–619, 621–623, 628–632, 634, 638–639, 641, 644, 665–666, 668–669, 673, 676–684, 687, 692–694, 697, 699–701, 706–710, 712, 717–718, 722, 725, 764, 766, 768–769, 771–773, 776–779, 782, 784, 787–789, 793–799, 801–802, 804, 807, 830–831, 833–834, 836–838, 841–843, 845–848, 850–853, 856, 859–861, 863–868, 871–876
TOTAL14908714252% 

@xingyaoww
Copy link
Collaborator Author

@OpenHands please address the two review comments in this PR

@openhands-ai
Copy link

openhands-ai bot commented Jan 7, 2026

I'm on it! xingyaoww can track my progress at all-hands.dev

…ndant code

1. Changed broad 'except Exception' to 'except (SkillError, OSError)' in
   load_project_skills() to only catch expected exceptions (addresses
   neubig's comment about over-broad catches)

2. Removed redundant third-party file loading from load_skills_from_dir()
   since load_project_skills() now handles this directly (addresses
   enyst's comment about duplicate code at line 567)

3. Updated tests to use load_project_skills() instead of load_skills_from_dir()
   for testing third-party file loading behavior

Co-authored-by: openhands <[email protected]>
@openhands-ai
Copy link

openhands-ai bot commented Jan 7, 2026

I've addressed both review comments in PR #1624 and pushed the changes:

Changes Made

1. Narrowed Exception Handling (neubig's comment)

  • Changed except Exception as e: to except (SkillError, OSError) as e: in load_project_skills()
  • This catches only the expected exceptions (skill validation errors and file I/O errors) rather than masking all errors

2. Removed Redundant Code (enyst's comment)

  • Removed the third-party file loading code from load_skills_from_dir() (lines 565-578)
  • This code was redundant since load_project_skills() now handles third-party file loading directly
  • Added a comment explaining that third-party files are loaded separately by load_project_skills()

3. Updated Tests

  • Updated 4 tests in test_skill_utils.py to use load_project_skills() instead of load_skills_from_dir() for testing third-party file loading behavior
  • All 96 tests pass

Verification

  • ✅ Pre-commit hooks pass (ruff format, ruff lint, pycodestyle, pyright)
  • ✅ All 96 skill tests pass
  • ✅ Changes are minimal and focused on addressing the review comments

The commit has been pushed to the openhands/fix-agents-md-loading branch.

View full conversation

@enyst
Copy link
Collaborator

enyst commented Jan 7, 2026

Ah! This was exactly what I was looking for, when I asked about the other place.

=========================== short test summary info ============================
FAILED tests/sdk/context/test_agent_context_model_specific.py::test_context_gates_claude_vendor_file
FAILED tests/sdk/context/test_agent_context_model_specific.py::test_context_gates_gemini_vendor_file
FAILED tests/sdk/context/test_agent_context_model_specific.py::test_context_uses_canonical_name_for_vendor_match
FAILED tests/sdk/context/test_agent_context_model_specific.py::test_context_includes_all_when_model_unknown
================== 4 failed, 1652 passed in 74.48s (0:01:14) ===================
Error: Process completed with exit code 1.

We have some code somewhere that makes sure that GEMINI.md is loaded only for Gemini models, and CLAUDE.md for Claudes. I think maybe this new code - or place in the code - could play nice with that. Maybe we need to adapt the AgentContext check for this PR? Sorry, I forgot how exactly it was doing this, but it was doing this. 😅

@openhands-ai
Copy link

openhands-ai bot commented Jan 7, 2026

Looks like there are a few issues preventing this PR from being merged!

  • GitHub Actions are failing:
    • Run tests

If you'd like me to help, just leave a comment, like

@OpenHands please fix the failing actions on PR #1624 at branch `openhands/fix-agents-md-loading`

Feel free to include any additional details that might help me get this PR into a better state.

You can manage your notification settings

@xingyaoww
Copy link
Collaborator Author

@OpenHands please fix the failing actions on PR #1624 at branch openhands/fix-agents-md-loading

There's error with sdk-tests

@openhands-ai
Copy link

openhands-ai bot commented Jan 7, 2026

I'm on it! xingyaoww can track my progress at all-hands.dev

@xingyaoww xingyaoww added the review-this This label triggers a PR review by OpenHands label Jan 7, 2026
The tests were using load_skills_from_dir() which no longer loads
third-party files (claude.md, gemini.md) from the work directory.
After the refactoring, third-party file loading was moved to
load_project_skills() to ensure they are loaded even when the
.openhands/skills directory doesn't exist.

Updated tests to use load_project_skills(root) instead of
load_skills_from_dir(skills_dir) to properly test the vendor-specific
file gating functionality.

Co-authored-by: openhands <[email protected]>
@openhands-ai
Copy link

openhands-ai bot commented Jan 7, 2026

Summary

I fixed the failing sdk-tests in PR #1624 by updating the test file tests/sdk/context/test_agent_context_model_specific.py.

Problem

The tests were failing because they were using load_skills_from_dir(skills_dir) to load skills, but after the PR's refactoring, third-party file loading (claude.md, gemini.md) was moved from load_skills_from_dir() to load_project_skills(). This meant the tests weren't loading the vendor-specific files they were trying to test.

Fix

Changed the tests to use load_project_skills(root) instead of load_skills_from_dir(skills_dir):

  • Updated the import from load_skills_from_dir to load_project_skills
  • Modified all 5 test functions to call load_project_skills(root) which properly loads third-party files from the work directory

Verification

  • All 5 tests in test_agent_context_model_specific.py now pass
  • All 263 tests in tests/sdk/context/ pass
  • All 96 tests in tests/sdk/context/skill/ pass
  • Pre-commit hooks pass (ruff format, ruff lint, pycodestyle, pyright)

Changes pushed

Commit c85da1e3 has been pushed to the openhands/fix-agents-md-loading branch.

View full conversation

Copy link
Collaborator

@enyst enyst left a comment

Choose a reason for hiding this comment

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

Thank you!

@xingyaoww xingyaoww merged commit 9b75953 into main Jan 8, 2026
21 checks passed
@xingyaoww xingyaoww deleted the openhands/fix-agents-md-loading branch January 8, 2026 02:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review-this This label triggers a PR review by OpenHands

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants