context.skills() – Centralized Registry for Structured Prompt Engineering¶
Skills are AetherGraph’s lightweight unit of instruction + metadata. They are used to:
- Provide consistent prompts / rubrics for planning and chat.
- Package domain knowledge (including examples) in a reusable, versioned format.
- Power discovery and routing via tags, domains, and modes.
A skill can be created:
- In code (a
Skillobject), or - From Markdown (
.md) files (or folders of.mdfiles) with a simple front-matter + section convention.
1. Skill Class¶
A Skill is a small container for:
id,title,descriptiontags,domain,modes(used for filtering and routing)config(arbitrary metadata)sections(named chunks of markdown used for prompts, examples, or notes)
Defining skills via Markdown¶
You can define a skill in a Markdown file. This is the recommended way to maintain prompt packs in a readable, reviewable format.
How sections work (skills().section)
context.skills().section(skill_id, section_key, default=...) returns the raw Markdown content stored under the H2 heading whose text matches section_key.
- If your file has
## chat.system, thensection_key="chat.system"returns everything under that heading. - Content before the first
## ...heading is stored under the special key"body".
(See the section format rules below.)
File format
Notes:
- The file must start with a YAML front matter block delimited by --- lines.
Example:
---
id: demo.prompts
title: Demo prompt pack
description: Shared prompts and examples for common interactions.
tags: [demo, prompts]
domain: general
modes: [planning, chat]
version: "0.1.0"
---
id and title are required. Additional keys are stored in Skill.config.
-
The body of the file is divided into sections using H2 headings (
##). Example:The heading text is used as the section key (e.g.,## chat.system System-level prompts for chat interactions. ## planning.header Header content for planning workflows."chat.system"). -
Content before the first
##heading is stored in a special section"body". -
Deeper headings (e.g.,
###) are treated as content within the current section. -
Empty sections are ignored, and section bodies are stored as raw markdown strings.
Minimal end-to-end example
---
id: demo.hello
title: Hello skill
description: Minimal skill example.
tags: [demo]
domain: general
modes: [chat]
---
## chat.system
You are a helpful assistant.
## chat.example
User: Say hello in one sentence.
Assistant: Hello! Nice to meet you.
Multiple .md files in a folder¶
You can organize skills as a folder of markdown files, typically one skill per file.
Common patterns:
-
Many independent skills (each file has its own
id):skills/ demo.hello.md demo.planning.md writing.email.md -
Topic packs (group related skills in a directory, load all at once):
skills/writing/ email.md summarize.md tone.md
Loading behavior:
- Use SkillRegistry.load_path(...) (or the runtime convenience wrapper) to scan a directory.
- Recommended convention: each file contains its own YAML front matter with a unique id.
Skill
Skill represents a reusable prompt "skill" that can be loaded from markdown or defined inline. It includes metadata, configuration, and sections of content that can be used to generate prompts.
Attributes:
| Name | Type | Description |
|---|---|---|
id |
str
|
Unique identifier for the skill. |
title |
str
|
Title of the skill. |
description |
str
|
Description of the skill. Defaults to an empty string. |
tags |
list[str]
|
Tags associated with the skill. Defaults to an empty list. |
domain |
str | None
|
Domain or category of the skill. Defaults to None. |
modes |
list[str]
|
Modes in which the skill can be used (e.g., 'chat', 'planning', 'coding'). Defaults to an empty list. |
version |
str | None
|
Version of the skill. Defaults to None. |
config |
dict[str, Any]
|
Additional configuration for the skill. Defaults to an empty dictionary. |
sections |
dict[str, str]
|
Parsed sections of the skill, keyed by dot-paths. |
raw_markdown |
str | None
|
Raw markdown content of the skill. Defaults to None. |
path |
Path | None
|
File path of the skill, if loaded from a file. Defaults to None. |
Methods:
| Name | Description |
|---|---|
section |
str, default: str = "") -> str: Retrieve a specific section by its dot-path key. Returns the default value if the section is missing. |
has_section |
str) -> bool: Check if a specific section exists in the skill. |
compile_prompt |
str, separator: str, fallback_keys: Iterable[str] | None = None) -> str: Compile a prompt by concatenating specified sections. If no sections are specified, compiles the entire skill. |
from_dict |
Mapping[str, Any], sections: Mapping[str, str], *, raw_markdown: str | None = None, path: Path | None = None) -> Skill: Class method to create a Skill instance from metadata and sections. Useful for programmatically defining skills. |
Skill represents a reusable prompt "skill" that can be loaded from markdown or defined inline. It includes metadata, configuration, and sections of content that can be used to generate prompts.
Attributes:
| Name | Type | Description |
|---|---|---|
id |
str
|
Unique identifier for the skill. |
title |
str
|
Title of the skill. |
description |
str
|
Description of the skill. Defaults to an empty string. |
tags |
list[str]
|
Tags associated with the skill. Defaults to an empty list. |
domain |
str | None
|
Domain or category of the skill. Defaults to None. |
modes |
list[str]
|
Modes in which the skill can be used (e.g., 'chat', 'planning', 'coding'). Defaults to an empty list. |
version |
str | None
|
Version of the skill. Defaults to None. |
config |
dict[str, Any]
|
Additional configuration for the skill. Defaults to an empty dictionary. |
sections |
dict[str, str]
|
Parsed sections of the skill, keyed by dot-paths. |
raw_markdown |
str | None
|
Raw markdown content of the skill. Defaults to None. |
path |
Path | None
|
File path of the skill, if loaded from a file. Defaults to None. |
Methods:
| Name | Description |
|---|---|
section |
str, default: str = "") -> str: Retrieve a specific section by its dot-path key. Returns the default value if the section is missing. |
has_section |
str) -> bool: Check if a specific section exists in the skill. |
compile_prompt |
str, separator: str, fallback_keys: Iterable[str] | None = None) -> str: Compile a prompt by concatenating specified sections. If no sections are specified, compiles the entire skill. |
from_dict |
Mapping[str, Any], sections: Mapping[str, str], *, raw_markdown: str | None = None, path: Path | None = None) -> Skill: Class method to create a Skill instance from metadata and sections. Useful for programmatically defining skills. |
2. SkillRegistry¶
Accessed from context.skills().
SkillRegistry is the primary API for:
- Registering skills (objects, inline definitions, files, or whole directories)
- Querying (
get,require,all,ids) - Reading sections (
section) and compiling prompts (compile_prompt) - Discovering skills by tag/domain/mode (
find) and emitting summaries (describe)
register(skill, *, overwrite)
Register a Skill object.
This method allows you to add a Skill object to the registry. If a
skill with the same ID already exists and overwrite is set to False,
a ValueError will be raised.
Examples:
Registering a skill object:
skill = Skill(
id="example.skill",
title="Example Skill",
description="An example skill for demonstration purposes.",
tags=["example", "demo"],
domain="general",
modes=["chat"],
)
registry.register(skill)
Overwriting an existing skill:
registry.register(skill, overwrite=True)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
skill
|
Skill
|
The |
required |
overwrite
|
bool
|
Whether to overwrite an existing skill with the same ID. (Optional) |
False
|
register_inline(*, id, title, description, tags, ...)
Convenience for defining a Skill entirely in Python.
This method allows you to define and register a Skill inline, without needing to create a separate markdown file. It is useful for quick prototyping or defining simple skills directly in code.
Examples:
Registering a basic coding helper skill:
registry.register_inline(
id="coding.generic",
title="Generic coding helper",
description="Helps with Python code generation and review.",
tags=["coding"],
modes=["chat", "coding"],
sections={
"chat.system": "You are a helpful coding assistant...",
"coding.system": "You write code as JSON ...",
},
)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
id
|
str
|
The unique identifier for the skill. (Required) |
required |
title
|
str
|
A short, descriptive title for the skill. (Required) |
required |
description
|
str
|
A longer description of the skill's purpose. (Optional) |
''
|
tags
|
list[str] | None
|
A list of tags for categorization. (Optional) |
None
|
domain
|
str | None
|
The domain or category the skill belongs to. (Optional) |
None
|
modes
|
list[str] | None
|
A list of modes the skill supports (e.g., "chat", "coding"). (Optional) |
None
|
version
|
str | None
|
The version of the skill. (Optional) |
None
|
config
|
dict[str, Any] | None
|
A dictionary of additional configuration options. (Optional) |
None
|
sections
|
dict[str, str] | None
|
A dictionary mapping section keys to their content. (Optional) |
None
|
overwrite
|
bool
|
Whether to overwrite an existing skill with the same ID. (Optional) |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
Skill |
Skill
|
The registered |
load_file(path, *, overwrite)
Load a single .md skill file and register it.
This method reads the content of a markdown file, parses it into a
Skill object, and registers it in the skill registry.
Examples:
Loading a skill from a file:
skill = registry.load_file("path/to/skill.md")
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path
|
The file path to the markdown skill file. (Required) |
required |
overwrite
|
bool
|
Whether to overwrite an existing skill with the same ID. (Optional) |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
Skill |
Skill
|
The registered |
load_path(root, *, pattern, recursive, overwrite)
Load all skill markdown files under a directory.
This method scans the specified directory for markdown files matching
the given pattern, parses them into Skill objects, and registers them
in the skill registry.
Examples:
Loading all skills from a directory recursively:
skills = registry.load_path("path/to/skills", pattern="*.md", recursive=True)
Loading skills from a directory without recursion:
skills = registry.load_path("path/to/skills", recursive=False)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
root
|
str | Path
|
The root directory to scan for markdown files. (Required) |
required |
pattern
|
str
|
The glob pattern to match files (e.g., |
'*.md'
|
recursive
|
bool
|
Whether to scan directories recursively. (Optional) |
True
|
overwrite
|
bool
|
Whether to overwrite existing skills with the same ID. (Optional) |
False
|
Returns:
| Type | Description |
|---|---|
list[Skill]
|
list[Skill]: A list of all successfully loaded and registered |
get(skill_id)
Get a registered Skill by id.
This method retrieves a Skill object from the registry using its unique
identifier. If the skill is not found, it returns None.
Examples:
Retrieving a skill by its ID:
skill = registry.get("coding.generic")
if skill:
print(skill.title)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
skill_id
|
str
|
The unique identifier of the skill to retrieve. (Required) |
required |
Returns:
| Type | Description |
|---|---|
Skill | None
|
Skill | None: The |
require(skill_id)
Retrieve a registered Skill by its unique identifier.
This method ensures that the requested Skill exists in the registry. If the Skill is not found, it raises a KeyError.
Examples:
Retrieving a skill by its ID:
skill = registry.require("coding.generic")
print(skill.title)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
skill_id
|
str
|
The unique identifier of the skill to retrieve. (Required) |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Skill |
Skill
|
The |
Raises:
| Type | Description |
|---|---|
KeyError
|
If the skill with the specified ID is not found. |
all()
Return all registered Skills.
This method retrieves all Skill objects currently registered in the
skill registry and returns them as a list.
Examples:
Retrieving all registered skills:
skills = registry.all()
for skill in skills:
print(skill.id, skill.title)
Returns:
| Type | Description |
|---|---|
list[Skill]
|
list[Skill]: A list of all registered |
ids(skill)
Return all registered Skill ids.
This method retrieves the unique identifiers of all Skill objects
currently registered in the skill registry and returns them as a sorted list.
Examples:
Retrieving all skill IDs:
skill_ids = registry.ids()
print(skill_ids)
Returns:
| Type | Description |
|---|---|
list[str]
|
list[str]: A sorted list of all registered skill IDs. |
section(skill_id, section_key, default)
Return a section for a given skill, or default.
This method retrieves the content of a specific section within a skill by its unique identifier and section key. If the skill or section is not found, it returns the provided default value.
Examples:
Retrieving a section from a skill:
section_content = registry.section("coding.generic", "chat.system")
print(section_content)
Providing a default value if the section is missing:
section_content = registry.section("nonexistent.skill", "missing.section", default="Default content")
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
skill_id
|
str
|
The unique identifier of the skill. (Required) |
required |
section_key
|
str
|
The key of the section to retrieve. (Required) |
required |
default
|
str
|
The value to return if the skill or section is not found. (Optional) |
''
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The content of the section if found, otherwise the default value. |
compile_prompt(skill_id, *section_keys, separator, fallback_keys)
Shortcut for Skill.compile_prompt(...) by id.
This method compiles a prompt by combining multiple sections of a skill identified by its unique ID. It allows you to specify the sections to include, the separator to use between sections, and fallback keys for missing sections.
Examples:
Compiling a prompt with specific sections:
prompt = registry.compile_prompt(
"coding.generic",
"chat.system",
"chat.user",
)
Using fallback keys for missing sections:
prompt = registry.compile_prompt(
"coding.generic",
"chat.system",
"chat.user",
fallback_keys=["default.system", "default.user"]
)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
skill_id
|
str
|
The unique identifier of the skill. (Required) |
required |
*section_keys
|
str
|
The keys of the sections to include in the prompt. (Required) |
()
|
separator
|
str
|
The string to use as a separator between sections. (Optional) |
'\n\n'
|
fallback_keys
|
list[str] | None
|
A list of fallback section keys to use if a section |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
The compiled prompt as a single string. |
find(tag, domain, mode, predicate)
Filter skills by tag, domain, mode, and/or a custom predicate.
This method allows you to filter registered skills based on specific criteria such as tags, domain, mode, or a custom predicate function.
Examples:
Finding skills with a specific tag and mode:
skills = registry.find(tag="surrogate", mode="planning")
Using a custom predicate to filter skills:
skills = registry.find(predicate=lambda s: "example" in s.title)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tag
|
str | None
|
A string representing the tag to filter by. (Optional) |
None
|
domain
|
str | None
|
The domain or category to filter by. (Optional) |
None
|
mode
|
str | None
|
The mode (e.g., "chat", "coding") to filter by. (Optional) |
None
|
predicate
|
callable | None
|
A callable that takes a |
None
|
Returns:
| Type | Description |
|---|---|
list[Skill]
|
list[Skill]: A list of |
describe()
Return a compact description of all registered skills.
This method provides a summary of all skills currently registered in the registry, including their metadata such as ID, title, description, tags, domain, modes, version, and sections.
Examples:
Retrieving skill descriptions for debugging or UI purposes:
descriptions = registry.describe()
for skill in descriptions:
print(skill["id"], skill["title"])
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
list[dict[str, Any]]: A list of dictionaries, each containing the |
list[dict[str, Any]]
|
metadata of a registered skill. |
3. Global Registration¶
Access through aethergraph.runtime.
When starting a server (or wiring up an app bootstrap), prefer the runtime convenience methods for global registration. They’re ergonomic and keep startup scripts concise.
register_skill(skill, *, overwrite)
Register an existing Skill object into the global registry.
This method adds a Skill instance to the global SkillRegistry, making it
available for use throughout the application. The overwrite flag determines
whether an existing skill with the same ID will be replaced.
Examples:
Registering a skill object:
skill = Skill(id="example.skill", title="Example Skill")
register_skill(skill)
Overwriting an existing skill:
skill = Skill(id="example.skill", title="Updated Skill")
register_skill(skill, overwrite=True)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
skill
|
Skill
|
The |
required |
overwrite
|
bool
|
Whether to overwrite an existing skill with the same ID. Default is |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
Skill |
Skill
|
The registered |
register_skill_inline(id, title, description, tags, ...)
Define and register a Skill entirely in Python.
This method allows you to define a Skill inline with all its metadata and sections, and directly register it into the global Skill registry.
Examples:
Registering a skill with basic metadata and sections:
register_skill_inline(
id="surrogate.workflow",
title="Surrogate workflow planning",
description="Prompts and patterns for surrogate planning.",
tags=["surrogate", "planning"],
modes=["planning"],
sections={
"planning.header": "...",
"planning.binding_hints": "...",
"chat.system": "...",
},
)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
id
|
str
|
The unique identifier for the Skill. (Required) |
required |
title
|
str
|
A human-readable title for the Skill. (Required) |
required |
description
|
str
|
A short description of the Skill's purpose. (Optional) |
''
|
tags
|
list[str]
|
A list of tags for categorization. (Optional) |
None
|
domain
|
str
|
The domain or namespace for the Skill. (Optional) |
None
|
modes
|
list[str]
|
The operational modes supported by the Skill. (Optional) |
None
|
version
|
str
|
The version string for the Skill. (Optional) |
None
|
config
|
dict[str, Any]
|
Additional configuration data. (Optional) |
None
|
sections
|
dict[str, str]
|
A dictionary mapping section names to their content. (Optional) |
None
|
overwrite
|
bool
|
Whether to overwrite an existing Skill with the same ID. (Optional) |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
Skill |
Skill
|
The registered Skill instance. |
register_skill_file(path, *, overwrite)
Load a single markdown skill file and register it.
This function processes a markdown file containing skill definitions and registers it into the global skill registry. The file must adhere to the expected format for parsing skill metadata and sections.
Examples:
Registering a skill from a markdown file:
skill = register_skill_file("skills/surrogate-workflow.md")
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path
|
The path to the markdown file to load. |
required |
overwrite
|
bool
|
Whether to overwrite an existing skill with the same ID. (Optional, default: False) |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
Skill |
Skill
|
The registered |
Notes
To start the server and load all desired packages:
1. Open a terminal and navigate to the project directory.
2. Run the server using the appropriate command (e.g., python -m aethergraph.server).
3. Ensure all required dependencies are installed via pip install -r requirements.txt.
register_skills_from_path(root, *, pattern, recursive, overwrite)
Load and register all skill markdown files under a directory.
This method scans the specified directory for markdown files matching the
given pattern, parses their content into Skill objects, and registers
them into the global skill registry. The directory can have a flat or
nested structure.
Examples:
Register all skills in a flat directory:
register_skills_from_path("skills/")
Register skills in a nested directory structure:
register_skills_from_path("skills/", recursive=True)
Use a custom file pattern to filter files:
register_skills_from_path("skills/", pattern="*.skill.md")
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
root
|
str | Path
|
The root directory to scan for skill files. |
required |
pattern
|
str
|
A glob pattern to match skill files. Default is |
'*.md'
|
recursive
|
bool
|
Whether to scan subdirectories recursively. Default is |
True
|
overwrite
|
bool
|
Whether to overwrite existing skills with the same ID. Default is |
False
|
Returns:
| Type | Description |
|---|---|
list[Skill]
|
list[Skill]: A list of all registered |
Notes
To start the server and load all desired packages:
1. Open a terminal and navigate to the project directory.
2. Run the server using the appropriate command (e.g., python -m aethergraph.server).
3. Ensure all required dependencies are installed via pip install -r requirements.txt.