sixty

クライアントエージェント

Supabase

エンドポイントが「いくらかかったか」ではなく「何であるか」を知っている唯一のエージェントです。だから、遅いクエリと、クエリを拒否したポリシーを区別できます。

パッケージ
@sixty-sh/supabase / npm
動作環境
ブラウザエージェントと並べて、バックエンドが Supabase のプロジェクトで。
ソース
sixty-sh/sixty-supabase

導入方法

For a frontend with no server of your own to deploy: runs entirely in the browser with a public, origin-pinned key. If the project has any server, use browser or node.

導入手順は、あなた向けのチェックリストではなく、すでに開いているコーディングエージェント向けのプロンプトとして書かれています。これは意図的です。どのファイルを編集するかではなく、導入が終わった時点で何が成り立っていなければならないかを述べています。コードをどこに置くかはフレームワーク次第で、置き場所を間違えると静かに失敗するからです。エージェントはリポジトリを読んでそれを判断できますが、ドキュメントの段落にはできません。

同じ文面は、 install_sixty が MCP サーバー 経由で返すものであり、コレクタが次の場所で配信しているものでもあります: /v1/setup?kind=lovable. 実体は1つだけです。

Supabase の導入手順(全文)
Add sixty.sh performance monitoring to this app. It measures Supabase query
shape, page speed, stuck loading states and browser errors, and reports
anonymously.

Before anything else: does this project run a server of its own? A Lovable
app often grows one — an API route, a serverless function, an Express or
FastAPI backend added later, a Supabase edge function you deploy. If it has
one, STOP and ask for the "browser" install instead, or the "node" or
"python" one if the server holds logic worth measuring. Those keep the key
server-side behind a proxy and can measure the server as well as the page.
This install is for the case where the frontend is genuinely the only code
you deploy, and it trades a world-readable key for that.

If that is this project, work out which shape it is, because it decides where
the code goes and there is no error if you get it wrong — it just silently
never runs:

  A. Client-only Vite SPA. There is a createRoot(...) call in a file like
     src/main.tsx and no server entry.
  B. Server-rendered framework app — React Router v7 framework mode, Remix,
     or similar. Signs: an entry.client.tsx / entry.server.tsx pair, a
     root.tsx, a hydrateRoot(...) call, or a routes.ts.

Then:

1. Add two dependencies: @sixty-sh/supabase and @sixty-sh/browser.

2. Call init() from "@sixty-sh/browser" exactly once, in the browser.

      init({ key: "sixty_pk_YOUR_KEY" })

   In shape A, module scope in the app entry is fine.
   In shape B it MUST go in the client entry (entry.client.tsx), after
   hydration. Do not put it in a shared module that the server also
   evaluates: there it runs during server rendering, finds no window,
   returns null, and reports nothing at all — with no error to tell you.

3. Find where the Supabase client is created. Search the repository for
   "createClient(" rather than guessing a path — it is often in
   src/integrations/supabase/client.ts but in this kind of project it may be
   anywhere. Then, at module scope in that same file:

      import { withSixty } from "@sixty-sh/supabase"
      withSixty(supabase, { key: "sixty_pk_YOUR_KEY", service: "my-app" })

   Use the client that already exists. withSixty patches the PostgREST
   prototype and returns the same object it was given, so it instruments every
   query in the app without replacing the export.

Constraints — correctness requirements, not style preferences:

- Do NOT create a second Supabase client. There must still be exactly one.
- Do NOT edit vite.config.ts and do NOT add a Vite plugin.
- Do NOT change any existing query, component, or hook. This is
  instrumentation only; no behaviour should change.
- The key above is PUBLIC by design: write-only, pinned to one service, and
  refused from any origin it does not list. Paste it literally. Do not move it
  into an environment variable or a secret.
- Do NOT add any analytics library, user id, session id, or cookie. This agent
  is deliberately anonymous and must stay that way.

