Logo made with PowerRP. Open it in PowerRP to edit it (source: assets/doc.json).
dtab
Delta Tab. Config files made of tab-separated paths. One line is one path into a tree, and later lines are deltas on top of earlier ones. Try it in your browser: dtab on the left, JSON on the right.
objects l1,l2 light
deltas l1 position
x 1 y .5 z -2
import dtab
dtab.parse(open("scene.dtab").read())
# {'objects': {'l1': 'light', 'l2': 'light'},
# 'deltas': {'l1': {'position': {'x': '1', 'y': '.5', 'z': '-2'}}}}
Why
-
Less to look at. No braces, quotes, or commas between values. A file with its tabs aligned reads like pseudocode, and is easy to write by hand, even on paper.
-
Simple. Six rules, one pass, about 70 lines per implementation.
-
Everything is addressable. There are no lists, so every value has a path:
config.deltas.l1.position.xwith EasyDict in Python or plain property access in JavaScript, brackets for keys likefile.json. -
You choose the shape. Lines stack, and
c,dwrites one value under several keys, so the same tree can be written wide, deep, or on one line, trading horizontal space for vertical. These are the same file:a b c x a b d xa b c x d xa b c,d xA long list goes one key per line, the comma at the end of each saying it goes on:
servers alpha, beta, gamma port 80
Rules
- Tabs separate the steps of a path.
deltas l1 positionwalks three keys down. Several tabs in a row count as one, so you can align columns. Trailing tabs outside string bodies are ignored. - An entry with a space is
key value. It sets the key and stays at the same level, sox 1 y .5sets two keys. - Deeper lines belong to the last non-comment entry: children for an object, text for a leaf.
- Writing a key again replaces it. Writing into an object merges.
a,bwrites the same value underaand underb. Spaces, tabs or a line break may follow the comma, soa, b, anda,at the end of a line withbon the next, are the same list. A key must follow the comma: a comment cannot stand there.- An entry that starts with a space is a comment.
- A leaf with lines indented under it is a multiline string. See below.
Every value is a string. Cast the ones you need. A key is any run of letters, digits, _, ., - and /,
so file.json, 2026-09-07, assets/logo and 0 are keys. Keys that happen to be identifiers work as attributes
(config.deltas.l1 with EasyDict and friends); the rest are reached with brackets (config["file.json"]).
Multiline strings
When the last non-comment entry is a leaf, deeper lines replace its value with a multiline string. Earlier entries keep their values. The body starts one tab past the header line's leading indentation and is taken verbatim from there. Tabs and deeper indentation inside are part of the value. This is the only way to put a tab in a value. Blank lines inside are kept, trailing ones dropped.
query sql a comment may follow the tag
SELECT name, age
FROM users
WHERE age > 30
The leaf's own text is a tag that tells editors which language to highlight, and it is not part of the
value. Any text will do, txt or nothing at all (prompt with a trailing space) for plain text.
Unknown tags are plain text, never an error. For example:
hello world moose meat
world happy
This gives {"hello": "world", "moose": "world happy"}: moose is last, so the text belongs to it.
These forms both give {"A": {"B": {"code": "Some Code Here"}}}:
A B code py
Some Code Here
A B
code py
Some Code Here
Trailing tabs after B or code py change nothing. A space is different: B is an empty leaf,
not an object key.
| Tag | Also |
|---|---|
sql |
|
python |
py |
javascript |
js |
typescript |
ts |
html, css, json, jsonl, yaml, markdown |
yml, md |
bash |
sh, shell, zsh |
c, cpp, rust, go, java, swift |
|
dtab |
Install
- Python:
pip install dtabthenimport dtab - JavaScript:
npm install deltatabthenconst dtab = require('deltatab'), or<script src="https://cdn.jsdelivr.net/npm/deltatab/dtab.js">forwindow.dtab - Vim:
Plugin 'RyannDaGreat/dtab'(Vundle) orPlug 'RyannDaGreat/dtab'(vim-plug), or pastedtab.viminto your vimrc. Highlights*.dtab, flags bad keys, gives the file a Δ icon in NERDTree if vim-devicons is installed,:DtabPreviewopens a split showing the tree as JSON that follows your edits (needs+python3), andJjoins the line below with a tab (deep form to wide form), or with a space after a comma, whenever that keeps the tree the same. - VS Code: search "dtab" in Extensions, or
code --install-extension RyannDaGreat.dtab. Highlighting, a Δ file icon, and a live JSON preview of the file beside it (the preview button in the title bar, or Cmd+K V). - Monaco, Shiki and other TextMate hosts:
npm install deltatabincludes the TextMate grammar,deltatab/vscode/syntaxes/dtab.tmLanguage.json. For Monaco,await highlight(monaco, {wasm: fetch(onigWasmUrl), grammars: {'source.sql': sqlGrammar}})fromdeltatab/monaco.mjscolors a registereddtablanguage the way VS Code does, multiline-string headers included. It needsvscode-textmate,vscode-oniguruma, and'semanticHighlighting.enabled': truein the editor options. - Claude Code, Codex, Cursor and other agents:
npx skills add RyannDaGreat/dtabinstalls a skill that teaches the agent the rules (skills/dtab/SKILL.md, in the Agent Skills format they all read).
API
parse(text)returns nested dicts (Python) or plain objects (JavaScript). Raises on an invalid key, with the line number.stringify(tree)writes the tree back out, one key per line.- Command line:
dtab scene.dtabprints the tree as JSON.
Metadata
Release files for dtab 0.5.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| dtab-0.5.4.tar.gz | 15.3 kB | Without provenance | Details for dtab-0.5.4.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| dtab-0.5.4-py3-none-any.whl | Python 3 | none | any | Details for dtab-0.5.4-py3-none-any.whl |
Total release size: 23.9 kB
Release files / dtab-0.5.4.tar.gz
| Download URL | dtab-0.5.4.tar.gz |
|---|---|
| Size | 15.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c1d7c11e4f2c5b1200aa696b8d9d12d9f3bd88a0675916a0010c67ed66b8ab6f
|
|
BLAKE2b-256 checksum How to use checksums |
ad98c155d993d511e3e3a73b787c5f39451390748261400e3a2da258a7ae4658
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Release files / dtab-0.5.4-py3-none-any.whl
| Download URL | dtab-0.5.4-py3-none-any.whl |
|---|---|
| Size | 8.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7c75b58901a7680c1c250e0d466e8edc3bf866f878310b8a020cd780c9d83d12
|
|
BLAKE2b-256 checksum How to use checksums |
f3dc0c1b674c31588a0ce45a59f9fba4b97362c3757790935fb7164073eb2e90
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Security for dtab 0.5.4
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.