# IC Reactor - AI Friendly Guide
IC Reactor is a modern, type-safe library for building Internet Computer applications. It provides seamless integration between JavaScript/TypeScript applications and IC canisters with full TypeScript support, intelligent caching (via TanStack Query), and React integration.
## AI Agent Context Files (Repository)
- `/llms.txt`: This file (high-level context for LLMs)
- `/CLAUDE.md`: Claude / Anthropic project context
- `/AGENTS.md`: OpenAI Codex agent instructions
- `/.github/copilot-instructions.md`: GitHub Copilot instructions
- `/.cursorrules`: Cursor IDE rules
- `/skill-packages/`: Local skill packages (multi-agent compatible)
- Skill: `ic-reactor-hooks` (file: `skill-packages/ic-reactor-hooks/SKILL.md`)
- External skills repo: `https://github.com/B3Pay/ic-reactor-skills`
If an agent supports skills/agent registries, prefer the `ic-reactor-hooks` skill from `skill-packages/ic-reactor-hooks/` (local) or `B3Pay/ic-reactor-skills` (external) when the task involves creating, refactoring, or explaining React hooks, query/mutation factories, cache invalidation, or usage inside vs outside React components.
## Core Packages
- `@ic-reactor/core`: Low-level API for managing actors, agents, and query caching.
- `@ic-reactor/react`: High-level React hooks and context providers for easy integration.
- `@ic-reactor/candid`: Dynamic Candid parsing and runtime reactors for unknown canisters.
- `@ic-reactor/cli`: Code generation for declarations + typed hooks/reactors.
- `@ic-reactor/vite-plugin`: Watch-mode code generation for Vite projects.
## Key Concepts
- **Reactor**: Manages a single canister's actor instance, handling method calls and query caching. (Replaces `CandidActor`)
- **DisplayReactor**: A specialized `Reactor` that automatically transforms Candid types (BigInt, Principal) to JS-friendly types (string, number). (Replaces `DisplayCodecActor`)
- **ClientManager**: Manages the IC Agent connection, handling authentication and identity provider integration.
- **Auto Codecs**: Automatically transforms Candid types (BigInt, Principal) to JS-friendly types (string, number).
- **Type Safety**: Provides end-to-end type safety from Candid definitions to React hooks.
## Common Code Patterns
### 1. Initialization (Core)
```typescript
import { ClientManager, Reactor, DisplayReactor } from '@ic-reactor/core';
import { QueryClient } from '@tanstack/query-core';
import { idlFactory, type _SERVICE } from './declarations/my_canister';
const queryClient = new QueryClient();
const clientManager = new ClientManager({ queryClient });
// Standard Reactor (Raw Candid Types)
const reactor = new Reactor<_SERVICE>({
clientManager,
idlFactory,
canisterId: 'rrkah-fqaaa-aaaaa-aaaaq-cai',
});
// OR DisplayReactor (Auto Transformation)
const displayReactor = new DisplayReactor<_SERVICE>({
clientManager,
idlFactory,
canisterId: 'rrkah-fqaaa-aaaaa-aaaaq-cai',
});
```
### 2. React Integration (Standard Hooks)
```typescript
import { createActorHooks } from '@ic-reactor/react';
const { useActorQuery, useActorMutation } = createActorHooks(reactor);
// Query call (cached)
function Profile() {
const { data, isLoading } = useActorQuery({
functionName: 'getUserProfile',
args: ['principal-id'],
});
return
{isLoading ? 'Loading...' : data.name}
;
}
// Update call (mutation)
function UpdateProfile() {
const { mutate, isPending } = useActorMutation({
functionName: 'updateUserProfile',
onSuccess: (data) => console.log('Updated!', data),
onCanisterError: (error) => console.error('Logic Error:', error),
});
return ;
}
```
### 3. Query and Mutation Factories (Recommended for shared use)
For reusable operations that must work both inside React and outside React (loaders/actions/services):
```typescript
import { createQuery, createMutation } from '@ic-reactor/react';
// Reusable query object
const profileQuery = createQuery(reactor, {
functionName: 'getUserProfile',
args: ['user-id'],
});
// In React: profileQuery.useQuery()
// Cache-first: await profileQuery.fetch()
// Fire-and-forget: profileQuery.prefetch() // warm cache before render
// Optimistic: profileQuery.setData({ name: 'Alice' }) // write to cache
// Helpers: profileQuery.invalidate(), profileQuery.getQueryKey(), profileQuery.getCacheData()
// Reusable mutation object
const updateProfile = createMutation(reactor, {
functionName: 'updateUserProfile',
onCanisterError: (err) => console.error('Canister Err:', err.code),
});
// In React: updateProfile.useMutation()
// Outside React: await updateProfile.execute([{ name: 'Alice' }])
```
### 4. Dynamic Query Factories (argument-at-call-time)
```typescript
import { createQueryFactory } from '@ic-reactor/react';
const profileQueryFactory = createQueryFactory(reactor, {
functionName: 'getUserProfile',
});
// In React
const { data } = profileQueryFactory(['user-id']).useQuery();
// Outside React (loader/prefetch)
await profileQueryFactory(['user-id']).fetch();
```
### 5. Infinite Queries
```typescript
import { createInfiniteQuery } from '@ic-reactor/react';
const activityQuery = createInfiniteQuery(reactor, {
functionName: 'getActivities',
initialPageParam: 0,
getArgs: (page) => [{ offset: page, limit: 20 }],
getNextPageParam: (lastPage, allPages) =>
lastPage.length < 20 ? null : allPages.length * 20,
});
// In React: activityQuery.useInfiniteQuery()
// Outside React: await activityQuery.fetch()
```
### 6. Generated Hooks (Best for many canisters/methods)
Prefer generated hooks for scale and consistency:
- Vite: `@ic-reactor/vite-plugin` (watch + hot regeneration)
- Non-Vite / CI: `@ic-reactor/cli`
Generated files typically expose method-specific query/mutation objects with both React and imperative methods (e.g., `.useQuery()` + `.fetch()` or `.useMutation()` + `.execute()`).
## API Reference (Summary)
### @ic-reactor/core
- `Reactor`: `callMethod`, `getQueryOptions`, `generateQueryKey`, `invalidateQueries`.
- `DisplayReactor`: Extended `Reactor` with automatic type transformation.
- `ClientManager`: `authenticate`, `login`, `logout`, `subscribeAuthState`.
### @ic-reactor/react
#### Core Factories
- `createActorHooks(reactor)`: Generates a typed hook suite for a canister:
- `useActorQuery`: Standard query hook.
- `useActorMutation`: Mutation hook. Supports `invalidateQueries` and `onCanisterError`.
- `useActorInfiniteQuery`: Infinite query hook (pagination).
- `useActorSuspenseQuery`: Suspense-enabled query hook.
- `useActorSuspenseInfiniteQuery`: Suspense-enabled infinite query hook.
- `useActorMethod`: Unified hook that auto-handles query vs update methods.
#### Standalone Factories
Each factory returns an object with both a React hook and imperative helpers.
- `createQuery(reactor, config)`: Returns `{ useQuery, fetch, prefetch, invalidate, getQueryKey, getCacheData, setData }`.
- `createSuspenseQuery(reactor, config)`: Returns `{ useSuspenseQuery, fetch, prefetch, invalidate, getQueryKey, getCacheData, setData }`.
- `createInfiniteQuery(reactor, config)`: Returns `{ useInfiniteQuery, fetch, invalidate, getQueryKey, getCacheData }`.
- `createSuspenseInfiniteQuery(reactor, config)`: Returns `{ useSuspenseInfiniteQuery, fetch, invalidate, getQueryKey, getCacheData }`.
- `createMutation(reactor, config)`: Returns `{ useMutation, execute }`. Supports `onCanisterError` for `Result { Err }` variants.
- `createQueryFactory(reactor, config)`: `(args) => QueryResult` — creates query instances with args supplied at call time.
- `createSuspenseQueryFactory(reactor, config)`: `(args) => SuspenseQueryResult` — suspense variant of `createQueryFactory`.
- `createInfiniteQueryFactory(reactor, config)`: `(getArgs) => InfiniteQueryResult` — accepts `getArgs` at call time for dynamic pagination.
- `createSuspenseInfiniteQueryFactory(reactor, config)`: `(getArgs, options?) => SuspenseInfiniteQueryResult` — suspense variant with optional per-call `queryKey`.
#### Query Result Methods (shared across all query factories)
| Method | Use |
|--------|-----|
| `fetch()` | Cache-first fetch. Use in route loaders. |
| `prefetch()` | Fire-and-forget warm-up. Use on hover or before navigation. |
| `invalidate()` | Invalidate cache (triggers refetch if mounted). |
| `getQueryKey()` | TanStack Query key for this query. |
| `getCacheData(select?)` | Read from cache without fetching. |
| `setData(updater)` | Write raw data into cache. Accepts value or `(prev) => next`. Use for optimistic updates. |
#### Authentication Hooks
- `useAuth`: Login/logout and identity management.
- `useAgentState`: Access agent initialization status and network details.
- `useUserPrincipal`: Access the current user's Principal.
- `createAuthHooks(clientManager)`: Creates a scoped set of authentication hooks (rarely needed, use top-level exports).
## Best Practices
1. Use `DisplayReactor` for simpler data handling with AI / UI layers.
2. Use `createActorHooks` for generic component hooks, or method-specific query/mutation factories for reusable operations.
3. Never call React hooks outside React components/custom hooks. Use `.fetch()` / `.prefetch()` / `.execute()` / `.invalidate()` / `.setData()` for imperative usage.
4. Prefer cache invalidation via `query.getQueryKey()` or `query.invalidate()` to avoid hard-coded key drift.
5. Leverage TanStack Query options (`staleTime`, refetch policies, select) passed through query hooks/factories.
6. Use `Suspense` versions (`useActorSuspenseQuery`) when the app already uses Suspense boundaries.
7. Use `onCanisterError` to handle typed `Result { Err }` responses separately from network/agent errors.
8. Prefer generated hooks (CLI/Vite plugin) for large canisters or frequent `.did` changes.
## High-Value File References (for AI agents)
- `skill-packages/ic-reactor-hooks/SKILL.md`
- `skill-packages/ic-reactor-hooks/references/patterns.md`
- `https://github.com/B3Pay/ic-reactor-skills`
- `/packages/react/src/createActorHooks.ts`
- `/packages/react/src/createQuery.ts`
- `/packages/react/src/createMutation.ts`
- `/packages/react/src/hooks/useActorMethod.ts`
- `/packages/react/README.md`
- `/packages/vite-plugin/README.md`
- `/packages/cli/README.md`
- `/examples/all-in-one-demo/src/lib/factories.ts`
- `/examples/tanstack-router/src/canisters/ledger/hooks/`