Programming Neam
📖 12 min read

Chapter 9: Modules and Code Organization #

💠 Why This Matters

How to declare modules, import dependencies with aliases and selective imports, and control visibility with pub, crate, and super. How to re-export modules with pub use. How to navigate the Neam standard library. How to structure a Neam project with neam.toml. How to use the neam-pkg package manager to create, install, and publish reusable libraries. How to design modular agent libraries that teams can share across projects.


💠 Why This Matters

Think of modules like departments in a company. The marketing team does not need to know how the engineering team writes code, and the finance department should not have direct access to every internal engineering document. But when marketing needs a product spec, there is a clear, agreed-upon way to request it. Modules work the same way: each one has its own responsibilities, keeps its internal details private, and collaborates with other modules through well-defined public interfaces. Without this structure, your codebase becomes like a company where everyone shares one giant desk -- chaotic, fragile, and impossible to scale.

In this chapter, you will learn how Neam's module system brings that organizational clarity to your code, from single-file scripts all the way to published packages used by teams around the world.


Why Modules? #

As your Neam programs grow beyond a single file, you need a way to organize code into logical units, control what is visible to the outside world, and reuse components across projects. Without modules, every function, every agent definition, and every helper lives in a single global scope -- a recipe for name collisions, tangled dependencies, and unmaintainable codebases.

Neam's module system draws inspiration from Rust and Go: modules map to files, visibility is explicit, and dependencies are declared in a manifest file (neam.toml). This chapter takes you from single-file programs to well-organized, multi-file projects with reusable packages.


Module Declaration #

Every Neam source file can declare which module it belongs to using the module keyword at the top of the file:

neam
module std.rag.error;

The module path uses dot-separated identifiers. By convention, the path mirrors the directory structure:

src/
  rag/
    error.neam      --> module myproject.rag.error
    config.neam     --> module myproject.rag.config
    retriever.neam  --> module myproject.rag.retriever
  ingest/
    error.neam      --> module myproject.ingest.error
    pipeline.neam   --> module myproject.ingest.pipeline

If a file does not include a module declaration, it belongs to the root (unnamed) module. This is typical for entry-point files like src/main.neam.

Naming Conventions #


Importing Modules #

The import Statement #

Use import to bring a module into scope. After importing, you access its public members through the module's last path segment:

neam
import std.rag.error;

{
  let err = error.config_error("model", "Model is required");
  emit str(err);
}

Here, import std.rag.error makes the module available as error. You then call error.config_error(...) to access the public function.

Import Aliases #

When two modules have the same final segment, or when you want a shorter name, use import ... as to create an alias:

neam
import std.rag.error as rag_err;
import std.ingest.error as ingest_err;

{
  let e1 = rag_err.config_error("model", "Model is required");
  let e2 = ingest_err.parse_error("pdf", "Invalid format");
}

Selective Imports #

You can import specific items from a module using curly braces:

neam
import std.math::{sin, cos, pi};

{
  let angle = pi / 4;
  emit "sin(pi/4) = " + str(sin(angle));
  emit "cos(pi/4) = " + str(cos(angle));
}

This brings only sin, cos, and pi into scope -- not the entire std.math module.

The use Statement #

The use statement is an alternative that brings the module into scope. In practice, use and import behave similarly in Neam. The convention is:

neam
module myproject.rag.config;

use myproject.rag.error;

pub fun build_config(config) {
  if (config.retriever == nil) {
    return { ok: false, error: error.config_error("retriever", "Retriever is required") };
  }
  return { ok: true, value: config };
}

The config module uses myproject.rag.error to create structured error values.

Import Patterns at a Glance #

Syntax Effect
import std.math; Access as math.sin(...)
import std.math as m; Access as m.sin(...)
import std.math::{sin, cos}; Access as sin(...), cos(...) directly
use myproject.utils; Same as import, for intra-project modules

Visibility: pub, crate, and super #

Not everything in a module should be accessible to the outside world. Neam uses visibility modifiers to control access.

