tkgally/je-dict-1

In-progress Japanese-English learner's dictionary

8

stars

9,368

commits

Python

primary language

Sep 2, 2026

updated

README

TKG Japanese-English Learner's Dictionary

This is the repository for a Japanese-English learner's dictionary delivered as a static website. Its production is being supervised by Tom Gally. All of the entry-writing and coding is being done by Claude in Claude Code for the Web, with some bug-hunting and improvement-suggesting by ChatGPT and Gemini.

Live site: https://www.tkgje.jp/

This dictionary is licensed under Creative Commons Zero v1.0 Universal, and anyone is free to copy the data and code for whatever purpose they like, including commercial uses.

Overview

This dictionary is designed for learners of Japanese as a second language. It uses an original three-tier vocabulary classification system:

  • Basic tier: About one thousand fundamental words essential for basic communication
  • Core tier: About two thousand needed for adult-level communication
  • General tier: All other vocabulary useful for learners

Dictionary features include:

  • Explanatory definitions that go beyond simple glosses
  • Natural example sentences optimized for learning
  • Usage notes covering grammar, register, and common patterns
  • Furigana support with toggle to show/hide readings above kanji
  • Kanji index linking each kanji in headwords to all other entries containing that kanji
  • Multiple interface modes: Search, Browse, Recent, and Random views
  • Cross-reference linking with prominent top-of-entry links for homophones, verb pairs, and N/Nする pairs, plus structured "Related Words" boxes for antonyms, keigo, synonyms, and more
  • Inline word links in example sentences allowing navigation to any word's entry
  • Transitivity and aspect information for verbs
  • Collocation patterns showing natural word combinations
  • Keigo (honorific) verb coverage with usage guidance

Audio readings for example sentences will be added in the future.

Current Status

  • Over 14,000 entries across three vocabulary tiers
  • Vocabulary tiers: Basic (801), Core (1,998), General (the rest) — all new entries are added to general tier
  • Many cross-references linking related entries
  • Over 50,000 example sentences with inline word links
  • Claude Code skills for consistent entry creation and revision
  • Entry tracking system with entries_index.json for current entries and candidate_words.json for future additions
  • Automated pipeline for batch dictionary maintenance tasks
  • Unattended improvement Routine (prompts/routine2.md) — scheduled Claude sessions that rotate between polishing, entry creation, cross-model accuracy review (via OpenRouter, budget-capped), systemic fixes, and knowledge-base maintenance; each run verifies its own entry changes with an independent model, records quality metrics, and merges its own PR
  • Robust build system with atomic builds, XSS protection, and comprehensive validation
  • CI/CD with GitHub Actions for validation and automated pipeline runs

Target Users

Intermediate learners of Japanese who:

  • Can read hiragana and katakana fluently
  • Know some kanji and are building vocabulary
  • Want to understand words fully, not just look them up quickly

Technology

The dictionary is built as a completely static website:

  • No server required—just open index.html directly in your browser
  • No external dependencies—pure HTML, CSS, and JavaScript
  • Offline-capable—download and use anywhere

Site Structure

The dictionary is built as a static HTML site at docs/:

  • Individual pages: Each entry has its own standalone HTML file
  • Lightweight pages: Each page loads only the content needed
  • Deep linking: Direct URLs to specific entries

URL Structure

Entry pages are organized by numeric ID ranges (500 entries per directory):

docs/
├── index.html           # Home page
├── search.html          # Search interface
├── browse.html          # Browse by kana row
├── recent.html          # Recently modified entries
├── random.html          # Random word cloud
├── entries/
│   ├── 00000/           # Entries 00000-00499
│   │   ├── 00396_taberu.html
│   │   └── 00499_sakana.html
│   ├── 00500/           # Entries 00500-00999
│   ├── 01000/           # Entries 01000-01499
│   └── ...
└── kanji/               # Kanji index pages
    ├── 00001_teki_mato_target.html
    ├── 00009_jin_hito_person.html
    └── ...              # One page per kanji

This numeric range structure allows the dictionary to scale to 10,000+ entries while staying within GitHub's 1,000 files per directory limit.

Web Interface

The dictionary provides four different ways to explore entries:

Search Mode

Quick lookup by Japanese, romaji, or English. The traditional dictionary experience for users who know what word they're looking for.

Browse Mode

Explore entries organized by:

  • Starting Kana: あ行, か行, さ行, etc.
  • Vocabulary Tier: Basic (801 fundamental words), Core (1,998 adult-communication words), General (all other vocabulary)

The dictionary uses an original three-tier classification system instead of JLPT levels. All new entries are added to the general tier.

Recent Mode

