// SPDX-License-Identifier: CC-BY-SA-4.0
// Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath)
= K9 SVC User Guide
:toc: left
:toclevels: 3
:icons: font
:source-highlighter: rouge
:imagesdir: assets

== Introduction

K9 SVC (Self-Validating Components) is a file format and tooling system for creating components that validate themselves. It uses the **must-just-nickel triad** architecture:

* **must** - POSIX shell shim for environment detection
* **just** - Task runner for orchestration (the Muscle)
* **nickel** - Typed configuration language for validation (the Brain)

image::triad-diagram.svg[The Must-Just-Nickel Triad,600]

=== Key Features

* **Self-describing** - Components declare their own requirements and capabilities
* **Type-safe** - Nickel contracts ensure configuration validity
* **Progressive trust** - The Leash security model (Kennel → Yard → Hunt)
* **Cryptographic verification** - Ed25519 signatures for Hunt-level execution
* **Cross-platform** - Runs on Linux, macOS, and POSIX systems

== Installation

=== Prerequisites

Install the triad tools:

[source,bash]
----
# Nickel (configuration language)
# See: https://nickel-lang.org/getting-started/
curl -L https://github.com/tweag/nickel/releases/latest/download/nickel-linux-x86_64 -o nickel
chmod +x nickel && sudo mv nickel /usr/local/bin/

# Just (task runner)
# See: https://just.systems/man/en/
cargo install just
# OR: brew install just (macOS)
# OR: pacman -S just (Arch Linux)
----

=== Quick Install

[source,bash]
----
# Clone the repository
git clone https://github.com/hyperpolymath/standards.git
# Note: K9-SVC is located in standards/k9-svc
cd k9-svc

# Check environment
./must status

# Run tests
./test.sh

# Install MIME types (user-level)
just setup-mime
----

=== Verify Installation

[source,bash]
----
# Check all dependencies
just check-deps

# Validate schemas
just typecheck

# Run full dogfood test
just dogfood
----

== The Leash Security Model

K9 uses a progressive trust model called "The Leash". Components declare their required trust level, and the system enforces boundaries.

image::leash-diagram.svg[The Leash Security Model,700]

=== Security Levels

[cols="1,2,3"]
|===
| Level | Capabilities | Use Case

| `'Kennel`
| Pure data only. No code execution.
| Static configuration, data files, templates

| `'Yard`
| Nickel evaluation (sandboxed). No I/O.
| Typed configs, validated settings, contracts

| `'Hunt`
| Full execution. Just recipes, network, filesystem.
| Deployments, installers, system modifications
|===

[WARNING]
====
**SECURITY NOTICE: Hunt-level components have full system access.**

Before running Hunt components:

1. **Verify digital signature** - Always check Ed25519 signatures
2. **Review Just recipes** - Audit all commands that will execute
3. **Use dry-run mode** - Preview actions before execution
4. **Run as non-root** - Never run as root unless absolutely required
5. **Sandbox when possible** - Use Docker/Firejail for external components

**See:** link:docs/SECURITY-BEST-PRACTICES.adoc[Security Best Practices] for detailed guidance.

**Current Security Status:** Hunt components are **development use only**. Production deployment requires Tier 1-3 security hardening (see link:docs/SECURITY-ROADMAP.adoc[Security Roadmap]).
====

=== Checking Security Level

[source,bash]
----
# Check a single component
just leash-level examples/deploy.k9.ncl

# List all example security levels
just leash-list
----

== Creating Components

=== Kennel Level (Pure Data)

The simplest component - just data with a magic number.

.examples/hello.k9
[source]
----
K9!
# This is a Kennel-level component
# Pure data, no execution

name = "hello-world"
version = "1.0.0"
message = "Hello from K9!"
----

=== Yard Level (Nickel Validation)

Components with typed contracts. Nickel evaluates them safely.

.examples/config.k9.ncl
[source,nickel]
----
let pedigree = import "../pedigree.ncl" in

let component_pedigree = {
  metadata = {
    name = "example-config",
    version = "1.0.0",
    breed = "application/vnd.k9+nickel",
    magic_number = "K9!",
  },
  security = {
    trust_level = 'Yard,  # <-- Yard level
    allow_network = false,
    allow_filesystem_write = false,
  },
  # ... rest of pedigree
} in

# Configuration with contracts
let config = {
  database | {
    host | String | default = "localhost",
    port | std.contract.from_predicate (fun p => p > 0 && p < 65536),
    name | String,
  } = {
    host = "db.example.com",
    port = 5432,
    name = "myapp",
  },
} in

