Add a skill tool that loads specialized instructions from markdown files.
Skills are domain-specific instruction sets that jr can load when working on specific types of tasks. For example:
data SkillArgs = SkillArgs
{ skillName :: Text -- Name of the skill to load
}
deriving (Show, Eq, Generic)
Skills are stored in Omni/Agent/Skills/ as markdown files:
Omni/Agent/Skills/haskell-refactoring.mdOmni/Agent/Skills/python-testing.mdskillTool :: Engine.Tool
skillTool = Engine.Tool
{ Engine.toolName = "skill",
Engine.toolDescription = "Load specialized instructions for a domain. Available skills: haskell-refactoring, python-testing, database-migrations.",
Engine.toolJsonSchema = ...,
Engine.toolExecute = executeSkill
}
1. Parse the skill name
2. Construct path: Omni/Agent/Skills/<name>.md
3. Check if file exists
4. If yes, read and return the content
5. If no, return error listing available skills
executeSkill :: Aeson.Value -> IO Aeson.Value
executeSkill v = do
case Aeson.fromJSON v of
Aeson.Error e -> pure (mkError (Text.pack e))
Aeson.Success args -> do
let name = skillName args
path = "Omni/Agent/Skills/" <> Text.unpack name <> ".md"
exists <- Directory.doesFileExist path
if exists
then do
content <- TextIO.readFile path
pure (mkSuccess content)
else do
-- List available skills
files <- Directory.listDirectory "Omni/Agent/Skills/"
let skills = [Text.pack (dropExtension f) | f <- files, ".md" `isSuffixOf` f]
pure (mkError ("Skill not found. Available: " <> Text.intercalate ", " skills))
{
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Name of the skill to load (e.g., haskell-refactoring, python-testing)"
}
},
"required": ["name"]
}
Create these starter skill files:
# Haskell Refactoring Skill
## Safe Refactoring Patterns
1. When splitting modules:
- Create the new module first with all needed imports
- Export the symbols from the new module
- Update the original to re-export from the new module
- Only after tests pass, remove the re-exports if desired
2. When renaming functions:
- Use search_codebase to find ALL usages first
- Update the definition and all call sites atomically
3. Common import patterns in this codebase:
- `import Alpha` provides the custom prelude
- Use qualified imports for Data.Text, Data.Aeson, etc.
# Python Testing Skill
## Testing Patterns
1. Tests are inline in the same file, in a `test()` function
2. Use the pattern: `def test() -> int:` returning exit code
3. Run tests with: `bild --test <namespace>`
1. Create the Skills directory 2. Create at least one skill file 3. Test that skill tool can load it 4. Test error message when skill not found