Feature: Consolidated Skill Combined scenarios from: skill_context, skill_discovery, skill_flatten, skill_inline_coverage, skill_protocol, skill_resolution # ============================================================ # Originally from: skill_context.feature # Feature: Skill Context and Registry # ============================================================ Scenario: Create SkillContext with plan/project/sandbox info When I create a skill_context with plan "plan-001" project "proj-alpha" and sandbox "/tmp/sandbox" Then the skill_context should be created And the skill_context plan_id should be "plan-001" And the skill_context project_id should be "proj-alpha" And the skill_context sandbox_path should be "/tmp/sandbox" And the skill_context should not be read_only Scenario: Create read-only SkillContext When I create a read_only skill_context with plan "plan-002" project "proj-beta" Then the skill_context should be created And the skill_context should be read_only Scenario: SkillContext with custom metadata When I create a skill_context with metadata key "env" value "staging" Then the skill_context plan metadata should contain key "env" And the skill_context plan metadata key "env" should be "staging" # ---- Resource Resolution ---- Scenario: Resolve bound resources from context When I create a skill_context with resource "git-checkout" bound to "/repo/checkout" And I resolve resource "git-checkout" from the skill_context Then the resolved resource should be "/repo/checkout" Scenario: Resolve missing resource raises SkillError When I create a skill_context with no resources And I try to resolve resource "missing-resource" from the skill_context Then a skill_context resolution error should be raised # ---- Change Tracking ---- Scenario: Register tool invocation in change tracker When I create a skill_context with plan "plan-003" project "proj-gamma" and sandbox "/tmp/sb" And I register a tool invocation for "local/edit-file" with duration 42.5 Then the skill_context change tracker should have 1 records And the last change tracker record tool_name should be "local/edit-file" And the last change tracker record duration_ms should be 42.5 Scenario: Multiple tool invocations are tracked in order When I create a skill_context with plan "plan-004" project "proj-delta" and sandbox "/tmp/sb2" And I register a tool invocation for "local/read-file" with duration 10.0 And I register a tool invocation for "local/write-file" with duration 20.0 Then the skill_context change tracker should have 2 records # ---- Write Guard ---- Scenario: Enforce read-only write guard raises SkillError When I create a read_only skill_context with plan "plan-005" project "proj-epsilon" And I try to enforce write guard for tool "local/write-file" Then a skill_context permission denied error should be raised And the skill_context permission error tool_name should be "local/write-file" Scenario: Write guard passes in writable context When I create a skill_context with plan "plan-006" project "proj-zeta" and sandbox "/tmp/sb3" And I enforce write guard for tool "local/write-file" in writable context Then no skill_context error should be raised # ---- Plan Metadata ---- Scenario: Get plan metadata includes plan_id and project_id When I create a skill_context with plan "plan-007" project "proj-eta" and sandbox "/tmp/sb4" Then the skill_context plan metadata should contain key "plan_id" And the skill_context plan metadata key "plan_id" should be "plan-007" And the skill_context plan metadata should contain key "project_id" And the skill_context plan metadata key "project_id" should be "proj-eta" # ---- SkillRegistry Register/Get/List/Unregister ---- Scenario: SkillRegistry register and get skill When I create a skill_registry And I register a skill "local/test-reg" in the registry And I get skill "local/test-reg" from the registry Then the registry skill name should be "local/test-reg" Scenario: SkillRegistry register duplicate raises error When I create a skill_registry And I register a skill "local/dup-skill" in the registry And I try to register a duplicate skill "local/dup-skill" Then a skill_context validation error should be raised Scenario: SkillRegistry get missing skill raises error When I create a skill_registry And I try to get skill "local/missing" from the registry Then a skill_context not found error should be raised Scenario: SkillRegistry list_all returns metadata When I create a skill_registry And I register a skill "local/skill-a" in the registry And I register a skill "local/skill-b" in the registry And I list all skills from the registry Then the registry should have 2 skills And the registry skill list should contain "local/skill-a" And the registry skill list should contain "local/skill-b" Scenario: SkillRegistry unregister removes skill When I create a skill_registry And I register a skill "local/to-remove" in the registry And I unregister skill "local/to-remove" from the registry And I try to get skill "local/to-remove" from the registry Then a skill_context not found error should be raised Scenario: SkillRegistry unregister missing skill raises error When I create a skill_registry And I try to unregister skill "local/nonexistent" from the registry Then a skill_context not found error should be raised # ---- SkillRegistry Tool Resolution ---- Scenario: SkillRegistry resolve_tools through tool references When I create a skill_registry And I register a skill "local/resolve-test" with tool refs in the registry And I resolve tools for "local/resolve-test" from the registry Then the resolved tools should have 2 entries And the resolved tools should contain "local/tool-a" And the resolved tools should contain "local/tool-b" # ---- SkillRegistry Validation ---- @tdd_issue @tdd_issue_4241 @tdd_expected_fail Scenario: SkillRegistry validate_skill detects missing tools When I create a skill_registry with a mock tool registry And I validate a skill with missing tool refs Then the validation errors should contain "not found in tool registry" Scenario: SkillRegistry validate_skill detects missing includes When I create a skill_registry And I validate a skill with missing includes Then the validation errors should contain "is not registered" Scenario: SkillRegistry validate_skill returns empty for valid skill When I create a skill_registry And I validate a skill with no issues Then the validation errors should be empty # ============================================================ # Originally from: skill_discovery.feature # Feature: Agent Skills Discovery # ============================================================ Scenario: Config key skills.agent_skills_paths is registered Given the agent skills discovery module is available When I check the config registry for "skills.agent_skills_paths" Then the config entry should exist And the config entry type should be "str" And the config entry env var should be "CLEVERAGENTS_SKILLS_AGENT_SKILLS_PATHS" # --- Path parsing --- Scenario: Parse single agent skills path Given the agent skills discovery module is available When I parse agent skills paths "~/.cleveragents/agent_skills" Then the result should contain 1 path Scenario: Parse multiple comma-separated paths Given the agent skills discovery module is available When I parse agent skills paths "/opt/skills,/home/user/skills" Then the result should contain 2 paths Scenario: Parse empty agent skills paths Given the agent skills discovery module is available When I parse an empty agent skills path string Then the result should contain 0 paths Scenario: Parse paths with whitespace around commas Given the agent skills discovery module is available When I parse agent skills paths "/opt/skills , /home/user/skills" Then the result should contain 2 paths # --- Discovery --- Scenario: Discover agent skills from directory with SKILL.md Given the agent skills discovery module is available Given a temporary directory with agent skill folders | folder_name | skill_name | description | | my-tool | my-tool | A test agent skill | When I scan the directory for agent skills Then I should discover 1 agent skill And the discovered skill "my-tool" should have description "A test agent skill" Scenario: Discover multiple agent skills Given the agent skills discovery module is available Given a temporary directory with agent skill folders | folder_name | skill_name | description | | tool-a | tool-a | First tool | | tool-b | tool-b | Second tool | | tool-c | tool-c | Third tool | When I scan the directory for agent skills Then I should discover 3 agent skills Scenario: Skip directories without SKILL.md Given the agent skills discovery module is available Given a temporary directory with some folders missing SKILL.md When I scan the directory for agent skills Then I should discover 0 agent skills Scenario: Handle non-existent directory gracefully Given the agent skills discovery module is available When I run discovery on a non-existent directory Then the discovery result should have 0 discovered skills And the discovery result should have errors mentioning "does not exist" Scenario: Handle SKILL.md without front-matter Given the agent skills discovery module is available Given a temporary directory with a SKILL.md that has no front-matter When I scan the directory for agent skills Then I should discover 0 agent skills Scenario: Fall back to folder name when SKILL.md has no name field Given the agent skills discovery module is available Given a temporary directory with agent skill folders | folder_name | skill_name | description | | fallback-tool | _none_ | Some description | When I scan the directory for agent skills Then I should discover 1 agent skill And the discovered skill should use folder name as name # --- ToolSpec building --- Scenario: Build ToolSpec from discovered agent skill Given the agent skills discovery module is available Given a discovered agent skill named "my-tool" at "/opt/skills/my-tool" When I build a ToolSpec from the discovered skill Then the ToolSpec name should be "agent_skills/my-tool" And the ToolSpec source should be "agent_skills" And the ToolSpec source_metadata should contain path "/opt/skills/my-tool" # --- Registration --- Scenario: Register discovered agent skills in ToolRegistry Given the agent skills discovery module is available Given a ToolRegistry with no existing tools And a list of 2 discovered agent skills When I register discovered skills with "skip" conflict strategy Then 2 tools should be registered in the ToolRegistry And 0 conflicts should be reported Scenario: Skip registration on name collision with skip strategy Given the agent skills discovery module is available Given a ToolRegistry with an existing tool "agent_skills/collider" And a discovered agent skill named "collider" When I register discovered skills with "skip" conflict strategy Then 0 tools should be registered in the ToolRegistry And 1 conflict should be reported with tool name "agent_skills/collider" Scenario: Error on name collision with error strategy Given the agent skills discovery module is available Given a ToolRegistry with an existing tool "agent_skills/collider" And a discovered agent skill named "collider" When I register discovered skills with "error" conflict strategy Then a discovery ValueError should be raised mentioning "name collision" Scenario: Replace existing tool on collision with replace strategy Given the agent skills discovery module is available Given a ToolRegistry with an existing tool "agent_skills/collider" And a discovered agent skill named "collider" When I register discovered skills with "replace" conflict strategy Then 1 tool should be registered in the ToolRegistry And the tool "agent_skills/collider" should have source "agent_skills" # --- Refresh --- Scenario: Refresh removes old agent skills and re-discovers Given the agent skills discovery module is available Given a SkillRegistryService with a ToolRegistry And agent skills paths pointing to a directory with 2 skills When I call discover_and_register Then 2 agent skills should be registered When the directory now has 3 skills and I call refresh_agent_skills Then 3 agent skills should be registered # --- Edge cases --- Scenario: Register empty discovered list returns empty Given the agent skills discovery module is available Given a ToolRegistry with no existing tools When I register an empty discovered skills list Then the registration should return 0 specs and 0 conflicts Scenario: Scan non-directory path returns empty Given the agent skills discovery module is available When I scan a non-directory path for agent skills Then I should discover 0 agent skills Scenario: Discover with path that is a file not a directory Given the agent skills discovery module is available When I run discovery on a path that is a file Then the discovery result should have 0 discovered skills And the discovery result should have errors mentioning "not a directory" Scenario: SKILL.md with invalid YAML front-matter Given the agent skills discovery module is available Given a temporary directory with a SKILL.md that has invalid YAML When I scan the directory for agent skills Then I should discover 0 agent skills Scenario: SKILL.md with empty YAML block Given the agent skills discovery module is available Given a temporary directory with a SKILL.md that has empty front-matter When I scan the directory for agent skills Then I should discover 0 agent skills Scenario: SKILL.md with non-dict YAML Given the agent skills discovery module is available Given a temporary directory with a SKILL.md that has non-dict YAML When I scan the directory for agent skills Then I should discover 0 agent skills Scenario: Skill with non-string description in front-matter Given the agent skills discovery module is available Given a temporary directory with a SKILL.md that has numeric description When I scan the directory for agent skills Then I should discover 1 agent skill Scenario: Skill with empty description falls back to default Given the agent skills discovery module is available Given a temporary directory with a SKILL.md that has empty description When I scan the directory for agent skills Then I should discover 1 agent skill And the first discovered skill description should contain "Agent skill from" Scenario: Noop handler returns expected placeholder Given the agent skills discovery module is available When I call the noop handler Then the noop handler should return status "agent_skill_placeholder" # --- Source metadata --- Scenario: Source metadata is included when resolving skill tools Given the agent skills discovery module is available Given a registered skill "local/test-skill" with an agent_skill source When I resolve tools for "local/test-skill" Then the resolved tools should include agent_skill source entries # ============================================================ # Originally from: skill_flatten.feature # Feature: Skill Registry Flattening and Capability Summaries # ============================================================ @flatten_tool_refs Scenario: Flattening a skill with named tool refs produces deterministic order Given a flatten registry skill "local/basic" with tool refs "local/alpha,local/beta,local/gamma" When I flatten the skill "local/basic" Then the flatten result should have 3 entries And the flatten entry at index 0 should be "local/alpha" And the flatten entry at index 1 should be "local/beta" And the flatten entry at index 2 should be "local/gamma" # --------------------------------------------------------------------------- # Flattening with includes (depth-first ordering) # --------------------------------------------------------------------------- @flatten_includes Scenario: Flattening a skill with includes uses depth-first ordering Given a flatten registry skill "local/base" with tool refs "local/base-tool" And a flatten registry skill "local/mid" including "local/base" with refs "local/mid-tool" And a flatten registry skill "local/top" including "local/mid" with refs "local/top-tool" When I flatten the skill "local/top" Then the flatten result should have 3 entries And the flatten entry at index 0 should be "local/base-tool" And the flatten entry at index 1 should be "local/mid-tool" And the flatten entry at index 2 should be "local/top-tool" # --------------------------------------------------------------------------- # Flattening with inline tools # --------------------------------------------------------------------------- @flatten_inline Scenario: Flattening a skill with inline tools includes anonymous entries Given a flatten registry skill "local/inline-skill" with 2 inline tools When I flatten the skill "local/inline-skill" Then the flatten result should have 2 entries And the flatten entry at index 0 should be "local/inline-skill/_anon_0" And the flatten entry at index 1 should be "local/inline-skill/_anon_1" And the flatten entry at index 0 should be marked inline # --------------------------------------------------------------------------- # Cycle detection with clear error path # --------------------------------------------------------------------------- @flatten_cycle Scenario: Flattening detects cycles and reports a clear path Given a flatten registry skill "local/cycle-a" including "local/cycle-b" with no refs And a flatten registry skill "local/cycle-b" including "local/cycle-a" with no refs When I try to flatten the skill "local/cycle-a" Then a flatten cycle error should be raised And the flatten error should mention "local/cycle-a" And the flatten error should mention "local/cycle-b" # --------------------------------------------------------------------------- # Per-include override application # --------------------------------------------------------------------------- @flatten_include_overrides Scenario: Per-include overrides are applied to included tool entries Given a flatten registry skill "local/child" with tool refs "local/tool-x" And a flatten registry skill "local/parent" including "local/child" with overrides timeout 600 When I flatten the skill "local/parent" Then the flatten result should have 1 entries And the flatten entry "local/tool-x" should have override "timeout" equal to 600 # --------------------------------------------------------------------------- # Non-overridable field rejection # --------------------------------------------------------------------------- @flatten_non_overridable Scenario: Non-overridable fields are rejected with clear error Given a flatten registry skill "local/child-nr" with tool refs "local/tool-y" And a flatten registry skill "local/parent-nr" including "local/child-nr" with overrides on non-overridable field "name" When I try to flatten the skill "local/parent-nr" Then a flatten override error should be raised And the flatten error should mention "name" And the flatten error should mention "Non-overridable" # --------------------------------------------------------------------------- # Capability summary computation # --------------------------------------------------------------------------- @flatten_capability_summary Scenario: Capability summary aggregates read/write/checkpoint/side-effect flags Given a flatten registry skill "local/cap-skill" with mixed capability inline tools When I flatten the skill "local/cap-skill" and compute summary Then the flatten summary total_tools should be 3 And the flatten summary read_only_tools should be 1 And the flatten summary write_tools should be 1 And the flatten summary has_side_effects should be true And the flatten summary checkpointable_tools should be 2 # --------------------------------------------------------------------------- # tools() method returns both entries and summary # --------------------------------------------------------------------------- @flatten_tools_method Scenario: The tools() method returns entries and capability summary Given a flatten skill registry with skill "local/tools-test" having 3 refs When I call the flatten tools method for "local/tools-test" Then the flatten tools result should contain 3 entries And the flatten tools result should include a capability summary # --------------------------------------------------------------------------- # validate_plan() with valid plan # --------------------------------------------------------------------------- @flatten_validate_plan Scenario: validate_plan with a valid plan returns no errors Given a flatten skill registry with skill "local/plan-skill" having 2 refs When I call flatten validate_plan with skills "local/plan-skill" Then the flatten validation result should have 0 errors # --------------------------------------------------------------------------- # validate_plan() with missing skill # --------------------------------------------------------------------------- @flatten_validate_plan_missing Scenario: validate_plan with a missing skill reports error Given an empty flatten skill registry When I call flatten validate_plan with skills "local/nonexistent" Then the flatten validation result should have 1 errors And the flatten validation error should mention "local/nonexistent" # --------------------------------------------------------------------------- # validate_plan() with cycle in includes # --------------------------------------------------------------------------- @flatten_validate_plan_cycle Scenario: validate_plan detects cycle in includes Given a flatten registry skill "local/loop-a" including "local/loop-b" with no refs And a flatten registry skill "local/loop-b" including "local/loop-a" with no refs And the flatten registry skills are registered in the skill registry When I call flatten validate_plan with skills "local/loop-a" Then the flatten validation result should have 1 errors And the flatten validation error should mention "ycle" # --------------------------------------------------------------------------- # De-duplication semantics (last-wins) # --------------------------------------------------------------------------- @flatten_dedup Scenario: De-duplication uses last-wins for entry metadata Given a flatten registry skill "local/dup-a" with tool refs "local/shared" And a flatten registry skill "local/dup-b" with tool refs "local/shared" And a flatten registry skill "local/dup-top" including "local/dup-a,local/dup-b" with no refs When I flatten the skill "local/dup-top" Then the flatten result should have 1 entries And the flatten entry "local/shared" source_skill should be "local/dup-b" # --------------------------------------------------------------------------- # Override merging (shallow merge) # --------------------------------------------------------------------------- @flatten_override_merge Scenario: Override merging uses shallow merge semantics Given a flatten registry skill "local/merge-child" with tool refs "local/merge-tool" and overrides priority 1 And a flatten registry skill "local/merge-parent" including "local/merge-child" with overrides priority 2 and extra key When I flatten the skill "local/merge-parent" Then the flatten entry "local/merge-tool" should have override "priority" equal to 2 And the flatten entry "local/merge-tool" should have override "extra" equal to "yes" # ============================================================ # Originally from: skill_inline_coverage.feature # Feature: Inline Tool Executor Coverage Boost # ============================================================ Scenario: Executor rejects non-positive max_runtime_seconds Given I create an inline executor with invalid max runtime Then creating the executor should raise a ValueError about runtime Scenario: Executor rejects non-positive max_output_bytes Given I create an inline executor with invalid max output Then creating the executor should raise a ValueError about output # ---- Property Accessors ---- Scenario: Executor exposes max_runtime_seconds property Given an inline executor with max runtime 5.0 seconds Then the executor max_runtime_seconds should be 5.0 Scenario: Executor exposes max_output_bytes property Given an inline executor with max output 512 bytes Then the executor max_output_bytes should be 512 # ---- Null Argument Guards ---- Scenario: Execute rejects None tool argument Given a writable skill context with sandbox "/tmp/inline-sandbox" And an inline executor with max runtime 5.0 seconds When I execute with None tool Then executing should raise a ValueError about tool Scenario: Execute rejects None context argument Given an inline tool with code that prints "test" When I execute with None context Then executing should raise a ValueError about context Scenario: Execute rejects None input_data argument Given an inline tool with code that prints "test" And a writable skill context with sandbox "/tmp/inline-sandbox" When I execute with None input_data Then executing should raise a ValueError about input_data Scenario: Validate_tool rejects None tool argument Given an inline executor with max runtime 5.0 seconds When I validate with None tool Then validating should raise a ValueError about tool # ---- Validation Failure Return Path ---- Scenario: Execute returns validation failure without running code Given an inline tool with no code And a writable skill context with sandbox "/tmp/inline-sandbox" When I execute the inline tool Then the inline result should not be successful And the inline result error message should contain "Validation failed" And the inline result duration should be zero # ---- Sandbox Path Validation ---- Scenario: Execute rejects input paths outside sandbox Given an inline tool with code that prints "file op" And a writable skill context with sandbox "/tmp/inline-sandbox" When I execute the inline tool with path input escaping sandbox Then the inline result should not be successful And the inline result error message should contain "escapes sandbox" Scenario: Execute accepts input paths inside sandbox Given an inline tool with code that prints "ok" And a writable skill context with sandbox "/tmp/inline-sandbox" When I execute the inline tool with path input inside sandbox Then the inline result should be successful Scenario: Execute handles invalid path values gracefully Given an inline tool with code that prints "test" And a writable skill context with sandbox "/tmp/inline-sandbox" When I execute the inline tool with an invalid path value Then the inline result should not be successful And the inline result error message should contain "Invalid path" # ============================================================ # Originally from: skill_protocol.feature # Feature: Skill Protocol Types # ============================================================ Scenario: SkillErrorType has all expected members When I list all skill_protocol error types Then the skill_protocol error types should include "skill_not_found" And the skill_protocol error types should include "resolution_failure" And the skill_protocol error types should include "cycle_detected" And the skill_protocol error types should include "tool_activation_failure" And the skill_protocol error types should include "tool_execution_failure" And the skill_protocol error types should include "validation_error" And the skill_protocol error types should include "permission_denied" Scenario: SkillErrorType has exactly 7 members When I list all skill_protocol error types Then there should be 7 skill_protocol error types # ---- SkillError Creation ---- Scenario: Create a SkillError with required fields When I create a skill_protocol error with type "tool_execution_failure" and message "Tool timed out" for skill "local/my-skill" Then the skill_protocol error should be created And the skill_protocol error type should be "tool_execution_failure" And the skill_protocol error message should be "Tool timed out" And the skill_protocol error skill_name should be "local/my-skill" And the skill_protocol error tool_name should be none Scenario: Create a SkillError with optional tool_name When I create a skill_protocol error with tool_name "local/my-tool" Then the skill_protocol error should be created And the skill_protocol error tool_name should be "local/my-tool" Scenario: Create a SkillError with details When I create a skill_protocol error with details Then the skill_protocol error should be created And the skill_protocol error details should have key "trace_id" Scenario: SkillError is frozen (immutable) When I create a skill_protocol error with type "validation_error" and message "Bad input" for skill "local/test" Then the skill_protocol error should be immutable # ---- SkillMetadata Creation ---- Scenario: Create SkillMetadata from Skill domain model When I create a skill_protocol metadata from a basic skill Then the skill_protocol metadata should be created And the skill_protocol metadata name should be "local/test-skill" And the skill_protocol metadata description should be "A test skill" And the skill_protocol metadata version should be "0.0.0" And the skill_protocol metadata read_only should be true And the skill_protocol metadata writes should be false Scenario: Create SkillMetadata from Skill with tool refs When I create a skill_protocol metadata from a skill with tool refs Then the skill_protocol metadata should be created And the skill_protocol metadata tool_count should be 2 And the skill_protocol metadata source_types should contain "tool_ref" Scenario: Create SkillMetadata from Skill with inline write tools When I create a skill_protocol metadata from a skill with write tools Then the skill_protocol metadata should be created And the skill_protocol metadata writes should be true And the skill_protocol metadata read_only should be false Scenario: Create SkillMetadata from Skill with MCP sources When I create a skill_protocol metadata from a skill with mcp sources Then the skill_protocol metadata should be created And the skill_protocol metadata source_types should contain "mcp" Scenario: Create SkillMetadata from Skill with agent skill sources When I create a skill_protocol metadata from a skill with agent skill sources Then the skill_protocol metadata should be created And the skill_protocol metadata source_types should contain "agent_skill" Scenario: Create SkillMetadata with custom version When I create a skill_protocol metadata with version "1.2.3" Then the skill_protocol metadata should be created And the skill_protocol metadata version should be "1.2.3" Scenario: SkillMetadata is frozen (immutable) When I create a skill_protocol metadata from a basic skill Then the skill_protocol metadata should be immutable Scenario: SkillMetadata from_skill rejects None When I try to create skill_protocol metadata from None Then a skill_protocol value error should be raised # ---- SkillDefinition ---- Scenario: Create a SkillDefinition with resolved tools When I create a skill_protocol definition with resolved tools Then the skill_protocol definition should be created And the skill_protocol definition skill name should be "local/def-skill" And the skill_protocol definition should have 1 resolved tools Scenario: Create a SkillDefinition with input and output schemas When I create a skill_protocol definition with input and output schemas Then the skill_protocol definition should be created And the skill_protocol definition input_schema should have key "type" And the skill_protocol definition output_schema should have key "type" Scenario: SkillDefinition rejects input_schema without type key When I try to create a skill_protocol definition with invalid input_schema Then a skill_protocol validation error should be raised Scenario: SkillDefinition rejects output_schema without type key When I try to create a skill_protocol definition with invalid output_schema Then a skill_protocol validation error should be raised Scenario: SkillDefinition detects writes inconsistency When I try to create a skill_protocol definition with writes inconsistency Then a skill_protocol validation error should be raised Scenario: SkillDefinition is frozen (immutable) When I create a skill_protocol definition with resolved tools Then the skill_protocol definition should be immutable # ---- SkillResult ---- Scenario: Create a successful SkillResult When I create a skill_protocol result with success Then the skill_protocol result should be created And the skill_protocol result success should be true And the skill_protocol result skill_name should be "local/my-skill" And the skill_protocol result tool_name should be "local/my-tool" And the skill_protocol result error should be none And the skill_protocol result output_data should be "hello" Scenario: Create a failed SkillResult with error When I create a skill_protocol result with failure Then the skill_protocol result should be created And the skill_protocol result success should be false And the skill_protocol result error should not be none And the skill_protocol result error type should be "tool_execution_failure" Scenario: Create a SkillResult with duration and resource changes When I create a skill_protocol result with duration and resource changes Then the skill_protocol result should be created And the skill_protocol result duration_ms should be 150.5 And the skill_protocol result should have 1 resource changes Scenario: SkillResult is frozen (immutable) When I create a skill_protocol result with success Then the skill_protocol result should be immutable # ---- Error Mapping ---- Scenario: Map ValueError with cycle message to CYCLE_DETECTED When I map a skill_protocol ValueError with message "Cycle detected in skill includes" Then the skill_protocol mapped error type should be "cycle_detected" Scenario: Map ValueError with not found message to SKILL_NOT_FOUND When I map a skill_protocol ValueError with message "Skill not found" Then the skill_protocol mapped error type should be "skill_not_found" Scenario: Map generic ValueError to RESOLUTION_FAILURE When I map a skill_protocol ValueError with message "Something went wrong" Then the skill_protocol mapped error type should be "resolution_failure" Scenario: Map PermissionError to PERMISSION_DENIED When I map a skill_protocol PermissionError Then the skill_protocol mapped error type should be "permission_denied" Scenario: Map RuntimeError to TOOL_EXECUTION_FAILURE When I map a skill_protocol RuntimeError with message "Unexpected failure" Then the skill_protocol mapped error type should be "tool_execution_failure" Scenario: Map RuntimeError with activation in message When I map a skill_protocol RuntimeError with message "activation failed" Then the skill_protocol mapped error type should be "tool_activation_failure" Scenario: Error mapping with tool_name populated When I map a skill_protocol error with tool_name "local/my-tool" Then the skill_protocol mapped error tool_name should be "local/my-tool" And the skill_protocol mapped error details should have key "tool_name" Scenario: Error mapping rejects empty skill_name When I try to map a skill_protocol error with empty skill_name Then a skill_protocol value error should be raised # ---- Writes/Read-Only Metadata Propagation ---- Scenario: Skill with only read-only tools has read_only=True When I create a skill_protocol metadata from a skill with read_only tools Then the skill_protocol metadata read_only should be true And the skill_protocol metadata writes should be false Scenario: Skill with write tools has writes=True When I create a skill_protocol metadata from a skill with write tools Then the skill_protocol metadata writes should be true And the skill_protocol metadata read_only should be false Scenario: Empty skill has read_only=True When I create a skill_protocol metadata from an empty skill Then the skill_protocol metadata read_only should be true And the skill_protocol metadata writes should be false And the skill_protocol metadata tool_count should be 0 # ============================================================ # Originally from: skill_resolution.feature # Feature: Skill Domain Model and Resolution # ============================================================ Scenario: Create a skill with valid fields When I create a skill_model with name "local/code-tools" and description "Code editing tools" Then the skill_model should be created And the skill_model name should be "local/code-tools" And the skill_model description should be "Code editing tools" And the skill_model namespace should be "local" And the skill_model short_name should be "code-tools" Scenario: Create a skill with tool refs When I create a skill_model with tool refs "local/edit-file,local/read-file" Then the skill_model should be created And the skill_model should have 2 tool refs Scenario: Create a skill with all fields populated When I create a skill_model with all fields Then the skill_model should be created And the skill_model should have 2 tool refs And the skill_model should have 1 include And the skill_model should have 1 anonymous tool And the skill_model should have 1 mcp server And the skill_model should have 1 agent skill # ---- Skill Name Validation ---- Scenario: Skill name must match namespace/name pattern When I try to create a skill_model with invalid name "no-namespace" Then a skill_model validation error should be raised And the skill_model error should mention "namespace/name" Scenario: Skill name rejects spaces When I try to create a skill_model with invalid name "local/bad name" Then a skill_model validation error should be raised Scenario: Skill name rejects double slashes When I try to create a skill_model with invalid name "local//bad" Then a skill_model validation error should be raised Scenario: Skill name allows hyphens and underscores When I create a skill_model with name "my-ns/my_skill" and description "Test" Then the skill_model should be created And the skill_model namespace should be "my-ns" And the skill_model short_name should be "my_skill" Scenario: Skill description must not be empty When I try to create a skill_model with empty description Then a skill_model validation error should be raised # ---- Include Resolution (flat) ---- Scenario: Resolve skill with flat includes Given a skill_resolver registry with "local/basic-tools" containing refs "local/edit-file,local/read-file" And a skill_resolver root skill "local/code-tools" including "local/basic-tools" with own refs "local/format" When I resolve the skill_resolver root skill Then the skill_resolver result should have 3 tools And the skill_resolver result should contain tool "local/edit-file" And the skill_resolver result should contain tool "local/read-file" And the skill_resolver result should contain tool "local/format" # ---- Include Resolution (nested) ---- Scenario: Resolve skill with nested includes Given a skill_resolver registry with "local/base" containing refs "local/core-tool" And a skill_resolver registry with "local/mid" including "local/base" and containing refs "local/mid-tool" And a skill_resolver root skill "local/top" including "local/mid" with own refs "local/top-tool" When I resolve the skill_resolver root skill Then the skill_resolver result should have 3 tools And the skill_resolver result should contain tool "local/core-tool" And the skill_resolver result should contain tool "local/mid-tool" And the skill_resolver result should contain tool "local/top-tool" # ---- Cycle Detection ---- Scenario: Cycle detection with error message Given a skill_resolver registry with "local/a" including "local/b" And a skill_resolver registry with "local/b" including "local/a" When I try to resolve skill_resolver "local/a" Then a skill_resolver cycle error should be raised And the skill_resolver error should mention "local/a" And the skill_resolver error should mention "local/b" Scenario: Self-referencing cycle detection Given a skill_resolver registry with "local/self" including "local/self" When I try to resolve skill_resolver "local/self" Then a skill_resolver cycle error should be raised # ---- De-duplication ---- Scenario: De-duplication behavior last wins for overrides Given a skill_resolver registry with "local/a" containing refs "local/shared-tool" And a skill_resolver registry with "local/b" containing refs "local/shared-tool" And a skill_resolver root skill "local/top" including "local/a,local/b" with no own refs When I resolve the skill_resolver root skill Then the skill_resolver result should have 1 tools And the skill_resolver tool "local/shared-tool" should come from "local/b" # ---- Override Application ---- Scenario: Override application on tool refs When I create a skill_model with overrides for "local/edit-file" And I resolve the overridden skill_model Then the skill_resolver tool "local/edit-file" should have overrides # ---- Empty Skill ---- Scenario: Empty skill with no tools or includes When I create a skill_model with name "local/empty" and description "Empty skill" And I resolve the empty skill_model Then the skill_resolver result should have 0 tools # ---- from_config Loading ---- Scenario: Load skill from config dict When I load a skill_model from config with name "local/my-skill" Then the skill_model should be created And the skill_model name should be "local/my-skill" Scenario: Load skill from config missing name raises error When I try to load a skill_model from config missing "name" Then a skill_model config error should be raised with "name" Scenario: Load skill from config missing description raises error When I try to load a skill_model from config missing "description" Then a skill_model config error should be raised with "description" Scenario: Load skill from config with full YAML structure When I load a skill_model from full config Then the skill_model should be created And the skill_model should have 2 tool refs And the skill_model should have 1 include And the skill_model should have 1 anonymous tool And the skill_model should have 1 mcp server And the skill_model should have 1 agent skill Scenario: Load skill from config with string includes When I load a skill_model from config with string includes Then the skill_model should be created And the skill_model should have 1 include Scenario: Load skill from config with string agent skills When I load a skill_model from config with string agent skills Then the skill_model should be created And the skill_model should have 1 agent skill # ---- as_cli_dict Output ---- Scenario: Skill as_cli_dict has required keys When I create a skill_model and call as_cli_dict Then the skill_model cli dict should have key "name" And the skill_model cli dict should have key "description" And the skill_model cli dict should have key "namespace" And the skill_model cli dict should have key "short_name" Scenario: Skill as_cli_dict includes optional sections when set When I create a skill_model with all fields and call as_cli_dict Then the skill_model cli dict should have key "tool_refs" And the skill_model cli dict should have key "includes" And the skill_model cli dict should have key "anonymous_tools" And the skill_model cli dict should have key "mcp_servers" And the skill_model cli dict should have key "agent_skills" And the skill_model cli dict should have key "overrides" Scenario: Skill as_cli_dict omits empty sections When I create a skill_model with name "local/minimal" and description "Minimal" And I get the skill_model cli dict Then the skill_model cli dict should not have key "tool_refs" And the skill_model cli dict should not have key "includes" And the skill_model cli dict should not have key "anonymous_tools" And the skill_model cli dict should not have key "mcp_servers" And the skill_model cli dict should not have key "agent_skills" And the skill_model cli dict should not have key "overrides" # ---- Inline Tool Validation ---- Scenario: Inline tool with valid custom source When I create a skill_model inline tool with source "custom" and code "print('hi')" Then the skill_model inline tool should be created Scenario: Inline tool has default timeout of 300 When I create a skill_model inline tool with source "custom" and code "print('hi')" Then the skill_model inline tool timeout should be 300 Scenario: Inline tool timeout must be >= 1 When I try to create a skill_model inline tool with timeout 0 Then a skill_model validation error should be raised Scenario: Inline tool description must not be empty When I try to create a skill_model inline tool with empty description Then a skill_model validation error should be raised # ---- MCP Source Validation ---- Scenario: MCP source with specific tools When I create a skill_model mcp source with server "npx @mcp/server" and tools "read,write" Then the skill_model mcp source should be created And the skill_model mcp source should have 2 tools Scenario: MCP source with all tools (none specified) When I create a skill_model mcp source with server "npx @mcp/server" and no tools Then the skill_model mcp source should be created And the skill_model mcp source tools should be none Scenario: MCP source with env vars When I create a skill_model mcp source with env vars Then the skill_model mcp source should be created Scenario: MCP source server must not be empty When I try to create a skill_model mcp source with empty server Then a skill_model validation error should be raised # ---- Agent Skill Source Validation ---- Scenario: Agent skill source with valid path When I create a skill_model agent source with path "./skills/review" Then the skill_model agent source should be created Scenario: Agent skill source path must not be empty When I try to create a skill_model agent source with empty path Then a skill_model validation error should be raised # ---- CapabilitySummary Computation ---- Scenario: CapabilitySummary computation for skill with inline tools When I compute skill_model capability summary for a skill with inline tools Then the skill_model summary total tools should be 4 And the skill_model summary read_only_tools should be 1 And the skill_model summary write_tools should be 1 And the skill_model summary has_side_effects should be true And the skill_model summary mcp_sources should be 1 And the skill_model summary agent_skill_sources should be 1 Scenario: CapabilitySummary for empty skill When I compute skill_model capability summary for an empty skill Then the skill_model summary total tools should be 0 # ---- SkillToolRef ---- Scenario: SkillToolRef creation When I create a skill_model tool ref with name "local/my-tool" Then the skill_model tool ref should be created # ---- SkillInclude ---- Scenario: SkillInclude creation with overrides When I create a skill_model include with name "local/base" and overrides Then the skill_model include should be created And the skill_model include should have overrides Scenario: SkillInclude creation without overrides When I create a skill_model include with name "local/base" without overrides Then the skill_model include should be created # ---- Missing included skill ---- Scenario: Resolve with missing included skill raises error Given a skill_resolver root skill "local/broken" including "local/nonexistent" with no own refs When I try to resolve skill_resolver "local/broken" Then a skill_resolver missing skill error should be raised And the skill_resolver error should mention "local/nonexistent" # ---- MCP and agent skill resolution ---- Scenario: Resolve skill with MCP and agent skill sources When I create and resolve a skill_model with mcp and agent sources Then the skill_resolver result should have 3 tools # ---- ResolvedToolEntry ---- Scenario: ResolvedToolEntry creation When I create a skill_resolver resolved tool entry Then the skill_resolver entry should be created # ---- Robot Smoke Mirrors (Behave equivalents of robot/skill_resolution.robot) ---- Scenario: Resolver output ordering matches depth-first include order Given a skill_resolver registry with "local/base-tools" containing refs "local/edit-file,local/read-file" And a skill_resolver root skill "local/code-tools" including "local/base-tools" with own refs "local/format" When I resolve the skill_resolver root skill Then the skill_resolver result should have 3 tools And the skill_resolver tool at index 0 should be "local/edit-file" And the skill_resolver tool at index 1 should be "local/read-file" And the skill_resolver tool at index 2 should be "local/format" Scenario: Resolver de-duplicates overlapping include tools with last-wins Given a skill_resolver registry with "local/a" containing refs "local/shared-tool,local/a-only" And a skill_resolver registry with "local/b" containing refs "local/shared-tool,local/b-only" And a skill_resolver root skill "local/top" including "local/a,local/b" with no own refs When I resolve the skill_resolver root skill Then the skill_resolver result should have 3 tools And the skill_resolver tool "local/shared-tool" should come from "local/b" Scenario: Resolver includes inline tools with correct anon keys When I create and resolve a skill_model with inline tools Then the skill_resolver result should contain tool "local/inline-test/_anon_0" And the skill_resolver result should contain tool "local/inline-test/_anon_1" And the skill_resolver inline tool at index 1 should be marked inline