# Fullbleed CLI

## Epoch STEEL (1.0.0) - Enterprise CLI

### 1. Epoch Identity
- Project: Fullbleed CLI (standalone)
- Epoch: STEEL
- Version target: 1.0.0
- Scope: Stable, engine-faithful CLI for Fullbleed PDF rendering

### 2. Objective
Deliver an enterprise-grade CLI that matches the Fullbleed Rust engine's standards for determinism, correctness, and observability while preserving all current CLI features and schemas.

### 3. Principles (must hold)
- Offline by default. Network access is explicit and opt-in.
- Deterministic by default. Same inputs yield the same outputs when requested.
- Engine-faithful. CLI flags map to existing engine capabilities with no hidden behavior.
- Stable contract. JSON schemas and exit codes are versioned and backward compatible.
- Predictable I/O. PDF to file or stdout. Logs to stderr. JSON to stdout.
- Cross-platform parity. Windows, macOS, Linux behave the same.
- Security conscious. No implicit downloads or writes outside user intent.

### 4. Project Boundaries
- This is a standalone project, versioned and released independently.
- Package name: fullbleed-cli.
- Primary command name remains fullbleed.
- The engine repo may optionally ship a thin shim that delegates to this CLI.
- Dependency on the fullbleed engine package is explicit.

### 5. Implementation Stance
- Python-first. The CLI remains user-hackable and easy to extend.
- Rust touch policy: avoid engine changes unless required for parity or correctness.
- Any Rust changes must be justified by a missing contract requirement and documented in release notes.

### 6. CLI Contract (v1)

#### 6.1 Global options
| Flag | Type | Default | Notes |
| --- | --- | --- | --- |
| --json | bool | false | Emit JSON result schemas to stdout |
| --config | path | none | Optional config file path |
| --log-level | enum | info | error, warn, info, debug |
| --no-color | bool | false | Disable color in human output |
| --version | bool | n/a | Print version and exit |

--config and --log-level are enterprise additions. They must not change current defaults unless explicitly set.

#### 6.2 Commands
| Command | Purpose |
| --- | --- |
| render | Render HTML/CSS to PDF |
| verify | Run pipeline without requiring PDF output |
| debug-perf | Summarize perf logs |
| debug-jit | Summarize JIT logs |
| doctor | Print capability summary |
| assets | Asset registry and package management |
| cache | Cache inspection and pruning |
| init | Project initialization |
| new | Create starter templates |
| run | Run a Python module or file entrypoint |

#### 6.3 Common render and verify flags
| Flag | Type | Default | Notes |
| --- | --- | --- | --- |
| --html | path or - | none | Required if --html-str not set |
| --html-str | string | none | Inline HTML |
| --css | path | none | Repeatable |
| --css-str | string | none | Repeatable |
| --page-size | enum | none | letter, a4, legal |
| --page-width | length | none | Requires --page-height |
| --page-height | length | none | Requires --page-width |
| --margin | length | none | Engine margin |
| --page-margins | json or path | none | JSON dict or path |
| --reuse-xobjects | bool | true | Also supports --no-reuse-xobjects |
| --svg-form-xobjects | bool | false | Also supports --no-svg-form-xobjects |
| --svg-raster-fallback | bool | false | Also supports --no-svg-raster-fallback |
| --unicode-support | bool | true | Also supports --no-unicode-support |
| --shape-text | bool | true | Also supports --no-shape-text |
| --unicode-metrics | bool | true | Also supports --no-unicode-metrics |
| --jit-mode | enum | none | Values align with engine |
| --pdf-version | enum | none | 1.7, 2.0 |
| --pdf-profile | enum | none | none, pdfa2b, pdfx4, tagged |
| --color-space | enum | none | rgb, cmyk |
| --document-lang | string | none | BCP47 |
| --document-title | string | none | |
| --header-each | string | none | |
| --header-html-each | string | none | |
| --footer-each | string | none | |
| --footer-html-each | string | none | |
| --watermark-text | string | none | |
| --watermark-html | string | none | |
| --watermark-image | path | none | |
| --watermark-layer | string | overlay | |
| --watermark-opacity | float | 0.15 | |
| --watermark-rotation | float | 0.0 | |
| --emit-jit | path | none | Writes JIT log |
| --emit-perf | path | none | Writes perf log |
| --emit-glyph-report | path | none | Writes glyph report |
| --emit-page-data | path | none | Writes page data |
| --asset | path or builtin | none | Repeatable |
| --asset-kind | enum | none | Repeatable, indexed to --asset |
| --asset-name | string | none | Repeatable, indexed to --asset |
| --asset-trusted | bool | false | |
| --allow-remote-assets | bool | false | |
| --verbose-assets | bool | false | |
| --profile | enum | none | dev, preflight, prod |
| --fail-on | enum | none | Repeatable: overflow, missing-glyphs, font-subst, budget |
| --deterministic-hash | path | none | Writes SHA256 of output |

