agent_skill_parser 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/CHANGELOG.md +5 -1
  4. data/README.md +2 -1
  5. data/doc/AgentSkillParser/AllowedTool.md +28 -0
  6. data/doc/AgentSkillParser/AllowedToolsParser.md +33 -0
  7. data/doc/AgentSkillParser/DocumentSplitter/RawYamlDocument.md +20 -0
  8. data/doc/AgentSkillParser/DocumentSplitter.md +42 -0
  9. data/doc/AgentSkillParser/Errors/Base.md +8 -0
  10. data/doc/AgentSkillParser/Errors/Parser.md +18 -0
  11. data/doc/AgentSkillParser/Errors/Validation.md +19 -0
  12. data/doc/AgentSkillParser/Errors.md +7 -0
  13. data/doc/AgentSkillParser/Frontmatter.md +50 -0
  14. data/doc/AgentSkillParser/FrontmatterParser.md +26 -0
  15. data/doc/AgentSkillParser/Parser.md +35 -0
  16. data/doc/AgentSkillParser/Skill.md +35 -0
  17. data/doc/AgentSkillParser/Validator.md +37 -0
  18. data/doc/AgentSkillParser.md +98 -0
  19. data/doc/index.csv +51 -0
  20. data/lib/agent_skill_parser/allowed_tool.rb +4 -4
  21. data/lib/agent_skill_parser/allowed_tools_parser.rb +5 -2
  22. data/lib/agent_skill_parser/document_splitter.rb +7 -2
  23. data/lib/agent_skill_parser/errors/base.rb +0 -2
  24. data/lib/agent_skill_parser/errors/parser.rb +3 -3
  25. data/lib/agent_skill_parser/errors/validation.rb +2 -2
  26. data/lib/agent_skill_parser/errors.rb +0 -4
  27. data/lib/agent_skill_parser/frontmatter.rb +3 -4
  28. data/lib/agent_skill_parser/frontmatter_parser.rb +4 -0
  29. data/lib/agent_skill_parser/parser.rb +2 -6
  30. data/lib/agent_skill_parser/skill.rb +0 -2
  31. data/lib/agent_skill_parser/validator.rb +15 -8
  32. data/lib/agent_skill_parser/version.rb +1 -1
  33. data/lib/agent_skill_parser.rb +1 -2
  34. data/llm.txt +98 -0
  35. metadata +18 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bb27507d0523f0c0bb623a65b8817074f30f0c33bf415acfa29c16dd25e4d999
4
- data.tar.gz: 13913b040ccc6fd706c9ed5d7bd79d00ef6d1ca46c988fa6d5033e06db9dfc68
3
+ metadata.gz: 2224c369e94618cede997892493c8b809422e05668f0101fabf02eecd5b41859
4
+ data.tar.gz: f7f78dbcd3e8784e97ecf66264895f2dc1869c6ca7a2f3f8b6893617b8199b01
5
5
  SHA512:
6
- metadata.gz: 2ba5711dcaa15a855e53a45332f420c3d0c917e3d784468060ed3f7ce4c109eedbf90bdd88f04845402d165b55704403c63b40324cb641020dfd5dea6ee0fba3
7
- data.tar.gz: 2b40d143d5f582a5d805887511d726dd849fffa5fced18f3f47bd11b1826e8a41503a32d4b69bcf681e236c9bbd06c2ec7518dbef9ee7f399994f2b5ec33ecac
6
+ metadata.gz: 5005b0fe0044f0950c9386cc238b030b4165b72f9a85de12385e8d0f44ee1f374bd15fbe6f04b5cd89a37079b77865cca0c66353f12c3ec35aad8e3718ededef
7
+ data.tar.gz: fcc54de836504d1afdbb8f7afb9ee0c7ff4e5d8f348f41599609935256482b6f80b2d353333aa378da7c6e15a8681f56aecfce915f3641bb4e5687f6c1faa85e
data/.yardopts CHANGED
@@ -9,4 +9,4 @@ lib/**/*.rb
9
9
  -
10
10
  README.md
11
11
  CHANGELOG.md
12
- LICENSE.txt
12
+ LICENSE
data/CHANGELOG.md CHANGED
@@ -1,4 +1,8 @@
1
- ## [Unreleased]
1
+ ## [0.2.0] - 2026-02-01
2
+
3
+ - Added `generate_llm.rb` script to generate LLM content
4
+ - Improved documentation across all modules
5
+ - Generated LLM.txt documentation file
2
6
 
3
7
  ## [0.1.0] - 2026-01-29
4
8
 
data/README.md CHANGED
@@ -3,7 +3,8 @@
3
3
  A Ruby gem for parsing skill files that use YAML frontmatter and markdown body content. Designed for agent/AI systems where skills are defined as structured markdown documents with metadata.
4
4
 
5
5
  Warning:
6
- - This gem does not protect against Prompt Injection. It only parses the structure of the skill according with the specification from https://agentskills.io/specification
6
+ - This gem does not protect against Prompt Injection so if you read with this a skill file and pipe it through an LLM it will send there the exact skill file without any filtering.
7
+ - It only parses the structure of the skill according with the specification from https://agentskills.io/specification
7
8
 
8
9
  ## Installation
9
10
 
