# @prata.ma/anvil

User-facing Anvil library and CLI facade for governed workspaces.

## Overview

`@prata.ma/anvil` is the main package boundary for Anvil itself. It owns the `anvil.yaml` manifest contract, schema-backed validation, governed project and global sync behavior, catalog block resolution, lock handling, Forge and Smith helper exports, and the `anvil` / `anv` CLI surface that exposes those capabilities.

Within the workspace, this package is the top-level Anvil boundary for user-facing governance behavior plus shared Forge and Smith helper exports. Consumers should depend on `@prata.ma/anvil` for manifest loading, sync orchestration, schema access, the supported CLI, and the supported root helper exports instead of reaching into internal command modules or block-deployment helpers directly.

Release remains Changesets-based. The repo now uses generated package fragments at `@state/releases/changelog.md`, optional global intent at `@state/releases/global.md`, one curated repo-level summary at `@state/releases/active.md`, and one archived copy under `@state/releases/history/` after publish.

## Installation

Install the package from npm when using Anvil outside this monorepo.

### npm

```json
{
  "dependencies": {
    "@prata.ma/anvil": "^0.0.0"
  }
}
```

## Usage

`@prata.ma/anvil` supports both library-style usage and the packaged CLI surface.

### Library

```ts
import {
  anvilSync,
  getAnvilSchemaPath,
  loadAnvilManifest,
  validateAnvilManifest,
} from '@prata.ma/anvil'

const loadedManifest = loadAnvilManifest(process.cwd())

if (!loadedManifest) {
  throw new Error('No anvil.yaml found')
}

const validation = validateAnvilManifest(loadedManifest.manifest)
if (!validation.valid) {
  throw new Error(validation.issues.map(issue => issue.message).join('; '))
}

console.log(getAnvilSchemaPath())
await anvilSync(loadedManifest)
```

### CLI

```bash
anvil status # Show workspace status
anvil issue list # List HQ Rhythm issues
anvil issue create --title "Add issue subcommands" --kind Feature --workspace Anvil --problem "Manual issue handling" --intent "Add a first CLI slice"
anvil issue update ISS-7 --level Beat --stage Beat/Execute
anvil manifest validate # Validate anvil.yaml
anvil sync # Run governed project sync
anvil sync --global # Run standalone global sync
anvil sync --prune # Remove undeclared tool-target content, then sync
anvil release check # Validate release readiness
anvil release prepare # Apply versioning and scaffold @state/releases/active.md
anvil release publish # Publish packages and finalize the repo release
anvil release status # Show current release status
anvil hub query "status" # Query configured hub context
anv # Launch the interactive shortcut when running in a TTY
```

### Patterns

The package is typically used in one of two ways:

- as a library facade for manifest parsing, root resolution, recipe loading, and sync orchestration
- as the `anvil` CLI for workspace-facing command flows such as `catalog`, `hub`, `issue`, `manifest`, `plugin`, `release`, `status`, and `sync`

Internally, package command modules route shared prompt, spinner, and log behavior through `src/lib/cli.ts` and its `ux` facade instead of importing `@clack/prompts` ad hoc at each call site.

## API

`@prata.ma/anvil` exposes a documented library surface and two CLI binaries.

### Exports

- `@prata.ma/anvil` - root library facade
- `@prata.ma/anvil/changelog` - packaged Changesets changelog module for repos with a known `<owner>/<repo>` slug
- `@prata.ma/anvil/manifest` - manifest loading, parsing, validation, and root-resolution helpers
- `@prata.ma/anvil/schema` - packaged `anvil.yaml` JSON schema
- root exports from `src/index.ts`, including manifest helpers, recipe helpers, sync helpers, Forge product-discovery helpers, Smith layout helpers, and `getAnvilPackageStatus()`

### Commands

The package ships two binaries:

- `anvil` - standard CLI entrypoint
- `anv` - shorthand launcher entrypoint

Top-level CLI command areas currently include catalog, hub, issue, manifest, plugin, release, status, and sync.

#### Issues

```bash
anvil issue list
anvil issue list --workspace Anvil --query rhythm
anvil issue create --title "Add issue subcommands" --kind Feature --workspace Anvil --problem "Manual issue handling" --intent "Add a first CLI slice"
anvil issue update ISS-7 --level Beat --stage Beat/Execute
anvil issue update 356c08fe-bfbd-804a-b156-f90b4ddc56fc --kind Feature --problem "Normalize this row"
```

`anvil issue` is the first HQ-focused issue operator slice in this package:

- it reads the live Notion HQ root from `hub.document.rootId` in `anvil.yaml`
- it manages the shared `Issues` database using Rhythm/HQ field mapping instead of treating Notion as raw freeform CRUD
- `list` is the read/search surface for v1, with `--query` plus explicit lifecycle filters
- `update` accepts either a canonical HQ id such as `ISS-7` or a Notion page id
- existing partial intake rows remain visible and can be normalized through `update`

#### Workspace

```bash
anvil status
anvil sync
anvil sync --global
anvil sync --prune
```

#### Release

```bash
anvil release check
anvil release prepare
anvil release publish
anvil release status
```

The normal release workflow is Changesets-based:

- `pnpm changeset` authors the intended package version changes
- when a repo uses the packaged custom changelog surface, configure `.changeset/config.json` with `@prata.ma/anvil/changelog` plus a known GitHub repo slug
- `anvil release check` validates release readiness through Turbo-backed package and block-package tasks
- `anvil release prepare` applies version bumps, updates package changelogs, generates `@state/releases/changelog.md`, and scaffolds `@state/releases/active.md`
- review `@state/releases/global.md`, `@state/releases/changelog.md`, and compose `@state/releases/active.md`, especially `## Highlights` and `## Changelog`
- commit the prepared release changes
- `anvil release publish` publishes public packages, creates the coordinated GitHub Release from `@state/releases/active.md`, archives it to `@state/releases/history/`, and deletes `active.md`, `global.md`, and `changelog.md`

