// SPDX-License-Identifier: CC-BY-SA-4.0
// (PMPL-1.0-or-later preferred; MPL-2.0 required for Hex.pm)
// Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>

= k9_ex
:author: Jonathan D.A. Jewell
:revdate: 2026-03-17
:toc: preamble
:icons: font

K9 (Self-Validating Components) parser and renderer for
https://elixir-lang.org[Elixir]. Parse and render K9 component specifications
with idiomatic Elixir structs and pattern matching.

== What It Does

`k9_ex` provides a typed AST, parser, and renderer for the K9 format --
a security-tiered configuration language built on Nickel contracts. K9 files
embed pedigree metadata, security levels, build recipes, and validation
checksums directly in the document.

The library handles both K9 syntax variants:

* `.k9` -- YAML-like declarative syntax (Kennel level)
* `.k9.ncl` -- Nickel-based programmable syntax (Yard/Hunt level)

== Installation

Add `k9_ex` to your dependencies in `mix.exs`:

[source,elixir]
----
defp deps do
  [
    {:k9_ex, "~> 0.1.0"}
  ]
end
----

Then fetch:

[source,sh]
----
mix deps.get
----

Available on https://hex.pm/packages/k9_ex[Hex.pm].

== Usage

[source,elixir]
----
# Parse a K9 string into a Component struct
{:ok, component} = K9.parse("""
pedigree:
  name: hello-k9
  version: 1.0.0
  description: A greeting

security:
  level: kennel
""")

# Render the struct back to K9 format
output = K9.render(component)

# Work with security levels
{:ok, :kennel} = K9.Types.SecurityLevel.from_string("kennel")
K9.Types.SecurityLevel.to_string(:yard)  # => "yard"

# Compare security levels
K9.Types.SecurityLevel.compare(:kennel, :hunt)  # => :lt
----

== API Overview

=== Top-Level Module (`K9`)

`K9.parse(input) :: {:ok, Component.t()} | {:error, term()}`::
  Parse a K9 file string into a `Component` struct. Delegates to `K9.Parser`.

`K9.render(component) :: String.t()`::
  Render a `Component` struct back to K9 surface syntax. Delegates to `K9.Renderer`.

=== Modules

`K9.Types`::
  Core data structures. All types are Elixir structs with `@type` specs.

`K9.Parser`::
  Parser implementation. Accepts `.k9` and `.k9.ncl` content.

`K9.Renderer`::
  Renderer that produces K9 surface syntax from the struct AST.

=== Key Types

[cols="1,3"]
|===
| Module | Description

| `K9.Types.Component`
| Top-level struct. Fields: `pedigree`, `security`, `target`, `recipes`,
  `validation`, `content` (map), `tags` (list).

| `K9.Types.Pedigree`
| Identity metadata: `name`, `version`, `description`, `author`, `license`.

| `K9.Types.SecurityLevel`
| Trust tier: `:kennel`, `:yard`, or `:hunt`. Provides `from_string/1`,
  `to_string/1`, and `compare/2`.

| `K9.Types.SecurityPolicy`
| Security level plus permission flags: `allow_network`, `allow_fs_write`,
  `allow_subprocess`.

| `K9.Types.Target`
| Platform constraints: `os`, `is_edge`, `requires_podman`, `memory`.

| `K9.Types.Recipes`
| Lifecycle recipes: `install`, `validate`, `deploy`, `migrate`, plus
  `custom` map for additional recipes.

| `K9.Types.Validation`
| Self-validation block: `checksum`, `pedigree_version`, `hunt_authorized`.

| `K9.Types.Contract` / `K9.Types.ContractClause`
| Contractile system integration. Clause types: must, trust, dust, intend, k9.
|===

== Dependencies

* Elixir >= 1.14
* `ex_doc` (dev only) ~> 0.34

== Links

* https://hex.pm/packages/k9_ex[Hex.pm package]
* https://hexdocs.pm/k9_ex[HexDocs API reference]
* https://github.com/hyperpolymath/standards/tree/main/k9-svc/SPEC.adoc[K9 specification]

== Part of the K9 Ecosystem

This binding is part of the
https://github.com/hyperpolymath/standards/tree/main/k9-svc[K9 Self-Validating Components]
suite within the `standards` monorepo. See
link:../README.adoc[`bindings/README.adoc`] for the full feature matrix across
all five language bindings.