@@ -0,0 +1,28 @@
1
+ # Class: AgentSkillParser::AllowedTool
2
+ **Inherits:** Data
3
+
4
+
5
+ Represents an allowed tool with optional regex pattern. Pattern is used to
6
+ match tool arguments in skill files (e.g., git:* for git commands).
7
+
8
+
9
+ **@example**
10
+ ```ruby
11
+ AllowedTool.new(name: "search_files", pattern: "\\.(rb|js)$")
12
+ ```
13
+ **@example**
14
+ ```ruby
15
+ AllowedTool.new(name: "bash", pattern: nil)
16
+ ```
17
+ # Attributes
18
+ ## name[RW] [](#attribute-i-name)
19
+ Returns the value of attribute name
20
+
21
+ **@return** [Object] the current value of name
22
+
23
+ ## pattern[RW] [](#attribute-i-pattern)
24
+ Returns the value of attribute pattern
25
+
26
+ **@return** [Object] the current value of pattern
27
+
28
+
@@ -0,0 +1,33 @@
1
+ # Class: AgentSkillParser::AllowedToolsParser
2
+ **Inherits:** Object
3
+
4
+
5
+ Parses tool names with optional regex patterns for arguments.
6
+
7
+ Format: `ToolName` or `ToolName(pattern)` where pattern is optional. Multiple
8
+ tools are space or comma separated.
9
+
10
+
11
+ **@example**
12
+ ```ruby
13
+ parser = AllowedToolsParser.new("bash, search_files(\\.rb$)")
14
+ parser.call
15
+ # => [
16
+ # AllowedTool.new(name: "bash", pattern: nil),
17
+ # AllowedTool.new(name: "search_files", pattern: "\\.rb$")
18
+ # ]
19
+ ```
20
+
21
+ # Instance Methods
22
+ ## call() [](#method-i-call)
23
+
24
+ **@return** [Array<AllowedTool>] parsed tool definitions
25
+
26
+ **@see** []
27
+
28
+ ## initialize(string) [](#method-i-initialize)
29
+
30
+ **@param** [String] comma-separated tool list
31
+
32
+ **@return** [AllowedToolsParser] a new instance of AllowedToolsParser
33
+
@@ -0,0 +1,20 @@
1
+ # Class: AgentSkillParser::DocumentSplitter::RawYamlDocument
2
+ **Inherits:** Data
3
+
4
+
5
+ Represents a raw YAML document with separated YAML frontmatter and body. Used
6
+ as an intermediate structure during parsing.
7
+
8
+
9
+ # Attributes
10
+ ## body[RW] [](#attribute-i-body)
11
+ Returns the value of attribute body
12
+
13
+ **@return** [Object] the current value of body
14
+
15
+ ## yaml_string[RW] [](#attribute-i-yaml_string)
16
+ Returns the value of attribute yaml_string
17
+
18
+ **@return** [Object] the current value of yaml_string
19
+
20
+
@@ -0,0 +1,42 @@
1
+ # Class: AgentSkillParser::DocumentSplitter
2
+ **Inherits:** Object
3
+
4
+
5
+ Splits a markdown document into YAML frontmatter and body.
6
+
7
+
8
+ **@example**
9
+ ```ruby
10
+ splitter = DocumentSplitter.new("---\nname: skill\n---\n# Body")
11
+ result = splitter.call
12
+ result.yaml_string # => "name: skill"
13
+ result.body # => "# Body"
14
+ ```
15
+ **@example**
16
+ ```ruby
17
+ splitter = DocumentSplitter.new("# Just body")
18
+ result = splitter.call
19
+ result.yaml_string # => ""
20
+ result.body # => "# Just body"
21
+ ```
22
+ # Attributes
23
+ ## body[RW] [](#attribute-i-body)
24
+
25
+ **@return** [String] Markdown body content
26
+
27
+ ## yaml_string[RW] [](#attribute-i-yaml_string)
28
+
29
+ **@return** [String] YAML frontmatter content
30
+
31
+
32
+ # Instance Methods
33
+ ## call() [](#method-i-call)
34
+
35
+ **@return** [RawYamlDocument]
36
+
37
+ ## initialize(text) [](#method-i-initialize)
38
+
39
+ **@param** [String] full document content
40
+
41
+ **@return** [DocumentSplitter] a new instance of DocumentSplitter
42
+
@@ -0,0 +1,8 @@
1
+ # Exception: AgentSkillParser::Errors::Base
2
+ **Inherits:** StandardError
3
+
4
+
5
+ Base class for all parser exceptions.
6
+
7
+
8
+
@@ -0,0 +1,18 @@
1
+ # Exception: AgentSkillParser::Errors::Parser
2
+ **Inherits:** AgentSkillParser::Errors::Base
3
+
4
+
5
+ Raised when parsing fails.
6
+
7
+ Raised for: invalid YAML, missing frontmatter, file not found
8
+
9
+
10
+ **@example**
11
+ ```ruby
12
+ begin
13
+ AgentSkillParser.parse("invalid.md")
14
+ rescue AgentSkillParser::Errors::Parser => e
15
+ puts "Parsing error: #{e.message}"
16
+ end
17
+ ```
18
+
@@ -0,0 +1,19 @@
1
+ # Exception: AgentSkillParser::Errors::Validation
2
+ **Inherits:** AgentSkillParser::Errors::Base
3
+
4
+
5
+ Raised when frontmatter validation fails.
6
+
7
+ Raised for: invalid name format, description too long/short, compatibility too
8
+ long
9
+
10
+
11
+ **@example**
12
+ ```ruby
13
+ begin
14
+ AgentSkillParser.parse("skill.md")
15
+ rescue AgentSkillParser::Errors::Validation => e
16
+ puts "Validation error: #{e.message}"
17
+ end
18
+ ```
19
+
@@ -0,0 +1,7 @@
1
+ # Module: AgentSkillParser::Errors
2
+
3
+
4
+ Namespace for all parser exceptions.
5
+
6
+
7
+
@@ -0,0 +1,50 @@
1
+ # Class: AgentSkillParser::Frontmatter
2
+ **Inherits:** Data
3
+
4
+
5
+ Parsed frontmatter data from a skill file.
6
+
7
+
8
+ **@example**
9
+ ```ruby
10
+ Frontmatter.new(
11
+ name: "my-skill",
12
+ description: "A useful skill",
13
+ license: "MIT",
14
+ compatibility: "v1.2.3+",
15
+ metadata: { "author" => "Alice" },
16
+ allowed_tools: [AllowedTool.new(name: "bash", pattern: nil)]
17
+ )
18
+ ```
19
+ # Attributes
20
+ ## allowed_tools[RW] [](#attribute-i-allowed_tools)
21
+ Returns the value of attribute allowed_tools
22
+
23
+ **@return** [Object] the current value of allowed_tools
24
+
25
+ ## compatibility[RW] [](#attribute-i-compatibility)
26
+ Returns the value of attribute compatibility
27
+
28
+ **@return** [Object] the current value of compatibility
29
+
30
+ ## description[RW] [](#attribute-i-description)
31
+ Returns the value of attribute description
32
+
33
+ **@return** [Object] the current value of description
34
+
35
+ ## license[RW] [](#attribute-i-license)
36
+ Returns the value of attribute license
37
+
38
+ **@return** [Object] the current value of license
39
+
40
+ ## metadata[RW] [](#attribute-i-metadata)
41
+ Returns the value of attribute metadata
42
+
43
+ **@return** [Object] the current value of metadata
44
+
45
+ ## name[RW] [](#attribute-i-name)
46
+ Returns the value of attribute name
47
+
48
+ **@return** [Object] the current value of name
49
+
50
+
@@ -0,0 +1,26 @@
1
+ # Class: AgentSkillParser::FrontmatterParser
2
+ **Inherits:** Object
3
+
4
+
5
+ Parses YAML frontmatter into a {Frontmatter} object.
6
+
7
+
8
+ **@example**
9
+ ```ruby
10
+ parser = FrontmatterParser.new("name: my-skill\ndescription: A skill")
11
+ parser.call # => Frontmatter.new(name: "my-skill", description: "A skill", ...)
12
+ ```
13
+
14
+ # Instance Methods
15
+ ## call() [](#method-i-call)
16
+
17
+ **@raise** [Errors::Parser] if YAML is invalid
18
+
19
+ **@return** [Frontmatter] parsed frontmatter data
20
+
21
+ ## initialize(yaml_string) [](#method-i-initialize)
22
+
23
+ **@param** [String] YAML content (may be empty)
24
+
25
+ **@return** [FrontmatterParser] a new instance of FrontmatterParser
26
+
@@ -0,0 +1,35 @@
1
+ # Class: AgentSkillParser::Parser
2
+ **Inherits:** Object
3
+
4
+
5
+ Orchestrates the parsing pipeline for skill files.
6
+
7
+ Pipeline stages: DocumentSplitter → FrontmatterParser → Validator → Skill
8
+ construction
9
+
10
+
11
+ **@example**
12
+ ```ruby
13
+ parser = Parser.new("my_skill.md")
14
+ skill = parser.call
15
+ skill.name # => "my-skill"
16
+ skill.body # => "# My Skill..."
17
+ ```
18
+
19
+ # Instance Methods
20
+ ## call() [](#method-i-call)
21
+
22
+ **@raise** [Errors::Parser] if YAML is invalid or file cannot be read
23
+
24
+ **@raise** [Errors::Validation] if frontmatter fails validation
25
+
26
+ **@raise** [Errno::ENOENT] if file does not exist
27
+
28
+ **@return** [Skill] parsed skill object
29
+
30
+ ## initialize(file_path) [](#method-i-initialize)
31
+
32
+ **@param** [String] path to skill file
33
+
34
+ **@return** [Parser] a new instance of Parser
35
+
@@ -0,0 +1,35 @@
1
+ # Class: AgentSkillParser::Skill
2
+ **Inherits:** Data
3
+
4
+
5
+ A parsed skill with frontmatter and body.
6
+
7
+
8
+ **@example**
9
+ ```ruby
10
+ Skill.new(
11
+ frontmatter: Frontmatter.new(name: "skill", description: "...", ...),
12
+ body: "# My Skill\n\n..."
13
+ )
14
+ ```
15
+ # Attributes
16
+ ## body[RW] [](#attribute-i-body)
17
+ Returns the value of attribute body
18
+
19
+ **@return** [Object] the current value of body
20
+
21
+ ## frontmatter[RW] [](#attribute-i-frontmatter)
22
+ Returns the value of attribute frontmatter
23
+
24
+ **@return** [Object] the current value of frontmatter
25
+
26
+
27
+ # Instance Methods
28
+ ## description() [](#method-i-description)
29
+
30
+ **@return** [String] skill description (delegates to frontmatter)
31
+
32
+ ## name() [](#method-i-name)
33
+
34
+ **@return** [String] skill name (delegates to frontmatter)
35
+
@@ -0,0 +1,37 @@
1
+ # Class: AgentSkillParser::Validator
2
+ **Inherits:** Object
3
+
4
+
5
+ Validates frontmatter data against schema rules.
6
+
7
+ Validation rules:
8
+ * Name: 1-64 chars, lowercase letters/numbers/hyphens only, no consecutive
9
+ hyphens, cannot start/end with hyphen
10
+ * Description: 1-1024 characters
11
+ * Compatibility: optional, max 500 characters
12
+
13
+
14
+ **@example**
15
+ ```ruby
16
+ fm = Frontmatter.new(name: "skill", description: "A skill", ...)
17
+ Validator.new(fm).call # => nil (no error)
18
+ ```
19
+ **@example**
20
+ ```ruby
21
+ fm = Frontmatter.new(name: "Bad Name!", description: "...", ...)
22
+ Validator.new(fm).call # => raises Errors::Validation
23
+ ```
24
+
25
+ # Instance Methods
26
+ ## call() [](#method-i-call)
27
+
28
+ **@raise** [Errors::Validation] if validation fails
29
+
30
+ **@return** [void]
31
+
32
+ ## initialize(frontmatter) [](#method-i-initialize)
33
+
34
+ **@param** [Frontmatter] parsed frontmatter data
35
+
36
+ **@return** [Validator] a new instance of Validator
37
+
@@ -0,0 +1,98 @@
1
+ # Module: AgentSkillParser
2
+
3
+
4
+ Parses skill files with YAML frontmatter and markdown body.
5
+
6
+ Skill file format: ```markdown
7
+ ---
8
+ name: my-skill description: A helpful skill license: MIT compatibility:
9
+ v1.2.3+ metadata:
10
+ author: Alice
11
+
12
+ allowed-tools: bash, search_files(.rb$)
13
+ ---
14
+ # My Skill
15
+
16
+ Body content here... ```
17
+
18
+
19
+ **@example**
20
+ ```ruby
21
+ skill = AgentSkillParser.parse("my_skill.md")
22
+ skill.name # => "my-skill"
23
+ skill.description # => "A helpful skill"
24
+ ```
25
+ **@example**
26
+ ```ruby
27
+ begin
28
+ AgentSkillParser.parse("invalid.md")
29
+ rescue AgentSkillParser::Errors::Parser => e
30
+ puts "Parse error: #{e.message}"
31
+ rescue AgentSkillParser::Errors::Validation => e
32
+ puts "Validation error: #{e.message}"
33
+ end
34
+ ```
35
+ # Class Methods
36
+ ## parse(file_path ) [](#method-c-parse)
37
+ **@param** [String] path to skill file
38
+
39
+ **@raise** [Errors::Parser] if YAML is invalid or file cannot be read
40
+
41
+ **@raise** [Errors::Validation] if frontmatter fails validation
42
+
43
+ **@raise** [Errno::ENOENT] if file does not exist
44
+
45
+ **@return** [Skill] parsed skill object
46
+
47
+ # Attributes
48
+ ## allowed_tools[RW] [](#attribute-i-allowed_tools)
49
+
50
+ **@return** [Array<AllowedTool>] list of allowed tools
51
+
52
+ ## body[RW] [](#attribute-i-body)
53
+
54
+ **@return** [String] markdown content after frontmatter
55
+
56
+ ## compatibility[RW] [](#attribute-i-compatibility)
57
+
58
+ **@return** [String, nil] compatibility notes (optional)
59
+
60
+ ## description[RW] [](#attribute-i-description)
61
+
62
+ **@return** [String] human-readable description
63
+
64
+ ## frontmatter[RW] [](#attribute-i-frontmatter)
65
+
66
+ **@return** [Frontmatter] parsed metadata
67
+
68
+ ## license[RW] [](#attribute-i-license)
69
+
70
+ **@return** [String, nil] license name (optional)
71
+
72
+ ## metadata[RW] [](#attribute-i-metadata)
73
+
74
+ **@return** [Hash{String => String}] custom key-value metadata
75
+
76
+ ## name[RW] [](#attribute-i-name)
77
+
78
+ **@return** [String] tool name (e.g., "bash")
79
+
80
+ ## pattern[RW] [](#attribute-i-pattern)
81
+
82
+ **@return** [String, nil] optional regex pattern for arguments
83
+
84
+ # Documentation
85
+
86
+ - [AgentSkillParser/AllowedTool.md](AgentSkillParser/AllowedTool.md)
87
+ - [AgentSkillParser/AllowedToolsParser.md](AgentSkillParser/AllowedToolsParser.md)
88
+ - [AgentSkillParser/DocumentSplitter.md](AgentSkillParser/DocumentSplitter.md)
89
+ - [AgentSkillParser/DocumentSplitter/RawYamlDocument.md](AgentSkillParser/DocumentSplitter/RawYamlDocument.md)
90
+ - [AgentSkillParser/Errors.md](AgentSkillParser/Errors.md)
91
+ - [AgentSkillParser/Errors/Base.md](AgentSkillParser/Errors/Base.md)
92
+ - [AgentSkillParser/Errors/Parser.md](AgentSkillParser/Errors/Parser.md)
93
+ - [AgentSkillParser/Errors/Validation.md](AgentSkillParser/Errors/Validation.md)
94
+ - [AgentSkillParser/Frontmatter.md](AgentSkillParser/Frontmatter.md)
95
+ - [AgentSkillParser/FrontmatterParser.md](AgentSkillParser/FrontmatterParser.md)
96
+ - [AgentSkillParser/Parser.md](AgentSkillParser/Parser.md)
97
+ - [AgentSkillParser/Skill.md](AgentSkillParser/Skill.md)
98
+ - [AgentSkillParser/Validator.md](AgentSkillParser/Validator.md)
data/doc/index.csv ADDED
@@ -0,0 +1,51 @@
1
+ name,type,path
2
+ AgentSkillParser,Module,AgentSkillParser.md
3
+ AgentSkillParser.parse,Method,AgentSkillParser.md#method-c-parse
4
+ allowed_tools,Attribute,AgentSkillParser.md#attribute-i-allowed_tools
5
+ body,Attribute,AgentSkillParser.md#attribute-i-body
6
+ compatibility,Attribute,AgentSkillParser.md#attribute-i-compatibility
7
+ description,Attribute,AgentSkillParser.md#attribute-i-description
8
+ frontmatter,Attribute,AgentSkillParser.md#attribute-i-frontmatter
9
+ license,Attribute,AgentSkillParser.md#attribute-i-license
10
+ metadata,Attribute,AgentSkillParser.md#attribute-i-metadata
11
+ name,Attribute,AgentSkillParser.md#attribute-i-name
12
+ pattern,Attribute,AgentSkillParser.md#attribute-i-pattern
13
+ AgentSkillParser::Errors,Module,AgentSkillParser/Errors.md
14
+ AgentSkillParser::Skill,Class,AgentSkillParser/Skill.md
15
+ AgentSkillParser::Skill.description,Method,AgentSkillParser/Skill.md#method-i-description
16
+ AgentSkillParser::Skill.name,Method,AgentSkillParser/Skill.md#method-i-name
17
+ body,Attribute,AgentSkillParser/Skill.md#attribute-i-body
18
+ frontmatter,Attribute,AgentSkillParser/Skill.md#attribute-i-frontmatter
19
+ AgentSkillParser::Parser,Class,AgentSkillParser/Parser.md
20
+ AgentSkillParser::Parser.call,Method,AgentSkillParser/Parser.md#method-i-call
21
+ AgentSkillParser::Parser.initialize,Method,AgentSkillParser/Parser.md#method-i-initialize
22
+ AgentSkillParser::Validator,Class,AgentSkillParser/Validator.md
23
+ AgentSkillParser::Validator.call,Method,AgentSkillParser/Validator.md#method-i-call
24
+ AgentSkillParser::Validator.initialize,Method,AgentSkillParser/Validator.md#method-i-initialize
25
+ AgentSkillParser::Errors::Base,Class,AgentSkillParser/Errors/Base.md
26
+ AgentSkillParser::Frontmatter,Class,AgentSkillParser/Frontmatter.md
27
+ allowed_tools,Attribute,AgentSkillParser/Frontmatter.md#attribute-i-allowed_tools
28
+ compatibility,Attribute,AgentSkillParser/Frontmatter.md#attribute-i-compatibility
29
+ description,Attribute,AgentSkillParser/Frontmatter.md#attribute-i-description
30
+ license,Attribute,AgentSkillParser/Frontmatter.md#attribute-i-license
31
+ metadata,Attribute,AgentSkillParser/Frontmatter.md#attribute-i-metadata
32
+ name,Attribute,AgentSkillParser/Frontmatter.md#attribute-i-name
33
+ AgentSkillParser::AllowedTool,Class,AgentSkillParser/AllowedTool.md
34
+ name,Attribute,AgentSkillParser/AllowedTool.md#attribute-i-name
35
+ pattern,Attribute,AgentSkillParser/AllowedTool.md#attribute-i-pattern
36
+ AgentSkillParser::Errors::Parser,Class,AgentSkillParser/Errors/Parser.md
37
+ AgentSkillParser::DocumentSplitter,Class,AgentSkillParser/DocumentSplitter.md
38
+ AgentSkillParser::DocumentSplitter.call,Method,AgentSkillParser/DocumentSplitter.md#method-i-call
39
+ AgentSkillParser::DocumentSplitter.initialize,Method,AgentSkillParser/DocumentSplitter.md#method-i-initialize
40
+ body,Attribute,AgentSkillParser/DocumentSplitter.md#attribute-i-body
41
+ yaml_string,Attribute,AgentSkillParser/DocumentSplitter.md#attribute-i-yaml_string
42
+ AgentSkillParser::DocumentSplitter::RawYamlDocument,Class,AgentSkillParser/DocumentSplitter/RawYamlDocument.md
43
+ body,Attribute,AgentSkillParser/DocumentSplitter/RawYamlDocument.md#attribute-i-body
44
+ yaml_string,Attribute,AgentSkillParser/DocumentSplitter/RawYamlDocument.md#attribute-i-yaml_string
45
+ AgentSkillParser::Errors::Validation,Class,AgentSkillParser/Errors/Validation.md
46
+ AgentSkillParser::FrontmatterParser,Class,AgentSkillParser/FrontmatterParser.md
47
+ AgentSkillParser::FrontmatterParser.call,Method,AgentSkillParser/FrontmatterParser.md#method-i-call
48
+ AgentSkillParser::FrontmatterParser.initialize,Method,AgentSkillParser/FrontmatterParser.md#method-i-initialize
49
+ AgentSkillParser::AllowedToolsParser,Class,AgentSkillParser/AllowedToolsParser.md
50
+ AgentSkillParser::AllowedToolsParser.call,Method,AgentSkillParser/AllowedToolsParser.md#method-i-call
51
+ AgentSkillParser::AllowedToolsParser.initialize,Method,AgentSkillParser/AllowedToolsParser.md#method-i-initialize
@@ -2,16 +2,16 @@
2
2
 