View the most recently added or revised entries (up to 250). Each entry shows:

  • NEW: Newly created entries
  • REVISED: Updated existing entries
  • Date of addition/revision

Useful for tracking dictionary updates and discovering new content.

Random Mode

A word cloud of randomly selected entries. Click any word to view its full entry. Great for serendipitous discovery and vocabulary review.

Furigana System

The dictionary uses a custom notation for furigana (reading annotations above kanji):

Format

{kanji|reading}

Examples:

  • {食|た}べる → 食べる with た above 食
  • {友達|ともだち} → 友達 with ともだち above it
  • {日本語|にほんご}が{分|わ}かる → Multiple annotations in one sentence

In the Web Interface

  • Click the Furigana button in the header to toggle readings on/off
  • When enabled, readings appear above kanji using HTML <ruby> tags
  • Preference is saved in localStorage

Example sentences can contain inline word links that allow users to click any word to navigate to its dictionary entry.

In JSON source files, links use special Unicode delimiters:

⟦{surface|reading}→baseform:entry_id⟧

Components:

  • (U+27E6) - Opening bracket
  • surface - The word as it appears in the sentence (may include furigana notation)
  • (U+2192) - Arrow separator
  • baseform - The dictionary form of the word (displayed in tooltip)
  • (U+FF1A) - Fullwidth colon separator
  • entry_id - The target dictionary entry ID (e.g., 00111_hon)
  • (U+27E7) - Closing bracket

Example:

"japanese": "⟦{本|ほん}→本:00111_hon⟧⟦を→を:00422_wo⟧⟦{読|よ}む→読む:00426_yomu⟧。"

In the Web Interface

  • Click the Wordlinks button in the header to toggle link visibility
  • When enabled, words with links show a dotted underline
  • Hover over a linked word to see a tooltip with the dictionary form
  • Click to navigate to that word's entry
  • Preference is saved in localStorage

Special Cases

  • noentry: Use for words without dictionary entries: ⟦{矍鑠|かくしゃく}→矍鑠:noentry⟧
  • Conjugated forms: Link to the dictionary form (e.g., 食べました → 食べる)
  • No self-reference: Don't link the headword in its own examples
  • Punctuation: Do not link punctuation marks (。、?!)

Kanji Index

The kanji index allows users to find all dictionary entries containing a specific kanji character.

How It Works

  1. On entry pages: Each kanji in the headword is a clickable link
  2. Hover tooltip: Shows "Other words with this kanji" when hovering over a kanji
  3. Kanji page: Clicking displays a page with the kanji and all entries containing it
  4. Entry list: Sorted by hiragana reading order

Kanji ID Format

Each kanji is identified by a unique ID:

{5-digit number}_{onyomi}_{kunyomi}_{gloss}

Examples:

  • 00009_jin_hito_person (人)
  • 00116_kou_taka_tall (高)
  • 00431_yo_ama_surplus (余)

The ID uses none when a kanji lacks on'yomi or kun'yomi.

Technical Details

  • 2,040 kanji indexed from dictionary headwords
  • kanji_list.json: Master mapping of kanji characters to IDs
  • Individual JSON files: Entry lists for each kanji in kanji/
  • HTML pages: Generated in docs/kanji/ during site build
  • Automatic updates: New kanji are detected and indexed when entries are added

Project Structure