pub -- Public Visibility #

Functions, variables, and other declarations marked with pub are accessible from any module that imports the containing module:

neam
module myproject.agents.base;

// Public: accessible from anywhere that imports this module
pub fun create_agent(kind, config) {
  return {
    kind: kind,
    config: config,
    id: generate_agent_id(),
    state: agent_state_idle()
  };
}

// Public states
pub fun agent_state_idle() { return { kind: "Idle" }; }
pub fun agent_state_running() { return { kind: "Running" }; }
pub fun agent_state_error(message) { return { kind: "Error", message: message }; }

// Private: only accessible within this file
fun generate_agent_id() {
  return "agent_" + str(random(100000));
}

In this example, create_agent, agent_state_idle, and agent_state_running are public. The helper generate_agent_id is private -- it has no pub keyword, so only code within the same module can call it.

Default (Private) Visibility #

Any declaration without a visibility modifier is private to its module. This is the most restrictive level:

neam
module myproject.utils;

// Private: only usable within myproject.utils
fun internal_helper(data) {
  return data + "_processed";
}

// Public: usable by anyone who imports myproject.utils
pub fun process(data) {
  return internal_helper(data);
}

crate -- Package-Level Visibility #

The crate modifier makes a declaration visible to all modules within the same package (defined by the same neam.toml), but not to external packages that depend on yours:

neam
module myproject.agents.internal;

// Visible within the myproject package, but not to external consumers
crate fun reset_agent_state(agent) {
  agent.state = { kind: "Idle" };
  return agent;
}

This is useful for shared internals that multiple modules in your project need, but that should not be part of your public API.

super -- Parent Module Access #

The super keyword refers to the parent module. It is useful when a submodule needs to access something from its parent without spelling out the full path:

neam
module myproject.agents.helpers;

use super.base;  // Refers to myproject.agents.base

pub fun create_default_agent() {
  return base.special_agent_base("default", {});
}

Visibility Summary #

Modifier Accessible From
pub Any module that imports the declaring module
(none) Only the declaring module (private)
crate Any module in the same package
super Used in use to reference the parent module

Re-Exporting with pub use #

Sometimes a module serves as a facade -- it re-exports items from other modules to provide a simpler public API. The pub use statement makes an imported module's public items available through the re-exporting module:

neam
// File: src/lib.neam
module mylib;

// Re-export these modules as part of mylib's public API
pub use mylib.agents;
pub use mylib.config;
pub use mylib.utils;

Consumers can now import from mylib directly:

neam
import mylib.agents;
import mylib.config;

This pattern keeps your internal module structure flexible -- you can reorganize files without breaking the public API, as long as the re-exports remain the same.


The Standard Library #

Neam ships with a comprehensive standard library organized into focused modules. You access these through the std namespace. Here is an overview of what is available:

Namespace Purpose Key Functions
std.agents Agent utilities base, handoffs, prompts, serving
std.ai AI/ML primitives embed(), classify(), generate()
std.async Asynchronous operations resolve(), all(), delay()
std.audio Audio I/O record(), play(), stream()
std.collections Lists, maps, sets push(), filter(), fold(), keys(), to_set()
std.core Option and Result types some(), none(), ok(), err(), unwrap()
std.crypto Cryptography sha256(), uuid_v4(), base64_encode()
std.data Data formats (JSON, CSV) parse(), stringify(), pretty()
std.graders Agent output grading grade(), rubric(), score()
std.ingest Document ingestion pipeline, parser, store
std.io File I/O read_file(), write_file()
std.math Mathematical functions sin(), cos(), sqrt(), abs(), pi
std.media Image and video utilities resize(), thumbnail(), transcode()
std.net HTTP client and networking get(), post(), request()
std.observability Tracing and monitoring trace(), span(), metrics()
std.project Project metadata access name(), version(), config()
std.rag RAG pipeline retriever, config, document
std.realtime Real-time streaming stream(), subscribe(), emit()
std.schemas Schema definitions define(), validate(), to_json_schema()
std.speech Speech-to-text / TTS transcribe(), synthesize()
std.testing Test framework assert_eq(), assert_ok(), test()
std.text String utilities split(), join(), trim(), replace()
std.time Date and time now(), format(), duration()
std.trust Trust and safety primitives sanitize(), validate(), audit()
std.vad Voice activity detection detect(), is_speech(), threshold()
std.voice Voice agent support listen(), speak(), voice_loop()

