Part of #1906
Why
A user pointed Memry at a vault whose tasks are managed by the Obsidian Tasks plugin (obsidian-tasks-plugin, currently v8.4.0, the standard choice for tasks in Obsidian). Memry imported the notes and dropped every task on the floor, because it only recognises its own {task:<id>} suffix.
Anyone arriving from Obsidian with tasks arrives in exactly this state. This is the import path that makes an Obsidian migration real rather than partial.
The source format
The plugin ships two serializers. A reference clone sits at ~/workspace/obsidian-tasks; read src/TaskSerializer/DefaultTaskSerializer.ts and src/TaskSerializer/DataviewTaskSerializer.ts rather than trusting this summary.
Default (emoji) format — DEFAULT_SYMBOLS in src/TaskSerializer/DefaultTaskSerializer.ts:
| Field |
Symbol |
Value |
| priority |
🔺 ⏫ 🔼 🔽 ⏬ |
highest → lowest, none absent |
| start date |
🛫 |
YYYY-MM-DD |
| created date |
➕ |
YYYY-MM-DD |
| scheduled date |
⏳ (also ⌛) |
YYYY-MM-DD |
| due date |
📅 (also 📆 🗓) |
YYYY-MM-DD |
| done date |
✅ |
YYYY-MM-DD |
| cancelled date |
❌ |
YYYY-MM-DD |
| recurrence |
🔁 |
[a-zA-Z0-9, !]+, e.g. every week |
| on completion |
🏁 |
[a-zA-Z]+ |
| id |
🆔 |
[a-zA-Z0-9-_]+ |
| depends on |
⛔ |
comma-separated ids |
Each symbol may carry an optional Variant Selector 16 (️) and the regexes are end-anchored and stripped from the tail one at a time — see fieldRegex. A trailing ^blockid block link may follow.
Dataview format — DATAVIEW_SYMBOLS in src/TaskSerializer/DataviewTaskSerializer.ts: the same fields as inline fields, [due:: 2026-09-01], [priority:: high], [repeat:: every week], [completion:: ...], [cancelled:: ...], [start:: ...], [scheduled:: ...], [created:: ...], [id:: ...], [dependsOn:: ...]. Note the field name differences: completion not done, repeat not recurrence.
Both formats hang off a normal list checkbox, and the plugin supports custom status characters beyond [ ] and [x] (src/Statuses/StatusRegistry.ts) — [/] in progress, [-] cancelled and whatever the user has configured.
Tags are plain #tag in the description. A "global filter" tag may be configured, in which case only lines carrying it are tasks.
What to build
Read an Obsidian markdown file, recognise task lines in either format, and produce a Memry task the user can actually edit — a tasks row plus the {task:<id>} suffix written back into the line, so the two stay reconciled by the existing reconcileTaskCheckboxesFromMarkdown path.
Field mapping is the substance of this work. Decide and write down, per field, whether Memry has a home for it, and what happens when it does not:
- due / scheduled / start / done / cancelled dates → Memry's task date fields
- priority → Memry's priority scale
- recurrence → Memry's recurrence, or dropped with the original text preserved
🆔 / ⛔ dependencies → Memry has no task dependencies today; decide explicitly
- custom status characters → Memry's statuses
#tags in the description → Memry tags, case-preserving
Never silently drop a field. A dropped field must either stay as literal text in the title or be recorded somewhere the user can find. Losing someone's due dates on import is worse than not importing.
Backward compatibility
Existing installs must be unaffected: a vault with no Obsidian task lines behaves exactly as it does today, and a re-import of an already-imported file must not duplicate tasks. Rewriting a line to add {task:<id>} is a write into a user's vault file — it must go through whatever write path respects contentHash, and it must be idempotent.
Acceptance criteria
- Both serializer formats parse, including Variant Selector 16, the alternate due/scheduled symbols, and custom status characters.
- A parsed task appears in the Tasks page and is fully editable: title, project, dates, priority, delete.
- Round-trip: import, edit in Memry, and the Obsidian file still reads correctly in Obsidian.
- Re-running the import over the same file creates no duplicates.
- Fixture tests over real plugin output, not hand-written approximations. Borrow cases from
~/workspace/obsidian-tasks/tests/TaskSerializer.
Verify
pnpm --filter @memry/desktop test:main
pnpm test
pnpm typecheck
pnpm check:architecture
Part of #1906
Why
A user pointed Memry at a vault whose tasks are managed by the Obsidian Tasks plugin (
obsidian-tasks-plugin, currently v8.4.0, the standard choice for tasks in Obsidian). Memry imported the notes and dropped every task on the floor, because it only recognises its own{task:<id>}suffix.Anyone arriving from Obsidian with tasks arrives in exactly this state. This is the import path that makes an Obsidian migration real rather than partial.
The source format
The plugin ships two serializers. A reference clone sits at
~/workspace/obsidian-tasks; readsrc/TaskSerializer/DefaultTaskSerializer.tsandsrc/TaskSerializer/DataviewTaskSerializer.tsrather than trusting this summary.Default (emoji) format —
DEFAULT_SYMBOLSinsrc/TaskSerializer/DefaultTaskSerializer.ts:🔺⏫🔼🔽⏬🛫YYYY-MM-DD➕YYYY-MM-DD⏳(also⌛)YYYY-MM-DD📅(also📆🗓)YYYY-MM-DD✅YYYY-MM-DD❌YYYY-MM-DD🔁[a-zA-Z0-9, !]+, e.g.every week🏁[a-zA-Z]+🆔[a-zA-Z0-9-_]+⛔Each symbol may carry an optional Variant Selector 16 (
️) and the regexes are end-anchored and stripped from the tail one at a time — seefieldRegex. A trailing^blockidblock link may follow.Dataview format —
DATAVIEW_SYMBOLSinsrc/TaskSerializer/DataviewTaskSerializer.ts: the same fields as inline fields,[due:: 2026-09-01],[priority:: high],[repeat:: every week],[completion:: ...],[cancelled:: ...],[start:: ...],[scheduled:: ...],[created:: ...],[id:: ...],[dependsOn:: ...]. Note the field name differences:completionnotdone,repeatnotrecurrence.Both formats hang off a normal list checkbox, and the plugin supports custom status characters beyond
[ ]and[x](src/Statuses/StatusRegistry.ts) —[/]in progress,[-]cancelled and whatever the user has configured.Tags are plain
#tagin the description. A "global filter" tag may be configured, in which case only lines carrying it are tasks.What to build
Read an Obsidian markdown file, recognise task lines in either format, and produce a Memry task the user can actually edit — a
tasksrow plus the{task:<id>}suffix written back into the line, so the two stay reconciled by the existingreconcileTaskCheckboxesFromMarkdownpath.Field mapping is the substance of this work. Decide and write down, per field, whether Memry has a home for it, and what happens when it does not:
🆔/⛔dependencies → Memry has no task dependencies today; decide explicitly#tagsin the description → Memry tags, case-preservingNever silently drop a field. A dropped field must either stay as literal text in the title or be recorded somewhere the user can find. Losing someone's due dates on import is worse than not importing.
Backward compatibility
Existing installs must be unaffected: a vault with no Obsidian task lines behaves exactly as it does today, and a re-import of an already-imported file must not duplicate tasks. Rewriting a line to add
{task:<id>}is a write into a user's vault file — it must go through whatever write path respectscontentHash, and it must be idempotent.Acceptance criteria
~/workspace/obsidian-tasks/tests/TaskSerializer.Verify
pnpm --filter @memry/desktop test:main pnpm test pnpm typecheck pnpm check:architecture