Plugin System¶
Sase uses Python entry points to discover
optional functionality installed in the same Python environment as sase. Runtime providers use
pluggy hooks; resource plugins expose package data such as xprompt files and
default_config.yml.
The core sase package provides the plugin infrastructure, the built-in LLM providers, and local git/directory
workspace support. Extra packages add hosted VCS workflows, internal workflows, or integrations without changing the
core package.
Plugin Groups¶
Sase defines six entry point groups:
| Entry Point Group | Entry Point Value | Purpose | Example Plugin |
|---|---|---|---|
sase_vcs |
Provider class | VCS provider plugins (git, hg, etc.) | sase-github |
sase_workspace |
Provider class | Workspace provider plugins (ref resolution, submit) | sase-github |
sase_llm |
Provider class | LLM provider plugins | built-in or third-party |
sase_xprompts |
Package module | XPrompt templates and workflows | my_sase_plugin |
sase_config |
Package module | Default configuration (default_config.yml) |
sase-github, my_sase_plugin |
sase_plugin_manifest |
Package module | Plugin metadata resource used by diagnostics | third-party plugin packages |
Provider-class entry points resolve to a class that is instantiated and registered with pluggy. Package-module entry points resolve to a module whose package resources are read by Sase.
Available Plugin Packages¶
| Package | Description | Entry Points |
|---|---|---|
sase (core) |
Bare-git VCS, bare-git and #cd workspaces, and built-in LLM providers |
sase_vcs: bare_git, sase_workspace: bare_git, cd, sase_llm: agy, claude, codex, opencode, qwen |
sase-github |
GitHub VCS and workspace support, including GitHub CLI (gh) PR operations |
sase_vcs: github, sase_workspace: github, sase_config: sase_github, sase_xprompts: sase_github |
sase-telegram |
Telegram integration via chop scripts (sase_chop_tg_outbound, sase_chop_tg_inbound) |
CLI scripts (not pluggy entry points) |
sase-nvim |
Neovim integration, including project spec syntax and prompt helpers | standalone Neovim plugin files (not Python entry points) |
Installation¶
# Core sase (includes BareGitPlugin for plain git repos)
pip install sase
# Add GitHub PR support
pip install sase-github
CLI Diagnostics¶
sase plugin defaults to sase plugin list.
sase plugin
sase plugin list --verbose
sase plugin doctor
sase plugin doctor --json
sase plugin list inventories installed SASE entry points, plugin distributions, configured axe chop scripts, and
available unconfigured chop scripts. sase plugin doctor runs the same inventory plus health checks for resource entry
point load failures, missing configured chops, unconfigured scripts, GitHub CLI/auth prerequisites when GitHub plugins
are installed, and Telegram pass/environment prerequisites when Telegram chop scripts are present. The doctor status
is ERROR for resource entry point load failures or missing configured script chops. Unconfigured available scripts and
optional integration prerequisites report WARN. Use the explicit list or doctor subcommand when passing flags;
sase plugin --verbose and sase plugin --json are not valid forms.
How Plugins Are Discovered¶
Plugin discovery uses importlib.metadata.entry_points() to find installed packages that declare one of Sase's entry
point groups.
There are two discovery paths:
- Provider classes:
sase_vcs,sase_workspace, andsase_llmentry points resolve to classes. The relevant registry loads the class, instantiates it, and registers the instance with a pluggyPluginManager. - Package resources:
sase_xprompts,sase_config, andsase_plugin_manifestentry points resolve to modules. The shared helper insrc/sase/main/plugin_discovery.pysorts config and xprompt entry points by name, loads the modules, and skips module load failures after logging them at debug level.sase plugin doctorloads resource entry points directly so packaging problems are visible as diagnostics instead of only debug logs.
VCS Plugins (pluggy)¶
VCS plugins use pluggy's hook system. The hook specification is defined in VCSHookSpec
(src/sase/vcs_provider/_hookspec.py). Each hook method uses firstresult=True, meaning the first plugin to return a
non-None result wins.
The VCS registry (src/sase/vcs_provider/_registry.py) uses sase_vcs entry points in two ways:
- Detection/classification builds a pluggy manager containing all registered VCS plugins.
- Runtime operations create a
VCSPluginManagerfor the selected provider name, such asbare_git,github, orhg.
Workspace Plugins (pluggy)¶
Workspace plugins use pluggy's hook system, similar to VCS plugins. The hook specification is defined in
WorkspaceHookSpec (src/sase/workspace_provider/_hookspec.py). Most hooks use firstresult=True; the exception is
ws_get_workflow_metadata which collects results from all plugins. All hook method names are prefixed with ws_.
The workspace registry (src/sase/workspace_provider/_registry.py) creates a singleton WorkspacePluginManager,
registers WorkspaceHookSpec, and loads all sase_workspace provider classes from entry points. This is why all
workspace metadata can be listed at once while hook dispatch still lets a single plugin handle each operation.
See docs/workspace.md for the full workspace provider reference.
LLM Plugins (pluggy)¶
LLM provider plugins use pluggy's hook system. The hook specification is defined in LLMHookSpec
(src/sase/llm_provider/_hookspec.py). Core dispatch hooks (llm_invoke, llm_resolve_model_name) use
firstresult=True so the first matching plugin handles a call; metadata hooks (llm_provider_name,
llm_known_model_names, llm_skill_template_context, llm_skill_deploy_subpath, llm_cli_status_color,
llm_autodetect_priority, llm_autodetect_cli_name, llm_default_retry_config) are invoked per-plugin by the registry
so each provider contributes its own metadata. All hook method names are prefixed with llm_.
Core Sase ships Claude, Codex, Antigravity (agy), Qwen, and OpenCode providers as built-in entry points. Additional
providers belong in external plugin packages that declare sase_llm entry points and provide their own metadata hooks.
See docs/llms.md for the full LLM provider reference, including authoring new providers with @hookimpl.
XPrompt Plugins¶
Plugin packages can contribute xprompt templates by declaring a sase_xprompts entry point that points to a module. The
module's package directory is searched for xprompts/*.md files and xprompts/*.yml / xprompts/*.yaml workflow
files. Plugin xprompts are priority 8 in the discovery order (above built-in files and
below config-based xprompts).
Config Plugins¶
Plugin packages can provide default configuration by declaring a sase_config entry point. The referenced module's
package must contain a default_config.yml file. Plugin configs are merged between the bundled package defaults and the
user's sase.yml. See the Deep-Merge System for details on the merge chain.
Disabling Plugins¶
Resource plugins can be disabled via environment variables:
| Variable | Effect |
|---|---|
SASE_DISABLE_PLUGINS |
Disable resource plugin loading for config and xprompts |
SASE_DISABLE_PLUGIN_XPROMPTS |
Disable xprompt/workflow resource plugins only |
SASE_DISABLE_PLUGIN_CONFIG |
Disable plugin default_config.yml resource loading only |
Any non-empty value enables the disable. The VCS, workspace, and LLM provider registries currently load their provider entry points directly and do not consult these resource-plugin disable switches.
Writing a Plugin¶
A sase plugin is a standard Python package that declares entry points in pyproject.toml.
Example: VCS Plugin¶
# pyproject.toml
[project.entry-points."sase_vcs"]
my_vcs = "my_sase_plugin.vcs:MyVCSPlugin"
[project.entry-points."sase_config"]
my_vcs = "my_sase_plugin"
The VCS plugin class implements hooks from VCSHookSpec using the @hookimpl decorator:
from sase.vcs_provider._hookspec import hookimpl
class MyVCSPlugin:
@hookimpl
def vcs_checkout(self, revision: str, cwd: str) -> tuple[bool, str | None] | None:
# Implementation here
...
@hookimpl
def vcs_diff(self, cwd: str) -> tuple[bool, str | None] | None:
# Implementation here
...
Methods should return None (implicitly or explicitly) for operations they don't support, allowing other plugins to
handle them.
Example: Workspace Plugin¶
# pyproject.toml
[project.entry-points."sase_workspace"]
my_workspace = "my_sase_plugin.workspace:MyWorkspacePlugin"
The workspace plugin class implements hooks from WorkspaceHookSpec using the @hookimpl decorator:
from sase.workspace_provider._hookspec import WorkflowMetadata, hookimpl
class MyWorkspacePlugin:
@hookimpl
def ws_get_workflow_metadata(self) -> WorkflowMetadata | None:
return WorkflowMetadata(
workflow_type="my_vcs",
ref_pattern=r"#my_vcs:(\w+)",
display_name="My VCS",
pre_allocated_env_prefix="SASE_MYVCS",
vcs_family="git",
vcs_provider_name="my_vcs",
)
@hookimpl
def ws_detect_workflow_type(self, project_file: str) -> str | None:
# Return workflow type if this plugin handles the project
...
Example: XPrompt Plugin¶
Place xprompt files in your package's xprompts/ directory and register the module:
[project.entry-points."sase_xprompts"]
my_plugin = "my_sase_plugin"
my_sase_plugin/
├── __init__.py
└── xprompts/
├── my_template.md
└── my_workflow.yml
Use .md for prompt templates and .yml / .yaml for workflow definitions.
Example: Config Plugin¶
Place a default_config.yml alongside your module and register it:
[project.entry-points."sase_config"]
my_plugin = "my_sase_plugin"
my_sase_plugin/
├── __init__.py
└── default_config.yml
Plugin configs are merged using the deep-merge system. User config in sase.yml
takes precedence over plugin defaults.
Example: LLM Provider Plugin¶
LLM providers declare a sase_llm provider class:
[project.entry-points."sase_llm"]
my_llm = "my_sase_plugin.llm:MyLLMProvider"
The provider implements hooks from LLMHookSpec using @hookimpl, including llm_invoke() for execution and metadata
hooks such as llm_provider_name(), llm_known_model_names(), and llm_autodetect_priority(). See
docs/llms.md for the full provider contract.