本文へ移動
cccskills
無料GitHub で公開日本語紹介

sharing

ユーザーが作成した資料やダッシュボードを非公開で管理し、共有範囲や閲覧・編集権限、共有ダイアログをアプリに組み込む方法を案内します。

原文原文の説明を見る

Framework-level sharing and privacy for user-authored resources (dashboards, documents, forms, decks, etc.). Use when making a resource table ownable, wiring list/read/update access checks, or dropping the standard share dialog into a template.

BuilderIO/agent-nativeスター 7,522(GitHub 7,522 + cccskills 0)

実行スコア 未検証

インストール方法を見る

こんなときに便利

  • 資料を作成者の非公開にしたいとき
  • 既存テーブルに共有機能を追加したいとき
  • 閲覧・編集権限を役割ごとに設定したいとき
  • 共有ダイアログをテンプレートに追加したいとき

日本語での紹介

できること

ユーザーが作成した資料やダッシュボードなどを、作成者の所有物として登録し、初期状態を非公開にする仕組みを扱います。公開範囲は本人と個別共有、組織内、リンクを知る人向けに分けられます。共有相手には閲覧、コメント、編集、共有管理の役割を割り当てられます。リストや読み取りではアクセス可能な項目だけを返し、更新や削除では必要な権限を確認します。共有操作や表示には共通アクションと ShareButton などのUIを使います。

こんなときに便利

新しいリソース表に所有者や公開範囲を追加するとき、既存データに共有機能を後付けするときに役立ちます。共有相手や組織ごとに閲覧・編集範囲を制御したい場合や、テンプレート間で共有画面の操作をそろえたい場合にも使えます。

使い方の例

  • 「この資料を作成者だけが見られる設定にして、共有操作を追加してください」
  • 「一覧と更新処理に、共有状況に応じたアクセス確認を組み込んでください」

注意点

匿名で使う公開URLは共有機能とは別の仕組みです。組織内共有を例外として初期設定にするワークスペースアプリもあります。

この紹介文は、公開されている SKILL.md をもとに AI(OpenAI Codex)が作成しました。正確な仕様は下の原文を確認してください。

含まれるファイル(1)

  • SKILL.md13.5 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Sharing — Private by Default, Explicit Share

Rule

Any resource a user creates (dashboards, documents, forms, decks, compositions, booking links, issues, analyses) is private to the creator by default and visible to others only when they have been explicitly shared with or when the creator changes visibility to org or public.

This is the framework-level primitive. Every ownable resource gets it for free — same API, same UI, same skill.

Workspace apps are the intentional organization-scoped exception: their default visibility is org, configurable by an organization owner/admin. The creator is stored as the app owner, and the creator or an organization owner/admin can change the app's visibility or manage its share grants.

Concepts

Three visibility levels

  • private — owner + explicit share grants only. Default.
  • org — owner + explicit grants + anyone in the same org (read-only).
  • public — owner + explicit grants + anyone with the link (read-only). Public docs do NOT appear in other users' list/sidebar/search results — accessFilter omits them by default. They're reachable by id (resolveAccess admits them) so direct links and SSR routes like /p/:id keep working. If a list endpoint legitimately needs cross-user public discovery (a template gallery, etc.), pass accessFilter(table, shares, ctx, minRole, { includePublic: true }).

Visibility is coarse. Explicit share grants are fine-grained (per user, reusable organization group, or per org).

Roles on a share grant

  • viewer — read only.
  • commenter — read + add comments, but cannot edit the resource or manage shares.
  • editor — read + write.
  • admin — read + write + manage shares. Does NOT replace the single owner_email on the resource.

There are three role systems and they never imply one another. A share role answers "what may this person do to one row". An org role (org_members.role) answers "what may this person do to the team". An app role (defineAppRoles, see the authentication skill) answers "what may this person do inside one app". A share admin is not an app admin and neither is an org admin.

Anonymous public URLs stay separate

