HeliBorg/HeliBoard
Customizable and privacy-conscious open-source keyboard
Mixed signals — read the receipts
weakest axiscopyleft license (GPL-3.0) — review compatibility; no tests detected
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 1w ago
- ✓13 active contributors
- ✓GPL-3.0 licensed
Show all 7 evidence items →Show less
- ✓CI configured
- ⚠Concentrated ownership — top contributor handles 75% of recent commits
- ⚠GPL-3.0 is copyleft — check downstream compatibility
- ⚠No test directory detected
What would change the summary?
- →Use as dependency Concerns → Mixed 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.
[](https://repopilot.app/r/heliborg/heliboard)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/heliborg/heliboard on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: HeliBorg/HeliBoard
Generated by RepoPilot · 2026-05-09 · 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:
- 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. - 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.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/HeliBorg/HeliBoard 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 1w ago
- 13 active contributors
- GPL-3.0 licensed
- CI configured
- ⚠ Concentrated ownership — top contributor handles 75% of recent commits
- ⚠ 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 HeliBorg/HeliBoard
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/HeliBorg/HeliBoard.
What it runs against: a local clone of HeliBorg/HeliBoard — 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 HeliBorg/HeliBoard | 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 main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 39 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of HeliBorg/HeliBoard. If you don't
# have one yet, run these first:
#
# git clone https://github.com/HeliBorg/HeliBoard.git
# cd HeliBoard
#
# 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 HeliBorg/HeliBoard and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "HeliBorg/HeliBoard(\\.git)?\\b" \\
&& ok "origin remote is HeliBorg/HeliBoard" \\
|| miss "origin remote is not HeliBorg/HeliBoard (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 main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "app/build.gradle.kts" \\
&& ok "app/build.gradle.kts" \\
|| miss "missing critical file: app/build.gradle.kts"
test -f "app/src/main/AndroidManifest.xml" \\
&& ok "app/src/main/AndroidManifest.xml" \\
|| miss "missing critical file: app/src/main/AndroidManifest.xml"
test -f "app/src/main/assets/layouts/main" \\
&& ok "app/src/main/assets/layouts/main" \\
|| miss "missing critical file: app/src/main/assets/layouts/main"
test -f "app/src/main/assets/dicts" \\
&& ok "app/src/main/assets/dicts" \\
|| miss "missing critical file: app/src/main/assets/dicts"
test -f ".github/workflows/build-debug-apk.yml" \\
&& ok ".github/workflows/build-debug-apk.yml" \\
|| miss "missing critical file: .github/workflows/build-debug-apk.yml"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 39 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~9d)"
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/HeliBorg/HeliBoard"
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).
⚡TL;DR
HeliBoard is a privacy-first, fully offline open-source Android keyboard (based on AOSP/OpenBoard) with 100% customization of themes, layouts, and input methods. It replaces the system keyboard without any internet permissions and supports features like emoji search via custom dictionaries, glide typing, multilingual input, clipboard history, and split/one-handed modes—all while collecting zero user data. Standard Android app monolith: app/src/main/ contains the primary keyboard implementation (Java/Kotlin source), app/src/debug/ and app/src/debugNoMinify/ provide debug variants. Native code (C++) lives in jniLibs for glide typing. Build via Gradle (app/build.gradle.kts); ProGuard rules in app/proguard-rules.pro; dontoptimize.pro for selective optimization. Resources (layouts, strings, gesture data) in app/src/*/res/.
👥Who it's for
Android users concerned about privacy who want granular control over keyboard appearance and behavior; power users who need custom layouts or multilingual typing; app developers contributing to the open-source keyboard ecosystem; F-Droid and IzzyOnDroid communities seeking de-Googled input methods.
🌱Maturity & risk
Actively developed with distributed releases on F-Droid, GitHub Releases, and IzzyOnDroid (indicates sustained maintenance). The polyglot codebase (1.5MB Java, 1.5MB Kotlin, 1.4MB C++, native JNI for glide typing) and structured GitHub workflows (build-debug-apk.yml, build-test-auto.yml) suggest production-ready maturity. CI/CD is in place; no explicit star count in data, but established distribution channels indicate real user base.
Single-maintainer risk (HeliBorg org) is typical for smaller open-source keyboards but requires monitoring for burnout. Glide typing depends on proprietary closed-source libraries (swypelibs from GApps) that must be manually extracted—a fragile external dependency. No observable breaking-change policy documented in CONTRIBUTING.md snippet; native C++ code (1.4MB) requires Android NDK expertise and raises build reproducibility concerns if dependencies drift.
Active areas of work
Build and test automation is configured (.github/workflows/build-debug-apk.yml, build-test-auto.yml) indicating ongoing CI integration. GitHub discussion templates for custom-colors.yml and custom-layout.yml suggest active feature requests around theming and layout customization. No specific commit log provided, but structured issue/PR templates and funding.yml indicate sustained community engagement.
🚀Get running
git clone https://github.com/HeliBorg/HeliBoard.git
cd HeliBoard
./gradlew assembleDebug # Requires Android SDK (API 33+ recommended) and NDK for C++ compilation
adb install app/build/outputs/apk/debug/app-debug.apk
Daily commands:
./gradlew installDebug # Build and install debug APK to connected device/emulator
./gradlew build # Full release build (requires signing config)
Emulator: Launch Android Virtual Device (AVL) with API 33+, then run installDebug. Physical device: Enable developer mode, USB debugging, connect via adb.
🗺️Map of the codebase
app/build.gradle.kts— Primary build configuration for the keyboard app; defines dependencies, build variants (debug/release), and SDK settings that all contributors must understandapp/src/main/AndroidManifest.xml— Android app manifest declaring permissions, services, and activities; essential to understand why HeliBoard is 100% offline (no INTERNET permission)app/src/main/assets/layouts/main— Layout definition files (JSON/TXT) for all supported keyboard layouts; core data structure contributors modify when adding language supportapp/src/main/assets/dicts— Dictionary files for spell checking and word suggestions across 15+ languages; critical data asset for the prediction engine.github/workflows/build-debug-apk.yml— CI/CD pipeline for automated APK builds; shows how pull requests are tested before mergeCONTRIBUTING.md— Contribution guidelines covering issue reporting, translations, and code submission procedures for the open-source community
🛠️How to make changes
Add a New Keyboard Layout
- Create a new layout file in JSON or TXT format following the structure of existing layouts (
app/src/main/assets/layouts/main/[language_code].json) - Register the layout name in the app's layout configuration (typically in build or preference definitions) (
app/src/main/res/values/arrays.xml (or equivalent configuration)) - Add a flag or emoji identifier for the language in the layout selector UI (
app/src/main/assets/layouts/main)
Add Word Dictionary for a Language
- Build or obtain a .dict dictionary file in the expected binary format (
app/src/main/assets/dicts/main_[language_code].dict) - Compute the SHA-256 hash of the dictionary and add it to the known hashes file (
app/src/main/assets/known_dict_hashes.txt) - Update the dictionary repository CSV if sourcing from external repos (
app/src/main/assets/dictionaries_in_dict_repo.csv)
Add Emoji to a Category
- Edit the relevant emoji category file to append new emoji entries (
app/src/main/assets/emoji/[CATEGORY].txt) - Verify emoji is compatible with minApi version by checking minApi.txt (
app/src/main/assets/emoji/minApi.txt) - Rebuild to include emoji in the emoji keyboard row (
app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row.json)
Create a New Build Variant
- Add a new flavor or buildType block in the Gradle configuration (
app/build.gradle.kts) - Create corresponding source directories with variant-specific resources (
app/src/[variantName]/res/values/strings.xml) - Add a CI/CD workflow file to test the new variant on every push (
.github/workflows/build-[variant]-apk.yml)
🔧Why these technologies
- Android IME (Input Method Editor) Framework — Integrates keyboard as a system input method service, required for device-level keyboard functionality
- Gradle Kotlin DSL (build.gradle.kts) — Type-safe build configuration with dependency management; enables multiple build flavors (debug/release/noMinify)
- JSON/TXT Layout Files — Declarative, language-agnostic layout definitions allow community to contribute new layouts without code changes
- Binary Dictionary Format (.dict) — Compact, efficient storage for large word lists; enables fast prefix-matching for suggestions without network calls
- GitHub Actions CI/CD — Automated APK builds and testing on every commit; validates changes work on target Android versions before merge
⚖️Trade-offs already made
-
100% offline with no INTERNET permission
- Why: Privacy-first design; users don't want keyboard data sent to servers
- Consequence: Cannot offer cloud-based predictions, AI-powered corrections, or sync across devices; must pre-ship all dictionaries
-
Precompiled binary dictionaries bundled in app
- Why: Fast runtime lookup (no parsing) and smaller APK footprint vs raw text files
- Consequence: Adding/updating dictionaries requires app rebuild and redownload; cannot hot-patch without new release
-
Multiple layout files (JSON + TXT) with functional key layers
- Why: Flexibility to support diverse writing systems (Latin, Arabic, Bengali, etc.) without code branching
- Consequence: Layout engine complexity; contributors must understand layout file format to add languages
-
Debug + Release + DebugNoMinify build variants
- Why: Enable development (unobfuscated code), testing (minified), and production (optimized) builds
- Consequence: Three separate APK paths; CI/CD must test all variants to catch build-specific issues
🚫Non-goals (don't propose these)
- Cloud synchronization of keyboard settings across devices
- Real-time internet connectivity for dynamic prediction updates
- Native code (NDK) integration for custom input processing
- Support for non-Android platforms (iOS, Windows, Linux desktop)
- Built-in commercial advertising or telemetry
- Complex AI/ML models running on-device (uses simple dictionary-based suggestions)
🪤Traps & gotchas
Glide typing requires external proprietary libs: swypelibs must be manually extracted from GApps or downloaded separately; no automated fetch—builds will fail silently if missing and glide-feature is enabled. NDK build complexity: C++ compilation requires Android NDK setup; version mismatches between ndk.version in build.gradle.kts and local NDK can cause linker errors. Debug vs. Release: debugNoMinify variant disables ProGuard (useful for debugging); release builds require signing config (keystore.properties or similar) not in repo—must provide yourself. Dictionary format: Custom dictionaries must follow AOSP binary dictionary format; plain text fails silently. Language fallback: 'use system languages' setting disables custom layouts—easy to overlook when testing.
🏗️Architecture
💡Concepts to learn
- InputMethodService (Android IME framework) — HeliBoard is an IME (input method editor) that must subclass InputMethodService to integrate with Android's keyboard input pipeline; understanding this class is essential to modifying core keyboard behavior
- AOSP Binary Dictionary Format — Custom dictionaries for suggestions and spell-check must follow AOSP's binary dictionary format; plain text files will not work, and the format is non-obvious
- Android Native Development Kit (NDK) & JNI — Glide typing functionality relies on C++ native libraries linked via JNI; understanding NDK build config (in build.gradle.kts) and JNI calling conventions is required to debug or extend glide features
- ProGuard Code Obfuscation & Minification — app/proguard-rules.pro controls which classes survive obfuscation in release builds; misconfiguration can break keyboard functionality or expose internal APIs
- Android Gradle Build Flavors & Build Variants — HeliBoard uses multiple flavors (debug, debugNoMinify, release) with different ProGuard rules and resource overlays; understanding Gradle flavors is necessary to manage build variants correctly
- Gesture Recognition & Glide Typing — Glide typing (continuous finger motion for word input) is a machine-learning gesture recognition task; HeliBoard delegates this to swypelibs (proprietary), but understanding gesture data structures (gesture_data.xml) helps extend input methods
- Keyboard Layout & Key Mapping (XML-based) — Custom layouts are defined in XML (app/src/main/res/layout/); understanding how HeliBoard parses these into a key grid and event dispatcher is essential to adding new layouts or fixing layout bugs
🔗Related repos
openboard-team/openboard— Direct predecessor and upstream—HeliBoard is a fork of OpenBoard with additional customization and privacy focuserkserkserks/openboard— Alternative OpenBoard fork with glide typing integration; source for extracting swypelibs JNI libraries that HeliBoard usesHelium314/aosp-dictionaries— Companion repo providing pre-built dictionaries (language, emoji, symbols) required for HeliBoard's suggestion and spell-check featuresAnySoftKeyboard/AnySoftKeyboard— Alternative customizable open-source Android keyboard with different feature set; useful for benchmarking privacy and extensibility approachesflorisboard/florisboard— Modern Kotlin-first alternative keyboard IME with haptic feedback and clipboard manager; shows contemporary Android keyboard architecture patterns
🪄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 instrumented tests for keyboard input handling and gesture recognition
The repo contains gesture_data.xml files in debug variants (app/src/debug/res/values/gesture_data.xml and app/src/debugNoMinify/res/values/gesture_data.xml) but no corresponding Android instrumented tests visible in the file structure. Adding tests for gesture recognition, key input processing, and custom layout handling would ensure core keyboard functionality remains stable across refactors and new features.
- [ ] Create app/src/androidTest/java/ directory structure if not present
- [ ] Add instrumented tests for gesture input handling using Espresso or similar framework
- [ ] Add tests for custom layout parsing and validation
- [ ] Add tests for multi-language dictionary loading from app/src/main/assets/dicts/
- [ ] Update build.gradle.kts with Android test dependencies
Add CI workflow to validate dictionary integrity and build consistency across multiple locales
The repo includes 13+ language dictionaries (main_bg.dict, main_en-US.dict, main_fr.dict, etc.) and a CSV manifest (dictionaries_in_dict_repo.csv), but there's no visible CI workflow to validate that: (1) all declared dictionaries exist, (2) dictionary format is correct, (3) the app builds successfully for each supported locale. This prevents silent failures where missing or corrupted dictionaries slip into releases.
- [ ] Create .github/workflows/validate-dictionaries.yml
- [ ] Add step to parse app/src/main/assets/dictionaries_in_dict_repo.csv and verify all listed dicts exist
- [ ] Add step to validate dictionary file format/integrity (if using binary format)
- [ ] Add step to build debug APK and verify no locale-specific build errors
- [ ] Add step to run lint checks on app/src/main/AndroidManifest.xml for locale declarations
Add unit tests for keyboard settings/preferences parsing and validation
The app uses Kotlin (build.gradle.kts) and has build customization variants (debug, debugNoMinify, main). Keyboard settings, custom colors (custom-colors.yml discussion template), and custom layouts (custom-layout.yml) are core features, but there's no visible test coverage for settings deserialization, validation, or edge cases. This is critical to prevent user settings corruption or crashes from invalid custom configurations.
- [ ] Create app/src/test/java/ unit tests directory if not present
- [ ] Add tests for settings preferences parsing (SharedPreferences or DataStore)
- [ ] Add tests for custom layout JSON/XML deserialization and validation
- [ ] Add tests for custom color configuration validation and fallback handling
- [ ] Add tests for migrating settings across app versions
- [ ] Update build.gradle.kts with unit testing dependencies (JUnit, Mockito)
🌿Good first issues
- Add unit tests for dictionary parsing: app/src/main/java likely contains dictionary loading logic with no visible test coverage in file list. Create tests/DictionaryParserTest.java to verify binary dictionary parsing handles edge cases (corrupted headers, empty entries, unicode).
- Document glide typing setup: CONTRIBUTING.md does not explain how to extract swypelibs from GApps or validate NDK linking. Add a new doc/GLIDE_TYPING_SETUP.md with step-by-step instructions and common error diagnostics.
- Expand theme customization docs: .github/DISCUSSION_TEMPLATE/custom-colors.yml exists but layouts.md (referenced in README) may be incomplete. Audit layouts.md for missing examples (e.g., custom function key rows, RTL layout support) and add clarifying diagrams.
⭐Top contributors
Click to expand
Top contributors
- @Helium314 — 75 commits
- @eranl — 9 commits
- @qomarhsn — 3 commits
- @stanissay — 2 commits
- @davidzx84 — 2 commits
📝Recent commits
Click to expand
Recent commits
65c3fe3— add Unicode 17.0 emoji support (#2472) (kabaww)0bd9bb6— move KeyboardActionListener swipe actions to enum (Helium314)bd3a8a1— use SystemClock.elapsedRealtime for timing (Helium314)8f6a6ee— comments (Helium314)82a709a— Add Touchpad Mode for multi-directional cursor control (port from LeanType) (#2438) (stanissay)e84d69a— update emoji readme (Helium314)c1f055a— add setting to customize punctuation suggestions (Helium314)61a2d26— upgrade dependencies and build.gradle files (Helium314)22d2fd5— more rememberSaveable in GestureDataScreen (Helium314)2c88e2e— use TextFieldState in TextInputDialog (Helium314)
🔒Security observations
HeliBoard demonstrates strong security posture as a privacy-focused keyboard application. No critical vulnerabilities were identified in the provided file structure. Key strengths include: (1) Privacy-by-design with no internet permissions, (2) Open-source codebase enabling community auditing, (3) Presence of hash verification for bundled dictionaries, and (4) ProGuard obfuscation rules. Minor recommendations focus on enhancing integrity verification mechanisms and ensuring proper build variant isolation. The codebase follows Android security best practices for input handling. Dependency analysis was limited due to incomplete build.gradle.kts content - a full review of actual dependencies is recommended.
- Low · ProGuard Configuration Exposure —
app/proguard-rules.pro, app/dontoptimize.pro. The repository contains app/proguard-rules.pro which may expose obfuscation rules. While this is standard practice, ensure sensitive class names or API endpoints are properly obfuscated to prevent reverse engineering. Fix: Review ProGuard rules to ensure all sensitive classes are obfuscated. Verify that dontoptimize.pro only excludes necessary classes and doesn't expose security-critical code. - Low · Dictionary File Integrity —
app/src/main/assets/dicts/, app/src/main/assets/known_dict_hashes.txt. The app includes pre-packaged dictionary files (main_*.dict) and a hash verification file (known_dict_hashes.txt). While hash verification is present, there's no indication of signature verification for integrity validation. Fix: Implement cryptographic signature verification in addition to hash checking to prevent dictionary tampering. Document the hash verification mechanism in code comments. - Low · Build Variant Security Configuration —
app/src/debug/, app/src/debugNoMinify/. Debug and debugNoMinify build variants exist with separate resource files. These may bypass ProGuard optimization and minification, creating security analysis risks. Fix: Ensure debug variants are never distributed to production. Implement CI/CD checks to prevent debug APKs from being published. Document build variant usage in CONTRIBUTING.md.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.