je-dict-1/
├── entries/              # Dictionary entries (one JSON file per word)
│   ├── 00000/            # Entries 00000-00499
│   ├── 00500/            # Entries 00500-00999
│   ├── 01000/            # Entries 01000-01499
│   └── ...               # (500 entries per directory)
├── kanji/                # Kanji index data
│   ├── kanji_list.json   # Master list mapping kanji to IDs
│   └── {kanji_id}.json   # Entry lists for each kanji
├── build/                # Build and management scripts
│   ├── schema.json       # JSON schema for entries
│   ├── validate.py       # Entry validation (schema, cross-refs)
│   ├── validate_tags.py  # Tag taxonomy validation
│   ├── build_flat.py     # Static HTML site generator (atomic builds)
│   ├── entry_renderer.py # Entry page HTML generation
│   ├── page_generators.py      # Navigation page generation
│   ├── search_index_builder.py # Search index and JS generation
│   ├── report.py         # Dictionary health dashboard
│   ├── generate_word_lookup.py # Builds word_id_lookup.json
│   ├── path_utils.py     # Shared path/prefix utilities
│   ├── japanese_utils.py # Hiragana/romaji/furigana utilities
│   ├── constants.py      # Centralized cross-reference type definitions
│   ├── update_indexes.py # Updates entries_index.json and candidate list
│   ├── manage_candidates.py    # Manages candidate_words.json
│   ├── get_entry_path.py       # Computes correct path for new entries
│   ├── get_timestamp.py        # Generates UTC timestamp for metadata
│   ├── check_duplicate.py      # Checks for duplicate entries
│   ├── verify_furigana.py      # Verifies furigana coverage
│   ├── templates/        # CSS and JS templates (styles.css, search.js, etc.)
│   ├── tests/            # Unit tests (pytest)
│   ├── archive/          # One-time migration scripts (no longer used)
│   └── requirements.txt  # Python 3.10+ dependencies
├── pipeline/             # Automated task pipeline
│   ├── run-pipeline.sh   # Task runner (reads config, invokes claude, validates)
│   ├── validate-task.sh  # Task-specific validation gates
│   ├── update-status.py  # Pipeline status tracking and reporting
│   ├── update-brief.py   # Regenerates PROJECT_CONTEXT_BRIEF.md
│   ├── recommend-tasks.py      # Task scheduler recommendations
│   ├── routine_next.py   # Unified Routine mode selector (weighted rotation + health nudges)
│   ├── metrics_snapshot.py     # Per-run quality metrics → metrics-history.jsonl
│   ├── openrouter-ledger.json  # Daily OpenRouter spend ledger ($5/day cap)
│   └── pipeline-config.json    # Active pipeline configuration
├── polishing/            # Progress tracking for polishing tasks
├── prompts/              # Task prompts (interactive and batch/)
├── docs/                 # Generated output (served as static site)
│   ├── entries/          # Individual entry HTML files
│   │   ├── 00000/        # (same numeric range structure as entries/)
│   │   └── ...
│   └── kanji/            # Kanji index HTML pages
├── .claude/              # Claude Code configuration
│   ├── skills/           # Agent skills for entry guidelines (auto-loaded)
│   └── settings.json
├── .github/workflows/    # GitHub Actions (validate.yml, pipeline.yml)
├── Makefile              # Build runner (make validate, make build, etc.)
├── entries_index.json    # Index of all dictionary entries
├── candidate_words.json  # Words to potentially add in future
├── PROJECT_CONTEXT_BRIEF.md  # Quick-reference counts for session start
└── PROJECT_STATUS.md     # Session continuity and recent change log

Entry Schema

Each entry is a JSON file with the following structure:

{
  "id": "00396_taberu",
  "headword": "{食|た}べる",
  "reading": "たべる",
  "part_of_speech": "verb (ichidan)",
  "gloss": "to eat",
  "definitions": [
    {
      "sense_number": 1,
      "gloss": "to eat",
      "explanation": "The most common verb for eating..."
    }
  ],
  "examples": [
    {
      "id": "00396_taberu_ex1",
      "japanese": "{朝|あさ}ごはんを{食|た}べましたか。",
      "english": "Did you eat breakfast?",
      "notes": null,
      "sense_numbers": [1]
    }
  ],
  "notes": "Usage notes, grammar notes, etc.",
  "cross_references": [
    {
      "type": "pair",
      "reading": "たべもの",
      "headword": "{食|た}べ{物|もの}"
    }
  ],
  "metadata": {
    "created": "2026-01-05T10:00:00Z",
    "modified": "2026-01-05T10:00:00Z",
    "ai_model": "claude-opus-4-5",
    "vocabulary_tier": "basic"
  }
}

Sense Numbers in Examples

The sense_numbers field on example sentences links each example to one or more definition senses:

  • Required for multi-sense entries: Every example must specify which sense(s) it illustrates
  • Format: Array of integers matching sense_number values in definitions (e.g., [1], [2], or [1, 2])
  • Single-sense entries: Use [1] for all examples
  • Multi-sense examples: An example can illustrate multiple senses with [1, 2]

This enables future features like filtering examples by sense and helps learners understand which meaning each example demonstrates.

File Naming Convention

Files use the format: {id}_{romanized_reading}.json

  • IDs are 5-digit zero-padded numbers at the START of the filename
  • Use Modified Hepburn romanization for the reading
  • Long vowels follow kana spelling: 東京 → toukyou, not tokyo
  • Katakana loanwords use hiragana reading (e.g., アルバイト → arubaito)

Directory Placement

Files go in directories based on the numeric ID range (500 entries per directory):

  • Entry 00396_taberu → entries/00000/00396_taberu.json
  • Entry 00538_aruku → entries/00500/00538_aruku.json
  • Entry 01186_mukau → entries/01000/01186_mukau.json

The directory name is determined by rounding down to the nearest 500:

  • IDs 00000-00499 → entries/00000/
  • IDs 00500-00999 → entries/00500/
  • IDs 01000-01499 → entries/01000/

Phased Roadmap

