Skip to main content

File-native model and experiment registry

Project description

Koobi project icon

Koobi

File-native model and experiment registry for local workflows.

Koobi stores experiment metadata as plain Markdown cards, builds a disposable DuckDB index, and serves an interactive Marimo UI for browsing, filtering, visualizing, and editing cards. The source of truth is always your files.

Why Koobi

Most experiment trackers assume a hosted service and database-backed runs. Koobi is designed for local-first users who want:

  • readable, versionable records in Git
  • zero-server operation
  • domain-agnostic metrics and parameters
  • workflows friendly to both humans and coding agents

Current MVP Capabilities

  • Markdown card parsing and serialization with preserved body/key ordering
  • additive card updates (only targeted fields are rewritten)
  • DuckDB index build with:
    • cards table (metadata + body)
    • measures table (long-format metrics)
    • series_registry table (series pointers)
  • Marimo app with:
    • project/status/search filters
    • model table view
    • card detail view (metrics/params/tags/body)
    • edit form (name/status/tags/body) with write-back
    • one measure bar chart
  • Execution model (Mode B) — optionally let Koobi run an experiment instead of just recording it:
    • one function registry with component / series / measure / items kinds; functions live in your package and self-register on import (never embedded in cards)
    • components declared as cards (a model, a framework) backed by registered functions, composed into a typed-port dataflow
    • koobi run <experiment> resolves the components, runs them in dependency order, computes the declared measures, persists a result series, and stamps provenance — writing the same card a human would have authored by hand
    • opt-in input-hash caching (off by default, so research runs always re-execute)
    • a finance pack providing Sharpe / Calmar / max-drawdown measures
  • CLI commands:
    • koobi init
    • koobi new
    • koobi index
    • koobi run
    • koobi ui

Architecture Overview

