@kontextmind/kxm 0.7.95 → 0.7.97

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.kxm/README.md +39 -9
  3. package/CHANGELOG.md +23 -1
  4. package/README.md +147 -257
  5. package/SECURITY.md +21 -12
  6. package/docs/README.md +133 -54
  7. package/docs/adr/ADR-0002-browser-automation-steel-doks.md +24 -18
  8. package/docs/adr/ADR-0003-sqlite-only-store.md +100 -0
  9. package/docs/adr/ADR-0004-edge-identity-authentik.md +99 -0
  10. package/docs/adr/README.md +33 -0
  11. package/docs/concepts/architecture.md +262 -0
  12. package/docs/concepts/data-and-storage.md +194 -0
  13. package/docs/concepts/trust-model.md +153 -0
  14. package/docs/contracts/README.md +22 -14
  15. package/docs/contracts/effects-and-recovery.md +3 -0
  16. package/docs/contracts/migration.md +2 -2
  17. package/docs/contracts/routing.md +6 -5
  18. package/docs/contributing/assignment-runner.md +388 -0
  19. package/docs/contributing/ci-and-release.md +231 -0
  20. package/docs/contributing/development.md +362 -0
  21. package/docs/contributing/harness-routing-internals.md +192 -0
  22. package/docs/{packages.md → contributing/packages.md} +13 -15
  23. package/docs/{skills → contributing}/repo-work-delivery.md +20 -21
  24. package/docs/contributing/test-matrix.md +208 -0
  25. package/docs/{tui-components.md → contributing/tui-components.md} +30 -22
  26. package/docs/contributing/writing-docs.md +340 -0
  27. package/docs/glossary.md +471 -0
  28. package/docs/guides/agent-skills.md +137 -0
  29. package/docs/guides/browser-automation.md +160 -0
  30. package/docs/guides/context-and-memory.md +352 -0
  31. package/docs/guides/continuous-improvement.md +228 -0
  32. package/docs/guides/governed-skills.md +173 -0
  33. package/docs/guides/nous-providers.md +186 -0
  34. package/docs/guides/peer-messaging.md +304 -0
  35. package/docs/guides/pi-workers.md +219 -0
  36. package/docs/guides/provenance-gates.md +313 -0
  37. package/docs/guides/webhook-workflows.md +399 -0
  38. package/docs/kb/how-credentials-retrieved-safely.md +38 -12
  39. package/docs/kb/how-to-capture-and-annotate-section.md +15 -13
  40. package/docs/kb/how-to-connect-playwright-to-steel.md +16 -11
  41. package/docs/kb/how-to-recover-expired-session-or-orphan.md +26 -16
  42. package/docs/kb/how-to-resume-after-mfa.md +19 -11
  43. package/docs/kb/how-to-take-over-session.md +17 -13
  44. package/docs/kb/why-authentication-disappeared.md +22 -14
  45. package/docs/kb/why-automation-opened-different-browser.md +23 -14
  46. package/docs/kb/why-session-viewer-cannot-control.md +13 -12
  47. package/docs/operations/backup-and-restore.md +248 -0
  48. package/docs/operations/deploy.md +307 -0
  49. package/docs/operations/monitoring.md +209 -0
  50. package/docs/operations/runtime-sync.md +192 -0
  51. package/docs/operations/troubleshooting.md +266 -0
  52. package/docs/operations/upgrade.md +124 -0
  53. package/docs/prompts/browser-annotate-feedback.md +7 -7
  54. package/docs/prompts/browser-diagnose-recover.md +11 -10
  55. package/docs/prompts/browser-explore.md +7 -7
  56. package/docs/prompts/browser-repro-fix.md +7 -7
  57. package/docs/prompts/browser-start.md +12 -11
  58. package/docs/prompts/browser-takeover.md +8 -8
  59. package/docs/{cli-reference.md → reference/cli-reference.md} +88 -46
  60. package/docs/{config-reference.md → reference/config-reference.md} +159 -148
  61. package/docs/reference/configuration.md +299 -0
  62. package/docs/reference/harness-routing.md +508 -0
  63. package/docs/reference/http-api.md +203 -0
  64. package/docs/reference/tools.md +370 -0
  65. package/docs/{workflow-guide.md → reference/workflow-catalog.md} +92 -153
  66. package/docs/reference/workflow-definitions.md +286 -0
  67. package/docs/start/first-workflow.md +287 -0
  68. package/docs/start/install.md +146 -0
  69. package/docs/start/quickstart-claude-code.md +405 -0
  70. package/docs/start/quickstart-pi.md +213 -0
  71. package/docs/templates/README.md +78 -73
  72. package/docs/templates/adr.md +13 -13
  73. package/docs/templates/architecture.md +55 -71
  74. package/docs/templates/bug-fix.md +13 -16
  75. package/docs/templates/feature.md +14 -19
  76. package/docs/templates/handoff.md +44 -46
  77. package/docs/templates/postmortem.md +30 -43
  78. package/docs/templates/research.md +15 -20
  79. package/docs/templates/review.md +49 -50
  80. package/docs/templates/runbook.md +38 -30
  81. package/docs/templates/test-plan.md +16 -23
  82. package/docs/templates/test-report.md +14 -17
  83. package/examples/README.md +9 -5
  84. package/examples/provenance-workflow.json +1 -1
  85. package/examples/webhook-workflows/jira-development.json +59 -0
  86. package/examples/webhook-workflows/jira-issue-updated.json +12 -0
  87. package/examples/workflow-signal.ts +4 -5
  88. package/package.json +1 -1
  89. package/packages/core/tui/README.md +1 -1
  90. package/plugins/kxm/.claude-plugin/plugin.json +1 -1
  91. package/plugins/kxm/README.md +31 -32
  92. package/plugins/kxm/dist/claude-hook.js +11 -1
  93. package/plugins/kxm/dist/cli.js +164 -79
  94. package/plugins/kxm/dist/client.js +3 -1
  95. package/plugins/kxm/dist/core.js +11 -1
  96. package/plugins/kxm/dist/extension.js +45 -13
  97. package/plugins/kxm/dist/mcp-server.js +20 -4
  98. package/plugins/kxm/dist/runtime-supervisor.js +1 -3
  99. package/plugins/kxm/dist/runtime.js +18 -4
  100. package/plugins/kxm/dist/server.js +115 -20
  101. package/plugins/kxm/package.json +1 -1
  102. package/plugins/kxm/skills/kxm/references/protocol.md +3 -1
  103. package/plugins/kxm/skills/kxm-browser-auth/SKILL.md +1 -1
  104. package/plugins/kxm/skills/kxm-browser-diagnostics/SKILL.md +5 -5
  105. package/plugins/kxm/skills/kxm-browser-explore/SKILL.md +2 -2
  106. package/plugins/kxm/skills/kxm-browser-session/SKILL.md +10 -13
  107. package/plugins/kxm/skills/kxm-browser-takeover/SKILL.md +1 -1
  108. package/plugins/kxm/skills/kxm-browser-verify/SKILL.md +1 -1
  109. package/plugins/kxm/skills/kxm-context-memory/SKILL.md +13 -4
  110. package/plugins/kxm/skills/kxm-hub-ops/SKILL.md +3 -1
  111. package/plugins/kxm/skills/kxm-mind-setup/SKILL.md +2 -1
  112. package/plugins/kxm/skills/kxm-project-setup/SKILL.md +31 -54
  113. package/plugins/kxm/skills/kxm-projects/SKILL.md +1 -1
  114. package/plugins/kxm/skills/kxm-protocol/SKILL.md +1 -1
  115. package/plugins/kxm/skills/kxm-routing-improve/SKILL.md +15 -7
  116. package/plugins/kxm/skills/kxm-runs/SKILL.md +11 -5
  117. package/plugins/kxm/skills/kxm-session/SKILL.md +1 -1
  118. package/plugins/kxm/skills/kxm-tasks/SKILL.md +9 -7
  119. package/plugins/kxm/skills/kxm-workflow/SKILL.md +10 -2
  120. package/plugins/kxm/src/cli/system.ts +1 -1
  121. package/plugins/kxm/src/cli/workflows.ts +12 -7
  122. package/plugins/kxm/src/cli.ts +22 -8
  123. package/plugins/kxm/src/client.ts +4 -0
  124. package/plugins/kxm/src/commands.ts +23 -1
  125. package/plugins/kxm/src/extension.ts +20 -14
  126. package/plugins/kxm/src/github-watch.ts +8 -5
  127. package/plugins/kxm/src/hub-env.ts +19 -1
  128. package/plugins/kxm/src/hub.ts +105 -21
  129. package/plugins/kxm/src/improve-sources.ts +2 -7
  130. package/plugins/kxm/src/init-guide-setup.ts +1 -1
  131. package/plugins/kxm/src/mcp-server.ts +9 -2
  132. package/plugins/kxm/src/modes.ts +1 -1
  133. package/plugins/kxm/src/runtime-store.ts +23 -0
  134. package/plugins/kxm/src/workflow.ts +70 -1
  135. package/schemas/README.md +1 -1
  136. package/scripts/smoke-multi-pi.mjs +5 -1
  137. package/docs/agent-communication-envelopes-and-gates.md +0 -553
  138. package/docs/agent-skills.md +0 -198
  139. package/docs/architecture.md +0 -245
  140. package/docs/assignment-runner.md +0 -264
  141. package/docs/browser-automation.md +0 -139
  142. package/docs/configuration.md +0 -437
  143. package/docs/continuous-improvement.md +0 -226
  144. package/docs/getting-started.md +0 -277
  145. package/docs/harness-routing.md +0 -616
  146. package/docs/kb/qa-authentik-authentication.md +0 -97
  147. package/docs/kb/qa-extension-install-and-hub-bootstrap.md +0 -85
  148. package/docs/kb/qa-hub-on-a-public-host.md +0 -48
  149. package/docs/kb/qa-sqlite-vs-duckdb.md +0 -35
  150. package/docs/kb/qa-what-the-hub-stores.md +0 -64
  151. package/docs/kxm-handbook.md +0 -1181
  152. package/docs/operations.md +0 -510
  153. package/docs/operator-pi-packages.md +0 -67
  154. package/docs/provenance-gates.md +0 -295
  155. package/docs/skills.md +0 -47
  156. package/docs/test-matrix.md +0 -132
  157. package/docs/troubleshooting.md +0 -322
  158. package/docs/webhook-workflows.md +0 -240
