Agent skill

Adding Internal API Route

by TriliumNext in 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…

AGPL-3.0Auto-check passedTesting & QA

Install Adding Internal API Route

skills CLI
$ npx skills add TriliumNext/Trilium --skill adding-internal-api-route -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install TriliumNext/Trilium adding-internal-api-route --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/TriliumNext/Trilium.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/adding-internal-api-route .claude/skills/adding-internal-api-route && rm -rf skills-src

Use ~/.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/

Facts

Skill name
adding-internal-api-route
GitHub stars
38k
Token cost
~3.3k tokens
SKILL.md length
1,244 words
Files
2 (incl. references)
Skills in repo
22
Repo updated
First seen
Licence
AGPL-3.0

At a glance

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…

  • Works in 6 steps: Decide: core-shared vs server-only → Pick the wrapper → Return value conventions → …
  • ~140 routes that ALSO run in the standalone sqlite-wasm build) and a server-only one (apps/server/src/routes/routes.ts)
  • SKILL.md covers Footgun checklist (read before…, Step 1 — Decide: core-shared…, Step 2 — Pick the wrapper and Step 3 — Return value…, plus 5 more sections
  • Calls pnpm

What it does

Adding Internal API Route is an agent skill from TriliumNext/Trilium. Use 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 buildSharedApiRoutes, ~140 routes that ALSO run in the standalone sqlite-wasm build) and a server-only one (apps/server/src/routes/routes.ts), picking the apiRoute vs asyncApiRoute vs route/asyncRoute wrapper, and getting the implicit return conventions (object→200, undefined→204, [status, body] tuple→that status) and…

Its SKILL.md is about 3.3k tokens, which your agent loads only when the skill is triggered. The skill folder holds 2 other files, including reference files (for example `references/wrappers-and-conventions.md`).

It sits in Testing & QA, covering REST APIs and Unit testing. It works with WebAssembly and SQLite. The repository describes itself as: Build your personal knowledge base with Trilium Notes. The licence is AGPL-3.0.

When your agent uses it

  • ~140 routes that ALSO run in the standalone sqlite-wasm build) and a server-only one (apps/server/src/routes/routes.ts)
  • Picking the apiRoute vs asyncApiRoute vs route/asyncRoute wrapper
  • Getting the implicit return conventions (object→200
  • Body] tuple→that status) and convertEntitiesToPojos narrow entity-unwrapping right

Example prompts

  • “/adding-internal-api-route”

Workflow steps

