Skip to main content

Configure Nova

Generate or update the Nova config file with an interactive wizard that guides you through each step and saves when you confirm.

Summary

The configure command creates and maintains the complete nova.config.json file through focused editors for every supported configuration field.

Existing values populate each prompt so you can edit an accurate snapshot and only persist changes when you confirm them.

Why Use This Command?

  • The wizard writes the JSON with only the fields you confirm, no extra cleanup required.
  • The wizard lists each field, explains what each field is for, and guides you to fill known values.
  • Every supported nova.config.json value is reachable through the wizard; no field is reserved for direct JSON editing.
  • Avoid typos and mismatched formats with built-in validation for slugs, emails, and URLs.
  • Dry run lets you walk through the questions without touching the config file until you're ready.

Use Cases

  • Onboarding — Create the first nova.config.json for a new or migrated repository.
  • Metadata refresh — Keep project descriptions, entities, and canonical URLs in sync after ownership changes.
  • Normalization — Clean up manually edited entries without hunting for typos in raw JSON.
  • Generator support — Feed consistent metadata to Nova generators so docs, README files, and release notes stay accurate.

Requirements

  • Node.js runtime — Use any Node.js LTS release with either the installed nova CLI or npx.
  • Project root — Run the command from the directory containing the top-level package.json (monorepo root included).
  • Interactive terminal — The session needs to support interactive prompts for the wizard to function.

Usage

You can run this command in two ways:

Options

FlagDescription
-d, --dry-runRun without writing any files.
-r, --replace-fileOverwrite the existing nova.config.json instead of creating a dated copy.
-s, --statusShow the read-only GitHub environment status and exit without opening the wizard.

Read-Only Environment Status

Use --status when you only want to compare the environment declarations with their GitHub Variable and Secret names. This path does not open the wizard and does not write nova.config.json or reconcile any values. With environment profiles enabled, it also warns about any workspace that still holds a plain .env.sample, even when the gh CLI is unavailable.

bash
nova utility configure --status

Flow Overview

Without --status, the command loops until you choose Save & Exit or Cancel. You can edit any category multiple times during the same run.

Editing an existing config?

Existing values are pre-filled in each prompt. Press Enter to keep a value, type a new value to replace it, or enter a single space to clear that field.

Project

  • Purpose: Edit project display name, slug, short/long descriptions, keywords, legal name, pronouns, supported platforms, starting year, and license in one guided step.
  • Nice to know: Slug updates propagate to workspace names for roles that depend on it (project, docs, config, app, tool) to keep names consistent. Pronouns control first-person wording (we/us/our vs I/me/my), platforms help suggest initial issue fields and badges, and starting year plus license feed the LICENSE generator.
  • Things to watch: Slug allows only letters, numbers, hyphens, and underscores up to 214 characters; keywords are validated per item (50 characters max); starting year must be an integer ≥ 1970. When a dockerHub section exists, the short-description prompt shows its current character count and rejects values longer than Docker Hub's 100-character limit.

Entities

  • Purpose: Manage project-related people and organizations with name, email, URL, and roles in a single flow.
  • Nice to know: Roles are chosen from the allowed set (author, contributor, supporter) so you don't have to remember labels.
  • Things to watch: Emails must be valid (contain @ and a domain); URLs must be valid http:// or https:// before they're saved.

Emails

  • Purpose: Capture a canonical contact for issues/support so tools and metadata can reference a single address.
  • Nice to know: Single email field today, kept simple for quick updates.
  • Things to watch: Only valid addresses persist; blanks remove the stored email.

URLs

  • Purpose: Configure canonical links with validation/normalization before persisting: homepage, repository, bugs, license, logo, docs, npm, docker, funding, privacy policy, and terms of use.
  • Nice to know: Repository accepts git:, git+https:, git+ssh:, git+http: plus http://, https://; all other URLs are http://, https:// only. Privacy policy and terms of use URLs appear in generated GitHub issue templates.
  • Things to watch: Funding sources are entered comma-separated and saved as a list after validation.

