Version-control your custom dictionary with Git
Bareun's custom dictionary is managed through the CustomDictionaryService API.
The server stores the custom dictionary in its own format (binary), so you do not edit the files in the dictionary directory by hand.
That means what you manage with Git is not the server's dictionary files but the word list (source) that you own.
We recommend keeping your list of dictionary entries as a human-readable source (text, CSV, or whatever format you like), managing it with Git, and then applying it to Bareun through the UpdateCustomDictionary API.
Do not put the server's dictionary directory files in Git
The files in the custom dictionary directory are binary files managed by the server. They are not suited to being edited by people or handled with Git diff and merge. Version-control your own word list source instead.
Why manage it with Git
| What you get | Description |
|---|---|
| Change history | Track who added or removed which word, and when |
| Review | Review word list changes in a PR/MR before applying them |
| Rollback | Return a wrongly registered word to its earlier state |
| Consistency | Apply the same dictionary identically to several environments (development, production) |
| Collaboration | Split the word list among domain experts |
Example repository layout
It helps to split your word list source by domain and by dictionary type. The format is up to you (the example below uses one entry per line), and a deployment script reads this source and registers it through the API.
Each txt file has a simple structure with one word per line.
custom-dict-src/
legal/
np.txt # proper nouns, one per line (민식이법, 김영란법 ...)
cp.txt # compound nouns (압수수색 ...)
cp-caret.txt # compound noun split, split points marked with ^ (손해^배상 ...)
vv.txt # verbs (기소하다 ...)
va.txt # adjectives
finance/
np.txt
cp.txt
README.md # notes on classification criteria and registration rules
For example, legal/np.txt looks like this (one word per line).
민식이법
김영란법
공수처
Collaboration workflow
graph LR A[Edit word list source] --> B[Conflict check]; B --> C[PR/MR review]; C --> D[Merge]; D --> E[Apply via UpdateCustomDictionary API]; E --> F[Reload without downtime];
- Edit: The owner adds or edits entries in the domain word list source.
- Conflict check: Before applying, check for duplicates and conflicts with
CheckConflict(you can automate this in CI). - Review: Review "why this word goes into this dictionary" together in a PR/MR.
- Merge and apply: A deployment script reads the merged source and registers it through the
UpdateCustomDictionaryAPI. - Apply without downtime:
Bareundetects the dictionary change and applies the new dictionary without a restart.
Put the conflict check in CI
If you add a CI job that runs CheckConflict whenever the word list changes, changes that conflict are filtered out before they merge. It is the surest way to keep the production dictionary at zero conflicts at all times.
Deployment patterns
- Deploy by applying through the API: A deployment script reads the word list source pulled from Git and registers it through the
UpdateCustomDictionaryAPI. It is easy to combine with your application deployment pipeline, and changes apply without downtime after registration. - Source = single source of truth: If the contents of the production dictionary always start from the word list source in Git, you can reproduce the same state in any environment.
Keep API keys and sensitive information separate from the word list
Keep only entries in the word list source. Manage sensitive information such as API keys and connection details separately, and do not commit them to the same repository.
Example: read txt lists and apply them through the API
This script reads per-POS txt files (one word per line) and applies them to Bareun's custom dictionary.
When the word list changes in Git (after a merge, or in CI), run this script once to register it through the UpdateCustomDictionary API. It applies immediately, without downtime.
import os
from bareunpy import Tagger
# -- Settings ------------------------------------------------
# API_KEY : Your own API key issued at bareun.ai. Do not write it directly in
# the source; inject it through an environment variable
# (os.environ["BAREUN_API_KEY"]) or similar.
# HOST : Bareun server host. Use "localhost" for a local installation.
# PORT : Bareun server port. The default is 5656.
# SRC_DIR : The directory of "my word lists" managed in Git (holds per-POS txt files).
# DOMAIN : Name of the custom dictionary to register and update in Bareun
# (selected with custom_dict_names in a request).
API_KEY = "koba-..."
HOST, PORT = "localhost", 5656
SRC_DIR = "custom-dict-src/legal"
DOMAIN = "legal"
def read_words(path: str) -> set:
"""Read a per-POS txt file and return it as a set of entries.
A txt file has a "one word per line" structure. Leading and trailing
whitespace on each line is stripped, and blank lines and comment lines
starting with '#' are skipped. Because the result is a set, duplicates
are removed automatically even if the same word appears several times.
Args:
path (str): Path of the txt file to read (e.g. "custom-dict-src/legal/np.txt").
Returns:
set: A set of entry strings. If the file does not exist, an empty set
is returned (which has the effect of registering that POS
dictionary as empty).
"""
# A POS with no file yet (e.g. va.txt not written) is treated as an empty set.
if not os.path.exists(path):
return set()
# Read as UTF-8 and collect only words, after stripping whitespace and
# dropping blank lines and comments (#).
with open(path, encoding="utf-8") as fp:
return {ln.strip() for ln in fp
if ln.strip() and not ln.startswith("#")}
# 1) Read each per-POS txt list into a set.
np_set = read_words(f"{SRC_DIR}/np.txt") # proper nouns (NP)
cp_set = read_words(f"{SRC_DIR}/cp.txt") # compound nouns (CP)
cp_caret_set = read_words(f"{SRC_DIR}/cp-caret.txt") # compound noun split (CP^), split points marked with ^
vv_set = read_words(f"{SRC_DIR}/vv.txt") # verbs (VV)
va_set = read_words(f"{SRC_DIR}/va.txt") # adjectives (VA)
# 2) Connect to the server, open the target custom dictionary (DOMAIN), and
# fill it with the per-POS sets.
# copy_*_set REPLACES the whole contents of that POS dictionary with the set.
# (It replaces rather than accumulates, so the txt file becomes the final
# state of that dictionary.)
tagger = Tagger(API_KEY, HOST, PORT)
cust = tagger.custom_dict(DOMAIN)
cust.copy_np_set(np_set)
cust.copy_cp_set(cp_set)
cust.copy_cp_caret_set(cp_caret_set)
cust.copy_vv_set(vv_set)
cust.copy_va_set(va_set)
# 3) Call the UpdateCustomDictionary API to apply it on the server.
# It takes effect on that server immediately (no downtime), and if several
# servers share the dictionary directory, it propagates to the others right away.
cust.update()
print(f"'{DOMAIN}' dictionary updated: "
f"NP {len(np_set)}, CP {len(cp_set)}, CP^ {len(cp_caret_set)}, "
f"VV {len(vv_set)}, VA {len(va_set)}")
'legal' dictionary updated: NP 3, CP 1, CP^ 1, VV 1, VA 0
Connect it directly to CI/deployment
If you put this script in a deployment job that runs after a merge, the word list in Git becomes the production dictionary.
It is safer still to check for conflicts once with CheckConflict before running it.
Frequently asked questions
Q. Can I manage the custom dictionary with Git?
The server's dictionary files (binary) themselves are not meant to be managed in Git. Instead, manage your own word list source in Git and apply it through the UpdateCustomDictionary API, and you can use change history, review, and rollback as they are.
Q. How should I lay out the repository?
Split directories by domain and keep list files per dictionary type (np/cp/cp-caret/vv/va), which makes them easy to manage. The format is up to you. Leave the classification criteria in a README alongside.
Q. How do I apply a word list I merged in Git to production?
A deployment script reads the word list source and registers it through the UpdateCustomDictionary API.
Once registered, Bareun detects the dictionary change and applies it without downtime.