This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
mobilecritical PriorityID: rn-077-bridgeless-jsi-memory-pinning-standard

React Native 0.77 Bridgeless TurboModule JSI Memory Pinning Standard

Enforces safe C++ HostObject reference pinning and deterministic lifecycle management across concurrent native-to-Hermes execution boundaries in React Native 0.77 bridgeless mode. Prevents Hermes heap corruption, race conditions, and use-after-free crashes caused by capturing raw JSI values across asynchronous native threads without CallInvoker synchronization.

Prohibited Anti-Pattern: Capturing Unpinned JSI Value Pointers Across Asynchronous Native Threads and Retaining Leaked HostObjects

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: React Native 0.77 Bridgeless TurboModule JSI Memory Pinning Standard - Enforces safe C++ HostObject reference pinning and deterministic lifecycle management across concurrent native-to-Hermes execution boundaries in React Native 0.77 bridgeless mode. Prevents Hermes heap corruption, race conditions, and use-after-free crashes caused by capturing raw JSI values across asynchronous native threads without CallInvoker synchronization.
globs: src/**/*.{ts,tsx}, tm/**/*.{ts,tsx}, cpp/**/*.{h,cpp}, ios/**/*.{h,mm}, android/src/main/jni/**/*.{h,cpp}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/rn-077-bridgeless-jsi-memory-pinning-standard"
---

# React Native 0.77 Bridgeless TurboModule JSI Memory Pinning Standard

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Capturing Unpinned JSI Value Pointers Across Asynchronous Native Threads and Retaining Leaked HostObjects

## System Constraints
You are a Principal Mobile Systems Architect enforcing the React Native 0.77 Bridgeless TurboModule JSI Memory Pinning Standard. In React Native 0.77 Bridgeless mode, the legacy bridge is eliminated, and all communication relies on direct C++ JSI bindings. You must mandate strict memory invariants: never capture raw facebook::jsi::Value, jsi::Object, or jsi::Pointer across concurrent thread boundaries; always pin host state via std::shared_ptr<jsi::HostObject>; always marshal native-to-Hermes calls through react::CallInvoker; and enforce explicit disposal semantics on the TypeScript consumer layer to prevent native resource leaks.

## Strict Guidelines
- Engineers MUST ALWAYS schedule Hermes VM access through facebook::react::CallInvoker::invokeAsync when returning callbacks from background threads.
- Engineers MUST NOT store raw jsi::Value, jsi::Object, or jsi::String instances in native member variables or capture them by reference across asynchronous dispatch queues.
- Code MUST pin native state using std::shared_ptr<facebook::jsi::HostObject> and expose pinned resources to JavaScript via TurboModule HostObject references.
- TypeScript interfaces MUST expose an explicit dispose() or unpin() method for native-backed HostObjects and register them with FinalizationRegistry as a defensive safeguard.
- Native C++ TurboModules MUST verify runtime validity and guard against torn reads by executing inside jsi::Runtime locking scopes where multi-threading is enabled.

## Bad vs Good Implementations
### TypeScript Native HostObject Lifecycle and Pinning Management

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: The implementation relies on primitive identifiers without explicit lifecycle controls or native finalization tracking. If the JS instance is garbage-collected, the native thread retains asynchronous callback listeners and orphaned native resources, causing leaks in Hermes Bridgeless runtimes.
```typescript
import { TurboModuleRegistry } from 'react-native';
import type { TurboModule } from 'react-native';

interface Spec extends TurboModule {
  createSession(id: string): { sessionId: string };
  subscribeSession(sessionId: string, callback: (event: string) => void): void;
}

const NativeSessionModule = TurboModuleRegistry.getEnforcing<Spec>('SessionModule');

export class SessionHandle {
  private sessionId: string;

  constructor(id: string) {
    // ANTI-PATTERN: Native HostObject is referenced only by raw primitive string without
    // lifecycle cleanup or deterministic native pinning contract, risking heap desync.
    const res = NativeSessionModule.createSession(id);
    this.sessionId = res.sessionId;
    NativeSessionModule.subscribeSession(this.sessionId, (evt) => {
      console.log('Event received:', evt);
    });
  }
}
```

#### Production Standard (Correct)
> **Standard**: Uses a pinned JSI HostObject reference, captures unsubscription tokens directly, implements deterministic dispose() calls, and provides a FinalizationRegistry fallback to guarantee native-side C++ object unpinning.
```typescript
import { TurboModuleRegistry } from 'react-native';
import type { TurboModule } from 'react-native';

interface SessionNativeHostObject {
  readonly sessionId: string;
  dispose(): void;
}

interface Spec extends TurboModule {
  createSessionHostObject(id: string): SessionNativeHostObject;
  subscribeSession(
    hostObject: SessionNativeHostObject,
    callback: (event: string) => void
  ): () => void;
}

const NativeSessionModule = TurboModuleRegistry.getEnforcing<Spec>('SessionModule');

export class SessionHandle {
  private hostObject: SessionNativeHostObject | null;
  private unsubscribe: (() => void) | null = null;
  private static registry = new FinalizationRegistry<(obj: SessionNativeHostObject) => void>(
    (cleanup) => cleanup(this as unknown as SessionNativeHostObject)
  );

  constructor(id: string) {
    this.hostObject = NativeSessionModule.createSessionHostObject(id);
    this.unsubscribe = NativeSessionModule.subscribeSession(this.hostObject, (evt) => {
      this.handleEvent(evt);
    });
    SessionHandle.registry.register(this, () => this.dispose());
  }

  private handleEvent(event: string): void {
    if (!this.hostObject) return;
    // Safe processing while pinned HostObject is alive
  }

  public dispose(): void {
    if (this.unsubscribe) {
      this.unsubscribe();
      this.unsubscribe = null;
    }
    if (this.hostObject) {
      this.hostObject.dispose();
      this.hostObject = null;
    }
    SessionHandle.registry.unregister(this);
  }
}
```

