Double Shift RU/EN layout rescue for GNOME, KDE, Wayland and X11
lay
Double Shift RU/EN layout rescue для Linux
lay чинит слово, набранное не в той раскладке: нажал Shift два раза и продолжил писать.
Статус: alpha. Основной сценарий уже рабочий. Главная зона активной доводки — автопомощь после пробела и редкие desktop edge cases.
curl -fsSL https://raw.githubusercontent.com/radislabus-star/lay-public/main/scripts/install-remote.sh | bash
Что это
lay — локальный клавиатурный помощник для Linux-пользователей, которые пишут на русском и английском вперемешку.
Главный сценарий:
Набрал: ghbdtn
Нажал: Shift Shift
Стало: привет

lay не использует буфер обмена для основного сценария и не требует облачной модели. Он слушает физические клавиши локально, помнит короткий хвост набора и при команде перепечатывает его в другой раскладке.
По умолчанию double Shift исправляет 1 последнее слово. Области 2 слова и 3 слова можно включить отдельно в трее.
Что нового в 0.2.0
- заложен первый системный слой
Typing Correction Core: входной текст теперь
- deterministic typing-assist и NANDA-кандидаты проходят через общий
CandidateBoard, вместо разрозненного применения частных правил;
- добавлены классы ошибок: wrong layout, mixed script, missing/extra/repeated
- IME остаётся backend отображения/вставки: новый core не переносит принятие
Что нового в 0.1.245
- общий рубильник
Журнал отладки действийтеперь реально гасит runtime
- runtime-журналы ограничены кольцевым хвостом 500 KiB, чтобы
cell_traceи
precognition не разрастались во время живого набора;
- добавлен контекстный guard для
b -> и: замена разрешается только внутри
- IME profile-тесты закрепляют различие Kitty terminal passthrough и managed
Что нового в 0.1.244
- добавлен и документирован экспериментальный IME backend: inline/preedit
- демо
docs/publicity/demo.gifобновлено: теперь показывает double Shift,
- усилены guard-правила автозамены по живым логам: NANDA/L2 больше не должны
модель генерит -> модель
генерал.
Что нового в 0.1.232
- в окне настроек поменяны местами блоки
УправлениеиАрбитры и каналы,
Что нового в 0.1.231
- IME double Shift восстанавливает потерянную первую layout-букву в
hbdtn -> привет,
dnjpfvtyf -> автозамена;
- mixed-script автозамена удаляет дублирующий латинский layout-префикс перед
fавтозамена -> автозамена;
- NANDA Wave trainer умеет дообучать Cell32-память из успешных live-действий
typing-assist, ime-typing-assist, layout-replay, smart-text;
- ручные
user-correctionне попадают в обучение по умолчанию и требуют
Что нового в 0.1.230
- IME-подсказки больше не переводят уже напечатанный токен в активную
- это защищает Kitty/терминалы от рассинхрона preedit, потери пробела и
- генерация подсказок остаётся быстрой и работает как безопасный suffix-preedit.
Что нового в 0.1.229
- установщик больше не проверяет и не предлагает Ollama/smollm;
- при установке или обновлении выполняется миграция старых lay-установок:
ollama.service, бинарник и локальные модели Ollama удаляются;
- если Ollama нужна пользователю отдельно от lay, перед установкой можно
LAYKEEPOLLAMA=1 bash install.sh;
- в настройках NANDA вынесена в отдельное окно: в основном меню осталась
NANDA ячейки;
- старый Expert64/microbrain runtime удалён, окно NANDA показывает только
lay-nanda-wave-eval --status-json;
- live smoke harness научился использовать
LAYCONFIGPATH, чтобы тестировать
$HOME и без поломки session bus.
Что нового в 0.1.222
- CI smoke-проверка на GitHub переведена на стабильный главный сценарий:
ghbdtn -> привет, без зависимости от словарной autocorrect-эвристики
runner-а.
Что нового в 0.1.221
- починен публичный CI/status на GitHub: architecture guard синхронизирован с
- статус последнего коммита на странице репозитория больше не должен оставаться
Что нового в 0.1.220
- исправлен idle busy-loop в non-GNOME backend:
lay-daemonбольше не
poll() на 1 мс из-за stale focus-poll timestamp;
- настройки демона кешируются по
mtimeс коротким интервалом проверки, чтобы
~/.config/lay/config.json на каждом цикле;
- русские горячие словари упакованы компактнее: текущая память свежего демона
Что нового в 0.1.219
- исправлен Niri/backend-кейс без
focusedwindowidentity: при смене
fieldcontextepoch, поэтому
хвост из одного поля не склеивается с вводом в другом поле;
- добавлен регрессионный тест на сценарий без информации об окне.
Что нового в 0.1.218
- GNOME extension больше не пишет штатные success-сообщения в журнал при каждом
DBus enabled, DBus disabled, LayImpl enabled;
- диагностические сообщения в GNOME journal оставлены только для ошибок и
Что нового в 0.1.217
- режим
Смелеестал действительно смелее для одиночных раскладочных букв:
z может исправляться в я, b — в и, при этом нормальный режим эти
короткие замены не включает;
- короткий технический RU→EN перевёртыш
ьытеперь распознаётся какms; - усилены существующие typo-слои: соседняя клавиша ловит формы вроде
кнорку -> кнопку, а фразовый missing-letter может исправлять контекст
вроде с фалом -> с файлом;
- область помощи при наборе отделена от области ручного double Shift: по
1 слово, а typing assist может смотреть
короткий хвост отдельно;
- окно настроек получило desktop entry и нормальную иконку в GNOME panel /
- иконки в GNOME tray, меню и окне настроек приведены к одному компактному
- часть пунктов меню настроек переведена на русский и дополнительно сжата по
Что нового в 0.1.216
- исправлен mixed-word рассинхрон в KDE/Kate и других backend: если слово почти
- живой проверочный кейс:
привеnпо double Shift становитсяпривет, без
приве + n.
Что нового в 0.1.215
- добавлен Niri layout backend через прямой
niri-ipc; autoстал умнее: в KDE/Plasma VM с nested Niri он выбирает KDE, а не
NIRI_SOCKET;
- в GNOME и KDE tray добавлен ручной выбор среды раскладки:
auto / KDE / X11 / GNOME / Niri;
- KDE tray показывает выбор среды в верхнем блоке меню и не закрывается после
- Niri помечен как экспериментальный режим для реальной Niri-сессии, а не как
Что нового в 0.1.214
- откатили небезопасную GNOME/uinput speed-оптимизацию, которая в терминале
- перед replay снова обязательно синхронизируются GNOME Shell и IBus, чтобы
- фиксы
b, коротких кириллических фрагментов иon/offиз0.1.213
Что нового в 0.1.213
- standalone
bбольше не автозаменяется вв/ибез фразового контекста; - короткие кириллические фрагменты больше не улетают в случайный EN-токен,
ыл не должен превращаться в sk;
- технические короткие EN-слова
on/offоставлены разрешёнными для
- GNOME/uinput speed-path был добавлен в этом релизе, но в
0.1.214откатан
Что нового в 0.1.212
- GNOME tray разрезан на отдельные модули: DBus bridge, меню последних
- установщик, dev-reload и CI теперь копируют и проверяют все JS-модули
- таблицы русской морфологии вынесены в
data/lexicon, чтобы runtime-код не
- встроенные сценарии
lay-test-inputвынесены вdata/test_input; - исправлен баг
protected_words.txt: пользовательские защищённые ASCII-слова
cd не должен
превращаться в св после пробела.
Что нового в 0.1.210
- KDE backend кэширует
qdbusи список раскладок вместо повторного запроса на
- короткий KDE replay теперь использует тот же быстрый isolated-output путь,
- проверено live в KDE/Plasma X11 VM.
- KDE: короткое слово
~54-67 ms; - KDE: backspace/replay для коротких хвостов
~0-1 ms; - основной остаток в KDE теперь тоже переключение layout.
Что нового в 0.1.209
- double Shift стал быстрее: если daemon успешно изолировал физическую
- длинные хвосты остаются на paced-пути, чтобы приложения не теряли
- debug-лог теперь показывает разрез времени по стадиям: layout, delete,
- ускоренный manual replay и typing assist проверены live в GNOME.
- GNOME: manual double Shift на 2-3 слова
~40 ms; - GNOME: короткое слово
~53-62 ms, основной остаток — переключение layout; - GNOME: typing assist после пробела
~61-75 ms; - длинный хвост около 240 клавиш остаётся безопасно paced:
~1.1 s.
Быстрый старт
Установка одной командой:
curl -fsSL https://raw.githubusercontent.com/radislabus-star/lay-public/main/scripts/install-remote.sh | bash
После установки выйди из сессии и зайди снова. Это нужно для группы input, доступа к /dev/uinput и desktop-интеграции.
Проверка:
1. Включи русскую и английскую раскладки.
- Набери ghbdtn.
- Нажми Shift два раза.
- Должно получиться привет.
Обновление:
cd ~/projects/lay && bash update.sh
В GNOME и KDE обновление также доступно из меню трея: Проверить обновления.
Возможности
- Double Shift исправляет последнее слово в другой раскладке.
- Replay физически перепечатывает хвост теми же keycode.
- Smart старается не трогать уже нормальные соседние слова.
- Помощь при наборе после пробела исправляет только уверенные ошибки.
- Автоподмена включает автоматические исправления после пробела.
- NANDA — экспериментальный клеточный слой внутри автоподмены; включается
NANDA ячейки.
- ptah_alexs жёстко ставит раскладку для выбранных окон.
- Прямые RU/EN хоткеи могут включать конкретную раскладку без toggle.
- KDE/Niri/X11 backend есть, но покрытие меньше, чем у GNOME Wayland.
good ntrcn -> good текст
Здесь good остаётся на месте, а исправляется только ntrcn.
Что включено по умолчанию
Для новой установки базовое поведение консервативное:
- double Shift включён;
- область double Shift —
1 слово; - автоматическая помощь после пробела выключена, пока пользователь сам её не
- точная автоподмена выключена, пока пользователь сам её не включит;
- основной вывод идёт через
uinput; - среда раскладки выбирается автоматически:
layout_backend=auto; - сетевые LLM/API не используются.
ollama.service для экспериментов.
Новые установки и обновления его вычищают. Это часть перехода на локальный
deterministic/NANDA pipeline без фонового LLM-сервиса.
Настройки хранятся в:
~/.config/lay/config.json
Поддержка окружений
Основная проверенная среда: Ubuntu/GNOME Wayland с RU/EN раскладками.
Текущая матрица:
- GNOME Wayland — основной и самый зрелый путь.
- KDE/Plasma Wayland — поддерживается, но покрытие меньше.
- Niri Wayland — есть backend через прямой
niri-ipc, требует проверки
- X11 — есть native XKB backend, проверяется как экспериментальный путь.
- Sway/Hyprland/другие WM — пока не заявлены как поддержанные.
- Языки — текущая цель только RU/EN.
- GNOME: Shell extension, tray и DBus bridge для переключения раскладки;
- KDE/Plasma: отдельный
lay-kde-trayи переключение черезqdbus6; - Niri: прямой IPC через Unix socket и crate
niri-ipc; - X11: native XKB backend через
x11rb.
layout_backend=auto. Обычно это правильный выбор:
GNOME выбирает GNOME, KDE/Plasma выбирает KDE, X11 выбирает X11, настоящая Niri
сессия выбирает Niri. Ручной выбор нужен только для диагностики или нестандартной
вложенной среды.
KDE, Niri и X11 моложе GNOME-пути. Если что-то ломается в другой сборке Linux, лучше открыть issue с точным примером: что набрано, что ожидалось, что получилось.
Языки
Текущая цель проекта — качественная пара RU/EN.
Используется:
- физическое соответствие US ↔ RU;
- Hunspell-словари, если они есть в системе;
- локальные RU/EN правила;
- char n-gram и LEM scoring;
- пользовательские точные замены;
- пользовательский список защищённых слов.
- другие пары раскладок;
- полноценная грамматика русского языка;
- исправление целых абзацев;
- универсальные серые подсказки во всех приложениях. Экспериментальный IME
NANDA Wave / клеточный мозг
lay экспериментирует с маленькой локальной NANDA Wave-архитектурой. Это не облачная LLM и сейчас не замена основного автокорректора. Основной runtime остаётся детерминированным: словари, LEM/ngram, protected words, rule graph и safe replacement pipeline. NANDA Wave отдельно изучает клеточные признаки, кандидаты, ablation и ансамблевые моды.
Базовая единица:
Cell32 = 32 KB волновой клетки
Клетка маленькая по памяти, но может видеть весь короткий хвост предложения. Она не обязана отвечать только за одно слово. Текущие зоны:
L1сенсоры: UTF-8, письмо/форма, клавиатура, границы;L2кандидаты: раскладка, технические токены, фразовый сигнал;L3согласование: защитный контекст, фразовая связность, Mesh.
layout— точное/обратное совпадение раскладки, расстояние до layout-кандидата;script— кириллица, ASCII, смешанные токены, переходы RU/EN;token_identity— известное русское/английское слово, technical, protected,
boundary— число слов, пробелы, склейка/разрыв, сохранение хвостового
shape— форма токена, регистр, цифры, пунктуация, дефисы;edit— edit distance, replacement span, длина правки;risk— plain-layout risk, technical/protected risk, prefix deletion risk;context— последовательность типов токенов в коротком хвосте.
Текущая цель по масштабу:
- минимальный живой мозг:
16active-клеток; - нормальный локальный организм:
64warm-клетки; - большой персональный мозг: до
1024клеток в локальной памяти.
Ensemble Mode
Важная часть NANDA Wave — искать моды не только внутри одной клетки, а в ансамбле.
Ensemble Mode — устойчивый паттерн совместной активации Cell32-клеток, который причинно отвечает за класс решений.
Пример безопасного wrong-layout режима:
layout_writer high
layout_signal high
space_boundary high
technical_guard low
undo_guard low
sentence_mesh high
=> apply
Пример режима запрета:
layout_writer high
layout_signal high
technical_guard high
cli_guard high
sentence_mesh low
=> keep original
Иными словами, ответ не обязан жить в одной клетке. Он появляется как когерентный пик нескольких независимых сигналов. Mesh делает несколько коротких вычислительных тактов без задержек ввода: если пик устойчивый — исправление можно применить; если клетки спорят — lay молчит.
Кто учит клетки
Клетки не должны хаотично самообновляться во время печати. Обучение должно быть отдельным локальным процессом:
- пользователь даёт главный сигнал истины: оставил, удалил, откатил,
- deterministic
layдаёт безопасные initial labels: layout, словари, n-gram,
- старший teacher/arbiter может помогать разбирать спорные случаи и создавать
- offline trainer собирает fixtures, synthetic cases, learning log, user
- Mesh supervisor учит не одну клетку, а связи: какие сочетания клеток усиливать
Схема:
user feedback
- deterministic labels
- teacher labels
- synthetic cases
-> trainer
-> new Cell32 candidate
-> eval
-> ablation
-> promote or reject
Runtime остаётся безопасным: клетки не печатают напрямую в систему. Они предлагают или оценивают кандидаты, а вывод всё равно идёт через существующий safe replacement pipeline.
Текущий статус NANDA: старый Expert64/microbrain runtime удалён. В коде остался NANDA Wave-слой: Cell32-паспорт, L1/L2/L3, Wave trace, real-suite, status JSON и ablation.
Проверка Wave-слоя:
lay-nanda-wave-eval --status-json
lay-nanda-wave-eval --trace "djn "
lay-nanda-wave-eval --real-suite --ablation
Клетку нельзя делать главной только потому, что она существует. Минимальный критерий: lay-nanda-wave-eval не ухудшает baseline, а ablation показывает, что отключение клетки ухудшает её конкретный класс задач.
Сравнение 64x3-vs-192 пока остаётся исследовательской задачей, а не production-командой.
Для ансамбля критерий жёстче. Это называется **LayMesh Ensemble Mode Criterion**:
synergy(E, C) =
quality(E, C) - maxi quality({ei}, C)
ablationdrop(ei, E, C) = quality(E, C) - quality(E without e_i, C)
Ансамблевая мода считается найденной только если одновременно верно:
synergy(E, C)выше порога: связка лучше любой одиночной клетки;ablation_dropключевой клетки заметный: разрушение связки ломает эффект;falsepositivedeltaне вырос: мода не шумит на чужих классах;stabilityподтверждена на разных split-корпуса;localityподтверждена: улучшение живёт в своём классе ошибок.
lay-nanda-wave-eval --real-suite --ablation печатает текущие признаки:
synergyvsbest_single
synergyvsbest_pair
ablation_drop
falsepositivedelta
stability
locality
mode_status
Если отчёт пишет modestatus: ensemblemode_found, связка прошла критерий. Если отчёт пишет tooeasyor_redundant, корпус не доказывает новую моду: одиночные клетки уже справляются или связка ничего причинно не добавляет. Если пишет rejectedfalsepositives, связка полезна в своём классе, но опасно портит чужие случаи.
Ограничения
lay сознательно работает с коротким хвостом текста, который daemon видел через evdev. Это делает основной сценарий быстрым, но задаёт границы:
- не исправляет произвольное слово под курсором после ручного перемещения;
- не меняет выделенный текст как универсальную функцию;
- не читает весь текст поля и не знает весь документ;
- Enter-autocorrect не включён в публичный стабильный UI, потому что evdev/uinput
- IME/preedit и inline-подсказки доступны как экспериментальный режим ввода, но
- автопомощь после пробела остаётся консервативной: лучше пропустить сомнительный
Меню в трее
Основные пункты:
Помощь при наборе— осторожная правка после пробела.Автоподмена— главный рубильник автоматических исправлений после пробела.NANDA ячейки— отдельное окно с клеточным Wave-слоем, статусом и ablation.Режим—ReplayилиSmart.Режим ввода— быстрый uinput или экспериментальный IME backend с
Область— сколько слов брать для double Shift, по умолчанию1.Арбитр— LEM и auto-layout настройки.ptah_alexs— жёсткая раскладка по окну.Daemon— запуск, остановка и статус сервиса.О программе— версия, ссылка на GitHub и служебная информация.
CLI
lay можно использовать из терминала:
lay "Ye djn ghbvth"
Ну вот пример
lay "руддщ цщкдв"
hello world
echo "ghbdtn" | lay
привет
Приватность
lay-daemon читает клавиатурные события локально, потому что иначе double Shift rescue невозможен. По умолчанию он не отправляет набранный текст в сеть, не требует удалённой модели и не ведёт полный keylog.
Опциональный learning log локальный и выключен по умолчанию:
~/.local/share/lay/corrections.jsonl
Диагностические файлы и счётчики тоже локальные:
~/.local/share/lay/recent_actions.jsonl
~/.local/share/lay/learning_candidates.json
~/.local/share/lay/stats.json
На Unix такие файлы создаются с правами 0600.
Статус alpha
Стабильное ядро: ручной double Shift и локальная RU/EN конвертация.
Активно оттачиваются:
- автопомощь после пробела;
- пробелы и границы слов после автозамены;
- mixed RU/EN сценарии;
- KDE/X11 edge cases;
- работа в старых/особых текстовых полях;
- экспериментальный IME backend и preedit-кандидаты в разных приложениях.
- что набрано;
- что ожидалось;
- что получилось;
- GNOME/KDE/Niri/X11 и версия системы;
- включены ли
Помощь при наборе,Автоподмена,Smart, LEM.
Документация
- Как это работает
- Проверочный список архитектуры
- Multi-tap Shift scope
- Research: Linux input correction best practices
- Публичные материалы
Разработка
cargo test
cargo build --release
bash install.sh
Полная локальная проверка перед публикацией:
scripts/check-lay-full.sh
English
lay is a local Double Shift RU/EN layout rescue tool for Linux desktops.
Main workflow:
Typed: ghbdtn
Press: Shift Shift
Result: привет
Quick install:
curl -fsSL https://raw.githubusercontent.com/radislabus-star/lay-public/main/scripts/install-remote.sh | bash
After installation, log out and log back in so the input group, /dev/uinput permissions, and desktop integration are picked up.
Main tested target: GNOME Wayland with RU/EN layouts. KDE/Plasma Wayland and Niri Wayland are supported with a smaller compatibility matrix. X11 has a native XKB backend and is treated as experimental. Other layouts and non-RU/EN pairs are not supported yet.
Known limitations: lay works on a short typed tail, not arbitrary selected text or the whole document. Enter autocorrect is not the stable default path. IME/preedit-style inline assistance exists as an experimental input backend, but the fast uinput path remains the default.
By default lay does not use cloud APIs, does not require an LLM, and does not send typed text anywhere.
License
Lay Non-Commercial License v1.0. Commercial use is prohibited without prior written permission from the copyright holders. See LICENSE.