Auto-generated from Python source using mkdocstrings.
All signatures and docstrings reflect the current src/ztlctl/ codebase.
This page documents the stable public API surface: plugin hookspecs, contribution contracts, the action system, and API versioning. Use the section headings to navigate to the module you need. For usage examples and step-by-step tutorials, see the Plugin Authoring Guide.
Scope
This reference covers the plugin public API only — the contracts, hookspecs, and action system that plugin authors and advanced integrators interact with. Internal service and infrastructure layers are not documented here.
Plugin Hookspecs¶
The ZtlctlHookSpec class defines all pluggy hookspecs. Implement any subset of these in your plugin class.
ztlctl.plugins.hookspecs
¶
Pluggy hook specifications for ztlctl lifecycle events and extensions.
ZtlctlHookSpec
¶
Hook specifications for the ztlctl plugin system.
Source code in src/ztlctl/plugins/hookspecs.py
class ZtlctlHookSpec:
"""Hook specifications for the ztlctl plugin system."""
# ------------------------------------------------------------------
# Generic action hooks (PLUG-02) — preferred over per-event hooks
# ------------------------------------------------------------------
@hookspec(firstresult=True)
def pre_action(
self, action_name: str, kwargs: dict[str, Any]
) -> ActionRejection | dict[str, Any] | None:
"""Called before action execution.
Return an :class:`~ztlctl.plugins.contracts.ActionRejection` to abort
the action, a modified *kwargs* dict to replace the original keyword
arguments, or ``None`` to pass through unchanged.
This is a ``firstresult`` hook — the first plugin returning a non-``None``
value wins and subsequent plugins are not called.
"""
@hookspec
def post_action(self, action_name: str, kwargs: dict[str, Any], result: Any) -> None:
"""Called after action execution with the ServiceResult.
All registered plugins receive this hook regardless of the action outcome.
"""
# ------------------------------------------------------------------
# Plugin configuration (PLUG-03)
# ------------------------------------------------------------------
@hookspec(firstresult=True)
def get_config_schema(self) -> type[BaseModel] | None:
"""Return the Pydantic model class used to validate this plugin's config.
The schema is retrieved once at load time. If the ``[plugins.<name>]``
TOML section exists, its contents are validated against the returned
model and then passed to :meth:`initialize`.
"""
@hookspec
def initialize(self, config: BaseModel | None) -> None:
"""Called once after plugin loading with validated configuration.
*config* is a validated Pydantic model instance if a schema was
declared via :meth:`get_config_schema` and a matching TOML section
exists, otherwise ``None``.
"""
# ------------------------------------------------------------------
# Deprecated per-event lifecycle hooks
# Prefer implementing post_action and filtering by action_name.
# ------------------------------------------------------------------
@hookspec(
warn_on_impl=DeprecationWarning(
"post_create is deprecated since plugin API v2; "
"implement post_action and filter by action_name instead"
)
)
def post_create(
self,
content_type: str,
content_id: str,
title: str,
path: str,
tags: list[str],
) -> None:
"""Called after content creation."""
@hookspec(
warn_on_impl=DeprecationWarning(
"post_update is deprecated since plugin API v2; "
"implement post_action and filter by action_name instead"
)
)
def post_update(
self,
content_type: str,
content_id: str,
fields_changed: list[str],
path: str,
) -> None:
"""Called after content update."""
@hookspec(
warn_on_impl=DeprecationWarning(
"post_close is deprecated since plugin API v2; "
"implement post_action and filter by action_name instead"
)
)
def post_close(
self,
content_type: str,
content_id: str,
path: str,
summary: str,
) -> None:
"""Called after close/archive."""
@hookspec(
warn_on_impl=DeprecationWarning(
"post_reweave is deprecated since plugin API v2; "
"implement post_action and filter by action_name instead"
)
)
def post_reweave(
self,
source_id: str,
affected_ids: list[str],
links_added: int,
) -> None:
"""Called after reweave completes."""
@hookspec(
warn_on_impl=DeprecationWarning(
"post_session_start is deprecated since plugin API v2; "
"implement post_action and filter by action_name instead"
)
)
def post_session_start(self, session_id: str) -> None:
"""Called after a session begins."""
@hookspec(
warn_on_impl=DeprecationWarning(
"post_session_close is deprecated since plugin API v2; "
"implement post_action and filter by action_name instead"
)
)
def post_session_close(
self,
session_id: str,
stats: dict[str, Any],
) -> None:
"""Called after a session closes."""
@hookspec(
warn_on_impl=DeprecationWarning(
"post_check is deprecated since plugin API v2; "
"implement post_action and filter by action_name instead"
)
)
def post_check(
self,
issues_found: int,
issues_fixed: int,
) -> None:
"""Called after integrity check."""
@hookspec(
warn_on_impl=DeprecationWarning(
"post_init is deprecated since plugin API v2; "
"implement post_action and filter by action_name instead"
)
)
def post_init(
self,
vault_name: str,
client: str,
tone: str,
) -> None:
"""Called after vault init."""
@hookspec(
warn_on_impl=DeprecationWarning(
"post_init_profile is deprecated since plugin API v2; "
"implement post_action and filter by action_name instead"
)
)
def post_init_profile(
self,
vault_name: str,
profile: str,
tone: str,
managed_paths: list[str],
) -> None:
"""Called after vault init with canonical workspace profile metadata.
``managed_paths`` reports the scaffold surface associated with the
selected profile during init. It is descriptive metadata, not a promise
of future lifecycle management by ztlctl.
"""
# ------------------------------------------------------------------
# Extension contribution hooks
# ------------------------------------------------------------------
@hookspec
def register_content_models(self) -> dict[str, type[ContentModel]] | None:
"""Return subtype -> ContentModel mappings to extend CONTENT_REGISTRY."""
@hookspec
def register_cli_commands(self) -> list[CliCommandContribution] | None:
"""Return plugin CLI command contributions."""
@hookspec
def register_mcp_tools(self) -> list[McpToolContribution] | None:
"""Return plugin MCP tool contributions."""
@hookspec
def register_mcp_resources(self) -> list[McpResourceContribution] | None:
"""Return plugin MCP resource contributions."""
@hookspec
def register_mcp_prompts(self) -> list[McpPromptContribution] | None:
"""Return plugin MCP prompt contributions."""
@hookspec
def register_workflow_modules(self) -> list[WorkflowModuleContribution] | None:
"""Return plugin workflow export modules."""
@hookspec
def register_workspace_profiles(self) -> list[WorkspaceProfileContribution] | None:
"""Return plugin workspace profile contributions."""
@hookspec
def register_vault_init_steps(self) -> list[VaultInitStepContribution] | None:
"""Return ordered plugin steps to run during `ztlctl init`."""
@hookspec
def register_source_providers(self) -> list[SourceProviderContribution] | None:
"""Return plugin-provided source ingestion providers."""
# ------------------------------------------------------------------
# Custom note type + rendering hooks (PLUG-05, PLUG-06)
# ------------------------------------------------------------------
@hookspec
def register_note_types(self) -> list[NoteTypeDefinition] | None:
"""Return NoteTypeDefinitions to register into NoteTypeRegistry + ActionRegistry.
PluginManager will auto-create create/update/close ActionDefinitions for
each registered NoteTypeDefinition and add them to the ActionRegistry so
the CLI and MCP generators pick them up automatically.
"""
@hookspec
def register_render_contributions(self) -> list[RenderContribution] | None:
"""Return render contributions for custom note types.
Each :class:`~ztlctl.plugins.contracts.RenderContribution` provides a
``rich_formatter`` and an ``mcp_formatter`` callable for one note type,
enabling custom terminal and MCP output formatting.
"""
# ------------------------------------------------------------------
# Security — capability declarations (SECU-02)
# ------------------------------------------------------------------
@hookspec
def declare_capabilities(self) -> set[str] | None:
"""Return the set of capabilities this plugin requires.
Valid values: ``{"filesystem", "network", "database", "git"}``.
Missing declaration is treated as a warning (not an error) in plugin
API v2 to avoid breaking existing plugins. Future API versions may
enforce declarations. Returns ``None`` or does not implement to
indicate no declaration.
"""
pre_action
¶
pre_action(action_name: str, kwargs: dict[str, Any]) -> ActionRejection | dict[str, Any] | None
Called before action execution.
Return an :class:~ztlctl.plugins.contracts.ActionRejection to abort
the action, a modified kwargs dict to replace the original keyword
arguments, or None to pass through unchanged.
This is a firstresult hook — the first plugin returning a non-None
value wins and subsequent plugins are not called.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec(firstresult=True)
def pre_action(
self, action_name: str, kwargs: dict[str, Any]
) -> ActionRejection | dict[str, Any] | None:
"""Called before action execution.
Return an :class:`~ztlctl.plugins.contracts.ActionRejection` to abort
the action, a modified *kwargs* dict to replace the original keyword
arguments, or ``None`` to pass through unchanged.
This is a ``firstresult`` hook — the first plugin returning a non-``None``
value wins and subsequent plugins are not called.
"""
post_action
¶
post_action(action_name: str, kwargs: dict[str, Any], result: Any) -> None
Called after action execution with the ServiceResult.
All registered plugins receive this hook regardless of the action outcome.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec
def post_action(self, action_name: str, kwargs: dict[str, Any], result: Any) -> None:
"""Called after action execution with the ServiceResult.
All registered plugins receive this hook regardless of the action outcome.
"""
get_config_schema
¶
get_config_schema() -> type[BaseModel] | None
Return the Pydantic model class used to validate this plugin's config.
The schema is retrieved once at load time. If the [plugins.<name>]
TOML section exists, its contents are validated against the returned
model and then passed to :meth:initialize.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec(firstresult=True)
def get_config_schema(self) -> type[BaseModel] | None:
"""Return the Pydantic model class used to validate this plugin's config.
The schema is retrieved once at load time. If the ``[plugins.<name>]``
TOML section exists, its contents are validated against the returned
model and then passed to :meth:`initialize`.
"""
initialize
¶
initialize(config: BaseModel | None) -> None
Called once after plugin loading with validated configuration.
config is a validated Pydantic model instance if a schema was
declared via :meth:get_config_schema and a matching TOML section
exists, otherwise None.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec
def initialize(self, config: BaseModel | None) -> None:
"""Called once after plugin loading with validated configuration.
*config* is a validated Pydantic model instance if a schema was
declared via :meth:`get_config_schema` and a matching TOML section
exists, otherwise ``None``.
"""
post_create
¶
post_create(content_type: str, content_id: str, title: str, path: str, tags: list[str]) -> None
Called after content creation.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec(
warn_on_impl=DeprecationWarning(
"post_create is deprecated since plugin API v2; "
"implement post_action and filter by action_name instead"
)
)
def post_create(
self,
content_type: str,
content_id: str,
title: str,
path: str,
tags: list[str],
) -> None:
"""Called after content creation."""
post_update
¶
post_update(content_type: str, content_id: str, fields_changed: list[str], path: str) -> None
Called after content update.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec(
warn_on_impl=DeprecationWarning(
"post_update is deprecated since plugin API v2; "
"implement post_action and filter by action_name instead"
)
)
def post_update(
self,
content_type: str,
content_id: str,
fields_changed: list[str],
path: str,
) -> None:
"""Called after content update."""
post_close
¶
post_close(content_type: str, content_id: str, path: str, summary: str) -> None
Called after close/archive.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec(
warn_on_impl=DeprecationWarning(
"post_close is deprecated since plugin API v2; "
"implement post_action and filter by action_name instead"
)
)
def post_close(
self,
content_type: str,
content_id: str,
path: str,
summary: str,
) -> None:
"""Called after close/archive."""
post_reweave
¶
post_reweave(source_id: str, affected_ids: list[str], links_added: int) -> None
Called after reweave completes.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec(
warn_on_impl=DeprecationWarning(
"post_reweave is deprecated since plugin API v2; "
"implement post_action and filter by action_name instead"
)
)
def post_reweave(
self,
source_id: str,
affected_ids: list[str],
links_added: int,
) -> None:
"""Called after reweave completes."""
post_session_start
¶
post_session_start(session_id: str) -> None
Called after a session begins.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec(
warn_on_impl=DeprecationWarning(
"post_session_start is deprecated since plugin API v2; "
"implement post_action and filter by action_name instead"
)
)
def post_session_start(self, session_id: str) -> None:
"""Called after a session begins."""
post_session_close
¶
post_session_close(session_id: str, stats: dict[str, Any]) -> None
Called after a session closes.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec(
warn_on_impl=DeprecationWarning(
"post_session_close is deprecated since plugin API v2; "
"implement post_action and filter by action_name instead"
)
)
def post_session_close(
self,
session_id: str,
stats: dict[str, Any],
) -> None:
"""Called after a session closes."""
post_check
¶
post_check(issues_found: int, issues_fixed: int) -> None
Called after integrity check.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec(
warn_on_impl=DeprecationWarning(
"post_check is deprecated since plugin API v2; "
"implement post_action and filter by action_name instead"
)
)
def post_check(
self,
issues_found: int,
issues_fixed: int,
) -> None:
"""Called after integrity check."""
post_init
¶
post_init(vault_name: str, client: str, tone: str) -> None
Called after vault init.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec(
warn_on_impl=DeprecationWarning(
"post_init is deprecated since plugin API v2; "
"implement post_action and filter by action_name instead"
)
)
def post_init(
self,
vault_name: str,
client: str,
tone: str,
) -> None:
"""Called after vault init."""
post_init_profile
¶
post_init_profile(vault_name: str, profile: str, tone: str, managed_paths: list[str]) -> None
Called after vault init with canonical workspace profile metadata.
managed_paths reports the scaffold surface associated with the
selected profile during init. It is descriptive metadata, not a promise
of future lifecycle management by ztlctl.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec(
warn_on_impl=DeprecationWarning(
"post_init_profile is deprecated since plugin API v2; "
"implement post_action and filter by action_name instead"
)
)
def post_init_profile(
self,
vault_name: str,
profile: str,
tone: str,
managed_paths: list[str],
) -> None:
"""Called after vault init with canonical workspace profile metadata.
``managed_paths`` reports the scaffold surface associated with the
selected profile during init. It is descriptive metadata, not a promise
of future lifecycle management by ztlctl.
"""
register_content_models
¶
register_content_models() -> dict[str, type[ContentModel]] | None
Return subtype -> ContentModel mappings to extend CONTENT_REGISTRY.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec
def register_content_models(self) -> dict[str, type[ContentModel]] | None:
"""Return subtype -> ContentModel mappings to extend CONTENT_REGISTRY."""
register_cli_commands
¶
register_cli_commands() -> list[CliCommandContribution] | None
Return plugin CLI command contributions.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec
def register_cli_commands(self) -> list[CliCommandContribution] | None:
"""Return plugin CLI command contributions."""
register_mcp_tools
¶
register_mcp_tools() -> list[McpToolContribution] | None
Return plugin MCP tool contributions.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec
def register_mcp_tools(self) -> list[McpToolContribution] | None:
"""Return plugin MCP tool contributions."""
register_mcp_resources
¶
register_mcp_resources() -> list[McpResourceContribution] | None
Return plugin MCP resource contributions.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec
def register_mcp_resources(self) -> list[McpResourceContribution] | None:
"""Return plugin MCP resource contributions."""
register_mcp_prompts
¶
register_mcp_prompts() -> list[McpPromptContribution] | None
Return plugin MCP prompt contributions.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec
def register_mcp_prompts(self) -> list[McpPromptContribution] | None:
"""Return plugin MCP prompt contributions."""
register_workflow_modules
¶
register_workflow_modules() -> list[WorkflowModuleContribution] | None
Return plugin workflow export modules.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec
def register_workflow_modules(self) -> list[WorkflowModuleContribution] | None:
"""Return plugin workflow export modules."""
register_workspace_profiles
¶
register_workspace_profiles() -> list[WorkspaceProfileContribution] | None
Return plugin workspace profile contributions.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec
def register_workspace_profiles(self) -> list[WorkspaceProfileContribution] | None:
"""Return plugin workspace profile contributions."""
register_vault_init_steps
¶
register_vault_init_steps() -> list[VaultInitStepContribution] | None
Return ordered plugin steps to run during ztlctl init.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec
def register_vault_init_steps(self) -> list[VaultInitStepContribution] | None:
"""Return ordered plugin steps to run during `ztlctl init`."""
register_source_providers
¶
register_source_providers() -> list[SourceProviderContribution] | None
Return plugin-provided source ingestion providers.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec
def register_source_providers(self) -> list[SourceProviderContribution] | None:
"""Return plugin-provided source ingestion providers."""
register_note_types
¶
register_note_types() -> list[NoteTypeDefinition] | None
Return NoteTypeDefinitions to register into NoteTypeRegistry + ActionRegistry.
PluginManager will auto-create create/update/close ActionDefinitions for each registered NoteTypeDefinition and add them to the ActionRegistry so the CLI and MCP generators pick them up automatically.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec
def register_note_types(self) -> list[NoteTypeDefinition] | None:
"""Return NoteTypeDefinitions to register into NoteTypeRegistry + ActionRegistry.
PluginManager will auto-create create/update/close ActionDefinitions for
each registered NoteTypeDefinition and add them to the ActionRegistry so
the CLI and MCP generators pick them up automatically.
"""
register_render_contributions
¶
register_render_contributions() -> list[RenderContribution] | None
Return render contributions for custom note types.
Each :class:~ztlctl.plugins.contracts.RenderContribution provides a
rich_formatter and an mcp_formatter callable for one note type,
enabling custom terminal and MCP output formatting.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec
def register_render_contributions(self) -> list[RenderContribution] | None:
"""Return render contributions for custom note types.
Each :class:`~ztlctl.plugins.contracts.RenderContribution` provides a
``rich_formatter`` and an ``mcp_formatter`` callable for one note type,
enabling custom terminal and MCP output formatting.
"""
declare_capabilities
¶
declare_capabilities() -> set[str] | None
Return the set of capabilities this plugin requires.
Valid values: {"filesystem", "network", "database", "git"}.
Missing declaration is treated as a warning (not an error) in plugin
API v2 to avoid breaking existing plugins. Future API versions may
enforce declarations. Returns None or does not implement to
indicate no declaration.
Source code in src/ztlctl/plugins/hookspecs.py
@hookspec
def declare_capabilities(self) -> set[str] | None:
"""Return the set of capabilities this plugin requires.
Valid values: ``{"filesystem", "network", "database", "git"}``.
Missing declaration is treated as a warning (not an error) in plugin
API v2 to avoid breaking existing plugins. Future API versions may
enforce declarations. Returns ``None`` or does not implement to
indicate no declaration.
"""
Plugin Contracts¶
Data classes returned from and passed to hookspecs.
ztlctl.plugins.contracts
¶
Typed plugin contribution contracts for public extension points.
CliCommandContribution
dataclass
¶
One plugin-provided CLI command.
McpToolContribution
dataclass
¶
One plugin-provided MCP tool.
McpResourceContribution
dataclass
¶
One plugin-provided MCP resource.
McpPromptContribution
dataclass
¶
One plugin-provided MCP prompt.
WorkflowModuleContribution
dataclass
¶
One plugin-provided workflow export module.
WorkspaceProfileContribution
dataclass
¶
One workspace profile definition exposed by core or plugins.
managed_paths identifies the vault roots a profile scaffolds during init
so ownership and post-init hooks can classify them. It does not imply that
ztlctl will later validate or rewrite those files.
VaultInitContext
dataclass
¶
Normalized context passed to plugin-contributed vault init steps.
VaultInitInstruction
dataclass
¶
One user-facing instruction emitted during vault initialization.
VaultInitStepResult
dataclass
¶
Files, warnings, and user-visible setup guidance from one init step.
VaultInitStepContribution
dataclass
¶
One plugin-contributed step in the ordered vault init pipeline.
SourceFetchRequest
dataclass
¶
Normalized source-provider request.
SourceFetchResult
dataclass
¶
Normalized source-provider response.
SourceProviderContribution
dataclass
¶
One plugin-provided source acquisition provider.
RenderContribution
dataclass
¶
Plugin-provided rendering for a custom note type.
Fields¶
note_type
The note type name this contribution applies to (e.g. "sprint").
rich_formatter
Callable that receives a dict[str, Any] of note data and returns
a Rich-formatted string for terminal display.
mcp_formatter
Callable that receives a dict[str, Any] of note data and returns
a dict[str, Any] suitable for MCP tool responses.
ActionRejection
dataclass
¶
Returned from pre_action to abort action execution.
A plugin's pre_action implementation can return an instance of this
class to prevent the registered action handler from running. The caller
(BaseController._dispatch_pre_action) converts this into an appropriate
error ServiceResult.
PluginMetadata
dataclass
¶
Structured metadata from [tool.ztlctl-plugin] in a plugin's pyproject.toml.
Used for future plugin discoverability and marketplace listing. Plugin
authors include this section in their pyproject.toml to declare
compatibility and capabilities.
Fields¶
name
Plugin display name.
version
Plugin version string (e.g. "1.0.0").
author
Author or organization name.
capabilities
Tuple of capability identifiers the plugin provides
(e.g. ("register_note_types", "register_cli_commands")).
ztlctl_api_version
The PLUGIN_API_VERSION integer this plugin was built against.
description
Optional human-readable description.
API Versioning¶
ztlctl.plugins._version
¶
Plugin API versioning helpers (PLUG-01).
Kept in a private module to allow manager.py to import without creating a circular dependency through plugins/init.py.
PluginLoadError
¶
Bases: Exception
Raised when a plugin declares an incompatible API version.
check_plugin_api_version
¶
check_plugin_api_version(plugin: object, plugin_name: str) -> list[str]
Check a plugin's declared API version against the host.
Returns:
| Type | Description |
|---|---|
list[str]
|
A list of warning strings (may be empty) if the plugin is compatible. |
Raises:
| Type | Description |
|---|---|
PluginLoadError
|
If the plugin requires a newer API version than the host provides, or if its declared version is below the compatibility window. |
Action System¶
ActionDefinition and ActionParam are the frozen dataclasses that describe every registered action.
Plugin authors use these when implementing register_note_types() — PluginManager auto-creates
ActionDefinition instances for each NoteTypeDefinition returned.
ztlctl.actions.definitions
¶
ActionParam and ActionDefinition frozen dataclasses.
ActionParam is a single-source-of-truth parameter descriptor that captures all metadata needed to auto-generate CLI options, MCP tool parameters, and interactive prompts.
ActionDefinition is a frozen descriptor for one operation in the system. All controller methods are registered as ActionDefinitions, enabling auto-generation of CLI and MCP surfaces.
Both dataclasses are frozen for thread safety and hashability.
ActionParam
dataclass
¶
One parameter descriptor — single source of truth for CLI and MCP.
Fields¶
name
Parameter name (e.g. "query", "limit").
type
Python built-in type: str, int, bool, list[str].
required
Whether the parameter is required. Defaults to True.
default
Default value when not required. Defaults to None.
description
Human-readable description for CLI help and MCP docs.
choices
Tuple of valid string choices (used for Click choice type and
MCP enum). None means unrestricted.
cli_multiple
When True, the CLI option accepts multiple values (--tag x --tag y).
cli_is_argument
When True, rendered as a Click positional argument instead of
an option.
cli_flag
When True, rendered as a boolean Click flag (--verbose).
cli_name
Override the Click option/argument name. When None, the CLI
name is derived from name by replacing underscores with hyphens
(e.g. content_type → --content-type). Use this to expose a
friendlier flag name (e.g. cli_name="type" → --type) while
keeping a Python-safe internal name.
mcp_example
Example value shown in MCP tool docs ("find notes about python").
ActionDefinition
dataclass
¶
One operation in the system. Frozen for thread safety and hashability.
All controller methods are registered as ActionDefinitions. The define-once model allows CLI and MCP surfaces to be auto-generated from this single descriptor.
Fields¶
name
Unique dotted name (e.g. "note.search", "note.create").
description
Human-readable description of what this action does.
category
Logical category for grouping (e.g. "query", "create",
"graph").
params
Tuple of :class:ActionParam descriptors in argument order.
handler
Callable that performs the action; returns a ServiceResult.
Typed as Callable[..., Any] to avoid circular imports.
side_effect
"read" for non-mutating operations; "write" for mutating.
MCP-specific metadata¶
mcp_when_to_use Guidance for the agent about when to invoke this action. mcp_avoid_when Guidance for the agent about when not to invoke this action. mcp_common_errors Tuple of common error messages that callers should handle.
CLI-specific metadata¶
cli_group
Click command group name (None means top-level).
cli_examples
Example CLI invocations shown in --help output.
cli_interactive_params
Param names to prompt interactively when --interactive is set.
Presentation¶
custom_presentation Escape hatch for actions with complex output that can't be rendered by the generic presenter.
cli_name
class-attribute
instance-attribute
¶
cli_name: str | None = None
Explicit CLI command name (cli_name) override.
When None, the generator derives the name from action.name by
stripping the cli_group prefix (if present) and replacing
underscores with hyphens.
ztlctl.actions.registry
¶
ActionRegistry and module-level singleton accessor.
ActionRegistry stores ActionDefinitions and enforces name-uniqueness on
registration. The module-level singleton _REGISTRY is the shared
registry for all built-in and plugin-contributed actions.
Use get_action_registry() to access the singleton.
Plugin authors register actions via get_action_registry().register().
ActionRegistry
¶
Registry of all ActionDefinitions (built-in + plugin-contributed).
Thread safety: registrations are expected to happen at module-load time only — no locking is performed.
register
¶
register(action: ActionDefinition) -> None
get
¶
get(name: str) -> ActionDefinition
list_actions
¶
list_actions(*, category: str | None = None, side_effect: Literal['read', 'write'] | None = None, custom_presentation: bool | None = None) -> list[ActionDefinition]
Return a filtered list of registered actions.
All provided filters are combined with AND logic. Omit a parameter to skip that filter.
get_action_registry
¶
get_action_registry() -> ActionRegistry
Return the module-level ActionRegistry singleton.