When you are done, tell me which shape you found and which files you changed,
then publish the app. Findings need two published releases with traffic under
each before anything can be compared.

公開鍵が必要です — オリジンに固定されたもので、自前のサーバーを持たないアプリには秘密を置く場所がないからです。

何を測るか

シグナル単位意味
errorserror ratea larger fraction of calls are throwing
new_erroroccurrencesan error that did not occur in the previous release
latencyms per callthis operation takes longer end to end than it used to
silent_empty—The query runs and succeeds, and returns no rows where it used to return plenty. Nothing reports an error, so the page just renders blank — this is what a broken permission rule looks like from the outside.
auth_failures—The server is turning these away on permission grounds rather than failing. People see an empty page or a save that quietly does nothing.

名前を付けられる失敗

シグナルではありません。エラーに付ける分類であり、「呼び出しが失敗した」と「ポリシーが拒否した」の違いを生むものです。

rls_deniedA row-level security policy refused the statement (Postgres 42501). It reaches the browser as an empty list and your logs as nothing at all.
schema_missingA column, table, relationship or function the code expects is not in the database.
constraint_violatedA write was rejected by a database constraint.
jwt_expiredA session token was expired or invalid where one was required.
realtime_duplicate_subscriptionOne topic subscribed concurrently three times or more — an effect with no teardown, seen from the wire.
realtime_channel_errorA channel reported CHANNEL_ERROR or TIMED_OUT instead of subscribing.

どこに入り込むか

  • supabase-js — PostgREST の呼び出し、リアルタイムのチャンネル、認証を、それが行われる場所で計測します。
  • Vite — プラグイン。Vite でビルドしているプロジェクト向け。

データベース

  • PostgREST — リクエスト自体がクエリを記述しているので、テーブルも絞り込みも失敗コードも、SQL 文なしで読み取れます。

これだけができること

  • 失敗に名前を付ける — 他のどのエージェントも「呼び出しが失敗した」とは言えます。これは「ポリシーが拒否した」「カラムがない」「トークンが期限切れだった」と言えます。PostgREST のリクエストは、単にコストを持つのではなくクエリそのものを記述しているからです。
  • 読み取りだけでなくリアルタイムも — エラーになる、タイムアウトする、あるいは後片付けのない副作用のせいで三重に購読されてしまうチャンネル。

できないこと

  • これはブラウザ用または Lovable 用のエージェントへの追加であって、置き換えではありません。Supabase の失敗を説明しますが、ページを測るわけではありません。
  • 自前のサーバーを持たないプロジェクトは、オリジンに固定された公開鍵を使います。API ルートや Edge Function が生えたなら、ブラウザまたは Node の段にしてください — キーはサーバー側に留まり、サーバーも一緒に測れます。

設定

どのエージェントも同じ4つの変数を読みます。そして SIXTY_* が答えるところでは DRIFT_* も引き続き答えます — 製品名は変わりましたが、その名前は他人のデプロイから引き上げてよい類のものではありません。

SIXTY_API_KEYこれがないとエージェントは何もせず、そのことを伝えます。推測もせず、未知のエンドポイントに再試行もせず、例外も投げません。
SIXTY_SERVICEこのサービスを何と呼ぶか。読み取れる場合はプロジェクト名が既定になります。
SIXTY_RELEASEいちばん重要なもの。Vercel、Render、Railway、Fly、Heroku、GitHub Actions では自動で拾われます。それ以外ではコミットの SHA を設定してください。これがないとすべての計測が名前のない1つのバケツに入り、比較は永遠にできません。
SIXTY_ENDPOINTどこへ報告するか。既定は http://localhost:4319で、ノートPCの上では正しく、そのアプリが他人に配信された瞬間に間違いになります。

残り — 送信間隔、サンプリング率、何を計測するか — はパッケージ自身の README にあります。エージェントが変わっても正しいままでいられる場所だからです。

sixty の Supabase エージェント — 何を測り、どう導入するか