Using Standard Library Modules #

neam
import std.net.http;
import std.data.json;
import std.core.result;

fun fetch_weather(city) {
  let url = "https://api.weather.example.com/v1/" + city;

  try {
    let response = http.get(url);
    let data = json.parse(response);
    return result.ok(data);
  } catch (err) {
    return result.err("Failed to fetch weather: " + str(err));
  }
}

The standard library follows the same module conventions as your own code: every public function is marked with pub, internal helpers are private, and modules are organized into clear namespaces. As you progress through this book, you will use many of these modules in agent systems.

🎯 Try It Yourself #1: Standard Library Sampler

Standard Library Sampler

Write a short Neam program that imports three different standard library modules and uses at least one function from each. For example:

  1. Use std.text to split a sentence into words.
  2. Use std.collections.list to filter only words longer than 4 characters.
  3. Use std.data.json to stringify the result and emit it.

Bonus: wrap your logic in a pub fun inside a module called myproject.text_demo and import it from a separate main.neam file.


Project Structure with neam.toml #

Every Neam project has a neam.toml file at its root. This file defines the project metadata, dependencies, build configuration, and more. Here is the complete manifest from the Neam sample project:

toml
# Neam Project Manifest
neam_version = "1.0"

# ============================================
# Project Metadata
# ============================================
[project]
name = "ai-assistant"
version = "0.1.0"
type = "binary"
description = "An AI-powered assistant using Neam"
authors = ["Developer <dev@example.com>"]
license = "MIT"

[project.entry_points]
main = "src/main.neam"
api = "src/api.neam"

# ============================================
# Dependencies
# ============================================
[dependencies]
# Version-based dependency
# utils = "1.0.0"

# Git-based dependency
# ai-tools = { git = "https://github.com/neam/ai-tools" }

# Dependency with features
# ml-lib = { version = "2.0.0", features = ["gpu", "advanced"] }

[dev-dependencies]
# test-utils = "0.1.0"

# ============================================
# Scripts
# ============================================
[scripts]
build = "neamc src/main.neam -o build/main.neamb"
run = "neam build/main.neamb"
test = "neam-cli test tests/**/*.neam"
api = "neam-api --port 8080"
clean = "rm -rf build/"

# ============================================
# Features (Conditional Compilation)
# ============================================
[features]
default = ["basic-agents"]
basic-agents = []
advanced-rag = ["hyde", "self-rag"]
multi-provider = ["openai", "ollama", "anthropic"]

# ============================================
# Agent Configuration
# ============================================
[agent]
provider = "openai"
model = "gpt-4o-mini"
capabilities = ["text-generation", "code-generation"]

[agent.limits]
max-tokens-per-request = 4096
max-concurrent-tools = 5
timeout-seconds = 300
max-retries = 3

# ============================================
# Test Configuration
# ============================================
[test]
timeout = 60
parallel = true
coverage = true
coverage-threshold = 80
include = ["tests/**/*.neam"]
exclude = ["tests/fixtures/**"]

Key Sections #

[project] and [package] -- Name, version, type (binary or library), description, and license. The entry_points table maps named targets to source files.

📝 Note

The [package] key is also accepted as an alternative to [project] in your manifest. Both are recognized by the toolchain. The [package] key is the preferred convention for published libraries, while [project] remains common for applications. Here is an example using [package]:

toml
[package]
name = "agent-utils"
version = "1.0.0"
description = "Utility functions for Neam agents"
keywords = ["agents", "utilities"]
categories = ["agent-development"]
repository = "https://github.com/neam-lang/agent-utils"

[dependencies] -- External packages your project depends on. Three formats are supported: - Version string: utils = "1.0.0" - Git repository: ai-tools = { git = "https://github.com/neam/ai-tools" } - Version with features: ml-lib = { version = "2.0.0", features = ["gpu"] }

[dev-dependencies] -- Packages needed only for development and testing.

[scripts] -- Named commands you can run with neam-cli run <script-name>.

[features] -- Conditional compilation flags. Enable or disable features at build time.

[agent] -- Default agent configuration shared across the project.

[test] -- Test runner configuration: timeout, parallelism, coverage thresholds.


Standard Project Layout #

The following directory structure is the recommended layout for Neam projects:

text
my-agent-project/
  neam.toml                   # Project manifest
  src/
    main.neam                 # Main entry point
    api.neam                  # Alternative entry point (API server)
    agents/
      triage.neam             # Triage agent module
      specialist.neam         # Specialist agents module
      helpers.neam            # Shared agent helpers
    utils/
      validation.neam         # Input validation utilities
      formatting.neam         # Output formatting utilities
  tests/
    test_agents.neam          # Agent integration tests
    test_utils.neam           # Unit tests for utilities
  docs/
    README.md                 # Project documentation
  build/
    main.neamb                # Compiled bytecode (generated)
main.neam
agents/
triage.neam
agents/
specialist
agents/
helpers
std.rag.*
std.agents.*

Building a Multi-File Project #

Let us walk through creating a project from scratch.

Step 1: Initialize the Project #

bash
neam-pkg init customer-support
cd customer-support

This creates the directory structure with a neam.toml and a src/main.neam stub.

Step 2: Define Shared Utilities #

Create src/utils/validation.neam:

neam
module customer_support.utils.validation;

pub fun validate_email(email) {
  if (email == nil) {
    return {"ok": false, "error": "Email is required"};
  }
  if (!email.contains("@")) {
    return {"ok": false, "error": "Invalid email format"};
  }
  return {"ok": true, "value": email};
}

pub fun validate_query(query) {
  if (query == nil) {
    return {"ok": false, "error": "Query is required"};
  }
  if (len(query) < 3) {
    return {"ok": false, "error": "Query too short (minimum 3 characters)"};
  }
  if (len(query) > 1000) {
    return {"ok": false, "error": "Query too long (maximum 1000 characters)"};
  }
  return {"ok": true, "value": query};
}

Step 3: Define Agent Modules #

Create src/agents/triage.neam:

neam
module customer_support.agents.triage;

use customer_support.utils.validation;

agent TriageAgent {
  provider: "openai"
  model: "gpt-4o-mini"
  system: "Classify queries into: BILLING, TECHNICAL, GENERAL. Reply with only the category."
}

pub fun classify(query) {
  let valid = validation.validate_query(query);
  if (!valid["ok"]) {
    return valid;
  }

  try {
    let category = TriageAgent.ask(query);
    return {"ok": true, "value": category};
  } catch (err) {
    return {"ok": false, "error": "Triage failed: " + str(err)};
  }
}

Create src/agents/specialist.neam:

neam
module customer_support.agents.specialist;

use customer_support.utils.validation;

agent BillingAgent {
  provider: "openai"
  model: "gpt-4o-mini"
  system: "You are a billing specialist. Help with payment and invoice questions."
}

agent TechnicalAgent {
  provider: "openai"
  model: "gpt-4o"
  system: "You are a technical support specialist. Help with product issues."
}

agent GeneralAgent {
  provider: "openai"
  model: "gpt-4o-mini"
  system: "You are a general support agent. Help with common questions."
}

