Using and Organizing Skills
In AI4J, a Skill is not "a special tool," nor is it "a large template that auto-injects a complete prompt."
Along the Coding Agent path, its more precise definition is:
- A human-readable workflow description that lives on the file system
- Discovered as a summary at session startup
- Read on demand by the model from
SKILL.mdwhen a task actually matches
So it solves "how to reuse experience," not "how to execute actions."
1. The real position of Skills in the Coding Agent
Compressing the startup chain into a single line makes it easiest to follow:
DefaultCodingCliAgentFactory.buildWorkspaceContext(...)
-> CodingAgentBuilder.build()
-> CodingSkillDiscovery.enrich(workspaceContext)
-> Skills.discoverDefault(workspaceRoot, skillDirectories)
-> WorkspaceContext.availableSkills + allowedReadRoots
-> CodingContextPromptAssembler.mergeSystemPrompt(...)
-> The model first sees the skills summary, then read_file's the relevant SKILL.md on demand
The key point here is not "how many skills were discovered," but that two things happen at once:
availableSkillsis written back intoWorkspaceContextfor prompt assembly and/skillsdisplayallowedReadRootsis also written back intoWorkspaceContext, so skill root directories can be read byread_file
This shows that in the current implementation the skill system is not a pure documentation scanner, but part of the workspace permission model.
2. How the discovery chain actually runs
CodingSkillDiscovery.discover(...) itself is very thin; it just hands WorkspaceContext off to Skills.discoverDefault(...).
The real discovery logic lives in ai4j/skill/Skills.java:
- Normalize the workspace root
- Resolve skill roots
- Scan for skills under each root
- Build a
SkillDescriptor - Deduplicate by name
- Collect
allowedReadRoots
The default root order is:
<workspace>/.ai4j/skills~/.ai4j/skillsskillDirectoriesconfigured inworkspace.json
The resolution rules for skillDirectories are straightforward:
- Absolute paths are used as-is
- Relative paths are resolved against the workspace root
An important consequence:
- Skills inside the workspace and skills under the user home can coexist naturally
- Team-shared skill bundles can be mounted in via
skillDirectories - But whether they actually take effect still depends on the name-dedup result, not "later-mounted always overrides earlier-mounted"
3. The scanning rules are more conservative than many assume
Skills.discoverFromRoot(...) does not recursively walk the entire directory tree.
Its rules are:
3.1 The root itself is a skill
If a SKILL.md or skill.md exists directly under a root directory, that root itself is treated as a skill.
Once this rule hits, the subdirectories of the current root are not scanned again as skill containers.
This means:
- A directory is either treated as "the skill body"
- Or as "a skill container"
The current implementation never consumes it as both at once.
3.2 Otherwise, only the first level of subdirectories is checked
If the root itself is not a skill, this round only checks its direct subdirectories for SKILL.md / skill.md.
It does not recurse into deeper levels.
So:
skills/sql-review/SKILL.mdis discoveredskills/backend/sql-review/SKILL.mdis not discovered by default
If you want hierarchical organization, you can only do it via "multiple roots," not via "deeply nested directories."
4. Which fields in SKILL.md actually get read
The current descriptor construction logic is in Skills.buildDescriptor(...).
It only extracts a few stable fields:
namedescriptionskillFilePathsource
The resolution priority for name is:
namein the front matter- The first markdown heading
- The parent directory name of the skill file
The resolution priority for description is:
descriptionin the front matter- The first body paragraph
- The default copy
No description available.
The design behind this is pragmatic:
- Front matter is the most stable structured metadata
- Omitting front matter does not disable the skill entirely
- But missing
name/descriptiondirectly lowers the chance of a skill being matched and displayed correctly
A minimal, most-robust example is still recommended:
---
name: sql-review
description: Review SQL changes with indexing, execution-plan, and migration risk checks.
---
# SQL Review
Use this skill when the task involves SQL schema or query review.
5. The dedup rules decide "who wins"
Skills.discover(...) normalizes skill names with trim + lowercase, then keeps the descriptor for the first occurrence of a name.
This means deduplication is:
- Case-insensitive
- First-win, not last-win
- Content is not merged; only the first descriptor is kept
Combined with the default root order, the actual effect today is usually:
- Workspace skills take precedence
- Home skills come next
- Extra mounted directories come last
If you put skills with the same name in multiple roots, the later one is typically shadowed silently rather than producing an error.
This is completely different from MCP conflict handling.
- Same-named skill: usually the first one is kept
- Same-named MCP tool: the server is treated as an error outright
The reason is simple:
- Skills are prompt-layer knowledge
- MCP is execution-layer capability
Execution-layer conflicts must be stricter.
6. What the model actually sees in the prompt
CodingContextPromptAssembler.mergeSystemPrompt(...) does not splice each skill's body directly into the system prompt.
What it does:
- Build the workspace prompt
- Append built-in tool rules
- Call
Skills.buildAvailableSkillsPrompt(...) - Put only the skill summary list into the prompt
The information currently spliced in is of this kind:
- skill name
- file path
- description
- "Do not read every skill up front; only read_file the corresponding
SKILL.mdwhen there is an obvious match"
This point is critical.
The current skill mechanism is not:
- Dumping every experience bundle into the model's context at startup
But rather:
- Exposing a "catalog of available skills" at startup
- Letting the model decide at runtime whether to read a given skill's body
The direct payoffs:
- The first-turn prompt does not bloat linearly with the number of skills
- Skill bodies can be written longer without polluting the context every time
- The model is more likely to treat skills as "knowledge packs read on demand" rather than "global rules permanently bound to the system"
7. Why skills affect the file-read boundary
CodingSkillDiscovery.enrich(...) does not only write availableSkills; it also writes the allowedReadRoots returned by discovery back into WorkspaceContext.
And WorkspaceContext has two path semantics:
resolveWorkspacePath(...)resolveReadablePath(...)
The distinction matters:
resolveWorkspacePath(...)by default allows only paths inside the workspaceresolveReadablePath(...)also acceptsallowedReadRootsin addition to the workspace
So the real permission model for skill root directories today is:
- Read is allowed
- Write is not automatically allowed
- Execute is not automatically allowed either
That is why team-shared skills can live in a directory outside the workspace yet still be opened normally by read_file.
It also shows:
- Skills are an excepted read path on the "knowledge input surface"
- Not "granting the model arbitrary external file access"
8. What the /skills command actually exposes
The /skills output in the CLI/TUI is not the skill body; it is the discovery result.
The current CodingCliSessionRunner.renderSkillsOutput(...) shows:
- count
- workspaceConfig path
- roots
- each skill's
name / source / path / description
/skills <name> shows for a single skill:
- name
- source
- path
- description
- roots
There are two practical implications:
/skillsis more an "index view" than a "reading view"- If you can see a skill summary but the model still does not use it, the problem is usually not discovery but matching and prompt strategy
9. The most common failure paths
9.1 Skill placed too deep
Discovery today scans only the root or the first level of subdirectories.
A deeper SKILL.md is not discovered by default.
9.2 name and description not written clearly
Although there is a heading / paragraph fallback, match quality drops noticeably, especially when multiple skills cover similar topics.
9.3 Same-named skill shadowed silently
If skills with the same name exist in workspace, home, and shared roots, the later-discovered one does not error; it simply never enters the final list.
9.4 Treating skills as a privilege-escalation lever
A skill only extends readable roots; it does not automatically open write access, nor does it bypass the write boundary enforced by allowOutsideWorkspace.
9.5 Treating skills as automatic executors
A skill itself performs no actions. Actual execution still relies on:
read_filebashwrite_fileapply_patch- or MCP tools
10. When to use a Skill, and when not to
The most reliable criterion: are you capturing "how to do it," or exposing "a capability."
Scenarios better suited to Skills
- Code review standards
- SQL review checklists
- Engineering conventions for a class of frameworks
- Multi-step troubleshooting playbooks
- Documentation writing or release processes
Scenarios better suited to Tools / MCP
- Genuinely needing to execute commands
- Genuinely needing to read and write external systems
- Genuinely needing to call databases, browsers, search, or internal platform APIs
Scenarios better suited to Agent Definitions
- Needing a fixed model, fixed system prompt, fixed handoff policy
- Needing to turn a class of workers into delegable subagents
One-line mnemonic:
- Skills define "how to do it"
- Tools/MCP provide "the hands that do it"
- Agent Definitions fix "the identity and boundary of that class of worker"
11. Which entry points to look at first when extending or troubleshooting
If you want to extend the skill system further, the entry points worth looking at first are:
ai4j-coding/.../CodingSkillDiscoveryai4j/.../skill/Skillsai4j-coding/.../workspace/WorkspaceContextai4j-coding/.../prompt/CodingContextPromptAssemblerai4j-cli/.../runtime/CodingCliSessionRunner.renderSkillsOutput
The recommended troubleshooting order is:
- Run
/skillsto see whether it was discovered - Check whether the root path is actually in
roots - Check whether
nameconflicts with another skill - Check whether the skill file sits at the root or the first level of subdirectories
- Check whether the model only saw the summary but did not proceed to
read_file
12. The conclusions most worth remembering from this page
- In the current implementation a Skill is "file-based workflow knowledge," not an executor
CodingSkillDiscoverydoes not just scan; it populates bothavailableSkillsandallowedReadRootsat once- Discovery by default looks only at the root itself or the first level of subdirectories; it does not recurse deeply
- Same-named skills are kept first-win; later ones are typically shadowed silently
- The prompt carries only summaries by default, not full skill bodies
- Skills can extend readable paths, but they do not extend write or execute permissions