Skip to content

Support Agent Skills with the Ballerina Interpreter#13

Merged
RadCod3 merged 9 commits intowso2:agent-skillsfrom
MaryamZi:support-agent-skills
Mar 19, 2026
Merged

Support Agent Skills with the Ballerina Interpreter#13
RadCod3 merged 9 commits intowso2:agent-skillsfrom
MaryamZi:support-agent-skills

Conversation

@MaryamZi
Copy link
Member

@MaryamZi MaryamZi commented Mar 12, 2026

Purpose

$title.

Summary by CodeRabbit

  • New Features

    • Added local skills support enabling users to define and integrate custom skills with the interpreter.
    • Introduced skill discovery and activation system with resource management.
  • Documentation

    • Updated README with guidance and Docker examples for running with local skills.
  • Chores

    • Updated core dependencies and packages to latest versions.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 12, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6f309119-c3a8-4cc0-a2a9-61446ebf4993

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This pull request introduces a local skills system for the Ballerina interpreter. It adds skill discovery from local directories, YAML frontmatter parsing for SKILL.md files, a SkillsToolKit class for skill activation and resource access, comprehensive test coverage, new type definitions, and full integration into the agent creation flow with directory-based context passing.

Changes

Cohort / File(s) Summary
Dependency & Configuration Updates
ballerina-interpreter/Dependencies.toml, ballerina-interpreter/agent_template.afm.md
Updated distribution version (2201.12.7 → 2201.12.10), bumped data.xmldata (1.5.2 → 1.6.1) and ai.anthropic (1.3.0 → 1.3.1) versions; added file package modules. Added SKILLS section to AFM template with local skills path configuration.
Core Parser Refactoring
ballerina-interpreter/parser.bal
Extracted frontmatter extraction logic into new extractFrontmatter() function returning [map, string]|error; replaced inline YAML parsing with call to new function; updated AFMRecord construction and body parsing flow; extended validation for new SkillSource[] in metadata.
Type System Extensions
ballerina-interpreter/types.bal
Added LocalSkillSource record with 'type="local" and path fields; created SkillSource type alias; added SkillInfo record with name, description, body, basePath, resources; extended AgentMetadata with optional SkillSource[] skills field.
Skill Catalog System (New)
ballerina-interpreter/skills.bal
New 236-line implementation providing skill discovery, SKILL.md parsing with frontmatter validation, isolated SkillsToolKit class with activate_skill() and read_skill_resource() methods, catalog generation, resource listing with access controls, and comprehensive error handling and logging.
Agent Integration
ballerina-interpreter/agent.bal, ballerina-interpreter/main.bal
Updated createAgent() signature to accept afmFileDir parameter; added extractSkillCatalog() integration with conditional tool kit and instruction augmentation; refined getModel() with providerLower for case-insensitive comparisons; main.bal computes afmFileDir from AFM path and threads it through runAgentFromAFM().
Documentation & Example
ballerina-interpreter/README.md
Added documentation for running with local skills including Docker example with skills directory mount and afmFilePath setting; noted AFM path should be relative for local skills; updated project structure with skills.bal entry.
Test Infrastructure
ballerina-interpreter/tests/agent_test.bal, ballerina-interpreter/tests/skills_test.bal
Updated agent test calls to pass new afmFileDir parameter; added comprehensive 599-line test suite covering parseSkillMdContent, buildSkillCatalog, SkillsToolKit activation/resource reading, filesystem discovery, duplicate handling, progressive disclosure, and tool configuration.
Test Skill Fixtures
ballerina-interpreter/tests/skills/**/SKILL.md, ballerina-interpreter/tests/skills/multi_skills/security_review/assets/template.json, ballerina-interpreter/tests/skills/multi_skills/security_review/references/REFERENCE.md
Added comprehensive test fixtures across multiple skill scenarios: valid/invalid frontmatter, duplicate names, missing frontmatter, multi-skill sources, security review skill with template and OWASP reference, PR summary, test generation, and release notes skills.

Sequence Diagram(s)

