RepoPilotOpen in app →

rime/squirrel

【鼠鬚管】Rime for macOS

Mixed

Mixed signals — read the receipts

worst of 4 axes
Use as dependencyConcerns

copyleft license (GPL-3.0) — review compatibility; no tests detected

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 2d ago
  • 11 active contributors
  • Distributed ownership (top contributor 39% of recent commits)
Show 4 more →
  • GPL-3.0 licensed
  • CI configured
  • GPL-3.0 is copyleft — check downstream compatibility
  • No test directory detected
What would change the summary?
  • Use as dependency ConcernsMixed if: relicense under MIT/Apache-2.0 (rare for established libs)

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Forkable" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Forkable
[![RepoPilot: Forkable](https://repopilot.app/api/badge/rime/squirrel?axis=fork)](https://repopilot.app/r/rime/squirrel)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/rime/squirrel on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: rime/squirrel

Generated by RepoPilot · 2026-05-10 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/rime/squirrel shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

WAIT — Mixed signals — read the receipts

  • Last commit 2d ago
  • 11 active contributors
  • Distributed ownership (top contributor 39% of recent commits)
  • GPL-3.0 licensed
  • CI configured
  • ⚠ GPL-3.0 is copyleft — check downstream compatibility
  • ⚠ No test directory detected

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live rime/squirrel repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/rime/squirrel.

What it runs against: a local clone of rime/squirrel — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in rime/squirrel | Confirms the artifact applies here, not a fork | | 2 | License is still GPL-3.0 | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 32 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>rime/squirrel</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of rime/squirrel. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/rime/squirrel.git
#   cd squirrel
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of rime/squirrel and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "rime/squirrel(\\.git)?\\b" \\
  && ok "origin remote is rime/squirrel" \\
  || miss "origin remote is not rime/squirrel (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(GPL-3\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"GPL-3\\.0\"" package.json 2>/dev/null) \\
  && ok "license is GPL-3.0" \\
  || miss "license drift — was GPL-3.0 at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "sources/SquirrelApplicationDelegate.swift" \\
  && ok "sources/SquirrelApplicationDelegate.swift" \\
  || miss "missing critical file: sources/SquirrelApplicationDelegate.swift"
test -f "sources/SquirrelInputController.swift" \\
  && ok "sources/SquirrelInputController.swift" \\
  || miss "missing critical file: sources/SquirrelInputController.swift"
test -f "sources/SquirrelPanel.swift" \\
  && ok "sources/SquirrelPanel.swift" \\
  || miss "missing critical file: sources/SquirrelPanel.swift"
test -f "sources/BridgingFunctions.swift" \\
  && ok "sources/BridgingFunctions.swift" \\
  || miss "missing critical file: sources/BridgingFunctions.swift"
test -f "sources/SquirrelConfig.swift" \\
  && ok "sources/SquirrelConfig.swift" \\
  || miss "missing critical file: sources/SquirrelConfig.swift"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 32 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~2d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/rime/squirrel"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Squirrel (鼠鬚管) is the macOS frontend for the Rime Input Method Engine, providing a native macOS input method that enables typing in Chinese and other scripts using customizable input schemas. It wraps the cross-platform librime C++ engine with a Swift-based macOS application, handling keyboard input, candidate selection, and integration with the macOS input method system. Single Xcode project (Squirrel.xcodeproj) with Swift sources in sources/ directory (BridgingFunctions.swift, InputSource.swift, MacOSKeyCodes.swift) providing the macOS input method frontend. Build artifacts and packaging handled by shell scripts in package/ (make_package, sign_app, bump_version). Configuration lives in data/squirrel.yaml and resources/ (Info.plist, entitlements for notarization).

👥Who it's for

Chinese language users on macOS 13.0+ who need a free, open-source, customizable input method; also macOS developers contributing to the Rime ecosystem who want to extend input method functionality or fix platform-specific IME behaviors.

🌱Maturity & risk

Actively maintained and production-ready. The project has regular CI/CD pipelines (.github/workflows/commit-ci.yml, release-ci.yml), tagged releases on GitHub, and is part of the established Rime project ecosystem. However, the small primary codebase (131KB Swift, 165B Objective-C) suggests it is relatively lean and focused, with the heavy lifting delegated to librime.

Low maintenance bus factor: the contributors list shows multiple developers but commit history would reveal active maintainers. Dependency on librime (external C++ library) means breaking changes in librime could require coordination. macOS-specific code paths (input method integration, keyboard handling) are difficult to test comprehensively without actual macOS hardware. The Objective-C bridging layer (164 bytes visible) suggests tight OS-level coupling that could break with macOS updates.

Active areas of work

Active development with GitHub Actions CI (commit-ci.yml, pull-request-ci.yml, release-ci.yml automating builds and releases). The CHANGELOG.md and release tagging indicate regular version bumps. SwiftLint configuration (.swiftlint.yml) and Periphery dead-code detection (.periphery.yml) suggest ongoing code quality improvements.

🚀Get running

Clone the repo: git clone --recursive https://github.com/rime/squirrel.git && cd squirrel. Install dependencies: make deps (inferred from Makefile). Build: make build or open Squirrel.xcodeproj in Xcode. Install locally: make install (runs package/action-install.sh). For development: xcode-select --install to ensure Xcode CLI tools are present.

Daily commands: Open Squirrel.xcodeproj in Xcode 15+, select the 'Squirrel' scheme, and press Cmd+R to build and run. Alternatively: make build && make install installs to /Library/Input Methods/. To test: switch input method in System Preferences → Keyboard → Input Sources → Chinese (Squirrel).

🗺️Map of the codebase

  • sources/SquirrelApplicationDelegate.swift — Main entry point for the Squirrel IME; handles application lifecycle, input method registration, and menu setup that every contributor must understand.
  • sources/SquirrelInputController.swift — Core input processing layer that bridges Rime engine with macOS text input; all keyboard and composition logic flows through here.
  • sources/SquirrelPanel.swift — Candidate/suggestion popup UI rendering; critical for understanding how input candidates are displayed to users.
  • sources/BridgingFunctions.swift — Swift-to-C bridge layer interfacing with the Rime input engine; essential for understanding engine integration.
  • sources/SquirrelConfig.swift — Configuration loading and theme management; controls how user settings and appearance preferences are applied.
  • Squirrel.xcodeproj/project.pbxproj — Xcode project configuration with build settings, target dependencies, and framework linking for the macOS application.
  • data/squirrel.yaml — Default input method configuration file defining UI appearance, key bindings, and behavior settings.

🛠️How to make changes

Add a new theme configuration option

  1. Define the new property in the YAML schema within data/squirrel.yaml under the appearance section (data/squirrel.yaml)
  2. Add a corresponding Swift property to parse and store the value in SquirrelConfig.swift (sources/SquirrelConfig.swift)
  3. Use the new property in SquirrelTheme.swift to apply styling during theme initialization (sources/SquirrelTheme.swift)
  4. Reference the theme property in SquirrelView.swift's drawing code to render the themed element (sources/SquirrelView.swift)

Handle a new keyboard shortcut

  1. Add the key binding definition to data/squirrel.yaml under the bindings section (data/squirrel.yaml)
  2. Map the macOS key code to the Rime key code in MacOSKeyCodes.swift if needed (sources/MacOSKeyCodes.swift)
  3. Handle the key event in SquirrelInputController.swift's handleKeyEvent method, invoking the appropriate Rime engine method via BridgingFunctions (sources/SquirrelInputController.swift)
  4. Update the candidate panel display in SquirrelPanel.swift if the shortcut changes the composition or candidate state (sources/SquirrelPanel.swift)

Add a new menu command or system setting

  1. Create the menu item in SquirrelApplicationDelegate.swift's setupMenuBar method (sources/SquirrelApplicationDelegate.swift)
  2. Implement the action handler in SquirrelApplicationDelegate.swift, calling BridgingFunctions to interact with the Rime engine if needed (sources/BridgingFunctions.swift)
  3. If the command affects UI or input state, update SquirrelInputController.swift to propagate state changes (sources/SquirrelInputController.swift)
  4. Add the localized menu string to resources/Localizable.xcstrings (resources/Localizable.xcstrings)

🔧Why these technologies

  • Swift — Modern, safe language for macOS development; the standard for Cocoa framework integration since Xcode 6+.
  • Objective-C Bridging (via .h bridging header) — Allows Swift code to call C functions and Objective-C APIs; necessary to interface with the Rime engine C library.
  • macOS Input Method API (Cocoa IMF) — Only way to hook into text input on macOS; required to capture keyboard events and inject text into applications.
  • YAML configuration (squirrel.yaml) — Human-readable format for end-user customization of themes, key bindings, and input schemas without recompiling.
  • Rime Input Engine (C library) — Provides linguistic processing, composition, candidate generation, and schema management; battle-tested engine powering multiple IMEs.

⚖️Trade-offs already made

  • Swift + C bridge instead of pure Swift wrapper

    • Why: Rime engine is a mature C library with complex state management; wrapping it would add maintenance burden.
    • Consequence: Developers must understand C function signatures and manual memory management in BridgingFunctions.swift.
  • Custom candidate popup (SquirrelPanel/View) instead of system popover

    • Why: Allows pixel-perfect control over positioning, styling, and animation; system components cannot achieve the required flexibility.
    • Consequence: Higher maintenance burden for rendering and event handling; must manually manage window lifecycle and input source coordination.
  • YAML over programmatic configuration

    • Why: End users customize themes and bindings without rebuilding the app; community-driven schema sharing requires text-based config.
    • Consequence: Parser complexity in SquirrelConfig.swift; changes to schema require app restart.
  • Monolithic SquirrelInputController instead of smaller handlers

    • Why: Rime's session API is inherently stateful; centralizing composition state in one controller simplifies synchronization.
    • Consequence: SquirrelInputController is the largest file and potential bottleneck; any key event touches it.

🚫Non-goals (don't propose these)

  • Cross-platform support (macOS only; Windows has 小狼毫, Linux has ibus-rime/fcitx-rime)
  • Real-time collaboration or cloud sync of user settings
  • Support for macOS versions below 13.0
  • Built-in schema editing UI (users edit YAML files directly)
  • Audio feedback or haptic support

🪤Traps & gotchas

  1. librime must be compiled and linked; the Makefile likely depends on a pre-built librime or submodule (check .gitmodules). 2) macOS code signing and notarization are mandatory for distribution; requires Apple Developer account and valid certificates in Xcode (see resources/Squirrel.entitlements). 3) Input method bundles are loaded into the system; changes require logout/login or restart to take effect. 4) Testing input method behavior is difficult without physical macOS hardware; CI likely runs on hosted macOS runners. 5) Swift-Objective-C bridging requires header files for librime; missing or mismatched C++ headers cause linker errors.