pub fun handle(category, query) {
  let valid = validation.validate_query(query);
  if (!valid["ok"]) {
    return valid;
  }

  try {
    if (category == "BILLING") {
      return {"ok": true, "value": BillingAgent.ask(query)};
    }
    if (category == "TECHNICAL") {
      return {"ok": true, "value": TechnicalAgent.ask(query)};
    }
    return {"ok": true, "value": GeneralAgent.ask(query)};
  } catch (err) {
    return {"ok": false, "error": "Specialist failed: " + str(err)};
  }
}

Step 4: Wire It Together in main.neam #

neam
// File: src/main.neam
// Entry point -- no module declaration needed

import customer_support.agents.triage;
import customer_support.agents.specialist;

{
  emit "=== Customer Support System ===";

  let query = "Why was I double-charged this month?";
  emit "Query: " + query;

  // Step 1: Classify
  let classification = triage.classify(query);
  if (!classification["ok"]) {
    emit "Error: " + classification["error"];
    panic("Triage failed");
  }
  let category = classification["value"];
  emit "Category: " + category;

  // Step 2: Route to specialist
  let response = specialist.handle(category, query);
  if (response["ok"]) {
    emit "Response: " + response["value"];
  } else {
    emit "Error: " + response["error"];
  }

  emit "=== Done ===";
}

Step 5: Build and Run #

bash
# Compile
neamc src/main.neam -o build/main.neamb

# Run
neam build/main.neamb

The Package Manager: neam-pkg #

Neam includes a package manager for creating, installing, and publishing reusable libraries.

Creating a New Package #

bash
neam-pkg init my-agent-lib --type library

This generates:

text
my-agent-lib/
  neam.toml
  src/
    lib.neam          # Library entry point
  tests/
    test_lib.neam

The neam.toml has type = "library" instead of type = "binary":

toml
[project]
name = "my-agent-lib"
version = "0.1.0"
type = "library"
description = "A reusable agent library"

Installing Dependencies #

bash
# Install a published package
neam-pkg install rag-utils

# Install from a Git repository
neam-pkg install --git https://github.com/neam-community/rag-utils

# Install a specific version
neam-pkg install rag-utils@2.1.0

After installation, the dependency is added to your neam.toml automatically:

toml
[dependencies]
rag-utils = "2.1.0"

Publishing a Package #

bash
# Verify the package builds and passes tests
neam-pkg check

# Publish to the Neam package registry
neam-pkg publish
💡 Tip

Run neam-pkg check before every publish. It validates your neam.toml, compiles all source files, runs tests, and checks that all public functions are documented.

Common neam-pkg Commands #

Command Description
neam-pkg init <name> Create a new project
neam-pkg init <name> --type library Create a new library
neam-pkg install <pkg> Install a dependency
neam-pkg install --git <url> Install from Git
neam-pkg update Update all dependencies
neam-pkg remove <pkg> Remove a dependency
neam-pkg check Validate, compile, and test
neam-pkg publish Publish to registry
neam-pkg search <query> Search the package registry
neam-pkg list List installed packages
neam-pkg outdated Show outdated packages
neam-pkg link Link local package for development
neam-pkg login Authenticate with registry
neam-pkg docs <pkg> Open package documentation

The Package Format (.neampkg) #

When you publish a package, neam-pkg bundles your source code, manifest, and metadata into a .neampkg archive. Here is what the package contains:

my-package-1.0.0.neampkg

The checksums.sha256 file ensures integrity during download, and the optional signature.sig file allows cryptographic verification of the package author.

The Registry Ecosystem #

The package registry is the central hub that connects your local tooling to shared packages. Here is how the pieces fit together:

neam-pkg
CLI
registry.neam
.dev
Package Storage
(S3/CloudFlare)
neam.toml
manifest
neam.lock
lock file
~/.neam/packages/
(local cache)

When you run neam-pkg install, the CLI resolves versions from the registry at registry.neam.dev, downloads packages into your local cache at ~/.neam/packages/, and writes a neam.lock file to pin exact versions. The lock file ensures that every developer on your team -- and your CI pipeline -- uses identical dependency versions.

💡 Pro Tip