@@ -7,48 +7,58 @@ project: "kxm"
7
7
  status: "accepted"
8
8
  owner: "@operator"
9
9
  created: "2026-09-14"
10
- updated: "2026-09-14"
10
+ updated: "2026-09-23"
11
11
  authority: "instruction"
12
12
  confidence: "verified"
13
- summary: "Procedures for detecting and releasing stale or orphaned browser sessions on Steel."
13
+ summary: "Find and release stale or orphaned browser sessions on Steel."
14
14
  tags: ["browser", "cleanup", "orphans", "troubleshooting"]
15
- related: ["docs/browser-automation.md", "docs/kb/why-authentication-disappeared.md"]
15
+ related: ["docs/guides/browser-automation.md", "docs/kb/why-authentication-disappeared.md"]
16
16
  ---
17
17
 
18
18
  # How do I recover an expired session or remove an orphaned browser?
19
19
 
20
- If an automation run crashed or disconnected without calling `/release`, a browser container may remain idling on DOKS.
20
+ If an automation run crashed or disconnected without releasing its session, the
21
+ browser can keep running on your Steel deployment until its timeout.
21
22
 
22
- ## 1. List Active Remote Sessions
23
+ ## 1. List active sessions
24
+
25
+ Load `STEEL_API_URL` and `STEEL_API_KEY` from your secret manager first. With
26
+ `pass-cli`, for example:
23
27
 