Phase 1: Foundation ✓ COMPLETE

  • Project structure and schema
  • Build and validation scripts
  • Basic web interface
  • Furigana system with toggle

Phase 2: Core Vocabulary ✓ COMPLETE

  • Basic vocabulary foundation (~761 entries)
  • Multi-model LLM evaluation
  • Quality specification v2
  • Entry revision to v2 standards

Phase 3: Entry Enhancement ✓ COMPLETE

  • Add transitivity/aspect to all verbs
  • Expand particle entries with predicate lists
  • Add collocation patterns
  • Standardize adjective forms
  • Notes formatting with bullet points

Phase 4: Vocabulary Expansion & Interface ✓ COMPLETE

  • Added ~7,500+ vocabulary entries (10,300+ total)
  • Multiple interface modes (Search, Browse, Recent, Random)
  • Sticky header with interface toggle and furigana button
  • Entry tracking system (entries_index.json, candidate_words.json)
  • Cross-reference linking system (3,300+ references)
  • Inline word links in example sentences
  • Static HTML site generation (flat HTML only)
  • Prefix-based subdirectory structure (scalable to 10,000+ entries)
  • Three-tier vocabulary system (basic 801, core 1,998, general 7,504+)
  • Vocabulary tier realignment complete — all entries assigned
  • Tier-based filtering in Browse mode

Phase 5: Code Refactoring & Automation ✓ COMPLETE

  • Extracted CSS/JS from build_flat.py to standalone templates
  • Split build_flat.py into entry_renderer.py, page_generators.py, search_index_builder.py
  • Unit tests for japanese_utils.py and path_utils.py
  • Makefile with validate, build, quick, report targets
  • Dictionary health dashboard (build/report.py)
  • GitHub Actions CI for validation on push/PR
  • Automated pipeline system (pipeline/run-pipeline.sh)
  • GitHub Actions pipeline workflow for browser-triggered runs

Phase 6: Continued Expansion & Polish (Current)

  • Continue adding vocabulary
  • Add audio readings for example sentences
  • Conjugation search indexing
  • Offline package generation
  • Export to Anki format

For AI Assistants

Available Skills

The following skills are available in .claude/skills/ and will be automatically invoked by Claude Code when relevant:

SkillPurpose
entry-guidelinesGeneral quality standards for all entries
verb-entryRequirements for verb entries (transitivity, aspect, collocations)
adjective-entryRequirements for adjective entries (forms, conjugations)
particle-entryRequirements for particle entries (predicate lists, contrasts)
other-entriesRequirements for nouns, counters, adverbs, expressions
example-sentencesRequirements for example sentences (counts, length, vocabulary)
vocabulary-notesFormatting guidelines for notes field
vocabulary-tiersGuidelines for the three-tier vocabulary system
cross-reference-entryGuidelines for adding cross-references between entries
find-candidatesGuidelines for finding new candidate words to add
revise-entriesChecklist for revising existing entries to v2 standards
polish-entriesSystematic review and improvement of entries
delete-entryGuidelines for safely deleting entries
resolve-duplicatesGuidelines for identifying and resolving duplicate entries
kanji-indexGuidelines for maintaining the kanji index feature
inline-word-linksGuidelines for adding inline cross-reference links to examples

Skills are automatically loaded when Claude determines they're relevant to the current task.

Workflow for Creating/Editing Entries

  1. Read PROJECT_CONTEXT_BRIEF.md for current counts and rules
  2. Claude will automatically load relevant skills based on the entry type being created/revised
  3. Follow the guidelines from the loaded skills
  4. Validate entries after creation: make validate
  5. Place files correctly based on the numeric ID range
  6. Build the site: make build (or make quick for incremental)
  7. Update PROJECT_STATUS.md at the end of each session

Key Quality Standards (v2)

Based on multi-model LLM evaluation, these are HIGH PRIORITY for all entries:

For Verbs:

  • Transitivity type and pair verb
  • Aspect/ている behavior
  • Common collocations

For Particles:

  • List of predicates requiring this particle
  • Contrast with similar particles

For All Entries:

  • Examples progress from simple to complex
  • At least one collocation or fixed phrase
  • Consistent depth with similar entries

Directory Structure Quick Reference

Entries are organized by numeric ID ranges (500 entries per directory):

ID RangeDirectory
00000-00499entries/00000/
00500-00999entries/00500/
01000-01499entries/01000/
......

Use python3 build/get_entry_path.py <reading> <entry_id> to get the correct path for new entries.

License

Creative Commons Zero v1.0 Universal

Contributing

Email suggestions for enhancements to Tom Gally.

Contributors

tkgally

4,208 commits

claude

3,115 commits

actions-user

1,165 commits

tkgally/je-dict-1

In-progress Japanese-English learner's dictionary

