# Ansible Role: Scriptorium Installs and configures [Scriptorium](https://gitea.maximumdirect.net/eric/scriptorium) from source on Ubuntu 26.04 (`x86_64` or `aarch64`). The role requires gathered facts and uses privilege escalation only for dependency installation and root-owned application state. ## Variables ```yaml scriptorium_version: v0.15.0 scriptorium_repository_url: https://gitea.maximumdirect.net/eric/scriptorium.git scriptorium_source_dir: /usr/local/src/scriptorium scriptorium_binary_path: /usr/local/bin/scriptorium scriptorium_manage_build_dependencies: true scriptorium_go_snap_channel: 1.26/stable scriptorium_go_binary: /snap/bin/go scriptorium_config_path: /usr/local/etc/scriptorium/config.yml scriptorium_config_owner: root scriptorium_config_group: root scriptorium_config_directory_mode: "0755" scriptorium_config_file_mode: "0644" scriptorium_configkit_imports: null scriptorium_prompt_dir: null scriptorium_profile_dir: null scriptorium_schema_dir: null scriptorium_server_addr: null scriptorium_server_artifact_root: null scriptorium_server_max_request_bytes: null scriptorium_server_max_artifact_bytes: null scriptorium_server_max_response_bytes: null scriptorium_defaults_render_format: null scriptorium_backends: null scriptorium_transient_retries: null ``` When `scriptorium_manage_build_dependencies` is `false`, Git and the executable selected by `scriptorium_go_binary` must already be available. Otherwise, the role installs Git with APT and the classic Go Snap from `scriptorium_go_snap_channel`. It checks out `scriptorium_version` authoritatively, builds `./cmd/scriptorium` directly to `scriptorium_binary_path`, and rebuilds only when that checkout changes or the binary is absent. The source tree is recursively owned by `root:root`; the binary is `root:root` mode `0755`. Every application configuration variable defaults to `null`, so it and any empty parent section are omitted and Scriptorium retains ownership of its built-in defaults. When no values are selected, the role writes `{}` to `scriptorium_config_path`. It manages that file and its parent directory with `scriptorium_config_owner`, `scriptorium_config_group`, `scriptorium_config_directory_mode`, and `scriptorium_config_file_mode`. The standalone defaults are `root:root`, directory mode `0755`, and file mode `0644`; composing roles may override this generic configuration interface. Non-null falsey values are retained. `scriptorium_backends` is the native mapping supplied by the caller; the role does not merge or rewrite it. For example, inventory can compose fragments in the ordinary way: ```yaml scriptorium_backends: "{{ scriptorium_local_backends | combine(scriptorium_remote_backends) }}" ``` Backend entries may name a credential environment variable through `api_key_env`; credential values themselves belong outside this role. The role does not install prompt, profile, or schema content and does not manage a service. `scriptorium_configkit_imports` accepts a list of native ConfigKit import mappings. Paths and globs are interpreted by Scriptorium relative to the configuration root; the caller supplies and owns the referenced files. For example, an inventory may select a caller-managed fragment: ```yaml scriptorium_configkit_imports: - path: fragments/server.yml scriptorium_transient_retries: 0 ``` Both settings are omitted when `null`. Setting `scriptorium_transient_retries` to `0` disables additional transient attempts; omission leaves the retry budget with Scriptorium and PromptKit. Leave these newer fields unset when selecting an older Scriptorium version that does not support them. ## Upgrading to v0.15.0 The intervening v0.14.0 release adopted ConfigKit. It rejects empty configuration files, unknown fields, multiple YAML documents, and YAML anchors or aliases. Use `{}` when no application settings are selected; the role already renders that document. See the tagged [configuration reference](https://gitea.maximumdirect.net/eric/scriptorium/src/tag/v0.15.0/docs/config.md) and [migration notes](https://gitea.maximumdirect.net/eric/scriptorium/src/tag/v0.14.0/docs/releases/v0.14.0.md) for the complete acceptance and precedence rules. ConfigKit imports are resolved relative to the selected configuration file's canonical directory. ConfigKit files under `overlays/` are selected by the application's `--config-overlay` flag; they are separate from PromptKit LLM profiles selected through profile settings and `profile_dir`. Application path *values* such as `prompt_dir` and `profile_dir` remain relative to the Scriptorium process working directory, even when declared in an import or overlay. This role only supplies import entries; callers own referenced files and runtime overlay selection. PromptKit now makes up to two additional attempts by default for eligible transient provider responses. `scriptorium_transient_retries` can change that application budget, while repair generations have separate budgets. Review provider call count and latency when upgrading; see the tagged [retry guidance](https://gitea.maximumdirect.net/eric/scriptorium/src/tag/v0.15.0/docs/config.md#credentials-and-outbound-behavior). The legacy `deepseek-3-2`, `deepseek-4-flash`, and `deepseek-4-pro` catalog profile IDs were removed without aliases; select a maintained profile when updating callers. Scriptorium v0.15.0's application source and binaries are distributed under GPL-3.0-or-later; its tagged [copyright](https://gitea.maximumdirect.net/eric/scriptorium/src/tag/v0.15.0/COPYRIGHT), [license](https://gitea.maximumdirect.net/eric/scriptorium/src/tag/v0.15.0/LICENSE), and [attribution notices](https://gitea.maximumdirect.net/eric/scriptorium/src/tag/v0.15.0/docs/oss/attribution.md) describe that grant and separately attributed material. The Ansible role's own [CC0 license](LICENSE) is unchanged. ## Example ```yaml - hosts: scriptorium_hosts roles: - role: ansible-role-scriptorium ``` ## Validation The repository-local integration suite installs its pinned collection and runs syntax checking and production-profile lint. It applies the default role, validates the managed application configuration with the native CLI, performs offline profile inspection, and requires clean repeated convergence. It also combines missing-binary recovery with a caller-supplied Go executable while dependency management is disabled. Representative configuration coverage checks null omission, intentional zero and false values, backend pass-through, native validation, and offline profile inspection. A caller-owned fragment exercises relative imports and explicit retry zero through native `config show`. The suite restores the default configuration during cleanup. These offline checks do not establish provider connectivity, service operation, or suite-level compatibility. ```sh tests/integration ```