Pack format
A pack is a folder of JSON files, usually sent as a .zip. This page lists every file and field Kotowa reads. To have an AI agent write the pack for you, see Make your own pack. The format is also available as JSON Schema for the manifest and a unit file, and a checker script tests a pack folder.
Files
| File | Meaning |
|---|---|
manifest.json | Required. The pack's title, languages, license and the list of its units. |
units/<id>.json | Required for every unit the manifest lists: the unit's items. The path is whatever the manifest's path says. |
media/… | The images that items point to with image. |
search-index.json, jmdict.json, characters.json | Written by the pack tool. Kotowa reads them for search, for dictionary entries and for speaker pages. A pack without them is still accepted when you add it. |
In the .zip, manifest.json sits at the top, or inside one folder that holds everything. File paths may not start with /, contain \ or contain ... A pack's id becomes a folder name on the device: it uses letters, digits, ., _ and -, and starts with a letter or digit.
When you add a .zip, Kotowa unpacks it in memory and checks the manifest and every unit before it writes anything. A pack with a problem is refused and nothing is changed.
Version
The current format version is 1. A manifest may carry schemaVersion; without it the pack counts as version 1. A pack with a higher number is refused with a message that it needs a newer Kotowa.
Languages
Language codes are short text like ja, en and es. A translation is always an object that maps a code to text, such as {"en": "Hello"}. The pack tool writes Japanese packs; sourceLanguage is ja for them.
Manifest
| Field | Type | Meaning |
|---|---|---|
id | text | The pack's name on the device, as described above. |
title | text | Shown in the Library. |
sourceLanguage | language code | The language of the lines you read. |
targetLanguages | list of language codes | The languages the pack's translations and glosses are in. The list must be present; it may be empty. |
license | text | The license the content is offered under, such as cc-by-4.0 or public-domain, or private when the content is for your own use only. Shown in Settings. |
attribution | text | The credit line, when the license asks for one. |
credits | text | Who made the content and where it came from. Shown in Settings under the license, and on the About screen. |
units | list of unit entries | Every unit of the pack, see Unit entry below. Kotowa draws the folder tree from this list alone. |
videos | list of videos | The videos that items' timing points into, see Video below. Leave it out when the pack has no video. |
schemaVersion | number | The format version the pack was made for, see Version above. |
contentHash | text | An identifier that changes whenever the pack's content changes. The pack tool writes one; Kotowa only carries it. |
Unit entry
A unit is a section of the pack: a scene, a chapter, a page. A folder is a unit with children, at any depth, and units point to their parent with parentId. Each manifest entry repeats the unit's own details so that Kotowa can draw the tree without opening the unit files. Every field that the unit file also has (id to kind) must have the same value in both.
| Field | Type | Meaning |
|---|---|---|
id | text | The unit's identifier, unique in the pack. |
title | text | Shown in the tree. |
order | text | Sort key among units with the same parent. Text, compared character by character, so use zero-padded numbers like 0001. |
parentId | text or null | The id of the folder this unit is in. Null or absent at the top level. |
day | text | A day, if the source has one. The format is yours. |
moment | text | A time of day within day. The format is yours. |
label | text | A short label printed in a box before the title, such as a day of the month or an episode number. |
labelNote | text | A note under the label. |
kind | text | What the unit is, as a singular noun that Kotowa makes plural in counts: day gives "23 days". |
path | text | Where the unit's file is, from the pack's top, for example units/morning.json. |
itemCount | number | How many items the unit file holds. 0 marks a folder that only groups other units. |
part | number | Which part of a long source the unit first appears in. The downloads screen groups by it. |
bytes | number | Size of the unit's file in bytes. |
contentVersion | text | An identifier of this export of the unit. It changes when the unit or its images change, which lets Kotowa tell a downloaded copy from a newer one. |
mediaBytes | number | Total size in bytes of the images this unit's items use, 0 if none. |
image | object | The picture that stands for the unit in previews: {"path": "media/page1.png", "unitId": "page-1"}, where unitId is the unit whose files include the image. |
videos | list of video spans | The videos this unit's own items are timed in, see Video span below. |
Video
A pack made from a video says where each line is in it. The pack never holds the video: the learner links their own copy.
| Field | Type | Meaning |
|---|---|---|
id | text | What items' timing.video refers to. |
title | text | Shown when Kotowa asks the learner to link the video. |
sourceId | text | An identifier of the video where it comes from, such as a video site's id. |
sourceUrl | text | An http or https address where the learner can get a copy. The link dialog offers it. |
durationSeconds | number | The video's length. Kotowa compares a chosen file to it and asks before linking one that differs by more than 5 seconds. |
Video span
One entry of a unit entry's videos list: where the unit's own items sit in one video.
| Field | Type | Meaning |
|---|---|---|
video | text | The id of a video in the manifest. |
start | number | The earliest start among the unit's items, in seconds. |
end | number | The latest end, in seconds. An item without an end counts as ending where it starts. |
itemCount | number | How many of the unit's items are in this video. |
Unit file
The file a unit entry's path points to.
| Field | Type | Meaning |
|---|---|---|
id | text | Same as in the manifest. |
title | text | Same as in the manifest. |
order | text | Same as in the manifest. |
parentId | text or null | Same as in the manifest. |
day | text | Same as in the manifest. |
moment | text | Same as in the manifest. |
label | text | Same as in the manifest. |
labelNote | text | Same as in the manifest. |
kind | text | Same as in the manifest. |
items | list of items | What the unit says, in reading order. Empty for a folder. |
Item
An item is what the reader shows at once: one line, or several that belong together, such as a speech balloon or a subtitle cue, with one translation.
| Field | Type | Meaning |
|---|---|---|
id | text | Unique within the unit. |
speaker | speaker | Who says it, see Speaker below. |
lines | list of lines | At least one line, see Line below. |
translations | object | The whole item translated: a language code mapped to text. It may be empty {} when a pack has no sentence translations. |
image | text | Path of an image, from the pack's top, shown with the item. The file must be in the pack. |
timing | timing | Where the item is in a video, see Timing below. |
Timing
| Field | Type | Meaning |
|---|---|---|
video | text | The id of a video in the manifest's videos. |
start | number | Seconds from the start of the video. |
end | number | Seconds from the start, only when the source recorded a real end. Without it an item lasts until the next one starts. |
Line
| Field | Type | Meaning |
|---|---|---|
source | text | The line in the source language. It may not be empty. |
transliteration | text | A reading aid in the source language's usual form, such as romaji for Japanese. |
gloss | list of gloss pieces | The line cut into words, each with its meaning, see Gloss piece below. Punctuation may be left out of the pieces. |
furigana | list of furigana tokens | The line cut into pieces with their readings. Putting every token's text together gives source exactly. |
translations | object | This line's own translation, for items whose lines are translated one by one, such as the options of a choice. Ordinary items are translated as a whole on the item. |
Furigana token
| Field | Type | Meaning |
|---|---|---|
text | text | A piece of the line. |
reading | text | Its reading, drawn above it. Only on pieces that contain kanji. |
Speaker
| Field | Type | Meaning |
|---|---|---|
text | text | The speaker's name as the source gives it. |
furigana | list of furigana tokens | Readings for the name, as for a line. |
tier | "minor" | Marks a background or one-off speaker. Kotowa treats all speakers alike. |
romaji | text | The name in Latin letters. |
translations | object | What the name means, when it is a role rather than a name. |
character | text | The id of this speaker's page in characters.json. |
characterName | object | The character's name when text describes them instead: {"text": "…", "furigana": […]}. |
Gloss piece
A gloss cuts a line into words. Only raw is needed by the app, but Kotowa draws a piece from its japanese text, so give every piece one: a line whose pieces have none is shown as plain text without the word-by-word view. The pack tool fills in the rest from the JMdict dictionary. You do not have to write these by hand: an AI agent can, see the agent guide. The facts at the end are optional and absent where they don't apply; each is an object or list whose exact shape is in the format's schema file.
| Field | Type | Meaning |
|---|---|---|
raw | text | A label for the piece. The pack tool writes meaning (word), such as umbrella (傘). Kotowa shows it only when the piece has no japanese. |
japanese | text | The piece's text in the source language. |
pos | text | Part of speech. |
lemma | text | The dictionary form, when the word conjugates. |
reading | text | The reading in kana. |
translations | object | The piece's meaning per language: {"es": "regresar"}. |
note | text | A remark about the piece. |
confidence | text | confident, uncertain or unsupported: how sure the draft is of the meaning. |
lemma_kanji | text | The kanji spelling of a lemma written in kana. |
word_class | object | Word class, conjugation class and transitivity. |
steps | list | The conjugation steps from the dictionary form to the form in the line. |
expanded | text | A contraction written out in full. |
attach | object | What the piece attaches to within its line. |
register | list of text | Usage tags such as colloquial or honorific. |
loan | object | The origin of a loanword. |
kanji | list | One entry for each kanji in the piece: meaning, school grade and JLPT level. |
pitch | list | Pitch accent of the dictionary form. |
freq | object | How common the word is. |
pattern | object | A named grammar pattern the piece belongs to. |
seen | object | How often the word came up earlier in a long source. Only in packs that were made from one. |
sources | object | Where each stored fact came from and how well supported a gloss is. |
A smallest pack
This is a whole pack: one unit with one line. Put the two files in a folder, with the second one at units/morning.json, and zip them.
manifest.json
{
"id": "my-first-pack",
"title": "My first pack",
"sourceLanguage": "ja",
"targetLanguages": ["en"],
"license": "private",
"units": [
{
"id": "morning",
"title": "朝",
"order": "0001",
"path": "units/morning.json",
"itemCount": 1,
"bytes": 262,
"mediaBytes": 0
}
]
}
units/morning.json
{
"id": "morning",
"title": "朝",
"order": "0001",
"items": [
{
"id": "m1",
"lines": [{ "source": "今日は雨だ。" }],
"translations": { "en": "It is raining today." }
}
]
}
Kotowa shows this pack with the line and its translation. It has no furigana or word breakdown, because those are what the pack tool adds.