README

  • Purpose: Select the exact badges and order generated inside Nova's README badges region.
  • Nice to know: When readme.badges has never been configured, the wizard suggests badges from the project platforms and available npm, Docker, GitHub, and funding sources. Saving the category writes your choices explicitly, so later generators never guess.
  • Things to watch: Verified Homebridge status is never inferred. Badges that depend on npm, Docker, GitHub, or funding metadata require the corresponding source field.

Workspaces

  • Purpose: List detected workspaces (package.json) and edit each with role/policy in one place.
  • Nice to know: Roles (project, config, docs, app, package, tool, template) and policies (freezable, trackable, distributable) are constrained to allowed combinations so you don't accidentally pick an invalid pairing.
  • Things to watch: Naming rules enforced by role (config/app/tool require the project-slug prefix when set); distributable workspaces can opt into syncing selected metadata fields.

Environment variables

Environment variables and secrets live in the top-level environment block and are editable in the Environment category below.

Artifacts

  • Purpose: Edit the complete top-level artifacts map as validated JSON, including each final product's workspace build selectors and source-to-destination mappings.
  • Nice to know: A blank value removes the entire optional section. Existing values are pre-filled exactly, so reopening and saving the category preserves every named product.
  • Things to watch: Artifact names must be simple slugs. Every artifact needs a non-empty build array and sources array; path safety and registered workspace references are validated again when Nova loads the saved config.

Workflows

  • Purpose: Manage the list of GitHub Actions workflow templates that the workflow generator reads from at generation time.
  • Nice to know: The menu lists existing workflow entries with Edit and Remove actions alongside an Add option and a Back option to return to the category menu. When adding or editing, the wizard prompts for a template, name, runner, optional timeout, trigger filters, build scopes, deployment targets, target ordering, target settings, and workflow settings. A workflow with a Docker Hub or GHCR target also chooses one or both supported container platforms. Existing custom template and target names remain selectable so opening the wizard never replaces or drops them.
  • Things to watch: runsOn is required. The runner menu reads GitHub's runner-images list, offers exact pinned available labels, and marks paid larger runners. Moving -latest, preview, and deprecated labels are excluded. The workflow form cancels with an error if the list cannot be read, and workflow generation stops before writing files under the same condition. Container platform jobs use the matching x64 or arm64 label derived from this selection. Enter a whole number from 1 through 360 for timeoutMinutes, or leave it blank to preserve each generated job's template timeout. The name must be unique within the same template so the output filenames remain distinct. Upstream choices use another workflow's {template}-{name} key. Multiple upstream choices are alternatives: any one completion can start this workflow; the wizard does not create a wait-for-all chain.

Multiline values

The interactive prompt is single-line. To include line breaks in a setting value (e.g., issue messages with paragraphs), type \n where you want a newline.

The wizard converts \n sequences to actual line breaks when saving. Trigger branch, path, tag, and workflow filters use validated JSON arrays; workflow and target setting maps use validated JSON objects whose values must be strings. These focused inputs keep arbitrary template-specific values editable without leaving the configure flow.

GitHub

  • Purpose: Configure GitHub repository settings, policies, issue-template fields, and the GitHub recipes stored under the top-level recipes.github block.
  • Nice to know: The focused submenu covers repository identity and features, GitHub Actions permissions and allow-lists, ordered labels, every repository policy, the complete default-branch ruleset, security toggles, issue-template fields, and GitHub recipe toggles. Optional booleans include an explicit Unset state, so absence stays different from false.
  • Actions and policies: Configure action availability, SHA requirements, selected-action patterns, workflow-token permissions, artifact retention, merge methods and message presentation, auto-merge, update-branch behavior, web signoff, security features, and every supported default-branch protection field without hand-editing JSON.
  • Bug report fields: A multiselect chooses the exact semantic fields and order the issue template generator includes, saved under github.issueTemplate.bugReportFields. When this array has never been configured, the wizard suggests an initial selection from project.platforms and configured URLs; saving no choices writes an explicit empty array.
  • Things to watch: Owner and repository name are required (non-empty) and trimmed before they're saved.

