Commit Graph
5741 Commits
Author SHA1 Message Date
abkslm 5e858a1088 Merge nucleic/plucky-opal-weasel into dev 2026-07-11 02:49:29 -07:00
abkslm 2f8d05d51b Merge nucleic/plucky-opal-weasel into dev 2026-07-11 02:28:09 -07:00
abkslm 99e7375c2e Merge nucleic/olive-glass-quail into dev 2026-07-11 01:27:32 -07:00
abkslm 1d33dbd935 Merge nucleic/rustic-dewy-ibis into dev 2026-07-11 01:06:49 -07:00
abkslm 97e876114c Merge nucleic/sleek-yarn-tapir into dev 2026-07-11 00:44:10 -07:00
abkslm 708b8dc334 Merge nucleic/warm-umber-panda into dev 2026-07-11 00:15:05 -07:00
abkslm a861a23bc6 Merge nucleic/gentle-coral-lynx into dev 2026-07-11 00:13:14 -07:00
abkslm 0962145926 Merge nucleic/humble-harbor-viper into dev 2026-07-11 00:09:26 -07:00
abkslm 6d9216bef9 Merge nucleic/olive-spruce-koala into dev 2026-07-11 00:02:06 -07:00
abkslm 59acb026a6 Merge nucleic/clever-iris-shrew into dev 2026-07-11 00:00:28 -07:00
abkslm e1e49e7f79 Merge nucleic/amber-opal-shrew into dev 2026-07-10 23:59:45 -07:00
abkslm 40aa6b653d Merge nucleic/clever-pebble-lynx into dev 2026-07-11 06:53:29 +00:00
abkslm ab6be4933c Reduce settings sidebar width 2026-07-11 06:53:18 +00:00
abkslm dd782e2e56 Merge nucleic/humble-harbor-viper into dev 2026-07-10 23:51:32 -07:00
abkslm 27cbf167b6 Merge nucleic/clever-coral-vole into dev 2026-07-10 23:46:07 -07:00
abkslm 94d496d0a0 Merge nucleic/dapper-breezy-shrew into dev 2026-07-10 23:23:44 -07:00
abkslm 1dcd6a7b61 Merge nucleic/quiet-spruce-bison into dev 2026-07-10 23:15:22 -07:00
abkslm 23c467423e Merge nucleic/clever-iris-seal into dev 2026-07-10 22:55:10 -07:00
abkslm 3c5c82cfed Merge nucleic/amber-thistle-viper into dev 2026-07-10 22:36:05 -07:00
abkslm 2ac279112e Merge nucleic/humble-harbor-viper into dev 2026-07-10 22:31:32 -07:00
abkslm 73c64ade93 Merge nucleic/zesty-north-toad into dev 2026-07-10 22:25:00 -07:00
abkslm b9db2577b0 Merge nucleic/frosty-drift-raven into dev 2026-07-10 21:58:38 -07:00
abkslm 25abdeac25 Merge branch 'nucleic/plucky-umber-viper' into dev 2026-07-11 04:38:01 +00:00
abkslmandClaude Fable 5 516f2acfc8 Item 5 tail: all seven credential kinds + Mac "shared with runners" UI
Finishes item 5's mechanical remainder. The runner vault is now table-driven
(RunnerCredentialVault.landings) covering every kind CredentialKind already
defines:
- file-native rotating logins: claude-oauth → ~/.claude/.credentials.json,
  codex-auth → ~/.codex/auth.json (both mirrorable — mirrorableKinds is
  derived from the table)
- grok-config → ~/.grok/config.toml
- env-backed secrets landed to a 0600 nucleic-owned file AND exported as
  their env var so spawned agents inherit them: github-token → GITHUB_TOKEN,
  anthropic/openai/xai keys → ANTHROPIC_API_KEY / OPENAI_API_KEY /
  XAI_API_KEY. missingKinds/land/currentPlaintext/exportPersistedTokens all
  read the one table.

