Capture your journal notes to askMyu, encrypted before they leave, and read your day beside your vault.
Capture your journal notes to askMyu, encrypted before they leave, and read your day beside your vault.
Working home: packages/obsidian in the askmyu-frontend monorepo. The public
mirror (AskMyu/askmyu-obsidian-plugin) carries the same source plus the three release
artifacts — main.js, manifest.json, styles.css.
who is this? ▸ instead of guessing.myu-meeting: true) become meetings Myu understands — decisions,
owners, follow-ups. This content is processed on askMyu's servers like every
meeting source (it is not end-to-end encrypted like journal capture) — the
consent screen says exactly that before anything is shared..canvas;
a conversation as a note. Always behind an exposure warning, never automatic,
always marked myu-generated: true so everything Myu ever wrote stays one
search away.app.plugins.plugins.askmyu.api — getBrief(), getPrep(id),
getPersonCard(name), getWeeklyReview(); read-only, null while locked.[[Marcus Webb]] in a note is a person-tag, for free. The
plugin passes the names as hints; it never decides who anyone is.myu.askmyu.com, and that is the only remote host the plugin talks to. Offline, everything Myu already wrote into your vault still opens (it is plain markdown, .canvas and .base); capture pauses and catches up when the connection returns.myu: false in its frontmatter.Myu/ by default). Your notes are read (when shared) and linked to, never edited.myu-generated: true.Notice is used for errors and status only, never to tell you
something about a person. Obsidian is a desk, not a notification channel.Myu/), and carries myu-generated: true frontmatter so everything Myu ever
wrote stays one search — and one delete — away. Myu never writes into notes
you authored: not your daily notes, not your People/ pages, not your
templates. It links to them. Card views are ephemeral panes.Everything. That is the point of writing files.
Myu/ stays exactly as it is — people, companies, journal, meetings, calendar, commitments, canvases, conversations. None of it needs the plugin to open: markdown, .canvas (an open standard), .base (an Obsidian core feature). They stop refreshing; nothing breaks.data.json goes with the plugin — your plugin token and wrapped key. No custody is left on this device.Two doors, for two different things:
Myu/Export.md saying what landed, what could not, and what was never vault material.Your notes are encrypted on this device before they leave, with the same key your other askMyu devices use.
At rest, that key is split: this device holds it wrapped under a key it does not have, and the server holds the wrapping key with nothing to wrap. Neither half is useful alone. On start-up the plugin fetches the wrapping key over your session, opens the blob in memory, and keeps it there — nothing raw is ever written to disk.
Consequences worth knowing before you install:
data.json (which holds your token and
the wrapped blob). We designed around that as far as it can be designed around;
we cannot design around a plugin that hooks the browser's crypto before we
load. That is true of every plugin you install, and we would rather say it.Myu/ folder (and Myu/Canvas/, Myu/Conversations/) after your explicit consent, plus one CSS snippet in your vault's config folder (.obsidian/snippets/myu-look.css) when you press Install the look — removable from the same row. Never outside the vault.Obsidian's developer policies require network use to be disclosed; here is all
of it. The plugin talks ONLY to the askMyu backend you configure (default
myu.askmyu.com) — no third-party services, no analytics endpoints, no CDN.
Links that open in your browser, never fetched by the plugin. A few buttons hand a page to your browser: the beta terms and privacy policy on askmyu.com, the askMyu web app (Google sign-in, subscription), the look snippet on github.com, and a person's LinkedIn profile from their card or the Career row. Each opens only when you press it; the plugin itself never requests those sites. The LinkedIn address also appears as placeholder text in the fields that ask for one.
Base64 is how ciphertext and keys travel. Encrypted notes, wrapped keys and the device-transfer blob are binary; the plugin base64-encodes them into JSON for the wire and decodes them back. That is the only use of base64, and none of it hides anything: the bundle ships unminified, and every endpoint is listed below.
There is no client-side telemetry in this plugin. It does not measure,
count, or report your use of it, and there is no toggle to turn on — the
capability is absent, and a build check (pnpm verify) fails if any module
outside the transport layer opens a network connection at all. askMyu's servers
record their own API usage the way any service does; that is described in the
privacy policy.
| endpoint | when | carries |
|---|---|---|
POST /account/plugin-token/exchange |
connect + every app start | your plugin token |
POST /account/plugin-token/create |
after sign-in | nothing outbound but the request |
POST /account/session/escrow-key |
every unlock | your content key, to your session |
POST /account/device/kek/store · kek/get |
device setup · each unlock | the wrapping key (split custody) |
POST /account/device/transfer-request · -approve · -deny |
device approval | ECDH public keys; the 4-digit code |
GET /account/device/transfer-pending · -receive |
device approval | requests only |
GET /account/recovery/wrapped-key |
recovery-phrase unlock | requests only |
POST /account/recovery/setup |
recovery ceremony | your key wrapped under the phrase — the phrase never leaves this device |
POST /account/create |
in-plugin signup (password door) | email, name, password, the terms version you agreed to |
POST /auth/magic-link/request · GET /auth/magic-link/validate |
in-plugin signup | email, name, the terms version you agreed to; then the emailed single-use token |
GET /terms |
opening the Create-account door | nothing — public; it says which version the door shows |
POST /account/terms/accept |
the "Before you start" screen | the terms version you agreed to |
POST /account/background-work/set |
settings toggle | your choice |
| endpoint | when | carries |
|---|---|---|
POST /journal/add |
journal capture | your note, encrypted on this device |
POST /meetings/ingest_note |
meeting-note capture (opt-in) | the note, plaintext by disclosed consent |
POST /journal/add · POST /journal_chats/add |
chat | your messages (+ any note or selection you seeded) |
| endpoint | when | carries |
|---|---|---|
GET /feed/brief · /review/weekly · /initiative/mirror · /card/self |
Today pane (5-min ambient) | requests only |
POST /calendar/events |
Today + calendar | the date range |
GET /prep/meeting · POST /prep/subject/link |
prep pane | the event id; the link you choose |
GET /feed/entities · /feed/entities/search · /card/person · /card/company |
lookups + cards | your queries |
POST /card/board-lite |
a card's extra takes | the entity id |
POST /card/identity/confirm · /v2/relationships/linkedin/suggestion/resolve |
card confirm ▸ / disambiguation |
the identity you picked |
GET /memories/relationship/{id} |
person pages | the relationship id |
GET /meetings/list · /meetings/get |
meeting history | requests only |
GET /journal/get · /journal_chats/get |
journal history | requests only — entries decrypt on this device |
GET /composition?id= |
save-to-vault | the composition you asked for |
POST /initiative/pattern-feedback/submit |
the mirror's confirm | your yes or no |
POST /composition/interaction · /composition/refresh · /composition/history |
a canvas card pressed; Refresh; Past canvases | the card and choice you pressed (composition + component ids, the option label); requests otherwise |
GET /feed/help-myu · /feed/related-persons · /feed/related-memories · /feed/entities/dispatch · /feed/search · /card/source-detail |
Today's Help Myu; a card's "around them"; "what's up with X"; Search Myu; "where this came from" | ids, or the words you typed into search |
POST /feed/entities/dismiss · /relationships/merge (reject) · /v2/relationships/linkedin/{id} (unlink) |
dismissing a dispatch; "Not the same"; Unlink LinkedIn | the ids involved |
POST /meetings/add-decision · /meetings/add-commitment · GET/POST /meetings/drive/* · POST /meetings/import/drive |
a bullet you type under a meeting note's Decisions/Commitments; Drive import | that bullet's text (and owner); the Drive file ids you choose |
GET /personal_loop/get · POST /feedback/signal · POST /feedback/submit |
Today's loop strip and its 👍/👎; a reply's 👍/👎; Send feedback | your rating; your feedback text, the build number, and (for a reply) the conversation id — never a screenshot, never your notes |
GET <origin>/sse/get |
live updates (streaming) | nothing outbound; events inbound |
| endpoint | when | carries |
|---|---|---|
POST /vault/commitments |
Myu's folder | nothing outbound but the request |
POST /vault/interaction |
Myu's folder | which Myu checkbox you ticked (ids + that line, never your own notes) |
| endpoint | when | carries |
|---|---|---|
GET /account/state/check · POST /account/state/update |
onboarding | your onboarding answers |
GET /linkedin/seek · POST /account/career/update |
onboarding arc | the LinkedIn profile you chose |
GET /onboard/current_employment · POST /onboard/current_employment_confirm |
onboarding arc | your confirmation |
POST /resume/upload |
onboarding arc (optional) | the resume file you chose |
POST /onboard/classify_career_moment |
onboarding moment | what you wrote |
POST /oauth/google/init · /oauth/microsoft/init (scope_set, return_to in the query) |
connect (opt-in) — calendar, mail and meeting notes each on their own when the server splits consent | nothing outbound; consent happens in your browser |
GET /oauth/google/status · /oauth/microsoft/status · /slack/connections · /zulip/connections |
settings | requests only |
POST /oauth/{google,microsoft}/disconnect · /oauth/{google,microsoft}/credential/set-primary · /slack/connect · /slack/disconnect · /zulip/connect · /zulip/disconnect |
settings, when you press them | the account/connection you chose; for Zulip the realm, email and API key you entered (sent once, kept on the server) |
POST /account/update · GET /account/career |
settings → Account | your name; requests only |
GET/POST /email/generic/* |
IMAP source (opt-in) | the mail-server credentials you entered |
GET/POST /calendar/caldav/* |
CalDAV source (opt-in) | the calendar credentials you entered |
POST /calendar/ical/add · POST /calendar/ics/upload |
calendar link or file (opt-in; settings → Connection, or the offer in the welcome canvas) | the private iCal address you pasted, or the .ics file you chose |
GET /features |
on sign-in | requests only (which server-side features are on) |
POST /composition/career-trajectory |
after you confirm your LinkedIn read | requests only (asks for the career canvas) |
The plugin also registers six obsidian:// URL verbs — myu, myu-prep,
myu-card, myu-chat, myu-signin, myu-connected — so askMyu's emails and
its web sign-in page can open the right pane. Mail clients strip custom-scheme
links, so emails link an HTTPS page on the askMyu backend that fires the verb;
no data rides those links beyond the meeting id or name in the URL itself, and
the sign-in verb carries a single-use token that expires in five minutes.
pnpm install
pnpm --filter @askmyu/obsidian dev # esbuild watch → main.js
pnpm --filter @askmyu/obsidian type-check
pnpm --filter @askmyu/obsidian lint
pnpm --filter @askmyu/obsidian test # behavioural QA invariants
pnpm --filter @askmyu/obsidian verify # structural QA invariants
pnpm --filter @askmyu/obsidian build # production bundle
pnpm verify enforces the structural invariants, including the two that keep
this plugin listable: all network egress goes through src/transport/ (so
client-side telemetry cannot be added by accident — Obsidian's developer
policies forbid it), and no module assigns HTML as a string.
Turn on Settings → askMyu → Use mock backend to run the whole unlock path against an in-memory stand-in, including its failure modes.
To test in a real vault, symlink the package into it:
ln -s "$PWD" "$VAULT/.obsidian/plugins/askmyu"
then enable askMyu in Community plugins (Restricted Mode off).
Everything Myu renders carries a stable myu-* class — .myu-voice (Myu's
words), .myu-whisper (quiet labels), .myu-chat-block, .myu-canvas-component,
.myu-affordance (buttons) — so you can restyle Myu's panes with an ordinary
CSS snippet, the same way you style any plugin. The plugin itself never
overrides your theme.
One look ships with the plugin: snippets/myu-look.css
— Myu's own identity, the web app's accents, a serif voice. Settings → askMyu
→ Advanced → Myu look → Install the look writes it into your vault's config
folder (.obsidian/snippets/myu-look.css) and turns it on; the same row turns
it off, updates it after a plugin update, or removes it. Nothing is fetched:
the look for the build you are running is the look it installs. The file is
yours after that — edit it (the row will not overwrite an edited copy without
asking), or take the raw file from
https://github.com/AskMyu/askmyu-obsidian-plugin/raw/main/snippets/myu-look.css and manage it by hand.