- Rust 50.6%
- Python 41.2%
- Shell 6.6%
- Just 1.6%
Capture how CI was diagnosed (forge API) and the runner facts
(forgejo-runner v6.4.0, node:20-bookworm image, data.forgejo.org action
mirror, node20-only runtime), the layered fixes (#3-#5), and the caching
tradeoff. v0.1.0 stays on the CI-green commit
|
||
|---|---|---|
| .forgejo/workflows | ||
| crates | ||
| docs | ||
| keys | ||
| scripts | ||
| training | ||
| .gitignore | ||
| AGENTS.md | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| clippy.toml | ||
| CONTRIBUTING.md | ||
| DATA_SOURCES.md | ||
| deny.toml | ||
| EVAL.md | ||
| justfile | ||
| LICENSE | ||
| README.md | ||
| rustfmt.toml | ||
shepherd-swipe
A standalone, host-agnostic swipe-typing decoder: a pure-Rust inference library plus the training pipeline that produces signed, versioned model bundles. Given a finger gesture over a keyboard, it returns a ranked list of candidate words.
This repository is the decoder core and its training pipeline only. It has no
dependency on any compositor, OS input stack, or shepherd-launcher. Whatever
eventually hosts the IME (a Wayland input-method-v2 backend, an Android keyboard,
something else) consumes this repo through a small, versioned, one-way contract
(docs/integration.md).
Ethos (non-negotiable)
- Offline only. No network at inference time. Ever.
- No telemetry. The decoder reports nothing, anywhere.
- No cloud training. Models are trained on hardware you control.
- Auditable provenance. Every data source's license and origin is recorded in
DATA_SOURCES.md. - Closed-vocabulary safety. A word absent from a profile's lexicon is
unemittable — a structural guarantee, not a post-filter. This underpins the
childprofile's safety invariants (§4 of the spec,docs/spec.md).
Layout
crates/shepherd-swipe-core/ pure-Rust inference library — the portable contract
crates/shepherd-swipe-cli/ standalone decode/evaluate binary (no compositor)
training/ Python (PyTorch) pipeline: data → models → signed bundles
docs/ spec, integration contract, gesture interchange format
bundles/ build output — gitignored, NEVER committed
scripts/setup-box.sh provision a blank box (driver, Rust, Python, NDK)
DATA_SOURCES.md provenance + licenses + verified dataset schema
The portability bar (compiles for an Android target, no OS deps) applies only
to shepherd-swipe-core. The CLI and training pipeline are not constrained.
Profiles
adult and child bundles share the encoder (gesture geometry is profile-
agnostic) and differ only in their lexicon and context language model. The
child profile is built from a profanity-free-at-source corpus and enforces three
tested safety invariants (INV-1/2/3 — see docs/spec.md §4).
Quick start
# 1. Provision the box (driver, Rust+Android target, uv Python 3.12, NDK, just).
./scripts/setup-box.sh
# 2. Build and test the Rust workspace.
cargo build --workspace
cargo test --workspace
# 3. Reproduce a bundle end-to-end (downloads data, trains, signs).
just bundle adult
just bundle child
# 4. Decode a recorded gesture with the CLI.
cargo run -p shepherd-swipe-cli -- decode \
--bundle bundles/adult --gesture crates/shepherd-swipe-core/tests/fixtures/hello.gesture.json
# ...or as a library (minimal consumer example):
cargo run -p shepherd-swipe-core --example decode -- \
bundles/adult crates/shepherd-swipe-core/tests/fixtures/hello.gesture.json
Consuming this repo
See docs/integration.md. In short: pin a git tag of the
crate and download a pinned, signed bundle from the forge releases; the decoder
verifies the signature and per-file hashes before use.
License
Source code: MIT. Model bundles may carry separate terms — see
DATA_SOURCES.md and each bundle's metadata.toml.