Skip to content

FAQ & troubleshooting

Every answer below was hit by someone on the fleet. If your problem isn’t here, check the kaboum reference docs (04 API, 05 configuration, 08 operations) before anything else.

9.4.0 or newer. copier.yml pins _min_copier_version: "9.4.0" — the oldest version CI actually tests. The README’s “9.0.0+” table row is stale: 9.0.0 was claimed but never exercised, and it does not install on Python 3.12.

Terminal window
pip install "copier>=9.4.0" # or: pipx install copier / uv tool install copier

Why did my render include template edits that weren’t committed?

Section titled “Why did my render include template edits that weren’t committed?”

Because a dirty template checkout is rendered. When you generate from a local kaboum checkout with uncommitted changes, copier includes them automatically (DirtyLocalWarning: Dirty template changes included automatically) — even with --vcs-ref set. The render passes, but it proves nothing about what a clean checkout produces: CI, other kreators, and copier update only ever see what is committed.

Commit before you verify. Treat the dirty warning as a signal your green render proved less than you think.

Why is my fresh render missing the template’s newest changes?

Section titled “Why is my fresh render missing the template’s newest changes?”

Copier defaults to the latest git tag, not HEAD. A plain copier copy . ../my-actor from a kaboum checkout renders whatever the last release was. To test current template state:

Terminal window
copier copy . ../my-actor --vcs-ref=HEAD --data project_name=myactor --defaults

Or render a specific release: --vcs-ref=v1.7.2. Also generate from a git ref, not a local path, in real use — .copier-answers.yml then records _commit and copier update works later.

What are the .rej files copier update left behind?

Section titled “What are the .rej files copier update left behind?”

Update conflicts. Copier found a file you had customized (an extension point like src/agent/agent.py or orchestrator.py) whose template also changed, and it could not merge them. For each .rej:

  1. Open the rejected hunk and the target file side by side.
  2. Re-apply your customization by hand on top of the new template version — or consciously adopt the template’s version and re-port your change.
  3. Delete the .rej file once resolved.

Never leave .rej files in a commit — CI and reviewers treat them as an unfinished update. Expect conflicts exactly where you customized template-owned files; orchestrator.py is a documented extension point and will conflict on update no matter what.

src/kaoohi/config.json is derived, never hand-edited — emitted from your Pydantic Settings fields plus [tool.kaoohi] in pyproject.toml. The check fails when the committed file no longer matches what the emitter would produce (stale after a config.py edit, a pyproject change, or a partial hand-edit).

Fix: regenerate and commit the derived file.

Terminal window
make kaoohi-config # emit + freshness check
git add src/kaoohi/config.json

The same validation runs at image build — a malformed config fails the Docker build, so fix it locally first.

A tuning rule (A–G) failed my config check — what do they mean?

Section titled “A tuning rule (A–G) failed my config check — what do they mean?”

The emitter validates config.json against src/kaoohi/schema.json plus seven tuning rules:

Rule Meaning
A A required user-managed item cannot be hidden.
B A platform-managed visible item must carry a creator_value.
C fed_by_connector must reference a declared connector (e.g. integration_type=n8n declares n8n for you).
D A creator_value’s type must match the item’s type.
E Boolean items reject min/max/pattern/length/enum validation.
F creator_value and fed_by_connector are mutually exclusive.
G A type='secret' parameter must never carry a value.

The error message names the item and the rule — fix the annotation in config.py (or [tool.kaoohi]), never the emitted JSON.

Why does test_contract.py (topic-contract) fail?

Section titled “Why does test_contract.py (topic-contract) fail?”

The vendored topic-contract test dumps your actor’s OpenAPI and asserts the kaoohi-required surface. A hard failure means a required endpoint (/agent/invoke, /health, /ready, /metrics) is missing — usually because a router import or create_app() wiring broke, or because tests/topic-contract.schema.json (vendored by the template) was deleted. Missing recommended endpoints only warn. Restore the vendored schema with copier update, and re-check src/main.py router mounting.

Why does test_system_prompt.py fail after I edited the prompt?

Section titled “Why does test_system_prompt.py fail after I edited the prompt?”

Because it is designed to. Pinned phrases in tests/test_system_prompt.py lock the parts of the system prompt that must not drift (identity, boundaries, tone). If you intentionally changed the prompt, update the pinned phrases in the test — deliberately. Never edit the template-owned prompt sections to make a test pass; put your customization in the ROLE_PLAYBOOK section instead.

