Personal-style data model description library
  • Rust 79.7%
  • TypeScript 20%
  • Shell 0.3%
Find a file
PerishFire 5be11b1629
All checks were successful
guard / guard (push) Successful in 1m16s
release: keel family 0.4.1 (#110)
2026-07-21 15:23:22 +00:00
.cargo release: publish the crate family through the perish registry (#56) 2026-07-16 10:52:25 +00:00
.forgejo/workflows guard: the gate is global, not pinned per repo (#107) 2026-07-21 12:11:24 +00:00
.runseal guard: the gate is global, not pinned per repo (#107) 2026-07-21 12:11:24 +00:00
crates wire: revive the connection between ops, so a dead pg is not forever (#108) 2026-07-21 14:17:31 +00:00
docs name: the tree keel already derives for authority now names things too (#109) 2026-07-21 15:16:16 +00:00
.gitignore repo: cold-start scaffold for PerishLab/keel 2026-07-14 12:28:16 +08:00
AGENTS.md name: the tree keel already derives for authority now names things too (#109) 2026-07-21 15:16:16 +00:00
Cargo.lock release: keel family 0.4.1 (#110) 2026-07-21 15:23:22 +00:00
Cargo.toml release: keel family 0.4.1 (#110) 2026-07-21 15:23:22 +00:00
docker-compose.yml conform: scaffold the postgres substrate and portability plan (#62) 2026-07-16 11:59:27 +00:00
keel.toml http: rest without joins and text query entry (#10) 2026-07-14 07:03:38 +00:00
LICENSE repo: cold-start scaffold for PerishLab/keel 2026-07-14 12:28:16 +08:00
negentropy.toml blob: ship presigned object storage where bytes never touch keel (#66) 2026-07-16 12:44:36 +00:00
README.md split: fan the engine into layered modules for v0.5.0 (C-19) (#83) 2026-07-20 07:26:05 +00:00
runseal.toml repo: cold-start scaffold for PerishLab/keel 2026-07-14 12:28:16 +08:00
sidecar.toml http: Core face, axum serve, and sidecar plan (#8) 2026-07-14 06:27:29 +00:00
vocabulary.toml vocabulary: register into_response as one atom (#103) 2026-07-21 07:17:03 +00:00

keel

Data model description engine. Business code defines resources, fields, and relations only. Control fields and control capabilities stay inside the engine. HTTP and store adaptors project the engine surface — they are not a business authoring API.

Canonical source: PerishLab/keel.

Cold start

use keel::adapt::db::Sqlite;
use keel::atom::string;
use keel::resource;
use keel::{Graph, bind};

#[resource]
struct Course {
    #[field(string)]
    code: string,
    #[field(string)]
    title: string,
}

#[resource]
struct Student {
    #[field(string)]
    no: string,
    #[field(string)]
    name: string,
    #[relation(Course, many2many)]
    courses: Course,
}

fn main() {
    let mut graph = Graph::new();
    graph.plug::<Course>().plug::<Student>();
    let core = bind(graph, Sqlite::memory()).expect("bind");
    let _id = core
        .put("Student", &[("no", "S01"), ("name", "ada")])
        .expect("put");
}

Engine face (Core)

Method Meaning
put / set / live / end insert, partial update, live list, soft-end
query / ask text → AST → run; ask takes Tree directly
AST from + where + link + order/page → always pack
tie / ties / cut many2many write on Core; read via link bond bags (H0)
edge law flat pack; root-only order/page — docs/model/edge.md
serve / listen axum (http feature)

HTTP surface

Native REST per resource (no association queries):

Method Path Engine
GET {prefix}/health liveness
GET {prefix}/{unit} live
GET {prefix}/{unit}/{id} one live row by id
POST {prefix}/{unit} put
PATCH {prefix}/{unit}/{id} set (partial body)
DELETE {prefix}/{unit}/{id} end
POST {prefix}/{unit}/{id}/{bond} tie body {"right": id}
DELETE {prefix}/{unit}/{id}/{bond}/{tie} cut
POST {prefix}/query body {"q":…} → always pack

listen.prefix in keel.toml is the api prefix (default empty).

Runtime config (keel.toml)

Repo-rooted, negentropy-style. Missing file uses the same defaults:

[listen]
host = "127.0.0.1"
port = 3000
prefix = ""
# prefix = "/api"

[store]
kind = "memory"
# kind = "file"
# path = ".local/keel.sqlite"

[cache]
kind = "memory"
# kind = "none"
let cfg = keel::config::load(".");
let store = cfg.open()?;
let core = bind(graph, store)?;
// listen(core.share(), &cfg.listen.host, cfg.listen.port).await?;

keel-api [ROOT] loads ROOT/keel.toml (default ROOT=.). CLI does not re-express policy keys — change the file.

Local process (sidecar)

# requires sidecar CLI installed
sidecar start --config sidecar.toml
# health: http://127.0.0.1:3000/health
sidecar stop --config sidecar.toml

keel-api is a demo binary (Student/Course selection + store/listen from keel.toml). forge is the staged scenario binary (docs/model/spec.md); keel-gate ships the default credential package (gate!(Actor) + wall).

Operating

runseal :init
runseal :guard    # unit tests + smoke + course + forge scenarios
runseal :smoke    # thin L2
runseal :course   # classic enroll/drop/schedule L2
runseal :forge    # forge slice act 1: data completeness L2
cargo run -p keel-api --locked

Scenario notes: docs/run/scenario.md.

Cold-start verification boundary: docs/run/verify.md.