kind: SavedView
What it is
kind: SavedView declares a workspace-scoped filter + sort preset for
the issue, mission, or run lists. A saved view is the data form of
“my open bugs sorted by newest first” or “team-wide active missions
this sprint” — the structured filter clause + a sort order, given a
human-readable name.
Two visibility modes:
- Per-user (
shared: false, default) — the view shows up only in the creating user’s saved-view list. Useful for personal filters that don’t belong in a shared manifest. - Workspace-shared (
shared: true) — every workspace member sees the view. The common case for manifest-committed views: the whole team should see the “Open P0 bugs” board the same way.
filter_json, sort_json). The manifest exposes them
as nested structured objects so YAML stays readable; the apply
pipeline marshals them into JSON on the way in, and crewship export
unmarshals them on the way out.
YAML schema
Examples
Per-user view: my open bugs
The canonical personal-workspace example. A developer adds this view to their personal manifest (orcrewship apply -f of a one-off file)
so their bug-triage board persists across machines.
Label named bug existing in the same
workspace. The topological apply order
(internal/manifest/apply.go runs Phase 4: Labels before
Phase 16: SavedViews) guarantees the label exists by the time the
saved-view POST body is built.
Shared team view: active P0 missions across the roadmap
A workspace-shared view that the whole team uses. Committing this to the workspace manifest means every onboarded engineer sees it on their dashboard the moment they join — no per-user setup.Projectq2-roadmap(Phase 3)Labelp0andLabelcritical(Phase 4)
Phase 16: SavedViews, so a single
crewship apply --file workspace.yaml carrying all four documents
succeeds in one command.
CLI reference
| Command | Description |
|---|---|
crewship saved-view list | List every saved view visible to the current user (own + shared). |
crewship saved-view delete <view-id> | Delete a saved view (owner-only). Takes the view id, not a slug — saved views have no slug column server-side. |
crewship apply -f saved-view.yaml | Create or update from a manifest |
crewship export workspace | Include saved views in the workspace export |
REST endpoint mapping
| Manifest field | POST body field | DB column |
|---|---|---|
metadata.name | name | name |
spec.shared | shared | shared |
spec.entity_type | entity_type | entity_type (logical — see note below) |
spec.filter (struct) | filter_json (string) | filters_json |
spec.sort (struct) | sort_json (string) | sort_json |
The currentEndpoints:saved_viewsschema uses aview_typecolumn with the values('board','list')— a UI presentation hint. The manifest’sentity_typeis a logical field tracking which record kind the filter operates over; the SPEC-2 wiring step adds the server-side column. Until then, the manifest layer round-tripsentity_typevia the POST body and tolerates a missing field on read.
GET /api/v1/saved-views— list (own + workspace-shared)POST /api/v1/saved-views— createPATCH /api/v1/saved-views/{viewId}— update (owner-only)DELETE /api/v1/saved-views/{viewId}— delete (owner-only)
Validation rules
metadata.slugis required (and must be unique within the manifest).spec.entity_typemust be one of{issue, mission, run}.spec.sort.fieldmust be non-empty.spec.sort.directionmust be one of{asc, desc}.- Every entry in
spec.filter.label_slugsmust resolve viaWorkspaceContext.HasLabel(declared in the same manifest or already present on the server). Unknown slugs surface as a validate-time error that names the missing slug. spec.filter.project_slug, when non-empty, must resolve viaWorkspaceContext.HasProject.
assignee_agent_slug are passed through
unchanged — the server validates them at apply time because the valid
set differs per entity_type and per workspace.
Apply behavior
| Mode | Behavior |
|---|---|
ApplyUpsert (default) | Lookup by name. Create if missing, PATCH if drifted, no-op if identical. Label-order drift in label_slugs does NOT trigger an update — the diff sorts slices before comparing. |
ApplyStrict | Fail with already exists if a row with the same name already exists in the workspace. |
ApplyReplace | Delete the existing row first (if any), then create. Destructive: requires --yes or interactive confirmation. |
crewship apply --dry-run reports per-view planned action without
issuing any mutating call.
Round-trip via export
crewship export workspace runs ExportSavedViews(ctx, client),
which:
GET /api/v1/saved-views(the user’s own + workspace-shared).- For each row, unmarshals
filters_jsonandsort_jsonback into structuredSavedViewFilter/SavedViewSort. - Derives
metadata.slugfrom the row’sname(savedViewSlugify— lowercase ASCII, non-alnum →-, trimmed). Use an explicit slug in the manifest if you need stability acrossnameedits — the server keys onnameregardless. - Emits one
SavedViewDocumentper row in the sameapiVersion: crewship/v1shape the manifest accepts.
See also
kind: Label— referenced viaspec.filter.label_slugs.kind: Project— referenced viaspec.filter.project_slug.kind: TriageRule— sibling read-list automation; triage rules tag issues, saved views surface the tagged subset.- Apply order in SPEC-2 (
.claude/context/specs/SPEC-2-manifest-complete.md) — Phase 16 (SavedViews) depends on Phase 4 (Labels) and Phase 3 (Projects).