8

stars

9,368

commits

Python

primary language

Sep 2, 2026

updated

README

TKG Japanese-English Learner's Dictionary

This is the repository for a Japanese-English learner's dictionary delivered as a static website. Its production is being supervised by Tom Gally. All of the entry-writing and coding is being done by Claude in Claude Code for the Web, with some bug-hunting and improvement-suggesting by ChatGPT and Gemini.

Live site: https://www.tkgje.jp/

This dictionary is licensed under Creative Commons Zero v1.0 Universal, and anyone is free to copy the data and code for whatever purpose they like, including commercial uses.

Overview

This dictionary is designed for learners of Japanese as a second language. It uses an original three-tier vocabulary classification system:

  • Basic tier: About one thousand fundamental words essential for basic communication
  • Core tier: About two thousand needed for adult-level communication
  • General tier: All other vocabulary useful for learners

Dictionary features include:

  • Explanatory definitions that go beyond simple glosses
  • Natural example sentences optimized for learning
  • Usage notes covering grammar, register, and common patterns
  • Furigana support with toggle to show/hide readings above kanji
  • Kanji index linking each kanji in headwords to all other entries containing that kanji
  • Multiple interface modes: Search, Browse, Recent, and Random views
  • Cross-reference linking with prominent top-of-entry links for homophones, verb pairs, and N/Nする pairs, plus structured "Related Words" boxes for antonyms, keigo, synonyms, and more
  • Inline word links in example sentences allowing navigation to any word's entry
  • Transitivity and aspect information for verbs
  • Collocation patterns showing natural word combinations
  • Keigo (honorific) verb coverage with usage guidance

Audio readings for example sentences will be added in the future.

Current Status

  • Over 14,000 entries across three vocabulary tiers
  • Vocabulary tiers: Basic (801), Core (1,998), General (the rest) — all new entries are added to general tier
  • Many cross-references linking related entries
  • Over 50,000 example sentences with inline word links
  • Claude Code skills for consistent entry creation and revision
  • Entry tracking system with entries_index.json for current entries and candidate_words.json for future additions
  • Automated pipeline for batch dictionary maintenance tasks
  • Unattended improvement Routine (prompts/routine2.md) — scheduled Claude sessions that rotate between polishing, entry creation, cross-model accuracy review (via OpenRouter, budget-capped), systemic fixes, and knowledge-base maintenance; each run verifies its own entry changes with an independent model, records quality metrics, and merges its own PR
  • Robust build system with atomic builds, XSS protection, and comprehensive validation
  • CI/CD with GitHub Actions for validation and automated pipeline runs

Target Users

Intermediate learners of Japanese who:

  • Can read hiragana and katakana fluently
  • Know some kanji and are building vocabulary
  • Want to understand words fully, not just look them up quickly

Technology

The dictionary is built as a completely static website:

  • No server required—just open index.html directly in your browser
  • No external dependencies—pure HTML, CSS, and JavaScript
  • Offline-capable—download and use anywhere

Site Structure

The dictionary is built as a static HTML site at docs/:

  • Individual pages: Each entry has its own standalone HTML file
  • Lightweight pages: Each page loads only the content needed
  • Deep linking: Direct URLs to specific entries

URL Structure

Entry pages are organized by numeric ID ranges (500 entries per directory):

docs/
├── index.html           # Home page
├── search.html          # Search interface
├── browse.html          # Browse by kana row
├── recent.html          # Recently modified entries
├── random.html          # Random word cloud
├── entries/
│   ├── 00000/           # Entries 00000-00499
│   │   ├── 00396_taberu.html
│   │   └── 00499_sakana.html
│   ├── 00500/           # Entries 00500-00999
│   ├── 01000/           # Entries 01000-01499
│   └── ...
└── kanji/               # Kanji index pages
    ├── 00001_teki_mato_target.html
    ├── 00009_jin_hito_person.html
    └── ...              # One page per kanji

This numeric range structure allows the dictionary to scale to 10,000+ entries while staying within GitHub's 1,000 files per directory limit.

Web Interface

The dictionary provides four different ways to explore entries:

Search Mode

Quick lookup by Japanese, romaji, or English. The traditional dictionary experience for users who know what word they're looking for.

Browse Mode

Explore entries organized by:

  • Starting Kana: あ行, か行, さ行, etc.
  • Vocabulary Tier: Basic (801 fundamental words), Core (1,998 adult-communication words), General (all other vocabulary)

The dictionary uses an original three-tier classification system instead of JLPT levels. All new entries are added to the general tier.

Recent Mode

View the most recently added or revised entries (up to 250). Each entry shows:

  • NEW: Newly created entries
  • REVISED: Updated existing entries
  • Date of addition/revision

