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.6.tar.gz (493.0 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.6-py3-none-any.whl (483.1 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: koobi-0.0.6.tar.gz
  • Upload date:
  • Size: 493.0 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.6.tar.gz
Algorithm Hash digest
SHA256 912a9574122627d7f67871e5f10c27b20620aa20d41fae9a32172efd516a8311
MD5 8909713e5088beaa456ac538966261ea
BLAKE2b-256 2919ef369cd8d9aab2b61d3c4066eb741dcafbc5cee75816469e645f0bdc9edf

See more details on using hashes here.

File details

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

File metadata

  • Download URL: koobi-0.0.6-py3-none-any.whl
  • Upload date:
  • Size: 483.1 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.6-py3-none-any.whl
Algorithm Hash digest
SHA256 46dee8f5f2b9f4564b385725a09387b6640c8c51a66fbc2694057f5391a68933
MD5 b7cf9631f9166470926230c1dbf44a1b
BLAKE2b-256 8faff48bdd80366c1e41562cd036a8cbbfc15ba99c9c616289dbafdc87d315f2

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