24
28
  ```bash
25
- STEEL_KEY=$(pass-cli item view --vault-name "AI Provider Keys" --item-title "Steel Browser (KontextMind DOKS)" --field STEEL_API_KEY)
29
+ export STEEL_API_URL="https://<steel-host>"
30
+ STEEL_API_KEY=$(pass-cli item view --vault-name "<vault>" --item-title "<item>" --field STEEL_API_KEY)
31
+ export STEEL_API_KEY
26
32
 
27
- curl -s https://steel.kontextmind.com/v1/sessions \
28
- -H "x-steel-api-key: $STEEL_KEY" | jq .
33
+ curl -s "$STEEL_API_URL/v1/sessions" \
34
+ -H "x-steel-api-key: $STEEL_API_KEY" | jq .
29
35
  ```
30
36
 
31
- ## 2. Release Orphaned Sessions
32
-
33
- To terminate a specific stale session:
37
+ ## 2. Release an orphaned session
34
38
 
35
39
  ```bash
36
- curl -s -X POST https://steel.kontextmind.com/v1/sessions/<SESSION_ID>/release \
37
- -H "x-steel-api-key: $STEEL_KEY"
40
+ curl -s -X POST "$STEEL_API_URL/v1/sessions/<session-id>/release" \
41
+ -H "x-steel-api-key: $STEEL_API_KEY"
38
42
  ```
39
43
 
40
- ## 3. Automatic Orphan Sweeping via KXM Client
44
+ ## 3. Sweep orphans with the KXM client
41
45
 
42
- The KXM client provides `checkOrphanedSessions(maxIdleMs)` to automate this:
46
+ `checkOrphanedSessions(maxIdleMs)` returns two kinds of session: live or idle
47
+ sessions this client does not track that have run longer than the limit, and
48
+ tracked sessions idle longer than the limit, unless a person has taken over.
49
+ `releaseSession()` releases one:
43
50
 
44
51
  ```typescript
45
52
  import { SteelClient } from "@kontextmind/kxm/runtime";
46
53
 
47
54
  const client = new SteelClient();
48
- const orphans = await client.checkOrphanedSessions(600000); // > 10 min idle
55
+ const orphans = await client.checkOrphanedSessions(600000); // idle over 10 minutes
49
56
 
50
57
  for (const sessionId of orphans) {
51
58
  console.log(`Releasing orphaned session: ${sessionId}`);
52
59
  await client.releaseSession(sessionId);
53
60
  }
54
61
  ```
62
+
63
+ It returns an empty list when the Steel API request fails, so an empty result
64
+ does not prove there are no orphans. Check with the `curl` call above.
@@ -7,22 +7,30 @@ project: "kxm"
7
7
  status: "accepted"
8
8
  owner: "@operator"
9
9
  created: "2026-09-14"
10
- updated: "2026-09-14"
10
+ updated: "2026-09-23"
11
11
  authority: "instruction"
12
12
  confidence: "verified"
13
- summary: "Details the verification and observation refresh sequence when resuming automation after MFA."
13
+ summary: "The verification and observation refresh an agent performs before resuming after MFA."
14
14
  tags: ["browser", "mfa", "resume", "verification"]
15
- related: ["docs/kb/how-to-take-over-session.md", "docs/browser-automation.md"]
15
+ related: ["docs/kb/how-to-take-over-session.md", "docs/guides/browser-automation.md"]
16
16
  ---
17
17
 
18
18
  # How does an agent resume after MFA?
19
19
 
20
- Once the human completes the MFA challenge in the browser viewer, the agent must not immediately execute blind clicks. It follows this sequence:
20
+ After you complete an MFA challenge in the session viewer, the agent does not
21
+ click blindly. It follows this sequence:
21
22
 
22
- 1. **State Transition**: Moves from `HUMAN_CONTROL` to `VERIFY_AUTHENTICATION`.
23
- 2. **CDP Re-attachment**: Re-queries the active tab target from the remote Steel CDP endpoint.
24
- 3. **App State Verification**:
25
- - Inspects `page.url()` to confirm the browser navigated away from the MFA prompt to the intended destination (e.g. `/dashboard` or `/overview`).
26
- - Checks for authenticated elements (e.g. account menu, logout button, user profile avatar).
27
- 4. **Observation Refresh**: Runs a fresh `agent-browser snapshot` or queries fresh DOM locators before executing the next action.
28
- 5. **Restore Control**: Returns to `AGENT_CONTROL` and proceeds with the task.
23
+ 1. **State transition.** The session moves from `HUMAN_CONTROL` to
24
+ `VERIFY_AUTHENTICATION`. The `SteelClient` keeps this state in memory for
25
+ its own lifetime; a new client does not inherit it.
26
+ 2. **CDP re-attachment.** The agent re-queries the active tab from the Steel
27
+ CDP endpoint.
28
+ 3. **Application state check.**
29
+ - It confirms that `page.url()` left the MFA prompt for the intended page,
30
+ for example `/dashboard`.
31
+ - It looks for signed-in elements such as an account menu or a sign-out
32
+ button.
33
+ 4. **Observation refresh.** It takes a fresh `agent-browser snapshot`, or
34
+ queries fresh DOM locators, before the next action.
35
+ 5. **Control returns.** The session returns to `AGENT_CONTROL` and the task
36
+ continues.
@@ -7,26 +7,30 @@ project: "kxm"
7
7
  status: "accepted"
8
8
  owner: "@operator"
9
9
  created: "2026-09-14"
10
- updated: "2026-09-14"
10
+ updated: "2026-09-23"
11
11
  authority: "instruction"
12
12
  confidence: "verified"
13
- summary: "Instructions for taking over an active Steel browser session during an authentication gate."
13
+ summary: "Take over an active Steel browser session at an authentication gate."
14
14
  tags: ["browser", "takeover", "auth", "mfa"]
