Actual
actualbudget.orgA local-first personal finance app
- Homepage: actualbudget.org
- GitHub: github.com/actualbudget/actual
- Discord: 8JfAXSgfRf
- Web info: web-check.xyz/check/actualbudget.org
Actual Source Code
Author
Description
A local-first personal finance app
Homepage
https://actualbudget.orgLicense
MIT
Created
29 Apr 22
Last Updated
30 Jun 26
Latest version
Primary Language
TypeScript
Size
554,246 KB
Stars
27,289
Forks
2,624
Watchers
27,289
Language Usage
Star History
Top Contributors
-
@MatissJanis (1066)
-
@matt-fidd (393)
-
@joel-jeremy (369)
-
@j-f1 (312)
-
@MikesGlitch (237)
-
@youngcw (173)
-
@TomAFrench (161)
-
@jfdoming (159)
-
@carkom (127)
-
@shall0pass (114)
-
@dependabot[bot] (103)
-
@rich-howell (89)
-
@jlongster (80)
-
@psybers (76)
-
@lelemm (76)
-
@bpaulien (66)
-
@Juulz (53)
-
@UnderKoen (42)
-
@twk3 (41)
-
@alecbakholdin (40)
-
@RubenOlsen (37)
-
@PartyLich (29)
-
@trevdor (28)
-
@StephenBrown2 (27)
-
@Shazib (23)
-
@kyrias (22)
-
@Copilot (17)
-
@misu-dev (16)
-
@tim-smart (14)
-
@pogman-code (13)
-
@milanalexandre (13)
-
@wdpk (12)
-
@github-actions[bot] (12)
-
@aleetsaiya (12)
-
@Kidglove57 (12)
-
@Jackenmen (12)
-
@albertogasparin (11)
-
@emiltb (11)
-
@Kovah (11)
-
@mnil (11)
-
@qedi-r (10)
-
@samaluk (10)
-
@shaankhosla (10)
-
@tcrasset (9)
-
@MattFaz (9)
-
@JSkinnerUK (9)
-
@jonner (8)
-
@Marethyu1 (8)
-
@jonathan-fang (8)
-
@Crazypkr (8)
-
@gsumpster (7)
-
@julianwachholz (7)
-
@tostasmistas (7)
-
@pa4uslf (7)
-
@sjones512 (7)
-
@Kennedy242 (6)
-
@tabedzki (6)
-
@rodriguestiago0 (6)
-
@ftbboy2115 (6)
-
@tlesicka (6)
-
@SamBobBarnes (6)
-
@rgoldfinger (6)
-
@HansiWursti (6)
-
@davidkaufman (6)
-
@JukeboxRhino (6)
-
@totallynotjon (5)
-
@winklevos (5)
-
@Jod929 (5)
-
@csenel (5)
-
@passabilities (5)
-
@Wizmaster (5)
-
@migillett (5)
-
@karimkodera (5)
-
@Cldfire (5)
-
@Miodec (5)
-
@a-gradina (5)
-
@OlivierKamers (4)
-
@olets (4)
-
@mannkind (4)
-
@duplaja (4)
-
@tempiz (4)
-
@sys044 (4)
-
@joel-rich (4)
-
@biohzrddd (4)
-
@aujkb (4)
-
@zachwhelchel (4)
-
@MatthiasBenaets (4)
-
@NikxDa (4)
-
@kymckay (4)
-
@sinistersnare (4)
-
@nikhilweee (4)
-
@skliaruk (4)
-
@hostyn (4)
-
@ShayanAraghi (4)
-
@sreetamdas (4)
-
@tjex (4)
-
@tmchow (4)
-
@YusefOuda (4)
-
@m3nu (3)
-
@mk-french (3)
Recent Commits
-
edwei06 (30 Jun 26)
Fix mobile category delete confirmation (#8301)
-
Julien Vincent (29 Jun 26)
Resolve payee name during rule evaluation (#8360) When a rule action sets payee_name, resolve it to the actual payee ID immediately during rule execution instead of waiting until finalization. This allows later staged rules to match on the resolved payee. Previously, payee_name actions temporarily set payee to "new", and the real payee ID was only resolved in finalizeTransactionForRules after rule matching had completed. Fixes #8359
-
Matt Fiddaman (29 Jun 26)
reorganise the SimpleFIN key saving logic (#8362) * remove the simplefin intercept in the secrets handler * note
-
Carlisle Nightingale (29 Jun 26)
Add Thyrium to custom theme catalog (#8295) * Update customThemeCatalog.json Add Thyrium to custom theme catalog * Create add-thyrium-theme.md * Update repository reference for Thyrium theme --------- Co-authored-by: Matiss Janis Aboltins <[email protected]>
-
Matt Fiddaman (28 Jun 26)
make SimpleFIN token 'forbidden' check more flexible (#8339) * make SimpleFIN token 'forbidden' check more flexible * clear accessKey when token is updated * https -> fetch * [AI] Add tests for SimpleFIN token claim fix Cover the flexible 'Forbidden' matching, full claim-response handling, and access-key invalidation when the setup token changes. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> * note * Update upcoming-release-notes/fix-simplefin-token-claim.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * coderabbit feedback * [AI] Test SimpleFIN blank access key handling Cover rejecting a blank claim response (not persisted) and re-claiming when an empty access key is cached. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> --------- Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
-
Darwin Do (28 Jun 26)
Always show stacked bar graph tooltip label on hover (#8356) * Always show stacked bar graph tooltip label on hover * Handle edge case with maxToolTipItems+1 labels showing * Replace last item label instead of adding new one * Filter visible items on non zero values for consistency
-
Matiss Janis Aboltins (27 Jun 26)
[AI] Add design competition blog post for sidenav redesign (#8297) * [AI] Add design competition blog post for sidenav redesign Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01HbXFM9ooWVw9SRA9No7vhF * [AI] Set design competition blog post publish date to 27th July 2026 Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01HbXFM9ooWVw9SRA9No7vhF * [AI] Remove stray closing tags from design competition blog post Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01HbXFM9ooWVw9SRA9No7vhF * Update 2026-07-27-design-competition-sidenav.md --------- Co-authored-by: Claude <[email protected]>
-
clintharris (27 Jun 26)
Restore budget table scroll position when navigating back from spent transactions (#8144) * feat: Restore budget table scroll position when navigating back from spent transactions page * fix: Update transaction tests to include new categories and adjust assertions * Add release notes for budget scroll position restoration * refactor: Improve error handling when clicking on visible spent-amount cells, per suggestion from coderabbit bot * refactor: revert changes to test budget, add separate scroll-test test budget * revert previous snapshot changes * Add gitignore pattern for personal devcontainer config * fix: broken tests * refactor: address coderabbitai feedback https://github.com/actualbudget/actual/pull/8144#discussion_r3446850158 * fix: update VRT snapshots for onboarding screen * [autofix.ci] apply automated fixes * refactor: modify scrolling test to add categories to existing test budget instead of creating separate budget --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
-
Matiss Janis Aboltins (26 Jun 26)
[AI] api: make the browser build work in consumer production bundles (#8289) * api: make the browser build work in consumer production bundles The browser build shipped `new Worker(new URL("./worker.js", import.meta.url))` in dist/browser.js. A consumer bundler (Vite/Rollup) recognizes that as a worker entry and re-bundles the already-prebuilt worker.js from scratch, which desyncs the absurd-sql/connection RPC so `init` throws a structured-clone error. It only worked in dev and in the package's own e2e because both serve dist verbatim. Make the browser build fully self-contained instead: - Inline the worker into browser.js and spawn it from a Blob URL, so consumer bundlers never see a worker entry to re-bundle. The worker is built as an IIFE (classic worker), mirroring the web app's kcab.worker. - Embed the sql.js wasm and the default filesystem data (migrations + default DB) into the worker so it performs no PUBLIC_URL asset fetches: - loot-core sqlite gains an opt-in `setWasmBinary` (dormant for web/node); - the worker installs a scoped fetch shim serving the embedded data/* files from a sentinel base URL. - Share the asset-collection logic between the Node disk copy and the embedded build via scripts/embedded-assets.mjs so the two never drift. Result: `import '@actual-app/api'` + `init()` works in any bundler with zero config; only COOP/COEP headers remain required (SharedArrayBuffer). Adds an e2e (e2e/consumer + e2e/global-setup.mjs) that builds a real consumer app for production and boots it under COOP/COEP — coverage the verbatim-dist harness can't provide. Docs note the build is self-contained and that cross-origin isolation is still required. Co-Authored-By: Claude Opus 4.8 <[email protected]> * [AI] api: address review feedback (guard DOM lookup, revoke blob URL on worker failure) Co-Authored-By: Claude Opus 4.8 <[email protected]> * [AI] api: address review nitpicks (drop BodyInit cast, reword release note) Co-Authored-By: Claude Opus 4.8 <[email protected]> * [AI] api: build the browser worker via Vite ?worker&inline Replace the hand-rolled worker inlining (a custom Vite plugin that read the prebuilt worker.js off disk and inlined it as a string, plus a second build config and a build-ordering dependency) with Vite's native `?worker&inline` import. This collapses the two browser build configs into one, removes the `virtual:actual-worker-code` module and the manual Blob URL spawn, and drops the worker-before-facade build step. Vite's `?worker&inline` sub-build doesn't receive vite-plugin-node-polyfills' global-shim injection (the plugin writes it to `build.rollupOptions`, but the worker sub-build reads `worker.rollupOptions`), so the worker crashed on `process is not defined`. Patch the plugin to also emit the injection on `worker.rollupOptions` — additive and backwards compatible (the web app build, including loot-core's nodePolyfills worker, is unaffected). Co-Authored-By: Claude Opus 4.8 <[email protected]> * [AI] api: embed browser assets via Vite, drop the embedded-assets script Replace scripts/embedded-assets.mjs with Vite-native asset imports in the worker entry: `?inline` for the sql.js wasm and default DB, `import.meta.glob` (`?raw`) for the migrations. The worker builds the default-filesystem wire format from those at module load, so the embedded set comes straight from loot-core and can't drift. The Node build only needs migrations + the default DB on disk (it reads them at runtime); the old script also wrote sql-wasm.wasm and the data/ fetch tree, which are dead now that the browser worker is self-contained. Replace writeEmbeddedAssetsToDist with a small closeBundle copy of just those two. Co-Authored-By: Claude Opus 4.8 <[email protected]> * [AI] api: simplify embedded data map; drop loot-core comment churn Merge the worker's binData/textData into a single dataFiles map (Response accepts both bytes and strings), collapsing the fetch shim's two lookups into one. Revert the unrelated comment edits to loot-core's backend-worker.ts and fs/index.ts. Co-Authored-By: Claude Opus 4.8 <[email protected]> * [AI] api: rename e2e consumer-dist to consumer/dist; drop a prose comment Use the standard `dist` directory name for the consumer fixture's build output (now e2e/consumer/dist), and remove the verbose comment from index.browser.ts. Co-Authored-By: Claude Opus 4.8 <[email protected]> * [AI] loot-core: own the default-filesystem assets; consumers stop reaching in Add packages/loot-core/default-filesystem.mjs as the single source of truth for loot-core's runtime assets (sql.js wasm, default DB, migrations) and the data-file-index wire format, exported as @actual-app/core/default-filesystem. - @actual-app/api: the browser worker embeds them via the actual-embedded-assets Vite plugin (which calls collectEmbeddedAssets), replacing the relative ?inline/?raw/import.meta.glob reaches into ../loot-core; the Node build copies migrations + default DB using the helper's paths. Drops the direct @jlongster/sql.js devDependency (loot-core resolves the wasm). - @actual-app/web: stagePublicData copies from the helper's paths instead of hardcoding loot-core's tree and the sql.js wasm location. Co-Authored-By: Claude Opus 4.8 <[email protected]> * [AI] loot-core: scan migrations once when collecting embedded assets collectEmbeddedAssets() read the migrations directory twice — once in its own loop and once via buildDataFileIndex(). List the names once and pass them through, keeping the index wire-format defined in a single place. Co-Authored-By: Claude Opus 4.8 <[email protected]> --------- Co-authored-by: Claude Opus 4.8 <[email protected]>
-
Alec Bakholdin (26 Jun 26)
[AI] Add performance indexes for transactions table (#8335) * [AI] Add performance indexes for transactions table * release notes * [AI] Remove unselective tombstone-only index from performance migration
-
Matt Fiddaman (26 Jun 26)
mdx -> md (#8338) * mdx -> md * [AI] Outlaw .mdx in the docs package Docusaurus 3 compiles .md through MDX, so JSX and imports work in plain .md files and there is no need for the .mdx extension. Narrow the enforce-doc-links remark plugin to only accept .md: reject any .mdx source file at build time, flag links that target a .mdx file, and drop the .mdx branches from the directory scanner and link resolution. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> --------- Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
-
Matt Fiddaman (26 Jun 26)
speed up electron builds (#8337) * size up runners, skip translations where possible * note
-
Matiss Janis Aboltins (25 Jun 26)
[AI] Add cross-platform hook adding :robot: emoji to comments (#8331) * [AI] Add cross-platform hook keeping GitHub comments/issues in Chinese or pirate voice Adds a shared agent hook that requires anything an agent posts to GitHub (PR/issue comments, PR reviews, created issues) to be written in 简体中文 (preferred) or, failing that, a fun pirate voice — never plain English. - scripts/agent-hooks/github-comment-style.sh: shared guard. Reads tool_input.body/.title, allows CJK or pirate-flavoured text, blocks plain English via exit 2. Fails open on malformed payloads. - Wired for Claude (.claude/settings.json PreToolUse), Codex (.codex/config.toml PreToolUse) and Cursor (beforeMCPExecution adapter). - Documents the rule in AGENTS.md, the canonical pr-and-commit-rules.md and the Cursor rule so platforms without hook support apply it manually. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01Lqu3eZi5djm2cPAEm3yVht * [AI] Use a slug for the release-note filename; document slug naming in AGENTS.md Release-note filenames don't need to be the PR number — a short descriptive slug works too (the PR link is resolved at release time). Rename the new note accordingly and note this in AGENTS.md's directory reference. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01Lqu3eZi5djm2cPAEm3yVht * [autofix.ci] apply automated fixes * [AI] Auto-label PRs with Chinese descriptions as "ai spam" via CodeRabbit Add a CodeRabbit labeling instruction (auto_apply_labels is already on) that applies the "ai spam" label when a PR description contains Chinese/CJK characters — a strong signal of AI-generated spam for this English-language project. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01Lqu3eZi5djm2cPAEm3yVht * [AI] Exempt CodeRabbit-addressed comments from the Chinese/pirate voice hook CodeRabbit parses its commands (@coderabbitai review/resolve/etc.) as plain English, so the github-comment-style guard now skips any comment mentioning @coderabbitai / @coderabbit instead of forcing it into Chinese or pirate. Documented the exception in the canonical and Cursor rule files. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01Lqu3eZi5djm2cPAEm3yVht * [AI] Key CodeRabbit voice exemption on authorship, not mentions The hook only ever runs on the agent's own outgoing comments, so CodeRabbit's own comments are already out of scope (it posts under its own identity). Drop the @coderabbitai mention bypass — a comment merely name-dropping the bot is still the agent's prose and must follow the Chinese/pirate rule, closing an easy plain-English bypass. Docs updated to match. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01Lqu3eZi5djm2cPAEm3yVht * [AI] Pin CodeRabbit reviews to English CodeRabbit was reading AGENTS.md / pr-and-commit-rules.md (which ask contributors to comment in Chinese/pirate) and applying that to its own reviews, posting them in Chinese. Set `language: en-US` and `tone_instructions` so the bot's own reviews, summaries and replies stay in English; the Chinese/pirate rule is for contributor/agent comments, not CodeRabbit. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01Lqu3eZi5djm2cPAEm3yVht * [AI] Replace Chinese/pirate comment voice with a robot-emoji prefix Scrap the 简体中文/pirate voice scheme (and its CodeRabbit language override and Chinese-based "ai spam" label) in favour of one simple rule: every GitHub comment, review or issue an agent posts must be prefixed with 🤖. The shared guard now blocks any body — or, for issues, title — that doesn't start with the robot emoji; docs and per-platform wiring updated to match. .coderabbit.yaml is restored to its original state. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01Lqu3eZi5djm2cPAEm3yVht * [AI] Silence SC1007 false positive on CDPATH= cd in Cursor MCP adapter shellcheck flags the intentional `CDPATH= cd` empty-env prefix as SC1007 (mistaking it for an assignment). Add a scoped inline disable directive on that line; behaviour is unchanged. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01Lqu3eZi5djm2cPAEm3yVht * [AI] Fail closed on guard execution errors in Cursor MCP adapter The adapter previously allowed the call on any non-0/2 exit from github-comment-style.sh, so a broken or missing guard would silently disable enforcement. Deny on unexpected exits instead (matching guard-shell.sh), with a message that marks it as an execution problem rather than a real policy denial. The shared guard still fails open on malformed payloads (its own exit-0 choice). Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01Lqu3eZi5djm2cPAEm3yVht * [AI] Add hook requiring a blank PR template when agents create PRs New shared guard pr-template-blank.sh blocks mcp__github__create_pull_request unless the body is the repo's PR template, unmodified (cosmetic whitespace aside) — agents must leave it blank for the human, per AGENTS.md. Wired for Claude (PreToolUse), Codex (PreToolUse) and Cursor (the beforeMCPExecution adapter now dispatches per-tool to the right guard). Docs and a release note updated. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01Lqu3eZi5djm2cPAEm3yVht * [AI] Simplify agent-hook guard scripts - github-comment-style.sh: fold the empty/whitespace-only case into the prefix check, dropping a redundant tr subshell per field. - pr-template-blank.sh: drop the dead CR strip in canon() (the trailing whitespace sub already removes a trailing carriage return). - before-mcp-github.sh: emit the constant allow payload with printf instead of spawning jq on the common (allow) path. Co-Authored-By: Claude Opus 4.8 <[email protected]> * [AI] Drop duplicated PR-template/robot-emoji rules now that hooks enforce them The PR-template-blank and GitHub-comment robot-emoji-prefix rules are enforced by cross-platform hooks, so the copies scattered across AGENTS.md and the Cursor rules file are redundant. Remove them and point at the canonical pr-and-commit-rules.md, which keeps the full rule (including the PR-template Chinese exception that no hook can enforce). Also delete the internal PR-template-guard release note. Co-Authored-By: Claude Opus 4.8 <[email protected]> * [AI] Drop "enforced by hooks" wording from the PR/comment rule docs State the rules plainly without the meta-commentary about hook enforcement. Keeps the actual rules (don't fill the PR template, prefix GitHub comments/reviews/issues with 🤖, the Chinese exception, and the your-own-comments-only note) intact. Co-Authored-By: Claude Opus 4.8 <[email protected]> * [AI] Trim enforcement meta-commentary; shorten robot-emoji release note Drop the "isn't enforced automatically" / "handled by tooling" framing from AGENTS.md and pr-and-commit-rules.md (keeping the rule and the "apply it yourself" responsibility), and shorten the robot-emoji-prefix release note. Co-Authored-By: Claude Opus 4.8 <[email protected]> * [AI] Fail closed on unreadable payloads in the GitHub agent guards Align the new guards with the git-guard.sh / guard-shell.sh convention: fail closed when the hook payload can't be read, fail open only on a genuinely absent optional field. - github-comment-style.sh: block on invalid JSON / missing / non-object .tool_input; allow only an absent body/title within a valid object. - before-mcp-github.sh: deny on a jq parse failure / missing .tool_name instead of falling through to allow. - pr-template-blank.sh: an absent/null body now fails open (previously it normalized to "" and wrongly blocked PR creation); an empty-string body is still treated as a real non-template submission. - .codex/config.toml: describe the full guard scope (comment body + issue title) in the hook comment and statusMessage. Co-Authored-By: Claude Opus 4.8 <[email protected]> --------- Co-authored-by: Claude <[email protected]> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
-
Matt Fiddaman (25 Jun 26)
update release process (#8334)
-
tabedzki (25 Jun 26)
[AI] feat(budget analysis report): show hidden categories (#8164) * [AI] feat(budget-report): add toggle to include hidden categories Add a 'Show hidden categories' button that includes hidden expense categories in the Budget Analysis report. This prevents historic data from being misrepresented when a category (e.g. a car fund) is hidden. Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * [AI] feat(budget-report): replace hidden categories button with icon toggle Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * [AI] fix(budget-analysis): use correct package alias in test import Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * fix: added in release note * [AI] refactor(budget-analysis): extract isBaseCategory helper and reuse in tests Assisted-by: ClaudeCode:claude-sonnet-4-6 * [AI] feat(budget-report): clarify hidden categories toggle state Replace the ambiguous icon-only toggle with a highlighted active state and explicit click-to-show/hide tooltip text so the current selection is clear. Add aria-pressed for accessibility. Assisted-by: ClaudeCode:claude-opus-4.8 * [AI] feat(budget-report): consolidate chart options into Options dropdown menu Replace the separate chart-type icon toggle, balance/category Select dropdown, and hidden-categories eye icon with a single Options popover (Popover + Menu) matching the pattern used by other reports (Sankey). The menu contains: - Switch to line/bar chart - Show balance (toggle) - Show categories (toggle, replaces balanceOnly) - Show hidden categories (toggle) Also rebases onto upstream/master to incorporate the balanceOnly/Select changes from #8162 before consolidating them. Assisted-by: ClaudeCode:claude-sonnet-4-6 * [AI] fix(budget-report): use static 'Bar chart' toggle in Options menu for i18n Replace the dynamic 'Switch to line/bar chart' string with a static 'Bar chart' label and a boolean toggle (on = bar, off = line), matching the toggle pattern used by other menu items and making the string straightforward to translate. Assisted-by: ClaudeCode:claude-sonnet-4-6 * Enhance budget analysis report with dropdown options Introduced a dropdown to group options and added the ability to show hidden categories in the budget analysis report. --------- Co-authored-by: Claude Sonnet 4.6 <[email protected]>
-
Dustin Brewer (24 Jun 26)
Initial payee location documentation (#8241) * Initial payee location documentation * Move to dedicated experimental section Based on PR feedback
-
Matt Farrell (24 Jun 26)
Update docs with Actuali iOS app (#8324) * Update docs with Actuali iOS app * Update packages/docs/docs/community-repos.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
-
Matt Fiddaman (24 Jun 26)
fix flaky vrt by increasing timeout (#8323) * fix test * note
-
youngcw (23 Jun 26)
[AI] Fix Age of Money report widget title not saving correctly (#8320) * [AI] Fix Age of Money report widget title not saving correctly Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * [AI] Use mutateAsync to properly await mutations in AgeOfMoney widget Co-Authored-By: Claude Sonnet 4.6 <[email protected]> --------- Co-authored-by: Claude Sonnet 4.6 <[email protected]>
-
tabedzki (23 Jun 26)
[AI] feat(budget analysis report): Add Balance & Category selector (#8162) * [AI] feat(budget-report): add balance-only view mode Add a 'Balance only' toggle to the Budget Analysis report that hides the Budgeted, Spent, and Overspending Adjustment series and renders the balance as a plain line chart, similar to the Net Worth graph. Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * [AI] fix(budget-report): always display ending balance for consistent header spacing Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * [AI] feat(budget-report): replace balance toggle buttons with series dropdown Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * [AI] fix(budget-report): capitalize Categories in balance mode dropdown Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * [AI] fix(budget-report): fix test imports and lint errors in BudgetAnalysisGraph test Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * fix: added in release note --------- Co-authored-by: Claude Sonnet 4.6 <[email protected]>
-
Matt Fiddaman (23 Jun 26)
automation UI: reference schedule by ID not name (#8308) * schedule by id * migrate schedule indicators * add tests * update release note * fix loading states
-
Matiss Janis Aboltins (22 Jun 26)
[AI] DX: add recommended VS Code extensions for onboarding (#8303) * [AI] Add recommended VS Code extensions for onboarding Add a .vscode/extensions.json so contributors are prompted to install the oxc formatter (matching the configured editor.defaultFormatter), plus the Playwright and Vitest extensions. Whitelist the file in .gitignore. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01G1m2LJehnDTuhbvBhRdCze * [AI] Add release notes for VS Code recommended extensions Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01G1m2LJehnDTuhbvBhRdCze --------- Co-authored-by: Claude <[email protected]>
-
Matiss Janis Aboltins (22 Jun 26)
[AI] DX: enable oxlint no-useless-default-assignment in strict packages (#8306) * [AI] Disable oxlint no-useless-default-assignment rule This rule requires the `strictNullChecks` compiler option to function, but the project intentionally keeps `strict: false` (per-file strictness is handled by typescript-strict-plugin, which oxc's type-aware linter doesn't understand). As a result the rule only emitted noise — over 1,200 warnings telling us it couldn't run — so turn it off explicitly, matching how other ill-fitting type-aware rules are already disabled. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_014K4HhohrAYT7K4vY1L7Q2G * [AI] Simplify no-useless-default-assignment disable comment Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_014K4HhohrAYT7K4vY1L7Q2G * [AI] Add release note for disabling no-useless-default-assignment Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_014K4HhohrAYT7K4vY1L7Q2G * [AI] Enable no-useless-default-assignment, disable only in non-strict packages Turn the rule on by default so the strict packages (ci-actions, cli, component-library, crdt) enforce it, and add an override disabling it in the packages that still set `strict: false` (api, desktop-client, desktop-electron, loot-core, plugins-service, sync-server), where the rule can't function without strictNullChecks. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_014K4HhohrAYT7K4vY1L7Q2G * [AI] Trim no-useless-default-assignment override comment to just the TODO Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_014K4HhohrAYT7K4vY1L7Q2G * [AI] Rename release note to a slug Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_014K4HhohrAYT7K4vY1L7Q2G --------- Co-authored-by: Claude <[email protected]>
-
Matiss Janis Aboltins (22 Jun 26)
[AI] Add knip to detect unused files, dependencies and exports (#8309) Adds the knip tool with a monorepo-tuned config (knip.json) and a CI gate in check.yml, plus the dead-code and dependency cleanup it surfaced. The unused-export/type/duplicate rules are disabled so exporting an unused symbol is allowed. Co-authored-by: Claude Opus 4.8 <[email protected]>
-
Matiss Janis Aboltins (22 Jun 26)
[AI] DX: scope CI Lage cache key per job (#8311) * [AI] DX: scope CI Lage cache key per job The Lage cache key was shared across every job in the Build and Test workflows. The `setup` job (a dependency that finishes first) runs no Lage task, so it persisted an empty cache under the shared key; every other job then saw the key already existed and skipped saving its real cache. The next run restored that empty cache, causing a 100% cache miss. Key the cache per job so each job restores and persists its own Lage cache. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01GsWzGLUnt9TWkmNVDiYTof * [AI] DX: remove comment and shorten release note Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01GsWzGLUnt9TWkmNVDiYTof --------- Co-authored-by: Claude <[email protected]>
-
Matiss Janis Aboltins (22 Jun 26)
[AI] DX: strip color codes in expectSnapshotWithDiffer (#8310) * [AI] Strip ANSI codes in expectSnapshotWithDiffer to make snapshots deterministic The expectSnapshotWithDiffer helper snapshots the output of jest-diff's diff(), which chalk colorizes with ANSI escape codes when a color-capable terminal is detected. The committed snapshots were generated with color off (CI/no-TTY), so they are plain text and mismatched when the same tests ran locally in a color-capable terminal. Wrap the diff() output in util.stripVTControlCharacters so the snapshotted string is plain text regardless of terminal color detection. This fixes every test using the helper, not just the four currently failing. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01NEq4AkTQ5gSh1xKMfZXDQE * [AI] Add release note for snapshot helper ANSI fix Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01NEq4AkTQ5gSh1xKMfZXDQE * [AI] Rename release note to slug-based filename Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01NEq4AkTQ5gSh1xKMfZXDQE --------- Co-authored-by: Claude <[email protected]>
-
Matiss Janis Aboltins (22 Jun 26)
[AI] DX: replace ts-node with Node native TypeScript execution (#8304) * [AI] Replace ts-node with Node native TypeScript execution Node 22.18+ runs TypeScript files directly via type stripping, so the ts-node dependency is no longer needed for the repo's helper scripts. - Run bin/ and loot-core pack-hook scripts with `node` instead of `ts-node` - Rename bin/*.ts scripts to .mts (unambiguous ESM, runs warning-free) - ESM-ify validate-publish-imports: __dirname / require.main via import.meta - Drop ts-node devDependency and the tsconfig ts-node override block - Bump engines.node to >=22.18.0 (first release with stable type stripping) Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_019d6S7BWQdmtAcYg89WuAVd * [AI] Use .mts import specifier and simplify release note Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_019d6S7BWQdmtAcYg89WuAVd * [AI] Bump .nvmrc to v22.18.0 to match engines floor Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_019d6S7BWQdmtAcYg89WuAVd --------- Co-authored-by: Claude <[email protected]>
-
Matiss Janis Aboltins (22 Jun 26)
[AI] DX: fix CI Lage cache (#8305) * [AI] Fix CI Lage cache to target the real cache directory The "Cache Lage" step in the shared setup action cached the repo-root .lage directory, but Lage writes its build/test cache to node_modules/.cache/lage. The configured directory was always empty (the step even mkdir -p's it first), so the cache step did nothing and Lage results only persisted incidentally inside the yarn.lock-keyed node_modules cache, frozen between lockfile changes. Point both the mkdir and the cache step at node_modules/.cache/lage so the existing sha key + prefix restore-key actually roll the cache forward: each run restores the most recent prior entry and saves a fresh one, letting CI jobs/shards and reruns reuse earlier build/test results. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_013fQ9w27xTJdsb4Q9QUmHD9 * [AI] Address review: drop comment, use slug release note Remove the explanatory comment from the Cache Lage step and rename the release note to a descriptive slug with a shorter, user-facing body, per the repo's release-note conventions. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_013fQ9w27xTJdsb4Q9QUmHD9 --------- Co-authored-by: Claude <[email protected]>
-
Matiss Janis Aboltins (22 Jun 26)
[AI] Fix append/prepend notes rules on new transactions (#8300) Append/prepend notes rules were ignored when adding a new transaction that already had a note, because rule changes are only applied to fields the user left empty (so manual input isn't overwritten). Add a shared `shouldApplyRuleChange` helper that still protects user-entered values but lets the notes field through when the rule result preserves the existing note as a prefix or suffix (append/prepend). The check is idempotent: rules re-run on every keystroke during entry, so it refuses to re-add text that a previous run already applied, preventing the appended text from duplicating. Used by both the desktop register and the mobile transaction editor. Co-authored-by: Claude Opus 4.8 <[email protected]>
-
Dustin Brewer (22 Jun 26)
Attempt to fix entered amount being lost sometimes when tapping the Nearby payee chip before field loses focus (#8196) Co-authored-by: Matiss Janis Aboltins <[email protected]>
Actual Security
Security Advisories (13)
- high Patched CVSS 8.3
CVE-2026-49229 Disabled OpenID users keep access through existing session tokens
- medium Patched CVSS 4.2
CVE-2026-50179 CSV Formula Injection in Transaction Export via Imported Payee/Notes Fields
- medium Patched CVSS 4.3
CVE-2026-46700 Missing authorization on GET /secret/:name allows non-admin OpenID users to enumerate admin-configured bank-sync secrets
- medium Patched CVSS 4.6
CVE-2026-46672 CSV Formula Injection in `@actual-app/cli` `--format csv` Output via Custom `escapeCsv` Helper
- medium Patched
CVE-2026-42890 Electron Run As Node in actual
- high Patched
CVE-2026-42604 OpenID `client_secret` Disclosure via Broken Authorization Guard in `/openid/config`
- high Patched
CVE-2026-50007 Shared users can perform owner-only file management actions
- medium Patched
CVE-2026-43872 Path traversal vulnerability in actual-server
- high Patched CVSS 8.8
CVE-2026-33318 Privilege Escalation via 'change-password' Endpoint on OpenID-Migrated Servers
- medium Patched
CVE-2026-3089 Actual Sync Server 26.2.1 - Authenticated Path Traversal
- critical Patched
CVE-2026-27584 Missing Authentication for SimpleFIN and Pluggy AI bank sync endpoints
- high Patched
CVE-2026-27638 Missing authorization in sync endpoints allows cross-user budget file access in multi-user mode
- medium Patched CVSS 4.2
GHSA-xvp7-8vm8-xfxx Gocardless service is logging sensitive data including bearer tokens, account numbers, etc...
Actual Website
Website
Your Finances — made simple | Actual Budget
Actual Budget is a super fast and privacy-focused app for managing your finances. At its heart is the well proven and much loved Envelope Budgeting methodology.
Redirects
Does not redirect
Security Checks
All 65 security checks passed
Server Details
- IP Address 98.84.224.111
- Hostname ec2-98-84-224-111.compute-1.amazonaws.com
- Location Ashburn, Virginia, United States of America, NA
- ISP Amazon Technologies Inc.
- ASN AS14618
Associated Countries
-
US
Safety Score
Website marked as safe
100%
Blacklist Check
actualbudget.org 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
Actual Docker
Actual Socials
Actual Reviews
More Secure Budgeting
-
Privacy-first cross-platform personal expense tracker (Android/iOS/Web) with offline-first design. Multi-cloud sync options — self-hosted BeeCount Cloud, iCloud, Supabase, WebDAV or S3 — keep data under user control.
-
A lightweight, self-hosted personal finance app for recording daily transactions and analyzing spending patterns. Self-hosted, with all data staying on your own server. Supports 2FA and OICD.
-
A free and open source personal finance manager. Firefly III features a clean and clear UI, is easy to set up and use, and is backed by a strong community. Regular updates bring new features, improvements, and fixes. There's also a hass.io addon, and compatibility with Home Assistant. Ensure your server is securely configured.
-
A full-featured cross-platform accounting application suitable for personal and small business finance. Stable and reliable, GnuCash offers a comprehensive suite of financial management tools. Available for Windows, Mac, Linux, and Android.
-
Utilizes plain text files and scriptable, command-line-friendly software for bookkeeping/accounting, offering full control over data. Popular tools include Ledger, hledger, and Beancount among others, providing a flexible and vendor-independent approach to accounting.
About the Data: Actual
Change History
- Added #364
API
You can access Actual's data programmatically via our API. Simply make a GET request to:
https://api.awesome-privacy.xyz/v1/services/actual The REST API is free, no-auth and CORS-enabled. To learn more, view the API Docs or read the API Usage Guide.
Share Actual
Help your friends compare Secure Budgeting, and pick
privacy-respecting software and services.
Share Actual and Awesome Privacy with your network!