← Documentation index Foundations › Architecture handbook
Architecture handbook · July 2026

Metnos

From the whole system to its component contracts

One tutorial, two levels of detail. Start with the ideas, follow a real request, then zoom into the components that make each promise executable.

Status: pre-1.0
Self-contained HTML — printable as PDF

Audience: curious readers first, implementers second.
Simple language, exact contracts, diagrams that can be read without the code.
5learning stages
15+visual explanations
26component deep dives
1continuous architecture

Your route through the system

OrientPurpose, bets, vocabulary and boundaries. Follow a turnFrom a message to a measured, honest result. Understand actionExecutors, authority, placement and synthesis. See what persistsMemory, senses, channels, safety and undo. Open the machineComponent map, contracts and implementation guides.
Full chapter index
  1. What Metnos is
  2. The three bets
  3. The key concepts
  4. The layered architecture
  5. Anatomy of a multitool turn
  6. Executors and authority
  7. Synt: the tool factory
  8. Models and deterministic routing
  9. Memory
  10. Image pipeline
  11. Channels
  12. Safety and reversibility
  13. Component atlas
  14. Eight principles
  15. What Metnos is not
  16. Where to go next

One architecture, three levels of zoom

WhyThe principles and limits that make Metnos a particular kind of assistant.
What happensThe complete path of a turn, including denial, recovery and undo.
How it is builtCanonical component contracts: schemas, calls, authority and error conditions.
How to use this handbook. Read straight through once. On a second pass, use the component links as trapdoors into implementation detail. The overview explains the promise; the component page defines the contract that keeps it.
Part I · Orientation

Know what you are looking at

Purpose first, then design bets, then the small vocabulary used throughout the rest of the handbook.

1. What Metnos is

Metnos is a self-hosted architecture for a governed agent. Its core does not define an application domain: it plans, applies policy, remembers, synthesizes, isolates and audits. The admitted executor set defines what a concrete instance can actually do. Executors are small signed programs, generated or imported only inside a closed vocabulary and orchestrated by a local-first LLM planner. Frontier models are optional consults, not the residence of the system.

The name comes from mētis (cunning intelligence) + noûs (mind). It lives on a machine under your physical and legal control. The reference instance is reached through Telegram and the browser (port 8770), and its current executor catalog covers files, mail, photos, calendars, the web, GitHub and host operations. Those are uses of that catalog, not limits of Metnos. Change the admitted executors and enabled skills/backends, and the operational domain changes without changing the governing architecture.

Scope rule. Mail, photos and calendars do not belong to Metnos itself. They belong to executors in the reference catalog. Maintaining Metnos through GitHub is already a different use of the same architecture.
Metnos at a glance your machine — data, logic and models stay here Phone Telegram, anywhere confirmation buttons Browser chat + admin dashboards HTTP :8770 outbound long-poll the Metnos process Channels Telegram daemon · web server :8770 The mind (ch. 5) intent → plan memory → Mētis engine a whole plan in ONE LLM call deterministic routing: same request, same plan The guards (ch. 12) policy · vaglio (consent) · sandbox Vectorized executors (ch. 6) signed catalog + synthesis under control list in → list out backends & skills (your choice) files & folders mail (IMAP/SMTP) photos & indices calendar web & search GitHub they act here configured LLM backends endpoints resolved for fast · middle · wise local or remote, without changing the planner it thinks here persistent memory mnestome · fast-paths · undo history · audit (SQLite) frontier tier (cloud, opt-in) a consult when asked for — never the engine self-hosted: no mandatory dependency on third-party services; the cloud is a door you open, not a room you live in.
Figure 1 — Metnos at a glance. The process lives on your machine: channels receive, the mind plans through configured tiers, guards filter, and executors act on enabled backends. Remote providers and the frontier tier are explicit choices.

The identity card

ItemActual state
ShapePython ≥ 3.11 process, executor-based microarchitecture; ReAct runtime with one-shot planning (the Mētis engine, ch. 5).
ToolsSigned executors in the catalog, plus those synthesized on the fly and those imported behind a gate (ch. 7). All are vectorized: list in, list out. The domain reference provides the user view; current names and counts live in the generated catalog.
BrainCompatible local or remote LLM endpoints; four abstract tiers fast / middle / wise / frontier (ch. 8). Frontier = cloud opt-in.
ChannelsTelegram (outbound long-poll, no open ports) + web on port 8770 (chat and admin dashboards), ch. 11.
DevicesA controlled part of the catalog can run on registered PCs in the same network through metnos-client: the server remains the point of policy, selection, signing and audit; the device runs only executors declared compatible. Detail: remote executors.
SensesIn-process image pipeline: semantics + faces + EXIF in one unified index (ch. 10).
Languagei18n by construction: every string and prompt is per-language data. IT + EN validated; other languages = drop-in translation packs (not yet tested).
License / statusAGPL-3.0; pre-1.0. Public repo: github.com/brunialti/metnos — a deterministic export-subset of the daily-driven instance.
Pre-1.0, not a polished product. Metnos is installable and operational, but interfaces and defaults may still change. Contracts, security, tests and explicit failures take priority over promises of stability.

2. The three bets

The whole project rests on three architectural bets. They are deliberate positions, not optimizations: each one reverses a widespread habit of agent frameworks.

Three bets, one system 1 · Closed vocabulary Tools are not imported on trust: they are synthesized inside a closed, audited grammar. «don't trust the package: the package has to earn its place» ch. 3 · 6 · 7 2 · Local first The planner is an LLM on your hardware. No cloud round-trip to think or act. the frontier is an optional consult, not the engine ch. 8 3 · Determinism Same request → same plan, every run: pinned seed, ties broken by curated data, grammar. auditable and testable like software, not like a prompt ch. 5 · 8 together: a reproducible, verifiable agent of your own
Figure 2 — The three bets. Each one reverses an agent-framework habit: skills imported on trust, cloud-first design, the LLM as an oracle re-rolled every turn.

The comparison, with no discounts

Typical agent frameworkMetnos
ToolsHand-written, imported or generated free-form, then run as-is with the assistant's privilegesSynthesized at runtime too — but from a closed, audited vocabulary: signed, aged, smoke-tested and screened before they can ever run
SafetyTrust the author of the packageDon't trust the package: the package must pass the checks (7-layer gate, ch. 7)
LLMOften cloud-firstLocal first; frontier opt-in
RoutingThe model picks a tool each turn — non-reproducibleDeterministic by construction: seed-pinned local inference, ties broken by curated affinity (ch. 8)
OutputFree-form, different per toolUniform: list in / list out, pipeable between steps (ch. 6)
UndoRare or best-effortFirst-class: a closed catalog of reverse patterns, moves = COPY-then-DELETE, honest ok_count (ch. 12)
LanguageEnglish only, strings in the codei18n by construction: strings and prompts are per-language data
Why determinism pays off. Most agents treat the LLM as an oracle to re-roll: ask twice, get two different plans. Metnos makes the opposite bet: a local planner, constrained to a closed vocabulary, can be made reproducible. Routing can then be measured, put under regression tests, audited — like ordinary software. And it compounds: a request that has been solved once is replayed by a fast path with no LLM call at all (ch. 9).

