Artifact References¶
Artifact references are typed @<kind>:<argument> citations in launch prompts. They are
not macros: SASE resolves them late in prompt preprocessing, after macro expansion and
command substitution, using the project context for that prompt segment. Each successful
reference expands to prompt text, records a per-agent use row, and can publish as a
numbered Markdown reference link.
Prompt references record consumed artifacts; Artifact Links record relationships. For a follow-up workflow, see Hand a result to another agent.
Prompt Grammar¶
Use the unquoted form when the argument contains no spaces:
@plan:202608/artifact_ref_contract.md
@bead:sase-<id>
@stitch:sase@f499469
Use quotes when the argument contains spaces:
@patch:"artifact references adoption"
@file:"~/bob/Research Inbox.md"
Fragments such as #L10-L20, #page=2, and #t=30 stay attached to the reference when
the target kind supports them. Inline code, fenced code, and disabled macro regions stay
literal. Unknown @kind: text remains prose; malformed or missing references for a
known kind stop launch with a diagnostic.
Live Kinds¶
Canonical live categories are:
| Form | Meaning |
|---|---|
@stitch:<sha> |
Commit in the prompt segment's project repository |
@stitch:<repo>@<sha> |
Commit in a named primary, linked, or sidecar repo |
@patch:<name> |
Patch in the prompt segment's project |
@bead:<id> |
Bead by full id or unambiguous shorthand |
@agent:<name> |
Published agent page and related transcript context |
@goal:<id> |
Goal in the prompt segment's project (a citation that never binds) |
@goal:<project>@<id> |
Goal in a named project |
@file:<path> |
Allow-listed local file captured by content digest |
@file:<source>:<digest> |
Indexed file, where source is explicit or default |
@<document-kind>:<repo-path> |
Document in a configured artifact sidecar, such as plan or research |
The built-in plans sidecar exposes @plan:<path> through ref: {use: builtin@plan}.
The sase-research-artifacts plugin exposes @research:<path> for the research content
sidecar. Other artifact sidecars can add their own document kind with an inline ref:
spec or with ref.use: <plugin>@<provider> from an installed provider plugin.
Compatibility readers preserve older persisted references. @commit: canonicalizes to
@stitch: permanently. @plans: and the bare plans: machine-field spelling used by
SDD plan references are both read-only compatibility spellings of plan — kept because
commit trailers and bead event streams that already carry them are immutable — and
neither is ever emitted again; new references always render as @plan: in prose and
plan: in machine fields. Historical @chat: and @bug: references remain archive
readers and are not offered for new authoring. The retired #ref/<kind>:<argument>
macro renderer syntax is not accepted.
Project Context¶
Short references resolve from the prompt segment, not from the current working
directory. A segment's leading +<project>
project tag, #git:, #gh:, or other VCS
workflow tag supplies the project context. If a segment has no explicit tag, the
caller's launch identity supplies it.
Context affects ambiguity:
@stitch:<sha>searches the selected project's primary repo; qualify with@stitch:<repo>@<sha>when needed.@patch:<name>searches the selected project's active Patch store, then its archive.- A short
@bead:<suffix>searches the selected project first, then rejects cross-project collisions instead of guessing. @agent:<local-name>canonicalizes to the durable global agent identity.@goal:<id>cites the segment project's goal ledger; qualify with@goal:<project>@<id>when needed. A citation never binds (binding is a later epic's%goal); citing a settled goal is allowed.
On-demand document sidecars¶
During final preprocessing of each agent prompt at launch, a well-formed reference for a
path-bound document kind (see Expansion) in a workspace-backed prompt
segment can materialize its configured sidecar when that role has a recorded remote but
no local clone. For example, the first live citation of an explicitly path-bound custom
kind can clone its sidecar, refresh that segment's project context, and then resolve the
document. SASE prints the role it is materializing. A clone failure stops launch with
the remote's error and an explicit sase repo path <role> --ensure retry command.
Pointer document kinds, including @plan:... and @research:..., never trigger this:
their expansion does not depend on a local checkout, so citing one never clones its
sidecar.
This write is launch-only. Validation, macro display and expansion previews, editor
catalogs, and other discovery paths remain read-only and never clone a missing sidecar.
Materialize the role explicitly when one of those surfaces needs a local inventory —
sase repo path <role> --ensure is the CLI form, and typing @<kind>:: in sase's TUI
prompt (empty payload, immediately after the kind's colon) is the in-prompt equivalent:
it syncs or first-clones that kind's sidecar, rebuilds the completion catalog, and
reopens the payload menu with the newly-arrived rows badged. Pointer kinds such as
@plan: and @research: never auto-materialize at launch (see above), but they are
reachable this way — @research:: clones the sidecar on first use. See
sase's TUI for the full gesture and its status row. References inside
inline code, fenced code, or disabled macro regions stay literal and do not trigger
materialization.
Allow-Listed Files¶
Path-backed @file: references are opt-in. Configure roots in sase.yml:
artifact_refs:
file:
roots:
- name: bob
path: ~/bob
path_globs: ["**/*.md"]
The root name becomes the portable logical identity in published metadata. path must
be absolute or ~/ rooted. path_globs are root-relative POSIX globs with !
exclusions. SASE accepts regular files that stay under exactly one effective root, pass
the glob policy, and fit the configured capture size limit.
At launch, SASE reads the bytes once, hashes them with SHA-256, stores the captured
object, and expands the prompt to the <captured-path> file. Later source edits do not
change what the agent received.
Provider Specs¶
Document artifact providers are declarative. A project can start from an installed provider:
repos:
sidecar:
custom:
research:
ref:
use: sase-research-artifacts@research
or define the same policy inline:
repos:
sidecar:
custom:
design:
ref:
kind: design
icon: ◆
expansion_format:
"the {repo_relative_path} file in the {sidecar_role} sidecar repo"
properties: {}
detail: {}
identity: {}
inventory:
globs: ["**/*.md", "!drafts/**"]
publication:
link: vcs_permalink
referenced_by: markdown_table
use and inline fields normalize to the same spec. An assembled reference provider spec
must include ref.icon, the Artifacts tab mark; installed providers supply it, and
inline specs declare it directly. Scalar values replace, mappings deep-merge, and lists
replace. Missing providers fail soft during launch and surface as
sase doctor -C config.repos findings. A linked repo or cloned sidecar is not an
installed Python distribution; the provider package must be installed so its entry
points are visible.
A sidecar's reference kind is independent of its role name. ref.kind (or the kind
inherited through ref.use) is the @<kind>: prefix agents author; the sidecar role is
storage identity only — the repo checkout path, sase repo open <role>, and similar
plumbing. The builtin roles ship with kinds that differ from their role names on
purpose: role plans writes kind plan, role beads writes kind bead, and role
agents writes kind agent. Any sidecar, builtin or custom, can set its own ref.kind
independently of its role.
Expansion¶
A document reference expands through its provider spec's expansion_format, a template
drawn from a subset of the shared placeholder vocabulary:
| Placeholder | Value |
|---|---|
kind |
The reference's kind, such as research. |
argument |
The authored argument, fragment stripped. |
canonical_argument |
The canonical <kind>:<argument> reference text. |
repo_relative_path |
The sidecar-relative POSIX path; identical to argument. |
display_label |
The argument's filename. |
sidecar_role |
The sidecar role backing this document kind. |
checkout_path |
The resolved absolute path in a local checkout. |
A format that uses checkout_path is path-bound: expansion resolves the reference
to a local file, materializing a missing auto_clone sidecar when needed, and fails the
launch with a diagnostic when the document cannot be found there. Path-bound expansion
is an opt-in compatibility capability for an explicit custom provider. Those providers
should render prose such as the {checkout_path} file, not an @-prefixed filesystem
path.
A format that uses no path placeholder is a pointer: expansion renders straight from
the reference itself, with no resolution dependency. A pointer reference never clones
its sidecar and never fails a launch — an unresolvable pointer still expands, using
whatever prose the format declares. @plan:, @research:, and every unconfigured
document sidecar use the default pointer format
"the {repo_relative_path} file in the {sidecar_role} sidecar repo", so
@plan:202608/foobar.md expands to "the 202608/foobar.md file in the plans sidecar
repo" whether or not the plans sidecar is cloned.
Built-in non-document kinds follow the same portable-prose rule. @file: becomes
the <captured-or-materialized-path> file; @bead:<id> becomes
the <canonical-id> bead in the <project> project; @agent:<name> becomes
the <canonical-name> agent in the <project> project; @stitch: / @commit: become
the <full-sha> stitch in the <repository> repo; @patch:<name> becomes
the <name> Patch in the <project> project; @goal:<id> becomes the one-line goal
citation (goal ⌖<id> "<title>" in the <project> project (<status>) with outcome and
criteria). Historical @chat: becomes the <resolved-path> file, and historical
@bug: becomes issue #<number> in the <project> project (<resolved-url>). Authored
citations remain @<kind>:<argument>; none of these expansions inject an @ sigil in
front of a filesystem path. Fragments such as (lines 10-20) are appended after that
pointer.
Publication¶
Published prompts rewrite live references as stable Markdown reference links:
Read [@research:202608/report.md][1] and [@file:~/bob/gtd.md][2].
[1]: https://github.com/sase-org/sase--research/blob/<revision>/202608/report.md
[2]: ../../../files/objects/sha256/ab/<sha256>
Clean repository-backed documents link to the captured revision. Dirty or untracked documents and local files link to the captured object. Tracking does not depend on linkability: an unlinkable reference still records a use row and remains visible in the published prompt metadata. A pointer document reference that never resolved to a local file — no clone of its sidecar was ever made — publishes the same way: unlinked, but with its use row intact.
Artifact repos that opt into referenced_by: markdown_table get a managed
Referenced By section at the bottom of cited Markdown documents. That section is a
projection of recorded use rows, not part of the document's semantic content version.
Each row names the publishing agent, project, canonical reference, publication date, and
use count; the agent name links to its published page when SASE can build that URL.
Repeated publication of the same agent revision and document is idempotent, while
multiple citations of the document in that prompt increase the row's use count.
The write-back workflow runs in this order:
- SASE finishes prompt-archive publication in the agents sidecar, including its push when the sidecar has changes or is ahead of its remote.
- It queues one durable request per cited provider document, then synchronously tries to drain the project's queue before the publishing command returns.
- The drain groups requests by sidecar role, pulls each artifact repository with
rebase, updates only the managed Markdown block and its tracked
links/index (links/<artifact-relpath>.json, original extension preserved), and prepares any changed document and index files. The sidecar is the provider, so the index path does not repeat areferenced-by/<provider>/prefix, and the JSON is committed with the projection rather than written under.sase/. - When the refresh changes files, SASE creates a local
Update artifact link projectionscommit and starts a detached push. The first refresh in a sidecar also installs the rooted/links/**/*.lockignore rule in that same commit so lock sentinels never become a later lock-only cleanup. A successful refresh, including an idempotent no-op, acknowledges the request without waiting for that push to finish.
A failure before a successful local artifact-sidecar refresh leaves the request queued
for a later mutating sase agent sync. The same --retry-quarantined and
--drop-retired controls used for agent publication also operate on queued Referenced
By requests; --retry-retired revives retired agent-publication requests only. See
Agent Hood Synchronization. Once the local
refresh succeeds, SASE removes the request from that outbox. A later detached-push
failure is recorded in the managed SDD sync log and is not retried from the Referenced
By outbox.
The write-back attempt can delay the publishing command's return, but it begins only
after the prompt archive has been pushed and cannot roll that publication back. Because
the managed block is stripped when SASE hashes a clean Markdown input, adding a
back-reference does not make the original citation appear to have changed. These commits
use the non-user file-hook cause artifact_links, so ordinary file hooks ignore the
managed write unless they explicitly opt in with filters.causes.
Deliberate relationships render separately as a top Links table, while
prompt-reference and read rows use the unified link graph behind the same Referenced By
projection. See Artifact Links for the relation registry and CLI.
Related¶
- Artifact links — typed relationships between records.
- Prompt history — replaying prompts that cited artifacts.
- Hand a result to another agent — follow-up workflow.
sase file¶
With no subcommand, sase file defaults to sase file list.
Moved to sase file.
sase file-history¶
With no subcommand, sase file-history defaults to sase file-history list.
Moved to sase file-history.
sase artifact¶
sase artifact creates, discovers, inspects, resolves, opens, and repairs indexed
artifacts. Bare sase artifact delegates to sase artifact list, and
sase artifact-file remains a compatibility alias for the whole group.
sase artifact create is intended for code agents running with SASE_AGENT=1 and
SASE_ARTIFACTS_DIR set. It copies a generated file into persistent SASE artifact
storage and associates it with the current agent so the Agents tab can open it with A,
even after the agent has been dismissed and revived. -k/--kind accepts chat, plan,
image, markdown, pdf, or file and defaults to a kind inferred from the file
extension. -m/--move opts into removing the source after it is stored, -l/--label
sets the display label (default: the source file name), and -b/--bead [ID] attaches
the new file: reference to a bead (a bare -b uses the agent's SASE_BEAD_ID bead).
On success the command prints the artifact's id:, absolute source:, stored path:,
durable ref: (file:<id>), and var: artifacts[<index>] (bead: follows with
--bead). It also records the artifact in the agent's SASE-managed artifacts output
variable. Only create is agent-gated; every other artifact subcommand works outside an
agent run.
Moved to sase artifact.
Moved to Artifact References.
Command behavior¶
list filters: -k/--kind is repeatable and accepts the artifact kinds above;
-l/--limit defaults to 50 and 0 means unlimited; -p/--project accepts a display
name, alias, or canonical key and exits 2 for an unknown project; -q/--query is a
case-insensitive substring match over label and paths; -s/--since accepts the same
DATE forms as sase plan search (YYYY-MM-DD, YYYY-MM, YYYYMM, or relative 14d /
3w / 2m); and -u/--unused shows only artifact files with no recorded file:<id>
consumption. Pretty output is a Rich panel with KIND, REF, LABEL, PROJECT (display
name), AGENT, SIZE, and CREATED columns; -j/--json emits every record field —
including sha256, size_bytes, and mime_type — plus the rendered ref.
show, path, and open accept canonical artifact references (file:, stitch:,
patch:, bead:, agent:, and document kinds such as plan:, research:, or
designs:). Historical commit:, chat:, bug:, and plans: aliases remain readable
for compatibility. Document kinds and file: preserve supported #L, #page=, and
#t= fragments; bead: and agent: reject fragments because they resolve to
regenerated pages whose anchors can drift. bead: resolves to the generated bead page
in the current project's beads sidecar, and agent: resolves to the generated
agents/<global-name>/README.md page in the current project's agents sidecar, so path
and open work for both after sase bead pages refresh or sase agent sync has
published the page. Bead and agent resolution is intentionally scoped to the reference
context's single project; foreign bead prefixes report unknown_project instead of
scanning every enabled project.
A bare default:<hash> or explicit:<hash> index id is accepted as sugar for
file:<id>. path exits 0 on success, 1 when the reference is malformed, missing, or
ambiguous (status and candidates go to stderr), and 2 for kinds with no filesystem
identity (stitch:, patch:, and historical commit: / bug:), pointing at show
instead. open treats historical commit: as non-viewable, opens historical bug: in
a browser, and currently opens a canonical stitch: at its resolved checkout; patch:
has no viewer path. show also reports consumption from the append-only
~/.sase/artifacts/consumption.jsonl ledger: consumption_count, consumed_by_agents,
consuming_agents, and last_consumed_at in pretty output, plus an additive
consumption object in -j/--json output. doctor exits 1 when it finds missing
enrichment fields, missing stored files, duplicate ids, unsupported schema versions,
malformed rows, digest mismatches, or an unhealthy artifact-link graph. Its link report
includes dangling refs, stale projections, durable-versus-aggregate counts, read-outbox
counts, derived coverage, and relation/origin totals; see
Artifact Links.
stats, prune, reclaim, and opt-in automatic retention use one shared protection
collector. It unions IDs found in persistent ProjectSpec and SDD text with canonical
fragment-free file: IDs recorded in the consumption ledger, then passes the
deduplicated set to the applicable planner. Stats keeps referenced, consumed, overlap,
and total protection counts distinct. Prune and reclaim are dry runs unless --apply is
passed and never select explicit or protected rows; automatic retention enforces the
same union after agent finalization when artifacts.retention.enabled is true. A
missing consumption ledger contributes no IDs; a present ledger that cannot be queried
appears in protection-source evidence and blocks destructive apply or skips automatic
enforcement.
Every removal prune, reclaim, and automatic retention perform routes through the
restorable trash under ~/.sase/artifacts/trash/: one directory per entry holding
entry.json (the complete original index row plus trashed_at, reason, and
size_bytes) and, for a byte-backed row, the moved payload file. Nothing else
hard-deletes. trash restore puts the payload back and re-inserts the index row; only
trash purge deletes permanently, and without -a/--all it deletes only entries older
than artifacts.retention.trash_grace_days. Because trashed bytes still occupy disk,
du does not drop until a purge runs; both apply summaries print the trash root, and
reclaim --apply says so outright. See
Store Lifecycle for the end-to-end workflow.
_[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.