#### 6.4 Command specifics

render
- Requires --out.
- Rejects --json with --out -.
- Writes outputs and emits fullbleed.render_result.v1.

verify
- Optional --emit-pdf.
- If --emit-jit is set and no --emit-pdf, set jit_mode=plan.
- Emits fullbleed.verify_result.v1.

debug-perf
- --perf-log required.
- --top default 20.
- Emits fullbleed.debug_perf.v1.

debug-jit
- --jit-log required.
- --errors-only optional.
- Emits fullbleed.debug_jit.v1.

doctor
- Emits fullbleed.doctor.v1.

assets
- list with --available, --json
- info <package> with --json
- install <package> with --vendor, --global, --json
- verify <package> with --json
- lock with --add, --output, --json

cache
- dir with --json
- prune with --max-age-days, --dry-run, --json

init
- path optional, defaults to .
- --force, --json.

new
- template, path optional.
- --force, --json.

run
- entrypoint accepts module:engine or path/to/file.py:engine.
- Requires --html and --out.
- --css, --css-str, --html-str supported.
- Emits fullbleed.run_result.v1.

### 7. JSON Schemas (v1)
- fullbleed.render_result.v1
- fullbleed.verify_result.v1
- fullbleed.run_result.v1
- fullbleed.error.v1
- fullbleed.assets_list.v1
- fullbleed.assets_info.v1
- fullbleed.assets_install.v1
- fullbleed.assets_verify.v1
- fullbleed.assets_lock.v1
- fullbleed.cache_dir.v1
- fullbleed.cache_prune.v1
- fullbleed.init.v1
- fullbleed.new_template.v1
- fullbleed.doctor.v1
- fullbleed.debug_perf.v1
- fullbleed.debug_jit.v1

### 8. Exit Codes (v1)
- 0 success
- 1 validation failure for --fail-on conditions
- 3 CLI or input error
- Other codes are reserved and must be documented before use

### 9. Configuration and Precedence
- Optional fullbleed.toml at project root.
- Precedence: CLI flags > environment variables > config file > defaults.
- The CLI must never silently change defaults.

### 10. Asset System Contract
- Built-ins include @bootstrap and @noto-sans.
- Remote assets are available only when explicitly requested and allowed.
- Lock file assets.lock.json must be updated on install in a project.
- Vendor directory defaults to ./vendor for project installs.
- Cache directory is platform-specific.
- Project root detection uses assets.lock.json, report.py, or fullbleed.toml.

### 11. Determinism and Reproducibility
- --deterministic-hash computes SHA256 of output bytes.
- Asset ordering is deterministic and explicit.
- Stable ordering for log entries and JSON output.

### 12. Observability
- Human output to stderr, JSON to stdout.
- Structured error records for all failures.
- Debug logs must be machine readable.

### 13. Quality Bar
- Cross-platform CLI tests.
- Contract tests for all JSON schemas.
- Golden test fixtures for render and verify outputs.
- Static typing and linting enforced.

### 14. Security
- No network activity unless explicitly requested.
- Remote downloads must verify hash when known.
- Paths are normalized to prevent traversal when writing.

### 15. Delivery Plan
Phase 0: Finalize spec and contract tests.
Phase 1: New repo skeleton and command wiring.
Phase 2: Parity port for render, verify, debug, doctor.
Phase 3: Parity port for assets, cache, scaffold, run.
Phase 4: Hardening, docs, CI, releases.
Phase 5: Optional Rust core for CLI with parity test suite.

### 16. Migration
- fullbleed remains the command name.
- Existing flags and schemas remain supported.
- Deprecations require a documented window and warnings.

### 17. Compiler Target Model
The CLI is the compiler front end. The engine is the backend. The compiler unit is a document bundle and the compiler output is an artifact set.

Terms
- Source bundle: HTML input, CSS inputs, assets, and CLI or config options.
- Build profile: dev, preflight, or prod settings as resolved by the CLI.
- Artifact set: PDF plus optional logs and reports.
- Result record: the JSON schema emitted by --json.

Compiler target statement
- The CLI compiles a source bundle into a deterministic artifact set using the engine as the backend.
- The CLI owns input normalization, validation, asset resolution, and output packaging.

### 18. Compiler Pipeline
Stages are defined so each phase is observable and contractually stable.

Stages
- Ingest: parse CLI args, resolve file paths, read stdin where allowed.
- Normalize: apply profile defaults, resolve page size, merge CSS.
- Validate: required flags, flag conflicts, asset kinds, and remote asset policy.
- Plan: build AssetBundle and construct PdfEngine with normalized options.
- Render: call the engine render functions for PDF and optional reports.
- Package: write artifacts to disk or stdout and compute deterministic hash if requested.
- Report: emit JSON result or human output.