3
3
  module AgentSkillParser
4
4
  # Represents an allowed tool with optional regex pattern.
5
+ # Pattern is used to match tool arguments in skill files (e.g., git:* for git commands).
5
6
  #
6
7
  # @!attribute [r] name
7
- # @return [String] the tool name (e.g., "bash")
8
+ # @return [String] tool name (e.g., "bash")
8
9
  # @!attribute [r] pattern
9
10
  # @return [String, nil] optional regex pattern for arguments
10
11
  #
11
- # @example Tool without pattern
12
- # AllowedTool.new(name: "bash", pattern: nil)
13
- #
14
12
  # @example Tool with pattern
15
13
  # AllowedTool.new(name: "search_files", pattern: "\\.(rb|js)$")
14
+ # @example Tool without pattern
15
+ # AllowedTool.new(name: "bash", pattern: nil)
16
16
  AllowedTool = Data.define(:name, :pattern)
17
17
  end
@@ -1,7 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AgentSkillParser
4
- # Parses tool names with optional argument patterns.
4
+ # Parses tool names with optional regex patterns for arguments.
5
+ #
6
+ # Format: `ToolName` or `ToolName(pattern)` where pattern is optional.
7
+ # Multiple tools are space or comma separated.
5
8
  #
6
9
  # @example Parse tools
