oto_resource_v2
BETA. Same governance surface as oto_resource (ADR 0030), with a STRICT input contract: resource_type is REQUIRED (no default) ∈ {datastore_namespace, project, procedure, doc}, and resource_id must be numeric. PROCEDURES (resource_type=procedure): op=transfer MOVES the procedure with its history — same resource_id, every revision, its project links and its shares follow it (a slug already taken at the destination gets a suffix, nothing is overwritten). By contrast, transferring a PROJECT with cascade=true COPIES its linked procedures into the target (see DELIVER A FULL PROJECT below). resource_type="doc" shares ONE PAGE ALONE (resource_id = its oto_doc id), read-only: role viewer (the default — editor/manager are refused with doc_viewer_only), audience person/team/org only (public/secret do not apply to a page). The recipient reads it with oto_doc op=get and finds it with oto_doc op=shared_with_me — never its project, sibling pages, sub-pages, revisions or backlinks. Sharing a page takes the right to govern its project; op=unshare closes it at once; op=list lists the pages you shared one by one; a page is never transferred on its own. APPS (resource_type=app): an app has its OWN owner and shares — viewer opens and uses it, editor changes it, manager re-shares it; op=transfer moves it to a person, a team or an org. The projects it is filed in give no access. No cascade, no credentials: an open app acts as its viewer, bounded by its author. Prefer this tool over oto_resource: on the legacy one, omitting resource_type silently targets a datastore namespace, so op=transfer/share act on a DIFFERENT resource than the one you meant. Everything else is identical — op=list: resources you govern (platform admins see all); op=get: owner + shares + metadata (each grant carries a role); op=transfer: hand ownership to a user (new_owner_email), to one of YOUR orgs (new_owner_org, you must be a member) OR to one of YOUR teams (new_owner_group, ADR 0049 — scoping a resource to a pôle IS the way to restrict it); a user-owned previous owner keeps editor access (transfer is owner/admin only, never a grantee). ANTI-LOCKOUT: if the transfer would leave YOU unable to ever get the resource back (handing to a third party, or to an org/team you don't administer), it is refused with code confirm_loss_of_control — resend with confirm_transfer=true to proceed consciously (a platform admin is never blocked and can always recover it). op=share/unshare — ONE unified « Share », two axes (ADR 0048): AUDIENCE (audience) = where it goes: person (email) / team (group_id, a group of an org you belong to) / org (org_id, a whole org, client delivery) → a grant; public/secret → PUBLISH the project (public = listed, secret = unguessable link) with mcp_tools (defaults to the already-published set); private → unpublish. ROLE (role) = what they can do: viewer (read), editor (write), manager (GOVERNANCE — re-share / delete / publish, grantable, but NOT ownership transfer); public/secret force viewer. PUBLISHING (public/secret) also takes being a member of the org that owns the project (the parent org of an owning team; the owner themself for a personal project): a manager from outside is refused 403 publish_requires_membership — private (unpublish) stays open to whoever governs. Legacy permission read|write is still accepted (mapped to viewer/editor). KEYS (credentials, project share only, same for person/team/org): a recipient works in the project with THEIR OWN keys (own, the default) — the owner org's and team's keys are NOT lent. credentials='inherit' lends them, bounded by your own rights (you must be a member of the owner org; refused with inherit_beyond_sharer_rights otherwise); re-share with credentials='own' or unshare to revoke. op=get shows each grant's credentials. EXPIRY (ttl_days, share to person/team/org only; refused with ttl_days_grant_only elsewhere): the share expires after N days — past it the recipient loses access (content, listings, lent keys), with NO reminder before. Omitted on a re-share: an active share keeps its expiry, an expired one is reopened without one; to remove an expiry, unshare then share. With cascade=true the linked tableaux/procedures get the same expiry. op=share returns expires_at (null = none); op=get lists each grant's expires_at and expired — an expired share stays listed, marked, until unshared. PENDING SHARE (audience person, email with NO oto account yet): the share is NOT refused — it is kept pending: the address gets an email with a link, and on signup (or by opening the link) gets access to THIS resource with the given role and NOTHING else — they never join your org. op=share returns pending: true and pending_note; sharing again to the same address reuses it (already_pending). op=get lists it in grants with pending: true; op=unshare with the same email withdraws it. Refused with cascade=true or credentials='inherit' (pending_share_plain_only): share again once they have an account. To give someone ONE resource, share it — never invite them into your org, which opens everything the org owns. DELIVER A FULL PROJECT (#52): share/transfer a project with cascade=true to carry its linked entities in one gesture — linked tableaux get the same share/transfer, linked procedures are share-granted read (readable cross-org via oto_procedure op=get guide_id) or COPIED into the target org on transfer (link re-pointed, source untouched), connector links report recipient_credential (the recipient plugs their own key; the project's pre-made identity/instructions overrides travel with it) or inherited_credential under credentials=inherit; docs & files follow automatically. Returns a per-entity cascade report. Owner OR org/platform admin governing it; never exposes row content.
Tool call template
Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.
{
"id": 1,
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"arguments": {
"op": "<op>",
"resource_type": "<resource_type>"
},
"name": "oto_resource_v2"
}
}Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| op | Yes | ||
| sub | No | Identifiant du compte destinataire, quand une adresse en désigne plusieurs. À passer SEUL, jamais avec `email`. | |
| _org | No | ||
| role | No | ||
| No | |||
| org_id | No | ||
| cascade | No | ||
| audience | No | ||
| group_id | No | ||
| mcp_slug | No | ||
| ttl_days | No | Share only (person/team/org): the share EXPIRES after this many days (integer ≥ 1) — past it, the recipient loses access. Omitted: an active share keeps its expiry, a new or expired one has none. Nobody is reminded before it expires. | |
| mcp_tools | No | ||
| permission | No | read | |
| credentials | No | Project share only — which keys the recipient works with. `own` (default): their own keys. `inherit`: also the project owner's org/team keys, bounded by YOUR rights (you must be a member of the owner org). Omitted = unchanged. | |
| resource_id | No | Identifiant numérique de la ressource (clé primaire). | |
| new_owner_org | No | ||
| resource_type | Yes | ||
| new_owner_email | No | ||
| new_owner_group | No | ||
| confirm_transfer | No |