# Ymer Node v0.5.0 - Table of Contents

> Headless local MCP node providing notebook, references and script capability to LLM workers

## Pages

- [README](readme.md)
- [Glossary](glossary.md)
- [Scripts — batteries and their boundary](scripts.md)

## Modules

- [YmerNode](YmerNode.md): This module is the **map** — what exists and why. Each entry defends a module's
existence; how a module is designed lives in its own `@moduledoc`.
- [YmerNode.Mcp](YmerNode.Mcp.md): The MCP mount — the node's entire external surface.
- [YmerNode.Mcp.Endpoint](YmerNode.Mcp.Endpoint.md): The HTTP entry point: routes paths to `YmerNode.Mcp`, and answers 404 to
everything else.
- [YmerNode.Mcp.McpServer](YmerNode.Mcp.McpServer.md): The instructions the node hands every MCP client at connect.
- [YmerNode.Mcp.Tools.Helpers](YmerNode.Mcp.Tools.Helpers.md): The four helpers a tool's action and format layers share, and nothing else.
- [YmerNode.Mcp.Tools.Notebook](YmerNode.Mcp.Tools.Notebook.md): Wymcp tool `notebook` — an open SQL surface over `notebook.db`, the node's own
private store, together with the actions that keep it safe.
- [YmerNode.Mcp.Tools.Notebook.Actions](YmerNode.Mcp.Tools.Notebook.Actions.md): Action implementations for the `notebook` MCP tool
(`YmerNode.Mcp.Tools.Notebook`, which calls `run/2`) — a thin boundary over
`YmerNode.Notebook` and `YmerNode.Notebook.Backup`. This is a trust boundary:
`sql`, `table` and `id` are guarded `is_binary` in each head because nothing
downstream validates them — the MCP dispatch layer checks that a parameter is
present but never what type it holds — so `sql` and `table` flow straight into
SQLite and `id` flows into filename construction. Each action returns
`{:ok, data, hint_ctx}` or `{:error, {reason, ctx}}` — and, where the error is one
the caller can act on, `{:error, {reason, ctx}, hint_ctx}`, the three-element form
that puts a follow-up hint on the error payload rather than only in its prose.
- [YmerNode.Mcp.Tools.Notebook.Errors](YmerNode.Mcp.Tools.Notebook.Errors.md): Translates `YmerNode.Notebook` and `YmerNode.Notebook.Backup` error reasons into
LLM-readable messages. SQLite errors are surfaced verbatim so the agent can read
and fix its own SQL; backup failures never are, because their detail carries
filesystem paths the caller must not see.
- [YmerNode.Mcp.Tools.Notebook.Format](YmerNode.Mcp.Tools.Notebook.Format.md): Shapes `YmerNode.Notebook` and `YmerNode.Notebook.Backup` results into
JSON-serialisable maps for MCP responses.
Query results pass through as parallel `columns`/`rows` arrays (compact and
order-preserving) rather than per-row maps.

- [YmerNode.Mcp.Tools.Notebook.Hints](YmerNode.Mcp.Tools.Notebook.Hints.md): Follow-up hints for the `notebook` tool, keyed off the hint_context maps
`YmerNode.Mcp.Tools.Notebook.Actions` produces. After `execute` creates schema, the
natural next steps are describing or querying it; after a capture the natural
next step is confirming it. A completed restore needs no follow-up either, since
the roll-back is already done — but a restore that failed recoverably does: the
hint carries the id of the backup to restore, or of the restore to retry, so the
recovery is one call away instead of a re-read of the error text. Everything else
falls through to none — including every answer about a notebook that cannot take
the call, whose next action is a person's and not another tool call, and a
backup that will not open, whose next action is a different id this module has
no way to choose.

- [YmerNode.Mcp.Tools.Notebook.Schemas](YmerNode.Mcp.Tools.Notebook.Schemas.md): Schema definitions for the `notebook` tool's actions. The `:notes`/`:examples` are the
agent's primary documentation for sqlite-vec usage and the INTEGER-PRIMARY-KEY
join discipline — they surface via the `help` tool.

