Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Core infrastructure providing backend connection configuration, storage client, and React app entry point.
.claude/skills/aiskillstore-extension-core-infrastructure/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 11% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 54% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 18% | 0% |
| case-04 | ✗→✓ | ▲ Improved | -7% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 63% | 0% |
Core infrastructure extension for Caffeine AI.
This component provides the foundational infrastructure for all projects: backend connection configuration, Internet Identity authentication hooks, and actor management utilities.
"@caffeineai/core-infrastructure": "^1.1.0"
"@caffeineai/object-storage": "^1.1.0"
"@icp-sdk/auth": "^7.1.0"
"@icp-sdk/core": "^5.3.0"@caffeineai/object-storage is a peer dependency of core-infrastructure. Every project must install it as a direct npm dependency (the build template includes both packages).
Core infrastructure is automatically included in every project. No manual integration steps are required.
The core-infrastructure frontend package (@caffeineai/core-infrastructure) is automatically included in every project.
Wrap the app with InternetIdentityProvider and QueryClientProvider:
typescriptimport { InternetIdentityProvider } from "@caffeineai/core-infrastructure"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import ReactDOM from "react-dom/client"; import App from "./App"; const queryClient = new QueryClient(); ReactDOM.createRoot(document.getElementById("root")!).render( <QueryClientProvider client={queryClient}> <InternetIdentityProvider> <App /> </InternetIdentityProvider> </QueryClientProvider>, );
useInternetIdentity() — Authentication HookProvides identity state, login, and logout for Internet Identity.
| Field | Type | Description | |---|---|---| | identity | Identity \| undefined | The user's identity (available after login or session restore) | | login | () => void | Opens the II popup. Fire-and-forget — do not await. | | clear | () => void | Logs out and clears stored identity. Fire-and-forget. | | isAuthenticated | boolean | true when user has a valid identity. Use this for UI gating. | | isInitializing | boolean | true while AuthClient is loading from IndexedDB | | isLoggingIn | boolean | true while the II popup is open | | isLoginSuccess | boolean | true only after interactive login (NOT after page reload restore) | | isLoginError | boolean | true if login or initialization failed | | loginError | Error \| undefined | The error object when isLoginError is true |
| Scenario | loginStatus | isAuthenticated | |---|---|---| | Page load, no stored session | "idle" | false | | Restoring stored session | "initializing" | false → true | | Stored session restored after reload | "idle" | true | | Interactive login in progress | "logging-in" | false | | Interactive login just completed | "success" | true | | Login popup failed / cancelled | "loginError" | false |
IMPORTANT: isLoginSuccess is only true after an interactive login via the popup — NOT when a stored identity is restored on page reload. Always use isAuthenticated for conditional rendering.
Gate authenticated UI on isAuthenticated:
typescriptconst { isAuthenticated } = useInternetIdentity(); {isAuthenticated ? <AuthenticatedApp /> : <LoginScreen />}
Disable the login button while initializing or logging in:
typescriptconst { login, isInitializing, isLoggingIn } = useInternetIdentity(); <button onClick={() => login()} disabled={isInitializing || isLoggingIn}> Sign in </button>
login() and clear() are fire-and-forget — the hook's state fields (isLoggingIn, isInitializing) track the async lifecycle. Do not wrap them in local useState / isPending logic.
useActor() — Backend Actor HookCreates and manages a typed backend actor instance. Automatically re-creates the actor when the user's identity changes (login/logout).
typescriptimport { useActor } from "@caffeineai/core-infrastructure"; import { createActor } from "declarations/backend"; function MyComponent() { const { actor, isFetching } = useActor(createActor); // actor is null while loading, then the typed backend actor if (!actor || isFetching) return <Loading />; // Call backend methods directly const data = await actor.myBackendMethod(); }
| Field | Type | Description | |---|---|---| | actor | T \| null | The typed backend actor, or null while loading | | isFetching | boolean | true while the actor is being created |
When the identity changes (login, logout, or session restore), the actor is automatically re-created with the new identity and all dependent queries are invalidated and refetched.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-22 | pass→fail | 10,921 | 9,311 | -15% | 1 | 1 | 0% | 2,062 | 2,970 | +44% | 0 | 0 | — |
case-01 | fail→pass | 16,363 | 11,355 | -31% | 1 | 1 | 0% | 2,224 | 2,474 | +11% | 0 | 0 | — |
case-02 | fail→pass | 18,511 | 18,827 | +2% | 1 | 1 | 0% | 2,991 | 4,592 | +54% | 0 | 0 | — |
case-03 | fail→pass | 21,161 | 26,733 | +26% | 1 | 1 | 0% | 3,307 | 3,915 | +18% | 0 | 0 | — |
case-04 | fail→pass | 18,757 | 11,067 | -41% | 1 | 1 | 0% | 2,545 | 2,379 | -7% | 0 | 0 | — |
case-05 | fail→pass | 13,706 | 12,396 | -10% | 1 | 1 | 0% | 1,638 | 2,676 | +63% | 0 | 0 | — |
case-06 | fail→pass | 16,583 | 11,196 | -32% | 1 | 1 | 0% | 2,174 | 2,276 | +5% | 0 | 0 | — |
case-07 | fail→pass | 10,506 | 8,164 | -22% | 1 | 1 | 0% | 1,133 | 1,720 | +52% | 0 | 0 | — |
case-08 | fail→pass | 11,881 | 7,688 | -35% | 1 | 1 | 0% | 2,001 | 1,661 | -17% | 0 | 0 | — |
case-09 | pass→pass | 13,232 | 8,685 | -34% | 1 | 1 | 0% | 2,179 | 1,907 | -12% | 0 | 0 | — |
case-10 | fail→pass | 21,030 | 6,973 | -67% | 1 | 1 | 0% | 2,743 | 2,237 | -18% | 0 | 0 | — |
case-11 | fail→pass | 13,659 | 8,770 | -36% | 1 | 1 | 0% | 1,531 | 1,858 | +21% | 0 | 0 | — |
case-12 | fail→pass | 13,173 | 2,162 | -84% | 1 | 1 | 0% | 1,499 | 1,506 | +0% | 0 | 0 | — |
case-13 | fail→pass | 11,031 | 4,298 | -61% | 1 | 1 | 0% | 1,824 | 1,916 | +5% | 0 | 0 | — |
case-14 | fail→pass | 15,169 | 6,754 | -55% | 1 | 1 | 0% | 2,884 | 2,456 | -15% | 0 | 0 | — |
case-15 | pass→pass | 10,831 | 7,800 | -28% | 1 | 1 | 0% | 963 | 1,687 | +75% | 0 | 0 | — |
case-16 | pass→pass | 8,471 | 8,839 | +4% | 1 | 1 | 0% | 1,416 | 1,811 | +28% | 0 | 0 | — |
case-17 | pass→pass | 13,213 | 6,895 | -48% | 1 | 1 | 0% | 1,309 | 1,461 | +12% | 0 | 0 | — |
case-18 | pass→pass | 10,478 | 2,581 | -75% | 1 | 1 | 0% | 1,551 | 1,548 | -0% | 0 | 0 | — |
case-19 | pass→pass | 13,935 | 13,933 | -0% | 1 | 1 | 0% | 2,500 | 2,953 | +18% | 0 | 0 | — |
case-20 | pass→pass | 19,505 | 14,653 | -25% | 1 | 1 | 0% | 2,706 | 3,311 | +22% | 0 | 0 | — |
case-21 | pass→fail | 13,849 | 15,118 | +9% | 1 | 1 | 0% | 2,448 | 3,858 | +58% | 0 | 0 | — |
case-23 | pass→pass | 13,575 | 5,876 | -57% | 1 | 1 | 0% | 1,490 | 1,520 | +2% | 0 | 0 | — |
case-24 | fail→pass | 10,836 | 6,557 | -39% | 1 | 1 | 0% | 1,899 | 1,449 | -24% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 24 cases were attempted. The headline lift of +50 percentage points is the difference between those two pass rates over the 24 comparable cases. 2 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.