Packages & Modules
As your programs grow from single-file scripts into substantial applications, you need a way to organize code across multiple files and directories. You also need a way to manage dependencies -- to pull in libraries written by others and keep track of which versions you're using.
Auto provides a complete project management system through automan, its package manager and build tool, combined with a module system that lets you control visibility and structure your code into clean, reusable units.
In this chapter, we'll cover:
- Managing Projects with
automan-- the package manager and build system auto.toml-- the project manifest and dependency declaration- Defining Modules -- the
modkeyword and nested modules - Controlling Visibility -- the
pubkeyword and private-by-default - Organizing into Files -- multi-file projects and the
usekeyword
Managing Projects with automan
automan is Auto's package manager and build tool, equivalent to Cargo for Rust or npm for Node.js. It handles creating projects, building code, running tests, and managing dependencies -- all from a single command-line tool.
Creating a New Project
To create a new Auto project, run automan new:
$ automan new my_project
Created binary (application) `my_project` package
$ cd my_projectThis generates a project with the following structure:
The project directory contains two key items:
auto.toml-- the project manifest file (we'll explore this in detail next)src/main.auto-- the entry point of the application, containing amainfunction
You can build and run the project with automan run, which compiles all .auto files and executes the resulting binary.
Key automan Commands
| Command | Description |
|---|---|
automan new <name> | Create a new project |
automan build | Compile the project |
automan run | Build and run |
automan test | Run tests |
automan add <dep> | Add a dependency |
auto.toml
The auto.toml file is the project manifest. It sits at the root of your project and describes the package metadata and dependencies. It uses TOML format, the same as Rust's Cargo.toml.
Package Metadata
Every auto.toml starts with a [package] section:
[package]
name = "my_project"
version = "0.1.0"This tells automan the package name and version. The name must be a valid identifier -- use underscores instead of hyphens.
Declaring Dependencies
To use external libraries, add them to the [dependencies] section:
When you run automan build, it reads auto.toml, downloads the specified dependencies from the package registry, and compiles everything together. The exact versions resolved are recorded in auto.lock, ensuring reproducible builds.
Auto vs Rust Toolchain Comparison
Concept Auto Rust Package manager automancargoConfig file auto.tomlCargo.tomlLock file auto.lockCargo.lockCompiler autocrustcSource files .auto.rs
Defining Modules
A module is a namespace that groups related functions, types, and constants together. In Auto, you define a module using the mod keyword followed by a block:
This prints:
Server started on port 8080
Connecting to localhostThe mod keyword creates a namespace. Inside mod server { ... }, the function start is grouped under the server namespace. You access it with the dot notation: server.start().
Modules can be nested. You can place a mod block inside another mod block to create a hierarchy:
mod network {
mod tcp {
fn listen(port int) {
print("TCP listening on port " + port)
}
}
}
fn main() {
network.tcp.listen(3000)
}How this maps across languages:
- Rust uses
modblocks with::path separators. Functions inside modules are markedpubto be accessible from outside. - Python flattens modules into prefixed function names (
server_start,client_connect). - C uses prefixed function names, similar to Python.
- TypeScript uses camelCase prefixed names (
serverStart,clientConnect).
Controlling Visibility
Auto follows Rust's philosophy: everything is private by default. Items inside a module are only visible within that module unless you explicitly mark them as public with pub.
This prints:
public helperThe pub keyword makes helper accessible from outside the utils module. The internal function has no pub, so it's private -- only code within utils can call it. Attempting to call utils.internal() from main is a compile-time error.
This is a deliberate design choice, borrowed from Rust. Private-by-default means:
- You must explicitly decide what to expose. The public API surface is always intentional.
- Internal implementation details stay hidden. You can refactor the internals of a module without breaking code that uses it.
- The compiler catches accidental access to private items at compile time.
How visibility maps across languages:
- Rust uses the same
pubkeyword with the same private-by-default semantics. - Python has no native visibility control -- the
_prefix convention signals "internal" but isn't enforced. The transpiler comments out the call instead. - C uses
staticfor file-level private functions. - TypeScript has no module-level visibility; the transpiler adds a
// privatecomment and comments out the call.
Organizing into Files
As a project grows, you'll want to split modules across separate files. Auto follows a convention similar to Rust: each file is a module, and directories create nested module namespaces.
Project Structure
A typical multi-file Auto project looks like this:
my_project/
├── auto.toml
└── src/
├── main.auto
├── utils.auto
└── network/
├── mod.auto
├── server.auto
└── client.autoEach .auto file becomes a module. The directory network/ becomes the network module namespace, with mod.auto as its entry point.
The use Keyword
The use keyword brings a module into scope so you can reference its items directly. This is similar to Rust's use or Python's import:
This prints:
public helper
Server started on port 8080use utils brings the utils module into scope. use network.server brings the server submodule from the network directory into scope. After these imports, you can call utils.helper() and server.start() directly.
Note the difference between the two use forms:
use utils-- imports the module as a namespace. You still access items through it:utils.helper().use network.server-- imports a specific submodule. You can call its functions directly:server.start().
How use maps across languages:
- Rust generates
moddeclarations for file-based modules and uses::for paths. - Python generates
from ... import ...statements. - C inlines the function definitions with comments indicating their origin.
- TypeScript inlines the functions with comments indicating their origin module.
File Naming Conventions
Auto follows these conventions for file-to-module mapping:
| File | Module Path |
|---|---|
src/main.auto | (binary entry point) |
src/utils.auto | utils |
src/network/mod.auto | network (directory module) |
src/network/server.auto | network::server |
src/network/client.auto | network::client |
Each directory must have a mod.auto file to serve as the module entry point. This file can re-export submodules or define items directly.
Summary
Auto's package and module system provides the tools to organize code at any scale:
| Concept | Auto | Rust |
|---|---|---|
| Package manager | automan | cargo |
| Project manifest | auto.toml | Cargo.toml |
| Lock file | auto.lock | Cargo.lock |
| Define module | mod name { } | mod name { } |
| Make public | pub fn | pub fn |
| Default visibility | private | private |
| Import module | use name | mod name; / use name::item; |
| Source files | .auto | .rs |
| Directory module | mod.auto | mod.rs |
Key design principles:
Private by default: You must explicitly opt in to making items public with
pub. This keeps your API surface intentional and manageable.Explicit imports: The
usekeyword makes dependencies between files visible at a glance. You can always see where a function comes from.Convention over configuration: File-to-module mapping follows predictable rules.
src/utils.autobecomes theutilsmodule.src/network/server.autobecomesnetwork::server.Reproducible builds:
auto.lockpins exact dependency versions, so builds are deterministic and reproducible across machines.
In the next chapter, we'll explore how Auto handles collections -- the data structures you'll use every day inside the modules you've learned to organize.