15
- related: ["docs/browser-automation.md", "docs/kb/how-to-resume-after-mfa.md"]
15
+ related: ["docs/guides/browser-automation.md", "docs/kb/how-to-resume-after-mfa.md"]
16
16
  ---
17
17
 
18
18
  # How do I take over a browser session to log in?
19
19
 
20
- When an agent encounters a login screen, OAuth prompt, or security challenge, it triggers the `kxm-browser-takeover` protocol.
20
+ When an agent reaches a login screen, an OAuth prompt or a security challenge,
21
+ it stops and asks you to take over, following the `kxm-browser-takeover` skill.
21
22
 
22
23
  ## Steps
23
24
 
24
- 1. **Copy the Takeover URL**:
25
- The agent will emit a message in the terminal with a link like:
26
- `https://steel.kontextmind.com/ui?sessionId=<SESSION_ID>`
27
- 2. **Open the Session Viewer**:
28
- Open that URL in your desktop browser. You will see the live screencast of the exact remote Chrome container the agent was operating.
29
- 3. **Interact and Authenticate**:
30
- Enter the username, password, or security key into the session, or use the devtools inspector (`https://steel.kontextmind.com/v1/devtools/inspector.html`) to trigger the submission.
31
- 4. **Signal Completion**:
32
- Return to your Herdr or Pi terminal session and notify the agent: `auth complete` or `proceed`.
25
+ 1. **Copy the takeover URL.** The agent prints a session viewer link such as
26
+ `<steel-ui-url>?sessionId=<session-id>`. The viewer URL is `STEEL_UI_URL`,
27
+ or `<steel-api-url>/ui` when that is unset.
28
+ 2. **Open the session viewer** in your desktop browser. It shows a live
29
+ screencast of the remote browser the agent was driving.
30
+ 3. **Sign in.** Enter the username, password or security key in the session.
31
+ If clicks on the screencast do not register, use the DevTools inspector at
32
+ `<steel-api-url>/v1/devtools/inspector.html`; see
33
+ [Why can I view a session but not control it?](why-session-viewer-cannot-control.md).
34
+ 4. **Signal completion.** Return to the agent's terminal session and tell it
35
+ `auth complete` or `proceed`. It then verifies the sign-in before it resumes;
36
+ see [How does an agent resume after MFA?](how-to-resume-after-mfa.md).
@@ -7,26 +7,34 @@ project: "kxm"
7
7
  status: "accepted"
8
8
  owner: "@operator"
9
9
  created: "2026-09-14"
10
- updated: "2026-09-14"
10
+ updated: "2026-09-23"
11
11
  authority: "instruction"
12
12
  confidence: "verified"
13
- summary: "Diagnosing lost authentication state, session expiration, and ephemeral container recreation."
13
+ summary: "Diagnose lost sign-in state: session expiry, a new session instead of an attached one, and cookie scoping."
14
14
  tags: ["browser", "authentication", "cookies", "troubleshooting"]
15
- related: ["docs/browser-automation.md", "docs/kb/why-automation-opened-different-browser.md"]
15
+ related: ["docs/guides/browser-automation.md", "docs/kb/why-automation-opened-different-browser.md"]
16
16
  ---
17
17
 
18
18
  # Why did authentication disappear?
19
19
 
20
- If an agent was authenticated on a previous step or run and suddenly encounters a login screen again, the root causes are typically:
20
+ If an agent was signed in on an earlier step or run and now sees a login screen
21
+ again, one of these is usually the cause.
21
22
 
22
- ## Root Causes & Fixes
23
+ ## Causes and fixes
23
24
 
24
- 1. **Session Released or Expired**:
25
- - Steel sessions are ephemeral by default. Once a session reaches its timeout (e.g. 5–30 minutes) or is released via `POST /v1/sessions/:id/release`, all memory cookies and local storage are cleared.
26
- - **Fix**: To reuse state across tasks, save `storageState` via Playwright and reload it on the next session initialization.
27
- 2. **New Session Launched Instead of Attaching**:
28
- - If the agent created a brand-new session instead of passing the existing `sessionId`, it opened a clean Chrome profile.
29
- - **Fix**: Verify that the task passes `sessionId` to `getSession()` or uses the existing CDP endpoint.
30
- 3. **Domain / Subdomain Cookie Scoping**:
31
- - OAuth flows often set cookies on subdomains (e.g., `auth.example.com`) that do not automatically share with `app.example.com`.
32
- - **Fix**: Ensure cookies were issued for the primary domain or that SSO redirect completed fully before saving state.
25
+ 1. **The session was released or expired.**
26
+ - Steel sessions are ephemeral. When a session reaches its timeout (the KXM
27
+ client defaults to five minutes) or is released through
28
+ `POST /v1/sessions/<session-id>/release`, its cookies and local storage
29
+ are gone.
30
+ - **Fix:** to reuse sign-in state across tasks, save Playwright
31
+ `storageState` and load it when you start the next session.
32
+ 2. **A new session was launched instead of attaching to the existing one.**
33
+ - A new session starts with a clean browser profile.
34
+ - **Fix:** make sure the task passes the existing `sessionId` to
35
+ `getSession()`, or connects to the existing CDP endpoint.
36
+ 3. **Cookies were scoped to another domain.**
37
+ - Sign-in flows often set cookies on a subdomain, such as
38
+ `auth.example.com`, that `app.example.com` does not receive.
39
+ - **Fix:** make sure the cookies were issued for the primary domain, or that
40
+ the single sign-on redirect finished, before you save state.
@@ -7,26 +7,35 @@ project: "kxm"
7
7
  status: "accepted"
8
8
  owner: "@operator"
9
9
  created: "2026-09-14"
10
- updated: "2026-09-14"
10
+ updated: "2026-09-23"
11
11
  authority: "instruction"
12
12
  confidence: "verified"
