Docs / The CLI / The agent surface
The agent surface
Reference for the jotura CLI agent commands: memory, context, conventions, agents sync, skill install and hook install, with every flag and exit code.
The commands on this page exist so that an automated agent can carry knowledge from one session to the next. They cover three separate mechanisms. The first is a memory store of decisions, facts and follow-ups written as ordinary notes. The second is a shared conventions note that every agent runtime reads. The third is a reconciler that keeps agent configuration files in the vault rather than scattered across your home directory.
Everything here writes plain Markdown into your vault. There is no hidden database and no separate agent format. If you open the vault in the desktop app you will see the memory notes, the conventions note and the Agents/ folder exactly as the CLI wrote them. For the commands that read and edit notes generally, see Reading and searching and Editing notes.
The global flags work on every command on this page. --vault picks the vault for one invocation, --json asks for structured output where the command honors it, and -v or --verbose logs the resolved vault path to standard error. Install and setup covers them in full. The tables below list only the arguments that are specific to each command.
Where agent content lives in the vault
| Path | Written by | What it holds |
|---|---|---|
Agent Conventions.md | jotura conventions (first use), then hand edits | The shared, synced rules every agent runtime follows in this vault. |
Memory/Decisions/, Memory/Facts/, Memory/Followups/ | jotura memory log | One note per memory. The root folder is configurable. |
Agents/<Runtime>/ | jotura agents sync | The canonical copy of instruction files, skills and subagent definitions. |
Agents/Agents.md | jotura agents sync | The anchor note. Its frontmatter declares custom runtimes and its body carries a generated index. |
Because these are ordinary vault files, cloud sync carries them between your machines end to end encrypted, like any other note. Cloud sync is a paid feature, and pricing covers what it costs. See Sync and shares for how the CLI relates to it.
jotura context
context is the single call that makes a session memory-aware. It prints a context pack containing the conventions note, any open follow-ups, a set of relevant memories and a drift flag for agent configuration.
jotura context "rewrite the sync retry backoff"
| Argument or flag | Type | Default | What it does |
|---|---|---|---|
[TASK] | string | none | Task description to recall memories against. Omit it for a session digest. |
--limit <LIMIT> | number | 8 | Maximum memories to include. This applies only to the task form. |
The two forms behave differently and the difference matters. With a task, the memories field is a full recall against that task with stale entries excluded, capped by --limit. Without a task, memories lists every non-closed memory marked importance: high, and that list is unbounded because --limit does not apply to it.
context respects --json. The JSON shape is:
{
"conventions": "<full text of Agent Conventions.md>",
"openFollowups": [ { "path": "…", "project": "…", "date": "…" } ],
"memories": [],
"agentConfigDrift": false
}
With a task, each entry in memories carries the full recall shape of path, kind, status, importance, project, date, snippet and score. Without a task, entries carry only path, kind, project and date. If the conventions note does not exist, conventions is an empty string. context does not create the note; only jotura conventions does that.
The text form prints named sections, and this is what the Claude SessionStart hook injects into a session:
=== Conventions ===
…
=== Relevant memory ===
- path (kind)
=== Open follow-ups ===
- path
=== Agent config ===
drift detected: run 'jotura agents sync'
Empty sections are omitted. The === Agent config === section is quieter than the others. It appears only when two things are true: jotura agents sync has run at least once on this machine, so that the per-machine state file exists, and the managed files have since drifted. If you have never used agents sync, or everything is currently in sync, the section stays silent.
jotura conventions
conventions prints the Agent Conventions note and creates it from a bundled seed the first time you run it.
jotura conventions
The note lives at the fixed vault path Agent Conventions.md, at the vault root, with a space in the filename. It has no command-specific arguments and it respects --json.
{ "path": "Agent Conventions.md", "hash": "…", "body": "…", "created": false }
Note the shape difference against jotura read: the JSON carries body with the frontmatter stripped and there is no frontmatter field. The text form prints the whole file including frontmatter.
The note is an ordinary vault note. It is user-visible, it syncs, every agent runtime shares it, and no installer touches it. To change it, edit it with the normal editing commands. conventions is only the read and bootstrap half of the loop.
jotura memory
Memory records decisions, work-world facts and follow-ups. The schema deliberately has no field for personal traits, and the source says so directly: memory is about the work, not about characterizing a person.
Notes are laid out as <root>/<Decisions|Facts|Followups>/<YYYY-MM-DD> <slug>.md, where <root> defaults to Memory. The slug is lowercased and reduced to ASCII alphanumerics, with spaces, hyphens and underscores collapsed to single hyphens and then trimmed.
A note counts as memory if its vault path starts with Memory/ or contains /Memory/. That is what lets you keep two entirely separate roots, for example Whitbread/Memory/ and Personal/Memory/, without them bleeding into each other.
Decisions and facts start with status: active. Follow-ups start with status: open. The closed statuses are superseded, reversed and resolved. A memory is considered stale when it is not closed and its date frontmatter key is more than 180 days old. That is worth reading twice, because staleness is computed from the date key that log wrote, not from the file’s modification time. Editing the body later does not refresh it, and editing the date key does.
memory log
jotura memory log --kind decision --title "Keep tantivy for body search" --project jotura --importance high
| Flag | Type | Default | What it does |
|---|---|---|---|
--kind <KIND> | string | required | decision, fact or followup, case-insensitive. Anything else exits 9. Sets both the subfolder and the initial status. |
--title <TITLE> | string | required | Becomes the H1 and the filename slug. A title that slugifies to nothing, such as pure punctuation, exits 9. |
--project <PROJECT> | string | none | Written as a project frontmatter key. recall and list filter on it. |
--importance <IMPORTANCE> | high or normal | normal | Ranking weight. Any other value exits 9. |
--tags <TAGS> | comma-separated string | none | Split on commas, each value trimmed, written as an inline flow sequence such as tags: [a, b]. |
--root <ROOT> | string | Memory | The memory root folder. Use it to keep work and personal memory apart. |
--body <BODY> | string or - | see below | The note body. - reads from stdin. |
The frontmatter block log writes carries four keys always, in this order, plus two more when you supply them:
| Key | Written when | Value |
|---|---|---|
kind | always | decision, fact or followup. |
status | always | active for decisions and facts, open for follow-ups. |
importance | always | high or normal. |
date | always | The log date as YYYY-MM-DD. Every staleness rule on this page reads this key. |
project | with --project | The project string verbatim. |
tags | with --tags | An inline flow sequence such as tags: [a, b]. |
If you omit --body, the result depends on the kind. A decision gets a section template with ## Context, ## Options considered, ## Decision & why and ## Outcome headings. A fact or followup gets an empty body. Passing - reads the body from standard input, which is the natural form when a script is generating it:
printf 'Chase the Play review on Monday.\n' | jotura memory log --kind followup --title "Chase Play Store review" --body -
Marking a memory --importance high has two effects: it multiplies its recall score by 1.5, and it makes the note appear in the bare jotura context digest.
The command always emits JSON, whether or not you pass --json:
{ "path": "Memory/Decisions/2026-08-30 keep-tantivy-for-body-search.md",
"hash": "…", "kind": "decision",
"similar": [ { "path": "…", "snippet": "…" } ] }
The similar array is a duplicate warning. Before writing, log recalls the title against the same kind with a limit of 5 and returns whatever it finds, on the expectation that you will supersede an existing memory rather than log a near-duplicate. It is advisory only and never blocks the write.
The same-day overwrite gotcha. The filename is derived from the date and the title slug, and the write is unconditional with no expected hash. Logging the same title twice on the same day therefore replaces the first note instead of creating a second one. The similar array is the only guard against this, and it does not stop anything. If you are recording a genuinely different memory, change the title.
memory recall
jotura memory recall "sync retry backoff" --kind decision --limit 5 --json
| Argument or flag | Type | Default | What it does |
|---|---|---|---|
<QUERY> | string | required | Free-text query. See the ranking notes below. |
--kind <KIND> | string | none | Restrict to decision, fact or followup. An invalid kind exits 9. |
--project <PROJECT> | string | none | Exact match on the project frontmatter key. |
--limit <LIMIT> | number | 10 | Maximum results returned. |
--include-stale | boolean | false | Include superseded, resolved and stale memories. Without it they are filtered out entirely. |
recall respects --json. The JSON is an array of objects with path, kind, status, importance, project, date, snippet and score. The text form is tab-separated: path, kind, status, snippet.
How ranking works. The underlying search engine ANDs its terms together, which is the wrong behavior for recall, because a task description rarely repeats a stored note word for word. So recall does something unusual. It runs the full query and then each significant term on its own, where a significant term is 4 or more alphanumeric characters. Terms are deduplicated and the whole set is capped at 7 queries, each with an internal limit of 200 results. The results are merged by path and their scores are summed, so a note that matches more of the query ranks higher than one matching a single word.
Three multipliers then apply to the summed score:
| Condition | Multiplier |
|---|---|
importance: high | 1.5 |
Stale, meaning open or active and a date more than 180 days old | 0.5 |
| Closed, meaning superseded, reversed or resolved | 0.25 |
Any result whose path is not a memory path is discarded. Recall is keyword-based today. Semantic recall is marked as future work in the source, so a query that shares no words with a note will not find it. For general semantic search over the rest of the vault, see Reading and searching.
memory list
jotura memory list --kind followup --status open --json
| Flag | Type | Default | What it does |
|---|---|---|---|
--kind <KIND> | string | none | Filter by kind. An invalid kind exits 9. |
--status <STATUS> | string | none | Exact match on the status key. |
--project <PROJECT> | string | none | Exact match on the project key. |
--stale | boolean | false | Show only active or open memories whose date is more than 180 days old. Closed statuses are excluded entirely. |
list respects --json. The JSON array entries carry path, kind, status, importance, project and date, with no snippet and no score. Text output is tab-separated: path, kind, status.
Two behaviors differ from recall. First, list walks the note tree directly instead of searching, and it skips any note whose frontmatter has no kind. Second, --status is not validated while --kind is. An invalid --kind exits 9, but an invalid --status is accepted and simply matches nothing, returning an empty list.
memory supersede
jotura memory supersede "Memory/Decisions/2026-05-02 use-polling-for-sync.md" \
--by "Memory/Decisions/2026-08-30 use-websockets-for-sync.md"
| Argument or flag | Type | Default | What it does |
|---|---|---|---|
<OLD> | string | required | The note being superseded. Its status becomes superseded and a superseded-by key is added. |
--by <BY> | string | required | The superseding note. A supersedes key is added to it. |
Both notes are checked for existence before either one is modified. The command always emits JSON: { "superseded": "<old>", "by": "<new>" }.
One caveat sits underneath that. The link is written as three separate hash-checked writes, for the status, the superseded-by key and the supersedes key. If another writer edits either note partway through the sequence, the pair can end up half-linked, so check both notes if a supersede reports a conflict.
memory resolve
jotura memory resolve "Memory/Followups/2026-08-12 chase-play-store-review.md"
It takes one positional <PATH> and sets status: resolved. It always emits JSON: { "resolved": "<path>" }.
Despite the help text saying “Mark a follow-up resolved”, the command is not restricted to follow-ups. It will set resolved on a decision or a fact just as readily, so check the kind before running it.
jotura agents
agents requires CLI 0.7.0 or later. On an older binary the command does not exist at all, and you get a bare usage error from the argument parser with no explanation. Run jotura --version to check, and see Install and setup for upgrading.
agents treats the vault as the canonical home for agent configuration. Global instruction files, skills and subagent definitions live under Agents/, one subfolder per runtime, with real filenames preserved. Because that folder is ordinary vault content, it syncs across your machines like any other note. The vault copy is the source of truth and the files in your home directory are managed outputs.
One overlap is worth flagging before the detail. jotura skill install, described further down this page, writes into ~/.claude/CLAUDE.md and ~/.claude/skills/, and both of those paths are also managed by agents sync. Under the three-way model below, a skill install run counts as a system-side change. The next agents sync therefore sees it as a pull into the vault, or as a conflict if the vault copy of the same file also moved.
The built-in runtime registry covers four runtimes:
| Runtime | Vault folder | Home folder | Instruction file | Skills | Subagents |
|---|---|---|---|---|---|
| claude | Agents/Claude/ | ~/.claude | CLAUDE.md | ~/.claude/skills maps to Agents/Claude/Skills/<name>/ | ~/.claude/agents maps to Agents/Claude/Subagents/<name>.md |
| codex | Agents/Codex/ | ~/.codex | AGENTS.md | ~/.codex/skills | none |
| gemini | Agents/Gemini/ | ~/.gemini | GEMINI.md | none | none |
| copilot | Agents/Copilot/ | ~/.copilot | copilot-instructions.md | none | none |
Adding a custom runtime
You extend the registry from the YAML frontmatter of Agents/Agents.md. That frontmatter is user-owned, so nothing overwrites it.
---
custom:
- name: Cursor
target: ~/.cursor/rules
kind: folder
- name: Windsurf
target: ~/.codeium/windsurf/memories/global_rules.md
kind: file
---
All three of name, target and kind are required. A malformed entry is reported as a warning and skipped, never as a fatal error. Use kind: file for a single text file and kind: folder for a tree of text files, which carries the same exclusions as skills. Write targets with a ~/ prefix and forward slashes. Absolute paths work but draw a non-portability warning. A target may not point inside the vault, because that would create a sync loop, and it may not overlap a built-in path.
What is never synced
Some files are refused structurally, even if a custom entry names them: auth.json, credentials.json, .credentials.json, settings.json, config.toml, *.pem, and id_rsa and its siblings. Dot-prefixed files and directories are skipped, which includes vendor skill sets under .system. Binary files found inside a synced folder are reported as skipped-binary warnings and left where they are.
Per-machine state lives outside the vault, at <config>/jotura/agents/<vault-id>.json, and records the last-synced hash for both sides of every file. That state file is what lets the reconciler tell a changed file from a new one.
agents status
jotura agents status --json
agents status is a read-only drift report and it takes no command-specific arguments. It always exits 0, by design, including when it reports conflicts. Only agents sync exits 16, so do not use status as a health gate on its exit code. Parse its output instead.
status respects --json and emits newline-delimited JSON, one object per line, with a final line for warnings:
{"item":"claude/CLAUDE.md","action":"apply","path":"Agents/Claude/CLAUDE.md","system":"/home/u/.claude/CLAUDE.md","custom":false}
{"warnings":["skipped-binary: …"]}
The text form prints the action padded to 14 characters followed by the key, with (custom) appended for custom entries, and then any warning: lines. The possible status labels are runtime-absent, in-sync, apply, pull, conflict, prune-candidate and forget.
The vocabulary differs slightly from the action list under agents sync below, because status reports what a sync would do rather than what one did. prune-candidate is the label for a deletion that sync will go on to report as either prune-skipped or pruned.
agents sync
jotura agents sync --dry-run
| Flag | Type | Default | What it does |
|---|---|---|---|
--dry-run | boolean | false | Compute and print the planned actions without writing anything. Adds "dryRun": true to each JSON line. |
--prune | boolean | false | Allow a vault deletion to delete the corresponding system file. |
--prefer <PREFER> | vault or system | none | Resolve both-sides-changed conflicts in that direction, for this run only. |
--item <KEY> | string, repeatable | none | Restrict the run to these item keys, as printed by agents status, for example claude/CLAUDE.md. Repeat the flag for more than one item. Any key not found in the current plan exits 9, naming the key in the message. |
Combine --item with --prefer to resolve one conflicting item without touching the rest of the registry:
jotura agents sync --item claude/skills/review --prefer vault
This is exactly what the desktop app’s Settings screen does behind its Keep vault and Keep this machine buttons: one --item, one --prefer, nothing else in the run. See Settings reference for that surface.
sync respects --json and emits newline-delimited JSON. The text form is the same padded action lines as status, followed by warnings, then a summary line reading applied N, pulled N, conflicts N, pruned N. The pulled count in that summary includes both pull and adopted.
Each file gets exactly one action:
| Action | Meaning |
|---|---|
apply | The vault changed and the system did not, so the vault content is written to the system path. The write is atomic, using a temporary file and a rename, and missing parent directories are created. |
pull | The system changed and the vault did not, so the vault note is updated through the normal note write path. The watcher, cloud sync and search index all pick it up. |
adopted | A pull of a file the state has never seen before. The first run adopts everything it finds on the system. |
conflict | Both sides changed. The file is skipped and reported, and nothing is written for it. No conflict copies are ever materialized. |
prune-skipped | Deleted in the vault, still present on the system, and --prune was not passed. |
pruned | The same deletion, carried out because --prune was passed. |
in-sync or noop | Nothing changed. |
forget | Neither side has the file any more, so the state entry is dropped. |
runtime-absent | The runtime is not installed on this machine, meaning ~/.claude or its equivalent is missing. This is inert: vault files for that runtime neither apply nor error. |
The three-way model. Every decision compares three things: the current vault content, the current system content, and the last-synced hashes recorded in the per-machine state file. That third input is what separates a change from a first sighting. One side changed means the change wins. Neither changed means nothing happens. Both changed is a conflict.
Conflicts and exit 16. When both sides of a file have changed since the last sync, that file is skipped. The command still completes every other piece of work first, and only then exits 16 with a conflicts array in the error JSON listing the vault-relative paths. Exit 16 is not an abort, so the rest of your configuration did sync. Re-run with --prefer vault to turn each conflict into an apply, or --prefer system to turn each into a pull. The preference applies to that run only and is not remembered.
jotura agents sync --prefer vault
The first-apply safety net. Before the first apply ever overwrites a system file whose content the state has never recorded, the original is copied alongside it as <name>.jotura-backup. This is one-shot: it protects the first contact, not subsequent applies.
Direction is asymmetric. A file deleted on the system but still present in the vault is re-applied, because the vault is canonical. If you want a system-side deletion to stick, delete the vault copy and then run the sync with --prune:
jotura agents sync --prune
The anchor note is amended, not clobbered. A real sync run, meaning any run without --dry-run, regenerates an index of every registry item in the body of Agents/Agents.md. That index is written inside a managed block delimited by <!-- jotura:begin --> and <!-- jotura:end --> lines, and everything outside those markers is left untouched. Your own prose in that note survives every sync. If the note does not exist, it is created with an # Agents heading, the managed block and a ## Links section linking to the conventions note.
jotura skill
skill installs Jotura’s own agent instructions into agent configuration directories. It needs no vault, so it runs before vault resolution and never exits 6.
The content is compiled into the binary, so an installed CLI always carries its own canonical instructions and never fetches anything over the network. Three documents are bundled: SKILL.md covering CLI mechanics, NOTES_SKILL.md covering filing and capture principles, and AGENT_NOTES.md carrying the standing instructions.
Managed blocks amend, they do not clobber
Everything between a <!-- jotura:begin --> line and a <!-- jotura:end --> line belongs to skill install. Everything outside those markers is yours and is never modified. This is the same mechanism agents sync uses for the anchor note.
Three details are worth knowing. The markers count only when they occupy a whole line on their own, so prose that merely quotes them inline is ignored rather than treated as a real marker. If the target file has no block at all and is not empty, the block is appended after a blank line, leaving your existing content in place above it. And a legacy install that wrote the entire file with no markers is migrated wholesale, but only when the content matches the bundled version exactly.
skill install
jotura skill install all
| Argument or flag | Type | Default | What it does |
|---|---|---|---|
<AGENT> | string | required | claude, codex, gemini, copilot or all, case-insensitive. Anything else exits 9 and prints the accepted list. |
--force | boolean | false | Overwrite a modified Claude skill file without asking. See the paragraph below, because unattended callers need this. |
--force is consulted only on the standalone-file path used for Claude’s two skill files. The managed-block merge ignores it, because that merge never destroys user content and so has nothing to confirm. Without --force, an install that would overwrite a skill file whose content differs from the bundled version asks for confirmation on the terminal. When there is no terminal attached, which is the normal case for an agent or a script, the answer is taken as no. Nothing is written, the action is reported as skipped, and the command still exits 0. Pass --force for any unattended install.
| Agent | Files written | What the managed block carries |
|---|---|---|
claude | ~/.claude/skills/jotura-vault/SKILL.md as a whole file, ~/.claude/skills/jotura-notes/SKILL.md as a whole file, and a managed block inside ~/.claude/CLAUDE.md | The standing instructions from AGENT_NOTES.md only. The CLI and filing material arrives as the two standalone skill files instead. |
codex | A managed block inside ~/.codex/AGENTS.md | The combined filing and CLI body. |
gemini | A managed block inside ~/.gemini/GEMINI.md | The combined filing and CLI body. |
copilot | A managed block inside ~/.copilot/copilot-instructions.md | The combined filing and CLI body. |
all | Everything above | As above, per agent. |
install emits newline-delimited JSON, one line per file touched, whether or not you pass --json. Each line is { "agent": "…", "path": "…", "action": "…" } where the action is installed, updated, unchanged or skipped.
skill list
jotura skill list --json
skill list takes no arguments and it respects --json. The JSON is an array, and the claude entry is richer than the others because Claude receives three files rather than one:
[ { "agent": "claude", "path": "…", "installed": true, "upToDate": true,
"notesSkillPath": "…", "notesSkillState": "up-to-date",
"agentNotesPath": "…", "agentNotesInstalled": true, "agentNotesUpToDate": true },
{ "agent": "codex", "path": "…", "installed": true, "upToDate": false } ]
notesSkillState is one of up-to-date, customized or missing. The text form prints the agent name padded to 12 characters, then missing, up-to-date or stale, then the path, with two extra lines under the Claude row for the notes skill and the agent notes.
skill show
jotura skill show
skill show takes no arguments. It prints the canonical SKILL.md to standard output verbatim and ignores --json, because it is a raw print rather than a structured emit. Be aware that it prints only SKILL.md, not the combined filing and CLI body that codex, gemini and copilot actually receive through their managed block. No command prints that combined body.
jotura hook install
hook install wires the context pack into a runtime’s session startup.
jotura hook install claude
| Argument | Type | Default | What it does |
|---|---|---|---|
<AGENT> | string | required | The runtime name. Only claude is supported, case-insensitively. |
Any other value exits 9 with a message explaining that other runtimes get the loop through their prompt file instead. Like skill, this command needs no vault and runs before vault resolution.
The install merges into ~/.claude/settings.json without touching unrelated keys, appending an entry to hooks.SessionStart that runs the literal command jotura context. The appended entry looks like this:
{ "hooks": [ { "type": "command", "command": "jotura context" } ] }
It is idempotent: an existing entry is detected by a substring match on jotura context across the serialized entry and reported as unchanged. The parent directory is created if it does not exist.
This is the one piece of agent configuration on the page that does not travel with your vault. settings.json is on the structural exclusion list above, so agents sync will never carry it. Run jotura hook install claude once on every machine you work from.
The command always emits JSON: { "agent": "claude", "path": "…/.claude/settings.json", "action": "installed" }, where the action is installed or unchanged. If settings.json is not valid JSON, or its hooks or hooks.SessionStart keys have the wrong type, the command exits 1 rather than repairing the file.
Exit codes on this page
| Code | Symbol | When you will see it here |
|---|---|---|
| 0 | none | Normal completion, including agents status reporting conflicts and skill install reporting skipped. |
| 1 | Error | A malformed ~/.claude/settings.json during hook install. |
| 2 | HashConflict | A hash-checked write lost a race, for example during a memory supersede sequence. |
| 3 | NotFound | A memory path passed to supersede or resolve does not exist. |
| 6 | NoVault | No vault resolved. skill and hook install never hit this. |
| 8 | PermissionDenied | A vault path that resolves outside the vault, including through a symlink or a Windows junction. |
| 9 | InvalidArgs | An unknown memory kind, an unrecognized agent name, an importance value other than high or normal, or a path argument that is empty or contains . or .. components. |
| 16 | AgentConflict | agents sync found files changed on both sides. Resolve with --prefer. |
The code field in the error JSON carries the symbol, and that string is the stable thing for a caller to match on. One collision is worth guarding against in scripts. Clap, the argument parser, defaults to exit code 2 for its own usage errors, such as a missing required argument or an unknown flag, and that number is also HashConflict. Usage errors print human-readable text on standard error rather than the JSON error envelope, so a caller that sees exit 2 should check whether stderr parses as JSON before concluding it hit a hash conflict. The full table is in Exit codes and JSON output.
A note on —json
The --json flag is not uniform across the CLI, and the agent commands sit on all three sides of that split. context, conventions, memory recall, memory list, agents status, agents sync and skill list branch on the flag. memory log, memory supersede, memory resolve, skill install and hook install emit JSON whether or not you pass it. skill show ignores it entirely. Errors are always a single-line JSON object on standard error in every case.
Related pages
- Install and setup for getting the
joturabinary onto your PATH and choosing a vault. - Editing notes for the hash-checked write loop that memory notes use underneath.
- Frontmatter and tags for editing the
kind,status,importance,date,projectandtagskeys directly. - Sync and shares for how the
Agents/folder travels between machines. - Exit codes and JSON output for the complete error envelope.
- Jotura for agents for the wider picture of what an agent can do with a vault.