Skip to main content

Pack manifest reference

pack.yml declares a pack. It requires a hyphen-separated alphanumeric id, non-empty author and license values, and a semantic version. Empty content collections remain valid during incremental authoring. name, description, homepage, tags, and draft are optional metadata. Discovery and search exclude manifests missing author or license attribution. They also exclude draft packs unless the consumer passes --allow-draft.

id: example-documentation-standard
name: Documentation standard
version: 1.0.0
license: MIT
author: Lunaris Digital Solutions <[email protected]>
description: Adds the engineering documentation standard.
tags:
- documentation
- engineering
managedFiles:
- source: targets/docs/standard.md
target: docs/standard.md

Release layout

Organize a catalog by pack ID and immutable release version. Keep complete managed files under targets/, mirroring their default project paths, and keep merge inputs under fragments/<target>/:

packs/
example-documentation-standard/
1.0.0/
pack.yml
targets/
docs/
standard.md
fragments/
package.json/
example-documentation-standard.json
instructions/
setup.md

Omit directories the release does not use. Use scripts/ for packed lifecycle programs, fixtures/ for isolated lifecycle test workspaces, and examples/ for content that is not installed. Folder names explain purpose; only manifest selectors install content.

FieldRules
idRequired stable identifier: alphanumeric segments joined by single hyphens.
versionRequired Semantic Version.
nameOptional non-empty human-readable name.
authorRequired non-empty author or maintainer attribution.
draftOptional visibility marker. Defaults to false; drafts require --allow-draft in discovery and search but remain available to direct commands.
homepageOptional absolute HTTP or HTTPS URI.
licenseRequired non-empty license identifier or expression.
managedFilesEach entry has one source, directory, or glob selector and a non-empty project-relative target that cannot contain . or .. segments.
packsEach composite reference has a hyphen-separated alphanumeric ID and an exact version. Optional condition selects whether the reference participates in lifecycle planning.
parametersOrdered identifier-named string, bool, or enum declarations. Enums require unique values and may set multiple: true; multi-select defaults are unique arrays of allowed values.
Reference parametersString, Boolean, or unique string-array bindings for a referenced pack. Runtime validation checks arrays against the target multi-select enum.
conditionBoolean, comparison, membership, and isDefault(identifier) expressions joined with logical operators.
strategycopy with overwrite, fail-if-exists, skip-if-exists, or backup-and-overwrite; or merge with lines, section, or json.
tagsOptional list of up to 15 unique, non-empty tags. Search matches tags; discover lists them, and inspect previews the first five.
templateEnables Scriban parsing. Defaults to false; set true only when this source uses parameters or Scriban functions.
hooksOrdered script or instruction declarations grouped by lifecycle event.

Parameters

Parameter declaration order is prompt order. Luna prompts each root pack's parameters before walking its references, then follows active references in manifest order. When a reference condition is false, parameters belonging only to that inactive branch are not prompted. A shared dependency remains promptable when another active reference reaches it.

Use required: true for an unconditional input or requiredWhen for a conditional input. These properties are mutually exclusive. requiredWhen uses the same Boolean, comparison, membership, isDefault(identifier), &&, ||, !, and parenthesized expressions as condition. Every parameter named by requiredWhen must appear earlier in the same parameters mapping.

parameters:
features:
type: enum
multiple: true
values: [api, web]
default: [api]
useDefaults:
type: bool
default: true
apiName:
type: string
requiredWhen: isDefault(useDefaults) && "api" in features

apiName is required only when both predicates are true. Do not alphabetize parameters when their prompt dependency requires another declaration first.

Lifecycle hooks

Optional hooks arrays run or display ordered work around install, update, and uninstall. Each declaration is a script or instruction. Script hooks use either a direct executable command or a packed file with an explicit runner. Arguments are Scriban templates rendered from resolved pack parameters. Each rendered item remains one literal argv value, not part of a shell command string.

hooks:
preInstall:
- type: instruction
file: instructions/setup.md
templating: true
condition: isDefault(projectType)
- type: script
file: scripts/setup.ps1
runner: pwsh
arguments:
- -ProjectType
- '{{ projectType }}'
description: Configure project tooling.
postUpdate:
- type: script
command: dotnet
arguments:
- tool
- restore
postUninstall:
- type: instruction
file: instructions/cleanup.md

Supported hook names are preInstall, postInstall, preUpdate, postUpdate, preUninstall, and postUninstall. Script items require type: script. Packed-file scripts require both file and runner; direct scripts require command. Instruction items require type: instruction and a pack-relative Markdown file; optional templating: true enables Scriban before display. Hook order within each event is significant. Optional condition uses the same parameter expressions as a managed file and omits the hook when false. isDefault(parameterName) compares the resolved value with an explicitly declared default. A composite reference can set disabledHooks to suppress every typed hook in selected events for that transient pack.

id: example-application-foundation
version: 1.0.0
license: MIT
author: Lunaris Digital Solutions <[email protected]>
packs:
- id: example-documentation-standard
version: 1.0.0
disabledHooks:
- preInstall
- postUpdate

Consumers select luna install, luna update, and luna uninstall behavior with --scripts prompt|run|skip. Prompt mode requires a matching source or source-plus-pack trust entry, or interactive approval for each untrusted hook. Run mode permits all non-suppressed scripts for one invocation; skip mode runs no scripts. --skip-instructions independently prevents instruction loading and display. Scripts execute with the invoking user's authority, so authors should keep them minimal and describe externally visible effects. Instructions never execute and do not use script trust. Argument and instruction rendering occurs before dry-run formatting; script arguments render before trust authorization. command, runner, and file remain literal. See Use Scriban templates.

Uninstall resolves hooks from the exact releases recorded in the lock file. If their source is unavailable, LunaPack warns and proceeds without uninstall hooks.

Manifests using the former top-level scripts map must migrate to hooks, turn each event value into an array, and add type: script to every declaration. LunaPack rejects the old shape so mixed ordering cannot be ambiguous.

CLI authoring migration is direct:

  • Replace luna pack add script ... with luna pack add hook script ....
  • Replace luna pack rm script <event> with luna pack rm hook <event> <position>.
  • Replace luna pack scripts with luna pack hooks.

The version directory containing the manifest is the pack root. Source selectors read from that root; directory and glob matches retain their relative paths below the target.

Managed-file target values are portable pack defaults. Consumers can remap them in project-level lunapack.yml configuration or through luna install options; pack authors do not declare consumer remapping in pack.yml. See Remap managed targets for mapping syntax, precedence, lifecycle retention, and explicit relocation.

LunaPack rejects rooted and escaping targets. Before mutation it also rejects existing symbolic-link, junction, or reparse-point ancestors inside the workspace. Replacing a hard-linked target creates a new file identity so other names retain their prior content. A same-user process can still race path inspection and use; do not run LunaPack concurrently with an untrusted local process that can modify the workspace.

Selected source files copy as-is unless their selector sets template: true. Template-enabled files are UTF-8 Scriban templates. Resolved parameter names are available as template globals, and supported date-time functions are available. Templates cannot access the filesystem, host services, or custom functions.

See Add managed content for selector and copy behavior, and Merge content into shared files for exact line, section, and JSON merge semantics.