Skip to main content

Re-own the shared agent

The symptom. Every chat turn fails, immediately and identically, with a message ending:

Agent 'prism' already exists but is not reachable by 'prism-provisioner' —
it is owned by another identity and not scoped to the shared workspace, so it
can be neither used nor replaced. It needs re-owning in the runner database:
an administrator runs reown_shared_agent.py once. See 'Re-own the shared
agent' in the Prism install docs.

Nothing else is wrong. The self test's runner line is green, sign-in works, ingest keeps running, and no upgrade fixes it.

Why. Prism keeps one agent that everybody chats to. Older versions created it as whichever person chatted first and shared it by a flag the runner has since stopped reading; current versions create it as a fixed identity, prism-provisioner, and share it through a workspace. An install created before that change and upgraded since is left with an agent row owned by somebody the app can no longer act as — and the agent's name is unique, so the app can neither use it nor create a replacement. It is one row, created once, that no upgrade migrates.

This is a one-off repair. Afterwards Prism adopts the agent into the shared workspace by itself, on the next chat turn.

What it does not touch. Only the agent row and the MCP profiles attached to it, and only their owner. No chat history, no sessions, no feedback, no ingested data, and nothing belonging to any other agent.

Before you start​

You need three things:

  • The script, scripts/reown_shared_agent.py, in the chart tarball beside the docs you are reading — helm pull and untar leaves it at prism/scripts/reown_shared_agent.py.
  • The runner database DSN, which is the runner-database-url key of the install's Secret. It already has the right host, database, user, password and sslmode; use it as it stands rather than rebuilding it.
  • Somewhere to run it with Python 3 and asyncpg, that can reach that database. If the database has no route from your workstation — a private endpoint, a peered network — the prism-app container already has both, and the second recipe below runs the script inside it without installing anything.

Read the DSN out of the Secret:

RUNNER_DSN=$(kubectl get secret <secret name> -n <namespace> \
-o jsonpath='{.data.runner-database-url}' | base64 -d)

The Secret is <release>-secrets unless you set existingSecret, in which case it is yours and you know its name.

Confirm the three values that identify the row, from the app's own environment — the script defaults to internal, default and prism, which is right for most installs and wrong for any install that set them:

kubectl exec deploy/<release>-app -n <namespace> -- \
printenv CUSTOMER_ID PROJECT_ID AGENT_SLUG

Pass anything that differs as --customer, --project and --slug.

Step 1 — the dry run​

The script writes nothing unless you pass --apply, so the first run is a report. From a machine that can reach the database:

python3 prism/scripts/reown_shared_agent.py --dsn "$RUNNER_DSN"

If the database is only reachable from inside the cluster, pipe the script into the app's container, which has Python and asyncpg already:

kubectl exec -i deploy/<release>-app -n <namespace> -- \
env RUNNER_DATABASE_URL="$RUNNER_DSN" python3 - \
< prism/scripts/reown_shared_agent.py

Both print the same thing: the agent's id, its current owner, the workspace it is in (left alone deliberately — that is the part Prism repairs itself), and every MCP profile attached to it with its owner.

Read the output before you go on. Three outcomes:

What it saysWhat it means
would re-own to 'prism-provisioner': the agent, N profile(s)This is the fault. Continue.
already owned by 'prism-provisioner' — nothing to doWhatever is wrong, it is not this. Stop, and see Troubleshooting.
no agent 'prism' in .../... — nothing to repairYou are looking at the wrong database, or the wrong customer, project or slug. Check them before running anything else.

The owner it reports will be an identity nobody recognises — an id from the directory, not an email address. That is expected, and is the whole fault: it is an id no later sign-in ever reproduced.

Step 2 — apply​

Whichever of the two you ran, the same command again with --apply on the end. In the piped form that goes before the <, not after it — everything after python3 - is an argument to the script:

python3 prism/scripts/reown_shared_agent.py --dsn "$RUNNER_DSN" --apply

kubectl exec -i deploy/<release>-app -n <namespace> -- \
env RUNNER_DATABASE_URL="$RUNNER_DSN" python3 - --apply \
< prism/scripts/reown_shared_agent.py

It moves the owner of the agent and of its attached MCP profiles, in one transaction, and prints applied.. Re-running it changes nothing — the second run reports already owned.

Step 3 — prove it​

Ask Prism a question. The turn that failed before now answers, and the first one also does the adoption the script left alone: the agent and its profiles join the shared workspace, so every other user is fixed by the same turn.

Then run the self test, which exercises the same provisioning path deliberately rather than incidentally.

If it does not work​

Send us the dry run output — not the apply — plus the error the chat turn gives afterwards. The dry run names the ids and owners involved and contains no credential, so it is the one artefact worth attaching.

Two failures worth recognising first:

  • unrecognized configuration parameter on connecting means the DSN carried something the script did not strip. It strips uselibpqcompat, the one the chart adds; report the rest.
  • A connection that hangs or is refused is the route, not the repair. The database is not reachable from where you ran it; use the in-cluster recipe in step 1.