Skip to content

Feature Budget ​

What Jotter does, where, how much code each part costs, and how much it is worth keeping. The point is to keep the code base small enough to hold in one head: every feature costs lines, tests and attention for as long as it lives, so each one is classified, and a new one has to be placed in this table before it is added (an ADR when it is large).

Sizes are lines of code including tests, rounded, from the tree of 2026-10-11 (python3 scripts/loc_history.py --current counts per area). They say what a feature costs, not how it is written. The whole code base is about 52k lines: backend 10.7k, web 31k, mobile 8.3k, shared packages 1.6k.

The classes ​

ClassMeaning
CoreJotter is not Jotter without it. It gets full care and must work on every client that offers it.
OptionalUseful and well isolated: it lives in its own feature folder or module, and the core does not depend on it. It is kept, and may be desktop-only.
ParkedKept, but it gets no new work, and it is the first thing to remove when it gets in the way (a refactor, a dependency, a failing test nobody wants to fix) or when it is not used. Removing it is cheap on purpose: nothing else depends on it.

The classification below is a proposal for the maintainer to correct. Move a row when the answer changes.

The table ​

FeatureDesktopMobileSizeClassWhere / notes
Vaults: a folder of Markdown files, several vaultsyesyes~1.2kCorefeatures/vaults, VaultManageModal; mobile has its own vault repository
Projects and columns (buckets), pinned projectsyesyes~2.5kCorefeatures/projects, features/buckets, ProjectSidebar, ColumnEditModal
Tasks with all attributes: notes, checklist, tags, priority, due, planned, colour, attachmentsyesyes~6kCorefeatures/tasks, features/task-editor, task card
Board viewyesyes~0.5kCoreBoardView
Search and filters (query language)yesyes~1.5kCorepackages/task-filter (shared), FilterModal; fixtures run against Python
Bulk actions on a selectionyesyes~1kCorecomponents/ui/bulk, mobile toolbar
Smart title input (dates, priority, tags, column)yesyes~0.6kCorepackages/title-parser (shared)
Vault format and Obsidian/PKM compatibilityyesyes~2kCorespec/, packages/vault-format, index.md manifests
Themes and languages (English, German)yesyes~1.7kCorepackages/themes (shared), locales
Indexing and periodic scanyesown~1.8kCorefeatures/sync (SQLite index, ADR 0014/0015); mobile scans through its repository
Postponing tasksyesyes~0.3kCorevirtual Postponed column
Recurring tasks: repeat rule, rolled over in place on completionyesyes~0.8kCorespec/FORMAT.md (Recurring tasks), ADR 0019; reuses postponed_until
Reminders: notifications at a floating local timeedit onlyyes~0.8kOptionalspec/FORMAT.md (Reminders), ADR 0019; mobile arms Android notifications (src/reminders.ts); the desktop sets and shows them but does not notify (browser notifications only work while the page is open: branch feat/desktop-reminder-notifications)
Tag view and planning viewyesyes~0.5kOptionalTagView, TimeView; mobile has them as tabbed views
Spreadsheet import and exportyesno~1.6kOptionalfeatures/task-import, useTaskExport; isolated
Git versioning and Time Machineyesno~1.3kOptionalgit part of features/sync, TimeMachineModal; ADR 0012
MCP server (AI assistants)yesno~0.7kOptionalmcp_server.py, optional package extra
Voice dictationyesno~0.2kOptionaluseSpeechRecognition, browser API
Share target: text shared from other Android apps becomes a tasknoyes~0.2kCoreMainActivity.java (turns it into a jotter://share link), src/shortcuts.ts, quick add
List viewyesno~0.3kOptionalListView
Home / project overviewyesno~0.2kOptionalHomeView
Task review session (triage cards)yesno~1.9kParkedfeatures/task-triage, ReviewView
Time blockingyesno~3.1kParkedfeatures/timeblock (+ backend features/timeblock)
2D infinite canvasyesno~2.5kParkedfeatures/canvas (+ backend features/canvas), ADR 0010
Eisenhower matrix viewyesno~0.5kParkedMatrixView
Static demo on GitHub Pagesyesn/a~0.7kParkedstorage/demoAdapter.ts, a second backend written in TypeScript. It stores repeat and reminders but does not roll recurring tasks over, so the demo differs from the backend and the mobile app there

The parked rows add up to about 9k lines (17 % of the code base), which no other feature depends on.

How to use this ​

  • Adding a feature: put a row here first, with a class and a rough size. A feature that would be more than ~1k lines, or that touches the core, gets an ADR (see docs/developer/adr/).
  • Mobile: it only takes what is core or what is cheap to share. The list of what is out of scope is in ADR 0017; a row marked "no" under Mobile stays out unless that ADR is changed.
  • Parking, not deleting, is the first step: a parked feature stays working but is not extended. If nobody has touched it for a long time and it costs attention (a dependency to keep, a test that breaks on every refactor), remove it in a commit of its own so that the removal can be reverted.
  • Check the cost now and then: python3 scripts/loc_history.py followed by python3 scripts/plot_loc.py shows growth per area. The table's sizes should be refreshed when a row changes class.

Released under the Apache-2.0 License.