Skip to content

Write a tested example

Goal: add a new example to Learn KAOS that runs with one command, stays offline, and is verified in CI — the contract every example here follows.

Put it in examples/<id>.py. Declare its dependencies inline so uv run resolves them with no virtualenv. End with asserts so the file is its own test.

If it calls an LLM, use FunctionClient for the offline path and gate the live path on KAOS_LEARN_LIVE — exactly like the canonical seam example:

examples/functionclient-chat.py
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.13"
# dependencies = ["kaos-llm-client>=0.1.9,<0.2"]
# ///
"""The offline LLM seam: a deterministic fake model via FunctionClient.
Every LLM example on this site runs for free in CI with no API key. The
trick is `FunctionClient` — a provider client that runs a Python callable
instead of making an HTTP request, while satisfying the *same* interface
as the real Anthropic / OpenAI / Google clients. So the same code path
(`client.chat(...)`) is exercised; only the model is faked.
By default this runs offline. Set `KAOS_LEARN_LIVE=1` (and an API key) to
hit a real provider instead — the rest of the program is identical.
Run it (offline, no key):
uv run examples/functionclient-chat.py
Run it live:
KAOS_LEARN_LIVE=1 ANTHROPIC_API_KEY=sk-... uv run examples/functionclient-chat.py
"""
from __future__ import annotations
import os
from kaos_llm_client.providers.function import FunctionClient
from kaos_llm_client.types import ContentPart, ProviderResponse
def fake_model(messages: list[dict], profile) -> ProviderResponse:
"""A deterministic 'model': echo the user's text back, uppercased.
A real provider would return a generated completion here; for tests we
return exactly what we want so assertions are stable.
"""
user_text = messages[-1]["content"]
return ProviderResponse(
provider="function",
model="function-test",
raw={},
parts=[ContentPart(type="text", text=f"FAKE MODEL SAYS: {user_text.upper()}")],
)
def make_client():
"""Offline by default; a real client when KAOS_LEARN_LIVE is set."""
if os.environ.get("KAOS_LEARN_LIVE"):
from kaos_llm_client import create_client
# Anthropic Haiku is the documented default for live examples.
return create_client("anthropic:claude-haiku-4-5")
return FunctionClient(function=fake_model)
def main() -> str:
client = make_client()
response = client.chat([{"role": "user", "content": "hello, kaos"}])
print(f"model said: {response.text!r}")
# The client records every call — handy for asserting what was sent.
if isinstance(client, FunctionClient):
print(f"calls recorded: {len(client.call_history)}")
return response.text
if __name__ == "__main__":
text = main()
if not os.environ.get("KAOS_LEARN_LIVE"):
# Offline path is fully deterministic.
assert text == "FAKE MODEL SAYS: HELLO, KAOS", text

Add one entry to examples/index.toml. This drives the gallery card, the kaos-learn launcher, and CI:

[[example]]
id = "my-example"
title = "My example"
summary = "One line describing what it shows."
packages = ["kaos-core"]
persona = "builder"
level = "intro"
offline_ok = true # true => runs in offline CI (no key)
needs_key = false
est_cost_usd = 0.0

In tests/test_examples.py, add the expected stdout substring so CI asserts the example produces the right output, not just a zero exit:

EXPECTED = {
# ...
"my-example": "the text it should print",
}

To show the code on a docs page, import the file with ?raw and render it — so what’s shown is exactly what’s tested:

import { Code } from '@astrojs/starlight/components';
import src from '#examples/my-example.py?raw';
<Code code={src} lang="python" title="examples/my-example.py" />
  • examples-smoke runs uv run on every examples/*.py.
  • snippets-test runs the pytest harness (exit code + your acceptance marker).
  • embed-check fails if a page ?raw-imports a file that doesn’t exist.
  • site-build builds the site (and validates internal links).

All offline — no API keys in CI. If your example needs a key, set needs_key = true and it’s skipped in offline CI and only run on the opt-in live path.