Nowspace is a task planning and coaching tool that works directly on your
Obsidian vault. It stores nothing of its own — your
plan is a markdown file you can read, edit and sync however you already do.
Week planning across day, 3-day and full-week views · a bucket for what isn't
this week yet · notes and wiki links beside the tasks they belong to · habits,
time tracking, and coaching questions when you want them.
Install
| Platform | Download |
|---|---|
| macOS (Apple Silicon) | Nowspace-macos-arm64.dmg |
| Windows | Nowspace-windows-x64-setup.exe |
| Linux (AppImage) | Nowspace-linux-x86_64.AppImage |
| Linux (deb) | Nowspace-linux-amd64.deb |
Docker, an always-on Mac with phone access, and development setup are in the
README.
Only the current release is published. Instances sharing one vault should
run the same release: the vault format carries a schema version, and an
older build refuses to write a newer vault rather than quietly damaging it.
What's new
Nowspace 0.6.0 — Room for extensions, and nothing else
Minor release with no data-format change: bucket schema stays at 3,
so this installs alongside any 0.5.x instance sharing the vault. Nothing here
changes behaviour, and nothing in it is visible — the release exists to make
the next one possible from a separate repository.
Stage 0 of the extension work: five places where an extension can attach,
opened so that its whole dependency on this repository is a short list of
imports. docs/EXTENSIONS.md carries the contract.
Added
-
backend/vault_io.py— one place that knows how to write to a synced
vault. Atomic writes (temp file beside the target, thenos.replace), the
expected_mtimeguard and its 409,.sync-conflict-*files neither read nor
written, and a read that retries a file caught mid-sync. Sixteen write sites
across the plan, notes and vault routers now go through it, so the discipline
is exercised by the baseline rather than kept for visitors.Two faults surfaced while extracting it: nothing wrote atomically, so a
truncating write left an empty file for any sync to propagate; and conflict
copies were being indexed, listed and scanned as ordinary notes, which makes
every[[link]]ambiguous and counts the tasks in one twice. -
HOST_API, reported by/health. The version of the extension seams —
bumped only for a breaking change to them, only on a minor release, and
deliberately independent ofBUCKET_SCHEMA_VERSION, which is the vault's
format and moves for entirely different reasons. -
A surface registry.
registerSurfacegives an extension a tab, placed by
anorderamong the built-ins and switched by a settings key of its own.
Every registered surface renders inside an error boundary: one that throws
costs its own tab and logs once, and the rest of Nowspace carries on. That
boundary is the only new component here, and it wraps only code from another
repository — a crash in the week plan is still a bug to fix rather than
something to swallow. -
A router mount. Extensions named in
backend/addons.pyare imported once
at startup and mounted under/api/<id>/*. One that isn't installed, or that
raises, produces a single log line and a server that still starts. The list
is a build input read by the same three places that have to agree — the app,
the PyInstaller sidecar and the Docker image — and it is empty by default. -
A week source point.
registerWeekSourcelets an extension offer
schedulable items and hear that one was scheduled or completed. Nothing
registers in Stage 0, so Plan Week is unchanged. An item that arrives this
way carries~x<6 hex>on its week line — a reference the baseline never
interprets, strips for display, and re-emits on save, so it survives a
carry-forward and the archive even on an instance where the extension isn't
installed. -
A CI job that builds and tests the baseline with nothing installed.
Its failure is a build failure, the same standing as the handoff canary. -
An installer for the frontend half.
npm run buildgenerates
addons.generated.tsfromNOWSPACE_ADDONS_UI, so a deployment installs an
extension by setting a variable rather than editing a file — which matters
on the mini, where every update is agit reset --hard. Unset, it writes
the empty stub byte for byte, so a baseline build leaves the tree clean.
deploy/update-nowspace.shreinstalls the packages named there before each
build, sincenpm ciwipesnode_modulesevery time. -
docs/EXTENSIONS.md— the five seams and their signatures, the
HOST_APIbump rule, the naming convention, the import allow-list, the
rule that an extension never writes a bucket or week file directly, and how
to install one on a deployment without touching a release.
Changed
-
The
app:settings map keeps keys it doesn't recognise. It filtered
them out, which meant an instance one release behind deleted a newer
instance's switch and synced the deletion to every device — the same loss
extra="forbid"prevents on bucket writes, running the other way. Unknown
boolean keys now round-trip. -
Settings carry an
addonsblock through untouched. Any top-level key the
baseline doesn't own is passed to clients as stored, which is how a surface
finds its own switch. The baseline never looks inside one. -
build-backend.shno longer bakes an absolute path into the generated
PyInstaller spec. It was correct until the project folder was renamed or the
build ran on another machine. -
The setup scripts say Nowspace, as does the API's own title.