Quickstart
Six requests with curl: store a memory, find it, wall one to a person, put one in a compartment and clear someone for it, read the audit row, and ask a question whose answer is grounded in what you stored. Every block below is run verbatim against app.yohanun.com before this page is published.
Before you start
You need a key. Steps 1 to 4 work with either key profile; steps 5 and 6 need a chat-profile key, because the audit read and chat are on the full surface. Put the key in your shell; nothing else is installed.
export YOHANUN_KEY="sile_..." # from your invite
export BASE="https://app.yohanun.com"
1. Store a memory
A memory is text plus a context (a shelf name of your choosing). Labels are optional; a memory with none is shared across the tenant, which is the right default for a handbook and the wrong one for a person's notes.
curl -s -X POST "$BASE/api/memory/memories" \
-H "X-API-Key: $YOHANUN_KEY" -H "Content-Type: application/json" \
-d '{"content": "Invoices go out in euro, net 30. Exceptions are listed in finance/terms.md.",
"context": "handbook"}'
{"memory_id": "1f3c…", "message": "Memory created successfully"}
2. Find it
Search is semantic. Each hit carries the content, a score, when it was created, its labels and its grade. The store has indexed the memory by the time the create call returns, so there is nothing to wait for.
curl -s -X POST "$BASE/api/memory/search" \
-H "X-API-Key: $YOHANUN_KEY" -H "Content-Type: application/json" \
-d '{"query": "what currency do we invoice in", "context": "handbook", "limit": 3}' \
| python3 -c "import sys, json; [print(round(r['score'], 2), r['content']) for r in json.load(sys.stdin)['results']]"
3. Wall a memory to a person
acl_owners names who may see a memory. A principal not among the owners does not get it, and
that is decided inside the retrieval query, not by anything reading the results afterwards. The same request
with two identities:
curl -s -X POST "$BASE/api/memory/memories" \
-H "X-API-Key: $YOHANUN_KEY" -H "Content-Type: application/json" \
-d '{"content": "Maeve prefers a 14:00 call on Thursdays.", "context": "handbook",
"acl_owners": ["user:maeve"]}'
for who in user:fionn user:maeve; do
curl -s -X POST "$BASE/api/memory/search" \
-H "X-API-Key: $YOHANUN_KEY" -H "Content-Type: application/json" \
-d "{\"query\": \"when does Maeve like a call\", \"context\": \"handbook\", \"identity\": \"$who\"}" \
| python3 -c "import sys, json; print('$who ->', [r['content'] for r in json.load(sys.stdin)['results']])"
done
Fionn's list is empty; Maeve's holds the Thursday note. The shared invoice memory is visible to both but is not a close enough match to this question to be returned.
4. A compartment, and a clearance for it
A compartment (compartment, stored as acl_matter) walls memory by subject rather
than by person: a client matter, a deal, a case. Who is cleared for a compartment is a ledger the platform
holds, and once a principal has any row in that ledger, the ledger is the only thing consulted: nothing the
calling application asserts about them is believed. Revocation is one row and takes effect on the next
request.
curl -s -X POST "$BASE/api/memory/memories" \
-H "X-API-Key: $YOHANUN_KEY" -H "Content-Type: application/json" \
-d '{"content": "Acme settlement offer: 40,000, open until 30 November.", "context": "handbook",
"compartment": "matter:acme", "acl_classification": 2}'
curl -s -X POST "$BASE/api/access/clearances/grant-matter" \
-H "X-API-Key: $YOHANUN_KEY" -H "Content-Type: application/json" \
-d '{"principal_id": "user:maeve", "compartment": "matter:acme", "reason": "instructed on Acme"}'
curl -s -X POST "$BASE/api/access/clearances/set-classification" \
-H "X-API-Key: $YOHANUN_KEY" -H "Content-Type: application/json" \
-d '{"principal_id": "user:maeve", "level": 2}'
for who in user:fionn user:maeve; do
curl -s -X POST "$BASE/api/memory/search" \
-H "X-API-Key: $YOHANUN_KEY" -H "Content-Type: application/json" \
-d "{\"query\": \"what is the Acme offer\", \"context\": \"handbook\", \"identity\": \"$who\"}" \
| python3 -c "import sys, json; print('$who ->', [r['content'] for r in json.load(sys.stdin)['results']])"
done
Maeve, cleared for the matter at level 2, gets the offer. Fionn, who has no clearance, gets nothing from the matter. Had a grant conflicted with one Maeve already holds (the other side of the same dispute), the grant call would have returned 409 and left a refusal on record.
5. Read the audit row
Every gated read wrote a row before it returned: who asked, what clearance and compartments applied, a preview of the question, and what was surfaced. Reading the audit is on the full surface, so this step and the next use a chat-profile key.
curl -s "$BASE/api/access/audit?principal=user:maeve&limit=3" -H "X-API-Key: $YOHANUN_KEY" \
| python3 -c "import sys, json; [print(r['created_at'][:19], r['user_id'], r['principal_matters'], 'surfaced', r['surfaced_count']) for r in json.load(sys.stdin)['rows']]"
6. Ask a grounded question
With a chat-profile key the platform calls the model for you. Retrieval runs through the same gate, so the answer Maeve gets and the answer Fionn gets are grounded in different material; the model never sees what the asker could not. The conversation is stored as memory under the asker's labels, and the stored answer inherits the wall of everything it drew on.
curl -s -X POST "$BASE/api/ai/chat" \
-H "X-API-Key: $YOHANUN_KEY" -H "Content-Type: application/json" \
-d '{"message": "What is the Acme settlement offer, and until when is it open?",
"user_id": "user:maeve", "memory_context": ["handbook"]}' \
| python3 -c "import sys, json; d = json.load(sys.stdin); print(d['response']); print('model:', d['model_used'])"
The streaming form, POST /api/ai/chat-stream, takes the same body and adds a sources
event before done: every memory that was in front of the model, ranked, with a cited
flag on the ones that grounded the answer. The same verdict is stamped on the stored turn, so the record of
why an answer was given outlives the connection.
Where next
- Give a coding agent memory in one command: the kit, in Memory for AI agents.
- Upload a document and ask across it: documents.
- Everything the gate can express: access control in retrieval.
- Use your own model, or your own provider key: model-agnostic.
Get a key
Yohanun is in invited beta. Tell us what you are building and we send a key with a developer account; a memory-profile key for your own model, or a chat-profile key if you want the platform to run the model and meter it. There is no card and no self-serve sign-up.
Request an invite