Skip to main content

Install visibility: debug vs production

An app_id is globally unique - there is exactly one install row per app_id on a daemon, never one row per user. What Digitorn actually gives you at install time is a visibility state machine (production / debug) plus an owner, and it exists for one purpose: letting you test a build in Studio before anyone else can see it.

VisibilitySet byWho sees itWho can run it
production (default)Any install that doesn't request debugEveryone on the daemonEveryone
debugStudio's Install for TestOnly the owner (and admins)Only the owner (and admins)

This is the same debug/production distinction documented in Digitorn Studio

  • this page is the mechanism behind it, not a separate feature.

What "owner" means here​

Installing sets owner_user_id from the caller's JWT automatically

  • there's no request field to choose it. A debug install requires an owner (the daemon rejects an anonymous debug install); a production install can have an owner or not.
jsonc
// POST /api/apps/install
{
"source": "https://.../my-app.yaml",
"accept_permissions": true
}

That's the whole request shape - source and (for Hub sources that need a consent step) accept_permissions. There's no scope field, no source_type/source_uri split, and no CLI flag to request a particular visibility: digitorn install always installs at production. Only Studio's own install action can request debug.

The debug → production lifecycle​

  1. Install for Test (Studio) installs the app at debug, owned by the person testing it. It's invisible to everyone else - the default app listing hides debug installs entirely, and even an explicit lookup by ID returns "not found" for anyone but the owner.
  2. Publish (Studio) promotes that same row from debug to production - a same-row flip, not a second install. Only the owner can promote it. Once promoted, everyone on the daemon can see and run it, and the app stays associated with that owner for ?mine=1 filtering afterward.

Because there's one row per app_id, a few conflicts are enforced when you install again:

  • You can't debug-install over an app_id that's already production (refused as a conflict).
  • You can't debug-install an app_id someone else already holds at debug (refused as forbidden).
  • You can't production-install over an app_id someone else owns, unless you're that app's publisher.

Listing your own installs​

bash
GET /api/apps?mine=1        # only your own installs (debug + production)
GET /api/apps # production installs, everyone's
GET /api/apps?include_debug=1 # also show debug installs (tooling)

What this is not​

There's no per-user private copy of a shared app: if you want each user to get their own isolated instance of the same template, that's a separate install per app_id you'd have to name differently per user - the daemon has no built-in mechanism for one app_id to resolve to different definitions depending on who's asking.

Isolation within one shared app instance - so concurrent users of the same production app don't see each other's data - comes from two unrelated mechanisms:

  • Per-user credentials - credential.scope: per_user stores a secret encrypted per (user_id, provider) - the only scope with real behavior today, see credentials.md.
  • Per-session memory - goals, facts, and tasks are keyed by session id, and a session belongs to one user, so two users' sessions never share state. See Cognitive Memory.

Cross-references​