Files and roles
In AEL, the Agent Engineering Language, a file's name says what it holds. Agents, subagents, nodes (business steps), edges (typed two-way connections), configuration, hooks and skills are first-class building blocks, each in its own named file, so a project's structure reads at a glance.
One component per file
Every source file except the root files, language files and extension files is named <name>.<role>.ael:
<name>is an AEL name: letters, digits and_, not starting with a digit, and not a reserved keyword; see Syntax basics.<role>is one of the roles below, in lower case.- The file declares exactly one component of that role, its primary, and the primary carries the file's name.
| File | Must declare | Refused |
|---|---|---|
summarize.node.ael | node summarize(…) | node billing(…), a second node, or none |
support.agent.ael | agent support(…) | fn support(…) in place of the agent |
auth.hook.ael | hook auth(…) | hook authorize(…) |
Names are case-sensitive, and the check refuses two files whose names differ only in letter case, so a project means the same thing on every operating system.
The roles
| Role | Declares | Holds |
|---|---|---|
agent | agent <name>(…) | A workflow: its nodes and edges, where work starts, what completes it. |
subagent | subagent <name>(…) | A short-lived agent that an agent spawns at run time: it does one task, returns a typed result to the agent that spawned it and ends. See Subagents. |
node | node <name>(…) | One business step: deterministic logic, or a model call with its tools. |
edge | edge <name>(…) | A typed, two-way channel between two components: a value one way, and its reply back. See Communication between agents. |
config | config <name>(…) | Typed, reusable configuration with defaults. See Configuration. |
hook | hook <name>(…) | Authorization, auditing or cleanup around other code. See Hooks. |
skill | skill <name>(…) | A versioned, reusable bundle of instructions, typed tools and functions that an agent or subagent loads. See Skills. |
global | global <name>(…) | A shared function visible in its folder and below. |
reuse | reuse <name>(…) | A shared function that a file imports by path. |
routes | routes <name>(…) | HTTP routes, a role that the server/http package adds. |
Functions and visibility explains global and reusable functions. A package can add a role only when a manifest selects that package directly, and no package can replace a built-in role or a root file.
An agent, a node or a subagent can carry the modifier isolated before its keyword, as in isolated node scrub(…), and its file keeps its name, scrub.node.ael; Isolated components describes the modifier.
Language files
Your application can hold private functions written in other languages, with typed AEL signatures, built and run with your own toolchains, pinned by version. A function that has a file of its own is in a language file, named <name>.<lang>.ael, where <lang> is the tag of a language, such as python:
| File | Must declare |
|---|---|
profile.python.ael | python profile(…), a function in Python with an AEL signature |
rotate.bash.ael | bash rotate(…), a function in bash |
- A language file's primary carries the file's name and the file's language, and it is private to that file and its extension files.
- A file name never holds both a language and a role. A component's file, such as
profile.reuse.ael, holds functions in other languages asfn python …beside its AEL helpers.
Functions in other languages describes both forms, their options and the list of languages.
The root files
Three files sit at the root of every project, and only there:
main.aeldeclares the program's only entry point,mainfollowed by the application's name:main <name>(), where<name>equalsnameinmetadata.ael. A project whosemetadata.aelholdsname = "support";declaresmain support(), andael buildnames the programsupport.main main()is refused.pack.aelis the manifest: a record of the packages the project uses, never code. A folder can add its ownpack.aelfor its own packages; see Folder scopes.metadata.aelis a record of the project's name, description and settings. The name is required: it namesmainand the program.
main takes no parameters. Without a result type it returns nothing, and the program exits successfully when main finishes; main support() -> i64 returns an i64 instead, and that value is the program's exit status. main calls your agents and functions and, in a service, mounts its routes. It is always written in AEL, and it can call functions in other languages.
A package project keeps a main.ael even when main does nothing. Its metadata.ael names the package, and main takes the last segment of the package name: a package named acme/billing declares main billing().
Nothing starts on its own. Declaring an agent, a node or a set of routes starts no model call, timer or server: main starts what your program runs.
Inside a component file
A component file holds an optional header, which always comes first, then the primary, any supporting types and any number of private helper functions.
# src/nodes/summarize.node.ael
import "../validation.reuse.ael";
struct Summary {
text: Str<1000>,
urgent: bool,
}
node summarize(request: Str<4000>) -> Summary {
let checked: Str<4000> = validation(request);
return write_summary(checked);
}
fn write_summary(request: Str<4000>) -> Summary {
# A private helper: only this component can call it.
}
- The header comes before the first declaration.
import "<relative path>";makes a reusable function available, herevalidation, and a subagent, asimport "./issue_reader.subagent.ael";does. A header can also name the exports of a package that the file uses, such asrefer server/http select get;; every selected export must be used. - Helper functions (
fn) are private to the component. There is nopub fn: to share a function, give it a file of its own as a global or reusable function. The body ofwrite_summaryabove is a placeholder, as A first agent explains. - Helpers in other languages are private helpers too:
fn python …and the other language tags sit beside the AEL helpers of every component except a hook, a configuration or a skill.
Extension files
When a component needs more private helpers than fit in its file, you move them into extension files beside it:
src/agents/
support.agent.ael
support.agent.extended.ael
support.agent.extended.2.ael
support.agent.extended.3.ael
- An extension file holds only private helper functions and comments: no header, no primary, no types. The helpers of a component's extension files are in AEL or, written
fn <lang>, in another language. - Its helpers belong to that one component and can call the component's other helpers; no other file can call them.
- It must sit in the same folder as its component.
main.aelusesmain.extended.ael, thenmain.extended.2.aeland up, and a subagentissue_reader.subagent.extended.aeland up. - A language file's extension files,
profile.python.extended.ael, thenprofile.python.extended.2.aeland up, hold only functions in that file's language. pack.aelandmetadata.aeltake no extension files.
Limits gives the size limit that every file, including each extension file, stays within.
Names that fail the check
- A file without a role or a language, such as
util.aelorglobal.ael. - A word that is neither a role nor a language in the list, such as
billing.service.ael, or an extra dot, such asbilling.v2.node.ael. A language tag is not an extra dot:profile.python.aelis a language file. - A language and a role in one name, in either order, such as
profile.python.reuse.aelorprofile.reuse.python.extended.ael. - A second entry point, such as
app.main.ael, or amain.aelbelow the project root. - An extension numbered 1 or with a leading zero, such as
support.agent.extended.1.ael. - An extension file with no component beside it, or in another folder.
- A primary whose name differs from the file's, even only in letter case, and a
mainwhose name differs from the application's.
Generated files
Two generated items appear beside a manifest, and you never edit either:
pack.lock, the lock file, records the exact packages a build used..package/holds the installed packages. It is not source.