How-to Guides
Use the normal Nova loop: scaffold → copilot guidance → build → test → import → reload
Most of your time with NovaModuleTools should stay in this loop. Once you are comfortable here, packaging, upload, publish, and release become much easier to reason about.
Create the project
Nova supports two scaffold styles:
- minimal scaffold for a clean new module
- example scaffold for a working sample you can inspect and adapt
PS> Initialize-NovaModule -Path ~/Work
PS> Initialize-NovaModule -Example -Path ~/Work
% nova init --path ~/Work
% nova init --example --path ~/Work
Use % nova init --path ~/Work or % nova init -p ~/Work, not positional
path syntax such as % nova init ~/Work.
Both scaffold styles ask the same core project questions, and both now offer an optional Agentic Copilot starter package after the Git prompt.
The starting version prompt now defaults to 0.1.0-preview, so new projects begin on
Nova's prerelease-friendly starter line unless you choose a different version. Before the first
question, Nova also checks whether a newer NovaModuleTools release is available and warns without
blocking the scaffold flow. When you enable Git in either scaffold style, Nova also creates or
updates a default .gitignore in the generated project root so common local and CI
artifact paths are ignored without overwriting existing rules.
The Agentic prompt defaults to No, and the package follows Nova's maintained agentic
guidance through a filtered starter mirror, including Nova build/test/package expectations,
project.json Manifest.PowerShellHostVersion compatibility guidance,
strict ScriptAnalyzer guidance without excluded rules, generated dist module files,
command-help ownership, source-mirrored test guidance, instructions to fix ScriptAnalyzer findings
reported by run.ps1 before handoff, explicit public/private PowerShell file ownership
guidance, a best-effort source/helper-script maintainability guidance plus separate test-design
guidance delivered through Agentic Copilot guidance files, explicit
PSScriptAnalyzer workflow guidance for ./scripts/build/Invoke-ScriptAnalyzerCI.ps1,
./run.ps1, and focused Invoke-ScriptAnalyzer usage, separate
Invoke-NovaTest unit-test and Test-NovaBuild build-validation guidance
that forbids direct Invoke-Pester, explicit valid-PlatyPS help
guidance for docs/<ProjectName>/en-US/*.md using
New-MarkdownCommandHelp, Update-MarkdownCommandHelp, and
Test-MarkdownCommandHelp, with a matching help file required for every new public
entry point, and a strict file-ending rule for changed or generated text files.
The generated project.json also starts with Nova's standard Pester
defaults, including explicit source coverage paths for src/public/, nested
src/private/ helper folders, and src/classes/. The minimal scaffold keeps
CodeCoverage disabled until you opt in, while the packaged example scaffold enables it
by default so Test-NovaBuild can measure src/**/*.ps1 without requiring a
prior build.
When you answer Yes, Nova also asks for a short project name used in generated guidance
placeholders such as Invoke-<ShortName>*. For NovaModuleTools the short name is
Nova, but it could also have been NMT.
Use the example scaffold when you want the shortest path to understanding a real project layout, test suite, and package configuration. Use the minimal scaffold when you already know the structure you want.
Apply the copilot workflow to an existing project
Use this workflow when the project already exists and you want Nova to add or refresh its managed Agentic Copilot guidance without recreating the module scaffold.
PS> Invoke-NovaAgenticCopilotScaffold -ShortName NMT
PS> Invoke-NovaAgenticCopilotScaffold -Path ~/Work/MyModule -ShortName NMT -OverrideWarning
% nova copilot --short-name NMT
% nova copilot --path ~/Work/MyModule --short-name NMT -o
The target directory must contain a valid project.json. Nova reads
ProjectName and Description from that file and requires an explicit short
name on every run for generated placeholders such as Invoke-<ShortName>*.
Nova refreshes only the managed Agentic guidance paths under .github/ together with
AGENTS.md and CONTRIBUTING.md. Existing README.md,
CHANGELOG.md, and RELEASE_NOTE.md are preserved and are created only when
they are missing.
By default Nova prompts before it overwrites the managed scaffold paths.
Use -OverrideWarning only when you intentionally
want a non-interactive apply, and use -WhatIf when you want to preview the changes
first.
Use --override-warning /
-o only when you intentionally want a non-interactive apply, and use
--what-if when you want to preview the changes first.
Build the module
PS> Invoke-NovaBuild
PS> Invoke-NovaBuild -ContinuousIntegration
% nova build
% nova build --continuous-integration
The build step turns your project into a real PowerShell module under
dist/<ProjectName>.
Use the continuous-integration form when the same CI/self-hosting session must keep using the freshly
built module after the build completes. Nova then re-imports the new dist/ output
before
returning.
What build includes
- generated
.psm1output - generated manifest
- external help generation from the command-help markdown
- resource copying
- duplicate function validation when enabled
If SetSourcePath is enabled, the generated module includes # Source:
markers before each source block. If Preamble is configured, those lines are written at
the top of the generated module before the rest of the content.
Run the tests
PS> Invoke-NovaTest
PS> Test-NovaBuild
PS> Invoke-NovaTest -TagFilter unit,fast
PS> Test-NovaBuild -ExcludeTagFilter slow
PS> Invoke-NovaTest -OutputVerbosity Detailed -OutputRenderMode Ansi
PS> $credential = Get-Credential
PS> $container = New-PesterContainer -Path 'tests/public/PublishNovaModule.Tests.ps1' -Data @{ Credential = $credential }
PS> Invoke-NovaTest -PesterConfigurationOverride @{ Run = @{ Container = @($container) } }
% nova test
% nova test --build
% nova test --what-if
Invoke-NovaTest reads the Pester configuration from project.json, runs the
unit-test flow, and writes results to artifacts/UnitTestResults.xml. Test-NovaBuild
runs the build-validation integration flow and writes results to artifacts/TestResults.xml.
Starter projects already include the matching Pester.CodeCoverage block in
project.json, but keep it disabled until you opt in. When you set
Pester.CodeCoverage.Enabled to true, Invoke-NovaTest also
writes JaCoCo coverage to artifacts/coverage.xml and stops if the measured coverage percentage is lower than the
configured CoveragePercentTarget.
Use -Build, --build, or -b when you want Nova to rebuild the
project before the test workflow starts.
Important behavior: when BuildRecursiveFolders is true,
nested test files are discovered. When it is false, Nova stays closer to top-level
Pester-style discovery.
Command-line note: the routed CLI covers the standard test flow, optional
build-before-test, and preview mode. Advanced test overrides such as -TagFilter,
-ExcludeTagFilter, -OutputVerbosity, and
-OutputRenderMode are PowerShell cmdlet parameters, so switch to the PowerShell
view when you need those controls.
Invoke-NovaTest also supports a guarded
-PesterConfigurationOverride hook for runtime-only unit-test data. In v1 Nova accepts
only Run.Container, so you can inject values such as PSCredential with
file-backed New-PesterContainer -Path objects while Nova still owns discovery,
coverage, result files, and the rest of the test workflow.
Use -WhatIf if you want to preview the test run and
output path without creating the
results directory or invoking Pester.
Use --what-if if you want to preview the
test run and output path without creating the
results directory or invoking Pester.
Import the built output
This is the recommended way to work with Nova-built modules during development:
PS> $project = Get-NovaProjectInfo
PS> Import-Module $project.OutputModuleDir -Force
pwsh -NoLogo -Command 'Import-Module (Get-NovaProjectInfo).OutputModuleDir -Force; Get-Command -Module (Get-NovaProjectInfo).ProjectName'
Command-line note: importing built output still happens inside PowerShell. The
one-liner above starts a fresh pwsh process, imports from dist/, and
lists the exported commands so you can confirm the built module loads cleanly.
Importing from dist/ keeps your runtime behavior aligned with what Nova will package and
publish later.
Reload safely after changes
When you edit source files, rebuild and reload the module instead of trusting the module already loaded in memory:
PS> $project = Get-NovaProjectInfo
PS> Remove-Module $project.ProjectName -ErrorAction SilentlyContinue
PS> Invoke-NovaBuild
PS> Import-Module $project.OutputModuleDir -Force
% nova build
pwsh -NoLogo -Command 'Import-Module (Get-NovaProjectInfo).OutputModuleDir -Force; Get-Command -Module (Get-NovaProjectInfo).ProjectName'
This avoids stale function definitions and stale resource loading.
Command-line note: a fresh pwsh -Command process starts clean, so
you usually do not need an explicit Remove-Module step there. If you are iterating
inside a long-lived interactive PowerShell session, switch to the PowerShell view and do the
full remove/build/import loop.
Publish-NovaModule -Local reloads the published module from the local install path
after a successful publish. That is different from the normal build/import loop, which works
from dist/.
% nova publish --local moves the module into the local install path so a fresh
PowerShell session can resolve the published copy directly. That is different from the normal
build/import loop, which still validates dist/.
When a later command in the same session must switch back to the built dist/ module,
use Invoke-NovaBuild -ContinuousIntegration so Nova restores the built module state
automatically.
When a later command in the same self-hosting session must switch back to the built
dist/ module, use % nova build --continuous-integration so Nova
restores the built module state automatically.
Move into packaging and release when you are ready
Once the build/test/import loop feels natural, the next question is usually one of these:
| If you want to… | Go here next |
|---|---|
| create package artifacts | Packaging & Delivery → Create package artifacts |
| upload package files to a raw endpoint | Packaging & Delivery → Upload package artifacts |
| publish the module locally or to PowerShell Gallery | Packaging & Delivery → Publish to a PowerShell repository |
| run a full release workflow with version bumping | Packaging & Delivery → Run the release workflow |
| tune the project configuration | project.json Reference |