Agent-friendly, local-first personal dashboard.
Hand this repo to your favorite agent, like Codex or Claude Code, tell it what you care about, and get a glanceable home screen powered by your own data, apps, and tools.
Think of this as a dashboard engine plus an agent playbook: the agent inspects your current dashboard, suggests relevant cards, picks the right connector for each data source, and wires it up safely. Your real information, API keys, local scripts, snapshots, and cache stay outside this repo — usually in ~/.config/fab-dashboard.
Ships with several beautiful themes, and you can ask your agent to design more.
Requires Bun 1.3 or later. Runs on macOS and Linux; background-service templates cover launchd and systemd.
This repo is designed to be handed to a coding agent. Paste this prompt into Codex or Claude Code and let the agent handle setup and interview you:
Clone https://github.com/linuz90/fab-dashboard.git and set it up, then guide me
through creating a personal dashboard that is relevant to me: ask me questions
about who I am, what I care about, and which apps, tools, and services I use,
then build the dashboard.Already cloned the repo? Run your agent from the project root and skip the clone step:
Guide me through creating a personal dashboard that is relevant to me: ask me
questions about who I am, what I care about, and which apps, tools, and
services I use, then build the dashboard.Once the first cards exist, keep asking for more in plain language, one at a time:
Add a tasks card with my to-dos, which are in Things on my Mac.Add a card that shows my Codex and Claude usage for the day.As the dashboard grows, you can ask the agent to organize whole cards into a few stable views:
Organize my dashboard into a Today tab for personal cards and a System tab
for usage, services, and logs. Keep the header widgets global.You can also share a card without exposing its private data or executable connector configuration:
Prepare my tasks and calendar cards so I can share them with a friend.When creating cards, the agent will:
- inspect your active dashboard with
bun run cli doctor --json, then read existing cards and connectors so it fits your layout instead of clobbering it - suggest concrete cards grouped by source: local files/apps, an API with a key, a command/script connector, or a manual/static starter
- choose the connector shape that honestly matches each source:
http,file,command, trustedts, orstatic - keep small dashboards flat, then suggest optional dashboard tabs when distinct contexts start competing for the same screen
- wire real data safely: API keys go in
$FAB_DASHBOARD_HOME/.env, real cards stay in your config home, and private data does not get committed to this engine repo
When sharing, the agent prepares a privacy-safe card pack first, then lets you choose clipboard, a secret GitHub gist, a local file, or another destination.
The interview-then-build flow is described in docs/bootstrap.md. Card creation and sharing live in the bundled create-card and share-card skills, while AGENTS.md carries the shared repo rules that Codex and Claude read automatically.
This is a clone-and-run project by design, not an npm package: you clone the whole engine so your agent has the source, skills, and repo instructions on hand to build and validate cards locally. package.json stays private: true to prevent accidental publication while the GitHub repository can still be public.
Prefer to see it running before involving an agent? Clone the repo and run the safe demo dashboard:
git clone https://github.com/linuz90/fab-dashboard.git
cd fab-dashboard
bun install
export FAB_DASHBOARD_HOME="$PWD/local/demo"
export FAB_DASHBOARD_STATE_HOME="$PWD/local/state"
bun run cli init --demo --force
bun run devOpen the Vite URL printed by bun run dev (normally http://127.0.0.1:5193).
The demo uses safe static fixtures and starts in the e-ink theme. Some entries use public, recognizable references so the cards feel concrete, but they do not contain private account data, secrets, or personal snapshots.
fab-dashboard is meant to become a small personal home screen you can open from any device. After your real dashboard exists, ask an agent to help you run it as a background service, expose it privately with Tailscale Serve, and install the HTTPS tailnet URL as a PWA on your phone or tablet:
Help me run fab-dashboard as a background service, expose it privately with Tailscale Serve, and install it as a PWA on my phone.Tailscale is a good default recommendation here: its Personal plan is free for individual/home use, and Serve keeps the dashboard available only to devices and users allowed in your tailnet. Use Tailscale Funnel only if you intentionally want a public internet URL.
For the practical setup and host allow-list details, see docs/service.md.
Most dashboards start as one-off code. fab-dashboard keeps the polished interface reusable while letting each user bring their own data through explicit connectors:
staticconnectors for demos and safe exampleshttpconnectors for JSON APIsfileconnectors for exported JSON snapshotscommandconnectors for local scripts that print JSON- trusted
tsconnectors for local normalization or multi-source reads
Cards stay declarative. Connectors own data access. Broken sources are scoped to the affected card instead of blanking the whole dashboard.
You can author dashboard files by hand, but the intended path is to let an agent create and validate them for you from the project root.
~/.config/fab-dashboard/
README.md
dashboard.json
cards/<type>/card.json
connectors/<id>/connector.json
.env
~/.local/state/fab-dashboard/
cache/
history.jsonPut API keys in $FAB_DASHBOARD_HOME/.env and reference them from connectors as env:NAME. Use file:/absolute/path for secrets stored in separate local files. Never commit real dashboards, private command scripts, personal snapshots, connector cache, or secret material.
Use $FAB_DASHBOARD_HOME/README.md as the private operating note for your dashboard: service manager, local URL, Tailscale URL, restart command, companion local APIs, and refresh jobs. bun run cli init creates a starter file, and bun run cli doctor --json reports whether it exists. Agents should read and update it when they change how the dashboard runs.
To use a different config home:
FAB_DASHBOARD_HOME="$PWD/local/my-dashboard" \
FAB_DASHBOARD_STATE_HOME="$PWD/local/my-dashboard/.state" \
bun run devA dashboard card has two parts:
cards/<type>/card.jsondescribes how the card renders.connectors/<id>/connector.jsondescribes where data comes from.
For example, a portfolio card can read portfolio.allocation and portfolio.history from a connector named portfolio. The card JSON stays reusable; the connector can later move from a static demo fixture to a file export, local command, or API.
Reusable block primitives include text, metric, rows, list, card-level tabs, status, allocation, leaderboard, sparkline, group, divider, and action-row. See docs/config.md for the schema shape and rendering options.
Dashboards start flat, including the public demo. When unrelated contexts begin competing for the same screen, top-level tabs can group whole cards into a few URL-addressable views:
{
"schemaVersion": 1,
"tabs": [
{ "id": "today", "label": "Today" },
{ "id": "system", "label": "System" }
],
"cards": [
{ "id": "tasks", "type": "tasks", "title": "Tasks", "tab": "today" },
{ "id": "usage", "type": "usage", "title": "Usage", "tab": "system" }
]
}The first tab is selected at the root URL; other tabs use ?tab=<id>. Command search remains global and can switch tabs before scrolling to a card. The title, header widgets, appearance, settings, and refresh behavior are global too.
Tabs organize the interface, not connector loading. Every configured card and connector still resolves eagerly, including cards on inactive tabs. Once tabs are enabled, every card must name one declared tab; invalid or missing membership fails validation instead of silently hiding the card. See docs/config.md for the complete config and URL behavior.
Themes and layout presets are built-in engine features, not arbitrary user CSS. Dashboards can choose the enabled theme list, theme order, maximum shell width, and maximum masonry columns:
{
"appearance": {
"defaultTheme": "e-ink",
"themes": ["e-ink", "basic", "apple", "classic-macos", "kingdom", "live"],
"layout": {
"width": "extra-large",
"maxColumns": 4
}
}
}Layout width presets are small, medium, large, and extra-large; large preserves the default 1400px shell. maxColumns accepts 1 through 4 and is a cap, so narrow screens still collapse naturally.
Themes can also use generic runtime signals like data-time-phase and data-local-hour for clock-aware variants. See docs/themes.md for adding, disabling, reordering, and authoring themes.
bun run dev # starts at API :7893 + Vite :5193; advances if busy
bun run start # serve built app + API on :7893
bun run build
bun run typecheck
bun run test
bun run create-demo-gif # regenerate docs/assets/fab-dashboard-demo.gif
bun run cli init
bun run cli init --demo
bun run cli validate
bun run cli doctor
bun run cli doctor --json
bun run cli doctor --fetch
bun run cli service print macos
bun run cli service print systemdFor a shell-style command during development, run bun link from this repo or call ./bin/fab-dashboard.
See docs/service.md for local service templates, Tailscale Serve notes, and safe exposure guidance.
FAB_DASHBOARD_PORT=7893
FAB_DASHBOARD_HOST=127.0.0.1
FAB_DASHBOARD_ALLOWED_HOSTS=localhost,127.0.0.1
FAB_DASHBOARD_PUBLIC_ORIGIN=
FAB_DASHBOARD_TRUSTED_CONFIG_ORIGINS=FAB_DASHBOARD_PORT wins over PORT. Without either override, bun run dev starts at port 7893 and advances to the first available API port; Vite independently starts at 5193 and does the same. Explicit port overrides remain strict. FAB_DASHBOARD_HOME and FAB_DASHBOARD_STATE_HOME override the default config and state directories. UI writes, such as card reordering and layout changes from settings, are enabled only when the server is bound to a local host. Add exact private proxy origins to FAB_DASHBOARD_TRUSTED_CONFIG_ORIGINS only when you intentionally want settings writes through something like Tailscale Serve.
Use .env.example as a safe starting point for local development overrides.
This repository is the public reusable engine. Contributions should be generic: new block primitives, connector kinds, schema/runtime improvements, themes, tests, docs, templates, and safe examples.
Private dashboards belong in $FAB_DASHBOARD_HOME, not in tracked files. If your private card needs a missing primitive or connector behavior, contribute that reusable engine change with a safe example.
Read CONTRIBUTING.md before opening a PR and SECURITY.md before reporting sensitive issues.
Validation for most changes:
bun run typecheck
bun run test
FAB_DASHBOARD_HOME="$PWD/local/demo" FAB_DASHBOARD_STATE_HOME="$PWD/local/state" bun run cli init --demo --force
FAB_DASHBOARD_HOME="$PWD/local/demo" FAB_DASHBOARD_STATE_HOME="$PWD/local/state" bun run cli validateMIT. See LICENSE.
