🧪 killBottleneck is in public beta — cloud and self-host.🧪 killBottleneck is in beta.Beta on GitHub →
Skip to content

Configuration

Configuration lives in .env next to docker-compose.yml, with one exception: SMTP is set in the PocketBase admin UI, not in the file. The complete variable list with defaults is in Environment variables; this page covers the decisions rather than the table.

After any change:

bash
docker compose up -d --build

AI

AI is off by default and the app is fully usable that way. Switch it on with KB_AI_PROVIDER:

ProviderWhat it means
noneNo AI. Nothing ever leaves your server. This is the default.
ollamaYour own local model. Install Ollama, ollama pull gpt-oss:20b, then set KB_AI_URL=http://IP:11434 and KB_AI_MODEL=gpt-oss:20b. Everything stays inside your network. Basic prompts; voice transcription is not included.
apiA remote AI service compatible with the killBottleneck API — an address and token from your provider. No GPU of your own and no maintenance.
customYour own endpoint honouring the same API contract.
bash
KB_AI_PROVIDER=ollama
KB_AI_URL=http://192.168.1.10:11434
KB_AI_MODEL=gpt-oss:20b

Which model to pick

gpt-oss:20b is the verified one — killBottleneck is tested against it. Plan for what it needs:

Model size~14 GB
Sensible operationa GPU with 16 GB of memory or more
Answer timeseconds to tens of seconds (~23 s measured for suggesting questions)

We recommend only this one, because it is the only one we have tested. You are free to try another — Ollama offers plenty — but that is at your own risk. It is not about how "smart" the model is: killBottleneck needs a machine-readable answer (JSON), and smaller or so-called reasoning models sometimes return it truncated — the feature then silently does nothing.

Of the ones we measured, gemma3:12b (~8 GB) held up and is usable on a 12 GB card, just slower. Another model of the same size returned a broken answer on the harder task — which is why "at your own risk" is meant literally. The quickest way to check a new model is to try Suggest a plan from a goal: either a tree appears, or nothing happens.

Without a GPU the model runs on the CPU and answers take minutes; that is not enough to work with.

killBottleneck talks to Ollama directly (/api/chat) — nothing sits in between and nothing leaves your network.

Where your data goes

With any provider other than none, map data is sent to the endpoint you configured. With ollama pointing at a machine you own, that is still your network. With api or custom it is whatever you pointed it at. There is no third option hidden anywhere.

A separate model just for daily summaries

The one-line encouragement in My day is short formatted text — a smaller, faster model is plenty. KB_SUMMARY_PROVIDER / _URL / _MODEL / _TOKEN override the general AI config for that one job. Left empty, the general configuration is used.

The summary is generated in the morning at KB_SUMMARY_HOUR (default 6) only for accounts that signed in within KB_SUMMARY_ACTIVE_DAYS days (default 14, 0 = everyone); everyone else gets theirs when they open the app.

What the AI is not allowed to do

The AI never enumerates your task lists — those are computed from your data and clickable. Task names are sanitised before they enter the prompt. Turning AI off costs you exactly one line in My day; the panel itself keeps working.

Registration and the registration key

The first account to register becomes the administrator. After that, either people register themselves, or an administrator invites them from Administration.

Set KB_SETUP_CODE and every registration requires that key. Hand it to the people you want to let in. An invitation from an administrator does not need the key.

Reachable from the internet?

Set KB_SETUP_CODE before you expose the instance. Empty means open registration.

Sign in with Google

Optional — users then sign in with Google instead of e-mail and password.

  1. In the Google Cloud Console: APIs & ServicesCredentialsCreate credentialsOAuth client IDWeb application.
  2. Under Authorized redirect URIs add: https://YOUR-DOMAIN/api/oauth2-redirect
  3. Put the values in .env:
    bash
    KB_GOOGLE_CLIENT_ID=…apps.googleusercontent.com
    KB_GOOGLE_CLIENT_SECRET=
  4. docker compose up -d --build — the button appears by itself.

Empty variables = Google sign-in is off and the button is not shown.

E-mail (SMTP)

SMTP is configured in the PocketBase admin UI, not in .env:

http://SERVER-IP:8090/_/SettingsMail settings

The superuser account is created on first start; the link is in docker compose logs.

What changes if you skip SMTP

E-mail is off by default and the instance is fully usable that way. Only these differ:

With SMTPWithout SMTP
Inviting a membere-mailed with a linkthe admin is shown a temporary password to hand over
"Forgot your password?"self-service, link arrives by e-mailnot offered — the admin resets it (see below)
Reminders and daily digestdelivered per each person's preferencesin-app bell only

The password-reset link is hidden on purpose without SMTP: the server would confirm the request, no message would arrive, and the person would wait for mail that does not exist.

Forgotten password without SMTP

For a team member, the admin resets it: Organisation settings → key icon next to the person → confirm. A new temporary password appears to hand over; the old password stops working immediately and the person is signed out everywhere. They are told in the bell that someone reset it.

For the admin, nobody can do this — there is no one above them (and the app does not offer resetting your own password either). Here the two versions differ:

  • Hosted version (killbottleneck.com): e-mail always works, so the admin uses the normal "Forgot your password?" on the sign-in page. Nothing else to handle.
  • Your own server without SMTP: the route goes through the PocketBase console, which you have access to as the operator:
  1. http://SERVER-IP:8090/_/ → sign in as superuser
  2. users collection → find your account → Change password

No superuser yet? Create one on the server (service name comes from docker-compose.yml):

bash
docker compose exec killbottleneck /app/pocketbase superuser upsert you@example.com 'YourStrongPassword'

Watch out

The console on :8090/_/ runs over plain HTTP — open it only from your local network or through an SSH tunnel, never over the internet. A password typed on the command line also stays in your shell history and is briefly visible to other users of the server; change it in the console afterwards and delete the history entry.

Recommendation

Create a second account with the admin role and keep its password in a password manager. The PocketBase route works, but it is extra work in the middle of a day when nobody can sign in.

Notification e-mails are off by default and controlled by each user's preferences. If e-mails were already reaching your users before an upgrade and you want to keep them, KB_NOTIFY_EMAIL_DEFAULT=1.

Time zone and recurring templates

TZ applies to the whole instance, not per user. It decides which zone "every Monday" and "at 5 in the morning" are counted in. A team spread across zones gets the server's zone.

If the server was powered off during KB_AUTO_HOUR, recurring projects are created at the next later hour the same day — they are not silently skipped.

Attachment limits

KB_FILES_MB caps uploaded files across the whole instance:

  • empty — no limit; the self-hosting default, it is your disk
  • a number — cap in MB (5000 = 5 GB)
  • 0 — uploading disabled; attachments can still be added as links, which take no space and always point at the current version of the file

Why 0 is the default on our hosted version

It is not about saving disk space, it is deliberate: we do not store other people's files. They never enter our backups, they do not turn into "we process customer documents" in a contract, and they stay where they already are. On your own server it is your disk and your call.

Automations

Only relevant if you drive goals from an automation. KB_PUBLIC_URL is the address the agent should call back on — see Environment variables → Automations for why leaving it empty can make a remote agent call itself, and why KB_ALLOW_PRIVATE_WEBHOOKS is off by default.

Instance mode

Leave KB_HOSTED empty on your own server. It exists for instances that run at a provider alongside other customers, where the instance administrator must not be able to point the AI service into a private network and probe the neighbours.

fair-code — self-hosting and internal use are free, reselling as a hosted service is not.