Browse the documentation

AEL 1.0.0

Manifest reference

pack.ael is the manifest of AEL, the Agent Engineering Language: the one file that says which packages a project, or one folder of it, uses. It is a declarative record, never code. It has no expressions, no includes and no scripts, and nothing in it runs. # comments are allowed. Using packages explains how manifests and folder scopes work together.

Top-level fields

pack {
    schema = 1;
    dependencies = [
        { name = "server/http"; version = "^1.2.0"; kind = "runtime";
          source = { kind = "registry"; };
          features = []; targets = []; capabilities = ["net.listen"];
          publisher = "openeng"; }
    ];
}
FieldRequiredMeaning
schemaYesThe format version: 1.
dependenciesYesThe packages this scope uses. [] for none.
toolchainNoThe AEL toolchain versions the project accepts, written like a version requirement. It is checked before anything is resolved.
registriesNoPackage registries and their publishers. The official registry is the default and needs no entry.

Unknown and repeated fields are refused. The project's name, description and settings belong in metadata.ael, never in pack.ael.

Dependency fields

Every dependency names each of these fields, even when a list is empty:

FieldMeaning
nameThe package name, such as "server/http". See Names and aliases.
versionA version requirement, such as "^1.2.0".
kind"runtime", "build" or "development". See Kinds.
sourceWhere the package file comes from. See Sources.
featuresThe package features you ask for, by name. [] for none.
targetsThe targets this dependency applies to. [] for all of the package's targets.
capabilitiesThe permissions the package asks for, such as "net.listen". [] for none.
publisher"openeng" for official packages; your own publisher name for private ones.
aliasOptional: a local name for the package in your source.

Version requirements

RequirementAcceptsExample
=M.m.pExactly that version."=1.2.3"
^M.m.pCompatible versions: the same major version from 1 up; the same minor version while the major is 0; only that version for 0.0.p."^1.2.3" accepts 1.2.3 up to, not including, 2.0.0
~M.m.pPatch updates within the same minor version."~1.2.3" accepts 1.2.3 up to, not including, 1.3.0
>=A <BA range with both bounds.">=1.2.0 <2.0.0"
  • There are no wildcards, no "or" and no requirement without an operator. Numbers have no leading zeros, and each is at most 2,147,483,647. Versions compare number by number, never as text.
  • A version with a suffix after a -, such as 1.3.0-rc.1, is chosen only when you name it exactly with =. Build metadata after a + is refused.
  • Adding, updating and locking choose the highest version that fits. Installing and building never choose again: they use the lock file.
  • One scope uses one version of each package.

Sources

kindFieldsFor
"registry"origin, optional; it defaults to https://pack.ael.openeng.aiOfficial packages from the official registry.
"https"url and digestA private package file at an https address that never changes.
"local"path and digestA private package file kept inside the project.

digest is the file's fingerprint: sha256: followed by 64 lower-case hex digits. There is no source that points at code to be built: every source is a built package file. Private packages gives the rules for addresses and paths.

Kinds

  • "runtime": part of your program.
  • "build": an explicit input for your builds that never becomes part of your program. It never runs inside the compiler, as an install script or by itself during a build, which runs no package code.
  • "development": used for tests and development only. It never reaches your program unless it is also declared as a runtime dependency.

Features and targets

  • A package has no default features: you get exactly the features you list. An unknown feature is refused.
  • When two packages in one scope ask for different features of a shared package, it gets the features that were explicitly requested, combined. Adding or updating shows any dependencies and capabilities that this brings.
  • targets lists exact target names; see Supported targets. A dependency limited to other targets stays in the lock file but is left out of builds for your target.

Capabilities and publishers

  • capabilities is a request, never a grant. Your deployment decides what a program may actually do, and a package still receives only what your code passes to it. See Effects and capabilities.
  • publisher has to match the publisher the package itself records. Only official packages from the official registry carry "openeng".

Names and aliases

  • Package names are lower case and slash-separated, such as server/http or acme/billing. Each part starts with a letter and continues with letters, digits, _ or -. A name is at most 128 characters.
  • AEL never guesses at a misspelled name or substitutes a similar-looking one: an unknown name is an error.
  • alias is an AEL identifier. It cannot be a keyword, _ or print, and two aliases in one scope cannot differ only in letter case.

Limits

  • Every pack.ael stays within the limits of every source file: at most 5,000 bytes and at most 5,000 lines. Split a long list of dependencies into folder scopes. See Limits.
  • The resolution limits for one scope are 1,024 packages and 8,192 dependency links, with no chain of dependencies more than 64 links long. Going over is an error, never a partial result.
  • A dependency cycle is refused, and the error names the whole cycle.

The lock file

pack.lock is generated beside each pack.ael by ael pack add, ael pack update and ael pack lock, and read by ael pack install --locked. It records:

  • the exact version, origin, publisher and fingerprint of every package in the scope, direct or not;
  • how the packages depend on each other;
  • the features and targets chosen;
  • which manifest it belongs to.

With it, builds repeat, even offline, and nothing downloads when an app starts. Never edit it by hand: if it no longer matches its manifest, ael pack install --locked stops instead of changing it. It never holds secrets, access tokens or absolute paths.

The data of a manifest and of a lock file each have a published JSON Schema, both marked as drafts: Package manifest and Package lock file. The manifest schema describes the parsed data; pack.ael itself is always written as shown above.