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 pulland untar leaves it atprism/scripts/reown_shared_agent.py. - The runner database DSN, which is the
runner-database-urlkey of the install's Secret. It already has the right host, database, user, password andsslmode; 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 — theprism-appcontainer 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 says | What 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 do | Whatever is wrong, it is not this. Stop, and see Troubleshooting. |
no agent 'prism' in .../... — nothing to repair | You 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 parameteron connecting means the DSN carried something the script did not strip. It stripsuselibpqcompat, 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.