{
  "markdown": "<p align=\"center\">\n  <img src=\"assets/znak-velky.webp\" alt=\"killBottleneck\" width=\"420\">\n</p>\n\n<h1 align=\"center\">killBottleneck</h1>\n\n<p align=\"center\">\n  <strong>English</strong> | <a href=\"./README.cs.md\">Čeština</a><br>\n  <a href=\"https://killbottleneck.com\">Website</a> ·\n  <a href=\"https://killbottleneck.com/guide/what-it-is\">Documentation</a> ·\n  <a href=\"./CHANGELOG.md\">Changelog</a> ·\n  <a href=\"#license--fair-code\">Licence</a>\n</p>\n\n> 🧪 **Public beta.** killBottleneck is feature-complete and in beta — the cloud\n> and the self-hosted version alike; it is one and the same app. What we are\n> testing here is the **self-hosted** side: installation, reverse proxies, your\n> own SMTP, upgrades. Install it (Quick start below), try to break it, and\n> tell us what happened: bugs → [Issues](../../issues), ideas → Discussions.\n> v1.0 ships when the beta goes quiet.\n\nA visual picture of your projects, your company and its processes — goal maps that people and AI agents work on together, **entirely on your own server: your data never leaves the company**. Open in the spirit of open source, just without the right to resell it as a hosted service — see [License](#license--fair-code).\n\n![The goal map editor](assets/mapa-en.jpg)\n\n**Nothing here phones home.** On a default install the server sends no request anywhere, and\nthe app loads nothing from a third-party CDN — fonts included, they are served from your own\ninstance. Everything that could leave your network is something **you** switch on:\n\n| Outbound request | When it happens | Turn it off |\n| --- | --- | --- |\n| GitHub Releases API | Version check, from the **user's browser** — not the server | `KB_UPDATE_CHECK=0` |\n| The AI endpoint you configured | Only with `KB_AI_PROVIDER` ≠ `none`; your own Ollama or any endpoint you choose | `KB_AI_PROVIDER=none` (default) |\n| Google (sign-in, Drive picker) | Only when you configure `KB_GOOGLE_*` | leave those empty (default) |\n\nThere is no telemetry, no analytics and no licence check.\n\n<details>\n<summary><strong>Contents</strong> — this README is the full reference; the short version is on <a href=\"https://killbottleneck.com/guide/quick-start\">the website</a>.</summary>\n\n- [Quick start](#quick-start)\n- [What it does without AI](#what-it-does-without-ai) · [On a phone](#on-a-phone)\n- [AI features (optional)](#ai-features-optional)\n- [AI assistant over MCP](#ai-assistant-over-mcp-claude-desktop-claude-code-)\n- [Who performs a step: a person, or an automation](#who-performs-a-step-a-person-or-an-automation) — includes the **webhook contract** for your own agents\n- [Moving a project elsewhere (JSON export/import)](#moving-a-project-elsewhere-json-export-and-import)\n- [Appearance (skins)](#appearance-skins) · [Notifications](#notifications) · [Time zone and recurring templates](#time-zone-and-recurring-templates)\n- [Data and backup](#data-and-backup) · [Team](#team) · [Registration and the registration key](#registration-and-the-registration-key)\n- [Sign in with Google](#sign-in-with-google-optional) · [Attachments](#attachments-on-goals-a-file-or-a-link) · [E-mail (SMTP)](#e-mail-smtp-optional)\n- [HTTPS (access from outside)](#https-access-from-outside) · [Updating](#updating)\n- [License — fair-code](#license--fair-code) · [Contact](#contact)\n\n</details>\n\n## Quick start\n\nAll you need is Docker. Then:\n\n```bash\ncp .env.example .env    # optional — the defaults are fine\ndocker compose up -d\n```\n\nkillBottleneck runs at `http://SERVER-IP:8090`. Colleagues on the local network just open it in a browser.\n\n**The first user to register automatically becomes the administrator.** Everyone else can\nregister themselves, or the administrator invites them from Administration (this creates an\naccount with a temporary password to hand over).\n\n## What it does without AI\n\nA full goal map editor (nodes, edges, statuses, notes), multiple maps per user, comments on\ngoals, sharing maps with colleagues (read / edit), public maps, export to image/PDF.\n\n![The \"My day\" panel](assets/muj-den-en.jpg)\n\n**The “My day” panel** (both the home page and the Tasks page): a clickable overview of\noverdue / today / within a week / blocking others, computed live from your data; name days\nnext to the date; a portrait PNG export for mobile — both full (with task names) and\n**anonymous** (names redacted, for social media). Over HTTPS you also get **Share…**\n(your phone's native Web Share dialog, no third-party service involved).\n\n**Time tracking**: a ⏱ timer in the top bar (one click starts an “empty” measurement — the\nproject/client/goal is assigned while it runs or afterwards), a timer on every task and every\ngoal in a map (measuring **never changes a status** — it is purely supplementary), a left-hand\n“Time tracking” panel with the records (from–to, retroactive assignment), a “Time worked”\ndialog in the user menu (today/this week, broken down by project and client), a **client**\nregistry (project→client, so time adds up per client too), and auto-stop for forgotten timers\nafter 12 h. **Inbox behaviour:** an unassigned measurement stopped with a note (e.g. “call with\nthe client”) also saves itself as an idea in your stash.\n\n### On a phone\n\n<img src=\"assets/lite-en.jpg\" alt=\"The simplified view on a phone\" width=\"300\" align=\"right\">\n\nThe same instance, opened on a phone, switches to a **simplified view**: today's tasks,\ntick them off, add one, and read messages — no map canvas to fight with on a small screen.\nYou can switch back to the full view at any time, and the app can be added to the home\nscreen (over HTTPS) so it behaves like a native one.\n\nMore in the [Simplified view guide](https://killbottleneck.com/features/lite-view).\n\n<br clear=\"right\">\n\n## AI features (optional)\n\n![Drafting a map with AI](assets/ai-navrhnout-en.jpg)\n\nThe AI advisor (draft a map from a goal, expand branches, chat about a map, AI project summary,\nsuggest tasks from a goal, a map from text/voice) is switched on in `.env` via `KB_AI_PROVIDER`:\n\n- `openai` — **any OpenAI-compatible API**: OpenAI, OpenRouter, Groq, Mistral, Together,\n  or your own vLLM / LM Studio / llama.cpp / liteLLM proxy. Set\n  `KB_AI_URL=https://openrouter.ai/api/v1` (the base address, usually ending in `/v1`),\n  `KB_AI_TOKEN=<your API key>` and `KB_AI_MODEL=<exact model name>`. Dictation works\n  through the same service; your provider bills you for the requests.\n- `api` — a remote AI service compatible with the killBottleneck API contract: enter the\n  address and token you got from your provider. No GPU of your own and no maintenance.\n- `ollama` — **your own local model**: install [Ollama](https://ollama.com), pull a model\n  (`ollama pull gpt-oss:20b`) and set\n  `KB_AI_URL=http://IP:11434` + `KB_AI_MODEL=gpt-oss:20b`.\n  Everything runs on your side, no data leaves your network. (Basic prompts; voice\n  transcription is not included.)\n- `custom` — your own endpoint honouring the same API contract\n  ([the contract is written down here](https://killbottleneck.com/reference/custom-ai-endpoint)).\n\nWhen AI is used, map data is sent to the endpoint you chose; with `none` (the default) nothing\never leaves your server.\n\n**Daily AI encouragement** (a line in the My day panel): 1–2 sentences prioritising “what\nblocks others → overdue → today”, with the occasional proverb. It is generated in the morning\nby a cron job (`KB_SUMMARY_HOUR`, default 6) only for accounts that signed in within the last\n`KB_SUMMARY_ACTIVE_DAYS` days (default 14, 0 = everyone); for the rest it is generated when\nthey open the app. Optionally a separate (smaller/faster) model just for the summaries:\n`KB_SUMMARY_PROVIDER/URL/MODEL/TOKEN` — without them the general AI configuration above is\nused. The panel works in full without AI, just without this one line. The AI never enumerates\ntask lists (those are computed from your data and clickable) and task names are sanitised\nbefore they go into the prompt.\n\n## AI assistant over MCP (Claude Desktop, Claude Code, …)\n\nkillBottleneck ships with a built-in **MCP server** (`mcp/`): connect your AI assistant to your\nown instance and maps get built conversationally — “make a map out of these meeting notes”,\nbulk edits, ticking off what's done. It works the same for self-hosted and hosted instances,\nonly the address differs.\n\n1. In the app: user menu → **API keys** → a new key with the **Read and write** scope\n   (**Read only** is enough for read access). The token is shown only once. Recommended: give\n   the key an expiry and revoke it once you stop using it.\n2. Nothing to install — the server is on npm as\n   [`killbottleneck-mcp`](https://www.npmjs.com/package/killbottleneck-mcp), so `npx` fetches\n   it on first use. (Prefer running it from this repository? `cd mcp && npm install` and use\n   `node /absolute/path/mcp/index.js` instead of the `npx` command below.)\n3. Register it with your assistant:\n\n   **Claude Code:**\n   ```bash\n   claude mcp add killbottleneck \\\n     -e KB_URL=http://SERVER-IP:8090 \\\n     -e KB_API_KEY=kb_user_... \\\n     -- npx -y killbottleneck-mcp\n   ```\n\n   **Claude Desktop** (`claude_desktop_config.json` → `mcpServers`):\n   ```json\n   {\n     \"mcpServers\": {\n       \"killbottleneck\": {\n         \"command\": \"npx\",\n         \"args\": [\"-y\", \"killbottleneck-mcp\"],\n         \"env\": {\n           \"KB_URL\": \"http://SERVER-IP:8090\",\n           \"KB_API_KEY\": \"kb_user_...\"\n         }\n       }\n     }\n   }\n   ```\n\nTools (17): `list_maps`, `get_map`, `create_map`, `add_nodes`, `update_node`, `delete_node`,\n`list_people`, `get_portfolio`, `get_org_structure` and the rule tools (`create_rule`, `list_rules`,\n`update_rule`, `delete_rule`, `list_rule_runs`, `list_rule_templates`, `save_rule_template`,\n`delete_rule_template`). A goal with an assignee or a deadline IS a task — there are no\nseparate task records. Assigning an `owner` through the API shares the map with that person as a\ncollaborator, so the work shows up in their My Day (the response lists who was shared with).\n\n**Remote, without anything local:** every instance also serves MCP directly at **`/mcp`**\n(Streamable HTTP, same keys, same tools) — `claude mcp add --transport http killbottleneck\nhttps://your-instance/mcp --header \"Authorization: Bearer kb_user_...\"`; the claude.ai connector\nsigns in through OAuth. Details: [MCP server](https://killbottleneck.com/reference/mcp).\n\n**Security:** a key acts as its owner — it sees and edits exactly what the owner can in the app,\nshared and team maps included (`edit`/own = full write; `work` and `read` = only the status of\nthe owner's own nodes, exactly like ticking off in the app); it never reads the account's role, so an admin's key cannot see\nanyone's private map, and someone else's public map is not reachable either (404). Administration,\nAI settings and users are never reachable. Writes can add/edit/delete goals and tasks; **a whole map cannot be deleted through the API**, and neither can the apex of\na map. Limits: 120 reads + 30 writes per minute per key, at most 200 nodes per call, at most 20\nkeys per account. Working alongside an open editor is handled by conflict detection (the editor\noffers to reload, the assistant reloads the map itself). Note: `add_nodes` re-runs the layout\nof the whole map. MCP tool output is in English (assistants always understand it); server error\nmessages arrive in the language of your account.\n\n## Who performs a step: a person, or an automation\n\nFor every goal in a map you can say whether a **person** or an **automation** does it. Whether\nthere is an AI agent or a scheduled cron job behind that automation is not your problem —\nwhoever builds it knows.\n\nImportant: **the responsible person for a goal is always a human.** Even for an automated step\nthere is someone accountable, who gets the notifications and whose “My day” the goal counts\ntowards. The automation does the work; a person is answerable for it.\n\nFor an automated step you also record **which automation does it** — this is a record of how\nthings are today (“n8n already does this step for us”), not a command. That is what makes it\nvisible at a glance which parts of the map are done by people and which by machines.\n\n### “I would like this automated”\n\nOn any goal you can tick **a request to have the step automated**, and optionally add a\nsentence explaining why. The request goes to the **AI agent manager** — a separate flag on a\nuser (User management → *AI manager*), independent of their role; both an administrator and an\nordinary member can hold it alongside their role.\n\nOnce the manager builds the automation and records it on the goal, **the request tidies itself\naway and the requester gets a message** that their goal is now automated. The full cycle:\n\n```\nperson: ☑ I would like this automated  (\"I upload subtitles by hand, 20 minutes\")\n   ↓\nthe AI manager gets a notification → decides → builds an n8n workflow\n   ↓\nthe manager records it on the goal: \"n8n — subtitle translation\"\n   ↓\nthe requester gets a notification: \"your goal is now automated by n8n — subtitle translation\"\n```\n\n### Attachments on a goal\n\nYou can upload files to any goal. On a goal with an automation, **uploading a file starts it\nright away** — instead of filling in a form somewhere else you simply attach whatever needs\nprocessing (typically subtitles, source material, an export).\n\nAttachments are visible only to people with access to the project. The files are protected: the\nlink alone gives nothing away.\n\n### AI agent registry\n\nThe AI agent manager (or an administrator) maintains a directory of automations under **AI\nagent registry**: name, webhook address, signing secret, enabled/disabled. On a goal the\nautomation is picked **by name** — team members never see the address or the secret. When the\nname on a goal matches an agent in the registry, killBottleneck can start it itself.\n\n**Who may start it.** Each agent can carry a list of allowed e-mail addresses. An empty list\nmeans the automation can be started by **anyone who can edit any map** — inside a company that\nis usually fine, but restrict it on an instance you let contractors into: whoever may edit a\nmap can otherwise start any of your n8n workflows and feed their own text into it (the goal's\ntitle and description go to the agent in the payload).\n\nAttachments are capped at 200 files per project, plus an optional space limit for the WHOLE\ninstance (`KB_FILES_MB` in MB; `0` = uploads disabled entirely, empty = no limit — set one on a\nshared disk so a hosted instance cannot fill it up). ⚠️ The former `FLOWMAP_MAP_FILES_MB` was a\nPER-PROJECT quota defaulting to 200 MB — if you have it set it still applies to you, but\nwithout it there is now NO space limit at all.\n\n### An automated run: killBottleneck → n8n → back\n\nAn automation starts when:\n\n- an **attachment is uploaded** to the goal, **or**\n- the goal's **turn comes** — it was waiting for its sub-goals and they have all just been\n  completed, **or**\n- somebody manually switches the goal to “in progress” (this is also how you **retry a failed\n  run**)\n\nA running automation will not be started a second time until it reports back or expires.\n\n**The outgoing request** (POST to the agent's address, with an `X-Signature` header =\nHMAC-SHA256 of the entire body using the agent's secret):\n\n```json\n{\n  \"run_id\": \"…\", \"run_token\": \"kbr_…\",\n  \"callback_url\": \"https://your-instance/api/kb/agent-callback\",\n  \"files_url\": \"https://your-instance/api/kb/agent-files?run_token=kbr_…\",\n  \"files\": [{ \"id\": \"…\", \"name\": \"subtitles.sbv\", \"size\": 1234, \"url\": \"https://…?run_token=kbr_…\" }],\n  \"map_id\": \"…\", \"map_title\": \"…\",\n  \"node_id\": \"…\", \"node_title\": \"…\",\n  \"description\": \"…\", \"deadline\": \"2026-08-01\",\n  \"owner\": \"responsible@company.com\", \"triggered_by\": \"who@company.com\"\n}\n```\n\nThe agent downloads files using its run token; `files_url` is a **live listing**, so it also\nsees attachments added while it is running. The token expires once the result is reported.\n\n**Reporting back** (POST to `callback_url`, no login — the run token authenticates it):\n\n```json\n{ \"run_id\": \"…\", \"run_token\": \"kbr_…\", \"status\": \"done\", \"result\": \"Translated into 3 languages\" }\n```\n\n`status` is `done` or `failed`. A token is valid **for one goal and one report** — a second\ncall with the same token will not go through.\n\nAfter `done` the goal is **completed**, and that sets the rest of the process in motion: the\nfollowing goal is unblocked and the person responsible for it is notified that they can start.\nIf that following goal is automated as well, it starts straight away — so the steps chain\nthemselves.\n\n**Set the address the agent should call back on.** `callback_url` is assembled by the server,\nnot the browser — without configuration it uses PocketBase's “Application URL”, which after\ninstallation is `http://localhost:8090`. An agent running on another machine would therefore\ncall itself, and the run would hang until it timed out. In `.env`:\n\n```env\nKB_PUBLIC_URL=https://killbottleneck.yourcompany.com\nKB_AGENT_TIMEOUT_MIN=90\n```\n\nAny address the agent can reach will do — on a self-hosted setup `http://192.168.1.10:8090` on\nthe LAN is perfectly fine. Hosted instances (killBottleneck Cloud) have this set automatically.\n\n**Is your n8n on the same network?** The webhook address is called by the server, which makes\nit a classic internal-network scanning vector — so by default killBottleneck **refuses to call\nprivate addresses** (`10.x`, `192.168.x`, `172.16–31.x`, `localhost`, cloud metadata). On a\nself-hosted setup where n8n runs next to killBottleneck, allow it:\n\n```env\nKB_ALLOW_PRIVATE_WEBHOOKS=1\n```\n\nWithout this the run is marked failed and the AI agent manager gets a message explaining why.\n**An agent must have its secret filled in** — without one the request would be signed with an\nempty key and the recipient would have no protection whatsoever, so killBottleneck rejects such\na run outright. The currently effective address is always shown at the bottom of the **AI agent\nregistry**, which warns you when it points at localhost. **This only concerns automations** — if\nyou do not use them, you do not need to set this variable.\n\n### When an automation does not finish\n\nThe state of a run is visible **right in the goal's dialog** — pending / running / done /\nfailed, with the reason on failure. A run is restarted by switching the goal back to “In\nprogress”.\n\nWhat each state means:\n\n| State | What is happening |\n|---|---|\n| pending | the run is queued and goes out within a minute (a single map save sends at most a handful of webhooks, so nobody is left waiting) |\n| running | the agent has picked up the work and has not reported back yet |\n| done / failed | the agent reported a result, or the run expired |\n\nA run that does not report back within `KB_AGENT_TIMEOUT_MIN` (default 90) minutes is marked\nfailed by a watchdog, which notifies both the responsible person and the AI agent managers — so\na goal never hangs silently.\n\nThe most common causes of failure: the agent is not in the registry or is disabled; it has no\nsecret; its address points into a private network and `KB_ALLOW_PRIVATE_WEBHOOKS=1` is missing;\nor the webhook is unreachable. The details (including connection errors) are in the server log —\n`docker compose logs killbottleneck` — they are deliberately not surfaced in the app.\n\n## Moving a project elsewhere (JSON export and import)\n\nA project can be exported to a `.json` file and imported somewhere else — between colleagues\nand between instances. In the editor: **Export → Export JSON**, choosing **with names** or\n**without names**. Import lives in the menu next to the “New project” button.\n\nWhat the file contains: the title, the description, the whole goal structure (including\nstatuses, deadlines, who performs each step and automation requests) and the tasks attached to\nit. The “without names” option clears both the responsible people and the assignees — the names\nof automations stay, since they describe the process.\n\n**Switching from Asana or Trello:** the same import also accepts an **Asana project export\n(CSV)** and a **Trello board export (JSON)**. Sections/lists become map branches, tasks/cards\nbecome goals, subtasks and checklists become child goals; statuses (done), due dates,\ndescriptions and — for Asana — assignees carry over (e-mails unknown to this instance are\ncleared and counted). Everything is converted locally in the browser — nothing calls Asana or\nTrello. Limit: 400 items per file.\n\nWhat is **not** transferred: attachments, comments, sharing, archiving and numbering series. An\nimport always creates a **new** project owned by whoever imports it, regenerates the goal\nidentifiers (so it does not collide with the original) and **shares nothing with anybody and\nsends no notifications** — you have to share the project manually to collaborate on it.\nAssignments to e-mail addresses that do not exist on this instance are dropped, and the import\ntells you how many.\n\n## Appearance (skins)\n\n![Choosing a skin](assets/skiny-dialog-en.jpg)\n\nIn the avatar menu → **Appearance** everyone picks a skin: Indigo (default),\nHigh contrast, Terminal or Paper. The choice is saved to the account, so it\napplies on every device, in both light and dark mode, and in the simplified\nlite view too (the picker there sits in the footer).\n\n**Custom skins:** a skin is a small JSON file (`kb-skin` v1 format) — a set of\ncolors (HSL), fonts and corner radius. The Appearance dialog can **export** the\ncurrent skin (for a built-in, its definition — \"take it and tweak it\") and\n**import** someone else's, from a file or by pasting. By design it is **not**\narbitrary CSS: values pass a whitelist on both the client and the server, so a\nshared skin cannot run or send anything. No web fonts are ever downloaded —\nonly fonts bundled with the app and system fonts are used; an unknown font\nharmlessly falls back to the next one in the stack.\n\n**Company look:** an administrator sets the instance-wide default skin in the\norganization admin — it applies to everyone who has not picked their own,\nincluding the login screen. A user's own choice always takes precedence.\n\nWhat a skin does **not** change in v1 (by design): status colors (red/amber/green\n= overdue/in progress/done stay readable everywhere the same). **Map export\n(PNG/PDF) is true to the screen** — captured in the active skin and light/dark\nmode, including the background color; only the backdrop artwork is left out.\nThe project dashboard PDF and the \"My day\" image deliberately stay light so\nthey can be sent to anyone.\n\nCommunity skins and the **open source skin editor**:\n<https://github.com/tengolabs/killbottleneck-skins> — skins are free data (CC0), the\neditor is MIT. Try the editor right in your browser, nothing to install:\n<https://tengolabs.github.io/killbottleneck-skins/>.\n\n## Notifications\n\nThe bell in the header shows the last 20 events; the full list with filters and paging is at\n`/notifications`. That is also where **notification settings** live, so everyone can switch\nindividual types on or off.\n\nNotifications are sent for: a task or a goal being assigned to you (including in a map that\nalready exists), a comment on a task or a goal, a project being shared with you, a waiting goal\nbeing unblocked, an approaching or missed deadline (one digest per day, not one per item), an\nautomation request and its fulfilment, an automation finishing or failing, and a timer being\nstopped automatically.\n\nDeadline reminders are sent in the morning; set the hour with `KB_DEADLINE_HOUR` (default 7,\nthe container's local time). Notifications you have read are cleaned up after 30 days.\n\nThe e-mail channel is ready but only switches on once SMTP is configured (see below) — until\nthen it is greyed out in the settings.\n\n## Time zone and recurring templates\n\nA template can be set up so that a project is created from it **automatically** (e.g. “every\nMonday” or “on the Nth day of the month”). For “Monday” and the time of creation to match your\nlocal time, set this in `.env`:\n\n```bash\nTZ=Europe/Prague     # your time zone (empty = UTC)\nKB_AUTO_HOUR=5  # the hour (0–23) from which projects are created on a given day\n```\n\n- If the server slept through that hour (it was switched off), the project is created at the\n  next later hour of the same day — it is not skipped.\n- The zone applies **to the whole instance** — for a team spread across zones the server's zone\n  is used, not each user's.\n- Recurring **tasks** (moving the deadline on completion) deliberately compute in UTC, so\n  crossing midnight or a daylight-saving change does not shift them by a day.\n\n## Data and backup\n\nAll data lives in the `./pb_data` folder (SQLite + uploaded files). Use the bundled script to\nback it up:\n\n```bash\n./backup.sh                 # creates kb-backup-YYYY-MM-DD.tgz\n./backup.sh restore FILE    # restores data from a backup\n```\n\n(By hand: to back up, copy the `pb_data` folder; to restore, put it back.)\n\nBackups can be encrypted: set `KB_BACKUP_PASSPHRASE` and the script writes\n`kb-backup-….tgz.gpg` (GPG, AES-256). `restore` accepts encrypted as well as\nolder plain archives. Keep the passphrase off the server — without it nobody\ncan read the backup.\n\n## Taking all your data with you\n\n**My account** has **Download all my data**: one JSON file (`killbottleneck.export/1`) with every\nproject you can see — each in the same shape as a single map export, so it imports elsewhere —\nplus tasks, rules, comments, change log, attachment list, idea stash, time entries, external\ncontacts and notifications. It works even after a trial has expired, and **Upload data from an export** brings the projects (with rules) and the idea stash back into another instance. Self-hosters additionally\nhave `./backup.sh`, which backs up the whole `pb_data` folder including uploaded files.\n\n## Team\n\nOne instance = one team. Roles: **Administrator** (manages users and roles, organization\nsettings — name and logo), **Manager** (invites members, sees and manages all tasks), **Member**\n(their own tasks and shared maps). Administrators and managers also get **Organization** in the\ntop bar — the view from above across team and shared projects (private projects are never counted). You can invite people from Administration or straight from\nthe Tasks page.\n\n## Registration and the registration key\n\nThe first account to register becomes the **administrator**. If the instance is reachable from\nthe internet, set `KB_SETUP_CODE` in `.env` — every registration then requires that key, so not\njust anyone who knows the address can create an account. Hand the key out to the people you\nwant to let in; on top of that an administrator can invite users directly (an invitation does\nnot need the key). Empty = registration without a key.\n\n## Sign in with Google (optional)\n\nUsers can sign in with Google instead of e-mail and password. To set it up:\n\n1. In the [Google Cloud Console](https://console.cloud.google.com/) go to **APIs & Services**\n   → **Credentials** → **Create credentials** → **OAuth client ID** → type **Web application**.\n2. Under **Authorized redirect URIs** add: `https://YOUR-DOMAIN/api/oauth2-redirect`\n3. Copy the **Client ID** and **Client secret** into `.env`:\n   ```\n   KB_GOOGLE_CLIENT_ID=…apps.googleusercontent.com\n   KB_GOOGLE_CLIENT_SECRET=…\n   ```\n4. `docker compose up -d` — the “Sign in with Google” button appears by itself.\n\nEmpty variables = Google sign-in is off (the button is not shown). On an instance with a\n**registration key**, Google sign-in is only for existing users — a new account cannot be\ncreated through Google (there is no way to enter the key), so the account has to be created\nwith the key first.\n\n## Attachments on goals: a file, or a link\n\nYou can pin either an **uploaded file** or a **link** (Drive, OneDrive, SharePoint, a specific\ne-mail, anything on `https://`) to any goal. A link has three advantages: it takes up no space,\nthe team always opens **the current version**, and the file stays where you keep it.\n\nHow much space uploaded files may take is governed by `KB_FILES_MB` — it applies to the **whole\ninstance**, not per project:\n\n| Value | Behaviour |\n|---|---|\n| empty | no limit (the default for self-hosting — it is your disk) |\n| a number | the cap in MB, e.g. `5000` = 5 GB |\n| `0` | uploads disabled, attachments as links only |\n\nHosted instances run with `0`: that way the provider does not hold your documents, only links\nto them. A link has to start with `http://` or `https://` — a network drive path\n(`\\\\server\\folder`) will not open from a browser for security reasons, so that belongs in the\ndescription.\n\n## E-mail (SMTP, optional)\n\nSMTP is configured in the PocketBase admin UI: `http://SERVER-IP:8090/_/` → Settings → Mail\nsettings (the superuser account is created on first start — you will find the link in\n`docker compose logs`). With SMTP configured:\n\n- an invitation to a new user is sent by e-mail (with a link to set a password) — without SMTP\n  the administrator is shown a temporary password to hand over manually,\n- self-service password reset works.\n\n## HTTPS (access from outside)\n\nkillBottleneck itself runs over HTTP — to reach it from outside your LAN, use a VPN or a reverse\nproxy. An example with [Caddy](https://caddyserver.com) (automatic HTTPS certificates):\n\n```\n# Caddyfile\nkillbottleneck.your-domain.com {\n    reverse_proxy 127.0.0.1:8090\n}\n```\n\nAdd it to compose through `docker-compose.override.yml` (that file is not overwritten by\nupdates):\n\n```yaml\nservices:\n  caddy:\n    image: caddy:2\n    ports: [\"80:80\", \"443:443\"]\n    volumes:\n      - ./Caddyfile:/etc/caddy/Caddyfile\n      - caddy_data:/data\nvolumes:\n  caddy_data:\n```\n\nHTTPS additionally unlocks **Share…** for the “My day” image (the Web Share API — your phone's\nnative share dialog, no third-party service) and **adding the app to your phone's home screen**\n(a service worker only runs in a secure context). Browsers do not allow either of these over\nplain HTTP; on an HTTPS domain they appear by themselves, with no configuration.\n\n### Turn on compression in your proxy — it is a threefold saving\n\nkillBottleneck does not compress responses itself (there is no way to enable it safely in\nPocketBase without breaking how the API behaves when it rejects an oversized body). The main\nfrontend file is **488 kB uncompressed and 157 kB gzipped** — on mobile data that is the\ndifference you notice most when opening it for the first time. One line is enough:\n\n```\n# Caddyfile\nkillbottleneck.your-domain.com {\n    encode gzip zstd\n    reverse_proxy 127.0.0.1:8090\n}\n```\n\n(In nginx: `gzip on; gzip_types application/javascript text/css;`. Behind Cloudflare or a\nsimilar service it happens on its own — there is nothing to configure.)\n\n## Updating\n\n```bash\ngit pull            # or download the new version\ndocker compose up -d --build\n```\n\nDatabase migrations run automatically on start. Before a bigger update it is worth taking a\nbackup (`./backup.sh`).\n\n> Always with `--build`: the app and its server-side logic are baked into the image, so after\n> every update (a code change, `.env` variables such as `TZ`) you need\n> `docker compose up -d --build`, not just `restart`.\n\n**One-off, when updating from a version up to v0.11:** after the product was renamed the\ncontainer is called `killbottleneck` instead of `flowmap`. The old container holds port 8090,\nso the new one would not come up — stop and remove it first:\n\n```bash\ndocker rm -f flowmap\ndocker compose up -d --build\n```\n\nYour data is in the `./pb_data` folder on disk, not in the container — you will not lose\nanything. `FLOWMAP_*` variables in your `.env` keep working, there is no need to rewrite them.\n\n## Notes\n\n- A public link to a map shares only the map canvas — tasks and task comments are not visible\n  through it.\n- Licence: **fair-code** — Sustainable Use License (see the License section below).\n\n## License — fair-code\n\nkillBottleneck isn't \"open source\" in the strict (OSI) sense — and we say so plainly. It's\n**fair-code**: the source is public, you can download it, run it, modify it and use it, and\nfor the vast majority of people it delivers the same benefits as classic open source.\nThe parts that *can* be classic **open source, are**: the\n[skin editor](https://tengolabs.github.io/killbottleneck-skins/) (MIT) and the whole\n[skin gallery](https://github.com/tengolabs/killbottleneck-skins) including its validator (CC0).\n\n**You get the whole of killBottleneck — every feature, including team collaboration and the AI\nfeatures.** No stripped-down \"free version\", nothing locked behind a paywall. You can even\n**power the AI yourself, for free** — with your own model (Ollama) on your machine, or your\nown API key. Our hosted cloud (AI included) is offered only as **a convenience for those who have\nnowhere to run killBottleneck** — it's convenience, not a condition.\n\n**What you may do with killBottleneck — free and with no catch:**\n- Run it yourself on your own computer or server — **your data stays with you**.\n- Use it in your company for your own work and your team — fully.\n- Plug in **your own AI** (a local model or your own API key), or use no AI at all.\n- Modify it however you need.\n- Offer services around killBottleneck (setup, consulting, customizations for a client).\n\n**What we keep for ourselves — and what keeps killBottleneck alive:**\n- Hosting killBottleneck and charging people for access.\n- White-labeling it — releasing it under someone else's brand.\n- Reselling it as a paid service.\n\nThat's our business — it's what lets us keep adding features, fixing bugs, and keeping\nkillBottleneck alive. **We actively encourage you to build on killBottleneck** and use it however you need;\njust don't turn it into a competing hosted service. Full terms: [LICENSE](./LICENSE).\nThird-party components keep their original licenses (MIT, Apache-2.0, BSD, …) — the full\nlist with license texts is in [THIRD-PARTY-LICENSES.md](./THIRD-PARTY-LICENSES.md).\n\n**Rights holder:** Tengo, s.r.o., ID No. 03339165, Dolní Valy 205, 262 72 Březnice, Czech Republic.\nWant to host killBottleneck as a service, ship it under your own brand, or resell it? The license doesn't allow that — but **a commercial license is available**, write to [licence@killbottleneck.com](mailto:licence@killbottleneck.com).\n\n*Česká verze této sekce je v [README.cs.md](./README.cs.md#licence--fair-code).*\n\nBuilt by **Richard Pobrislo** ([LinkedIn](https://www.linkedin.com/in/richard-pobrislo), [Ctrl+Alt+AI](https://www.youtube.com/@ctrlaltaicz)) — one person, which is why the support channels below are what they are.\n\nThe code is **written 100% by AI** — Claude Fable 5, Claude Opus 5 and Claude Opus 4.8 — under human direction. Every release goes through an automated regression suite and a manual click-through before it ships; the release notes list what was verified and what deliberately wasn't.\n\n## Contact\n\n| Where | What for |\n|---|---|\n| **GitHub Issues / Discussions** | bugs and ideas for improvements — in the open, so others can see them too |\n| **security@killbottleneck.com** | security issues (**not** in a public issue) — see [SECURITY.md](./SECURITY.md) |\n| **support@killbottleneck.com** | paid plans: the hosted instance |\n| **licence@killbottleneck.com** | commercial licensing — hosting as a service, white-label, reselling |\n| **info@killbottleneck.com** | everything else |\n\nWe do not accept code from outside contributors (see [CONTRIBUTING.md](./CONTRIBUTING.md)) —\nideas and bug reports we do, and they are welcome.\n\n## Supporting the project\n\nkillBottleneck is **fair-code** — the whole product (every feature) is free to self-host and\nwill stay that way. If it helps you:\n\n- follow our [YouTube channel](https://www.youtube.com/@ctrlaltaicz) with tutorials and AI news,\n- join us on [Discord](https://discord.gg/dkxMdVKwXw).\n",
  "bytes": 35741,
  "sha": "d960a51e85ffe71b676a7b553b1ba348d29a921ac87b0dbf405049cc8041debb",
  "repo_slug": "tengolabs/killbottleneck",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_com_killbottleneck_killbottleneck_e7063749/readme"
}