Metadata-Version: 2.4
Name: free-studio-flow
Version: 0.1.0rc4
Summary: AI-native film factory and Studio flows on top of ProDocuX contracts
Author: FSF Team
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/freestudioflow/free-studio-flow
Project-URL: Repository, https://github.com/freestudioflow/free-studio-flow
Project-URL: Issues, https://github.com/freestudioflow/free-studio-flow/issues
Project-URL: Releases, https://github.com/freestudioflow/free-studio-flow/releases
Keywords: film,studio,prodocux,kaggle,video
Classifier: Development Status :: 3 - Alpha
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: prodocux==0.3.0rc7
Requires-Dist: pdx-artifact-engine==0.3.0a8
Requires-Dist: pdx-adapter-media==0.2.0a3
Requires-Dist: python-docx==1.1.2
Requires-Dist: kaggle>=1.6.17
Requires-Dist: static-ffmpeg>=2.7
Provides-Extra: dev
Requires-Dist: pytest==8.3.4; extra == "dev"
Requires-Dist: static-ffmpeg>=2.7; extra == "dev"
Provides-Extra: media
Requires-Dist: static-ffmpeg>=2.7; extra == "media"
Dynamic: license-file

# free-studio-flow

AI-native film factory and Studio flows on [ProDocuX](https://github.com/prodocux/prodocux) contracts.

License: Apache-2.0. See [LICENSE](LICENSE).

<!-- pypi-release-status:start -->
Source version in this branch: **`0.1.0rc4`**.

> ⚠️ rc4 is not yet published to PyPI. Latest verified PyPI release remains rc3 (see below).

Latest verified PyPI release: **[`0.1.0rc3`](https://pypi.org/project/free-studio-flow/0.1.0rc3/)**,
published from tag **[`v0.1.0rc3`](https://github.com/freestudioflow/free-studio-flow/releases/tag/v0.1.0rc3)**
at commit `62e5abda89cbde43754c656d6c6fee35982dbb64`.

```powershell
python -m pip install "free-studio-flow==0.1.0rc3"
```

*(rc4 will be installable once the tag `v0.1.0rc4` is published and the release workflow completes.)*
<!-- pypi-release-status:end -->

Repository: [github.com/freestudioflow/free-studio-flow](https://github.com/freestudioflow/free-studio-flow). This tree is the FSF product. Machine-readable PDX freeze and pin records live under `compatibility/`. It does **not** ship the B-roll generator; that remains [b-roll-library-generator](https://github.com/prodocux/b-roll-library-generator).

Runtime pins: `prodocux==0.3.0rc7`, `pdx-artifact-engine==0.3.0a8`, `pdx-adapter-media==0.2.0a3`.

## What this checkout contains

- **FSF-M1–M4 Spine**: Word intake, execution plan compiler, authoritative resume invalidation, media conformance verification, and multi-executor abstraction
- **Plan Execution Runtime (`fsf execute`)**: Topological DAG execution engine for `pdx_execution_plan_v1` plans, orchestrating tool steps, transform steps, and fail-closed QC conformance checks
- **Fast Assembly**: Multi-shot video concatenation with external background music (BGM) mixing, embedded voice audio track mixing (`amix`), and subtitle policies (none, sidecar, burned)
- **Process Command Executor (`process_cmd`)**: Process adapter executing local CLI and script commands with isolated temporary output files, secret sanitization and atomic publication
- **Agent Handoff** *(rc4)*: Delegate generation to external agents through validated workorders and results, with retry and resume support.
- **Windows Subprocess Cleanup** *(rc4)*: Clean up descendant processes on timeout or cancellation, including when `taskkill` fails.
- **Audio Policies** *(rc4)*: Preserve explicit source audio contracts while controlling assembly audio with `--audio keep|strip|require`.
- **FSF-S Skills**: Fourteen Studio skills as CLI/skill (kaggle / api / local transports). No Studio desk in this release
- **Live Gate**: Kaggle API ping + private job envelope + published PyPI pins + local transport shape. Live local-model ping is skipped when this machine has no useful Comfy/GPU. GPU kernel submit is opt-in (`FSF_KAGGLE_SUBMIT=1`) and off by default. Extra API/local/process backends: `fsf-executors.example.json`

## Install

Python 3.11+.

```text
python -m venv .venv
.venv/Scripts/python -m pip install -U pip
.venv/Scripts/python -m pip install -e ".[dev]"
.venv/Scripts/python -m fsf.cli check
```

Unix: `.venv/bin/python` instead of `.venv/Scripts/python`. Do not activate the venv and then use a bare `python` or `fsf` from PATH.

## Verify

Run the contributor verification suite from the checkout:

```text
.venv/Scripts/python scripts/agent_verify.py
```

That runs public hygiene, offline pytest, then live Kaggle/API pytest, then `.venv/Scripts/python -m fsf.cli live-check`.  
Kaggle credentials: `KAGGLE_CONFIG_DIR` or `~/.kaggle/kaggle.json`. The key is never printed. Missing credentials **fail** the live gate; do not skip.

`.venv/Scripts/python -m fsf.cli run` defaults to **`mock.studio.video`** (writes `.mock.bin`, not media). `flow run` requires `--transport` and `--shape` and refuses mock executors. Built-in kaggle/api/local shape adapters write `.shape.bin`; configured process adapters used by `fsf execute` can produce real media. `verify` on those files is expected to fail.

Vendor API / extra backends: put tokens in process environment variables only (`FSF_VENDOR_API_KEY`, or the `key_env` name in `fsf-executors.json`). Do not put secrets in JSON, git, or `AGENTS.local.md`. FSF does not load `.env`. See [`docs/FSF_LIVE_VERIFY.md`](docs/FSF_LIVE_VERIFY.md).

## CLI

Windows paths below; Unix: `.venv/bin/python`.

```text
.venv/Scripts/python -m fsf.cli check
.venv/Scripts/python -m fsf.cli flows
.venv/Scripts/python -m fsf.cli intake path/to/sheet.docx --out output/job
.venv/Scripts/python -m fsf.cli plan path/to/sheet.docx --pipeline p0
.venv/Scripts/python -m fsf.cli plan path/to/sheet.docx --pipeline custom --skills storyboard,generate,dub
.venv/Scripts/python -m fsf.cli plan path/to/sheet.docx --pipeline p1 --media --assembly --bgm path/to/bgm.wav --out output/plan.json
.venv/Scripts/python -m fsf.cli execute output/plan.json --out output/execute
.venv/Scripts/python -m fsf.cli flow run studio.video.generate path/to/sheet.docx --transport kaggle --shape
.venv/Scripts/python -m fsf.cli run path/to/sheet.docx --executor mock.studio.video
.venv/Scripts/python -m fsf.cli verify path/to/clip.mp4
.venv/Scripts/python -m fsf.cli live-check
```

- `plan`: Compiles the execution plan (`pdx_execution_plan_v1`). Supports `--media` (real media routing) or `--shape` (contract stubs), plus `--assembly`, `--subtitles`, and `--bgm`.
- `execute`: Orchestrates the compiled plan DAG end-to-end, executing steps, assembly transforms, and QC conformance gates with authoritative resume support.
- `run`: Single-step video generation runner (defaults to `mock.studio.video` writing `.mock.bin`).
- `flow run`: Single Studio skill runner across kaggle/api/local transports (shape-only).
- Full sequence: [`AGENTS.md`](AGENTS.md).

## Handoff operations and constraints *(rc4)*

`fsf execute` can delegate media-generation tool steps to an asynchronous external agent.
Enable Handoff via any of:

```text
# Delegate all media-generation steps
fsf execute plan.json --out output/execute --handoff

# Delegate via executor override
fsf execute plan.json --out output/execute --executor handoff

# Per-step: set executor_id in the plan step inputs
inputs.executor_id = "handoff"
```

On the first run FSF emits workorders and exits with `status: "pending_handoff"`.
After the external agent writes result files into `<out_dir>/handoff/results/`,
re-run the **identical** command; FSF ingests the results and continues with QC
and assembly steps (those are always executed by FSF, never delegated).

**Workorder schema**: `fsf_workorder_v1`

Workorder fields used to prepare and validate a result:

| Field | Description |
|---|---|
| `workorder_id` | Unique per `job_id / run_id / step_id / attempt_id` |
| `target_artifact` | Exact output path the executor must write |
| `plan_digest` | SHA-256 of the compiled plan; must be echoed in the result |
| `inputs_digest` | SHA-256 of step input bindings; must be echoed in the result |
| `expected_contract_digest` | SHA-256 of the media QC contract; must be echoed if set |
| `workorder_digest` | SHA-256 of the workorder itself (tamper-evidence) |

**Acceptable result JSON** (`fsf_workorder_result_v1`):

```json
{
  "schema_version": "fsf_workorder_result_v1",
  "workorder_id":   "<copy from workorder>",
  "job_id":         "<copy from workorder>",
  "run_id":         "<copy from workorder>",
  "step_id":        "<copy from workorder>",
  "attempt_id":     "<copy from workorder>",
  "plan_digest":    "<copy from workorder>",
  "inputs_digest":  "<copy from workorder>",
  "expected_contract_digest": "<copy from workorder, or omit if null>",
  "status":         "completed",
  "artifact_path":  "<must equal workorder target_artifact exactly>",
  "artifact_sha256": "<sha256 of the written file>",
  "detail":         "optional free-text"
}
```

**Handoff cycle**:

1. **Emit workorder** — FSF writes a digest-bound `fsf_workorder_v1` to
   `<out_dir>/handoff/workorders/<workorder_id>.workorder.json`.
2. **Ingest result** — after the executor writes the output file and places
   `<workorder_id>.result.json` in `<out_dir>/handoff/results/`,
   `ingest_workorder_result()` verifies path confinement, zero-byte guard,
   SHA-256, and all mandatory digest fields.
   Violations raise `HandoffIntegrityError` or `HandoffSecurityError`.
3. **Retry on rejection** — re-run the same command to receive a new attempt.
   Use the new workorder's identifiers and digests when submitting a replacement result.

**Constraints**:

- Do **not** run `verify` on `.shape.bin` or `.mock.bin`; those are contract stubs, not media.
- `artifact_path` in the result must equal the workorder's `target_artifact` exactly; FSF
  does not accept substitutions. SHA-256 conflict detection rejects results whose digest
  differs from a previously accepted result for the same step.
- Path traversal in `target_artifact` is rejected unconditionally.
- Copy the result's identity and digest fields from the current workorder. Preserve the integer type of `attempt_id`; include `expected_contract_digest` when it is set.

## Audio contract behaviour under `--audio` flags *(rc4)*

CLI accepts `--audio keep` (default), `--audio strip`, or `--audio require`.
These flags govern two separate contract layers:

### Source QC contract (per-shot conformance gate)

Only intake-generated default contracts (`expected_media_contract_source: "intake_default"`)
are touched. Explicit operator contracts are never overridden.

| `--audio` value | Effect on intake-default source contract |
|---|---|
| `keep` *(default)* | `audio` relaxed to `"allowed"` |
| `strip` | No change to source contract |
| `require` | No change to source contract |

### Assembly output contract (concatenated output conformance)

Applies to the assembled output artifact regardless of contract source:

| `--audio` value | Assembly output audio expectation |
|---|---|
| `keep` *(default)* | `"required"` if BGM or dub track present; otherwise `"allowed"` |
| `strip` | `"forbidden"` (or `"required"` if BGM is attached) |
| `require` | `"required"` |

**Explicit operator contracts are never overridden.** If a shot carries an
explicit `audio: "forbidden"` or `audio: "required"` entry (no
`expected_media_contract_source: "intake_default"` marker), the source QC
contract is left untouched by any `--audio` flag.

## Docs

- Live verify: [`docs/FSF_LIVE_VERIFY.md`](docs/FSF_LIVE_VERIFY.md)
- Release / PyPI: [`docs/RELEASE.md`](docs/RELEASE.md)
- Security: [`SECURITY.md`](SECURITY.md)
- Data governance: [`docs/DATA_GOVERNANCE.md`](docs/DATA_GOVERNANCE.md)
- Runtime pins: [`compatibility/pdx_official_pin_rc7_a8_a3.json`](compatibility/pdx_official_pin_rc7_a8_a3.json)
