diff --git a/CLAUDE.md b/CLAUDE.md index 2f20d219..5ff74582 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -145,9 +145,6 @@ Swarm-level: crates. - **`swarm-builder/`** — builds agent config PR heads for commit status. Design: [`docs/swarm/builder.md`](docs/swarm/builder.md). -- **`swarm-claude-login/`** — runs `claude auth login` for one agent and - stores the credentials at `swarm/agents//claude-credentials`. - Design: [`docs/swarm/claude-login.md`](docs/swarm/claude-login.md). - **`swarm-review-classifier/`** — one `claude --print` per PR classification, no tools, no forge credential. Design: [`docs/swarm/review-classifier.md`](docs/swarm/review-classifier.md). diff --git a/Cargo.lock b/Cargo.lock index d4df3417..c735e9e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4851,22 +4851,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "swarm-claude-login" -version = "0.1.0" -dependencies = [ - "anyhow", - "async-nats", - "futures-util", - "hive-log", - "hive-types", - "serde_json", - "swarm-queue-client", - "swarm-secret-client", - "tokio", - "tracing", -] - [[package]] name = "swarm-controller" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 8f9f1a9b..096d4bd8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,6 @@ members = [ "swarm-agent-verify", "swarm-authelia-bridge", "swarm-builder", - "swarm-claude-login", "swarm-authelia-bridge-sock", "swarm-controller", "swarm-matrix-client", diff --git a/docs/README.md b/docs/README.md index 95c804ef..0121a33e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -91,9 +91,6 @@ declarations. (planned, not implemented yet). - **Does an agent config PR build before it's merged?** → [`swarm/builder.md`](swarm/builder.md). -- **How do I log an agent in to claude from the swarm UI, and why doesn't a - stale stored copy log it out again?** → - [`swarm/claude-login.md`](swarm/claude-login.md). ## Scheduler, CI, observability diff --git a/docs/swarm/claude-login.md b/docs/swarm/claude-login.md deleted file mode 100644 index 18b06f92..00000000 --- a/docs/swarm/claude-login.md +++ /dev/null @@ -1,82 +0,0 @@ -# Claude login from the swarm UI - -An operator logs an agent in to claude from the agent's card in the swarm UI. -No hive is in the path: the login runs in the swarm's `swarm-claude-login` -service, the credentials go to the agent's own leaf in the secret store, and the -agent's harness installs them from there. - -Where it runs and how it's enabled: [`services.md`](services.md#claude-login-minter). - -## What happens on a login - -1. The agent publishes `needs_login` in its turn-state header, and its card - shows **login needed** with a **log in** button. -2. **log in** opens a dialog, which calls - `POST /api/agents//claude-login`. swarm-controller relays the start as - a request on the queue subject `$SWARM.claude-login.request`. -3. The minter runs `claude auth login` with `HOME` and `CLAUDE_CONFIG_DIR` in a - fresh scratch directory, over plain stdio pipes, and answers with the first - `https://` URL it prints. The dialog shows that URL. -4. The operator opens the URL, signs in to the agent's own claude account, and - pastes the code the page shows into the dialog, which posts it to - `POST /api/agents//claude-login/code`. -5. The minter writes the code to claude's stdin and waits for it to exit. It - stores the `.credentials.json` claude wrote at - `swarm/agents//claude-credentials` (field `value`), as a new version - over any stored before, and removes the scratch directory. -6. The agent's harness, while it waits for a login, reads that leaf every 30 - seconds under the agent's own certificate. When the stored version is newer - than the one it installed last, it writes the file to - `~/.claude/.credentials.json`, records the version, and resumes its turn - loop as it does after a login from the agent's web UI. - -A started login waits 15 minutes for its code, then the minter stops it. -Starting another login for the same agent replaces the running one. Each step -has a minute to finish; a refused code fails the login, and the dialog shows -what claude printed. - -## Why the harness takes only a newer version - -`claude` rotates the refresh token in `.credentials.json` as it uses the -session, and the agent can't write the store. After the first refresh the -stored copy is stale. A harness that installed it whenever the bytes differed -would replace the agent's live session with a stale copy and log the agent -out. The harness therefore compares the store's KV version with the last -version it installed (`claude-credentials-version` under the harness dir): - -- it installs a newer version, that is, a new login; -- it leaves an equal or older version alone, even when the agent needs a - login again, so it never puts back a session that has gone bad; -- it reads nothing while the agent has a session. - -## Credentials - -| Principal | Grant | -| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | -| `swarm-claude-login`, in its container | `create`, `update` on `swarm/agents/+/claude-credentials`; `read` on `swarm/services//oidc/client` | -| the agent, under its own certificate | `read` on its own `swarm/agents//*`, which covers the leaf | - -The minter has no read on the leaf and nothing else under an agent. Every -hive's policy reads `swarm/agents/*`, so every hive can read every agent's -claude session, as it can read the GitHub token. - -The `operatorsOnly` authelia rule on the swarm domain, not the controller, -keeps these routes to operators: the controller checks only that the gateway -named a user. Without that rule any account authelia admits could store its -own claude session as any agent's, so no agent account may exist before the -rule reaches the swarm. - -The minter refuses a step whose agent name isn't an identifier before it -makes a directory or runs `claude`. - -## Caveat - -The installed-version record lives under the harness dir and the credentials -file under `~/.claude`. If only the record survives a rebuild, the agent -ignores the stored version until the operator logs it in again, which writes a -newer one. - -## What stays - -The agent's own web UI login (`/login`) still works, unchanged. It goes away -once the operator has confirmed the swarm login works. diff --git a/docs/swarm/credentials.md b/docs/swarm/credentials.md index 2c5cd4e4..7fd613a3 100644 --- a/docs/swarm/credentials.md +++ b/docs/swarm/credentials.md @@ -68,7 +68,6 @@ of the cell says how. | `swarm/agents//forge-token` | `swarm-controller`, at agent creation and in a pass every 5 minutes over every agent with a store identity | the agent container itself, under its own certificate, fetched to `/run/hive-agent-forge-token/token` | ✅ the controller re-mints when the stored token is missing or no longer matches the forge (last eight characters and scopes) | ✅ the agent re-fetches on a 10-minute timer | | `swarm/agents//forge/