7
10
  # parser = AllowedToolsParser.new("bash, search_files(\\.rb$)")
@@ -11,7 +14,7 @@ module AgentSkillParser
11
14
  # # AllowedTool.new(name: "search_files", pattern: "\\.rb$")
12
15
  # # ]
13
16
  class AllowedToolsParser
14
- # @return [Regexp] pattern matching "tool_name" or "tool_name(pattern)"
17
+ # Pattern matching "tool_name" or "tool_name(pattern)"
15
18
  TOOL_REGEX = /([A-Za-z_]\w*)(?:\(([^)]*)\))?/
16
19
 
17
20
  # @param string [String] comma-separated tool list
@@ -5,13 +5,18 @@ module AgentSkillParser
5
5
  #
6
6
  # @example With frontmatter
7
7
  # splitter = DocumentSplitter.new("---\nname: skill\n---\n# Body")
8
- # splitter.call # => ["name: skill", "# Body"]
8
+ # result = splitter.call
9
+ # result.yaml_string # => "name: skill"
10
+ # result.body # => "# Body"
9
11
  #
10
12
  # @example Without frontmatter
11
13
  # splitter = DocumentSplitter.new("# Just body")
12
- # splitter.call # => ["", "# Just body"]
14
+ # result = splitter.call
15
+ # result.yaml_string # => ""
16
+ # result.body # => "# Just body"
13
17
  class DocumentSplitter
