---
name: catalyst-cli
description: >
  Aurora Catalyst CLI usage for AI agents. Covers the `catalyst generate` and
  `catalyst origin` workflow, the schema-first principle (always express
  intent in `*.aurora.yaml` when possible), and the three-way reconciliation
  of `.origin` files (codegen output vs user customization vs AI session
  edits). Trigger: When running `catalyst …`, regenerating a module after
  schema or `aurora.yaml` changes, reconciling `.origin` files left behind
  by a regen, deciding whether a change belongs in YAML or in code, or
  inspecting which CLI command applies. Loads alongside `catalyst-schema`
  whenever a YAML edit might require regeneration afterwards.
license: MIT
metadata:
  author: aurora
  version: '1.0'
  auto_invoke:
    'Running catalyst commands, regenerating modules, reconciling .origin
    files, deciding YAML-vs-code, post-schema-edit workflows'
allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task
---

## When to Use

Load this skill when you are about to:

- Run any `catalyst <command>` in this repo (generate, origin, env, sheets, deploy, provision, …).
- Regenerate a module after editing its `*.aurora.yaml` schema.
- Edit generated code where a `.origin` file is present or will be produced.
- Decide whether a customization belongs in `aurora.yaml` (declarative) or in code (imperative).
- Inspect a divergent file the codegen left in `.origin` form.

**Always combine with:**

- [`catalyst-schema`](../catalyst-schema/SKILL.md) — for the YAML side of any change. If a feature is expressible in YAML, that is where it must live.
- [`conventional-commits`](../../skills/conventional-commits/SKILL.md) — when committing the result of a regen.
- [`business-rules-guard`](../business-rules-guard/SKILL.md) — if the regenerated module has registered business rules.

## Detailed References

- [`references/origin-conciliation.md`](references/origin-conciliation.md) — the full reconciliation algorithm for `.origin` files (three-way merge between codegen output, user customization, and AI session edits).
- [`references/schema-versioning.md`](references/schema-versioning.md) — how to discover the latest `aurora.yaml` schema version from SchemaStore and pin it.

---

## Critical Patterns

### Schema-first: ALWAYS check whether a change is expressible in YAML before touching code

Aurora's value proposition is that the YAML is the source of truth. The generator produces code from the YAML; user-facing meta-properties (icons, display fields, detail modes, embed support, widget types, validations, lengths, relationships, …) live in the schema, not in the emitted code.

Before editing any generated file, ask:

> Is this change something I could express in `cliter/<bc>/<module>.aurora.yaml`?

If **yes** → edit the YAML, regenerate, and let the codegen propagate the change to every file that depends on it. If you change the icon by hand in `<bc>.navigation.ts`, the next regen will fight you (an `.origin` file appears, your edit is at risk).

If **no** → the change is genuine custom logic. Make it in code, but put it where the merge engine will preserve it (inside an `AURORA:*-START/END` preservation region when one is available).

The list of meta-properties that live in YAML is non-trivial; consult [`catalyst-schema`](../catalyst-schema/SKILL.md) for the full grammar. Quick lookup:

| Want to change… | Where it lives in YAML |
|---|---|
| Module icon (sidebar / nav) | `front.icon` |
| Human-readable label of a record | `front.displayField` |
| Edit screen (full route vs dialog) | `front.detailMode: view | dialog` |
| Whether the aggregate can be embedded inside another | `front.embedSupport: true` |
| Relationship rendering (combobox, grid select, async search) | `<property>.widget.type` |
| Field length, nullability, validators | property attributes |
| Pivot / many-to-many membership UX | (currently disabled — see CLAUDE.md) |

If you cannot find the property in the schema and you believe it should exist, that is a **schema gap**, not a code customization — flag it via the OpenSpec flow rather than papering over it in the emitted file.

### Schema version discovery

The Aurora YAML schema is versioned and published to SchemaStore. The catalog at
`https://github.com/SchemaStore/schemastore/blob/master/src/api/json/catalog.json` lists every published version. When you need the canonical grammar for an edit, fetch the latest entry from the `aurora-N.N.json` family (currently `aurora-1.3.json`). See [`references/schema-versioning.md`](references/schema-versioning.md) for the exact fetch procedure.

### `.origin` files exist for one reason: hash mismatch

A `.origin` file is produced by `catalyst generate` if and only if the **stored skeleton hash** in the per-file lockfile does **not** match the **current skeleton hash** computed from the file on disk. In plain language: the file was modified by someone (a developer, an AI agent, a regex find-replace) since the last regen.

Concretely:

```
<file>                       ← user's modified content (untouched by the regen)
<file>.origin.<ext>          ← the new codegen proposal, with preservation
                               regions already merged from the user's file
```

