Repository navigation
Help Assistant Design
Status: built 2026-11-11, all six steps, coming in 5.0.0. This page is the design as agreed; for how it was built see the developer guide, the internals series (1 Β· 2 Β· 3) and every design question, answered. An assistant on every page that answers "how do I...?" from FreeITSM's own in-app help, in the user's language. It works on every install - with an AI provider it writes an answer, without one it still finds the right help section. It is for analysts and admins learning the system. The main decisions are made - see Decisions.
FreeITSM's in-app help is large: every module has a help page, plus 35 System help pages - about 186,000 tokens of English text, much of it translated into 24 other languages. It is all there, but finding the paragraph you need means knowing which module's help to open and scrolling to the right section.
People learning the system do not think in modules. They think "how do I create a ticketing department?" or "why did that reply open a new ticket?". The assistant takes the question as asked, finds the help that answers it, wherever it lives, and either answers it or takes the reader straight to it.
- An icon on every page, in the shared header, in every module - for analysts who have the assistant turned on (see Turning it on).
- Clicking it opens a chat window that can be dragged anywhere on the screen. Where it sits and whether it is open are remembered.
- The conversation is kept across pages. Every module is a separate page load, so the conversation is stored on the server for that analyst and reloaded on each page. It is cleared only when the user clicks Reset.
- Every answer links to the help it came from - π Tickets help β Settings - so it can always be checked, and so the reader learns where things are.
- It knows where the user is. In Workflows, "how do I add a step?" means a workflow step. Elsewhere it may answer "that depends - in Workflows..., in Starters & leavers...".
- It answers in the language the question was asked in, and writes menu and button names exactly as they appear on that user's screen.
Two separate keys are involved, and the assistant uses whatever the install has:
- a chat AI - writes the answer (any provider FreeITSM supports: Anthropic, OpenAI, Azure, OpenRouter, a local model)
- an embedding key - lets the search match by meaning (OpenAI today)
| The install has | The window | How it searches |
|---|---|---|
| No AI at all | Search help - the 5 best help sections, each with a short extract and a link straight to it. No written answer, but instant and free | Word search, in the user's language and English |
| An embedding key only | Search help, better at loosely worded questions | Word search + vectors |
| A chat AI only | Ask - a written answer, with links; searches again itself when the first results miss | Word search + the AI's own searches |
| Both | Ask, with the full hybrid | Word search + vectors + the AI's own searches + translating the question when needed |
Same icon, same window, same saved conversation at every level - only the label (Search help / Ask) and what comes back differ. An admin sees which level is active and why ("Ask is off - no AI provider is set up") with a link to fix it.
The no-AI level is worth having on its own: a question in plain words lands the reader on the exact paragraph, instead of a long page to scroll. Measured on the question set: a right section in the top 5 for 91% of plain questions and 100% of exact names, with no AI at all.
Most admins will assume an "AI assistant" does nothing without a key. System β Help assistant opens with a panel that says the opposite, before the key fields:
β The help assistant works without any AI. With nothing set up it searches every help page and takes your analysts straight to the right section - free, instant, and nothing leaves your server. An embedding key makes it better at loosely worded questions. A chat AI makes it write the answer in a sentence or two, in the asker's own language.
with a live line under it: "Right now: Search help (no AI set up)."
At every level the window is a conversation: the question as a bubble on the right, the reply on the left, kept until Reset. Without AI, the reply is a short line followed by the results as cards - section title, a line of preview, Open.
The line is one of a few canned phrases, chosen by how good the match is - so it never sounds sure about a weak result - and picked at random so it does not sound robotic:
| Situation | For example |
|---|---|
| One clear winner - the top result well ahead of the rest | "This looks like exactly what you need:" Β· "Good news - the help covers this:" Β· "I think this is the one:" |
| Several decent matches | "Here's what I found in the help:" Β· "These look like the closest matches:" Β· "You might find these helpful:" Β· "I had a look through the help and found these:" |
| Weak matches only | "I couldn't find an exact match, but these might be close:" Β· "Not a perfect match, but worth a look:" |
| Nothing | "I couldn't find anything for that - try different words, or name the module you're in?" Β· "Nothing in the help matches that. Maybe try a shorter question?" |
| The top result is from the module the asker is in | "Here's what the Workflows help says:" |
Two rules: the phrases never pretend an AI read anything ("I found these in the help" - not "I think the answer is..."), and they live in the language files like all other text. Where clear winner ends and weak begins is set from the question set's real scores, not guessed.
how do I create a ticketing department
Everything quoted below is the real help text.
The help is stored as hundreds of short keyed strings - tickets.help.settings.card_dept_body and so on. Too small to search one at a time, so a builder reads each help page and groups the strings into the sections the reader sees (each <div class="help-section" id="..."> and the t('...') keys inside it). Each section gets:
- an address -
tickets/help.php#settings - a title - Settings
- its text - every string in it, joined
- its module - for the access filter
Reading the pages, rather than the language files alone, means a string that no page shows is never searched, and every result links somewhere real. The sections are cached in a table (below) and rebuilt only when a help page or language file changes.
The browser sends the question, the user's language and where they are (Tickets). With a chat AI, the model is given:
- the rules - answer about FreeITSM only from the help it is given; if the help does not say, say so and never invent a button or menu; answer in the question's language; quote screen labels exactly as the user sees them
- the question
- the best sections already found (step 2)
-
one tool,
search_help(words), to look again
Two searches run at once, both on the server, both in milliseconds:
Word search (the classic search-engine scoring, BM25 - no AI involved):
- The question is cut into words, common ones dropped (how, do, I, a), plurals trimmed:
create,ticketing,department. -
Rare words count for more.
ticketappears in most sections - it says almost nothing.departmentappears in about 30 - it narrows things right down. - Every section is scored: each word's weight Γ how often it appears, with a bonus for a match in a title, and a small bonus for the module the user is in.
| Section | Why it scores | Score |
|---|---|---|
| Tickets β Settings | a card titled Departments: "Create departments like IT, HR, and Finance. Each department becomes a folder in the inbox and a filter on the dashboard" - both rare words, side by side, in a title | high |
| Tickets β Inbox | "Departments are configured in Settings and appear as sub-folders automatically" | good |
| Tickets β Working with tickets | "Route tickets to the correct team. Departments drive folder grouping and dashboard filters" | good |
| Reporting β Dashboards |
"narrow dashboard results to a specific department" - department but not create
|
medium |
Vectors, when there is an embedding key: the question becomes a vector and is compared with every section's vector, ranking them by meaning. This is what finds the right section when the question shares no words with it - "how do I stop the system spamming my requesters?" against a section about notifications.
The two lists are merged (reciprocal rank fusion - a section near the top of both comes first), and the top few go to the AI in full.
The AI reads only those few sections - a few thousand words, never the whole help - and writes:
Go to Tickets β Settings β Departments and add one (for example IT, HR or Finance). Each department becomes a folder in your ticket inbox and a filter on the dashboard, and you can make one the default for tickets that arrive by email. π Tickets help β Settings Β· Tickets help β Inbox
Most questions end here: one AI call.
If the sections do not answer the question, the AI calls search_help with words of its own - search_help("notification email requester") - and the same hybrid search runs again. Each extra search is one more round trip (1-3 seconds). This is the safety net for questions both searches missed.
The help has no step-by-step guide for creating a department - only that one card. The assistant gives what the help says and stops; it does not invent "click the green + button". That rule is what keeps it trustworthy, and questions it struggled with are the best possible list of help that needs writing (see Open questions).
The search runs against that language's help as well as English (word search), and the answer is read in the user's own language - see the key trick below. A German user asking in German gets a German answer quoting German screen labels.
Hogyan hozzak lΓ©tre jegykezelΕ rΓ©szleget?
- Vectors still work across languages. The embedding model places that question near the English "Create departments like IT, HR..." - less sharply than an English question, and less well for Hungarian than for German or Spanish, which have far more training text behind them.
- Word search cannot - there are no Hungarian words in the help.
- So the question is translated first, only when needed. If it is in neither English nor the user's interface language, a quick call to a small, fast model turns it into an English search phrase ("create a department in Tickets"), which both searches use. About 0.5-1 second, only for these questions.
- The answer is in Hungarian; the things to click are in English, because that is what is on the screen:
Nyissa meg a Tickets β Settings β Departments menΓΌt (Jegyek β BeΓ‘llΓtΓ‘sok β RΓ©szlegek), Γ©s adjon hozzΓ‘ egy rΓ©szleget...
| Asking | Screens in | Answer in | Menu names in |
|---|---|---|---|
| English user | English | English | English |
| German user | German | German | German |
| Hungarian user | English | Hungarian | English (Hungarian in brackets) |
| German user, screens switched to English | English | German | English |
Every language file uses the same keys - tickets.help.settings.card_dept_body is the same card in all of them. So the search can find a section using English vectors, then read that section from the user's own language file by its keys. A German user's AI receives the German text, with the German menu names exactly as on their screen - nothing is translated from English in the model's head, so a menu name cannot come out wrong. An untranslated string falls back to English, as the help pages themselves do.
Vectors, word search and the AI searching for itself each fail differently. That is why the design uses all three.
| Good at | Weak at | |
|---|---|---|
| Word search | Exact names - buttons, settings, error messages (HY093, Enforce approvals). Instant, free, and you can see why it matched |
A question that shares no words with the answer; a language with no help files |
| Vectors | Meaning - finds the right section on the first try when the wording differs; consistent whatever chat model is used | Rare exact words (returns something related instead); needs an embedding key and an index |
| The AI searching again | Recovering from a miss with better words | Costs a round trip each time; a weak or small local model may accept a poor result - or, worse, answer from general knowledge of ITSM tools rather than from FreeITSM's help |
Answer accuracy - representing the help faithfully - depends on the model sticking to the text it was given, which is the rules in step 1. Retrieval affects it only indirectly: the worse the search, the more a model is tempted to fill gaps. Better search is better accuracy.
None of this is new. Hybrid search (word scoring plus vectors, merged by reciprocal rank fusion) is now standard - Elasticsearch, OpenSearch, Azure AI Search and others ship it. An AI that searches with tools is how most assistants find things. Rewriting a question before searching and matching across languages are standard too. The one FreeITSM-specific touch is reading a section in the user's language by its keys, which falls out of how the translations are stored.
| AI calls | Typical wait | |
|---|---|---|
| A question the first search answers (most) | 1 | 2-4 seconds |
| A question in a language without help files | 1 small + 1 | 3-5 seconds |
| A question the first search missed | 2-3 | 4-9 seconds |
| No AI at all | 0 | instant |
On the server it is negligible: the word search is milliseconds, a vector lookup about 0.2 seconds, loading the saved conversation one small read. Answers stream in as they are written, and the window shows Searching help... while it looks.
Building vectors for all the English help costs well under a penny with OpenAI's small embedding model; so does each further language. A question costs a few thousand tokens - a fraction of a penny on most models. A long conversation sends its earlier messages back each time, as every AI chat does, so the history sent is capped, and Reset clears it.
- Off until an admin turns it on, on System β Help assistant.
- Then per analyst - an admin chooses who has it, so a team can start with a few people.
- Without it, an analyst sees no icon, and the endpoints behind the window refuse them.
Two layers, both applied on the server before anything reaches the AI:
-
Modules the analyst cannot open are never searched. Someone without Asset Management never gets Asset Management answers, and nobody learns about modules hidden from them.
-
A section that needs a permission says which. Help pages mark a section with the capability it describes - for example the Tickets settings section with the permission to change Tickets settings (a
data-capon the section, read by the section builder; capabilities are theCapenum, checked withanalystHasCapability()inincludes/rbac.php). The analyst's own capabilities go to the AI with the sections, and the rules say: when the analyst lacks the permission a section needs, tell them who can do it rather than how:An administrator does this, in Tickets β Settings β Departments. You don't have access to that, so ask your admin.
That is more useful than silence ("I don't know"), and nothing is given away - the help is documentation, already public on this wiki. Hiding is reserved for whole modules, where the reader cannot reach anything at all.
Sections with no mark are open to anyone who can open the module.
Putting help into knowledge_articles with an is_help flag was considered and rejected. 60 files hold 101 queries that read that table - the knowledge list, the self-service Help Centre, the REST API, the Knowledge AI chat, gap analysis, reports, review reminders, exports. Every one, and every future one, would need AND is_help = 0; one missed and help sections appear where they should not. And help is not an article: it has no author, owner, version, company or review date, it lives in the language files, and it changes on every upgrade.
So, a table of its own that is only a cache: the language files and help pages stay the truth, the table can be emptied and rebuilt at any time, and nothing else in FreeITSM reads it.
help_sections
| Column | Holds |
|---|---|
section_key |
which section - e.g. tickets/help.php#settings
|
locale |
en, de, pt-BR... - the language folder codes |
module |
for the access filter |
title |
shown in results |
body |
the section's text, for word search |
text_hash |
a fingerprint of the text - only a changed section is rebuilt |
embedding |
the vector (empty without an embedding key) |
built_datetime |
when |
One row per section per language, unique on (section_key, locale).
English vectors come first; other languages are optional. The locale column means vectors for German (or any language) can be added later without changing the table:
- The fallback is per section, not per language. For a German user: each section's German vector if there is one, otherwise its English one. A half-translated German index never hides the untranslated half.
- A German vector is only made from German text. Where a string is untranslated the German file shows English, and a "German" vector of that would just duplicate the English one - so the builder skips it.
- A German question scores slightly higher against German text than English text saying the same thing, so translated sections tend to rank a little ahead - mostly harmless (it prefers what the reader can read), and the word search evens out real misses.
help_assistant_messages - the saved conversation: analyst, role (question / answer), text, the sections used, when. Visible only to that analyst; Reset deletes their rows.
help_assistant_unanswered - questions the assistant could not answer (see Unanswered questions): the question, its language, the module the asker was in, the best search score, when, whether an admin has dealt with it, and the asker - only where Record who asked is on for them, otherwise empty. Kept separately from the conversation, so Reset does not remove it.
FreeITSM already calls OpenAI's embedding API from four places (includes/knowledge/kb_ai.php, api/knowledge/ai_chat.php, api/knowledge/generate_embedding.php, includes/services/knowledge.php) and has two copies of the vector comparison (kbCosineSimilarity(), cosineSimilarity()). kb_ai.php's own header notes that the copy in ai_chat.php should be switched over "when it's next touched". The general pieces also sit in a Knowledge file that loads Knowledge-only rules (audience, visibility, tenancy) with them.
So the first step (done - Embeddings - Developer Guide) is to move them into one small shared file - includes/ai_embeddings.php, with aiEmbed() and aiCosineSimilarity() - point all four existing callers at it, delete the copies, and prove with the Knowledge tests that nothing changed. The help assistant then uses the same file. A bonus: adding another embedding provider later (Azure OpenAI, a local model through Ollama) becomes a change in one place, which Knowledge, web chat and help all get at once.
The help text is identical on every install of a version, so its vectors are too. They can be built once, when the release is cut - a step in RELEASING, beside the notes - and shipped in the release (data/help-vectors/en.bin). On upgrade, or when Database Verify runs, the install loads them into help_sections: no cost, no wait, and every install has the same, tested index.
What it does not remove:
-
The question still needs an embedding key. A question only exists when someone asks it, so it is turned into a vector there and then - with the same model the shipped vectors were built with (
text-embedding-3-small). An install with that key gets vector search immediately; one without uses word search, and the shipped vectors simply wait. - A different embedding provider means a local build. Vectors from different models cannot be compared, so an install using another provider (once there is one) builds its own.
- A changed section is rebuilt locally. If an install has edited a language file, that section's fingerprint no longer matches the shipped one; it alone is rebuilt here (with a key) or searched by words.
Size: a full-size vector is about 6 KB, and there are several hundred sections - a few MB per language, too much to rewrite in git every release. The model can return shorter vectors (512 numbers instead of 1,536) for little loss, bringing English to roughly 1-2 MB. The question set (below) checks the shorter size before it is adopted.
One page for admins. On most installs nobody needs a button on it: the word-search index builds itself and the English vectors arrive with the release. It is there to see what is going on, and for the unusual cases.
| Part | What it does |
|---|---|
| On / off, and who | The master switch, and the analysts who have the assistant |
| Status | Which level is active and why - "Ask is off - no AI provider set up" - with a link to fix it |
| AI provider | The assistant's own provider, model and key - Anthropic, OpenAI, Azure OpenAI, OpenRouter, a local model - through the shared AI Providers panel, like every other AI feature. Its own key means its own bill |
| Embedding key | The assistant's own, separate from the Knowledge module's - again so its cost can be seen on its own |
| Search index | Per language: sections, how many have vectors, whether they came with the release or were built here, how many are out of date. Rebuild changed, Rebuild all, Build German... with progress, or left to the scheduler |
| Out-of-date warning | See When the vectors are out of date |
| Try it | Type a question, see the top 5 sections with their scores - for understanding why an answer was poor |
| Unanswered questions | The list below |
The page warns when help text has changed since its vectors were built.
Compared by the text, not by file dates. Dates give false alarms both ways: git pull, FTP or unzipping a release can put a new date on a file whose help did not change (a warning about nothing), and restoring a backup can put an old date on text that did change (no warning when it matters). Each section's row already holds text_hash, a fingerprint of the text its vector was built from; the page fingerprints the current text and compares. A different fingerprint is an out-of-date section - exact, and countable.
File dates are still used as the cheap first check: fingerprints are only recalculated when a help page or language file is newer than the last check, so the page stays quick.
β οΈ 12 English sections have changed since their vectors were built (Tickets 9, Workflows 3). Answers about those parts may miss the new text. [Rebuild changed]
- With the assistant's embedding key, the scheduler rebuilds changed sections by itself; the warning stays only if that fails, with the reason ("the OpenAI key was refused").
- Without a key, it says those sections are searched by words only until they are rebuilt.
- Shipped vectors carry the version they were built for, so the index shows "from the 5.1.0 release" or "built here 2026-11-12", and an upgrade whose help changed is spotted at once.
When the assistant cannot answer from the help - the search finds nothing good enough, or the AI reports the help does not cover it - the question is recorded in help_assistant_unanswered.
- Admins see the list on System β Help assistant: the question, its language, the module, when. Each can be marked dealt with once the help is written.
- A bell notification goes to the admins - "The help assistant could not answer a question", linking to the list.
- Never to the person who asked. They have already been told the help does not cover it; a notification about their own question would only be noise.
- The asker's name is recorded only where an admin chooses - a Record who asked setting, turned on per analyst. For anyone it is on for, their chat window says so in small print ("If the help can't answer a question, it's shared with your admins with your name"). Recording names silently would cost the trust that makes people willing to ask "basic" questions. Where it is off, the question is kept without a name.
This is the most useful output of the whole feature: a running list, in users' own words, of the help that is missing - like the department question in the worked example, where the help has one line and no steps.
Before the window is built, a set of about 50 realistic questions, each paired with the help section that should answer it:
- plain ones (how do I create a department)
- vague ones that share no words with the answer (stop the system spamming requesters)
- exact names (what does Enforce approvals do)
- other languages - German and Spanish (which have help files) and Hungarian and Polish-style questions (which may not)
Each search is run word search only, vectors only, and both, counting how often the right section is in the top 5. The numbers decide the details - whether the translation step earns its second, how much the module bonus should weigh - rather than opinion. The set then stays as a test, so a later change cannot quietly make the search worse.
Made 2026-11-11:
- Who gets it - off until an admin turns it on, then per analyst. See Turning it on.
- Unanswered questions are kept and shown to admins on System β Help assistant, with a bell notification to admins - never to the asker. See Unanswered questions.
- Its own AI provider and model, any FreeITSM supports - Azure, OpenAI, Anthropic, OpenRouter.
- Its own keys - chat and embedding - so its cost shows separately on the bill.
- The 35 System help pages stay English for now. Searching them works in any language; the only cost is that a non-English answer about a System screen relies on the AI to translate menu names itself, which it can occasionally get slightly wrong. It goes away when those pages move into the language files.
- No portal for now. This is for analysts and admins learning the system.
- Roles and permissions are respected - modules hidden, permission-marked sections answered with who can do it. See Respecting roles and permissions.
- The English vectors ship in each release - and other languages may follow. See Shipping the vectors.
- The page warns when vectors are out of date, by comparing text fingerprints. See When the vectors are out of date.
- Naming the asker is an admin setting, per analyst, and the analyst is told when it is on. See Unanswered questions.
- β One shared embedding file - the four copies become one; Knowledge behaves exactly as before. Done 2026-11-11 (#2769) - see Embeddings - Developer Guide. It also fixed a bug all four copies shared (#2770).
- β
The section builder, the
help_sectionscache and word search - and the module-access filter, and the question set measuring it. Done 2026-11-11 (#2771) - see The help assistant - Developer Guide. Word search alone: plain questions 91%, exact names 100%, vague 33%, other languages 33% in the top 5.data-capis read and stored; the marks go onto the pages with step 5. - β System β Help assistant and the window, at the no-AI level - the switch and per-analyst access, the icon, dragging, the saved conversation, Search help. Done 2026-11-11 (#2773) - for users, under the hood.
- β Vectors - English first, with the assistant's own embedding key; the question set shows the gain; then shipping them in the release. Done 2026-11-11 (#2775): vague questions 2/6 β 6/6, plain 43 β 46 of 47 - under the hood. Model changes warn and offer Rebuild, with the old model answering meanwhile.
- β
Ask - its own AI provider, the written answer,
search_help, permission-aware answers, reading sections in the user's language, the translation step. Done 2026-11-11 (#2777) - under the hood. The translation step became the AI's own Englishsearch_help. - β Unanswered questions - the list and the admins' bell notification. Done 2026-11-11 (#2776) - under the hood. Questions answered in a module the asker cannot open are not kept.
- Optional: vectors for other languages.
- AI Providers - the shared AI layer the answers would go through
- Knowledge Assistant and its Developer Guide - the existing embedding search this reuses
- Internationalisation (i18n) - how the language files and their keys work
- Help page house style - how help pages are laid out, which the section builder reads
FreeITSM β an open-source IT Service Management platform Β· github.com/edmozley/freeitsm Β· MIT licence
- Installation
- β° Scheduled tasks (cron jobs)
-
Architecture
- β³ π§Ή Root folder tidy (URL routing)
- β³ π Database Integrity (FKs & constraints)
- β³ π οΈ Database Verification β Developer Guide
- β³ π§© Service Layer (UI + API share code)
- β³ πͺ€ Code traps (the TRAP: comments)
- β³ π Commenting for the Engineering wiki
- β³ π οΈ Engineering wiki scanner - Developer Guide
- β³ π Service-Layer progress
- π€ Contributing (read before a pull request)
- π§ͺ Developer tests
- π PDF exports moved to PDFKit (#254)
- AI Providers
- Internationalisation (i18n)
- Timezones & Time Handling
- π Date & Time Formats
- π± Currencies
- π§ The sidebar (optional module rail)
- π§© Preference templates
- π Display order (modules, Watchtower cards) β Developer Guide
- Theming & Dark Mode
- ποΈ Recent β getting back to what you were doing
- β¨οΈ Command palette (βK)
- π Searching inside tickets
- π Attached documents
-
MobileβFriendly
- β³ π« Mobile: Tickets
- β³ π» Mobile: Assets
- β³ π Mobile: Calendar
- β³ π Mobile: Knowledge
- β³ π¦ Mobile: Service Status
- β³ πΌ Mobile: Watchtower
- β³ π§© Mobile: Problem Management
- β³ π Mobile: Change Management
- β³ πΏ Mobile: Software
- β³ β Mobile: Tasks
- β³ π Mobile: Forms
- β³ π Mobile: Contracts
- β³ π Mobile: Domains
- β³ π Mobile: People
- β³ π Mobile: Projects
- β³ ποΈ Mobile: Files
- β³ π Mobile: LMS
- β³ πΊοΈ Mobile: CMDB
- β³ πΊοΈ Mobile: Network Mapper
- β³ π§ Mobile: Process Mapper
- β³ βοΈ Mobile: Workflow
- β³ π₯οΈ Mobile: System
- β³ π Mobile: Reporting
- β³ π Mobile: System Wiki
- β³ π Mobile: Self-Service Portal
- β³ π§° Mobile: Techniques & Tricks
-
Security
- Layer 1 β which modules you can enter
- β³ π§© Module Access Control
- β³ π οΈ Module Access β Developer Guide
- β³ π Switching modules off
- β³ π οΈ Module availability β Developer Guide
- β³ π Module availability β design (#217)
- Layer 2 β what you can administer
- β³ π Roles & Permissions
- β³ π οΈ Roles β Developer Guide
- β³ π€ Why capabilities are constants
- Layer 3 β the System module
- β³ π Admin Access Control
- Hardening
- β³ π Security review response 2026-08
- β³ π‘οΈ Security hardening 2026-08
- β³ π οΈ Security hardening 2026-08 β Developer Guide
- β³ π‘οΈ Round three β plain English
- β³ π οΈ Round three β Developer Guide
- β³ π‘οΈ CSRF protection (S4) β Developer Guide
- Single Sign-On (SSO)
- ποΈ LDAP & Active Directory
-
π¦ Microsoft Entra ID
- β³ π₯ Importing people and groups
- β³ π» Intune: assets to their primary user
- β³ π’ Organisation chart
- β³ π οΈ Entra directory sync β Developer Guide
- β³ π οΈ Entra import - review (#235)
- β³ π οΈ Entra follow-ups - review (#237-#240)
- β³ π οΈ Intune primary user - review (#236)
- β³ π οΈ Organisation chart - reviews (#242, #265)
- π CardDAV contact sync
- Browser Extension
- API Reference
-
π REST API β how it works
- β³ π Proposal: custom fields, inventory import and change evidence (#194)
- β³ π οΈ Custom fields, evidence + inventory - review (#195-#197)
- β³ π οΈ Long forms in a task's Work view - review (#198)
- β³ π οΈ Empty Procedures fold - review (#247)
- β³ π« REST API: Tickets
- β³ π» REST API: Assets
- β³ π΄ REST API: Problems
- β³ π REST API: Changes
- β³ π REST API: Knowledge
- β³ β REST API: Tasks
- β³ ποΈ REST API: CMDB
- β³ π REST API: Contracts
- β³ ποΈ REST API: Calendar
- β³ πΏ REST API: Software
- β³ π REST API: Domains
- β³ π¦ REST API: Service Status
- β³ βοΈ REST API: Morning Checks
- β³ π REST API: Forms
- β³ βοΈ REST API: Workflow
- β³ π·οΈ REST API: Cost centres
- β³ π REST API: Chart of accounts
- β³ π§βπΌ REST API: Analysts
- β³ πΊοΈ REST API: Network Mapper
- β³ π§ Using the API docs page
- β³ π OpenAPI specification
- β³ β OpenAPI: kept correct
- β³ π οΈ Maintaining the catalogue
- Watchtower
-
Tickets
- β³ π Live updates
- β³ π οΈ Watching a ticket - Developer Guide (1 of 2)
- β³ π οΈ CSAT delay and reminder - Developer Guide
- β³ π οΈ Ticket checklist step types - Developer Guide (1 of 2)
- β³ π οΈ Right-click Attach checklist - Developer Guide
- β³ π οΈ Checklists in the REST API - Developer Guide
- β³ π οΈ Inbox.js map β Developer Guide
- β³ π οΈ Floating windows & the file viewer β Developer Guide
- β³ π οΈ Tickets settings β Developer Guide
- β³ π Simpler ticket and task forms - design (#218)
- β³ ποΈ The ticket workspace
- β³ π Forms on tickets
- β³ π The ticket table
- β³ π Rota copy and paste β Developer Deep Dive
- β³ β Checklists & SOPs
- β³ βοΈ Mandatory fields
- β³ π§Ύ Custom ticket fields
- β³ π·οΈ Ticket categories
- β³ π§Ύ A type for every new ticket
- β³ π₯ Assigning tickets to a team, and escalation
- β³ π’ One board across every company
- β³ π Ticket dashboard β Developer Guide
- β³ Mailbox Authentication
- β³ π€ Email send log
- β³ π Attachment size limits and large emails
-
β³ Basic IMAP mailboxes
- β³ π Basic IMAP without the PHP extension (#257)
- β³ π οΈ Basic IMAP client β Developer Guide
- β³ π§ͺ Basic IMAP client β Testing and verifying
- β³ π οΈ Basic IMAP - Sent copy - Developer Guide (#270)
- β³ π οΈ Verifying a mail folder β Developer Guide
- β³ π οΈ Mailbox providers β Developer Guide
- β³ π οΈ How Gmail mail collection works β Developer Guide
- β³ Email rendering & images
- β³ SLA Management
- β³ WhatsApp channel
-
β³
βοΈ Telegram channel - β³ β CSAT company scope and filters β Developer Guide
- β³ π₯ Microsoft Teams channel
- β³ π¨οΈ Mattermost channel
- β³ π¬ Web chat channel
- β³ π£ Slack channel
- β³ π Linking tickets
- β³ β Record previews
- β³ π Ticket notes: internal or shared
- β³ ποΈ Canned responses
- β³ βοΈ Limiting replies to particular senders
- β³ π¨ Telling the analyst a ticket is theirs
- β³ βοΈ Email signatures
- β³ π The public web address
- β³ π’ Ticket numbering
- β³ π Raising a ticket for someone else
- β³ π Merging tickets
- β³ π Confidential tickets
- β³ π₯ Portal managers
- β³ π Who has seen a ticket
- β³ π Reading long tickets
- β³ β Splitting tickets
- β³ β Selecting several tickets
- β³ ποΈ The folder pane
- β³ π½ Just my tickets, or no closed ones
- β³ π οΈ Snoozing tickets β Developer Guide
- β³ π₯ Collision detection
- β³ β±οΈ Time tracking
- β³ π Case reports - a ticket and its work as one PDF
- β³ π Scheduled work in your own calendar
- Problem Management
-
Tasks
- β³ π οΈ Task board and subtasks β Developer Guide
- β³ π§βπ€βπ§ People on a task ("Involved")
- β³ π Repeating tasks
- β³ π’ Moving a task between companies
- π Projects
-
Assets
- β³ π’ Moving an asset between companies
- β³ π Shared asset locations
- β³ π§βπΌ Assigning assets to analysts
- β³ π Warranty and lease alerts
- β³ π Leases
- β³ π Saved table views
- β³ π¨οΈ Recording anything, and importing it
- β³ π§© Asset type layouts
- β³ π Inventory freshness
- β³ π Linked configuration item
- β³ π Connected assets
- β³ π Asset review
-
β³ π·οΈ QR asset labels
- β³ π οΈ QR asset labels β Developer Guide
- β³ π Asset label designer - design (#229)
- β³ π· Asset scanning β Developer Guide
- β³ π οΈ Asset tag numbering β Developer Guide
- β³ π οΈ Asset reconciliation β Developer Guide
- β³ π οΈ Reconciliation, tags + labels - review (#164)
- β³ π Who holds what, and handover documents
- β³ π₯οΈ The inventory agent (PowerShell)
- β³ ποΈ Proxmox VE servers
- β³ βοΈ VMware Cloud Director servers
- β³ πͺ Hyper-V and Failover Clusters
- β³ π Linking equipment to tickets
- β³ βοΈ Follow-up tasks on a ticket
- Knowledge
- Change Management
- Calendar
- Morning Checks
- Reporting
- Software
-
Forms
- β³ π¨ The form designer β Developer Guide
- β³ π Layout & the grid β Developer Guide
- β³ ποΈ Collections β grouping submissions
- β³ π Submissions as PDFs
- β³ β‘ What happens next β a form's own actions
- β³ π οΈ Sections & conditional logic β Developer Guide
- β³ π οΈ Lookup fields β Developer Guide
- β³ π‘οΈ Catalogue request approvals
- People
- Starters & leavers
- Domains
- ποΈ Files
- Contracts
- Service Status
- π Notifications
- π¨ War Room
- Self-Service Portal
- LMS
- Process Mapper
-
CMDB
- β³ π οΈ CMDB β Developer Guide
- β³ π οΈ Impact analysis β Developer Guide
- β³ π οΈ Data quality β Developer Guide
- β³ π Linked assets
- β³ π Linking an asset to its CI - design (#201)
- β³ π Discovery and redundancy-aware impact - design (#199)
- β³ π οΈ Relationship wording - review (#297)
- Network Mapper
-
Workflows
- β³ π οΈ Workflow engine β Developer Guide
- β³ π οΈ Workflows for tasks β Developer Guide
- β³ π οΈ Workflow notes on a ticket β Developer Guide
- β³ π οΈ Workflow category routing β Developer Guide
- β³ β° Time-Based Triggers
- β³ πͺ Webhooks
- β³ π¬ Webhook Message Formats
- β³ π HTTPS Certificates & CA Bundles
- β³ π οΈ SSL Verification β the Global Setting
- β³ π Workflow & Webhook Pitfalls
- Issue trackers (Jira, Azure DevOps)
- π‘ Zabbix (monitoring)
- π¬ Microsoft Teams alerts
- π 3CX (phone system)
-
System
- β³ π οΈ Preferences β Developer Guide
- β³ π§Ή Maintenance
- β³ π Finding people in the Analysts list
- β³ πͺ When an analyst leaves
- β³ π οΈ System β Branding β Developer Guide
- β³ π©Ί Page health (D019) β Developer Guide
- β³ β Feature Bingo
- β³ π·οΈ Cost centres
- β³ π Chart of accounts
- β³ π· Photo Album
- β³ Demo Data
- β³ π οΈ Demo Data β Developer Guide
-
Overview
- β³ π Progress tracker
- β³ Concepts & vocabulary
- β³ Email routing & mailboxes
- β³ Settings: global vs per-company
- β³ Users & self-service
- β³ Staff cross-company access
- β³ One company supporting another
- β³ π’ One board across every company
- β³ Worked examples
- β³ Pitfalls & gotchas
- β³ Scope: what it's for
- β³ π οΈ Developer Guide (make a module multi-company)
- β³ ποΈ Case study: CMDB (a linked graph)
- β³ π§ͺ Test harness (prove it's isolated)
- What this is
-
π Bugs resolved
- β³ π Small fixes in 5.1.0
- β³ π CMDB relationships read backwards (5.1.0)
- β³ π #301 CSAT delay was never applied
- β³ π #281 Comments imported from Jira never arrived
- β³ π #288 A change failed to open with Enforce approvals on
- β³ π Long non-Latin articles never got an embedding
- β³ π« #280 Email lookups scanned the whole table
- β³ β #266 Dragging a task told nobody
- β³ π #255 Article previews showed HTML codes
- β³ π #252 A link to a Knowledge article did not open
- β³ π #254 PDFs could not print Polish
- β³ π #250 Clicking a folder left the open article on screen
- β³ π« #260 The dashboard cog did nothing
- β³ π« #248 A department rule never matched on four routes
- β³ π A directory account could be matched to someone else
- β³ π« #244 Reply went to the assigned analyst
- β³ π Mailbox sign-in was not checked
- β³ π Four weaknesses around signing in
- β³ π A lookup answer could name any record
- β³ π« #227 A mailbox could not be deleted
- β³ π« #226 A picture on a note could not be closed
- β³ π» #222 The Assets page never loaded in 4.3.0
- β³ βοΈ #214 A "contains" condition did not match capitals
- β³ βοΈ #216 A workflow email from a chosen mailbox always failed
- β³ π³ The Docker image was missing PHP extensions
- β³ π A failed DNS lookup read as a missing record
- β³ π A link could change data
- β³ π Access outlived its removal
- β³ π Knowledge articles could run scripts
- β³ π Knowledge writes ignored permissions
- β³ π Company boundaries (Oct 2026)
- β³ π Smaller gaps (Oct 2026)
- β³ π Escaped text could leave its attribute
- β³ π Task descriptions were not cleaned
- β³ π Task documents ignored company scope
- β³ π Repeating tasks ignored company scope
- β³ π¬ #183 Mailbox checks overlapped
- β³ π #188 Transfer lock shown off when unknown
- β³ β #184 Subtask names and Overdue
- β³ π§© #186 Teams: the buttons did nothing
- β³ π Text in a change could run script
- β³ π AI settings changed without the AI permission
- β³ πͺ #178 Deleting an analyst failed
- β³ π« A team with no departments showed 0 tickets
- β³ π Projects: adding a phase did nothing on Save
- β³ π Leavers could still sign in
- β³ πΌοΈ Logo and courses broke on Apache with PHP-FPM
- β³ π’ Chat tickets ignored your ticket numbering
- β³ π Dates shown as a dash, or in server time
- β³ π Assets β Users showed people from other companies
- β³ π Restricted analysts could read other modules' data
- β³ πΌοΈ Replies with a picture in the thread failed to send
- β³ π Reply attachments never reached the customer
- β³ π οΈ Outbound email attachments β Developer Guide
- β³ π A global SSO provider was missing from the portal
- β³ π Behind a proxy, the SSO redirect said http
- β³ βοΈ The portal tagline moved when you saved it
- β³ π¨ The portal settings screen forgot what you saved
- β³ π‘οΈ The approvals inbox said "Error" and nothing else
- β³ π A table's answers were missing from the PDF
- β³ β A single-select column let you tick every option
- β³ π The portal ignored a form's field widths
- β³ π The tasks board stopped taking clicks
- β³ ποΈ #121 The index list is out of date after upgrading
- β³ π #133 The calendar subscription was empty
- β³ π #131 Tasks always reopened on the board
- β³ π₯ #129 Every page returned HTTP 500 after upgrading
- β³ π³ #127 A PHP warning above the System page
- β³ π #126 Notes stamped with the server's clock
- β³ π Storing every date in UTC
- β³ πͺ The portal was down for everyone signed in
- β³ βοΈ #120 Workflow notes could never be written
- β³ βοΈ #123 Three errors when running Database Verification
- β³ π #122 The description box was a stub in the corner
- β³ π£ Demo data deleted real accounts
- β³ π #117 Sign-in redirected to the wrong address
- β³ π¨ #108 The priority dot was invisible
- β³ β±οΈ #116 Time logged from the right-click menu
- β³ π #114 API keys refused by our own guard
- β³ ποΈ #110 Assigning a task told nobody
- β³ πͺ #107 Signed out while still working
- β³ π #103 "Share with Requester" reached nobody
- β³ π #102 Search found nothing for hyphens
- β³ πͺ #101 Source code editor opened behind
- β³ βοΈ #88 Subtasks could not be ticked off
- β³ π» #84 Asset deep link selected nothing
- β³ π« #79 A new ticket arrived with no status
- β³ π§ #79 A ticket from email did not say so
- β³ π #78 Bell opened to nothing
- β³ π¬ #77 Mail only collected from Inbox
- β³ π #74 The default password could not be changed
- β³ π¦ #70 Renaming an impact level
- β³ π€ #67 App-only mailboxes could not send
- β³ π #45 Verify only ever worked for Microsoft
- β³ π #45 IMAP reported as not authenticated
- β³ βοΈ An email template stopped escaping itself
- β³ π The portal dashboard showed the wrong time
- β³ π’ The folder said 99 and the list showed 96