One memory. One link. One click to revoke.
Generate a public read-only URL for any memory in your store. Drop it in a Slack thread, an email, a ticket. When you're done, revoke and the URL goes dead the same instant. No login for the recipient, no metadata leaked, 256 bits of entropy keeping the link unguessable.
Three visibility states
Every memory in mnueron has one of three visibility states. Default is Private; you opt into wider audiences explicitly.
Private
Only youThe default for every memory. Visible in your dashboard, callable by your MCP clients, indexed by your search — not by anyone else in your org, and not by anyone with a public link. No row exists in memory_visibility, or the row reads visibility='private' with no token.
Team
Everyone in your orgVisible to every member of your mnueron organization in their own dashboards. Useful for shared decisions, team conventions, or runbooks you want a teammate to be able to recall through their own agent. Still no public URL — leaving the org's ACL is the only way the memory reaches an outsider.
Public
Anyone with the linkMints a 32-byte (256-bit) public_token on the server side and returns a /m/<token> URL. Anyone who opens that URL — no login, no session — gets a clean read-only view of the memory. The dashboard exposes a Copy button next to the URL; the MCP tool returns it as a string so an agent can paste it into a Slack message, an email, or a ticket comment.
Sharing from the dashboard
The fastest path — no command line.
- 1
Open /dashboard and click any memory row on the left. Its content opens in the right detail pane.
- 2
In the detail pane's action row, click Share (violet button next to Delete). A small dialog opens.
- 3
Pick Public read-only link. The server mints a fresh 32-byte token and returns the full /m/<token> URL.
- 4
Click Copy to put the absolute URL on your clipboard. Paste it into Slack, an email, a doc — anywhere.
- 5
To revoke, re-open Share and pick Private or Team. The token is wiped server-side and the URL stops working immediately.
Sharing from an agent (MCP)
The mnueron MCP server exposes a memory_share tool agents can call directly. Use phrases like "share this memory", "send this to X", or "make this public" and the agent picks the tool automatically.
Tool signature
memory_share({
memory_id: string, // from memory_recall / memory_list
visibility: "private" | "team" | "public"
})
// returns
{
ok: true,
memory_id: "...",
visibility: "public",
public_token: "wzqXJ7d8Y0sR3...",
url: "/m/wzqXJ7d8Y0sR3...",
updated_at: 1735503600000
}Hosted vs local
memory_share works only against hosted mnueron — the public viewer is a Next.js route served by the dashboard, which a local-first SQLite store doesn't have. If you call the tool in local mode it returns a clear hosted-only error so the agent can tell you to sign in (or run with MNUERON_API_URL + MNUERON_API_TOKEN to point at hosted) instead of guessing at a broken state.
Security model
What you\'re actually granting when you share a link.
256-bit tokens
Generated via crypto.randomBytes(32) and base64url-encoded. Unguessable. Even an attacker probing 10^9 URLs/sec needs 10^60 years for a 50% hit on a single live link.
Instant revoke
Flipping back to Private or Team wipes the token in the same SQL statement. The next request to the old URL returns 404 with no race window.
No metadata leaked
Viewer renders content + namespace + tags + created_at only. source_ref (IDE paths), metadata (client ids, parent_ref), org/user ids — all stripped.
noindex
Viewer pages emit `robots: noindex, nofollow` so well-behaved crawlers skip them. URLs aren\'t advertised anywhere, so search engines never see them in the first place.
RLS-scoped writes
memory_visibility writes go through withTenantScope. You can never set another org\'s memory visibility, even with a forged memory_id.
Single-row reads
The public viewer\'s query is hard-pinned to `WHERE public_token = $1 AND visibility = \'public\' LIMIT 1`. Future bugs in the SELECT shape can\'t leak neighboring rows.
FAQ
How does revoke work? Does the old link 404?
Yes — and immediately. Flipping a memory back to Private or Team clears its public_token at the database level. The next request to /m/<old-token> hits memory_visibility with no matching row whose visibility is 'public', and the viewer returns 404. Re-sharing the same memory mints a fresh token; the old URL stays dead.
Could an attacker brute-force the token?
Tokens are 32 bytes from Node's crypto.randomBytes — 256 bits of entropy, URL-encoded as 43 base64url characters. At a billion guesses per second a half-life enumeration takes ~10^60 years. The viewer also rejects malformed token shapes before touching the database, so probe traffic costs an attacker bandwidth without any database read.
What about search engines indexing my shared memories?
The viewer page sets `robots: noindex, nofollow` in its Next.js metadata, so well-behaved crawlers (Google, Bing, Anthropic, OpenAI) skip indexing. Bots that ignore robots can still load the page if they get the URL — same as any unlisted Notion or Loom link — but they can't discover it because the URL isn't advertised anywhere.
What's on the public viewer? What's NOT on it?
Visible: namespace name, created_at, source (e.g. 'agent', 'web-claude'), tags, content, a derived title from the first content line. Hidden: source_ref (often an IDE filesystem path), metadata (often contains parent_ref and client identifiers), org_id, user_id, and anything tenant-identifying. The query is scoped to one row by token, so the viewer page can't accidentally expose neighbouring rows even if a future bug changed the SELECT shape.
Can agents share memories on their own?
Yes — the memory_share MCP tool is registered alongside memory_save, memory_recall, etc. An agent that's saved something the user wants to send to a collaborator can do: memory_share({ memory_id, visibility: 'public' }) → returns { url, public_token, visibility }. The agent then pastes the URL into the user's chat or follow-on tool. Hosted mnueron only — local-first SQLite stores have no public HTTP surface, so the tool returns a clear hosted-only error in that mode.
What's the RLS model?
memory_visibility is RLS-scoped by org_id. Members of your org can read and write rows for memories they can otherwise access; nobody else can. The public viewer bypasses RLS via the service role, BUT the bypassing query is hard-coded to: WHERE mv.public_token = $1 AND mv.visibility = 'public' LIMIT 1. That's the audited path — anonymous traffic gets exactly one row back, identified by a token they already had. There is no anonymous SELECT policy on the table, deliberately, to avoid timing-side-channel enumeration.
Are shared memories counted in my plan quota?
Sharing changes nothing about storage — the underlying memory row still belongs to your org and counts toward your namespace memory cap the same as before. Public links don't fire recall_events or affect your savings dashboard. The only thing sharing adds is a row in memory_visibility (negligible storage) and one Postgres query per viewer hit.
Share a memory, not your account.
One link per memory. One click to revoke. No login required for the recipient. The simplest possible primitive for the moment you want a teammate to see one thing without giving them the whole store.