# 14.1 From scripts to programs: modules (/building-ai-workers/structuring-programs/modules)

---
type: Document
title: "14.1 From scripts to programs: modules"
description: "How to find your way around a repository an agent split into modules, by what each file imports, and what to check before it adds a package."
status: stable
order: 314.01
ksor:
  owner: team:panaversity
  audience: [ public ]
  approval:
    by: process:panaversity
    at: 2026-11-10T15:33:14Z
chapter: "14"
part: III
expert_status: builder-only
concepts: [ "14.1" ]
last_verified: 2026-10-30
sources:
  - id: node-typescript
    title: "Modules: TypeScript (Node.js, accessed 2026-10-30)"
    resource: https://nodejs.org/api/typescript.html
  - id: uv-cli
    title: "uv CLI reference (Astral, accessed 2026-10-30)"
    resource: https://docs.astral.sh/uv/reference/cli/
generated:
  at: 2026-11-10T15:33:14Z
  by: process:panaversity
trust_tier: unverified
build_id: sha256:46fd53c5d7ab1c14f6347908d45c9fdaecda4d914439923ee878bdcecd57803e
dirty: true
ksor_version: 0.0.60
---

**In everyday life.** A small shop keeps everything in one notebook, until it is too thick to use. A larger shop splits it into labeled folders, and each folder says on its cover which others it refers to. One wrong entry in the folder many others refer to, such as the price list, reaches every order.

**What you will learn.** How to find your way around a project an agent split into files, and when to let it add code someone else wrote.

**Why it matters.** The files that every other file uses are where one change reaches everything.

### Where do I start in a repository I did not write?

At the top of each file, with the lines that say what it uses from other files. These words name the parts.

| Idea | What it means | In `brightline-ap` |
| --- | --- | --- |
| **Module** | One file, one job | `src/money.ts` turns cents into dollars |
| **Export** | A name other files may use | `export function usd(...)` |
| **Import** | A name this file uses from another | `import { usd } from "./money.ts"` |
| **Package** | A named group of modules | `py/brightline_ap/`, or `zod` from npm |
| **Dependency** | A package your code needs | `zod` in `package.json`, `pydantic` in `pyproject.toml` |
| **Lock file** | The exact version of every dependency, and of theirs | `package-lock.json`, `py/uv.lock` |

**Read a repository by its imports.** A file's import lines are the note on a folder's cover that says which other folders it refers to. Drawn as boxes and arrows, they form an **import graph**. Look for three things on it.

- **Edges**, where data comes in from outside. Mark these first.
- **Foundations**, the files that many others import, like the shop's price list. A change there reaches everywhere.
- A file that nothing imports. It is either an **entry point**, the file a command starts, or **dead code**, which nothing uses.

**At work.** The agent split Brightline's scripts into nine modules in `src/`. Ana does not start with the longest file. She draws the graph on paper and marks the edges first: files that read a CSV export, such as `due-by-friday.ts`, and functions that turn its rows into records, such as `invoiceFromRow`. Five files import `csv.ts`, and three import `due-date.ts`. Those are the foundations, so she reads them next and tests them hardest.

Here is the note on one folder's cover: two import lines, then a line that uses both names. Predict what this prints.

```ts tab="TypeScript" tab-group="language"
import { usd } from "../src/money.ts";          // from the money file, take usd
import { dueDate } from "../src/due-date.ts";   // from the due-date file, take dueDate

console.log(usd(1922953), dueDate("2026-10-07", "Net 30"));
```

```python tab="Python" tab-group="language"
from brightline_ap.due_date import due_date   # from the due_date file, take due_date
from brightline_ap.money import usd           # from the money file, take usd

print(usd(1922953), due_date("2026-10-07", "Net 30"))
```

Both print:

```text
$19,229.53 2026-11-06
```

| Language | How to read where an import comes from |
| --- | --- |
| TypeScript | A path that starts with `./` or `../` is a file in this repository, and it ends in `.ts`, which Node requires. A name with no path, such as `"zod"`, is a package from `node_modules/`. |
| Python | A local import is a dotted name from the package, such as `brightline_ap.money`. |

### Should I let the agent add a package?

Only after three questions. A package is someone else's code, and it can do anything your account can do on this computer. Is the name spelled exactly right, is it the real, well-known package and not a made-up or look-alike name, and is it needed at all? To find out, ask the agent to show you each package's page on npmjs.com or pypi.org, and to say what this project uses it for. A real, well-known package has years of history and many downloads. Attackers publish packages one letter away from popular names, and agents sometimes suggest a package for a job three lines of code would do.

### Why commit the lock file?

So a clean copy of the repository next month installs exactly what you tested today. In this book, `npm ci` and `uv sync` install from the lock files.

### How do I set up to try this?

Once, for the whole chapter.

1. Download [brightline-practice-ch14.zip](https://github.com/panaversity/agentfactory-v2-resources/releases/latest/download/brightline-practice-ch14.zip), and unzip it.
2. Open the `brightline-practice-ch14` folder in your agent, in the mode that asks before it acts, as in [Chapter 13](../programming-fundamentals/you-read-the-agent-writes.md#how-do-i-set-up-to-try-this).
3. Its `AGENTS.md` says TypeScript. If you chose Python, send: "Please set my language in AGENTS.md to Python."
4. Open `package.json` and `pyproject.toml` in a text editor. Answer the three questions for each package they name. Then send: "Please install this folder's packages from its lock files, with `npm ci` and `uv sync`. Before each command, tell me which packages it will install." Compare the names with your list before you approve.

### Try it

**Run.** Send: "Please run the file in 14-1 and show me what it prints. Don't explain it yet."

**Modify.** Send: "Please also import TERMS_DAYS from the due-date module in the file, and print it on a new last line. Don't run it yet." TypeScript can import only a name marked `export`. Python can import any name that is not inside a function or a class. Open the due-date file in `14-1` in a text editor, find `TERMS_DAYS`, and write down what will happen. Then ask the agent to run it.

**Investigate.** Ask about anything you got wrong.

**Make.** Send: "Please make a module in 14-1 called fees, with one function that adds a $25.00 fee to an amount in cents, and a new file called mine that imports it and prints one answer. Don't run it yet." Find the import line, say what it will print, and then ask the agent to run it.

**What you should see.** TypeScript stops with a `SyntaxError`, Node's error for importing a name that is not exported. It prints nothing else, because Node loads every import before it runs any line. Python prints the usual line, then the terms and their days.

**The operating rule:** read the import graph before the functions. Mark where data comes in, read the foundations next, and approve a package only after you check its exact name and need.

![Figure 14.1. A reading map of brightline-ap in four layers: shared helpers and libraries (due-date, csv, money and zod), records and validation (schemas, vendor and invoice), workflow helpers (load-invoices and invoice-book), and commands (list-vendors, ap-client, export-json, reconcile, due-by-friday and scripts/ap-api). Mark the edges first: load-invoices and ap-client are outlined in red. Then read the shared helpers and the code that uses them. due-date is imported by six files and csv by seven. Two import paths are traced: export-json to load-invoices to schemas, and due-by-friday to invoice-book to invoice.](img/import-graph.png)

*Figure 14.1. A reading map at the end of the chapter, with more files than above. Red outlines mark its two main edges. After the edges, read the shared files at the bottom. Arrows point from a file to what it imports.*

**Next.** [14.2](types-you-write-down.md) writes down which values those files may pass to each other.
