Skip to main content
Your kDB has two parts. The kDB itself holds types: the ontology terms, and the classes and properties that say what a paper, a model or a result is. It is a bundle in Google’s Open Knowledge Format (OKF) v0.2: a directory of markdown files with YAML frontmatter, kept in a git repository. Read the spec. It is one short file. The lake holds the instances. Every paper, model, dataset, training link, result, contested claim, computation and analysis is a row in a table of a DuckLake catalog, and every PDF is registered in its media table. A page in the kDB describes a kind of thing. A row in the lake describes one thing, so if a page would only make sense for one paper or one model, it belongs in the lake as a row. Your project folder looks like this after kdb lake init and okf-seed:
The lake is local by default: a catalog file and a data folder next to kdb.toml. You can keep its data in RustFS instead, an S3-compatible store that runs in Docker on your own machine from the compose.yml that kdb lake init writes. Decide before your first lake init. kdb.toml.example in the starter shows how. Either way the lake runs on your machine, and you never need a cloud credential. Run every command from your project folder, because kdb finds kdb.toml in the current folder or a folder above it. okf-validate and okf-ground look for it in the folder of the bundle you name or a folder above that one.

Classes and tables

kdb lake init binds each VLA class to its own table. Every table also has the columns iri, type (the class IRI) and team, which are set for you. The Class pages under ontology/vla/classes/ map each column to a Property page under ontology/vla/properties/ or ontology/core/properties/, which gives its datatype and whether it is required. A paper’s media is the sha256 of its PDF. The condition columns of a result, a model’s model_class, a link’s role, and a dataset’s collection, embodiments, tasks and modalities hold the IRIs of Term pages. The model and dataset columns hold the IRIs of rows. Every row’s IRI starts with https://data.aegean.ai/vla/<team>/, where <team> is the id you gave kdb lake init: your team id, or your own id if you work alone. Derive the rest of the IRI from what the row is, such as the arXiv id, the model’s name, or the paper, table, row and column of a result. Ingesting the same paper again then finds the same rows instead of making new ones.

Evidence

Each row cites its evidence in its evidence column, as a list of MediaRefs. A MediaRef names a registered file by its sha256 and points into it. A sentence gives the page, the bbox and the quote. A table value gives the page, the bbox and the value. A cell of a spreadsheet gives the sheet, the cell and the value. A bbox is [x0, y0, x1, y1] in PDF points, with the origin at the bottom-left corner of the page. That is the space PDF highlights use. Pages are counted from 1. Your agent highlights every quote and value in annotated/<arxiv-id>.pdf with kdb_tools.annotate.highlight, which keeps the highlights already in the file, including the ones okf-seed wrote. You then register the annotated copy with RegisterMedia, giving annotates the sha256 of the original paper. okf-ground looks for each highlight in the registered copies that annotate the cited PDF, and a highlight in any one of them passes. Register the copy again each time you add highlights.

Actions

Every change to the kDB and the lake is an action: a typed operation that checks its parameters before it changes anything, applies its edits as one transaction, and writes a row to the action log in the lake. You, your agent and the course tools all use the same actions. The type actions (ProposeClass, AddProperty, BindTable and the rest) change Class and Property pages. kdb lake init uses them to set up the VLA classes, and you do not need them otherwise. UpsertObjects takes a class IRI and a list of rows. An update is a patch: a column you leave out keeps its stored value, and a column you set to null is cleared. Call dry_run first. It changes nothing and returns the plan, with the rows it would insert and update. Then submit the plan. A submit fails, and changes nothing, when something the plan read has changed since the dry run. In Python:
ctx is the context the starter’s kdbagent.lake.open_context gives every command: the kDB, the lake, your team and who is acting. An action that would be refused raises kdb_tools.actions.Failed from dry_run or submit, and its messages list every reason. A page changed by hand fails okf-validate with action.unlogged, even when the change is only whitespace. That includes index.md and log.md. You never edit a page yourself. The actions that change pages keep the index and the log up to date.

