Background decoration Background decoration Background decoration Background decoration

Menu

Wealthfolio logo Wealthfolio
Product & Process

Introducing Wealthfolio Add-ons

Opening Wealthfolio to add-ons: a safe, scoped way to build and share custom features while the core stays fast, private, and uncluttered.

A year ago, I built Wealthfolio, a simple desktop investment tracker that works offline. Today, with more than ~6,000 users, ~1,000 who paid to support the app, and more than ~5,000 GitHub stars, I’m faced with an interesting problem: everyone wants something slightly different. Each feature request makes perfect sense for that person, but would clutter the app for everyone else and make it difficult to maintain.

So instead of building every possible feature, I’m doing something different. I’m making Wealthfolio extensible through an add-ons system.

The Logic of Letting Go

The old model assumes the creator knows best; you build something and guard its purity. This is especially true for me since Wealthfolio is my side project, something I need to craft and shape as I want it to be. But personal finance is deeply individual. The way you track investments depends on your age, tax laws, risk tolerance, and countless other factors. No single app can capture all these variations without becoming bloated or requiring a large team.

Freedom Through Constraints

Add-ons work because they’re constrained. They can’t break the core app. They can’t access data they shouldn’t. They solve specific problems without creating general chaos. This constraint is liberating for both users and developers. Users get exactly the functionality they need without paying the complexity cost of features they don’t use. Developers can experiment with ideas that would be too risky or niche to include in the main application. It’s a different kind of democracy than the usual “feature request” model. Instead of voting on what should be built, people build what they need. The useful add-ons find their audience. The rest disappear without cluttering the experience for everyone else.

A perfect use case of “Vibe Coding”

There’s a shift happening in how people relate to code. We call it “vibe coding”. It’s the idea that you can describe what you want in plain language and let AI handle the implementation details. You focus on the creative intent, the “vibe” of what you’re building, rather than wrestling with syntax and boilerplate. This shift is enabled by powerful language models that can translate your ideas into working code, clearer documentation that helps you articulate what you need, and platforms that make it easy to share and extend existing work. More importantly, it’s enabled by a mindset shift: coding becomes less about memorizing APIs and more about clearly expressing your intent.

When someone with a specific need can spend an afternoon building a small add-on that solves their exact problem, then share it with others who have the same problem, something interesting happens. The software becomes more useful without becoming more complex for anyone who doesn’t need that specific feature.

Architecture Overview

Wealthfolio’s architecture is designed to support a wide range of addons while maintaining security and performance. At a high level, the system consists of three main components:

  1. Addon Runtime: This is the environment where addons are executed. It manages the lifecycle of each addon, including loading, unloading, and context management.

  2. Permission System: This component ensures that addons can only access the data and functionality they’re explicitly allowed to. It includes detection, validation, and enforcement mechanisms to maintain security.

  3. API Bridge: The API bridge provides a type-safe interface for addons to interact with Wealthfolio’s core functionality. It exposes 14 domain-specific APIs that cover everything from account management to investment tracking.

┌─────────────────────────────────────────────────────────────────┐
│                    Wealthfolio Host Application                 │
├─────────────────────────────────────────────────────────────────┤
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐  │
│  │  Addon Runtime  │  │  Permission     │  │   API Bridge    │  │
│  │                 │  │   System        │  │                 │  │
│  │ • Load/Unload   │  │ • Detection     │  │ • Type Safety   │  │
│  │ • Lifecycle     │  │ • Validation    │  │ • Domain APIs   │  │
│  │ • Context Mgmt  │  │ • Enforcement   │  │ • Scoped Access │  │
│  └─────────────────┘  └─────────────────┘  └─────────────────┘  │
├─────────────────────────────────────────────────────────────────┤
│                        Individual Addons                        │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │   Addon A   │ │   Addon B   │ │   Addon C   │ │   Addon D   │ │
│ │ Portfolio   │ │   Custom    │ │   Market    │ │    Tax      │ │
│ │ Analytics   │ │   Alerts    │ │   Data      │ │  Reports    │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘

Basic Addon Structure

An addon is just a function that receives a context object. That context gives you access to everything you need: financial data through type-safe APIs, UI components that match the app’s design system, and event listeners for real-time updates.

import React from 'react';
import { QueryClientProvider, useQuery } from '@tanstack/react-query';
import type { AddonContext, Holding, QueryKeys } from '@wealthfolio/addon-sdk';
import { Icons } from '@wealthfolio/ui';

