Session prompt versions and preflight recovery¶
python bin/studio_prompt.py exposes studio.prompt_operations without an app, Node, Pillow, a database, or installed Python packages. This is a storage/checking command: it does not write creative prompts for you, perform independent creative review, approve a take, or create a cue. Follow the shared creative workflow when authoring and reviewing actual production text.
Commands¶
Run from the repository root against an existing writable workspace production and registered shot. The examples describe an API; they do not authorize a real production change. --workspace <directory> goes before the subcommand, or the normal workspace resolver applies.
python bin/studio_prompt.py show example-film S1
python bin/studio_prompt.py save example-film S1 prompt-input.md --model seedance_2_5 --params params.json --operation-id prompt-save-001
python bin/studio_prompt.py status example-film prompt-save-001
python bin/studio_prompt.py resume example-film prompt-save-001
save requires a UTF-8 input file, model and operation ID. Optional --note records a proposal paragraph; --author is session by default (director, spine, unknown also supported). The byline records the caller's attribution; it is not an authorization mechanism. --ack-no-lint is the existing explicit acknowledgement for a model without a vendored linter. No review, waiver or acknowledgement is inferred. --prepare-only saves the version and leaves its preflight pending without running it. --expected '<JSON revision map>' from show refuses a changed observation.
The save allocates a version above the existing matching prompt family and current selection, retaining the current filename's suffix convention. It never overwrites an existing version or its companions. An orphan companion at the proposed destination refuses instead of being claimed. Prompt bytes preserve line structure, normalize line endings to LF and add a final newline if absent. Params and optional proposal note are written beside the version. The registry selects the new prompt and clears its review reference; older review files remain intact, as do live pointers and unrelated shot fields. Saving identical normalized prompt text refuses rather than splitting one prompt's takes across versions.
show returns the current path/text, version paths and revision map without creating files. Missing current text and corrupt JSON are errors. Writes require an explicit scene-structured workspace production with a workspace registry. They do not silently migrate a repository-only or archive production. Historical app reads keep their compatibility behavior; use the migration/structure workflow deliberately where needed.
Two durable stages¶
First, the prompt, params, note, registry, save record and prompt-saved history event are journaled together. The record at .studio/prompt-saves/<operation-id>.json starts in awaiting_preflight. Next, the existing preflight engine evaluates the saved bytes with write=False; its receipt, saved result and prompt history event are committed together. The worker runs with site packages disabled and an isolated workspace environment, so an app thread cannot redirect another thread's workspace. A valid workspace studio.json is required to resolve the production's doctrine context; failure to resolve or execute is recorded as BLOCKED, never a successful check against a guessed context. Params are supplied by their saved path so the engine binds their bytes.
The result's state: checked means that a preflight result was recorded. Read receipt.status and receipt.blockers: checked does not mean CLEAR. A successful save exits 0 even when its receipt is BLOCKED. CLI input/domain refusals exit 2, revision/recovery/lock conflicts exit 3, and filesystem failures exit 4, with JSON errors on stderr. Successful results are JSON on stdout. The result carries the version/path, operation ID, stored receipt/transcript, previous selection and cue: null.
The operation intentionally does not copy a previous review, acknowledge unreviewed doctrine, or emit a clean review artifact. Continue the shared review workflow after saving. A receipt is evidence of that check, not current authorization to generate; existing spend, phase, identity, lane and review gates still apply. To run a new check after deliberate review/params/context changes, use the existing bin/prompt_preflight.py workflow. resume completes the original save's interrupted check; it is not a receipt-refresh shortcut.
Retry and interruption¶
Retry the identical save ID and inputs to recover known partial writes without allocating a new version. A committed retry returns the original result and never reselects an older version over a later decision. Use a new ID for a new save. Keep IDs and recorded expectations when retrying after a lost response. prepare_only controls whether the caller proceeds to the second stage; it is not a different save identity.
status is read-only. After interruption, resume <production> <operation-id> completes pending preflight without rewriting the prompt. It refuses changed saved text/params, a newly added review/receipt, archive-policy changes or corrupt recovery state. If a newer version has already been selected, the old pending save records a BLOCKED result explaining that it is no longer current; it never selects itself again. Interrupted receipt/history completion rolls forward from its prepared journal without rerunning the check. Engine exceptions produce a durable BLOCKED result with the failure reason; they do not lose the saved text or claim it was reviewed.
Preserve the save records, operation journals and history during handoff. Do not delete them to bypass a conflict. Participating saves coordinate version allocation through the production lock. Other low-level writers and the standalone preflight command are not coordinated by this operation: run deliberate manual changes when no shared save is in progress. Recovery is not simultaneous visibility across files or a network-share guarantee.
Studio accepts optional operation_id, expected and ackNoLint on prompt save, stamps proposal notes as director, and runs the same two stages. Derived index refresh and SSE happen after durable completion; their failure returns a saved-result caveat. The UI's existing connection input is retained for compatibility and creates no cue. Frontend fixture receipts are illustrative; engine acceptance uses the real preflight in disposable workspaces.