Repo-only releases are also supported by default:

- if `anvil release prepare` finds no package version changes, it still writes `@state/releases/changelog.md` and scaffolds `@state/releases/active.md` as a repo-only release summary
- `anvil release publish` skips package publishing for that case and still finalizes the coordinated repo tag and GitHub Release

#### Manifest

```bash
anvil manifest validate
```

#### Plugins

```bash
anvil plugin add <source>
anvil plugin list
anvil plugin remove <name>
```

#### Catalog And Hub

```bash
anvil catalog review
anvil catalog block check .
anvil catalog block sync .
anvil catalog block apply .
anvil hub pull
anvil hub query <text>
anvil hub status
anvil hub sync --product
anvil hub sync --state
anvil hub sync --system
```

### Configuration

- `anvil.yaml` is the primary workspace manifest consumed by the package.
- `@prata.ma/anvil/schema` and `getAnvilSchemaPath()` expose the schema contract for that manifest.
- `anvil issue` currently relies on `hub.document.provider: notion` plus the live HQ `hub.document.rootId` to discover the shared `Issues`, `Workspaces`, `Products`, and optional `Instances` tables.
- `anvilSync()` materializes governed content into `.anvil/` and generated compatibility outputs.
- Active and finalized repo release summaries live under `@state/releases/`.
- Catalog agents are now authored as one markdown file at `content/agents/<name>.md`, staged into `.anvil/agents`, and rendered into tool-specific agent targets for OpenCode, Claude, Cursor, and Codex.
- The CLI `anvil sync` command owns the final enriched project lock snapshot after external manifest-backed skills and plugins are resolved.
- `anvil sync --global` routes the same sync command through the standalone global Anvil root under `~/.config/anvil/`.
- `anvil sync --prune` removes undeclared content from the agreed tool targets before sync after one grouped confirmation prompt, and aborts if that prompt is declined or cancelled.
- Project and global `anvil-lock.yaml` files are managed sync snapshots for provenance and ownership diagnostics, while deployed `metadata.anvil` markers remain the authoritative cleanup signal.
- Project and global sync now print the same `Deployed`, `Skipped`, and `Undeclared` summary surface, with conservative cleanup still preserving unmanaged deployed items.
- Lock snapshots now include deterministic instruction-budget metrics: top-level `summary` plus per-entry `lines`, `chars`, and `tokens` for managed agents, rules, commands, references, skills, and block rollups.
- Root-generated lock entries use synthetic managed refs such as `anvil:root-agents` and `anvil:root-agents-override` instead of filename-shaped keys.

## Development

Use the package-local scripts while working in `@packages/anvil`, and keep user-facing behavior routed through the documented facade and command layers instead of scattering it across unrelated packages.

This package participates in the repo's Changesets, npm publish, and GitHub Release automation through canonical Turbo tasks. `anvil release check` orchestrates package `build`, `lint`, `test`, and `test:type` tasks plus block package `lint` and `test` tasks so repeated release checks can reuse Turbo cache.

### Commands

```bash
pnpm --filter @prata.ma/anvil build
pnpm --filter @prata.ma/anvil lint
pnpm --filter @prata.ma/anvil test
pnpm --filter @prata.ma/anvil test:type
pnpm anvil release check
```

### Testing

The current Vitest coverage exercises manifest parsing and validation, block deployment, sync behavior, installer and lock helpers, live one-file agent deployment, project/global Codex parity, Forge product discovery, Smith layout helpers, the new Notion-backed issue helper layer, and representative CLI command flows such as `issue create`, `issue list`, `issue update`, release checks, and sync.

### Conventions

- Keep the CLI layer thin: command modules should delegate real behavior into importable library code.
- Keep shared command UX behavior centralized in `src/lib/cli.ts` through the internal `ux` facade.
- Preserve `@prata.ma/anvil` as the supported root package for workspace governance plus public Forge and Smith helper exports.
- Keep manifest and sync behavior deterministic because generated governance outputs depend on it.
- Treat internal command modules and `src/lib/*` helpers as implementation details unless they are explicitly exported.
- Keep lock snapshots and deployed markers aligned, but do not let lock state reclaim primary cleanup authority from `metadata.anvil`.
- Keep lock summaries aggregated from leaf instruction-bearing entries so block rollups do not double count the same content.
- Keep `anvilSync()` focused on managed deployment work; let the CLI sync command own the final project lock snapshot when external declarations are involved.

## Status

This package is active and central to the current workspace model.

### Maturity

`@prata.ma/anvil` is active for workspace dogfooding and public-package preparation.

### Scope

The package currently supports manifest loading and validation, schema access, governed project and global sync, block deployment, catalog tooling, plugin management, live HQ issue management for the shared Notion `Issues` database, Forge product discovery and naming helpers, Smith layout and naming helpers, and the main Anvil CLI facade. It is the supported user-facing package boundary for workspace governance operations.

## Notes

- This package is published as `@prata.ma/anvil`, and release validation now runs through Turbo-backed canonical tasks consumed by `anvil release check`.
- The supported library surface is limited to the documented exports; deep imports into `src/commands/*` or `src/lib/*` should not be treated as stable public API.
- `scripts/postbuild.mjs` is part of the package contract because it copies `.mjs` outputs to `.js` and stages catalog assets into build output after `tsdown` completes.
