Documentation Index
Fetch the complete documentation index at: https://docs.khal.ai/llms.txt
Use this file to discover all available pages before exploring further.
khal-app.json is the manifest every pack ships at its repo root. The platform reads it once at install time and from then on knows your pack’s identity, the permissions it requires, the frontend bundle to load, and the backend service (if any) to run. The schema is defined by @khal-os/types and validated with Zod, so mistakes are caught at build time rather than in production.
Required fields
Every pack manifest must declare these fields. The build will fail if any are missing or the wrong shape.| Field | Type | What it is |
|---|---|---|
id | string | Stable identifier — lowercase, hyphen-separated. Used for NATS subjects, install paths, and log lines. |
name | string | Human-readable name shown in the launcher and window title. |
version | string | Semantic version of the pack (1.0.0). Bumped on every release. |
icon | string | Relative path to the pack icon (SVG recommended). |
description | string | Short blurb shown in the launcher and the marketplace listing. |
author | string | The name or organization shipping the pack. |
permissions | string[] | The capabilities the pack needs (nats:publish, files:read, etc.). Declare the minimum — the platform enforces the list at runtime. |
Older manifests may include
frontend.package. New generated apps are git-native: the install source is the repo/ref plus khal-app.json, and the platform build/install path resolves the frontend bundle from the repo instead of an app npm package.Optional fields
These fields unlock additional pack shapes. You only declare what your pack needs.| Field | When to use it |
|---|---|
frontend | Legacy/shell frontend declaration. New app installs are git-native and should not require publishing an app npm package. |
services[] | Declare long-running processes your pack runs. Each entry names a process, its entry point, health check, and ports. |
windows[] | Default window sizes and titles for the shell. Override per-view dimensions here. |
backend | For packs that ship a container image — names the image, Helm chart, env vars, and ports. |
apps[] | For bundle packs that ship multiple frontend apps in one repo. Each entry has its own id, name, and frontend declaration. When present, the root frontend is ignored. |
sandbox | For packs that require a per-user container on install. Declares CPU, memory, and volume mounts. |
Worked examples
- Frontend-only
- Full-stack
A minimum viable manifest for a frontend-only app. No backend, no services, one frontend surface.Source: current
khal-app.json
khal new app scaffolds; exact optional fields may evolve with @khal-os/types.
Permissions: declare the minimum
permissions is where you tell the platform what your pack intends to do. The platform enforces the list at runtime — a pack without nats:publish cannot publish to NATS, period.
Principle of least privilege. Start with an empty
permissions array and add entries only when the build surfaces a denied capability. Packs that over-declare permissions are flagged in review.nats:publish, nats:subscribe, files:read, files:write, pty:spawn, http:fetch, system:clipboard, and system:notifications. The full list and the semantics of each lives in the khal-app.json schema reference.
Secrets: declare, don’t embed
Never put secrets directly inkhal-app.json. The manifest is committed to git and published as part of your pack. Instead, declare what your pack needs and let the platform provide the values at runtime — through the backend.env block (for non-sensitive config) or via the platform’s secret store (for credentials).
Validation
The toolchain validates your manifest on every build. If a required field is missing, a type is wrong, or a permission name is unrecognized, you’ll see a clear Zod error with the field path before the build proceeds. There’s no way to publish a pack with a malformed manifest.Next steps
Full schema reference
Every field, every type, every enum value — the exhaustive reference for writing non-trivial manifests.
Anatomy of a pack
Step back out to the directory-level view and see where the manifest sits relative to everything else.