Skip to main content
Documentation

Collaborators

Let other people deploy and operate your app.

On this page

Collaborators are DeepSpace users the app owner authorizes to work on the app. Ownership never moves: the deployed worker keeps the owner's identity and billing. Authorization keys to the app's immutable DEEPSPACE_APP_ID, so there is no per-resource grant and no link step.

Managing collaborators#

All four subcommands are owner-only. Run them from the app checkout, or pass --app <id or name>.

npx deepspace app collaborators list
npx deepspace app collaborators add teammate@example.com
npx deepspace app collaborators cancel teammate@example.com
npx deepspace app collaborators remove teammate@example.com
bash

list prints two sections - current collaborators, and any live invites with their expiry. With --json you get { collaborators, pending }.

Adding someone#

add has two paths, depending on whether the email already belongs to a DeepSpace user.

The email is an existing DeepSpace user

They become a collaborator immediately. The command prints ✓ <email> can now deploy <app>.

The email has no DeepSpace account yet

The server creates a pending invite and emails the person a /join/<token> link. The invite is billed to you as a transactional email, and expires after 7 days.

Signing in alone does not grant access — the invitee must explicitly accept, one of two ways:

  • open the emailed link, sign in with the invited address, and accept there, or
  • sign in and accept from the CLI — the path a headless agent takes:
npx deepspace app collaborators invites          # lists invites waiting for your email
npx deepspace app collaborators accept <app-id>  # accepts one
bash

Both are bound to the same rule: the signed-in email must match the invited email.

Re-running add while an invite is still live returns already_invited: no second email is sent and you are not charged again. To reset an invite, cancel it and then add again.

Failures you may see#

CodeMeaning
test_account_cannot_be_collaborator@deepspace.test accounts can never be collaborators. Use a real account.
insufficient_creditsInviting a brand-new email sends a billed transactional email. Top up and retry.
invite_email_failedTransient - the invite email could not be sent. You were not charged; the pending row is rolled back. Retry in a moment.
no_pending_invitecancel was given an email with no live invite.
not_a_collaboratorremove was given an email that isn't on the app.

What a collaborator can and can't do#

ActionAllowed
deploy (including --env)Yes - on-behalf. Billing stays with the owner.
dev start / test runYes
secrets list / get / download / pullYes - every config in the app's store
secrets set / upload / delete, configs create / deleteYes - writes are audited under the collaborator's own id
app undeployNo - owner (or platform admin) only
app transfer offerNo - owner only
app transfer status / cancel / acceptOnly as the named recipient of a pending offer. Either party may cancel; only the recipient may accept.
app collaborators add / remove / cancelNo - owner only
app source (change source authority)No - owner only

A collaborator who is the named recipient of an ownership transfer may accept it - but as that recipient, not through the collaborator role. transfer status is likewise visible only to the owner and the named recipient; other collaborators cannot see a pending offer at all.

Platform admins are not super-collaborators#

Through the platform override, admins can deploy, manage secrets, and undeploy. They cannot manage collaborators or change source authority, and ownership transfer remains the owner's handshake - an operator can at most open an offer on behalf of an unreachable owner, and even that is recorded as the owner's offer. The override never turns a collaborator into an admin.

On-behalf deploys#

When a collaborator deploys, the CLI prints Deployed on behalf of owner <id>. The release ships their code plus the store's secrets. Nothing about ownership changes, and billing follows the owner.

The release is attributed to the collaborator, not the owner. The ledger records the caller as the release actor, which is why releases --json names the collaborator on the releases they shipped and status --json reports byYou: true for them. Only the ownership and billing relationship is the owner's. Earlier CLI versions printed a warning claiming the release was attributed to the owner; that warning contradicted the ledger it was describing and has been removed.

Getting started as a collaborator#

You don't need to link or claim anything. The app's wrangler.toml already carries its DEEPSPACE_APP_ID, which is the whole authorization key.

Get the code

npx deepspace clone <app-name>
cd <app-name>
npm install
bash

Or clone the GitHub repo if the app uses GitHub source.

A DeepSpace-source app has no leased name before its first deploy, so clone it by id in that case: npx deepspace clone <app-id> (once you are added, your own deepspace app list shows the id; it is also in the repo's wrangler.toml). After the first deploy, the name resolves too.

Sign in

npx deepspace auth login
bash

Work normally

npx deepspace dev start
npx deepspace test run
npx deepspace deploy
bash

No linking step. Access is resolved from the app id on every request.

If you actually wanted your own separate copy rather than to collaborate, run npx deepspace app init --new-id to fork the checkout into a distinct app with fresh data and a fresh secrets store.

Revoking access#

npx deepspace app collaborators remove teammate@example.com
bash

Removal takes effect immediately for authorization: the next deploy, secrets, or dev call from that user is refused with a 403 Not the app owner or a collaborator.

To rescind an invite that was never accepted, use cancel rather than remove - the person is not a collaborator yet, so remove refuses with not_a_collaborator.

Troubleshooting#

403 Not the app owner or a collaborator on deploy or secrets. Either you were never added, your access was revoked, or you are signed in as a different account than the one that was invited. Check with npx deepspace auth whoami.

The invitee never got the email. Confirm the invite is live with collaborators list. If a pending row exists but no email arrived, cancel <email> and then add again - a re-add against a live row short-circuits without sending.

See also#