Docker Hub

  • Purpose: Configure the repository coordinates, visibility, categories, immutable-tag policy, and recipe toggles stored under dockerHub and recipes["docker-hub"].
  • Nice to know: The category list comes from Docker Hub so the wizard saves valid category slugs and readable labels. Choose up to three, select public or private visibility, and independently enable sync-identity and sync-policies.
  • Immutable tags: Enabling or disabling immutable tags opens a list prompt for the regular expressions Docker Hub applies to tags. Choosing Skip omits the policy so Nova leaves the current Docker Hub setting alone.
  • Things to watch: Namespace and repository are required lowercase Docker image components. If Nova cannot load the live category list, it logs an error and cancels this section without replacing its current values.

Ignore Files

  • Purpose: Manage every physical .gitignore, .dockerignore, and .assetsignore generated by the ignore-files generator.
  • Nice to know: Add or remove project-relative file paths, select the ordered Nova bundles for each file, and add, edit, or remove its project-owned patterns. On first open, the root .gitignore editor can import entries already beneath the Project Excludes marker.
  • Things to watch: Paths must begin with ./, end in a supported ignore-file basename, and cannot contain traversal or empty path components. .dockerignore is root-owned and must use exactly ./.dockerignore; nested .gitignore and .assetsignore paths remain supported. Bundle choices are determined by the physical file type.

Migrating an existing project

If your repository already has a hand-maintained .gitignore, open the Ignore Files category once to import those entries into nova.config.json before regenerating. A regenerate emits only what the config holds, so excludes that were never imported are dropped from the output.

