Docs · Toolchain

`package.vyipac`

package.vyipac is the package manifest: a YAML file at a package's root that declares its identity, its entry points, its dependencies, and which files belong to it. This page is the complete schema. For the narrative treatment — what a package is and how imports resolve — read guide 14 — Modules and packages; for the commands that consume the manifest see the CLI.

No manifest is required to get started. A lone .vyi file with only relative and @pkg imports compiles fine; add package.vyipac when the project needs an enforced root, named executables, or dependencies.

The file at a glance

yaml
name: greeter
version: 0.1.0
lang: 0.0.1

deps:
  json: ^1.0.0

entries:
  greeter: src/main.vyi
  greeter-admin: src/admin.vyi

export: src/lib.vyi

source:
  root: src
  include:
    - "**/*.vyi"
  exclude:
    - "**/*.tests.vyi"

The manifest must be a YAML mapping. These are the seven top-level keys — an unknown key is flagged in the editor (vyipacUnknownKey, a warning) and otherwise ignored:

KeyTypeRequiredPurpose
namestringnothe package's identity
versionstringnothe package's semantic version
langstringnoVyi language version to build against; pins the stdlib
depsmap string → stringnothird-party dependencies: name → version constraint
entriesmap string → pathnoexecutables: bin name → entry file
exportpathnothe package's library entry (its public API file)
sourcemappingnoscopes which files belong to the package

Every key is optional — an empty manifest is valid and still marks a package root.

How the manifest is found

The compiler walks up from the entry file's directory; the first package.vyipac it meets marks the package root. Everything follows from that:

  • Every .vyi file under the root belongs to the package (unless a

source scope narrows it).

  • Relative imports must stay inside the root. One that escapes —

import { thing } from "../../outside" — is a compile error: import "../../outside" escapes the package root.

  • The compilation's file system is rooted there, so a file deep in the tree

can import a sibling of the root with ../-paths that stay inside it.

When no manifest is found, the build is ad-hoc: the entry file's own directory is the root, no containment is enforced, and the stdlib resolves at its default version.

A manifest that is not valid YAML fails the build immediately with the parser's message, e.g. `parse manifest package.vyipac: yaml: line 1: did not find expected ',' or ']'`.

name, version, lang

yaml
name: greeter
version: 0.1.0
lang: 0.0.1
  • name — how consumers refer to the package. Names beginning with @

belong to the standard library (@core, @io, …); use a plain name for your own packages.

  • version — the package's own semantic version. Recorded for consumers

and future registry tooling.

  • lang — the Vyi language version to build against. This pins the

standard library project-wide: every @pkg import in the compilation resolves at exactly this version. Omitted (or with no manifest at all), the stdlib resolves at the toolchain's default version. Pinning a version that is not installed fails every stdlib import — `package "@io" ([email protected]) not found — and, since @core then cannot load, Result, Ok`, and the other prelude names go undefined with it.

All three are free-form scalars: the toolchain validates that they are strings (the editor flags a non-scalar with vyipacWrongType) but does not enforce a version format today.

deps

yaml
deps:
  json: ^1.0.0
  http: 2.3.0

deps maps each third-party dependency to a semantic-version constraint. A declared dependency is imported by its bare name — no ./, no @:

vyi
import { stdout } from "@io"   // stdlib: no declaration needed

fn main() !u8 {
    stdout.write("only stdlib here\n")
    return Ok(0)
}

A bare-name import that is not declared in deps is a compile error at the import line:

vyi-error
import { decode } from "json"   // error: unknown dependency "json"

fn main() !u8 { return Ok(0) }

Dependency resolution is (planned). The declaration side works today: the compiler validates bare imports against deps and reports unknownDependency for undeclared names. The tooling that fetches packages and populates the local dependency store has not landed yet, so a declared dependency currently fails one step later with `cannot resolve import "json"`. Until the resolver lands, the constraint strings are recorded but not solved.

entries

yaml
entries:
  greeter: src/main.vyi
  greeter-admin: src/admin.vyi

entries names the package's executables (bins). Each key is a bin name; each value is the path of that bin's entry file, relative to the manifest's directory. A program is the import graph rooted at an entry — one package can ship several bins, each rooting its own program.

Two rules are enforced per entry, live in the editor and when vyi build resolves a bin name:

RuleDiagnosticMessage shape
the entry file must existentryFileMissingentry "ghost" points at "src/nope.vyi", which does not exist
it must contain a top-level mainentryFileNoMainentry "broken" points at a file that has no main: "src/lib.vyi"

