Super Productivity

super-productivity.com
Super Productivity

Privacy-respecting, open-source task manager and time tracker. All data is stored locally on your device - no account required, no cloud dependency, and zero telemetry. Supports Jira, GitLab, GitHub, Gitea, OpenProject and CalDAV integration. Features include time tracking, Pomodoro timer, break reminders, and idle detection.

Open Source

Super Productivity Source Code

Author

super-productivity

Description

Super Productivity is an advanced todo list app with integrated Timeboxing and time tracking capabilities. It also comes with integrations for Jira, GitLab, GitHub and Open Project.

#android#flowmodoro#flowtime#habit-tracker#ios#issue-tracker#linux#local-first#macos#open-source#pomodoro#pomodoro-timer#privacy#productivity#task-manager#time-tracker#time-tracking#to-do-list#todo#windows

Homepage

http://super-productivity.com?ref=github

License

MIT

Created

06 Jan 17

Last Updated

04 Jul 26

Latest version

v18.13.1

Primary Language

TypeScript

Size

159,402 KB

Stars

20,451

Forks

1,824

Watchers

20,451

Language Usage

Language Usage

Star History

Star History

Top Contributors

Recent Commits

  • Johannes Millan (03 Jul 26)

    fix(tasks): shorten reminder snooze button label to fit small screens (#8743) The reminder dialog footer could not fit all actions in one row on small screens. Show only the snooze duration (e.g. "10m") on the split-button's main action instead of "Snooze 10m" โ€” the snooze icon already conveys the action โ€” freeing horizontal space so the row fits. Add a `mainLabel` input to the shared split-button so the abbreviated main action keeps a full tooltip and aria-label for discoverability/accessibility. Claude-Session: https://claude.ai/code/session_015797BREShEaTkBsA3tRBuX Co-authored-by: Claude <[email protected]>

  • Johannes Millan (03 Jul 26)

    fix(sync): report honest status when SuperSync encryption key is missing (#8741) * fix(work-context): use project icon for header title icon The header title icon read the active work context's icon, but selectActiveWorkContext forced icon: null for projects (a leftover from when projects had no icon field). Pass the project's own icon through so the header matches the side nav. * fix(sync): report honest status when SuperSync encryption key is missing When a provider mandates E2E encryption (SuperSync) but no key is configured, the GHSA-9v8x guard skips the upload while pending ops stay unsynced. The low-level result was byte-identical to "nothing to upload", so the wrapper claimed IN_SYNC โ€” silently one-way syncing (downloads apply, local edits never leave; device loss = data loss). Thread an `encryptionRequiredKeyMissing` flag from the upload guard through UploadResult and the orchestrator's UploadOutcome so the wrapper reports UNKNOWN_OR_CHANGED (UpdateRemote) instead of IN_SYNC, and short-circuits the LWW re-upload loop that would otherwise spin against the same missing key. Also stop reverting to a keyless config when enable-encryption fails after the server was already wiped: that left a mandatory-encryption provider with no key, so the upload guard blocked every future upload and the wiped server could never be repopulated (the advertised "Sync Now" recovery was a no-op โ€” account stranded). Keep the new key so the next sync re-uploads the data encrypted, mirroring the password-change flow. Refs #8731

  • Johannes Millan (03 Jul 26)

    feat(android): add home screen widget for today's tasks (#8737) * feat(android): add home screen widget for today's tasks (#3818) Revives PR #7124 (POC by @ilvez) on current master with the review punch-list addressed: - today's tasks pushed as a widget_data KeyValStore snapshot (memoized selector, debounced, hydration-guarded, re-pushed on sync-window end and on pause); Angular is the single writer of the blob - done-checkbox taps go through a SharedPreferences queue only; pending taps are overlaid natively at render time (no native blob write, no race with the serializer, no double setDone) - row title tap opens the app via fill-in extras branching (single PendingIntent template); exported receiver no longer lists the custom actions in its intent-filter - typed v:1 contract (android-widget.model.ts <-> WidgetData.kt) locked by golden-shape tests on both ends - drain dedupes and skips missing/already-done tasks; aggregated translated snack - KeyValStore: drop per-call db.close() (SQLiteOpenHelper caches the connection; access stays @Synchronized via the App singleton) Co-authored-by: ilvez <[email protected]> * feat(android): polish widget UI and support toggling done state Visual polish to match the app: - rounded surface card in the app's exact light/dark tokens (#f8f8f7 / #131314) with automatic day/night switching - branded header (SP logo + 'Today') with separator, matching brand purple (#8b4a9d light / #a05db1 dark) - app-style circle-check on the row end (Material check_circle in brand color when done), dimmed title for done tasks - project dot tinted with the project color and hidden for project-less tasks; whole row and empty state open the app Done-state toggle (was done-only): - queue is now a last-wins map {taskId: targetIsDone}; tapping a done task queues setUnDone, and a done->undone round trip before the app runs collapses to a no-op - checkbox target computed from the DISPLAYED state (incl. pending overlay) so repeated taps toggle back and forth while app is dead - drain applies setDone/setUnDone, still skipping missing tasks and tasks already in the target state --------- Co-authored-by: ilvez <[email protected]>

  • Johannes Millan (03 Jul 26)

    docs(security): revise secure-storage plan after multi-agent review

  • Johannes Millan (03 Jul 26)

    fix(local-rest-api): validate PATCH/create field value types (#8738) PATCH /tasks/:id picked allowed keys but never checked value types, so a wrong-typed value (e.g. tagIds:123, timeEstimate:"abc") was written into the store and the synced op-log, corrupting state locally and tripping typia-as-corrupt on other devices when the op replays. Both PATCH and create now typia.validate the values and return 400 before dispatching. Also harden the Electron server: reset isListening eagerly and call closeAllConnections() on stop so a keep-alive socket can't leave the server stuck and no-op a later re-enable, reject requests with 503 while disabled, and log an actionable message on EADDRINUSE. Closes #8732 Refs #7484

  • Johannes Millan (03 Jul 26)

    ci(lighthouse): raise script-count budget to 220, align warn to 210 (#8740) * fix(work-context): use project icon for header title icon The header title icon read the active work context's icon, but selectActiveWorkContext forced icon: null for projects (a leftover from when projects had no icon field). Pass the project's own icon through so the header matches the side nav. * ci(lighthouse): raise script-count budget 200->220, align warn to 210 The Lighthouse `resource-summary.script.count` budget in budget.json was an exact hard cap of 200 that the app has crept up against as it grows (master passed at <=200; a recent build hit 201 and failed CI on an unrelated PR). Bump the hard budget to 220 to restore headroom. The parallel warn threshold in .lighthouserc.json was 170 - already exceeded by ~30, so it fired on every run as permanent, meaningless noise. Raise it to 210 so it sits just below the 220 hard cap and again functions as an early warning before the budget is breached.

  • Johannes Millan (03 Jul 26)

    docs(sync): add sync-engine extraction plan

  • Johannes Millan (03 Jul 26)

    ci(android): publish per-push dev builds to the Play internal track Fold per-push Android dev distribution into build-android.yml (which already builds a signed APK on every master push) instead of a second workflow that duplicated the whole build. On non-tag master pushes it stamps a dev versionCode into the working copy of build.gradle and, after the existing build, ships the play APK to the Play 'internal' track so a fresh build auto-updates on the phone. Internal testing skips review, so builds land in minutes; dev builds (code base+1..999) and releases (base+9000) share the track but stay distinct by versionCode. All new steps are gated to refs/heads/master (non-tag); the tag/release path is untouched, and every dev step is continue-on-error so it can never break the release-critical build. versionCode = last stable release's code + commits-since-that-tag (first-parent), staying in the 999-slot band above the release and below the next version's base. The base is derived from the last stable tag (not the working tree), so a version bump landing on master before its tag is pushed can't make dev codes jump ahead and then regress. Logic lives in tools/android-dev-version-code.js (reusing getAndroidVersionInfo) with unit tests; it degrades to skip on any anomaly. Reuses existing keystore/Play/Unsplash secrets; no new secrets.

  • Johannes Millan (03 Jul 26)

    test(sync): reliably dismiss setup-time E2EE dialog in webdav e2e helper (#8727) #8709 added a mandatory disableClose "Encrypt before first upload?" modal on every fresh file-based sync setup. The setupWebdavSync helper dismissed it with locator.isVisible({ timeout }), but isVisible() returns the CURRENT state immediately and never polls โ€” the timeout is effectively ignored. The modal opens only after save()'s awaited provider-auth check and a lazy import() of the dialog chunk, so it appears a beat after the Save click; isVisible() raced it, returned false, and the Skip click was never issued. The leftover backdrop then blocked every following interaction, failing ~11-12 @webdav specs per run with "cdk-overlay-backdrop intercepts pointer events" and conflict dialogs that never appeared. It passed only when the modal happened to already be up at the instant of the check, which is why the failures looked flaky. Use waitFor({ state: 'visible' }), which actually polls until the modal appears, then click Skip and confirm it closes. Apply the same wait to the encrypt-at- setup fill path. Verified green via a full @webdav CI run.

  • Johannes Millan (03 Jul 26)

    feat(work-context): show active project/tag icon in header title

  • Johannes Millan (03 Jul 26)

    fix(task-repeat-cfg): don't crash on a deleted repeat config (#8715) (#8726) * ci(release): explain App Store 'previous version in review' failures When a release is tagged before the previous version clears Apple review, App Store Connect refuses to create the version or attach the build, and the lane died with a raw spaceship stacktrace ('cannot create a new version...' / 'pre-release build could not be added'). Both hit v18.13.1 (iOS + macOS) and v18.12.1 (macOS). Match those two messages and replace the stacktrace with a one-line, actionable annotation (let the previous version finish review, or pull it from review, then re-run) -- still a hard failure, since the version did not go out and a green run would falsely read as 'released'. The existing 'review submission already in progress' race stays a soft success. Static annotation text only (no e/options interpolation; key-material). * fix(task-repeat-cfg): don't crash when completing a task with a deleted repeat config selectTaskRepeatCfgById throws on a missing config; completing a recurring task (or editing its subtasks) whose repeatCfgId dangles โ€” e.g. after cross-client sync deleted the config โ€” crashed the whole app. Route those task-derived lookups through the non-throwing selector and skip instead. (#8715) * fix(task-repeat-cfg): guard remaining deleted-repeat-config crash paths Extend the #8715 fix to the three task-derived UI lookups that still used the throwing selectTaskRepeatCfgById: move-to-project (task + context menu) and the edit-repeat dialog. A task whose repeatCfgId dangles (e.g. the config was deleted via cross-client sync) no longer crashes the app on these actions โ€” move falls back to a plain task move, the edit dialog aborts and closes. (#8715)

  • Johannes Millan (03 Jul 26)

    fix(boards): keep Eisenhower "Not Completed" filter across restarts (#8723) (#8725) * ci(release): explain App Store 'previous version in review' failures When a release is tagged before the previous version clears Apple review, App Store Connect refuses to create the version or attach the build, and the lane died with a raw spaceship stacktrace ('cannot create a new version...' / 'pre-release build could not be added'). Both hit v18.13.1 (iOS + macOS) and v18.12.1 (macOS). Match those two messages and replace the stacktrace with a one-line, actionable annotation (let the previous version finish review, or pull it from review, then re-run) -- still a hard failure, since the version did not go out and a green run would falsely read as 'released'. The existing 'review submission already in progress' race stays a soft success. Static annotation text only (no e/options interpolation; key-material). * fix(boards): keep Eisenhower "Not Completed" filter across restarts (#8723) The fixBuggyDefaultBoardFilters normalizer ran on every loadAllData and reset any Eisenhower quadrant with taskDoneState UnDone back to All. With stable panel IDs it could not tell the old buggy default apart from a user's intentional "Not Completed" choice, so that choice was clobbered on every restart. Drop the Eisenhower taskDoneState branch; new installs already get the relaxed All default from DEFAULT_BOARDS. The Kanban DONE branch is kept (separate, unreported concern).

  • Johannes Millan (03 Jul 26)

    feat(plainspace): use Plainspace brand icon for header open link

  • Johannes Millan (03 Jul 26)

    fix(sync): name the discarded title in LWW conflict banner + fix fr dismiss label (#8694) (#8724) * ci(release): explain App Store 'previous version in review' failures When a release is tagged before the previous version clears Apple review, App Store Connect refuses to create the version or attach the build, and the lane died with a raw spaceship stacktrace ('cannot create a new version...' / 'pre-release build could not be added'). Both hit v18.13.1 (iOS + macOS) and v18.12.1 (macOS). Match those two messages and replace the stacktrace with a one-line, actionable annotation (let the previous version finish review, or pull it from review, then re-run) -- still a hard failure, since the version did not go out and a green run would falsely read as 'released'. The existing 'review submission already in progress' race stays a soft success. Static annotation text only (no e/options interpolation; key-material). * fix(sync): name discarded title in LWW conflict banner; fix fr dismiss label (#8694) * fix(sync): surface the last discarded title in LWW conflict banner Multi-review follow-up to the #8694 banner: - Show the LAST non-empty discarded title (the user's final offline rename), not the first โ€” a stale intermediate rename is misleading. Also simpler (drops the first-wins guard). - Document why the kept==discarded equality guard is correct: when a title edit loses to a concurrent other-field remote win, the current state still shows the rejected local title, so an annotation would only repeat it โ€” silencing it is right, not a hidden divergence. fr.json G.DISMISS "Rejeter"->"Ignorer" (prior commit) is an intentional, owner-approved deviation from the en-only rule: it is a mistranslation fix for the shared banner dismiss label, not a new string. Other locales may carry the same "Reject"-flavored label โ€” left as a follow-up.

  • Myk (03 Jul 26)

    fix(tasks): treat a missing title as blank instead of crashing isBlankTask #8713 (#8714)

  • Myk (03 Jul 26)

    fix(issuePanel): allow removing an issue provider whose plugin is uninstalled #8711 (#8712)

  • Johannes Millan (02 Jul 26)

    feat(sync): offer E2EE before first upload for file-based providers (#8709) * feat(sync): offer E2EE at setup for file-based providers File-based providers (WebDAV, Nextcloud, Dropbox, OneDrive, local file) support optional client-side encryption but, unlike SuperSync, have no mandatory-encryption upload guard โ€” so their first setup sync would ship plaintext before a user could enable E2EE. Offer to set an encryption password during first-time setup and persist it as part of the SAME config save: the key goes to the provider's privateCfg and isEncryptionEnabled to the global config, atomically with isEnabled. The normal first sync then encrypts from the first op via the standard download-first flow โ€” no separate snapshot-overwrite and no plaintext-upload race. Skipping keeps the existing unencrypted behavior; works offline too. Reuses DialogEnableEncryptionComponent in a new side-effect-free collectPasswordOnly mode (returns the password, writes nothing), with a provider-aware Skip action for the disableClose setup modal. * test(sync): skip file-based setup encryption prompt in webdav e2e helper Fresh file-based setup now opens the optional "Encrypt before first upload?" dialog before the config is persisted, so setupWebdavSync would stall on the disableClose modal. Dismiss it via a new Skip selector so every WebDAV spec proceeds unencrypted, exactly as before; encryption specs still enable it afterwards via enableEncryption(). * test(sync): add e2e for file-based setup-time encryption Adds a @webdav @encryption spec that configures WebDAV with the encryption password set in the setup dialog, then asserts the first upload's remote sync-data.json does NOT contain the task title in plaintext (compression is off by default, so a plaintext upload would) โ€” proving the first sync is encrypted โ€” and that a second client with the same password decrypts and receives the task without overwriting the remote. setupWebdavSync gains an encryptAtSetup option (fills the new dialog instead of skipping it); adds e2e selectors on the setup dialog password/confirm/ submit controls. * ci(e2e): allow targeting the webdav job via workflow_dispatch grep The webdav e2e job hardcoded --grep "@webdav"; add a webdav_grep dispatch input (default @webdav, mirroring the supersync job) so a specific WebDAV test can be run on demand. * test(sync): fix remote sync-file path in setup-encryption e2e Non-production builds nest the file under a /DEV segment (sync-providers.factory.ts). The raw-fetch assertion omitted it and 404'd; the CI trace confirmed the app uploaded to <folder>/DEV/sync-data.json and that the first upload was encrypted. * test(sync): cover joining an unencrypted remote with setup-time encryption Adds the data-safety edge case for file-based setup-time E2EE: a client that sets a password at setup while joining a remote that already holds UNENCRYPTED data. Asserts the join reads and preserves the existing data (does not overwrite the remote with the joining client's empty state) and that a subsequent write upgrades the remote to encrypted (no plaintext titles remain).

  • Johannes Millan (02 Jul 26)

    18.13.1

  • Johannes Millan (02 Jul 26)

    test(focus-mode): stub matchMedia so inline-launch tests are hermetic macOS/Windows CI runners report prefers-reduced-motion: reduce, making the component skip the rocket animation and dispatch startFocusSession immediately. The spec read the host setting directly, so the three inline-launch assertions failed on those platforms (release build 18.13.0) while passing on Linux. Stub matchMedia in both startSession describe blocks and add coverage for the reduced-motion shortcut.

  • Johannes Millan (02 Jul 26)

    ci(release): tolerate concurrent App Store review-submission race The iOS and macOS release lanes both run on a v* tag push and can race on App Store Connect's per-app review-submission state. When they collide, the lane that submits second fails with 'A review submission is already in progress' -- but only after its binary has already uploaded and processed successfully, so the build is safe. Route both lanes through a shared submit_to_app_store helper that treats that one collision as a soft success and emits a GitHub Actions warning annotation so the required manual step (add the build to the open submission) stays visible on a green run. Every other failure, and any failure before upload (e.g. the version-creation race), still aborts the lane loudly.

  • Johannes Millan (02 Jul 26)

    fix(sync): scan all tags when archiving to avoid dangling tag refs (#8710) * fix(sync): scan all tags when archiving to avoid dangling tag refs The archive path only cleaned tags named in each task's own tagIds, so a one-sided tag->task reference (tag.taskIds holds an id the task omits) left behind by a sync replay was never removed. That dangling reference later tripped cross-model validation and forced a reconciliation/REPAIR. Lift removeTasksFromAllTags into the shared helpers and reuse it in the archive path so cleanup is symmetric with the delete path (scans every tag). Add regression coverage. * refactor(store): route project-delete tag cleanup through shared helper Replace the hand-rolled all-tags scan in handleDeleteProject with the shared removeTasksFromAllTags helper, matching the delete and archive paths (and gaining its no-op skip for tags that don't reference the deleted tasks). Move the helper into the STATE UPDATE HELPERS section (it is a state->state transform, not a list helper) and let its JSDoc own the one-sided-tag-ref rationale, trimming the duplicated archive call-site comment to a pointer. No behavior change: final tag taskIds are identical; only unaffected tags now keep their reference identity instead of being rewritten to equal arrays.

  • Johannes Millan (02 Jul 26)

    18.13.0

  • Johannes Millan (02 Jul 26)

    docs: prefer GitHub Actions for E2E suites

  • Myk (02 Jul 26)

    fix(plugins): spawn nodeExecution scripts via process.execPath so packaged apps work #8707 (#8708)

  • Johannes Millan (02 Jul 26)

    refactor(ui): unify primary/secondary action button treatment across dialogs (#8706) Standardize dialog actions: primary=mat-flat-button color=primary, secondary/cancel=mat-button, destructive=color=warn. Drop dead Bootstrap 'btn btn-primary' classes and decorative check/close icons. Document the convention in docs/styling-guide.md and update e2e selectors that keyed on the old stroked variant. Closes #8683

  • Johannes Millan (02 Jul 26)

    feat(update-check): notify desktop users about new releases (#5463) (#8705) * feat(update-check): notify desktop users about new releases (#5463) * fix(update-check): build release URL locally, use HttpClient with timeout * feat(update-check): add translations for all locales

  • Johannes Millan (02 Jul 26)

    feat(rate-dialog): calm, recurring, win-timed store rating prompt (#8704) * feat(rate-dialog): native store review + prompt after a productive win Baseline of PR #8680 (squashed) so review improvements land as a separate, cherry-pickable commit on top. Co-Authored-By: Claude <[email protected]> * feat(rate-dialog): calm banner, feedback cooldown, delayed win prompt Review + UX follow-ups on top of PR #8680: - Fix (correctness): re-check full eligibility at prompt fire-time, not just opt-out, so a crash/data-damage recorded after arming still suppresses it. - Fix: iOS advances the rating cadence only once the native request resolves; a reject leaves eligibility intact instead of burning a lifetime prompt. - Fix: Android review-flow failure now logs and abandons instead of opening the Play Store unprompted (the trigger is an automatic win, not a user tap). - UX: web/electron/F-Droid now show a calm, non-modal banner that opens the full rate/feedback dialog on request, rather than a modal shoved in mid-flow. - UX: 'give feedback' no longer permanently opts out โ€” it starts a long cooldown (~90 app-start days) so an engaged user can still be asked once more later. - UX: the win prompt fires a few seconds after the completion, not on the tap. - UX: dedicated 'Send feedback' entry in the Help menu (GitHub Discussions). - UX: show the maintainer email as selectable text (mailto: dead-end fallback). - Refactor: move selectTodayProgress into work-context.selectors (colocation); idempotency guard on the win subscription. Co-Authored-By: Claude <[email protected]> * test(rate-dialog): import WIN_PROMPT_DELAY_MS in spec instead of mirroring it Export the delay constant from the service and reference it in the spec so the test can't silently drift from the real value. Found by a review pass. Co-Authored-By: Claude <[email protected]> * feat(rate-dialog): recurring cadence, version-age gate, GitHub star CTA Growth-focused follow-ups (review found the lifetime cap starves review recency/velocity, which is what stores rank on): - Recurring cadence: after the fixed onboarding tiers (32/96 app-start days) the prompt no longer stops forever โ€” it recurs every ~180 app-start days (~6+ months of real use), well inside Apple's ~3/365 allowance and Play's own quota. Still calm: win-timed, opt-out/crash/feedback-gated, OS-throttled. - Version-age gate: hold the prompt for 7 days after the app version changes so a fresh (possibly regressed) release isn't asked to be rated immediately. Tracked via two device-local LS keys, checked at arm time and fire time. - Play tier-burn is now only a deferral, not a lifetime loss (recurring cadence). - Web/Electron CTA: 'Star us on GitHub' (the desktop-distribution equivalent of store ranking) instead of the near-zero-conversion how-to-rate doc. Tests cover recurrence at + beyond the last tier, the version-age gate, and the updated cadence expectations. 60/60 green; tsc clean. Co-Authored-By: Claude <[email protected]> * fix(rate-dialog): register iOS plugin, drop version-age gate, cut per-tick churn Second multi-review pass (7 reviewers): - CRITICAL (Codex, verified): the iOS StoreReview Capacitor plugin was never registered โ€” CustomViewController registers WebDavHttpPlugin but not StoreReviewPlugin, so requestReview() rejected and the native App Store review card never showed. Register it via registerPluginInstance. - Remove the version-age gate (4 reviewers): getAppVersionStr() changes every release and the app ships ~weekly, so the 7-day window kept re-arming on every update (web SW reload / Electron auto-update) and near-permanently suppressed the prompt on desktop โ€” the platform where the GitHub-star intent matters most. It also duplicated the 30-day crash gate, which already covers crashing regressions. Drops 2 LS keys, a constant, and ~40 LOC. - Perf: add distinctUntilChanged on the armed win stream so the 1s time-tracking tick (new {done,total} with identical numbers) no longer re-runs scan/filter every second for the whole session. 59/59 specs green; tsc clean. Kotlin/Swift can't be compiled here โ€” the iOS registration needs an on-device/simulator smoke test. Co-Authored-By: Claude <[email protected]> * chore(i18n): translate new rate-prompt strings into all locales Add BANNER_ACTION, BTN_STAR_GITHUB (F.D_RATE) and SEND_FEEDBACK (MH.HM) to all 27 non-en locale files โ€” previously they existed only in en.json and fell back to English for everyone else. SEND_FEEDBACK reuses each locale's existing feedback wording for consistency; GitHub is kept untranslated. Deliberately edits locale files beyond the usual en-only workflow, per request. Best-effort translations โ€” a native check on the less-common languages is welcome. Co-Authored-By: Claude <[email protected]> --------- Co-authored-by: Claude <[email protected]>

  • jibin jose (02 Jul 26)

    feat(theme): add global wallpaper with per-context override (#8643) (#8663) Fixes the Today background leaking onto non-context pages (Planner, Schedule, Boards, Config) and the startup flash reported in #8643. The active work context stays "Today" (the reducer default) on pages that aren't a tag/project, so its background was shown there wrongly. Resolve the background per-route instead: per-context image -> global wallpaper -> none, with overlay-opacity and blur following whichever image is actually shown (never the sticky context's on global pages). - add a global wallpaper (image dark/light + overlay opacity + blur) to MiscConfig, surfaced via a "Set wallpaper..." dialog under Theme - resolveBackground() replaces the URL image helper and returns the styling source; a cleared/empty image falls back to the global one - app.component derives opacity/blur from the resolved source Builds on the URL-aware background stream contributed in the PR. Co-authored-by: Johannes Millan <[email protected]> Co-authored-by: jibin7jose <[email protected]>

  • Johannes Millan (02 Jul 26)

    fix(tasks): refocus add-task input after clicking + button (#8703) Clicking the + button moved focus onto the button, which unmounts once the input clears, dropping focus to <body>. Route the click through a new onSubmitBtnClick() that refocuses the input after addTask() settles so the next task can be typed right away. The Enter-key path already retained input focus, so it is unchanged.

  • Johannes Millan (02 Jul 26)

    fix(gitlab): reject bare project slugs in config validation (#8701) The #8667 regex only rejected pasted display names (values with spaces), so a bare single-segment slug like `test_config` still passed and produced a confusing 404 at poll time (#8665). A GitLab project reference must be a numeric ID or a namespace-qualified path (`group/project`, subgroups, or the `%2F`-encoded form) โ€” the REST API cannot resolve a bare slug (verified live: `/projects/gitlab/issues` โ†’ 404, `/projects/gitlab-org%2Fgitlab/issues` โ†’ 200). Require a path separator for the non-numeric branch so the mistake gets inline feedback (Save/Test are gated on form validity) instead. The separator lookahead keeps the char class a single unnested quantifier.

Super Productivity Security

6/10

Repo Security Summary

Updated 15 Jun 26

  • Code-Review 2/10
  • Maintained 10/10
  • Security-Policy 10/10
  • CII-Best-Practices 0/10
  • Dangerous-Workflow 10/10
  • Token-Permissions 0/10
  • License 10/10
  • Binary-Artifacts 9/10
  • Branch-Protection 6/10
  • Signed-Releases 0/10
  • SAST 10/10
  • Packaging 10/10
  • Pinned-Dependencies 6/10
  • Fuzzing 0/10

Super Productivity Website

Website

Super Productivity โ€“ Open-Source Deep Work Task Manager

The open-source deep work task manager for developers. Plan tasks, track time & notes in a privacy-first workspace for Windows, macOS, Linux, Android & iOS.

Redirects

Does not redirect

Security Checks

All 65 security checks passed

Server Details

  • IP Address 89.22.100.24
  • Hostname vps54630.alfahosting-vps.de
  • Location Dortmund, Nordrhein-Westfalen, Germany, EU
  • ISP dogado GmbH
  • ASN AS8648

Associated Countries

  • DE DE

Safety Score

Website marked as safe

100%

Blacklist Check

super-productivity.com was found on 0 blacklists

  • AntiSocial Blacklist
  • Artists Against 419
  • Badbitcoin
  • Bambenek Consulting
  • CERT Polska
  • CoinBlockerLists
  • CRDF
  • CryptoScamDB
  • EtherAddressLookup
  • EtherScamDB
  • Fake Website Buster
  • MetaMask EthPhishing
  • NABP Not Recommended Sites
  • OpenPhish
  • PetScams
  • PhishFeed
  • PhishFort
  • Phishing.Database
  • PhishStats
  • PhishTank
  • Phishunt
  • RPiList Not Serious
  • Scam.Directory
  • SecureReload Phishing List
  • Spam404
  • StopGunScams
  • Suspicious Hosting IP
  • ThreatFox
  • ThreatLog
  • TweetFeed
  • URLhaus
  • ViriBack C2 Tracker

Website Preview

Website preview

Super Productivity Android App

APK Info

De-Googled Compatibility

Native 4.00 / 4 1 ratings
microG 4.00 / 4 2 ratings

Tested on Android 14โ€“16 ยท Updated 13 Oct 25 ยท View on Plexus โ†’

Trackers

No trackers found

Permissions

  • Access Network State
  • Internet
  • Write External Storage

Super Productivity Reviews

More Task Management

โš ๏ธ This section is still a work in progress โš ๏ธ
Check back soon, or help us complete it by submiting a pull request on GitHub.
Or submit an entry here

About the Data: Super Productivity

Change History

API

You can access Super Productivity's data programmatically via our API. Simply make a GET request to:

https://api.awesome-privacy.xyz/v1/services/super-productivity

The REST API is free, no-auth and CORS-enabled. To learn more, view the API Docs or read the API Usage Guide.

Share Super Productivity

Help your friends compare Task Management, and pick privacy-respecting software and services.
Share Super Productivity and Awesome Privacy with your network!

View Task Management (1)