---
date: 2026-03-28
topic: "Rewrite @ansible package for npm publish"
status: draft
---

## Problem Statement

We currently have an example `ansible/` directory (not an npm-scoped `@ansible/` package) that demonstrates deployment and packaging for a different project. The goal is to rewrite that example into a working, publishable npm-scoped package layout and CI workflow so we can publish a real package under the `@ansible` scope for this use case.

**Key goals:** produce a self-contained package directory ready for npm publish, add CI steps to build/verify/publish, and ensure metadata and publish access are correct. Also correct author attribution to **Sven**.

## Constraints

- Keep changes minimal and isolated under `packages/@ansible/<package-name>` (or `@ansible/` top-level directory) so repo layout remains monorepo-friendly.
- Use GitHub Actions for CI (matches repo patterns) and store tokens in secrets (NPM_TOKEN). Do not expose secrets in logs.
- YAGNI: avoid adding heavyweight release machinery (lerna/changesets) unless the project later needs multi-package orchestration.
- No destructive changes to existing deployment pipelines.

## Approach (chosen)

I'm choosing a targeted, pragmatic approach: create a single-package layout that mirrors npm conventions and add a guarded GitHub Actions publish workflow. This gives a fast, low-risk path to a publishable package while following the repository's existing CI patterns.

**Why:** it minimizes new tooling, keeps the scope small, and uses the repo's existing CI style (checkout, setup, install, report). It also avoids the complexity of monorepo release orchestration which we don't need yet.

## Alternatives considered

1. Full monorepo release tooling (changesets/lerna)
   - Pros: scales to many packages, automates changelogs and versioning
   - Cons: more setup and maintenance; overkill for a single package example

2. Publish from root with ad-hoc scripts
   - Pros: quickest to get something published
   - Cons: fragile, error-prone in multi-package repos and easy to accidentally publish wrong content

I rejected (1) and (2) in favor of the chosen approach because it balances effort and correctness.

## Architecture

**High-level:** a new package directory contains package.json + README + src + tests. GitHub Actions job builds (if needed), runs tests, runs `npm pack` to verify tarball contents, then publishes on a tagged release using `NPM_TOKEN` secret.

- **Package directory**: packages/@ansible/<name>/
  - package.json (name: "@ansible/<name>", version, publishConfig.access: "public")
  - README.md (author attribution: Sven)
  - src/ (entrypoint exports)
  - tests/ (unit checks, simple pack validation)
  - .npmignore or package.json files field to control published files

- **CI workflow**: .github/workflows/publish-ansible-<name>.yml
  - triggers: push tag matching v*, or manual workflow dispatch
  - steps: checkout, setup-node, install, test, npm pack inspect, publish (only on tag and with NPM_TOKEN)

## Components and responsibilities

- **package.json**: authoritative package metadata. Must include: name, version, description, main/module, files (or .npmignore), license, repository, author (Sven), and **publishConfig.access = "public"** for a public org-scoped package.

- **README.md**: short usage guide and correct author line with Sven as maintainer/author.

- **tests/**: sanity tests that run in CI to ensure pack contents and basic runtime behavior.

- **.github/workflows/publish-ansible-<name>.yml**: build/verify/publish pipeline. Writes .npmrc with token only at publish step and removes it immediately after.

- **.npmrc in CI (ephemeral)**: created from secret, not checked in. Use: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc

## Data Flow

1. Developer updates package files and bumps version (or tags a version).
2. Developer creates a git tag vX.Y.Z and pushes it.
3. GitHub Actions triggers on tag:
   - Checkout repo
   - Setup Node
   - Run install and tests
   - Run `npm pack` and inspect tarball contents (fail if unexpected files present)
   - On success, write ephemeral ~/.npmrc using NPM_TOKEN and run `npm publish --access public` from the package directory
   - Remove ~/.npmrc
4. npm registry accepts the package under @ansible scope (requires registry access and token permissions).

## Error handling strategy

- **CI errors**: fail fast. Test/build/pack steps must pass before any ephemeral auth is written.
- **Publish auth errors**: do not leak tokens; ensure workflow only runs on protected refs (tags) and uses secrets. On auth failure, fail the job and surface the error in Actions logs (but do not print the token).
- **Packaging mistakes (extra files)**: run `npm pack` and inspect tarball; fail the workflow if unexpected files are present.
- **Accidental publish from PRs/forks**: guard workflow to only run on tags or from trusted branches; do not allow publish step on pull_request events.

## Testing strategy

- **Local dev:** run unit tests and `npm pack` locally to validate what would be published.
- **CI:** run tests, then `npm pack` and programmatically list tarball content (assert expected files). Add a tiny test that asserts package.json fields (name, version, publishConfig) are present.
- **Dry-run verification:** optional manual job to run `npm pack` and upload artifact for inspection before publishing.

## Deliverables (concrete edits)

1. Create package skeleton at `packages/@ansible/<name>/` with package.json, README.md (author: Sven), src/, tests/, and .npmignore or files field.
2. Add `scripts` in package.json: `test`, `prepublish:verify` (runs pack inspection).
3. Add GitHub Actions workflow `.github/workflows/publish-ansible-<name>.yml` (tag-triggered) that performs build/test/pack/publish and uses `secrets.NPM_TOKEN`.
4. Add a CI test `tests/test_package_json.js` or similar that asserts package.json readiness.
5. Document publish steps in the package README and top-level CONTRIBUTING or docs if desired.

## Open Questions

- What do you want the package name to be under the @ansible scope? (I'll assume `@ansible/example` and proceed; changeable later.)
- Do you want the package to be public or private? (I assumed **public**.)
- Do you prefer versioning via git tags (recommended) or manual package.json bumps?

I'm proceeding to create the design doc file in the repo and commit it. Interrupt if you want any changes to the scope above before I continue to the implementation planning step.