6 steps, taken from the step headings in SKILL.md.

  1. Decide: core-shared vs server-only
  2. Pick the wrapper
  3. Return value conventions
  4. Entity serialization (convertEntitiesToPojo)
  5. Registration order
  6. Test it (handoff, don't reinvent)

What it can do on your machine

Read from SKILL.md and the folder at commit 134a865. It shows what the files ask for, not the result of running them.

  • Tool permissions

    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.

  • Runs code

    Shell commands in SKILL.md call:

    • pnpm

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    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.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Adding Internal API Route loads about 3.3k tokens when it runs, and up to ~5.6k if it reads all its reference files. Until then it costs about 194 tokens; SKILL.md has 1,244 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~194
When it runs · the whole SKILL.md, loaded when a task matches
~3.3k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~5.6k

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.

Safety

Auto-check passed

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.

SKILL.md

The full file from TriliumNext/Trilium at commit 134a865, republished under its AGPL-3.0 licence (© TriliumNext). 1,244 words, ~3,303 tokens.

Download SKILL.mdSave it as .claude/skills/adding-internal-api-route/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.
name
adding-internal-api-route
description
Use 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` `buildSharedApiRoutes`, ~140 routes that ALSO run in the standalone sqlite-wasm build) and a server-only one (`apps/server/src/routes/routes.ts`), picking the `apiRoute` vs `asyncApiRoute` vs `route`/`asyncRoute` wrapper, and getting the implicit return conventions (object→200, `undefined`→204, `[status, body]` tuple→that status) and `convertEntitiesToPojo`'s narrow entity-unwrapping right. Most routes are core-shared (and run under WASM); `apps/server/src/routes/api/` is the minority case. Pairs with writing-unit-tests for the cross-runtime CoreApiTester spec.

Adding an internal API route in Trilium

The first decision is which routes/api/ directory. There are TWO, and the common assumption that all routes live server-side in apps/server/src/routes/api/ is wrong — that's the minority case. ~140 of the routes live in the core one:

DirectoryWired byRuns inTestable by
packages/trilium-core/src/routes/api/* (default, ~140 routes)buildSharedApiRoutes in packages/trilium-core/src/routes/index.ts:84server + desktop + standalone WASMCoreApiTester (cross-runtime) and supertest
apps/server/src/routes/api/* (server-only)register() in apps/server/src/routes/routes.ts:47server + desktop onlysupertest only

A route you add only in routes.ts is invisible to the standalone build and cannot be driven by CoreApiTester. A core handler that imports node:* or touches process.env breaks the WASM build. Pick the wrong side and you either lose standalone support or break it.

Footgun checklist (read before you start)

  1. Default to core. Note/branch/attribute/tree/search/revision/import logic is browser-safe → put it in packages/trilium-core/src/routes/api/ and register in index.ts's buildSharedApiRoutes. Only Node-only or genuinely server-scoped routes go in routes.ts. (Step 1.)
  2. Async handler ⇒ asyncApiRoute, never apiRoute. apiRoute runs sql.transactional(cb) synchronously (route_api.ts:100) — hand it an async function and it commits an empty transaction immediately; your awaited writes land outside any transaction. (Step 2.)
  3. Return conventions are implicit. object/array/string → 200; undefined/nothing → 204; [integerStatus, body] tuple → that status. Throw ValidationError/NotFoundError for 400/404. (Step 3.)
  4. convertEntitiesToPojo only unwraps narrow shapes. A BNote nested under result.notes[], result.parentNote, result.attributes[] serializes raw/broken — call .getPojo() yourself or shape under note/branch. (Step 4.)
  5. Core handlers must be browser-safe: no process.env (use getPlatform().getEnv()), no node:path/import path (use services/utils/path.ts extname/basename), no Node built-ins.
  6. Registration order matters cross-runtime — register a literal path before a same-method :param catch-all on the same prefix. (Step 5.)
  7. Don't write the test by hand — core route ⇒ CoreApiTester; Express transport ⇒ supertest. Hand off to the writing-unit-tests skill. (Step 6.)

Step 1 — Decide: core-shared vs server-only

Put the handler in…When
core packages/trilium-core/src/routes/api/<m>.ts + register in index.ts buildSharedApiRouteslogic uses only browser-safe deps (becca, getSql(), core services, platform providers) AND the feature should work in standalone. Default for note/branch/attribute/tree/search/etc.
server-only apps/server/src/routes/api/<m>.ts + register in routes.ts register()needs Node-only deps not behind a platform provider (multer fs paths, OCR/LLM SDKs, metrics, sender, electron), or is genuinely server-scoped (etapi-tokens, totp, recovery codes)

The server-only set is small and specific — clipper, database, llm_chat, ocr, metrics, sender, totp, fonts, link_embed, recovery_codes, system_info, etapi_tokens, plus a few files extras. See the register() body in routes.ts (the shared set is wired by buildSharedApiRoutes at routes.ts:97). Everything else is core.

Browser-safe rule for core handlers: no process.env, no node:path/import path, no Node built-ins — they run in the sqlite-wasm standalone build. (script.ts:75,86 reads process.env.TRILIUM_SAFE_MODE directly — that is a latent violation, not a pattern to copy.)

Step 2 — Pick the wrapper

All four wrappers live in apps/server/src/routes/route_api.ts (apiRoute:69, asyncApiRoute:73, route:77, asyncRoute:81). Their names arrive via the buildSharedApiRoutes context object, so registering once in index.ts auto-wires all three call sites (server routes.ts:97, standalone browser_routes.ts:281, api_tester.ts:264).

A fifth name, asyncRouteWithoutTransaction, is also in the context object (index.ts:84) — use it for a long-running async handler that must not hold a transaction open.

WrapperHandler shapeTransactionAuth + CSRFResult handling
apiRoute(method, path, h)synchronous (req) => valuesql.transactional (sync)checkApiAuth + csrf, autoapiResultHandler
asyncApiRoute(method, path, h)async (req) => Promiseasync (no sync wrap)checkApiAuth + csrf, autoapiResultHandler
route(method, path, [mw], h, resultHandler?)sync; writes res directly OR custom [mw] (image/file download, setup, sync)syncexplicit [mw]optional
asyncRoute(method, path, [mw], h, resultHandler?)async + explicit [mw] (import/export, multipart)asyncexplicit [mw]optional

The sync-transactional trap (route_api.ts:100):

ts
return transactional ? sql.transactional(cb) : cb();

apiRoute → route(...true) → internalRoute(..., transactional=true); asyncApiRoute → asyncRoute(...false) → transactional=false. So apiRoute calls sql.transactional(cb) synchronously. If cb is async, sql.transactional sees a returned Promise, commits the (empty) transaction, and your awaited writes run after the commit, outside any transaction. The standalone adapter documents this exact trap in browser_routes.ts:127-133 ("would commit an empty transaction immediately when passed an async callback"). Async handler ⇒ asyncApiRoute. Always.

Auth/CSRF: apiRoute/asyncApiRoute attach auth.checkApiAuth + csrfMiddleware automatically (route_api.ts:70,74). Mutating endpoints therefore carry CSRF for free. Routes called from outside a browser session (setup, sync, sender, image/file download) use bare route()/asyncRoute() with an explicit [middleware] array (often checkApiAuthOrElectron or checkApiAuth) — see the route(...)/asyncRoute(...) registrations in index.ts and routes.ts.

Step 3 — Return value conventions

From apiResultHandler (route_api.ts:29-47), mirrored by the standalone apiResultHandler (browser_routes.ts:227) and CoreApiTester.formatApiResult (api_tester.ts:100):

Your handler returns…HTTP statusReal example
object / array / string200most handlers
undefined / nothing204branches.ts setPrefix, setExpanded
[integer, body] (first elem is an int)that status codebranches.ts:42,90 [200, …]; import.ts:67,71,126 [500, msg]; revisions.ts:123 [400, "Description must be a string."]
throw new ValidationError(...) / NotFoundError(...)400 / 404mapped by handleException (route_api.ts:130); CoreApiTester maps HttpError→status at api_tester.ts:335

Direct-response handlers (image/download) write to res themselves and use route(), not apiRoute() — see the direct-response registrations in index.ts.

Show full SKILL.md (477 more words)Show less

Step 4 — Entity serialization (convertEntitiesToPojo)

index.ts:365-390 only unwraps AbstractBeccaEntity instances in five shapes:

  1. the top-level result is an entity (:366)
  2. the top-level result is an array of entities (:368-372)
  3. result.note (:375-376)
  4. result.branch (:379-380)
  5. (recursively) result.executionResult, from runOnBackend() (:384-387)

Anything else serializes raw. A BNote under result.notes[], result.parentNote, result.attributes[], result.attachment, or any other key is not unwrapped — JSON.stringify then ships the live entity (lazy getters, becca back-references) and the response is wrong or throws. Fix: call .getPojo() yourself when building the response, or place the entity under a recognized note/branch key. createTextNote relies on this: the create handler returns { note, branch } and both get unwrapped.

Step 5 — Registration order

Both Express and CoreApiTester match in registration order, first match wins — the tester iterates this.routes and returns on the first match (api_tester.ts:301). Register a literal path before a same-method :param catch-all on the same prefix. Precedent (etapi side): routes.ts:190 — "Register revisions routes BEFORE notes routes so /etapi/notes/history is matched before /etapi/notes/:noteId". Current core /api/notes/... literals avoid collisions only because they differ by HTTP method (e.g. POST /api/notes/erase-deleted-notes-now vs GET /api/notes/:noteId) — if you add a literal that shares a method with an existing :param route on the same prefix, put the literal first.

Step 6 — Test it (handoff, don't reinvent)

Don't hand-roll a route test. Use the existing harness:

What you addedTest withWhere
core handlerCoreApiTester.build() (packages/trilium-core/src/test/api_tester.ts)co-located packages/trilium-core/src/routes/api/<m>.spec.ts — runs under both server and standalone suites
Express transport (CSRF/auth wiring)supertest agent + bootLoggedInApp()apps/server/src/routes/api/core_routes_http.spec.ts
server-only routesupertest agentco-located apps/server/src/routes/api/<m>.spec.ts

Minimal core spec (full patterns + fixtures live in the writing-unit-tests skill, server-and-core.md Pattern 0/1 — reference it, don't restate):

ts
import { beforeAll, describe, expect, it } from "vitest";
import { createTextNote } from "../../test/api_fixtures";
import { CoreApiTester } from "../../test/api_tester";

let api: CoreApiTester;
describe("Widget API (core)", () => {
    beforeAll(() => { api = CoreApiTester.build(); });
    it("returns the widget", async () => {
        const note = await createTextNote(api, { title: "Source" });
        const res = await api.get(`/api/widgets/${note.noteId}`);
        expect(res.status).toBe(200);
    });
});

createTextNote(api, {...}) → { noteId, branchId } lives in packages/trilium-core/src/test/api_fixtures.ts. A core spec runs cross-runtime — run both suites before calling it done (pnpm --filter server exec vitest run <spec> AND pnpm --filter standalone exec vitest run <spec>); the providers differ. See writing-unit-tests for the cross-runtime traps and the Windows/sandbox vitest invocation.

Quick recipe (core route, the common case)

  1. Write getX/putX in packages/trilium-core/src/routes/api/<m>.ts as a sync (req) => value (or async if it awaits) handler; default-export the object of handlers.
  2. Add the registration line to buildSharedApiRoutes in index.ts — apiRoute(GET, "/api/...", <m>Route.getX) for sync, asyncApiRoute(...) for async. That single line wires server + desktop + standalone + CoreApiTester.
  3. Return a value (Step 3); keep it browser-safe (Step 1); unwrap entities under note/branch or via .getPojo() (Step 4); mind ordering (Step 5).
  4. Add a co-located <m>.spec.ts with CoreApiTester and run both suites (Step 6).

Reference map

FileWhat it covers
references/wrappers-and-conventions.mdFull wrapper matrix (handler shape, sync vs async transaction, middleware, result handler), the return-value table with real call sites, the convertEntitiesToPojo unwrap table, and how the three buildSharedApiRoutes call sites (Express route_api.ts, standalone browser_routes.ts, CoreApiTester api_tester.ts) each implement the same context.

Related skills: writing-unit-tests (server-and-core.md Pattern 0 = CoreApiTester, Pattern 1 = supertest transport) for testing; analyzing-coverage for chasing the new handler's coverage.

© 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

Files

SKILL.md and 1 other file (references) in .claude/skills/adding-internal-api-route of TriliumNext/Trilium.

  • SKILL.md
  • references/wrappers-and-conventions.md

Open the folder on GitHubat commit 134a865

Compare with similar skills

Adding Internal API Route 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.

Adding Internal API Route compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Adding Internal API Route this skillTriliumNext/Trilium38k—~3.3kAutomated safety check: PassAGPL-3.0
Backend Testingbiersoeckli/QuickStack361—~670Automated safety check: PassGPL-3.0
Sap Abapsecondsky/sap-skills460—~3.9kAutomated safety check: PassGPL-3.0
Dotnet Testingnovotnyllc/dotnet-artisan233—~972Automated safety check: PassMIT
Esp32 Test PlanFastLED/FastLED7.5k—~1.9kAutomated safety check: PassMIT
Node Sqlite Vecmizchi/skills356—~2.3kAutomated safety check: PassNone

Similar skills

  • Backend Testing

    biersoeckli/QuickStack

    Create and review QuickStack backend unit and integration tests using the project's Vitest, Prisma, SQLite, and k3s conventions.

    361 GitHub stars~670 tokensUpdated yesterday
    Testing & QAAuto-check passed
  • Sap Abap

    secondsky/sap-skills

    Comprehensive ABAP development skill for SAP systems. An agent skill from secondsky/sap-skills.

    460 GitHub stars~3.9k tokensUpdated 2 days ago
    DatabasesAuto-check passed
  • Dotnet Testing

    novotnyllc/dotnet-artisan

    Defines .NET test strategy and implementation patterns across xUnit v3 (Facts, Theories, fixtures, IAsyncLifetime), integration testing (WebApplicationFactory, Testcontainers), Aspire testing…

    233 GitHub stars~972 tokensUpdated 1 mo ago
    Testing & QAAuto-check passed
  • Esp32 Test Plan

    FastLED/FastLED

    Generate a structured multi-layer test plan for FastLED changes targeting ESP32.

    7.5k GitHub stars~1.9k tokensUpdated today
    Testing & QAAuto-check passed
  • Node Sqlite Vec

    mizchi/skills

    A skill your agent uses when setting up Node 24+ built-in node:sqlite with the loadable sqlite-vec extension for vector / RAG storage in TypeScript without better-sqlite3, or when debugging vec0…

    356 GitHub stars~2.3k tokensUpdated 5 days ago
    DatabasesAuto-check passed
  • Msw

    pproenca/dot-skills

    MSW (Mock Service Worker) best practices for API mocking in tests (formerly test-msw).

    214 GitHub stars~1.3k tokensUpdated 1 mo ago
    Testing & QAAuto-check passed

More from TriliumNext/Trilium

All 22 skills in this repo
  • Cutting A Release

    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.

    38k GitHub stars~3.2k tokensUpdated today
    Auto-check passed
  • Developing Electron Desktop

    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…

    38k GitHub stars~5.7k tokensUpdated today
    Auto-check passed
  • Evolving The Data Model

    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…

    38k GitHub stars~2.1k tokensUpdated today
    Auto-check passed
  • Adding LLM MCP Tools

    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/ —…

    38k GitHub stars~2.5k tokensUpdated today
    Auto-check passed
  • Ckeditor5 Plugin Development

    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/.

    38k GitHub stars~4.8k tokensUpdated today
    Auto-check passed
  • Ckeditor5 Testing

    TriliumNext/Trilium

    Testing CKEditor 5 plugins in the Trilium monorepo. An agent skill from TriliumNext/Trilium.

    38k GitHub stars~3.3k tokensUpdated today
    Auto-check passed

Questions about Adding Internal API Route

What does Adding Internal API Route do?

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…. Adding Internal API Route is an agent skill from TriliumNext/Trilium.

When should I use Adding Internal API Route?

Adding Internal API Route fits situations like: ~140 routes that ALSO run in the standalone sqlite-wasm build) and a server-only one (apps/server/src/routes/routes.ts); picking the apiRoute vs asyncApiRoute vs route/asyncRoute wrapper; getting the implicit return conventions (object→200; body] tuple→that status) and convertEntitiesToPojos narrow entity-unwrapping right.

How do I install Adding Internal API Route in Claude Code?

Run `npx skills add TriliumNext/Trilium --skill adding-internal-api-route -a claude-code`. Or copy the skill folder (.claude/skills/adding-internal-api-route in TriliumNext/Trilium) into .claude/skills/adding-internal-api-route in your project. Claude Code loads it when a task matches its description.

How do I install Adding Internal API Route in Codex?

Run `npx skills add TriliumNext/Trilium --skill adding-internal-api-route -a codex`. Or copy the skill folder (.claude/skills/adding-internal-api-route in TriliumNext/Trilium) into .agents/skills/adding-internal-api-route in your project. Codex loads it when a task matches its description.

Can I use Adding Internal API Route in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add TriliumNext/Trilium --skill adding-internal-api-route -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/adding-internal-api-route, .gemini/skills/adding-internal-api-route, .github/skills/adding-internal-api-route and .opencode/skills/adding-internal-api-route in your project.

What does Adding Internal API Route need to run?

Going by SKILL.md and its folder, Adding Internal API Route needs the command-line tools its instructions call (pnpm).

Does Adding Internal API Route access the network?

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.

Is Adding Internal API Route safe to install?

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.

What licence does Adding Internal API Route use?

Adding Internal API Route 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.

How many tokens does Adding Internal API Route use?

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. Its references folder adds about 2.3k tokens, read only when the agent opens those files.

What are the alternatives to Adding Internal API Route?

Skills that share tags, products or a category with Adding Internal API Route: Backend Testing (biersoeckli/QuickStack, 361 stars), Sap Abap (secondsky/sap-skills, 460 stars), Dotnet Testing (novotnyllc/dotnet-artisan, 233 stars) and Esp32 Test Plan (FastLED/FastLED, 7.5k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Adding Internal API Route?

TriliumNext (a GitHub organization) maintains it in TriliumNext/Trilium, which has 38,231 GitHub stars. The repository holds 22 skills in this directory. The repository was last updated on October 7, 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.