task-maxxing is a reference implementation that one person runs in production. It's open to changes, but the bar is:
- Does this make the sync more reliable, or less?
- Does this reduce the number of foot-guns a new user can hit during setup?
- Does this keep Obsidian as the canonical source of truth?
If a PR makes the answers worse, it's probably a no.
- Nate (the maintainer) pushes changes directly to
main. No branches, no PRs, no code review from himself. - Outside contributors should open a PR on GitHub. A PR lets the maintainer review, run the e2e tests, and merge.
- Issues are welcome from anyone. Bug reports, feature requests, setup questions — all fair game.
git pull --rebase origin main
# make changes
npm test
git add -A
git commit -m "feat: describe what changed"
git push origin mainThat's it. No PR, no review cycle.
-
Fork the repo on GitHub.
-
Clone your fork locally.
git clone https://github.com/{{YOUR_USERNAME}}/task-maxxing.git cd task-maxxing git remote add upstream https://github.com/fidgetcoding/task-maxxing.git -
Make your changes in
maindirectly. This repo doesn't use feature branches. -
Run the tests (see below).
-
Commit and push to your fork.
-
Open a PR against
fidgetcoding/task-maxxing:main. In the description:- What the change does.
- Why it matters.
- Which test scenarios you ran, and whether they passed.
- Whether you actually ran this against a real Obsidian + Morgen stack, or just unit tests.
PRs from people who ran the full smoke test get merged faster than PRs with only unit tests. This sync is too fiddly to trust tests alone.
There are no rigid style rules. Match what's already there. Specifically:
- 2-space indent.
- Semicolons at the end of statements in
.jsfiles. - Single quotes for strings unless you need interpolation.
constby default,letonly when re-assignment is required, nevervar.- Async/await over
.then()chains. - camelCase for variables and functions, PascalCase for classes, SCREAMING_SNAKE_CASE for env vars and module-level constants.
- File names:
kebab-case.jsfor scripts,lower-case.mdfor docs.
If a new file has 300+ lines, think about splitting it. Files over 500 lines will get a "can you split this" comment on PR.
If your change modifies the schema of .sync-state.json:
- Bump the
versionfield. - Add a migration path in
src/sync-helpers.js(read old version, upgrade to new). - Document the schema change in
docs/ARCHITECTURE.md. - Add a regression test that loads a v1 file and verifies it upgrades cleanly.
Users in the wild will have v1 state files. Breaking them is a hard no.
task-maxxing has two tiers of tests.
Fast, hermetic, no network. Cover src/sync-helpers.js (parsing, hashing,
diff computation, conflict resolution).
npm testBefore committing, this must be green. If you add logic in src/, add a test in
tests/ that covers the happy path and at least one edge case.
Slow, require real credentials, destructive (they create and delete rows in your Morgen account). Point at a dedicated scratch task list, not your main one.
# Set up a dedicated test env
cp .env .env.test
# Edit .env.test and point MORGEN_API_KEY at a scratch Morgen account/list
$EDITOR .env.test
# Run the e2e suite
DOTENV_FILE=.env.test node scripts/sync-e2e-tests.jsThe e2e suite still contains a
simulateW3mock + Notion-creation / Notion-wins / Notion-tie cases. Those exercise the pre-2026-05-04 three-way logic against in-memory mocks (no real Notion calls) and are kept as a regression safety net for the legacy code paths insrc/sync-helpers.js(area-key↔Notion-label mapping,notionPageIdshape in.sync-state.json). They do not require a Notion token and are scheduled for removal in a future cleanup pass.
What it does:
- Creates a fresh scratch markdown file in a temp directory.
- Runs the parser +
.sync-state.jsonbuilder. - Simulates a W1 run by calling the Morgen API directly (Notion calls are mocked in-memory only).
- Verifies the rows appear.
- Runs the smoke-test scenarios from SETUP.md.
- Cleans up all created rows.
Before merging to main, this must be green against a real Morgen test account. CI can run unit tests but not e2e, so the PR author has to report this manually.
npm run lintUses eslint with a minimal config. If the lint fails on style alone, npm run lint -- --fix
will handle most of it.
src/— production code (daemon, helpers).scripts/— one-shot maintenance scripts (backfill, e2e, install).workflows/— n8n workflow JSON exports.daemon/— launchd plist template.examples/— sample files users can copy.docs/— everything a user needs to read.tests/— unit tests (mirror thesrc/layout).
The notion/ directory referenced in older copies of this doc was
removed in the 2026-05-04 cutover and is no longer part of the repo.
Don't create new top-level directories without talking to the maintainer first.
In scope:
- Reliability improvements (fewer failed syncs, better conflict handling).
- Additional Obsidian Tasks plugin field support (start dates, recurrence, scheduled times if Morgen ever exposes them).
- Linux daemon port (systemd unit file + installer).
- Windows daemon port (Task Scheduler + installer).
- Better error messages in the daemon and workflows.
- Performance work (faster parse, smaller state files).
Out of scope:
- Other apps. task-maxxing is Obsidian ↔ Morgen as of 2026-05-04 (it was previously Obsidian ↔ Notion ↔ Morgen and the Notion leg was removed; see CHANGELOG and ARCHITECTURE.md §"What changed in May 2026"). Adding a third app — Notion or anything else — means rethinking the architecture and re-introducing the conflict-resolution surface area the cutover was meant to delete. If you want that, fork.
- Web UI. The point of task-maxxing is that the UI is already Obsidian and Morgen. A third UI is a liability.
- Mobile daemon. Not happening. Run the daemon on your Mac; edit your vault from your phone via Obsidian sync.
- Migrating from Todoist/Things/TickTick. If you want to import from those, write a one-shot script that emits markdown, then let task-maxxing take over.
Open a discussion rather than an issue. Discussions are better for "how would I...?" questions; issues are for "this is broken".