AGENTS.md@crates/client-ffi · git:20260610.164943c · 2026-06-10 · sha256 e0095e4a9acc07c5

AGENTS.md@crates/client-ffi git:20260610.164943cA

Immutable. This exact content never changes and is served at /api/v1/blob/e0095e4a9acc07c5.

# AGENTS.md

## Crate Role

`pioneer-client-ffi` is the shell boundary crate. It exposes the Rust client core
to mobile/Nitro/C ABI consumers and owns bridge-specific request/result/event
shapes.

This crate may be mobile-facing. It must not become a second client core.

## What Belongs Here

Put code in this crate when it adapts the shared Rust core to the bridge:

- `extern "C"` exported functions and raw pointer/memory ownership handling;
- Nitro/C ABI request and response envelopes;
- JSON-string deserialization/serialization used by the bridge;
- TS/Nitro-friendly `*Request`, `*Result`, and event envelope DTOs;
- wrappers that call `pioneer-client` planners/reducers/runtime methods;
- bridge-specific schema exports for mobile-generated TypeScript types;
- bridge threading/queue code that prevents long work from blocking the React
  Native JS thread.

Boundary DTOs are acceptable here even when desktop does not use them.

## What Does Not Belong Here

Do not implement application behavior here:

- no gateway registry rules duplicated from `pioneer-client`;
- no workspace switching/create/rename rules duplicated from `pioneer-client`;
- no thread tree sorting/projection rules duplicated from `pioneer-client`;
- no provider, skill, MCP, settings, timeline, or artifact business logic
  reimplemented for mobile;
- no desktop/GPUI code;
- no direct persistence policy that should be shell-owned.

If a bridge method needs new behavior, first add or reuse a shell-neutral
planner/reducer/projection in `pioneer-client`, then call it from this crate.

## Boundary Pattern

FFI functions should stay thin:

1. read and validate bridge input;
2. deserialize into a boundary DTO;
3. call `pioneer-client` typed API;
4. serialize a boundary result;
5. return through the common FFI response path.

When adding many exported methods, prefer shared helpers/macros for repeated
pointer/input/response handling instead of hand-writing the same boilerplate.

## Threading

Bridge calls must not block the React Native JS thread with long work.

- Keep websocket loops, reconnects, waits, and IO inside Rust runtime workers or
  nonblocking queues.
- Expose event draining/next-event style APIs that return promptly to JS.
- Do not run long polling, sleeps, or gateway connection loops directly in a
  synchronous bridge call.

## Storage And Secrets

Mobile-native storage belongs to the mobile shell. This crate may return plans
such as token writes/deletes, but should not hard-code MMKV, SecureStore, keychain
paths, or mobile app data directories.

Avoid adding direct `pioneer-protocol` dependencies unless there is a deliberate
reason. Prefer consuming `pioneer-client` public API and re-exported/shared DTOs.

## Testing

Use focused checks for FFI changes:

```bash
cargo test -p pioneer-client-ffi
cargo test -p pioneer-client
```

If bridge schemas are changed, verify schema generation/type generation in the
consumer workflow before handing the change off.

```bash
cargo run -p pioneer-client-ffi --features schema --bin schema -- schemas/client
```