Useful for tracking dictionary updates and discovering new content.

Random Mode

A word cloud of randomly selected entries. Click any word to view its full entry. Great for serendipitous discovery and vocabulary review.

Furigana System

The dictionary uses a custom notation for furigana (reading annotations above kanji):

Format

{kanji|reading}

Examples:

  • {食|た}べる → 食べる with た above 食
  • {友達|ともだち} → 友達 with ともだち above it
  • {日本語|にほんご}が{分|わ}かる → Multiple annotations in one sentence

In the Web Interface

  • Click the Furigana button in the header to toggle readings on/off
  • When enabled, readings appear above kanji using HTML <ruby> tags
  • Preference is saved in localStorage

Example sentences can contain inline word links that allow users to click any word to navigate to its dictionary entry.

In JSON source files, links use special Unicode delimiters:

⟦{surface|reading}→baseform:entry_id⟧

Components:

  • (U+27E6) - Opening bracket
  • surface - The word as it appears in the sentence (may include furigana notation)
  • (U+2192) - Arrow separator
  • baseform - The dictionary form of the word (displayed in tooltip)
  • (U+FF1A) - Fullwidth colon separator
  • entry_id - The target dictionary entry ID (e.g., 00111_hon)
  • (U+27E7) - Closing bracket

Example:

"japanese": "⟦{本|ほん}→本:00111_hon⟧⟦を→を:00422_wo⟧⟦{読|よ}む→読む:00426_yomu⟧。"

In the Web Interface

  • Click the Wordlinks button in the header to toggle link visibility
  • When enabled, words with links show a dotted underline
  • Hover over a linked word to see a tooltip with the dictionary form
  • Click to navigate to that word's entry
  • Preference is saved in localStorage

Special Cases

  • noentry: Use for words without dictionary entries: ⟦{矍鑠|かくしゃく}→矍鑠:noentry⟧
  • Conjugated forms: Link to the dictionary form (e.g., 食べました → 食べる)
  • No self-reference: Don't link the headword in its own examples
  • Punctuation: Do not link punctuation marks (。、?!)

Kanji Index

The kanji index allows users to find all dictionary entries containing a specific kanji character.

How It Works

  1. On entry pages: Each kanji in the headword is a clickable link
  2. Hover tooltip: Shows "Other words with this kanji" when hovering over a kanji
  3. Kanji page: Clicking displays a page with the kanji and all entries containing it
  4. Entry list: Sorted by hiragana reading order

Kanji ID Format

Each kanji is identified by a unique ID:

{5-digit number}_{onyomi}_{kunyomi}_{gloss}

Examples:

  • 00009_jin_hito_person (人)
  • 00116_kou_taka_tall (高)
  • 00431_yo_ama_surplus (余)

The ID uses none when a kanji lacks on'yomi or kun'yomi.

Technical Details

  • 2,040 kanji indexed from dictionary headwords
  • kanji_list.json: Master mapping of kanji characters to IDs
  • Individual JSON files: Entry lists for each kanji in kanji/
  • HTML pages: Generated in docs/kanji/ during site build
  • Automatic updates: New kanji are detected and indexed when entries are added

Project Structure

