kdb lake init and okf-seed:
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 itsevidence 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 theparams 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.
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.
bbox names the cell this result means.
perturbation, in a row of its own.
The rules
- 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. Everybboxmust match a highlight in the registered annotated copy of that PDF. - Each paper, model and dataset has exactly one row. List its other names under
aliases. No two rows ofpapers,modelsanddatasetsmay 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. - A result always states its conditions. A
resultsrow gives thetask, thebenchmark, the tasksuiteand theembodiment, and theperturbationwhen there is one, each as the IRI of a Term of theroboticsontology or one that extends it (project.result,project.condition). It gives the number oftrials. Many tables do not say how many trials stand behind a number. In that case, settrials_reportedto false and leavetrialsempty rather than guess. - A dataset lists in
collectionhow its data was collected, as terms of thedatasetsontology or one that extends it. Itsembodiments,tasksandmodalities, when given, are Term IRIs too (project.dataset). A model’smodel_class, when given, is a Term IRI. Eachtrained_onrow names amodelsrow, adatasetsrow, aroleterm of thedatasetsfamily and at least oneMediaRef(project.trained-on). - A number you compute from other numbers, such as an average gain across benchmarks, is a
computationsrow. Itscodeis a short Python script that reads only the values named ininputs, so anyone can run it again. Each input is<row IRI>#<column>, such ashttps://data.aegean.ai/vla/team-7/results/openvla-libero-long#value.okf-validatechecks thatinputsis not empty, that each named row exists in your lake, and that its table has the column (project.computation). - When two papers disagree, keep both rows and both sources, and write a
contestedrow. Itsclaimnames the older statement as<row IRI>#evidence/<index>, where the index counts the entries of that row’sevidencelist from 0.disputed_bylists the statements that dispute it in the same form, at least one, and never the claim itself.okf-validatechecks that each named row exists and has that evidence entry (project.contested). Do not overwrite a claim. - Every row IRI starts with your lake’s
iri_base, and any class or property you add has an IRI underhttps://kdb.aegean.ai/vla/<team>/(project.iri). - 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. - A
Termpage lives underontology/<ontology>/and has apref_label. Itsbroaderterms 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, whoseextendslists 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.

