Skip to main content

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.

A pack is a self-contained KhalOS app: a frontend React package plus an optional backend service, a manifest that declares both, and a Helm chart for shipping. In this walkthrough you’ll go from an empty directory to a running “Hello FDE” pack in under ten minutes.
This page is the fast path. For the full pack contract — every manifest field, every CI workflow, every deploy mode — follow the Next steps links at the bottom.

1. Scaffold with khal new

@khal-os/app-kit ships the public khal CLI. Install it from npmjs, verify the version/template bundle, then scaffold locally.
npm install --global @khal-os/app-kit@latest
khal --version
khal new --list
Use @khal-os/app-kit@next only when a release owner explicitly asks you to validate an unreleased CLI fix. Fresh FDE installs should use @latest.
For target login, install dry-runs, and CLI troubleshooting, see FDE CLI quickstart.
khal new app <name>
cd <name>
Replace <name> with your pack’s identifier — lowercase, hyphen-separated, and short. It becomes the Helm chart name, the manifest id, and the package name. khal new substitutes the token everywhere it appears in the bundled template.
Run khal new with no arguments to see the three available types and their one-line descriptions. Add --list to inspect the bundled template versions.

Flags you’ll reach for

FlagWhat it does
--forceOverwrite a non-empty target directory. Default behaviour aborts.
--from <git-url>Clone an unofficial template instead of using the bundled one. Prints an “unofficial template — not version-locked” warning to stderr.
--listPrint bundled template versions and exit.
The legacy GitHub-template path (using gh repo create against the deprecated pack-template repo) no longer applies. Existing packs scaffolded that way keep working unchanged — only new scaffolds should use khal new.

2. Edit the React component

The frontend lives in package/src/index.tsx and must default-export a React component. That’s the only contract — any hook, any styling, any UI library. Start with something that proves the full loop works:
package/src/index.tsx
import { useState } from 'react';

export default function Pack() {
  const [count, setCount] = useState(0);

  return (
    <div style={{ padding: 16, fontFamily: 'system-ui' }}>
      <h1>Hello FDE</h1>
      <p>You clicked {count} times.</p>
      <button onClick={() => setCount(c => c + 1)}>Click me</button>
    </div>
  );
}
The shell hosts your component inside a window. React state, effects, and context all work as you’d expect.

3. (Optional) edit the service

If your pack needs a backend — a long-running process, a NATS subscriber, a side-effectful endpoint — edit service/src/index.ts. The app template ships a Bun HTTP server with a sample NATS subscription. If your pack is frontend-only, delete the service/ directory and remove the backend block from khal-app.json. CI will skip the Docker build and Helm release automatically.
Authoring ≠ deployment. You declare what your pack needs in khal-app.json (permissions, service shape, env vars, requires.postgres, requires.nats.streams, requires.temporal.namespace). The platform provides the runtime — NATS connections, secrets, networking, provisioned resources. You never wire up infrastructure yourself.

4. Build and typecheck

bun install
bun run build
bun run typecheck
bun run build produces CJS + ESM bundles plus TypeScript declarations in package/dist/. bun run typecheck validates both the frontend package and the service (if present).
Terminal showing bun run build output with dist artifacts listed, followed by a green bun run typecheck summary.

5. Dry-run install before a target mutation

Before installing into any shared target, run the CLI preflight from the generated repo root:
khal install . --target dev --dry-run --json
The dry-run validates source shape, khal-app.json, env declarations, target resolution, and the command that would perform the real install. It performs no mutation. For remote app repos, use an explicit branch:
khal install <private-khal-gitea-repo-url> --branch dev --target dev --scope shared --dry-run --json

6. See it in the shell

You’ve got two paths to render your pack in a live shell:
Install your pack into a local KhalOS instance. The shell hot-reloads the frontend bundle whenever bun run build emits new output, so you can iterate on the component without re-installing.
The scaffolded pack running inside the KhalOS desktop shell — a titled window with Hello FDE and a click counter.
For the full CI-driven publish and install story — workflows, tags, rollout — see Publish your pack.

Next steps

Anatomy of a pack

A directory-level tour of every file khal new just generated and what it’s for at runtime.

Hooks reference

The @khal-os/sdk React hooks — how your component talks to the shell, NATS, and other packs.

Full-stack pack pattern

The end-to-end reference pattern for packs with both a frontend and a backend service.