Macro fields¶
This page documents the snippet, skill, and memory fields available to macros.
Snippet Field¶
Macros can opt-in to sase's TUI snippet expansion by setting the snippet field in
their front matter. When set, the macro's content is converted into a snippet template
and merged into sase's TUI snippet registry at startup, so users can expand it by typing
the trigger word and pressing Tab.
---
name: review
snippet: true
input:
language: word
---
Review this {{ language }} code for correctness and style.
Values:
| Value | Behavior |
|---|---|
true |
Use the macro's base name (part after last /) as trigger |
"custom_name" |
Use the custom string as the trigger word |
Conversion rules:
- Normal macro references in the content are expanded before conversion, so snippets can compose reusable macros
{{ input_name }}placeholders for required inputs become snippet tabstops ($1,$2, etc.){{ input_name }}placeholders for inputs with defaults are pre-filled with the default value- Placeholder mode for
{N}templates is described in Macro migration notes - Macros with complex Jinja2 control flow (
{% %}or{# #}) are skipped - User-defined snippets in
ace.snippetstake precedence over macro-derived snippets on name collision
Snippet templates can reuse other snippets with #[trigger] after the macro snippets
and ace.snippets entries are merged. The referenced snippet's $1, $2, ... tabstops
are spliced into the caller and renumbered in document order:
ace:
snippets:
greet: "Hello $1!$0"
welcome: "#[greet] Welcome to $1.$0"
welcome expands as Hello $1! Welcome to $2.$0. Positional arguments fill the
referenced tabstops before the splice: #[greet(World)] or #[greet:World] expands as
Hello World!.
After the merge, each effective snippet also gains a generated initial-capital alias —
only the first character of the trigger and of the resolved template is uppercased. A
macro-derived foo therefore expands as both foo and Foo, already-capitalized
triggers produce no extra entry, an explicitly authored Foo is never replaced, and
both spellings can be referenced with #[foo] / #[Foo]. The aliases are runtime-only.
See Capitalized aliases for the complete
rule.
Snippets saved from sase's TUI prompt panel become available immediately to all prompt
inputs in that running TUI. With use_chezmoi enabled, this includes a snippet written
only to the chezmoi source tree: sase's TUI keeps a session overlay until the applied
config catches up. The optional confirmed commit/push flow applies chezmoi; saving by
itself does not apply unconfirmed source changes.
Editor clients receive the same templates through sase lsp when they support LSP
snippets. To troubleshoot the raw registry, run:
printf '{"schema_version":1}\n' | sase editor helper-bridge snippet-catalog
See Snippets for snippet usage in the prompt input
widget and editor completion, and Snippets panel
for sase's TUI browse-and-edit panel (gT / Ctrl+G T).
Snippet CLI¶
sase snippet inspects the same composed catalog sase's TUI and the editor helper use.
Bare sase snippet defaults to sase snippet list. -p/--project accepts a display
name, alias, or project key, and output always renders the configured project name.
sase snippet list
sase snippet list todo -f names
sase snippet list Hello --definitions
sase snippet show greet
sase snippet show Greet -f markdown
sase snippet add todo "TODO($1)$0"
sase snippet add todo "TODO($1)$0" -F
sase snippet delete todo -n
sase snippet delete todo -a -f json
Each effective explicit trigger appears once. Generated initial-capital aliases (foo →
Foo) are metadata on that source entry, not extra rows; lookup still maps an alias or
unique prefix back to the explicit trigger. Macro-derived entries are viewable and
linkable, but they are source-edited: converting the generated template back into
macro/Jinja source would be lossy. Add and delete write only ace.snippets
contributions; deleting a read-only, plugin, or macro-derived entry is refused and the
command points at its source. When a config overlay is removed, the command reports the
definition that becomes effective next.
sase snippet add TRIGGER TEMPLATE validates a nonblank alphanumeric/underscore trigger
and a nonblank template, writes the resolved ace.snippet_config_path by default, and
supports -t/--target, -n/--dry-run, and -f/--format rich|json. It refuses an
accidental overwrite or shadow unless -F/--force is given and names the source that
currently wins. Dry runs run the same validation and planning as a real write without
touching the destination, config caches, chezmoi, or git.
sase snippet delete TRIGGER removes the winning writable ace.snippets contribution.
-a/--all removes every writable config-layer contribution. The output includes a
shell-quotable sase snippet add … restore command (with -F when restoring would
shadow again) and any newly revealed lower-priority definition.
sase snippet list [PATTERN] supports -d/--definitions matching and
-f/--format table|names|json. The table shows trigger, origin, calls, backlinks, and a
compact raw-template summary. Names and JSON are color-free and pipe-safe.
sase snippet show TRIGGER supports -f/--format rich|markdown|json and prints the raw
template, composed expansion, source stack, aliases, calls, backlinks, unresolved calls,
and cycle diagnostics.
See CLI Reference.
Source: src/sase/macro/snippet_bridge.py, src/sase/macro/models.py,
src/sase/snippet/
Skill Field¶
A skill is a Markdown source that lives in a canonical skills/ directory and sets a
truthy skill field in its front matter. Both halves are required, and the rule is
two-way: a skill: declaration in an ordinary macros/ directory or a config entry is
rejected with a migration diagnostic, and a file in a skills/ directory that declares
no truthy skill value is rejected the same way. sase skill list shows the loaded
skill catalog without writing files, and reports misplaced sources instead of silently
dropping them.
sase skill init reads that catalog to determine which sources should be rendered into
per-provider SKILL.md files and deployed to agent skill directories; it refuses to
generate anything while any placement violation remains. By default, generated skill
files begin with a sase skill use <name> --reason ... directive so SASE can audit
which skills an agent used; set log_skill_use: false in a skill source to omit that
directive (see below). Recorded skill uses can be summarized and inspected with
sase skill log. The compatibility alias sase init skills runs the same initializer.
---
# sase/skills/sase_git_commit.md
name: sase_git_commit
skill: true
description: Commit changes using sase stitch create for git-based VCS
---
Commit instructions here...
Canonical Skill Sources¶
Skill sources are discovered from these directories, first source wins:
| Scope | Directory | # reference |
|---|---|---|
| Project | <project>/sase/skills/ |
#<project>/skill/<name> |
| Home | ~/sase/skills/ (home/sase/skills/ under chezmoi) |
#skill/<name> |
| Project (home) | ~/sase/skills/<project>/ |
#<project>/skill/<name> |
| Plugin | the plugin's skills/ resource directory |
#skill/<name> |
| Package | src/sase/macros/skills/ |
#skill/<name> |
Ordinary project and home macros, workflows, and shared steps/ stay under
sase/macros/; that tree never holds a skill. Bundled SASE skill Markdown is the
package-source exception and lives in the nested src/sase/macros/skills/ resource.
Source, Reference, and Provider Names¶
One skill source carries three distinct names, and they are not interchangeable:
- The source name is the file stem (or the front matter
name), e.g.sase_plan. - The macro reference name is namespaced with a
skill/segment, so#skill/sase_planexpands the source inline. A project-scoped source is qualified further:#app/skill/foo. - The provider skill name is the bare source name, so the installed agent skill is
invoked as
/sase_planand generated files keep their existing.../skills/sase_plan/SKILL.mdpaths.
This split was a hard cutover: there is no #sase_plan compatibility alias, no fallback
from #foo to #skill/foo, and no read compatibility for the old bundled Markdown
src/sase/skills/ layout. sase doctor, sase validate, sase macro show,
sase skill list, and sase skill init all name the offending source and the exact
move required.
Machine-readable surfaces carry both names: sase macro list, the structured catalog,
and the mobile/editor helper bridges emit name as the # reference alongside
is_skill and a skill_name field holding the / name. sase macro show prints the
reference, a slash row, and a skill · /<name> chip.
Values:
| Value | Behavior |
|---|---|
true |
Deploy to all registered providers |
["claude", "agy"] |
Deploy only to the listed providers |
The description field provides a human-readable summary shown in sase macro list and
sase skill list output. The structured catalog also marks these entries with
is_skill: true; sase's TUI and editor clients use that flag together with skill_name
to offer slash-skill completions such as /sase_plan while keeping ordinary macros out
of slash completion results. # completion inserts #skill/sase_plan, / completion
inserts /sase_plan, and both resolve the same source definition for argument hints,
hover, and definition navigation.
The optional log_skill_use boolean field controls the generated audit directive. It
defaults to true, so generated skills instruct the agent to run
sase skill use <name> --reason ... as their first step. Set log_skill_use: false to
suppress that directive for skills that should not record their own use (the bundled
/sase_plan and /sase_memory_read skills set this). The field only affects sources
that are also marked as skills.
Workflow: Edit packaged skill sources in src/sase/macros/skills/, or add a source
to a project's sase/skills/ or your ~/sase/skills/ directory. Saving a draft that
declares skill: from sase's TUI only offers those canonical directories, and the
ordinary macro and config writers refuse a request that would smuggle a skill definition
into sase/macros/. Do not include the sase skill use directive yourself; the
generator injects it unless log_skill_use: false is set. Then run sase skill list
and sase skill init --dry-run (or --diff) to preview. Commit the source change and
land it on the canonical branch before deploying, then run sase skill init --force: a
chezmoi deploy is refused when src/sase/macros/skills/ is dirty, when HEAD is not an
ancestor of the canonical branch, or when it would move the destination off the source
commit recorded in the provenance manifest — see
Commit Before Deploying. The same manifest is also an
ownership registry for generated source/live skill-file pairs. When a source changes
name, is deleted, or stops targeting a provider, a full sase skill init --force deployment
tombstones the retired pair, commits the source-side removal, deletes the live target
immediately before chezmoi apply --force, and keeps the tombstone so an interrupted
cleanup can be retried idempotently. When use_chezmoi is enabled, sase skill init
commits, pushes, and applies the generated files unless passed --no-commit,
--no-push, or --no-apply; those skip flags also leave retired live targets untouched
for a later full deployment. Do not edit deployed SKILL.md files directly.
sase init skills is a compatibility alias for sase skill init.
Editing an existing skill source from sase's TUI targets it like any other macro
definition, and saving it offers sase skill init in place of a bare commit/push, since
that command already commits, pushes, and deploys for you — see
Editing an Existing Macro from the TUI.
Provider plugins declare where generated skills should be written. A source can target multiple providers, and a provider can have multiple filesystem targets. Built-in targets are:
sase skill list reports retired managed targets as deletion drift, including both the
chezmoi source path and the live home path that the next successful full deployment will
remove.
| Provider | Skill target(s) |
|---|---|
| Claude | ~/.claude/skills/<skill>/SKILL.md |
| Codex | ~/.codex/skills/<skill>/SKILL.md |
| Antigravity (agy) | ~/.gemini/antigravity-cli/skills/<skill>/SKILL.md |
| Qwen | ~/.qwen/skills/<skill>/SKILL.md |
| OpenCode | ~/.config/opencode/skills/<skill>/SKILL.md |
| Muse Code | ~/.config/muse/skills/<skill>/SKILL.md |
| Grok Build | ~/.grok/skills/<skill>/SKILL.md |
Bundled Skills¶
The following skills ship in src/sase/macros/skills/ and are deployed by
sase skill init. They are packaged with sase, included in sase macro list as
skill/<name>, and available to prompt completion clients even when a checkout does not
have local skill files. Coding agents invoke them by their provider names, such as
/sase_plan or /sase_repo; expand one inline as #skill/sase_plan. Other scopes can
add more skill sources, so sase skill list may show entries that are not bundled here:
| Skill | Purpose |
|---|---|
sase_agents_status |
Report on currently running SASE agents |
sase_chats |
Inspect prior SASE agent prompts and responses |
sase_final |
Submit the current turn's SASE finalizer declaration |
sase_gate |
Create a durable custom confirmation gate for a proposed command or decision |
sase_git_commit |
Commit through sase stitch create for git and GitHub workflows |
sase_handoff |
Hand this agent's turn to the next session member with sase pipe |
sase_memory_read |
Perform audited reference memory reads through sase memory read |
sase_memory_write |
Gate every SASE memory-file create, edit, or delete before making it |
sase_monitor |
Run a long command without blocking your turn |
sase_new_task |
Use before creating, filing, proposing, or otherwise recording any new SASE task bead |
sase_notify |
Inspect SASE notifications and notification inbox entries |
sase_patches |
Inspect and reason about Patches, stitches, hooks, comments, and mentors |
sase_plan |
Create and submit an implementation plan when provider-native plan mode is disabled |
sase_project |
Inspect or manage project lifecycle state and aliases |
sase_questions |
Ask the user structured questions when the provider-native question tool is disabled |
sase_repo |
Open and audit linked, sidecar, other-project, or external repositories before accessing them |
sase_run |
Request an agent-initiated launch through LaunchApproval |
sase_sudo |
Request reviewed privileged execution through a typed sudo gate instead of raw sudo |
sase_var |
Attach named output variables to the current SASE agent run |
The sudo request workflow behind sase_sudo is described under
Sudo Requests.
Memory Field¶
Every valid, flat, non-README SASE memory note that declares type: core
or type: reference frontmatter is automatically a macro — no opt-in field is required.
A note's filename remains its identity: sase/memory/sase_beads.md (or the home
equivalent) is invoked as #memory/sase_beads. Nested files such as
sase/memory/assets/** and README.md are never catalog entries. Type-free memory-web
descriptors are not catalog entries either: their bodies are already loaded through the
generated ## Memory Webs instruction section, while strand bodies come from
sase memory read <web>:<keyword> (see Memory Webs).
The memory/ reference segment is reserved. There is no bare #sase_beads alias for
#memory/sase_beads, no #memory/long/sase_beads compatibility form, and an ordinary
macro, workflow, config entry, plugin, or skill that claims the memory/ namespace is
rejected with a load diagnostic rather than silently losing the collision.
Resolution is contextual and first-wins: the selected project's note shadows a same-stem home note, and an explicit registered-project selection reads only that project's workspace rather than merging in another project's notes. Memory trees that coexist in either scope use the memory subsystem's exclusive collision policy. See Memory Order.
Expansion uses the ordinary simple-Markdown-macro rendering path after memory
frontmatter is stripped: a #memory/<stem> reference takes no arguments and does not
synthesize the ## Children section that sase memory read
appends. Macro references already authored in the note body still expand recursively.
#memory/<stem> is a launch-time, explicitly authored inclusion, not an audited
agent-side lookup: catalog discovery, previews, and expansion never append
sase memory read audit events. Use /sase_memory_read (sase memory read) instead
when an already-running agent needs to consult reference memory on its own and have that
access recorded. This is explicit prompt composition only — it does not restore the
retired dynamic-memory runtime, so there is no keyword matching, prompt scanning, or
automatic context injection.
Editing an existing note from sase's TUI targets it like any other macro definition, and
saving it offers sase memory init in place of a bare commit/push, since that command
already regenerates AGENTS.md and the provider instruction shims and commits and
pushes for you — see
Editing an Existing Macro from the TUI.
With use_chezmoi enabled, the write itself redirects to the chezmoi source rather than
the applied copy under ~/sase/memory/; see
Paths That Did Not Move.
Source: src/sase/macro/loader_memory.py, src/sase/content_layout.py.
Related¶
_[project]: A sase project is a named unit of work registered with SASE. _[workspace]: A sase workspace is a numbered clone of a project's primary repo, managed by the workspace store and tracked in that project's registry.json. _[agent]: A sase agent is an agent session or a single agent that does not belong to a session. _[prompt]: A prompt is the text SASE hands to a provider to start an agent turn. _[macro]: A macro is a reusable prompt triggered with #name in agent prompts. _[Patch]: A Patch is SASE's local unit of change. _[bead]: A bead is one tracked work item in SASE's git-native issue tracker. _[plan]: A plan is a persisted, approved artifact recording the intent behind agent work. _[TUI]: The TUI is SASE's terminal interface for running agents and reviewing results. _[epic]: An epic is an executable multi-phase plan run with sase bead work. _[gate]: A sase gate is a durable, command-backed request for one user decision, created when work must pause for the user. _[monitor]: A sase monitor is a monitor turn that runs one long command under a detached supervisor, so the command outlives the agent that started it. *[stitch]: A stitch is the lightweight ordered change record inside a Patch's STITCHES: section.