ProjectSpec Format¶
A ProjectSpec is SASE's project-level .sase file. It groups the non-terminal
Patches for one project and may also store project metadata used by
workspace and agent coordination.
ProjectSpec files live under ~/.sase/projects/<project>/<project>.sase. Terminal
Patches are moved to the adjacent archive file,
~/.sase/projects/<project>/<project>-archive.sase. Legacy .gp files from earlier
releases remain readable as a fallback; the sase patch migrate-extension command
renames them to the canonical .sase extension. That migration changes only the
ProjectSpec filenames; it does not rewrite Patch blocks or alter review state.
Format¶
A ProjectSpec has two parts:
- Optional project metadata before the first
NAME:line. - One or more Patch blocks, separated by two truly empty lines.
The Patch parser finds blocks by scanning for NAME: lines. Project metadata is read by
narrower helpers and must stay before the first Patch. Two-space-indented blank lines
inside DESCRIPTION are body content, not Patch separators.
BARE_REPO_DIR: ~/.sase/repos/my_project.git
WORKSPACE_DIR: ~/projects/git/my_project/
PROJECT_STATE: enabled
PROJECT_NAME: my_project
PROJECT_ALIASES: docs
RUNNING:
#10 | 12345 | run | my_project_add_config_parser_1 | 260509_121314
NAME: my_project_add_config_parser_1
DESCRIPTION:
Add configuration file parser
This PR implements configuration loading and validation.
BUG: http://b/12345
STATUS: WIP
NAME: my_project_add_docs_1
DESCRIPTION:
Document configuration setup
This PR adds user-facing documentation for the configuration file.
PARENT: my_project_add_config_parser_1
STATUS: WIP
BUG Field¶
BUG: is a Patch field, not required project metadata. Put it inside each Patch that
should link to a bug or issue. SASE stores the value as text; common values are a plain
identifier or a URL:
BUG: 12345
BUG: http://b/12345
BUG: https://b/12345
PR workflows that receive SASE_BUG_ID or sase stitch create --bug-id write the Patch
field as http://b/<id>. Child Patches may inherit the parent's BUG: when SASE
creates them through the commit workflow.
Project Metadata Fields¶
Project metadata fields are optional and appear before the first NAME: line. SASE
currently uses these fields:
- BARE_REPO_DIR: Path to the local bare git repository for the built-in
#gitworkflow. - WORKSPACE_DIR: Path to the primary checkout (workspace
#0). Managed numbered checkouts are resolved through the per-project workspace store rather than by appending_<num>to this path; seedocs/workspace.mdfor the directory-layout reference anddocs/configuration.mdfor theworkspace.rootknob. - PROJECT_STATE: Project lifecycle state. User-facing values are
enabledanddisabled;siblingis reserved for internal linked-repository backing records. MissingPROJECT_STATEmeansenabled. Legacyactivenormalizes to enabled, whileinactive,archived, andclosednormalize to disabled. - PROJECT_NAME: Optional user-facing project name. The storage key remains the
directory name
~/.sase/projects/<project>/;PROJECT_NAMEis surfaced in project lists, launch pickers, agent grouping labels, and VCS workspace references. Patchproject:queries (including the+projectshorthand) also use this configured name exactly and case-insensitively, falling back to the directory key only whenPROJECT_NAMEis missing or invalid. - PROJECT_ALIASES: Comma-separated alternate project names accepted in VCS workspace
references and
+<project>tags. Aliases are canonicalized to the directory-key project name before launch state, prompt history, and agent artifacts are written. - RUNNING: Active workspace claims written and released by SASE while agents or
workflows are running. Machine-owned operational leases — the workspaces host work
such as jobs, bead-claim reconciliation, and plan archiving takes to get a writable
checkout — appear here too, with a reserved
lease(<workflow>)label in the workflow column. Those entries are not agent runs and are not shown as agents.
BARE_REPO_DIR and WORKSPACE_DIR are created by first-use #git:<project>
initialization or #git:<bare-repo-path> registration. They are parsed only before the
first Patch.
PROJECT_STATE is managed by sase project. If you edit this field by hand, keep it
before RUNNING: or the first NAME: line and use one of the valid lowercase values.
PROJECT_NAME is written by workspace providers such as sase-github and may be edited
by hand. If you edit it manually, keep it before RUNNING: or the first NAME: line
and use the same syntax as SASE project names.
PROJECT_ALIASES is managed by sase project alias and sase's TUI Projects tab (in the
SASE Admin Center). If you edit it by hand, keep it before RUNNING: or the first
NAME: line and use the same comma-separated form SASE writes.
Project Names and Aliases¶
The directory name remains the canonical storage key. PROJECT_NAME lets a known
project expose a primary user-facing name without renaming its project directory.
PROJECT_ALIASES adds secondary names. For example, PROJECT_NAME: bob in
~/.sase/projects/gh_bbugyi200__bob/gh_bbugyi200__bob.sase makes launch-bound VCS refs
such as #gh:bob, #gh_bob, and #gh(bob) behave like refs to the gh_bbugyi200__bob
directory-key project.
The same names drive project tags: +bob (or +Bob, an alias
such as +bobby, or the directory key +gh_bbugyi200__bob) expands at launch to
#gh:gh_bbugyi200__bob, the provider and directory key SASE already knows for that
project. The tag SASE offers in completion and shows in its TUI is +<PROJECT_NAME> (or
+<directory key> when PROJECT_NAME is unset), so a project only gets one when that
name starts with a letter, uses only letters, digits, _, ., or -, and does not end
in . or -. Every sase project subcommand that takes a project argument also
accepts the tag spelling, so sase project show +bob works like
sase project show bob.
Workspace providers can create display names automatically. The GitHub provider uses
this for first-use owner/repo refs: #gh:foo-org/foo can create a canonical SASE
project such as gh_foo-org__foo with WORKSPACE_DIR set to
~/projects/github/foo-org/foo/ and PROJECT_NAME: foo. If another GitHub repo has the
same basename, such as #gh:bar-org/foo, the provider keeps a distinct canonical
project such as gh_bar-org__foo and allocates the first available display name,
starting with foo_1, then foo_2, and so on.
Existing basename projects are compatibility anchors. If ~/.sase/projects/foo/foo.sase
already points at ~/projects/github/foo-org/foo/, the GitHub provider reuses foo
instead of migrating or renaming it. Existing auto-aliased GitHub projects also keep
their aliases; no automatic migration from PROJECT_ALIASES to PROJECT_NAME is
performed.
PROJECT_NAME and aliases are resolved at the launch/macro boundary before workspace
resolution, macro expansion, prompt history writes, and agent artifact writes. These
friendly refs should not persist in submitted_macros.md, raw_macros.md,
agent_meta.json, prompt history, history sort keys, or VCS refs. Storage paths and
metadata keep using the directory key, while display surfaces prefer PROJECT_NAME when
present. Display-only helpers also humanize filename-safe project stems in some
artifact, retry, and mobile-facing labels when they can map the stem back to a
ProjectSpec display name; the underlying files are not renamed.
Patch project: queries use PROJECT_NAME as their sole project identity when it is
configured; the directory key is not an additional query alias. PROJECT_ALIASES remain
launch/macro aliases and do not participate in this filter. Non-terminal and archived
Patches share the name configured in the main ProjectSpec.
Validation rules:
- Missing
PROJECT_NAMEmeans the user-facing name is the directory-key project name. - Missing
PROJECT_ALIASESmeans the project has no aliases. - Alias values are comma-separated, trimmed, deduplicated, and stored in sorted order.
PROJECT_NAMEand alias names use the same syntax as SASE project names.PROJECT_NAMEallocation tries the requested short name first, then appends_1,_2, and higher suffixes until it finds a value that does not collide.- Project alias mutation validates the exact aliases provided by the caller; it does not allocate alternate spellings automatically.
- An alias cannot equal its directory-key project name or the same project's
PROJECT_NAME. - Names compare case-insensitively:
Fooandfooare the same ref. - A directory key,
PROJECT_NAME, or alias cannot collide with another project's directory key,PROJECT_NAME, or alias across non-system projects in any lifecycle state. home, in any letter case, is reserved for the system-managedhomeproject and cannot be claimed as another project'sPROJECT_NAMEor alias.PROJECT_NAMEallocation skips case variants of taken names, so a newFoobecomesFoo_1whenfooexists.- Invalid or duplicate manually edited names and aliases are reported as parse warnings;
CLI and TUI mutation helpers reject invalid writes. Read paths drop a conflicting ref
rather than failing, and
sase doctorreports every conflict under itsproject.name_collisionscheck, with a suggestedsase project alias removeorPROJECT_NAMErename for each one. A project tag that matches more than one project fails at launch until the collision is fixed.
CLI commands:
sase project alias list [PROJECT] [-j|--json]
sase project alias add PROJECT ALIAS
sase project alias remove PROJECT ALIAS
sase project alias clear PROJECT
Alias mutation uses the normal ProjectSpec lock and can target enabled, disabled, or
sibling records. The system-managed home project cannot be mutated.
sase's TUI exposes aliases in the Projects tab of the SASE Admin Center (press #).
Rows show compact alias information, the detail pane shows the full list, the text
filter matches PROJECT_NAME and aliases, and A opens the alias editor for the
highlighted project. Alias edits replace the selected project's alias set; marked bulk
operations remain lifecycle-only.
Current Project¶
The current project is not a ProjectSpec field and not a lifecycle state. It is the
enabled project SASE treats as working context — in practice, the one you most recently
launched an agent on. Mechanically it is the first entry in the shared VCS macro MRU
store (~/.sase/vcs_macro_mru.json) that maps to an enabled project. A Patch entry in
that store yields its owning project.
Launching an agent on a project — or on a Patch owned by that project — promotes it to
that head. So do sase project set-current <project> and sase's TUI Projects tab c
key, without a launch. The working directory never sets it, and there may be none.
It supplies display and defaults only: sase's TUI top-bar +<project> chip, the
first-open value of project filters, and the top row of the + project-tag completion
menu. It never overrides an explicit project: / +name term, a pick you already made
this session, project lifecycle state, or what a command targets. sase project current
prints the resolved project, or explains that nothing resolves and exits 0. See
sase's TUI: Current project and
ace.current_project.
Project Lifecycle¶
Project lifecycle state controls whether a project appears in the default lists used to
start new work or browse current work. It is project-level metadata; it does not delete
project files. Do not confuse it with Patch status (WIP through Submitted or
Archived), an agent or workspace being active, or the is_sase_managed configuration
marker that authorizes generated project files.
| State | Meaning |
|---|---|
enabled |
Normal work state. Missing PROJECT_STATE also means enabled. |
disabled |
Dormant, historical, or finished project. Hidden from default launch and discovery lists. |
sibling |
Internal linked-repository backing marker. It is not a third user-facing project lifecycle state. |
Legacy PROJECT_STATE: active files normalize to enabled. Legacy inactive,
archived, and closed files normalize to disabled. Normal user workflows should use
sase project enable and sase project disable; sibling is reserved for SASE's
linked-repository bookkeeping.
Broad project discovery is enabled-only. That includes launch and completion pickers,
sase patch search, project-local macro catalogs, broad mobile helper catalogs, and
all-known bead helper reads. Disabled records are intentionally hidden from those
surfaces. An explicitly typed known-project VCS ref such as #gh:sase is the exception:
launch preparation treats it as intent to resume work and writes
PROJECT_STATE: enabled before claiming a workspace. A +<project> tag is not an
exception: a tag naming a disabled project fails launch with a hint to run
sase project enable <project>. A checkout cwd or mobile project value is only
prompt-resolution context, not a workspace ref; without an explicit ref, a bare prompt
defaults to #git:home. Direct workspace claims that bypass launch preparation remain
blocked by the claim guard while the ProjectSpec is disabled.
Agents use /sase_repo for configured linked repositories and for another SASE
project's primary repo. The underlying audited open infers the host project and
workspace from cwd; agent-history views that need old artifacts pass an explicit
all-state scan.
Use sase project list --state all to inspect disabled projects and sibling records,
and sase project show <project> to see state, workspace, launchability, and warnings.
Run sase project enable <project> before a direct workspace claim, or use an explicit
known-project VCS ref when automatic re-enablement is intended. The enable, disable,
and set-state forms update the ProjectSpec under the normal ProjectSpec lock.
Deprecated activate, deactivate, archive, and close aliases remain accepted for
compatibility. Disabling refuses projects with live RUNNING claims or active artifact
markers unless --force is passed. The system-managed home project cannot be mutated
through this command.
sase's TUI exposes the same lifecycle operations through the Projects tab of the SASE
Admin Center (press #). The tab shows enabled and disabled non-system projects
together, with enabled rows first. Its single text filter also matches the literal state
name. The tab supports marks for bulk enable/disable operations and bulk full-directory
deletion, and uses the same blocked-operation checks before disabling a project. It can
also open the selected ProjectSpec in $EDITOR. Its delete action removes the whole
SASE project directory under ~/.sase/projects/ after confirmation, including
ProjectSpecs, project-local config, and artifacts; it does not remove workspace
checkouts. This is broader than Ctrl+D in project launch pickers, which only removes
an empty project's ProjectSpec files.
Common workflows:
- Show the current project:
sase project current - Make a project current without launching:
sase project set-current my-project - Disable a dormant project:
sase project disable old-project - List disabled projects:
sase project list --state disabled - List sibling project records:
sase project list --state sibling - Inspect every lifecycle state as JSON:
sase project list --state all --json - Re-enable from the CLI:
sase project enable old-project - Add a short project alias:
sase project alias add bob-cli bob - Inspect project aliases as JSON:
sase project alias list bob-cli --json - Make a project current from sase's TUI: press
#, switch to the Projects tab (5), highlight the project, then pressc - Re-enable from sase's TUI: press
#, switch to the Projects tab, highlight the project, then pressa - Edit aliases from sase's TUI: press
#, switch to the Projects tab, highlight the project, then pressA - Bulk-disable from sase's TUI: press
#, switch to the Projects tab, mark projects withm, then pressd
Maintenance and agent-history scans intentionally keep reading all project directories.
This keeps live RUNNING claims, stale-claim cleanup, dismissed-agent recovery,
agent-name collision checks, and historical Agents-tab rows visible even after a project
is disabled.
The RUNNING section is managed by SASE. Each entry has this shape:
RUNNING:
#<WORKSPACE_NUM> | <PID> | <WORKFLOW> | <PATCH_NAME> | <TIMESTAMP> | PINNED
The timestamp and PINNED marker are optional. A <WORKFLOW> of the reserved form
lease(<workflow>) marks a machine-owned operational lease rather than an agent run. Do
not edit RUNNING by hand unless you are repairing a stale workspace claim and have
verified the process is gone.
Patch Fields¶
Each Patch in a ProjectSpec follows the Patch format. For hand-written entries, the normal minimum fields are:
- NAME: Unique Patch identifier. SASE-generated names normally start with
<project>_and end with a numeric uniqueness suffix such as_1. - DESCRIPTION: A title, a blank line, and a body, all indented by two spaces.
- STATUS: One of the lifecycle statuses documented in
change_spec.md. New manual work typically starts asWIP.
Common optional fields include:
- PARENT: The
NAMEof a parent Patch that must land first. Omit it when there is no dependency. - PR: URL for the created review, omitted until the PR exists. New files write
PR:; legacyCL:fields remain readable during the compatibility window. - PR_ORIGIN: Tri-state origin for the PR URL.
sasemeans SASE's tracked PR workflow created it,externalmeans it was adopted from the remote, andunknownmarks ambiguous evidence for manual review withsase patch set-origin. - BUG: Bug or issue reference for this Patch.
- REFS: References attached with
sase patch ref; seechange_spec.md. - STITCHES, DELTAS, HOOKS, COMMENTS, MENTORS, and TIMESTAMPS:
See
change_spec.mdfor details.
The external_pr_mirror job may adopt remote PRs that SASE did not create. Adopted
Patches get NAME:, DESCRIPTION:, PR:, PR_ORIGIN:, and STATUS: only. They do
not get fabricated PARENT:, STITCHES:, HOOKS:, TIMESTAMPS:, workspace claims, or
inferred dependencies from the PR base branch.
Example¶
WORKSPACE_DIR: ~/projects/git/my_project/
PROJECT_STATE: enabled
PROJECT_NAME: my_project
PROJECT_ALIASES: docs
NAME: my_project_add_config_parser_1
DESCRIPTION:
Add configuration file parser for user settings
This PR implements a YAML-based configuration parser that reads
user settings from ~/.myapp/config.yaml. The parser includes load
and validation behavior, plus tests for valid YAML, invalid config,
and missing file handling.
BUG: http://b/12345
STATUS: WIP
NAME: my_project_integrate_parser_1
DESCRIPTION:
Integrate config parser into application startup
This PR loads the parser during application initialization and
surfaces validation errors clearly. Tests cover valid and invalid
startup configuration.
PARENT: my_project_add_config_parser_1
STATUS: WIP
NAME: my_project_add_docs_1
DESCRIPTION:
Document configuration setup
This PR explains where the configuration file lives, shows common
examples, and documents the supported keys.
PARENT: my_project_integrate_parser_1
STATUS: WIP
Important Notes¶
- Project file path: Use
~/.sase/projects/<project>/<project>.sasefor non-terminal Patches and~/.sase/projects/<project>/<project>-archive.sasefor terminal history. - Project metadata: Keep
BARE_REPO_DIR,WORKSPACE_DIR,PROJECT_STATE,PROJECT_NAME,PROJECT_ALIASES, andRUNNINGbefore the firstNAME:line. - Blank lines between Patches: Separate Patches with exactly two truly empty lines.
Two-space-indented blank lines inside
DESCRIPTIONremain body content. - NAME field: Prefer SASE-generated names, which use the project prefix and a numeric suffix.
- PARENT field: Set it only to another Patch
NAME; omit it when there is no dependency. - PR field: Omit until the PR exists, then set it to the review URL.
- No file modification lists: Keep file lists out of
DESCRIPTION; SASE records file-level deltas separately.