Form "publish" slugs, booking-link slugs, any feature that exposes a URL to unauthenticated users — these are a different axis and are NOT controlled by the sharing system. Keep them alongside it.

Make a resource ownable

In your template's server/db/schema.ts:

import {
  table,
  text,
  integer,
  now,
  ownableColumns,
  createSharesTable,
} from "@agent-native/core/db/schema";

export const decks = table("decks", {
  id: text("id").primaryKey(),
  title: text("title").notNull(),
  data: text("data").notNull(),
  createdAt: text("created_at").notNull().default(now()),
  updatedAt: text("updated_at").notNull().default(now()),
  ...ownableColumns(), // adds owner_email, org_id, visibility
});

export const deckShares = createSharesTable("deck_shares");

Then register it in server/db/index.ts (not the schema file — keeps the schema file free of the getDb closure and avoids circular imports):

// server/db/index.ts
import * as schema from "./schema.js";
import { createGetDb } from "@agent-native/core/db";
import { registerShareableResource } from "@agent-native/core/sharing";

export const getDb = createGetDb(schema);
export { schema };

registerShareableResource({
  type: "deck",
  resourceTable: schema.decks,
  sharesTable: schema.deckShares,
  displayName: "Deck",
  titleColumn: "title",
  getResourcePath: (deck) => `/deck/${deck.id}`,
  getDb,
});

The type string is the stable id the UI and actions use. getDb is required — the framework-level share actions use it to reach your template's DB.

Restricting public visibility and cross-org user shares

Some resources should NOT be reachable by an arbitrary authenticated user even with the link, and should NOT be shareable to an email outside the org. Two optional registration flags lock these axes down:

registerShareableResource({
  type: "extension",
  // ...
  allowPublic: false, // hides "Public" in the share dialog and rejects it server-side
  requireOrgMemberForUserShares: true, // user shares must target an org member or pending invitee
  supportsGroupShares: true, // enable reusable organization groups for this resource
});
  • allowPublic: false — set-resource-visibility('public') throws ForbiddenError, accessFilter / resolveAccess treat any stored 'public' row as private (defense in depth against bad data), and the share popover hides the "Public" option. list-resource-shares returns policy.allowPublic: false so the UI follows the server.
  • requireOrgMemberForUserShares: true — share-resource looks up principalId in org_members and org_invitations (pending) for the resource's orgId and rejects user shares to anyone else. The same flag also pins principalType: "org" shares to the resource's own org — sharing to a different org would let that org's members run code in the viewer's auth context (same threat model as a public extension). (The flag name is kept for backward compatibility; treat it as "lock both user and org shares to the resource's org".)

Use both for resources that execute code or expose privileged data with the viewer's credentials. Extensions ship with both set: an extension's HTML calls actions / SQL / the secrets-injecting proxy as the viewer, so a public or cross-org-shared extension would let a stranger run arbitrary code with someone else's auth context. scripts/guard-extension-no-public.mjs (CI + pnpm prep) statically enforces that the extension registration keeps both flags set.

Defaults match historical behaviour: allowPublic: true, requireOrgMemberForUserShares: false. Resources that don't set the flags work as before.

Reusable organization groups

The workspace organization model stores reusable groups in workspace_user_groups. Organization owners/admins manage the groups and their members through the existing group actions. Set supportsGroupShares: true on a resource registration to enable principalType: "group" in the generic share actions and the shared popover's autocomplete. Group ids are always checked against the resource's organization, and membership is evaluated at access time so group changes apply to existing shares.

Workspace apps opt into this flag and use the organization default visibility setting. The app creator is the durable owner_email, while organization owners/admins receive admin access through the registration's canManageAccess callback.

Filter list/read queries

import { accessFilter } from "@agent-native/core/sharing";

const rows = await db
  .select()
  .from(schema.decks)
  .where(accessFilter(schema.decks, schema.deckShares));