Why does test_capability_boundary.py fail with FORBIDDEN_VERBS?

Section titled “Why does test_capability_boundary.py fail with FORBIDDEN_VERBS?”

The test ships with FORBIDDEN_VERBS: tuple[str, ...] = () and refuses to pass while it is empty. Fill it with the verbs your actor must not carry (e.g. ("send", "sign", "pay", "bind") if those actions belong to a human). Empty means “no boundary declared”, which is a product decision the template refuses to make for you — edit it on purpose, not in passing.

Why does the Docker build fail around version / SETUPTOOLS_SCM?

Section titled “Why does the Docker build fail around version / SETUPTOOLS_SCM?”

Version comes from git tags via hatch-vcs, and Docker builds cannot read .git/. If the build cannot derive a version, pass it explicitly — the template Dockerfile already wires the arg:

Terminal window
docker build --build-arg BUILD_VERSION=v1.2.3 -t ghcr.io/allcare/myactor:v1.2.3 .

Untagged builds fall back to a dev version (0.0.1.devN+g<sha>). To release, tag the repo (git tag v1.2.3 && git push --tags) and rebuild — /health, /ready and /api/actor/metadata all report the version.

The actor won’t start: PostgreSQL connection refused

Section titled “The actor won’t start: PostgreSQL connection refused”

PostgreSQL is the only critical service — startup fails without it by design (conversations, messages, stats all live there). Check the connection settings (host/port/db/user env vars) and that PG is actually up (docker compose up -d postgres or your platform provision). Once the process is up, /health keeps returning 200 with status: degraded if Postgres drops, so Kubernetes restarts are controlled rather than a crash loop.

Redis or an integration is failing but the actor still runs — why?

Section titled “Redis or an integration is failing but the actor still runs — why?”

By design. Non-critical services — Redis (auth cache, reply queue), the auth layer, the domain client, MCP servers — log a warning and keep serving. Only PostgreSQL is allowed to prevent startup. So a warning in the logs is not a defect; it tells you which optional capability is degraded.

MCP_SERVERS_JSON must be valid JSON mapping each server to an object with transport, url, and optional headers:

{"my-server": {"transport": "streamable_http", "url": "http://mcp:3000/mcp", "headers": {}}}

At startup main.py builds a MultiServerMCPClient (langchain-mcp-adapters) from that env var and merges the tools with your domain tools. A typo in the JSON or the wrong transport key silently yields no tools — check startup logs for the MCP section, and validate the JSON before deploying.

Why was my domain_module rejected as reserved?

Section titled “Why was my domain_module rejected as reserved?”

The validator refuses mesh, agent, api, core, kaoohi, shared, integrations, middleware, models, storage — modules the template itself renders under src/. A domain package with one of those names would shadow template-owned code; mesh specifically made {{domain_module}}_tools.py.jinja and the mesh tools render to the same src/agent/tools/mesh_tools.py, which killed non-interactive renders. Pick another name (booking, email, pipeline, …).

The scheduler job refuses to start (JOB_IMPLEMENTED) — why?

Section titled “The scheduler job refuses to start (JOB_IMPLEMENTED) — why?”

You answered include_scheduler=true but left the stub job in place. The template deliberately refuses to boot an unimplemented job rather than run a no-op on a schedule. Implement the job in src/{domain_module}/jobs.py (replacing the JOB_IMPLEMENTED sentinel), or turn the scheduler off. Note: integration_type=n8n implies the scheduler for workflow sync regardless of this answer.

You can set pricing now (free / one_time / subscription + price) so the listing is ready — see ](en/feature-status/) for what is live.

Why can’t Kaoohi pull my image at registration?

Section titled “Why can’t Kaoohi pull my image at registration?”

The registration wizard reads config.json straight out of your image over the OCI Distribution API (default path /app/src/kaoohi/config.json), so the registry must be able to serve the pull:

  • The GHCR image must be publicly readable (or otherwise reachable by the platform) — a private image fails extraction.
  • The tag must exist — check you pushed the exact ref you entered (ghcr.io/allcare/myactor:v1.2.3, not just latest).
  • The image must be built with the kaboum template so the config is baked in at the expected path. If extraction fails with “Was the image built with the kaboum template?”, rebuild via the template Dockerfile and re-push.

Sources: kaboum facts pack (§1–§6, §12–§13) and kaboum CLAUDE.md / README.md gotchas, verified 2026-10-13.