The `.origin` file is **not** the user's old version. It is the **codegen's proposed new content**, already merged with whatever bodies the user had inside `AURORA:*-START/END` regions. The reconciliation task is therefore: should I adopt the proposal, keep my current file, or take the proposal and re-apply the diverged parts on top?

### Three-way reconciliation: who wrote which hunk?

When you (the AI) face an `.origin` file in a session that you also generated code in, three sources can contribute to the divergent content:

1. **Codegen** — the templates produced this. Likely improvements when templates evolve (new wrapper, new pattern, new import, restructured signal API).
2. **User customization** — the human developer wrote this. Often outside preservation regions because they had no better place to put it. Must be preserved unless the user explicitly says otherwise.
3. **AI session work** — code the AI agent wrote during the current conversation, before the regen ran. The AI knows what it wrote because it sees the conversation; it can also check `git diff` against the last commit.

The reconciliation algorithm and the per-hunk decision tree live in [`references/origin-conciliation.md`](references/origin-conciliation.md). Read it before acting on `.origin` files in a non-trivial regen.

**Default to safety.** When in doubt about a hunk: leave the user's version, run `catalyst origin diff <path>` for the human, and ask. Do not adopt the proposal and re-apply on top blindly.

### Regenerate when YAML changes — always

If any of these changes happens, the affected module(s) must be regenerated:

- A property added, removed, renamed, or retyped.
- `front.icon`, `front.displayField`, `front.detailMode`, `front.embedSupport`, or any other `front.*` meta-property edited.
- A relationship added, removed, or its widget type changed.
- A validation, length, nullability, or default changed.
- A schema version bump that adds new emit paths.

The regen is the contract: schema is the source of truth, and the only way for the code to reflect a YAML change is to run the codegen. Editing by hand defeats the model.

---

## Commands

The CLI binary is `catalyst` (published as `@aurorajs.dev/catalyst-cli`). Run from the consumer repo root unless noted.

### Generation

```bash
# Regenerate a back-end module
catalyst generate back module --name=<bc>/<module>

# Regenerate a front-end module
catalyst generate front module --name=<bc>/<module>

# Force overwrite of files even if user-modified (creates .origin pairs)
catalyst generate <scope> module --name=<bc>/<module> --force

# Generate e2e tests alongside the module
catalyst generate back module --name=<bc>/<module> --tests

# Skip GraphQL type regen (default runs `pnpm back:graphql:types`)
catalyst generate back module --name=<bc>/<module> --noGraphQLTypes

# Verbose: per-file, per-region log
catalyst generate <scope> module --name=<bc>/<module> --verbose
```

`generate` is non-interactive. After it finishes, look at its closing line — if any `.origin` files were created, the count is printed and you are pointed at `catalyst origin list` and `catalyst origin review`.

### `.origin` reconciliation (the AI workflow)

```bash
# List pending .origin files under cwd (or any pathspec)
catalyst origin list
catalyst origin list backend/
catalyst origin list backend/foo.ts
catalyst origin list --json                # machine-readable

# Show a unified diff of <origin> against <current>
# Output direction: + lines are what the codegen would add, - lines are what
# the user currently has that the proposal removes
catalyst origin diff <path>
catalyst origin diff --json

# Adopt the codegen proposal (atomic rename of .origin over current)
catalyst origin accept <path>              # one file
catalyst origin accept backend/iam/        # subtree
catalyst origin accept                     # everything under cwd

# Reject the proposal (delete .origin, keep current as-is)
catalyst origin reject <path>

# Reject the proposal AND mark the file as "skip on future regens"
# (prepends `// ignored file` / `<!-- ignored file -->` / `# ignored file`
# depending on extension; the next regen will skip the file entirely)
catalyst origin ignore <path>

# Interactive walk-through for humans (inquirer + optional VS Code diff)
catalyst origin review
```

All five non-`review` verbs accept the same pathspec semantics:

| Form | Behaviour |
|---|---|
| no arg | start from `cwd`, recurse |
| file (`backend/foo.ts`) | act on that file's `.origin` if it exists |
| `.origin` path | normalised to the current file path, then acted on |
| directory | recurse under it |

Idempotency: `accept`/`reject`/`ignore` on a path without a corresponding `.origin` is a silent no-op (exit 0). Retries are safe; AI agents do not need to check existence first.

### Other commands (less central to the AI workflow)

```bash
catalyst env encrypt --env <name>          # SOPS encrypt .env.<env>
catalyst env decrypt --env <name>          # SOPS decrypt .env.<env>.enc

catalyst sheets pull --bc <bc>             # Pull schemas from Google Sheets
catalyst sheets push --bc <bc>             # Push schemas to Google Sheets
catalyst sheets diff --bc <bc>             # Compare YAML vs Sheet

