From 0349682eb96e7a95d80cd218a08853383c2c28e2 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Mon, 7 Sep 2026 17:08:09 +0000 Subject: [PATCH] Initial commit --- .gitignore | 16 +++ AGENTS.md | 77 +++++++++++++ README.md | 26 +++++ docs/decisions/README.md | 8 ++ docs/plans/template.md | 37 +++++++ docs/roadmap/mvp.md | 229 +++++++++++++++++++++++++++++++++++++++ docs/status.md | 26 +++++ scripts/status | 54 +++++++++ workspace.yml | 88 +++++++++++++++ 9 files changed, 561 insertions(+) create mode 100644 .gitignore create mode 100644 AGENTS.md create mode 100644 README.md create mode 100644 docs/decisions/README.md create mode 100644 docs/plans/template.md create mode 100644 docs/roadmap/mvp.md create mode 100644 docs/status.md create mode 100755 scripts/status create mode 100644 workspace.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8209fa9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +# Independent repositories managed within this workspace. +/ansible-collection-dnd/ +/ansible-role-dnd-pipeline/ +/ansible-role-audita/ +/ansible-role-narratio/ +/ansible-role-notarius/ +/ansible-role-scriptorium/ +/ansible-role-seriatim/ +/rakestraw-ansible/ + +# Local tool state. +/.codebase-memory/ +/.idea/ +/.vscode/ +*.swp +*~ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..caebb50 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,77 @@ +# Workspace Instructions + +## Purpose + +This is the control repository for the Ansible roles and collection that +deploy the D&D transcript-processing pipeline. It owns cross-repository plans, +decisions, status, and workspace tooling. Each application and Ansible project +is an independent Git repository. + +## Repository Map + +Repositories inside this directory: + +- `ansible-collection-dnd`: the `rakestraw.dnd` collection that bundles and + distributes the pipeline suite. +- `ansible-role-dnd-pipeline`: independent source repository for the + suite-level role exposed by the collection as `rakestraw.dnd.pipeline`. +- `ansible-role-{narratio,notarius,audita,seriatim,scriptorium}`: standalone + application roles. +- `rakestraw-ansible`: working deployment repository containing the + `pipeline_dnd` proof of concept; treat it as read-only reference unless the + task explicitly includes it. + +Relevant upstream repositories are siblings of this directory: + +- `../{narratio,notarius,audita,seriatim,scriptorium}`: application source and + authoritative application contracts. +- `../narratio-prompts`: pipeline prompt-library content. + +Use `workspace.yml` as the complete machine-readable inventory of paths and +remotes. + +## Sources of Truth + +- `docs/roadmap/mvp.md`: settled MVP scope, architecture, and open design work. +- `docs/status.md`: current cross-repository progress and next work. +- `docs/decisions/`: durable rationale for significant architectural choices. +- `docs/plans/`: temporary implementation plans for substantial work. +- Application repositories: CLI, configuration, build, and integration + contracts. +- Individual Ansible repositories: implementation and repository-local tests. + +Do not duplicate an application contract in workspace documentation when a +link and a concise deployment consequence are sufficient. + +## Working Conventions + +- Confirm the target repository before editing; never treat this directory as + a monorepo. +- Inspect the relevant upstream application before designing or changing its + Ansible role. +- Keep standalone application roles independently usable. Cross-application + policy belongs in `ansible-role-dnd-pipeline` and is exposed to consumers as + `rakestraw.dnd.pipeline`. +- Use `ansible.builtin` modules directly unless a concrete requirement justifies + another dependency. +- Prefer codebase-memory graph tools for code discovery. Use text/file search + for documentation, configuration, literals, or when the graph is + insufficient. +- Preserve unrelated and pre-existing working-tree changes in every + repository. +- Never place credentials or secret values in plans, examples, inventory, or + tests. +- Validate changes in the repository that owns them and report the commands + run. + +## Planning and Progress + +- Update `docs/roadmap/mvp.md` when a design question becomes a settled scope + or architecture decision. +- Update `docs/status.md` when cross-repository work starts, becomes blocked, + or is completed. Completed items must point to concrete evidence. +- Create a file in `docs/plans/` only for work spanning multiple meaningful + steps or repositories. Remove or archive stale execution detail after the + work is complete; durable rationale belongs in `docs/decisions/`. +- Use the status values `proposed`, `ready`, `in_progress`, `blocked`, `done`, + and `deferred`. diff --git a/README.md b/README.md new file mode 100644 index 0000000..627355a --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# Ansible D&D Development Workspace + +This repository coordinates development of the Ansible roles and collection +used to deploy the D&D transcript-processing pipeline. The application and +Ansible projects remain independent Git repositories; this repository tracks +only workspace documentation, planning, and shared development utilities. + +## Start Here + +- [`AGENTS.md`](AGENTS.md) describes repository boundaries and working + conventions. +- [`workspace.yml`](workspace.yml) inventories the repositories used during + development. +- [`docs/roadmap/mvp.md`](docs/roadmap/mvp.md) records settled MVP decisions + and open design work. +- [`docs/status.md`](docs/status.md) records current cross-repository progress. + +Run `./scripts/status` to see the branch and working-tree state of every +repository in the workspace manifest. + +## Repository Boundaries + +The directories ignored by this repository are intentional nested Git working +trees. Run Git commands from within the repository whose history should be +affected. A commit in this control repository never includes changes from an +application, role, collection, or proof-of-concept repository. diff --git a/docs/decisions/README.md b/docs/decisions/README.md new file mode 100644 index 0000000..13ebe65 --- /dev/null +++ b/docs/decisions/README.md @@ -0,0 +1,8 @@ +# Architecture Decisions + +Use this directory for concise records of significant decisions whose +rationale should remain visible after implementation plans and roadmap details +change. Number records sequentially, for example +`0001-application-and-suite-role-boundaries.md`. + +Do not create a decision record for routine implementation choices. diff --git a/docs/plans/template.md b/docs/plans/template.md new file mode 100644 index 0000000..53c213d --- /dev/null +++ b/docs/plans/template.md @@ -0,0 +1,37 @@ +# Plan: + +Status: proposed + +## Goal + +State the outcome this plan must achieve. + +## Non-goals + +List adjacent work that is intentionally outside this plan. + +## Owning Repositories + +List every repository this work may change and what each repository owns. + +## Dependencies and Settled Decisions + +Link applicable roadmap sections and decision records. Record prerequisites +that constrain implementation. + +## Acceptance Criteria + +- Define observable conditions for completion. + +## Implementation Sequence + +1. Describe the first independently verifiable step. + +## Validation + +List the commands, tests, or inspections that demonstrate completion. + +## Progress + +Keep only concise current state and blockers here. Git history should preserve +obsolete execution detail. diff --git a/docs/roadmap/mvp.md b/docs/roadmap/mvp.md new file mode 100644 index 0000000..e325620 --- /dev/null +++ b/docs/roadmap/mvp.md @@ -0,0 +1,229 @@ +# Initial Roadmap + +## Purpose + +This document records the decisions that define the initial MVP of the +Narratio Ansible roles and D&D collection. It is the durable reference for +choices that have been settled while the suite is being designed. Open +questions and later ideas should remain clearly distinguished from these +locked decisions. + +## MVP Goal + +Build independently usable Ansible roles for the five Narratio applications +and compose them through a suite-level role developed in its own repository. +The `rakestraw.dnd` collection exposes that role as `rakestraw.dnd.pipeline`. +The suite-level role installs and configures the complete D&D transcript +processing pipeline on a single supported host. Human operators invoke +Narratio commands directly to process D&D session recordings and produce +transcripts and related artifacts. + +## Locked Decisions + +### Supported platform + +- The MVP supports Ubuntu 26.04. +- The MVP supports both `amd64` and `arm64` hosts. +- The roles should be structured so support for additional distributions and + releases can be added after the MVP without redesigning them. + +### Managed applications + +The suite-level role installs and configures all five applications in the +Narratio suite: + +- Narratio +- Notarius +- Audita +- Seriatim +- Scriptorium + +WhisperX is an external HTTP service consumed by Narratio. Deploying or +managing the WhisperX service is outside the MVP scope, although the Narratio +role will manage the native configuration needed to connect to it. + +### Application installation + +- The MVP builds all five applications from their official Git repositories on + the target host. This consistent model avoids making the suite depend on + every upstream project publishing prebuilt artifacts. +- Released roles build an explicitly selected application release tag. + Development may override the selected revision with a branch or commit. +- Source checkouts reside at `/usr/local/src/<app>` and are owned by `root`. +- Roles build into a staging location, validate the result, and then install + the binary at `/usr/local/bin/<app>` with `root:root` ownership and mode + `0755`. A failed build must not replace a working installed binary. +- Builds use the application repository's own build contract, including any + application-specific version-injection linker flags. The common baseline is + `GOWORK=off`, `GOTOOLCHAIN=local`, `CGO_ENABLED=0`, and `-trimpath`. +- Build state must account for the checked-out commit, Go toolchain, and build + arguments so that roles rebuild when a relevant input changes rather than + relying only on the existence of the installed binary. +- Each application role exposes variables for its repository, selected + version or revision, source directory, binary path, and build settings. + +### Go toolchain + +- Go is installed on the target host through the official Snap package using + classic confinement. +- The Snap channel is configurable and should track an explicit Go minor + release channel, rather than unconstrained `latest/stable`, when that channel + is available for the required Go version. +- The installed Go toolchain must satisfy the application's `go.mod` + requirement. Builds set `GOTOOLCHAIN=local` so provisioning does not silently + download a different toolchain. +- Each standalone application role can install its own build prerequisites and + exposes a variable allowing that behavior to be disabled. Repeating an + idempotent prerequisite task across the small roles is preferable to adding + a shared-role dependency during the MVP. + +### Role and collection architecture + +- All Ansible roles and collections in this suite use the root namespace + `rakestraw`. +- Each of the five managed applications has a separate, targeted Ansible role + in its own repository. +- Each application role owns installation and native configuration of that + application. +- The Narratio application role remains application-specific even though + Narratio is the runtime orchestrator for the full pipeline. +- The suite-level role is developed in the standalone + `ansible-role-dnd-pipeline` repository rather than directly in the collection + repository. +- The application and pipeline roles are independently developed, tested, + versioned, and released. An application-specific change therefore requires a + release of that application's role without requiring changes or releases in + unrelated role repositories. +- The collection is named `rakestraw.dnd`. +- The collection bundles and exposes the independently developed suite-level + role as `rakestraw.dnd.pipeline`, providing one opinionated interface for + consumers. +- The pipeline role owns compatible application-version selection, + cross-application configuration, D&D campaign deployment, prompt-library + deployment, operator access, the pipeline-wide secret-delivery policy, and + end-to-end validation. +- The pipeline role uses the Git-hosted standalone application roles as + dependencies. This is an intentional choice for the controlled project + environment despite the additional repository and dependency structure and + Ansible's preference for published collection dependencies. +- Consumer installation may require a dependency manifest or bootstrap step + that installs both the collection and its standalone role dependencies; a + plain collection installation is not assumed to resolve arbitrary Git role + dependencies by itself. + +This design keeps repository ownership and change blast radius aligned with +the independently released applications while retaining a single opinionated +installation interface for the complete suite. It avoids forcing each small +role to become its own published collection and avoids coupling unrelated +application-role releases in one source repository. + +### Ansible dependencies and task structure + +- The standalone application roles are self-contained and use + `ansible.builtin` modules directly. +- The roles do not depend on the private + `maximumdirect.core.ansible_role_loader` role used by the proof of concept. +- Platform-specific task selection may be added later using ordinary Ansible + includes when another supported platform creates a concrete need. +- Small amounts of repeated prerequisite or installation logic are acceptable + during the MVP. A shared helper role or collection plugin should be + introduced only if substantial, stable shared behavior emerges. + +### Dependency and release reproducibility + +- Development dependency manifests may temporarily refer to branches or + commits while the roles are changing rapidly. +- Every released dependency manifest must pin each Git-hosted role dependency + to an immutable role release tag. +- The collection release is the compatibility record for the exact set of + application-role versions it composes. +- Collection integration tests must install and exercise the same pinned role + combination delivered to consumers, starting from an environment in which + the dependencies are not already installed. +- Updating one application role in the suite requires updating its pinned + version in the collection, validating the assembled suite, and releasing a + new collection version. Unrelated application-role repositories remain + unchanged. + +### Prompt library + +- The pipeline role installs Narratio's PromptKit-compatible prompt library + from the `narratio-prompts` Git repository. The Scriptorium role owns its + native prompt, profile, and schema directory configuration, while the + pipeline role owns populating those locations with suite integration + content. +- The upstream repository is + `https://gitea.maximumdirect.net/eric/narratio-prompts`. +- For the MVP, the pipeline role tracks and pulls the latest upstream commit. +- Pinning the prompt library to a version or release is deferred until the + upstream repository provides versioned releases. + +### Accounts, ownership, and operator access + +- The roles create a dedicated `narratio` user and `narratio` group as needed. +- The `narratio` account owns Narratio's writable runtime directories. +- Application source trees and installed binaries are owned by `root` and are + not writable by operators or the runtime account. +- Ordinary human users run `narratio run` and other Narratio commands directly. +- Those operators receive the required access by membership in the `narratio` + group. +- Managed configuration should be owned by `root`, readable by the `narratio` + group where needed, and remain under Ansible control rather than being + routinely edited by operators on the host. +- Shared runtime directories must grant the `narratio` group the write access + needed for direct operator invocations. + +### Execution model + +- Narratio is installed as a command-line application, not a persistent + daemon. +- Scheduling Narratio invocations through cron, systemd timers, or another + automation mechanism is not currently part of the locked MVP scope. + +## Expected Filesystem Areas + +The roles align with the applications' established default locations unless a +later design decision changes them: + +- `/usr/local/etc/narratio` for Narratio configuration +- `/usr/local/etc/audita/config.yml` for Audita configuration +- `/usr/local/etc/notarius/config.yml` for Notarius configuration +- `/usr/local/etc/scriptorium/config.yml` for Scriptorium configuration +- `/usr/local/share/narratio/campaigns` for version-controlled campaign data +- `/usr/local/src/<app>` for root-owned application source checkouts +- `/usr/local/bin/<app>` for root-owned application binaries +- `/var/lib/narratio` for durable workspace and session state +- `/var/spool/narratio` for spool data +- `/var/cache/narratio` for cached data + +The Narratio role creates and configures the campaign root; the pipeline role +populates it from the selected campaign source. `/usr/local/share` assumes Git +is authoritative and operators do not edit campaign content directly on the +managed host. The exact prompt-library checkout and installed-content paths +remain to be designed. + +## Deferred Beyond the MVP + +- Linux distributions and Ubuntu releases other than Ubuntu 26.04 +- Architectures other than `amd64` and `arm64` +- Installation from prebuilt application release artifacts +- Deploying or managing WhisperX +- Versioned Narratio prompt-library releases and pinning +- A role-managed scheduler or persistent Narratio service + +## Design Work Still Open + +The following areas require investigation and decisions before implementation: + +- Exact application repository URLs, default release tags, build commands, + version-injection flags, and validation commands +- Standalone role Galaxy names and the dependency-manifest/bootstrap layout +- The mechanism used to incorporate the independently developed pipeline role + into collection releases +- Configuration contracts and filesystem requirements of Notarius, Audita, + Seriatim, and Scriptorium +- The prompt-library destination and its integration with Scriptorium +- Secret injection and storage +- Operator-group membership variables and directory permission details +- Upgrade, downgrade, and removal behavior +- Ansible dependency, validation, and test strategy diff --git a/docs/status.md b/docs/status.md new file mode 100644 index 0000000..0b32856 --- /dev/null +++ b/docs/status.md @@ -0,0 +1,26 @@ +# Workspace Status + +Last updated: 2026-09-07 + +Current milestone: MVP design and workspace foundation + +Current focus: Select the next open design topic before role implementation. + +| ID | Deliverable | Owner | State | Evidence or next step | +| --- | --- | --- | --- | --- | +| M0-01 | Workspace control repository | workspace | done | Root repository and `workspace.yml` created | +| M0-02 | Workspace conventions | workspace | done | Root `AGENTS.md` created | +| M0-03 | Tracked MVP roadmap | workspace | done | `docs/roadmap/mvp.md` established | +| M0-04 | Aggregate repository status | workspace | done | `scripts/status` created | +| M0-05 | Suite-level role repository | ansible-role-dnd-pipeline | done | Repository created and added to `workspace.yml` | +| M1-01 | Remaining MVP design decisions | workspace | ready | Select the next item from the roadmap | +| M1-02 | Standalone application roles | role repositories | proposed | Begin after relevant interfaces are settled | +| M1-03 | Suite-level pipeline role | ansible-role-dnd-pipeline | proposed | Begin after standalone role interfaces stabilize | +| M1-04 | Collection assembly | ansible-collection-dnd | proposed | Select and implement the pipeline-role incorporation mechanism | + +## Updating This File + +Use `proposed`, `ready`, `in_progress`, `blocked`, `done`, or `deferred` for +state. Keep this dashboard concise. Link completed implementation work to the +owning repository's file, commit, test, or release rather than copying detailed +implementation notes here. diff --git a/scripts/status b/scripts/status new file mode 100755 index 0000000..aaf147b --- /dev/null +++ b/scripts/status @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +set -u + +workspace_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +manifest="$workspace_root/workspace.yml" + +if [[ ! -f "$manifest" ]]; then + printf 'workspace manifest not found: %s\n' "$manifest" >&2 + exit 1 +fi + +printf '%-30s %-18s %-7s %s\n' REPOSITORY BRANCH STATE UPSTREAM + +while IFS= read -r relative_path; do + if [[ "$relative_path" == "." ]]; then + repository_name=workspace + repository_path=$workspace_root + else + repository_name=$(basename "$relative_path") + repository_path="$workspace_root/$relative_path" + fi + + if [[ ! -d "$repository_path/.git" ]]; then + printf '%-30s %-18s %-7s %s\n' "$repository_name" - missing "$relative_path" + continue + fi + + branch=$(git -C "$repository_path" branch --show-current) + if [[ -z "$branch" ]]; then + branch="detached@$(git -C "$repository_path" rev-parse --short HEAD)" + fi + + if [[ -n $(git -C "$repository_path" status --porcelain) ]]; then + state=dirty + else + state=clean + fi + + upstream=$(git -C "$repository_path" rev-parse \ + --abbrev-ref --symbolic-full-name '@{upstream}' 2>/dev/null || true) + if [[ -n "$upstream" ]]; then + read -r behind ahead < <(git -C "$repository_path" rev-list \ + --left-right --count "$upstream...HEAD") + tracking="ahead=$ahead behind=$behind ($upstream)" + else + tracking=untracked + fi + + printf '%-30s %-18s %-7s %s\n' \ + "$repository_name" "$branch" "$state" "$tracking" +done < <( + printf '.\n' + awk '$1 == "path:" { print $2 }' "$manifest" +) diff --git a/workspace.yml b/workspace.yml new file mode 100644 index 0000000..899b2a9 --- /dev/null +++ b/workspace.yml @@ -0,0 +1,88 @@ +--- +name: ansible-workspace-dnd +remote: https://gitea.maximumdirect.net/eric/ansible-workspace-dnd.git + +repositories: + - name: ansible-collection-dnd + path: ansible-collection-dnd + remote: https://gitea.maximumdirect.net/eric/ansible-collection-dnd.git + category: ansible-collection + purpose: Bundles and distributes the rakestraw.dnd pipeline suite + + - name: ansible-role-dnd-pipeline + path: ansible-role-dnd-pipeline + remote: https://gitea.maximumdirect.net/eric/ansible-role-dnd-pipeline.git + category: ansible-role + purpose: Develops the suite-level role exposed as rakestraw.dnd.pipeline + + - name: ansible-role-narratio + path: ansible-role-narratio + remote: https://gitea.maximumdirect.net/eric/ansible-role-narratio.git + category: ansible-role + purpose: Installs and configures Narratio + + - name: ansible-role-notarius + path: ansible-role-notarius + remote: https://gitea.maximumdirect.net/eric/ansible-role-notarius.git + category: ansible-role + purpose: Installs and configures Notarius + + - name: ansible-role-audita + path: ansible-role-audita + remote: https://gitea.maximumdirect.net/eric/ansible-role-audita.git + category: ansible-role + purpose: Installs and configures Audita + + - name: ansible-role-seriatim + path: ansible-role-seriatim + remote: https://gitea.maximumdirect.net/eric/ansible-role-seriatim.git + category: ansible-role + purpose: Installs and configures Seriatim + + - name: ansible-role-scriptorium + path: ansible-role-scriptorium + remote: https://gitea.maximumdirect.net/eric/ansible-role-scriptorium.git + category: ansible-role + purpose: Installs and configures Scriptorium + + - name: rakestraw-ansible + path: rakestraw-ansible + remote: https://gitea.maximumdirect.net/eric/ansible.git + category: reference + purpose: Existing deployment repository and pipeline_dnd proof of concept + + - name: narratio + path: ../narratio + remote: https://gitea.maximumdirect.net/eric/narratio.git + category: application + purpose: Narratio source and authoritative application contracts + + - name: notarius + path: ../notarius + remote: https://gitea.maximumdirect.net/eric/notarius.git + category: application + purpose: Notarius source and authoritative application contracts + + - name: audita + path: ../audita + remote: https://gitea.maximumdirect.net/eric/audita.git + category: application + purpose: Audita source and authoritative application contracts + + - name: seriatim + path: ../seriatim + remote: https://gitea.maximumdirect.net/eric/seriatim.git + category: application + purpose: Seriatim source and authoritative application contracts + + - name: scriptorium + path: ../scriptorium + remote: https://gitea.maximumdirect.net/eric/scriptorium.git + category: application + purpose: Scriptorium source and authoritative application contracts + + - name: narratio-prompts + path: ../narratio-prompts + remote: https://gitea.maximumdirect.net/eric/narratio-prompts.git + category: content + purpose: PromptKit-compatible pipeline prompt library