je-dict-1/
├── entries/              # Dictionary entries (one JSON file per word)
│   ├── 00000/            # Entries 00000-00499
│   ├── 00500/            # Entries 00500-00999
│   ├── 01000/            # Entries 01000-01499
│   └── ...               # (500 entries per directory)
├── kanji/                # Kanji index data
│   ├── kanji_list.json   # Master list mapping kanji to IDs
│   └── {kanji_id}.json   # Entry lists for each kanji
├── build/                # Build and management scripts
│   ├── schema.json       # JSON schema for entries
│   ├── validate.py       # Entry validation (schema, cross-refs)
│   ├── validate_tags.py  # Tag taxonomy validation
│   ├── build_flat.py     # Static HTML site generator (atomic builds)
│   ├── entry_renderer.py # Entry page HTML generation
│   ├── page_generators.py      # Navigation page generation
│   ├── search_index_builder.py # Search index and JS generation
│   ├── report.py         # Dictionary health dashboard
│   ├── generate_word_lookup.py # Builds word_id_lookup.json
│   ├── path_utils.py     # Shared path/prefix utilities
│   ├── japanese_utils.py # Hiragana/romaji/furigana utilities
│   ├── constants.py      # Centralized cross-reference type definitions
│   ├── update_indexes.py # Updates entries_index.json and candidate list
│   ├── manage_candidates.py    # Manages candidate_words.json
│   ├── get_entry_path.py       # Computes correct path for new entries
│   ├── get_timestamp.py        # Generates UTC timestamp for metadata
│   ├── check_duplicate.py      # Checks for duplicate entries
│   ├── verify_furigana.py      # Verifies furigana coverage
│   ├── templates/        # CSS and JS templates (styles.css, search.js, etc.)
│   ├── tests/            # Unit tests (pytest)
│   ├── archive/          # One-time migration scripts (no longer used)
│   └── requirements.txt  # Python 3.10+ dependencies
├── pipeline/             # Automated task pipeline
│   ├── run-pipeline.sh   # Task runner (reads config, invokes claude, validates)
│   ├── validate-task.sh  # Task-specific validation gates
│   ├── update-status.py  # Pipeline status tracking and reporting
│   ├── update-brief.py   # Regenerates PROJECT_CONTEXT_BRIEF.md
│   ├── recommend-tasks.py      # Task scheduler recommendations
│   ├── routine_next.py   # Unified Routine mode selector (weighted rotation + health nudges)
│   ├── metrics_snapshot.py     # Per-run quality metrics → metrics-history.jsonl
│   ├── openrouter-ledger.json  # Daily OpenRouter spend ledger ($5/day cap)
│   └── pipeline-config.json    # Active pipeline configuration
├── polishing/            # Progress tracking for polishing tasks
├── prompts/              # Task prompts (interactive and batch/)
├── docs/                 # Generated output (served as static site)
│   ├── entries/          # Individual entry HTML files
│   │   ├── 00000/        # (same numeric range structure as entries/)
│   │   └── ...
│   └── kanji/            # Kanji index HTML pages
├── .claude/              # Claude Code configuration
│   ├── skills/           # Agent skills for entry guidelines (auto-loaded)
│   └── settings.json
├── .github/workflows/    # GitHub Actions (validate.yml, pipeline.yml)
├── Makefile              # Build runner (make validate, make build, etc.)
├── entries_index.json    # Index of all dictionary entries
├── candidate_words.json  # Words to potentially add in future
├── PROJECT_CONTEXT_BRIEF.md  # Quick-reference counts for session start
└── PROJECT_STATUS.md     # Session continuity and recent change log

Entry Schema

Each entry is a JSON file with the following structure:

{
  "id": "00396_taberu",
  "headword": "{食|た}べる",
  "reading": "たべる",
  "part_of_speech": "verb (ichidan)",
  "gloss": "to eat",
  "definitions": [
    {
      "sense_number": 1,
      "gloss": "to eat",
      "explanation": "The most common verb for eating..."
    }
  ],
  "examples": [
    {
      "id": "00396_taberu_ex1",
      "japanese": "{朝|あさ}ごはんを{食|た}べましたか。",
      "english": "Did you eat breakfast?",
      "notes": null,
      "sense_numbers": [1]
    }
  ],
  "notes": "Usage notes, grammar notes, etc.",
  "cross_references": [
    {
      "type": "pair",
      "reading": "たべもの",
      "headword": "{食|た}べ{物|もの}"
    }
  ],
  "metadata": {
    "created": "2026-01-05T10:00:00Z",
    "modified": "2026-01-05T10:00:00Z",
    "ai_model": "claude-opus-4-5",
    "vocabulary_tier": "basic"
  }
}

Sense Numbers in Examples

The sense_numbers field on example sentences links each example to one or more definition senses:

  • Required for multi-sense entries: Every example must specify which sense(s) it illustrates
  • Format: Array of integers matching sense_number values in definitions (e.g., [1], [2], or [1, 2])
  • Single-sense entries: Use [1] for all examples
  • Multi-sense examples: An example can illustrate multiple senses with [1, 2]

This enables future features like filtering examples by sense and helps learners understand which meaning each example demonstrates.

File Naming Convention

Files use the format: {id}_{romanized_reading}.json

  • IDs are 5-digit zero-padded numbers at the START of the filename
  • Use Modified Hepburn romanization for the reading
  • Long vowels follow kana spelling: 東京 → toukyou, not tokyo
  • Katakana loanwords use hiragana reading (e.g., アルバイト → arubaito)

Directory Placement

Files go in directories based on the numeric ID range (500 entries per directory):

  • Entry 00396_taberu → entries/00000/00396_taberu.json
  • Entry 00538_aruku → entries/00500/00538_aruku.json
  • Entry 01186_mukau → entries/01000/01186_mukau.json

The directory name is determined by rounding down to the nearest 500:

  • IDs 00000-00499 → entries/00000/
  • IDs 00500-00999 → entries/00500/
  • IDs 01000-01499 → entries/01000/

Phased Roadmap

Phase 1: Foundation ✓ COMPLETE

  • Project structure and schema
  • Build and validation scripts
  • Basic web interface
  • Furigana system with toggle

