Per-keystroke JSONL trace of the live decision path:
key_in → core verdict (consume/forward, dual-buffer/lock state, predictions) → dispatched actions → accept (committed vs typed + script class) → outcome.
Off by default. Without SMARTKEY_DEBUG (env) or an enable marker the
trace is a single boolean check per keystroke — zero I/O, production
byte-for-byte identical.
| Level | How | What is logged |
|---|---|---|
| off | (default) | nothing |
| structural | SMARTKEY_DEBUG=1 or ./smartkey-debug enable |
verdicts, state, lengths, script classes (cyr/lat/…) — no typed text: printable keys appear only as key_class=char + key_lang; raw keyname/keyval/keycode are kept for special keys (Tab/BackSpace/…) only |
| full | SMARTKEY_DEBUG=full or ./smartkey-debug enable full |
+ verbatim typed/ghost/committed/predictions (plaintext banner on start) |
Script classes are always logged: committed_lang=lat while typed_lang=cyr
is exactly the Space-inject signature, visible even in structural mode.
- Trace JSONL lives under
~/.local/state/smartkey/debug/(override:SMARTKEY_DEBUG_DIR; an override inside the repo is refused). Full mode also enablessmartkey.log,predictions.log, andreplay.jsonlunder$XDG_DATA_HOME/smartkey/(normally~/.local/share/smartkey/). Both directories are 0700 and files 0600. Never network, never engine stdout. - Trace JSONL is bounded: flush off the hot path, 48h age purge + 50MB size
cap at start. The three legacy full-mode sinks are not rotated; keep full
mode brief and use
wipewhen the capture is complete. ./smartkey-debug wipedeletes every trace and all three legacy content sinks in one command. Recycle SmartKey afterward if it was still running.
./smartkey-debug enable full- Switch to a fallback keyboard and recycle only SmartKey (do not globally
restart IBus). With an explicit environment instead:
SMARTKEY_DEBUG=full <engine start>. - Type the repro phrase in the failing app (e.g. Bulgarian typing where a prediction got injected), then switch focus once (flushes the buffer).
./smartkey-debug dump→ prints the path of a merged 0600 JSONL.- Read the trace: find the
seqof the bad keystroke; checkcore.verdict(was the key consumed or forwarded?), theactionlist (what was dispatched through_execute_actions), andaccept(committed_textvstyped_prefix,committed_langvstyped_lang). ./smartkey-debug wipewhen done;./smartkey-debug disableto turn off.
./smartkey-debug status shows level, dir and file sizes; tail [N] prints
the last N events of the newest trace.