# Mobile Bindings Overview _Status: in progress; corpus bindings are the primary scope_ ## Goals - Provide a minimal C ABI for corpus access without leaking internal C++ types. - Enable embedders to build thin Swift/Kotlin/Flutter wrappers on top of a shared library (`libyams_mobile`). - Maintain binary compatibility across minor releases via versioned structs and feature flags. ## Product Boundary The current intended split is: - `libyams_mobile` owns corpus access: context lifecycle, ingest, update/delete, list/search/get, metadata, and graph retrieval where supported. - The host app owns the LLM runtime and chat UX: model download/load, prompt assembly, generation, streaming responses, tool orchestration, and conversation presentation. This means mobile bindings should be evaluated as a corpus SDK, not as an inference SDK. ## Target Platforms - iOS 15+/macOS 13+ (Swift Package Manager integration) - Android API 26+ (AAR with JNI bindings) - Additional consumers via C-compatible dynamic libraries (e.g., React Native, Flutter) ## Architectural Shape 1. **Core ABI Layer** — versioned header `include/yams/api/mobile_bindings.h` compiled into `libyams_mobile`. 2. **Platform Glue** — Swift/Kotlin wrappers (future milestone) translate native types and may layer async semantics over the blocking C entrypoints. 3. **Service Facade** — long-lived `yams_mobile_context_t` mapping to `AppContext` with configurable storage paths, caches, and worker executors. 4. **Lifecycle Hooks** — initialization, shutdown, and JSON-based diagnostics helpers. ``` [Swift/Combine] [Kotlin/Coroutines] \ / \ yams_mobile C ABI / \ / Core corpus services (ingest/search/get + fixture-driven corpora) ``` ## Data Model Principles - All structs are POD with explicit sizes; optional fields are represented via nullable pointers or sentinel flags. - Strings use UTF-8 `char*` with caller-managed allocation; response containers return opaque handles with dispose functions. - Errors propagate through `yams_mobile_status` enums plus optional extended payloads. ## Threading & Concurrency - Embedders may call APIs from any thread; the library owns a background `boost::asio::thread_pool` per context. - The current C ABI exposes synchronous entrypoints only (`yams_mobile_*_execute`). Async helpers will ship with platform wrappers. - Swift/Kotlin adapters should wrap the blocking calls using dispatch queues/coroutines to surface async behaviour. ## Responsibility Split ### In Scope For Bindings - Open and manage a local YAMS corpus context. - Store and update documents, tags, and metadata. - Retrieve context for prompt assembly through list/search/get APIs. - Expose graph and metadata inspection where the backend supports it. - Return stable JSON payloads suitable for thin platform wrappers. ### Out Of Scope For Bindings - Hosting Gemma or any other local model. - Chat session state, streaming token output, or response rendering. - Model lifecycle UX such as download progress, preload controls, and provider settings. - App-side ranking, prompt composition, or summarization policy beyond raw corpus retrieval. ## Feature Skeleton | Area | Available entrypoints | Notes | |-----------------------|------------------------------------------------|-------| | Context lifecycle | `yams_mobile_context_create`, `yams_mobile_context_destroy` | Config accepts working/cache dirs and a `telemetry_sink` string (`console`, `stderr`, `noop`, or `file:/path`). | | Grep/Search | `yams_mobile_grep_execute`, `yams_mobile_search_execute`, destroy helpers, `yams_mobile_{grep,search}_result_stats_json` | Blocking calls returning opaque handles plus JSON stats (latency, retry counters). | | Document lifecycle | `yams_mobile_store_document`, `yams_mobile_download`, `yams_mobile_update_document`, `yams_mobile_delete_by_name`, `yams_mobile_remove_document` | CRUD exists; delete APIs now align on the common status/payload contract across embedded and daemon mode. Naming cleanup is still in progress. | | Document retrieval | `yams_mobile_list_documents`, `yams_mobile_get_document` | Core surface for app-side prompt assembly and memory recall; `list_documents` and `get_document` now return stable JSON payloads across embedded and daemon mode. | | Metadata inspection | `yams_mobile_get_metadata`, `yams_mobile_metadata_result_json` | JSON payload mirrors DocumentService metadata map. | | Graph retrieval | `yams_mobile_graph_query`, `yams_mobile_graph_query_result_json` | Supported in both daemon and embedded mode for corpus-backed documents; follow-up parity review is still needed for edge cases and cleanup behavior. | | Corpus status | `yams_mobile_get_vector_status`, `yams_mobile_vector_status_result_json` | JSON now reports corpus/index readiness, embedding coverage, and corpus feature signals. The request-side `warmup` flag is deprecated and ignored for ABI compatibility. | ## Current Gaps - Embedded and daemon backends do not yet expose identical behavior for all corpus APIs. - `get_document.include_content` parity is fixed and covered by daemon/mobile tests, but other corpus APIs still need backend-by-backend review. - `list_documents` now returns a stable top-level/document JSON shape in both embedded and daemon mode for the common non-`paths_only` corpus flow. - `search_execute` now returns a stable top-level/result JSON shape in both embedded and daemon mode, while preserving the effective search type after runtime fallback. - `delete_by_name` now returns the same empty-result payload across backends when nothing matches, while `remove_document` preserves `NOT_FOUND` semantics for strict hash deletes. - `update_document` now returns a stable JSON shape in both embedded and daemon mode, including real `updatesApplied`, `tagsAdded`, and `tagsRemoved` counters from the daemon path. - Embedded graph query now works for corpus-backed mobile stores, but backend parity still needs review for edge cases and deletion/cleanup behavior. - `yams_mobile_get_vector_status` still carries legacy naming and a deprecated `warmup` request field, but the payload is now corpus-shaped and `warmup` is explicitly ignored. - The documentation previously implied demo apps and ABI automation that are not present in this checkout. ## Compatibility Strategy - ABI version encoded in `yams_mobile_version_info` (major/minor/patch) and mirrored in the header macros `YAMS_MOBILE_API_VERSION_{MAJOR,MINOR,PATCH}`. - Every request struct now embeds a `struct_size`/`version` header so older clients continue to function when fields are appended. Callers should initialize structs via the `yams_mobile_context_config_default()` / `yams_mobile_request_header_default()` helpers before setting additional fields. - Breaking changes must bump `YAMS_MOBILE_API_VERSION_MAJOR` and ship a parallel symbol surface (`yams_mobile_v2_*`) while preserving the previous version for at least one minor release. - The current source of truth for compatibility is the versioned C header plus mobile ABI smoke coverage. CI now verifies that the built shared library exports every `YAMS_MOBILE_API` symbol declared in the versioned header. ## Build & Distribution - CI packaging and ABI verification live in `mobile-builds.md` (in the [yams-app](https://github.com/trvon/yams-app) repository). - The current CI artifact is a host-native shared library bundle for validation and downstream integration work, not yet a shipped `.xcframework` or `.aar`. - The intended layering is: - this repo publishes the native corpus library plus headers - platform wrappers package that library for iOS/Android - the Flutter app/plugin consumes those packaged native artifacts ## Fixtures & Test Corpora - `tests/common/search_corpus_presets.h` exposes `mobileSearchCorpusSpec()` which captures the curated mobile dataset (sync deltas, path sensitivity, semantic warm-up, case toggles). Use this in unit/integration tests to align with the demo apps and smoke suites. - `tests/mobile/mobile_abi_smoke_test.cpp` now runs on Catch2, validates the round-trip ingest/list/search flow against the new corpus, covers daemon `get_document.include_content` parity, verifies embedded graph query on a corpus-backed store, checks the corpus-status payload in both embedded and daemon modes, and verifies stable `search_execute`, `list_documents`, `delete_by_name`, and `update_document` payload shapes across embedded and daemon backends, plus `remove_document` status parity for missing hashes. `update_document` coverage now also asserts real tag counter parity instead of shape-only presence checks. The current suite also retries the first daemon store call in smoke coverage to absorb daemon-startup transport flakiness seen only in full-suite execution. ## Platform Wrappers Reference Swift/Android/Flutter wrappers are planned, but they are not yet checked into this repo. Until those wrappers land, `libyams_mobile` should be treated as the stable integration seam and the wrapper layer should stay intentionally thin. ## Developer Workflow 1. Initialize the fixtures using `FixtureManager` (see smoke test for a template) or reuse the packaged corpora in CI. 2. Link against `yams_mobile` from the host platform wrapper. 3. Validate corpus flows first: store, list, search, get, update, delete, metadata, and graph. 4. Keep app-owned LLM concerns outside the bindings layer.