When you are building a library that is used by multiple local projects, use neam-pkg link instead of publishing to the registry during development. This command creates a symlink from your library's source directory into the consuming project's dependency tree, so every change you make is immediately reflected without re-publishing. Run neam-pkg link from the library directory, then neam-pkg link <library-name> from the consuming project. When you are ready to ship, replace the link with a versioned dependency in neam.toml.

Building Your First Package #

Let us walk through the complete lifecycle of creating, testing, and publishing a small library package from scratch.

Step 1: Create the Package

bash
# Initialize a new library package
neam-pkg init text-toolkit --type library
cd text-toolkit

This scaffolds the standard library layout:

text
text-toolkit/
  neam.toml
  src/
    lib.neam
  tests/
    test_lib.neam

Step 2: Define the Public API

Edit src/lib.neam to re-export your modules:

neam
module text_toolkit;

pub use text_toolkit.core;

Step 3: Write the Core Logic

Create src/core.neam:

neam
module text_toolkit.core;

// Count the number of words in a text string
pub fun word_count(text) {
  if (text == nil || len(text) == 0) {
    return 0;
  }
  let words = split(text, " ");
  // Filter out empty strings from multiple spaces
  let real_words = filter(words, fn(w) { return len(w) > 0; });
  return len(real_words);
}

// Truncate text to a maximum length, appending "..." if shortened
pub fun truncate(text, max_length) {
  if (text == nil) {
    return "";
  }
  if (len(text) <= max_length) {
    return text;
  }
  return slice(text, 0, max_length) + "...";
}

// Convert a string to a URL-friendly slug
pub fun slugify(text) {
  if (text == nil) {
    return "";
  }
  let lower = lowercase(text);
  let slug = replace(lower, " ", "-");
  return slug;
}

Step 4: Write Tests

Edit tests/test_lib.neam:

neam
import text_toolkit.core;

test "word_count counts words correctly" {
  assert_eq(core.word_count("hello world"), 2);
  assert_eq(core.word_count("one"), 1);
  assert_eq(core.word_count(""), 0);
  assert_eq(core.word_count(nil), 0);
}

test "truncate shortens long text" {
  assert_eq(core.truncate("hello world", 5), "hello...");
  assert_eq(core.truncate("hi", 10), "hi");
  assert_eq(core.truncate(nil, 5), "");
}

test "slugify creates URL-friendly strings" {
  assert_eq(core.slugify("Hello World"), "hello-world");
  assert_eq(core.slugify("Neam Is Great"), "neam-is-great");
  assert_eq(core.slugify(nil), "");
}

Step 5: Validate and Publish

bash
# Run the full check: validate manifest, compile, run tests
neam-pkg check

# Authenticate with the registry (first time only)
neam-pkg login

# Publish to the Neam package registry
neam-pkg publish

After publishing, anyone can install your package with:

bash
neam-pkg install text-toolkit
🎯 Try It Yourself #2: Extend the Package

Extend the Package

Add two more functions to text-toolkit:

  1. reverse(text) -- returns the text with characters in reverse order.
  2. capitalize(text) -- returns the text with the first character uppercased and the rest unchanged.

Write tests for both functions, run neam-pkg check, and verify everything passes. Then think about this: should reverse and capitalize live in core.neam, or would a new module like text_toolkit.transform be a better home? What are the trade-offs?


Creating Reusable Agent Libraries #

A well-designed agent library exposes a clean public API, hides implementation details, and is configurable through parameters rather than hardcoded values.

Example: A Reusable Summarization Library #

neam
module summarizer;

// Re-export the public API
pub use summarizer.core;
pub use summarizer.config;
neam
module summarizer.config;

pub fun default_config() {
  return {
    "provider": "openai",
    "model": "gpt-4o-mini",
    "max_length": 200,
    "style": "concise"
  };
}

pub fun with_model(config, model) {
  config["model"] = model;
  return config;
}