14
18
  # Represents a raw YAML document with separated YAML frontmatter and body.
19
+ # Used as an intermediate structure during parsing.
15
20
  #
16
21
  # @!attribute [r] yaml_string
17
22
  # @return [String] YAML frontmatter content
@@ -3,8 +3,6 @@
3
3
  module AgentSkillParser
4
4
  module Errors
5
5
  # Base class for all parser exceptions.
6
- #
7
- # @abstract
8
6
  class Base < StandardError
9
7
  end
10
8
  end
@@ -2,7 +2,9 @@
2
2
 
3
3
  module AgentSkillParser
4
4
  module Errors
5
- # Raised when parsing fails (e.g., invalid YAML, file not found).
5
+ # Raised when parsing fails.
6
+ #
7
+ # Raised for: invalid YAML, missing frontmatter, file not found
6
8
  #
7
9
  # @example Rescue pattern
8
10
  # begin
@@ -10,8 +12,6 @@ module AgentSkillParser
10
12
  # rescue AgentSkillParser::Errors::Parser => e
11
13
  # puts "Parsing error: #{e.message}"
12
14
  # end
13
- #
14
- # @see FrontmatterParser#call
15
15
  class Parser < Base
16
16
  end
17
17
  end
@@ -4,14 +4,14 @@ module AgentSkillParser
4
4
  module Errors