- [YmerNode.Mcp.Tools.References](YmerNode.Mcp.Tools.References.md): Wymcp tool `references` — the registry of pointers at where knowledge lives,
and the cache of what their targets say.
- [YmerNode.Mcp.Tools.References.Actions](YmerNode.Mcp.Tools.References.Actions.md): Action implementations for the `references` tool — the boundary over the
`YmerNode.References` context.
- [YmerNode.Mcp.Tools.References.Errors](YmerNode.Mcp.Tools.References.Errors.md): Translates the `references` tool's error reasons, optionally with context,
into messages a worker can act on. Called by
`YmerNode.Mcp.Tools.References`'s `c:Wymcp.Tool.handle_error/1`.
- [YmerNode.Mcp.Tools.References.Format](YmerNode.Mcp.Tools.References.Format.md): Response shaping for the `references` tool.
- [YmerNode.Mcp.Tools.References.Hints](YmerNode.Mcp.Tools.References.Hints.md): Follow-up hints for the `references` tool, keyed off the hint_context maps
`YmerNode.Mcp.Tools.References.Actions` produces.
- [YmerNode.Mcp.Tools.References.Schemas](YmerNode.Mcp.Tools.References.Schemas.md): Action schemas for the `references` tool. The `notes` surface through the
`help` tool and are the worker-facing contract documentation — the mode
contract, the duplicate rule, the read window, and the membrane
(`YmerNode.References` § The membrane).

- [YmerNode.Mcp.Tools.References.Validate](YmerNode.Mcp.Tools.References.Validate.md): Value validation for the `references` tool's params.
- [YmerNode.Mcp.Tools.Schedules](YmerNode.Mcp.Tools.Schedules.md): Wymcp tool `schedules` — adding, listing, updating and removing the standing
instructions `YmerNode.Schedules` fires, and listing and stopping the watches
the `references` tool starts.
- [YmerNode.Mcp.Tools.Schedules.Actions](YmerNode.Mcp.Tools.Schedules.Actions.md): Action implementations for the `schedules` tool — the boundary over
`YmerNode.Schedules`.
- [YmerNode.Mcp.Tools.Schedules.Errors](YmerNode.Mcp.Tools.Schedules.Errors.md): Translates the `schedules` tool's error reasons into messages a worker can act
on. Called by `YmerNode.Mcp.Tools.Schedules`'s `c:Wymcp.Tool.handle_error/1`.
- [YmerNode.Mcp.Tools.Schedules.Schemas](YmerNode.Mcp.Tools.Schedules.Schemas.md): Action schemas for the `schedules` tool. The `notes` surface through the `help`
tool and are the worker-facing contract: what a cron expression and a lifetime
look like, what `add` refuses rather than leaving to a firing, and what a
firing skips.

- [YmerNode.Mcp.Tools.ScriptAuthor](YmerNode.Mcp.Tools.ScriptAuthor.md): Wymcp tool `script_author` — writing the scripts this node accepts.
- [YmerNode.Mcp.Tools.ScriptAuthor.Actions](YmerNode.Mcp.Tools.ScriptAuthor.Actions.md): Action implementations for the `script_author` tool — the boundary over
`YmerNode.Scripts`'s write verbs.
- [YmerNode.Mcp.Tools.ScriptAuthor.Errors](YmerNode.Mcp.Tools.ScriptAuthor.Errors.md): Translates the `script_author` tool's error reasons into messages a worker can
act on. Called by `YmerNode.Mcp.Tools.ScriptAuthor`'s
`c:Wymcp.Tool.handle_error/1`.
- [YmerNode.Mcp.Tools.ScriptAuthor.Hints](YmerNode.Mcp.Tools.ScriptAuthor.Hints.md): Follow-up hints for the `script_author` tool, keyed off the hint_context maps
`YmerNode.Mcp.Tools.ScriptAuthor.Actions` produces.
- [YmerNode.Mcp.Tools.ScriptAuthor.Schemas](YmerNode.Mcp.Tools.ScriptAuthor.Schemas.md): Action schemas for the `script_author` tool. The `notes` surface through the
`help` tool and are the worker-facing contract of each call — what it does,
what it refuses, what its flags mean. The script contract itself is not
written here: `scripts guide` renders it from `YmerNode.Script`'s own docs,
and the notes of `check` and `create` point there.

