opencode-skills-antigravity 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,350 @@
1
+ ---
2
+ name: pydantic-ai
3
+ description: "Build production-ready AI agents with PydanticAI — type-safe tool use, structured outputs, dependency injection, and multi-model support."
4
+ category: ai-agents
5
+ risk: safe
6
+ source: community
7
+ date_added: "2026-03-18"
8
+ author: suhaibjanjua
9
+ tags: [pydantic-ai, ai-agents, llm, openai, anthropic, gemini, tool-use, structured-output, python]
10
+ tools: [claude, cursor, gemini]
11
+ ---
12
+
13
+ # PydanticAI — Typed AI Agents in Python
14
+
15
+ ## Overview
16
+
17
+ PydanticAI is a Python agent framework from the Pydantic team that brings the same type-safety and validation guarantees as Pydantic to LLM-based applications. It supports structured outputs (validated with Pydantic models), dependency injection for testability, streamed responses, multi-turn conversations, and tool use — across OpenAI, Anthropic, Google Gemini, Groq, Mistral, and Ollama. Use this skill when building production AI agents, chatbots, or LLM pipelines where correctness and testability matter.
18
+
19
+ ## When to Use This Skill
20
+
21
+ - Use when building Python AI agents that call tools and return structured data
22
+ - Use when you need validated, typed LLM outputs (not raw strings)
23
+ - Use when you want to write unit tests for agent logic without hitting a real LLM
24
+ - Use when switching between LLM providers without rewriting agent code
25
+ - Use when the user asks about `Agent`, `@agent.tool`, `RunContext`, `ModelRetry`, or `result_type`
26
+
27
+ ## How It Works
28
+
29
+ ### Step 1: Installation
30
+
31
+ ```bash
32
+ pip install pydantic-ai
33
+
34
+ # Install extras for specific providers
35
+ pip install 'pydantic-ai[openai]' # OpenAI / Azure OpenAI
36
+ pip install 'pydantic-ai[anthropic]' # Anthropic Claude
37
+ pip install 'pydantic-ai[gemini]' # Google Gemini
38
+ pip install 'pydantic-ai[groq]' # Groq
39
+ pip install 'pydantic-ai[vertexai]' # Google Vertex AI
40
+ ```
41
+
42
+ ### Step 2: A Minimal Agent
43
+
44
+ ```python
45
+ from pydantic_ai import Agent
46
+
47
+ # Simple agent — returns a plain string
48
+ agent = Agent(
49
+ 'anthropic:claude-sonnet-4-6',
50
+ system_prompt='You are a helpful assistant. Be concise.',
51
+ )
52
+
53
+ result = agent.run_sync('What is the capital of Japan?')
54
+ print(result.data) # "Tokyo"
55
+ print(result.usage()) # Usage(requests=1, request_tokens=..., response_tokens=...)
56
+ ```
57
+
58
+ ### Step 3: Structured Output with Pydantic Models
59
+
60
+ ```python
61
+ from pydantic import BaseModel
62
+ from pydantic_ai import Agent
63
+
64
+ class MovieReview(BaseModel):
65
+ title: str
66
+ year: int
67
+ rating: float # 0.0 to 10.0
68
+ summary: str
69
+ recommended: bool
70
+
71
+ agent = Agent(
72
+ 'openai:gpt-4o',
73
+ result_type=MovieReview,
74
+ system_prompt='You are a film critic. Return structured reviews.',
75
+ )
76
+
77
+ result = agent.run_sync('Review Inception (2010)')
78
+ review = result.data # Fully typed MovieReview instance
79
+ print(f"{review.title} ({review.year}): {review.rating}/10")
80
+ print(f"Recommended: {review.recommended}")
81
+ ```
82
+
83
+ ### Step 4: Tool Use
84
+
85
+ Register tools with `@agent.tool` — the LLM can call them during a run:
86
+
87
+ ```python
88
+ from pydantic_ai import Agent, RunContext
89
+ from pydantic import BaseModel
90
+ import httpx
91
+
92
+ class WeatherReport(BaseModel):
93
+ city: str
94
+ temperature_c: float
95
+ condition: str
96
+
97
+ weather_agent = Agent(
98
+ 'anthropic:claude-sonnet-4-6',
99
+ result_type=WeatherReport,
100
+ system_prompt='Get current weather for the requested city.',
101
+ )
102
+
103
+ @weather_agent.tool
104
+ async def get_temperature(ctx: RunContext, city: str) -> dict:
105
+ """Fetch the current temperature for a city from the weather API."""
106
+ async with httpx.AsyncClient() as client:
107
+ r = await client.get(f'https://wttr.in/{city}?format=j1')
108
+ data = r.json()
109
+ return {
110
+ 'temp_c': float(data['current_condition'][0]['temp_C']),
111
+ 'description': data['current_condition'][0]['weatherDesc'][0]['value'],
112
+ }
113
+
114
+ import asyncio
115
+ result = asyncio.run(weather_agent.run('What is the weather in Tokyo?'))
116
+ print(result.data)
117
+ ```
118
+
119
+ ### Step 5: Dependency Injection
120
+
121
+ Inject services (database, HTTP clients, config) into agents for testability:
122
+
123
+ ```python
124
+ from dataclasses import dataclass
125
+ from pydantic_ai import Agent, RunContext
126
+ from pydantic import BaseModel
127
+
128
+ @dataclass
129
+ class Deps:
130
+ db: Database
131
+ user_id: str
132
+
133
+ class SupportResponse(BaseModel):
134
+ message: str
135
+ escalate: bool
136
+
137
+ support_agent = Agent(
138
+ 'openai:gpt-4o-mini',
139
+ deps_type=Deps,
140
+ result_type=SupportResponse,
141
+ system_prompt='You are a support agent. Use the tools to help customers.',
142
+ )
143
+
144
+ @support_agent.tool
145
+ async def get_order_history(ctx: RunContext[Deps]) -> list[dict]:
146
+ """Fetch recent orders for the current user."""
147
+ return await ctx.deps.db.get_orders(ctx.deps.user_id, limit=5)
148
+
149
+ @support_agent.tool
150
+ async def create_refund(ctx: RunContext[Deps], order_id: str, reason: str) -> dict:
151
+ """Initiate a refund for a specific order."""
152
+ return await ctx.deps.db.create_refund(order_id, reason, ctx.deps.user_id)
153
+
154
+ # Usage
155
+ async def handle_support(user_id: str, message: str):
156
+ deps = Deps(db=get_db(), user_id=user_id)
157
+ result = await support_agent.run(message, deps=deps)
158
+ return result.data
159
+ ```
160
+
161
+ ### Step 6: Testing with TestModel
162
+
163
+ Write unit tests without real LLM calls:
164
+
165
+ ```python
166
+ from pydantic_ai.models.test import TestModel
167
+
168
+ def test_support_agent_escalates():
169
+ with support_agent.override(model=TestModel()):
170
+ # TestModel returns a minimal valid response matching result_type
171
+ result = support_agent.run_sync(
172
+ 'I want to cancel my account',
173
+ deps=Deps(db=FakeDb(), user_id='user-123'),
174
+ )
175
+ # Test the structure, not the LLM's exact words
176
+ assert isinstance(result.data, SupportResponse)
177
+ assert isinstance(result.data.escalate, bool)
178
+ ```
179
+
180
+ **FunctionModel** for deterministic test responses:
181
+
182
+ ```python
183
+ from pydantic_ai.models.function import FunctionModel, ModelContext
184
+
185
+ def my_model(messages, info):
186
+ return ModelResponse(parts=[TextPart('Always this response')])
187
+
188
+ with agent.override(model=FunctionModel(my_model)):
189
+ result = agent.run_sync('anything')
190
+ ```
191
+
192
+ ### Step 7: Streaming Responses
193
+
194
+ ```python
195
+ import asyncio
196
+ from pydantic_ai import Agent
197
+
198
+ agent = Agent('anthropic:claude-sonnet-4-6')
199
+
200
+ async def stream_response():
201
+ async with agent.run_stream('Write a haiku about Python') as result:
202
+ async for chunk in result.stream_text():
203
+ print(chunk, end='', flush=True)
204
+ print() # newline
205
+ print(f"Total tokens: {result.usage()}")
206
+
207
+ asyncio.run(stream_response())
208
+ ```
209
+
210
+ ### Step 8: Multi-Turn Conversations
211
+
212
+ ```python
213
+ from pydantic_ai import Agent
214
+ from pydantic_ai.messages import ModelMessagesTypeAdapter
215
+
216
+ agent = Agent('openai:gpt-4o', system_prompt='You are a helpful assistant.')
217
+
218
+ # First turn
219
+ result1 = agent.run_sync('My name is Alice.')
220
+ history = result1.all_messages()
221
+
222
+ # Second turn — passes conversation history
223
+ result2 = agent.run_sync('What is my name?', message_history=history)
224
+ print(result2.data) # "Your name is Alice."
225
+ ```
226
+
227
+ ## Examples
228
+
229
+ ### Example 1: Code Review Agent
230
+
231
+ ```python
232
+ from pydantic import BaseModel, Field
233
+ from pydantic_ai import Agent
234
+ from typing import Literal
235
+
236
+ class CodeReview(BaseModel):
237
+ quality: Literal['excellent', 'good', 'needs_work', 'poor']
238
+ issues: list[str] = Field(default_factory=list)
239
+ suggestions: list[str] = Field(default_factory=list)
240
+ approved: bool
241
+
242
+ code_review_agent = Agent(
243
+ 'anthropic:claude-sonnet-4-6',
244
+ result_type=CodeReview,
245
+ system_prompt="""
246
+ You are a senior engineer performing code review.
247
+ Evaluate code quality, identify issues, and provide actionable suggestions.
248
+ Set approved=True only for good or excellent quality code with no security issues.
249
+ """,
250
+ )
251
+
252
+ def review_code(diff: str) -> CodeReview:
253
+ result = code_review_agent.run_sync(f"Review this code:\n\n{diff}")
254
+ return result.data
255
+ ```
256
+
257
+ ### Example 2: Agent with Retry Logic
258
+
259
+ ```python
260
+ from pydantic_ai import Agent, ModelRetry
261
+ from pydantic import BaseModel, field_validator
262
+
263
+ class StrictJson(BaseModel):
264
+ value: int
265
+
266
+ @field_validator('value')
267
+ def must_be_positive(cls, v):
268
+ if v <= 0:
269
+ raise ValueError('value must be positive')
270
+ return v
271
+
272
+ agent = Agent('openai:gpt-4o-mini', result_type=StrictJson)
273
+
274
+ @agent.result_validator
275
+ async def validate_result(ctx, result: StrictJson) -> StrictJson:
276
+ if result.value > 1000:
277
+ raise ModelRetry('Value must be under 1000. Try again with a smaller number.')
278
+ return result
279
+ ```
280
+
281
+ ### Example 3: Multi-Agent Pipeline
282
+
283
+ ```python
284
+ from pydantic_ai import Agent
285
+ from pydantic import BaseModel
286
+
287
+ class ResearchSummary(BaseModel):
288
+ key_points: list[str]
289
+ conclusion: str
290
+
291
+ class BlogPost(BaseModel):
292
+ title: str
293
+ body: str
294
+ meta_description: str
295
+
296
+ researcher = Agent('openai:gpt-4o', result_type=ResearchSummary)
297
+ writer = Agent('anthropic:claude-sonnet-4-6', result_type=BlogPost)
298
+
299
+ async def research_and_write(topic: str) -> BlogPost:
300
+ # Stage 1: research
301
+ research = await researcher.run(f'Research the topic: {topic}')
302
+
303
+ # Stage 2: write based on research
304
+ post = await writer.run(
305
+ f'Write a blog post about: {topic}\n\nResearch:\n' +
306
+ '\n'.join(f'- {p}' for p in research.data.key_points) +
307
+ f'\n\nConclusion: {research.data.conclusion}'
308
+ )
309
+ return post.data
310
+ ```
311
+
312
+ ## Best Practices
313
+
314
+ - ✅ Always define `result_type` with a Pydantic model — avoid returning raw strings in production
315
+ - ✅ Use `deps_type` with a dataclass for dependency injection — makes agents testable
316
+ - ✅ Use `TestModel` in unit tests — never hit a real LLM in CI
317
+ - ✅ Add `@agent.result_validator` for business-logic checks beyond Pydantic validation
318
+ - ✅ Use `run_stream` for long outputs in user-facing applications to show progressive results
319
+ - ❌ Don't put secrets (API keys) in `Agent()` arguments — use environment variables
320
+ - ❌ Don't share a single `Agent` instance across async tasks if deps differ — create per-request instances or use `agent.run()` with per-call `deps`
321
+ - ❌ Don't catch `ValidationError` broadly — let PydanticAI retry with `ModelRetry` for recoverable LLM output errors
322
+
323
+ ## Security & Safety Notes
324
+
325
+ - Set API keys via environment variables (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, etc.) — never hardcode them.
326
+ - Validate all tool inputs before passing to external systems — use Pydantic models or manual checks.
327
+ - Tools that mutate data (write to DB, send emails, call payment APIs) should require explicit user confirmation before the agent invokes them in production.
328
+ - Log `result.all_messages()` for audit trails when agents perform consequential actions.
329
+ - Set `retries=` limits on `Agent()` to prevent runaway loops on persistent validation failures.
330
+
331
+ ## Common Pitfalls
332
+
333
+ - **Problem:** `ValidationError` on every LLM response — structured output never validates
334
+ **Solution:** Simplify `result_type` fields. Use `Optional` and `default` where appropriate. The model may struggle with overly strict schemas.
335
+
336
+ - **Problem:** Tool is never called by the LLM
337
+ **Solution:** Write a clear, specific docstring for the tool function — PydanticAI sends the docstring as the tool description to the LLM.
338
+
339
+ - **Problem:** `RunContext` dependency is `None` inside a tool
340
+ **Solution:** Pass `deps=` when calling `agent.run()` or `agent.run_sync()`. Dependencies are not set globally.
341
+
342
+ - **Problem:** `asyncio.run()` error when calling `agent.run()` inside FastAPI
343
+ **Solution:** Use `await agent.run()` directly in async FastAPI route handlers — don't wrap in `asyncio.run()`.
344
+
345
+ ## Related Skills
346
+
347
+ - `@langchain-architecture` — Alternative Python AI framework (more flexible, less type-safe)
348
+ - `@llm-application-dev-ai-assistant` — General LLM application development patterns
349
+ - `@fastapi-templates` — Serving PydanticAI agents via FastAPI endpoints
350
+ - `@agent-orchestration-multi-agent-optimize` — Orchestrating multiple PydanticAI agents
@@ -0,0 +1,286 @@
1
+ ---
2
+ name: sveltekit
3
+ description: "Build full-stack web applications with SvelteKit — file-based routing, SSR, SSG, API routes, and form actions in one framework."
4
+ category: frontend
5
+ risk: safe
6
+ source: community
7
+ date_added: "2026-03-18"
8
+ author: suhaibjanjua
9
+ tags: [svelte, sveltekit, fullstack, ssr, ssg, typescript]
10
+ tools: [claude, cursor, gemini]
11
+ ---
12
+
13
+ # SvelteKit Full-Stack Development
14
+
15
+ ## Overview
16
+
17
+ SvelteKit is the official full-stack framework built on top of Svelte. It provides file-based routing, server-side rendering (SSR), static site generation (SSG), API routes, and progressive form actions — all with Svelte's compile-time reactivity model that ships zero runtime overhead to the browser. Use this skill when building fast, modern web apps where both DX and performance matter.
18
+
19
+ ## When to Use This Skill
20
+
21
+ - Use when building a new full-stack web application with Svelte
22
+ - Use when you need SSR or SSG with fine-grained control per route
23
+ - Use when migrating a SPA to a framework with server capabilities
24
+ - Use when working on a project that needs file-based routing and collocated API endpoints
25
+ - Use when the user asks about `+page.svelte`, `+layout.svelte`, `load` functions, or form actions
26
+
27
+ ## How It Works
28
+
29
+ ### Step 1: Project Setup
30
+
31
+ ```bash
32
+ npm create svelte@latest my-app
33
+ cd my-app
34
+ npm install
35
+ npm run dev
36
+ ```
37
+
38
+ Choose **Skeleton project** + **TypeScript** + **ESLint/Prettier** when prompted.
39
+
40
+ Directory structure after scaffolding:
41
+
42
+ ```
43
+ src/
44
+ routes/
45
+ +page.svelte ← Root page component
46
+ +layout.svelte ← Root layout (wraps all pages)
47
+ +error.svelte ← Error boundary
48
+ lib/
49
+ server/ ← Server-only code (never bundled to client)
50
+ components/ ← Shared components
51
+ app.html ← HTML shell
52
+ static/ ← Static assets
53
+ ```
54
+
55
+ ### Step 2: File-Based Routing
56
+
57
+ Every `+page.svelte` file in `src/routes/` maps directly to a URL:
58
+
59
+ ```
60
+ src/routes/+page.svelte → /
61
+ src/routes/about/+page.svelte → /about
62
+ src/routes/blog/[slug]/+page.svelte → /blog/:slug
63
+ src/routes/shop/[...path]/+page.svelte → /shop/* (catch-all)
64
+ ```
65
+
66
+ **Route groups** (no URL segment): wrap in `(group)/` folder.
67
+ **Private routes** (not accessible as URLs): prefix with `_` or `(group)`.
68
+
69
+ ### Step 3: Loading Data with `load` Functions
70
+
71
+ Use a `+page.ts` (universal) or `+page.server.ts` (server-only) file alongside the page:
72
+
73
+ ```typescript
74
+ // src/routes/blog/[slug]/+page.server.ts
75
+ import { error } from '@sveltejs/kit';
76
+ import type { PageServerLoad } from './$types';
77
+
78
+ export const load: PageServerLoad = async ({ params, fetch }) => {
79
+ const post = await fetch(`/api/posts/${params.slug}`).then(r => r.json());
80
+
81
+ if (!post) {
82
+ error(404, 'Post not found');
83
+ }
84
+
85
+ return { post };
86
+ };
87
+ ```
88
+
89
+ ```svelte
90
+ <!-- src/routes/blog/[slug]/+page.svelte -->
91
+ <script lang="ts">
92
+ import type { PageData } from './$types';
93
+ export let data: PageData;
94
+ </script>
95
+
96
+ <h1>{data.post.title}</h1>
97
+ <article>{@html data.post.content}</article>
98
+ ```
99
+
100
+ ### Step 4: API Routes (Server Endpoints)
101
+
102
+ Create `+server.ts` files for REST-style endpoints:
103
+
104
+ ```typescript
105
+ // src/routes/api/posts/+server.ts
106
+ import { json } from '@sveltejs/kit';
107
+ import type { RequestHandler } from './$types';
108
+
109
+ export const GET: RequestHandler = async ({ url }) => {
110
+ const limit = Number(url.searchParams.get('limit') ?? 10);
111
+ const posts = await db.post.findMany({ take: limit });
112
+ return json(posts);
113
+ };
114
+
115
+ export const POST: RequestHandler = async ({ request }) => {
116
+ const body = await request.json();
117
+ const post = await db.post.create({ data: body });
118
+ return json(post, { status: 201 });
119
+ };
120
+ ```
121
+
122
+ ### Step 5: Form Actions
123
+
124
+ Form actions are the SvelteKit-native way to handle mutations — no client-side fetch required:
125
+
126
+ ```typescript
127
+ // src/routes/contact/+page.server.ts
128
+ import { fail, redirect } from '@sveltejs/kit';
129
+ import type { Actions } from './$types';
130
+
131
+ export const actions: Actions = {
132
+ default: async ({ request }) => {
133
+ const data = await request.formData();
134
+ const email = data.get('email');
135
+
136
+ if (!email) {
137
+ return fail(400, { email, missing: true });
138
+ }
139
+
140
+ await sendEmail(String(email));
141
+ redirect(303, '/thank-you');
142
+ }
143
+ };
144
+ ```
145
+
146
+ ```svelte
147
+ <!-- src/routes/contact/+page.svelte -->
148
+ <script lang="ts">
149
+ import { enhance } from '$app/forms';
150
+ import type { ActionData } from './$types';
151
+ export let form: ActionData;
152
+ </script>
153
+
154
+ <form method="POST" use:enhance>
155
+ <input name="email" type="email" />
156
+ {#if form?.missing}<p class="error">Email is required</p>{/if}
157
+ <button type="submit">Subscribe</button>
158
+ </form>
159
+ ```
160
+
161
+ ### Step 6: Layouts and Nested Routes
162
+
163
+ ```svelte
164
+ <!-- src/routes/+layout.svelte -->
165
+ <script lang="ts">
166
+ import type { LayoutData } from './$types';
167
+ export let data: LayoutData;
168
+ </script>
169
+
170
+ <nav>
171
+ <a href="/">Home</a>
172
+ <a href="/blog">Blog</a>
173
+ {#if data.user}
174
+ <a href="/dashboard">Dashboard</a>
175
+ {/if}
176
+ </nav>
177
+
178
+ <slot /> <!-- child page renders here -->
179
+ ```
180
+
181
+ ```typescript
182
+ // src/routes/+layout.server.ts
183
+ import type { LayoutServerLoad } from './$types';
184
+
185
+ export const load: LayoutServerLoad = async ({ locals }) => {
186
+ return { user: locals.user ?? null };
187
+ };
188
+ ```
189
+
190
+ ### Step 7: Rendering Modes
191
+
192
+ Control per-route rendering with page options:
193
+
194
+ ```typescript
195
+ // src/routes/docs/+page.ts
196
+ export const prerender = true; // Static — generated at build time
197
+ export const ssr = true; // Default — rendered on server per request
198
+ export const csr = false; // Disable client-side hydration entirely
199
+ ```
200
+
201
+ ## Examples
202
+
203
+ ### Example 1: Protected Dashboard Route
204
+
205
+ ```typescript
206
+ // src/routes/dashboard/+layout.server.ts
207
+ import { redirect } from '@sveltejs/kit';
208
+ import type { LayoutServerLoad } from './$types';
209
+
210
+ export const load: LayoutServerLoad = async ({ locals }) => {
211
+ if (!locals.user) {
212
+ redirect(303, '/login');
213
+ }
214
+ return { user: locals.user };
215
+ };
216
+ ```
217
+
218
+ ### Example 2: Hooks — Session Middleware
219
+
220
+ ```typescript
221
+ // src/hooks.server.ts
222
+ import type { Handle } from '@sveltejs/kit';
223
+ import { verifyToken } from '$lib/server/auth';
224
+
225
+ export const handle: Handle = async ({ event, resolve }) => {
226
+ const token = event.cookies.get('session');
227
+ if (token) {
228
+ event.locals.user = await verifyToken(token);
229
+ }
230
+ return resolve(event);
231
+ };
232
+ ```
233
+
234
+ ### Example 3: Preloading and Invalidation
235
+
236
+ ```svelte
237
+ <script lang="ts">
238
+ import { invalidateAll } from '$app/navigation';
239
+
240
+ async function refresh() {
241
+ await invalidateAll(); // re-runs all load functions on the page
242
+ }
243
+ </script>
244
+
245
+ <button on:click={refresh}>Refresh</button>
246
+ ```
247
+
248
+ ## Best Practices
249
+
250
+ - ✅ Use `+page.server.ts` for database/auth logic — it never ships to the client
251
+ - ✅ Use `$lib/server/` for shared server-only modules (DB client, auth helpers)
252
+ - ✅ Use form actions for mutations instead of client-side `fetch` — works without JS
253
+ - ✅ Type all `load` return values with generated `$types` (`PageData`, `LayoutData`)
254
+ - ✅ Use `event.locals` in hooks to pass server-side context to load functions
255
+ - ❌ Don't import server-only code in `+page.svelte` or `+layout.svelte` directly
256
+ - ❌ Don't store sensitive state in stores — use `locals` on the server
257
+ - ❌ Don't skip `use:enhance` on forms — without it, forms lose progressive enhancement
258
+
259
+ ## Security & Safety Notes
260
+
261
+ - All code in `+page.server.ts`, `+server.ts`, and `$lib/server/` runs exclusively on the server — safe for DB queries, secrets, and session validation.
262
+ - Always validate and sanitize form data before database writes.
263
+ - Use `error(403)` or `redirect(303)` from `@sveltejs/kit` rather than returning raw error objects.
264
+ - Set `httpOnly: true` and `secure: true` on all auth cookies.
265
+ - CSRF protection is built-in for form actions — do not disable `checkOrigin` in production.
266
+
267
+ ## Common Pitfalls
268
+
269
+ - **Problem:** `Cannot use import statement in a module` in `+page.server.ts`
270
+ **Solution:** The file must be `.ts` or `.js`, not `.svelte`. Server files and Svelte components are separate.
271
+
272
+ - **Problem:** Store value is `undefined` on first SSR render
273
+ **Solution:** Populate the store from the `load` function return value (`data` prop), not from client-side `onMount`.
274
+
275
+ - **Problem:** Form action does not redirect after submit
276
+ **Solution:** Use `redirect(303, '/path')` from `@sveltejs/kit`, not a plain `return`. 303 is required for POST redirects.
277
+
278
+ - **Problem:** `locals.user` is undefined inside a `+page.server.ts` load function
279
+ **Solution:** Set `event.locals.user` in `src/hooks.server.ts` before the `resolve()` call.
280
+
281
+ ## Related Skills
282
+
283
+ - `@nextjs-app-router-patterns` — When you prefer React over Svelte for SSR/SSG
284
+ - `@trpc-fullstack` — Add end-to-end type safety to SvelteKit API routes
285
+ - `@auth-implementation-patterns` — Authentication patterns usable with SvelteKit hooks
286
+ - `@tailwind-patterns` — Styling SvelteKit apps with Tailwind CSS
package/dist/index.js CHANGED
@@ -15,7 +15,18 @@ const AntigravityAutoUpdater = async (_ctx) => {
15
15
  fs.cpSync(bundledSkillsPath, skillsPath, { recursive: true, force: true });
16
16
  }
17
17
  catch (error) {
18
- // silently fail
18
+ setTimeout(async () => {
19
+ try {
20
+ const { exec } = await import("child_process");
21
+ const util = await import("util");
22
+ const execAsync = util.promisify(exec);
23
+ const fallbackPath = path.join(os.homedir(), ".config", "opencode", ".agents", "skills");
24
+ await execAsync(`npx --yes antigravity-awesome-skills --path "${fallbackPath}"`);
25
+ }
26
+ catch (e) {
27
+ // silently fail completely
28
+ }
29
+ }, 0);
19
30
  }
20
31
  return {};
21
32
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-skills-antigravity",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "OpenCode CLI plugin that automatically downloads and keeps Antigravity Awesome Skills up to date.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",