accessFilter admits rows the current user owns, has been shared on, or that the user can reach via org visibility. public rows are NOT admitted by default — see the visibility section above for why and how to opt in.

Guard write actions

import { assertAccess } from "@agent-native/core/sharing";

export default defineAction({
  schema: z.object({ id: z.string(), title: z.string() }),
  run: async (args) => {
    await assertAccess("deck", args.id, "editor");
    // ...proceed
  },
});

For delete actions use "admin" (or fold in "owner" to require the real owner).

authorize is a different axis, not an alternative: it gates whether the caller may run the operation at all, while assertAccess scopes which row they may touch. A write action restricted to some teammates needs both — authorize: appAccess.requireAny(...) on the action, assertAccess inside run.

Create actions must set owner

When inserting a new row, fill ownerEmail and orgId from the request context:

import {
  getRequestUserEmail,
  getRequestOrgId,
} from "@agent-native/core/server/request-context";

const ownerEmail = getRequestUserEmail();
// Never fall back to a sentinel like "local@localhost" — that pools every
// unauthenticated write into one shared tenant (see the 2026-04-29 leak and
// guard-no-localhost-fallback). Throw / 401 when there is no session instead.
if (!ownerEmail) throw new Error("Not authenticated");

await db.insert(schema.decks).values({
  id: nanoid(),
  title,
  data,
  ownerEmail,
  orgId: getRequestOrgId(),
  // visibility defaults to 'private'
  // ...
});

Drop in the share UI

import { ShareButton } from "@agent-native/core/client/sharing";

// In the resource's header/toolbar:
<ShareButton
  resourceType="deck"
  resourceId={deck.id}
  resourceTitle={deck.title}
/>;

For list views, show <VisibilityBadge visibility={row.visibility} /> next to each resource.

Standard share surface

All app share popovers should use the same compact surface contract:

  • Use the text-only ShareTrigger from @agent-native/toolkit/sharing.
  • Render ordinary links with ShareCopyRow, which exposes a Copy action without printing the raw URL.
  • Keep general access and individual people access in the standard Core sharing flow. The people flow supports email invites, roles, notifications, and removal through the shared share actions.
  • Add ShareAgentsSection only when the resource has a real agent-readable link or prompt. Keep it collapsed by default and supply domain-specific content through the shared section shell.
  • When supportsGroupShares is enabled, keep the existing people input as the only entry point and include organization groups in its autocomplete. Do not add a separate group-management surface to each resource.
  • App-specific tabs or controls may remain when they represent a real domain action (for example, an embed-code editor), but they should retain the same trigger, copy-row, access, and spacing language.

ShareDisclosureSection is the toolkit-owned shell for optional expandable share details; use its ShareAgentsSection or SharePeopleSection wrappers instead of creating another collapsible share panel in a template.

Actions available everywhere

The framework auto-mounts these actions in every template — no per-template boilerplate:

ActionArgsPurpose
share-resourceresourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?Grant a user, group, or org access. notify defaults to true for individual user shares; resourceUrl can provide the direct app link and message an optional short note for the notification email.
unshare-resourceresourceType, resourceId, principalType, principalIdRevoke access.
list-resource-sharesresourceType, resourceIdCurrent visibility + all share grants.
set-resource-visibilityresourceType, resourceId, visibilityChange to private / org / public.

Both the agent and the UI use these same actions. The agent calls them as tools; UI code should use ShareButton / ShareDialog or the action client hooks instead of hand-writing route calls.

Migration pattern for existing tables

When retrofitting an existing resource table:

  1. Add owner_email, org_id, visibility columns (defaults 'local@localhost', NULL, 'private').
  2. Backfill owner_email from any prior creator trail; otherwise leave the default.
  3. Add the companion {type}_shares table.
  4. Register via registerShareableResource.
  5. Update list/read actions to use accessFilter.
  6. Update update/delete actions to assertAccess with the correct role.
  7. Add <ShareButton> to the resource header.
  8. Add getResourcePath in the registration so agent-triggered shares can email a direct link even when no UI supplied resourceUrl.