13
- summary: "Preventing accidental local browser launches and ensuring Playwright and agent-browser connect to remote Steel."
13
+ summary: "Prevent accidental local browser launches and make Playwright and agent-browser attach to remote Steel."
14
14
  tags: ["browser", "cdp", "playwright", "agent-browser", "troubleshooting"]
15
- related: ["docs/browser-automation.md", "docs/kb/how-to-connect-playwright-to-steel.md"]
15
+ related: ["docs/guides/browser-automation.md", "docs/kb/how-to-connect-playwright-to-steel.md"]
16
16
  ---
17
17
 
18
18
  # Why did automation open a different browser?
19
19
 
20
- If you expected automation to run on DOKS Steel but saw a local Chrome window pop up or failed to see the agent's actions in the Steel session viewer:
20
+ You expected automation to run on your Steel deployment, but a local Chrome
21
+ window opened, or the agent's actions never appeared in the Steel session
22
+ viewer.
21
23
 
22
- ## Root Causes
24
+ ## Causes
23
25
 
24
- 1. **Called `chromium.launch()` Instead of `chromium.connectOverCDP()`**:
25
- - `chromium.launch()` spawns a local browser process on the workstation.
26
- - **Fix**: In Playwright, always use `chromium.connectOverCDP(cdpUrl)`.
27
- 2. **Missing `--cdp` Flag in `agent-browser`**:
28
- - Running `agent-browser open <url>` without `--cdp` spawns a local headless browser.
29
- - **Fix**: Always pass `--cdp "wss://steel.kontextmind.com/v1/devtools?sessionId=<id>&apiKey=<key>"`.
30
- 3. **Missing Environment Variables**:
31
- - If `STEEL_CDP_URL` is undefined, scripts that fall back to local execution will launch a local browser.
32
- - **Fix**: Ensure `STEEL_CDP_URL` or `STEEL_API_KEY` is loaded from `pass-cli`.
26
+ 1. **The script called `chromium.launch()` instead of
27
+ `chromium.connectOverCDP()`.**
28
+ - `chromium.launch()` starts a browser on the local machine.
29
+ - **Fix:** in Playwright, connect with `chromium.connectOverCDP(cdpUrl)`.
30
+ 2. **`agent-browser` ran without `--cdp`.**
31
+ - `agent-browser open <url>` without `--cdp` starts a local headless
32
+ browser.
33
+ - **Fix:** always pass the session's CDP URL:
34
+ `--cdp "wss://<steel-host>/v1/devtools?sessionId=<session-id>&apiKey=<steel-api-key>"`.
35
+ Build it with `formatCDPEndpoint()`; see
36
+ [How do I connect Playwright to the existing Steel session?](how-to-connect-playwright-to-steel.md).
37
+ 3. **Environment variables were missing.**
38
+ - A script that falls back to local execution when `STEEL_CDP_URL` is
39
+ unset launches a local browser.
40
+ - **Fix:** load `STEEL_CDP_URL`, or `STEEL_API_URL` and `STEEL_API_KEY`,
41
+ from your secret manager before the run.
@@ -7,25 +7,26 @@ project: "kxm"
7
7
  status: "accepted"
8
8
  owner: "@operator"
9
9
  created: "2026-09-14"
10
- updated: "2026-09-14"
10
+ updated: "2026-09-23"
11
11
  authority: "instruction"
12
12
  confidence: "verified"
13
- summary: "Understanding self-hosted Steel OSS screencast viewer capabilities vs devtools inspector input modes."
13
+ summary: "The self-hosted Steel screencast viewer versus the DevTools inspector for interactive control."
14
14
  tags: ["browser", "takeover", "steel", "ui"]
15
- related: ["docs/browser-automation.md", "docs/kb/how-to-take-over-session.md"]
15
+ related: ["docs/guides/browser-automation.md", "docs/kb/how-to-take-over-session.md"]
16
16
  ---
17
17
 
18
18
  # Why can I view a session but not control it?
19
19
 
20
- In self-hosted open-source Steel (`steel-dev/steel-browser`), the web UI at `/ui` provides a real-time screencast stream, event logs, and network tracking. Depending on browser canvas capture modes, direct clicks on the video canvas may not send synthetic mouse events.
20
+ In self-hosted open-source Steel (`steel-dev/steel-browser`), the web UI at
21
+ `/ui` shows a live screencast, event logs and network activity. Depending on how
22
+ the canvas is captured, clicks on the video may not reach the browser.
21
23
 
22
24
  ## Resolution
23
25
 