pub fun with_max_length(config, max_length) {
  config["max_length"] = max_length;
  return config;
}

pub fun with_style(config, style) {
  config["style"] = style;
  return config;
}
neam
module summarizer.core;

use summarizer.config;

// This agent is configured at runtime based on the config
agent SummarizeAgent {
  provider: "openai"
  model: "gpt-4o-mini"
  system: "Summarize the given text concisely."
}

pub fun summarize(text, cfg) {
  if (cfg == nil) {
    cfg = config.default_config();
  }

  let prompt = build_prompt(text, cfg);

  try {
    let result = SummarizeAgent.ask(prompt);
    return {"ok": true, "value": result};
  } catch (err) {
    return {"ok": false, "error": "Summarization failed: " + str(err)};
  }
}

pub fun summarize_batch(texts, cfg) {
  let results = [];
  for (text in texts) {
    let result = summarize(text, cfg);
    push(results, result);
  }
  return results;
}

// Private helper -- not exported
fun build_prompt(text, cfg) {
  let prompt = "Summarize the following text";

  if (cfg["style"] == "concise") {
    prompt = prompt + " in a concise, bullet-point format";
  } else if (cfg["style"] == "detailed") {
    prompt = prompt + " in a detailed paragraph format";
  }

  if (cfg["max_length"] != nil) {
    prompt = prompt + " (maximum " + str(cfg["max_length"]) + " words)";
  }

  prompt = prompt + ":\n\n" + text;
  return prompt;
}

Using the Library from Another Project #

In the consuming project's neam.toml:

toml
[dependencies]
summarizer = "1.0.0"

In the consuming project's code:

neam
import summarizer.core;
import summarizer.config;

{
  let cfg = config.default_config();
  cfg = config.with_style(cfg, "detailed");
  cfg = config.with_max_length(cfg, 100);

  let article = "Neam is a programming language designed for building AI agent systems...";
  let result = core.summarize(article, cfg);

  if (result["ok"]) {
    emit result["value"];
  } else {
    emit "Error: " + result["error"];
  }
}

Library Design Guidelines #

1. Expose configuration through builder functions. Instead of requiring users to construct config maps manually, provide default_config() and with_*() builder functions. This pattern is used throughout the Neam standard library.

2. Return result maps from public functions. Do not throw exceptions from library code. Return {ok: true/false, ...} so the consumer decides how to handle errors.

3. Keep agents private when possible. If your library creates agents internally, the consumer should not need to know about them. Expose a function-based API, not raw agent references.

4. Document your public API. Every pub fun should have a comment explaining its parameters, return value, and error conditions.

5. Include tests. Ship a tests/ directory with your library. The neam-pkg check command runs them automatically.


Feature Flags #

The [features] section of neam.toml enables conditional compilation. Different consumers can enable different subsets of functionality:

toml
[features]
default = ["basic-agents"]
basic-agents = []
advanced-rag = ["hyde", "self-rag"]
multi-provider = ["openai", "ollama", "anthropic"]

In consumer neam.toml:

toml
[dependencies]
my-agent-lib = { version = "1.0.0", features = ["advanced-rag", "multi-provider"] }

This keeps the compiled output lean: features not enabled are not compiled into the final bytecode.


Summary #

This chapter covered the full lifecycle of code organization in Neam:

Concept Syntax / Tool
Module declaration module myproject.utils;
Import import std.rag.error;
Import alias import std.rag.error as rag_err;
Selective import import std.math::{sin, cos};
Use (intra-project) use myproject.utils;
Re-export pub use mylib.agents;
Public visibility pub fun ...
Package-level visibility crate fun ...
Parent module reference use super.base;
Project manifest neam.toml
Create project neam-pkg init <name>
Install dependency neam-pkg install <pkg>
Publish package neam-pkg publish
Link local package neam-pkg link
Package format .neampkg archive

