@kontextmind/kxm
Version:
KXM local-first multi-agent orchestration and operator dashboard
67 lines (53 loc) • 2.37 kB
Markdown
---
schema: "kxm.doc.v1"
id: "KB-BROWSER-008"
type: "kb"
title: "How do I recover an expired session or remove an orphaned browser?"
project: "kxm"
status: "accepted"
owner: "@operator"
created: "2026-09-14"
updated: "2026-09-27"
authority: "instruction"
confidence: "verified"
summary: "Find and release stale or orphaned browser sessions on Steel."
tags: ["browser", "cleanup", "orphans", "troubleshooting"]
related: ["docs/guides/browser-automation.md", "docs/kb/why-authentication-disappeared.md"]
---
# How do I recover an expired session or remove an orphaned browser?
If an automation run crashed or disconnected without releasing its session, the
browser can keep running on your Steel deployment until its timeout.
## 1. List active sessions
Load the `svc-steel` credential from 1Password into this process. Do not write
it to disk. `STEEL_API_URL` defaults to `https://steel.kontextmind.com`.
`STEEL_API_KEY` is deprecated and is not enforced.
```bash
export STEEL_AUTH_BASIC="$(op read 'op://kontextmind/Steel (svc-steel)/basic_auth')"
case "$STEEL_AUTH_BASIC" in
Basic\ *) header="$STEEL_AUTH_BASIC" ;;
*) header="Basic $STEEL_AUTH_BASIC" ;;
esac
printf 'Authorization: %s\n' "$header" | curl -sS -H @- "${STEEL_API_URL:-https://steel.kontextmind.com}/v1/sessions" | jq .
```
## 2. Release an orphaned session
```bash
printf 'Authorization: %s\n' "$header" \
| curl -sS -X POST -H @- "${STEEL_API_URL:-https://steel.kontextmind.com}/v1/sessions/<session-id>/release"
```
## 3. Sweep orphans with the KXM client
`checkOrphanedSessions(maxIdleMs)` returns two kinds of session: live or idle
sessions this client does not track that have run longer than the limit, and
tracked sessions idle longer than the limit, unless a person has taken over.
`releaseSession()` releases one:
```typescript
import { SteelClient } from "@kontextmind/kxm/runtime";
const client = new SteelClient();
const orphans = await client.checkOrphanedSessions(600000); // idle over 10 minutes
for (const sessionId of orphans) {
console.log(`Releasing orphaned session: ${sessionId}`);
await client.releaseSession(sessionId);
}
```
It returns an empty list when the Steel API responds with an error status, so
an empty result does not prove there are no orphans. A 302 from Authentik
throws instead of looking like an empty list. Check with the `curl` call above.