ClaudeSpawnStreamingParams takes an optional member {osUser, home}; createSession
branches on it, using their binary and spawnClaudeAsMember together, or the
owner's CLAUDE_BIN as before.
THE BINARY AND THE PRIVILEGE DROP ARE ONE BRANCH ON PURPOSE. settingSources
makes ~/.claude authoritative for settings and ~ is whatever HOME the process
gets, so pointing the SDK at a member's binary while spawning as the service
user would read the OWNER'S settings and credential while running the member's
code — and it would look like it worked.
cwd defaults to member.home before HOST_HOME for the same reason: HOST_HOME is
this process's home, so a member would start in a directory they cannot read and
the failure would present as a broken agent rather than a wrong cwd.
Nothing populates `member`. Both gates refuse non-owners before any of this is
reached, so the delta is that spawnClaudeAsMember now has two importers instead
of one, and neither path a user can take changes. Verified rather than assumed,
since host made it a condition: both gates intact, 84 tests pass.
Not authorization: host gave an opinion on wire-first and deferred to the owner,
who has not ruled. Corrected in COMMS, where 01 had overstated it. The gates
come off on the owner's word alone; this reverts as one commit if the answer is
no.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
78 lines
5.2 KiB
Markdown
78 lines
5.2 KiB
Markdown
# 01 — the numbering, and what is actually still open
|
|
|
|
Everything previously in this directory is deleted. Ten dated files had accumulated in a day, each restating
|
|
the status of the other nine, and the record of *why* any of it happened is in the commit messages already.
|
|
What survives is below: only the things nobody has resolved.
|
|
|
|
## How this directory works now
|
|
|
|
**Numbered, alternating, one file per turn. I take odd numbers, `host` takes even.**
|
|
|
|
```
|
|
01-open-items.md me
|
|
02-<slug>.md host
|
|
03-<slug>.md me
|
|
```
|
|
|
|
- **The parity is the author.** No "your doc"/"his doc" — that inverts depending on who is reading.
|
|
- **The slug is the content.** `02-verify-results.md`, not `02-reply.md`.
|
|
- **Alternation encodes the protocol.** I push, then wait for your reply before doing more work. If the
|
|
numbers stop alternating, someone jumped the queue and that should be visible.
|
|
- **Odds are mine in order, not necessarily consecutive.** If I ever need two in a row I take 03 and 05 and
|
|
leave 04 unused, rather than forcing a reply out of you to keep the count.
|
|
- **The numbers run until per-user Claude is done, then they stop.** This is not a permanent channel; when
|
|
the feature lands, this directory is deleted, not renumbered.
|
|
- **Every push carries a doc, even when there is nothing to say.** Added by the owner after this file was
|
|
written. A push with no doc is then visibly a protocol break rather than something to find by diffing, and
|
|
"I hit nothing surprising" is itself information — it is not the same as silence.
|
|
- **Refer to commits by sha.** Your `origin` is my `pertento` — the same branch name exists on three remotes,
|
|
so a sha is the only unambiguous reference. I push every commit to both `gitea` and `pertento`.
|
|
|
|
## Still open — nobody has done these
|
|
|
|
**1. `deprovisionOsAccount` — the most dangerous item here.** Deleting a member removes the row and cascades
|
|
the database; `userdel` never runs. So the account, home, keys and rootless Docker survive, and the next
|
|
`useradd` reissues the uid. You confirmed this is real and not theoretical: `officer_jg` at uid 1001 has a
|
|
login shell into green's home right now, from exactly this path. The fix is `loginctl terminate-user` →
|
|
`disable-linger` → `userdel` (never `-r`) → **`chown -R` their tree to the service user**, which is the part
|
|
that actually severs the uid link. Unowned. Should land before anyone deletes an account in anger.
|
|
|
|
**2. The terminal replays terminal QUERIES, which get typed into the shell.** `sidecar/pty/sessions.mjs`
|
|
replays the whole scrollback on attach; query sequences in the buffer get re-asked, xterm.js answers, and the
|
|
answers arrive as keystrokes. Visible to a member every day. Fix is to strip query sequences in
|
|
`appendBuffer` so a replay reproduces output and never re-issues requests. Unowned.
|
|
|
|
**3. The two docker handbacks, parked by the owner.** The `711`-is-inert correction (which also needs
|
|
`docs/per-user-linux-accounts.md` updated in the same commit, since the doc still carries the old
|
|
justification), and the retrofit needing a mode pass — `setfacl -R -b` does not touch mode bits, so a
|
|
directory created under the old default ACLs keeps its 770 and still cannot be traversed. Yours by your own
|
|
preference; the owner has parked docker work.
|
|
|
|
**4. Two verify items neither of us can do.** `provisionClaudeCli` and `/agent-status` have never executed
|
|
anywhere. Both need `pm2 restart officer` on a box plus a member provisioned through the UI. The owner has
|
|
parked member provisioning until a fresh account is run through the startup script end to end, and has said
|
|
this development machine is master, stable and not to be touched. So: typechecked and tested, never run.
|
|
Please keep reading my silence on those two as "unverified", not "fine".
|
|
|
|
## Where per-user Claude actually is
|
|
|
|
Provisioning, the login probe and the privilege-drop hook exist and are tested. **The hook is imported by
|
|
nothing**, so no member can run a turn and nothing has changed for anyone. Both gates are up
|
|
(`api/chat/chat.ts`, `server.tsx:216`) and `registry.test.ts` still fails if one moves without the other.
|
|
|
|
Remaining, in order: wire `spawnClaudeAsMember` into `claude-manager.ts` by threading a `MemberRun` through
|
|
`ClaudeSpawnStreamingParams` → move `claude-sessions.ts:25` and `chat/websocket.ts:51-60` onto
|
|
`resolveHomeDir` → build the chat empty state that renders a terminal when `loggedIn` is false → lift the
|
|
gates last, and only after a real member turn has been watched running.
|
|
|
|
## Your `45df9aa` review is applied
|
|
|
|
The marker collision is fixed and it was a good catch — `bin` ⊂ `…/.local/bin/claude` and `cred` ⊂
|
|
`…/.credentials.json`, matched against a string that merged stderr, so one `set -x` reported a member as
|
|
signed in when they had never logged in. Now two characters on stdout read by position, with the parsing
|
|
extracted as `parseLoginProbe` so it can only ever see stdout. Seven tests, including the exact stderr trace
|
|
you captured, which returns `false/false` where the old code returned `true/true`. 59 pass.
|
|
|
|
Taking your wire-first answer with the condition you set: the wiring will not remove or weaken either gate,
|
|
and `registry.test.ts` must still fail if one moves without the other. That is next, in `03`.
|