# Pipeline Orchestration Guide ## Overview The Research Project Template provides **two main entry points** for pipeline operations: 1. **`run.sh`** - Main entry point for manuscript pipeline operations (interactive menu and flags) 2. **`uv run python scripts/runner/execute_pipeline.py --project {name} --core-only`** - Core pipeline via [`infrastructure/core/pipeline/pipeline.yaml`](../infrastructure/core/pipeline/pipeline.yaml): **8** DAG stages (clean → copy) with **`llm`-tagged and opt-in stages removed**. The default full run executes **10** core+LLM stages, while the YAML declares **16** stages including the opt-in science, provenance, ebook, metadata, bundle, and archival contracts. ## Thin Orchestration Architecture The Research Project Template follows a **thin orchestrator pattern** where all business logic resides in `infrastructure/` and `projects/{name}/src/` modules, while entry points and scripts act as lightweight coordinators. ### Architecture Overview ```mermaid flowchart TB UI["User Interface
run.sh / secure_run.sh → infrastructure.orchestration"] ORCH["Orchestration Layer
scripts/pipeline/stage_NN_*.py → infrastructure
projects/<name>/scripts/*.py → projects/<name>/src/"] LOGIC["Business Logic
infrastructure/ (reusable) + projects/<name>/src/ (custom)"] UI -- delegates to --> ORCH ORCH -- implements --> LOGIC classDef ui fill:#1e3a8a,stroke:#0f172a,color:#fff classDef orch fill:#0f766e,stroke:#0f172a,color:#fff classDef logic fill:#7c2d12,stroke:#0f172a,color:#fff class UI ui class ORCH orch class LOGIC logic ``` ### Key Principles **Layer 1: Entry Points (Thin Orchestrators)** - **`run.sh` / `secure_run.sh`**: Bootstrap `uv`, then `exec uv run python -m infrastructure.orchestration` (interactive menu, pipeline, multi-project, and secure subcommands) - **`infrastructure.orchestration`**: `PipelineRunner` wrapping `PipelineExecutor`; menu rendering in `menu.py` - **`execute_pipeline.py`**: Alternate non-interactive pipeline entry using `PipelineExecutor` directly - **`execute_multi_project.py`**: Multi-project orchestration using `MultiProjectOrchestrator` - **Purpose**: User interface and high-level coordination only **Layer 2: Stage Scripts (Thin Orchestrators)** - **`scripts/pipeline/stage_NN_*.py`**: Import from `infrastructure/` for business logic. These canonical filenames are thin stage orchestrators; their numeric prefixes identify the stage implementation, while pipeline-position indices remain defined by `pipeline.yaml`. - **`projects/{name}/scripts/*.py`**: Import from `projects/{name}/src/` for business logic - **Purpose**: Stage-specific coordination and I/O handling **Layer 3: Business Logic (Actual Implementation)** ### Pipeline stage → infrastructure → project script map Live test and coverage totals: [`docs/_generated/COUNTS.md`](_generated/COUNTS.md). | Stage (default full run) | Root orchestrator | Primary infrastructure modules | Typical project script | | --- | --- | --- | --- | | 0 Clean outputs | built-in (`PipelineExecutor`) | `infrastructure.core.files` | — | | 1 Environment setup | `scripts/pipeline/stage_00_setup.py` | `infrastructure.project.discovery` | — | | 2 Infrastructure tests | `scripts/pipeline/stage_01_test.py --infra-only` | `infrastructure.core.test_runner` | — | | 3 Project tests | `scripts/pipeline/stage_01_test.py --project-only` | `infrastructure.core.test_runner` | — | | 4 Project analysis | `scripts/pipeline/stage_02_analysis.py` | `infrastructure.core.pipeline` | `projects/templates//scripts/*.py` | | 5 PDF rendering | `scripts/pipeline/stage_03_render.py` | `infrastructure.rendering` | optional `render_*.py` in project | | 6 Output validation | `scripts/pipeline/stage_04_validate.py` | `infrastructure.validation` | — | | 7–8 LLM stages | `scripts/pipeline/stage_06_llm_review.py` | `infrastructure.llm` | — | | 9 Copy outputs | `scripts/pipeline/stage_05_copy.py` | `infrastructure.core.files` | — | Qualified discovery names (`templates/`, `active/`) resolve under `projects/` via `infrastructure.project.discovery`. - **`infrastructure/`**: Generic, reusable algorithms and utilities - **`projects/{name}/src/`**: Project-specific scientific code and analysis - **Purpose**: All computational logic and algorithms ### Orchestration Flow ```mermaid graph TD A[User] --> B[run.sh or secure_run.sh] B --> C[infrastructure.orchestration] C --> D[PipelineRunner] D --> E[PipelineExecutor] E --> F[scripts/pipeline/stage_00_setup.py] E --> G[scripts/pipeline/stage_01_test.py] E --> H[scripts/pipeline/stage_02_analysis.py] E --> I[scripts/pipeline/stage_03_render.py] F --> J[infrastructure.core.runtime.environment] G --> K[infrastructure.reporting.pipeline_test_runner] H --> L[infrastructure.core.script_discovery] I --> M[infrastructure.rendering] L --> N["projects/{name}/scripts/*.py"] N --> O["projects/{name}/src/"] ``` ### Benefits - **Separation of concerns** — clear boundaries between orchestration and computation - **Reusability** — infrastructure modules work across all projects - **Testability** — business logic isolated and thoroughly tested - **Maintainability** — changes to algorithms do not affect orchestration - **Extensibility** — new projects inherit infrastructure ### Examples **Correct: thin orchestrator pattern** ```python # scripts/pipeline/stage_03_render.py (orchestrator) from infrastructure.rendering import RenderManager def run_render_pipeline(): renderer = RenderManager() # Import business logic pdf = renderer.render_pdf("manuscript.tex") # Delegate computation return validate_output(pdf) # Orchestrate validation ``` **Incorrect: violates architecture** ```python # scripts/pipeline/stage_03_render.py (WRONG - implements logic) def render_pdf_to_tex(content): # Business logic in orchestrator - WRONG! lines = content.split('\n') tex_lines = [] for line in lines: if line.startswith('# '): tex_lines.append(f'\\section{{{line[2:]}}}') # ... complex rendering logic ... return '\n'.join(tex_lines) ``` ## Multi-Project Support The template now supports **multiple research projects** in a single repository. You can: - **Run individual projects**: `./run.sh --project --pipeline` - **Run all projects sequentially**: `./run.sh --all-projects --pipeline` - **Interactive project selection**: `./run.sh` (shows menu of available projects) ### Available Projects Projects are discovered dynamically from `projects/` (see `infrastructure.project.discovery.discover_projects()`). **Authoritative names:** [_generated/active_projects.md](_generated/active_projects.md) (see [_generated/README.md](_generated/README.md) for policy and regeneration). **Examples in this guide** use **`template_code_project`** as the stable control-positive layout under `projects/`. Archived and in-progress work lives under `projects/archive/` and `projects/working/` and is not executed by default `./run.sh` discovery. Render it explicitly with a qualified name such as `--project working/`, or deliberately restore it through optional sidecar `active/` when it should appear in the normal menu. Private work normally lives in the sibling repo configured by `$TEMPLATE_PRIVATE_PROJECTS_ROOT`. The simplified sidecar uses `working/` and `archive/` by default; optional legacy `active/`, `published/`, and `other/` folders are still linked when present. `run.sh` auto-syncs existing lifecycle folders into matching `template/projects//` symlinks before discovery. Use `uv run python -m infrastructure.orchestration link-projects --dry-run` to preview link changes, `TEMPLATE_PRIVATE_PROJECTS_ROOT` or `.private_projects_root` to override the sibling repo, and `TEMPLATE_SKIP_LINK_SYNC=1` to skip auto-sync for a command. ### Multi-Project Commands ```bash # Interactive project selection ./run.sh # Run specific project ./run.sh --project template_code_project --pipeline # Run all projects sequentially ./run.sh --all-projects --pipeline # Alternative orchestrator (all projects) uv run python scripts/runner/execute_multi_project.py ``` ## Entry Point 1: Manuscript Operations (`run.sh`) `run.sh` is a thin bootstrap shell: it sources `scripts/shell/shell_bootstrap.sh`, then `exec uv run python -m infrastructure.orchestration`. Bare `./run.sh` opens the interactive menu; `uv run` syncs the workspace on demand. Invocations with pipeline flags also run `uv sync` when `.venv` is missing. For pipeline + steganography, use `./secure_run.sh --project ` or `./run.sh --secure-run --project ` (see [`docs/security/secure_execution.md`](security/secure_execution.md)). ### `shell_bootstrap.sh` (shared bootstrap) Both [`run.sh`](../run.sh) and [`secure_run.sh`](../secure_run.sh) source [`scripts/shell/shell_bootstrap.sh`](../scripts/shell/shell_bootstrap.sh) only — not [`scripts/shell/bash_utils.sh`](../scripts/shell/bash_utils.sh) (operational backup/health scripts). | Helper | Role | | --- | --- | | `setup_orchestration_sandbox_env` | Sets `MPLCONFIGDIR` and `UV_CACHE_DIR` under `$TMPDIR` for headless/cache-safe runs | | `ensure_uv` | Locates or installs `uv` (quiet; no colored logging) | | `print_uv_install_instructions` | Prints install guidance when `uv` is unavailable | **`run.sh`-specific behaviour:** - Internal `PIPELINE_MODE` (bash-local, **not exported**) triggers conditional `uv sync` when `.venv` is missing on pipeline-capable flags. - **Argv shaping:** `--pipeline` / `--all-projects` → prepend `pipeline` subcommand; `--secure-run` → prepend `secure`; other flags forward verbatim to `python -m infrastructure.orchestration`. - **`FEP_LEAN_GAUSS_WORKFLOWS`:** defaults to `1`; `--no-lean-workflows` sets it to `0`. **`secure_run.sh`-specific behaviour:** - Always runs `uv sync --group steganography` before exec (except `--help` fast path). - No args → exit **2** with quick-start stderr; `--help` skips stego sync. - Forwards all flags (including `--deterministic`) to the Python `secure` subcommand. ```bash ./run.sh ``` ### Manuscript Menu The menu is rendered by [`render_menu()`](../infrastructure/orchestration/menu.py) (`template_code_project` shown as an example project name): ```text +========================================================================+ | MANUSCRIPT PIPELINE · thin orchestrator template | | project > template_code_project | +========================================================================+ Single stages 0-7 · Presets 8 / 9 / f · Multi a-d · p · i · q Keys 0-5: setup, tests, analysis, render, validate, copy | 6-7: LLM (Ollama) | 8/9/f: pipelines | a-d: all projects Flow: [0..5] script chain + (6,7) LLM | 8/9/f DAG presets | a-d multi-project -- INDIVIDUAL STAGES - one script per key -------------------------------- 0 | Environment Setup | stage_00_setup.py 1 | Run Tests | stage_01_test.py (infra + project) 2 | Run Analysis | stage_02_analysis.py 3 | Render PDF | stage_03_render.py 4 | Validate Output | stage_04_validate.py 5 | Copy Outputs | stage_05_copy.py 6 | LLM Review | stage_06_llm_review.py (Ollama) 7 | LLM Translations | stage_06_llm_review.py (Ollama) -- ORCHESTRATION - full DAG, current project ----------------------------- 8 | Core Pipeline | current project · infra on · LLM off · 8 stages 9 | Full Pipeline | current project · infra on · LLM on · 10 stages f | Full Pipeline (fast) | current project · skip infra · LLM on -- MULTI-PROJECT - every discovered project ------------------------------ a | All projects full | all projects · infra on · LLM on · report b | All projects full (fast) | all projects · skip infra · LLM on · report c | All projects core | all projects · infra on · LLM off · report d | All projects core (fast) | all projects · skip infra · LLM off · report -- PROJECT --------------------------------------------------------------- p | Change Project i | Show Project Info q | Quit -------------------------------------------------------------------------- Infra tests: Layer-1 pytest (tests/infra_tests/), then project tests. LLM: optional Ollama stages; pipeline skips them when Ollama is unavailable. Executive report: written after all projects finish (keys a-d only). -------------------------------------------------------------------------- Tip: chain stage digits (e.g. 234 = analyze -> render -> validate); comma or space also work. use p to switch project · i for current name · q to quit. -- OTHER WORKFLOWS - opt-in, run directly (not in this menu) ------------- Secure + watermark | ./secure_run.sh --project (steganography PDF) Steganography only | ./secure_run.sh --steganography-only (re-watermark, no re-render) Ebook formats | uv run python scripts/pipeline/stage_11_ebook.py --project Metadata package | uv run python scripts/pipeline/stage_12_metadata.py --project Executable bundle | uv run python scripts/runner/bundle_executable.py --project Archival deposit | uv run python scripts/runner/archive_publication.py --project (dry-run by default) Full release | uv run python scripts/publish/publish_project_release.py --project --tag vX --repo owner/repo Credential check | uv run python -m infrastructure.publishing.credential_check --env-file .env Reproducible matrix | uv run python scripts/runner/run_matrix.py (reads run.config) Repro bundle | uv run python scripts/runner/repro_bundle.py build See docs/guides/publishing-guide.md and docs/maintenance/archival-targets.md for details. ``` After the menu, the interactive loop prints a one-line key legend, a blank line, then `Choice: ` before reading input. Choosing **p** prints the project list to stdout and then `Choice [index / a=all / q=quit]: ` before reading the picker line. Progress logs use a **pre-step** `[0/9] Clean Output Directories`, then **`[1/9]` through `[9/9]`** for the nine tracked steps in the default core+LLM path (see `STAGE_NAMES` in [`infrastructure/orchestration/menu.py`](../infrastructure/orchestration/menu.py); `run.sh` is a thin shell dispatcher into `infrastructure.orchestration`). The **Python executor** follows [`pipeline.yaml`](../infrastructure/core/pipeline/pipeline.yaml), which declares 16 stages total: 8 core, 2 science/provenance, 2 optional LLM, 2 opt-in ebook/metadata, and 2 opt-in bundle/archival stages. ### Manuscript Menu Options #### Option 0: Environment Setup Verifies the environment is ready for the pipeline. - Checks Python version (requires >=3.10) - Verifies dependencies are installed - Confirms build tools (pandoc, xelatex) are available - Validates directory structure - Sets up environment variables #### Option 1: Run Tests Executes the test suite with coverage validation. - Runs infrastructure tests (`tests/infra_tests/`) with 60%+ coverage threshold - Runs project tests (`projects/{name}/tests/`) with 90%+ coverage threshold - Generates HTML coverage reports for both suites - Generates structured test reports (JSON, Markdown) **Coverage Reports**: `htmlcov/index.html` #### Option 2: Run Analysis Executes project analysis scripts with progress tracking. - Discovers scripts in `projects/{name}/scripts/` - Executes each script in order with progress tracking - Rejects configured or direct script paths that escape that `scripts/` tree - Redacts credential-like parent environment variables by default; set `ANALYSIS_ALLOW_SECRETS=1` only for an explicitly reviewed live integration - Collects outputs to `projects/{name}/output/` #### Option 3: Render PDF Generates manuscript PDFs with progress tracking. - Processes `projects/{name}/manuscript/` markdown files - Converts to LaTeX via pandoc - Compiles to PDF via xelatex - Also runs analysis scripts first (option 2) **Output**: `projects/{name}/output/pdf/` #### Option 4: Validate Output Validates build quality with reporting. - Checks generated PDFs for issues - Validates markdown references - Checks figure integrity - Generates validation reports (JSON, Markdown) #### Option 5: Copy Outputs Copies final deliverables into the repo-level `output/{name}/` tree (and related publishing outputs per project settings). #### Option 6: LLM Review Generates AI-powered manuscript reviews using local Ollama LLM. - Checks Ollama availability and selects best model - Extracts full text from combined PDF manuscript - Generates executive summary, quality review, methodology review, and improvement suggestions - Saves all reviews to `projects/{name}/output/llm/` **Requires**: Running Ollama server with at least one model installed. Skips gracefully if unavailable. #### Option 7: LLM Translations Generates multi-language technical abstract translations. - Translates abstract to configured languages (see `projects/{name}/manuscript/config.yaml`) - Uses local Ollama LLM for translation - Saves translations to `projects/{name}/output/llm/` **Requires**: Running Ollama server and translation configuration in `config.yaml`. #### Menu `8`: Core Pipeline Runs `execute_pipeline.py` with **`--core-only`** (default [`pipeline.yaml`](../infrastructure/core/pipeline/pipeline.yaml): **8** stages, no LLM-tagged steps). - Stops on first failure with clear error messages - Suitable for CI/CD environments #### Menu `9`: Full Pipeline Runs the **full** default DAG (**10** stages in `pipeline.yaml`, including clean, both LLM stages, and copy). - LLM stages are optional at runtime (exit code 2 skip) if Ollama is unavailable - Bash progress lines use `[0/9]` for clean, then `[1/9]`–`[9/9]` for the nine entries in `STAGE_NAMES` in [`infrastructure/orchestration/menu.py`](../infrastructure/orchestration/menu.py) (see menu block above) #### Menu `f`: Full Pipeline (fast) Same as full pipeline but **skips infrastructure tests** (`--skip-infra` / fast path in `run.sh`). ### Manuscript Non-Interactive Mode ```bash # Core Build Operations ./run.sh --pipeline # Default full run (10 executed stages; pipeline.yaml declares 16 total) ./run.sh --pipeline --resume # Resume from last checkpoint uv run python scripts/pipeline/stage_01_test.py --infra-only # Run infrastructure tests only uv run python scripts/pipeline/stage_01_test.py --project-only # Run project tests only uv run python scripts/pipeline/stage_03_render.py --project {name} # Render PDF manuscript only # LLM Operations (requires Ollama) uv run python scripts/pipeline/stage_06_llm_review.py --reviews-only # LLM manuscript review only (English) uv run python scripts/pipeline/stage_06_llm_review.py --translations-only # LLM translations only # Show help ./run.sh --help ``` ## Entry Point 2: Python Orchestrator (`scripts/runner/execute_pipeline.py`) For programmatic access or CI/CD integration, use the Python orchestrator: ```bash # Core pipeline (8 DAG stages in default pipeline.yaml — excludes LLM-tagged stages) uv run python scripts/runner/execute_pipeline.py --project {name} --core-only ``` **Features**: - **Eight** DAG stages by default: clean → setup → infrastructure tests → project tests → analysis → PDF → validation → copy. Omit infrastructure tests with `--skip-infra` (**seven** stages). - No LLM-tagged stages (`scripts/pipeline/stage_06_llm_review.py` / `scripts/pipeline/stage_07_executive_report.py` are not part of `--core-only`; the executive stage is for multi-project reporting) - No LLM dependencies required for `--core-only` - Suitable for automated environments - Checkpoint/resume support: `uv run python scripts/runner/execute_pipeline.py --project {name} --core-only --resume` ### Core Pipeline Stages + Executive Reporting The canonical pipeline-stage table (rendered from `pipeline.yaml`): | Stage | Script | Tags | Failure mode | | ----- | ------ | ---- | ------------ | | **0** Clean Output Directories | built-in `_run_clean_outputs` | `core`, `clean` | soft fail | | **1** Environment Setup | `scripts/pipeline/stage_00_setup.py` | `core` | hard fail | | **2** Infrastructure Tests | `scripts/pipeline/stage_01_test.py --infra-only --verbose --infra-scope pipeline-smoke` | `core`, `tests` | configurable tolerance | | **3** Project Tests | `scripts/pipeline/stage_01_test.py --project-only --verbose` | `core`, `tests` | configurable tolerance | | **4** Project Analysis | `scripts/pipeline/stage_02_analysis.py` | `core` | hard fail | | **5** Connector Search | `scripts/pipeline/stage_08_connector_search.py` | `science` | skipped if not configured | | **6** Provenance Record | `scripts/pipeline/stage_09_provenance_record.py --stage Connector Search` | `provenance` | skipped if not configured | | **7** PDF Rendering | `scripts/pipeline/stage_03_render.py` | `core` | hard fail | | **8** Output Validation | `scripts/pipeline/stage_04_validate.py` | `core` | PDF/bookends and artifact/provenance failures block; optional-format structure remains a warning + report | | **9** LLM Scientific Review | `scripts/pipeline/stage_06_llm_review.py --reviews-only` | `llm` | skipped if Ollama absent | | **10** LLM Translations | `scripts/pipeline/stage_06_llm_review.py --translations-only` | `llm` | skipped if Ollama absent | | **11** Copy Outputs | `scripts/pipeline/stage_05_copy.py` | `core` | soft fail | | **12** Ebook Generation | `scripts/pipeline/stage_11_ebook.py` | `core`, `ebook` | soft fail | | **13** Metadata Package | `scripts/pipeline/stage_12_metadata.py` | `core`, `metadata` | soft fail | | **14** Executable Bundle | `scripts/runner/bundle_executable.py` | `bundle` | soft fail | | **15** Archival Publication | `scripts/runner/archive_publication.py` | `archival` | soft fail | The table above lists pipeline-position indices (0-based, as the executor sees them); the table below maps script *filename* prefixes to their high-level purpose: | Script | Purpose | |--------|---------| | `scripts/pipeline/stage_00_setup.py` | Environment setup & validation | | `scripts/pipeline/stage_01_test.py` | Run test suite (infrastructure + project) | | `scripts/pipeline/stage_02_analysis.py` | Discover & run `projects/{name}/scripts/` | | `scripts/pipeline/stage_03_render.py` | PDF rendering orchestration | | `scripts/pipeline/stage_04_validate.py` | Output validation & reporting | | `scripts/pipeline/stage_05_copy.py` | Copy final deliverables to `output/` | | `scripts/pipeline/stage_06_llm_review.py` | LLM manuscript review & translations (optional, requires Ollama) | | `scripts/pipeline/stage_07_executive_report.py` | Executive summaries & dashboards (multi-project only) | `--core-only` runs the executor stages through copy outputs and does **not** run the optional LLM/executive stages. ## Entry Point Comparison | Entry Point | Pipeline Stages | LLM Support | Use Case | |-------------|----------------|--------------|----------| | `./run.sh` | Main entry point | Optional | Interactive menu or manuscript pipeline with LLM | | `./run.sh --pipeline` | Full DAG (**10** stages in default `pipeline.yaml`) | Optional | Manuscript pipeline with LLM stages present in the graph | | `./run.sh --secure-run` | Same as `./secure_run.sh` via argv shaping | Optional | Secure subcommand from the main thin shell | | `./secure_run.sh` | Full/core DAG + steganography | Optional | Dedicated secure entry; always `uv sync --group steganography` | | `uv run python scripts/runner/execute_pipeline.py --project {name} --core-only` | Core DAG (**8** stages; LLM stages omitted) | None | Core pipeline, CI/CD automation | | `uv run python scripts/runner/run_matrix.py` | Exactly the (project, stage) pairs declared in `run.config` | Per stage | **Reproducible subset runs** across several projects | ## Entry Point 3: Reproducible Run Matrix (`scripts/runner/run_matrix.py`) The deterministic, version-controllable alternative to the interactive menu. A top-level `run.config` (YAML) declares a matrix of **projects × stages** — the exact subset of the pipeline to run, for exactly which projects. Stages always execute in canonical pipeline order (analysis before render, etc.) regardless of how they are listed, so a given `run.config` reproduces the same run every time. ```bash # Uses ./run.config (or run.config.yaml). See run.config.example.yaml. uv run python scripts/runner/run_matrix.py uv run python scripts/runner/run_matrix.py --dry-run # print the resolved plan, run nothing uv run python scripts/runner/run_matrix.py --fail-fast # stop at the first failing stage uv run python scripts/runner/run_matrix.py --config path/to/other.yaml ``` `run.config` schema (see [`run.config.example.yaml`](../run.config.example.yaml)): ```yaml version: 1 defaults: stages: [setup, project_tests, analysis, render_pdf, validate, copy] runs: - project: templates/template_code_project # qualified, bare, or sidecar path - project: working/my_paper stages: [render_pdf, validate] # overrides defaults ``` A project reference may be a qualified name (`templates/template_code_project`), a bare name (resolved to its canonical location), or a sidecar path stem (`working/my_paper`); path traversal is rejected. Valid stage keys match `execute_pipeline.py --stage`. The user's `run.config` is git-ignored (it may reference private `working/` projects); only `run.config.example.yaml` is tracked. ## Usage Examples ### Interactive Mode ```bash ./run.sh # main dispatcher (project menu + pipeline options) ``` ### Non-Interactive Mode ```bash # Run manuscript pipeline ./run.sh --pipeline # Resume manuscript pipeline from checkpoint ./run.sh --pipeline --resume # Run core pipeline (Python) uv run python scripts/runner/execute_pipeline.py --project {name} --core-only ``` ### Individual Stage Execution Individual stages can also be run directly via Python: ```bash uv run python scripts/pipeline/stage_00_setup.py # Setup environment uv run python scripts/pipeline/stage_01_test.py --project {name} # Run tests only uv run python scripts/pipeline/stage_01_test.py --project {name} --verbose # Run tests with verbose output uv run python scripts/pipeline/stage_02_analysis.py --project {name} # Run project scripts uv run python scripts/pipeline/stage_03_render.py --project {name} # Render PDFs only uv run python scripts/pipeline/stage_04_validate.py --project {name} # Validate outputs only uv run python scripts/pipeline/stage_05_copy.py --project {name} # Copy final deliverables uv run python scripts/pipeline/stage_06_llm_review.py --project {name} # LLM manuscript review uv run python scripts/pipeline/stage_06_llm_review.py --project {name} --reviews-only # Reviews only uv run python scripts/pipeline/stage_06_llm_review.py --project {name} --translations-only # Translations only ``` ## Exit Codes - **0**: Operation succeeded - **1**: Operation failed - review errors and fix issues - **2**: Operation skipped (e.g., Ollama not available for LLM review) ## Environment Variables Root entry shells (`run.sh`, `secure_run.sh`) do **not** export `PROJECT_ROOT` or `PYTHONPATH`. Pipeline stages set runtime paths via [`set_environment_variables()`](../infrastructure/core/runtime/_packages.py) and the test runner adds project `src/` when needed. You can override logging or render toggles before running: ```bash export LOG_LEVEL=0 # Enable debug logging ./run.sh --pipeline ``` ### Logging variables | Variable | Default | Description | |----------|---------|-------------| | `LOG_LEVEL` | `1` | `0`=DEBUG `1`=INFO `2`=WARN `3`=ERROR | | `NO_EMOJI` | unset | Set to disable emoji in output | | `STRUCTURED_LOGGING` | unset | Set to emit JSON log lines | | `LOG_TERMINAL_VERBOSE` | unset | Restore the verbose `[ts] [LEVEL] msg` prefix on the terminal (the file always has it) — see [operational/logging/output-design.md](operational/logging/output-design.md) | ### Render-format variables Format toggles default to PDF/HTML/Slides **on**, DOCX/EPUB **off**. Set in `projects/{name}/manuscript/config.yaml` under `render.formats`, or override per-run via env (env precedence beats yaml): | Variable | Type | Default | Effect | |----------|------|---------|--------| | `ENABLE_PDF` | `0/1`,`true/false`,`yes/no` | `1` | Combined PDF + per-section LaTeX/PDF | | `ENABLE_HTML` | same | `1` | Combined HTML index + per-section HTML | | `ENABLE_SLIDES` | same | `1` | Per-section Beamer PDFs | | `ENABLE_DOCX` | same | `0` | Combined Word document (`output//docx/`) | | `ENABLE_EPUB` | same | `0` | Combined EPUB (`output//epub/`) | See [`usage/output-formats.md`](usage/output-formats.md) for the full configuration matrix. ### LLM Review Variables | Variable | Default | Description | |----------|---------|-------------| | `LLM_MAX_INPUT_LENGTH` | `500000` | Max chars to send to LLM. Set to `0` for unlimited. | | `LLM_REVIEW_TIMEOUT` | `300` | Timeout per review in seconds | | `LLM_LONG_MAX_TOKENS` | `16384` | Maximum tokens per review response | ## Error Handling The scripts use strict error handling: - Stops immediately on first failure - Provides clear error messages - Shows which stage/operation failed - Returns to menu after each operation (interactive mode) **Example error output**: ``` ✗ Infrastructure tests failed Operation completed in 45s Press Enter to return to menu... ``` ## Troubleshooting ### "Permission denied: ./run.sh" Make the script executable: ```bash chmod +x run.sh ``` ### Tests fail with import errors Verify each project has `projects//tests/conftest.py` with path bootstrap for that project's `src/` (and template root when needed). Do not rely on a repository-root `conftest.py` for project imports. ### Coverage threshold not met Check `pyproject.toml` `[tool.coverage.report]` for coverage thresholds. Increase test coverage in `tests/` and `projects/{name}/tests/`. ### PDF rendering fails Ensure pandoc and xelatex are installed: ```bash # macOS brew install pandoc brew install --cask mactex # Ubuntu/Debian sudo apt-get install -y pandoc texlive-xetex texlive-fonts-recommended ``` For manuscripts that use **pandoc-crossref** syntax (`@sec:…`, `@tbl:…`, `@fig:…`), install the filter so it appears on `PATH` (the PDF combined renderer passes `--filter` when found). Example on macOS: `brew install pandoc-crossref`. If the binary is missing, the build still succeeds; cross-reference tokens are not expanded until the filter is installed. ### LLM review fails or skips Ensure Ollama is running: ```bash # Start Ollama server ollama serve # Install a model (if needed) ollama pull gemma3:4b ``` ## See Also - [`scripts/README.md`](../scripts/README.md) — Stage orchestrators - [`scripts/AGENTS.md`](../scripts/AGENTS.md) — `scripts/` technical guide - [`AGENTS.md`](AGENTS.md) — Documentation hub (`docs/`) - [`../AGENTS.md`](../AGENTS.md) — Repository system reference - [`CLOUD_DEPLOY.md`](CLOUD_DEPLOY.md) — Headless / cloud server deployment - [`core/workflow.md`](core/workflow.md) — Development workflow --- ## Headless / Cloud Server Deployment For a fresh headless server (Ubuntu/Debian), all dependencies including `uv` are installed automatically when you invoke any non-interactive pipeline flag: ```bash # 1. Install system deps (LaTeX + git + curl) sudo apt-get update && sudo apt-get install -y \ curl git python3 pandoc \ texlive-xetex texlive-latex-extra texlive-fonts-recommended # 2. Clone the repository git clone https://github.com/docxology/template.git && cd template # 3. Run — uv is installed automatically, .venv is synced ./run.sh --pipeline ``` The `MPLBACKEND=Agg` environment variable is required on headless servers (no display): ```bash export MPLBACKEND=Agg ./run.sh --pipeline ``` > **Full guide:** see [`CLOUD_DEPLOY.md`](CLOUD_DEPLOY.md) for system prerequisites, > optional dependency groups, Docker alternative, Ollama setup, and troubleshooting.