cards/*.md  -->  index.duckdb  -->  Marimo app
   ^                                  |
   |---------- edit/write-back -------|
  • Cards are authoritative.
  • Index is derived and disposable.
  • UI reads from index and writes edits back to cards.

Koobi works two ways over one data model: you can record results yourself (Mode A), or declare runnable components and let koobi run produce the card (Mode B). Either way the card is the contract; execution is just an optional producer of it. The engine stays domain-free — it wires named ports and runs functions; finance knowledge (the Sharpe formula, date slicing) lives only in packs and your own project code.

experiment card  -->  resolve components  -->  run in dependency order  -->  measures + series  -->  write card back  -->  reindex
   (model + framework, by typed ports)                                          (provenance stamped)

Installation

Install into any project or environment directly from Git:

pip install git+https://github.com/blu3c0ral/koobi.git

This installs the koobi command and the importable koobi package.

For local development on Koobi itself, install editable with dev extras:

python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[dev]"

Quickstart

Koobi discovers its configuration automatically: every command searches the current directory and its parents for a koobi.toml. Work from inside your workspace and no --config flag is needed.

1) Create (or enter) a workspace

koobi init --path my-registry
cd my-registry

Or use the bundled demo workspace:

python examples/local_example_to_cards.py --overwrite
cd examples/local

2) Build the index

koobi index

3) Launch the UI

koobi ui

The UI opens at http://localhost:2718.

Running from outside the workspace

If you prefer not to cd, point Koobi at the config explicitly or via an environment variable (precedence: --config > KOOBI_CONFIG > current dir):

koobi ui --config examples/local/koobi.toml
# or
export KOOBI_CONFIG=examples/local/koobi.toml
koobi ui

CLI Reference

Initialize a new workspace:

koobi init --path /path/to/workspace

Create a new card (run from inside the workspace):

koobi new demo_project.my_model

Rebuild index:

koobi index

Run an experiment (Mode B):

koobi run my_project.exp_001            # --force to ignore the cache
koobi run my_project.exp_001 --dry-run  # validate wiring only — runs nothing, pulls no data

run exits non-zero on a degraded run (a component raised, a port produced no output, or a declared measure didn't compute), printing the reasons to stderr — so a scheduled run can't mistake a silent partial failure for success. -v/-vv add per-node progress and (at -vv) tracebacks, and may go before or after the subcommand.

Run UI:

koobi ui

Running Experiments (Mode B)

An experiment is a composition of components — e.g. a model and an entry/exit framework. You declare each as a card backed by a registered function, then declare an experiment card that wires them together; koobi run executes the graph and fills in the results.

Point config at your function module and any datasets (a name → loader binding — the engine only sees the name; your loader gives it meaning):

# koobi.toml
[koobi]
function_modules = ["my_project.koobi_functions"]   # imported to register runners/measures
cache = false                                        # opt-in; default off

[datasets.prices]
loader = "my_project.koobi_functions:load_prices"
params = { universe = "16etf" }

[display]
packs = ["finance"]                                  # Sharpe / Calmar / max-drawdown

Register the functions in your own package (never code in cards):

# my_project/koobi_functions.py
from koobi import registry

@registry.component("my_project.model", produces="predictions")
def run_model(ctx):
    return predict(ctx.artifact("model"), ctx.data("prices"))   # resources pulled in

@registry.component("my_project.framework", needs=["predictions"], produces="equity_curve")
def run_framework(ctx):
    return backtest(ctx.get("predictions"), ctx.data("prices"), **ctx.params)

Declare the cards. needs/produces list ports only (the node-to-node dataflow); external inputs like prices are pulled via ctx.data, not wired as ports:

# model card — produces a "predictions" port
id: my_project.model
type: model
runner: my_project.model
produces: predictions
# framework card — consumes "predictions", produces "equity_curve"
id: my_project.framework
type: framework
runner: my_project.framework
needs: [predictions]
produces: equity_curve
# experiment card — composes the two by role and pins params
id: my_project.exp_001
type: experiment
components:
  model: my_project.model
  framework: my_project.framework
params: { entry_threshold: 0.025 }
measures: [sharpe, calmar, max_drawdown]

Then koobi run my_project.exp_001 writes metrics, a result series, and a provenance block back into the experiment card. See docs/backend_technical_design.md §16 for the full model.

Use as a Library

Koobi's core is importable, so other projects and coding agents can read, query, and write cards programmatically:

from koobi import load_config, build, connect, query_cards
from koobi import Card, load_card, save_card

# Resolve config by searching upward from a path (file or directory)
cfg = load_config("path/to/workspace")

# Build the disposable DuckDB index from the Markdown cards
build(cfg)

# Query cards joined with wide-format measures
con = connect(cfg)
df = query_cards(con, project="demo_project", status="candidate")

# Read, mutate, and write back a single card (only targeted fields change)
card = load_card("path/to/workspace/cards/demo_project.my_model.md")
card.status = "promoted"
save_card(card, fields=["status"])

The execution engine is importable too:

from koobi import load_config, bootstrap, resolve_card, run_experiment

cfg = load_config("path/to/workspace")
bootstrap(cfg)                                   # load packs + import function_modules
exp = resolve_card(cfg, "my_project.exp_001")
run_experiment(exp, cfg, ran_at="2026-06-26T00:00:00")   # writes results back to the card

The full public API is exported from the top-level koobi package; see koobi.__all__.

Repository Layout

src/koobi/                  # core package (schema, cards, config, index, charts, app, cli)
src/koobi/engine.py         # execution engine (run_experiment, Context, toposort)
src/koobi/registry.py       # component/series/measure function registry + bootstrap
src/koobi/packs/            # domain packs (finance: Sharpe/Calmar/max-drawdown)
tests/                      # unit tests
examples/local/             # self-contained demo workspace
examples/local_example_to_cards.py
docs/                       # product, technical, and future feature docs

Development

Run tests:

pytest

Recommended pre-PR checklist:

  • run pytest
  • regenerate local example cards if example inputs changed
  • verify koobi index and koobi ui against examples/local/koobi.toml

Documentation

Status

Phase 0 (the file-native registry) is built, reviewed, and stable. The §16 B1 execution slice — koobi run composing a model + framework experiment — is now implemented and tested. Next: card types (framework/strategy) as first-class declared types, then parameter sweeps and the measure-vs-parameter dashboards. See docs/status.md.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

koobi-0.0.5.tar.gz (485.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

koobi-0.0.5-py3-none-any.whl (474.7 kB view details)

Uploaded Python 3

File details

Details for the file koobi-0.0.5.tar.gz.

File metadata

  • Download URL: koobi-0.0.5.tar.gz
  • Upload date:
  • Size: 485.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.6

File hashes

Hashes for koobi-0.0.5.tar.gz
Algorithm Hash digest
SHA256 5a9bf5dff85a8b53e8a14f331ef944b6f4cc27a57b7d4ec5a5190de954634015
MD5 7923d7e6e96cb393e4449022c5135e1e
BLAKE2b-256 479ba8bec10d0f0e6ac06374829f9a843d8878f0add36c3a006cd582aad8ecec

See more details on using hashes here.

File details

Details for the file koobi-0.0.5-py3-none-any.whl.

File metadata

  • Download URL: koobi-0.0.5-py3-none-any.whl
  • Upload date:
  • Size: 474.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.6

File hashes

Hashes for koobi-0.0.5-py3-none-any.whl
Algorithm Hash digest
SHA256 b20678eb309168526ae17711f59c1e6d2829df7477e78e2c75c5a3665baef410
MD5 2dbb82147a49d968022ac4c8618dc70d
BLAKE2b-256 608a2bb0519315bef338dba5747482d2bbea4fa15fcf4e661994f0a367665c7f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page