{"id":51723609,"url":"https://github.com/lukaisailovic/openislands","last_synced_at":"2026-07-17T15:36:48.509Z","repository":{"id":365761883,"uuid":"1267720676","full_name":"lukaisailovic/openislands","owner":"lukaisailovic","description":"Local-first dashboards your AI agent builds and keeps maintaining, over data that never leaves your machine.","archived":false,"fork":false,"pushed_at":"2026-07-14T16:55:24.000Z","size":1999,"stargazers_count":19,"open_issues_count":2,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-17T15:36:46.385Z","etag":null,"topics":["agent-tools","ai-agents","dashboards","data-apps","data-visualization","duckdb","local-first","mcp","model-context-protocol","react","self-hosted","sql","tanstack-start","typescript"],"latest_commit_sha":null,"homepage":"https://openislands.sh/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lukaisailovic.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-06-12T19:58:28.000Z","updated_at":"2026-07-14T16:55:41.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/lukaisailovic/openislands","commit_stats":null,"previous_names":["lukaisailovic/openislands"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/lukaisailovic/openislands","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukaisailovic%2Fopenislands","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukaisailovic%2Fopenislands/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukaisailovic%2Fopenislands/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukaisailovic%2Fopenislands/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lukaisailovic","download_url":"https://codeload.github.com/lukaisailovic/openislands/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukaisailovic%2Fopenislands/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35587132,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-17T02:00:06.162Z","response_time":116,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-tools","ai-agents","dashboards","data-apps","data-visualization","duckdb","local-first","mcp","model-context-protocol","react","self-hosted","sql","tanstack-start","typescript"],"created_at":"2026-07-17T15:36:47.719Z","updated_at":"2026-07-17T15:36:48.504Z","avatar_url":"https://github.com/lukaisailovic.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://raw.githubusercontent.com/lukaisailovic/openislands/main/apps/docs/public/logo-light.svg\"\u003e\n  \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://raw.githubusercontent.com/lukaisailovic/openislands/main/apps/docs/public/logo-dark.svg\"\u003e\n  \u003cimg alt=\"OpenIslands\" src=\"https://raw.githubusercontent.com/lukaisailovic/openislands/main/apps/docs/public/logo-light.svg\" width=\"84\" height=\"84\"\u003e\n\u003c/picture\u003e\n\n# OpenIslands\n\n**Dashboards your AI agent builds and keeps maintaining, over data that never leaves your machine.**\n\nPoint a coding agent at a folder of files. It builds a typed, durable dashboard\nand keeps it healthy for months as the data changes. No cloud, no account,\nno rendering code to rot.\n\n\u003cp\u003e\n  \u003ca href=\"./LICENSE\"\u003e\u003cimg alt=\"License: MIT\" src=\"https://img.shields.io/badge/License-MIT-2dd4bf.svg\"\u003e\u003c/a\u003e\n  \u003cimg alt=\"Node \u0026gt;= 20\" src=\"https://img.shields.io/badge/Node-%3E%3D_20-2dd4bf.svg\"\u003e\n  \u003cimg alt=\"ESM only\" src=\"https://img.shields.io/badge/Module-ESM-2dd4bf.svg\"\u003e\n  \u003cimg alt=\"Status: alpha\" src=\"https://img.shields.io/badge/Status-alpha-f59e0b.svg\"\u003e\n  \u003ca href=\"./CONTRIBUTING.md\"\u003e\u003cimg alt=\"PRs welcome\" src=\"https://img.shields.io/badge/PRs-welcome-2dd4bf.svg\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp\u003e\n  \u003ca href=\"#quickstart\"\u003eQuickstart\u003c/a\u003e \u0026nbsp;·\u0026nbsp;\n  \u003ca href=\"#why-openislands\"\u003eWhy\u003c/a\u003e \u0026nbsp;·\u0026nbsp;\n  \u003ca href=\"#how-it-works\"\u003eHow it works\u003c/a\u003e \u0026nbsp;·\u0026nbsp;\n  \u003ca href=\"#islands\"\u003eIslands\u003c/a\u003e \u0026nbsp;·\u0026nbsp;\n  \u003ca href=\"#documentation\"\u003eDocs\u003c/a\u003e \u0026nbsp;·\u0026nbsp;\n  \u003ca href=\"./CONTRIBUTING.md\"\u003eContributing\u003c/a\u003e\n\u003c/p\u003e\n\n\u003c/div\u003e\n\n---\n\nAI agents are great at building a dashboard once. Then a column gets renamed, a new\nexport lands, you ask a different question, and the generated app quietly breaks or,\nworse, keeps rendering the wrong number. OpenIslands fixes the part agents are bad at:\nkeeping it alive.\n\nIt's a local-first compiler and runtime. An app is a typed **manifest** of reusable\nvisual **islands** (KPI cards, charts, tables, gauges, timelines) bound to **typed data\ncontracts** built from your files. Your agent edits the manifest, never the rendering\ncode, through a pipeline that validates, diffs, and can roll back every change. When the\ndata and an island disagree, the build fails loudly and names the island instead of\ndrawing something wrong.\n\n## Quickstart\n\nScaffold a project, then serve it over your files:\n\n```bash\nnpx openislands init my-dashboard            # blank starter (the empty template)\ncd my-dashboard\nnpx openislands serve                        # http://127.0.0.1:4321\n```\n\nWith no flag, `init` scaffolds the `empty` template: a blank starter you build up from your\nown files. Want a populated example? Pass `--template finance` (the flagship: net worth,\nallocation, holdings, and transactions over CSVs you own). `health` and `operations` ship\ntoo.\n\nNow hand it to an agent. Add the MCP server to your tool of choice (Claude Code, Cursor,\nand friends), pointed at the project directory:\n\n```jsonc\n// .mcp.json\n{\n  \"mcpServers\": {\n    \"openislands\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@openislands/mcp\", \".\"]\n    }\n  }\n}\n```\n\nThen just ask:\n\n\u003e Drop `data/spending.csv` into the project and add a page charting monthly spend by category.\n\nThe agent reads your data, proposes the change so you see a diff before anything is\nwritten, applies it with a snapshot of the prior version, and rolls back if the result\nis wrong. Leave `serve` running and the page live-updates over SSE as each edit lands.\n\n### Agents and skills\n\n`init` sets this up for you. Every scaffolded project ships a local `.mcp.json`, an\n`AGENTS.md`, and the OpenIslands skill under `.agents/skills/openislands/`, so an agent\nthat opens the folder picks up the MCP tools and the conventions with no extra wiring.\n\nWant the skill in another project or in your own agent setup? Install it anywhere:\n\n```bash\nnpx skills add lukaisailovic/openislands --skill openislands\n```\n\nOr skip the scaffold entirely and let an agent drive from a single paste:\n\n\u003e Read https://openislands.sh/start.md then help me build my first agent-maintained dashboard.\n\n## Why OpenIslands\n\n|  |  |\n|---|---|\n| **Your data, your disk** | Plain files you own. No account, no cloud, nothing to sign into. |\n| **Built to last** | Typed islands from a closed registry. There's no 300-line React component to rot. |\n| **Agent-maintained** | A CLI and an MCP server, so Claude Code or Cursor build the dashboard and keep it healthy. |\n| **Fails loudly** | Bind an island to a field that doesn't exist and validation stops with a named error. You never get a silently wrong chart. |\n| **Always live** | Edit the manifest or drop a new export and the dashboard updates over your live files. No rebuild, no snapshot to drift. |\n\nIt isn't a hosted app builder or a BI platform. It's the typed, file-based layer your\nagent edits safely.\n\n## How it works\n\n```text\n files (CSV / JSON / Parquet / md)\n        │\n        ▼\n DuckDB query core  ──  runs transforms + queries live  ──┐\n        │                                                 │\n manifest (typed islands)  ──►  serve runtime  ──►  your dashboard\n                                (TanStack Start SSR)      ▲\n                                       │ SSE on file change → islands refetch\n        AI agent  ──(Code Mode: execute → validate → apply → rollback)──┘\n```\n\nThe pieces, smallest contract first:\n\n| Package | Role |\n|---|---|\n| `@openislands/schema` | The keystone. Zod schemas for the manifest and islands, emitted as TypeScript types and JSON Schema for editor autocomplete and agent grounding. Everything else depends on it. |\n| `@openislands/compiler` | The DuckDB query core. Turns files into typed data contracts, runs transforms and queries live, and checks every island binding against the data. |\n| `@openislands/runtime` | The island registry and renderers behind `serve` (TanStack Start SSR + React islands + live updates). |\n| `openislands` | The CLI: `init`, `validate`, `serve`, `add`, `infer`. |\n| `@openislands/mcp` | The MCP server, in Code Mode: one `execute` tool the agent drives with JavaScript against the `oi` API. Read many, write one, so it edits the manifest without breaking it. |\n\n## Islands\n\nAn island is a reusable, typed visual block. You declare it in the manifest, bind it to\nfields that exist in your data, and the runtime renders it. The built-ins cover most of a\ndashboard:\n\n- **Metrics \u0026 gauges:** KPI cards, scorecards, goal rings, meters, status grids.\n- **Charts:** line, bar, combo, and pie, over time or category.\n- **Tables \u0026 feeds:** sortable grids and activity feeds.\n- **Content \u0026 layout:** Markdown notes, a rich content editor, and rows that group islands.\n\nNeed something the registry doesn't have? Drop a renderer under `components/custom/` and\nbind to it like any other island. The full catalog, with required fields and live\npreviews, lives in the [docs](#documentation).\n\n## Templates\n\nThree templates ship with the repo, and the same engine renders all of them with no\ndomain-specific hacks:\n\n- **`finance`:** net worth, portfolio allocation, holdings, transactions.\n- **`health`:** macros, biomarkers, and wearables (pairs with [health-mcp](https://github.com/lukaisailovic/health-mcp)).\n- **`operations`:** a non-personal template that proves the breadth of the island set.\n\n## Self-host with Docker\n\nWant it always-on — on a home server or NAS, reachable by a remote agent? Run the published\nimage. One process serves the dashboard **and** the MCP server (over Streamable HTTP) on a single\nport. Mount a single app or a workspace dir at `/project`:\n\n```bash\n# MCP is a write surface, so off-loopback it needs a token:\ndocker run -d -p 127.0.0.1:4321:4321 \\\n  -e OPENISLANDS_MCP_TOKEN=\"$(openssl rand -hex 32)\" \\\n  -v \"$PWD/my-dashboard:/project\" \\\n  ghcr.io/lukaisailovic/openislands:latest\n```\n\nThen open [127.0.0.1:4321](http://127.0.0.1:4321). To reach it across your LAN, bind `0.0.0.0` and\nkeep the token set — and restrict who can connect with `OPENISLANDS_ALLOWED_IPS=192.168.1.0/24`\n(your subnet). For a dashboard-only container with no agent write path, set `OPENISLANDS_MCP=0` to\nboot token-free. See [Self-hosting](https://openislands.sh/self-hosting) for the full guide.\n\n## Status\n\nAlpha, and live-first. The schema, compiler, runtime, CLI, MCP server, and all three\ntemplates work today, and `pnpm test` is green. There's no static export in v1: `serve`\nboots the production runtime and queries your files on every request. A hosted\npublish/sync tier may come later.\n\n## Documentation\n\n- [Data app model](./docs/data-app-model.md): the manifest, the island catalog, data contracts, and workspaces.\n- [Agent edit loop](./docs/agent-edit-loop.md): the read-many/write-one MCP loop in Code Mode (`execute` + `oi`), actions, queries, and connectors.\n- [Contributing](./CONTRIBUTING.md): adding an island, the PR gate, releases.\n\nThe full docs site lives in [`apps/docs`](./apps/docs) (built with Fumadocs on TanStack Start, deployed static to Cloudflare Workers).\n\n## Develop\n\n```bash\npnpm install\npnpm build                 # tsdown (rolldown / Oxc) across packages\npnpm test                  # vitest\npnpm typecheck             # tsc --noEmit per package\npnpm lint                  # oxlint\npnpm validate:templates    # every template's manifest + bindings\npnpm demo                  # serve the finance template locally\n```\n\nToolchain: pnpm + Turborepo + Changesets, tsdown for builds, oxlint and oxfmt for\nlint/format, Vitest, Node ≥ 20, ESM only. See [CONTRIBUTING.md](./CONTRIBUTING.md) before\nopening a PR.\n\n## License\n\n[MIT](./LICENSE) © Luka Isailovic\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukaisailovic%2Fopenislands","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flukaisailovic%2Fopenislands","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukaisailovic%2Fopenislands/lists"}