### 19. Compiler Input Contract
The compiler input is implicit and derived from CLI options. It is equivalent to the following logical schema.

CompilerInput.v1 (logical)
```
{
  "html": "path or inline string",
  "css": ["path", "path", "..."],
  "css_str": ["string", "string", "..."],
  "assets": [
    {"path": "...", "kind": "...", "name": "...", "trusted": false, "remote": false}
  ],
  "page": {"size": "letter|a4|legal", "width": "...", "height": "...", "margin": "..."},
  "engine": {"jit_mode": "...", "reuse_xobjects": true, "...": "..."},
  "pdf": {"version": "1.7|2.0", "profile": "none|pdfa2b|pdfx4|tagged"},
  "profile": "dev|preflight|prod",
  "fail_on": ["overflow", "missing-glyphs", "font-subst", "budget"],
  "artifacts": {"jit": "...", "perf": "...", "glyph_report": "...", "page_data": "..."},
  "output": {"path": "...", "stdout": true, "deterministic_hash": "..."}
}
```

Notes
- --config is parsed but not interpreted in v1. It is reserved for future config loading.
- This contract must remain backward compatible. Any new fields are additive only.

### 20. Compiler Output Contract
The compiler output is an artifact set plus a result record.

Artifacts
- PDF file or stdout stream.
- Optional JIT log, perf log, glyph report, and page data.
- Optional deterministic hash file.

Result record
- The JSON payload emitted by --json is the authoritative result record.
- It must be stable and schema versioned.

### 21. Error Taxonomy and Exit Mapping
Errors are classified by CLI ownership and reported via JSON error schema and exit code.

Classes and examples
- CLI_ERROR: argument parsing, invalid flag combinations, missing required inputs.
- VALIDATION_ERROR: fail-on triggers such as missing glyphs.
- ASSET_ERROR: package not found, download failed, asset kind required.
- PROJECT_ERROR: already initialized, file exists, unknown template.
- RUNTIME_ERROR: unexpected exceptions while rendering or packaging.

Exit mapping
- 0 success
- 1 validation failure for fail-on checks
- 3 CLI or input error

### 22. Determinism Contract
The CLI guarantees deterministic outputs when inputs are stable and remote access is disabled.

Rules
- All inputs are read deterministically and combined in a stable order.
- Asset order is explicit and repeatable.
- --deterministic-hash computes SHA256 of output bytes for verification.

### 23. Security and Asset Policy
The CLI enforces a strict, offline-by-default asset policy.

Rules
- Remote assets require --allow-remote-assets.
- Asset paths are normalized and must be explicit.
- Vendor and cache directories are the only allowed automatic asset destinations.
- The CLI does not execute remote code or scripts.

### 24. Observability and Auditability
The CLI provides machine-readable output for audit and CI.

Mechanisms
- --json for structured result records.
- --emit-jit and --emit-perf for performance and planning logs.
- --emit-glyph-report and --emit-page-data for verification.
- doctor for capability reporting.

### 25. Versioning Policy
The CLI and its schemas are versioned independently of the engine.

Rules
- Schema versions are immutable once published.
- Breaking changes require a major version bump and deprecation window.
- New fields are additive and optional by default.

### 26. Acceptance Criteria for Compiler Target
The CLI is enterprise grade when it satisfies all of the following.

Acceptance
- Deterministic outputs for stable inputs with offline assets.
- Stable JSON schemas with contract tests.
- Cross-platform parity for command behavior.
- Asset policy enforcement and explicit remote opt-in.
- Observability outputs are machine readable and complete.

### 27. AI Agent Usability Mandates
The CLI must be seamless for AI agents and automation.

Mandates
- Machine-first output. All commands must support stable, schema-validated JSON outputs.
- Non-interactive by default. No prompts or TTY-only flows unless explicitly requested.
- Idempotent behavior. Repeated runs with the same inputs must not diverge.
- Determinism preserving. The CLI must not introduce non-determinism or hidden state.
- Actionable diagnostics. Errors must include codes, causes, and remediation hints.
- Self-describing. Every result must include schema name and version.
- Discoverable. The CLI must provide a static list of commands and flags via `--help`.
- Scriptable paths. All outputs must be addressable via explicit paths or stdout.
- Safe defaults. Remote asset access is still opt-in and must be explicit in flags.
- Auditability. The CLI should log enough metadata to reconstruct the exact build.

Agent mode (recommended)
- `--json-only`: suppress human output entirely; JSON to stdout only.
- `--no-prompts`: disable any interactive prompts or confirmations.
- `--schema`: print the JSON schema for the requested command and exit.
- `--emit-manifest`: write a compiler input manifest derived from the CLI flags.