🏗️Architecture

💡Concepts to learn

  • Input Method Kit (IMKit) — Squirrel integrates via macOS IMKit framework to hook into the system input pipeline; understanding IMKit architecture is essential for debugging input events and candidate selection
  • Librime C++ FFI / Language Interop — Squirrel bridges Swift to C++ via Objective-C; understanding how BridgingFunctions.swift marshals data between languages prevents crashes and memory leaks in the engine integration
  • macOS Code Signing & Notarization — Squirrel must be signed and notarized for distribution; failure to understand signing requirements will block releases and user installation
  • Input Schema / Composition Engine — Rime's core abstraction; defines how keystroke sequences map to candidates (e.g., Pinyin to Chinese characters). Squirrel's YAML config (squirrel.yaml) configures schema behavior and appearance
  • Keyboard Event Handling & Key Code Translation — MacOSKeyCodes.swift translates system key codes to input method events; incorrect mappings break arrow keys, special modifiers, and dead key composition
  • Package Signing & Distribution Automation — Release process uses codesign, notarization, and GitHub Actions; understanding the package/ scripts and CI workflows is needed to ship reliable updates
  • YAML Configuration Schema — squirrel.yaml and librime's YAML-based config system define input method behavior; modifying schemas is the primary user-facing customization path that new contributors often encounter
  • rime/librime — The C++ core engine that Squirrel wraps; essential dependency providing the actual input method logic and schema system
  • rime/plum — Schema package manager for Rime; users of Squirrel use plum to install additional input methods beyond the bundled ones
  • rime/home — Central discussion and issue-tracking repo for the Rime project; Squirrel issues and feature requests are discussed here
  • rime/ibus-rime — Linux frontend for Rime using IBus; parallel project showing how Rime is adapted to non-macOS input method systems
  • rime/weasel — Windows frontend for Rime (小狼毫); sister project with analogous Swift/C++ architecture adapted for Windows Input Method API

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add unit tests for SquirrelConfig.swift configuration parsing