"Contains a main" means a top-level fn main declaration (or a top-level con main bound to a function value). This check is purely syntactic presence; the entry contractmain takes nothing and returns !u8 — is enforced when the program actually compiles:

vyi
import { stdout } from "@io"

fn main() !u8 {
    stdout.write("hello from the greeter bin\n")
    return Ok(0)
}

vyi build accepts a bin name in place of a file path — any positional argument that doesn't end in .vyi is looked up in the current directory's entries:

sh
vyi build -o greeter greeter        # by bin name, via the manifest
vyi build -o greeter src/main.vyi   # by path — entries not consulted

An unknown name lists what's available: `no bin "nosuch" in package.vyipac entries (have: greeter, greeter-admin). A package with no entries` block gets `package.vyipac declares no entries (pass a .vyi path, or add an entries block)`. See the CLI.

export

yaml
export: src/lib.vyi

export names the package's library entry: the single file other packages receive when they import this package by name — its public API surface. It is conventionally a barrel that re-exports the public names. Unlike an entries file, it needs no main; the only rule is that the path must exist (entryFileMissing otherwise: `export points at "src/lib.vyi", which does not exist). A package can declare both entries (its tools) and export` (its library surface), or either alone.

Today the field is declared and validated, but the import machinery reaches a name-imported package through the file package.vyi at its root — the convention the standard packages follow. Routing dependency imports through export lands together with the dependency resolver (planned).

source

yaml
source:
  root: src
  include:
    - "**/*.vyi"
  exclude:
    - "vendor/**"
    - "**/*.tests.vyi"

source scopes which files under the manifest's directory belong to the package. Absent, every .vyi under the directory belongs. Present, a file belongs when it passes all three tests, in order:

  1. it sits under root (a manifest-dir-relative directory; omitted or

. means the manifest's own directory; the editor flags a non-directory with sourceRootMissing),

  1. it matches at least one include glob (an absent or empty list

includes every .vyi under root),

  1. it matches no exclude glob (applied after include).

Globs are matched against paths relative to root, /-separated:

PatternMatches
*any run of characters within one path segment
?exactly one character within a segment
**zero or more whole segments

So **/*.tests.vyi matches test files at any depth (including directly under root — ** can match zero segments), while vendor/*.vyi matches only files immediately inside vendor/.

The scope governs discovery and checking: which files the workspace tooling enumerates, checks, and treats as package members. It does not cut imports — an explicit import resolves wherever it points, even at an excluded file.

Which manifest governs a file

Manifests can nest — a package vendored inside another, a sub-project in a monorepo. For any .vyi file, exactly one manifest governs it: the deepest package.vyipac at or above it in the directory tree.

  • The governing manifest's source scope — and only that one — decides

whether the file belongs. Outer manifests never re-filter files that a nested manifest governs.

  • A manifest without a source scope still claims its whole directory:

everything under it belongs to it, not to an ancestor package.

  • A file with no manifest above it always belongs (ad-hoc mode).

So given package.vyipac at the repo root and another at vendor/lib/, the root manifest's exclude: ["vendor/**"] is not what keeps vendor/lib/x.vyi out of the root package — the nested manifest already governs it.

Package capabilities (registry)

Authors do not declare capability flags or target support in package.vyipac. When a package is published, the package registry records the privileges and platforms it may use — including hasBuiltIns, hasInlineMarkers, hasFileSystemAccess, hasNetworkAccess, and supportedTargets. Local application manifests only carry identity, sources, entries, and dependencies.

That registry-side grant model is (planned); today the bootstrap compiler still recognises a few of these flags internally for the standard library.

Validation summary

Where each manifest-level finding surfaces:

DiagnosticMeaningSurfaces
YAML parse errorthe manifest is not valid YAMLfails every build under the root
vyipacUnknownKey (warning)a key outside the schemaeditor
vyipacWrongTypea value of the wrong YAML shapeeditor
entryFileMissingan entries/export path that does not existeditor; vyi build by bin name
entryFileNoMainan entries file with no top-level maineditor; vyi build by bin name
sourceRootMissingsource.root is not a directoryeditor
unknownDependencya bare import not declared in depscompiling any program that imports it
importEscapesRoota relative import leaving the package rootcompiling any program that imports it

The editor tooling (the language server) also completes the schema's keys inside package.vyipac documents.