pi-config-valid¶
Pi package and project resource declarations must have valid types
| Severity | warning (auto) |
| Autofix | - |
| Since | v0.21.0 |
| Repo Types | pi, pi-package |
| Category | Pi |
Why¶
Pi reads resource declarations from package.json#pi and project
.pi/settings.json, and handles a malformed field differently in each file.
.pi/settings.jsonis not sanitized. A number or object where an array belongs, or a non-string entry, stops Pi at startup with aTypeError. A string is iterated character by character, so"skills": "./x"makes Pi scan the filesystem root.package.json#pifields that are not arrays of strings are ignored, so that resource type silently loads nothing.
This rule names the field and the expected type before Pi runs.
Checks¶
- JSON must parse to an object. Duplicate keys use JavaScript's last-value behavior.
- The package's
pifield must be an object when present. extensions,skills,prompts, andthemesmust be arrays of strings.- Project
packagesmust contain source strings or objects with a nonemptysource, optional resource filter arrays, and an optional booleanautoload. nullis accepted where Pi reads it as absent: top-level settings resource fields andpackages, a package entry'sautoload, andpiresource fields. Anullpackage filter still warns, because Pi drops that package.- Pi only tests
autoload === false, so a non-booleanautoloadwarns: Pi loads that package as if autoload were on.
Unknown npm fields, Pi gallery metadata, and unrelated settings are accepted.
Empty resource lists are valid. Findings are consolidated by file and default to
warning, because the same checks cover package.json#pi fields that Pi ignores.
Legacy project settings such as "skills": {"customDirectories": ["../skills"]}
are normalized before validation and discovery, as in Pi's settings loader.
A nonempty customDirectories array supplies the skill paths; an empty, missing,
or non-array value removes the legacy override and leaves autoload active.
Malformed array members still warn. This migration applies only to project
settings, not package manifests or package selectors.
How to fix¶
Put paths in arrays, such as "skills": ["./skills"]. In project settings,
use "packages": [{"source": "npm:my-package", "skills": []}] to configure
a package and disable its skills. Keep settings paths relative to the directory
containing settings.json, and package paths relative to package.json.
Examples¶
Use arrays for resource paths:
A string such as "skills": "./skills" is invalid. In a package manifest it
drops that resource type; in .pi/settings.json Pi reads each character as
a path and scans from the filesystem root.
Discovery and boundaries¶
The pi-package repository type comes from a pi key, the pi-package npm
keyword, or a repository-local directory listed in project packages. Ordinary
npm packages and unmarked conventional directories do not establish Pi ownership.
A conventional-only package can be selected through project settings. The pi
type comes from .pi project resources, including those in monorepo subprojects.
Portable SKILL.md files not selected by Pi keep their Agent Skills checks.
A pi object replaces conventional Pi package discovery; omitted resource types
and empty arrays contribute no resources. Without that object, packages use
extensions/, skills/, prompts/, and themes/. Manifest globs discover visible
paths; ! exclusions, + exact re-inclusions and - exact exclusions filter
those resources. Project resource lists resolve literal paths and use wildcards
as filters, matching the native loader. Project prompt and theme autoload is shallow;
explicit prompt directories and package prompts are recursive.
Locally referenced packages are linted as authored packages, including resources
that a particular consumer's package filters disable. Package filters are
validated, but do not suppress diagnostics on the package's authored content.
Remote sources and paths outside the checkout are not loaded. Glob traversal
does not descend through symlinked directories; exact contained roots may use
symlinks. Resource walks read .gitignore, .ignore, and .fdignore at or below each
resource root, using Pi's directory-relative prefixing.
Pi-only packages receive shared prose checks for README, commands, agents and
rules. Claude configuration at hooks/hooks.json or settings.json is checked
only when the directory also declares Claude ownership.
Extensions are represented as entrypoint nodes. Themes
are configuration nodes, not prose; theme colors and runtime extension behavior
are outside this rule. First-party .pi/mcp.json servers receive shared
MCP security checks and the opt-in pi-mcp-valid rule.
Upstream reference¶
Pinned to Pi commit
36b60d2e,
particularly packages/coding-agent/src/core/pi-manifest.ts,
package-manager.ts, and skills.ts. See the Pi package documentation.
Configuration¶
Run skillsaw explain pi-config-valid to see this documentation and the rule's effective configuration in your terminal.