{ pedigree = component_pedigree, config = config }
----

Validate with:

[source,bash]
----
nickel typecheck examples/config.k9.ncl
just show-config  # Export as JSON
----

=== Hunt Level (Full Execution)

[CAUTION]
====
**⚠️ DANGER ZONE: Hunt-level components have unrestricted system access.**

Hunt components can:

- Execute arbitrary shell commands
- Modify any file on the system
- Access network resources
- Install software packages
- Change system configuration

**REQUIRED before running Hunt components:**

1. ✅ **Signature verified** - `./must verify component.k9.ncl`
2. ✅ **Signing key trusted** - Verify fingerprint from 3+ independent sources
3. ✅ **Code reviewed** - Read every line of Just recipes
4. ✅ **Dry-run tested** - `./must --dry-run deploy component.k9.ncl`
5. ✅ **Running as non-root** - Unless absolutely required

**See:** link:docs/SECURITY-BEST-PRACTICES.adoc[Security Best Practices] - Security checklist for Hunt components.
====

Components that can execute recipes. **Requires cryptographic signature.**

.examples/deploy.k9.ncl
[source,nickel]
----
let pedigree = import "../pedigree.ncl" in

{
  metadata = {
    name = "deployment-component",
    version = "1.0.0",
  },
  security = {
    trust_level = 'Hunt,  # <-- Hunt level (DANGEROUS)
    allow_network = true,
    allow_filesystem_write = true,
    allow_subprocess = true,
  },
  validation = {
    hunt_authorized = true,  # Must be signed!
    signature = "YOUR_SIGNATURE_HERE",
  },
  recipes = {
    deploy = "podman run --rm k9-svc:latest",
    rollback = "echo 'Rolling back...'",
  },
}
----

== Signing and Verification

Hunt-level components must be cryptographically signed before execution.

image::signing-workflow.svg[Ed25519 Signing Workflow,800]

=== Generate Keys

[source,bash]
----
# Generate a keypair
just keygen alice

# Keys stored in:
#   ~/.config/k9/keys/alice.key (private - keep secret!)
#   ~/.config/k9/keys/alice.pub (public - share this)

# List all keys
just list-keys
----

=== Sign a Component

[source,bash]
----
# Sign with your key
just sign examples/deploy.k9.ncl alice

# Creates: examples/deploy.k9.ncl.sig
# Also outputs signature for embedding in pedigree
----

=== Trust a Public Key

Recipients must trust the signer's public key:

[source,bash]
----
# Add to trusted keys
just trust /path/to/alice.pub

# Trusted keys stored in:
#   ~/.config/k9/keys/trusted/
----

=== Verify Signature

[source,bash]
----
# Verify a component
just verify examples/deploy.k9.ncl
# Output: ✓ Signature VALID (key: alice)
----

=== Full Hunt Authorization

[source,bash]
----
# Check if component is authorized for execution
just authorize examples/deploy.k9.ncl
----

This checks:

1. Component declares `trust_level = 'Hunt`
2. Valid Ed25519 signature exists
3. Signature matches a trusted public key
4. `hunt_authorized = true` in pedigree

== MIME Type Setup

K9 registers a custom MIME type so file managers recognize `.k9` files.

=== Linux (Freedesktop)

[source,bash]
----
# User-level installation
just install-mime

# System-wide (requires sudo)
just install-mime-system

# Install magic file for file(1) command
just install-magic

# Verify
file examples/hello.k9
# Output: examples/hello.k9: K9 Self-Validating Component
----

=== macOS

[source,bash]
----
# Install UTI definition
just install-uti

# May require logout/login to take effect
----

== Container Deployment

K9 includes Podman/Docker support for containerized deployment.

=== Build Container

[source,bash]
----
# Build the container image
just build-container

# Run interactively
just run-container status

# Run dogfood test in container
just run-container dogfood
----

=== Docker Compose

[source,bash]
----
# Start development environment
podman-compose up -d

# Or with Docker
docker-compose up -d
----

== Justfile Reference

=== Environment

[source,bash]
----
just                  # Show status (default)
just status           # K9 environment report
just ensure           # Install missing tools
just check-deps       # Verify all dependencies
----

=== Validation

[source,bash]
----
just typecheck        # Typecheck all schemas
just validate FILE    # Validate a component
just validate-all     # Full validation suite
----

