Update History
GCTRL gets better with every release - and we ship in the open. Below is the running record of what's new: fresh capabilities, faster extraction and retrieval, and continuous hardening. Every change earns its place, proven against our benchmarks and automated shipping gate before it reaches you.
Transparency is part of the product. A knowledge platform you build on should visibly keep improving - so here it is, release by release.
v0.9.28 - Your knowledge base keeps what you asked it to keep
19 October 2026 · GCTRL Team / TortillaJackson
- Agents write back only when you ask. Connected agents used to store their own conclusions after every larger task, including unchecked research results. Later answers quoted those notes back as facts. Agents now store something only when you ask them to remember it or confirm their offer, and never store unverified findings or future dates as facts. Notes an agent stored rank after your documents in search.
- Placeholders no longer turn into the wrong word. A cloud model sometimes rewrote a name placeholder such as
[Org-631]as[Term-631]. The gateway then restored an unrelated term with the same number. It now maps such a slip back to the name it came from, and leaves any other[Term-N]in a request as it is. - Clear feedback for placeholder lookups. A search, lookup or store call that contains nothing but placeholders now gets a short note instead of an empty result, because such a placeholder can never resolve.
v0.9.27 - Search answers in a fraction of a second, even for long questions
17 October 2026 · GCTRL Team / TortillaJackson
- Long questions no longer stall retrieval. When a question did not match word for word, the keyword half of hybrid search fell back to "any of these words" over every word of the question, "the", "and" and "die" included. A chat message of a thousand characters became a hundred search terms, matched most of the knowledge base and took 5 to 14 seconds. Chat clients that look up context before every turn ran into their timeout and answered without your knowledge. The fallback now uses the content words only, at most 16, the most specific first. On real chat questions over a large knowledge base, the 95th percentile fell from 5.9 seconds to under half a second, and the passages that come back match the question more closely.
- Pasted texts get context too. A search over 2000 characters used to come back empty.
search_chunksnow searches with the first 2000 characters. - Parallel searches run in parallel. The search worker handled one request at a time. It now serves several at once, each with its own database connection: eight searches that used to take two seconds finish in about 0.6.
- Learning from use no longer gets in the way of answers. Every search strengthens the passages it returns. Two searches that returned the same passages could block each other in the database, and the caller waited for it. These updates now take their locks in a fixed order, retry a lost race, and run after the answer is already on its way.
v0.9.26 - Short names are hidden in every spelling
17 October 2026 · GCTRL Team / TortillaJackson
- A short name in capitals is cloaked however you type it. The gateway matched names of up to four capital letters, such as "DENA", only in exactly that spelling, so "dena" or "Dena" in a message reached the cloud model in clear. Such a name now matches in any case. The strict spelling stays only where the lowercase word means something else: "MIT" never hides the German "mit", "US" never hides "us", "BILD" never hides "Bild". Names of one or two letters and names with digits keep the strict spelling too.
- Your instructions reach Ollama models again. Some clients send their system prompt with the newer OpenAI role
developer. Ollama ignores that role, so the model answered with no instructions at all. The gateway now sends such messages assystemto Ollama, for local models and cloud tags alike. Requests to OpenAI keep thedeveloperrole.
v0.9.25 - Ordinary words stay ordinary words
17 October 2026 · GCTRL Team / TortillaJackson
- The chat gateway no longer swallows everyday words. KEX types many ordinary words as people, organisations or places: "IT", "HR", "Geschäftsführung", "Betriebsrat", "Kunde", "Owner", "CISO", "Backend", "Portal". The gateway turned each of them into a placeholder, so a cloud model read "Der [Place-94] hat im [Place-74] die IT gebeten" and you saw brackets where words belonged. The gateway now skips role words, group words, legal forms, regions, our own product names and common tools, plus any one-word organisation that is a common German or English word. Real names stay hidden: "Fabio Chiaramonte", "Knorr-Bremse AG" and "Deutsche Energie-Agentur" still travel as placeholders.
- Places are opt-in. A city or a country hides no personal data, and the location class held the most everyday words. Set
GCTRL_CLOAK_PLACES=1to cloak places again. Postal addresses are now caught on their own, as[ADDRESS-n]. - Numbers stay numbers. The phone sweep took any run of seven digits: dates, year ranges, decimals, ticket numbers and timestamps. It now needs the shape of a dialled number (a leading
+,(or0) or a keyword such as "Tel." right before it. This also removes most of the database work the gateway did for new placeholders on each request. - Identity numbers are cloaked. A tax ID, VAT ID, ID card, passport or social security number that follows its keyword becomes
[ID-n]. - A name keeps the type most mentions give it. A person typed once as an organisation was cloaked as
[Org-n]. The majority type now wins, and a tie goes to the person. - Old placeholders heal. Placeholders from the October 7 and 8 releases sit in files, boards and chat histories. The gateway now restores name and term placeholders it finds in a request before it cloaks, so the model never copies one it cannot map back. It restores only entities from your own knowledge bases, at most 50 per request, and never phone numbers, IBANs, e-mail addresses, ID numbers, addresses, amounts or dates: those placeholders stay as they are.
- Changed placeholders still come back. The gateway now also restores placeholders a model translated (
[Ort-2]), re-cased ([place-2]), wrote with a space or another dash, or escaped for Markdown (\[Person-1\]), across stream chunks too.
v0.9.24 - The cloak hides names, not your vocabulary
8 October 2026 · GCTRL Team / TortillaJackson
- Only people, organisations and places are pseudonymized in the chat gateway. The previous release put every known entity of your knowledge bases into the gateway's dictionary. On a large corpus that included thousands of concepts, tools, quantities and dates, and a cloud model editing a slide deck read
[Term-8517]for a service name,[NUM-3229]for a pixel width and[DATE-12]for the date on the cover. It wrote the placeholders back into files and spent 145k tokens on one edit working around them. Those classes carry no personal data. The dictionary now holds named entities only — everything KEX typed as a person, organisation or location — together with the e-mail, phone and IBAN sweep that always ran, and every one of them still fits without a cap. A name KEX typed only as a technology or a field (a brand, say) is treated as vocabulary and travels in clear. A name counts as a person, organisation or place when at least half of its mentions say so, so a single stray mention of "Service" as an organisation no longer turns the word into a placeholder, while a company typed as such throughout stays hidden. - Retrieval is unchanged. Answers over your graph still pseudonymize the mentions of the chunks they retrieved, amounts and dates included. The change applies to the free-chat gateway that agents such as pi, Claude Code and Codex talk to.
- Identifiers, numbers and dates are proven stable in the stream. A new test replays a slide edit with a file path, a width and a date split at every byte of the stream and checks that prose and tool arguments come back byte for byte.
v0.9.23 - Lessons keep the classification of the work they come from
8 October 2026 · GCTRL Team / TortillaJackson
- A lesson is as confidential as its source. Every lesson now carries a classification. Without one it inherits the classification of its knowledge base; a stricter one is kept, a looser one is never accepted. Existing lessons are lifted to the level of their knowledge base, so nothing that was confidential stays readable as public.
- You only see lessons you are cleared for. Listing lessons, reporting a lesson as applied and searching return only lessons at or below your clearance, the same rule that already applies to every other chunk. The search service checks each hit against the database before it answers, so an older vector entry can never hand out a lesson that was classified higher later.
- Team lessons take the strictest source. When a lesson proven in several projects is promoted to team knowledge, the promoted copy gets the strictest classification of the lessons it came from.
- Acting on behalf of a person, never above them. Account-level integrations can pass
clearanceRankto read on behalf of a person with a lower clearance. The value can only lower what the key may see, never raise it, and it applies after any per-graph grant.
v0.9.22 - Agents see one consistent set of placeholders, and the token filter is searchable
8 October 2026 · GCTRL Team / TortillaJackson
- Tool results are pseudonymized on
/v1/chat/completions, too. Agents such as pi talk to the gateway in the chat-completions format. There the gateway cloaked the conversation but sent tool results and the tool calls the agent sent back in clear. A model then sawPlace-3in the conversation and "Berlin Hbf" in the browser result, could not connect the two, and typed an invented city into a real form. Tool results and replayed tool calls now go through the same cloak as the conversation, so the model sees one mapping everywhere. Tool definitions stay unchanged. To send tool results in clear, addX-Cloak-Tool-Outputs: 0, as on/v1/responses. - Placeholders are bracketed. Every pseudonym now travels as
[Place-3],[Person-7]or[Term-12], and a cloaked request carries a short system note: bracketed terms are placeholders for real names, pass them to tools unchanged and never replace them with invented values. The stored mapping is unchanged; answers with the old formPlace-3are still translated back. - No more garbled names in answers. The translation back replaced
Term-2insideTerm-27and produced text like "Ursache7". A placeholder is now restored only when it is complete, also when the stream splits it across chunks. - Tool arguments stay valid JSON. When a real name contains a quote or a backslash, the restored tool arguments now escape it. Several tool calls in one stream chunk without an index no longer share one buffer.
- Find a token in a long list. The token filter on the extraction list is now a searchable picker: type part of a token name and only matching tokens remain, "All" and "Web login" always stay at the top. Arrow keys, Home and End move, Enter selects, Escape clears the search and closes on the second press. The job search beside it is wider, Escape clears it, "Clear filters" now also resets the search, and an empty result says that nothing matches instead of "No extractions yet".
v0.9.21 - Your projects learn from their own work, and syncs read only what changed
7 October 2026 · GCTRL Team / TortillaJackson
- Your projects remember what worked. A knowledge base can now hold lessons: conventions ("how we do X here"), recipes (steps that worked), pitfalls (what broke and the fix) and decisions with their reason. Agents store them with the new
store_lessontool, read them withlist_lessons, and report withlesson_appliedwhen a lesson helped. Lessons are stored without entity extraction, so they cost almost nothing and never reach the entity graph unconfirmed. - Only lessons that prove useful stay in front. A lesson starts cold. Every time an agent reports it applied it, it warms up strongly; when a search finds it, a little. Unused lessons cool down and are archived after a month, and come back when they are found again. Listing lessons does not count as use, so a playbook can never keep itself warm. Each lesson counts how often it was applied.
- The wiki gets a playbook page. Wiki distillation now writes a page "Playbook" with the source projects' lessons, proven ones per type and most used first, new ones below as candidates. The page is rendered without a language model, so it shows exactly what the team proved, and a change in what is used refreshes the wiki on schedule.
- What several projects learned becomes team knowledge. When the same lesson is proven in three projects, GCTRL promotes one copy into the knowledge base "Team-Lehren" in the folder Global/Lessons. It starts warm, names the lessons it came from, and is found by every project. Chunk deduplication no longer merges lessons, because the same lesson in several projects is exactly this signal.
- An unchanged file is not extracted again. Every ingest path (upload, text extraction, the agent tools, Google Drive, SharePoint, Obsidian) now checks whether the same content was already extracted with the same classification, ontology and access token. If so, the existing extraction is linked to the target knowledge base and nothing is queued or charged; the response says
"status": "unchanged". A changed file still becomes a new version and is extracted. Sendforce=trueto extract unchanged content again, for example after switching models. A failed extraction is never reused, so sending a file again still repairs it. - Drive and SharePoint syncs read only what changed. A file whose modified time equals the one recorded for its latest version is not even downloaded, and sync results report
unchangednext tosynced. Scheduled syncs of a Drive folder or a SharePoint library can now be created as triggers (google_drive,microsoft); the scheduler ran them already, but the API refused them. A SharePoint sync or trigger can name a target knowledge base. - SharePoint files are extracted at all. The SharePoint path queued a job type the extraction worker did not know, so every SharePoint file failed. The API now fetches the file through Microsoft Graph itself, like Google Drive, which also keeps the tenant's client secret out of the job queue. Large Drive folders (over 1000 entries) and multi-page SharePoint libraries are now listed completely, and a note synced by hand and the same note re-ingested on a schedule are one document instead of two.
v0.9.20 - Secrets stay out of logs, and GCTRL recovers on its own after a Redis restart
7 October 2026 · GCTRL Team / TortillaJackson
- Passwords no longer appear in logs or status pages. The extraction and fusion workers printed their Redis address, including the password, into the container log at start, and their health endpoints returned the database addresses in full. Every service now masks credentials in addresses before it writes or returns them (
redis://default:***@...). The setup status also reads a password-protected Redis address correctly now; before, it showed such a Redis as disconnected. - GCTRL reconnects after a Redis restart. The API opened one Redis connection at start and never replaced it. After Redis restarted, new jobs waited until someone restarted the API, and the listener for finished jobs stopped silently, so jobs could stay pending. The API now reconnects and retries a failed command, and the listener subscribes again with a growing wait. The workers check idle connections and retry on connection errors.
- Qdrant can require an API key. Set
QDRANT_API_KEYin your.envand every GCTRL service sends it to Qdrant, and the bundled Qdrant starts with that key. Leave it empty and nothing changes: no key is sent and Qdrant stays open as before, so an update never locks your own services out. - Scoped tokens see only their own extractions and their granted knowledge bases. A token limited to some knowledge bases could list every extraction of its owner, with file names, and the job details named knowledge bases outside its grants. It now sees only the jobs it started and only the knowledge bases it is granted.
- An empty result from the entity resolver no longer triggers a looser merge. When LIMES ran fine but found no matching pair, the merge treated that as a failure and fell back to a looser name comparison, which could merge two different companies with similar names. A successful empty result now counts as an answer; the fallback runs only when the resolver really fails.
v0.9.19 - Cloaking covers every known name, and long knowledge base lists load at once
7 October 2026 · GCTRL Team / TortillaJackson
- Every person your knowledge base knows is cloaked, not only the 2,000 most mentioned. The cloak gateway took its dictionary of names from your knowledge bases, but stopped at the 2,000 entities mentioned most often. On a large instance that left most people, companies and places out, and names at the edge switched between cloaked and plain text every ten minutes. Now every known entity is in, and a name that is both a person and a concept counts as a person. A word index keeps it fast: with 50,000 names and a 60,000-character prompt cloaking takes 43 ms instead of 230 ms.
- IBANs written in groups of four are masked as one value. An IBAN with spaces, such as
DE02 1203 0000 0000 2020 51, was only partly masked, and parts of it could even turn into a company pseudonym. The gateway now recognizes grouped IBANs, also with non-breaking spaces, and replaces them as a single[IBAN-N]. Phone, invoice and order numbers stay untouched. - The list of knowledge bases loads in a fraction of a second. For each knowledge base the list counted nodes and edges with two separate graph queries, one after the other. With 260 knowledge bases that took over ten seconds, and every screen that shows the list waited for it. One query now counts the whole page: 0.1 s instead of 10.5 s, with the same numbers.
- Knowledge bases are grouped by folder, everywhere you pick one. A picker used to be one flat run of names in creation order. On an instance where a whole team works in one account that is a wall of look-alikes: several graphs named "Personal", one "Standard", one graph per project room. Every list that offers knowledge bases now groups them by their folder (
Users/...,Projects/<client>,Global/...) and shows that path: the token dialog, the FUSE target picker, the Talk-to-Graph selector, the auto-FUSE target in extraction, the wiki and trigger pickers, the merge dialog and the graph list of the workspace. Two graphs with the same name are finally distinguishable at a glance. - The knowledge base picker of an access token has a search field. Type part of a name or part of a folder and the list narrows while you type, with a count that tells you the list is filtered rather than short. The same search sits in the "grant" menu on an existing token.
- Pickers no longer stop at the 100 newest knowledge bases. Several lists asked for the server default. On a large instance the older, most established knowledge bases silently fell out of the window, which looked like they had been deleted. Every picker now asks for the full set.
- New: a token can carry a release class instead of a fixed list. An explicit list of knowledge bases is a snapshot of the day the token was issued, so a colleague with an internal clearance kept seeing only the knowledge that existed back then, and every new project graph had to be granted by hand. A token can now carry a classification as its release class and automatically READS every knowledge base of the account classified at or below it, including ones created later. Two limits are built in and cannot be switched off: personal knowledge bases (anything under
Users/) are never part of a class, and a class never grants writing, which still requires an explicit grant on a graph. The token's own clearance caps the class, and an unfiled knowledge base is never included. - A re-uploaded file no longer merges twice. GCTRL already kept a version chain per file (same path, changed content = new version). Fusing a knowledge base still read every version, so an updated CV or org chart contributed its old facts next to its new ones. A merge now takes only the newest version of each file; the older extractions stay in the knowledge base for history and retrieval but no longer shape the merged graph. The job result lists what was left out (
superseded_sources). - Answers follow the source document's date, not the upload order. When two documents disagree on a fact the conflict scan ranks them by the document's own modified date. The chat context used the upload order instead, so re-uploading an old file made its value "current". Graph facts in answers now carry the scan's verdict; without one, the newest assertion still wins as before. The registry of single-valued relations gains
works_at: the extraction vocabulary defines it as the CURRENT employer, so a second value is an update or an error - exactly what the conflict page is for. - The merge learns its matching rule from the merges you confirmed. Every merge recorded which pairs a person confirmed, or two independent matchers agreed on. Once an owner has enough confirmed pairs of one entity type, the LIMES resolver (WOMBAT) learns a link rule from them after the next merge. A learned rule goes live only if, run exactly as the merge would run it, it reproduces the confirmed pairs better than the default rule (F1), never links a pair marked "not the same", and fits the resolver. Otherwise it is kept as a proposal on the conflicts tab.
GCTRL_LEARN_AUTO_APPLY=falsemakes every rule a proposal;GCTRL_LEARN_ENABLED=falseturns learning off. - An ontology's match rules reach the merge. The merge form has offered an ontology since the beginning and the worker has read its rules just as long, but the API never passed them on. It does now; the compilation also records which ontology it was merged with.
v0.9.18 - The cloak gateway covers the ChatGPT subscription (Codex) and OpenAI's Responses API
7 October 2026 · GCTRL Team / TortillaJackson
- Codex on your ChatGPT subscription is pseudonymized, too. The Codex CLI talks to ChatGPT in OpenAI's Responses API format, and that traffic left the machine in plain text. The gateway now serves
POST /v1/responsesfor two upstreams:chatgpt(your ChatGPT subscription, the way Codex uses it) andopenai(the public Responses API). Point Codex at the gateway, keep its ChatGPT login inAuthorization: Bearer, send your GCTRL token inX-GCTRL-TokenandX-Upstream-Provider: chatgptoropenai. The gateway pseudonymizes names and organizations in the instructions, in every message, in the tool calls Codex sends back and in tool outputs such as file contents and search hits, and translates text, tool arguments and patch input in the streamed answer back before Codex sees them. To send tool outputs in clear, addX-Cloak-Tool-Outputs: 0, but only when a tool breaks: outputs in clear sit next to pseudonymized calls, so the vendor can link pseudonyms to the real names. Reasoning items and tool definitions travel unchanged on purpose.GET /v1/modelswith the same headers returns the model catalog of your account. - Claude's tool calls stay pseudonymized on the way back. On
/v1/messagesthe gateway now also cloaks the tool calls a client sends back in its history. Tool results keep traveling unchanged on this route, as before, so names in file contents and command output still reach Anthropic in clear. - Names inside file paths stay in clear. A name that is part of a path or slug, such as
crm/Max Müller.mdorMax_Mueller.md, travels unchanged, and so do JSON keys in tool arguments. Cloaking them would break tools on the way back. A vendor can therefore still link a pseudonym to a name through a path: keep sensitive data under neutral file names. - Clients can see the new upstream.
GET /v1/cloak/capabilitiesnow listschatgptnext toollama,anthropicandopenai. The ChatGPT host is pinned tochatgpt.com, redirects are never followed, and Codex session headers reach onlychatgpt.com.
v0.9.17 - The cloak gateway now covers Anthropic and OpenAI directly
6 October 2026 · GCTRL Team / TortillaJackson
- Claude and GPT requests are pseudonymized, too. Until now the cloak gateway only protected cloud models that your local Ollama passes through (
:cloudtags). Requests sent straight toapi.anthropic.comorapi.openai.comleft the machine in plain text. The gateway now speaks Anthropic's Messages API atPOST /v1/messages(streaming and non-streaming,count_tokens,GET /v1/models) and accepts an OpenAI upstream onPOST /v1/chat/completions. Send your vendor key where the SDK puts it (x-api-keyorAuthorization: Bearer, Claude subscription tokens included), your GCTRL token inX-GCTRL-Token, andX-Upstream-Provider: anthropicoropenai. Names, organizations, e-mail addresses, IBANs and phone numbers reach the vendor as stable pseudonyms; text and tool arguments in the reply are translated back before your client sees them. Thinking blocks, tool results, tool definitions and the Claude Code identity block are forwarded unchanged on purpose. Without the new headers everything behaves exactly as before. - Clients can tell which upstreams a gateway offers.
GET /v1/cloak/capabilitiesanswers{"upstreams": ["ollama", "anthropic", "openai"]}without authentication, so a client talking to an older gateway keeps its old routing. Errors produced by the gateway itself carry the response headerx-cloak-gateway-error: 1, so a client can tell a gateway refusal from a relayed vendor error and will not blame your vendor key for it. - Only vendor headers travel upstream. The gateway forwards an allow-list of headers and drops everything else, including cookies,
accept-encodingand the GCTRL token itself. Vendor hosts are pinned toapi.anthropic.comandapi.openai.com; redirects are never followed. SetANTHROPIC_BASEorOPENAI_BASEon the api service only if you really run a mirror. - Common words are no longer pseudonymized. When an extracted entity equals a German or English function word (an organization named "MIT" turned every "mit" into
Org-259), it stays untouched, and short acronyms of up to four letters now match case-sensitively: "MIT" is cloaked, "mit" is not. Longer names keep matching regardless of case. - Streaming is safe across every byte boundary. A chunk that was cut inside a multi-byte character (an umlaut, for example) could be dropped by the OpenAI-format stream parser. Lines are now reassembled at the byte level before they are decoded.
v0.9.16.1 - The cloak gateway also covers agent turns
3 October 2026 · GCTRL Team / TortillaJackson
- Agent turns are cloaked like chat turns. The cloak gateway pseudonymizes names, e-mail addresses and phone numbers before a request reaches a cloud model. It did so only when a message carried its text as a plain string. Agent harnesses send every message as a list of content parts, and the gateway forwarded those unchanged, so the cloud model read the original text although the turn was routed through the gateway. Text parts are now cloaked exactly like plain text. Images and tool results stay untouched, as before. If you route an agent through
/v1/chat/completionswith a cloud model, update the api service.
v0.9.16 - Every background job uses the model you chose
30 September 2026 · GCTRL Team / TortillaJackson
- Dossiers are written by your active model, never by a second one. After each wiki distillation GCTRL refreshes the dossiers of the most important entities, and the memory cycle regularly promotes frequently used entities to dossiers. Both steps ignored the runtime you selected and asked the default model of the local Ollama instead, so a host running one model on a dedicated server (oMLX, vLLM, llama.cpp) loaded a second model next to it about once an hour. Both now use the runtime and model of the distill task, like the wiki pages already did.
- You can stop the runtime guardrail from switching to Ollama. When the active runtime fails repeatedly, the guardrail switches GCTRL to the bundled Ollama and stays there until you re-apply your runtime. On a host sized for exactly one model that switch does more harm than the outage. Set
GCTRL_GUARDRAIL_REVERT=falseon the api service and the guardrail only reports the failing runtime in the dashboard; your runtime stays selected and resumes as soon as the server is back. Without the setting nothing changes.
v0.9.15 - The in-app update installs a release's own settings, too
28 September 2026 · GCTRL Team / TortillaJackson
- After an in-app update, each service runs with the settings of the new release. The in-app update pulls the new images and recreates every service with its existing configuration, so your own settings (environment overrides, labels, volumes, networks) survive. That configuration also contained the defaults baked into the previous image, and they were carried over unchanged: the most visible one is the version number, so after updating to 0.1.295 an instance still reported 0.1.294, and any new default a release introduced never took effect after an in-app update. The update now tells the two apart: values that came from the old image are replaced by those of the new image, values you set yourself are kept, and the start command follows the new image unless you changed it.
- Instances that already show a version behind catch up by themselves. The version number is never something you set, so it now always comes from the new image. The next update corrects it on every install, including those whose number fell behind during earlier updates.
v0.9.14 - Fused graphs keep their relations, and cloud-only installs stay on the cloud
28 September 2026 · GCTRL Team / TortillaJackson
- Fusing knowledge graphs no longer drops relations at merged entities. When FUSE recognizes that "Maren Thiele" and "Dr. Maren Thiele", or "Nordlicht Robotics" and "Nordlicht Robotics GmbH", are the same entity, it writes one merged node under a canonical name. The relations were then copied over by looking up the merged node under each relation's original spelling - so every relation attached to a spelling that did not become the canonical name found no node and was silently left out. The better the entity linking worked, the more edges disappeared: in a two-document test on a live instance, both entity pairs were linked correctly and 4 of 5 relations were lost. Relations now follow their entities onto the merged node, readings of the same fact from several documents become one edge that keeps all their sources, and an edge between two spellings of the same entity is dropped instead of turning into a self-loop. Existing fused knowledge bases pick up the missing relations the next time they are refreshed or re-fused.
- An incomplete extraction can be retried. An extraction that finished with entities but without relations or embeddings - because the language model or the embedder was unreachable at the time - is marked "Incomplete" with the reason. So far only failed jobs had a retry button, so the only way to get the missing relations was to delete the document and upload it again. Incomplete jobs now have the same retry button: once the model is reachable, the job runs again in place and adds what was missing.
- A saved Ollama Cloud key no longer pulls extraction onto the local machine. Entering an Ollama Cloud key in Settings unlocks the cloud models in the model picker. But a provider entry that held only that key was treated as a full provider configuration and took precedence over the instance runtime, so relation extraction quietly went to the local Ollama - on a machine without a GPU that means timeouts and knowledge bases with entities but no relations. A key alone now leaves the instance runtime in charge; an entry with its own address still takes precedence as before. Relatedly, if the Ollama address itself is set to the cloud, the background workers keep using the local Ollama for embeddings instead of sending requests the cloud rejects (Ollama Cloud offers no embedding models), and the settings page explains what the key and the address are for.
- An empty answer from the relation model is reported, not counted as success. Reasoning models can spend the whole token budget on thinking and return no text. Relation extraction used to record that as a successful run with zero relations. It is now reported as incomplete with the reason and a hint (raise
RELEX_NUM_PREDICTor pick a model without a reasoning phase), and a local Ollama setup falls back to its lighter model. - The version in your update notice matches the release again.
gctrl.tech/version.jsonwas only rebuilt when the website changed, so releases that built only product images left it behind (the update check showed "latest 0.1.292" next to a notice for 0.1.294). It is now rebuilt after every release that ships a product image, and only once those images are published. - Also shipped since v0.9.13: every ingest now records the source document it came from, so search results name the file a passage belongs to and integrations can pass their own source reference; and the knowledge-base folder navigation works in every view mode.
v0.9.13 - "Update available" tells the truth, on every install
17 September 2026 · GCTRL Team / TortillaJackson
- The update banner now follows what is actually installed, not a version number. GCTRL has long detected updates the reliable way - each instance compares the digests of its running images with the registry, no matter where it runs or how it was installed. But the yellow banner and the bell in the header did not use that result: they compared version numbers, and the number is a release counter baked into the API image only. On 17 September two website-only releases advanced the counter without building a single product image. Every instance showed "Update available", the in-app update correctly found nothing to pull - and the banner stayed, however often you updated. The banner and bell now take the digest verdict: they appear when an image of yours is behind the registry and disappear the moment the update has been installed. The version comparison remains only as a fallback for installs that cannot reach the registry.
- It also catches updates the version number used to miss. The mirror image of the same flaw: a release that rebuilt only the web interface left the API's number unchanged, so an instance could be told it was current while a newer image was waiting. Digests have no such blind spot.
- A version is only announced when there is something to pull. The release pipeline publishes a new version to the update channel and the license service only if at least one product image was built for it; a website or documentation release re-ships the version that is already live.
- Seeing the banner right now? Run the in-app update once (or
curl -fsSL https://gctrl.tech/update | bash). That installs this release, and the banner clears when it finishes.
v0.9.12 - Scoped tokens now scope source passages too
17 September 2026 · GCTRL Team / TortillaJackson
- Security fix: a knowledge-base-scoped token could read source passages from other knowledge bases of the same account. A scoped token sees only the knowledge bases it was granted - that has held for the graph tools (
list_graphs,search_entities,get_entity,get_neighbors,shortest_path) since July. The passage paths were missed:search_chunks, the blendedquery/ Talk-to-Graph answer and the grounding snippets returned withget_entityandget_dossierwere limited to the account owner and the clearance rank only. We found it in an end-to-end test of an integration: a fresh token with a single grant on an empty knowledge base received passages from a colleague's audit report. Other accounts were never reachable, and clearance ranks were always enforced - the missing boundary was the knowledge base inside one account. Every passage read now goes through the same job allow-list the graph tools use, the blended answer is grounded on and cites only passages inside the token's scope, and a guard test fails the build if a future retrieval path forgets the scope. We recommend updating promptly if you hand scoped tokens to colleagues, agents or integrations. Details and a two-minute live check:docs/security/2026-09-17-chunk-scope.mdin the repository. compilationIdis now a hard filter for retrieval.search_chunksandqueryused to treat it as a preference and quietly fall back to the whole account when the knowledge base had no hit, so an answer "from knowledge base X" could rest on knowledge base Y. They now return what X holds and nothing else - an out-of-scope or unknown id yields an empty result. A Knowledge Wiki resolves to the passages of its source knowledge bases, so wiki chats keep working. If you relied on the old fallback, call withoutcompilationId.search_chunkstakes alimit. Up to 50 passages per call (default 5, as before), so an integration that fuses several searches no longer has to work with five.- Rollout note. The API enforces the scope on its own, so updating
gctrl-apicloses the hole even beforegctrl-kexis updated; the new KEX image then filters at the source, which restores full recall for tokens whose grants cover a small part of a large account.
v0.9.11 - The Knowledge Wiki stays visible on large instances
17 September 2026 · GCTRL Team / TortillaJackson
- The Wiki page finds your wiki no matter how many knowledge bases you have. The page loaded the 100 newest knowledge bases and picked the wikis out of that list in the browser. On an instance that had grown past 100 knowledge bases - easy to reach once an integration such as Anvil files a knowledge base and a code graph per project - an older Knowledge Wiki fell out of that window and the page showed "No wikis yet", although the wiki was intact and had been distilled the same day. The list endpoint now filters by type on the server (
GET /api/kg/compilations?type=WIKI, alsoRAWandCODE;totalrespects the filter), and the Wiki page asks for exactly the wikis, plus exactly the raw knowledge bases for the source picker, which had the same blind spot. The wiki picker for auto-distill schedules on the Triggers page was affected in the same way and is fixed with it. Nothing was lost and nothing needs to be re-distilled - the wiki reappears with the update. - The version shown in your update notice keeps pace with the release again. Finding an update never depended on us: each instance compares its local images with the registry. But the version number and changelog next to that notice come from
gctrl.tech/version.json, and that file had stood still since 11 September because the website deploy logged in to the registry with a 90-day access token that expired unnoticed. The deploy now uses the short-lived token of the release job itself and logs out again when it is done, so there is no credential left that can quietly run out. A second release step that leaned on the same token only rewrote a version marker in our deploy repository that no installer reads; it is removed rather than re-credentialed.
v0.9.10 - A trigger that fails once is retried, not retired
11 September 2026 · GCTRL Team / TortillaJackson
- Scheduled triggers recover from transient failures on their own. Every trigger - the Knowledge Wiki's auto-distill heartbeat, Obsidian, Google Drive and SharePoint syncs - was flipped to
erroron its first failed run, and the executor only ever picked upactivetriggers again. A single database pool timeout during a busy minute was enough to stop a trigger for good; on one instance the auto-distill had been silently idle for four days while its source graphs kept changing, and nothing but a red dot on the Triggers page told the story. An errored trigger is now retried like an active one - only paused stops it - after a short back-off of five minutes, so a transient hiccup heals itself and a permanently broken configuration stays visible aserrorwith its last error message without re-logging every minute. Existing triggers stuck inerrorpick up again with the update, no manual resume needed.
v0.9.9 - Read-only grants on access tokens
8 September 2026 · GCTRL Team / TortillaJackson
- A token can now be granted a knowledge base for reading only. Until now the read/write switch lived on the token as a whole: a colleague's personal, read-write token could not be given a shared knowledge base without also being able to write into it, so integrations such as Anvil minted a second, read-only token per room and member - and the shared room never appeared under the colleague's own token. Each grant carries its own
readOnlyflag (POST /api/users/api-keys/:id/grantswithreadOnly: true, also inside thegrantslist when a token is created; re-posting a grant flips it). A read-only grant keeps every read path unchanged - list, query, search, graph tools - and refuses every mutation that targets that knowledge base:store,ingest_file, node and relationship edits, chunk deletion and superseding, renaming, refreshing, deleting. A token whose grants are all read-only has no default knowledge base either, socreate_extractionis refused instead of producing an orphaned extraction. Existing grants stay read-write; the token list and the Access Control page show the flag (ro).
v0.9.8 - Corrections that stick
8 September 2026 · GCTRL Team / TortillaJackson
- A deleted chunk no longer haunts the search.
delete_chunkremoved the Postgres row but only deleted the Qdrant point when theqdrant_point_idcolumn was set - and on thestore/text path it never is. The vector stayed, its payload carries the full text, and the "deleted" passage kept coming back as a cited source. On one instance three chunks a user had just corrected were still quoted after their deletion. The chunk id is now the fallback point id (KEX writes row and point under the same UUID), so a delete is a delete. A second cause hid behind the first: the API guessed the collection nameGCTRL_chunkswheneverQDRANT_COLLECTIONwas not set on its own container, while KEX had createdgctrl_chunks- Qdrant names are case-sensitive, so every API-side vector delete (chunk, supersede, job) 404ed silently. The API now lists the collections once and matches the name case-insensitively. supersede_chunkretires a statement without deleting its document. When a user corrects a fact that a reviewed document still states, the document must stay - but the old passage must stop being cited. The new gateway tool andPOST /api/kex/chunks/:id/supersedearchive the chunk with reasonsuperseded, remove its vector (the vector path has noarchivedfilter) and record the retirement inknowledge_corrections(element_kindchunk,actionflag). Reinforcement never revives a superseded chunk, just as it never revives a dedup duplicate.
v0.9.7 - Images become knowledge
7 September 2026 · GCTRL Team / TortillaJackson
- Image uploads no longer die as
application/octet-stream. Every extension outside pdf/txt/md/html/csv/json/docx was enqueued with a generic type, so a PNG, a PPTX, an XLSX or an .eml uploaded through the API or an agent'singest_filefailed in KEX with "Unsupported mimetype" - although KEX could read all of them. One extension-to-type map now covers images (PNG/JPG/WEBP/TIFF/BMP/GIF), the Office, OpenDocument, mail and markup types, the web dropzones accept images, and KEX routes image files by extension as well. OCR reads English, German, French and Spanish, orients phone photos by their EXIF tag and flattens transparent images before Tesseract sees them. - Images are transcribed by the model you already run - never by a second one. When the active runtime understands images, KEX hands each image (and the first pages of a scanned PDF) to it and stores a structured transcript: title, type, every legible word in reading order, the structure of a board as groups, items and
A -> Bconnections, the entities on it, a short summary. Tesseract's text is appended so exact strings stay findable, and it remains the fallback whenever vision is off, unknown, busy or empty. The image goes to the model only when the relation runtime is the globally loaded model on the same server - on a box that shares its RAM between GCTRL and other agents, nothing ever loads a second model for a picture. - A busy queue is no longer reported as a failure. The job watchdog failed every upload that had waited more than ten minutes as "Queue stalled" - even while the single extraction worker was busy completing the queue in front of it. A folder import of 69 documents on one instance saw 43 of them, every image among them, flagged as failed at minute ten and then quietly finished by the worker afterwards. Pending jobs are now only failed when the worker itself has made no progress for ten minutes (or after six hours regardless); a long queue simply waits, visibly, as pending.
- The runtime knows whether it can see. Settings → Infrastructure gains an Image understanding switch (Auto / On / Off). In Auto, GCTRL probes the model once with a 1×1 image - a vision-language model such as Qwen3.6 on oMLX answers, a text-only server rejects the part - and shows the result as a Vision or Text only badge next to the health pill; an inconclusive probe (busy server) is retried in the background and never counts as a verdict.
get_active_runtimereportsvision,vision_modeandvision_detected;switch_runtimetakesvision.
v0.9.6 - Memory that learns from use
5 September 2026 · GCTRL Team / TortillaJackson
- Hot memory no longer empties itself overnight. The memory governance cycle archived any non-pinned dossier whose heat had decayed for one idle hour - about eight hours after it was built - and any passage that had grounded exactly one answer some three hours later. An office that stops at five found every dossier archived by nine: the next
get_dossieranswered "no dossier" and rebuilt the same profile through the LLM, and every passage that had ever been cited had quietly left lexical retrieval. On the two instances we checked that left 1 dossier live against 49 archived, and 0 against 443. Eviction is now a long-idle decision - seven idle days for a dossier, thirty for a passage - a dossier that was never read is never evicted, an archived dossier is revived on access instead of rebuilt, and a migration brings back everything the old policy took while leaving deduplicated duplicates (whose vectors are gone) archived. - Use strengthens, disuse forgets. GCTRL's memory tiers now follow the Hebbian rule. Every read path reinforces what it returned - the chat answer, an agent's
search_chunks,get_entity,get_dossierand amemory_feedbackvote - weighted by rank and by how strong the signal is; until now only the chat path left a trace, so a memory used exclusively through agents could never learn what those agents actually use. Each use also lengthens the item's own half-life: fresh knowledge halves in a week, knowledge that keeps being used decays on a scale of months (capped at 180 days), and the fixed "lose five percent every ten minutes" decay is gone. A rejected fact (memory_feedbackdown) drops out of the hot set at once. - Passages that fire together wire together. The passages returned in one retrieval are linked as co-activated, with a bounded Hebbian weight that grows on every joint hit and fades with a thirty-day half-life. At search time a strongly linked neighbour of the hits is pulled into the result, so a fact that always mattered together with the one you asked about comes along even when the query did not mention it.
- Heat finally reaches ranking. Search gives reinforced passages a bounded rank bonus on top of dense + lexical fusion and the cross-encoder rerank: one previous use lifts a passage about three positions, ten uses about twelve, and the bonus caps at fifteen - a prior on what has proven useful, never an override of relevance. Every returned passage reports its
hebb_bonus; a pulled-in neighbour is markedvia: coactivation. - The memory snapshot shows the new layer.
memory_healthreports the number of co-activation pairs, how many are strong, and the average half-life of the knowledge in use, next to the heat and trust distributions it already had. Settings → Memory shows the same four numbers as tiles under "Association & consolidation", and the last-run breakdown lists decayed and pruned pairs. - Folder counts say what the folder shows, and users are managed from Settings. A folder card counted every knowledge base of the account regardless of clearance caps, token grants, KB scope and the Codebase-access switch, while opening the folder listed only the twenty newest graphs of the whole account. Counts now use the same visibility rule as the list, the card separates "graphs here" from "in subfolders", the list takes
folderId(rootfor unfiled graphs) and defaults to 100 rows.list_graphson the agent gateway now carriestype,folderId,folderPathand live counts so an agent picks its knowledge base by placement, not by guessing from names. A new Users tab (administrators only) lists every account and adds the switch that was missing: activate or deactivate an account (PUT /api/admin/users/:id/active).
v0.9.5 - Entity recognition tuned on a real Apple-Silicon box: recall 0.94 -> 0.99
Measured on the 6-document quick gold set on a Mac Studio running Qwen 3.6 on MLX; two repeat runs each, no memory pressure, embeddings untouched.
- Organizational units are entities now. Departments, business units, divisions and subsidiaries ("Produktentwicklung", "Vertrieb & Partnermanagement") were the only systematic misses left on the gold set, and every "who heads what" relation depends on them. The label set only ever grows; the bi-encoder NER stays label-count independent, so this costs no time.
- The entity-verify tier runs before relation extraction. It used to run after, so the relation prompt still saw every junk candidate. Verify-first hands the relation model a curated list. On a strong local model (Qwen 3.6, thinking off) the tier costs no recall any more (0.940 -> 0.941 before, 0.976 with verify-first) and lifts entity F1 from 0.70 to 0.76-0.77. Still opt-in (
KEX_ENTITY_VERIFY=true); with a slightly lower detection threshold (NER_THRESHOLD=0.40) the same set reaches detection-recall 0.988 and F1 0.771 at ~26 s per document. - Markets served are no longer "located in". The largest true relation false-positive class was located_in(org, region) for sales territories ("active in EMEA, France and the Nordics"). located_in is now reserved for headquarters, offices and residence.
- Measured, not applied: turning off the per-document fact log saves ~4.5 s per document but removes the atomic-fact chunks retrieval relies on; the format pre-pass (dates, money, quantities) stays on - switching it off did not improve quality.
v0.9.4 - Apple-Silicon inference as a first-class runtime, and a guardrail that tells busy from broken
4 September 2026 · GCTRL Team / TortillaJackson
- MLX / oMLX is now a selectable runtime. Settings → Infrastructure lists "MLX / oMLX (Apple Silicon, this host)" next to Ollama, llama.cpp and vLLM: point it at the server on your Mac (the default is
http://host.docker.internal:8020), paste the server's API key, and every purpose that inherits the global runtime - chat, Talk to Graph, relation extraction, wiki distillation, dossiers and the user profile - runs on it. Batch workers authenticate against a keyed server through an internal credential lookup; the key never enters the job queue. - A busy model server no longer looks like a dead one. Under memory pressure an inference server answers with "busy, retry later" style codes (409, 429, 503, 507). GCTRL used to count three of those as three failures and silently switch the whole platform back to bundled Ollama, where the configured model does not even exist, and left an alarm banner up for a day. Those responses are now retried with backoff on every path (API, extraction, fusion), never count toward the auto-revert, and the guardrail only ever reverts when bundled Ollama is proven able to take over. Re-applying a runtime clears stale banners.
- The health probe finally sends your API key and accepts a base URL with or without a trailing
/v1- the same root the chat call uses, so "unhealthy" now means unreachable, not "the probe forgot the key". The Infrastructure card shows the actual reason when a runtime is unhealthy. - Thinking is switched off for extraction on OpenAI-compatible runtimes (
enable_thinking: false, overridable withGCTRL_LLM_THINK/KEX_THINK/FUSE_THINK), and the relation-extraction token budget (RELEX_NUM_PREDICT) now reaches/v1servers asmax_tokens. A reasoning model such as Qwen 3.6 answers structured extraction calls in seconds instead of thinking for a minute first. - Max parallel requests per runtime. A new per-runtime limit (default 4) caps how many generation requests GCTRL opens at once against a local server, so a batch ingest cannot push a 48 GB machine into memory pressure on its own.
- A leftover local-Ollama connection no longer hijacks the global runtime. A per-user Ollama entry without key, URL or model (what the Ollama override screen leaves behind) used to win over the operator-configured runtime, so extraction, fusion and chat quietly ran on Ollama while Settings showed MLX. Such an empty entry is now ignored whenever a global runtime is configured; an explicitly chosen provider still wins.
- Three more call sites follow the configured runtime: the fact log during ingest, entity dossiers and the user-profile distillation were hard-wired to Ollama; they now use the same runtime as everything else. Entity-resolution embeddings in FUSE deliberately stay on Ollama
nomic-embed-text- the licensed tuning profile is calibrated on those vectors.
v0.9.3 - An update keeps your containers the way you configured them
28 August 2026 · GCTRL Team / TortillaJackson
- Updating from inside the app no longer strips your deployment configuration. The in-app updater recreated every service container from a short list of settings and silently dropped the rest: the reverse-proxy labels that put GCTRL behind your own domain (the site answered 404 after every update), the identity that lets
docker composerecognise the containers, the host entry that points the extraction engine at an Ollama running on your machine (extractions finished with entities and no relations), the health check that the extraction and fusion services wait for, and named volumes. The updater now carries a container's complete configuration across, exactly as it was created, and only leaves out what must be fresh - the auto-generated hostname and the old container's network alias. Custom labels, extra hosts, health checks and volumes survive the update, in the published stack and in any override file you maintain next to it. - If an earlier update already took your labels with it: remove the affected service containers and bring them back with
docker compose up -donce; from this version on they stay intact.
v0.9.2.1 - Memory that survives the night, numbers you can trust
26 August 2026 · GCTRL Team / TortillaJackson
- Hot memory no longer empties itself overnight. The memory governance cycle archived any non-pinned dossier whose heat had decayed for one idle hour - about eight hours after it was built - and any chunk that had grounded exactly one answer about three and a half hours later. An office that stops at five found every dossier archived by nine: the next
get_dossieranswered "no dossier", rebuilt the same profile through the LLM, and every passage that had ever been cited had silently left lexical retrieval. On one live instance that left 1 dossier live against 46 archived and 1,141 archived chunks. Eviction is now a long-idle decision - seven idle days for a dossier, thirty for a chunk - heat keeps ranking, an archived dossier is revived on access instead of rebuilt, and the migration brings back everything the old policy evicted while leaving deduplicated duplicates (whose vectors are gone) archived. - Folder counts say what the folder shows. A folder card counted every knowledge base of the account - across clearance caps, token grants, KB scope and the Codebase-access switch - while opening the folder listed only the twenty newest graphs of the whole account, filtered in the browser. A card could read "7 graphs" over an empty folder, and a KB-scoped colleague token learned the size of graphs it may not see. Counts now use the same visibility rule as the list, the card separates "graphs here" from "in subfolders", and the folder view asks the server for exactly that folder (
GET /api/kg/compilations?folderId=…,rootfor unfiled graphs). The list's default page grew from 20 to 100 (max 500) - the FUSE picker, the Access page and the published MCP server'slist_graphsall read that page. - Agents see where a knowledge base lives.
list_graphson the agent gateway returned only id, name and classification, so a model told to "pick your knowledge base" had to guess between "Team Wave" and "Team Wave (code)". Every entry now carriestype(RAW, WIKI, CODE),folderIdandfolderPath(Users/<name>/Code,Projects/<client>/…,Global/…), live node/edge counts and the number of sources, and the skill explains the placement rule: personal learnings underUsers/<you>, confirmed team facts in the project, code decisions in the repository's CODE graph. - Users are managed from Settings. A new Users tab (administrators only) lists every account with role, clearance, verification, tier, token balance, number of graphs and API keys and when it registered, with a seven-day registration counter - and adds the switch that was missing from the product entirely: activate or deactivate an account (
PUT /api/admin/users/:id/active). Deactivation was enforced on login, on every request and on API-key auth, but could only be triggered through SCIM. An administrator cannot deactivate their own account.
v0.9.2 - Every agent codes with the graph
25 August 2026 · GCTRL Team / TortillaJackson
- The Codebase KB is now automatic for every access token. A token with Codebase access - the default - can create the code graph of the repository its agent works in, a KB-scoped colleague token included, and is granted it the moment it exists; nothing for an administrator to prepare. The published MCP server (
gctrl-mcp1.2.0) indexes the repository it is started in right after start-up whenGCTRL_CODE_AUTO_INDEXis set (incremental - a warm repository takes seconds), the Access page's connect snippet sets it, andgctrl initwrites the same two-entry config into.mcp.json,.cursor/mcp.jsonor.codex/mcp.jsonin one command. Auto-indexing stays explicit on purpose: code leaves the machine only where someone wrote that line. - The skill teaches the coding protocol. Skill v6 tells every connected agent how to work in a repository: index once per session, navigate through
code_symbol/code_trace/code_architectureBEFORE opening files and read only the ranges they point to, runcode_impactbefore changing a symbol, re-index after larger edits, askqueryfor the why and the code tools for the where, and store decisions next to the symbols they concern. It is one text in one place now - the served skill, the MCP server instructions, the gateway instructions and the Cursor/Codex copies are generated from it, and a test fails when a copy falls behind. - Measured, not assumed. A new protocol bench answers the same structural questions once through the graph and once by grep-and-read (grep plus a 40-line window around every hit - deliberately generous to grep). On GCTRL's own repository (Rust, TypeScript, Python), twelve questions: 94.2 % fewer tokens, 12 of 12 answered correctly; on a 1,000-file TypeScript application: 89.8 % fewer, 12 of 12. The bench also caught a trap before it shipped:
code_traceandcode_impactanswered a bare symbol name with an empty result - "no callers", exactly the wrong answer before a refactor - because graph names are file-scoped. Both now resolve bare names too. - Agents file what they create.
create_compilationon the agent gateway takesfolderPathandtype, so a graph an agent creates lands inUsers/<name>/…orProjects/<client>/…instead of unfiled at the tree root.
v0.9.1 - Knowledge bases land where they belong
25 August 2026 · GCTRL Team / TortillaJackson
- Agents file the knowledge bases they create. The
create_compilationtool of the agent gateway now takes afolderPathand files the new knowledge base on creation, find-or-create, exactly like the web app and the REST API already did. Until now every knowledge base an agent created over MCP sat unfiled at the root of the tree, next to theUsers/andProjects/folders everyone else keeps - on a shared instance that was most of them. The tool tells the agent to always pass a path. - Code graphs go to the right person's folder.
gctrl_code_indexreads two new settings from its environment:GCTRL_CODE_COMPILATION_IDpins the compilation a session indexes into (one project, one repository, one code graph), andGCTRL_CODE_FOLDERnames the folder an auto-created code graph is filed in. A host that launches the MCP server per user - Anvil does - sets them, so a colleague's repository lands inUsers/<colleague>/Codeand a project's inProjects/<client>/<project>/Code, instead of in the account owner's default folder. An explicitcompilationIdfrom the agent still wins.
v0.9.0 - Your code becomes a knowledge base
23 August 2026 · GCTRL Team / TortillaJackson
- Point GCTRL at a repository and its structure becomes a knowledge base. A new knowledge base type, CODE, holds files, classes, functions and methods as graph nodes, connected by CONTAINS, IMPORTS, CALLS, INHERITS and IMPLEMENTS edges, with one searchable chunk per symbol. Indexing runs wherever the code already lives:
gctrl code index <path>from the CLI,gctrl_code_indexfrom the MCP server, or agctrl-codeentry inside an Anvil agent. Python, TypeScript/JavaScript and Rust are parsed with tree-sitter, and re-indexing is incremental - only files whose content hash changed are uploaded, and files that were removed are cleaned up. Agents get four tools built on the graph:code_symbol(where is X defined),code_trace(who calls X, what does X call),code_impact(what breaks if these files change - run it before a refactor) andcode_architecture(one call for languages, packages, hotspots and dead-code candidates). Decisions and notes can live in the same knowledge base as the symbols they concern, so the why and the where stay together. Measured on GCTRL's own repository (464 code files, 7,134 symbols, 9,080 edges): call-graph edges were 100% correct on 1,119 independently checked edges (cross-checked against the TypeScript compiler and by hand), every edge carries its own resolution quality (exact vs heuristic), and answering structural questions through the tools used 95.6% fewer tokens than grep-style exploration. Code knowledge bases file themselves underUsers/<name>/Codeautomatically. - Access tokens now have a dedicated switch for code. Creating or editing an access token exposes a "Codebase access" toggle that decides whether that token can see code knowledge bases and use the code tools at all - off means no code tools, no code knowledge bases in any list or grant, no code chunks in search or chat answers, and no code writes or changes, for both scoped colleague tokens and full tokens. Existing tokens keep what they already had (the default is on); turn it off per token from the Access page.
- A dead container on gctrl.tech is gone for good. A legacy standalone API container, left over from an older deployment path and silently recreated by every release since, had been restarting every few seconds for weeks without ever serving a request. It is removed, and the release pipeline no longer creates it. Builds are leaner too: build contexts no longer drag along multi-gigabyte local build artefacts.
v0.8.8 - A new knowledge base starts empty, as it should
16 August 2026 · GCTRL Team / TortillaJackson
- A knowledge base you had just created showed everything else in the account. Create a knowledge base, open it before extracting anything into it, and it listed the entities of your other knowledge bases as if they were its own. The cause was a single rule: a knowledge base holds whatever its extractions put there, and when there were none yet, the graph was read for the account instead of for the knowledge base. That was meant as a convenience for the very first knowledge base of a new account, but it applied to every knowledge base that had not been extracted into - and since a knowledge base only gains extractions once you run one, "empty" is what every new knowledge base is. It affected the entity counts, the graph view, the entity detail and the graph tool your agents use. A knowledge base is now exactly its own extractions, and an empty one is empty.
- The same rule reached further than the eye. A knowledge base published as a public embed showed the account's whole graph to anyone with the link while it was still empty, and an edit or a deletion aimed at an empty knowledge base was applied across all the others. Both are scoped to the knowledge base itself now.
- Nothing became invisible in the process. Older installations can hold extractions that were never filed into any knowledge base, and until now those were only reachable through the very rule that has been removed. They are now filed into their owner's default knowledge base on update, so what you could see before, you can still see - in the one place it belongs to, and only for the account it belongs to.
v0.8.7 - A fresh install works out of the box, and says so when it does not
16 August 2026 · GCTRL Team / TortillaJackson
- A new installation reached under its own hostname flickered instead of showing the activation dialog. The screen reloaded several times a second and nothing could be clicked. The activation check runs before anyone signs in, because a machine installed minutes ago has no accounts yet, but it was answered as if a session were required. The rejection sent the browser to the sign-in page, loading that page ran the check again, and the loop never ended. Installing on localhost never showed it, because the activation step is skipped there. The check now answers without a session, and it answers with less: reachability and activation state only, never the licence tier or credit balance of an installation that has not signed anyone in yet.
- On Linux, extractions produced entities and no relations at all. If Neo4j, Qdrant or Ollama were already running on the machine, GCTRL was told to reach them under a name that Docker on Linux does not resolve unless the container is explicitly taught it - and of the services that need it, only one had been. So the extraction engine could not reach the model that reads relations, could not reach the one that builds embeddings, and quietly finished with a handful of unconnected entities, most of which were then tidied away as isolated. Every service that can be pointed at a program on your own machine now resolves it, in the published stack and the deployment template alike, and a build check keeps the installer from ever again handing out an address the stack cannot resolve.
- An extraction that lost half its pipeline no longer reports plain success. Relations skipped because the language model was unreachable, or embeddings that never came back, left the job marked "completed" with the reason buried in a log file - which is precisely why a broken installation looked healthy. Such a job is now marked as completed but incomplete, carries the reason with it, and shows up that way in the extraction list, the job page, the command line, the n8n trigger and for connected agents. A knowledge graph that is missing half of itself says so.
v0.8.6 - Deleting a knowledge base now deletes its knowledge
14 August 2026 · GCTRL Team / TortillaJackson
- Deleting a knowledge base left every entity behind in the graph database. The knowledge base disappeared from your account, but its nodes and relationships stayed in Neo4j forever, and with the knowledge base gone there was nothing left that could ever find them again. Deleting an extraction had the same result by a different route: it skipped the graph on purpose and deferred to knowledge-base deletion, which did not do it either. Nothing in GCTRL ever removed an entity, so every install has been accumulating the remains of everything its owner deleted. Both paths now clean up after themselves, and a nightly sweep clears what earlier versions left behind.
- Shared entities survive a deletion that is not theirs. The same entity often comes from several documents, so removing one of them must not take the entity with it. Every node and relationship now records all the extractions it came from, not just the most recent one, and deletion removes an entity only once the last of them is gone. Existing graphs are upgraded to this record automatically on the first start after the update.
- A knowledge base shared with a colleague showed them less than it should. Access for a scoped colleague was decided by which extraction touched an entity last, so an entity that also appeared in a knowledge base someone else updated more recently silently vanished from their view - it was in the graph, it was granted to them, and it did not show up. Access is now decided by everything an entity belongs to.
- Exporting a knowledge base produced an empty file. Every export - JSON-LD, RDF Turtle and GraphML alike - looked up the graph by a marker that only an internal bookkeeping node carries, so it never found a single entity. Exports now contain what the knowledge base actually holds.
v0.8.5 - Word documents laid out in text boxes are readable again
14 August 2026 · GCTRL Team / TortillaJackson
- A .docx whose text sits in text boxes or tables was rejected as empty. The extractor read only the document's plain paragraphs, which is exactly what a layouted Word file does not use: a booklet, a one-pager or a form puts every line in a text box, and tables were skipped as well. Such a file came back as "DOCX contained no extractable text" although it was full of it - on the document that surfaced this, 3806 characters in 16 text boxes and nothing outside them. Text boxes, tables, headers and footers are now read along with the body, in document order. Word stores a text box twice (a modern and a legacy copy of the same text), and a repeated header is inherited rather than re-written, so both are recognised and counted once instead of turning up as duplicates in your knowledge base.
v0.8.4 - Updates clean up after themselves
13 August 2026 · GCTRL Team / TortillaJackson
- Every update used to leave its predecessor on your disk, forever. GCTRL's images ship under a moving
latesttag, so each update pulled the new image and quietly abandoned the old one: still on the machine, still several gigabytes, referenced by nothing. Nothing ever collected them, so a machine that had been updated a dozen times was carrying a dozen dead copies of GCTRL. Updates now reclaim them, both before pulling and right after the swap, so an installation stays at the size of the version it is running. The clean-up runs in the in-app updater, thegctrl.tech/updatescript and the pip installer alike, and it reports what it freed instead of doing it behind your back. - The clean-up only ever touches GCTRL's own images. It identifies them by the registry they came from, and skips anything a container still uses, running or stopped. Other software on the same machine is never considered, not even its unused images. If you need the old copies kept anyway, for instance on a machine with no route to the registry, set
GCTRL_KEEP_OLD_IMAGES=1in your.env. - Freeing the disk before the download also fixes the update that ran out of space. The reclaim happens first, so the room the incoming images need is made available before they start arriving rather than after.
- Rollback works now. It was recording internal image IDs and then trying to fetch them as if they were addresses, which cannot work, and the failure was swallowed, so rolling back appeared to succeed and changed nothing. It now records proper image addresses, fetches the previous version from the registry and repoints your stack at it.
https://gctrl.tech/rollbackalso served the website instead of the script until now, so the command printed at the end of every update was never able to run.
v0.8.3 - The install command on the homepage works on every machine again
13 August 2026 · GCTRL Team / TortillaJackson
- The one-line install on the homepage was a dead end on most Linux machines. It read
pip install gctrl && gctrl install, and on Arch, Debian 12+, Ubuntu 23.04+, Fedora 38+ and any Mac running Homebrew's Python, pip flatly refuses to write into the system Python: it answerserror: externally-managed-environmentand stops before it has even looked up the package. Nothing was wrong with the package, but the very first command on the site failed for a large share of self-hosters. The homepage shows the shell installer again,curl -fsSL https://gctrl.tech/install | bash, which has no such gate. - The install docs now say what to run on your system instead of what usually works. curl is the recommended path on macOS and Linux, pip is the native Windows path, and a new section on externally managed environments gives the four real answers - pipx, uv, an explicit
--break-system-packages, or a virtualenv - along with the follow-on trap where the freshly installedgctrlcommand is not yet on yourPATH. The pip package itself is unchanged and still installs the identical stack.
v0.8.2 - A new knowledge base can be born private
13 August 2026 · GCTRL Team / TortillaJackson
- An integration creating knowledge bases for you can now set their privacy mode. Private Memory (
open/cloaked/local_only) could only ever be changed from a signed-in session, so anything created on your behalf through an access token - a workspace tool provisioning a graph per project, for instance - was stuck at the open default, and a tool that tried to tighten it got a refusal it could only swallow. The setting is now accepted when the knowledge base is created, and the response says which mode it got. Changing the mode of an existing knowledge base stays a signed-in-session action: at creation there is no earlier choice to overrule, but later there is, and a delegated key must not be able to loosen what you decided.
v0.8.1 - Folders tell the truth, and new knowledge bases file themselves
10 August 2026 · GCTRL Team / TortillaJackson
- Every folder showed "0 graphs", however full it was. The count was worked out in the browser from the knowledge-base list, and that list is the 20 newest unless you ask for more - so any folder whose graphs were older simply counted nothing. It also shrank while you typed in the search box, because it counted the filtered result. The number now comes from the server, covers everything in a folder including its subfolders, and no longer moves when you search.
- New knowledge bases now land in a folder by themselves. Placement used to be a separate step after creation, and several paths skipped it: knowledge bases created from a chat, the result of a fusion, and graphs made through the API all ended up loose at the top level. Creating a knowledge base and filing it are now one operation, so personal graphs go to
Users/<name>/and a project's graph toProjects/<customer>/without anyone having to remember. - Deleting a folder moves its contents up, as the button always promised. Until now the graphs and subfolders inside it dropped to the top level instead of moving into the parent folder.
- Obsidian imports get their own graph under
Global/Obsidian. An import that named no target used to be added to your oldest knowledge base, which is how a single graph quietly absorbed years of unrelated material. Choosing a target explicitly still overrides this. - Access tokens scoped to specific knowledge bases can no longer reshape your folders. Such a token could rename, move and delete any folder in the account and relocate graphs it had no access to. Folder changes are now an owner action, and moving a graph into a folder that is not yours is refused instead of silently hiding it.
- A new account starts in
Users/<name>. The old "My Workspace" folder is gone; it was created for everyone and used by nothing.
v0.8.0 - Cloaked cloud chat is as fast as uncloaked
7 August 2026 · GCTRL Team / TortillaJackson
- Pseudonymizing a chat request no longer costs you seconds. Cloaking compares your prompt against the entity dictionary built from your own documents, and it used to test every character of the prompt against every entry of that dictionary. On a long conversation with a large knowledge base that got expensive fast: on our own box a 60,000-character prompt spent about 35 seconds in the cloak step alone, before the model had even seen it. Now only the entities that can actually occur in the text are considered, the matcher runs without re-allocating on every comparison, and the pseudonym registry is read once per request instead of once per message. The same measurement is now about 0.3 seconds, and time-to-first-token with cloaking on is indistinguishable from cloaking off. What the cloud model receives is byte-for-byte what it received before, so nothing about the protection changes, only its cost.
v0.7.9 - Extraction duration shows real processing time, not queue wait
5 August 2026 · GCTRL Team / TortillaJackson
- "Your Extractions" now reports the actual processing time. The per-job duration was measured enqueue-to-completion, which also counted the time a job spent waiting in the queue behind other jobs - so a 4.8-second extraction inside a batch could read as ~481 seconds. The worker now stamps the true processing time (dequeue to result) onto each job and the list shows that. Jobs recorded before this update fall back to the old wall-clock reading.
v0.7.8 - Reasoning-skip speedup extended to distillation and conflict resolution
5 August 2026 · GCTRL Team / TortillaJackson
- The
think: falsespeedup now covers the rest of the pipeline's background LLM work. After extraction (v0.7.7), the same reasoning-skip now applies to the FUSE distillers - the auto-maintained knowledge wiki, on-demand dossiers and the user-profile summary - and to the classification-conflict resolver. On a reasoning model like gemma4:31b these skip the chain-of-thought they only discard anyway, for the same multi-x speedup at identical output. User-facing chat and RAG answers are deliberately left untouched, so they keep their reasoning. Per-service overrides to keep reasoning on:FUSE_THINK=trueandCONFLICT_RESOLVER_THINK=true.
v0.7.7 - Faster structured extraction on reasoning models
5 August 2026 · GCTRL Team / TortillaJackson
- Extraction skips the reasoning trace on thinking models. Relation extraction, auto-classification, entity verification and the fact-log distiller now tell Ollama
think: false, so a reasoning model (gemma3 / gemma4, gpt-oss, qwen3, deepseek-r1) no longer spends most of its output on a chain-of-thought the extraction parsers then throw away. Measured about 3.7x faster on gemma4:31b (44.7s to 12.0s) at identical JSON, and a ~200-character document drops from ~56s to under 20s. Models without a thinking capability (like the default qwen2.5:7b relation model) ignore the field, so nothing changes for them, and chat keeps its reasoning. SetKEX_THINK=true, or a per-purposeRELEX_THINK/AUTO_CLASSIFY_THINK/ENTITY_VERIFY_THINK/FACT_LOG_THINK, to keep the reasoning.
v0.7.6 - EU AI Act transparency + the GCTRL blog
5 August 2026 · GCTRL Team / TortillaJackson
- EU AI Act transparency, shipped in the product. Since 2 August 2026 the Act's Article 50 obligations apply, and GCTRL now wears them visibly: Talk to Graph states plainly that you are interacting with an AI system, auto-generated wiki pages carry a machine-readable
ai_generatedmarking in their frontmatter (it travels with every Obsidian sync and export), public graph embeds declare themselves via meta tags, and graph exports include AI provenance in their JSON-LD. Our full self-assessment - where GCTRL sits under the Act and what deployers get for their own duties - is published on the Compliance page. - The GCTRL blog is live at gctrl.tech/blog: engineering notes on self-hosted knowledge graphs, GraphRAG, sovereign AI memory and compliance, starting with four posts. Linked from the site footer.
v0.7.5 - Faster extraction, embeddable node deep-links, cloak-safe tool calls
5 August 2026 · GCTRL Team / TortillaJackson
- Extraction stops stalling on the wrong model. Default installs now run relation extraction on their configured relation model (qwen2.5:7b) right away, instead of falling through a 180-second timeout when a mismatched chat model slipped in - so a small document that could take minutes now finishes in seconds. Extra safety net: if you deliberately pick a relation model that is not loaded, the worker fast-fails to the fallback instead of re-paying that timeout on every window of the document.
- Embeddable graphs can open a specific node. An embed can now deep-link straight to a node and its Source Text (the underlying chunks), offer free-text node search, and be driven by the hosting page over a strict, origin-checked message channel - all inside the embed's existing read-only, single-graph scope. Nothing new is exposed; it reuses the access the shared embed link already had.
- Cloud cloaking no longer garbles agent tool calls. With entity cloaking on for a cloud model, tool results and tool-call arguments now stay byte-exact: machine data handed back to the model is left untouched, and any pseudonym that reaches a tool-call argument is reversed before it leaves the gateway, streaming included - so agentic file and write actions through the cloak gateway are safe again.
v0.7.4 - Pricing rework: unlimited tokens everywhere, plans buy access & compliance
5 August 2026 · GCTRL Team / TortillaJackson
- Inference tokens are now unlimited on every plan - including Free. The 1,000,000-token monthly grant on Free is retired; there is no grant because there is no meter. Extraction, fusion and chat run on your hardware, and plans never touch day-to-day usage.
- Free is the whole platform for one person: all four modules, Wiki-LLM, MCP gateway, one full-access token and single-file manual ingest. Non-commercial use.
- Business (€29 per license / month) is the compliance suite: 10 scoped colleague tokens per license - stack licenses as the team grows - with KB scoping, clearance enforcement (PUBLIC / INTERNAL / CONFIDENTIAL / RESTRICTED), instant revocation and an audit trail, plus drive connectors and scheduled refresh.
- Enterprise replaces the former "Individual" tier: €25,000 / year with 100 seats included and additional seats individually priced - premium support and SLAs, deployment as managed cloud, your cloud, on-prem, air-gapped or sovereign, custom connectors, TISAX & ISO 27001-aware hardening, SSO / SCIM.
- The pricing page grew a full plan comparison and a definitions section, so what an inference token, an access token, a license and a seat each mean is spelled out in one place.
v0.7.3 - pip install, bigger uploads, sharper recall
29 July 2026 · GCTRL Team / TortillaJackson
pip install gctrl: a second, first-class way to self-host, alongside the curl script.pip install gctrl(orpipx install gctrl) thengctrl installbrings up the same stack - now cross-platform including native Windows, with Docker as the only prerequisite (no curl/openssl/bash needed). The curl one-liner keeps working unchanged.- Uploads over 2 MB now ingest: a hidden framework default capped request bodies at 2 MB, so any document larger than that failed with a "multipart parse" error before the real 25 MB limit ever applied. Lifted - a 3.4 MB PDF ingests end to end.
- Session fact log: each ingested document is now distilled into atomic memory facts stored as their own retrievable chunks, so buried one-liners (an updated deadline, a denial, a dated event) surface directly instead of losing the top-k race to bulk prose. A backfill script retrofits already-ingested corpora.
v0.7.2 - Developer community
29 July 2026 · GCTRL Team / TortillaJackson
- The GCTRL developer community is live: join us at reddit.com/r/GCTRL for questions, setups, benchmarks and roadmap discussion. Linked from the site footer next to GitHub.
v0.7.1 - License activation survives container recreates
22 July 2026 · GCTRL Team / TortillaJackson
Self-hosted operators reported that recreating the app containers (docker compose up -d, same images) could invalidate the license activation and silently stop ingestion. This release removes that whole failure class:
- Stable instance identity: activation now binds to a UUID persisted in your config volume, not to ephemeral container properties. Recreates, image updates and compose changes keep the activation - automatically.
- Self-healing activation: if the binding ever mismatches, the agent honors your validly signed license in a grace mode and re-attests itself in the background with the stored key. Only an active rejection by the license server (revoked, seat limit) stops enforcement - a temporarily unreachable server never does.
- No more lost jobs on license hiccups: ingestion jobs denied by a transient license state are now parked, visibly, and resume automatically the moment the license recovers - instead of failing terminally. Business denials (insufficient credits) still surface immediately.
- Honest health signals: the agent's status now reports a machine-readable reason, and a new /health endpoint returns non-200 while the license is unenforceable - so monitoring and the built-in container healthcheck actually catch it.
- Pin your versions: set GCTRL_IMAGE_TAG in your .env to pin the whole stack to a release (e.g. v0.1.230) or a commit sha. Every build is published under latest, a version tag and its git sha.
- Also fixed: agent timeouts are treated like an unreachable agent (graceful degradation instead of hard job failures), and retried jobs no longer trip the "queue stalled" watchdog prematurely.
v0.7.0 - Plans that scale, unlimited tokens & a big reliability sweep
22 July 2026 · GCTRL Team / TortillaJackson
- New plan model - Free, Business, Enterprise. Free now includes 1,000,000 tokens every month at no cost. Business and Enterprise run on unlimited tokens. Plans gate features and seats, never your day-to-day usage.
- Scoped colleague tokens by seat: Business includes 10 scoped tokens per license (stack licenses for more seats); Enterprise is unlimited. Embedding your own graph never counts against that.
- Your balance and plan now read correctly in the client: the free monthly grant is visible instead of a stale figure, and unlimited plans show as "Unlimited" rather than a meaningless number. The License tab was cleaned up into a single, clear view.
- Imports reliably land in the graph you chose: connector and vault ingests (Obsidian, folder sync, uploads) that completed but left their nodes invisible now appear in the target graph as expected.
- Retry failed extractions without re-uploading: re-run a single failed job or all failed jobs at once; connector jobs re-fetch straight from the source.
- Cloud cloaking hardened further: hosted "-cloud" models served through a local Ollama are now cloaked too, and the reasoning traces of reasoning models are de-cloaked - so a pseudonym never surfaces to you, and plaintext never leaves for the cloud.
- Model picker follows your active runtime: switch to a native GPU Ollama and the installed/selected state reflects that instance; missing recommended models re-appear for one-click download.
- Cleaner, tidier housekeeping: deleting an extraction now works and removes its chunks and vectors; auto-generated iframe embed keys no longer clutter your Access Tokens list (only the tokens you deliberately created show, and expired embed keys are pruned nightly); a background loop that could pile up maintenance jobs was fixed.
- Hardware panel detects Apple Silicon and NVIDIA GPUs for host GPU reporting.
- Security hardening: license activation is more robust, and access-token creation never trusts client-supplied plan or credit values.
v0.6.0 - Observability, GPU extraction & hardened cloaking
13 July 2026 · GCTRL Team / TortillaJackson
- GPU acceleration for knowledge extraction (NER): on GPU boxes now up to ~130× faster - a large document extracts in seconds instead of minutes.
- End-to-end observability across the whole platform (optional, self-hosted Arize Phoenix): every extraction, retrieval and LLM step is traceable. Off by default.
- Cloud cloaking hardened and proven end-to-end: names, companies, amounts and emails are pseudonymized before they reach a cloud model, and the answer is de-cloaked locally. Two edge cases (word boundaries, streaming leak) fixed.
- MCP server: GCTRL functions are now machine-accessible over MCP-over-HTTP (usable by Claude and other agents).
- Shipping-test gate extended: the automated release gate now also covers cloaking (11 checks) and catches compose drift before it ships.
v0.5.0 - Extraction & retrieval quality
12 July 2026 · GCTRL Team / TortillaJackson
- New bi-encoder NER as the default: the ontology can grow almost without bound without slowing extraction down (label-count independent). Quality-gated - better than before on two benchmarks.
- Typo- and mishearing-tolerant entity search: "skan module" finds "ScanModule", casing no longer matters - measurably better retrieval.
- Knowledge dossiers: on-demand build decoupled (no longer blocks the answer), Ollama models stay warm (no cold-start stutter), revived dossiers are served again.
- Large documents ingest reliably (no more spurious "worker died" on multi-minute extractions).
v0.4.0 - Reliable, scope-safe retrieval
11 July 2026 · GCTRL Team / TortillaJackson
- Multi-hop graph neighbourhood fixed: connected nodes (across several edges) are found reliably - including incoming edges like "person develops module".
- Scoped colleague tokens: a restricted user gets exactly the knowledge of their granted knowledge bases - without a colleague's knowledge leaking in (leak-safe by construction).