CredentialProvider (device side) reads each from its real Mac source:
Keychain OAuth, ControlAPIKeyStore/CodexControlAPIKeyStore, the ~/.codex
and ~/.grok files, GitHubCredentialStore, and process env for xAI.
landUpdate now reconciles a mirrored-back Codex rotation newest-wins by
last_refresh (CodexAuthFile) alongside Claude's expiresAt; freshness()
stamps both logins' manifest descriptors from their own timestamps.

Mac UI: Settings ▸ Antimatter ▸ Runner gains a read-only "Credentials
shared with runners" list (AppStore.credentialKindsSharedWithRunners) —
what a credentialNeeded is answered with, sealed on request, never exposed
to the relay.

Verified: 6 CredentialMeshTests green (incl. codex land+mirror, xAI
file+env, and a provider/vault kind-lockstep check); Darwin app + iOS
builds; Linux nucleicd build + 171 protocol tests green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-11 04:35:01 +00:00
abkslmandClaude Opus 4.8 983cf37b22 Merge nucleic/humble-slate-tapir into dev
Narrate Linux container lifecycle (create/stop/remove + exec cold-start)
in the chat transcript, mirroring the VM lifecycle lines.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-11 04:34:08 +00:00
abkslmandClaude Opus 4.8 0d7fcee52a Nucleic: Narrate Linux container lifecycle in transcript
Mirror the VM lifecycle transcript lines for agent-managed Linux
containers (linux_container tool): create/stop/remove emit friendly
narration notes that replace the redundant tool card, and an exec
cold-start emits a plain "Starting…" note alongside the exec card
(warm reuse stays silent). Generalize announceVMTransition ->
announceLifecycleTransition, register the container tool in
narratedToolNames, and add ContainerManager.isRunning.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-11 04:32:44 +00:00
abkslm f43088dd23 Merge nucleic/humble-slate-tapir into dev 2026-07-10 21:29:05 -07:00
abkslm 9b942b1dfa Merge branch 'dev' into nucleic/humble-slate-tapir 2026-07-10 21:29:05 -07:00
abkslm a133958fba Nucleic: Add Linux Container Lifecycle Logs 2026-07-10 21:29:05 -07:00
abkslmandClaude Fable 5 fb826bbcf1 Item 5 complete: credential mesh, device side + runner→device mirror-back
Finishes ANTIMATTER_RUNNER §6 / §0.2 item 5 — both directions of the
credential mesh, replacing the smoke stand-in with production device code.

Device providing (CredentialProvider, NucleicCore): captures the Mac's
login credentials (Keychain OAuth via ClaudeLoginKeychain, managed token
via GitHubCredentialStore), gossips a CredentialManifest — now carrying the
device's own sealing key (additive CredentialManifest.sealingPublicKey) so
a runner can seal updates back — and seals its held kinds to a runner's key
answering credentialNeeded. PeerClient.setCredentialHandlers routes all
three (manifest push on connect to a canReceiveSealedCredentials peer,
seal-on-credentialNeeded, land-on-credentialUpdate) into AppStore.

Mirror-back (runner → device, the syncClaudeLoginBack analogue): a
session's CLI refreshes the OAuth token in place; a 30s digest-gated sweep
in nucleicd (AppStore.mirrorRefreshedCredentials) seals the rotation to
each connected device's sealing key and pushes credentialUpdate; the device
reconciles it newest-wins into its Keychain (CredentialProvider.landUpdate
→ ClaudeLoginKeychain.shouldWriteBack). RunnerCredentialVault gains the
current-plaintext read, the change digest, and mirrorBackEnvelope; SyncHost
gains pushCredentialUpdate; ConnectionHandler gains deliverCredentialUpdate.

Refresh lease: AppStore.credentialRefreshHolder arbitrates devices'
gossiped leases with CredentialRefreshLease.merged (earliest live claim
wins), so at most one device advances a rotating token; the runner's own
session CLI is the de-facto refresher and the digest-gated mirror-back
keeps everyone coherent.