The SquirrelConfig.swift file handles critical input method configuration but has no corresponding test file. Adding unit tests would ensure configuration parsing is robust, especially for edge cases in theme and input source settings. This is particularly important given the complexity of macOS input method configuration.

  • [ ] Create Tests/SquirrelConfigTests.swift with XCTest framework
  • [ ] Add test cases for parsing squirrel.yaml settings from data/squirrel.yaml
  • [ ] Test theme configuration loading and validation
  • [ ] Test input source initialization edge cases
  • [ ] Integrate tests into Squirrel.xcodeproj and CI workflows

Add GitHub Action workflow for building and testing on multiple macOS versions

The repo targets macOS 13.0+ but the current CI workflows (commit-ci.yml, pull-request-ci.yml, release-ci.yml) don't explicitly test against multiple macOS versions. Adding a matrix build strategy would catch version-specific regressions early and ensure compatibility across the supported range.

  • [ ] Extend .github/workflows/pull-request-ci.yml with macOS 13, 14, and 15 matrix builds
  • [ ] Configure xcodebuild to test SquirrelInputController.swift and SquirrelPanel.swift on each macOS version
  • [ ] Add step to verify code signing and entitlements (resources/Squirrel.entitlements) work across versions
  • [ ] Report test results with version-specific failure logs

Create InputSource.swift integration tests for keyboard layout switching

