KnowType, Chinese name 知键, is a macOS Chinese/English input method with AI-assisted continuation. It is written in Swift and built around a strict product rule: correction may improve the prefix you are typing, but continuation must not rewrite the locked prefix you have already accepted.
| Area | Current state |
|---|---|
| Language | Swift 6.2 |
| Platform | macOS 13+ |
| Core package | Swift Package Manager |
| Input method host | AppKit + InputMethodKit |
| Settings UI | SwiftUI |
| Integration branch | dev |
KnowType separates "make what I typed correct" from "continue after what I accepted".
raw input -> correction -> locked prefix -> continuation -> commit
Example:
raw input: wo jue de zhege fagnan
locked prefix: 我觉得这个方案
continuation: 还有进一步优化空间
Tab commit: 我觉得这个方案还有进一步优化空间
The AI continuation is only 还有进一步优化空间. It is not allowed to turn
the locked prefix into another sentence.
- Chinese input first: the production IMK hot path uses bundled
librimefor synchronous pinyin conversion, Space commit, number selection, and paging. - Local candidate learning: recent prefix choices can boost local ranking across input-method restarts without being sent to providers.
- Prefix-locked AI recommendation: the first candidate stays Rime conversion, the second slot is reserved for AI, and locked prefixes are never rewritten.
- macOS input method flow: marked text, candidate selection, paging, punctuation handling, and a compact native-style AppKit candidate panel that stays above Spotlight/search overlays.
- Provider compatibility: OpenAI-compatible chat, OpenAI Responses, Anthropic Messages, Gemini native, Ollama native, and custom HTTP profiles normalize into one provider interface.
- Privacy guardrails: correction protects URLs, emails, paths, commands, code-like text, and protected app contexts from rewrite; real-time AI is hard disabled only for suspected secrets and filters secret-like candidate hints.
- Local lexicons: bundled seed lexicon plus user-owned JSON/TSV resources and a managed Rime Pinyin Simplified install path.
KnowType is currently a local MVP for development and manual testing. It includes a Swift package, unit tests, a local InputMethodKit app bundle, SwiftUI settings hosts, provider profile storage, Keychain-backed API keys, and local dictionary tooling.
It is not yet a notarized installer, auto-updater, or App Store package.
GitHub Releases provide a Developer Preview DMG named
KnowType-vX.Y.Z-macos-dev-preview.dmg. It contains KnowType.app, a
command-file installer, a release manifest, and a SHA256 file. The DMG is not
Developer ID signed or notarized; macOS may require Control-click > Open or
Privacy & Security > Open Anyway before installation. The local MVP zip remains
available as a developer/debug asset.
Requirements:
- macOS 13 or newer
- Swift 6.2 toolchain
Build and test:
swift build
swift testTry the package-level flow without installing the input method:
swift run knowtype-demo --locale zh-CN --action tab wo jue de zhege fagnan
swift run knowtype-demo --locale mixed --action tab zhege api latnecy youdian gao
swift run knowtype-demo --locale en-US --action tab I thikn this approchBuild and install the local development bundle:
./scripts/build-inputmethod-bundle.sh --configuration release
./scripts/install-inputmethod.sh
./scripts/diagnose-inputmethod.shThe local installer refreshes the traditional InputMethodKit app registration,
purges stale .Mode development state, registers and enables the KnowType
parent input method plus the visible .Hans input mode from the installed app
context, and repairs history without moving KnowType ahead of the retained
current source. It does not rewrite selected preferences during install.
It does not launch the installed input-method host, does not auto-select
KnowType, and does not initialize Rime user data during install.
Use ./scripts/install-inputmethod.sh --configuration release for local typing
tests and do not register dist/KnowType.app directly. The installer copies the
source bundle to ~/Library/Input Methods/KnowType.app, unregisters stale
LaunchServices records for source, temporary, and backup paths, then registers
only that canonical installed target.
If macOS prelaunches the host while refreshing TIS or LaunchServices state, the
controller cold start still keeps Rime sessions, provider profiles, AI learning
and profile files, ENV.md, and CORRECTION.md lazy until real input, an AI
request, or explicit maintenance.
Before replacement, the installer switches away from KnowType, disables existing
KnowType input-source rows, restarts text-input menu agents, and asks a running
KnowTypeInputMethodApp to exit with TERM. If the host still does not exit,
quit it manually or rerun the installer with --force-stop-host for local
development.
KnowType uses the mature macOS IMK shape: com.knowtype.inputmethod.KnowType
is the non-selectable parent input method, and
com.knowtype.inputmethod.KnowType.Hans is the only user-selectable visible
mode. Old .Mode records and parent-only selected/history rows are treated as
legacy cache entries and cleaned by the repair scripts. System Settings and the
menu bar should show exactly one user-selectable KnowType item.
scripts/install-inputmethod.sh defaults to a release build so local typing
tests exercise the optimized hot path. Rime runtime files are packaged inside
KnowType.app; if they are missing or fail to load, KnowType keeps raw input
usable and reports degraded conversion state instead of falling back to the
retired clean-room converter.
Overwrite installs create an app-level rollback backup under
~/Library/Application Support/KnowType/Backups/ and record the active install
in ~/Library/Application Support/KnowType/install-state.json. The backup
contains install artifacts only: KnowType.app and optional KnowType.prefPane.
It does not copy, restore, or mutate Rime userdb, provider profiles, Keychain
secrets, AI context documents, ~/.knowtype, or local lexicons. First real
typing after manually selecting KnowType may initialize Rime as normal product
use; that is intentionally outside the install step.
New rollback manifests record checksums, bundle IDs, versions/builds, and code
signing requirements/identities for both artifacts. Rollback verifies all
metadata plus codesign --verify --deep --strict before replacement. Legacy
schema-v1 backups are rejected unless the explicitly dangerous
--allow-unverified-backup flag is supplied; that flag never bypasses a current
manifest failure. Installer paths also refuse to remove or replace a same-name
PreferencePane unless it is the canonical non-symlink
com.knowtype.preferencepane bundle.
KnowType-specific settings follow the native IMK input-method pattern used by
McBopomofo and OpenVanilla: choose KnowType from the macOS input menu and select
KnowType 设置... (KnowType Settings... in the explicit English resource
path). It opens a macOS-native sidebar and grouped settings window that defaults
to a user-facing Overview for input-method, AI continuation, lexicon, and
privacy status. Provider details, Base URL, Custom HTTP, logs, and local paths
live under AI advanced configuration or the Advanced troubleshooting page.
Simplified Chinese is the default copy; English resources remain available for
explicit English locale queries and missing-key fallback. The local install does not
install a standalone settings app. The default install removes any stale local compatibility
KnowType.prefPane so it cannot drift out of sync. A matching compatibility pane
is only built and installed when ./scripts/install-inputmethod.sh --with-prefpane
is used. If System Settings still shows a KnowType sidebar entry after a
default install, it is stale macOS PreferencePane cache state; run the install
script again or ./scripts/uninstall-inputmethod.sh to refresh the cache, then
reopen System Settings.
After the first install or a mode-id migration, macOS may still require the
System Settings input-source approval path. Open System Settings > Keyboard >
Input Sources, remove stale KnowType rows, add 知键 / KnowType again, and
click Allow if macOS asks. If the menu still shows stale entries, log out and
back in to clear the Text Input Source cache. This follows the same boundary
used by mature IMK input methods: installation uses TIS registration and
enablement, while System Settings writes the protected third-party input-source
approval rows.
After install, activate the target app, select KnowType from the macOS input menu, or run the selection helper while that target app is active:
./scripts/select-inputmethod.sh --require-selectedManual acceptance requires the real macOS input menu to show the K icon and a
知键 / KnowType entry. Helper selection alone is not sufficient.
Remove the local bundle:
./scripts/uninstall-inputmethod.shList or restore local rollback points:
./scripts/rollback-inputmethod.sh --list
./scripts/rollback-inputmethod.sh --latestRollback preserves profile values and Keychain secrets. If the selected backup predates provider storage generation 2, the current app converts the latest profile metadata to the compatible numeric schema before the old app is published; an unsafe conversion fails closed.
For a trusted legacy backup only, inspect it first and make the override explicit:
./scripts/rollback-inputmethod.sh --to BACKUP_ID --dry-run --allow-unverified-backupLocal IME behavior must still be verified by typing in real host apps. See Local Input Method Testing and MVP Acceptance for the macOS policy, selection, and manual acceptance flow.
For a GitHub Release DMG, verify the downloaded image with the published
.sha256 file first:
cd ~/Downloads
shasum -a 256 -c KnowType-v0.2.8-macos-dev-preview.dmg.sha256Open the DMG and run Install KnowType.command. If macOS blocks it, use
Control-click > Open, or open System Settings > Privacy & Security and choose
Open Anyway. The command records source=dmg-dev-preview, release commit/tag,
and manifest digest in diagnostics, but it does not launch the input method host
or perform a typing probe. Pass --with-prefpane only when the optional
compatibility System Settings pane is needed. Do not use a stale System Settings
sidebar entry unless the matching pane is installed.
The older local MVP zip can still be installed for developer debugging:
./scripts/install-inputmethod.sh --from-release-zip ~/Downloads/KnowType-v0.2.8-macos-local-mvp.zipProvider profiles are stored as JSON metadata; API keys are stored separately. The profile file uses a revisioned transactional format so concurrent settings windows cannot silently overwrite each other. Changed keys use immutable Keychain references. Base URLs may contain runtime query parameters, but not userinfo or fragments; diagnostics omit userinfo, query, and fragment. The running input-method host observes committed profile revisions. The next eligible recommendation or context digest uses the new provider without a host restart, cancels older in-flight provider work, and never polls provider files from the ordinary key path.
~/Library/Application Support/KnowType/providers.v2.json
During upgrade, the installer preserves the original providers.json as
providers.legacy.json, rekeys Keychain references, and replaces the legacy
path with a compatibility tombstone. Do not edit either compatibility file. If
diagnostics report that an older Settings process wrote the legacy path again,
close that process and preserve both payloads for conflict resolution.
Local candidate-learning history:
~/Library/Application Support/KnowType/user-selection-history.json
Local JSON/TSV lexicons:
~/Library/Application Support/KnowType/Lexicons
KNOWTYPE_LEXICON_DIR and colon-separated KNOWTYPE_LEXICON_DIRS can add
development lexicon directories before the default directory.
Install the recommended managed lexicon pack:
scripts/install-lexicon-pack.sh rime-pinyin-simpThe installer downloads a pinned Apache-2.0 Rime dictionary, verifies SHA256, converts it into KnowType TSV, and writes local metadata beside the TSV. Third-party bulk dictionary data is not committed to this repository.
When providers.v2.json is missing on a genuinely new install or is empty, KnowType seeds a local
OpenAI-compatible profile at http://127.0.0.1:8317/v1 with no embedded API
key. Remote OpenAI-compatible profiles require an explicit model ID; local
OpenAI-compatible profiles may leave the model blank for /v1/models
discovery.
New Anthropic and Gemini profiles use claude-haiku-4-5-20251001 and
gemini-3.5-flash. Saved profiles using the exact retired template IDs are
updated once only on the matching official API endpoint; custom proxy endpoints
keep their configured model. Custom HTTP body placeholders are expanded in one
pass, so placeholder-like text inside user input is preserved. Unknown or
unclosed {{...}} placeholders fail the connection request as an invalid
template.
AI context files live under ~/.knowtype/. ENV.md stores local context
memory for the AI recommendation slot, CORRECTION.md stores user-editable AI
correction instructions, and LEXICAL_PROFILE.md mirrors the local top-K
lexical profile built from Rime userdb frequency plus recent KnowType commits
and selections plus bounded summaries of AI recommendations the user explicitly
accepted. Verified edits made immediately after accepting AI recommendations
are summarized separately as local AI feedback; ordinary Backspace is ignored
unless the cursor range proves the edit is inside the just-accepted AI span.
The full accepted-AI and feedback history is stored locally under Application
Support and is not injected directly into provider requests. The canonical
lexical profile JSON lives under
~/Library/Application Support/KnowType/AI/. Traditional input does not depend
on these files. Use ./scripts/accepted-learning.sh status, rebuild, or
clear --yes to inspect, rebuild, or delete accepted-AI learning and feedback
data. Clear removes accepted-learning/feedback history, summary, and mirror
files and scrubs accepted-AI context from the lexical profile without deleting
Rime, provider, Keychain, ENV, or CORRECTION data.
Committed Context Digest events are queued locally as JSONL under
~/.knowtype/events/. Text fields are limited to 2,048 Unicode scalars, and
pending data keeps at most 500 events or 1 MiB by dropping the oldest derived
events after overflow. Each provider digest sends at most the oldest 50 events
or 256 KiB. Successful claims move to events/processed/, which is retained
for at most 7 days, 100 files, and 10 MiB; cleanup runs only after a successful
digest, never during startup or install. Context diagnostics contain counts,
bytes, and cooldown durations only, not typed text, provider output, or keys.
Real-time AI recommendations use a task-specific suffix-generation prompt, have
a 10-second runtime timeout, prefer provider-level structured JSON schema output
when available, and emit privacy-preserving substate diagnostics through macOS
unified logging. While Rime is composing, the current page of Rime candidates is
not sent to the realtime AI request and unselected candidates are not treated as
the locked prefix. If no locked prefix exists yet, the AI response is a full
commit-ready recommendation based on raw input, context documents, and the
persistent lexical profile rather than a suffix attached to the first Rime
candidate. The logs distinguish schema fallback, structured decode failures,
prefix-lock sanitizer rejections, and too-short prefixes without recording raw
text. To inspect them, run
log stream --predicate 'subsystem == "com.knowtype.inputmethod.KnowType" && category == "ai"' --style compact.
Debug output is off by default. When enabled, diagnostics use privacy-safe key/value fields only: ids, lengths, revisions, generations, reasons, elapsed times, bundle ids, write modes, anchor sources, and handled/pass-through state. They do not log raw input, preedit, candidate text, committed text, prompts, provider output, context bodies, or API keys.
Use KNOWTYPE_PERF_DEBUG=1 for a broad performance trace, or combine narrower
switches such as KNOWTYPE_AI_DEBUG=1, KNOWTYPE_PANEL_DEBUG=1,
KNOWTYPE_TURN_DEBUG=1, KNOWTYPE_CLIENT_WRITE_DEBUG=1, and
KNOWTYPE_ANCHOR_DEBUG=1.
launchctl setenv KNOWTYPE_PERF_DEBUG 1
log stream --predicate 'subsystem == "com.knowtype.inputmethod.KnowType"' --style compactFor AI cancellation and token-cost checks, summarize a captured log with
python3 scripts/summarize-ai-debug-log.py /tmp/knowtype-ai-debug.log.
Clear debug variables after testing:
launchctl unsetenv KNOWTYPE_PERF_DEBUG
launchctl unsetenv KNOWTYPE_AI_DEBUG
launchctl unsetenv KNOWTYPE_PANEL_DEBUG
launchctl unsetenv KNOWTYPE_TURN_DEBUG
launchctl unsetenv KNOWTYPE_CLIENT_WRITE_DEBUG
launchctl unsetenv KNOWTYPE_ANCHOR_DEBUGSee Debug Diagnostics for focused recipes for first-key stalls, AI latency, candidate-panel residue, host writes, and anchor placement.
| Shortcut | Behavior |
|---|---|
Space |
Commit the highlighted/current Rime candidate during composition; with no active composition, produce a normal space, U+3000 in full-width mode, or pass it through in compatibility hosts. |
1...9 |
Select Rime current-page candidates during native composition, even if the custom panel is hidden; with no active composition, produce ordinary or full-width digits according to character width. |
Arrow keys, PageUp / PageDown, - / =, , / . |
Move within the current Rime page, page at candidate-list edges when another page is available, and otherwise let punctuation fall back to the normal commit path. Left/up from the first row lands on the previous page's last row. |
Return / Enter |
Commit the original raw composition. |
Tab |
Commit the AI recommendation when the second slot is ready; pending or unavailable AI keeps the composition active. |
0 |
Commit the raw composition when correction candidates are visible; with no active composition, produce 0 or pass it through in compatibility hosts. |
| Plain punctuation | Let Rime handle composing schema keys first, then commit composition plus punctuation, show symbol candidates, insert punctuation directly, or pass it through in compatibility hosts when no composition is active. |
/ and other ambiguous symbols |
In Chinese punctuation mode, show a symbol-candidate row set; Space/1 commits the first symbol, numbers commit the visible symbol, and Escape cancels. Arrow and paging commands are consumed while the row set is active, including at list boundaries, and return to normal host navigation after it closes. |
| Command/Control host shortcuts | Cancel an open symbol-candidate overlay before passing the shortcut to the focused host, so a later Space cannot commit a stale symbol. |
Option + . |
In Chinese text mode, manually toggle Chinese/English punctuation until the next text-mode switch. In ASCII mode it leaves punctuation English and only repeats the mode status. |
Option + / |
Toggle the process-wide Chinese/ASCII text mode. The switch also restores linked Chinese/English punctuation and is shared across apps. |
Shift + Space |
Toggle process-wide half-width/full-width characters without changing text or punctuation mode. Full width maps ASCII ! through ~ and normal space; controls, Tab, and newline are unchanged. |
Option + 1 |
Commit the ready AI recommendation explicitly. |
Option + 2...9 |
Commit legacy continuation rows when they are present. |
Text mode, punctuation language, and symbol width remain separate state
dimensions, but text and punctuation now follow a predictable global linkage:
Chinese input starts with Chinese punctuation, ASCII input always uses English
punctuation, and Option + / restores that link. A manual Option + .
override is available only while Chinese input is active and lasts until the
next text-mode switch. Symbol width remains independent. All apps share the
current state for the lifetime of the input-method host; a host restart begins
again in linked Chinese mode with the saved global width. The active native Rime
session receives the same ascii_mode, ascii_punct, and full_shape values
after creation and on each process-mode generation change. A period immediately
after an ASCII digit stays . for decimals and numbered lists, even in Chinese
punctuation or full-width mode; comma and unknown/selected caret contexts keep
the normal punctuation policy. Chinese quotes use caret context: whitespace or
opening punctuation opens, while text, digits, or closing punctuation closes;
unknown context falls back to session alternation. External delete, focus or
selection movement, and mode changes reset that fallback. Mode changes briefly
show a status row such as 中 · 中文标点 · 半角.
Host compatibility is conservative. Standard AppKit-style text fields, browsers,
editors, IDEs, Electron shells, and unknown clients use inline composition with
attributed marked text by default, so raw preedit appears in the focused text
field. Host identity no longer changes the global text or punctuation mode.
KnowType registers only key-down events with InputMethodKit, preserving IMK's
default behavior of committing active composition when the user clicks outside
its marked range. Shortcut modifiers continue to come from key-down flags.
InputMethodKit responder navigation commands are handled separately only while
symbol candidates are active, preventing the same arrow from moving the host
caret or selection.
Terminal, iTerm, MacVim, and Emacs-style hosts therefore also begin in Chinese
mode, but use a full-width-space attributed
marked-text placeholder to keep the host composition and candidate anchor alive;
the real raw/preedit string is shown in KnowType's candidate panel above the
candidates, then committed with insertText. When the global mode is switched
to ASCII, idle half-width printable input is passed back to the focused host;
full-width printable input is transformed and inserted by KnowType. A UserDefaults override can force
any bundle back to commitOnlyComposition when a host proves incompatible with
inline marked text.
The candidate panel shows Rime prefix candidates, a fixed AI recommendation state row, terminal/override commit-only preedit when the host receives a placeholder carrier, and raw input only when no suggestion is available. The preedit row has no shortcut, selection, or commit action, and inline hosts do not render it because the focused text field already shows preedit. The panel is a compact AppKit panel using macOS material, system highlight colors, mouse hover/click selection, one-page-per-trackpad-gesture scroll paging, and VoiceOver press for enabled candidate rows. Disabled status rows remain readable but cannot commit. When a provider is configured, Rime prefix candidates appear immediately and provider-backed AI recommendations update asynchronously. Provider failures do not show fixed local fallback text as if it were AI output.
The first candidate slot is reserved for Rime conversion. The second slot is reserved for AI recommendation state, so async provider results update that slot without reordering the Rime candidate list. Ready AI uses Tab or explicit Option-number rather than ordinary digit shortcuts. Pending, unavailable, or ineligible AI states are shown as muted status rows without numeric shortcuts or click commit behavior.
Level 0 correction protects text that should usually commit unchanged. It prevents correction from rewriting protected content such as URLs, paths, commands, code-like text, and protected app contexts.
Correction-protected examples include:
- URLs and
www.addresses - email-like input
- absolute, home-relative, and relative file paths
- command-like input such as
swift testorgit status - code-like snippets containing braces, semicolons, or
=> - Terminal, iTerm, and Xcode sessions by bundle identifier
Real-time AI recommendation uses a narrower cloud privacy gate: AI 已禁用
appears only when raw input or confirmed prefix looks like a credential, such as
API keys, bearer tokens, JWTs, private keys, or password/token assignments.
Secret-like Rime candidate hints are filtered without disabling the whole
request.
Accepted AI learning uses the same secret-like hard block: credential-shaped
accepted text is not recorded, while ordinary technical text can be summarized
locally for future recommendations. AI feedback learning follows the same
secret-only block and records only verified post-accept edits.
Technical tokens such as API, JSON, FastAPI, iOS, macOS,
InputMethodKit, snake_case, and camelCase are preserved or canonicalized.
Repository layout:
Sources/KnowTypeCore/ Product models, protection, correction, continuation
Sources/KnowTypeProviders/ Provider profiles, runtime loading, adapters
Sources/KnowTypeAI/ AI recommendation, context memory, correction instructions
Sources/KnowTypeInputMethod/ IMK controller, session actions, candidate panel
Sources/KnowTypeInputMethodApp/ Local macOS input-method app entry point
Sources/KnowTypeSettingsUI/ Shared SwiftUI settings UI
Sources/KnowTypeSettingsApp/ Developer preview settings app host
Sources/KnowTypePreferencePane/ Compatibility PreferencePane host
Tests/ Unit tests
doc/ Current engineering documentation
plan/ Active and recently delivered implementation plans
Resources/ macOS bundle resources
Branch workflow:
main: stable branchdev: integration branch- topic branches:
feature/<desc>,fix/<desc>,docs/<desc>,refactor/<desc>,test/<desc>,release/<version>
Use Conventional Commits and open topic PRs into dev first. For code changes,
run swift test; for input-method hot-path changes also run
./scripts/perf-input-hotpath.sh. For documentation-only changes, run at least
git diff --check and keep indexes in doc/ and plan/ synchronized.
Current non-goals:
- signed installer, notarization, auto-update, or App Store distribution
- complete real-world pinyin dictionary coverage without licensed local lexicons
- universal compatibility claims for every macOS host app
- using local fallback continuation as fake configured-provider output
- rewriting locked prefixes
License not declared yet.