複数のアプリやMCPホストからブランド画像・動画を生成、調整、書き出し、挿入する作業を支援します。ライブラリ選択や修正依頼も扱います。
- スライド用のブランド画像を作りたいとき
- 既存素材をフィードバックに合わせて直したいとき
- 動画素材を生成して書き出したいとき
エージェント対応アプリのデータをSQLに保存する設計や、Drizzle ORMでのモデル・読み書き、ファイル保存先の使い分けを案内するスキルです。
How to store application data in agent-native apps. All data lives in SQL. Use when adding data models, deciding where to store data, or reading/writing application data.
実行スコア 未検証
インストール方法を見るエージェント対応アプリで、データの種類に応じた保存先と読み書きの方法を案内します。構造化されたレコードや設定、画面状態はSQLに保存し、通常のアプリ機能ではDrizzle ORMを使ってスキーマやクエリを定義します。画像・動画・PDFなど大きなファイルはファイル/Blobストレージへ送り、SQLにはURLやIDなどの参照だけを残す方針です。スキーマ変更ではマイグレーションの作り方や後方互換性、既存データを壊さない追加方法も扱います。エージェント側のアクションやフロントエンドのReact Queryフックを通じたデータアクセス、単発の確認・修正に使うDB用コマンドの使い分けも説明します。
新しいデータモデルや機能を設計するとき、データをSQL・設定ストア・ファイルのどこへ置くか迷うときに役立ちます。開発環境から永続データベースを使う本番環境へ移す場合や、既存レコードを安全に調査・修正したい場合にも向いています。
開発ではPGlite、本番などで再起動後もデータを保持するには永続的なPostgreSQLとDATABASE_URLが必要です。大きなファイルにはuploadFile()やputPrivateBlob()などの設定済みストレージを使います。
この紹介文は、公開されている SKILL.md をもとに AI(OpenAI Codex)が作成しました。正確な仕様は下の原文を確認してください。
インストールする前に、エージェントに与えられる指示の中身を確認できます。
All application data lives in SQL (local PGlite, hosted Postgres in production). The agent and UI share the same database. SQL stores structured records, metadata, references, and searchable text — not large raw file payloads. Do not store durable app data in the filesystem unless the app is explicitly running a Local File Mode artifact flow described below.
Large binary or file-like payloads (images, video/audio, PDFs, ZIPs, screenshots, session replay chunks, thumbnails, generated assets, data: URLs, and base64 file bodies) must go through configured file/blob storage such as uploadFile() or putPrivateBlob(). Persist only the returned URL, asset id, or opaque blob handle in SQL. If storage is unavailable in hosted or persistent-database mode, fail closed with setup guidance instead of falling back to base64 in application_state, settings, resources, or app tables.
Local File Mode exception: some artifact apps (Content, Plans, Slides, Dashboards, Designs, etc.) can intentionally use repo files as the source of truth for the artifact itself. This must be explicit via agent-native.json, AGENT_NATIVE_MODE=local-files, or an app-owned local-file action helper. In that mode, the UI and agent still go through app actions, but those actions read/write scoped files through @agent-native/core/local-artifacts instead of SQL rows. App state, auth, settings, credentials, collaboration metadata, and hosted database mode remain SQL. File-to-database or file-to-provider synchronization is an explicit sync step, not an implicit side effect of editing.
When you add a data model, a list, or a read path, also follow the performance skill: project only the columns a list renders, index the columns hot queries filter/sort on, and avoid query waterfalls — so apps stay fast as data grows.
Agent-Native apps use Drizzle ORM over PostgreSQL. Local development uses PGlite at data/pglite; production and shared preview deploys need a persistent hosted PostgreSQL DATABASE_URL.
For app code, use Drizzle's schema/query DSL by default. Raw SQL is an escape hatch for additive migrations, health checks, or one-off maintenance, not the normal way to build features.
When the project contains drizzle.config.ts and drizzle/START_HERE.md, that managed Drizzle scaffold is the only app migration path. Define app tables in drizzle/schema.ts, run pnpm db:generate, and apply them with pnpm db:migrate. scripts/migrate-production.ts is framework-only: do not create a parallel runMigrations([...]) list in server/plugins/db.ts or import an app migration runner into the release script.
In projects without that managed scaffold, every entry added to a framework runMigrations([...]) list (@agent-native/core/db) needs a unique name: slug (for example, name: "analytics-alert-rules-table") alongside its version. Never renumber or reuse version numbers on existing entries.
Why: version numbers alone are not a safe identity. Two branches that each independently extend the same migration list can ship different DDL under the same version numbers — whichever branch deploys first "claims" those version numbers in the bookkeeping table, and the other branch's DDL is silently treated as already applied even though it never ran. A name: slug is tracked independently of version numbers, so it applies exactly once per database regardless of what any other branch already recorded.
Existing unnamed migrations don't need to be renamed retroactively (the two gating strategies coexist), but any new entry should always carry a name.
Every migration must also be backward compatible, not just additive. Beta and production now migrate independently against the same shared database, so one lane's migration can run before the other lane's matching code deploy. A new ADD COLUMN ... NOT NULL with no DEFAULT breaks on the first existing row, and breaks any already-deployed INSERT that doesn't know the column exists yet — make the column nullable, give it a DEFAULT, or use a self-filling type (SERIAL, GENERATED ... AS IDENTITY), and backfill separately if it needs a real value. guard:additive-migrations enforces this.
| Store | Purpose | Access |
|---|---|---|
application_state | Ephemeral UI state (compose windows, navigation) | readAppState() / writeAppState() |
settings | Persistent KV config (preferences, app settings) | getSetting() / putSetting() |
oauth_tokens | OAuth credentials | @agent-native/core/oauth-tokens |
sessions | Auth sessions | @agent-native/core/server |
In a managed Drizzle scaffold, define the PostgreSQL schema in drizzle/schema.ts. Otherwise, define schema with Drizzle's PostgreSQL exports in server/db/schema.ts. Get a database instance with const db = getDb() from server/db/index.ts. All queries are async.
import { eq, sql } from "drizzle-orm";
import { boolean, pgTable, text } from "drizzle-orm/pg-core";
export const tasks = pgTable("tasks", {
id: text("id").primaryKey(),
title: text("title").notNull(),
completed: boolean("completed").notNull().default(false),
createdAt: text("created_at").notNull().default(sql`now()`),
});
const rows = await db.select().from(tasks).where(eq(tasks.id, taskId));
Outside a managed Drizzle scaffold, use drizzle-orm/pg-core so app schemas
state their PostgreSQL types directly.
| Template | Tables |
|---|---|
| emails, labels (+ Gmail API when connected) | |
| Calendar | events, bookings |
| Forms | forms, responses |
| Content | documents |
| Slides | decks (JSON stored in SQL) |
| Videos | compositions in registry + localStorage |
The agent uses app-specific actions to read/write the database. Core DB scripts are for inspection and maintenance, not for implementing normal product behavior:
pnpm action db-schema — Show all tables, columns, typespnpm action db-query --sql "SELECT * FROM forms" — Run SELECT queriespnpm action db-exec --sql "UPDATE ..." — Last-resort ad-hoc maintenance for short columns, multi-column writes, or computed updates when no domain action exists. For several related writes, prefer --statements '[{"sql":"...","args":[...]}]' so they run sequentially in one transaction. Schema changes are blocked; use reviewed additive migrations/startup code instead.pnpm action db-patch --table <t> --column <c> --where "<clause>" --find "<old>" --replace "<new>" — Surgical search/replace on a large text column. Sends the diff instead of re-transmitting the whole value, so it's dramatically more token-efficient than db-exec UPDATE when editing multi-kilobyte documents, slide HTML, dashboard/form JSON, etc. Targets exactly one row per call — narrow --where by primary key. Supports --edits '[{find,replace},...]' for batch edits and --all to replace every occurrence.db-patch is the generic fallback for tables without a dedicated edit action.For one-off maintenance, how to choose between db-exec UPDATE and db-patch:
| Scenario | Use |
|---|---|
SET status = 'published' on one row | db-exec |
SET calories = calories + 50 | db-exec |
| Updating several columns at once | db-exec |
| Inserting/updating several rows as one logical operation | db-exec --statements |
Fixing a typo in a 50KB markdown document's content column | db-patch |
| Changing a single key in a dashboard's JSON blob | db-patch |
Tweaking one paragraph of slide HTML stored in decks.data | db-patch |
| Any edit where you'd otherwise re-send thousands of characters | db-patch |
All of these honor the per-user / per-org data scoping — you can't read or write rows outside the current user's data, regardless of which tool you choose.
The frontend calls actions using React Query hooks from the client API. The framework owns the HTTP transport behind these hooks, so components should not call action routes with raw fetch.
import { useActionQuery, useActionMutation } from "@agent-native/core/client/hooks";
// Read data
const { data } = useActionQuery("list-meals", { date: "2025-01-01" });
// Write data
const { mutate } = useActionMutation("log-meal");
Actions are the preferred way for the frontend to access data. You rarely need custom /api/ routes — only for file uploads, streaming, webhooks, or OAuth callbacks.
Local PGlite works out of the box for development. To deploy to production or any environment where data must survive restarts:
DATABASE_URL to a persistent hosted PostgreSQL database.Polling streams database changes to the UI. When the agent writes to the database via scripts, the UI updates automatically via useDbSync() which invalidates React Query caches.
select, insert, update, delete) and standard operators from drizzle-orm (eq, and, or, inArray, desc, etc.) for app reads/writes@agent-native/core/db/schema instead of direct Drizzle schema-driver importssettings store for app configuration and user preferencesapplication-state for ephemeral UI state that the agent and UI shareoauth-tokens for OAuth credentialsuploadFile() or putPrivateBlob() for large files/blob data and store only URLs, ids, or handles in SQLdb-schema, db-query, db-exec, db-patch) for ad-hoc database operationsdb-exec --statements instead of several separate db-exec calls for related writes; it is faster and rolls back the whole batch if one statement failsdb-patch instead of db-exec UPDATE whenever you're making a small change to a large text/JSON column — it's much cheaper on tokensdata: URLs, screenshots, videos, audio, PDFs, ZIPs, or session replay chunks directly in SQL rows, application_state, settings, or resourcesgetDbExec() when Drizzle can express the queryWhen storing app-state, include navigation state — the agent needs to know what the user is looking at. The application_state table holds ephemeral UI state that both the agent and UI share. Key patterns:
navigation key — the UI writes current view and selection on every route change. The agent reads this before acting.navigate key — the agent writes one-shot commands to navigate the UI. The UI processes and deletes them.compose-{id}) — bidirectional state for features like email drafts.When adding a new data model or feature, also consider what navigation and selection state needs to be exposed via application-state. See the context-awareness skill for the full pattern.
defineAction to query the databaseまだレビューはありません。使ってみた感想をお寄せください。
ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。
まだコメントはありません。最初のコメントを書いてみませんか。
複数のアプリやMCPホストからブランド画像・動画を生成、調整、書き出し、挿入する作業を支援します。ライブラリ選択や修正依頼も扱います。
特定の顧客企業について、契約と製品利用の数値を照らし合わせ、根拠や不足情報を明記した健全性レポートをまとめます。
アプリの操作をエージェントと画面の両方から呼び出せるアクションとして実装し、API連携や画面のデータ取得を一貫した形で追加するスキルです。
新機能をUI・エージェント用アクション・説明資料・画面状態の4領域でそろえ、利用者とエージェントのどちらからも一貫して使えるようにするチェックリストです。
複数のデータソースを照合して、傾向や指標、根拠をまとめた分析結果を作成します。必要に応じて、再実行できるダッシュボードとして保存できます。
Analyticsの管理画面で、機能フラグの状態確認と切り替え、ダッシュボード利用状況の調査、接続先アプリのデータベース管理を行います。