=== Security

[source,bash]
----
just leash-level FILE # Check security level
just leash-list       # List all example levels
just keygen NAME      # Generate keypair
just sign FILE NAME   # Sign component
just verify FILE      # Verify signature
just authorize FILE   # Full Hunt authorization
just trust PUBKEY     # Add trusted key
just list-keys        # Show all keys
----

=== MIME

[source,bash]
----
just install-mime     # User-level MIME
just install-magic    # Magic file for file(1)
just install-uti      # macOS UTI
just verify-mime      # Check registration
just setup-mime       # Full MIME setup
just uninstall-mime   # Remove MIME types
----

=== Container

[source,bash]
----
just build-container  # Build image
just run-container    # Run interactively
just deploy-podman    # Deploy via Podman
just deploy-native    # Deploy without container
just deploy           # Auto-select method
----

=== Development

[source,bash]
----
just fmt              # Format Nickel files
just repl             # Nickel REPL with pedigree
just export-schema    # Export pedigree as JSON
just export-leash     # Export leash levels as JSON
just docs             # Generate HTML docs
just test             # Run test suite
just test-quick       # Quick validation only
just dogfood          # Self-validation test
just clean            # Remove generated files
----

== Troubleshooting

=== "Nickel not found"

Install Nickel from https://nickel-lang.org/getting-started/

[source,bash]
----
# Check version
nickel --version
----

=== "Signature verification failed"

1. Ensure the signer's public key is trusted:
+
[source,bash]
----
just trust /path/to/signer.pub
just list-keys
----

2. Ensure the .sig file exists alongside the component

3. Check OpenSSL supports Ed25519:
+
[source,bash]
----
openssl genpkey -algorithm Ed25519 -out /dev/null
----

=== MIME type not recognized

[source,bash]
----
# Refresh MIME database
update-mime-database ~/.local/share/mime

# Check registration
xdg-mime query filetype examples/hello.k9
----

=== Container build fails

[source,bash]
----
# Ensure Podman is installed
podman --version

# Or use Docker
DOCKER_HOST=unix:///var/run/docker.sock just build-container
----

== Architecture Deep Dive

=== Pedigree Schema

Every K9 component has a **pedigree** - a self-description declaring:

* **metadata** - name, version, breed (MIME type), description
* **target** - OS, edge deployment, resource requirements
* **security** - trust level, allowed capabilities
* **validation** - checksum, signature, authorization status
* **recipes** - install, validate, deploy, migrate commands

See `pedigree.ncl` for the full schema with contracts.

=== File Extensions

[cols="1,2,2"]
|===
| Extension | Meaning | Security Level

| `.k9`
| Pure data component
| 'Kennel

| `.k9.ncl`
| Nickel component (needs evaluation)
| 'Yard or 'Hunt

