Skip to content

feat: skills system - named prompt snippets with tool orchestration#5

Merged
piorpua merged 17 commits into
mainfrom
feat/skills
Apr 8, 2026
Merged

feat: skills system - named prompt snippets with tool orchestration#5
piorpua merged 17 commits into
mainfrom
feat/skills

Conversation

@piorpua
Copy link
Copy Markdown
Collaborator

@piorpua piorpua commented Apr 8, 2026

Summary

  • Add complete skills system: named prompt snippets that the agent can invoke on demand, supporting YAML frontmatter, variable substitution ($ARGUMENTS, ${CLAUDE_SKILL_DIR}), shell command expansion, conditional activation via glob paths, and permission rules
  • Support skill loading from project-level (.aionrs/skills/), user-level (<CONFIG_DIR>/aionrs/skills/), legacy commands (.aionrs/commands/), MCP servers, and bundled (compiled-in) sources with priority-based deduplication
  • Implement context modifiers (model/effort/allowedTools overrides), skill hooks (PreToolUse/PostToolUse/Stop), fork-mode execution via sub-agent spawning, file change detection (watcher), and system prompt budget-aware skill listing
  • Add --skills-path CLI command to display all skill directory paths with exists/not found status
  • Include 588 unit/integration tests and 11 E2E tests covering the full pipeline

Phases

  1. Core skill types and frontmatter parser
  2. Directory discovery and skill loading
  3. SkillTool and inline execution engine
  4. Shell command execution in skills
  5. Skill permission system
  6. Context modifier system for skill overrides
  7. Fork mode execution for skills
  8. Conditional skill activation and runtime discovery
  9. System prompt integration and skill listing
  10. Bundled skills framework
  11. Skill hooks integration
  12. MCP skills discovery and loading
  13. Skill file change detection
  14. Integration tests and documentation
  15. --skills-path CLI and E2E tests

Test plan

  • cargo test — 860+ tests pass (588 skills unit/integration + others)
  • cargo test --test skills_e2e — 11 E2E tests pass
  • cargo run -- --skills-path — prints skill directories with status
  • Place a SKILL.md in .aionrs/skills/<name>/SKILL.md and verify discovery

zynx 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 piorpua merged commit 4a5183f into main Apr 8, 2026
@piorpua piorpua deleted the feat/skills branch April 8, 2026 05:01
@github-actions github-actions Bot mentioned this pull request Apr 9, 2026
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>
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.

1 participant