- [YmerNode.Mcp.Tools.ScriptFormat](YmerNode.Mcp.Tools.ScriptFormat.md): Response shaping for both script tools — `YmerNode.Mcp.Tools.Scripts` and
`YmerNode.Mcp.Tools.ScriptAuthor`.
- [YmerNode.Mcp.Tools.Scripts](YmerNode.Mcp.Tools.Scripts.md): Wymcp tool `scripts` — the scripts this node has accepted, and running one.
- [YmerNode.Mcp.Tools.Scripts.Actions](YmerNode.Mcp.Tools.Scripts.Actions.md): Action implementations for the `scripts` tool — the boundary over
`YmerNode.Scripts`.
- [YmerNode.Mcp.Tools.Scripts.Errors](YmerNode.Mcp.Tools.Scripts.Errors.md): Translates the `scripts` tool's error reasons into messages a worker can act
on. Called by `YmerNode.Mcp.Tools.Scripts`'s `c:Wymcp.Tool.handle_error/1`.
- [YmerNode.Mcp.Tools.Scripts.Hints](YmerNode.Mcp.Tools.Scripts.Hints.md): Follow-up hints for the `scripts` tool, keyed off the hint_context maps
`YmerNode.Mcp.Tools.Scripts.Actions` produces.
- [YmerNode.Mcp.Tools.Scripts.Schemas](YmerNode.Mcp.Tools.Scripts.Schemas.md): Action schemas for the `scripts` tool. The `notes` surface through the `help`
tool and are the worker-facing contract: what a run costs, what acceptance
means, and why `describe` is the call to make before `run`.
- [YmerNode.Notebook](YmerNode.Notebook.md): The notebook — `notebook.db`, a separate, portable SQLite store of user- and
LLM-governed memories, working and long-term: agent-defined schema, open SQL,
embeddings, backup and restore. Potentially precious (tutoring records,
curated knowledge); the node's obligation is durability — governance stays with
the user and the LLM. This module is its raw-SQL surface (via
`YmerNode.Notebook.Repo`).
- [YmerNode.Notebook.Backup](YmerNode.Notebook.Backup.md): Capture and restore for `notebook.db` — the node's one durable obligation.
- [YmerNode.Notebook.Backup.Lock](YmerNode.Notebook.Backup.Lock.md): Singleton mutex serializing `YmerNode.Notebook.Backup` operations — capture and
restore.
- [YmerNode.Notebook.Repo](YmerNode.Notebook.Repo.md): Ecto repo for `notebook.db` — the node's one deliberate local store.
- [YmerNode.Notebook.VecLoadCheck](YmerNode.Notebook.VecLoadCheck.md): One-shot boot probe that aborts application start when the sqlite-vec `vec0`
extension did not load into `YmerNode.Notebook.Repo`.
- [YmerNode.References](YmerNode.References.md): The registry of pointers at where knowledge lives, served to LLM workers as
the `references` tool, and beside it the cache of what their targets say —
§ The membrane is the rule between the two.
- [YmerNode.References.Cache](YmerNode.References.Cache.md): The cache: what the targets of this node's references say, fetched by each
reference's own script and kept here — one cache entry per reference, text
in the node database, files in the cache directory. What the cache is for,
and the rule that keeps a reference a pointer while its content lives here,
is `YmerNode.References` § The membrane.
- [YmerNode.References.Cache.Reconcile](YmerNode.References.Cache.Reconcile.md): The boot step that makes the cache directory rebuildable with the node
database: it runs `YmerNode.References.Cache.reconcile/0` once, after the
migrator and before anything can fill an entry, and leaves no process
behind.
- [YmerNode.References.Cache.Window](YmerNode.References.Cache.Window.md): One window onto a text cache entry: the lines from `offset`, at most `limit`
of them, and never more bytes than the budget — whichever comes first.
- [YmerNode.References.CacheEntry](YmerNode.References.CacheEntry.md): One reference's cache entry: what the script its fetch recipe names last
answered for it, and when. How an entry is filled, refreshed and served is
`YmerNode.References.Cache`'s; this is the row.
- [YmerNode.References.Reference](YmerNode.References.Reference.md): One row of the registry: a pointer naming where knowledge lives and when to
look, never what it says — that is its cache entry's
(`YmerNode.References.CacheEntry`). The rule between the two — the membrane —
is stated in `YmerNode.References`.
- [YmerNode.References.Search](YmerNode.References.Search.md): The find surface — two composable layers on one call.
- [YmerNode.References.Sources](YmerNode.References.Sources.md): Derives a reference's source and fetch recipe from its uri, at read time and
never from storage.
- [YmerNode.Repo](YmerNode.Repo.md): Ecto repo for `node.db` — the node database, and the rebuildable half of what
the node stores.
- [YmerNode.Schedules](YmerNode.Schedules.md): The node's schedules: standing instructions to run one action of one accepted
script, with fixed args, on a cron expression in the node's time zone, until
each one's [*lifetime*](docs/glossary.md#lifetime) ends — and the watches that
keep references' cache entries current (§ Watches). They are added, listed,
updated and removed through the `schedules` tool and the CLI, a watch is
started and stopped through the `references` tool, and all of them are fired
by `YmerNode.Schedules.Scheduler`.
- [YmerNode.Schedules.Cron](YmerNode.Schedules.Cron.md): A schedule's cron expression: which ones the node accepts, and when one comes
due next in the node's time zone. The `crontab` package parses and walks them;
this module decides only what that package leaves open.
- [YmerNode.Schedules.InFlight](YmerNode.Schedules.InFlight.md): Which schedules have a run in flight right now, and until when at the latest —
a process registry of its own, unique by schedule, whose entry a firing takes
for as long as its run lasts.
- [YmerNode.Schedules.LastRun](YmerNode.Schedules.LastRun.md): What a schedule's row keeps of its last run: the moment the firing that started
it came due, one of four outcomes, the runner's own message, and how long the
run took. Nothing before it — there is no run history, and a skipped firing
leaves no trace — because the node is a script runner, not a reliable
scheduler. What a script produces goes where the script puts it; anything it
wants kept beyond one line, it writes to the notebook. A watch's firing is the
one whose answer is kept, and the cache keeps it
(`YmerNode.References.Cache`), not this row.
- [YmerNode.Schedules.Lifetime](YmerNode.Schedules.Lifetime.md): A schedule's lifetime — how far into the future it keeps firing — read from what
a caller gives `add` or `update` into the one instant it ends.
- [YmerNode.Schedules.Schedule](YmerNode.Schedules.Schedule.md): A standing instruction for the node to run one action of one accepted script,
with fixed args, on a cron expression in the node time zone, until its lifetime
ends — or a watch, a reference's own schedule, which names no script and no
action because each firing derives the reference's recipe afresh
(`YmerNode.Schedules` § Watches).
- [YmerNode.Schedules.Scheduler](YmerNode.Schedules.Scheduler.md): The process that fires schedules: once a minute, on the minute, it reads the
active schedules and starts a firing for each one due in that minute — each in
a task of its own under `YmerNode.Schedules.FiringSupervisor`, so a long run
never holds the next minute back.
- [YmerNode.Secrets](YmerNode.Secrets.md): The values a script resolves by name — one file of `NAME=value` lines,
outside every database.