Verified: device→runner E2E over the production relay (runner asked,
provisioned, files landed 0600, real claude turn authenticated); the
runner→device reverse-seal + AAD binding + digest change-gate unit-tested
(CredentialMeshTests, 3 tests); Darwin app + iOS builds; 171 protocol tests
green on Linux; sync suites green.

Remaining of item 5 is mechanical (doc'd): more kinds (codex/grok/API
keys) and a Mac UI surface for what it shares.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-11 04:21:25 +00:00
abkslm 91490e875c Merge nucleic/plucky-umber-viper into dev 2026-07-10 20:59:00 -07:00
abkslm 1c47343ae5 Merge branch 'dev' into nucleic/plucky-umber-viper 2026-07-10 20:59:00 -07:00
abkslm 6016ff6059 Nucleic: Read Document Continuation 2026-07-10 20:59:00 -07:00
abkslmandClaude Fable 5 f99f418674 Item 5, runner half: credential mesh receiving — proven E2E over the relay
ANTIMATTER_RUNNER §6 / §0.2 item 5, the runner side. RunnerCredentialVault
(NucleicCore): a credential-sealing X25519 keypair minted on first boot and
persisted in the secret store (distinct from the Noise identity, so
credentials survive identity rotation), a missing-kinds inventory, and the
0600-file landing map — claude-oauth → ~/.claude/.credentials.json (what
the CLI reads), github-token → ~/.nucleic/github-token + GITHUB_TOKEN in
the daemon env, re-exported at boot.