### C++ TurboModule CallInvoker Synchronization vs Raw Pointer Capture

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Raw jsi::Value and jsi::Function instances are thread-confined to the Hermes runtime thread. Calling them from a std::thread or native background queue without CallInvoker invokes undefined behavior and immediate memory corruption.
```cpp
// ANTI-PATTERN: Capturing jsi::Function or jsi::Value across threads without CallInvoker
void SessionModule::subscribeSession(
    facebook::jsi::Runtime& rt,
    const facebook::jsi::Object& hostObj,
    const facebook::jsi::Function& callback) {
  // DANGEROUS: Capturing raw reference to JSI function directly into native worker queue
  std::thread([&rt, &callback]() {
    std::string payload = fetchBackgroundPayload();
    // CRASH: Accessing jsi::Runtime directly from non-Hermes thread causes use-after-free and SIGSEGV
    callback.call(rt, facebook::jsi::String::createFromUtf8(rt, payload));
  }).detach();
}
```

#### Production Standard (Correct)
> **Standard**: Pins C++ state via std::shared_ptr<SessionHostObject> and safely transfers execution back to the Hermes runtime using CallInvoker::invokeAsync, ensuring thread-safe access to JSI values.
```cpp
// PRODUCTION STANDARD: Pinning Native State via HostObject and CallInvoker Marshaling
void SessionModule::subscribeSession(
    facebook::jsi::Runtime& rt,
    std::shared_ptr<SessionHostObject> sessionHostObject,
    facebook::jsi::Function callback) {
  
  // Convert JSI function to Value and pin into a shared CallInvoker callback
  auto pinnedCallback = std::make_shared<facebook::jsi::Value>(rt, callback);
  auto jsInvoker = this->jsInvoker_;

  nativeQueue_->async([sessionHostObject, pinnedCallback, jsInvoker]() {
    if (!sessionHostObject->isValid()) {
      return;
    }
    std::string payload = sessionHostObject->fetchBackgroundPayload();

    // Safe asynchronous boundary crossing via CallInvoker
    jsInvoker->invokeAsync([pinnedCallback, payload](facebook::jsi::Runtime& runtime) {
      if (pinnedCallback->isObject() && pinnedCallback->getObject(runtime).isFunction(runtime)) {
        auto fn = pinnedCallback->getObject(runtime).getFunction(runtime);
        fn.call(runtime, facebook::jsi::String::createFromUtf8(runtime, payload));
      }
    });
  });
}
```

Recommended MCP Servers (mcp-serverlist.com)

Equip agent with system tools to verify code for this stack.

Recommended Agent Skills (askills.dev)

Ready-to-use executable skill functions tailored to this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: React Native 0.77 Bridgeless TurboModule JSI Memory Pinning Standard

React Native 0.77 Bridgeless TurboModule JSI Memory Pinning Standard defines an industrial-grade behavioral standard for mobile engineering. Enforces safe C++ HostObject reference pinning and deterministic lifecycle management across concurrent native-to-Hermes execution boundaries in React Native 0.77 bridgeless mode. Prevents Hermes heap corruption, race conditions, and use-after-free crashes caused by capturing raw JSI values across asynchronous native threads without CallInvoker synchronization. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Capturing Unpinned JSI Value Pointers Across Asynchronous Native Threads and Retaining Leaked HostObjects Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftCapturing Unpinned JSI Value Pointers Across Asynchronous Native Threads and Retaining Leaked HostObjectsCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST ALWAYS schedule Hermes VM access through facebook

Engineers MUST ALWAYS schedule Hermes VM access through facebook::react::CallInvoker::invokeAsync when returning callbacks from background threads.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST NOT store raw jsi

Engineers MUST NOT store raw jsi::Value, jsi::Object, or jsi::String instances in native member variables or capture them by reference across asynchronous dispatch queues.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Code MUST pin native state using std

Code MUST pin native state using std::shared_ptr<facebook::jsi::HostObject> and expose pinned resources to JavaScript via TurboModule HostObject references.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

TypeScript interfaces MUST expose an explicit dispose() or unpin() method for native-backed HostObjects and register them with FinalizationRegistry as a defensive safeguard.

TypeScript interfaces MUST expose an explicit dispose() or unpin() method for native-backed HostObjects and register them with FinalizationRegistry as a defensive safeguard.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Native C++ TurboModules MUST verify runtime validity and guard against torn reads by executing inside jsi

Native C++ TurboModules MUST verify runtime validity and guard against torn reads by executing inside jsi::Runtime locking scopes where multi-threading is enabled.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is React Native 0.77 Bridgeless TurboModule JSI Memory Pinning Standard critical for AI coding assistants?

Enforces safe C++ HostObject reference pinning and deterministic lifecycle management across concurrent native-to-Hermes execution boundaries in React Native 0.77 bridgeless mode. Prevents Hermes heap corruption, race conditions, and use-after-free crashes caused by capturing raw JSI values across asynchronous native threads without CallInvoker synchronization. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Capturing Unpinned JSI Value Pointers Across Asynchronous Native Threads and Retaining Leaked HostObjects) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

Related MOBILE Rules

View all rules →
1 Rule in Stack

React