Templates that opt out

Sharing doesn't apply to:

  • Personal-data apps (mail) — user-scoped by design.
  • External source-of-truth apps (issues → Jira, recruiting → Greenhouse) — ACL lives in the upstream system.
  • Demo/boilerplate (starter) — no resources.

For these, add a short note to the template's AGENTS.md explaining why.

Analytics (follow-up)

Dashboards and analyses in the analytics template currently live in the settings KV store (u:<email>:dashboard-* keys), not SQL. Sharing requires either migrating them to SQL tables (then applying this skill) or extending the settings store with a parallel share overlay. This is a tracked follow-up — see the analytics template's AGENTS.md.

Debugging

  • ForbiddenError from an action means the current user isn't owner / hasn't been shared / can't meet the role bar.
  • If the agent can't see a resource it just created, check that the insert actually set owner_email from the request context.
  • If a share doesn't take effect in the UI, confirm the template's list-* action uses accessFilter — the share rows are there but nothing is reading them yet.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

コメント

ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。

まだコメントはありません。最初のコメントを書いてみませんか。

送信するとすぐに公開されます。メールアドレスや電話番号などの個人情報は書かないでください。URL は 2 つまでです。

0 / 1000 文字

このフォームは reCAPTCHA で保護されており、Google のプライバシーポリシーと利用規約が適用されます。

同じリポジトリのスキル

a2a-assets

無料概要あり

複数のアプリやMCPホストからブランド画像・動画を生成、調整、書き出し、挿入する作業を支援します。ライブラリ選択や修正依頼も扱います。

  • スライド用のブランド画像を作りたいとき
  • 既存素材をフィードバックに合わせて直したいとき
  • 動画素材を生成して書き出したいとき
BuilderIO/agent-native7,5222026年10月26日 更新

account-health

無料概要あり

特定の顧客企業について、契約と製品利用の数値を照らし合わせ、根拠や不足情報を明記した健全性レポートをまとめます。

  • 顧客の健全性を確認したいとき
  • 契約席数と実利用を比べたいとき
  • 更新前に利用状況を整理したいとき
BuilderIO/agent-native7,5222026年10月26日 更新

actions

無料概要あり

アプリの操作をエージェントと画面の両方から呼び出せるアクションとして実装し、API連携や画面のデータ取得を一貫した形で追加するスキルです。

  • 新しいアプリ操作を追加したいとき
  • 外部APIと連携したいとき
  • 画面からデータを取得したいとき
BuilderIO/agent-native7,5222026年10月26日 更新

adding-a-feature

無料概要あり

新機能をUI・エージェント用アクション・説明資料・画面状態の4領域でそろえ、利用者とエージェントのどちらからも一貫して使えるようにするチェックリストです。

  • 新機能追加の作業範囲を整理したいとき
  • UIとエージェント操作をそろえたいとき
  • 画面状態の同期漏れを防ぎたいとき
BuilderIO/agent-native7,5222026年10月26日 更新

adhoc-analysis

無料概要あり

複数のデータソースを照合して、傾向や指標、根拠をまとめた分析結果を作成します。必要に応じて、再実行できるダッシュボードとして保存できます。

  • 商談と通話記録を照合したいとき
  • 顧客の利用状況を横断して調べたいとき
  • 繰り返し更新できる分析を保存したいとき
BuilderIO/agent-native7,5222026年10月26日 更新

admin-surfaces

無料概要あり

Analyticsの管理画面で、機能フラグの状態確認と切り替え、ダッシュボード利用状況の調査、接続先アプリのデータベース管理を行います。

  • アプリごとの機能フラグを確認・変更したいとき
  • ダッシュボードの所有者や利用状況を調べたいとき
  • 接続済みアプリのテーブルを管理したいとき
BuilderIO/agent-native7,5222026年10月26日 更新

BuilderIO のスキルをすべて見る

このスキルの問題を報告する