Skip to main content
The fastest way to build a new pack is to read one that already works. Every pack below is a real, shipping pack in the khal-os org — with its actual khal-app.json manifest pasted inline so you can see the shape before you clone.

Reference map

PackShapeWhy you’d read it
pack-helloBundle (4 frontends + 1 service)Multi-app bundle pattern — several frontends under one manifest, sharing a backend.
pack-settingsFrontend-onlyuseKhalAuth, React state, no service. Canonical frontend-only shape.
pack-notesFrontend-only (public)Clean data-model example. Public repo — the best code you can read without access permissions.
pack-terminalFull-stack (PTY)useNats + Bun service + Dockerfile + helm/ chart. Canonical full-stack reference.
pack-filesFull-stack (filesystem)Sandboxed filesystem access + NATS bridge. Shows full permission surface.
pack-genieFull-stack + AIEmbedding agent features; uses the automagik genie toolchain inside a pack.
pack-nats-viewerDev toolIntrospecting NATS messages during development. Keep it installed in your dev instance — it earns its keep.

Real manifests, side by side

Every manifest below is verbatim from the pack repo as of this sprint. Compare how permissions, backend, env, and ports scale with the pack’s ambition.

pack-settings — frontend-only, minimal

No backend block. No ports. Reads user config via useKhalAuth() and writes UI preferences via NATS.
pack-settings/khal-app.json
{
  "$schema": "https://raw.githubusercontent.com/khal-os/app-kit/dev/packages/types/src/khal-app-schema.json",
  "id": "settings",
  "name": "Settings",
  "version": "1.0.0",
  "description": "Desktop settings — manage appearance, services, SSH keys, keyboard shortcuts, and system configuration.",
  "author": "Namastex",
  "permissions": ["nats:subscribe", "nats:publish", "system:clipboard"],
  "frontend": {
    "package": "@khal-os/pack-settings"
  }
}

pack-terminal — full-stack, single service

The canonical full-stack pattern. Frontend subscribes to PTY output; backend owns the PTY and publishes stdout over NATS.
pack-terminal/khal-app.json
{
  "$schema": "https://raw.githubusercontent.com/khal-os/app-kit/dev/packages/types/src/khal-app-schema.json",
  "id": "terminal",
  "name": "Terminal",
  "version": "1.0.0",
  "icon": "./package/src/assets/icon.svg",
  "description": "PTY terminal emulator for KhalOS with NATS-bridged stdin/stdout",
  "author": "KhalOS Core Team",
  "permissions": ["pty:spawn", "nats:publish", "nats:subscribe"],
  "frontend": {
    "package": "@khal-os/pack-terminal"
  },
  "backend": {
    "image": "ghcr.io/khal-os/pack-terminal-service",
    "helmChart": "oci://ghcr.io/khal-os/charts/pack-terminal",
    "env": {
      "KHAL_PTY_SHELL": "/bin/bash",
      "KHAL_NATS_URL": "nats://nats.khal-system.svc:4222"
    },
    "ports": [8002]
  }
}

pack-files — full-stack, filesystem permissions

Same shape as pack-terminal but a different permission surface (files:read, files:write) and a customer-scoped OCI registry (gru.ocir.io — this pack is deployed into a specific customer’s OCI tenancy).
pack-files/khal-app.json
{
  "$schema": "https://raw.githubusercontent.com/khal-os/app-kit/dev/packages/types/src/khal-app-schema.json",
  "id": "files",
  "name": "Files",
  "version": "1.0.0",
  "description": "File manager — browse, read, write, and watch filesystem operations over NATS.",
  "author": "Namastex",
  "permissions": ["files:read", "files:write", "nats:publish", "nats:subscribe"],
  "frontend": {
    "package": "@khal-os/pack-files"
  },
  "backend": {
    "image": "gru.ocir.io/grkjlq07pmjv/pack-files-service",
    "helmChart": "oci://gru.ocir.io/grkjlq07pmjv/charts/pack-files",
    "env": {
      "KHAL_FILES_ROOT": "/data",
      "KHAL_NATS_URL": "nats://nats.khal-os.svc.cluster.local:4222"
    },
    "ports": [8001]
  }
}

pack-hello — bundle (4 frontends + 1 shared service)

When you’re shipping a suite of related apps, declare them under a single apps[] array. One manifest, one publish, four windowed apps in the shell, sharing one backend.
pack-hello/khal-app.json
{
  "$schema": "https://raw.githubusercontent.com/khal-os/app-kit/dev/packages/types/src/khal-app-schema.json",
  "id": "hello",
  "name": "Hello Bundle",
  "version": "1.0.0",
  "description": "KhalOS Hello demo bundle — 4 frontend apps + voice engine",
  "author": "KhalOS Core Team",
  "permissions": [],
  "apps": [
    { "id": "hello-console",        "name": "Hello Console",        "frontend": { "package": "@khal-os/pack-hello-console" } },
    { "id": "hello-agent-manager",  "name": "Hello Agent Manager",  "frontend": { "package": "@khal-os/pack-hello-agent-manager" } },
    { "id": "hello-flow-designer",  "name": "Hello Flow Designer",  "frontend": { "package": "@khal-os/pack-hello-flow-designer" } },
    { "id": "hello-sac",            "name": "Hello SAC",            "frontend": { "package": "@khal-os/pack-hello-sac" } }
  ],
  "backend": {
    "image": "ghcr.io/khal-os/pack-hello-voice-engine",
    "helmChart": "oci://ghcr.io/khal-os/charts/pack-hello",
    "env": {
      "NATS_URL": "nats://nats.khal-system.svc:4222",
      "GEMINI_API_KEY": "",
      "HELLO_VOICE_PORT": "8000"
    }
  }
}
Note the empty GEMINI_API_KEY — customers fill that in at install time.

What the manifests teach you

Reading four real manifests side by side reveals the shape language:
WantLook atCopy this pattern
Minimal pack, no backendpack-settingspermissions + frontend.package — that’s it
Full-stack with one servicepack-terminalfrontend.package + backend.{image, helmChart, env, ports}
Permission-heavy packpack-filespermissions grows with what you touch (filesystem, PTY, network)
Customer-scoped registrypack-filesbackend.image can target any OCI registry, not just ghcr.io/khal-os/*
Multi-frontend suitepack-helloSwap frontend for apps[], keep a single shared backend

How to use these

1

Find the shape closest to what you need

Frontend-only with auth? pack-settings. Full-stack with a long-lived process? pack-terminal. Multi-app suite? pack-hello.
2

Read its `khal-app.json`

The manifest tells you what permissions, ports, env, and services the pack uses. Copy the shape, not the identifiers.
3

Read its `package/src/`

The frontend entry. See which SDK hooks it reaches for.
4

Read its `service/` (if full-stack)

The Bun entry. See how it subscribes, how it publishes, and how it handles the NATS connection.
5

Diff against `pack-template`

Anything in your pack that looks different from pack-template should be justified by your pack’s requirements. Drift from the template is a maintenance bill.
Reference packs evolve. The repo READMEs are the canonical state; this page is a map. If a reference pack’s README contradicts this page, trust the README.

What’s next

khal-app.json schema

Every field these manifests use, exhaustively.

Patterns: full-stack

The pattern writeup of pack-terminal’s shape.