24
- 1. **Use the Chrome DevTools Inspector**:
25
- Navigate to the devtools inspector page for the session:
26
- `https://steel.kontextmind.com/v1/devtools/inspector.html`
27
- or open the remote debugger on port 9223.
28
- 2. **Interact via the DOM Console**:
29
- The devtools inspector gives full interactive control over the DOM, console, network, and storage.
30
- 3. **Agent Automation Coexistence**:
31
- Ensure the agent is in `HUMAN_CONTROL` state so automation does not race or override your clicks.
26
+ 1. **Use the Chrome DevTools inspector.** Open the inspector page of your Steel
27
+ deployment, `<steel-api-url>/v1/devtools/inspector.html`, or the remote
28
+ debugger port your deployment exposes.
29
+ 2. **Interact through DevTools.** The inspector gives full control of the DOM,
30
+ console, network and storage.
31
+ 3. **Keep the agent out of the way.** Make sure the session is in
32
+ `HUMAN_CONTROL`, so automation does not race your clicks.
@@ -0,0 +1,248 @@
1
+ # Back up and restore KXM
2
+
3
+ Protect every piece of KXM state, not only the hub database, and bring it back after a disk loss, a bad change, or a move to a new host. This page is for operators. You learn which six roots hold state, what `kxm backup` and `kxm restore` do and do not cover, and a stopped-state procedure for the rest.
4
+
5
+ ## Before you begin
6
+
7
+ - The `kxm` CLI and the project checkout, on the machine that runs the hub and the [Runtime](../glossary.md#runtime).
8
+ - Permission to stop the hub, the Runtime supervisor, and anything that restarts them.
9
+ - Protected, preferably encrypted, backup storage. Backups contain message bodies, prompts and, if you include them, credentials.
10
+
11
+ ## Know where state lives
12
+
13
+ KXM spreads state over six roots. Some of them move with environment variables, and a backup that assumes one location silently misses another. The following diagram shows each root, what it holds, and the variable that moves it.
14
+
15
+ ```mermaid
16
+ flowchart TB
17
+ subgraph R["$R checkout root: the Git checkout, never moves"]
18
+ R1["Project definition: .kxm/project.yaml, config.yaml, agents/, models/, workflows/, gates.yaml, roles/, role-hosts.yaml, routes.yaml, roster.yaml, prices.yaml, repo/, project/env.yaml"]
19
+ R2["Durable records: .kxm/memory/, skills/, goals/, tasks/, candidates/"]
20
+ end
21
+ subgraph D["$D workspace: KXM_WORKSPACE_DIR or --workspace, default $R/.kxm"]
22
+ D1["logs/ (KXM_LOGS_DIR): kxm-hub.jsonl (KXM_LOG_PATH), worker logs, telemetry.jsonl"]
23
+ D2["assets/ (KXM_ASSETS_DIR): retrospectives, improvements, evidence"]
24
+ end
25
+ subgraph W["$W workspace state: KXM_STATE_DIR, default $D/state"]
26
+ W1["kxm.db hub store (KXM_DATA_PATH)"]
27
+ W2["Pi sessions, worker manifests, PID claims"]
28
+ end
29
+ subgraph S["$S user state root: KXM_STATE_HOME"]
30
+ S1["runtime/registry.db, runtime/projects/KEY/run-events.db and prompt sidecars"]
31
+ S2["hub-env.json, hub-binding.json, update.yaml, projects/HASH/repository-bindings.json"]
32
+ end
33
+ subgraph C["$C user config: KXM_USER_CONFIG_DIR, default ~/.config/kxm"]
34
+ C1["config.yaml, roles/, workflows/, role-hosts.yaml, session.token"]
35
+ end
36
+ subgraph T["$T federated telemetry: XDG_CONFIG_HOME/kxm/telemetry"]
37
+ T1["model-metrics.jsonl, not written by any command today"]
38
+ end
39
+ R -->|".kxm/ by default"| D
40
+ D -->|"state/ by default"| W
41
+ ```
42
+
43
+ | Root | Default | Moved by |
44
+ |---|---|---|
45
+ | `$R` checkout | The Git checkout | Nothing. `.kxm/` definition files always stay here |
46
+ | `$D` workspace | `$R/.kxm` | `KXM_WORKSPACE_DIR` or `--workspace`, relative to `KXM_WORKDIR` or the current directory |
47
+ | `$W` workspace state | `$D/state` | `KXM_STATE_DIR`; `KXM_DATA_PATH` moves only `kxm.db` |
48
+ | `$S` user state root | `~/.local/state/kxm` (Linux, honoring `XDG_STATE_HOME`), `~/Library/Application Support/KXM` (macOS), `%LOCALAPPDATA%\KXM` (Windows) | `KXM_STATE_HOME`, which must be absolute |
49
+ | `$C` user config | `~/.config/kxm` | `KXM_USER_CONFIG_DIR` |
50
+ | `$T` federated telemetry | `~/.config/kxm/telemetry` | `XDG_CONFIG_HOME` |
51
+
52
+ Three override rules catch people out:
53
+
54
+ - `--workspace` derives `config/`, `logs/`, `assets/` and `state/` from one directory and ignores the per-directory variables. Without it, `KXM_CONFIG_DIR`, `KXM_LOGS_DIR`, `KXM_ASSETS_DIR` and `KXM_STATE_DIR` each move only their own target. `KXM_STATE_DIR=/srv/state` alone leaves `$D` at `$R/.kxm`.
55
+ - A relative `KXM_STATE_HOME` fails with `local_state_root_not_absolute`. A relative `XDG_STATE_HOME` or `LOCALAPPDATA` base is ignored without an error, and the platform default is used.
56
+ - `KXM_WORKER_LOG_PATH` and `KXM_AGENT_LOG_PATH` move worker logs out of `$D/logs`.
57
+
58
+ Record every override with the backup. A restore that lands where the running service does not look is not a restore.
59
+
60
+ ## Know what each backup covers
61
+
62
+ `kxm backup` protects SQLite stores it can find from the current directory. Everything else needs the stopped-state copy described below.
63
+
64
+ > [!WARNING]
65
+ > `kxm backup` does not back up the Runtime. It looks for Runtime stores under `.kxm/runtime/` in the checkout, but the Runtime writes them under the user state root (`$S/runtime/registry.db` and `$S/runtime/projects/<key>/run-events.db`). In practice a backup holds only the hub store. Back up the Runtime stores and their prompt sidecars by hand, stopped, as shown in [Back up everything else](#back-up-everything-else).
66
+
67
+ | Path | Holds | In `kxm backup` |
68
+ |---|---|---|
69
+ | `$W/kxm.db` | Hub store: agents, messages, workflow runs, journals, context items, leases, synced run facts | Yes, at `<current directory>/.kxm/state/kxm.db` only |
70
+ | `$S/runtime/registry.db` | Runtime registry: projects, their roots, the supervisor identity and claim | No |
71
+ | `$S/runtime/projects/<key>/run-events.db` | Event-sourced runs, drive receipts, gate evidence, the sync outbox | No |
72
+ | `$S/runtime/projects/<key>/run-events.db.run-prompts.json` | Run prompt text; restoring a store without it loses every prompt | No |
73
+ | `$S/projects/<hash>/repository-bindings.json`, `$S/update.yaml` | Member repository paths; updater settings | No |
74
+ | `$S/hub-env.json`, `$S/hub-binding.json`, `$C/session.token` | Credentials and the machine's hub binding | No; prefer regenerating secrets to copying them |
75
+ | `$R/.kxm/` definition files and durable records | Project, roles, routes, prices, roster, memory, skills, goals, tasks, candidates | No; commit them to Git or copy the checkout |
76
+ | Each member repository's `.kxm/repo/*.yaml` | Member definition and environment | No; they live in the member's own checkout |
77
+ | `$W/worker-*.json`, `$W/pi-sessions/` | Worker routing and recovery manifests; Pi model history | No; manifests are required for resumable workers, Pi history is optional |
78
+ | `$D/assets/`, `$D/logs/` | Retrospectives and evidence; logs and local usage accounting (`telemetry.jsonl`) | No |
79
+ | `$C` | User-level roles, workflows and settings | No |
80
+
81
+ A restore without `roster.yaml`, `routes.yaml` or `prices.yaml` comes back healthy but with different admission and cost behavior, so treat them as part of the backup even though they are plain files. `kxm improve report --out-dir` can write candidates outside `$R/.kxm/candidates/`; include that directory if you use it.
82
+
83
+ These files are disposable and need no backup: `hub.pid`, `hub.stop`, `worker-*.pid`, `session-brief.json`, `update-check.json`, `runtime/supervisor.token`, `runtime/supervisor.error`.
84
+
85
+ ## Back up the hub store with `kxm backup`
86
+
87
+ Run it from the checkout root. It resolves stores from the current directory and ignores `--workspace`, `KXM_WORKDIR`, `KXM_STATE_DIR` and `KXM_DATA_PATH`, so a relocated hub database is not found.
88
+
89
+ Preview first. A dry run lists what it would write, opens no store and writes nothing:
90
+
91
+ ```bash
92
+ cd /srv/kxm/product
93
+ kxm backup --dry-run
94
+ ```
95
+
96
+ Expected output:
97
+
98
+ ```text
99
+ dry run: back up 1 store(s) to /srv/kxm/product/.kxm/backups/backup-2026-09-23T18-29-09-107Z (sources are not opened, so their WAL is not checkpointed)
100
+ would write /srv/kxm/product/.kxm/backups/backup-2026-09-23T18-29-09-107Z/kxm.db
101
+ would write /srv/kxm/product/.kxm/backups/backup-2026-09-23T18-29-09-107Z/manifest.json
102
+ ```
103
+
104
+ Then write the backup outside the checkout:
105
+
106
+ ```bash
107
+ kxm backup --out /backups/kxm/2026-09-23/hub
108
+ ```
109
+
110
+ Expected output:
111
+
112
+ ```text
113
+ Created SQLite backup with 1 store(s):
114
+ - hub-store: /srv/kxm/product/.kxm/state/kxm.db -> kxm.db (schema v5, 110592 bytes, sha256 sha256:86549...)
115
+ Manifest: /backups/kxm/2026-09-23/hub/manifest.json
116
+ ```
117
+
118
+ For each store, `kxm backup` checkpoints the write-ahead log, runs `PRAGMA integrity_check`, copies the database with `VACUUM INTO`, checks the copy's integrity, sets mode `0600`, and records its schema version and SHA-256 in `manifest.json` (`kxm.backup-manifest.v1`). `VACUUM INTO` reads one consistent snapshot, so the hub can keep running during this step.
119
+
120
+ > [!NOTE]
121
+ > Without `--out`, backups go to `.kxm/backups/` inside the checkout. Keep that directory out of Git, or always pass `--out`.
122
+
123
+ It fails with `backup_no_stores` when `.kxm/state/kxm.db` does not exist under the current directory, and with `database_corrupted` when an integrity check fails.
124
+
125
+ ## Back up everything else
126
+
127
+ Copy the remaining state with both services stopped. SQLite runs in write-ahead-log mode, so a plain copy of a live database can miss committed data.
128
+
129
+ 1. Stop the Runtime, then the hub, and confirm both are down:
130
+
131
+ ```bash
132
+ kxm runtime stop
133
+ kxm hub stop
134
+ kxm runtime status # expect "runtime supervisor is not running" and exit status 1
135
+ kxm hub view # expect "hub health=false ready=false" and exit status 1
136
+ ```
137
+
138
+ 2. Keep them down until the copy finishes. Pause your service manager's restart policy, Pi sessions with `hub.autoStart: background`, and anything that runs Runtime commands, because `kxm run`, `kxm runs list` and similar commands start the supervisor on demand.
139
+ 3. Copy the hub store and the user state root:
140
+
141
+ ```bash
142
+ S="${KXM_STATE_HOME:-$HOME/.local/state/kxm}" # macOS: "$HOME/Library/Application Support/KXM"
143
+ B=/backups/kxm/2026-09-23
144
+ mkdir -p "$B"
145
+ kxm backup --out "$B/hub"
146
+ tar -C "$S" --exclude 'supervisor.token' --exclude 'hub-env.json' -czf "$B/user-state.tgz" .
147
+ ```
148
+
149
+ The archive holds `registry.db`, every project's `run-events.db` with any `-wal` and `-shm` files and its `.run-prompts.json` sidecar, the repository bindings, the hub binding and `update.yaml`. It leaves out the credential file; keep tokens in your secret store, or include `hub-env.json` and protect the archive as a secret.
150
+
151
+ If `KXM_STATE_DIR` or `KXM_DATA_PATH` moved the hub database, `kxm backup` fails with `backup_no_stores`. With both services stopped, copy that database file and any `-wal` and `-shm` files instead.
152
+ 4. Copy the other roots your recovery needs: the checkout's untracked `.kxm/` records, `$D/assets/`, `$W/worker-*.json` (and `$W/pi-sessions/` only if your policy keeps model history), and `$C`.
153
+ 5. Record the KXM version (`kxm --version`), the configuration commit, the schema versions from `manifest.json`, and every override variable, next to the copy.
154
+ 6. Start the hub, then the Runtime with `kxm runtime start`, and resume the paused restart policies.
155
+
156
+ Keep at least one previous backup, and bound retention: run events and prompt sidecars grow with every run.
157
+
158
+ ## Restore with `kxm restore`
159
+
160
+ `kxm restore` overwrites the live database and deletes its `-wal` and `-shm` files, and it does not check whether the hub is running. Stop the hub and the Runtime first, and move the current state aside rather than deleting it.
161
+
162
+ Preview the restore. The dry run performs every check below and lists what it would overwrite:
163
+
164
+ ```bash
165
+ cd /srv/kxm/product
166
+ kxm restore /backups/kxm/2026-09-23/hub/manifest.json --dry-run
167
+ ```
168
+
169
+ Expected output:
170
+
171
+ ```text
172
+ dry run: restore 1 store(s) from /backups/kxm/2026-09-23/hub/manifest.json; digests verified against the manifest
173
+ would write /srv/kxm/product/.kxm/state/kxm.db
174
+ would delete /srv/kxm/product/.kxm/state/kxm.db-wal
175
+ would delete /srv/kxm/product/.kxm/state/kxm.db-shm
176
+ ```
177
+
178
+ Then run it without `--dry-run`:
179
+
180
+ ```bash
181
+ kxm restore /backups/kxm/2026-09-23/hub/manifest.json
182
+ ```
183
+
184
+ Expected output:
185
+
186
+ ```text
187
+ Restored 1 SQLite store(s) from /backups/kxm/2026-09-23/hub/manifest.json:
188
+ - hub-store: -> /srv/kxm/product/.kxm/state/kxm.db (schema v5, integrity ok)
189
+ ```
190
+
191
+ Before it overwrites anything, `kxm restore` checks that the manifest is a `kxm.backup-manifest.v1` document, that every listed file exists, that each file's SHA-256 matches the manifest, and that no store is newer than this build supports. The manifest's own `manifestSha256` is not checked.
192
+
193
+ It then checks each backup's integrity and schema version again, copies it into place with mode `0600`, and checks the result. Each store returns to its recorded path, rebased onto the current directory when the manifest came from another checkout.
194
+
195
+ ### Restore ceilings
196
+
197
+ A backup newer than this build is refused with `runtime_schema_newer` before any file changes. KXM has no migrations: an older backup restores, but its store then refuses to open with `runtime_schema_outdated`. Restore an older backup with the release that wrote it; see [Upgrade KXM](upgrade.md#understand-schema-changes).
198
+
199
+ The ceilings come from `KXM_BACKUP_CEILINGS` in `plugins/kxm/src/database.ts` and match each store's own schema version:
200
+
201
+ | Store id | Highest schema version restored |
202
+ |---|---|
203
+ | `hub-store` | 5 |
204
+ | `registry` | 1 |
205
+ | `events:<key>` | 7 |
206
+ | `binding-store` | 1 (no current store uses it) |
207
+
208
+ ### Restore the Runtime stores by hand
209
+
210
+ 1. Stop the Runtime and the hub, as in the backup procedure.
211
+ 2. Move `$S/runtime/registry.db` and `$S/runtime/projects/` aside.
212
+ 3. Extract the archive into the user state root:
213
+
214
+ ```bash
215
+ S="${KXM_STATE_HOME:-$HOME/.local/state/kxm}"
216
+ tar -C "$S" -xzf /backups/kxm/2026-09-23/user-state.tgz
217
+ ```
218
+
219
+ The archive also brings back the hub binding, `update.yaml` and repository bindings.
220
+ 4. Keep the checkout at the same absolute path. The Runtime derives each project's store key from the canonical checkout path, so a checkout restored elsewhere does not find its runs.
221
+
222
+ ## Verify the restore
223
+
224
+ 1. Start the hub and check `/ready` and `kxm hub view`, including that the reported `loopback` or `remote` scope matches the environment.
225
+ 2. Run `kxm runtime start`, then `kxm runtime status`, and wait for the sync state to return to `ok`.
226
+ 3. Run `kxm runs list`, open one run with `kxm runs status <run-id>`, and confirm its prompt sidecar came back. A run store without its sidecar is a partial restore.
227
+ 4. Send one test request between two agents.
228
+
229
+ Test a full restore on a spare machine before you rely on it, and repeat the test periodically.
230
+
231
+ ## Troubleshooting
232
+
233
+ | Symptom | Cause | Fix |
234
+ |---|---|---|
235
+ | `backup_no_stores` | No `.kxm/state/kxm.db` under the current directory, or it was moved with `KXM_STATE_DIR` or `KXM_DATA_PATH` | Run from the checkout root; copy a relocated database with the stopped-state procedure |
236
+ | Runs are missing after a restore | `kxm backup` never contained the Runtime stores | Restore `$S/runtime/` from the stopped-state archive |
237
+ | `restore_manifest_digest_mismatch` | A backup file changed after the manifest was written | Use another backup; do not edit files in a backup set |
238
+ | `restore_file_missing` | A file listed in the manifest is not beside it | Copy the whole backup directory, not only `manifest.json` |
239
+ | `runtime_schema_mismatch` | A backup file's schema version differs from the one its manifest records | Use another backup set; never mix files between sets |
240
+ | `runtime_schema_newer` | The backup came from a newer release | Upgrade KXM first, then restore |
241
+ | The hub refuses to start with `runtime_schema_outdated` | The restored store is older than this build | Run the release that wrote it, or start fresh |
242
+
243
+ ## Next steps
244
+
245
+ - Move to a new release safely: [Upgrade KXM](upgrade.md)
246
+ - What each store contains and how sensitive it is: [Data and storage](../concepts/data-and-storage.md)
247
+ - Watch the restored service: [Monitor KXM](monitoring.md)
248
+ - Exact flags and JSON fields: [CLI reference](../reference/cli-reference.md#kxm-backup)