尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Edit one table as a grid, Markdown, CSV, TSV, HTML, Jira, JSON or records, with every view synchronized and everything running in your browser
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
Edit one table as a grid, Markdown, CSV, TSV, HTML, Jira, JSON or records, with every view
synchronized and everything running in your browser.
Tabelo is a table editor for the moments when a spreadsheet is too much, but hand-editing pipes
and commas is no fun either. Change a cell in the visual table and the Markdown updates. Fix the CSV
and the table updates. Open up to four views at once and they all stay in sync. Everything runs
in your browser: no account, no server, no upload.查看完整 README ↗Edit one table as a grid, Markdown, CSV, TSV, HTML, Jira, JSON or records, with every view synchronized and everything running in your browser.
Tabelo is a table editor for the moments when a spreadsheet is too much, but hand-editing pipes and commas is no fun either. Change a cell in the visual table and the Markdown updates. Fix the CSV and the table updates. Open up to four views at once and they all stay in sync. Everything runs in your browser: no account, no server, no upload.
Tabelo is the word for table in the language Esperanto. It exists because moving a table between a wiki, a ticket, a spreadsheet and a code review usually means retyping it, and every retype is a chance to lose a line break, an alignment marker or a leading zero. Here one canonical document backs every format, so a round trip through CSV or Jira and back leaves the table exactly as it was.
Requires Node.js 24+ and pnpm 11+.
pnpm install
pnpm dev
Then open the URL it prints, which on a plain checkout and in CI is http://localhost:3001.
Every other worktree gets its own port derived from its path, so several checkouts can run side by side without serving each other's build.
An optional local MCP connection lets an agent edit the open table while you keep working. See setup and command conventions. No hosted backend or store registration is needed; the editor works without it.
| Command | What it does |
|---|---|
pnpm validate | The full gate before a commit |
pnpm dev | Dev server |
pnpm build | Production build |
pnpm test | Unit and property tests |
pnpm test:watch | Unit tests, re-running on change |
pnpm test:unit | Unit tests only |
pnpm test:property | Property tests only |
pnpm bench | Benchmarks |
pnpm test:e2e:install | Install Chromium for browser tests |
pnpm test:e2e | Browser tests in Chromium |
pnpm test:e2e:failed | Only the tests that failed last time |
pnpm test:e2e:changed | Only the specs affected by uncommitted changes |
pnpm test:e2e:ui | Playwright's watch and time-travel interface |
pnpm test:e2e:serve | Build once and keep the preview server warm |
pnpm check-types | TypeScript |
pnpm lint | Biome check |
pnpm check | Biome check, writing fixes |
pnpm check:dead-code | Knip, for unused files, exports and dependencies |
pnpm test:e2e builds and serves the app itself. test:e2e:serve is worth starting first when a fix
needs several test:e2e:failed rounds: the suite reuses that server and skips its boot. Each round
rebuilds first when a product file changed since the last build, and skips the build when only the
browser specs changed, so the warm server never tests an old build.
Property tests run 100 generated cases per invariant. A failure reports its seed, path, and
minimal counterexample. Replay it by temporarily passing the reported { seed, path } beside
numRuns in that test.prop call, then run the focused spec. Keep the property after the fix. Add
the shrunk example as an ordinary regression test only when it communicates a distinct contract more
clearly than the property itself.
Chromium is the only browser the suite runs, locally and in CI, because it is the only browser Tabelo supports. There is no second project to opt into and no cross-browser command to remember before opening a pull request.
[!TIP] Before you commit:
pnpm validate, that ispnpm check,pnpm check:dead-code,pnpm check-typesandpnpm test. Addpnpm test:e2ewhen the change crosses a UI boundary, which is the coverage CI selects for you anyway.
There is no application secret to configure: Tabelo has no backend, no API key and no account. Both
workflows use only the GITHUB_TOKEN that GitHub Actions provides on its own.
| Variable | Where | What it does |
|---|---|---|
BASE_PATH | Build | Public base path of the built site. Defaults to /; the deploy workflow sets it explicitly |
SITE_ORIGIN | Build | Absolute origin used in the page metadata and social card tags |
TABELO_DEV_PORT | Local dev | Overrides the path-derived dev server port |
TABELO_PREVIEW_PORT | Local dev | Overrides the path-derived preview server port |
TABELO_PWA_DEV | Local dev | Enables the service worker in dev, for working on the worker itself |
CI | CI | Set by GitHub Actions; pins the canonical ports and the Playwright retry policy |
These are not separate files. They are the same table:
Grid
| Name | Role | Active |
|---|---|---|
| Ingrid | Designer | Yes |
| Paulo | Developer | No |
Markdown: alignment and all
| Name | Role | Active |
| :----- | :-------: | -----: |
| Ingrid | Designer | Yes |
| Paulo | Developer | No |
CSV
Name,Role,Active
Ingrid,Designer,Yes
Paulo,Developer,No
Jira
||Name||Role||Active||
|Ingrid|Designer|Yes|
|Paulo|Developer|No|
JSON
[
{"Name": "Ingrid", "Role": "Designer", "Active": "Yes"},
{"Name": "Paulo", "Role": "Developer", "Active": "No"}
]
Records: each row as a titled block of bullets
Name: Ingrid
- Role: Designer
- Active: Yes
Name: Paulo
- Role: Developer
- Active: No
Go through CSV or Jira and back and those :---: alignment markers are still
there. Those formats cannot express alignment, so Tabelo quietly remembers it.
No formulas, extra sheets, charts, macros, pivot tables, accounts, cloud sync, collaboration, or analytics. Tabelo is happiest staying small.
Both hands stay where they are.
| Keys | What happens |
|---|---|
| Arrows | Move between cells |
Shift + arrows | Extend the selection |
Enter / F2 | Edit the focused cell |
| Any character | Replace the cell and start typing |
Enter while editing | Commit, move down |
Shift Enter while editing | Line break inside the cell |
Tab / Shift Tab | Next / previous cell |
Alt + arrows | Move the row or column itself |
Backspace | Clear the selected cells |
⌘ Backspace | Delete the selected rows or columns |
⌘ Enter | Add a row below |
⌘ A | Select everything |
⌘ Z / ⌘ ⇧ Z | Undo / redo |
Undo is layered: inside a source view it undoes your keystrokes, and once that history runs out it keeps going through the table's own history. One timeline underneath, native behaviour on top.
Every shortcut also has a menu entry, so nothing is reachable only by keyboard.
React 19, Vite, Tailwind v4, shadcn/ui on Base UI, CodeMirror 6 for source views (lazily loaded), Papa Parse for delimited formats. Scaffolded with Better-T-Stack. The grid is hand-built, with no grid library, and there is no router: the one page is mounted directly.
One idea holds the whole thing up: there is a single canonical table document, and every format is a parser and serializer around it. No text format is ever the source of truth. That is what makes round trips safe.
Formats and views live in two small registries. Adding a format is one file plus one registry line, and it becomes editable, downloadable, importable, and pasteable everywhere at once.
The decisions worth reading before you change anything:
docs/design-system.md is binding for anything visual,
CONTEXT.md defines the vocabulary, and AGENTS.md
holds the working agreements.
Editing never sends your data anywhere. There is no backend, no account, and no
telemetry of any kind. Your tables live in localStorage on your machine.
Clear your browser storage and they are gone: there is no copy anywhere else,
including with us.
The one exception is the optional external agent, and only after you pair it yourself. A paired agent on your computer reaches that tab's tables, to read, create, open, rename and edit them but never delete one, and it may send what it reads to its own model provider. Disconnect it from the app menu at any time; until you pair one, nothing is shared.
. That is the price
of not losing it: a table row is one line. Renderers read it as whitespace
rather than as a visible break. Settings has Use <br> for line breaks in
cells for renderers that draw <br> as a break, such as GitHub's; strict
CommonMark renderers show <br> literally.MIT © 2026 Marton Paulo.