- Scripts
  - [YmerNode.Script](YmerNode.Script.md): The contract a script implements — its description, its actions and their
read/write marks, its declarations — and the version `use YmerNode.Script`
stamps into its row.
  - [YmerNode.Script.Context](YmerNode.Script.Context.md): What the node hands every run — Req, `JSON`, the notebook, secrets, the
throttles it declares, the node's time zone, the files directory, the Typst
renders and browser calls — provided by the node rather than declared by the script.
  - [YmerNode.Script.Harness](YmerNode.Script.Harness.md): What a VM running script code outside the node needs, for a test or a live
run: the processes a script's run reaches for, and the three configuration
keys the node's own environments would otherwise set.
  - [YmerNode.Script.Test](YmerNode.Script.Test.md): Testing a script in a repository of its own: an ExUnit setup callback and
the functions a script test calls, over `YmerNode.Script.Harness`. Nothing is
`use`d — as with `Req.Test`, a test module names what it wants in `setup`.
  - [YmerNode.Scripts](YmerNode.Scripts.md): The scripts this node has accepted, and every door they arrive and leave
through — the context both script tools wrap and the node's own callers use.
  - [YmerNode.Scripts.BrowserService](YmerNode.Scripts.BrowserService.md): The node's half of the **browser service**: the Node program in