catalyst deploy --env <name>               # Trigger CI/CD pipeline
catalyst provision --env <name>            # Provision DNS + hosting + CI/CD secrets

catalyst keys                              # Generate RSA private/public key pair
catalyst new <project-name>                # Scaffold a new Aurora monorepo
catalyst add <package-name>                # Add an Aurora package
catalyst pipeline                          # Generate a deploy workflow
catalyst ai setup                          # Sync AI provider config (CLAUDE.md/AGENTS.md)
```

The full per-command surface is in `aurora-catalyst-cli/docs/<command>.md` (or `catalyst <command> --help`).

---

## Workflow: editing a generated module

The decision tree the AI should run before touching any file under `backend/src/` or `frontend/src/` that was emitted by the codegen:

```
                  About to edit a generated file?
                            │
                            ▼
              ┌─────────────────────────────────┐
              │ Is the desired change           │
              │ expressible in <module>.aurora  │
              │ .yaml (icon, displayField,      │
              │ detailMode, widget, validator,  │
              │ length, relation, …)?           │
              └─────────────────────────────────┘
                  │ yes                  │ no
                  ▼                      ▼
        Edit the YAML.            Is the change inside an
        Then regenerate.          AURORA:*-START/END
        Reconcile .origin if      preservation region?
        any.                          │ yes        │ no
                                      ▼            ▼
                              Edit inside     The customization will
                              the region.     be lost on regen unless
                              Safe forever:   you reject the proposal
                              the merge       every time. Strongly
                              engine will     consider:
                              keep your body  - widening the YAML to
                              across regens.    cover the case (file
                                                a `catalyst-schema`
                                                gap report)
                                              - using `origin ignore`
                                                permanently on the
                                                file (only if the
                                                whole file is custom
                                                from now on)
                                              - leaving the edit and
                                                accepting that future
                                                regens require
                                                manual merge
```

---

## Workflow: a regen produced `.origin` files — what to do

```
                catalyst generate finished
                "N origin files pending review"
                            │
                            ▼
                catalyst origin list --json
                            │
              for each entry in the list:
                            │
                            ▼
                catalyst origin diff <path>
                            │
                  inspect the patch
                            │
              ┌─────────────┼─────────────────────────────┐
              ▼             ▼                             ▼
       hunk looks      hunk looks                  hunk looks like a
       like template   like user                   change YOU wrote
       improvement     custom logic                this session
       (new wrapper,   (business rule,             (check `git diff`
       new import,     custom validator,           since last commit;
       new shape)      hand-written copy)          confer with the
              │             │                     conversation log)
              ▼             ▼                             ▼
       accept the      reject the                  Three options, see
       proposal IF     proposal: keep              `references/origin-
       no user/AI      what the user               conciliation.md`
       hunks are in    already had.                §"Session-aware
       the same file.                              merge"
       Otherwise:
       three-way
       merge (see
       references/).
```

When `accept`-ing because the proposal carries genuine template improvements but the file also contains user/AI customization, the correct sequence is:

1. `git stash` (or commit) the user/AI work in this file.
2. `catalyst origin accept <path>` — adopt the new scaffolding.
3. Re-apply the user/AI hunks on top of the new scaffolding manually (or via `git stash pop` and resolve).

This is the **three-way reconciliation** mentioned above. Read [`references/origin-conciliation.md`](references/origin-conciliation.md) before doing it on a complex file — there are pitfalls.

---

## Anti-patterns to call out

- **Editing a file the codegen owns to change an icon, label, or display field.** Refuse and edit the YAML.
- **Running `catalyst origin accept` blindly across an entire subtree after a regen that touched files the AI edited this session.** This silently overwrites session work. Always `diff` first or check `git status`.
- **Adding `--force` to `catalyst generate` without intent.** `--force` turns *every* user-modified file into an `.origin` pair to triage; without it, modified files are left as-is. Reach for `--force` only when you have a concrete reason to inspect divergence on multiple files.
- **Treating `.origin` files as backups.** They are not. They are *proposals* that disappear once you decide. Never let them accumulate across many regens — they get stale and confusing.
- **Ignoring (`origin ignore`) a file that should instead be expressed in YAML.** `ignore` is for genuinely hand-written files that no longer belong to the codegen. If the customization is YAML-expressible, fix the YAML, do not opt out of regens.

---

## Resources

- **Templates**: this skill has no `assets/`. The CLI itself owns its emission templates (`aurora-catalyst-cli/src/templates/`).
- **Documentation**: see [references/](references/) for the conciliation algorithm and schema versioning details.
- **CLI source of truth**: `aurora-catalyst-cli/` (the published `@aurorajs.dev/catalyst-cli` package).
- **Schema source of truth**: SchemaStore catalog → `aurora-1.3.json` (or latest) — see `references/schema-versioning.md`.
