Translation Diff Export
Devolutions/UniGetUI
Compares UniGetUI JSON locale files against English, identifies untranslated or source-changed keys, and generates patch, reference, and handoff files for a target language.
A skill your agent uses when adding, finding, changing, reading or auditing a UI string in Trilium — "is there already a key for X?", "add a translation key", "what does <key say?", "what does this…
$ npx skills add TriliumNext/Trilium --skill working-with-translations -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install TriliumNext/Trilium working-with-translations --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/TriliumNext/Trilium.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/working-with-translations .claude/skills/working-with-translations && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "working-with-translations" agent skill from https://github.com/TriliumNext/Trilium/tree/main/.claude/skills/working-with-translations into .claude/skills/working-with-translations/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "working-with-translations", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/TriliumNext/Trilium/tree/main/.claude/skills/working-with-translationsType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add TriliumNext/Trilium --skill working-with-translations -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install TriliumNext/Trilium working-with-translations --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/TriliumNext/Trilium.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/working-with-translations .agents/skills/working-with-translations && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "working-with-translations" agent skill from https://github.com/TriliumNext/Trilium/tree/main/.claude/skills/working-with-translations into .agents/skills/working-with-translations/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "working-with-translations", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add TriliumNext/Trilium --skill working-with-translations -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install TriliumNext/Trilium working-with-translations --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/TriliumNext/Trilium.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/working-with-translations .cursor/skills/working-with-translations && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "working-with-translations" agent skill from https://github.com/TriliumNext/Trilium/tree/main/.claude/skills/working-with-translations into .cursor/skills/working-with-translations/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "working-with-translations", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/TriliumNext/Trilium.git --path .claude/skills/working-with-translations--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add TriliumNext/Trilium --skill working-with-translations -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install TriliumNext/Trilium working-with-translations --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/TriliumNext/Trilium.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/working-with-translations .gemini/skills/working-with-translations && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "working-with-translations" agent skill from https://github.com/TriliumNext/Trilium/tree/main/.claude/skills/working-with-translations into .gemini/skills/working-with-translations/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "working-with-translations", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install TriliumNext/Trilium working-with-translationsInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add TriliumNext/Trilium --skill working-with-translations -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/TriliumNext/Trilium.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/working-with-translations .github/skills/working-with-translations && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "working-with-translations" agent skill from https://github.com/TriliumNext/Trilium/tree/main/.claude/skills/working-with-translations into .github/skills/working-with-translations/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "working-with-translations", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add TriliumNext/Trilium --skill working-with-translations -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install TriliumNext/Trilium working-with-translations --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/TriliumNext/Trilium.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/working-with-translations .opencode/skills/working-with-translations && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "working-with-translations" agent skill from https://github.com/TriliumNext/Trilium/tree/main/.claude/skills/working-with-translations into .opencode/skills/working-with-translations/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "working-with-translations", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
working-with-translationsA skill your agent uses when adding, finding, changing, reading or auditing a UI string in Trilium — "is there already a key for X?", "add a translation key", "what does <key say?", "what does this…
Working With Translations is an agent skill from TriliumNext/Trilium. Use when adding, finding, changing, reading or auditing a UI string in Trilium — "is there already a key for X?", "add a translation key", "what does <key say?", "what does this button say in German?", "has this string been translated yet?", "which catalogue does this go in?", "any unused or misspelled keys?". Covers the three English catalogues (client / entry / server) and the routing rule that decides which one a key belongs to, and includes i18n.mjs to look a key up across all 39 locales, so neither the 226…
Its SKILL.md is about 3.3k tokens, which your agent loads only when the skill is triggered. The skill folder holds 1 other file.
It sits in Writing & Content, covering Translation and Internationalization. The repository describes itself as: Build your personal knowledge base with Trilium Notes. The licence is AGPL-3.0.
Read from SKILL.md and the folder at commit 4d9cb6d. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Ships script files (JavaScript), which the agent can run.
Shell commands in SKILL.md call:
nodepnpmFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use pnpm, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Working With Translations loads about 3.3k tokens when it runs. Until then it costs about 191 tokens; SKILL.md has 1,531 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from TriliumNext/Trilium at commit 4d9cb6d, republished under its AGPL-3.0 licence (© TriliumNext). 1,531 words, ~3,314 tokens.
.claude/skills/working-with-translations/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.Trilium's UI is localized with i18next. English is the source of truth and the only catalogue you edit by hand — the other ~38 locales belong to Weblate. This skill is the everyday case: you are building or changing a feature and need to add a string, find one that already exists, or check that nothing dangles.
Every mechanical step is i18n.mjs.
S=.claude/skills/working-with-translations/i18n.mjs
node $S find "Cancel" # English text → catalogue + dotted key
node $S find totp_enroll --key # search key paths instead of values
node $S show about.channel # dump one section
node $S show delete_note.delete_note --locales # what the string says in every language
node $S add client dialog.my_thing "My text" # insert, preserving key order + formatting
node $S callers about.channel.nightly # where a key is referenced
node $S missing # keys used in code but absent from the catalogue
node $S unused # catalogue keys nothing referencesNever read a whole catalogue to answer a question. apps/client/src/translations/en/translation.json is 226 KB / 4032 lines / 3384 keys across 304 top-level sections — reading it costs more than any question it answers. find and show exist so nothing has to.
Never hand-edit the JSON either. add writes through the file's own indent (2), EOL (LF) and trailing newline, and appends into the correct parent object. A round-trip is byte-identical, so a one-string change is a 3-line diff. A hand-edit gets the nesting or the trailing comma wrong; a naive JSON.parse → stringify at the wrong indent rewrites all 4032 lines.
show <key> --locales prints the value in every locale that has it, then the locales that don't
and the ones whose value is byte-identical to English:
--- client: delete_note.delete_note
en "Delete note"
de "Notiz löschen"
ro "Șterge notița"
…
22/39 locales translated
missing: az, bg, ca, el, en-GB, fa, fi, hr, hu, md, mr, nb-NO, nl, sl, sv, ur, viUse it to answer "what does this button say in German?", "has this been translated yet?", or
"why does the Romanian UI show that?". Identical-to-English is usually legitimate — a proper noun
(hidden-subtree.llm-title is "AI / LLM" nearly everywhere) or a word the language shares
(Italian login.password is "Password"). It works for all three catalogues.
This tool never writes a non-English file. add takes a catalogue (client / entry / server),
not a locale, so add ro … is rejected outright — there is no path by which it can touch a
Weblate-owned file. Editing a locale is the translating-locales skill's merge, and even then only
for a deliberate maintainer pass.
Changing an English string does not update the ~38 existing translations, which then read as
translations of text that no longer exists — show --locales makes that visible. Weblate flags them
for review on its next pull; you don't hand-edit them.
| Catalogue | File | Read by |
|---|---|---|
client | apps/client/src/translations/en/translation.json | the browser UI — everything after login |
entry | apps/client/src/translations/en/entry.json | only the setup wizard, login and password-reset pages |
server | apps/server/src/assets/translations/en/server.json | apps/server, the Electron main process, packages/trilium-core, and the standalone worker |
Getting this wrong is the most common mistake, and add warns when a key's section lives in a different catalogue than the one you named.
entry exists for weight. The three pre-login pages call initLocale(locale, "entry") and read ~12 KB instead of the app's 226 KB — which matters because the wizard reloads the catalogue every time the user picks a language. Put a login.* / set_password.* / setup.* key in client and the pre-login pages simply will not find it.client and entry with fallbackNS: "entry", so a call site writes t("login.password") without caring which file holds it. Only the new key has to go in the right place.server.json is misnamed — it is the catalogue for every runtime outside the browser UI. A t() call added to trilium-core resolves in server, desktop and standalone with no extra work (apps/standalone/vite.config.mts copies apps/server/src/assets/** and the worker loads it with ns: "server"). Don't assume a core string needs a fallback to work in the browser build.Client code imports t from ../services/i18n; server, desktop and core import it from i18next directly.
node $S find "Save changes" # 1. does it already exist?
node $S add client dialog.my_thing "Save changes"add prints two advisories worth reading:
add refuses to overwrite an existing key (--force to override) and refuses to nest under one that is already a string.
Then use it: t("dialog.my_thing"). Only en/ changes — Weblate carries the string to the other locales, and you should not hand-edit the other ~38 locale files.
en-GBThe en catalogues are US English: color, center, meter, recognize, labeled, canceled,
organize, defense, gray. en-GB is a locale of its own, and unlike the ~38 translated locales it
is sparse on purpose — it carries only the strings whose British spelling differs ("color_type": "Colour", "centerContent": "Keep content centred"), and falls back to en for everything else.
So a string containing one of those words is two edits, not one:
node $S add client dialog.my_thing "Pick a color"
# then, only because the spelling differs:
printf '{"dialog.my_thing":"Pick a colour"}' > /tmp/en-GB.json
node .claude/skills/translating-locales/locale.mjs merge en-GB client /tmp/en-GB.jsonLeave en-GB alone where the spelling is the same in both — an entry identical to English is noise
that measure then reports as untranslated. i18n.mjs writes en/ only, by design; locale.mjs merge is the sanctioned way into a locale file, and it preserves key order and formatting.
To check a catalogue, grep its values for the British halves of those pairs — colour, centre,
metre, -ise/-isation, -lled/-lling, defence, licence, grey, programme, whilst.
The English catalogues currently read 0 hits, so anything found is newly introduced.
i18next pluralizes only when the translation has _one / _other keys and the call site passes { count }. Add both forms and call t("key", { count }):
node $S add client space_usage.my_notes_one "{{count}} note"
node $S add client space_usage.my_notes_other "{{count}} notes"There is no base key — find --key space_usage.my_notes shows only the suffixed pair, and that is correct. Converting an existing single-form English key to a plural pair removes the base key, so every other locale falls back to English until Weblate migrates them; call that out in the PR.
{{var}} everywhere. The client turns i18next's HTML-escaping off in initLocale(), so {{var}} and
{{- var}} behave the same there; the server catalogue still escapes, which is why server.json keeps
{{- var}} on values carrying quotes or markup. A value interpolated into a string that is rendered as markup is
escaped by the caller: Menu titles and highlightedNotePathTitle take HTML, so their values go through
escapeHtml(); the confirm/info dialogs sanitize a string message with DOMPurify. When a string embeds components whose order varies by language (links, note references), use <Trans> from react-i18next rather than t(), so translators can reorder them.
Text that runs to several paragraphs is one message with a blank line (\n\n) between paragraphs,
never one key per paragraph. The translator then sees the whole text and decides where its paragraphs
fall — a language can merge two or split one — and a translation that drops the blank line still
renders, as a single paragraph. Some 18 English strings already work this way
(toast.critical-error.message, call_to_action.new_layout_message, the breadcrumb_badges.*_description
tooltips, llm.antigravity_agent_description).
Pass real newlines to add — in bash, $'First paragraph.\n\nSecond paragraph.'. Then render it so
the breaks survive, by one of:
white-space — put the text in one element with the shared .pre-wrap-text class
(stylesheets/style.css), as the call-to-action dialog does. Tooltips (pre-line), toasts and
confirm() dialogs already keep line breaks on their own.<p> — when each paragraph should get paragraph spacing:
text.split(/\n\s*\n/).map((p) => <p key={p}>{p}</p>), as the add-provider wizard does for
connectionDescription.missing is the one that catches real bugs — a t("…") whose key is in no catalogue renders the raw key to the user:
node $S missing # currently 1 known hit, see below
node $S unused # advisory onlyunused is advisory, not a delete list. It already suppresses three legitimate patterns (plural bases, dynamic prefixes, keys travelling as bare strings), but ~27 call sites build a key from a variable with no visible prefix, and keys can also be referenced from a test fixture or a docs note. Run callers <key> and confirm before deleting anything.
missing / unused / callers scan apps/client/src (against client + entry) and apps/server/src, apps/desktop/src, packages/trilium-core/src (against server). Within those:
| Pattern | Handled |
|---|---|
t("some.key"), <Trans i18nKey="some.key"> | resolved exactly |
t("pdf.annotations", { count }) → _one / _other | plural bases bridged in both directions |
t(`about.channel.${channel}`) | static prefix keeps every key under it live |
"security-dialog.lan-access" passed to a helper that calls t() | counted as a soft reference |
t(labelKey) — a bare variable | invisible; reported as a caveat count |
packages/ckeditor5 is deliberately not scanned. Its plugins pass the English text itself to CKEditor's t(), so the argument is a message, not a key — scanning it would produce nothing but noise. That mechanism has its own rules (a text-editor.ck entry keyed by the slug of the English text) and apps/client/src/services/i18n.spec.ts already enforces it in both directions, so a missing entry and a stale one both fail. See the CKEditor section of CLAUDE.md; don't reimplement that check here.
pnpm --filter client test src/services/i18n.spec.tsThat is the repo's only translation test: valid JSON, no duplicate keys, plus the CKEditor message-catalogue check. There is no locale-parity test and no typed i18next, so a missing key fails at runtime as a raw key on screen, not at build time — which is exactly why missing is worth running before you finish.
packages/trilium-core/src/services/hidden_subtree_launcherbar.ts:136 calls t("hidden-subtree.llm-chat-title"), which does not exist in server.json (the nearby keys are llm-title, llm-chat-history-title, sidebar-chat-title). Low impact — that launcher entry is enforceDeleted: true, so the note is removed rather than displayed. Fix it or delete the dead entry if you are in that file anyway.
<locale> to 100%".© TriliumNext, AGPL-3.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 1 other file in .claude/skills/working-with-translations of TriliumNext/Trilium.
Open the folder on GitHubat commit 4d9cb6d
Working With Translations next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Working With Translations this skillTriliumNext/Trilium | 38k | — | ~3.3k | Automated safety check: Pass | AGPL-3.0 | |
| Translation Diff ExportDevolutions/UniGetUI | 26k | — | ~1.1k | Automated safety check: Pass | MIT | |
| Translation Diff TranslateDevolutions/UniGetUI | 26k | — | ~934 | Automated safety check: Pass | MIT | |
| Plane UI Translationmakeplane/plane | 61k | — | ~16k | Automated safety check: Pass | AGPL-3.0 | |
| Translatetagspaces/tagspaces | 5.3k | — | ~2.2k | Automated safety check: Pass | AGPL-3.0 | |
| Translation Source SyncDevolutions/UniGetUI | 26k | — | ~1.2k | Automated safety check: Pass | MIT |
Devolutions/UniGetUI
Compares UniGetUI JSON locale files against English, identifies untranslated or source-changed keys, and generates patch, reference, and handoff files for a target language.
Devolutions/UniGetUI
Translates a sparse UniGetUI JSON language patch, writes completed entries into the working copy, preserves placeholders and terminology, and prepares the patch for merge-back.
makeplane/plane
Sets the rules for translating and updating Plane's UI strings across locales: do-not-translate terms, plural forms, placeholders and AI translation review.
tagspaces/tagspaces
Translate new or untranslated i18n strings from the English locale files (core.json + peri.json) into all other locales, maintaining consistency with each language's existing translations.
Devolutions/UniGetUI
Synchronizes the UniGetUI English language file with source-code usage, identifies missing translation keys, removes unused entries, reports localization drift, and can reorder locale files to match…
videojs/video.js
Translate or audit the values in a Video.js locale pack. An agent skill from videojs/video.js.
TriliumNext/Trilium
A skill your agent uses when cutting, preparing, or debugging a Trilium release — bumping the monorepo version, tagging, or diagnosing a failed "Release" workflow run.
TriliumNext/Trilium
A skill your agent uses when working on the Trilium Electron desktop app (apps/desktop) — adding or changing an electronApi method / IPC channel, touching preload.ts, main.ts, services/window.ts or…
TriliumNext/Trilium
A skill your agent uses when adding a DB migration or a new column/field to a Becca entity in Trilium ("add a migration", "new column on notes/attributes", "ALTER TABLE", "add a field to…
TriliumNext/Trilium
A skill your agent uses when adding, moving, or wiring an internal REST endpoint in Trilium (a new /api/ route) — choosing between a core-shared handler (packages/trilium-core/src/routes/index.ts…
TriliumNext/Trilium
A skill your agent uses when adding, changing, or reviewing an LLM/MCP tool in Trilium (the defineTools definitions under packages/trilium-core/src/services/llm/tools/ —…
TriliumNext/Trilium
Write, extend, and review CKEditor 5 plugins in the Trilium (TriliumNext Notes) monorepo — the rich-text-note editor under packages/ckeditor5, whose plugins live in src/plugins/.
Categories
A skill your agent uses when adding, finding, changing, reading or auditing a UI string in Trilium — "is there already a key for X?", "add a translation key", "what does <key say?", "what does this…. Working With Translations is an agent skill from TriliumNext/Trilium.".
Working With Translations fits situations like: auditing a UI string in Trilium — is there already a key for X?; add a translation key; what does <key say?; what does this button say in German?.
Run `npx skills add TriliumNext/Trilium --skill working-with-translations -a claude-code`. Or copy the skill folder (.claude/skills/working-with-translations in TriliumNext/Trilium) into .claude/skills/working-with-translations in your project. Claude Code loads it when a task matches its description.
Run `npx skills add TriliumNext/Trilium --skill working-with-translations -a codex`. Or copy the skill folder (.claude/skills/working-with-translations in TriliumNext/Trilium) into .agents/skills/working-with-translations in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add TriliumNext/Trilium --skill working-with-translations -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/working-with-translations, .gemini/skills/working-with-translations, .github/skills/working-with-translations and .opencode/skills/working-with-translations in your project.
Going by SKILL.md and its folder, Working With Translations needs JavaScript for the scripts in its folder and the command-line tools its instructions call (node and pnpm). Our summary lists: Node.js.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Working With Translations is published under the AGPL-3.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 3.3k tokens (SKILL.md is roughly 13k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Working With Translations: Translation Diff Export (Devolutions/UniGetUI, 26k stars), Translation Diff Translate (Devolutions/UniGetUI, 26k stars), Plane UI Translation (makeplane/plane, 61k stars) and Translate (tagspaces/tagspaces, 5.3k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
TriliumNext (a GitHub organization) maintains it in TriliumNext/Trilium, which has 38,274 GitHub stars. The repository holds 23 skills in this directory. The repository was last updated on October 11, 2026.
Source: TriliumNext/Trilium on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.