`browser-service/` that a user starts on their own machine, outside the node,
which runs Playwright code a script sends it — each browser call in a fresh
browser context — and keeps the storage states.
  - [YmerNode.Scripts.BrowserService.Error](YmerNode.Scripts.BrowserService.Error.md): A browser call's failure — the exception `YmerNode.Script.Context.playwright/3`
answers as `{:error, exception}`, the way `YmerNode.Scripts.Throttle.Error`
is what `YmerNode.Script.Context.request/2` answers for a refused request: a
script matches on `kind`, or hands the exception back unchanged and the run's
answer shows its message.
  - [YmerNode.Scripts.CLI](YmerNode.Scripts.CLI.md): The operator's verbs, run on the machine the node runs on — the node's own
human door, beside the client's approval.
  - [YmerNode.Scripts.Compiler](YmerNode.Scripts.Compiler.md): Turns a script's code into a loaded module tree, or into a refusal that names
what is wrong with it.
  - [YmerNode.Scripts.Guide](YmerNode.Scripts.Guide.md): The text `scripts guide` renders — the script contract and the batteries a
script is handed — read at the call from the docs the release keeps.
  - [YmerNode.Scripts.Loader](YmerNode.Scripts.Loader.md): Owns the VM's script module trees: every compile and every purge goes through
this process, and it remembers what each one produced.
  - [YmerNode.Scripts.PackageDocs](YmerNode.Scripts.PackageDocs.md): A promised package's own documentation, rendered from this release — what
`scripts info <name>` answers.
  - [YmerNode.Scripts.Runner](YmerNode.Scripts.Runner.md): One run — one execution of one action of one accepted script, whoever started
it — and what is checked before it, the process it happens in, and the shape of
every answer that comes back.
  - [YmerNode.Scripts.Script](YmerNode.Scripts.Script.md): An Elixir module stored as a row in the node database — its code, the hash of
that code and the hash this node has accepted — compiled into the VM and
reachable through the `scripts` tool and by the node itself; `Script.<Name>`,
named after its module.
  - [YmerNode.Scripts.Throttle](YmerNode.Scripts.Throttle.md): One throttle on this node: the process that holds its bucket, its breaker and
the requests waiting on it — and the two request steps that put a request
naming it through that process.
  - [YmerNode.Scripts.Throttle.Bucket](YmerNode.Scripts.Throttle.Bucket.md): A throttle's token bucket as a value: a rate per minute, a burst, the tokens it
holds and the instant it last counted them.
  - [YmerNode.Scripts.Throttle.Error](YmerNode.Scripts.Throttle.Error.md): A throttle's refusal of a request — the exception `YmerNode.Script.Context.request/2`
answers as `{:error, exception}` when a request never left the node.

## Mix Tasks

- [mix ymer_node.browser_check](Mix.Tasks.YmerNode.BrowserCheck.md): Runs the browser service's own tests — `node --test` in `browser-service/`,
against the real Chromium its pinned Playwright drives.
- [mix ymer_node.build](Mix.Tasks.YmerNode.Build.md): Build the release image and tag it with the commit it was built from.
- [mix ymer_node.build.live_output](Mix.Tasks.YmerNode.Build.LiveOutput.md): A subprocess's output reaching the terminal as it is produced — faithful
for valid UTF-8, with anything unreadable shown as `�`, and unable to stop
the task that runs it, whatever bytes it carries.
- [mix ymer_node.consumer_check](Mix.Tasks.YmerNode.ConsumerCheck.md): Proves the way a script author's own repository takes the node: a project
depending on this checkout under `runtime: false`, where none of the
node's applications start, tests a script through `YmerNode.Script.Test`
and starts the run tree through `YmerNode.Script.Harness`.
- [mix ymer_node.deploy](Mix.Tasks.YmerNode.Deploy.md): Deploy: move the checkout's committed `main` into the install — name the
rollback target, build, carry the compose file, recreate the install's
container on the image, and verify it came up on it.

