Synthèse automatique
Explique comment relier les services Effect-TS à React au moyen des atoms d'effect-atom (Atom.make, Atom.runtime, operation atoms et gestion des Result).
Points forts
- Fournit un arbre de décision clair qui associe chaque besoin d'état (valeur simple, dérivée, asynchrone, stream, clé) au bon pattern d'atom
- Donne des signatures, des imports et des exemples de code complets, avec les numéros de ligne des sources canoniques d'effect-atom
- Impose la doctrine « Atom-as-State » et explique pourquoi éviter Effect.Ref lorsque React est le consommateur
- S'appuie sur des implémentations internes déjà éprouvées (DataManager, Slider, testbed) comme références concrètes
Limites
- Très lié à un dépôt précis (TMNL, chemins de submodules, doctrine interne), donc peu portable tel quel vers un autre projet
- L'exemple de code final est tronqué, et plusieurs patterns ne sont décrits que par leur nom sans exemple complet
- Suppose une bonne maîtrise préalable d'Effect-TS et de React ; aucun rappel des concepts de base
À utiliser lorsqu'on écrit ou révise la gestion d'état React dans une base de code Effect-TS qui s'appuie sur effect-atom.
À éviter si le projet n'utilise ni Effect ni effect-atom, ou s'il s'agit d'un état React classique géré par useState, Zustand ou Redux.
Analyse de sécurité
SûrThis skill is purely informational documentation about using the effect-atom library with React. It contains no executable commands, no instructions to modify files or run scripts, and no dangerous tool usage. The declared allowed-tools list is empty, and the content only provides code examples and guidance for developers.
Aucun point d'attention détecté
Comment cette analyse est faiteExemples
I want to expose my SearchService from an Effect Layer to React with effect-atom. Show me how to build the runtime using Atom.runtime(Layer) and read the result in a component with useAtomValue, handling Result.isSuccess and Result.isFailure.Turn my search trigger into an operation atom: define runtime.fn<SearchArgs>()((args, ctx) => Effect...) on my runtime, call it with useSetAtom(op)(args) from the component, and add a separate clear operation that resets the results atom.My service mutates an Effect.Ref and React subscribes via a stream. Is that the right approach with effect-atom, or should the service write directly to an Atom.make state with ctx.set? Walk me through the Atom-as-State doctrine and the trade-offs.name: effect-atom-integration description: Atom.runtime, Atom.make, runtimeAtom.fn, operation atoms, Result handling. Atom-as-State doctrine for integrating Effect services with React. model_invoked: true triggers:
- "Atom.runtime"
- "Atom.make"
- "effect-atom"
- "runtimeAtom"
- "operation atom"
- "Result"
Effect-Atom Integration
Overview
effect-atom bridges Effect-TS services with React via reactive atoms. This is the canonical state management pattern for TMNL.
CRITICAL DOCTRINE: Atom-as-State
From .edin/EFFECT_PATTERNS.md:
NO EFFECT.REF. EVER.
When React is the consumer via effect-atom,
Atom.make()is the primary state mechanism—notEffect.Refinside services.
- Service methods mutate Atoms directly (
Atom.set,ctx.set)- React subscribes directly to atoms
- This eliminates the Ref→Atom bridge: no polling, no SubscriptionRef, no streams-to-consume-streams
Canonical Sources
effect-atom Core
- Submodule:
../../submodules/effect-atom/packages/atom/src/Atom.ts:370-391— Atom.make (Effect detection)Atom.ts:458-463— Writable atomsAtom.ts:328-338— Readable (derived) atomsAtom.ts:643-715— Atom.runtimeAtom.ts:553-588— AtomRuntime.fn (operation atoms)Atom.ts:1316-1351— Atom.family
effect-atom Tests
- Submodule:
../../submodules/effect-atom/packages/atom/test/Atom.test.ts— Canonical usage patternsResult.test.ts— Result type handling
TMNL Battle-tested Implementations
- DataManager atoms —
src/lib/data-manager/v1/atoms/index.ts(canonical Atom-as-State) - Slider atoms —
src/lib/slider/v1/atoms/index.ts(runtime factories) - Testbed —
src/components/testbed/EffectAtomTestbed.tsx(comprehensive examples)
Patterns
Decision Tree: Which Atom Pattern?
Need reactive state?
│
├─ Simple mutable state (counter, toggle)?
│ └─ Use: Atom.make(value) → Writable<A>
│ Read: get(atom), Write: ctx.set(atom, value)
│
├─ Derived from other atoms (computed value)?
│ └─ Use: Atom.make((get) => ...) → Atom<A> (readonly)
│ Auto-tracks dependencies
│
├─ Async data (API call, database query)?
│ └─ Use: Atom.make(Effect) → Atom<Result<A, E>>
│ Result.isSuccess, Result.isFailure, Result.isInitial
│
├─ Service access (yield* MyService)?
│ └─ Use: Atom.runtime(Layer) → AtomRuntime<R, E>
│ Create atoms with service dependencies
│
├─ Mutation/action (searchOp, clearOp)?
│ └─ Use: runtime.fn<Arg>()((arg, ctx) => Effect)
│ Trigger with useSetAtom(op)(arg)
│
├─ Stream data (progressive, ticking)?
│ └─ Use: Atom.make(Stream) → Atom<Result<A, E>>
│ Updates progressively as stream emits
│
└─ Keyed atoms (layer-123, user-456)?
└─ Use: Atom.family((key) => Atom.make(...))
Stable references via WeakRef
Pattern 1: Atom.make — PRIMITIVE ATOMS
When to use:
- Simple mutable state
- UI toggles, counters, input bindings
- State that doesn't derive from async sources
Signature:
Atom.make<A>(initialValue: A): Atom.Writable<A>
Full Example:
import { Atom } from '@effect-atom/atom-react'
import { useAtomValue, useSetAtom } from '@effect-rx/rx-react'
// Module-level atoms (stable references)
const countAtom = Atom.make(0)
const nameAtom = Atom.make('')
const isOpenAtom = Atom.make(false)
// React component
function Counter() {
const count = useAtomValue(countAtom)
const setCount = useSetAtom(countAtom)
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
)
}
Key Features:
- Writable — Can read AND write
- Stable references — Define at module level
- Type-safe — TypeScript infers
Atom.Writable<number>
TMNL Example (src/lib/data-manager/v1/atoms/index.ts:51):
// State atoms (readonly from components)
export const resultsAtom = Atom.make<SearchResult[]>([])
export const statusAtom = Atom.make<StreamStatus>('idle')
export const statsAtom = Atom.make<StreamStats>({ chunks: 0, items: 0, ms: 0 })
Pattern 2: Atom.make with Getter — DERIVED ATOMS
When to use:
- Computed values from other atoms
- Derived state (fullName from firstName + lastName)
- Auto-tracking dependencies
Signature:
Atom.make<A>((get) => A): Atom.Atom<A> // Readonly
Full Example:
import { Atom } from '@effect-atom/atom-react'
const firstNameAtom = Atom.make('John')
const lastNameAtom = Atom.make('Doe')
// Derived atom (auto-tracks dependencies)
const fullNameAtom = Atom.make((get) => {
const first = get(firstNameAtom)
const last = get(lastNameAtom)
return `${first} ${last}`
})
// Another derived atom
const greetingAtom = Atom.make((get) => {
const name = get(fullNameAtom)
return `Hello, ${name}!`
})
// React component
function Greeting() {
const greeting = useAtomValue(greetingAtom)
return <h1>{greeting}</h1> // "Hello, John Doe!"
}
Key Features:
- Readonly — Cannot be written to directly
- Auto-tracks — Re-computes when dependencies change
- Lazy — Only computes when subscribed
TMNL Example (src/lib/data-manager/v1/atoms/index.ts:94):
export const isSearchingAtom = Atom.make((get) => {
const status = get(statusAtom)
return status === 'streaming'
})
export const hasResultsAtom = Atom.make((get) => {
const results = get(resultsAtom)
return results.length > 0
})
Pattern 3: Atom.make with Effect — RESULT ATOMS
When to use:
- Async data (API calls, database queries)
- Fallible operations (can fail with typed errors)
- Need
Initial | Success | Failurestates
Signature:
Atom.make<A, E>(effect: Effect.Effect<A, E>): Atom.Atom<Result<A, E>>
Result Type:
type Result<A, E> =
| { readonly _tag: 'Initial' }
| { readonly _tag: 'Success'; readonly value: A }
| { readonly _tag: 'Failure'; readonly error: E }
Full Example:
import { Atom } from '@effect-atom/atom-react'
import { Effect, Result } from 'effect'
import { useAtomValue } from '@effect-rx/rx-react'
// Effect atom
const userAtom = Atom.make(
Effect.gen(function* () {
yield* Effect.sleep('100 millis')
const response = yield* Effect.tryPromise(() =>
fetch('/api/user').then(r => r.json())
)
return response
})
)
// React component
function UserProfile() {
const result = useAtomValue(userAtom)
// Pattern match on Result
if (Result.isInitial(result)) {
return <div>Loading...</div>
}
if (Result.isFailure(result)) {
return <div>Error: {result.error.message}</div>
}
// Result.isSuccess
return <div>User: {result.value.name}</div>
}
Key Features:
- Three states — Initial, Success, Failure
- Type-safe errors —
Eis typed - Pattern matching —
Result.isSuccess,Result.isFailure,Result.isInitial
TMNL Example (src/components/testbed/EffectAtomTestbed.tsx:1016):
const dataAtom = Atom.make(
Effect.gen(function* () {
yield* Effect.sleep('500 millis')
return { message: 'Hello from Effect!' }
})
)
function EffectExample() {
const result = useAtomValue(dataAtom)
return (
<div>
{Result.isInitial(result) && <Spinner />}
{Result.isSuccess(result) && <div>{result.value.message}</div>}
{Result.isFailure(result) && <Error error={result.error} />}
</div>
)
}
Pattern 4: Atom.runtime — SERVICE COMPOSITION
When to use:
- Need access to Effect services in atoms
- Compose multiple service layers
- Create service-scoped atom runtime
Signature:
Atom.runtime<R, E>(layer: Layer.Layer<R, E>): AtomRuntime<R, E>
Full Example:
import { Atom } from '@effect-atom/atom-react'
import { Effect, Layer } from 'effect'
// Services
class Logger extends Effect.Service<Logger>()(
"app/Logger",
{ effect: Effect.succeed({ log: (msg: string) => Effect.sync(() => console.log(msg)) }) }
) {}
class ApiClient extends Effect.Service<ApiClient>()(
"app/ApiClient",
{
effect: Effect.gen(function* () {
const logger = yield* Logger
return {
fetchUsers: () => Effect.gen(function* () {
yield* logger.log('Fetching users...')
return yield* Effect.tryPromise(() => fetch('/api/users').then(r => r.json()))
})
} as const
}),
dependencies: [Logger.Default]
}
) {}
// Create runtime from composed layers
export const appRuntime = Atom.runtime(
Layer.mergeAll(Logger.Default, ApiClient.Default)
)
// Create atoms with service access
export const usersAtom = appRuntime.atom(
Effect.gen(function* () {
const api = yield* ApiClient
return yield* api.fetchUsers()
})
)
// React component
function UserList() {
const result = useAtomValue(usersAtom)
if (Result.isSuccess(result)) {
return <List items={result.value} />
}
return <Loading />
}
Key Methods on AtomRuntime:
runtime.atom(effect)— Create Result atom with service accessruntime.fn<Arg>()((arg, ctx) => effect)— Create operation atomruntime.pull(stream)— Create pull-based stream atom
TMNL Example (src/lib/data-manager/v1/atoms/index.ts:142):
export const runtimeAtom = Atom.runtime(
Layer.mergeAll(
IdGenerator.Default,
SearchKernel.Default,
DataManager.Default
)
)
Pattern 5: runtimeAtom.fn — OPERATION ATOMS
When to use:
- Mutations (create, update, delete)
- Actions (search, submit, clear)
- Operations that update other atoms
Signature:
runtime.fn<Arg>()((arg, ctx) => Effect.Effect<A, E>): AtomResultFn<Arg, A, E>
Full Example:
import { Atom } from '@effect-atom/atom-react'
import { Effect } from 'effect'
import { useSetAtom, useAtomValue } from '@effect-rx/rx-react'
// State atoms
const resultsAtom = Atom.make<string[]>([])
const statusAtom = Atom.make<'idle' | 'loading' | 'complete'>('idle')
// Operation atom
const searchOp = runtimeAtom.fn<string>()((query, ctx) =>
Effect.gen(function* () {
const api = yield* ApiClient
// Update state
ctx.set(statusAtom, 'loading')
ctx.set(resultsAtom, [])
// Perform search
const results = yield* api.search(query)
// Update state
ctx.set(resultsAtom, results)
ctx.set(statusAtom, 'complete')
return results
})
)
// React component
function SearchBox() {
const doSearch = useSetAtom(searchOp)
const results = useAtomValue(resultsAtom)
const status = useAtomValue(statusAtom)
return (
<div>
<input onChange={(e) => doSearch(e.target.value)} />
{status === 'loading' && <Spinner />}
<List items={results} />
</div>
)
}
Context API (ctx):
ctx.get(atom)— Read atom valuectx.set(atom, value)— Write atom valuectx.setSelf(value)— Write to operation's result atom
Key Features:
- Writable — Trigger with
useSetAtom(op)(arg) - Service access —
yield* ServiceNamein Effect - State updates —
ctx.set(atom, value)directly
TMNL Example (src/lib/data-manager/v1/atoms/index.ts:166):
export const doSearch = runtimeAtom.fn<{ query: string; limit: number }>()(
({ query, limit }, ctx) =>
Effect.gen(function* () {
const dm = yield* DataManager
ctx.set(statusAtom, 'streaming')
ctx.set(resultsAtom, [])
const stream = yield* dm.searchStream(query, limit)
yield* Stream.runForEach(stream, (result) =>
Effect.sync(() => {
const prev = ctx.get(resultsAtom)
ctx.set(resultsAtom, [...prev, result])
})
)
ctx.set(statusAtom, 'complete')
})
)
Pattern 6: Atom.family — KEYED ATOMS
When to use:
- Dynamic atom creation (layer-123, user-456)
- Stable references for same key
- Per-entity atoms
Signature:
Atom.family<K, A>((key: K) => Atom.Atom<A>): (key: K) => Atom.Atom<A>
Full Example:
import { Atom } from '@effect-atom/atom-react'
import { Effect } from 'effect'
// Family of user atoms
const userAtom = Atom.family((id: string) =>
Atom.make(
Effect.gen(function* () {
const api = yield* ApiClient
return yield* api.fetchUser(id)
})
)
)
// Same ID returns same atom instance
const alice1 = userAtom('alice')
const alice2 = userAtom('alice')
console.log(alice1 === alice2) // true
// React component
function UserCard({ userId }: { userId: string }) {
const result = useAtomValue(userAtom(userId))
if (Result.isSuccess(result)) {
return <div>{result.value.name}</div>
}
return <Loading />
}
// Render multiple users
<div>
<UserCard userId="alice" />
<UserCard userId="bob" />
<UserCard userId="charlie" />
</div>
Key Features:
- Stable references — Same key = same atom
- Weak references — Garbage collected when unused
- Type-safe keys — Can use objects, not just strings
TMNL Example (src/components/testbed/EffectAtomTestbed.tsx:1026):
const itemAtom = Atom.family((id: string) =>
Atom.make(
Effect.gen(function* () {
yield* Effect.sleep('200 millis')
return { id, name: `Item ${id}`, timestamp: Date.now() }
})
)
)
Pattern 7: Materialized View Pattern
When to use:
- Separate state (readonly views) from operations (write-only actions)
- Service methods update state via
ctx.set - Clean separation of concerns
Structure:
atoms/
├── state/
│ ├── resultsAtom ← Primitive, readonly from components
│ ├── statusAtom ← Primitive, readonly from components
│ └── statsAtom ← Derived from above
└── operations/
├── searchOp ← runtime.fn, writes to state
└── clearOp ← runtime.fn, writes to state
Full Example:
import { Atom } from '@effect-atom/atom-react'
import { Effect } from 'effect'
// ====== STATE (Readonly Views) ======
export const resultsAtom = Atom.make<SearchResult[]>([])
export const statusAtom = Atom.make<'idle' | 'loading' | 'complete'>('idle')
export const statsAtom = Atom.make((get) => {
const results = get(resultsAtom)
return {
count: results.length,
hasResults: results.length > 0
}
})
// ====== OPERATIONS (Write-Only Actions) ======
export const searchOp = runtimeAtom.fn<string>()((query, ctx) =>
Effect.gen(function* () {
const api = yield* ApiClient
ctx.set(statusAtom, 'loading')
ctx.set(resultsAtom, [])
const results = yield* api.search(query)
ctx.set(resultsAtom, results)
ctx.set(statusAtom, 'complete')
})
)
export const clearOp = runtimeAtom.fn<void>()((_, ctx) =>
Effect.sync(() => {
ctx.set(resultsAtom, [])
ctx.set(statusAtom, 'idle')
})
)
// ====== REACT COMPONENT ======
function SearchUI() {
const results = useAtomValue(resultsAtom)
const status = useAtomValue(statusAtom)
const stats = useAtomValue(statsAtom)
const doSearch = useSetAtom(searchOp)
const clear = useSetAtom(clearOp)
return (
<div>
<input onChange={(e) => doSearch(e.target.value)} />
<button onClick={() => clear()}>Clear</button>
{status === 'loading' && <Spinner />}
<div>Found {stats.count} results</div>
<List items={results} />
</div>
)
}
Key Pattern:
- State atoms — Define at module level, readonly from components
- Operation atoms — Define with
runtime.fn, write to state atoms viactx.set - Components — Subscribe to state, trigger operations
TMNL Example (src/lib/data-manager/v1/atoms/index.ts:34):
// State atoms
export const resultsAtom = Atom.make<SearchResult[]>([])
export const statusAtom = Atom.make<StreamStatus>('idle')
// Operations
export const doSearch = runtimeAtom.fn<{ query: string; limit: number }>()(...)
export const clearResults = runtimeAtom.fn<void>()(...)
Pattern 8: Parallel Atom Setup (Effect.all)
When to use:
- Setting multiple atoms from within an Effect
- Initializing UI state before opening drawer/modal
- Resetting multiple atoms at once
Anti-pattern (sequential):
// DON'T — Sequential updates
yield* Effect.sync(() => registry.set(modeAtom, 'command'))
yield* Effect.sync(() => registry.set(promptAtom, 'M-x '))
yield* Effect.sync(() => registry.set(inputAtom, ''))
yield* Effect.sync(() => registry.set(selectedIndexAtom, 0))
Pattern (parallel):
// DO — Parallel updates with Effect.all
yield* Effect.all([
Effect.sync(() => registry.set(modeAtom, 'command')),
Effect.sync(() => registry.set(promptAtom, 'M-x ')),
Effect.sync(() => registry.set(inputAtom, '')),
Effect.sync(() => registry.set(selectedIndexAtom, 0)),
], { concurrency: 'unbounded' })
Key Features:
- Parallel execution — All updates happen at once
- Effect.sync — Wrap synchronous registry operations
- concurrency: 'unbounded' — No limit on parallelism
TMNL Example (src/lib/minibuffer/hooks/useMinibuffer.tsx:124):
const openCommandMode = runtimeAtom.fn<void>()((_, ctx) =>
Effect.gen(function* () {
yield* Effect.all([
Effect.sync(() => ctx.set(modeAtom, 'command')),
Effect.sync(() => ctx.set(promptAtom, 'M-x ')),
Effect.sync(() => ctx.set(inputAtom, '')),
], { concurrency: 'unbounded' })
})
)
Pattern 9: Atom Lifecycle
keepAlive — Prevent disposal:
const runtimeAtom = Atom.keepAlive(Atom.runtime(ServiceLayer))
setIdleTTL — Dispose after idle:
const cachedAtom = Atom.setIdleTTL(Atom.make(expensiveFetch), '5 minutes')
autoDispose — Default behavior (dispose when no subscribers).
Examples
Example 1: Counter (Primitive Atom)
import { Atom } from '@effect-atom/atom-react'
import { useAtomValue, useSetAtom } from '@effect-rx/rx-react'
const countAtom = Atom.make(0)
function Counter() {
const count = useAtomValue(countAtom)
const setCount = useSetAtom(countAtom)
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
)
}
Example 2: Todo List (Operation Atoms)
import { Atom } from '@effect-atom/atom-react'
import { Effect } from 'effect'
type Todo = { id: string; text: string; done: boolean }
const todosAtom = Atom.make<Todo[]>([])
const addTodoOp = runtimeAtom.fn<string>()((text, ctx) =>
Effect.sync(() => {
const todos = ctx.get(todosAtom)
ctx.set(todosAtom, [...todos, { id: nanoid(), text, done: false }])
})
)
const toggleTodoOp = runtimeAtom.fn<string>()((id, ctx) =>
Effect.sync(() => {
const todos = ctx.get(todosAtom)
ctx.set(todosAtom, todos.map(t => t.id === id ? { ...t, done: !t.done } : t))
})
)
function TodoList() {
const todos = useAtomValue(todosAtom)
const addTodo = useSetAtom(addTodoOp)
const toggleTodo = useSetAtom(toggleTodoOp)
return (
<div>
<input onKeyDown={(e) => {
if (e.key === 'Enter') addTodo(e.currentTarget.value)
}} />
<ul>
{todos.map(todo => (
<li key={todo.id} onClick={() => toggleTodo(todo.id)}>
{todo.done ? '✅' : '⬜'} {todo.text}
</li>
))}
</ul>
</div>
)
}
Anti-Patterns
1. Effect.Ref in React-consumed Services (BANNED)
// WRONG — Ref + Atom bridging complexity
const service = Effect.gen(function* () {
const stateRef = yield* Ref.make(initial)
// Now need: polling, SubscriptionRef, streams-to-consume-streams
})
// CORRECT — Atom-as-State
const stateAtom = Atom.make(initial)
const service = {
update: (value) => Effect.sync(() => Atom.set(stateAtom, value))
}
2. Atoms Inside Components
// WRONG — Creates new atom every render
function MyComponent() {
const atom = Atom.make(0) // ❌ New atom every render!
return <div>{useAtomValue(atom)}</div>
}
// CORRECT — Module-level atom
const countAtom = Atom.make(0)
function MyComponent() {
return <div>{useAtomValue(countAtom)}</div>
}
3. useState for Cross-Component State
// WRONG — useState for shared state
const [results, setResults] = useState([])
const [status, setStatus] = useState('idle')
// CORRECT — Atoms
const resultsAtom = Atom.make([])
const statusAtom = Atom.make('idle')
Quick Reference
| Pattern | Constructor | Use Case |
|---------|-------------|----------|
| Primitive atom | Atom.make(value) | Simple mutable state |
| Derived atom | Atom.make((get) => ...) | Computed from other atoms |
| Effect atom | Atom.make(Effect) | Async data with Result |
| Runtime | Atom.runtime(Layer) | Service composition |
| Operation | runtime.fn<Arg>() | Mutations/actions |
| Family | Atom.family((key) => ...) | Keyed atoms |
Related Skills
- effect-service-authoring — Create services for use with runtimeAtom
- effect-stream-patterns — Use streams with Atom.make(Stream)
- effect-testing-patterns — Test atom-based code
Du fichier au premier essai
Le téléchargement contient exactement le contenu affiché sur cette fiche. Cette copie peut différer de la dernière version du dépôt source.
Consulter la source et ses fichiers annexesCe téléchargement contient uniquement SKILL.md. Les scripts, références, modèles et dépendances éventuels ne sont pas inclus. Récupérez les fichiers nécessaires depuis la source en conservant leur arborescence avant de poursuivre.
1. Télécharger le fichier
Télécharger SKILL.mdDepuis la racine d’un projet de test, enregistrez le fichier sous .skill-downloads/effect-atom-integration-ms71b4bz/SKILL.md, ou utilisez la commande suivante. Ce dossier sert à examiner la skill avant son installation.
Commande pour macOS/Linux ou WSL : un shell POSIX et curl sont nécessaires. Sous Windows sans WSL, utilisez le bouton de téléchargement et créez le dossier manuellement.
mkdir -p '.skill-downloads/effect-atom-integration-ms71b4bz' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/effect-atom-integration-ms71b4bz/download' --output '.skill-downloads/effect-atom-integration-ms71b4bz/SKILL.md.part' && mv '.skill-downloads/effect-atom-integration-ms71b4bz/SKILL.md.part' '.skill-downloads/effect-atom-integration-ms71b4bz/SKILL.md'2. Vérifier les prérequis
Lisez SKILL.md avant de l’utiliser. Si le fichier cite des scripts ou services externes, examinez-les et préparez les accès nécessaires dans votre environnement de test.
Extrait original : Quick Reference
| Pattern | Constructor | Use Case |
|---|---|---|
| Primitive atom | Atom.make(value) | Simple mutable state |
| Derived atom | Atom.make((get) => ...) | Computed from other atoms |
| Effect atom | Atom.make(Effect) | Async data with Result |
| Runtime | Atom.runtime(Layer) | Service composition |
| Operation | runtime.fn<Arg>() | Mutations/actions |
| Family | Atom.family((key) => ...) | Keyed atoms |
Les plateformes de la fiche sont des indications du catalogue. Les chemins ci-dessous suivent la documentation des outils ; ils ne prouvent pas que cette skill y a été exécutée. Aucune version minimale de ces outils n’est attestée pour cette fiche.
3. Charger la skill
Après vérification, copiez le dossier complet dans le projet avec l’une des commandes ci-dessous, puis ouvrez une nouvelle session de l’outil. La commande s’arrête si un dossier du même nom existe déjà : comparez les fichiers avant de le remplacer.
Claude Code
test -f '.skill-downloads/effect-atom-integration-ms71b4bz/SKILL.md' && test -s '.skill-downloads/effect-atom-integration-ms71b4bz/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/effect-atom-integration' && cp -R '.skill-downloads/effect-atom-integration-ms71b4bz' '.claude/skills/effect-atom-integration'OpenSkills
OpenSkills doit déjà être installé. La procédure locale install/read est contrôlée avec OpenSkills 1.5.0, qui exige Node.js ≥ 20.6.0. Aucun slug du catalogue n’est résolu automatiquement.
Installation officielle d’OpenSkillsopenskills install './.skill-downloads/effect-atom-integration-ms71b4bz'openskills read 'effect-atom-integration-ms71b4bz'La lecture doit afficher le contenu du fichier installé et son dossier de base. Elle ne lance ni la skill ni ses dépendances.
Pour un agent qui lit AGENTS.md, synchronisez ensuite l’index. Cette commande modifie AGENTS.md : relisez le diff avant de l’utiliser.
openskills syncMode manuel ou autre outil : joignez SKILL.md à une conversation, ou ouvrez-le dans un agent capable de lire les fichiers. Ajoutez les ressources annexes nécessaires. Il n’existe pas de dossier universel reconnu par tous les outils.
4. Faire un premier essai
Utilisez une entrée courte et fictive : un endpoint d’API, un petit document ou un brief d’interface. Dans une nouvelle conversation, joignez le fichier ou donnez son chemin à l’agent, puis adaptez cette demande :
Lis .skill-downloads/effect-atom-integration-ms71b4bz/SKILL.md et applique ses instructions à cet exemple : [décrire une entrée de test]. Indique les fichiers, dépendances ou accès qui manquent. Produis le résultat demandé par la skill sans inventer de données ni exécuter de script non examiné.Résultat attendu : une sortie correspondant aux instructions de la skill, ou une liste précise des prérequis manquants. Une simple confirmation de lecture ne valide pas le premier usage. Si une ressource externe est indisponible, ce parcours reste à tester.
Bonnes pratiques React Hook Form
Developpement
Maîtrisez React Hook Form : évitez les anti-patterns, gérez les abonnements, et traitez correctement reset, dirty state et entrées contrôlées.
Migration Emotion vers Mantine
Developpement
Migrer les styled-components Emotion vers des composants Mantine avec style props et modules CSS. Pour convertir .styled.tsx ou supprimer les imports @emotion.
Détecteur de dérive de périmètre
Developpement
Analyse les diffs git par rapport à une intention pour détecter la dérive de périmètre, fichiers non liés et PR trop larges, puis suggère de garder, diviser ou justifier.