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.
Which Copier version do I need?
Section titled “Which Copier version do I need?”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.
pip install "copier>=9.4.0" # or: pipx install copier / uv tool install copierWhy 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:
copier copy . ../my-actor --vcs-ref=HEAD --data project_name=myactor --defaultsOr 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:
- Open the rejected hunk and the target file side by side.
- 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.
- Delete the
.rejfile 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.
Why did make kaoohi-config-check fail?
Section titled “Why did make kaoohi-config-check fail?”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.
make kaoohi-config # emit + freshness checkgit add src/kaoohi/config.jsonThe 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:
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.
Why isn’t my MCP server loading?
Section titled “Why isn’t my MCP server loading?”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.
Why can’t anyone buy my paid actor?
Section titled “Why can’t anyone buy my paid actor?”You can set pricing now (free / one_time / subscription + price) so the listing is ready — see ](en/feature-status/) for what is live.
Where is my payout?
Section titled “Where is my payout?”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 justlatest). - 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.