Skip to content

14. Teams and sharing

Runnable companion: examples/11_share_a_dataset.py

Everything you built in the previous chapters is private. A store you import into, a workset you select, a dataset you convert — they are readable by you and by nobody else, until you say otherwise.

This chapter is how you say otherwise.

A team owns it

A team is a named set of users. Every store, dataset and split set has exactly one owning team, recorded when it is created.

You always have at least two teams: a personal team of just you, and the reserved global team called everyone, which every authenticated caller belongs to.

A resource you create lands in your personal team unless you name one. There is no setting to change that — you name the team when you create the resource, where the consequence is in front of you:

me = client.get_auth_status()
[team.id for team in me.teams]           # your teams, `everyone` included

Name a team explicitly when you want the work to belong to the team rather than to you:

client.create_store(name="voice_v2", team="speech-research")

You have to be a member of the team you name. Nothing else inherits: a store you create by copying another, or by adding samples from three others, belongs to your personal team — never to a source's.

Sharing is one thing: a grant

A grant binds one resource to one team at level read or write:

client.grant_resource_access("dataset", "voice_train_v1", team="qc", level="read")

read lets that team read the dataset and its samples. write also lets them write to it — attach keys, add samples — and confers read. Neither lets them re-share it or give it away; those stay with the owning team.

Unsharing is the same verb backwards:

client.revoke_resource_access("dataset", "voice_train_v1", team="qc")

Publishing is a grant to everyone

There is no "public" flag. Publishing is a read grant to the global team, and withdrawing is revoking it:

client.grant_resource_access("dataset", "voice_train_v1", team="everyone")   # publish
client.revoke_resource_access("dataset", "voice_train_v1", team="everyone")  # withdraw

Because it is an ordinary grant, it is reversible like any other, and clients derive the label you see — private (no grants), shared (grants to named teams), public (a grant to everyone) — from the grants alone. A write grant to the global team is refused: implicit membership must never confer write.

Sharing a dataset is enough

Read access on a dataset authorizes reading its samples, without granting anything on the stores it was built from:

# `qc` can read every sample in the dataset...
client.grant_resource_access("dataset", "voice_train_v1", team="qc")
# ...and still cannot read the store it came from.

That is the common case, not a loophole — you want to share the training set, not the raw corpus. It works because a dataset is frozen: its membership was fixed at conversion, so the grant cannot silently widen later.

Building is the other way round. Creating a workset or dataset requires read access on what you are building from: each source store, or — when the source is a dataset — that dataset. And because a workset is live, it re-checks on every read: revoke a grant and the next read stops, rather than serving membership the caller can no longer reach.

From the CLI

datavo teams list

datavo share dataset voice_train_v1 --to qc --level read
datavo share dataset voice_train_v1 --list
datavo unshare dataset voice_train_v1 --to qc

What you learned

Owning team one per store / dataset / split set, set at creation
Where it lands your personal team, unless you name one at creation
Grant one resource, one team, read or write
Publish a read grant to everyone; withdraw revokes it
Dataset read sufficient for its samples; source access is checked when you build

Next: 15. Shard caching and the cache hierarchy — why the second read of a dataset is free.