| name | agentdocs |
| description | Use when an AI agent needs to store, retrieve, or share end-to-end encrypted JSON documents. Triggers on requests like "save this", "store memory", "encrypted storage", "track tasks as docs", or any task requiring persistent encrypted content that agents and humans can collaborate on. |
agentdocs — Encrypted JSON Documents for AI Agents
agentdocs is an end-to-end encrypted document platform. It uses a hybrid model:
- latest full encrypted snapshot stored on the document row for fast reads
- append-only encrypted incremental patches as the edit history
The server stores only ciphertext and cannot read titles, bodies, ticket state,
or any other domain metadata.
This skill bundles safescript files — one per operation — that handle crypto and
signed HTTP requests end-to-end.
API base URL: https://agentdocs-api.uriva.deno.net safescript language:
https://safescript.dev
Step 1 — Get an identity from the user
Agents do not generate identities. Ask the user to create one in the web UI and
export it:
- Open https://agentdocs-nine.vercel.app and sign in.
- Create or choose an identity and click Export.
- Copy the base64url exported bundle.
- Pass it as the
agentdocsIdentity parameter to every function (see
script signatures below).
Bundle shape (decoded JSON):
{
"id": "<identity UUID>",
"name": "<display name>",
"signing": { "privateKey": "<base64url PKCS8 Ed25519 private key>" },
"encryption": { "privateKey": "<base64url PKCS8 X25519 private key>" },
"algorithm": {
"signing": "Ed25519",
"keyExchange": "X25519",
"symmetric": "AES-GCM-256"
}
}
Step 2 — Use the scripts
| Script | Purpose |
|---|
create-document.ss | Create a document with initial snapshot + first patch |
add-edit.ss | Append encrypted patch and update checkpoint snapshot |
share-document.ss | Grant another identity access |
list-documents.ss | Return decrypted latest snapshot per doc |
get-document.ss | Return one decrypted latest snapshot |
search-documents.ss | Return all decrypted latest snapshots |
delete-document.ss | Delete a single document by ID |
Script signatures
createDocument(title: string, content: string, agentdocsIdentity: string)
-> { documentId, documentKey, status, body }
addEdit(documentId: string, documentKey: string, newSnapshotJson: string, agentdocsIdentity: string)
-> { status, body, sequenceNumber }
shareDocument(documentId: string, documentKey: string, granteeIdentityId: string, agentdocsIdentity: string)
-> { status, body }
listDocuments(agentdocsIdentity: string)
-> { documents: [{ documentId, kind, title, content, documentKey }] }
getDocument(documentId: string, agentdocsIdentity: string)
-> { documentId, kind, title, content, documentKey, sequenceNumber }
searchDocuments(agentdocsIdentity: string)
-> { documents: [{ documentId, kind, title, content, documentKey }] }
deleteDocument(documentId: string, agentdocsIdentity: string)
-> { success: boolean, deleted: number }
How agents should modify documents
Edits are incremental patches. The latest full snapshot is also stored as a
checkpoint on the document for fast reads.
Recommended update flow:
- Read current state with
getDocument(documentId).
- Parse
content as JSON if kind is not enough, or use known convention.
- Apply changes in memory.
- Build the new full snapshot JSON.
- Call
addEdit(...) which sends a replace_snapshot patch and updates the
encrypted checkpoint snapshot atomically.
Example: rename a doc
Read the latest snapshot, change title, keep everything else, then append:
{
"kind": "doc",
"title": "New Title",
"content": "...existing content..."
}
Example: update ticket status
{
"kind": "ticket",
"title": "Fix auth timeout",
"content": "Description and acceptance criteria",
"status": "in_progress",
"priority": "high",
"assigneeIdentityId": "<identity-id>",
"labels": ["bug", "auth"],
"comments": [
{
"authorIdentityId": "<identity-id>",
"timestamp": "2026-04-17T12:34:56.000Z",
"content": "Investigating token refresh path"
}
]
}
Important: preserve fields you are not changing. Current patch type is
replace_snapshot, so dropping a field means deleting it.
Wiki links between documents
Use one canonical linking convention. Do not invent alternate fields or custom
markdown syntaxes.
When one document references another document:
- Add a normal markdown link in
content using the agentdocs: protocol:
[Architecture Details](agentdocs:0b639d84-5998-4e86-8ef9-d1bd4b7c6cce)
- Also add or update a top-level
linkedDocuments array in the JSON snapshot.
Canonical snapshot shape:
{
"kind": "doc",
"title": "Project Context & Wiki Initialization",
"content": "See [Architecture Details](agentdocs:0b639d84-5998-4e86-8ef9-d1bd4b7c6cce).",
"linkedDocuments": [
{
"documentId": "0b639d84-5998-4e86-8ef9-d1bd4b7c6cce",
"title": "Architecture Details",
"relationship": "related"
}
]
}
Rules:
linkedDocuments is top-level, not inside content.
- Use
documentId, not id, docId, target, or href.
- Keep
title as the target document's current human-readable title.
- Use
relationship only for a short label like related, parent, child,
source, or reference.
- Preserve existing
linkedDocuments entries when adding a new link.
- If you create the target document, use the
documentId returned by
createDocument in both the markdown agentdocs: URL and linkedDocuments.
- Do not use hardcoded web domains for internal document links. Use
agentdocs:<documentId> so links work across localhost, previews, and custom
domains.
JSON-first model (everything is a document)
The platform has one primitive: encrypted document snapshots, with patch-based
history.
- A note/spec doc is a JSON snapshot.
- A ticket is a JSON snapshot with ticket fields.
- A spreadsheet is a JSON snapshot with
kind: "spreadsheet" and data.
Recommended conventions are documented in:
conventions/doc.md
conventions/ticket.md
conventions/spreadsheet.md
conventions/contact.md
Searching
searchDocuments decrypts every accessible latest snapshot and returns them.
Your agent filters locally (substring, embeddings, LLM ranking, etc.).
Permission surface
All scripts:
hosts: agentdocs-api.uriva.deno.net
env: timestamp (all), randomBytes (create/share grant flows)
What scripts do not cover
- Webhook lifecycle (
/api/webhooks) is not wrapped here.
- Key rotation / hard revocation is not implemented by API.