# Building modules

URL: https://aycode.ai/docs/modules/

Build your own extensions for AyCode without AyCode’s source: one folder, one program, clear permissions.

## Your first module in a minute

1. **Settings → Modules → New module** and pick an empty folder.
2. AyCode writes a module that runs right away: the manifest `aycode-module.json`, a skill, a program in `server/index.mjs` with the SDK `server/aycode.mjs`, and tests. The folder is linked afterwards.
3. The module’s card shows what it may do. **Allow and turn on**, then mention **$module-name** in a chat.
4. Tests run without AyCode: `node --test server/index.test.mjs`.

The SDK is a single file without dependencies (Node 18 or newer). The guide is in the new folder as `README.md`.

## Separate from AyCode

Your own code runs as its own program, an MCP server the agents call, never inside AyCode. The program talks to AyCode only through the **module API**: on this computer only (127.0.0.1), with its own key per module, versioned. Through the API, one module cannot speak for another or read its storage.

On the **Mac** the program runs walled in (macOS sandbox): it reads the system, its runtime (Node) and its own folder, but nothing in your home folder, so no vault, no projects, no keys. It writes only to its data folder (`AYCODE_MODULE_DATA`) and its temp folder. On the network it reaches only AyCode, and the internet only with the `network` permission. It cannot make other programs act for it. A program that cannot be walled in does not start on the Mac at all, and the module’s card says why.

> On **Windows and Linux** there are no such walls yet: there the program runs with your user’s rights and can do anything you can. Permissions there only govern what AyCode gives it. The boundary is then where it comes from: public modules must be signed, and you choose to trust a publisher. Each module’s card says whether its program runs walled in.

## Permissions

Every module may use its own settings and storage. Everything else is listed in the manifest under `permissions`, and you confirm it before turning the module on. If an update asks for more, AyCode asks again.

| Permission | What the module may do |
| --- | --- |
| `brain:read` | search and read notes in your second brain, look up what AyCode remembered |
| `brain:propose` | suggest note changes; you confirm each one |
| `notify` | show notices in AyCode, at most six a minute |
| `projects:read` | see your projects and their folders |
| `network` | connect to the internet (blocked on the Mac without it) |

## The API

| SDK call | Permission |
| --- | --- |
| `aycode.app.info()` | always |
| `aycode.settings()` | always |
| `aycode.storage.get / set / delete / keys` | always (4 MB per module) |
| `aycode.brain.search / note / related / memory` | `brain:read` |
| `aycode.brain.proposeNote({ path, text, reason })` | `brain:propose` |
| `aycode.notify(text)` | `notify` |
| `aycode.projects.list()` | `projects:read` |

Errors come with a code (`forbidden`, `off`, `unavailable` …) and a readable message. Writing in another language? Use the protocol directly: `POST /v1/call` with the module’s key; AyCode hands the address and the key to the program as environment variables.

## Sharing

- **Private**: just for you, may be unsigned.
- **Public**: for everyone, must be signed with your publisher key. Every version with the same key, or AyCode refuses the update.
- **Licensed**: for buyers with a licence key you issue with the same key. AyCode checks it offline.

A module is packed into one `.aymodule` file, opened under **Modules → Install module**.
