Fabric Dashboards is one window for every local agent service on your Mac. It finds each
service that speaks fabric-service/0.1, shows whether it is alive and what it did last,
starts, stops and restarts it through launchd, and opens its dashboard inside the app — signed
in, one live view per service — instead of a browser tab per port. It is the monitoring tool of
Fabric, PassionCode.ai's CEO AI agent, and it also works on its own:
agents drive it over MCP, people use the window.
Version 0.6.4 — download the latest release (until 0.6.4 is published there, that is 0.6.3 or 0.6.2, which update themselves to 0.6.4). Updates install themselves, on by default; the interface speaks English and Russian. See HANDOFF for what is released and what is next.
Screenshots of the real app against the kit's sample service under example names (npm run screenshots, scripts/screenshots.ts).
| Overview | a status strip (agents ready, not answering, needing attention, spend today and in 30 days), compact Needs attention rows, then a card per agent — its instances (main, projection, read-only) inside one card (ADR-0012), state, version and commit, uptime, the service's own tiles, its latest event — and Needs attention first, per instance; services without a dashboard under Background |
| Service view | the service's dashboard takes the window: a one-line header (state, name, the first problem, the tabs) that opens to the full card with Restart · Stop/Start · Update · Doctor · Logs; a toolbar over the dashboard: Back, Forward, Reload, Home, the page's address, Copy address and Copy app link (ADR-0014, ADR-0017); the sidebar folds into a rail |
| Agent console | beside the dashboard, the agent's own runtime — Claude Code, Codex or another one installed — in the agent's repository, on the account Fabric Switchboard binds to it; New, Continue, Open in Terminal (ADR-0017) |
| Activity | every service's events and the app's own observations in one feed, filterable, each row opening the exact item |
| Spend | what every agent spent today, in 7 and 30 days, on which models and against its own budget — from each agent's own usage report (contract DEC-0021); an unknown cost reads unknown, never $0 |
| Notifications | not answering (three missed probes in a row and 60 s of silence — a slow answer under load is not an outage, ADR-0008), back, two copies, another program on the port, and, from the events a service marks for you, only a decision it waits for, a failure or a warning — once per subject, titled with the agent and what it wants (ADR-0010); quiet hours and per-service levels |
| Menu bar | the aggregate state as a shape, problems first |
| Links from agents and Fabric | fabric-dashboards://service/<id.instance>?path=/… opens that service, or that page of it, here, signed in — the link Fabric's "Open dashboard" opens |
| MCP for agents | list services, hand out links, open a page, restart or update — through the app's own rules |
States it tells apart: Ready, Degraded, Not answering, Off, Starting/Stopping, Two copies (the answering pid is not launchd's), Wrong program on port (another id answers), Port conflict (two descriptors claim one port), Invalid descriptor.
It never starts a service process itself — launchd is the only supervisor (ADR-0002) — and quitting it stops nothing.
A service writes a descriptor into
~/Library/Application Support/ai.passioncode.fabric/services/; the app picks it up
within five seconds. The protocol is fabric-service/0.1, an extension of the Fabric
Agent Contract. Its public description is section 2 of the
design,
and the contract's fixtures are copied under test/fixtures/contract/.
Project Observatory
has spoken it since 0.8.0 and is a public example
(its design note).
The protocol's specification is
docs/specification/service.md
in the Fabric Agent Contract; the
Fabric Agent Adapter, whose
building-fabric-services skill builds or migrates a service, is the kit. Both are public.
Download Fabric-Dashboards-<version>.dmg from the
latest release, open it and
drag Fabric Dashboards to Applications. It is signed with a Developer ID and notarized, so it
opens without a Gatekeeper warning (spctl -a -vv -t exec "/Applications/Fabric Dashboards.app"
prints accepted, source=Notarized Developer ID). macOS 13 or later. Releases after 0.4.1 are
built and signed by GitHub Actions, and each carries SHA256SUMS, its GPG signature and a build
attestation (how to verify).
Open it from Applications. It lives in the menu bar and opens its window; with no service installed the overview says No services yet and Show folder opens the services folder. A service appears within five seconds of its installer writing a descriptor there. The first window asks once whether to open it at login (off until you choose; Settings changes it later). It updates itself from GitHub releases: a new version downloads on its own and installs while the window is closed, and the app reopens in the menu bar (Settings → Updates → Install updates automatically, on by default). Updates install only into Applications; a copy opened from the disk image offers to move itself there (ADR-0015).
To remove it: Settings → Uninstall Fabric Dashboards… removes the login item and its entry in
Claude Code's MCP servers, and moves the app to the Trash. Your settings and activity history stay,
so installing it again picks up where you left off, with the login item and the MCP entry back;
tick Also delete my settings and activity history to remove them too. Your services and their
data always stay. fabric-dashboards-mcp --unregister removes only the MCP entry; once the app is
already in the Trash, claude mcp remove --scope user fabric-dashboards does the same.
No keys. Each service's token is read from that service's own descriptor, in the main process
only (SECURITY). Optional environment variables: FABRIC_DASHBOARDS_USER_DATA
(a separate profile and log folder, for a checkout build or tests) and FD_SKIP_LAUNCHD
(tests without a GUI login session).
Register the stdio server that ships inside the app, once, for every project (--scope user;
without it Claude Code registers it for the current directory only):
claude mcp add --scope user fabric-dashboards -- "/Applications/Fabric Dashboards.app/Contents/Resources/bin/fabric-dashboards-mcp"
claude mcp get fabric-dashboards # Status: ✔ ConnectedOne call that proves it works, from a real client:
claude -p "Call the fabric-dashboards list_services tool once and reply with only the number of services it returned." \
--allowedTools mcp__fabric-dashboards__list_services --max-turns 3The answer is the number of installed services (0 until one is installed). Any other MCP
client runs the same file as a stdio server with no arguments; without a client, two JSON-RPC
lines prove the server answers:
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18"}}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_services","arguments":{}}}' \
| "/Applications/Fabric Dashboards.app/Contents/Resources/bin/fabric-dashboards-mcp"; echo "exit $?"Two JSON lines come back — serverInfo with the app's version, then services and
services_dir — and exit 0. The server exits by itself when stdin closes, and after an app
update an old server answers its next call stale and exits: restart the agent session to load
the new version (AGENTS.md → Lifecycle). Release 0.2.0 hands out links as open?service=…; later releases
as service/… (below). Both open.
Node 20 or later, macOS:
git clone https://github.com/passioncode-ai/fabric-dashboards && cd fabric-dashboards
npm ci
npm start # run from source
npm run check # the gate: typecheck, tests, brand pins, code regions, UX lint
npm run test:e2e # drives the real Electron app against a live sample serviceThe MCP server from a checkout is node out/main/mcp/server.js after npm run build. A checkout
build does not register the fabric-dashboards:// scheme; links open only in the installed app.
While the installed app runs, a checkout build shares its profile and only brings the installed
window forward: quit the installed app first, or give the checkout its own profile with
FABRIC_DASHBOARDS_USER_DATA=/tmp/fd-dev npm start. More in CONTRIBUTING.
Tools: host_status, list_services, service_status, service_context, link, open, control, doctor, update,
activity, spend (spend from 0.5.6; service_context — everything about one service a coding agent needs before working on it, its descriptor without auth — from FD-39). A console the app starts for a service already holds that context and this server (ADR-0020). An agent that starts work on a service hands the operator the open_link from
link — fabric-dashboards://service/<id.instance>?path=/…, which opens that page inside the
app. Keep http_url for diagnostics or confirmed-absent fallback. open opens it now;
fallback=never forbids the browser, and installed-host failure never falls back. spend gives
each agent's own usage entries; a service that does not answer is an error entry (unknown spend),
never "not reporting". list_services and service_status carry dashboard_min_width: the floor a
service declares for its dashboard (contract DEC-0036 ED-9), null when it declares none; the app
keeps every dashboard at least max(480, dashboard_min_width) px wide beside the console (ED-7).
doctor and update run the service's own programs: announce them first.
An unknown tool is a JSON-RPC error; an argument a tool does not declare, or of the wrong type, is
refused. A token goes only to the service itself: never to another program on its port, and never
again to an online address that answered as something else.
ADR-0004 and ADR-0005
have the rules.
See CONTRIBUTING. Runbook: docs/RUNBOOK.md. Contributions are accepted under the Contributor License Agreement.
- Design: docs/design/2026-09-28-fabric-dashboards-design.md
- UX: scenarios, screens, foundation
- Decisions: docs/adr/ · glossary: CONTEXT.md
- Shared with Fabric:
packages/service-host— the code that readsservices/(descriptors, health, state, service links)
Open source under the GNU AGPL-3.0. A commercial license is available for use that does not meet the AGPL's terms — passioncode.ai/business. Versions up to and including v0.3.0 were released under PolyForm Noncommercial or Internal Use (v0.2.0–v0.3.0) and the MIT License (v0.1.0 and earlier); those releases keep their licence.
For a registered dashboard, consumers return link.open_link as the primary
action; http_url remains diagnostic data. host_status reads installation,
version and the registered handler without launching anything. open accepts
fallback=if_absent (default) or never: an installed host failure never opens
a browser. Its accepted_by_os receipt is not proof of page readiness. See the
implementation and checks.
These additions require Fabric Dashboards 0.3.2 or later.
Version 0.3.3 also clears the MCP-only Electron RunAsNode flag when dispatching a dashboard link, so a closed host starts as a graphical application.