export default function enable(ctx: AddonContext) {
  const HoldingsViewer = () => {
    const { data: holdings = [], isLoading } = useQuery<Holding[]>({
      queryKey: [QueryKeys.HOLDINGS],
      queryFn: () => ctx.api.portfolio.getHoldings("TOTAL")
    });

    if (isLoading) return <div className="p-6">Loading holdings...</div>;

    return (
      <div className="p-6">
        <h1 className="text-2xl font-bold mb-4">Holdings</h1>
        {holdings.map((holding) => (
          <div key={holding.id} className="border rounded p-4 mb-2">
            <div className="flex justify-between">
              <span className="font-semibold">{holding.symbol}</span>
              <span>{formatAmount(holding.marketValue)}</span>
            </div>
          </div>
        ))}
      </div>
    );
  };

  const HoldingsWrapper = () => (
    <QueryClientProvider client={ctx.api.query.getClient()}>
      <HoldingsViewer />
    </QueryClientProvider>
  );

  ctx.sidebar.addItem({
    id: 'holdings-viewer',
    label: 'Holdings',
    icon: <Icons.TrendingUp className="h-5 w-5" />,
    route: '/addons/holdings'
  });

  ctx.router.add({
    path: '/addons/holdings',
    component: React.lazy(() => Promise.resolve({ default: HoldingsWrapper }))
  });
}

Permission System

The permission system works in three stages: static code analysis during installation detects API usage patterns, categorizes them by risk level (from low-risk market data access to high-risk portfolio modifications), and requires explicit user approval. This means you see exactly what an addon can do before you install it.

Installation Flow:
┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│             │    │             │    │             │    │             │
│  ZIP File   │───▶│   Extract   │───▶│  Validate   │───▶│  Analyze    │
│             │    │             │    │ Manifest    │    │ Permissions │
└─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘

┌─────────────┐    ┌─────────────┐    ┌─────────────┐              │
│             │    │             │    │             │              │
│   Running   │◀───│   Enable    │◀───│    Load     │◀─────────────┘
│   Addon     │    │             │    │             │
└─────────────┘    └─────────────┘    └─────────────┘

Development Experience

The addon system is designed to feel familiar to anyone who’s built modern web applications. It’s TypeScript and React all the way down—no proprietary languages or frameworks to learn.

The development workflow is straightforward:

# Create a new addon using the CLI
npx @wealthfolio/create-addon my-awesome-addon

# Navigate to the generated project
cd my-awesome-addon

# Start the hot-reload development server
npm run dev:server

# Your addon appears in Wealthfolio automatically
# Edit your code, see changes instantly

We provide a CLI tool that scaffolds a complete addon project with:

  • TypeScript configuration
  • React components setup
  • Permission manifest template
  • Development server configuration
  • Example code and documentation
┌─────────────────────────────────────────────────────────────────────┐
│                      Your Development Machine                       │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  ┌─────────────────┐              ┌─────────────────────────────┐   │
│  │   Dev Server    │              │       Wealthfolio App       │   │
│  │                 │              │                             │   │
│  │ localhost:3001  │◀────────────▶│   Auto-discovery &          │   │
│  │                 │   Hot Reload │   Live Integration          │   │
│  │ • /health       │              │                             │   │
│  │ • /manifest     │              │ ┌─────────────────────────┐ │   │
│  │ • /addon.js     │              │ │      Your Addon         │ │   │
│  └─────────────────┘              │ │     Running Live        │ │   │
│           │                       │ └─────────────────────────┘ │   │
│           │                       └─────────────────────────────┘   │
│  ┌─────────────────┐              ┌─────────────────┐               │
│  │   Your Code     │              │   CLI Tool      │               │
│  │                 │              │                 │               │
│  │ src/addon.tsx   │◀─────────────│ • Scaffold      │               │
│  │ components/     │    generates │ • Templates     │               │
│  │ pages/          │              │ • Project Gen   │               │
│  └─────────────────┘              └─────────────────┘               │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

Wrapping Up

Perhaps this is what boring software really means. Not software that lacks features, but software that stays out of your way while enabling you to build exactly what you need on top of it.

Wealthfolio still does one thing: it tracks your investments locally, privately, simply. But now it also does something else: it gets out of the way when you need it to do more.

This feels like a small thing. Maybe it is. But small things compound. And in a world increasingly dominated by platforms that want to control every aspect of your digital life, the ability to modify your tools to fit your needs feels increasingly radical.

The addons launch next week. We’ll see what people build.

Tags

Add-ons
Open Source
Extensibility
Software Architecture
User Empowerment
← Back to The Blog
Published August 19, 2025