# OpenBoard > A terminal UI (TUI) and non-interactive CLI that turns a CSV or JSON file into > one authenticated React analytics app, then builds it, pushes it to GitHub, and > deploys it to Vercel. Each new dataset becomes another tab in the same shared > app. Generation is done by a configured LLM (OpenAI, Anthropic, OpenAI Codex, > Moonshot, or local Ollama). MIT licensed. This file is a plain-text contract for LLM agents and automation runners (OpenClaw, cron, CI). Humans should read https://github.com/syedateebulislam/openboard ## Mental model - OpenBoard owns the whole pipeline: parse data -> analyze -> LLM writes React files -> build (auto-repairs build failures via the LLM, max 2 passes) -> commit/push to GitHub -> deploy to Vercel -> verify the live URL -> tag the deploy (deploy-N) for rollback. - It maintains ONE shared authenticated app. The first dataset scaffolds it; later datasets are added as tabs, not new projects. - An agent only supplies a data file and, optionally, prompts. - Every run persists resumable state in ~/.openboard/runs/.json. - A project lock prevents concurrent runs from colliding (E_LOCKED -> wait, retry). ## Prerequisites (configured once by a human) - An LLM provider (OpenAI key, OpenAI Codex login, Anthropic, Moonshot, or Ollama). - A GitHub token or authenticated GitHub CLI. - A Vercel token or Vercel Git integration. - Dashboard login credentials. - Node 18+. Install: `npm install -g openboard-cli` (the command is `openboard`). From source instead: `npm install && npm run build`, then use `node dist/index.js`. ## Commands ### Create (onboard a new dataset as a tab) ``` openboard agent create --data "" --name "" \ [--type health|finance|grocery|custom] [--prompt "<intent>"] \ [--dry-run] [--idempotency-key "<key>"] [--json] ``` Alias: `openboard agent onboard`. Returns a reusable dashboard selector and a runId. Flags: - --data (required) CSV or JSON file path. Quote Windows paths. Do not prefix with "- ". - --name (optional) Dashboard title; derived from the file name if omitted. - --type (optional) health | finance | grocery | custom. Default: custom. - --prompt (optional) Intent for the initial dashboard. - --dry-run (optional) Parse + analyze and return a `plan` (title, selector, rowCount, columnCount, dataSummary). No LLM call, no files, no deploy. - --idempotency-key (optional) If a previous run with this key succeeded, returns that run's result with "reused": true instead of creating a duplicate. Use it whenever your runner retries on timeout. - --json (optional) Final JSON on stdout; NDJSON progress events on stderr. ### Update (change an existing dashboard) ``` openboard agent update --dashboard "<selector>" --prompt "<request>" \ [--data "<csv|json>"] [--dry-run] [--json] ``` Flags: - --dashboard (required) Dashboard id, slug/name, or exact title. - --prompt (required) Instruction for the UI/code change. - --data (optional) Override the linked data file for this run. - --dry-run (optional) Plan only; no LLM call. - --json (optional) JSON result on stdout. ### Refresh (regenerate from saved prompt history; no new prompt) ``` openboard update --dashboard "<selector>" # one board, latest data openboard update --all # every registered board ``` ### Query (discover state before acting) ``` openboard agent list --json # all dashboards + deploy URLs + dataStale openboard agent status --dashboard "<selector>" --json # one dashboard's full status openboard agent runs --json # recent runs + failure summary ``` `status` returns `dataStale: true` when a linked data file changed after the last generation — use it to decide whether a refresh is needed at all. ### Resume (continue a failed run) ``` openboard agent resume "<run-id>" --json ``` If generation already succeeded (files written), only build -> push -> deploy -> verify re-runs — no LLM cost. Otherwise the original action replays. Run ids come back in every result and from `agent runs`. ### Rollback (restore the previous deploy) ``` openboard rollback --dashboard "<selector>" openboard agent rollback --dashboard "<selector>" --json ``` Restores the previous deploy-N git tag, rebuilds, pushes, and redeploys it. ## JSON output Use --json for reliable parsing. The final JSON is the only thing on stdout. stderr streams NDJSON progress events, one JSON object per line: ``` {"event":"phase","phase":"generate","pct":8,"message":"Generating dashboard code"} {"event":"log","message":"codex still generating… 30s elapsed","phase":"generate","pct":12} {"event":"result","success":true,"pct":100} ``` Phases in order: parse, analyze, generate, write, build, push, deploy, verify, done. Track `pct` for progress; a phase emitting no events for several minutes is wedged. Exit code 0 on success, non-zero on failure. Success: ``` { "success": true, "action": "create" | "update" | "resume" | "rollback", "dashboard": "Uber Rides", "dashboardSelector": "uber-rides", "projectDir": "projects/openboard-app-workspace-...", "deployUrl": "https://example.vercel.app", "deployTag": "deploy-4", "verified": true, "runId": "run-2026-06-10-ab12cd34", "tokenUsage": { "promptTokens": 5200, "completionTokens": 3100, "estimated": false }, "writtenFiles": ["App.tsx", "components/UberRidesDashboard.tsx"] } ``` `verified` is a post-deploy health check (app shell + /api/auth respond at the deploy URL). `verified: false` means deployed but not yet healthy — re-check the URL before reporting success to a user. Failure: ``` { "success": false, "action": "update", "dashboardSelector": "uber-rides", "runId": "run-2026-06-10-ab12cd34", "error": "Dashboard not found: uber-rides", "errorCode": "E_DASHBOARD_NOT_FOUND", "writtenFiles": [] } ``` ## Error codes (branch on errorCode, never on the prose error string) - E_VALIDATION bad/missing flags -> fix the command - E_DATA_NOT_FOUND data file missing -> check the path - E_DATA_PARSE file unparseable -> check the format - E_DASHBOARD_NOT_FOUND unknown selector -> `agent list` to discover selectors - E_NO_LLM no LLM configured -> ask a human to run setup - E_LLM_EMPTY/E_LLM_FAILED generation failed -> retry once, then escalate - E_SCAFFOLD_FAILED/E_INSTALL_FAILED workspace setup failed -> escalate - E_BUILD_FAILED build failed after self-repair -> `agent resume <runId>` - E_PUSH_FAILED git push failed -> check GitHub auth - E_DEPLOY_AUTH Vercel auth missing -> ask a human to re-auth - E_DEPLOY_FAILED deploy failed -> `agent resume <runId>` - E_VERIFY_FAILED deployed but URL unhealthy -> re-check later - E_LOCKED another run holds the project lock -> wait and retry - E_RUN_NOT_FOUND bad run id -> `agent runs` to list ids - E_UNKNOWN unclassified -> read `error`, escalate ## Decision rules - Use `agent create` for a new data file with no existing selector. - Use `agent create --dry-run` first when you want to validate a data file cheaply. - Use `agent update` for a UI/metric/chart change on an existing dashboard. - Use `agent status` to check `dataStale` before refreshing; skip if false. - Use `update --dashboard` when only the data changed and saved intent should drive it. - Use `update --all` to rebuild/deploy every dashboard (e.g. after a nightly data refresh). - On failure with a runId: prefer `agent resume <runId>` over re-running the original command — it skips completed phases and avoids duplicate LLM spend. - On a bad/broken deploy: `agent rollback --dashboard <selector>`. - Do NOT run `openboard` or `openboard start` from automation — those open the interactive TUI. ## Links - Source: https://github.com/syedateebulislam/openboard - Full agent contract: https://github.com/syedateebulislam/openboard/blob/main/Agent.md - Human manual: https://github.com/syedateebulislam/openboard/blob/main/user-manual.md