Phase 2: Core Vocabulary ✓ COMPLETE

  • Basic vocabulary foundation (~761 entries)
  • Multi-model LLM evaluation
  • Quality specification v2
  • Entry revision to v2 standards

Phase 3: Entry Enhancement ✓ COMPLETE

  • Add transitivity/aspect to all verbs
  • Expand particle entries with predicate lists
  • Add collocation patterns
  • Standardize adjective forms
  • Notes formatting with bullet points

Phase 4: Vocabulary Expansion & Interface ✓ COMPLETE

  • Added ~7,500+ vocabulary entries (10,300+ total)
  • Multiple interface modes (Search, Browse, Recent, Random)
  • Sticky header with interface toggle and furigana button
  • Entry tracking system (entries_index.json, candidate_words.json)
  • Cross-reference linking system (3,300+ references)
  • Inline word links in example sentences
  • Static HTML site generation (flat HTML only)
  • Prefix-based subdirectory structure (scalable to 10,000+ entries)
  • Three-tier vocabulary system (basic 801, core 1,998, general 7,504+)
  • Vocabulary tier realignment complete — all entries assigned
  • Tier-based filtering in Browse mode

Phase 5: Code Refactoring & Automation ✓ COMPLETE

  • Extracted CSS/JS from build_flat.py to standalone templates
  • Split build_flat.py into entry_renderer.py, page_generators.py, search_index_builder.py
  • Unit tests for japanese_utils.py and path_utils.py
  • Makefile with validate, build, quick, report targets
  • Dictionary health dashboard (build/report.py)
  • GitHub Actions CI for validation on push/PR
  • Automated pipeline system (pipeline/run-pipeline.sh)
  • GitHub Actions pipeline workflow for browser-triggered runs

Phase 6: Continued Expansion & Polish (Current)

  • Continue adding vocabulary
  • Add audio readings for example sentences
  • Conjugation search indexing
  • Offline package generation
  • Export to Anki format

For AI Assistants

Available Skills

The following skills are available in .claude/skills/ and will be automatically invoked by Claude Code when relevant:

SkillPurpose
entry-guidelinesGeneral quality standards for all entries
verb-entryRequirements for verb entries (transitivity, aspect, collocations)
adjective-entryRequirements for adjective entries (forms, conjugations)
particle-entryRequirements for particle entries (predicate lists, contrasts)
other-entriesRequirements for nouns, counters, adverbs, expressions
example-sentencesRequirements for example sentences (counts, length, vocabulary)
vocabulary-notesFormatting guidelines for notes field
vocabulary-tiersGuidelines for the three-tier vocabulary system
cross-reference-entryGuidelines for adding cross-references between entries
find-candidatesGuidelines for finding new candidate words to add
revise-entriesChecklist for revising existing entries to v2 standards
polish-entriesSystematic review and improvement of entries
delete-entryGuidelines for safely deleting entries
resolve-duplicatesGuidelines for identifying and resolving duplicate entries
kanji-indexGuidelines for maintaining the kanji index feature
inline-word-linksGuidelines for adding inline cross-reference links to examples

Skills are automatically loaded when Claude determines they're relevant to the current task.

Workflow for Creating/Editing Entries

  1. Read PROJECT_CONTEXT_BRIEF.md for current counts and rules
  2. Claude will automatically load relevant skills based on the entry type being created/revised
  3. Follow the guidelines from the loaded skills
  4. Validate entries after creation: make validate
  5. Place files correctly based on the numeric ID range
  6. Build the site: make build (or make quick for incremental)
  7. Update PROJECT_STATUS.md at the end of each session

Key Quality Standards (v2)

Based on multi-model LLM evaluation, these are HIGH PRIORITY for all entries:

For Verbs:

  • Transitivity type and pair verb
  • Aspect/ている behavior
  • Common collocations

For Particles:

  • List of predicates requiring this particle
  • Contrast with similar particles

For All Entries:

  • Examples progress from simple to complex
  • At least one collocation or fixed phrase
  • Consistent depth with similar entries

Directory Structure Quick Reference

Entries are organized by numeric ID ranges (500 entries per directory):

ID RangeDirectory
00000-00499entries/00000/
00500-00999entries/00500/
01000-01499entries/01000/
......

Use python3 build/get_entry_path.py <reading> <entry_id> to get the correct path for new entries.

License

Creative Commons Zero v1.0 Universal

Contributing

Email suggestions for enhancements to Tom Gally.

See what people are saying

Contributors

tkgally

4,208 commits

claude

3,115 commits

actions-user

1,165 commits

Languages

Python

90.8%

Shell

3.8%

CSS

3.1%

JavaScript

2.2%