Documentation
¶
Overview ¶
Package workspace models a reel workspace on disk — the resumable unit of the authoring loop (spec 0001 §3.2, contract 0002 §2). A workspace is a directory the owning project commits; keryx is stateless and only requires the internal shape. All operations go through an afero.Fs so they unit-test in memory.
Index ¶
- Constants
- Variables
- func Dir(root, slug string) string
- func Duplicate(fs afero.Fs, root, srcSlug, dstSlug string) error
- func KindIndexed(kind string) (bool, error)
- func Link(fs afero.Fs, root, slug, bundle string) error
- func LoadStoryboard(fs afero.Fs, dir string) (reel.Storyboard, error)
- func New(fs afero.Fs, root string, meta Meta, force bool) (string, error)
- func Relabel(fs afero.Fs, root, slug, label string) error
- func Remove(fs afero.Fs, root, slug string) error
- func Rename(fs afero.Fs, root, oldSlug, newSlug string) error
- func Save(fs afero.Fs, dir string, meta Meta) error
- func Status(fs afero.Fs, dir string) string
- func ValidateSlug(slug string) error
- type Locked
- type Meta
Constants ¶
const ( KindVO = "vo" KindCard = "card" KindMusic = "music" KindCover = "cover" )
Lock kinds — the selected asset kinds that can be reviewed/approved ("locked").
const ( MetaFile = "workspace.yaml" StoryboardFile = "storyboard.json" SocialFile = "social.json" CoverFile = "cover.png" MusicFile = "music.mp3" ReelFile = "reel.mp4" // SourceFile holds pasted source content for the reel — the subject material // when NO article is linked (a linked reel's subject is the article itself, // 0029 §9 note 44). Also seeds `storyboard draft` + the studio chat (R-UI-4). SourceFile = "source.md" // DirectionFile holds the reel's creative direction (0029 §9 note 44): // explicit intent — what the reel should convey, the emotions to invoke — // that grounds AI generation ALONGSIDE the subject (article or source). DirectionFile = "direction.md" VODir = "vo" CardsDir = "cards" )
File / dir names within a workspace (the 0002 §2 contract).
const SchemaVersion = 1
SchemaVersion is recorded in workspace.yaml so an old workspace fails loudly rather than mis-rendering (R-WS-2).
Variables ¶
var ( ErrInvalidSlug = errors.NewSentinel("keyrx.invalid_slug", "invalid slug (want lowercase kebab-case)") ErrExists = errors.NewSentinel("keyrx.exists", "workspace already exists") ErrNotFound = errors.NewSentinel("keyrx.not_found", "workspace not found") )
Sentinel errors.
Functions ¶
func Duplicate ¶
Duplicate copies a workspace's authoring inputs into a new slug but resets the posting status — a copy hasn't been posted, so social.json is not carried (R-WS-17). takes/ and .cache/ are skipped (regenerable).
func KindIndexed ¶ added in v0.4.0
KindIndexed reports whether a lock kind is keyed by a 1-based index (vo/card) rather than being a singleton (music/cover); it also validates the kind, so the command layer can give a clear error before touching state.
func Link ¶
Link records an associated content directory (a page bundle or any dir) on the workspace (R-WS-19).
func LoadStoryboard ¶
Load reads workspace.yaml from dir. LoadStoryboard reads + parses a workspace's storyboard.json — the one canonical loader shared by the gen, build, and make paths.
func New ¶
New scaffolds a workspace at root/<slug>: workspace.yaml, an empty schema-valid storyboard.json, the vo/ + cards/ dirs, and a .gitignore for takes/cache. It refuses to clobber an existing workspace unless force is set (R-WS-5).
func Relabel ¶ added in v0.9.0
Relabel sets a reel's human label (spec 0033) — the id/dir stays stable; only the display name changes. An empty label clears it (the UI falls back to the slug).
func Rename ¶
Rename re-slugs a workspace (directory + meta.Slug). It refuses to clobber an existing destination (R-WS-18).
func Status ¶
Status is a coarse workspace status for `reel list`. The detailed per-platform status (draft → approved → posted) is read from social.json once the posting layer (Phase 2) defines it; until then a workspace with no social.json is a plain "draft" and one with a social set is "social".
func ValidateSlug ¶
ValidateSlug checks a slug is short kebab-case with no path separators.
Types ¶
type Locked ¶ added in v0.4.0
type Locked struct {
VO []int `yaml:"vo,omitempty"`
Cards []int `yaml:"cards,omitempty"`
Music bool `yaml:"music,omitempty"`
Cover bool `yaml:"cover,omitempty"`
}
Locked records which selected assets have been approved and frozen, so tooling treats them as immutable (a re-roll/pick refuses without --force; `reel make` skips them). VO and cards are keyed by 1-based index; music and cover are singletons. Stored in workspace.yaml under `locked` (spec 0025).
func (*Locked) Add ¶ added in v0.4.0
Add locks the asset. For vo/card an index >= 1 is required; music/cover ignore it.
type Meta ¶
type Meta struct {
Slug string `yaml:"slug"`
// Label is the reel's human name in the studio (spec 0033) — a post may have
// several reels, distinguished by label; the id (Slug/dir) stays stable. Additive
// and optional: a reel without a label falls back to its slug in the UI.
Label string `yaml:"label,omitempty"`
Theme string `yaml:"theme,omitempty"`
// Avatars is the reel's cast — the avatar names (from the project registry) this
// reel uses (spec 0034 D4). Scenes tick a subset of it; empty = no cast.
Avatars []string `yaml:"avatars,omitempty"`
// Aspect overrides the reel's frame shape ("W:H", 0029 §9 note 27). Empty =
// the configured default (reel.aspect), itself defaulting to 9:16.
Aspect string `yaml:"aspect,omitempty"`
Bundle string `yaml:"bundle,omitempty"`
SchemaVersion int `yaml:"schema_version"`
// Unreviewed marks a workspace whose storyboard is an unreviewed AI draft
// (R-WS-8).
Unreviewed bool `yaml:"unreviewed,omitempty"`
// Locked records reviewed/approved assets that must not be re-rolled without
// --force (spec 0025). Omitted from workspace.yaml when nothing is locked.
Locked Locked `yaml:"locked,omitempty"`
}
Meta is workspace.yaml.