Verified plugins

ai.oz0/memory

Notes, decisions and definitions agents keep beyond a job, under the platform's retention, holds and erasure, and the accepted ones in an agent's start-up context.

For: tenant administrators and plugin users.

ai.oz0/memory stores notes, decisions and term definitions beyond the end of a job. Its entries use plugin records, so tenant retention, legal holds and erasure apply to them.

Tenant exports include the entries, and the audit log records each read with the returned versions. Search matches words; it does not use embeddings or semantic search.

FunctionWhat it does
oz0_memory.rememberKeep a note or a decision, about work (the default) or about people (about: person). A decision is proposed until a person accepts it. The same text (case and spacing aside) is kept once per scope
oz0_memory.recallRead entries by scope, kind and words: the newest version of each, with its ID and version; include_ended adds replaced entries and those past their review date
oz0_memory.supersedeReplace an entry, naming the version you read: the new entry links to the old one and has only the tags the call gives. A note or a proposed decision is replaced at once; an accepted one stays in force until a person accepts its replacement
oz0_memory.acceptAccept a proposed decision or definition, naming its text (and a definition's term). The call asks a person by default, and the person reads the text and the term being accepted
oz0_memory.changed_sinceWhat was written, replaced, accepted or ended since this agent last asked
oz0_memory.defineRead a term's definition, or propose one: one definition per term and scope. A new definition of an accepted term is proposed, and the accepted one stays in force until it is accepted
oz0_memory.startup_contextCalled by the platform when a job starts, never by a model

The agent oz0-decision-log keeps a team's decision log and glossary with these functions.

Safe by default

Memory follows the tenant's rules, which the platform holds, not the plugin:

  • Work or people. Every entry is memory about work (decisions, procedures, definitions, facts about systems) or about people (a preference, what someone asked or decided). Memory about people is off for every agent until a tenant admin turns it on for that agent and a purpose (below). The writer's word is not enough: whatever a job with a data subject writes counts as memory about people, and is refused while that is off, with the reason and the command that turns it on.
  • Every entry ends. On the date its writer gives (ends), at the latest the tenant's longest end (365 days by default), or else after the tenant's default (90 days). An entry about people is deleted at its end. An entry about work leaves start-up context and recall at its end, which is a review date: a memory_review finding asks its owner to renew it or let it go, and nothing about work is deleted before retention.

Purposes

Every entry carries the purpose its job ran for (the purpose the job tree was started with, never what the plugin says). Jobs read entries written for their own purpose, or for one the tenant maps as compatible, and entries about work written without a purpose, which are the tenant's general knowledge. A job without a purpose reads only entries written without one.

A job changes only entries of its own purpose: reading through a compatible pair never lets it write, and an entry about work written without a purpose (the tenant's shared decision log and glossary) is changed only by jobs started without one, so it stays in force for every purpose. supersede and accept check every entry they would change before writing anything, and refuse with the purpose that may change it; a job that disagrees with a shared decision proposes a new one of its own purpose instead.

  • Caps. One plugin keeps at most 5,000 entries and 8 MiB in one scope by default. Replaced entries and entries past their end count until retention (or, for entries about people, their end) removes them. A write past a cap is refused with the cap in the answer, never dropped.
SettingDefaultHow
Default end90 daysoz0 memory settings set --default-days N
Longest end365 days (at most 3,650)oz0 memory settings set --max-days N
Entries per scope5,000 (at most 20,000)oz0 memory settings set --max-records N
Bytes per scope8 MiB (at most 64 MiB)oz0 memory settings set --max-bytes N
Compatible purposesnoneoz0 memory settings set --compatible from>to

Each change is a governance change: it takes a reason, and a longer end, a higher cap or a new compatible pair waits for another admin while four eyes is on. A pair is one way: --compatible support>billing lets jobs for billing read what was written for support, not the reverse, and never write it. Changes apply to writes from then on. After a shorter longest end, accepting or replacing an entry brings the end it carries down to the new longest end.

Memory about people

Terminal
oz0 inventory purposes set --legal-basis contract='The support contract' --purpose customer-support='Answering customers' \
  --purpose-basis customer-support=contract --reason 'DPIA 2026-14'
oz0 memory person support-triage --purpose customer-support --reason 'DPIA 2026-14 approved'
oz0 run support-triage "…" --purpose customer-support
  • The purpose must be one the agent's definition declares (purposes:), with a legal basis in the tenant's lists (purposes and legal bases). The platform checks the basis again at every write, so a basis removed from the lists stops new entries at once.
  • Only the agent's jobs that run for one of those purposes keep memory about people; a job without a purpose never does.
  • Its entries about people stay in its own scope. --share agent:<name> lets another agent read them (and only them); --share project:<name> or --share tenant lets them be written there.
  • Turning it on, or sharing it further, waits for another admin while four eyes is on, and always in works-council mode (on for every tenant by default), since the platform cannot tell which people are employees. --off turns it off at once.
  • What the tenant may keep about people, for which purpose and on which legal basis, is the tenant's to decide; the platform enforces what the tenant set.

oz0 memory settings shows the settings and every agent that keeps memory about people.

Review dates

An entry about work past its end is out of agents' start-up context and recall. The expiry run, part of the platform's retention pass, opens one finding per plugin and scope that lists such entries:

Terminal
oz0 eval findings --kind memory_review
oz0 memory renew memory tenant d-3f2a91c07b --days 180

Renewing moves the entry's review date (the tenant's default when --days is left out, at most its longest end), and the finding closes once nothing of its scope is due. To let the entries go, resolve the finding with a reason (oz0 eval resolve ID --reason ...): it opens again only when another entry of that scope reaches its review date. An entry let go stays out of start-up and recall until retention deletes it. Entries about people cannot be renewed: their end deletes them, unless the writing agent's keep-for period runs longer. A legal hold stops the run.

Each run that changed something is in the audit log as plugin.records.expired, with counts only.

Scopes

Its agent oz0-decision-log asks for the tenant's fast model alias with tools, never a vendor's model, so it runs on whichever provider the tenant set up first; map it elsewhere with oz0 model alias set fast <provider>/<model>.

An entry lives in one scope:

  • agent: the calling agent's own. Only jobs of that agent read or write it; the platform holds them to it. Another agent reads the entries about people in it only when the tenant shares them with that agent.
  • project:<name>: a project's, which any agent that uses the plugin reads, for the purposes it may read. The plugin remembers which projects each agent used.
  • tenant: the whole tenant's.

Notes and entries about people go to the agent's own scope unless the call names another; decisions and definitions go to the tenant's. Entries about people go elsewhere only where the tenant shares them.

Decisions and definitions in the start-up context

When a job of an agent that uses the plugin starts, the platform asks the plugin for the accepted decisions and definitions that have not ended, of the purposes the job may read, and adds them to the agent's start-up context, after its instructions and its skills index, under the heading ## Context from plugin memory. The agent's own scope comes first, then its projects', then the tenant's, newest first.

They share the agent's limits.startup_tokens (4,000 by default) with its skills index: what does not fit is left out in order, and the agent reads it with recall (by scope) or define (by exact term). A job that continues as new keeps the text its first run got.

## Context from plugin memory

- Accepted decisions and definitions you work under; more with recall (by scope) or define (by term).
- Decision (tenant): Deploy on Wednesdays, never on Fridays. [tenant/d-3f2a91c07b v2]
- Definition of 'active customer' (tenant): A customer with an order in the last 90 days. [tenant/t-5b1e0c2d4a v2]

The job's trace shows the start-up step (startup memory), and the audit log's plugin.records.read entry for it lists the entries and versions the agent was shown, with startup: true, never their text.

Accepting

The plugin's suggested policy asks a person about every write by default ("the plugin asks before it writes"): remember, define, supersede, changed_since (whose only write is the agent's own bookmark) and accept, which asks before it accepts a decision or a definition (approvals).

