SharingCAUTION
A framework for building agentic apps
Overview
A framework for building agentic apps
d31edd75948aOBSERVED · 2026-10-14What it tells the agent
The instruction file, verbatim from the audited commit — this is the text the model reads, and the surface the audit's instruction layer examines. Quoted here so you can judge it without cloning anything.
---
name: sharing
description: >-
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.
scope: dev
metadata:
internal: true
---
# 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.
Share roles apply to one resource; organization roles apply to a team; app
roles apply within one app. These are separate permissions. For role setup,
use `agent-native-docs` to find the current organization and app-role guide.
Before adding an admin gate, identify which role system protects that operation
and use its existing role descriptor and permission checks. Do not replace role
checks with an email comparison or a custom `isAdmin` column.
### 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`:
```ts
import { sql } from "drizzle-orm";
import { pgTable, text } from "drizzle-orm/pg-core";
import {
createSharesTable,
ownableColumns,
} from "@agent-native/core/db/schema";
export const decks = pgTable("decks", {
id: text("id").primaryKey(),
title: text("title").notNull(),
data: text("data").notNull(),
createdAt: text("created_at").notNull().default(sql`now()`),
updatedAt: text("updated_at").notNull().default(sql`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):
```ts
// 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:
```ts
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. A public or cross-org-shared resource with that access could let an unrelated user act with the viewer's credentials.
Defaults match historical bTrust audit
CAUTIONgrade B · trust 89/100 Install with care. The audit found things worth knowing before you trust its output.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | WARN |
| L1 | Static analysis of the code | NA |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | PASS |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- none-observed
- Network
- none-observed
- Shell
- none-observed
- Dependencies
- pinned
- Secrets in source
- none-found
Findings (5)
.agents/skills/an
.agents/skills/content-product-development
.agents/skills/design-exploration
.agents/skills/turn-into-app
.agents/skills/visual-edit
Gates applied: no_behavioural_pass.
d31edd75948afull audit observations/trust-audit/skill/builderio__sharing.json · Report an issue / request a re-scanAudit history
Every audit this skill has had.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-14 | d31edd75948a | CAUTION | B | 89 | first audit |
Questions
What does the Sharing skill do?
A framework for building agentic apps
Is Sharing safe to install?
With care. The audit graded it B (89/100) and found 5 things worth knowing before you trust this skill, listed below with the exact line each was found on.
What can Sharing access on my machine?
The audit observed no filesystem, network or shell use at all in its source.
How current is this page?
The grade is for one exact copy of the source (d31edd75948a), read on 2026-10-14. The repository is watched, and a new audit runs when it changes — this is the first audit.
Add this badge to your README
Shows this page's audit result and links back to it. It updates when the audit does.
[](https://modelsatlas.com/skills/builderio/sharing/)
Not your listing, or something out of date? Claim or update your listing.