Guide
Scoped access — who can upload in a multi-user project
Every member's write is scoped by role and recorded by name. Here's how the access model governs uploads, what `viewer` can't do, and conventions for keeping members from clobbering each other.
5/18/2026 · connect0 · 3 min
Roles decide who can write; the audit trail records who did — the core governs both.
connect0 projects are multi-tenant: an account can have many members, each at one of four roles. The upload surface respects that, with a couple of subtleties worth knowing.
Who can upload
| Role | Can call upload.create_link / upload.write / use dashboard drop-zone? |
|---|---|
owner | Yes. |
admin | Yes. |
member | Yes. |
viewer | No — uploads return insufficient_role. Read-only. |
viewer is the "see the dashboard, don't change anything" role. It exists so non-engineers can browse activity without being able to write into the workspace.
All members write to the same workspace
There's no per-member /workspace/. The R2 prefix is projects/<project-id>/... — every member of a project shares it. Conventions matter:
- One subdirectory per member for in-progress work:
/workspace/alice/,/workspace/bob/. - A shared
/workspace/data/for inputs everyone reads. - A
/workspace/notes/for the team journal (agent-notebook). - Don't put two members' iterations of the same file at the same path — last write wins, no version history, hard to recover from.
The audit trail tells you who
Every upload_link row has ip_local_id (the Identity Platform user id of the person who issued the link). The dashboard's "Recent uploads" card surfaces this so you can answer "who put this file here?" without guessing.
SELECT ul.target_path, ul.issued_at, ul.bytes_received,
ul.ip_local_id -- cross-reference to Identity Platform for a real name
FROM upload_link ul
WHERE ul.project_id = '<uuid>'
ORDER BY issued_at DESC LIMIT 50;
Conventions we recommend
- Tell the agent to scope paths. "Always put my uploads under /workspace/alice/." The agent will pass
target_path: "alice/foo.txt"etc. - Reserve a shared
/workspace/data/and treat it as read-only after a setup step. Nobody writes there after the first upload. - Use the dashboard's "Recent uploads" to spot accidental overwrites — a
target_paththat appears twice with differentip_local_ids is worth a conversation.
When you genuinely need isolation
connect0 doesn't ship per-user sub-prefixes (e.g. "Alice can only PUT under projects/<id>/alice/"). The model is "if you're a member, you can write anywhere in the project's workspace." If you need stricter isolation:
- Separate projects per member. Cleanest. Each member is owner of their own project; they invite the others as
viewerif they need read access. - Per-account scoped API tokens (when those land — see CI uploads guide). The token's project scope acts as the boundary.
What viewers can do today
- Read
recent_uploadsviainfo. - View the dashboard's project pages.
- Cannot
sh, cannot upload, cannot mutate.
Next steps
Where this fits
This is the One system of record pillar of connect0 — the core that connects everything your company runs on. The core enforces each member's role at write time and stamps every upload with the identity behind it, so scoped access and attribution come from the same place. Start building → · All guides →