killBottleneck
MCP serverAI & modelsYour AI can turn a goal into clear, mapped steps and follow a process the way your team actually runs it. killbottleneck provides goal and process maps that both people and AI agents can read and use. The maps run in your own environment, so this picture of your work stays under your control.
Unavailable. This server has no hosted endpoint yet, so Ahel can't serve it.
Ahel cannot run this one yet; its page stays here for reference.
What your AI can do with it
- Create goal and process maps for a project or workflow
- Break a goal into steps an AI can follow
- Read the same maps your team uses, so people and AI work from one shared picture
- Keep all maps in your own environment rather than on someone else's hosted setup
Getting started
- Read the source or reference documentation for what it needs to run.
- Check this page for availability before you add it to a pipeline on Ahel.
From the project's README
As published by tengolabs/killbottleneck in README.md.
🧪 Public beta. killBottleneck is feature-complete and in beta — the cloud and the self-hosted version alike; it is one and the same app. What we are testing here is the self-hosted side: installation, reverse proxies, your own SMTP, upgrades. Install it (Quick start below), try to break it, and tell us what happened: bugs → Issues, ideas → Discussions. v1.0 ships when the beta goes quiet.
A 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.
Nothing here phones home. On a default install the server sends no request anywhere, and the app loads nothing from a third-party CDN — fonts included, they are served from your own instance. Everything that could leave your network is something you switch on:
| Outbound request | When it happens | Turn it off |
|---|---|---|
| GitHub Releases API | Version check, from the user's browser — not the server | KB_UPDATE_CHECK=0 |
| The AI endpoint you configured | Only with KB_AI_PROVIDER ≠ none; your own Ollama or any endpoint you choose | KB_AI_PROVIDER=none (default) |
| Google (sign-in, Drive picker) | Only when you configure KB_GOOGLE_* | leave those empty (default) |
There is no telemetry, no analytics and no licence check.
- Quick start
- What it does without AI · On a phone
- AI features (optional)
- AI assistant over MCP
- Who performs a step: a person, or an automation — includes the webhook contract for your own agents
- Moving a project elsewhere (JSON export/import)
- Appearance (skins) · Notifications · Time zone and recurring templates
- Data and backup · Team · Registration and the registration key
- Sign in with Google · Attachments · E-mail (SMTP)
- HTTPS (access from outside) · Updating
- License — fair-code · Contact
Quick start
All you need is Docker. Then:
cp .env.example .env # optional — the defaults are fine
docker compose up -d
killBottleneck runs at http://SERVER-IP:8090. Colleagues on the local network just open it in a browser.
The first user to register automatically becomes the administrator. Everyone else can register themselves, or the administrator invites them from Administration (this creates an account with a temporary password to hand over).
What it does without AI
A full goal map editor (nodes, edges, statuses, notes), multiple maps per user, comments on goals, sharing maps with colleagues (read / edit), public maps, export to image/PDF.
The “My day” panel (both the home page and the Tasks page): a clickable overview of overdue / today / within a week / blocking others, computed live from your data; name days next to the date; a portrait PNG export for mobile — both full (with task names) and anonymous (names redacted, for social media). Over HTTPS you also get Share… (your phone's native Web Share dialog, no third-party service involved).
Time tracking: a ⏱ timer in the top bar (one click starts an “empty” measurement — the project/client/goal is assigned while it runs or afterwards), a timer on every task and every goal in a map (measuring never changes a status — it is purely supplementary), a left-hand “Time tracking” panel with the records (from–to, retroactive assignment), a “Time worked” dialog in the user menu (today/this week, broken down by project and client), a client registry (project→client, so time adds up per client too), and auto-stop for forgotten timers after 12 h. Inbox behaviour: an unassigned measurement stopped with a note (e.g. “call with the client”) also saves itself as an idea in your stash.
On a phone
The same instance, opened on a phone, switches to a simplified view: today's tasks, tick them off, add one, and read messages — no map canvas to fight with on a small screen. You can switch back to the full view at any time, and the app can be added to the home screen (over HTTPS) so it behaves like a native one.
More in the Simplified view guide.
AI features (optional)
The assistant lives in a side panel next to your maps. It plans your day with you (morning briefing, evening planning), sorts notes from a photo, a PDF or a voice note, drafts a whole project after a few questions, prepares a meeting, reviews your week and, for managers, runs a team meeting. It reads your maps itself; every change it proposes is a card you confirm — nothing is written behind your back. E-mails, notes and summaries it writes are kept as documents next to the chat. Besides the assistant there is the wand on a node (sub-steps, milestones, KPIs, risks), an AI project summary and the daily encouragement in My day.
AI is switched on in .env via KB_AI_PROVIDER:
openai— any OpenAI-compatible API: OpenAI, OpenRouter, Groq, Mistral, Together, or your own vLLM / LM Studio / llama.cpp / liteLLM proxy. SetKB_AI_URL=https://openrouter.ai/api/v1(the base address, usually ending in/v1),KB_AI_TOKEN=<your API key>andKB_AI_MODEL=<exact model name>. Voice notes are transcribed by the same service when it offers a Whisper / transcribe model; your provider bills you for the requests.api— a remote AI service compatible with the killBottleneck API contract: enter the address and token you got from your provider. No GPU of your own and no maintenance. (Runs the wand, the summary and the encouragement; the assistant needsollamaoropenai.)ollama— your own local model: install Ollama, pull a model (ollama pull gpt-oss:20b) and setKB_AI_URL=http://IP:11434+KB_AI_MODEL=gpt-oss:20b. Everything runs on your side, no data leaves your network. (Voice notes need a speech-to-text service of your own — see below.)custom— your own endpoint honouring the same API contract (the contract is written down here).
The assistant uses the same model unless you give it its own
(KB_CHAT_PROVIDER/URL/MODEL/TOKEN). Reading photos needs a vision model (KB_VISION_*, or
tick The assistant reads images in Administration → AI). Voice notes work with any
speech-to-text in the OpenAI shape (KB_TRANSCRIBE_PROVIDER=openai + KB_TRANSCRIBE_URL —
speaches, whisper.cpp, OpenAI…); the recording itself is never stored. Browsers allow the
microphone only over HTTPS (or localhost), and a reverse proxy in front must let request
bodies of about 5 MB through (a voice note or a photo travels inside the request).
More in the assistant guide.
When AI is used, map data is sent to the endpoint you chose; with none (the default) nothing
ever leaves your server.
Daily AI encouragement (a line in the My day panel): 1–2 sentences prioritising “what
blocks others → overdue → today”, with the occasional proverb. It is generated in the morning
by a cron job (KB_SUMMARY_HOUR, default 6) only for accounts that signed in within the last
KB_SUMMARY_ACTIVE_DAYS days (default 14, 0 = everyone); for the rest it is generated when
they open the app. Optionally a separate (smaller/faster) model just for the summaries:
KB_SUMMARY_PROVIDER/URL/MODEL/TOKEN — without them the general AI configuration above is
used. The panel works in full without AI, just without this one line. The AI never enumerates
task lists (those are computed from your data and clickable) and task names are sanitised
before they go into the prompt.
AI assistant over MCP (Claude Desktop, Claude Code, …)
killBottleneck ships with a built-in MCP server (mcp/): connect your AI assistant to your
own instance and maps get built conversationally — “make a map out of these meeting notes”,
bulk edits, ticking off what's done. It works the same for self-hosted and hosted instances,
only the address differs.
-
In the app: user menu → API keys → a new key with the Read and write scope (Read only is enough for read access). The token is shown only once. Recommended: give the key an expiry and revoke it once you stop using it.
-
Nothing to install — the server is on npm as
killbottleneck-mcp, sonpxfetches it on first use. (Prefer running it from this repository?cd mcp && npm installand usenode /absolute/path/mcp/index.jsinstead of thenpxcommand below.) -
Register it with your assistant:
Claude Code:
claude mcp add killbottleneck \ -e KB_URL=http://SERVER-IP:8090 \ -e KB_API_KEY=kb_user_... \ -- npx -y killbottleneck-mcpClaude Desktop (
claude_desktop_config.json→mcpServers):{ "mcpServers": { "killbottleneck": { "command": "npx", "args": ["-y", "killbottleneck-mcp"], "env": { "KB_URL": "http://SERVER-IP:8090", "KB_API_KEY": "kb_user_..." } } } }
Tools (20): list_maps, get_map, create_map, add_nodes, update_node, delete_node,
list_people, get_portfolio, get_org_structure, calendar events and timed reminders (create_event,
list_events, create_reminder) and the rule tools (create_rule, list_rules,
update_rule, delete_rule, list_rule_runs, list_rule_templates, save_rule_template,
delete_rule_template). A goal with an assignee or a deadline IS a task — there are no
separate task records. Assigning an owner through the API shares the map with that person as a
collaborator, so the work shows up in their My Day (the response lists who was shared with).
Remote, without anything local: every instance also serves MCP directly at /mcp
(Streamable HTTP, same keys, same tools) — claude mcp add --transport http killbottleneck https://your-instance/mcp --header "Authorization: Bearer kb_user_..."; the claude.ai connector
signs in through OAuth. Details: MCP server.
Security: a key acts as its owner — it sees and edits exactly what the owner can in the app,
shared and team maps included (edit/own = full write; work and read = only the status of
the 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
anyone's private map, and someone else's public map is not reachable either (404). Administration,
AI 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
a map. Limits: 120 reads + 30 writes per minute per key, at most 200 nodes per call, at most 20
keys per account. Working alongside an open editor is handled by conflict detection (the editor
offers to reload, the assistant reloads the map itself). Note: add_nodes re-runs the layout
of the whole map. MCP tool output is in English (assistants always understand it); server error
messages arrive in the language of your account.
Who performs a step: a person, or an automation
For every goal in a map you can say whether a person or an automation does it. Whether there is an AI agent or a scheduled cron job behind that automation is not your problem — whoever builds it knows.
Important: the responsible person for a goal is always a human. Even for an automated step there is someone accountable, who gets the notifications and whose “My day” the goal counts towards. The automation does the work; a person is answerable for it.
For an automated step you also record which automation does it — this is a record of how things are today (“n8n already does this step for us”), not a command. That is what makes it visible at a glance which parts of the map are done by people and which by machines.
“I would like this automated”
On any goal you can tick a request to have the step automated, and optionally add a sentence explaining why. The request goes to the AI agent manager — a separate flag on a user (User management → AI manager), independent of their role; both an administrator and an ordinary member can hold it alongside their role.
Once the manager builds the automation and records it on the goal, the request tidies itself away and the requester gets a message that their goal is now automated. The full cycle:
person: ☑ I would like this automated ("I upload subtitles by hand, 20 minutes")
↓
the AI manager gets a notification → decides → builds an n8n workflow
↓
the manager records it on the goal: "n8n — subtitle translation"
↓
the requester gets a notification: "your goal is now automated by n8n — subtitle translation"
Attachments on a goal
You can upload files to any goal. On a goal with an automation, uploading a file starts it right away — instead of filling in a form somewhere else you simply attach whatever needs processing (typically subtitles, source material, an export).
Attachments are visible only to people with access to the project. The files are protected: the link alone gives nothing away.
AI agent registry
The AI agent manager (or an administrator) maintains a directory of automations under AI agent registry: name, webhook address, signing secret, enabled/disabled. On a goal the automation is picked by name — team members never see the address or the secret. When the name on a goal matches an agent in the registry, killBottleneck can start it itself.
Who may start it. Each agent can carry a list of allowed e-mail addresses. An empty list means the automation can be started by anyone who can edit any map — inside a company that is usually fine, but restrict it on an instance you let contractors into: whoever may edit a map can otherwise start any of your n8n workflows and feed their own text into it (the goal's title and description go to the agent in the payload).
Attachments are capped at 200 files per project, plus an optional space limit for the WHOLE
instance (KB_FILES_MB in MB; 0 = uploads disabled entirely, empty = no limit — set one on a
shared disk so a hosted instance cannot fill it up). ⚠️ The former FLOWMAP_MAP_FILES_MB was a
PER-PROJECT quota defaulting to 200 MB — if you have it set it still applies to you, but
without it there is now NO space limit at all.
An automated run: killBottleneck → n8n → back
An automation starts when:
- an attachment is uploaded to the goal, or
- the goal's turn comes — it was waiting for its sub-goals and they have all just been completed, or
- somebody manually switches the goal to “in progress” (this is also how you retry a failed run)
A running automation will not be started a second time until it reports back or expires.
The outgoing request (POST to the agent's address, with an X-Signature header =
HMAC-SHA256 of the entire body using the agent's secret):
{
"run_id": "…", "run_token": "kbr_…",
"callback_url": "https://your-instance/api/kb/agent-callback",
"files_url": "https://your-instance/api/kb/agent-files?run_token=kbr_…",
"files": [{ "id": "…", "name": "subtitles.sbv", "size": 1234, "url": "https://…?run_token=kbr_…" }],
"map_id": "…", "map_title": "…",
"node_id": "…", "node_title": "…",
"description": "…", "deadline": "2026-08-01",
"owner": "responsible@company.com", "triggered_by": "who@company.com"
}
The agent downloads files using its run token; files_url is a live listing, so it also
sees attachments added while it is running. The token expires once the result is reported.
Reporting back (POST to callback_url, no login — the run token authenticates it):
{ "run_id": "…", "run_token": "kbr_…", "status": "done", "result": "Translated into 3 languages" }
status is done or failed. A token is valid for one goal and one report — a second
call with the same token will not go through.
After done the goal is completed, and that sets the rest of the process in motion: the
following goal is unblocked and the person responsible for it is notified that they can start.
If that following goal is automated as well, it starts straight away — so the steps chain
themselves.
Set the address the agent should call back on. callback_url is assembled by the server,
not the browser — without configuration it uses PocketBase's “Application URL”, which after
installation is http://localhost:8090. An agent running on another machine would therefore
call itself, and the run would hang until it timed out. In .env:
KB_PUBLIC_URL=https://killbottleneck.yourcompany.com
KB_AGENT_TIMEOUT_MIN=90
Any address the agent can reach will do — on a self-hosted setup http://192.168.1.10:8090 on
the LAN is perfectly fine. Hosted instances (killBottleneck Cloud) have this set automatically.
Is your n8n on the same network? The webhook address is called by the server, which makes
it a classic internal-network scanning vector — so by default killBottleneck refuses to call
private addresses (10.x, 192.168.x, 172.16–31.x, localhost, cloud metadata). On a
self-hosted setup where n8n runs next to killBottleneck, allow it:
KB_ALLOW_PRIVATE_WEBHOOKS=1
Without this the run is marked failed and the AI agent manager gets a message explaining why. An agent must have its secret filled in — without one the request would be signed with an empty key and the recipient would have no protection whatsoever, so killBottleneck rejects such a run outright. The currently effective address is always shown at the bottom of the AI agent registry, which warns you when it points at localhost. This only concerns automations — if you do not use them, you do not need to set this variable.
When an automation does not finish
The state of a run is visible right in the goal's dialog — pending / running / done / failed, with the reason on failure. A run is restarted by switching the goal back to “In progress”.
What each state means:
| State | What is happening |
|---|---|
| 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) |
| running | the agent has picked up the work and has not reported back yet |
| done / failed | the agent reported a result, or the run expired |
A run that does not report back within KB_AGENT_TIMEOUT_MIN (default 90) minutes is marked
failed by a watchdog, which notifies both the responsible person and the AI agent managers — so
a goal never hangs silently.
The most common causes of failure: the agent is not in the registry or is disabled; it has no
secret; its address points into a private network and KB_ALLOW_PRIVATE_WEBHOOKS=1 is missing;
or the webhook is unreachable. The details (including connection errors) are in the server log —
docker compose logs killbottleneck — they are deliberately not surfaced in the app.
Moving a project elsewhere (JSON export and import)
A project can be exported to a .json file and imported somewhere else — between colleagues
and between instances. In the editor: Export → Export JSON, choosing with names or
without names. Import lives in the menu next to the “New project” button.
What the file contains: the title, the description, the whole goal structure (including statuses, deadlines, who performs each step and automation requests) and the tasks attached to it. The “without names” option clears both the responsible people and the assignees — the names of automations stay, since they describe the process.
Switching from Asana or Trello: the same import also accepts an Asana project export (CSV) and a Trello board export (JSON). Sections/lists become map branches, tasks/cards become goals, subtasks and checklists become child goals; statuses (done), due dates, descriptions and — for Asana — assignees carry over (e-mails unknown to this instance are cleared and counted). Everything is converted locally in the browser — nothing calls Asana or Trello. Limit: 400 items per file.
What is not transferred: attachments, comments, sharing, archiving and numbering series. An import always creates a new project owned by whoever imports it, regenerates the goal identifiers (so it does not collide with the original) and shares nothing with anybody and sends no notifications — you have to share the project manually to collaborate on it. Assignments to e-mail addresses that do not exist on this instance are dropped, and the import tells you how many.
Appearance (skins)
In the avatar menu → Appearance everyone picks one of twelve built-in skins — Indigo (default), High contrast, Terminal, Paper, Ocean, Forest, Midnight, Plum, Peach, Graphite, Ruby or Rose. The choice is saved to the account, so it applies on every device, in both light and dark mode, and in the simplified lite view too (the picker there sits below the list).
Custom skins: a skin is a small JSON file (kb-skin v1 format) — a set of
colors (HSL), fonts and corner radius. The Appearance dialog can export the
current skin (for a built-in, its definition — "take it and tweak it") and
import someone else's, from a file or by pasting. By design it is not
arbitrary CSS: values pass a whitelist on both the client and the server, so a
shared skin cannot run or send anything. No web fonts are ever downloaded —
only fonts bundled with the app and system fonts are used; an unknown font
harmlessly falls back to the next one in the stack.
Company look: an administrator sets the instance-wide default skin in the organization admin — it applies to everyone who has not picked their own, including the login screen. A user's own choice always takes precedence.
What a skin does not change in v1 (by design): status colors (red/amber/green = overdue/in progress/done stay readable everywhere the same). Map export (PNG/PDF) is true to the screen — captured in the active skin and light/dark mode, including the background color; only the backdrop artwork is left out. The project dashboard PDF and the "My day" image deliberately stay light so they can be sent to anyone.
Shortened here. Read the whole README on GitHub.
Signals
- GitHub stars
- 8
- Forks
- 3
- Last commit
- Oct 2026
- Weekly downloads
- 58
- Weekly_downloads
- 54 weekly_downloads
Advanced
- Delivery
- killbottleneck MCP server → your Ahel connector (mcp.ahel.ai) → your AI.
- Item type
- mcp-server
- Key
com-killbottleneck-killbottleneck- Source
- github.com/tengolabs/killbottleneck
github.com/tengolabs/killbottleneck
More in AI & models
MCP server · upstash
More in AI & modelsAdButler
MCP server · adbutler
More in AI & modelsatom-mcp-server
MCP server · a7om-ai
More in AI & modelsottasia
MCP server · aiweather-anurag
More in AI & modelsCurrents
MCP server · currents-dev
More in AI & modelsunphurl
MCP server · 123ergo
More in AI & models