5
5
  # Raised when frontmatter validation fails.
6
6
  #
7
+ # Raised for: invalid name format, description too long/short, compatibility too long
8
+ #
7
9
  # @example Rescue pattern
8
10
  # begin
9
11
  # AgentSkillParser.parse("skill.md")
10
12
  # rescue AgentSkillParser::Errors::Validation => e
11
13
  # puts "Validation error: #{e.message}"
12
14
  # end
13
- #
14
- # @see Validator#call
15
15
  class Validation < Base
16
16
  end
17
17
  end
@@ -2,10 +2,6 @@
2
2
 
3
3
  module AgentSkillParser
4
4
  # Namespace for all parser exceptions.
5
- #
6
- # @see Base
7
- # @see Parser
8
- # @see Validation
9
5
  module Errors
10
6
  end
11
7
  end
@@ -25,12 +25,11 @@ module AgentSkillParser
25
25
  # metadata: { "author" => "Alice" },
26
26
  # allowed_tools: [AllowedTool.new(name: "bash", pattern: nil)]
27
27
  # )
28
- #
29
- # @see FrontmatterParser
30
28
  Frontmatter = Data.define(:name, :description, :license, :compatibility, :metadata, :allowed_tools)
31
29
 
32
- # A singleton nil object for empty frontmatter.
33
- # Used when YAML frontmatter is missing or empty.
30
+ # Nil object for empty frontmatter.
31
+ # Returned by FrontmatterParser when YAML string is empty or missing.
32
+ # All fields are nil or empty to safely handle missing frontmatter.
34
33
  NilFrontmatter = Frontmatter.new(
35
34
  name: "",
36
35
  description: "",
@@ -28,12 +28,14 @@ module AgentSkillParser
28
28
  private
29
29
 
30
30
  # @return [Hash] parsed YAML data
31
+ # :nodoc:
31
32
  def parse_yaml
32
33
  YAML.safe_load(@yaml_string) || {}
33
34
  end
34
35
 
35
36
  # @param data [Hash] raw YAML data
36
37
  # @return [Frontmatter] constructed frontmatter
38
+ # :nodoc:
37
39
  def build_frontmatter(data)
38
40
  allowed_tools_data = data.delete("allowed-tools")
39
41
  metadata_data = data.delete("metadata") || {}
@@ -50,6 +52,7 @@ module AgentSkillParser
50
52
 
51
53
  # @param data [Object] metadata value
52
54
  # @return [Hash{String => String}] stringified metadata
55
+ # :nodoc:
53
56
  def coerce_metadata(data)
54
57
  return {} unless data.is_a?(Hash)
55
58
 
@@ -58,6 +61,7 @@ module AgentSkillParser
58
61
 
59
62
  # @param data [String, Array, nil] allowed-tools value
60
63
  # @return [Array<AllowedTool>] parsed tool list
64
+ # :nodoc:
61
65
  def parse_allowed_tools(data)
62
66
  return [] if data.nil? || data.empty?
63
67
 
@@ -1,13 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AgentSkillParser
4
- # Main parser that orchestrates the parsing pipeline.
4
+ # Orchestrates the parsing pipeline for skill files.
5
5
  #
6
- # Pipeline stages:
7
- # 1. {DocumentSplitter} - Split YAML frontmatter from body
8
- # 2. {FrontmatterParser} - Parse YAML into {Frontmatter}
9
- # 3. {Validator} - Validate frontmatter schema
10
- # 4. Construct {Skill} object
6
+ # Pipeline stages: DocumentSplitter → FrontmatterParser → Validator → Skill construction
11
7
  #
12
8
  # @example Parse a skill file
13
9
  # parser = Parser.new("my_skill.md")
@@ -15,13 +15,11 @@ module AgentSkillParser
15
15
  # )
16
16
  Skill = Data.define(:frontmatter, :body) do
17
17
  # @return [String] skill name (delegates to frontmatter)
18
- # @see Frontmatter#name
19
18
  def name
20
19
  frontmatter.name
21
20
  end
22
21
 
23
22
  # @return [String] skill description (delegates to frontmatter)
24
- # @see Frontmatter#description
25
23
  def description
26
24
  frontmatter.description
27
25
  end
@@ -3,6 +3,12 @@
3
3
  module AgentSkillParser
4
4
  # Validates frontmatter data against schema rules.
5
5
  #
6
+ # Validation rules:
7
+ # - Name: 1-64 chars, lowercase letters/numbers/hyphens only, no consecutive hyphens,
8
+ # cannot start/end with hyphen
9
+ # - Description: 1-1024 characters
10
+ # - Compatibility: optional, max 500 characters
11
+ #
6
12
  # @example Successful validation
7
13
  # fm = Frontmatter.new(name: "skill", description: "A skill", ...)
8
14
  # Validator.new(fm).call # => nil (no error)
@@ -10,20 +16,18 @@ module AgentSkillParser
10
16
  # @example Failed validation
11
17
  # fm = Frontmatter.new(name: "Bad Name!", description: "...", ...)
12
18
  # Validator.new(fm).call # => raises Errors::Validation
13
- #
14
- # @see Errors::Validation
15
19
  class Validator
16
- # @return [Integer] maximum name length
20
+ # Maximum name length
17
21
  NAME_MAX_LENGTH = 64
18
- # @return [Integer] minimum name length
22
+ # Minimum name length
19
23
  NAME_MIN_LENGTH = 1
20
- # @return [Regexp] allowed name pattern
24
+ # Allowed name pattern
21
25
  NAME_PATTERN = /\A[a-z0-9-]+\z/
22
- # @return [Integer] maximum description length
26
+ # Maximum description length
23
27
  DESCRIPTION_MAX_LENGTH = 1024
24
- # @return [Integer] minimum description length
28
+ # Minimum description length
25
29
  DESCRIPTION_MIN_LENGTH = 1
26
- # @return [Integer] maximum compatibility length
30
+ # Maximum compatibility length
27
31
  COMPATIBILITY_MAX_LENGTH = 500
28
32
 
29
33
  # @param frontmatter [Frontmatter] parsed frontmatter data
@@ -43,6 +47,7 @@ module AgentSkillParser
43
47
 
44
48
  # @return [void]
45
49
  # @raise [Errors::Validation] if name is invalid
50
+ # :nodoc:
46
51
  def validate_name
47
52
  name = @frontmatter.name
48
53
 
@@ -63,6 +68,7 @@ module AgentSkillParser
63
68
 
64
69
  # @return [void]
65
70
  # @raise [Errors::Validation] if description is invalid
71
+ # :nodoc:
66
72
  def validate_description
67
73
  description = @frontmatter.description
68
74
 
@@ -77,6 +83,7 @@ module AgentSkillParser
77
83
 
78
84
  # @return [void]
79
85
  # @raise [Errors::Validation] if compatibility is too long
86
+ # :nodoc:
80
87
  def validate_compatibility
81
88
  return if @frontmatter.compatibility.nil?
82
89
 
@@ -2,5 +2,5 @@
2
2
 
3
3
  module AgentSkillParser
4
4
  # @return [String] gem version
5
- VERSION = "0.1.0"
5
+ VERSION = "0.2.0"
6
6
  end
@@ -9,7 +9,7 @@ loader.setup
9
9
  # Parses skill files with YAML frontmatter and markdown body.
10
10
  #
11
11
  # Skill file format:
12
- # ```yaml
12
+ # ```markdown
13
13
  # ---
14
14
  # name: my-skill
15
15
  # description: A helpful skill
@@ -43,7 +43,6 @@ module AgentSkillParser
43
43
  # @raise [Errors::Parser] if YAML is invalid or file cannot be read
44
44
  # @raise [Errors::Validation] if frontmatter fails validation
45
45
  # @raise [Errno::ENOENT] if file does not exist
46
- # @see Parser#call
47
46
  def self.parse(file_path)
48
47
  Parser.new(file_path).call
49
48
  end
data/llm.txt ADDED
@@ -0,0 +1,98 @@
1
+ # Module: AgentSkillParser
2
+
3
+
4
+ Parses skill files with YAML frontmatter and markdown body.
5
+
6
+ Skill file format: ```markdown
7
+ ---
8
+ name: my-skill description: A helpful skill license: MIT compatibility:
9
+ v1.2.3+ metadata:
10
+ author: Alice
11
+
12
+ allowed-tools: bash, search_files(.rb$)
13
+ ---
14
+ # My Skill
15
+
16
+ Body content here... ```
17
+
18
+
19
+ **@example**
20
+ ```ruby
21
+ skill = AgentSkillParser.parse("my_skill.md")
22
+ skill.name # => "my-skill"
23
+ skill.description # => "A helpful skill"
24
+ ```
25
+ **@example**
26
+ ```ruby
27
+ begin
28
+ AgentSkillParser.parse("invalid.md")
29
+ rescue AgentSkillParser::Errors::Parser => e
30
+ puts "Parse error: #{e.message}"
31
+ rescue AgentSkillParser::Errors::Validation => e
32
+ puts "Validation error: #{e.message}"
33
+ end
34
+ ```
35
+ # Class Methods
36
+ ## parse(file_path ) [](#method-c-parse)
37
+ **@param** [String] path to skill file
38
+
39
+ **@raise** [Errors::Parser] if YAML is invalid or file cannot be read
40
+
41
+ **@raise** [Errors::Validation] if frontmatter fails validation
42
+
43
+ **@raise** [Errno::ENOENT] if file does not exist
44
+
45
+ **@return** [Skill] parsed skill object
46
+
47
+ # Attributes
48
+ ## allowed_tools[RW] [](#attribute-i-allowed_tools)
49
+
50
+ **@return** [Array<AllowedTool>] list of allowed tools
51
+
52
+ ## body[RW] [](#attribute-i-body)
53
+
54
+ **@return** [String] markdown content after frontmatter
55
+
56
+ ## compatibility[RW] [](#attribute-i-compatibility)
57
+
58
+ **@return** [String, nil] compatibility notes (optional)
59
+
60
+ ## description[RW] [](#attribute-i-description)
61
+
62
+ **@return** [String] human-readable description
63
+
64
+ ## frontmatter[RW] [](#attribute-i-frontmatter)
65
+
66
+ **@return** [Frontmatter] parsed metadata
67
+
68
+ ## license[RW] [](#attribute-i-license)
69
+
70
+ **@return** [String, nil] license name (optional)
71
+
72
+ ## metadata[RW] [](#attribute-i-metadata)
73
+
74
+ **@return** [Hash{String => String}] custom key-value metadata
75
+
76
+ ## name[RW] [](#attribute-i-name)
77
+
78
+ **@return** [String] tool name (e.g., "bash")
79
+
80
+ ## pattern[RW] [](#attribute-i-pattern)
81
+
82
+ **@return** [String, nil] optional regex pattern for arguments
83
+
84
+ # Documentation
85
+
86
+ - [doc/AgentSkillParser/AllowedTool.md](doc/AgentSkillParser/AllowedTool.md)
87
+ - [doc/AgentSkillParser/AllowedToolsParser.md](doc/AgentSkillParser/AllowedToolsParser.md)
88
+ - [doc/AgentSkillParser/DocumentSplitter.md](doc/AgentSkillParser/DocumentSplitter.md)
89
+ - [doc/AgentSkillParser/DocumentSplitter/RawYamlDocument.md](doc/AgentSkillParser/DocumentSplitter/RawYamlDocument.md)
90
+ - [doc/AgentSkillParser/Errors.md](doc/AgentSkillParser/Errors.md)
91
+ - [doc/AgentSkillParser/Errors/Base.md](doc/AgentSkillParser/Errors/Base.md)
92
+ - [doc/AgentSkillParser/Errors/Parser.md](doc/AgentSkillParser/Errors/Parser.md)
93
+ - [doc/AgentSkillParser/Errors/Validation.md](doc/AgentSkillParser/Errors/Validation.md)
94
+ - [doc/AgentSkillParser/Frontmatter.md](doc/AgentSkillParser/Frontmatter.md)
95
+ - [doc/AgentSkillParser/FrontmatterParser.md](doc/AgentSkillParser/FrontmatterParser.md)
96
+ - [doc/AgentSkillParser/Parser.md](doc/AgentSkillParser/Parser.md)
97
+ - [doc/AgentSkillParser/Skill.md](doc/AgentSkillParser/Skill.md)
98
+ - [doc/AgentSkillParser/Validator.md](doc/AgentSkillParser/Validator.md)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: agent_skill_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lucian Ghinda
@@ -39,6 +39,21 @@ files:
39
39
  - LICENSE
40
40
  - README.md
41
41
  - Rakefile
42
+ - doc/AgentSkillParser.md
43
+ - doc/AgentSkillParser/AllowedTool.md
44
+ - doc/AgentSkillParser/AllowedToolsParser.md
45
+ - doc/AgentSkillParser/DocumentSplitter.md
46
+ - doc/AgentSkillParser/DocumentSplitter/RawYamlDocument.md
47
+ - doc/AgentSkillParser/Errors.md
48
+ - doc/AgentSkillParser/Errors/Base.md
49
+ - doc/AgentSkillParser/Errors/Parser.md
50
+ - doc/AgentSkillParser/Errors/Validation.md
51
+ - doc/AgentSkillParser/Frontmatter.md
52
+ - doc/AgentSkillParser/FrontmatterParser.md
53
+ - doc/AgentSkillParser/Parser.md
54
+ - doc/AgentSkillParser/Skill.md
55
+ - doc/AgentSkillParser/Validator.md
56
+ - doc/index.csv
42
57
  - lib/agent_skill_parser.rb
43
58
  - lib/agent_skill_parser/allowed_tool.rb
44
59
  - lib/agent_skill_parser/allowed_tools_parser.rb
@@ -53,6 +68,7 @@ files:
53
68
  - lib/agent_skill_parser/skill.rb
54
69
  - lib/agent_skill_parser/validator.rb
55
70
  - lib/agent_skill_parser/version.rb
71
+ - llm.txt
56
72
  - sig/agent_skill_parser.rbs
57
73
  homepage: https://github.com/lucianghinda/agent_skill_parser
58
74
  licenses:
@@ -69,7 +85,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
69
85
  requirements:
70
86
  - - ">="
71
87
  - !ruby/object:Gem::Version
72
- version: 3.2.0
88
+ version: 3.4.0
73
89
  required_rubygems_version: !ruby/object:Gem::Requirement
74
90
  requirements:
75
91
  - - ">="