nucleicd sets the vault at boot, which flips canReceiveSealedCredentials
on; SyncHost pushes HostMsg.credentialNeeded post-hello to approve-scope
peers (defaulted SyncHostBridge.credentialNeed hook); AppStore's
receiveCredentialProvision opens each box (kind string bound as AAD — a
box can't be replayed as another kind) and lands it, skipping records
sealed to a stale key. nucleic-smoke plays the holding device: it answers
credentialNeeded by sealing its local files to the runner's key, and holds
the chat until the provision round-trip lands so the turn itself proves
the credentials.

E2E on Linux over the production relay: a fresh-HOME runner reported both
kinds missing, the client sealed + provisioned them, both landed 0600, and
a real claude turn authenticated with the landed OAuth credential — the
item-2 "copied files" interim is retired for the receive side.

Gotcha encoded in processHome(): corelibs' homeDirectoryForCurrentUser
reads passwd and ignores an overridden $HOME on Linux — resolve from the
environment or credentials land where no CLI looks.

Remaining of item 5 (doc'd): Mac-side capture/vault, manifest mirroring,
more kinds, the refresh-lease loop.

Verified: Darwin builds + 170 protocol / 24 sync tests green; the live
Linux E2E above.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-11 03:58:29 +00:00
abkslmandClaude Fable 5 fc8142dfd1 Item 4 tail: the runner-pool credential rides the mesh
Completes §0.2 item 4. HostMsg.runnerPoolCredential (WireRunnerPoolCredential:
poolId/secret/url/updatedAt) is pushed post-hello to control-scope peers the
way relayMembership is (SyncHost.register → ConnectionHandler gate →
defaulted SyncHostBridge.runnerPoolCredential hook), so every trusted mesh
device manages the SAME pool instead of PoP-enrolling its own — which
rotates the secret out from under whoever shared it.

Receivers converge on updatedAt (newest wins): PeerClient routes the push
into AppStore.mergeRunnerPoolCredential, which persists it and hands it to
any in-flight RunnerPoolClient. The credential store upgrades to a JSON
record (legacy bare "poolId.secret" tolerated as distantPast, so any shared
revision supersedes it). RunnerPoolClient now manages the STORED
credential's pool (possibly another device's), resolves the control-plane
URL the credential carries, and only auto-re-enrolls on 401 for its OWN
pool — a rotated shared credential surfaces "re-share from the owning Mac"
rather than silently creating the wrong pool. iOS handles the new event
inertly (Macs are the pool managers today).

Verified: Darwin builds (app + iOS), wire round-trip/tolerance + sync
suites green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-11 03:45:21 +00:00
abkslm 3d32dcbb84 Merge branch 'dev' into nucleic/plucky-umber-viper 2026-07-10 20:38:31 -07:00
abkslm 41bef61853 Merge nucleic/warm-river-lynx into dev 2026-07-10 20:16:09 -07:00
abkslm 469d7b0f62 Merge nucleic/warm-river-lynx into dev 2026-07-10 20:13:36 -07:00
abkslm bc3779c4c5 Merge nucleic/frosty-dewy-quail into dev 2026-07-10 20:09:55 -07:00
abkslm ded6d0a637 Merge nucleic/zesty-glass-heron into dev 2026-07-10 19:47:50 -07:00
abkslm 8e7e1db440 Merge nucleic/zesty-glass-heron into dev 2026-07-10 19:41:06 -07:00
abkslm a4dcb0c26b Merge remote-tracking branch 'origin/dev' into dev 2026-07-11 02:25:34 +00:00
abkslmandClaude Opus 4.8 cb1d0f1ab5 Runner smoke: probe relay with a valid key + classify reachability
The egress probe sent a deliberately-invalid staticKey, so a now-reachable
relay returns 422 'staticKey not base64' — which reads like a failure but
actually proves the Cloudflare challenge is gone (the Worker, not the edge,
answered). Send a well-formed 32-byte key (healthy relay -> 200) and print an
explicit verdict: Cloudflare-blocked vs unreachable vs reachable.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-11 02:24:46 +00:00
abkslm 78e28e5f0b updating runner container version tag 2026-07-10 19:24:38 -07:00
abkslmandClaude Opus 4.8 a75dd4c8b3 Runner image: base on multi-arch nucleic-sandbox:v6 (amd64 slice)
The runner image builds linux/amd64 (Cloudflare Containers), but was still
FROM nucleic-sandbox:v5, which is arm64-only — so buildx pulled the arm64 base
and the first RUN failed with exit 255 (wrong-arch exec). v6 is the first
multi-arch sandbox tag (linux/amd64 + arm64, verified present in GHCR), so
base on it. Comment updated to match.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-11 01:59:57 +00:00
abkslm 5cf0821399 updating wrangler configs, preparing for runners 2026-07-10 18:57:16 -07:00
abkslmandClaude Opus 4.8 d9c43b25bc Runner smoke: don't gate image on Cloudflare bot-challenge of the relay
Root cause of the boot smoke failure is a Cloudflare edge bot-challenge (HTTP
403 'Just a moment') served for relay.nucleic.blakeslee.xyz from the runner's
datacenter IP — the identical curl probe gets the same 403, so it's an infra
policy, not a nucleicd defect. Treat that specific signature as a loud
non-fatal skip so the image still publishes, while still hard-failing on any
other early-boot error. The real fix is a Cloudflare WAF Skip rule exempting
the relay host from Super Bot Fight Mode / Managed Challenge; the enroll
endpoint is already X25519 proof-of-possession protected.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-11 01:34:32 +00:00
abkslm 714e786dd6 Merge branch 'dev' into nucleic/clever-breezy-lynx 2026-07-10 18:14:19 -07:00
abkslm 0129dc3b27 Merge nucleic/clever-breezy-lynx into dev 2026-07-10 18:14:18 -07:00
abkslmandClaude Opus 4.8 0c2fb86de9 Runner smoke: surface relay-enroll failure cause + curl egress probe
The runner image smoke test only reported an opaque "challenge request"
when nucleicd failed to enroll with the relay on boot. RelayAccess.postJSON
collapsed transport errors, non-200 statuses, and malformed bodies into one
string, hiding whether the fully-static musl binary's URLSession/libcurl leg
is failing vs the relay rejecting vs no egress. Surface the specific cause,
and add an independent curl probe to the smoke step so one build tells us
which layer is at fault.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-11 01:13:51 +00:00