3. The key concepts, in seven cards

Seven words carry the whole document. Defining them now saves you half an hour of confusion thirty lines from here; each one has its implementation contract in the component atlas below.

executor — an executable capability: a small program that does one thing well (read files, send an email, move messages, search photos). It accepts lists as input and produces lists as output, carries a manifest that describes it, an Ed25519 signature that authenticates it and a sandbox profile that confines it. It is the only class of things that act in the system.
closed vocabulary — every executor is named verb_object[_qualifier[_descriptor]], composing governed sets of canonical actions and objects plus qualifiers in four families. It is not an aesthetic convention: it is the boundary of what the system can name — and therefore synthesize. New terms enter only through explicit governance (necessary · general · understandable).
manifest — the TOML identity card of an executor: a description in prescriptive chapters (SCOPE / PATTERN / NOT / OUT), the argument schema, affinity keywords, the reversibility pattern, the code digest. It is not documentation for humans: it is the tool's prompt, written so that a mid-size LLM uses it well (ch. 6).
synt — the process that brings into existence what the pool cannot do yet: a cascade of strategies ordered by cost that first composes existing executors and only as a documented exception generates new code, in five stages plus a semantic check (ch. 7). It proposes; the human approves.
vaglio — (Italian for «sifting») the filter that always sits before execution: a deterministic guard (forbidden paths, unrecoverable commands) followed by a judge that weighs grey-zone operations and, above threshold, asks the user for explicit confirmation with buttons on the channel (ch. 12).
mnest · mnestome — a mnest is the thread linking two executors that were activated together: it is born from context, reinforced by use, and decays if not reused. The mnestome is the graph of all mnests: the system's associative memory, on SQLite, curated by a nightly process (the ager). It gives the planner the intuition of «which executor usually follows which» (ch. 9).
skill ↔ backend — two orthogonal axes: a skill decides whether a group of capabilities is active, trusted and configured (dormant until its prerequisite appears); a backend decides how an action runs against a concrete service (calendar = local ICS or Google), chosen by configuration — never by the LLM. The planner never sees the provider.

The anatomy of a name

The closed vocabulary is the project's most fertile idea: it makes names composable (the planner can predict what a capability it has never seen is called), filterable (the prefilter reasons over verb and object) and synthesizable (synt cannot name anything outside the grammar).

Anatomy of a name: verb_object[_qualifier[_descriptor]] find _ images _ indices _ dry-run action governed canonical set read, write, move, find, get, list, filter, send, … object governed canonical set files, messages, events, images, urls, entries, … qualifier (opt.) 4 families format · mode safety · provider descriptor (opt.) kebab-case, max 30 behavioural variant with identical arguments the 5 producer verbs, orthogonal find = pattern / query get = known ids or snapshot read = id → content list = enumerate the container filter = predicate over a list the axis is the primary input, never a synonym read_messages move_files get_urls classify_entries write_files_doc find_issues_github The vocabulary is CLOSED: a new term enters only if necessary, general and understandable to a mid-size LLM. Synonyms before extension; human escalation for every new word. The grammar decides what is nameable.
Figure 3 — The anatomy of a name. Four positional levels, the last two optional; the five producer verbs are distinguished by their primary input, so the planner never has to choose among synonyms.
Part II · A request in motion

Follow one turn from words to effects

The layers are easier to understand after watching data, decisions and authority move through them.

4. The layered architecture

Metnos is an onion: the outside talks to the world, the inside executes. Each layer trusts only the one beneath it, and privileges shrink as you move toward the core. A request — whether from a user or from a scheduled task — crosses all of them, in order.