sequenceDiagram
    participant Main as Main Entry
    participant AFMParser as AFM Parser
    participant SkillDisco as Skill Discovery
    participant SkillParse as SKILL.md Parser
    participant AgentBuilder as Agent Builder
    participant SkillsKit as SkillsToolKit
    participant AIAgent as AI Agent

    Main->>AFMParser: parseAfm(afmContent, afmFileDir)
    AFMParser->>AFMParser: extractFrontmatter(content)
    AFMParser->>Main: AFMRecord with metadata.skills

    Main->>AgentBuilder: createAgent(afmRecord, afmFileDir)
    AgentBuilder->>SkillDisco: extractSkillCatalog(metadata, afmFileDir)
    
    SkillDisco->>SkillDisco: discoverSkills(sources, afmFileDir)
    SkillDisco->>SkillParse: parseSkillMd(skillMdPath, basePath)
    SkillParse->>SkillParse: extractFrontmatter(skillContent)
    SkillParse->>SkillParse: listLocalResources(basePath)
    SkillParse->>SkillDisco: SkillInfo record
    
    SkillDisco->>SkillDisco: buildSkillCatalog(skills)
    SkillDisco->>AgentBuilder: [catalogText, SkillsToolKit]
    
    AgentBuilder->>AgentBuilder: Augment instructions & toolKits with catalog
    AgentBuilder->>AIAgent: create with effectiveInstructions & toolKits
    
    AIAgent->>SkillsKit: activate_skill(name)
    SkillsKit->>AIAgent: skill content + resources
    
    AIAgent->>SkillsKit: read_skill_resource(skillName, resourcePath)
    SkillsKit->>AIAgent: resource content
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 A skills garden grows so bright,
With SKILL.md files dancing in the light,
Frontmatter parsed, resources found,
SkillsToolKit stands its ground,
Local wisdom now takes flight!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is severely incomplete, containing only a single line '$title.' with no actual content addressing any required template sections such as Purpose, Goals, Approach, User stories, Release notes, or other documentation requirements. Provide a comprehensive description following the repository template, including Purpose, Goals, Approach, User stories, Release notes, Documentation, and other relevant sections to explain the feature implementation.
✅ Passed checks (2 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title 'Support Agent Skills - Take I' clearly describes the main feature being added across multiple files: a comprehensive agent skills system including skill discovery, catalog generation, resource management, and integration with the agent workflow.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Tip

You can disable poems in the walkthrough.

Disable the reviews.poem setting to disable the poems in the walkthrough.

@MaryamZi MaryamZi marked this pull request as ready for review March 13, 2026 09:06
@MaryamZi MaryamZi changed the base branch from main to agent-skills March 13, 2026 09:07
@MaryamZi MaryamZi changed the title Support Agent Skills - Take I Support Agent Skills with the Ballerina Interpreter Mar 13, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (5)
ballerina-interpreter/tests/skills/invalid_skill/SKILL.md (1)

1-4: Consider verifying complete test coverage for invalid field combinations.

The test suite now covers two invalid scenarios:

  1. Empty name with valid description (in partial_invalid/invalid_skill/)
  2. Both fields empty (this file)

Consider verifying that test coverage also includes the inverse case: valid name with empty description, if that's also an invalid scenario per the validation rules.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ballerina-interpreter/tests/skills/invalid_skill/SKILL.md` around lines 1 -
4, The test set currently has cases for empty name with valid description and
both fields empty (file SKILL.md under tests/skills/invalid_skill), so add or
verify a test for the inverse invalid case (valid name with empty description)
if validation rules treat an empty description as invalid; create a new test
file or update the invalid suite (e.g., under partial_invalid/invalid_skill/)
that supplies a non-empty name and an empty description and assert the same
validation failure path (same error type/message) as the other invalid cases to
ensure full coverage.
ballerina-interpreter/tests/skills_test.bal (1)

575-581: Redundant assertion.

Line 576 already asserts tools.length() == 2, making the assertion on line 580 redundant.

🔧 Suggested cleanup
     // Should return 2 tools: activate_skill and read_skill_resource
     test:assertEquals(tools.length(), 2);
 
     // Verify both tools are present by checking the function references
     // The tools array contains ToolConfig records with the function metadata
-    test:assertTrue(tools.length() == 2, "Should have exactly 2 tools");
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ballerina-interpreter/tests/skills_test.bal` around lines 575 - 581, The test
contains a redundant assertion: after calling test:assertEquals(tools.length(),
2) the later test:assertTrue(tools.length() == 2, "Should have exactly 2 tools")
duplicates the same check; remove the redundant test:assertTrue call (or replace
it with a different verification such as checking presence of function refs) so
only one assertion verifies tools.length(), referencing the tools variable and
the existing test:assertEquals assertion in the test function.
ballerina-interpreter/main.bal (1)

46-46: Consider edge case for root-level AFM files.

The computation correctly derives the parent directory for relative path resolution. However, if the AFM file is located at the filesystem root (e.g., /agent.afm.md), file:parentPath may return an empty string or /, which could affect skill path resolution.

This is a minor edge case unlikely to occur in practice, but worth noting.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ballerina-interpreter/main.bal` at line 46, The parent-path result for
afmFileDir (computed via file:parentPath(file:getAbsolutePath(fileToUse))) can
be empty for root-level AFM files; add a guard after computing afmFileDir to
detect an empty string (or a non-useful value such as "") and normalize it to
"/" (or another appropriate root indicator) so subsequent skill path resolution
uses a valid directory; update the code that sets string afmFileDir = check
file:parentPath(check file:getAbsolutePath(fileToUse)); to compute afmFileDir,
then if afmFileDir == "" set afmFileDir = "/" (and ensure any downstream joins
respect this normalized value).
ballerina-interpreter/skills.bal (2)

123-139: LGTM with minor note.

The error handling silently swallows failures when directories don't exist, which is intentional. However, this also hides permission errors on existing directories. The debug-level logging is sufficient for troubleshooting, but consider logging at warn level if the directory exists but is unreadable.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ballerina-interpreter/skills.bal` around lines 123 - 139, In
listLocalResources, the on-fail handler currently always logs a debug message,
which hides permission errors on existing directories; change the handler to
first check whether dirPath exists (use file:exists or equivalent for the
computed dirPath from file:joinPath) and if it exists but file:readDir failed,
log a warn (including the error e) instead of debug, otherwise keep the
debug-level log for non-existent dirs; update the on-fail block around
file:readDir/file:basename to perform that exists check and include the error
details in the log message.

45-61: Consider validating that skill paths are relative.

If source.path is an absolute path, file:joinPath may ignore afmFileDir entirely on some platforms, allowing skills to be loaded from arbitrary filesystem locations. If this is unintentional, add validation:

Suggested fix
 foreach SkillSource 'source in sources {
+    if check file:isAbsolutePath('source.path) {
+        return error(string `Skill path must be relative: ${'source.path}`);
+    }
     string resolvedPath = check file:joinPath(afmFileDir, 'source.path);

If loading from absolute paths is intentional, this can be ignored.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ballerina-interpreter/skills.bal` around lines 45 - 61, The discoverSkills
function currently joins afmFileDir with source.path via file:joinPath which can
be bypassed if source.path is absolute; update discoverSkills to validate that
each SkillSource's 'source.path is a relative path before joining (use a
platform-aware check such as file:isAbsolutePath or equivalent) and return an
error or skip the entry if it's absolute; ensure you perform this check right
before calling file:joinPath and reference the same symbols (discoverSkills,
SkillSource, 'source.path, file:joinPath, discoverLocalSkills) so absolute paths
are rejected or handled consistently rather than allowing arbitrary filesystem
access.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@ballerina-interpreter/main.bal`:
- Line 46: The parent-path result for afmFileDir (computed via
file:parentPath(file:getAbsolutePath(fileToUse))) can be empty for root-level
AFM files; add a guard after computing afmFileDir to detect an empty string (or
a non-useful value such as "") and normalize it to "/" (or another appropriate
root indicator) so subsequent skill path resolution uses a valid directory;
update the code that sets string afmFileDir = check file:parentPath(check
file:getAbsolutePath(fileToUse)); to compute afmFileDir, then if afmFileDir ==
"" set afmFileDir = "/" (and ensure any downstream joins respect this normalized
value).

In `@ballerina-interpreter/skills.bal`:
- Around line 123-139: In listLocalResources, the on-fail handler currently
always logs a debug message, which hides permission errors on existing
directories; change the handler to first check whether dirPath exists (use
file:exists or equivalent for the computed dirPath from file:joinPath) and if it
exists but file:readDir failed, log a warn (including the error e) instead of
debug, otherwise keep the debug-level log for non-existent dirs; update the
on-fail block around file:readDir/file:basename to perform that exists check and
include the error details in the log message.
- Around line 45-61: The discoverSkills function currently joins afmFileDir with
source.path via file:joinPath which can be bypassed if source.path is absolute;
update discoverSkills to validate that each SkillSource's 'source.path is a
relative path before joining (use a platform-aware check such as
file:isAbsolutePath or equivalent) and return an error or skip the entry if it's
absolute; ensure you perform this check right before calling file:joinPath and
reference the same symbols (discoverSkills, SkillSource, 'source.path,
file:joinPath, discoverLocalSkills) so absolute paths are rejected or handled
consistently rather than allowing arbitrary filesystem access.

In `@ballerina-interpreter/tests/skills_test.bal`:
- Around line 575-581: The test contains a redundant assertion: after calling
test:assertEquals(tools.length(), 2) the later test:assertTrue(tools.length() ==
2, "Should have exactly 2 tools") duplicates the same check; remove the
redundant test:assertTrue call (or replace it with a different verification such
as checking presence of function refs) so only one assertion verifies
tools.length(), referencing the tools variable and the existing
test:assertEquals assertion in the test function.

In `@ballerina-interpreter/tests/skills/invalid_skill/SKILL.md`:
- Around line 1-4: The test set currently has cases for empty name with valid
description and both fields empty (file SKILL.md under
tests/skills/invalid_skill), so add or verify a test for the inverse invalid
case (valid name with empty description) if validation rules treat an empty
description as invalid; create a new test file or update the invalid suite
(e.g., under partial_invalid/invalid_skill/) that supplies a non-empty name and
an empty description and assert the same validation failure path (same error
type/message) as the other invalid cases to ensure full coverage.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9ebd02d5-d64e-4256-b21f-5b27fbcbb517

📥 Commits

Reviewing files that changed from the base of the PR and between 1493056 and 5a025fa.

📒 Files selected for processing (24)
  • ballerina-interpreter/Dependencies.toml
  • ballerina-interpreter/README.md
  • ballerina-interpreter/agent.bal
  • ballerina-interpreter/main.bal
  • ballerina-interpreter/parser.bal
  • ballerina-interpreter/skills.bal
  • ballerina-interpreter/tests/agent_test.bal
  • ballerina-interpreter/tests/skills/duplicate_names/error_translator/SKILL.md
  • ballerina-interpreter/tests/skills/duplicate_names/error_translator_dup/SKILL.md
  • ballerina-interpreter/tests/skills/empty_dir/.gitkeep
  • ballerina-interpreter/tests/skills/invalid_skill/SKILL.md
  • ballerina-interpreter/tests/skills/multi_skills/pr_summary/SKILL.md
  • ballerina-interpreter/tests/skills/multi_skills/security_review/SKILL.md
  • ballerina-interpreter/tests/skills/multi_skills/security_review/assets/template.json
  • ballerina-interpreter/tests/skills/multi_skills/security_review/references/REFERENCE.md
  • ballerina-interpreter/tests/skills/no_frontmatter/SKILL.md
  • ballerina-interpreter/tests/skills/partial_invalid/invalid_skill/SKILL.md
  • ballerina-interpreter/tests/skills/partial_invalid/valid_skill/SKILL.md
  • ballerina-interpreter/tests/skills/single_skill/SKILL.md
  • ballerina-interpreter/tests/skills/source1/release_notes/SKILL.md
  • ballerina-interpreter/tests/skills/source2/release_notes/SKILL.md
  • ballerina-interpreter/tests/skills_test.bal
  • ballerina-interpreter/types.bal
  • templates/agent_template.afm.md

@MaryamZi MaryamZi requested a review from Copilot March 13, 2026 09:16
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds support for Agent Skills (AgentSkills format) to the Ballerina interpreter, including local skill discovery, progressive activation, and resource access.

Changes:

  • Introduces new skill-related types and AFM metadata (skills:) plus a local skills discovery/activation toolkit.
  • Refactors frontmatter parsing into a shared extractFrontmatter() utility and extends validation for http: variables into skill paths.
  • Adds extensive fixtures + tests for discovery, duplicate handling, progressive disclosure, and resource reading; updates docs/template and bumps dependencies.

Reviewed changes

Copilot reviewed 23 out of 24 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
templates/agent_template.afm.md Adds an optional skills: section example for AFM authors.
ballerina-interpreter/types.bal Defines skill source + skill info records; adds skills? to agent metadata.
ballerina-interpreter/skills.bal Implements local skill discovery, catalog building, and skill/resource AgentTools.
ballerina-interpreter/parser.bal Replaces inline AFM frontmatter parsing with extractFrontmatter() and validates skills.path for http: vars.
ballerina-interpreter/agent.bal Wires discovered skills into agent instructions and toolkits; minor model/provider cleanup.
ballerina-interpreter/main.bal Passes AFM directory into agent creation so relative skill paths resolve correctly.
ballerina-interpreter/tests/agent_test.bal Updates integration tests to pass afmFileDir into runAgentFromAFM.
ballerina-interpreter/tests/skills_test.bal Adds unit + fixture-based tests covering skill parsing, discovery, duplicates, and progressive disclosure.
ballerina-interpreter/tests/skills/** Adds skill fixtures (SKILL.md) + resources (references/assets) used by tests.
ballerina-interpreter/README.md Documents running the container with skills mounted and path expectations.
ballerina-interpreter/Dependencies.toml Bumps Ballerina distribution and selected packages; adds ballerina/file dependency.

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

You can also share your feedback on Copilot code review. Take the survey.

@MaryamZi MaryamZi requested a review from Copilot March 16, 2026 09:30
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds support for “Agent Skills” (local skill discovery + activation tooling) to the Ballerina interpreter, and updates the CLI/runtime flow to resolve skills relative to the AFM file location.

Changes:

  • Introduces skill source / skill info types and a skills discovery + toolkit implementation.
  • Updates agent creation/runtime to load skills and append a skills catalog to the system instructions.
  • Adds extensive tests and fixtures covering skill parsing, discovery, progressive disclosure, and security/path validation.

Reviewed changes

Copilot reviewed 25 out of 26 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
templates/agent_template.afm.md Adds an optional skills: section to the AFM template.
ballerina-interpreter/web_chat_ui.bal Allows web UI metadata to be optional and safely dereferenced.
ballerina-interpreter/types.bal Introduces skill-related types and makes AFM metadata optional.
ballerina-interpreter/skills.bal Implements local skill discovery, catalog generation, and agent tools.
ballerina-interpreter/parser.bal Refactors frontmatter parsing and adds extractFrontMatter() helper.
ballerina-interpreter/main.bal Passes AFM file directory into agent creation to resolve relative skill paths.
ballerina-interpreter/agent.bal Appends skill catalog to instructions and registers the Skills toolkit.
ballerina-interpreter/tests/skills_test.bal Adds comprehensive unit/E2E tests for skills behavior and validation.
ballerina-interpreter/tests/main_test.bal Updates AFM parsing tests to match optional metadata behavior.
ballerina-interpreter/tests/agent_test.bal Updates agent start helper to pass a base directory for skills resolution.
ballerina-interpreter/tests/skills/** Adds SKILL.md fixtures, resources, and duplicate/invalid skill scenarios.
ballerina-interpreter/README.md Documents running with skills via Docker and relative-path expectations.
ballerina-interpreter/Dependencies.toml Bumps distribution/deps and adds file module dependency.

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

You can also share your feedback on Copilot code review. Take the survey.

@MaryamZi MaryamZi requested a review from RadCod3 March 19, 2026 05:04
@RadCod3 RadCod3 merged commit 086bc07 into wso2:agent-skills Mar 19, 2026
2 checks passed
@MaryamZi MaryamZi deleted the support-agent-skills branch March 19, 2026 05:20
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.

3 participants