Examples

The examples below are the params of real UpsertObjects actions, written as YAML. The quotes, values and bboxes are from the papers, and every row passes okf-validate and okf-ground. A paper is a row of its own, and so is a dataset. The sha256 is that of the arXiv version the library links. Before these rows were written, the three PDFs they cite were registered with RegisterMedia, the quotes and values were highlighted, and each annotated copy was registered.
A model is a row of models, and each dataset it was trained on is a row of trained_on with the role the dataset played and the sentence that says so. One action can write several rows of the same class.
A result states the conditions under which its number holds, as Term IRIs, and cites the table cell and the sentence that gives the number of trials. Table I of the OpenVLA-OFT paper has two rows labeled “OpenVLA-OFT (ours)”, one for each set of policy inputs, and 94.5 appears three times on its page. The bbox names the cell this result means.
Two numbers contest each other only when they were measured under the same conditions. A newer paper that reruns a model under perturbed camera views reports a different result under a different perturbation, in a row of its own.

The rules

  1. A quoted sentence must appear word for word on its cited page. When a sentence runs onto the next page, cite the part on each page as its own MediaRef. A quote must also stay within one column. Words taken from two columns are not a sentence of the paper. Every bbox must match a highlight in the registered annotated copy of that PDF.
  2. Each paper, model and dataset has exactly one row. List its other names under aliases. No two rows of papers, models and datasets may share a title or an alias, compared after normalizing, and the check runs across all three tables (project.entity). Give a paper its full title, so that it does not take the name of the model or dataset it presents. You lose points if you merge two different things into one row or leave one thing split across two rows. Benchmarks, suites and robots are Terms of the ontology, not rows.
  3. A result always states its conditions. A results row gives the task, the benchmark, the task suite and the embodiment, and the perturbation when there is one, each as the IRI of a Term of the robotics ontology or one that extends it (project.result, project.condition). It gives the number of trials. Many tables do not say how many trials stand behind a number. In that case, set trials_reported to false and leave trials empty rather than guess.
  4. A dataset lists in collection how its data was collected, as terms of the datasets ontology or one that extends it. Its embodiments, tasks and modalities, when given, are Term IRIs too (project.dataset). A model’s model_class, when given, is a Term IRI. Each trained_on row names a models row, a datasets row, a role term of the datasets family and at least one MediaRef (project.trained-on).
  5. A number you compute from other numbers, such as an average gain across benchmarks, is a computations row. Its code is a short Python script that reads only the values named in inputs, so anyone can run it again. Each input is <row IRI>#<column>, such as https://data.aegean.ai/vla/team-7/results/openvla-libero-long#value. okf-validate checks that inputs is not empty, that each named row exists in your lake, and that its table has the column (project.computation).
  6. When two papers disagree, keep both rows and both sources, and write a contested row. Its claim names the older statement as <row IRI>#evidence/<index>, where the index counts the entries of that row’s evidence list from 0. disputed_by lists the statements that dispute it in the same form, at least one, and never the claim itself. okf-validate checks that each named row exists and has that evidence entry (project.contested). Do not overwrite a claim.
  7. Every row IRI starts with your lake’s iri_base, and any class or property you add has an IRI under https://kdb.aegean.ai/vla/<team>/ (project.iri).
  8. Every change goes through an action. A page that no logged action wrote, or that differs from what the last action wrote, fails with action.unlogged.
  9. A Term page lives under ontology/<ontology>/ and has a pref_label. Its broader terms are in the same ontology or in one it extends. They must never loop back to it. Each ontology has a page, ontology/<ontology>/ontology.md, whose extends lists the ontologies it specializes. Ontologies never extend each other in a loop. No two terms share a label within an ontology and the ontologies it extends. Unrelated ontologies may share a label.

Found an error on this page? Report an issue.