You also surveyed the Neam standard library (std.*), which provides ready-made modules for agents, AI primitives, async operations, audio, collections, cryptography, data formats, grading, ingestion, I/O, math, media, networking, observability, project metadata, RAG, real-time streaming, schemas, speech, testing, text, time, trust and safety, voice activity detection, and voice agents.

You now have all the language fundamentals needed to build real agent systems. Part II is complete. In Part III, you will use everything you have learned to declare your first AI agent, connect to LLM providers, and build multi-agent architectures.


Exercises #

Exercise 9.1: Module Extraction Take the customer-support example from this chapter and add a new module: customer_support.utils.formatting. Move any string formatting logic into this module and expose it via pub fun declarations. Update the existing modules to import and use the new formatting module.

Exercise 9.2: Visibility Audit Review the following code and identify which functions should be pub, which should be crate, and which should be private. Justify each choice.

neam
module myproject.agents.router;

fun calculate_score(query, agent_description) {
  // Internal scoring logic
  return 0.85;
}

fun select_best_agent(scores) {
  // Pick the highest scoring agent
  let best = nil;
  let best_score = 0;
  // ...
  return best;
}

fun route_query(query, agents) {
  // Main routing logic
  let scores = [];
  // ...
  return select_best_agent(scores);
}

fun reset_router_state() {
  // Clear cached routing decisions
}

Exercise 9.3: Library from Scratch Create a reusable Neam library called text-toolkit that provides: 1. A word_count(text) function. 2. A truncate(text, max_length) function that cuts text at max_length characters and appends "..." if it was truncated. 3. A slugify(text) function that converts a string to lowercase and replaces spaces with hyphens.

Write the neam.toml, the module file(s), and at least three tests. Follow the builder pattern for any configuration.

Exercise 9.4: Dependency Graph Draw the module dependency graph (on paper or as ASCII art) for a project with these imports:

text
main.neam        imports: agents.router, agents.specialist, utils.logging
agents/router    imports: agents.specialist, utils.validation
agents/specialist imports: utils.validation, utils.formatting
utils/validation  imports: (none)
utils/formatting  imports: (none)
utils/logging     imports: utils.formatting

Identify whether there are any circular dependencies. What would happen if utils.validation tried to import agents.router?

Exercise 9.5: Feature Flags Design a neam.toml for an agent library called smart-agents that supports these optional features: - openai -- enables OpenAI provider support. - ollama -- enables Ollama provider support. - rag -- enables RAG retrieval integration. - voice -- enables voice agent capabilities.

The default features should be openai only. Write out the complete [features] section and explain how a consumer would enable ollama and rag but not voice.

Exercise 9.6: Package Publishing Simulation Walk through the complete lifecycle of building and consuming a package:

  1. Create a package called string-metrics with neam-pkg init string-metrics --type library. It should expose two public functions:
  2. levenshtein(a, b) -- returns the edit distance between two strings (you can use a simplified version that just counts character differences at each position).
  3. similarity(a, b) -- returns a number between 0.0 and 1.0 representing how similar the strings are (hint: use levenshtein internally).

  4. Write the neam.toml using the [package] key with at least name, version, description, keywords, and categories.

  5. Write at least four tests covering normal cases, edge cases (empty strings, nil input), and identical strings.

  6. Create a consumer project called name-matcher with neam-pkg init name-matcher. In its neam.toml, add string-metrics as a dependency. Write a main.neam that imports string_metrics.core and uses similarity() to find the closest match for a name in a list of candidates:

neam
import string_metrics.core;

{
  let target = "Praveen";
  let candidates = ["Pravin", "Praven", "Preveen", "Pranav", "Pavan"];

  let best_match = nil;
  let best_score = 0.0;

  for (name in candidates) {
    let score = core.similarity(target, name);
    if (score > best_score) {
      best_score = score;
      best_match = name;
    }
  }

  emit "Best match for '" + target + "': " + best_match + " (score: " + str(best_score) + ")";
}
  1. Verify the full workflow: neam-pkg check in the library, neam-pkg install in the consumer, then compile and run.
Start typing to search...