The layers, from the outside in 1 · Channels adapters to the world: Telegram daemon (pairing, buttons) · web server :8770 (chat, admin, SSE) runtime/channels/ · metnos_http_server 2 · Turn runtime normalizes the request · literal shortcuts · intent extraction (verb + object + keywords) agent_runtime · intent_extractor 3 · Cognitive engine — Mētis plan memory (fastpath ★ · autopath) → prefilter → proposer (1 call, GBNF) → validator → execution targeted recovery on errors · honest terminator on dead ends — ch. 5 runtime/engine/* 4 · Guards policy (three autonomy levels) · vaglio = guard + judge + consent · bubblewrap sandbox around every invoke policy · vaglio · sandbox 5 · Executors signed, synthesized or imported behind the gate — all vectorized, all with their manifest executors/ · ~/.local/…/executors/ 6 · Backends & skills the concrete provider (local files, IMAP, Google Workspace, GitHub, web…) chosen by configuration, never by the LLM backends/ · skills 7 · Persistent tissues mnestome · fast-path/autopath archives · undo history + blobs · append-only audit (all SQLite + filesystem) ~/.local/share/metnos/ a request crosses them in order privileges and trust shrink downwards
Figure 4 — The seven real layers, with the modules that implement them. The cognitive engine (layer 3) is the heart of chapter 5; the guards (layer 4) sit always between the plan and the effect.

5. Anatomy of a multitool turn

If you read only one chapter, read this one. We follow a real request — «find the spam mails and move them to the trash» — from entry to answer: four tools chained together, a single call to the model, every step measured and annotated.

5.1 The cascade, step by step

The ground rule: the model is the last resort, not the first. Memory is tried first (zero LLM, milliseconds); if the request is new, the model is asked once, for the whole plan; the execution that follows is pure deterministic mechanics.

One turn, from entry to answer «find the spam mails and move them to the trash» literal shortcuts a closed table: «what time is it», «where am I», «undo»… microseconds ✗ no match → continue intent_extractor — fast-tier LLM, reasoning off verb = move object = messages kw = spam… ~0.4 s compound requests → an ordered list of clauses the Mētis engine — one entry point, every layer records whether it answered Fastpath ★ — user-approved shortcuts exact fingerprint <5 ms · semantic similarity <150 ms 0 LLM ✗ miss Autopath — plans learned from successful turns searches by meaning of the request, then by exact intent 0 LLM ✗ miss: new request prefilter → the clause's pool find_messages classify_entries filter_entries move_messages rank: verb+object » qualifier » affinity (cap +3) 0 LLM deterministic: same query → same pool, same order Mētis Proposer — wise tier, ONE call proposes the whole plan: steps + links + final message N adaptive candidates, each constrained by the GBNF grammar verb-filter on the pool · early-stop if the first convinces · teleological ranking 1× LLM the model chooses INSIDE the rail: no prose, no invented args (ch. 8) Validator — deterministic plan check do the tools exist? are the args well-formed? do references point to real steps? 0 LLM trivial error → 1 re-proposal, never run Deterministic execution — step by step, no dice 1 find_messages → 42 entries 2 classify spam / not spam 3 filter → 12 entries 4 move_messages ⚙ vaglio: consent → ok_count=12 for each step: resolve from_step and placeholders → vaglio → invoke in sandbox → observation safety caps: max 12 steps per turn · same executor max 3 times in a row render of the final message "Moved ${step4.ok_count} mails to the trash." → real values Autopath records the successful plan next time: same answer, 0 LLM (ch. 9) a step fails? Targeted recovery classifies: wrong tool · wrong args · missing input re-proposes excluding the failed tool, re-runs Terminator — the honest dead end «I cannot solve: X. To proceed: Y.» records the gap — never an invented answer «Moved 12 mails to the trash.» the log records which layer answered and the ms of every phase per-phase telemetry: intent_ms · prefilter_ms · vaglio_ms · exec_ms — every turn is measurable and comparable
Figure 5 — The anatomy of a multitool turn. Shortcuts (0 LLM) are tried first; if the request is new, the Proposer asks the model for the whole plan in a single constrained call; execution is deterministic, with the vaglio in front of the only state-changing step. On the right, the two error paths: targeted recovery and the honest dead end.
  1. Literal shortcuts. A closed table recognizes the most common phrases («what time is it») in microseconds. Here: no match.
  2. Intent. One call to the fast tier (reasoning off, ~0.4 s) extracts the canonical verb, the object and keywords. Compound requests become an ordered list of clauses, each with its own pool.
  3. Plan memory. Fastpath (shortcuts you approved with the ★ button) and Autopath (plans learned on their own) answer without the model if they recognize the request. Here: miss, it's the first time.
  4. Prefilter. The catalog shrinks to the relevant pool for the clause: verb+object match, qualifier bonus, and — to break ties among siblings — the curated affinity bonus (cap +3). All deterministic: same query, same pool, same order.
  5. Mētis Proposer. ONE call to the wise tier produces the whole plan: steps, links, final message. It generates up to N candidates (adaptive, with early-stop), each physically constrained by the pool's GBNF grammar; a teleological ranking picks the best.
  6. Validator. A typecheck of the plan before running it: existing tools, well-formed args, real references. A trivial error costs one re-proposal, not one wrong execution.
  7. Execution. Pure mechanics: for every step the runtime resolves the placeholders, passes through the vaglio, invokes in the sandbox, accumulates the observation. Caps: 12 steps per turn, same executor max 3 times in a row.
  8. Closing. The final message is a template filled with the real results. If the turn succeeds, Autopath records it: next time we jump straight to point 3.

5.2 The plan: what the model actually proposes

The Proposer does not produce prose: it produces a structured object — steps, slots to fill (fillers), final message. This is the real plan for our request:

{
  "steps": [
    {"tool": "find_messages",
     "args": {"folder": "INBOX", "query": "is:unread"}},
    {"tool": "classify_entries",
     "args": {"from_step": 1, "dimension": "spam"}},
    {"tool": "filter_entries",
     "args": {"from_step": 2, "where_field": "spam", "where_value": "spam"}},
    {"tool": "move_messages",
     "args": {"from_step": 3, "dst_folder": "${FILLER:trash_folder}"}}
  ],
  "fillers": {
    "trash_folder": {
      "prompt": "What is the trash folder called for this account?",
      "default": "Trash",
      "tier": "fast"
    }
  },
  "final_message": "Moved ${step4.ok_count} mails to the trash."
}

Worth noting: the model does not know the account's trash folder name — and does not make one up. It declares a slot (${FILLER:trash_folder}) that the runtime will fill at the right moment with a cheap micro-call (cached) or with the default.

5.3 Data piping: how the steps talk to each other

PlaceholderWhat it does
from_step: NTake the entries produced by step N (1-based) and pass them whole to this step. Lists travel only this way: never pasted back into the prompt.
${stepN.field}Extract a scalar field from step N's result (nested paths supported). Used mostly in the final message.
${FILLER:name}A slot filled on the fly by a micro-call to the fast tier (cached) or by the declared default.
${RUNTIME:key}Turn context, resolved by the runtime: actor (who is speaking), lang, channel.
Data piping: lists between steps, scalars in placeholders step 1 · find_messages folder="INBOX" query="is:unread" → entries (42 mails) step 2 · classify_entries from_step: 1 dimension="spam" → entries + spam field step 3 · filter_entries from_step: 2 where spam == "spam" → entries (12 mails) step 4 · move_messages from_step: 3 dst=${FILLER:trash_folder} → results, ok_count=12 entries entries entries ${FILLER:trash_folder} a slot declared by the plan, filled by the runtime: fast-tier micro-call (cached) or the default → «Trash» ${RUNTIME:actor · lang · channel} turn context, injected by the runtime: who is speaking, in which language, from which channel final_message — the template of the reply "Moved ${step4.ok_count} mails to the trash." filled after execution with the real values → «Moved 12 mails to the trash.» ${step4.ok_count} a scalar, not a list legend of the links from_step — whole lists between steps ${stepN.field} — a scalar field ${FILLER:name} — a slot filled on the fly ${RUNTIME:key} — turn context
Figure 6 — The plan of Figure 5 seen as a data flow. Lists stream between steps via from_step; scalars, slots and context pass through typed placeholders that the executor resolves deterministically.
When a cap bites, you see it. If a limit truncates a result (entries, bytes, steps), the executor declares it in the fields (truncated: true, used, available_total) and the runtime says so in the reply — offering to widen only if technically possible, and never widening on its own. A partial result presented as complete is considered a bug, not an optimization.
Part III · Acting

Small programs, explicit authority

Executors do the work. Manifests limit it. Policy and placement decide where the work may happen.

6. Executors: vectorized by construction

Every executor accepts a list and returns a list — even when the list has zero or one element. There is no *_batch anywhere: the batch version is the executor. It is the decision that keeps plans short and results composable.

One contract for N = 0, 1, a thousand paths = [] paths = ["/tmp/x.txt"] paths = [… ×1000] degenerate or huge list: same entrance, no special case move_files iteration, pagination and time windows live INSIDE; branching goes back to the planner explicit caps: max_total, max_results, max_bytes always a list, plus the truth results = […] ok_count = 12 (real, not hoped) truncated = true used = 200, available_total = 312 cap_field = "max_total" move_files_batch  does not exist — and never will: the vectorized form is the only form.
Figure 7 — The vectorized contract. Zero, one or a thousand elements cross the same code; caps are explicit arguments and truncation is declared in the fields, never hidden.

Three conventions follow from the contract, and you will see them everywhere:

The manifest: the tool's prompt

Every executor carries a TOML manifest. It is not courtesy documentation: it is what the planner reads when it decides whether and how to use the tool — written for a mid-size local LLM, not for a frontier model. Short sentences, literal examples, defaults spelled out; the description follows four prescriptive chapters:

The same manifest also declares where the executor may run. The platforms and [placement] fields prevent sending to Windows a tool written only for Linux, or running on a PC an executor that has not been audited for the device. When the chat names a paired PC, the runtime uses those declarations to choose server or device execution; if the target is not reachable, the outcome is honest, not a silent fallback.

[description]
en = "SCOPE: search files by pattern in directory.
      PATTERN: find_files(base_path=\"/\", patterns=[\"*.jpg\"]).
      NOT: list_dirs+filter_entries; get_files (ID lookup).
      OUT: entries=[{path,name,type,mime,kind,size,mtime}]."
One manifest feeds four different mechanisms executors/find_files/manifest.toml name = "find_files" affinity = ["find","search","cerca", "file","glob","pattern",…] [description] SCOPE: … PATTERN: find_files(…) NOT: … OUT: entries=[{…}] per language (IT+EN), with state tracking [args] — JSON Schema base_path (req) · patterns · recursive max_total … types, defaults, examples reverse_pattern + capabilities e.g. "swap_src_dst" · fs:read · provider:access [code] sha256 digest + signature files = ["find_files.py"] prefilter (ch. 5) curated affinity breaks ties among siblings Proposer pool (ch. 5) the model copies the FORM from PATTERN, never invents GBNF grammar (ch. 8) the args schema becomes the decode rail undo (ch. 12) the reverse pattern comes from a closed catalog the digest binds manifest to code: if the file changes without re-signing, the loader discards the executor — no code drifting away
Figure 8 — One manifest, four consumers: prefilter, planner pool, grammar and undo each read different fields of the same TOML. The digest binds the manifest to the signed code.

One execution policy

Every executor call, local or remote, crosses the same execution engine. In one place the runtime applies metrics, backpressure, per-resource limits and a cap derived from the hardware. The default deliberately remains serial and the cross-executor pool is off: adopting the infrastructure does not change the order, inputs, outputs or capabilities of existing executors.

[execution]
effect = "unknown"
parallelism_class = 0
resource_class = "default"
concurrency_key = "none"
equivalence_gate = "unverified"
ClassRequested budgetAdmission
0No cross-executor thread.Default for every existing and generated executor.
1Moderate concurrency.Only after verified equivalence; always within engine and hardware limits.
2High concurrency.
3Controlled maximum.

The class measures only a budget: it grants no authority and does not mean read-only. A future executor that creates or mutates objects may run concurrently, but it must declare an isolation key, provide the resource identity, and pass equivalence, collision, idempotency and postcondition tests. If any evidence is missing, the loader reduces it to class 0.

All three executor-generation paths — Synt proposals, reactive synthesis and skill generation — also consume one central contract. The local model may design a rich implementation, but it cannot rewrite identity, lifecycle, I/O or the initial execution policy. When it parallelizes independent entries, the worker count comes from the engine and results must return in input order.

Preservation rule. An executor stays serial until it explicitly declares parallel eligibility and passes equivalence testing. Changing the central policy propagates limits and observability to all executors; it never promotes one implicitly.

Remote authority: declared once, consumed three times

A provider name in an argument is data, not permission. For a conforming executor, remote access exists only when the manifest declares an effective provider:access capability. A closed when condition can make that capability active only for the selected backend. Invalid or non-matching conditions grant nothing.

Authority rule. The same effective binding governs credentials, network and placement. Names, suffixes and arbitrary arguments are never independent permission paths for conforming executors. Legacy inference exists only as a temporary migration bridge.

Execution on the server or on a registered PC

The normal shape remains simple: the plan selects an executor, the runtime sends it through policy and vaglio, then invokes it in the server sandbox. Remote executors add one controlled detour: for selected executors declared portable, the execution point may be a registered PC in the same LAN or overlay network.

This is not a new channel and not a generic backend. The channel is still Telegram or web; the backend is still files, mail, calendar or another service. The remote executor is the place where the small signed program runs. Metnos keeps on the server the executor choice, policy checks, device registry, payload signing, timeout and audit.

chat "on office PC" Metnos server planner + policy + vaglio manifest: platforms + placement signed queue, deadline, audit metnos-client outbound poll + signature check registered PC compatible executor Job Object / bwrap signed result signed result: same shape as a local executor
Figure 8b — A remote executor does not move the mind: it moves only the execution of an admitted executor. The server remains the authority that decides, signs, waits and records.

The choice does not depend on the browser IP address. In the web UI, the machine opening the page may be the server, another PC on the network, or a browser behind a proxy; from Telegram there is no local browser at all. Metnos therefore uses the name of the paired device and anchors it in the request language: “on the laptop” is a target, “the laptop” alone is not.

The remote client does not receive general freedom. It polls the server instead of exposing ports; verifies the server signature before execution; downloads only signed and compatible executors; writes the result to a local spool before delivery. If the server is not reachable, it retries delivery without rerunning the work already done.

The remote client is contained by construction: on Windows the Job Object bounds duration, memory and process trees; on Linux the sandbox uses bwrap when present. On this foundation remote executors are no longer read-only: since C7 (ADR 0183) mutating ones — file write, move and delete — run on the device too, made safe by the policy they long required: idempotency, audit, and device-aware reversibility (deterministic reverse patterns and blob backups queued to the same device for undo; the known gap being that blob-restore is not remotable). Executors whose dependencies cannot be resolved on the device stay server-only.

The operational details — PC pairing, UI installation, heartbeat, signed queue, per-OS sandboxing and current limits — live in the remote executors component contract.

7. Synt: the tool factory

When the pool cannot do something, the planner does not improvise code in the middle of the turn: it hands over to synt, the process that brings into existence what is missing. It first tries to compose existing executors; only as a documented exception does it generate a new one — in five stages, each with its own contract.

The assembly line: five stages + verification each stage sees only the minimal slice of context; the closed vocabulary enters ONLY at stage 1 1 · NAMING a name conforming to the closed vocabulary + revertible, critical middle tier 2 · SIGNATURE args schema, required capabilities, reversibility pattern middle tier 3 · TESTS 4-6 birth tests: happy case, empty list, invalid args, edge middle tier 4 · DESCRIPTION chaptered description (SCOPE/PATTERN/NOT/OUT) + affinity keywords middle tier 5 · CODE the Python file with def invoke() (+ reverse if needed) wise tier stage 6 · semantic verification (fail-safe) a separate LLM compares description and code: do they say the same thing? when in doubt it rejects: better to lose a good synth than admit a bogus one Ed25519 signature + digest manifest and code bound together birth tests in the sandbox the 4-6 tests of stage 3, actually run into the pool, next to its siblings same vectorized contract, same manifest, same sandbox as the hand-written executors Synthesis is local: no external provider writes code that will run on your machine. And a bug in a synthesized executor is fixed by iterating the stage's prompt, never by hand-editing the generated file.
Figure 9 — The synthesis pipeline: four procedural stages on the middle tier, the code on the top tier, then independent semantic verification, signature and birth tests. The multi-stage design converges where the single prompt failed.

Two triggers, one cascade

ModeTriggerTiming
ReactiveDuring a turn: the planner finds no executor that satisfies the request.Synchronous — the user is waiting; composition of existing executors is tried first.
IntrovertAt night: the ager walks the mnestome and finds recurrences, overlapping traces, families with the same shape.Asynchronous, in homeostasis: it proposes merges, generalizations, specializations.

In both cases the same rule holds: synt proposes, the human approves. No self-modification without a filter; every proposal comes with its rationale, and is reversible.

The 7-layer gate

The same funnel applies to synthesized code and to skills imported from outside: no package runs on trust.

The admission gate: seven layers, no exceptions package / new synth untrusted 1 signature Ed25519+digest 2 vocabulary name + affinity 3 aging usage quarantine 4 sandbox profile from manifest 5 smoke test execution proven 6 LLM verifier description vs code 7 audit append-only trusted executor in the pool «don't trust the package — the package has to earn its place» drop-in skill formats execute third-party code with the assistant's privileges: for an agent that touches files, mail and shell, that is remote code execution by design. Metnos chooses security by construction. roadmap: map the public skill ecosystem INTO this model, not run it raw
Figure 10 — The 7-layer gate, identical for synthesized and imported executors: signature, vocabulary, usage quarantine, sandbox, smoke test, semantic verification, audit. Only at the end of the funnel does a package become a trusted executor.

8. Four tiers, one deterministic routing

Tiers are abstract roles, not pinned models: fast / middle / wise are assignments you bind to whatever endpoint you have, and frontier is the optional cloud role. Several tiers may share one endpoint or use separate endpoints: the planner always sees the role.

TierRoleConstraint
fastShort structured extractions: intent, fillers, classifications. Reasoning off.Configured endpoint; short replies. Mandatory.
middleProcedural work: synthesis stages 1-4, descriptions, judgments.Endpoint and parameters configured for the role.
wiseThe planner: proposes the whole plan; writes the stage-5 code.Mandatory: it never degrades to fast.
frontierAn external consult when explicitly requested (e.g. analyzing an issue).Cloud API, opt-in, with managed fallback if the key is absent.
Tier ≠ model. No GPU or NPU is required by construction: a CPU endpoint, a model you already serve, or the frontier fallback are all first-class paths. A weaker local model means weaker planning, not a broken install.

The three locks of determinism

An LLM at temperature zero is not enough to make routing reproducible: the local server stays non-deterministic because of speculative decoding with a random seed. Metnos closes the door with three locks, one per noise source:

Abstract tiers on the left, determinism on the right fast intent · fillers · classify middle synt 1-4 · descriptions wise plans · synth code configured endpoints shared or distinct by role model and parameters may change: think · num_predict frontier cloud consult, opt-in only when asked, never the engine Lock 1 — pinned seed at temperature 0 the server stays non-deterministic (speculative decoding with a random seed): the seed must be pinned via env. METNOS_LLM_SEED=42 (default; -1 = explicit randomness) Lock 2 — ties broken by curated data among siblings with the same object, the manifest's distinctive affinity decides (generic verbs excluded), never a coin flip. prefilter: bonus = min(|query ∩ affinity|, 3) Lock 3 — the grammar as a rail from the step's pool a GBNF is generated (discriminated union): the model CANNOT emit a malformed tool_call, nor mix one tool's name with another tool's args. same request → same pool → same plan, every run routing goes under benchmarks and regression tests like ordinary software a soft constraint = «please keep to the right lane» · a grammar = the guard-rail the first can be ignored, the second cannot: every candidate token is filtered against the grammar before being chosen + verb-filter: the pool narrows to the verbs compatible with the clause's intent
Figure 11 — On the left, tiers as roles bound to configured endpoints; on the right, the locks that make routing reproducible: pinned seed, curated affinity for ties, and a GBNF decode grammar.
No fragile parsers. Tool use is native: the model emits structured tool_calls, and the grammar guarantees the shape upstream. There is no fishing JSON out of prose — the classic weak point of home-grown agents.
Part IV · What surrounds action

Memory, senses, channels and safeguards

These tissues make the executor system useful over time, visible to the user and safe enough to operate.

9. The memory that speeds things up

Metnos trains no models: no fine-tuning, no RLHF. Everything it learns is inspectable data — plans, traces, shortcuts — and anything learned can be read, corrected, deleted. The practical effect: the more you use it, the less it calls the model.

The circle: use → remember → stop asking a successful turn the plan actually worked Autopath records it the plan is indexed by the meaning of the request (embeddings) a similar request, tomorrow the plan is ready: replayed in milliseconds, 0 LLM ★ explicit promotion a button under the reply promotes the plan to a guaranteed Fastpath shortcut mnestome — the graph of mnests (SQLite) two executors activated together → a thread that strengthens with use and decays if unused; gaps remain as aspirations the clock is usage time, not the calendar: a system that sleeps does not age at night: the ager + synt proposals heavily used multi-step sequences (>50 runs) become candidates for synthetic executors; overlapping traces propose merges and generalizations — always behind the human filter proposals are logged, never auto-applied (ch. 7) every turn leaves traces learning = accumulating verifiable data, never touching weights
Figure 12 — The circle of learning without training: successful plans become shortcuts (Autopath, Fastpath ★), co-activations become mnests, nightly recurrences become synthesis proposals. Everything is readable, reversible data.

10. The senses: the image pipeline

To search your photos, Metnos ships nothing to anyone: three in-process extractors turn every image into three signals — what is seen, who is there, where and when — fused into one unified index queried through the ordinary vocabulary.

Three signals from every photo, one single index a photo from the archive semantics — SigLIP the image becomes a vector: «sunset at the sea», «birthday cake», «mountain trail» faces — RetinaFace + ArcFace finds the faces, turns them into identity prints; people get registered by name only if you ask context — EXIF GPS coordinates, date and time, camera: the where and the when with no model at all unified index one record per photo: scene + people + place + time built once, queried forever «the mountain photos from last summer» find_images_indices the same vocabulary as everything else all in-process, on your machine: the photo archive never leaves home
Figure 13 — The image pipeline: SigLIP for the scene, RetinaFace+ArcFace for identities, EXIF for place and time. The three signals converge into a unified index queried by an ordinary executor of the vocabulary.

A search arrives from the channel like any other request: the planner composes find_images_indices with the criteria extracted from the sentence, and the channel shows inline previews. Building the index is a background job, incremental and restartable, started with a sentence («index the photos in…»).

11. The channels: Telegram and web

A channel is an adapter: it converts an external interface into messages and replies, plus one optional capability — rendering buttons for confirmations and choices. Two channels come with the install; adding more does not touch the core.

Two entrances, zero ports open to the Internet the Metnos machine web server — port 8770 chat (SSE streaming) + admin dashboards Telegram daemon OUTBOUND long-poll toward the bot API browser on the LAN (or via your own VPN overlay) admin key on first connect proposals · executors · runs safety · turns · charts HTTP :8770 Telegram API the daemon does the asking: no open ports, no public IP phone wherever there's network, you talk to your bot inline buttons who may speak? only the paired: signed Ed25519 codes with expiry, an authorization level per person an unknown sender is discarded without echo; vaglio confirmations and choices (get_inputs) arrive as buttons on the channel
Figure 14 — The two channels. The browser talks directly to the server on 8770 (streaming chat + dashboards); Telegram works by outbound long-poll, so no open ports and no public IP. Below, the pairing that decides who may speak.
ChannelWhat it offers
Web :8770Chat in the browser with streaming replies (SSE), image previews, feedback badges; admin dashboards for proposals, executors, runs, safety and turns. The same API answers JSON or HTML depending on Accept. Admin key auto-created on first start, file with 0600 permissions.
TelegramYour personal bot: messages, photos, inline buttons for vaglio confirmations and multiple-choice inputs. Pairing via the /pair command and a signed, expiring code.

The Tutor: explaining without executing

Explicit questions about how to use Metnos are intercepted at the shared HTTP/Telegram boundary, before the planner and without consuming a pending dialog. A conservative detector recognizes only the request class; the relevant card is selected neither by synonyms nor exact phrases, but by local BGE-M3 embeddings compared with vectors held in the signed SQLite catalog.

After retrieval, the authenticated principal filters the content. Administrative procedures remain deterministic; for informational guides the local model composes the answer using only the retrieved card and the admitted instance inventory. It receives no tools and crosses the central llm slot in the serial class: it can explain, not act. An invalid catalog, a weak match, or insufficient context produces an explicit outcome, never an invented capability.

The essential split. Deterministic code governs detection, identity, audience, integrity, and safety procedures; embeddings and the local LLM are used where language variety would make a phrase table brittle.

12. Safety and reversibility

Safety is not a module: it is a chain of independent guards, and an action must pass all of them. And since even the best guard makes mistakes, the last defense is being able to go back: honest undo, by construction.

The chain of guards — and undo as the last defense pairing who are you? signed code, a role per person unknown = discarded policy three autonomy levels: ReadOnly · Supervised · Full capability per category vaglio guard: forbidden and unrecoverable; judge + consent via buttons always BEFORE running sandbox bubblewrap with a profile from the manifest: network, user, IPC isolated never bare subprocesses signature + audit code bound to manifest via digest; every action in an append-only ledger drift = silent discard the last defense: first-class undo ● a closed catalog of reverse patterns (5): swap src/dst · delete what was created · restore from blob · delete by id ● every move is COPY → check → DELETE: never a deletion without a confirmed copy ● overwritten content goes to sha256-hashed blobs in the turn history: «undo» puts it back where it was ● honest ok_count in undo too: if it says it undid 3 things, it undid 3 things skills stay dormant until their prerequisite appears; disabling one removes the whole surface the system skill (shell, sudo, packages, mounts) exists — which is exactly why every privileged action requires explicit consent, and the whole skill can be switched off with one sentence
Figure 15 — Five guards in series (pairing, policy, vaglio, sandbox, signature+audit) and, below, the safety net: an undo with a closed catalog of reverse patterns, verified copies before any deletion, and honest counts.
The power is real, which is why it is bridled. With the corresponding executor set, a Metnos instance can genuinely administer a machine (shell, sudo, packages, mounts). That makes it an operational architecture rather than a chatbot. But every privileged action passes through the vaglio with explicit confirmation, runs in the sandbox, lands in the audit; and the whole system skill can be disabled, locking Metnos out of the operating system.
Part V · Open the machine

From promises to component contracts

The overview and the implementation model meet here: one map, one worked request and one catalog of deeper contracts.

13. Component atlas

The architecture above says what the system promises. This atlas shows which component owns each promise and where its exact contract lives.

13.1 From overview to component contracts

Metnos architecture has two levels of zoom. The upper level describes the system as a whole: its layers, organs, laws and ends. It is the path you have just followed from chapter 1.

The lower level is the set of component deep dives linked below: one HTML document per component, with the detail needed to write the code without guessing. Decisions here are not opinions — they are contracts: data schemas, function signatures, sandbox flags, error conditions. When the code and the document drift apart, the document wins and the code is adjusted; or the document is corrected on the spot — never «later».

The rule of life is short: a component is not implemented until its HTML exists, has been approved, and speaks the same language as the code already in place.

Check. Before you read on, two points should be obvious: (a) Level 1 explains what, Level 2 explains how; (b) Level 2 documents are contracts, not drafts. If either is unclear, re-read the previous paragraph before continuing.

13.2 Four nouns, now as implementation contracts

Everything in Metnos revolves around four nouns. Defining them now saves half an hour of confusion thirty lines down.

executor
An executable capability: a small program that does one thing well (read files, send mail, compute a hash, OCR a PDF, discover fresh URLs on a site). Every executor takes lists in and returns lists out; it has a manifest that describes it, an Ed25519 signature that authenticates it, and a sandbox profile that confines it. Product membership, origin, and transport remain separate axes. GitHub executors maintained by Metnos are builtin with handcrafted origin, not imports; the generated catalog is the single source for the source-tree domain breakdown.
mnest
The thread that links two executors when the planner has fired them together. It is not a code pointer, it is a trace: born from context, reinforced by repetition, decayed when unused.
mnestome
The emergent graph of all mnests. It is the system’s associative memory: it lives on SQLite, is curated by a nightly process (the ager), and gives the planner the intuition for «which executor usually follows which». The Italian counterpart of the term is mnestoma.
agent runtime
The engine that orchestrates everything: it receives the user request, breaks it into steps, picks executors, runs them in a sandbox, gathers observations, decides the next step. It implements the ReAct loop with native tool-use (local LLM, wise tier) and leans on the other components for the hard calls (Vaglio for safety, Synt for missing capabilities, Telos for ends).
Check. Try to finish these sentences out loud: «An e-mail is sent by an…», «When two executors often work together, between them a… is born», «All these threads together form the…», «Who decides the order of the steps is the…». If you answer executor, mnest, mnestome, agent runtime, you may proceed.

13.3 The component map

The documented components are organized by role. The diagram below groups the main nodes by role: thick black border for the central engine, green shapes for the «services» the engine consults, blue shapes for the «tissues» that hold state, bronze shapes for the peripheral organs facing the user and the environment. Arrows show who calls whom.

telos — ultimate ends channel (Telegram) pairing approval_ux agent runtime ReAct loop · planner native tool-use vaglio policy sandbox synt executor (pool) signed contracts + controlled synthesis scratchpad turn state mnest co-activation traces mnestome graph + ager obs. dashboard orients
Component map. Solid arrow: direct call. Dashed arrow: orientation or read.

Three observations to read the diagram well.

  1. Telos sits above everything: it is not a service one calls, it is an orientation. The runtime weighs alternatives in light of the ends declared in the homonymous workspace file.
  2. Vaglio always runs before execution, never after. Once an executor has fired, going back is not free: undo exists, but it costs history and backup blobs.
  3. The executor pool is open: synt can compose new executors out of existing ones, or — if that is not enough — generate one from scratch, with signing and automatic install.

13.4 A second worked request

To pin the map down, let’s follow a simple request from inbox to reply: «move to ~/Archive/2026 the invoice PDFs that arrived this week».

  1. Channel. Telegram receives the user message. The daemon checks that the sender is paired with sufficient authorisation; otherwise the message is silently dropped. Pairing means «channel + sender ID recognised»: it is obtained by replying to a signed Ed25519 code with a TTL.
  2. Agent runtime — planning. The runtime extracts the intent (canonical verb: move; object: files; criterion: invoice-attached PDFs in the «last week» window), asks the prefilter to narrow the catalog to relevant executors, and prepares the first step of the ReAct loop.
  3. Vaglio — guard + judge. Before the executor fires, Vaglio checks two things: that the path is not forbidden, that the shell command is not unrecoverable (rm -rf and friends). For grey-zone operations, the rule-based judge assigns a score and, above threshold, asks the user for confirmation via the three-line card (what / where / why).
  4. Sandbox + executor. The runtime invokes read_messages inside bwrap with the flags derived from the manifest. The output comes back as a list of entries; each entry is a dict with the PDF path and metadata.
  5. Pipe. The next step is move_files; it takes the previous step’s list via from_step: N. Ground truth lives in the scratchpad: the planner sees not the whole list, but a synthetic view large enough to decide.
  6. Mnest + mnestome. The pair read_messages → move_files reinforces an existing trace in the graph; if absent, it creates one. The nightly ager will do upkeep: decay, merges, drops.
  7. Reply. The runtime answers the user via Telegram with the number of files moved and the first reason for skipping if any have been left out. The final_answer includes a truncation marker if the input list had been capped.
Check. Without looking back: who talks to the user? who decides the sequence? who fires the executors? who checks the operation is allowed? who remembers that two capabilities went hand in hand? If your answers are channel, agent runtime, agent runtime, vaglio, mnestome, the map is yours.

13.5 Canonical component deep dives

Below, the documents are grouped by role. All have an Italian counterpart at /it/architecture/.

Central engine
ComponentScope
Cognitive engine The four-layer engine that plans and executes (replaces the iterative step-by-step planner): Fastpath serves user-approved shortcuts (hash + BGE-M3 cosine), Autopath recognises and reuses skills learned from feedback (sqlite, semantic + intent match), Validator checks the plan before running it, and the Engine block proposes the whole plan in a single local LLM call (Proposer), executes it deterministically (Executor), recovers by classifying the error into 4 classes (Recovery) and, if there is no way out, honestly explains what is missing (Terminator). One proposal instead of six calls: faster, zero cost, and faster still as it learns.
agent_runtime ReAct loop, mode router, data piping between steps (from_step: int for lists, {{stepN.field}} for scalars), scratchpad, mnestome hooks. The engine that calls everyone else.
scratchpad Per-turn temporary store: holds large observations without crowding the planner’s context. Builtin scratchpad_read with head/tail/range.
grammar Constrained generation via GBNF for the PLANNER tool_call. Discriminated union name+args, recursive schema, contextual pool filter, post-decode validator. Solves thinking-loop, args mix-match, arbitrary escape-hatches. Bench convergence 50% → 100%.
fastpath and autopath Two layers of memoization before the planner. L0 — fastpath: the shortcut for the same request, recognised by fingerprint (hash) or semantic proximity (BGE-M3 cosine) and served again with the plan already prepared, concrete arguments included. L1 — autopath: the generalised plan for a cluster of related requests (the skeleton without arguments), promoted from repeated positive feedback and kept in autopath.sqlite (tables autopaths/anti_autopaths). Hybrid argument extractor (rule + memory + optional LLM).
Tutor Local pre-planner guide: compiles admitted manifests, allowlisted public documentation, and curated procedures into a signed BGE-M3 catalog. It answers with no tools, filters audience before the model, separates explanations from actions, and reports gaps. Includes the F2 architecture and F3/F4 roadmap.
mail accounts Configuration of IMAP/SMTP mailboxes, including non-Google providers: encrypted bindings, multiple accounts, env-file compatibility, and the boundary with Gmail-specific features.
lifecycle Unified system-change lifecycle: one change_intent object, one state machine (proposed→accepted→applied→observed→finalized, plus staged/rejected/failed/rolled_back), one UI /admin/changes. Funnels the proposal sources (telos, introspective, synt, fast-path, feedback) into one queue. Nightly pipeline: materialization (cross-source fingerprint dedup), per-kind application, observation with a grace window and physical rollback.
model virtualization How Metnos picks and swaps its models: three facades (get_llm, get_embedder, get_vlm) that ask for a role, not a model, and translate the role by reading the {llm,embedding,vlm}_tiers.toml files. Change a model = edit a TOML, never the code. Segregation (no consumer imports the concrete embedder any more), embedding autonomy (BGE-M3 and SigLIP run ONNX in-process), remote endpoint via provider="http". A lightweight subset of the supranet pattern: Protocol + factory, no registry/DI.
Executable capabilities and their birth
ComponentScope
executor Anatomy of an executor: TOML manifest, Ed25519 signature, sandbox profile, lifecycle, and vector contract (list-in, list-out). The current count lives in the generated catalog rather than this prose.
executor catalog Inventory generated from signed manifests: every first-party executor grouped by canonical domain, with purpose, criticality, platforms, and source location.
remote_executors How a controlled part of the executor catalog can run on registered devices: metnos-client, device pairing, manifest placement, per-OS sandboxing, UI installation and explicit Windows/Linux limits.
intelligent executors Narrow-mandate agents behind a regular executor contract: bounded adaptive loops, deterministic resolvers before models, unchanged authority, and verifiable postconditions. login_sites is the first example.
synt How new executors are born: five-stage pipeline (naming, signature, tests, description, code), reactive cascade (compose → generate) and introspective cascade (dedupe, generalize, specialize).
skill_importer Imports third-party skills from agentskills.io and turns them into Metnos executors: five-stage pipeline (fetch, parse, map, wrap, register), verb mapping table skill_vocab_map.json, wrapping helpers with verb boundary, and CLI metnos-skills import|list|uninstall|status|evaluate.
skills & backends Why skills and backends are two orthogonal axes: the backend says HOW you run a verb_object (configuration, backend_resolver, invisible to the LLM), the skill says WHETHER/WHICH capabilities are unlocked (activation, dormancy, sandbox). Three tiers (core / first_party / imported), multi-provider architecture transparent to the planner, promotion with a one-off frontier.
Associative memory
ComponentScope
mnest The co-activation trace between two executors: anatomy, lifecycle, decay, persistence, proto-mnest.
mnestome The emergent graph of all mnests: SQLite data schema, atomic operations, nightly ager, snapshot. Italian term: mnestoma.
Safety, rules, sandbox
ComponentScope
vaglio Binary guard (forbidden paths, near-unrecoverable shell commands) and graded rule-based judge with configurable threshold. Probabilistic LLM judge deferred.
policy Closed capability registry, autonomy × capability table (ReadOnly / Supervised / Full), per_target persistent grants, combined effective_outcome.
sandbox bwrap profile derived from the manifest: read-only mount of the code, network isolation if no capability requires it, graceful fallback if bwrap is missing. Landlock deferred.
User-facing channel
ComponentScope
channel Channel adapter (Protocol with send / poll) and first concrete implementation: TelegramChannel with long-poll, last_update_id persistence, daemon and systemd user unit. Multi-user: send_to(chat_id, OutboundMessage) + /start <token> for guest pairing.
http_api Second HTTP server (port 8770): uniform agent channel on POST /agent/turn (SSE + JSON), /admin dashboard in htmx + Jinja2 + uPlot, user management, introvertiva proposals, scheduler runs. Auth via admin key (7-day cookie) or device Bearer.
pairing Two paths: /pair with TTL-bound signed Ed25519 codes for technical devices, and /start <token> short-lived for family/guests (multi-user). Registry users.db with host + guests, user_channels, resolve_recipients. Host bootstrap on first run.
approval_ux Three-line card for confirmation prompts: render_approval_card, ApprovalRequest, modulation full / medium / short by recurrence, Telegram dispatcher approve:<tok> / reject:<tok>.
Multilingual
ComponentScope
multilang Three multilingual layers: LLM prompts (runtime/prompts/<lang>/<role>.j2), executor descriptions (TOML manifest + companion JSON), user-facing messages (i18n.sqlite). Latest-wins source-of-truth: no language is canonical by construction; the latest editor wins. Admin command metnos-prompts add-language <code>. Opt-in frontier tier for higher quality.
Visibility and ends
ComponentScope
observability Static HTML dashboard aggregating Metnos’s data sources (mnestome, pairings, turns, Vaglio decisions, scheduler). Generated on demand: no live server, no JavaScript.
telos The user’s ultimate ends, the alignment function, the bother budget with scheduler quotas, the non-renunciation telos (t.coltivazione_strumenti) and the stop clause. The TELOS.md file lives in the workspace.

13.6 Vocabulary and primitives

The closed vocabulary stands at 26 actions (read, write, move, delete, create, find, list, filter, sort, group, classify, get, set, send, describe, render, extract, compress, compute, compare, change, order, share, open, login, act) and 26 objects (files, dirs, packages, messages, events, contacts, places, processes, urls, numbers, images, signatures, texts, proposals, persons, tasks, inputs, approval, credentials, issues, pulls, calendars, entries, lists, skills, sites). Qualifiers come in four families: format/encoding, modality, safety policy, and provider (for specific non-default backends like _google_workspace). Centralised in runtime/vocab.py.

The planner currently exposes nine consumers for lists of entries. The five structural or numeric operators are filter_entries, filter_lists, sort_entries, group_entries, and compute_entries. The four in-process semantic helpers are classify_entries, compare_entries, extract_entries, and describe_entries. The first group filters one list, combines two lists, sorts, merges/deduplicates, or computes an aggregate; the second classifies, compares semantically, extracts structured records, or summarizes. The list is checked against the runtime registry and signed manifests. Concrete user example: «Is there an HLT appointment that overlaps with an MNM one in the next 3 months?» → the planner builds in six steps read_events → filter HLT → filter MNM → filter_lists(op=overlap) → final_answer.

The verified live inventory contains 115 standard, signed executors: 82 handcrafted executors in the main tree, 16 builtin GitHub executors with handcrafted origin, and 17 runtime builtins using in-process transport. The Composer sees the same contract for all of them and does not select by transport. Five orthogonal producer verbs (find for patterns, get for ids/state, read for blobs from a source, list for containers, filter for reduction).

13.7 Contract-writing conventions

Every component-contract file follows the same template as this handbook's architectural overview:

14. The principles, in eight cards

If you remember only eight sentences from this document, make it these. Everything else — code, prompts, conventions — follows from here.

1Vectorized by construction. Every executor accepts a list and returns a list, even a degenerate one. The batch version is the executor: *_batch does not exist.
2A closed, governed vocabulary. Everything that acts has a composable name inside a closed grammar. A new term enters only if necessary, general and understandable.
3No silent failure. Counts reflect what actually happened; truncation is declared, not hidden; a partial result presented as complete is a bug.
4Deterministic > LLM. Where an automaton or a table suffices, the model is not used. The LLM enters where an equipotent parser would genuinely be too complex — and it enters constrained.
5Never an implicit delete. Every move is copy → check → delete; never DELETE without a confirmed COPY.
6Reversibility with a rationale. Every evolutionary act (synthesis, merge, archive) is reversible and motivated. Saying yes costs less when you can go back.
7i18n by construction. Every user-facing string and prompt is per-language data: a new language is a translation pack, not a fork of the code.
8Understandability as a duty. If the user does not understand the system, the system is useless. Simplicity is not aesthetics: it is the criterion that selected everything else.

15. What Metnos is NOT

Half of the design lives in the no's. Every temptation to add an item from this list must be resisted.

16. Where to go next

You now have both levels: the system from above and the map of its component contracts. Use the atlas for implementation detail, or continue with the tour, glossary and design dialogues.

reference
Component contracts
Return to the atlas and open the exact implementation contract you need.
operational reference
Domains and examples
What you can ask Metnos, domain by domain, with natural phrases ready to adapt.
introductory guide
The interface
The two channels, the Settings sections, and the map of pages with their navigation paths.
tour · 10 min
Quick Tour
The fast lap with screenshots: what using it feels like, before studying it.
reference
Glossary
Every project term, defined once and linked everywhere.
dialogue · 40 min
Dialogue on ends and limits
The Galilean origins: teleology, the 4 Laws, the vaglio. Why a proactive agent needs a brake.
dialogue · 45 min
Dialogue on executors
The technical foundation: executors, mnest, mnestome, traces, ager, the six original principles.
component contract
Remote executors
How Metnos moves selected executors from the server to a registered PC while keeping policy, audit and explicit limits.
code
The repository
AGPL-3.0, pre-1.0: the public subset of the daily-driven instance, installer included.

Metnos — Architecture Handbook (July 2026).
mētis + noûs: cunning intelligence in the service of the mind — on your own hardware.
Bilingual IT+EN documentation at metnos.com; code at github.com/brunialti/metnos.