The document format¶
A vibe-sketch document is one JSON object that holds a drawing and
everything the compute side needs from it. It is saved as QVF, the vibe
family’s file format, or as plain JSON in a .vsk file. This page describes
schema version 1, identified by "schema": "vibe-sketch/1".
In a QVF file¶
A vibe-sketch QVF (the QVF specification, release 0.3, lives in the qvf repository) holds:
Section |
Kind |
Contents |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The x_vibesketch namespace is declared in the manifest’s extensions,
version 1, not critical: a QVF reader that does not know vibe-sketch skips the
document and still knows every molecule, the scheme and the calculations.
source.program is vibe-sketch, and the media type is
application/vnd.vibe-qc.qvf+zip.
The scheme records each species by its chemical role, as QVF does: a
retrosynthetic arrow points from the target to its precursors, so the
species drawn at its tail are the step’s products. A reagent without a 3D
structure is named in the step’s conditions. A yield printed as 87% is
also given as a number.
The calculations are a QVF job set. Each job names its structure and
states the species’ charge and multiplicity, the method and functional in
vibe-qc’s names (rks with b3lyp, uhf, ccsd(t), r2scan-3c), the
basis, dispersion, solvation and resources. What only some programs can do
goes into the job’s options: aux_basis, approximation (such as
rijcosx), states for TDDFT, constraints. A runner that does not know an
option refuses the job rather than drop it, so a job fails closed as the
input writers do. A geometry job computes nothing and has no section.
The machine-readable contract is the JSON schema in
schema/vibe-sketch-1.schema.json (draft 2020-12), which
vibe-sketch schema prints and the server serves at
GET /api/schema/document. It is generated from the Python model and a test
fails when the two drift.
Two layers¶
The canvas is the drawing exactly as the canvas engine stores it. Today that is KET, Ketcher’s JSON format, embedded verbatim: whatever the engine writes comes back unchanged, including fields vibe-sketch does not know about. That is what makes a round trip through the browser lossless.
The normalized layer is what the compute side reads: species with their identifiers, charge, multiplicity and 3D conformers; reactions with roles, arrows and conditions; program-neutral job specifications; the figure style; and provenance. It is derived from the canvas by the server and can be written directly through the API by an agent.
A minimal document¶
{
"schema": "vibe-sketch/1",
"provenance": {"app": "vibe-sketch 0.1.0", "created": "2026-10-13T00:00:00Z"}
}
Every other field has a default: revision 0, an empty KET canvas, no
species, reactions or jobs, and the acs-1996 style.
Fields¶
Field |
Type |
Meaning |
|---|---|---|
|
|
The format and its major version. |
|
integer, at least 0 |
Incremented by the server on every accepted edit; an edit names the revision it read. |
|
object |
|
|
list |
The molecules and ions in the drawing. |
|
list |
The steps of the scheme. |
|
list |
Calculations to run. |
|
object |
|
|
object |
|
A species has an id and optionally a label (its compound number in
the scheme), smiles, inchikey, name, and conformers. charge is the
sum of the formal charges (default 0). multiplicity is the spin
multiplicity 2S+1 (default 1); it defaults from the radical count when the
server derives it and is always editable, because a drawing cannot know the
spin state of a metal centre. A name records its value, its source
(for example vibeqc_naming or user) and a confidence of high,
medium or low.
A conformer is one 3D structure: method (how it was made: etkdg+mmff94,
etkdg+uff or etkdg from vibe-sketch’s embedding, atom for a lone atom,
imported), symbols (one element per atom) and xyz_angstrom (one
[x, y, z] per atom). Every conformer of a species has the same atoms in the
same order, the drawing’s atoms first and then the hydrogens; the first
conformer, the lowest in energy, is the one writers use.
A reaction has an id, reactants and products (at least one each),
reagents (species drawn at the arrow), an arrow (forward,
equilibrium, retrosynthetic or resonance), conditions (text lines at
the arrow) and a yield as printed, such as "87%".
A job has an id, the species it computes, the program that writes
its input (a writer name; see input writers) and a spec, the
program-neutral specification:
|
Example |
Meaning |
|---|---|---|
|
|
|
|
|
Required for every task but |
|
|
Basis sets. |
|
|
Integral approximation. |
|
|
Dispersion correction. |
|
|
Implicit solvation, |
|
|
Excited states; required for |
|
|
Coordinates an optimisation holds fixed; |
|
|
Processes and memory per core. |
A job may also carry runs, its submissions to a queue, oldest first:
each has the queue (vibe-queue), the host (localhost), the queue’s
id for the run and when it was submitted.
A constraint has a kind (distance, angle, dihedral or
position), the 0-based atoms it names in the species’ conformer (2, 3, 4
or 1 of them: the drawing’s atoms first, then the hydrogens) and an optional
value in angstrom or degrees; without one, the starting geometry’s value is
kept. A position fixes an atom where it is.
A geometry task sets none of the calculation fields. Nothing in the
specification names a program: each writer translates it, and refuses what
it cannot express.
An edit in provenance.edits records the revision it produced, when
(at), the actor (human, agent or system), the client it came
through (browser, cli, rest, mcp) and a one-line summary.
What validation checks¶
The model is strict, so a mistake is reported instead of silently dropped:
Unknown fields are refused, at every level except inside the canvas data.
Identifiers start with a letter and are unique across species, reactions and jobs. Every species a reaction or a job names exists.
No species appears twice in one role of a reaction.
A conformer has one position per atom, three finite coordinates each, and known element symbols.
Charge and multiplicity agree with the conformer’s atoms: the charge leaves a non-negative electron count, and the number of unpaired electrons (multiplicity minus one) has the parity of the electron count. A methyl radical drawn as a singlet is refused.
The JSON schema expresses the structural rules. The cross-references and the
charge and spin rule are checks it cannot express, so a client that has only
the schema should still validate through vibe-sketch validate or
POST /api/documents/validate before trusting a document.
Reading and writing¶
vibe-sketch validate scheme.vsk
from vibesketch.document import load, save, new_document
document = load("scheme.vsk")
document.species[0].multiplicity = 3 # validated on assignment
save(document, "scheme.vsk") # written atomically
Files are written with two-space indentation, unescaped Unicode and a
trailing newline, and loading then saving an unchanged document reproduces it
byte for byte, so .vsk files diff cleanly under version control.
Versioning¶
The major version is part of the schema value. A change that would make an
existing document invalid, or change the meaning of a field, is a new major
version with a migration; that decision is the maintainer’s (AGENTS.md).
Because unknown fields are refused, adding a field is also a schema change,
and the committed JSON schema changes with it in the same commit.