feat: skills system - named prompt snippets with tool orchestration#5
Merged
Conversation
added 17 commits
April 6, 2026 17:19
Add skill system foundation with YAML frontmatter parsing: - src/skills/types.rs: FrontmatterData, SkillMetadata, and supporting enums - src/skills/frontmatter.rs: two-pass YAML parser with special char handling - 95 unit tests covering parsing, brace expansion, and edge cases
Add multi-level skill directory scanning and loading: - src/skills/paths.rs: path resolution (XDG user dir, project walk-up, git root) - src/skills/loader.rs: async skill loader with dedup, namespace, bare mode - Support SKILL.md directory format and legacy flat .md commands - 161 tests covering paths, loading, dedup, and edge cases
Add SkillTool as LLM-callable tool with inline execution:
- src/tools/skill.rs: SkillTool implementing Tool trait
- src/skills/executor.rs: inline content preparation with base dir header
- src/skills/substitution.rs: argument substitution ($ARGUMENTS, $n, $name,
${CLAUDE_SKILL_DIR}, ${CLAUDE_SESSION_ID}) with quote-aware parsing
- 94 new tests covering substitution, executor, and SkillTool execution
Add shell command parsing and execution for skill content: - src/skills/shell.rs: block (```!\n...\n```) and inline (!`...`) syntax - Parallel execution via join_all, output replaces original pattern - MCP skills blocked from shell execution (security) - executor.rs async-ified, skill.rs gains cwd field - 58 new tests covering parsing, execution, and edge cases
Add skill-level permission control with a 5-step decision chain: deny rules → allow rules → safe-properties → auto_approve → ask. - New SkillPermissionChecker with exact and prefix (namespace:*) matching - Deny rules always enforced, even when auto_approve is enabled - Skills with hooks or allowed-tools require explicit user approval - SkillsPermissionConfig in config.toml with global+project concat merge - SkillTool integrated with permission check before content preparation
Add ContextModifier mechanism allowing skills to override engine behavior (model, effort, allowed-tools) for subsequent turns. - New ContextModifier type with from_skill() builder - Tool trait gains context_modifier_for() default method - SkillTool overrides to return modifier from skill metadata - ToolCallOutcome wraps results + modifiers in orchestration layer - AgentEngine.apply_context_modifiers() updates model, effort, allow_list - ToolConfirmer.add_to_allow_list() for runtime permission grants - session_id wired through to SkillTool via with_session_id() - ToolResult struct unchanged (zero breakage to existing code)
Add fork execution path allowing skills with `context: fork` to spawn independent sub-agents. Introduces Spawner trait for testability, ForkOverrides for model/effort/allowed_tools propagation, and build_tool_registry filtering.
Add ConditionalSkillManager for path-based skill activation (dormant → active state machine with glob pattern matching) and RuntimeDiscovery for finding .aionrs/skills/ directories in subdirectories at runtime. - conditional.rs: partition_skills, activate_for_paths, reset_all - discovery.rs: discover_dirs_for_paths, add_skill_directories - loader.rs: load_skills_from_dir changed to pub(crate) - 55 new tests (14 inline + 41 supplemental), 641 total passing
Add skill listing with budget-controlled formatting to system prompt. - New src/skills/prompt.rs: three-level degradation (full → truncated → minimal) with unicode-width based display width for accurate CJK character handling - Modified build_system_prompt() to accept skills and inject <system-reminder> block - Filter skills with disable_model_invocation from prompt listing - Budget: 1% of context window × 4 chars/token (default 8000 chars) - Per-entry cap: 250 display-width characters - Bundled skills never truncated; non-bundled degrade gracefully
Add support for discovering skills from MCP servers via skill:// resources. MCP servers that declare resources capability are queried for skill:// URIs, parsed as Markdown with frontmatter, and merged into the skill list with bundled > MCP > local priority ordering.
Add SkillWatcher that monitors skill directories for filesystem changes and broadcasts version-stamped notifications via tokio::sync::watch channel. - notify v8 crate for cross-platform file watching (FSEvents/inotify) - 300ms debounce window coalesces rapid changes into single notification - Hidden file filtering (editor swap/temp files) - Metadata-only event filtering (macOS FSEvents quirk) - Dynamic directory addition via watch_directory() - Graceful stop with Drop impl cleanup - RuntimeDiscovery::clear_checked_dirs() for cache invalidation - 37 new tests (19 black-box + 18 white-box), 841 total passing
Fix SkillWatcher spurious notifications on macOS: FSEvents emits a Create(Folder) event on the watched directory itself when the watcher is first registered and again when a hidden file is written inside it. Add Create(Folder) to the should_ignore filter — directory creation is never a skill-relevant change, and this event type is not emitted by inotify on Linux, so the filter is safe cross-platform. Also update documentation: - AGENTS.md: add Skills module developer guide (submodule table, development conventions, test organization) - docs/skills.md: new user guide covering front matter reference, variable substitution, shell expansion, conditional activation, MCP skills, bundled skills, and prompt budget - README.md: add Skills to the feature list with link to docs/skills.md
Add 47 integration tests (19 black-box E2E + 28 white-box) covering the complete skill lifecycle: loading, variable substitution, shell execution, permissions, conditional activation, context modifiers, bundled skills, MCP skills, prompt budget, deduplication, legacy commands, and hooks parsing.
Add --skills-path flag that prints all skill directory paths with exists/not found status, matching the --config-path pattern. Add E2E tests (tests/skills_e2e.rs) that create real skill files in temp directories and verify the full pipeline: discovery, loading, variable substitution, shell expansion, system prompt injection, and SkillTool execution. Update docs/skills.md to show platform-specific config paths and reference the new --skills-path command.
Remove E12-E14 (user-level / add_dirs tests) since user-level and additional directory paths share the same load_skills_from_dir code already covered by unit tests. E2E tests now focus on the project-level scenario which is the primary use case.
piorpua
pushed a commit
that referenced
this pull request
Apr 9, 2026
🤖 I have created a release *beep* *boop* --- ## [0.1.3](v0.1.2...v0.1.3) (2026-04-09) ### Features * accept optional session ID in SessionManager::create and AgentEngine::init_session ([b5e50e8](b5e50e8)) * add --config-path flag and warn on config parse failure ([2f67ed8](2f67ed8)) * add --session-id flag and --resume support in json-stream mode ([6ecfa09](6ecfa09)) * add --version flag support for AionUi integration ([0d32f1f](0d32f1f)) * add ProviderCompat configuration layer (Phase 0.1) ([cc4a315](cc4a315)) * add session_id field to Ready protocol event ([f1025b5](f1025b5)) * Bedrock schema sanitization via compat config (Phase 1.4) ([7802f19](7802f19)) * compat-driven message alternation, merging, and auto tool ID (Phase 1.1, 1.8) ([9bd5b3c](9bd5b3c)) * **compat:** add configurable api_path for chat completions endpoint ([ad8b6e9](ad8b6e9)) * enhanced Bedrock error messages with actionable hints (Phase 2.1) ([a80d0ff](a80d0ff)) * initial commit of aionrs ([f8f3249](f8f3249)) * integrate ProviderCompat into config system (Phase 0.2) ([c0a4753](c0a4753)) * OpenAI compat features - max_tokens field, message merging, orphan cleanup, dedup, strip patterns (Phase 1.2, 1.3, 1.5, 1.6, 1.7) ([c61896d](c61896d)) * OpenAI reasoning model support (Phase 3.1) ([106108a](106108a)) * pass ProviderCompat to all providers (Phase 0.3) ([d9c6e1b](d9c6e1b)) * session ID and resume support for JSON stream mode ([d36df5e](d36df5e)) * skills system - named prompt snippets with tool orchestration ([#5](#5)) ([4a5183f](4a5183f)) * support custom provider aliases in configuration ([#2](#2)) ([9fde728](9fde728)) * wire up skills system in main.rs and fix symlink traversal ([f93303c](f93303c)) ### Bug Fixes * **ci:** fix invalid workflow files (matrix.if + YAML syntax) ([#6](#6)) ([4fd6de4](4fd6de4)) * **release:** bootstrap release-please for Cargo workspace ([#8](#8)) ([18dd3e3](18dd3e3)) ### Code Refactoring * remove Claude branding, use AGENTS.md and AIONRS_* variables ([97dc25c](97dc25c)) * split into Cargo workspace with fine-grained crates + CI/E2E ([#3](#3)) ([a4537d9](a4537d9)) ### Documentation * add AGENTS.md with architecture principles and CLAUDE.md reference ([5dfeb89](5dfeb89)) * document --session-id flag and session_id in Ready event ([510c141](510c141)) * replace hardcoded ~/.config/aionrs paths with --config-path ([d94d518](d94d518)) * update README with ProviderCompat layer and reasoning model support ([c831e21](c831e21)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
$ARGUMENTS,${CLAUDE_SKILL_DIR}), shell command expansion, conditional activation via glob paths, and permission rules.aionrs/skills/), user-level (<CONFIG_DIR>/aionrs/skills/), legacy commands (.aionrs/commands/), MCP servers, and bundled (compiled-in) sources with priority-based deduplication--skills-pathCLI command to display all skill directory paths with exists/not found statusPhases
--skills-pathCLI and E2E testsTest plan
cargo test— 860+ tests pass (588 skills unit/integration + others)cargo test --test skills_e2e— 11 E2E tests passcargo run -- --skills-path— prints skill directories with status.aionrs/skills/<name>/SKILL.mdand verify discovery