AI Tools

  • Purpose: Select which AI tools the agent-conventions generator emits files for, saved under the top-level agents field. Claude Code writes CLAUDE.md and Codex writes AGENTS.md; both share VISION.md, PROJECT_RULES.md, and conventions/*.md.
  • Nice to know: The category is a multiselect that pre-checks whatever is already stored, so reopening it shows your current selection.
  • Things to watch: Selecting no tools removes the optional agents field, which disables agent-convention output until a tool is selected again.

Recipes

  • Purpose: Configure all Docker Hub, GitHub, license, miscellaneous, Nova config, README, and per-workspace package.json recipes from one category.
  • Nice to know: Each recipe has an individual enabled toggle, including fix-markdown-tables and normalize-order. Generic recipe settings remain editable through a validated prompt, while closed recipes such as remove-operating-system-files present only Nova's reviewed platform and file choices.
  • Things to watch: package-json recipes are scoped by workspace path. The menu includes registered workspaces plus any existing recipe path, so temporarily unregistered paths are preserved and remain editable. Cleanup recipes do not accept arbitrary paths or patterns.

Environment

  • Purpose: Manage the environment block — per-workspace environment values, project-wide keys, and their namespace prefixes — without editing nova.config.json by hand.
  • Nice to know: Each value has a required reach: local stays on the developer machine, managed is tracked locally and on GitHub but delivered nowhere, build is injected into CI builds, runtime is reconciled to deployed servers, and "build and runtime" saves the list ["build", "runtime"] so one value does both. Editing a list value preselects "build and runtime". managed, build, runtime, and build-and-runtime values also require secret to choose GitHub Secret or Variable storage. The wizard can add the repo root ./ workspace alongside the others, bringing its .env under management.
  • Things to watch: Removing a value is confirm-gated and offers to drop its local .env line as well. Every namespace — the project group, each workspace (including the root ./), and each workflow — requires a prefix that matches ^[A-Z][A-Z0-9]*_$: one uppercase word that starts with a letter, may contain digits, and ends with _ (for example, CBN_). The prefix prompts reject inner underscores, lowercase, a missing trailing underscore, a leading digit, and the reserved GITHUB_ namespace. Existing collision validation also rejects a prefix that overlaps another project, workspace, or workflow prefix. On exit, the section can check GitHub status and reconcile — stubbing missing keys and deleting stale ones through the gh CLI — so Nova manages key names and existence only, never their values.

Settings

  • Purpose: Select the project's release strategy, lock-step versioning behavior, per-script workspace concurrency, verified local cache settings, and whether the root runs as part of the workspace tree.
  • Nice to know: With no release history or pending changelog entries, you can revisit this category and change SemVer (major.minor.patch) to CalVer (YYYY.M.MICRO) or back. On save, Nova migrates every workspace version, exact internal version pin, Android versionName, and authoritative Apple MARKETING_VERSION together; freezable workspaces remain 0.0.0. Workspace limits, lock-step versioning, and every cache setting remain editable independently at any time.
  • Things to watch: A pending .changelog/*.md entry blocks a strategy switch so its release meaning cannot change underneath it. Once the root or any non-freezable workspace changelog contains a release heading, Nova detects that history and makes only the version strategy read-only. A configured mismatch, mixed strategies, or an unsupported numeric heading stops configuration and identifies the affected changelog.

Saving and Canceling

  • Choosing Save & Exit writes to a file called nova.config.json.
  • Choosing Cancel exits immediately without persisting changes and prints a debug log.

Output Example

nova.config.json
json
{
  "project": {
    "name": {
      "slug": "example",
      "title": "Example"
    },
    "description": {
      "short": "A Nova-powered JavaScript toolkit."
    },
    "keywords": ["example", "nova", "tooling"],
    "legalName": "Example Author LLC",
    "pronouns": "business",
    "platforms": ["nodejs", "linux", "windows"],
    "startingYear": 2025,
    "license": "MIT"
  },
  "entities": [
    {
      "name": "Example Author",
      "email": "author@example.com",
      "url": "https://example.com/author",
      "roles": ["author"]
    }
  ],
  "emails": {
    "bugs": "bugs@example.com"
  },
  "github": {
    "owner": "example",
    "repo": "example-project",
    "topics": ["nova", "tooling"],
    "features": {
      "issues": true,
      "wiki": false,
      "projects": false,
      "discussions": false,
      "sponsorships": true
    },
    "policies": {
      "visibility": "public",
      "defaultBranch": "main",
      "mergeMethods": {
        "merge": false,
        "squash": true,
        "rebase": false
      },
      "autoDeleteHeadBranch": true
    },
    "issueTemplate": {
      "bugReportFields": ["nodejs", "screenshots"]
    }
  },
  "dockerHub": {
    "namespace": "example",
    "repository": "example-project",
    "visibility": "public",
    "categories": ["developer-tools"],
    "immutableTags": {
      "enabled": false,
      "rules": []
    }
  },
  "urls": {
    "homepage": "https://example.com",
    "repository": "https://github.com/example/example-project",
    "bugs": "https://github.com/example/example-project/issues",
    "license": "https://github.com/example/example-project/blob/main/LICENSE",
    "logo": "https://example.com/assets/logo.svg",
    "documentation": "https://docs.example.com/project",
    "npm": "https://www.npmjs.com/package/example-project",
    "docker": "https://hub.docker.com/r/example/example-project",
    "fundSources": ["https://github.com/sponsors/example"],
    "privacyPolicy": "https://example.com/privacy",
    "termsOfUse": "https://example.com/terms"
  },
  "readme": {
    "badges": [
      "npm-version",
      "npm-downloads",
      "docker-pulls",
      "docker-image-size",
      "github-release",
      "github-top-language",
      "github-license",
      "funding"
    ]
  },
  "workspaces": {
    "./": {
      "name": "example-project",
      "role": "project",
      "policy": "freezable"
    },
    "./apps/docs": {
      "name": "example-docs",
      "role": "docs",
      "policy": "freezable"
    },
    "./packages/nova": {
      "name": "@company/example",
      "role": "package",
      "policy": "distributable"
    }
  },
  "artifacts": {
    "example-docs": {
      "build": ["./apps/docs"],
      "sources": [
        {
          "from": "./apps/docs/build",
          "to": "./"
        }
      ]
    }
  },
  "workflows": [
    {
      "template": "lock-inactive-issues",
      "name": "project",
      "triggers": ["schedule-weekly"],
      "runsOn": "ubuntu-24.04"
    },
    {
      "template": "publish",
      "name": "project",
      "triggers": ["release"],
      "runsOn": "ubuntu-24.04",
      "build": ["./packages/nova"],
      "deploy": [
        {
          "to": "npm",
          "path": "./packages/nova"
        }
      ],
      "with": {
        "NPM_TOKEN": "NPM_TOKEN"
      }
    }
  ],
  "ignoreFiles": {
    "./.gitignore": {
      "bundles": ["nova"],
      "patterns": [".local/", "scratch/"]
    }
  },
  "agents": ["claude-code", "codex"],
  "recipes": {
    "docker-hub": {
      "sync-identity": { "enabled": true },
      "sync-policies": { "enabled": true }
    },
    "github": {
      "sync-actions": { "enabled": false },
      "sync-features": { "enabled": true },
      "sync-identity": { "enabled": true },
      "sync-labels": { "enabled": false },
      "sync-policies": { "enabled": true },
      "sync-rulesets": { "enabled": false },
      "sync-security": { "enabled": false }
    },
    "license": {
      "update-copyright": { "enabled": true }
    },
    "miscellaneous": {
      "fix-markdown-tables": { "enabled": true }
    },
    "nova-config": {
      "normalize-order": { "enabled": true }
    },
    "read-me": {
      "update-badges": { "enabled": true },
      "update-credits": { "enabled": true }
    },
    "package-json": {
      "./": {
        "cleanup": {
          "enabled": true,
          "settings": {
            "removeUnknownKeys": true,
            "reorderKeys": true
          }
        },
        "normalize-dependencies": {
          "enabled": true,
          "settings": {
            "pinDependencyVersions": true,
            "pinDevDependencyVersions": true
          }
        }
      },
      "./packages/nova": {
        "sync-identity": {
          "enabled": true,
          "settings": {
            "description": true,
            "keywords": true,
            "displayName": true
          }
        }
      }
    }
  },
  "environment": {
    "project": {
      "prefix": "EXAMPLE_",
      "variables": [
        { "key": "NPM_TOKEN", "reach": "managed", "secret": true }
      ]
    },
    "workspaces": {
      "./": {
        "prefix": "ROOT_"
      },
      "./apps/docs": {
        "prefix": "DOCS_",
        "variables": [
          { "key": "LOCAL_API_MOCK", "reach": "local", "defaultValue": "http://127.0.0.1:8787" },
          { "key": "SENTRY_PROJECT", "reach": "managed", "secret": false },
          { "key": "PUBLIC_SITE_URL", "reach": "build", "secret": false, "defaultValue": "https://docs.example.com" },
          { "key": "STRIPE_SECRET_KEY", "reach": "runtime", "secret": true }
        ]
      }
    },
    "workflows": {
      "project": {
        "prefix": "PUBLISH_"
      }
    }
  },
  "settings": {
    "lockStepVersioning": false,
    "runWorkspaces": {
      "cache": {
        "directory": "./node_modules/.cache/nova/run-workspaces",
        "enabled": true,
        "scripts": ["build", "check"]
      },
      "concurrency": {
        "build": 2,
        "check": 2,
        "deploy": 2
      }
    },
    "versionStrategy": "semver"
  }
}

Troubleshooting

  • "Must be run inside the project root directory." — Verify you execute the command where the project root package.json resides. App or package folders inside monorepos are not allowed.
  • Validation loops keep reappearing — Fix the highlighted email or URL before continuing. To drop the value, enter a single space and press Enter.
  • No file was created — Confirm that nova.config.json is writable and that --dry-run was not passed or Cancel was not chosen.