Editor Integration¶
SASE exposes two editor-facing surfaces for prompt and macro editing:
sase lspis the interactive editor path. Configure your editor to launch it as a stdio language server when you want completions, snippets, hover, diagnostics, code actions, and jump-to-definition while editing a prompt.sase editor helper-bridge ...is the integration/debugging path. It reads one JSON request from stdin and writes one JSON response to stdout, so clients can fetch the same catalogs without implementing an LSP client.
Language Server¶
sase lsp starts the SASE macro language server over stdio. Run --version or --help
in a terminal to verify the wrapper, then point your editor's LSP configuration at
sase lsp:
sase lsp --version
sase lsp --help
In editor configuration terms, the command is sase and the argument list is ["lsp"].
The wrapper resolves the server command in this order:
SASE_MACRO_LSP_CMD, parsed as a shell-style command for development.- A
sase-macro-lspbinary in the current Python environment'sbin/directory. sase-macro-lsponPATH.- The newer debug or release
sase-macro-lspbinary under a sibling../sase-corecheckout. cargo run --manifest-path ../sase-core/Cargo.toml -p sase_macro_lsp --whencargois available and the sibling checkout has aCargo.toml.
Use SASE_MACRO_LSP_CMD when you need to point the editor wrapper at a different source
checkout or command, including a custom binary that should beat the managed venv copy.
Full editable-install SASE updates reinstall the server into the uv-tool venv when
pulled sase-core commits change. The Justfile uses SASE_CORE_DIR and
SASE_LINKED_REPO_SASE_CORE_DIR (with the legacy SASE_SIBLING_REPO_* variables as
fallbacks) for local sase-core build/install targets, but sase lsp itself does not
read those variables.
The macro LSP binary is built and installed from the local sase-core checkout
(just rust-lsp-install for development/editor validation). It is separate from the
sase-core-rs Python wheel; installing or rebuilding that wheel alone does not install
the language server.
The wrapper also exports installed package macro locations, bundled default config,
plugin macro directories, and plugin config paths to the Rust server. It also
materializes a local artifact-reference catalog under ~/.sase/macro_lsp/ by default.
The server refreshes its macro catalog when the LSP session starts, keeps a short cache
for completion requests, and exposes a sase.macroLsp.refreshCatalog command for
clients that surface LSP commands. Artifact-reference diagnostics and semantic
highlighting re-read their catalog on each request, so a launcher refresh or external
rewrite is visible on the next editor pass; artifact-reference completion reads the same
catalog through a short-lived cache keyed by the catalog file's signature (see
LSP Features).
LSP Features¶
The macro language server is focused on prompt and macro editing:
| Feature | Behavior |
|---|---|
| Macro completion | Completes #name, #!workflow, namespaced references, and slash-skill references from the structured catalog. Skills complete as #skill/<name> after # and as /<name> after a slash. Memory notes complete as #memory/<stem> and never appear in slash completion. |
| Project/Patch tags | Completes +query at the start of the prompt or after whitespace, {, or \| from enabled projects and active Patches. Project rows insert the +<project> tag (or #<workflow>:<name> when the name is not tag-shaped); Patch rows insert #<workflow>:<patch>. Accepting a row also removes the other project tags, and any line-leading # workspace refs, in the same --- segment. Tags also get hover, diagnostics, quick fixes, and a #<workflow>:<name> to +<project> rewrite action. See Project Tags. |
| VCS ref roots | Completes #gh:, #git:, and other registered VCS workflow ref roots from project, Patch, and namespace catalog rows. |
| VCS repositories | Completes repository names after namespace slashes such as #gh:owner/ through the owning workspace provider. |
| Argument assistance | Completes named arguments, path inputs, closed-set enum values (inline, builtin effort, and plugin <dist>@<id>), bool values, and model tokens for typed macro inputs where the catalog exposes input metadata. Enum and bool rows come from the shared Rust candidate builder: they insert the canonical value (quoted when argument syntax requires it), replace the whole current value span, and carry labels, descriptions, and a default badge without preselecting the default. model rows reuse the %model catalog (aliases on @, provider drill-down, effort suffix). Frontmatter type: values — including shortform scalars such as env: word — complete from the advertised input-type catalog. See Typed Inputs. |
| Directive completion | Completes the shared directive matrix: directive names and aliases, fixed values, %model: catalog rows and provider drill-down, parenthesized %model(..., alias=...) keys, and %id / %clan / %wait(...) / %queue(...) / %hold(...) keyword rows and values. Static %if(should_run=...) and %hold assistance is always available, as are %if::, %proc, and type: code assistance. |
| Model shortcuts | Completes =alias and ==model at prompt/line start or after an ASCII space into canonical %m: values, using the same shared Rust filters and edit plans as sase's TUI. = is an LSP trigger character; manual completion also works inside a valid equals token. See Equals model shortcuts. |
| Artifact references | Fuzzy-completes bare @ and @query tokens as canonical artifact kinds, adding local paths on a kind-prefix miss or manual completion request, then completes local payloads after @kind:, including local stitch references. |
| File completion | Completes path-like tokens and recent file-history entries; @-prefixed local paths appear automatically when no artifact kind prefix-matches, or on manual invocation. |
| Snippets | Offers SASE snippets after bare trigger words when the client advertises LSP snippet support. |
| Jinja completion | Inside {{ }} and {% %}, completes variables (declared input: properties first, then template locals, sase run-time names, positional/provider vars, and Jinja globals), filters after \|, tests after is, members after wait./loop., and statement keywords (open-block closers first) inside {% %}. Uses the same Rust engine as the TUI prompt menu. { and \| are LSP trigger characters; outside tags they stay silent so literal braces and alternation pipes never pop a menu. gitcommit documents get no Jinja completion. |
| Hover | Shows macro metadata, descriptions, previews, source display paths, tags, and active input hints. Argument hover uses the shared type label, the input type's source (builtin or plugin <distribution> from a qualified named type), the default, and a value/label/description table capped at 12 rows with an exact remaining count. Agent arguments hover the same way. Memory entries also show kind memory and the current UI's tier label (core/reference), which is the note's memory type. Inside Jinja tags, hover shows the engine's markdown for the variable, member, filter, or test under the cursor, including availability reasons for out-of-scope builtins. |
| Diagnostics | Reports macro/directive issues, macro call arguments that are unknown (unknown_macro_arg), repeated (duplicate_macro_arg), or the wrong type for the declared input (invalid_macro_arg_type), invalid closed-set values as Errors (invalid_macro_arg_choice) with ranked suggestions in diagnostic data, and unroutable model tokens as Warnings (invalid_macro_arg_model) with a preferred "Replace with" fix. See Typed Inputs. Frontmatter carries source-indexed fixes for an unknown type (Change type to ...), deprecated string (Use \line`), and unquoted PyYAML-typed choices/defaults (Quote `yes`). Also reports malformed or unresolved filesystem-backed artifact references outside prompt literal zones, and project-tag issues: a disabled+tag warns with ``+is disabled —sase project enable `` (disabled_project_tag), an anchored unknown tag warns (unknown_project_tag; unanchored unknown tags are plain text), an ambiguous tag errors (ambiguous_project_tag), and a tag with no VCS provider warns (providerless_project_tag`). |
| Quick fixes | Diagnostic-driven quickfix actions consume published diagnostic data: invalid enum arguments get a preferred Replace with `brief` edit that replaces only the value; frontmatter unknown types, string→line, and quote fixes use the same path. Existing refactors, canonical-marker fixes, tag quick fixes, and catalog refresh remain. |
| Semantic highlighting | Highlights macro reference names, directive names, and their argument lists, plus the kind, payload, and supported fragment of known artifact references, glossary phrases, and +<project> project tags, outside prompt literal zones using LSP semantic tokens. See Semantic token legend. |
| Definition | Jumps from macro and slash-skill references to real source files when the catalog provides a resolvable path, including the backing note for #memory/<stem>. |
When a client enables LSP on-type formatting for (, the server shares the prompt
input's argument shorthand edits. Typing ( after an argument-opening : removes that
colon; typing it after :: plus zero or more ASCII spaces inserts () before the
delimiter and leaves the caret inside the pair, for example #review:: body becomes
#review():: body. Typing it after a closed macro argument list adds a comma and moves
the caret before ), including when a :: text tail follows. These are on-type text
edits only; the argument menu comes from the client's next completion request. The edits
preserve authored spacing and suffix text, and the syntax/literal-region exclusions
match the TUI prompt input.
Snippet completions come from the same registry sase's TUI uses: macros with snippet
front matter plus user-defined ace.snippets, with ace.snippets winning on trigger
collisions. The server asks the host helper bridge for that authoritative registry and
falls back to native Rust loading only for simple macro snippets and configured
ace.snippets when the helper is unavailable. In sase's TUI, that shared registry
expands into nested snippet sessions: expanding a trigger while another snippet's
tabstops are live visits the inner tabstops first, then returns to the remaining outer
tabstops. LSP clients receive ordinary editor snippets from the same catalog, so
placeholder navigation in external editors is handled by the editor.
Directive completion uses UTF-16 LSP ranges, so accepting a row replaces the correct
token even after non-BMP characters earlier on the line. %wait: remains positional and
never offers bead= or time=; those keywords are only in parenthesized %wait(...).
capacity=, priority=/p=, and weight=/w= complete on %queue/%q only.
Keyword menus omit duplicate and conflicting entries, and model keyword values omit a
self-reference such as @medium while completing %model(..., medium=...). Static
directive names, aliases, keyword rows, and fixed values still complete if the helper
bridge cannot refresh dynamic catalogs; model, agent, bead, repository, and artifact
inventories degrade independently.
Feature flags¶
The sase lsp wrapper snapshots the launch-related
feature flags when it starts the server and
passes them to the Rust process, so completion matches what a launch from the same
machine would accept. The %queue capacity budget needs no flag: capacity help always
describes this launch's runner-capacity budget, and %q: suggests 1, 100, and
1.5x.
The server reads these values once, so restart the LSP session after changing a flag.
Equals model shortcuts¶
Typing = in an eligible prompt document requests model shortcut completion through the
same Rust contracts sase's TUI uses. A valid equals token sits at prompt offset zero, at
the start of a logical line, or immediately after an ASCII space, with the caret after
the equals marker. Escaped or embedded equals signs, Markdown-style =text= /
==text== marker pairs, paths, inline and fenced code, disabled prompt regions,
frontmatter, Jinja, placeholders, and directive-owned input stay ordinary text. The
*alias and **model forms are compatibility spellings that remain ordinary text.
The =alias menu lists only effective implicit_alias and user_alias rows from the
launcher-materialized model catalog, in canonical catalog order, with case-insensitive
prefix matching. Accepting @large replaces the whole =query token, including any
suffix to the right of a mid-token caret, with %m:@large. The ==model menu lists
concrete model rows only, including provider-qualified matches such as ==codex/g;
accepting gpt-6.1-sol replaces the whole ==query token with %m:gpt-6.1-sol.
At prompt or line end the expansion appends one ASCII space; before a tab it appends none; before an existing ASCII space it consumes and reinserts that first space so later whitespace is preserved and the caret lands after the first space.
A valid shortcut context with no matching rows returns an empty incomplete completion
list instead of falling through to prose, file, or snippet rows. Missing or malformed
catalogs do the same. The list is isIncomplete with filterText set to the typed
equals prefix so clients re-request as the query changes instead of dropping the row
because the source text differs from the inserted %m: value. The catalog is a
launch-time snapshot: restart the LSP after config or plugin changes. Manual editor
completion also works while the caret is in a valid equals token.
ace.prompt_completion.auto_directive_menu remains a setting for the prompt bar in
sase's TUI and does not govern an editor client's trigger policy. The TUI prompt input
uses these same shortcuts; see
Prompt Input and
Equals model shortcuts.
Artifact assistance is local-only. Before a : appears, @ completion withholds local
file rows whenever the query prefix-matches an artifact kind (including bare @), and
returns them automatically when no kind prefix-matches. A manually invoked completion
request includes the file rows explicitly. Completion labels are the reference that gets
inserted, such as @plan: and @src/. Document kinds (including dynamic sidecar
roles), indexed artifact files, Patches, beads, agents, and stitches are enumerated or
resolved from the selected project's local catalog roots and checkout paths. bead and
agent payloads resolve locally from generated sidecar pages, and stitch payloads are
enumerated from local git checkouts, excluding SDD sidecar repositories (plans,
beads, agents, research) since their commits are machine-written bookkeeping
rather than a human's recent work. A sidecar stitch reference still resolves when
written out in full, such as @stitch:plans@<sha> — the exclusion only curates what
completion offers. Historical aliases such as @commit:, @plans:, @chat:, and
@bug: are not offered by completion. The LSP never contacts git hosts, issue trackers,
or other network providers. Unknown @kind: text remains ordinary prose.
This canonical-only rule is specific to the editor LSP. sase's TUI prompt bar currently
also lists recognized aliases and historical kinds, and its repository-history payload
picker remains attached to @commit:; both @commit: and @stitch: resolve through
the same launch resolver.
Matching is fuzzy and ranked on the server for every enumerated kind — document
roles, indexed artifact files, Patches, beads, agents, and stitches — against the
inserted payload, the row's title, and, for scoped rows, the qualified scope@title
target. For example, @stitch:core@fix can match the sase-core repository scope and a
commit subject containing fix in the same query. Likewise, @research:site finds
@research:202607/sase_sites_hub_and_pages/sase_sites_hub_and_pages.md, @agent:blue
finds @agent:team.blue.checker from a mid-name fragment, and @file:panel finds a
default:<hex> indexed file by its file name. Rows are grouped into tiers so a fuzzy
hit never outranks a literal one, then ordered by score, provider rank where a provider
declares one, shorter text, and case-insensitive text:
| Tier | Meaning | Example query against 202607/sase_sites_hub_and_pages/… |
|---|---|---|
| 0 | query is a prefix of the primary text | 202607/ |
| 1 | query is a prefix of the basename segment | sase_sites |
| 2 | query is a contiguous substring | hub_and |
| 3 | query is an ordered subsequence | site, shubp |
An empty query is not ranked at all: each group keeps its provider order (builtin order
for kinds, directories-before-files for paths, and provider order for payloads). Kind
rows and the trailing partial of a local path are matched the same way, but a @ path
token's directory portion stays exact, so @src/ still lists src/ and @src/fcb can
still find src/…/_file_completion_base.py. Stitch SHA text is still part of the lowest
fuzzy tier, so hex-like queries such as add can subsequence-match a SHA; subject and
repository matches outrank those tier-3 rows.
Bounds are disclosed rather than silent. Filesystem-backed enumeration walks up to 5000
payloads per root, so a root larger than that is matched only over the rows the walk
reached. Stitch completion reads at most 200 revisions per repository, gives each
repository two seconds to answer, and merges at most 1000 commit rows across
repositories. Matching then returns at most 200 rows per group to the editor. Whichever
bound bites, the count of payloads left out is appended to every item's detail as
at least N additional payloads not shown, on top of the list's isIncomplete: true.
Because the walk is query-independent, the enumerated and titled inventory is cached
in-process per project and per catalog signature (path, mtime, size) with a two-second
TTL, so a keystroke re-ranks a warm corpus instead of re-walking the filesystem. A
watched catalog write or the sase.macroLsp.refreshCatalog command invalidates it
immediately.
Keeping server-ranked rows alive in the client is an explicit contract. Every
artifact-reference item sets filterText to the reference text as typed
(@research:site in the payload stage, @rsch in the kind stage) rather than to the
inserted reference, because a client that prefix-filters @research:202607/… against
@research:site would discard every fuzzy row. The response is a CompletionList with
isIncomplete: true, which makes clients re-request on each keystroke instead of
re-filtering a stale list and, in Neovim's native completion, disables the client's own
fuzzy re-sort so the server's sortText order survives. Insertion is unaffected: each
item carries the full reference in textEdit.newText.
Editors cannot highlight individual characters inside a completion label, so the "why is
this row here" affordance moves into the preview. labelDetails.description keeps the
group word (artifact kind, file, directory, or a payload kind such as stitch,
patch, research, bead, or agent). labelDetails.detail adds the row's title
when it differs from the label — a document's frontmatter title, an indexed file's
basename, a Patch or bead title, an agent's short name, or a commit subject — and
markdown documentation shows the matched payload with the matched runs wrapped in
**, followed by that title on a second line. Stitch rows also include the bounded
commit body when one is available.
Semantic token legend¶
Most semantic tokens use a standard LSP token type, so editors style them with their
normal semantic-token theme. The exception is project tags, which use the custom
saseProjectTag token type that the server declares in its legend:
| Prompt element | Token type | Modifiers |
|---|---|---|
Macro reference name (#name) |
function |
— |
Directive name (%queue, %if, ...) |
macro |
— |
Argument delimiters and = |
operator |
— |
Argument key (count=) |
parameter |
— |
String argument value, including [[...]] text |
string |
— |
| Numeric argument value | number |
— |
| Boolean argument value | keyword |
— |
| Artifact-reference kind | namespace |
documentation for dynamic document-role references |
| Artifact-reference payload | string |
documentation for dynamic document-role references |
| Artifact-reference fragment | number |
documentation for dynamic document-role references |
| Glossary phrase | type |
— |
Project-tag sigil (+) |
saseProjectTag |
sigil plus the name's modifier below |
Project-tag name (+<project>) |
saseProjectTag |
accent0–accent17, unknown, or disabled |
A resolved tag name carries the accentN modifier for its project, matching the accent
sase's TUI uses. An unknown or ambiguous tag name carries unknown instead, and a
disabled tag — or a resolved tag whose project has no detected provider — carries
disabled alongside a warning diagnostic (see LSP Features). The
server also advertises the catalog's accent palette at
experimental.sase.projectTagPalette in its initialize result, so clients can paint
accentN-modified tags with the same colors as sase's TUI.
Argument spans come from the same sase-core argument parser that colors arguments in
sase's TUI prompt input, so both surfaces agree on roles. Argument tokens that belong to
a key the macro does not declare carry the deprecated modifier; type mismatches and
duplicate keys are reported only through diagnostics. A call that is still being typed
(no closing parenthesis yet) gets structural tokens without validity markers. Multi-line
[[...]] values are tokenized line by line with UTF-16 positions, and an artifact
reference inside an argument value keeps its own kind and payload tokens.
sase-nvim keeps the glossary token's theme color and adds an overridable
SaseGlossaryTerm underline on top through Neovim's LspTokenUpdate hook.
Helper Bridge¶
Editor integrations that do not need live LSP behavior can call fixed helper operations directly:
printf '{"schema_version":1,"project":"sase"}\n' | sase editor helper-bridge macro-catalog
printf '{"schema_version":1,"project":"sase"}\n' | sase editor helper-bridge snippet-catalog
printf '{"schema_version":1}\n' | sase editor helper-bridge agent-catalog
printf '{"schema_version":1}\n' | sase editor helper-bridge finalizer-catalog
printf '{"schema_version":1,"workflow":"gh","namespace":"sase-org"}\n' \
| sase editor helper-bridge vcs-repo-catalog
macro-catalog returns the structured macro catalog used by mobile/editor clients,
including insertion text, reference prefix, kind, tags, typed inputs, display/source
fields, and definition_path when SASE can resolve a real file.
snippet-catalog returns the composed snippet registry:
- Macro-derived snippets from markdown files with
snippetfront matter. - User snippets from
ace.snippetsin merged SASE config. - Valid trigger words only; user snippets override macro snippets on collision.
#[trigger]snippet references resolved after the macro/user merge.- Generated initial-capital aliases (
foo→Foo, uppercasing only the first character of the trigger and template) composed after that merge, so the registry matches sase's TUI. ExplicitFoodefinitions are never overwritten.
agent-catalog requires only {"schema_version":1} and reads across projects. It
returns active and recent ordinary agent rows, de-duplicated by name, with status and
project; monitor rows use kind: monitor. When the same artifact snapshot contains
usable group metadata, the response adds the latest identifiable generation of each
session and clan plus @tribe references derived from stored tribe assignments and clan
declarations. Every row has name, kind, member_count, and display-ready detail;
clan rows also have status, which follows the Agents-tab clan rule (a lone running
member's status, otherwise the aggregate).
Session rows carry a detail of session · N members by default. For the 20 sessions
with the most recent activity — and only those, so the short-lived helper subprocess
stays fast enough for interactive completion — the helper additionally tries to resolve
an associated plan or bead. It checks concrete session members newest-first and uses the
session root only as a compatibility fallback, then enriches the row in three descending
rungs:
- A plan or bead resolved with a title:
detailbecomes<kind> · <structure> · <title>, such asepic · 5 phases · 2 waves · Bead review hardening.kindis the rawtale/epic/plan/phase/tasktoken.structureis theN phases · M wavesfragment, present only when a plan exposes its phase list; bead-derived rows never have it. - A kind resolved but no title (an untitled, missing, or unreadable plan file): a cleaned snippet of the session's launch prompt fills the title slot in that same shape.
- Nothing resolved but a usable prompt snippet exists:
detailbecomessession · N members · <snippet>.
Rungs 1 and 2 also attach Markdown documentation — the plan's goal, its epic phase
list, or a phase/task bead's parent context, closed by a
session · N members · <status> footer. Rung 3 and unenriched sessions have no
documentation. Every session keeps its plain session · N members detail if
resolution fails outright, and group enrichment is additive throughout, so missing plans
or malformed compatibility metadata never hide ordinary agent rows.
finalizer-catalog requires {"schema_version":1} and optionally accepts project.
Unknown request fields are ignored. It returns the effective configured finalizer
instances in policy order (required, remaining defaults, then optional, each group
alphabetically) with value, provider_ref, required/default flags, after,
max_attempts, documentation, and provenance_id. Malformed finalizer configuration
returns status: error with an empty entries list instead of invented rows, and the
builder never loads provider code.
vcs-repo-catalog requires a workflow and namespace, then asks that workflow's
registered workspace provider for repositories. The response reports status,
error_kind, message, provider_display, and whether returned cache data is stale.
Each entry has a short name and a full ref such as sase-org/sase; replace the
current VCS ref with ref rather than appending it after the namespace.
All five helper operations read one JSON object from stdin and write one compact JSON object to stdout. They are fixed catalog operations, not a general shell or filesystem bridge.
Authoring Snippets¶
Use ace.snippets for local trigger-word templates:
ace:
snippets:
fix: "Please fix the following issue:\n$0"
review: "Review this code for correctness, performance, and style.\n$0"
Use macro front matter when a reusable prompt should also appear as a snippet:
---
name: review
snippet: true
input:
path: path
---
Review {{ path }} for correctness, tests, and maintainability.
Required macro inputs become snippet tabstops. Optional inputs are pre-filled from defaults. Macros with complex Jinja control flow are skipped by snippet conversion so the generated editor template stays predictable.
Snippet templates can reuse other snippets by trigger with #[trigger]. Positional
forms such as #[trigger(value)] and #[trigger:value] fill the referenced snippet's
tabstops before the composed template is renumbered.
Snippet templates can also reference the prompt's target project with #{project} (for
example the #{project}-$1 bead). The LSP resolves it from the document's leading
+<project> tag or #gh:/#git: VCS ref, then the SASE current project; when nothing
resolves, the token stays verbatim. Unknown #{name} tokens are never touched.
When the composed registry is used in sase's TUI, Tab moves forward through $1,
$2, ... and $0, while Shift+Tab retreats through visited tabstops. Expanding a
second trigger from inside an active snippet nests it instead of discarding the
remaining outer stops.
Troubleshooting¶
| Symptom | Check |
|---|---|
sase lsp cannot start |
Run sase lsp --version; run a full editable SASE update, build ../sase-core, or set SASE_MACRO_LSP_CMD. |
| Snippets do not appear | Confirm the editor advertises LSP completionItem.snippetSupport; inspect sase editor helper-bridge snippet-catalog. |
| Completion catalog looks stale | Restart the LSP session after changing installed plugin resources; for rewritten artifact catalogs, retry completion or diagnostics. |
%proc rows are missing |
Restart the LSP session so the server reloads the directive contract and catalogs. |
| Jump-to-definition is missing | Check whether the catalog entry has a real definition_path; plugin or built-in virtual entries may only have display paths. |
| A user snippet is ignored | Trigger names must contain only ASCII letters, digits, or _. |
Related Pages¶
- Macro reference for macro syntax, discovery order, typed inputs, snippets, and workflows.
- Integration APIs for the Python helper facade.
- Configuration for CLI flag and environment-variable reference.
- sase's TUI snippets for the in-TUI prompt widget behavior.
sase editor¶
sase editor exposes JSON-over-stdin helper operations for editor integrations. It is
intentionally a fixed-operation bridge rather than a generic shell or filesystem API.
Moved to sase editor.
Moved to Editor Integration.
Command behavior¶
The finalizer-catalog request is {"schema_version":1} with an optional project
hint; unknown fields are ignored. The response is a compact status/message/entries
envelope. Malformed finalizer configuration returns status: error and no rows, and the
builder never loads provider code.
The agent-catalog request is just {"schema_version":1}; it has no project filter and
reads the cross-project agent snapshot. Ordinary rows are de-duplicated by name and
include status and project, with kind: agent for agents and kind: monitor for
monitors. When group metadata is available, additive session, clan, and @tribe rows
include kind, member_count, and display-ready detail; clan rows also include
aggregate status. For the 20 most recently active sessions, SASE tries to enrich
detail with the associated plan or bead's kind, structure, and title, and to add
Markdown documentation carrying the goal, phase list, or parent/task context plus a
session status footer. Unresolved or older sessions keep the plain member-count detail,
and enrichment failure never removes ordinary rows; see
Editor Integration: Helper Bridge for the exact fallback ladder. The
structured macro catalog includes insertion metadata (insertion, reference_prefix,
kind), typed argument metadata, display/source fields, and definition_path when SASE
can resolve a real file to jump to.
The snippet catalog uses the same source ordering as sase's TUI: macros marked with
snippet front matter plus user-defined ace.snippets, with ace.snippets winning on
trigger collisions. It also includes the generated initial-capital aliases (foo →
Foo), so editor completion and the native fallback expose exactly the same
trigger/template pairs as the TUI.
sase lsp¶
Starts the macro language server over stdio for editor integrations.
SASE_MACRO_LSP_CMD can override the server command during development. Without that
override, sase lsp uses the current Python environment's bin/sase-macro-lsp, then
sase-macro-lsp from PATH, then the newer debug/release binary from a sibling
../sase-core checkout, then falls back to cargo run from that sibling checkout when
Cargo is available. Full editable-install SASE updates reinstall the server into the
uv-tool venv when pulled sase-core commits change.
Moved to sase lsp.
_[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.