@kontextmind/kxm 0.7.146 → 0.7.147
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.
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +26 -3
- package/docs/README.md +1 -1
- package/docs/adr/ADR-0002-browser-automation-steel-doks.md +8 -5
- package/docs/adr/ADR-0005-obscura-default-playwright.md +4 -3
- package/docs/adr/ADR-0006-machine-account-names.md +90 -0
- package/docs/adr/ADR-0007-steel-caddy-authentik.md +97 -0
- package/docs/adr/README.md +3 -1
- package/docs/contributing/operating-rules.md +13 -1
- package/docs/guides/agent-skills.md +1 -1
- package/docs/guides/browser-automation.md +44 -28
- package/docs/kb/how-credentials-retrieved-safely.md +22 -23
- package/docs/kb/how-to-connect-playwright-to-steel.md +8 -5
- package/docs/kb/how-to-recover-expired-session-or-orphan.md +11 -10
- package/docs/kb/why-automation-opened-different-browser.md +4 -3
- package/docs/operations/deploy.md +31 -0
- package/docs/operations/troubleshooting.md +23 -1
- package/docs/prompts/browser-diagnose-recover.md +2 -2
- package/docs/prompts/browser-start.md +1 -1
- package/docs/reference/configuration.md +9 -7
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +1 -1
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/dist/runtime.js +3 -3
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/skills/kxm-browser-auth/SKILL.md +11 -12
- package/plugins/kxm/skills/kxm-browser-diagnostics/SKILL.md +5 -4
- package/plugins/kxm/skills/kxm-browser-explore/SKILL.md +4 -3
- package/plugins/kxm/skills/kxm-browser-session/SKILL.md +5 -5
- package/plugins/kxm/skills/kxm-browser-verify/SKILL.md +1 -1
- package/plugins/kxm/src/browser.ts +12 -9
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/modes.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -142,6 +142,28 @@ All notable user-facing changes are documented here. The project follows [Semant
|
|
|
142
142
|
|
|
143
143
|
### Changed
|
|
144
144
|
|
|
145
|
+
- **Docs match the 2026-09-27 Steel and machine-account infrastructure.**
|
|
146
|
+
Steel (`steel.kontextmind.com`, alias `steel.theneuro.me`) is reached only
|
|
147
|
+
through Caddy on `kxmd-proxy` (VM 230) and Authentik forward auth. Direct
|
|
148
|
+
LAN, tailnet, and host-forward access is blocked. Sessions return
|
|
149
|
+
`websocketUrl` `wss://steel.kontextmind.com/` (previously
|
|
150
|
+
`ws://steel-browser/`). The CDP path is `/v1/devtools` with an
|
|
151
|
+
`Authorization` header. Allowed groups are `steel-users`, `kxmd-users`,
|
|
152
|
+
`kxmd-admins`, and `kxmd-owners`. `STEEL_API_URL` defaults to
|
|
153
|
+
`https://steel.kontextmind.com`. `STEEL_API_KEY` is deprecated and is not
|
|
154
|
+
enforced by Steel or Caddy. Migrate to `STEEL_AUTH_HEADER`, then
|
|
155
|
+
`STEEL_AUTH_BASIC`, then `STEEL_AUTH_USER` and `STEEL_AUTH_TOKEN`; those
|
|
156
|
+
override the key. The `svc-steel` credential is 1Password vault
|
|
157
|
+
`kontextmind`, item `Steel (svc-steel)`, field `basic_auth`, read with
|
|
158
|
+
`op read` and never written to disk. Steel requires `kxm` 0.7.135 or
|
|
159
|
+
newer. Playwright stays on Obscura ([ADR-0005](docs/adr/ADR-0005-obscura-default-playwright.md)).
|
|
160
|
+
The Proxmox boot order and VM names are in
|
|
161
|
+
[Deploy KXM](docs/operations/deploy.md#boot-the-kxmd-proxmox-host).
|
|
162
|
+
Machine accounts follow
|
|
163
|
+
[ADR-0006](docs/adr/ADR-0006-machine-account-names.md). The DOKS deployment
|
|
164
|
+
record is superseded by
|
|
165
|
+
[ADR-0007](docs/adr/ADR-0007-steel-caddy-authentik.md).
|
|
166
|
+
|
|
145
167
|
- **Workforce ids use one convention, and old ids still resolve.**
|
|
146
168
|
Role ids stay `planner`, `writer`, `reviewer-arch`, and `reviewer-cli`.
|
|
147
169
|
Agent ids and agent-step ids use those same names. Route ids are
|
|
@@ -472,9 +494,10 @@ All notable user-facing changes are documented here. The project follows [Semant
|
|
|
472
494
|
into `chromium.connectOverCDP`. Obscura stays the default and sends no Steel
|
|
473
495
|
headers. `STEEL_AUTH_HEADER` overrides the value. The CDP URL omits the credential when
|
|
474
496
|
those variables are set. A 302 to the identity provider fails closed and does
|
|
475
|
-
not follow the login redirect. `STEEL_API_KEY`
|
|
476
|
-
|
|
477
|
-
|
|
497
|
+
not follow the login redirect. `STEEL_API_KEY` is deprecated. Steel and
|
|
498
|
+
Caddy do not enforce it. `STEEL_AUTH_HEADER`, then `STEEL_AUTH_BASIC`, then
|
|
499
|
+
`STEEL_AUTH_USER` and `STEEL_AUTH_TOKEN` override it. A client that still
|
|
500
|
+
has only the legacy key warns once and is not authenticated. See
|
|
478
501
|
[Browser automation](docs/guides/browser-automation.md).
|
|
479
502
|
|
|
480
503
|
### Removed
|
package/docs/README.md
CHANGED
|
@@ -76,7 +76,7 @@ KXM connects coding agents through a durable, authenticated [hub](glossary.md#hu
|
|
|
76
76
|
| [Architecture](concepts/architecture.md) | Integrators, maintainers | The components, message and workflow lifecycles, and KXM's limits |
|
|
77
77
|
| [Trust model](concepts/trust-model.md) | Operators, security reviewers | Who holds which credential, project boundaries, and what provenance proves |
|
|
78
78
|
| [Data and storage](concepts/data-and-storage.md) | Operators, security reviewers | What each store holds, where it lives and how long it is kept |
|
|
79
|
-
| [Architecture decision records](adr/README.md) | Maintainers | The decision records: [browser automation](adr/ADR-0002-browser-automation-steel-doks.md), [Obscura for Playwright](adr/ADR-0005-obscura-default-playwright.md), [SQLite-only store](adr/ADR-0003-sqlite-only-store.md), [edge identity](adr/ADR-0004-edge-identity-authentik.md) |
|
|
79
|
+
| [Architecture decision records](adr/README.md) | Maintainers | The decision records: [browser automation](adr/ADR-0002-browser-automation-steel-doks.md), [Steel through Caddy](adr/ADR-0007-steel-caddy-authentik.md), [Obscura for Playwright](adr/ADR-0005-obscura-default-playwright.md), [machine account names](adr/ADR-0006-machine-account-names.md), [SQLite-only store](adr/ADR-0003-sqlite-only-store.md), [edge identity](adr/ADR-0004-edge-identity-authentik.md) |
|
|
80
80
|
| [KXM contract package](contracts/README.md) | Maintainers, reviewers | The normative specifications for the local-first architecture, listed below |
|
|
81
81
|
|
|
82
82
|
### Contracts
|
|
@@ -4,13 +4,13 @@ id: "ADR-0002"
|
|
|
4
4
|
type: "adr"
|
|
5
5
|
title: "Self-hosted Steel on DOKS for reusable browser automation and human takeover"
|
|
6
6
|
project: "kxm"
|
|
7
|
-
status: "
|
|
7
|
+
status: "superseded"
|
|
8
8
|
owner: "@operator"
|
|
9
9
|
created: "2026-09-14"
|
|
10
10
|
updated: "2026-09-27"
|
|
11
11
|
authority: "decision"
|
|
12
12
|
confidence: "verified"
|
|
13
|
-
summary: "
|
|
13
|
+
summary: "The 2026-09-14 choice of self-hosted Steel. The DOKS deployment in this record was superseded on 2026-09-27 by ADR-0007. Obscura is the Playwright default (ADR-0005)."
|
|
14
14
|
tags: ["architecture", "decision", "browser", "steel", "doks", "playwright"]
|
|
15
15
|
related: ["docs/guides/browser-automation.md", "docs/guides/agent-skills.md", "docs/adr/ADR-0005-obscura-default-playwright.md"]
|
|
16
16
|
details:
|
|
@@ -20,11 +20,15 @@ details:
|
|
|
20
20
|
- "Provide dual exploratory (agent-browser) and regression (Playwright) interfaces"
|
|
21
21
|
- "Enforce strict credential isolation via pass-cli"
|
|
22
22
|
supersedes: null
|
|
23
|
-
superseded_by:
|
|
23
|
+
superseded_by: "ADR-0007"
|
|
24
24
|
---
|
|
25
25
|
|
|
26
26
|
# ADR-0002: Self-hosted Steel on DOKS for reusable browser automation
|
|
27
27
|
|
|
28
|
+
## Status
|
|
29
|
+
|
|
30
|
+
Superseded on 2026-09-27 by [ADR-0007](ADR-0007-steel-caddy-authentik.md) for where Steel runs and how clients authenticate. [ADR-0005](ADR-0005-obscura-default-playwright.md) keeps Obscura as the Playwright default. The sections below are the 2026-09-14 decision. They are not the current deployment. Steel and Caddy do not enforce `STEEL_API_KEY`.
|
|
31
|
+
|
|
28
32
|
## Context and problem statement
|
|
29
33
|
|
|
30
34
|
AI coding agents and orchestration workflows in KXM require browser interaction for UI exploration, DOM mapping, bug reproduction, and end-to-end regression testing. Existing approaches suffered from three core issues:
|
|
@@ -100,8 +104,7 @@ AI coding agents and orchestration workflows in KXM require browser interaction
|
|
|
100
104
|
|
|
101
105
|
- **Verification**: Health endpoint `$STEEL_API_URL/v1/health` verified with HTTP 200 and Let's Encrypt TLS.
|
|
102
106
|
- **Integration Test**: `test/core/browser.test.ts` validates session lifecycle, CDP endpoint formatting, takeover transitions, and secret redaction.
|
|
103
|
-
- **Security Check**: `pass-cli`
|
|
104
|
-
- **Edge auth (2026-09-27)**: `steel.kontextmind.com` and `steel.theneuro.me`, including the CDP WebSocket, are behind Authentik forward auth. Steel does not check `STEEL_API_KEY`. Clients send `Authorization: Basic`. Unauthenticated requests are redirected to `id.kxmd.dev`. The legacy `x-steel-api-key` header and `apiKey` query parameter remain a temporary proxy shim.
|
|
107
|
+
- **Security Check**: `pass-cli` was the credential store named in this 2026-09-14 decision. Current clients read the `svc-steel` credential with `op read`, as [ADR-0007](ADR-0007-steel-caddy-authentik.md) records.
|
|
105
108
|
|
|
106
109
|
## Related
|
|
107
110
|
|
|
@@ -12,7 +12,7 @@ authority: "decision"
|
|
|
12
12
|
confidence: "verified"
|
|
13
13
|
summary: "Playwright testing and verification connect to pinned Obscura v0.2.3 over CDP. Steel stays the browser for human takeover, MFA, and the live session viewer."
|
|
14
14
|
tags: ["architecture", "decision", "browser", "obscura", "playwright", "cdp"]
|
|
15
|
-
related: ["docs/adr/ADR-0002-browser-automation-steel-doks.md", "docs/guides/browser-automation.md", "docs/kb/how-to-connect-playwright-to-obscura.md"]
|
|
15
|
+
related: ["docs/adr/ADR-0002-browser-automation-steel-doks.md", "docs/adr/ADR-0007-steel-caddy-authentik.md", "docs/guides/browser-automation.md", "docs/kb/how-to-connect-playwright-to-obscura.md"]
|
|
16
16
|
details:
|
|
17
17
|
decision_drivers:
|
|
18
18
|
- "Playwright tests must run without a Steel cluster or a Playwright-managed browser download"
|
|
@@ -26,7 +26,7 @@ details:
|
|
|
26
26
|
|
|
27
27
|
## Status
|
|
28
28
|
|
|
29
|
-
Accepted on 2026-09-27. This record does not supersede [ADR-0002](ADR-0002-browser-automation-steel-doks.md). Steel remains the browser for human takeover, MFA, and the live session viewer.
|
|
29
|
+
Accepted on 2026-09-27. This record does not supersede [ADR-0002](ADR-0002-browser-automation-steel-doks.md). [ADR-0007](ADR-0007-steel-caddy-authentik.md) is the current Steel deployment. Steel remains the browser for remote and hosted sessions, human takeover, MFA, and the live session viewer.
|
|
30
30
|
|
|
31
31
|
## Context
|
|
32
32
|
|
|
@@ -79,7 +79,8 @@ Obscura v0.2.3 is a headless Chromium build that speaks the Chrome DevTools Prot
|
|
|
79
79
|
|
|
80
80
|
## Related
|
|
81
81
|
|
|
82
|
-
- [ADR-0002: Self-hosted Steel on DOKS](ADR-0002-browser-automation-steel-doks.md)
|
|
82
|
+
- [ADR-0002: Self-hosted Steel on DOKS (superseded deployment)](ADR-0002-browser-automation-steel-doks.md)
|
|
83
|
+
- [ADR-0007: Steel through Caddy and Authentik](ADR-0007-steel-caddy-authentik.md)
|
|
83
84
|
- [Browser automation](../guides/browser-automation.md)
|
|
84
85
|
- [How do I connect Playwright to Obscura?](../kb/how-to-connect-playwright-to-obscura.md)
|
|
85
86
|
- [Environment variables and limits](../reference/configuration.md#browser-automation)
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema: "kxm.doc.v1"
|
|
3
|
+
id: "ADR-0006"
|
|
4
|
+
type: "adr"
|
|
5
|
+
title: "Machine account names"
|
|
6
|
+
project: "kxm"
|
|
7
|
+
status: "accepted"
|
|
8
|
+
owner: "@operator"
|
|
9
|
+
created: "2026-09-27"
|
|
10
|
+
updated: "2026-09-27"
|
|
11
|
+
authority: "decision"
|
|
12
|
+
confidence: "verified"
|
|
13
|
+
summary: "New machine accounts use svc-<system>-<purpose>, or svc-<tenant>-<system>-<purpose> when they belong to one tenant. Test accounts add a test- prefix and stay out of production groups."
|
|
14
|
+
tags: ["architecture", "decision", "authentik", "accounts"]
|
|
15
|
+
related: ["docs/adr/ADR-0004-edge-identity-authentik.md", "docs/operations/deploy.md", "docs/contributing/operating-rules.md"]
|
|
16
|
+
details:
|
|
17
|
+
decision_drivers:
|
|
18
|
+
- "One readable pattern for platform and tenant machine accounts"
|
|
19
|
+
- "Test and witness accounts must be unable to enter production groups"
|
|
20
|
+
- "Existing names stay until an approved inventory authorizes a rename"
|
|
21
|
+
supersedes: null
|
|
22
|
+
superseded_by: null
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# ADR-0006: Machine account names
|
|
26
|
+
|
|
27
|
+
## Status
|
|
28
|
+
|
|
29
|
+
Accepted on 2026-09-27.
|
|
30
|
+
|
|
31
|
+
## Context
|
|
32
|
+
|
|
33
|
+
Authentik machine accounts were created with local names such as `kxm-agent`, `kxm-witness-*`, `witness9`, `kxmdproof`, `kxm-provisioner`, and `agent-ilo-asus`. Those names do not say whether the account is platform-wide, tenant-scoped, or a test identity. Renaming them without an inventory would drop grants that still point at the old name.
|
|
34
|
+
|
|
35
|
+
## Decision drivers
|
|
36
|
+
|
|
37
|
+
1. A reader can tell the scope of an account from its name.
|
|
38
|
+
2. Test, witness, and proof accounts must not sit in production groups.
|
|
39
|
+
3. Authentik's own accounts keep the names Authentik assigns.
|
|
40
|
+
4. A rename of an account that already exists waits for an approved inventory.
|
|
41
|
+
|
|
42
|
+
## Considered options
|
|
43
|
+
|
|
44
|
+
1. **`svc-` names, with a `test-` prefix for non-production accounts.**
|
|
45
|
+
2. **Keep creating ad hoc names.**
|
|
46
|
+
3. **Put every machine account under Authentik's `ak-*` prefix.**
|
|
47
|
+
|
|
48
|
+
### Option 1: `svc-` names (chosen)
|
|
49
|
+
|
|
50
|
+
- Good, because platform and tenant scope are visible in the name.
|
|
51
|
+
- Good, because a `test-` prefix can be excluded from production groups.
|
|
52
|
+
- Bad, because accounts that already exist keep their old names until an inventory is approved.
|
|
53
|
+
|
|
54
|
+
### Option 2: ad hoc names (rejected)
|
|
55
|
+
|
|
56
|
+
- Good, because nothing already issued has to change.
|
|
57
|
+
- Bad, because the next account repeats the same ambiguity.
|
|
58
|
+
|
|
59
|
+
### Option 3: `ak-*` for every machine account (rejected)
|
|
60
|
+
|
|
61
|
+
- Good, because one prefix would match Authentik-managed users.
|
|
62
|
+
- Bad, because `ak-*` is Authentik's own namespace for outposts and internal users.
|
|
63
|
+
|
|
64
|
+
## Decision
|
|
65
|
+
|
|
66
|
+
Create machine accounts with these shapes. `<tenant>` is the tenant slug.
|
|
67
|
+
|
|
68
|
+
| Scope | Name |
|
|
69
|
+
|---|---|
|
|
70
|
+
| Platform-wide | `svc-<system>-<purpose>` |
|
|
71
|
+
| Tenant-scoped | `svc-<tenant>-<system>-<purpose>` |
|
|
72
|
+
| Test, witness, or proof | The same shapes with a `test-` prefix |
|
|
73
|
+
|
|
74
|
+
A `test-` account is never a member of a production group.
|
|
75
|
+
|
|
76
|
+
Authentik-managed accounts are exempt. That includes outposts and any account whose name starts with `ak-`.
|
|
77
|
+
|
|
78
|
+
The `svc-steel` credential that reaches the Steel server is the account operators use today. This record does not rename it. Names already recorded in plans and handoffs, including `kxm-agent`, `kxm-witness-*`, `witness9`, `kxmdproof`, `kxm-provisioner`, and `agent-ilo-asus`, stay as written until an approved inventory lists each rename. Do not invent a replacement for a specific account.
|
|
79
|
+
|
|
80
|
+
## Consequences
|
|
81
|
+
|
|
82
|
+
- New accounts follow the table above.
|
|
83
|
+
- This repository does not assign new names to the recorded accounts.
|
|
84
|
+
- Group names such as `kxmd-owners` are groups, not machine accounts, and this record does not rename them.
|
|
85
|
+
|
|
86
|
+
## Related
|
|
87
|
+
|
|
88
|
+
- [Edge identity](ADR-0004-edge-identity-authentik.md)
|
|
89
|
+
- [Deploy KXM](../operations/deploy.md#name-machine-accounts)
|
|
90
|
+
- [Operating rules](../contributing/operating-rules.md)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema: "kxm.doc.v1"
|
|
3
|
+
id: "ADR-0007"
|
|
4
|
+
type: "adr"
|
|
5
|
+
title: "Steel is reached only through Caddy and Authentik"
|
|
6
|
+
project: "kxm"
|
|
7
|
+
status: "accepted"
|
|
8
|
+
owner: "@operator"
|
|
9
|
+
created: "2026-09-27"
|
|
10
|
+
updated: "2026-09-27"
|
|
11
|
+
authority: "decision"
|
|
12
|
+
confidence: "verified"
|
|
13
|
+
summary: "The Steel server steel.kontextmind.com is an LXC behind Caddy and Authentik forward auth. Clients use the svc-steel credential. STEEL_API_KEY is not enforced. Playwright stays on Obscura."
|
|
14
|
+
tags: ["architecture", "decision", "browser", "steel", "authentik"]
|
|
15
|
+
related: ["docs/adr/ADR-0002-browser-automation-steel-doks.md", "docs/adr/ADR-0005-obscura-default-playwright.md", "docs/guides/browser-automation.md", "docs/adr/ADR-0006-machine-account-names.md"]
|
|
16
|
+
details:
|
|
17
|
+
decision_drivers:
|
|
18
|
+
- "Steel must not be reachable on the LAN, the tailnet, or a host forward"
|
|
19
|
+
- "Authentik groups are the access list"
|
|
20
|
+
- "Credentials stay in 1Password and are read into the process only"
|
|
21
|
+
supersedes: "ADR-0002"
|
|
22
|
+
superseded_by: null
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# ADR-0007: Steel is reached only through Caddy and Authentik
|
|
26
|
+
|
|
27
|
+
## Status
|
|
28
|
+
|
|
29
|
+
Accepted on 2026-09-27. This record supersedes the DigitalOcean Kubernetes deployment in [ADR-0002](ADR-0002-browser-automation-steel-doks.md). [ADR-0005](ADR-0005-obscura-default-playwright.md) still makes Obscura the Playwright default. Steel remains the browser for remote and hosted sessions, human takeover, MFA, and the live session viewer.
|
|
30
|
+
|
|
31
|
+
## Context
|
|
32
|
+
|
|
33
|
+
Steel now runs as LXC 240 on the Proxmox host, at startup order 40. Its public name is `steel.kontextmind.com`. `steel.theneuro.me` is an alias of that same server. Caddy on VM 230 (`kxmd-proxy`) is the only listener, and it forwards authentication to Authentik. Direct LAN, tailnet, and host-forward access is blocked.
|
|
34
|
+
|
|
35
|
+
Sessions return `websocketUrl` `wss://steel.kontextmind.com/`. The previous value was `ws://steel-browser/`. Clients connect Chrome DevTools Protocol at `/v1/devtools` and send `Authorization` on the handshake. The URL does not carry a credential.
|
|
36
|
+
|
|
37
|
+
Steel and Caddy do not enforce `STEEL_API_KEY`. Clients authenticate as the Authentik user `svc-steel`.
|
|
38
|
+
|
|
39
|
+
## Decision drivers
|
|
40
|
+
|
|
41
|
+
1. The browser host is not a second network entrance beside the proxy.
|
|
42
|
+
2. Membership in a known Authentik group is the allow list.
|
|
43
|
+
3. The credential is read at runtime and is not written to disk.
|
|
44
|
+
4. Playwright tests keep the Obscura default from ADR-0005.
|
|
45
|
+
|
|
46
|
+
## Considered options
|
|
47
|
+
|
|
48
|
+
1. **Caddy plus Authentik forward auth, with direct paths blocked.**
|
|
49
|
+
2. **Keep the DOKS ingress and a Steel API key.**
|
|
50
|
+
3. **Publish the LXC on the tailnet or a host forward.**
|
|
51
|
+
|
|
52
|
+
### Option 1: Caddy and Authentik only (chosen)
|
|
53
|
+
|
|
54
|
+
- Good, because one proxy terminates TLS and applies the group check.
|
|
55
|
+
- Good, because a client that still sends `STEEL_API_KEY` does not get a session.
|
|
56
|
+
- Bad, because clients older than `kxm` 0.7.135 still expect `ws://steel-browser/`.
|
|
57
|
+
|
|
58
|
+
### Option 2: DOKS and `STEEL_API_KEY` (rejected)
|
|
59
|
+
|
|
60
|
+
- Good, because existing scripts that sent `x-steel-api-key` would keep working.
|
|
61
|
+
- Bad, because that cluster is no longer where Steel runs, and neither Steel nor Caddy checks the key.
|
|
62
|
+
|
|
63
|
+
### Option 3: tailnet or host-forward access (rejected)
|
|
64
|
+
|
|
65
|
+
- Good, because an operator on the tailnet could open the API without the proxy.
|
|
66
|
+
- Bad, because it bypasses Authentik and the group check.
|
|
67
|
+
|
|
68
|
+
## Decision
|
|
69
|
+
|
|
70
|
+
Reach Steel only at `https://steel.kontextmind.com` (alias `steel.theneuro.me`) through Caddy and Authentik forward auth. `STEEL_API_URL` defaults to `https://steel.kontextmind.com`.
|
|
71
|
+
|
|
72
|
+
Authenticate with the `svc-steel` credential. Precedence is `STEEL_AUTH_HEADER`, then `STEEL_AUTH_BASIC`, then `STEEL_AUTH_USER` together with `STEEL_AUTH_TOKEN`. Those variables override `STEEL_API_KEY`. `STEEL_API_KEY` is deprecated: Steel and Caddy do not enforce it, and a value in the URL is not accepted. Migrate by setting one of the three Authentik variables and dropping the key from the environment.
|
|
73
|
+
|
|
74
|
+
Read the credential from 1Password at runtime. The vault is `kontextmind`, the item is `Steel (svc-steel)`, and the field is `basic_auth`. Use `op read`. Do not write the value to disk.
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
export STEEL_AUTH_BASIC="$(op read 'op://kontextmind/Steel (svc-steel)/basic_auth')"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The CDP path is `/v1/devtools` with an `Authorization` header.
|
|
81
|
+
|
|
82
|
+
These Authentik groups may use the server: `steel-users`, `kxmd-users`, `kxmd-admins`, and `kxmd-owners`.
|
|
83
|
+
|
|
84
|
+
`kxm` 0.7.135 or newer is required. Playwright testing stays on Obscura unless `KXM_BROWSER=steel`.
|
|
85
|
+
|
|
86
|
+
## Consequences
|
|
87
|
+
|
|
88
|
+
- A connection to the LXC by LAN address, tailnet address, or host forward fails.
|
|
89
|
+
- A client that only sets `STEEL_API_KEY` is not authenticated.
|
|
90
|
+
- The `svc-steel` name is the live account. [ADR-0006](ADR-0006-machine-account-names.md) does not rename it ahead of an approved inventory.
|
|
91
|
+
|
|
92
|
+
## Related
|
|
93
|
+
|
|
94
|
+
- [ADR-0002](ADR-0002-browser-automation-steel-doks.md)
|
|
95
|
+
- [ADR-0005](ADR-0005-obscura-default-playwright.md)
|
|
96
|
+
- [Browser automation](../guides/browser-automation.md)
|
|
97
|
+
- [Deploy KXM](../operations/deploy.md#boot-the-kxmd-proxmox-host)
|
package/docs/adr/README.md
CHANGED
|
@@ -7,10 +7,12 @@ An architecture decision record (ADR) captures one significant decision about KX
|
|
|
7
7
|
| ADR | Decision | Status | Date |
|
|
8
8
|
|---|---|---|---|
|
|
9
9
|
| [ADR-001](../contracts/architecture.md) | Local Runtime, project authority, and aggregate hub | Accepted target | — |
|
|
10
|
-
| [ADR-0002](ADR-0002-browser-automation-steel-doks.md) | Self-hosted Steel
|
|
10
|
+
| [ADR-0002](ADR-0002-browser-automation-steel-doks.md) | Self-hosted Steel on DOKS (deployment superseded) | Superseded by ADR-0007 | 2026-09-14 |
|
|
11
11
|
| [ADR-0003](ADR-0003-sqlite-only-store.md) | SQLite as the only store | Accepted | 2026-09-17 |
|
|
12
12
|
| [ADR-0004](ADR-0004-edge-identity-authentik.md) | Edge identity with Authentik; the hub owns no browser identity | Accepted | 2026-09-20 |
|
|
13
13
|
| [ADR-0005](ADR-0005-obscura-default-playwright.md) | Obscura is the default browser for Playwright; Steel stays for takeover | Accepted | 2026-09-27 |
|
|
14
|
+
| [ADR-0006](ADR-0006-machine-account-names.md) | Machine account names (`svc-` shapes, `test-` prefix, Authentik exemptions) | Accepted | 2026-09-27 |
|
|
15
|
+
| [ADR-0007](ADR-0007-steel-caddy-authentik.md) | Steel is reached only through Caddy and Authentik | Accepted | 2026-09-27 |
|
|
14
16
|
|
|
15
17
|
ADR-001 is the original decision record for the local Runtime. It lives with the contracts in [`docs/contracts/architecture.md`](../contracts/architecture.md) because it is the root of those contracts, and it keeps its original three-digit number. Records in this directory continue the sequence from 0002. There is no ADR-0001.
|
|
16
18
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
title: "Operating rules"
|
|
3
3
|
description: "Standing instructions from the operator that every agent session on this repository follows, with the date each was given. Read before planning, dispatching, landing, or editing the roadmap."
|
|
4
4
|
audience: "agents and maintainers"
|
|
5
|
-
updated: "2026-09-
|
|
5
|
+
updated: "2026-09-27"
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Operating rules
|
|
@@ -58,6 +58,18 @@ replacement.
|
|
|
58
58
|
`impl-bg`) retire last, after one real unit has run through the one-step
|
|
59
59
|
workflows. (2026-09-26.)
|
|
60
60
|
|
|
61
|
+
## Accounts
|
|
62
|
+
|
|
63
|
+
- **Machine account names follow [ADR-0006](../adr/ADR-0006-machine-account-names.md).**
|
|
64
|
+
Platform-wide accounts are `svc-<system>-<purpose>`. Tenant-scoped accounts
|
|
65
|
+
are `svc-<tenant>-<system>-<purpose>`, where `<tenant>` is the tenant slug.
|
|
66
|
+
Test, witness, and proof accounts use those shapes with a `test-` prefix
|
|
67
|
+
and are never members of production groups. Authentik-managed accounts
|
|
68
|
+
(outposts and `ak-*`) are exempt. Recorded names such as `kxm-agent`,
|
|
69
|
+
`kxm-witness-*`, `witness9`, and `kxmdproof` stay until an approved
|
|
70
|
+
inventory. Do not invent a replacement for a specific account.
|
|
71
|
+
(2026-09-27.)
|
|
72
|
+
|
|
61
73
|
## Decisions and debt
|
|
62
74
|
|
|
63
75
|
- **Every option comes with pros and cons and two recommendations**, the
|
|
@@ -68,7 +68,7 @@ Tools map the same way: peer tools to `kxm-peer`, workflow tools to `kxm-workflo
|
|
|
68
68
|
|
|
69
69
|
## Browser automation skills
|
|
70
70
|
|
|
71
|
-
Playwright testing and verification use Obscura ([ADR-0005](../adr/ADR-0005-obscura-default-playwright.md)). The Steel skills cover human takeover, MFA, and the live session viewer.
|
|
71
|
+
Playwright testing and verification use Obscura ([ADR-0005](../adr/ADR-0005-obscura-default-playwright.md)). The Steel skills cover remote and hosted browsing, human takeover, MFA, and the live session viewer. Steel is `https://steel.kontextmind.com`, reached only through Caddy and Authentik ([ADR-0007](../adr/ADR-0007-steel-caddy-authentik.md)). Send `Authorization: Basic` (`STEEL_AUTH_HEADER`, then `STEEL_AUTH_BASIC`, then `STEEL_AUTH_USER` and `STEEL_AUTH_TOKEN`) and keep the credential out of URLs. `STEEL_API_KEY` is deprecated and is not enforced. `kxm` 0.7.135 or newer is required for Steel. `kxm-browser-verify` owns `vision`. The other browser skills own no `kxm` command. See [Browser automation](browser-automation.md).
|
|
72
72
|
|
|
73
73
|
| Skill | Use it to |
|
|
74
74
|
|---|---|
|
|
@@ -5,9 +5,9 @@ Give agents a real browser without giving them your desktop. Playwright testing
|
|
|
5
5
|
## Before you begin
|
|
6
6
|
|
|
7
7
|
- For Playwright: Node, and `node scripts/obscura.mjs` (it downloads pinned Obscura v0.2.3). [ADR-0005](../adr/ADR-0005-obscura-default-playwright.md) records that default.
|
|
8
|
-
- For
|
|
8
|
+
- For Steel: `kxm` 0.7.135 or newer. [ADR-0007](../adr/ADR-0007-steel-caddy-authentik.md) is the current server. [ADR-0002](../adr/ADR-0002-browser-automation-steel-doks.md) is the superseded Kubernetes deployment.
|
|
9
9
|
- `curl` and `jq`. Optionally `agent-browser` for exploration. Playwright tests use Obscura; do not run `playwright install`.
|
|
10
|
-
-
|
|
10
|
+
- The 1Password CLI (`op`) for the `svc-steel` credential. Read it at runtime. Do not write it to disk.
|
|
11
11
|
- The `kxm-browser-*` skills from the plugin or Pi package. See [Agent skills](agent-skills.md#browser-automation-skills).
|
|
12
12
|
|
|
13
13
|
## Components
|
|
@@ -36,33 +36,37 @@ Set `video: "off"` in Playwright. Obscura does not record video. Connect with th
|
|
|
36
36
|
|
|
37
37
|
The KXM browser library reads these variables, and the shell procedure below uses the same names so both agree.
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
The Steel server is `https://steel.kontextmind.com`. `steel.theneuro.me` is an alias of that same server. The only path is Caddy on `kxmd-proxy` (VM 230) with Authentik forward auth. Direct LAN, tailnet, and host-forward connections are blocked. Unauthenticated requests receive a 302 redirect to `id.kxmd.dev`.
|
|
40
|
+
|
|
41
|
+
Sessions return `websocketUrl` `wss://steel.kontextmind.com/`. The previous value was `ws://steel-browser/`. Connect Chrome DevTools Protocol at `/v1/devtools` and send `Authorization` on the handshake. The URL never carries a credential.
|
|
42
|
+
|
|
43
|
+
Authentik accepts the `svc-steel` credential as `Authorization: Basic`. A Bearer token is refused. These groups may connect: `steel-users`, `kxmd-users`, `kxmd-admins`, and `kxmd-owners`. Steel needs `kxm` 0.7.135 or newer.
|
|
40
44
|
|
|
41
45
|
| Variable | Default | Effect |
|
|
42
46
|
|---|---|---|
|
|
43
|
-
| `STEEL_API_URL` |
|
|
47
|
+
| `STEEL_API_URL` | `https://steel.kontextmind.com` | Base URL of the Steel API |
|
|
44
48
|
| `STEEL_UI_URL` | `$STEEL_API_URL/ui` | Base URL of the session viewer |
|
|
45
|
-
| `STEEL_AUTH_HEADER` | unset | Full `Authorization` value.
|
|
46
|
-
| `STEEL_AUTH_BASIC` | unset | `base64(user:token)`, with or without a leading `Basic` prefix
|
|
47
|
-
| `STEEL_AUTH_USER` | unset | Authentik username
|
|
49
|
+
| `STEEL_AUTH_HEADER` | unset | Full `Authorization` value. First in the precedence below |
|
|
50
|
+
| `STEEL_AUTH_BASIC` | unset | `base64(user:token)`, with or without a leading `Basic` prefix |
|
|
51
|
+
| `STEEL_AUTH_USER` | unset | Authentik username `svc-steel`. Used with `STEEL_AUTH_TOKEN` |
|
|
48
52
|
| `STEEL_AUTH_TOKEN` | unset | Authentik app password. Used with `STEEL_AUTH_USER` |
|
|
49
|
-
| `STEEL_API_KEY` |
|
|
50
|
-
| `USE_PASS_CLI` | enabled |
|
|
53
|
+
| `STEEL_API_KEY` | unset | Deprecated. Steel and Caddy do not enforce it. See the migration note |
|
|
54
|
+
| `USE_PASS_CLI` | enabled | Turns the legacy `STEEL_API_KEY` lookup off when set to `false` |
|
|
51
55
|
|
|
52
|
-
Set one Authentik credential. Precedence is `STEEL_AUTH_HEADER`, then `STEEL_AUTH_BASIC`, then `STEEL_AUTH_USER` together with `STEEL_AUTH_TOKEN`. If only one of the user or token pair is set, configuration fails
|
|
56
|
+
Set one Authentik credential. Precedence is `STEEL_AUTH_HEADER`, then `STEEL_AUTH_BASIC`, then `STEEL_AUTH_USER` together with `STEEL_AUTH_TOKEN`. Those three override `STEEL_API_KEY`. If only one of the user or token pair is set, configuration fails closed. When any Authentik variable is set, the legacy key is not sent.
|
|
53
57
|
|
|
54
58
|
> [!WARNING]
|
|
55
|
-
>
|
|
59
|
+
> `STEEL_API_KEY` is deprecated. Steel and Caddy do not enforce it. A client that still sends `x-steel-api-key` or `?apiKey=` is not authenticated. Migrate by setting one Authentik variable above and removing `STEEL_API_KEY`. Read the credential with `op read`. Never write it to disk, a URL, a prompt, or a log.
|
|
56
60
|
|
|
57
61
|
```bash
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
export
|
|
62
|
+
# Optional. This is already the default.
|
|
63
|
+
export STEEL_API_URL="https://steel.kontextmind.com"
|
|
64
|
+
# Vault kontextmind, item "Steel (svc-steel)", field basic_auth.
|
|
65
|
+
# The value stays in this process. Do not redirect it to a file.
|
|
66
|
+
export STEEL_AUTH_BASIC="$(op read 'op://kontextmind/Steel (svc-steel)/basic_auth')"
|
|
63
67
|
```
|
|
64
68
|
|
|
65
|
-
`
|
|
69
|
+
`STEEL_AUTH_USER` is `svc-steel` when you set the user and token pair instead of `STEEL_AUTH_BASIC`. Keep the value in the environment of the process that calls Steel.
|
|
66
70
|
|
|
67
71
|
| Endpoint | Purpose |
|
|
68
72
|
|---|---|
|
|
@@ -70,20 +74,29 @@ export USE_PASS_CLI=false
|
|
|
70
74
|
| `GET /v1/sessions/<id>` | Inspect one session; `GET /v1/sessions` lists them all |
|
|
71
75
|
| `POST /v1/sessions/<id>/release` | Release a session |
|
|
72
76
|
| `POST /v1/scrape`, `POST /v1/screenshot` | One-shot page fetch or screenshot without a session |
|
|
73
|
-
| `wss
|
|
77
|
+
| `wss://steel.kontextmind.com/v1/devtools?sessionId=<id>` | CDP path. Send `Authorization` on the handshake. The session `websocketUrl` is `wss://steel.kontextmind.com/` |
|
|
74
78
|
| `$STEEL_UI_URL?sessionId=<id>` | Session viewer for human takeover |
|
|
75
79
|
|
|
76
80
|
## Run a browser task
|
|
77
81
|
|
|
78
|
-
1. Define a helper that sends `Authorization` on stdin, so the secret never appears in a process list:
|
|
82
|
+
1. Define a helper that sends `Authorization` on stdin, so the secret never appears in a process list. `STEEL_API_URL` defaults to `https://steel.kontextmind.com` when unset:
|
|
79
83
|
|
|
80
84
|
```bash
|
|
81
85
|
steel() { # usage: steel METHOD PATH [JSON-BODY]
|
|
82
|
-
local
|
|
83
|
-
|
|
86
|
+
local header args
|
|
87
|
+
args=(-sS -X "$1" "${STEEL_API_URL:-https://steel.kontextmind.com}$2" -H @- -H 'Content-Type: application/json')
|
|
84
88
|
if [ -n "${3:-}" ]; then args+=(-d "$3"); fi
|
|
85
|
-
|
|
86
|
-
|
|
89
|
+
if [ -n "${STEEL_AUTH_HEADER:-}" ]; then
|
|
90
|
+
header="$STEEL_AUTH_HEADER"
|
|
91
|
+
elif [ -n "${STEEL_AUTH_BASIC:-}" ]; then
|
|
92
|
+
case "$STEEL_AUTH_BASIC" in
|
|
93
|
+
Basic\ *) header="$STEEL_AUTH_BASIC" ;;
|
|
94
|
+
*) header="Basic $STEEL_AUTH_BASIC" ;;
|
|
95
|
+
esac
|
|
96
|
+
else
|
|
97
|
+
header="Basic $(printf '%s:%s' "$STEEL_AUTH_USER" "$STEEL_AUTH_TOKEN" | base64 | tr -d '\n')"
|
|
98
|
+
fi
|
|
99
|
+
printf 'Authorization: %s\n' "$header" | curl "${args[@]}"
|
|
87
100
|
}
|
|
88
101
|
```
|
|
89
102
|
|
|
@@ -157,16 +170,18 @@ The KXM browser library tracks these states in the process that owns the session
|
|
|
157
170
|
|
|
158
171
|
- **Timeouts.** Sessions end on their own when the timeout expires. Set a longer timeout at creation when a person will need time for a login step.
|
|
159
172
|
- **Orphan sweeps.** List sessions with `steel GET /v1/sessions` and release any you do not track. The library flags untracked sessions older than 10 minutes, and tracked ones idle that long unless a human holds them.
|
|
160
|
-
- **Shared memory.** Give Chromium a large `/dev/shm
|
|
173
|
+
- **Shared memory.** Give Chromium a large `/dev/shm` on Steel LXC 240, or tabs crash.
|
|
161
174
|
- **No shared profiles.** Concurrent sessions must not write to the same browser profile.
|
|
162
175
|
|
|
163
176
|
## Troubleshooting
|
|
164
177
|
|
|
165
178
|
| Symptom | Cause | Fix |
|
|
166
179
|
|---|---|---|
|
|
167
|
-
| `302` to `id.kxmd.dev` | The request had no Authentik
|
|
168
|
-
| `401` or `403` | Wrong
|
|
169
|
-
|
|
|
180
|
+
| `302` to `id.kxmd.dev` | The request had no Authentik credential | Export `STEEL_AUTH_BASIC` from `op read`, or the user and token pair. A Bearer token is not accepted |
|
|
181
|
+
| `401` or `403` | Wrong `svc-steel` credential, or the account is outside the allowed groups | Re-read `basic_auth` with `op read`. `STEEL_API_KEY` does not authenticate |
|
|
182
|
+
| Connection refused on a LAN, tailnet, or host-forward address | Those paths are blocked | Use `https://steel.kontextmind.com` through Caddy |
|
|
183
|
+
| `websocketUrl` is `ws://steel-browser/` | The client is older than `kxm` 0.7.135 | Upgrade `kxm`. The server returns `wss://steel.kontextmind.com/` |
|
|
184
|
+
| Requests go to an unexpected host | `STEEL_API_URL` points somewhere else | Unset it to use `https://steel.kontextmind.com`, or set that URL |
|
|
170
185
|
| Playwright opens a local browser | The client called `chromium.launch()` or `chromium.connect()` | Use the worker-scoped fixture and `connectOverCDP` against Obscura |
|
|
171
186
|
| Steel CDP connects without auth | `connectOverCDP` was called with only the URL | Call `connectOverCDP(url, { headers })` with the headers from `formatCDPConnect()` or `connectBrowserOverCdp()` |
|
|
172
187
|
| `Access to private/internal IP address` | Obscura was started without `--allow-private-network` | Run `node scripts/obscura.mjs`, which passes that flag |
|
|
@@ -199,5 +214,6 @@ The KXM browser library tracks these states in the process that owns the session
|
|
|
199
214
|
|
|
200
215
|
- The seven browser skills: [Agent skills](agent-skills.md#browser-automation-skills)
|
|
201
216
|
- Why Obscura is the Playwright default: [ADR-0005](../adr/ADR-0005-obscura-default-playwright.md)
|
|
202
|
-
-
|
|
217
|
+
- Where Steel runs now: [ADR-0007](../adr/ADR-0007-steel-caddy-authentik.md)
|
|
218
|
+
- The superseded Kubernetes deployment: [ADR-0002](../adr/ADR-0002-browser-automation-steel-doks.md)
|
|
203
219
|
- Estimate the `browser` mode's prompt footprint: [`kxm explain`](../reference/cli-reference.md#kxm-explain)
|
|
@@ -11,7 +11,7 @@ updated: "2026-09-27"
|
|
|
11
11
|
authority: "instruction"
|
|
12
12
|
confidence: "verified"
|
|
13
13
|
summary: "How the Steel client resolves Authentik Basic auth and how browser work keeps secrets out of model context."
|
|
14
|
-
tags: ["browser", "credentials", "
|
|
14
|
+
tags: ["browser", "credentials", "1password", "security"]
|
|
15
15
|
related: ["docs/guides/browser-automation.md", "docs/guides/agent-skills.md"]
|
|
16
16
|
---
|
|
17
17
|
|
|
@@ -28,37 +28,36 @@ secret to disk or to a log:
|
|
|
28
28
|
|
|
29
29
|
| Setting | Resolved from |
|
|
30
30
|
|---|---|
|
|
31
|
-
| API URL | An explicit override, then `STEEL_API_URL`, then
|
|
31
|
+
| API URL | An explicit override, then `STEEL_API_URL`, then `https://steel.kontextmind.com` |
|
|
32
32
|
| Authentik `Authorization` | `STEEL_AUTH_HEADER`, then `STEEL_AUTH_BASIC`, then `STEEL_AUTH_USER` and `STEEL_AUTH_TOKEN` |
|
|
33
|
-
| Legacy API key | An explicit override, then `STEEL_API_KEY`, then a
|
|
33
|
+
| Legacy API key | Deprecated. An explicit override, then `STEEL_API_KEY`, then a leftover lookup, and only when no Authentik credential is set. Steel and Caddy do not enforce it |
|
|
34
34
|
| Session viewer URL | An explicit override, then `STEEL_UI_URL`, then `<api-url>/ui` |
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
`Authorization: Basic` on every HTTP request and on the CDP WebSocket
|
|
38
|
-
token is
|
|
39
|
-
`
|
|
40
|
-
|
|
41
|
-
key. When an Authentik variable is set, the key is not sent and is not placed
|
|
42
|
-
in a URL.
|
|
36
|
+
The Steel server is behind Caddy and Authentik forward auth. The client sends
|
|
37
|
+
`Authorization: Basic` on every HTTP request and on the CDP WebSocket at
|
|
38
|
+
`/v1/devtools`. A Bearer token is refused. A credential in the URL is refused.
|
|
39
|
+
`STEEL_API_KEY` is deprecated. When an Authentik variable is set, that variable
|
|
40
|
+
overrides the key, and the key is not sent.
|
|
43
41
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
`USE_PASS_CLI=false` to turn the lookup off.
|
|
42
|
+
Read the `svc-steel` credential at runtime and do not write it to disk. The
|
|
43
|
+
1Password vault is `kontextmind`, the item is `Steel (svc-steel)`, and the
|
|
44
|
+
field is `basic_auth`:
|
|
48
45
|
|
|
49
|
-
|
|
46
|
+
```bash
|
|
47
|
+
export STEEL_AUTH_BASIC="$(op read 'op://kontextmind/Steel (svc-steel)/basic_auth')"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`kxm` 0.7.135 or newer is required. Sessions return `websocketUrl`
|
|
51
|
+
`wss://steel.kontextmind.com/`.
|
|
50
52
|
|
|
51
|
-
|
|
52
|
-
Pass through `pass-cli`, and load them into the environment of the process
|
|
53
|
-
that needs them:
|
|
53
|
+
## Mechanisms
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
```
|
|
55
|
+
1. **One secret store.** Keep the Steel credential in 1Password and load it
|
|
56
|
+
into the environment of the process that needs it, as the `op read` command
|
|
57
|
+
above. Do not redirect the command into a file.
|
|
59
58
|
|
|
60
59
|
2. **References, not values.** A prompt receives a credential reference such
|
|
61
|
-
as `
|
|
60
|
+
as `op://kontextmind/Steel (svc-steel)/basic_auth`, never the secret itself.
|
|
62
61
|
3. **Log sanitization.** The KXM browser client redacts `apiKey=` query values,
|
|
63
62
|
`Authorization` header values, `Basic` credentials, `steel_…` keys, and any
|
|
64
63
|
field named like a key, secret, token, auth or password before it logs or
|
|
@@ -43,16 +43,19 @@ const { url, headers } = formatCDPConnect(
|
|
|
43
43
|
);
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
The URL has this shape
|
|
46
|
+
The URL has this shape. The session field `websocketUrl` is the origin
|
|
47
|
+
`wss://steel.kontextmind.com/` (it used to be `ws://steel-browser/`). The
|
|
48
|
+
connect path is `/v1/devtools`:
|
|
47
49
|
|
|
48
50
|
```text
|
|
49
|
-
wss
|
|
51
|
+
wss://steel.kontextmind.com/v1/devtools?sessionId=<session-id>
|
|
50
52
|
```
|
|
51
53
|
|
|
52
54
|
`headers` is `{ Authorization: "Basic <base64>" }`. Pass that object to
|
|
53
|
-
Playwright. Do not log it.
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
Playwright. Do not log it. `STEEL_API_KEY` is deprecated and is not enforced
|
|
56
|
+
by Steel or Caddy. Do not put `apiKey` on the URL. `STEEL_AUTH_HEADER`, then
|
|
57
|
+
`STEEL_AUTH_BASIC`, then `STEEL_AUTH_USER` and `STEEL_AUTH_TOKEN`, override it.
|
|
58
|
+
`kxm` 0.7.135 or newer is required.
|
|
56
59
|
|
|
57
60
|
## 2. Connect in Playwright
|
|
58
61
|
|
|
@@ -22,23 +22,24 @@ browser can keep running on your Steel deployment until its timeout.
|
|
|
22
22
|
|
|
23
23
|
## 1. List active sessions
|
|
24
24
|
|
|
25
|
-
Load
|
|
26
|
-
|
|
25
|
+
Load the `svc-steel` credential from 1Password into this process. Do not write
|
|
26
|
+
it to disk. `STEEL_API_URL` defaults to `https://steel.kontextmind.com`.
|
|
27
|
+
`STEEL_API_KEY` is deprecated and is not enforced.
|
|
27
28
|
|
|
28
29
|
```bash
|
|
29
|
-
export
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
printf 'Authorization:
|
|
30
|
+
export STEEL_AUTH_BASIC="$(op read 'op://kontextmind/Steel (svc-steel)/basic_auth')"
|
|
31
|
+
case "$STEEL_AUTH_BASIC" in
|
|
32
|
+
Basic\ *) header="$STEEL_AUTH_BASIC" ;;
|
|
33
|
+
*) header="Basic $STEEL_AUTH_BASIC" ;;
|
|
34
|
+
esac
|
|
35
|
+
printf 'Authorization: %s\n' "$header" | curl -sS -H @- "${STEEL_API_URL:-https://steel.kontextmind.com}/v1/sessions" | jq .
|
|
35
36
|
```
|
|
36
37
|
|
|
37
38
|
## 2. Release an orphaned session
|
|
38
39
|
|
|
39
40
|
```bash
|
|
40
|
-
printf 'Authorization:
|
|
41
|
-
| curl -sS -X POST -H @- "$STEEL_API_URL/v1/sessions/<session-id>/release"
|
|
41
|
+
printf 'Authorization: %s\n' "$header" \
|
|
42
|
+
| curl -sS -X POST -H @- "${STEEL_API_URL:-https://steel.kontextmind.com}/v1/sessions/<session-id>/release"
|
|
42
43
|
```
|
|
43
44
|
|
|
44
45
|
## 3. Sweep orphans with the KXM client
|
|
@@ -42,6 +42,7 @@ You expected automation to run on Obscura, or on a Steel takeover session, but a
|
|
|
42
42
|
opens a local browser.
|
|
43
43
|
- **Fix:** use `resolveObscuraCdpEndpoint()` (default
|
|
44
44
|
`http://127.0.0.1:9222`). For a Steel takeover session, set
|
|
45
|
-
`KXM_BROWSER=steel` and load `
|
|
46
|
-
`
|
|
47
|
-
|
|
45
|
+
`KXM_BROWSER=steel` and load `STEEL_AUTH_BASIC` with `op read` (or
|
|
46
|
+
`STEEL_AUTH_HEADER`, or `STEEL_AUTH_USER` and `STEEL_AUTH_TOKEN`).
|
|
47
|
+
`STEEL_API_KEY` is deprecated. Steel and Caddy do not enforce it.
|
|
48
|
+
`kxm` 0.7.135 or newer is required for Steel.
|
|
@@ -279,6 +279,35 @@ server {
|
|
|
279
279
|
}
|
|
280
280
|
```
|
|
281
281
|
|
|
282
|
+
## Boot the kxmd Proxmox host
|
|
283
|
+
|
|
284
|
+
The Proxmox host starts these guests in the order below. The VMID is the Proxmox guest id. `up` is the delay, in seconds, after that guest starts.
|
|
285
|
+
|
|
286
|
+
| Order | Guest | VMID | Role | up |
|
|
287
|
+
|---|---|---|---|---|
|
|
288
|
+
| 1 | firewall | 200 | Firewall | |
|
|
289
|
+
| 2 | gateway | 201 | Gateway | |
|
|
290
|
+
| 3 | kxmd-pg | 220 | Postgres | 30 |
|
|
291
|
+
| 4 | kxmd-temporal | 221 | Temporal | 40 |
|
|
292
|
+
| 5 | kxmd-services | 300 | `kxm-control` | 30 |
|
|
293
|
+
| 6 | kxmd-studio | 241 | Hub | 20 |
|
|
294
|
+
|
|
295
|
+
VM 300 is named `kxmd-services`. VM 230 is named `kxmd-proxy` and runs Caddy. Steel is LXC 240 and uses Proxmox startup order 40.
|
|
296
|
+
|
|
297
|
+
Steel's public name is `steel.kontextmind.com`. `steel.theneuro.me` is an alias of that same server. Clients reach it only through Caddy and Authentik forward auth. Direct LAN, tailnet, and host-forward access is blocked. See [ADR-0007](../adr/ADR-0007-steel-caddy-authentik.md) and [Browser automation](../guides/browser-automation.md).
|
|
298
|
+
|
|
299
|
+
## Name machine accounts
|
|
300
|
+
|
|
301
|
+
New Authentik machine accounts follow [ADR-0006](../adr/ADR-0006-machine-account-names.md):
|
|
302
|
+
|
|
303
|
+
| Scope | Name |
|
|
304
|
+
|---|---|
|
|
305
|
+
| Platform-wide | `svc-<system>-<purpose>` |
|
|
306
|
+
| Tenant-scoped | `svc-<tenant>-<system>-<purpose>` |
|
|
307
|
+
| Test, witness, or proof | The same shapes with a `test-` prefix |
|
|
308
|
+
|
|
309
|
+
`<tenant>` is the tenant slug. A `test-` account is never in a production group. Outposts and `ak-*` accounts are Authentik-managed and are exempt. Names already in use, including `kxm-agent`, `kxm-witness-*`, `witness9`, and `kxmdproof`, wait for an approved inventory. Do not invent a new name for one of them. The live Steel account remains `svc-steel`.
|
|
310
|
+
|
|
282
311
|
## Plan for scale
|
|
283
312
|
|
|
284
313
|
Measure concurrent agents, request rate, event-loop delay, database size, disk latency and reconnect frequency for your workload. Terminal messages are purged after `KXM_MESSAGE_RETENTION_MS` (7 days by default), and finished workflow runs and their journals after 7 days. Keep free disk space ahead of the database's growth, and include workflow data in privacy reviews: verified evidence snapshots stay in a run after its source messages are purged.
|
|
@@ -304,4 +333,6 @@ See [Troubleshoot KXM](troubleshooting.md) for more.
|
|
|
304
333
|
- Move to a new release: [Upgrade KXM](upgrade.md)
|
|
305
334
|
- Keep run facts flowing to the hub: [Operate Runtime sync and leases](runtime-sync.md)
|
|
306
335
|
- Understand who can do what: [Trust model](../concepts/trust-model.md)
|
|
336
|
+
- Name machine accounts: [ADR-0006](../adr/ADR-0006-machine-account-names.md)
|
|
337
|
+
- Reach Steel: [ADR-0007](../adr/ADR-0007-steel-caddy-authentik.md)
|
|
307
338
|
- Every hub route: [Hub HTTP API reference](../reference/http-api.md)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Troubleshoot KXM
|
|
2
2
|
|
|
3
|
-
This page is a reference of symptoms, causes and fixes, grouped by area. Start with the quick check, then go to the area that matches: install, hub and authentication, Claude Code, peer messaging, Pi workers, workflows, Runtime runs, context and memory, or operations.
|
|
3
|
+
This page is a reference of symptoms, causes and fixes, grouped by area. Start with the quick check, then go to the area that matches: install, hub and authentication, Claude Code, peer messaging, Pi workers, workflows, Runtime runs, context and memory, Steel, or operations.
|
|
4
4
|
|
|
5
5
|
## Start with a quick check
|
|
6
6
|
|
|
@@ -239,6 +239,26 @@ See [Context and memory](../guides/context-and-memory.md).
|
|
|
239
239
|
|
|
240
240
|
For backup and restore errors such as `backup_no_stores`, see [Back up and restore KXM](backup-and-restore.md#troubleshooting). The dashboard's action keys do not act on runs; see [Monitor KXM](monitoring.md#keys).
|
|
241
241
|
|
|
242
|
+
## Steel
|
|
243
|
+
|
|
244
|
+
Steel is `https://steel.kontextmind.com` (`steel.theneuro.me` is an alias). Caddy and Authentik forward auth are the only path. Playwright tests use Obscura. The procedure is [Browser automation](../guides/browser-automation.md). `kxm` 0.7.135 or newer is required.
|
|
245
|
+
|
|
246
|
+
| Symptom | Cause | Fix |
|
|
247
|
+
|---|---|---|
|
|
248
|
+
| Connection refused or timeout on a LAN, tailnet, or host-forward address | Direct access to LXC 240 is blocked | Use `https://steel.kontextmind.com` |
|
|
249
|
+
| `302` to `id.kxmd.dev` | No Authentik credential on the request | Set `STEEL_AUTH_HEADER`, or `STEEL_AUTH_BASIC`, or `STEEL_AUTH_USER` and `STEEL_AUTH_TOKEN` |
|
|
250
|
+
| `401` or `403` | The `svc-steel` credential is wrong, or the account is outside `steel-users`, `kxmd-users`, `kxmd-admins`, and `kxmd-owners` | Re-read the credential with `op read`. `STEEL_API_KEY` is not enforced |
|
|
251
|
+
| `websocketUrl` is `ws://steel-browser/` | The client predates `kxm` 0.7.135 | Upgrade `kxm`. The server returns `wss://steel.kontextmind.com/` |
|
|
252
|
+
| CDP fails and the URL contains `apiKey` | `STEEL_API_KEY` was placed on `/v1/devtools` | Connect to `/v1/devtools` with an `Authorization` header and no credential in the URL |
|
|
253
|
+
|
|
254
|
+
Read the credential into the process only:
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
export STEEL_AUTH_BASIC="$(op read 'op://kontextmind/Steel (svc-steel)/basic_auth')"
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
The vault is `kontextmind`, the item is `Steel (svc-steel)`, and the field is `basic_auth`. Do not write that value to disk.
|
|
261
|
+
|
|
242
262
|
## Collect a useful bug report
|
|
243
263
|
|
|
244
264
|
Include:
|
|
@@ -263,4 +283,6 @@ Never attach tokens, private prompts, credentials, raw `pi-agent-*.log` files, o
|
|
|
263
283
|
- [Monitor KXM](monitoring.md)
|
|
264
284
|
- [Deploy KXM](deploy.md)
|
|
265
285
|
- [CLI reference](../reference/cli-reference.md)
|
|
286
|
+
- [Browser automation](../guides/browser-automation.md)
|
|
287
|
+
- [Steel through Caddy and Authentik](../adr/ADR-0007-steel-caddy-authentik.md)
|
|
266
288
|
- [Claude Code plugin](../../plugins/kxm/README.md)
|
|
@@ -52,5 +52,5 @@ Use this prompt to troubleshoot unresponsive sessions, CDP attachment errors, au
|
|
|
52
52
|
- For each orphan, invoke `POST /v1/sessions/:id/release`.
|
|
53
53
|
|
|
54
54
|
4. **Verify WebSocket / CDP Ingress**:
|
|
55
|
-
-
|
|
56
|
-
- If the response is a 302 to `id.kxmd.dev`, or CDP fails with 401, send `Authorization: Basic` from `STEEL_AUTH_BASIC
|
|
55
|
+
- Steel is reached only through Caddy and Authentik forward auth. Direct LAN, tailnet, and host-forward connections are blocked. The CDP path is `/v1/devtools` with an `Authorization` header.
|
|
56
|
+
- If the response is a 302 to `id.kxmd.dev`, or CDP fails with 401 or 403, send `Authorization: Basic` from `STEEL_AUTH_HEADER`, then `STEEL_AUTH_BASIC`, then `STEEL_AUTH_USER` and `STEEL_AUTH_TOKEN`. A Bearer token is not accepted. Do not put the credential in the URL. `STEEL_API_KEY` is deprecated. Steel and Caddy do not enforce it. Sessions return `websocketUrl` `wss://steel.kontextmind.com/`. `kxm` 0.7.135 or newer is required.
|
|
@@ -42,7 +42,7 @@ Use this prompt to initialize a remote browser session on self-hosted Steel for
|
|
|
42
42
|
## Instructions for the agent
|
|
43
43
|
|
|
44
44
|
1. **Verify Credential Reference**:
|
|
45
|
-
- Resolve the
|
|
45
|
+
- Resolve the `svc-steel` credential with `op read 'op://kontextmind/Steel (svc-steel)/basic_auth'` into `STEEL_AUTH_BASIC` (or set `STEEL_AUTH_HEADER`, or `STEEL_AUTH_USER` and `STEEL_AUTH_TOKEN`). Do not log the value or write it to disk. A Bearer token is not accepted. `STEEL_API_KEY` is deprecated and is not enforced. Keep the credential in a header, not a URL. `STEEL_API_URL` defaults to `https://steel.kontextmind.com`. `kxm` 0.7.135 or newer is required.
|
|
46
46
|
- Do not print credentials to the chat or save them to tracked files.
|
|
47
47
|
|
|
48
48
|
2. **Launch Remote Steel Session**:
|
|
@@ -200,21 +200,23 @@ The Runtime supervisor runs `kxm run` workflows and syncs their summaries to the
|
|
|
200
200
|
|
|
201
201
|
## Browser automation
|
|
202
202
|
|
|
203
|
-
Playwright testing and verification use Obscura. Steel is for human takeover, MFA, and the live session viewer. `resolveBrowserCdpEndpoint()` in `plugins/kxm/src/browser.ts` returns the CDP URL. `resolveBrowserCdpConnect()` returns that URL and the handshake headers, and `connectBrowserOverCdp()` passes them to `chromium.connectOverCDP`. `node scripts/obscura.mjs` downloads pinned Obscura v0.2.3 and serves it. See [Browser automation](../guides/browser-automation.md).
|
|
203
|
+
Playwright testing and verification use Obscura. Steel is for remote and hosted browsing, human takeover, MFA, and the live session viewer. `resolveBrowserCdpEndpoint()` in `plugins/kxm/src/browser.ts` returns the CDP URL. `resolveBrowserCdpConnect()` returns that URL and the handshake headers, and `connectBrowserOverCdp()` passes them to `chromium.connectOverCDP`. `node scripts/obscura.mjs` downloads pinned Obscura v0.2.3 and serves it. Steel needs `kxm` 0.7.135 or newer. See [Browser automation](../guides/browser-automation.md) and [ADR-0007](../adr/ADR-0007-steel-caddy-authentik.md).
|
|
204
204
|
|
|
205
205
|
| Variable | Default | Effect |
|
|
206
206
|
|---|---|---|
|
|
207
|
-
| `KXM_BROWSER` | `obscura` | `obscura` selects the Obscura CDP URL and sends no Steel headers. `steel` selects `
|
|
207
|
+
| `KXM_BROWSER` | `obscura` | `obscura` selects the Obscura CDP URL and sends no Steel headers. `steel` selects `/v1/devtools` plus `Authorization` and requires a session id. Any other value throws |
|
|
208
208
|
| `OBSCURA_CDP_URL` | `http://127.0.0.1:${OBSCURA_PORT:-9222}` | CDP URL passed to `chromium.connectOverCDP()`. When set, it wins over `OBSCURA_PORT` for that URL |
|
|
209
209
|
| `OBSCURA_PORT` | `9222` | TCP port for `obscura serve`. Used in the default CDP URL when `OBSCURA_CDP_URL` is unset. The launcher refuses to start when this port disagrees with the port in `OBSCURA_CDP_URL` |
|
|
210
|
-
| `STEEL_API_URL` |
|
|
210
|
+
| `STEEL_API_URL` | `https://steel.kontextmind.com` | Base URL of the Steel API. `steel.theneuro.me` is an alias of that server |
|
|
211
211
|
| `STEEL_UI_URL` | `$STEEL_API_URL/ui` | Base URL of the Steel session viewer |
|
|
212
|
-
| `STEEL_AUTH_HEADER` | unset | Full `Authorization` value.
|
|
212
|
+
| `STEEL_AUTH_HEADER` | unset | Full `Authorization` value. First among the Steel auth variables |
|
|
213
213
|
| `STEEL_AUTH_BASIC` | unset | `base64(user:token)`, with or without a leading `Basic` prefix. Sent as `Authorization: Basic` |
|
|
214
|
-
| `STEEL_AUTH_USER` | unset | Authentik username
|
|
214
|
+
| `STEEL_AUTH_USER` | unset | Authentik username `svc-steel`. Used with `STEEL_AUTH_TOKEN`. An incomplete pair fails closed |
|
|
215
215
|
| `STEEL_AUTH_TOKEN` | unset | Authentik app password. Used with `STEEL_AUTH_USER` |
|
|
216
|
-
| `STEEL_API_KEY` |
|
|
217
|
-
| `USE_PASS_CLI` | enabled | Set to `false` to
|
|
216
|
+
| `STEEL_API_KEY` | unset | Deprecated. Steel and Caddy do not enforce it. The three variables above override it. The library warns once |
|
|
217
|
+
| `USE_PASS_CLI` | enabled | Set to `false` to skip the legacy `STEEL_API_KEY` lookup. That lookup does not authenticate |
|
|
218
|
+
|
|
219
|
+
`STEEL_AUTH_HEADER`, then `STEEL_AUTH_BASIC`, then `STEEL_AUTH_USER` with `STEEL_AUTH_TOKEN`, override `STEEL_API_KEY`. Load field `basic_auth` from 1Password vault `kontextmind`, item `Steel (svc-steel)`, with `op read` into `STEEL_AUTH_BASIC`. Do not write the value to disk. The CDP path is `/v1/devtools` with an `Authorization` header. Sessions return `websocketUrl` `wss://steel.kontextmind.com/`.
|
|
218
220
|
|
|
219
221
|
Obscura's own `OBSCURA_TIMEZONE` (default `Europe/Berlin`) and `OBSCURA_CDP_TOKEN` (required only for a non-loopback bind) are read by the Obscura process, not by KXM.
|
|
220
222
|
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"name": "kxm",
|
|
4
4
|
"displayName": "KXM",
|
|
5
|
-
"version": "0.7.
|
|
5
|
+
"version": "0.7.147",
|
|
6
6
|
"description": "Headless multi-agent orchestration, durable workflows, and a live operator dashboard for Pi and Claude Code",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "KontextMind",
|
package/plugins/kxm/dist/cli.js
CHANGED
|
@@ -51929,7 +51929,7 @@ var DEFAULT_MODES_CONFIG = Object.freeze({
|
|
|
51929
51929
|
browser: {
|
|
51930
51930
|
description: "Remote Steel browser sessions and visual testing",
|
|
51931
51931
|
tools: ["steel_session", "steel_scrape", "steel_screenshot"],
|
|
51932
|
-
promptSnippet: "
|
|
51932
|
+
promptSnippet: "Playwright tests use Obscura. Steel is remote browsing and takeover through Caddy and Authentik; send Authorization, never a credential in the URL."
|
|
51933
51933
|
}
|
|
51934
51934
|
}
|
|
51935
51935
|
});
|
|
@@ -17313,7 +17313,7 @@ function sessionTokenFixHint(policy) {
|
|
|
17313
17313
|
}
|
|
17314
17314
|
|
|
17315
17315
|
// plugins/kxm/src/mcp-server.ts
|
|
17316
|
-
var VERSION = "0.7.
|
|
17316
|
+
var VERSION = "0.7.147";
|
|
17317
17317
|
var CONFIGURE_PLUGIN = "/plugin configure kxm@kxm";
|
|
17318
17318
|
var inbox = /* @__PURE__ */ new Map();
|
|
17319
17319
|
var notifiedInbox = /* @__PURE__ */ new Set();
|
|
@@ -33751,7 +33751,7 @@ var SteelAuthRedirectError = class extends Error {
|
|
|
33751
33751
|
this.host = host;
|
|
33752
33752
|
}
|
|
33753
33753
|
};
|
|
33754
|
-
var LEGACY_STEEL_AUTH_WARNING = "kxm: STEEL_API_KEY is deprecated for Steel.
|
|
33754
|
+
var LEGACY_STEEL_AUTH_WARNING = "kxm: STEEL_API_KEY is deprecated for Steel. Steel and Caddy do not enforce it. Set STEEL_AUTH_HEADER, or STEEL_AUTH_BASIC, or STEEL_AUTH_USER and STEEL_AUTH_TOKEN. Those override STEEL_API_KEY. Send Authorization on the request, not in the URL.\n";
|
|
33755
33755
|
var legacySteelAuthWarned = false;
|
|
33756
33756
|
function resetLegacySteelAuthWarningForTests() {
|
|
33757
33757
|
legacySteelAuthWarned = false;
|
|
@@ -34057,7 +34057,7 @@ var SteelClient = class {
|
|
|
34057
34057
|
return res;
|
|
34058
34058
|
}
|
|
34059
34059
|
/**
|
|
34060
|
-
* Launch a new Steel browser session
|
|
34060
|
+
* Launch a new Steel browser session.
|
|
34061
34061
|
*/
|
|
34062
34062
|
async createSession(options) {
|
|
34063
34063
|
const timeoutMs = options?.timeoutMs ?? this.config.timeoutMs ?? 3e5;
|
|
@@ -34340,7 +34340,7 @@ var DEFAULT_MODES_CONFIG = Object.freeze({
|
|
|
34340
34340
|
browser: {
|
|
34341
34341
|
description: "Remote Steel browser sessions and visual testing",
|
|
34342
34342
|
tools: ["steel_session", "steel_scrape", "steel_screenshot"],
|
|
34343
|
-
promptSnippet: "
|
|
34343
|
+
promptSnippet: "Playwright tests use Obscura. Steel is remote browsing and takeover through Caddy and Authentik; send Authorization, never a credential in the URL."
|
|
34344
34344
|
}
|
|
34345
34345
|
}
|
|
34346
34346
|
});
|
package/plugins/kxm/package.json
CHANGED
|
@@ -1,38 +1,37 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: kxm-browser-auth
|
|
3
|
-
description: Retrieve application credentials and manage authenticated browser profiles
|
|
3
|
+
description: Retrieve application credentials and manage authenticated browser profiles without secret exposure. Steel uses the svc-steel credential from 1Password via op read.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# KXM Browser Credentials & Authenticated Profiles
|
|
7
7
|
|
|
8
|
-
Use this skill to retrieve target application credentials and manage browser session state
|
|
8
|
+
Use this skill to retrieve target application credentials and manage browser session state. The Steel `svc-steel` credential comes from 1Password and is read with `op read`. It is never written to disk.
|
|
9
9
|
|
|
10
10
|
## Purpose & Scope
|
|
11
11
|
|
|
12
|
-
-
|
|
12
|
+
- Read the Steel credential at runtime from 1Password.
|
|
13
13
|
- Prevent secrets from leaking into git repositories, logs, prompts, or model-visible tool outputs.
|
|
14
14
|
- Support safe storage and retrieval of session storage state and authenticated profiles.
|
|
15
15
|
|
|
16
16
|
## Credential Retrieval Guidelines
|
|
17
17
|
|
|
18
|
-
### 1.
|
|
18
|
+
### 1. Steel credential: 1Password
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
`STEEL_API_KEY` is deprecated. Steel and Caddy do not enforce it. Authenticate as `svc-steel`. Precedence is `STEEL_AUTH_HEADER`, then `STEEL_AUTH_BASIC`, then `STEEL_AUTH_USER` and `STEEL_AUTH_TOKEN`. Those override `STEEL_API_KEY`. `STEEL_API_URL` defaults to `https://steel.kontextmind.com`. `kxm` 0.7.135 or newer is required.
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
#
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
# Retrieve the Authentik app password for Steel. The proxy accepts Authorization: Basic.
|
|
27
|
-
# STEEL_AUTH_USER is the Authentik username (for example svc-steel).
|
|
28
|
-
pass-cli item view --vault-name "<vault>" --item-title "<steel-item>" --field password
|
|
23
|
+
# Vault kontextmind, item "Steel (svc-steel)", field basic_auth.
|
|
24
|
+
# Do not redirect this into a file.
|
|
25
|
+
export STEEL_AUTH_BASIC="$(op read 'op://kontextmind/Steel (svc-steel)/basic_auth')"
|
|
29
26
|
```
|
|
30
27
|
|
|
28
|
+
`STEEL_AUTH_USER` is `svc-steel` when you use the user and token pair. Send the value as `Authorization` on `/v1/devtools`. Never put it in the URL.
|
|
29
|
+
|
|
31
30
|
### 2. Secret Redaction Invariants
|
|
32
31
|
|
|
33
32
|
- **Never** write plain passwords, session tokens, or API keys into markdown docs, commit messages, or prompts.
|
|
34
33
|
- **Never** pass plain credentials as unredacted command line arguments in shared logs.
|
|
35
|
-
-
|
|
34
|
+
- Keep the `op read` result in the environment of the process that calls Steel.
|
|
36
35
|
|
|
37
36
|
### 3. Profile & Storage State Management
|
|
38
37
|
|
|
@@ -15,16 +15,17 @@ Use this skill to investigate and resolve connectivity failures, CDP attachment
|
|
|
15
15
|
- **Diagnosis**:
|
|
16
16
|
- KontextMind Steel is behind Authentik forward auth. Unauthenticated requests redirect to `id.kxmd.dev`. Authentik accepts an app password only as `Authorization: Basic`. A Bearer token is refused.
|
|
17
17
|
- Check that `STEEL_AUTH_BASIC` is set, or that both `STEEL_AUTH_USER` and `STEEL_AUTH_TOKEN` are set (`test -n "$STEEL_AUTH_TOKEN" && echo set`); never print the value.
|
|
18
|
-
-
|
|
19
|
-
-
|
|
18
|
+
- `STEEL_API_KEY` is deprecated. Steel and Caddy do not enforce it. Do not put a credential in the URL. Direct LAN, tailnet, and host-forward connections are blocked.
|
|
19
|
+
- `websocketUrl` `ws://steel-browser/` means the client is older than `kxm` 0.7.135. The server returns `wss://steel.kontextmind.com/`.
|
|
20
|
+
- **Remedy**: Re-read the `svc-steel` field `basic_auth` with `op read 'op://kontextmind/Steel (svc-steel)/basic_auth'` into `STEEL_AUTH_BASIC`. Do not log it or write it to disk. Precedence is `STEEL_AUTH_HEADER`, then `STEEL_AUTH_BASIC`, then `STEEL_AUTH_USER` and `STEEL_AUTH_TOKEN`.
|
|
20
21
|
|
|
21
22
|
### 2. CDP WebSocket Attachment Failure
|
|
22
23
|
|
|
23
24
|
- **Symptom**: `WebSocket connection to wss://... failed: 404/500`.
|
|
24
25
|
- **Diagnosis**:
|
|
25
26
|
- Check if the target session ID has already been released or timed out.
|
|
26
|
-
-
|
|
27
|
-
- **Remedy**: Query `GET /v1/sessions/<id
|
|
27
|
+
- The CDP path is `/v1/devtools` on `wss://steel.kontextmind.com/` with an `Authorization` header. Caddy must pass the WebSocket upgrade. A credential in the URL is not accepted.
|
|
28
|
+
- **Remedy**: Query `GET /v1/sessions/<id>` with the same `Authorization` header. If status is `released`, launch a fresh session.
|
|
28
29
|
|
|
29
30
|
### 3. Session Timeout & Expiration
|
|
30
31
|
|
|
@@ -21,11 +21,12 @@ Use this skill for exploratory navigation, DOM inspection, scraping, and interac
|
|
|
21
21
|
Ensure an active Steel session exists and obtain its CDP endpoint:
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
|
-
# CDP
|
|
25
|
-
|
|
24
|
+
# CDP path only. The session websocketUrl is wss://steel.kontextmind.com/.
|
|
25
|
+
# The Authentik credential is an Authorization header, not a query parameter.
|
|
26
|
+
CDP_URL="wss://steel.kontextmind.com/v1/devtools?sessionId=<sessionId>"
|
|
26
27
|
```
|
|
27
28
|
|
|
28
|
-
Build that URL with `formatCDPConnect()` so the `Authorization
|
|
29
|
+
Build that URL with `formatCDPConnect()` so the `Authorization` header is available for the handshake. Precedence is `STEEL_AUTH_HEADER`, then `STEEL_AUTH_BASIC`, then `STEEL_AUTH_USER` and `STEEL_AUTH_TOKEN`. Those override `STEEL_API_KEY`, which Steel and Caddy do not enforce. A Bearer token is not accepted. `kxm` 0.7.135 or newer is required. Read `basic_auth` with `op read` and do not write it to disk.
|
|
29
30
|
|
|
30
31
|
### 2. Connect a client that can send the header
|
|
31
32
|
|
|
@@ -5,7 +5,7 @@ description: Start, attach to, inspect, and release self-hosted Steel browser se
|
|
|
5
5
|
|
|
6
6
|
# KXM Browser Session Management
|
|
7
7
|
|
|
8
|
-
Use this skill to create, inspect, attach automation tools to, and release isolated browser sessions
|
|
8
|
+
Use this skill to create, inspect, attach automation tools to, and release isolated browser sessions on the Steel server. `STEEL_API_URL` defaults to `https://steel.kontextmind.com`. `steel.theneuro.me` is an alias of that server. `kxm` 0.7.135 or newer is required.
|
|
9
9
|
|
|
10
10
|
Playwright testing and verification use Obscura by default (`resolveBrowserCdpEndpoint()`, or `npm run e2e`). Use this skill's Steel session for human takeover, MFA, and the live session viewer. Attach Playwright to that session only when `KXM_BROWSER=steel`.
|
|
11
11
|
|
|
@@ -18,9 +18,9 @@ Playwright testing and verification use Obscura by default (`resolveBrowserCdpEn
|
|
|
18
18
|
|
|
19
19
|
## Prerequisites
|
|
20
20
|
|
|
21
|
-
1.
|
|
22
|
-
2.
|
|
23
|
-
3.
|
|
21
|
+
1. `kxm` 0.7.135 or newer. The server is `https://steel.kontextmind.com`. Caddy and Authentik forward auth are the only path. Direct LAN, tailnet, and host-forward access is blocked. Sessions return `websocketUrl` `wss://steel.kontextmind.com/` (previously `ws://steel-browser/`).
|
|
22
|
+
2. The `svc-steel` Authentik credential in the environment. Allowed groups are `steel-users`, `kxmd-users`, `kxmd-admins`, and `kxmd-owners`. Read it at runtime and do not write it to disk: `export STEEL_AUTH_BASIC="$(op read 'op://kontextmind/Steel (svc-steel)/basic_auth')"`. Precedence is `STEEL_AUTH_HEADER`, then `STEEL_AUTH_BASIC`, then `STEEL_AUTH_USER` and `STEEL_AUTH_TOKEN`. Those override `STEEL_API_KEY`. `STEEL_API_KEY` is deprecated. Steel and Caddy do not enforce it. A Bearer token is refused. Never put the credential in a URL.
|
|
23
|
+
3. HTTPS to `steel.kontextmind.com` for the CDP path `/v1/devtools`. Send `Authorization` on the handshake.
|
|
24
24
|
|
|
25
25
|
## Session Lifecycle States
|
|
26
26
|
|
|
@@ -48,7 +48,7 @@ Playwright testing and verification use Obscura by default (`resolveBrowserCdpEn
|
|
|
48
48
|
- **Inputs**: Task ID, target URL, session timeout (default 300s, max 1800s), optional proxy or viewport dimensions.
|
|
49
49
|
- **Outputs**:
|
|
50
50
|
- `sessionId`: Unique session UUID.
|
|
51
|
-
- `cdpUrl`:
|
|
51
|
+
- `cdpUrl`: `wss://steel.kontextmind.com/v1/devtools?sessionId=<id>`. Send `Authorization` on the handshake. The URL has no credential. The session `websocketUrl` is `wss://steel.kontextmind.com/`.
|
|
52
52
|
- `sessionViewerUrl`: Interactive web session viewer URL (`$STEEL_UI_URL?sessionId=<id>`).
|
|
53
53
|
- `status`: `live` | `idle` | `released`.
|
|
54
54
|
|
|
@@ -77,7 +77,7 @@ Local pages require the launcher flag `--allow-private-network` (the launcher al
|
|
|
77
77
|
|
|
78
78
|
## Steel, only for takeover
|
|
79
79
|
|
|
80
|
-
When the case is human takeover, MFA, or the live session viewer, set `KXM_BROWSER=steel` and a session id. `connectBrowserOverCdp()` passes `formatCDPConnect()` headers into `chromium.connectOverCDP
|
|
80
|
+
When the case is human takeover, MFA, or the live session viewer, set `KXM_BROWSER=steel` and a session id. That path needs `kxm` 0.7.135 or newer. `connectBrowserOverCdp()` passes `formatCDPConnect()` headers into `chromium.connectOverCDP` for `/v1/devtools` on `wss://steel.kontextmind.com/`. The `Authorization` header is the `svc-steel` credential (`STEEL_AUTH_HEADER`, then `STEEL_AUTH_BASIC`, then `STEEL_AUTH_USER` and `STEEL_AUTH_TOKEN`). `STEEL_API_KEY` is deprecated and is not enforced. Closing the Playwright browser disconnects the client and does not release the Steel session.
|
|
81
81
|
|
|
82
82
|
```typescript
|
|
83
83
|
import { chromium } from "playwright";
|
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
* (`resolveBrowserCdpEndpoint()`). Steel remains the client for human
|
|
6
6
|
* takeover, MFA, and the live session viewer (`KXM_BROWSER=steel`).
|
|
7
7
|
* Manages remote Steel sessions, CDP endpoints, human takeover handoffs,
|
|
8
|
-
*
|
|
8
|
+
* and automated cleanup without leaking secrets.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* steel.kontextmind.com is reached only through Caddy and Authentik forward
|
|
11
|
+
* auth. Clients send `Authorization: Basic` for the svc-steel credential.
|
|
12
|
+
* A Bearer token is refused. `STEEL_API_KEY` is deprecated and is not
|
|
13
|
+
* enforced by Steel or Caddy. Do not put a credential in the URL.
|
|
13
14
|
*/
|
|
14
15
|
|
|
15
16
|
import { execSync } from "node:child_process";
|
|
@@ -188,9 +189,9 @@ export class SteelAuthRedirectError extends Error {
|
|
|
188
189
|
}
|
|
189
190
|
|
|
190
191
|
const LEGACY_STEEL_AUTH_WARNING =
|
|
191
|
-
"kxm: STEEL_API_KEY is deprecated for Steel.
|
|
192
|
-
"Set STEEL_AUTH_BASIC, or STEEL_AUTH_USER and STEEL_AUTH_TOKEN. " +
|
|
193
|
-
"
|
|
192
|
+
"kxm: STEEL_API_KEY is deprecated for Steel. Steel and Caddy do not enforce it. " +
|
|
193
|
+
"Set STEEL_AUTH_HEADER, or STEEL_AUTH_BASIC, or STEEL_AUTH_USER and STEEL_AUTH_TOKEN. " +
|
|
194
|
+
"Those override STEEL_API_KEY. Send Authorization on the request, not in the URL.\n";
|
|
194
195
|
|
|
195
196
|
let legacySteelAuthWarned = false;
|
|
196
197
|
|
|
@@ -310,6 +311,7 @@ export function resolvePassCliApiKey(
|
|
|
310
311
|
}
|
|
311
312
|
}
|
|
312
313
|
try {
|
|
314
|
+
// Deprecated lookup. The hosted server does not enforce STEEL_API_KEY.
|
|
313
315
|
const output = execFn(
|
|
314
316
|
'pass-cli item view --vault-name "AI Provider Keys" --item-title "Steel Browser (KontextMind DOKS)" --output json',
|
|
315
317
|
);
|
|
@@ -325,8 +327,9 @@ export function resolvePassCliApiKey(
|
|
|
325
327
|
}
|
|
326
328
|
|
|
327
329
|
/**
|
|
328
|
-
* Resolve Steel configuration from environment
|
|
330
|
+
* Resolve Steel configuration from the environment.
|
|
329
331
|
* Does not write secrets to disk or logs.
|
|
332
|
+
* Authentik Basic auth overrides `STEEL_API_KEY`. Steel and Caddy do not enforce that key.
|
|
330
333
|
*
|
|
331
334
|
* Authentik Basic auth (`STEEL_AUTH_HEADER`, `STEEL_AUTH_BASIC`, or
|
|
332
335
|
* `STEEL_AUTH_USER` + `STEEL_AUTH_TOKEN`) wins over `STEEL_API_KEY`.
|
|
@@ -610,7 +613,7 @@ export class SteelClient {
|
|
|
610
613
|
}
|
|
611
614
|
|
|
612
615
|
/**
|
|
613
|
-
* Launch a new Steel browser session
|
|
616
|
+
* Launch a new Steel browser session.
|
|
614
617
|
*/
|
|
615
618
|
async createSession(options?: CreateSessionOptions): Promise<SteelSession> {
|
|
616
619
|
const timeoutMs = options?.timeoutMs ?? this.config.timeoutMs ?? 300000;
|
|
@@ -11,7 +11,7 @@ import { deliverInboxNotification } from "./inbox.ts";
|
|
|
11
11
|
import type { HubEvent, MessageRecord } from "./protocol.ts";
|
|
12
12
|
import { sessionTokenFixHint } from "./session-token-hint.ts";
|
|
13
13
|
|
|
14
|
-
const VERSION = "0.7.
|
|
14
|
+
const VERSION = "0.7.147";
|
|
15
15
|
const CONFIGURE_PLUGIN = "/plugin configure kxm@kxm";
|
|
16
16
|
const inbox = new Map<string, MessageRecord>();
|
|
17
17
|
const notifiedInbox = new Set<string>();
|
package/plugins/kxm/src/modes.ts
CHANGED
|
@@ -123,7 +123,7 @@ export const DEFAULT_MODES_CONFIG: ModesConfig = Object.freeze({
|
|
|
123
123
|
browser: {
|
|
124
124
|
description: "Remote Steel browser sessions and visual testing",
|
|
125
125
|
tools: ["steel_session", "steel_scrape", "steel_screenshot"],
|
|
126
|
-
promptSnippet: "
|
|
126
|
+
promptSnippet: "Playwright tests use Obscura. Steel is remote browsing and takeover through Caddy and Authentik; send Authorization, never a credential in the URL.",
|
|
127
127
|
},
|
|
128
128
|
},
|
|
129
129
|
});
|