main
md 106 lines 7.48 KB
Rendered Raw
1 # skills.py DOX
2
3 ## Purpose
4
5 - Own the `skills.py` helper module.
6 - This module discovers, parses, filters, and resolves Agent Zero skills.
7 - Keep this file-level DOX profile synchronized with `skills.py` because this directory is intentionally flat.
8
9 ## Ownership
10
11 - `skills.py` owns the runtime implementation.
12 - `skills.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation.
13 - Classes:
14 - `ActiveSkillEntry` (`TypedDict`)
15 - `CatalogSkill` (`TypedDict`)
16 - `Skill` (no explicit base class)
17 - Top-level functions:
18 - `get_skills_base_dir() -> Path`
19 - `get_skill_roots(agent: Agent | None=...) -> List[str]`
20 - `_is_hidden_path(path: Path) -> bool`
21 - `discover_skill_md_files(root: Path) -> List[Path]`: Recursively discover SKILL.md files under a root directory.
22 - `_coerce_list(value: Any) -> List[str]`
23 - `_normalize_name(name: str) -> str`
24 - `_read_text(path: Path) -> str`
25 - `split_frontmatter(markdown: str) -> Tuple[Dict[str, Any], str, List[str]]`: Splits a SKILL.md into (frontmatter_dict, body_text, errors).
26 - `_parse_frontmatter_fallback(frontmatter_text: str) -> Dict[str, Any]`
27 - `parse_frontmatter(frontmatter_text: str) -> Tuple[Dict[str, Any], List[str]]`: Parse YAML frontmatter with PyYAML when available,
28 - `skill_from_markdown(skill_md_path: Path, include_content: bool=..., validate: bool=...) -> Optional[Skill]`
29 - `list_skills(agent: Agent | None=..., include_content: bool=..., include_hidden: bool=...) -> List[Skill]`: List skills, optionally filtered by agent scope.
30 - `delete_skill(skill_path: str) -> None`: Delete a skill directory.
31 - `find_skill(skill_name: str, agent: Agent | None=..., include_content: bool=..., include_hidden: bool=..., validate: bool=...) -> Optional[Skill]`
32 - `load_skill_for_agent(skill_name: str, agent: Agent | None=...) -> str`: Load skill and format it as a complete string for agent context.
33 - `skill_instruction_name(message: Any) -> str`
34 - `_get_skill_files(skill_dir: Path) -> str`: Get file tree for skill directory.
35 - `search_skills(query: str, limit: int=..., agent: Agent | None=..., include_hidden: bool=...) -> List[Skill]`
36 - `validate_skill(skill: Skill) -> List[str]`
37 - `validate_skill_md(skill_md_path: Path) -> List[str]`
38 - `_normalize_max_active_skills(value: Any) -> int`
39 - `get_max_active_skills(agent: Agent | None=..., project_name: str | None=...) -> int`
40 - `normalize_skills_config(config: dict[str, Any] | None) -> dict[str, Any]`
41 - `normalize_visibility_policy(raw: Any) -> dict[str, Any]`
42 - `get_visibility_policy(agent: Agent | None) -> dict[str, Any]`
43 - `is_skill_allowed(policy, skill_or_entry) -> bool`
44 - `ensure_skill_visible(agent, entry) -> None`
45 - `normalize_active_skills(raw: Any, limit: int | None=...) -> list[ActiveSkillEntry]`
46 - `normalize_hidden_skills(raw: Any) -> list[ActiveSkillEntry]`
47 - `normalize_skill_entries(raw: Any, limit: int | None=...) -> list[ActiveSkillEntry]`
48 - `list_skill_catalog(project_name: str=..., agent: Agent | None=...) -> list[CatalogSkill]`
49 - `get_scope_active_skills(agent: Agent | None) -> list[ActiveSkillEntry]`
50 - `get_scope_hidden_skills(agent: Agent | None) -> list[ActiveSkillEntry]`
51 - `get_chat_active_skills(context: Any | None) -> list[ActiveSkillEntry]`
52 - `get_chat_disabled_skills(context: Any | None) -> list[ActiveSkillEntry]`
53 - `get_loaded_skill_names(agent: Agent | None) -> list[str]`
54 - `set_loaded_skill_names(agent: Agent | None, skill_names: Any) -> list[str]`
55 - `add_loaded_skill_name(agent: Agent | None, skill_name: str, limit: int | None=...) -> list[str]`
56 - Notable constants/configuration names: `MAX_ACTIVE_SKILLS`, `ACTIVE_SKILLS_PLUGIN_NAME`, `AGENT_DATA_NAME_LOADED_SKILLS`, `CONTEXT_DATA_NAME_LOADED_SKILLS`, `CONTEXT_DATA_NAME_CHAT_ACTIVE_SKILLS`, `CONTEXT_DATA_NAME_CHAT_DISABLED_SKILLS`, `CONTEXT_DATA_NAME_CHAT_VISIBLE_SKILLS`, `_NAME_RE`.
57
58 ## Runtime Contracts
59
60 - Helper modules own reusable framework APIs and must preserve public callers unless all callers, tests, and docs are updated together.
61 - Update this file whenever public functions, classes, persistence behavior, path/security assumptions, side effects, or cross-module contracts change.
62 - Loaded skill names are chat-wide context data under `CONTEXT_DATA_NAME_LOADED_SKILLS`; legacy agent-local `loaded_skills` lists are migrated into context data and cleared when read.
63 - Loaded skill bodies live in chat history; hiding a skill changes catalog visibility but does not remove the loaded-skill ledger.
64 - `_skills.visibility_policy` is profile-aware and uses explicit future-skill
65 allow/block defaults. It filters discovery, search, new loading, chat
66 activation, and active-skill resolution without removing instructions already
67 stored in chat history.
68 - Visibility policy IDs match both canonical skill paths and their directory
69 names, and bulk discovery resolves the effective policy only once.
70 - Legacy `hidden_skills` remains default-allow with blocked exceptions; a chat
71 visibility override cannot bypass profile visibility policy.
72 - `build_active_skills_prompt()` returns empty because selected skills are loaded through history, not prompt protocol.
73 - `search_skills()` normalizes query words, scores normal terms against skill names, and scores only long terms against tags/triggers; descriptions match only full query phrases so generic prose does not produce irrelevant suggestions.
74 - `find_skill(validate=False)` lets validation tooling resolve a skill with incomplete metadata while preserving runtime validation by default.
75 - Slash command discovery is delegated to the built-in `_commands` helper through a local import, preserving its project/global/bundled/plugin precedence and avoiding its `split_frontmatter` import cycle. Picker-hidden commands remain hidden from Skills; reading a command returns its definition without executing it.
76 - Invalid `SKILL.md` frontmatter emits a once-per-path scan warning with the skipped skill path/name and a line number when the parser can identify one directly.
77 - Observed side-effect areas: filesystem reads, filesystem deletion, plugin state, settings/state persistence, context data, secret handling.
78 - Imported dependency areas include: `__future__`, `dataclasses`, `helpers`, `os`, `pathlib`, `re`, `typing`.
79
80 ## Key Concepts
81
82 - Important called helpers/classes observed in the source: `dataclass`, `re.compile`, `field`, `Path`, `root.rglob`, `results.sort`, `re.sub`, `path.read_text`, `text.splitlines`, `join.strip`, `parse_frontmatter`, `frontmatter_text.splitlines`, `_parse_frontmatter_fallback`, `split_frontmatter`, `str.strip`, `_coerce_list`, `Skill`, `get_skill_roots`, `_filter_hidden_skills`, `files.get_abs_path`.
83 - Keep request/response, tool, or helper semantics documented here at the same time as source changes.
84
85 ## Work Guidance
86
87 - Preserve public helper APIs used by core code and plugins unless every caller is updated.
88 - Keep path, auth, secret, persistence, network, and subprocess behavior explicit and bounded.
89 - Prefer adding cohesive helper functions here only when behavior is reused across modules.
90
91 ## Verification
92
93 - Run targeted tests for changed helper behavior; run security regressions for auth, filesystem, WebSocket, tunnel, upload, or secret-handling helpers.
94 - Related tests observed by source search:
95 - `tests/test_a0_connector_prompt_gating.py`
96 - `tests/test_browser_agent_regressions.py`
97 - `tests/test_document_query_plugin.py`
98 - `tests/test_fasta2a_client.py`
99 - `tests/test_office_canvas_setup.py`
100 - `tests/test_office_document_store.py`
101 - `tests/test_skills_runtime.py`
102 - `tests/test_time_travel.py`
103
104 ## Child DOX Index
105
106 No child DOX files.