InputSource.swift manages keyboard input source switching which is core to the input method's functionality, but no tests verify this behavior. Integration tests would validate that input source switching works correctly without breaking the input pipeline in SquirrelInputController.swift.

  • [ ] Create Tests/InputSourceTests.swift with integration test cases
  • [ ] Test InputSource initialization and enumeration of available input sources
  • [ ] Test switching between input sources and verifying state changes propagate to SquirrelInputController
  • [ ] Add test for macOS keyboard layout detection using MacOSKeyCodes.swift
  • [ ] Verify tests run in CI/CD pipeline without requiring user interaction

🌿Good first issues

  • Add unit tests for MacOSKeyCodes.swift key translation logic (currently no test/ directory visible); create tests/MacOSKeyCodesTests.swift with XCTest covering modifier combinations and special keys
  • Document the librime FFI contract in BridgingFunctions.swift with inline comments and a BRIDGING.md guide explaining how to add new C++ methods from librime; currently unclear to new contributors
  • Create a developer setup guide in INSTALL.md or a new DEVELOPMENT.md explaining how to link against librime locally, configure code signing for development, and test input without installation

Top contributors

Click to expand

📝Recent commits

Click to expand
  • d47b984 — feat(ui): 全屏時隨文字縮放動態調整行的長度 (lotem)
  • 6d0b748 — feat(ui): 全屏模式 (lotem)
  • a5af706 — fix(ui): 修復邊界重定位導致的背景錯位及超大字號排版截斷問題 (lotem)
  • 151a43c — 修复远程桌面软件按 modifier key 时产生幽灵 'a' 按键的问题 (#1116) (HunterTom94)
  • 4be026f — chore: upgrade librime to 1.16.1 (lotem)
  • 876adeb — chore(release): 1.1.2 :tada: (LEOYoon-Tsaw)
  • 714325e — feat(ui): update Icon that can adapt with system color scheme (LEOYoon-Tsaw)
  • e6612b2 — Merge pull request #1095 from Bambooin/master (lotem)
  • 2cc3d17 — ci: upgrade action with node 24 (Bambooin)
  • 550b355 — ci: use macos-latest image runner (Bambooin)

🔒Security observations

The Squirrel (rime/squirrel) macOS input method application has a generally solid security posture as a native macOS application. No critical vulnerabilities were identified in the static analysis. However, there are medium-severity concerns regarding code signing verification enforcement and entitlements configuration that should be reviewed. The application lacks visible dependency lock files which could impact build reproducibility. Recommendations focus on hardening the build pipeline, minimizing entitlements, and ensuring proper code signing practices are enforced throughout the CI/CD workflow.

  • Medium · Missing Code Signing Verification — package/sign_app. The package contains a 'sign_app' script in the packaging directory, but there is no evidence of mandatory code signing enforcement or signature verification in the build pipeline. This could allow unauthorized modifications to the application before distribution. Fix: Implement mandatory code signing verification in the CI/CD pipeline. Ensure all builds are signed with a valid developer certificate and verify signatures before release. Add notarization for macOS distribution.
  • Medium · Entitlements Configuration Review Required — resources/Squirrel.entitlements. The application uses entitlements (resources/Squirrel.entitlements) which grant special permissions. Without reviewing the specific entitlements granted, potential privilege escalation or sandbox escape vulnerabilities could exist. Fix: Review entitlements to ensure only necessary permissions are granted. Minimize the use of elevated privileges. Implement the principle of least privilege. Document why each entitlement is required.
  • Low · Missing Security Headers in Build Configuration — Squirrel.xcodeproj/project.pbxproj. The Xcode project configuration (Squirrel.xcodeproj/project.pbxproj) may not have security-related build settings explicitly documented, such as -fstack-protector-strong, FORTIFY_SOURCE, and PIE (Position Independent Executable). Fix: Ensure security compiler flags are enabled: -fstack-protector-strong, -D_FORTIFY_SOURCE=2, and enable PIE. Verify these settings in the build configuration.
  • Low · No Dependency Lock File Detected — Root directory / Package management. The codebase uses Swift and likely has dependencies managed through Swift Package Manager (SPM) or CocoaPods, but no lock file (Package.resolved or Podfile.lock) is visible in the provided file structure. This could lead to non-reproducible builds. Fix: Commit Package.resolved (for SPM) or Podfile.lock (for CocoaPods) to version control to ensure reproducible builds and detect unexpected dependency changes.
  • Low · Bridging Header Usage — sources/Squirrel-Bridging-Header.h. The Squirrel-Bridging-Header.h file exposes Objective-C interfaces to Swift. Improper bridging can introduce memory safety issues or unintended exposure of internal APIs. Fix: Review the bridging header to ensure only necessary Objective-C interfaces are exposed. Use Swift-native implementations where possible. Avoid exposing internal or security-sensitive APIs.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · rime/squirrel — RepoPilot