The install writes these as rules of the tenant's tool policy, marked as the plugin's; an admin switches them with a reason, for one function or the group: oz0 plugin policy memory --set write=allow --reason "agents keep their own notes", and --set accept=allow (or a rule by caller for some agents) where some decisions may be accepted without a person.

The call names the entry, its version and its text, and a definition's term too, and is refused when the text or the term is not that version's: the person approving reads what will reach every agent's start, not only an ID. Up to 1.1.0 accept was under requires_approval, which no tenant rule could lower; an update from one of those keeps asking about it until an admin switches it.

What a person accepted stays in force until a person accepts what replaces it. Superseding an accepted decision, or proposing a new definition of an accepted term, only proposes: the start-up context keeps the accepted one, and define shows both. Accepting the replacement ends the old decision, or makes the new definition the one in force. A proposal superseded by a better one before anyone accepted it ends at once, and its successor still replaces the accepted decision, so accepting the last proposal ends that one.

When another replacement of the same decision was accepted in the meantime, accepting is refused: supersede the decision now in force instead, so that two never hold at once. No call without an approval takes an accepted entry out of agents' start-up context; an entry's review date (its end) and the tenant's retention do, and renewing it brings it back.

Versions, stale writes and supersede

Every write is a new version; the old ones stay. supersede and accept name the version the agent read, and are refused when a newer one exists, so two agents cannot overwrite each other's work unseen: the refused agent recalls the entry again and decides from its newest version. A replaced entry is closed by a version that links to its successor, and keeps its own end.

A call that the platform retries (a node lost on the way, a timeout) writes once and answers with what its first try wrote. Entry IDs say nothing of what they hold: a definition's ID is not its term, so the audit log and an export without content never show the term.

Trust and walls

What a job reads from memory joins its labels with the source memory: an entry written by a job that was tainted, or by an agent of another plugin than the reader's, taints the job that reads it, from its start when the start-up step read it. An entry keeps the compartments of the job that wrote it, and what a call read goes with what it writes next.

When the tenant's label policies keep compartments apart, a read withholds an entry whose compartments the tenant keeps apart from the reading job's, or from those of an entry the same call was already shown, so that one call never reads both sides: the answer says how many entries were withheld, never what they hold. A tenant without such a policy has no walls, and nothing is withheld.

Secrets

A write whose text looks like a key or a token in a well-known format (cloud and source-control keys, provider API keys, private keys, tokens in URLs) is refused with what it seems to hold, never echoed. The platform also refuses any tool call whose arguments carry one of the tenant's own secrets.

Install

Terminal
oz0 plugin install hub:ai.oz0/memory
oz0 run oz0-decision-log "We decided to deploy on Wednesdays from now on"

Agents of other plugins use it by naming its functions in their tools and the plugin in their manifest's uses:, which a tenant admin grants at install. Such an agent gets the start-up text too; to give it no functions but the start-up text, name oz0_memory.recall only.

A glossary in a skill or in memory

A glossary that is part of how a plugin works, the same for every tenant and reviewed with the plugin's code, belongs in a skill: it ships and changes with the plugin's versions. Terms your own people decide, that change while agents run and need someone to accept them, belong in memory as definitions.

Copyright © 2026