| `.k9.ncl.sig`
| Detached signature
| (accompanies 'Hunt components)
|===

=== Key Storage

[source]
----
~/.config/k9/
├── keys/
│   ├── primary.key      # Your private key
│   ├── primary.pub      # Your public key
│   └── trusted/         # Trusted public keys
│       ├── alice.pub
│       └── bob.pub
----

== Container Deployment with k9-svc

This section covers how k9-svc wraps container deployments using the Leash
security model, selur-compose, and Nickel typed configuration.

=== When to Use k9-svc for Containers

k9-svc is designed for **operational deployment components** — things that
orchestrate, validate, and deploy container stacks. It is NOT a replacement
for `Cargo.toml`, `mix.exs`, or other build-time manifests.

Use k9-svc when you need:

* **Typed deployment configs** — Nickel contracts catch invalid port numbers,
  missing environment variables, and impossible resource limits at eval time,
  before any container starts.
* **Security-level enforcement** — The Leash system prevents accidental
  execution of destructive deployment recipes.
* **Signed deployment artifacts** — Ed25519 signatures ensure only authorized
  operators can run deployment scripts.
* **Self-validating components** — The dogfooding principle means each
  deployment component can validate its own configuration.

=== Security Level Selection Guide

Choosing the correct security level is the most important decision when
creating a k9 container deployment component.

[cols="1,2,3"]
|===
| Level | Use When | Container Example

| `'Kennel`
| The component is pure data with no execution.
| A static list of container image tags and their SHA256 digests. No commands, no evaluation. Just data.

| `'Yard`
| The component needs Nickel evaluation but performs no I/O.
| A typed configuration that validates port ranges, memory limits, and environment variable shapes. It produces validated JSON output but does not start any containers.

| `'Hunt`
| The component executes commands, accesses the network, or writes files.
| A deployment component that generates selur-compose files, pulls images, starts services, runs health checks, and performs rollback on failure.
|===

[IMPORTANT]
====
**Rule of thumb:** If your component runs `selur-compose`, `podman`, or any
shell command, it MUST be `'Hunt` level. If it only evaluates Nickel
expressions and produces output, use `'Yard`. If it is pure data (a list of
images, a set of environment variables), use `'Kennel`.

**Never use `'Hunt` for read-only operations.** If your component only reads
and displays data, `'Kennel` or `'Yard` is correct. Hunt requires
cryptographic signatures and should be reserved for components with real
side effects.
====

=== Example: Container Deployment as a Hunt Component

The `container-deploy.k9.ncl` example demonstrates a realistic multi-service
deployment component. It deploys an app + database + cache stack across
dev/staging/production environments.

[source,nickel]
----
# Security: Hunt level because this component:
# - Runs selur-compose commands (subprocess)
# - Pulls container images (network)
# - Writes deployment state files (filesystem)
security = {
  trust_level = 'Hunt,
  allow_network = true,
  allow_filesystem_write = true,
  allow_subprocess = true,
  signature = "REAL-ED25519-SIGNATURE-HERE",
},
----

Key features of this component:

* **Environment-specific overrides** — Dev (1 replica, debug logging),
  staging (2 replicas, info logging), production (3 replicas, warn logging).
  All validated by Nickel contracts.
* **Rolling deployment** — Replaces one replica at a time, waits for health
  checks, and automatically rolls back on failure.
* **Image signature verification** — Before deploying to staging or
  production, verifies that container images are signed with cerro-torre.
* **Self-validation** — The component typechecks itself before deployment.

See: `examples/container-deploy.k9.ncl` for the complete implementation.

=== Example: Config Validator as a Yard Component

Not every container-related component needs Hunt level. A configuration
validator that checks deployment configs without executing anything is a
perfect Yard-level component.

[source,nickel]
----
# Security: Yard level because this component:
# - Evaluates Nickel contracts (typed validation)
# - Produces validated JSON output
# - Does NOT execute commands, access network, or write files
security = {
  trust_level = 'Yard,
  allow_network = false,
  allow_filesystem_write = false,
  allow_subprocess = false,
},
----

This component can:

* Validate that container port mappings do not conflict
* Check that resource limits are within acceptable ranges
* Verify that environment variables match expected patterns
* Export validated config as JSON for consumption by other tools

See: `examples/config.k9.ncl` for a Yard-level configuration example.

=== How k9-svc Wraps selur-compose

The typical workflow for a k9-svc container deployment:

[source]
----
1. Author writes .k9.ncl with Nickel-typed service definitions
2. nickel typecheck validates the configuration (Yard-level eval)
3. nickel export generates selur-compose.toml from the typed config
4. The Hunt-level deploy script:
   a. Verifies component signature (Ed25519)
   b. Verifies container image signatures (cerro-torre)
   c. Runs selur-compose up with the generated config
   d. Monitors health checks
   e. Rolls back on failure
----

The key insight is that steps 1-3 are **Yard-level** operations — they only
evaluate Nickel expressions and produce data. Step 4 is a **Hunt-level**
operation that requires the cryptographic handshake. This separation means
you can validate configs without any security ceremony, but execution always
requires authorization.

=== Anti-Pattern Warnings

Before wrapping something in k9-svc, read link:examples/NOT-a-good-fit.adoc[NOT-a-good-fit.adoc].

Common mistakes:

* **Do NOT** wrap plain config files in k9 pedigree. A `config.toml` is
  already Kennel-level by nature. Adding pedigree overhead provides zero
  security benefit.
* **Do NOT** use k9-svc to manage library dependencies. Libraries are
  build-time artifacts, not deployment components. Use `Cargo.toml` or
  `mix.exs`.
* **Do NOT** use Hunt level for read-only operations. If your component
  only reads data, use Kennel or Yard.
* **Do NOT** wrap every directory in a2ml manifests. One at the repo root
  is sufficient for most projects.

See: link:examples/NOT-a-good-fit.adoc[Comparison, Deprecation Analysis, and Anti-Patterns]
for the full analysis.

== License

K9 SVC is licensed under PMPL-1.0-or-later. See LICENSE for details.
