Docs / Developer / JanitorAI format
JanitorAI format
JanitorAI has no character file of its own and no official card export. Its one importer is hidden in
the avatar upload on /create_character: when the uploaded image is a PNG with a chara tEXt chunk,
Janitor offers to fill the form from it. Everything below was read from Janitor's production bundle
(CharacterForm, ImageInput, ScriptsEditPage, 2026-10-24). Bundle file names change on every
deploy, so recheck the importer when Janitor changes behavior.
The folder src/formats/janitor/ default-exports two export-only codecs. Both return 0 fromdetect(), so a Janitor-bound PNG always imports through the SillyTavern reader, which is what it is;toCanonical delegates to that same reader, so the adapter can read back its own output.
janitor, kindcharacter, writes.pngonly.janitor-lorebook, kindlorebook, writes the SillyTavern world info JSON
(_shared/host-worldbook.ts) for the Scripts editor's "Import JSON" button.
The importer mapping below is the co-developer's recorded 2026-10-24 bundle inspection. Current integration tests verify Bunzai's emitted PNG and reports against that mapping; they do not prove a current live import on the external service. Recheck upstream behavior when it changes.
What Janitor's importer reads
- Only the
charakeyword. Accv3chunk is ignored, and JSON or charx are not accepted at all
(the avatar input takes images only, up to 10 MB). - Format checks run in order: Text-gen-webui, then "TavernAI Character" (all six top-level keys
name,description,personality,scenario,first_mes,mes_examplepresent), then
Character.AI shapes, then Character Card V2 (specplusdata). CCv3 is not recognized. - On the V1 branch, top-level
descriptionfills Janitor's Personality (the definition) and
top-levelpersonalityfills Janitor's public Description (the bio). On the pure V2 branchdata.descriptionlands in the bio instead. Either way, a plain SillyTavern card lands swapped or
with its definition in public view. - Every recognized field is written even when empty. Alternate greetings, tags, creator notes,
character_book, system prompt and post-history instructions are dropped.
What the adapter writes
fromCanonical builds the normal V2 card through the Tavern codec (v2CardObject in_shared/card-png.ts, so a V3 card yields its V2 backfill) and then sets the six top-level mirror
fields the way Janitor's V1 branch reads them:
| Top-level key | Value | Lands in Janitor as |
|---|---|---|
name |
data.name |
Name |
description |
data.description and data.personality, joined by a blank line |
Personality (definition) |
personality |
data.creator_notes |
Description (public bio) |
scenario |
data.scenario |
Scenario |
first_mes |
data.first_mes |
First message |
mes_example |
data.mes_example |
Example dialogs |
data stays an ordinary V2 card, so the same PNG still opens correctly in SillyTavern and every
other Tavern reader. The card is embedded under chara alone (charaOnlyPng). The carrier is the
inline PNG portrait or, when none is set, the PNG the card was imported from (the Studio keeps an
imported card's art only there). A card with neither is refused with an error naming janitor,
because Janitor requires an avatar.
The serialize report names the dropped fields from coverage.ts and adds warnings when the
definition or the first message is empty (both are required by Janitor's form) or the PNG is over
the 10 MB avatar limit.
Lorebooks
Janitor lorebooks are Scripts of type lorebook, separate objects linked to bots. The Scripts editor
imports SillyTavern world info JSON (its tooltip key is importSillyTavernFile), sojanitor-lorebook is the ST worldbook codec under Janitor's id. Linked lorebooks never travel inside
the PNG; the export dialog says so.
Source of truth
| Concern | File |
|---|---|
| Character adapter | src/formats/janitor/index.ts |
| Coverage declaration | src/formats/janitor/coverage.ts |
| V2 card object and chara-only PNG | src/formats/_shared/card-png.ts |
| Lorebook codec | src/formats/_shared/host-worldbook.ts |
| Tests | src/formats/janitor/janitor.test.ts |