# ExOKF

**The reference Elixir implementation of the [Open Knowledge Format (OKF)](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md).**

ExOKF provides standards-compliant parsing, validation with rich diagnostics, lossless reading and writing, link resolution, graph indexing, high-performance querying, and provenance-aware AI context assembly.

> Don't use this release (0.1.0) = I'm released it to hex.pm  to test it in a 3rd-party project

## Installation

```elixir
def deps do
  [
    {:ex_okf, "~> 0.1.0"}
  ]
end
```

## Quick start

```elixir
{:ok, bundle} = ExOKF.load("path/to/bundle")

{:ok, diags} = ExOKF.validate(bundle)
IO.puts(ExOKF.Diagnostics.format(diags))

concepts = ExOKF.query(bundle, type: "BigQuery Table", tag: "sales")

{:ok, ctx} = ExOKF.context(bundle, "tables/orders", depth: 2, token_budget: 4000)
IO.puts(ExOKF.Context.to_prompt(ctx))

:ok = ExOKF.write(bundle, "path/to/out")
```

## Mix tasks

```text
mix ex_okf.validate path/to/bundle
mix ex_okf.inspect  path/to/bundle
mix ex_okf.graph    path/to/bundle
mix ex_okf.context  path/to/bundle tables/orders
mix ex_okf.format   path/to/bundle --out path/to/normalized
```

## Architecture

| Module | Role |
|--------|------|
| `ExOKF.Parser` | Concurrent filesystem parser (`Task.async_stream`) |
| `ExOKF.Validator` | OKF §9 conformance with severity-ranked diagnostics |
| `ExOKF.Writer` | Lossless round-trip preserving unknown frontmatter |
| `ExOKF.Graph` | Link graph via `ExOKF.Graph.Backend` |
| `ExOKF.Graph.Adjacency` | Native adjacency backend (v0.1 default) |
| `ExOKF.Graph.GraphBLAS` | Sparse GraphBLAS backend (extension; full accel in v0.2) |
| `ExOKF.Query` | Filter concepts by type, tag, id, resource |
| `ExOKF.Context` | Provenance-aware context assembly for agents |

GraphBLAS, security masks, typed predicates, and ranking beyond the baseline scorer are **ExOKF extensions**, not part of the core OKF standard.

## OKF conformance

A bundle is conformant when:

1. Every non-reserved `.md` file has parseable YAML frontmatter
2. Every frontmatter block has a non-empty `type`
3. Reserved files (`index.md`, `log.md`) follow their defined structure

Broken links, missing recommended fields, and unknown keys are **warnings** — never rejection criteria.

## Roadmap

| Version | Focus |
|---------|-------|
| **v0.1** | Parser, validator, diagnostics, native graph, CLI, docs |
| **v0.2** | GraphBLAS backend, graph algorithms, benchmarks |
| **v0.3** | AI context engine, ranking, provenance, MCP |
| **v0.4** | Live watchers, incremental updates, Phoenix, hardening |

## Development

```bash
mix deps.get
mix test
mix format
mix credo --strict
mix coveralls
```

### Credo

Static analysis runs in strict mode against `lib/` (see `.credo.exs`).

```bash
mix credo --strict
mix lint   # format + compile --warnings-as-errors + credo --strict
```

### Coverage (ExCoveralls → Coveralls.io)

Minimum coverage is **95%** (`coveralls.json` / `mix.exs`).

```bash
# Terminal summary (fails below 95%)
mix coveralls

# Line-by-line detail for a file
mix coveralls.detail --filter lib/ex_okf/parser.ex

# HTML report → cover/excoveralls.html
mix coveralls.html

# Aliases
mix test.cover
mix test.cover.html
```

CI publishes coverage to [coveralls.io](https://coveralls.io) via `mix coveralls.github`.

**Required secret:** `COVERALLS_REPO_TOKEN`

1. Open [coveralls.io](https://coveralls.io) and add this GitHub repository
2. Copy the **repo token** from the Coveralls project settings
3. In GitHub → Settings → Secrets and variables → Actions, add `COVERALLS_REPO_TOKEN`

`GITHUB_TOKEN` is provided automatically by Actions and is also passed to ExCoveralls.

## CI / CD

| Workflow | Trigger | What it does |
|----------|---------|--------------|
| [CI](.github/workflows/ci.yml) | Push / PR to `main` | Credo, format, compile, tests + Coveralls.io publish, Hex dry-build, docs |
| [Release](.github/workflows/release.yml) | Tag `v*` (e.g. `v0.1.0`) | Credo + tests, then publishes package + docs to Hex.pm |

### Publishing to Hex.pm

1. Create an API key at [hex.pm/dashboard/keys](https://hex.pm/dashboard/keys) with **API write** permission.
2. In the GitHub repo, create an Environment named `hex` and add secret `HEX_API_KEY`.
3. Bump `@version` in `mix.exs` and update `CHANGELOG.md`.
4. Tag and push:

```bash
git tag v0.1.0
git push origin v0.1.0
```

The tag **must** match `mix.exs` (`v0.1.0` ↔ `0.1.0`). You can also run **Release** via Actions → workflow_dispatch (`dry_run` first).

## License

Apache-2.0
