From c72296368f8d00c247cc110056cc1d51410aed10 Mon Sep 17 00:00:00 2001 From: Alex Lavaee Date: Sat, 24 Oct 2026 00:05:12 -0700 Subject: [PATCH] Upgrade Atomic to the stable 0.9.43 release The harness catalog now pins @bastani/atomic 0.9.43, and the lockfile resolves @bastani/atomic, @bastani/atomic-natives with its eight platform packages, and @bastani/pi-ai at 0.9.43, with no older @bastani package left. Atomic's @earendil-works pi packages stay at 1.4.0. The release is about local workflow worker pools: a crashed worker's child is replayed on a new worker instead of failing the root, leases follow worker liveness, startup no longer reads the whole journal, and WorkflowInfrastructureError marks retryable pool faults. Pools stay off unless the operator's Atomic settings enable them, and the adapter calls nothing whose shape changed, so it needs no code change. Each worker's standard error is now kept in worker-logs/ beside the journal. A real Planner workflow with an operator-enabled pool and a child that crashes put those logs under Chopin's journal directory, not Atomic's default, replayed the child three times, and ended with a failed run card. That directory is private only because the adapter creates it with mode 0700, which nothing tested; the journal test now checks the mode and fails when the adapter drops it. The self-hosting guide names the new version and says where the logs go, that failed workers' logs are kept, and which settings set the startup timeout and lease. Assistant-model: Claude Opus 5.5 (fast) Assistant-workflow: inline (fast subagents) Assistant-verification: bun test (6734 pass, 22 skip, 0 fail), bun run types, bun run ci Assistant-verification: journal directory mode test fails without the adapter's 0700 mode, passes with it Assistant-verification: real Planner workflow with a local worker pool kept worker logs beside the journal and reported the run failed Assistant-verification: docker build of the server image; container started healthy with HARNESS=atomic and imports Atomic 0.9.43 Assistant-verification: targeted bun run e2e (35 passed) User-preference: Keep Atomic and its transitive packages on the same release everywhere Co-authored-by: Alex Lavaee --- apps/server/src/harness/atomic/full.test.ts | 10 +++++++-- bun.lock | 24 ++++++++++----------- docs/self-hosting.md | 13 ++++++++++- package.json | 2 +- 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/apps/server/src/harness/atomic/full.test.ts b/apps/server/src/harness/atomic/full.test.ts index 5c9f55f91..be6eeb874 100644 --- a/apps/server/src/harness/atomic/full.test.ts +++ b/apps/server/src/harness/atomic/full.test.ts @@ -1,7 +1,7 @@ import { afterAll, expect, test } from "bun:test"; -import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises"; +import { mkdir, mkdtemp, rm, stat, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; -import { join } from "node:path"; +import { dirname, join } from "node:path"; import { HarnessAgent } from "@ai-sdk/harness/agent"; import { createJustBashNetworkSandboxSession } from "@ai-sdk/sandbox-just-bash"; import { jsonSchema, tool } from "ai"; @@ -341,6 +341,10 @@ export default workflow({ let files = { operator: await Bun.file(join(agentDir, "settings.json")).exists(), journal: await Bun.file(journal).exists(), + journalDirectoryMode: await stat(dirname(journal)).then( + info => info.mode & 0o777, + () => undefined, + ), defaultJournal: await Bun.file(join(root, "workflows", "journal.sqlite")).exists(), environment: process.env.ATOMIC_WORKFLOW_JOURNAL_PATH, project: projectPackage @@ -558,6 +562,8 @@ test( // and through the session rather than the process-wide environment variable. expect(result.files).toMatchObject({ journal: true, defaultJournal: false }); expect(result.files?.environment).toBeUndefined(); + // Only the server's user can enter its directory, which also holds the worker-logs/ Atomic keeps. + expect(result.files?.journalDirectoryMode).toBe(0o700); } finally { if (environment !== undefined) process.env.NODE_ENV = environment; await room.close(); diff --git a/bun.lock b/bun.lock index 8d620cdfa..ddab69ea1 100644 --- a/bun.lock +++ b/bun.lock @@ -315,7 +315,7 @@ "@ai-sdk/harness": "1.0.146", "@ai-sdk/mcp": "2.0.72", "@ai-sdk/sandbox-just-bash": "1.0.146", - "@bastani/atomic": "0.9.42", + "@bastani/atomic": "0.9.43", "ai": "7.0.135", "typebox": "1.3.7", "zod": "4.4.3", @@ -456,27 +456,27 @@ "@base-ui/utils": ["@base-ui/utils@0.3.2", "", { "dependencies": { "@babel/runtime": "^7.29.2", "@floating-ui/utils": "^0.2.12", "reselect": "^5.2.0", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@types/react": "^17 || ^18 || ^19", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-oWy1aq/I2GmYjpl4PhEAhzflF8VPGKgZeq0xAWTbfD5KBWyxcN0ZP2+WHSUm/5Z6lVMBDLReLcoXwSYoRc/zNQ=="], - "@bastani/atomic": ["@bastani/atomic@0.9.42", "", { "dependencies": { "@bastani/atomic-natives": "0.9.42", "@bastani/pi-ai": "0.9.42", "@earendil-works/pi-agent-core": "1.4.0", "@earendil-works/pi-codemode": "1.4.0", "@earendil-works/pi-tui": "1.4.0", "@modelcontextprotocol/ext-apps": "^1.7.5", "@modelcontextprotocol/sdk": "1.32.1", "@mozilla/readability": "^0.6.0", "@silvia-odwyer/photon-node": "0.3.4", "@typesafe-ai/sdk": "0.7.0", "brace-expansion": "5.0.12", "chalk": "6.0.0", "cross-spawn": "7.0.6", "diff": "8.0.4", "glob": "13.0.6", "grok-mermaid": "0.2.3", "highlight.js": "10.7.3", "hosted-git-info": "9.0.3", "ignore": "7.0.8", "jiti": "2.7.0", "linkedom": "^0.18.13", "lru-cache": "11.5.3", "markit-ai": "0.5.3", "minimatch": "10.2.6", "open": "^11.0.1", "p-limit": "^7.3.2", "proper-lockfile": "4.1.2", "quickjs-wasi": "3.6.2", "semver": "7.8.5", "turndown": "^7.2.0", "typebox": "1.3.27", "undici": "8.10.2", "unpdf": "1.8.1", "yaml": "2.9.0", "zod": "^3.25.0 || ^4.0.0" }, "optionalDependencies": { "@mariozechner/clipboard": "0.3.9" }, "bin": { "atomic": "dist/cli.js" } }, "sha512-oumUw1AdVFvnGRdRFNl2Sv1JBd8feRQE2qLhsZ5ZLSF1NCKtKKlFjvKb71ENCcZ9DKBkSTibNwp99vTQyUCPRA=="], + "@bastani/atomic": ["@bastani/atomic@0.9.43", "", { "dependencies": { "@bastani/atomic-natives": "0.9.43", "@bastani/pi-ai": "0.9.43", "@earendil-works/pi-agent-core": "1.4.0", "@earendil-works/pi-codemode": "1.4.0", "@earendil-works/pi-tui": "1.4.0", "@modelcontextprotocol/ext-apps": "^1.7.5", "@modelcontextprotocol/sdk": "1.32.1", "@mozilla/readability": "^0.6.0", "@silvia-odwyer/photon-node": "0.3.4", "@typesafe-ai/sdk": "0.7.0", "brace-expansion": "5.0.12", "chalk": "6.0.0", "cross-spawn": "7.0.6", "diff": "8.0.4", "glob": "13.0.6", "grok-mermaid": "0.2.3", "highlight.js": "10.7.3", "hosted-git-info": "9.0.3", "ignore": "7.0.8", "jiti": "2.7.0", "linkedom": "^0.18.13", "lru-cache": "11.5.3", "markit-ai": "0.5.3", "minimatch": "10.2.6", "open": "^11.0.1", "p-limit": "^7.3.2", "proper-lockfile": "4.1.2", "quickjs-wasi": "3.6.2", "semver": "7.8.5", "turndown": "^7.2.0", "typebox": "1.3.27", "undici": "8.10.2", "unpdf": "1.8.1", "yaml": "2.9.0", "zod": "^3.25.0 || ^4.0.0" }, "optionalDependencies": { "@mariozechner/clipboard": "0.3.9" }, "bin": { "atomic": "dist/cli.js" } }, "sha512-3vxPdLY2RtFw52sdjVJK/nOQ8tMBJJezLwXbwuW0Fiba/zO+hlv9OqVmco+UK+lITdr4WUP1pNhbVdOHiDCGcQ=="], - "@bastani/atomic-natives": ["@bastani/atomic-natives@0.9.42", "", { "optionalDependencies": { "@bastani/atomic-natives-darwin-arm64": "0.9.42", "@bastani/atomic-natives-darwin-x64": "0.9.42", "@bastani/atomic-natives-linux-arm64-gnu": "0.9.42", "@bastani/atomic-natives-linux-arm64-musl": "0.9.42", "@bastani/atomic-natives-linux-x64-gnu": "0.9.42", "@bastani/atomic-natives-linux-x64-musl": "0.9.42", "@bastani/atomic-natives-win32-arm64-msvc": "0.9.42", "@bastani/atomic-natives-win32-x64-msvc": "0.9.42" } }, "sha512-WZCjkRF8R3BqqaoSalF6sl0HmCJCW0dJd+XahCFWLeUn51nmd8I3F0ew/IiOuXYMNOjW6xtyu+1RI4seAa8Yzg=="], + "@bastani/atomic-natives": ["@bastani/atomic-natives@0.9.43", "", { "optionalDependencies": { "@bastani/atomic-natives-darwin-arm64": "0.9.43", "@bastani/atomic-natives-darwin-x64": "0.9.43", "@bastani/atomic-natives-linux-arm64-gnu": "0.9.43", "@bastani/atomic-natives-linux-arm64-musl": "0.9.43", "@bastani/atomic-natives-linux-x64-gnu": "0.9.43", "@bastani/atomic-natives-linux-x64-musl": "0.9.43", "@bastani/atomic-natives-win32-arm64-msvc": "0.9.43", "@bastani/atomic-natives-win32-x64-msvc": "0.9.43" } }, "sha512-Z2kaOXqIV6Hzt8TPIiYulqXYjwSXsdD4WVyyD9AlsxOQYh0ZAVxcn2sofI2Lrbjv+ZVAoNcGnXRG+9mYXIvpFA=="], - "@bastani/atomic-natives-darwin-arm64": ["@bastani/atomic-natives-darwin-arm64@0.9.42", "", { "os": "darwin", "cpu": "arm64" }, "sha512-kB8p6Cu4C6Cbk5M8htoo0HeSVg7ASs83nvfUlu8j7mR/OVIojIieWhzQnFM/OvAhTrzzkwmFlY1fg7cd9ytSTw=="], + "@bastani/atomic-natives-darwin-arm64": ["@bastani/atomic-natives-darwin-arm64@0.9.43", "", { "os": "darwin", "cpu": "arm64" }, "sha512-L6IdGXu9byEYt5qDJo95DXhvdd8yreSHC0FcorNWQQHTDcJ0KQJp4vQv4wF2lEjXhyIUuQ6jbk2Akfy60XGjxA=="], - "@bastani/atomic-natives-darwin-x64": ["@bastani/atomic-natives-darwin-x64@0.9.42", "", { "os": "darwin", "cpu": "x64" }, "sha512-q5n6eq9mYTi/UkOC1KyQ9RLT5FwgCrxWkFBGiYOgAAVogCSe93b8kpPiMd1m+RUFzeDDmbXkp3pRC9JewXqK+g=="], + "@bastani/atomic-natives-darwin-x64": ["@bastani/atomic-natives-darwin-x64@0.9.43", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZPaZKQDIqN1mS8+UQWwoujZcHngMW00ZBtnZSmovtI4uHjlt7Uq6bLT4oDpV9w/j3C8m7eyuwqWc+hc2QLPzFQ=="], - "@bastani/atomic-natives-linux-arm64-gnu": ["@bastani/atomic-natives-linux-arm64-gnu@0.9.42", "", { "os": "linux", "cpu": "arm64", "libc": "glibc" }, "sha512-MWFfXLBauY9bCOSJG2yDFz/JqCw6SQnCH7j/HpMwVFlH50I0sqycqchp/WPmkgKj1RIDALmJdsiSgk+HoH3iJg=="], + "@bastani/atomic-natives-linux-arm64-gnu": ["@bastani/atomic-natives-linux-arm64-gnu@0.9.43", "", { "os": "linux", "cpu": "arm64", "libc": "glibc" }, "sha512-NlzeDTd1xfMnaUK4k7r3sVJnk6tUwQFXM+2bn9TMT/y9PmCwf/zdwhELeYmq1Dw3lTmCLDVCEvO+VLC19A6a5g=="], - "@bastani/atomic-natives-linux-arm64-musl": ["@bastani/atomic-natives-linux-arm64-musl@0.9.42", "", { "os": "linux", "cpu": "arm64", "libc": "musl" }, "sha512-6R+7YjhRcnhoR00J7+NYiCmzhT5I0zH3LHxnAWIf0Q1aBJ7BmR9eFPFkyrh4kiqUoDtHypz6BtVyoDGWRL5hTA=="], + "@bastani/atomic-natives-linux-arm64-musl": ["@bastani/atomic-natives-linux-arm64-musl@0.9.43", "", { "os": "linux", "cpu": "arm64", "libc": "musl" }, "sha512-KB5CxYvCTo3xpEk+1jVL4E1BfpqEy8SoUB929KkYw5BW/6a58iuBwSPVh7G8l4rttflQGS38SSBEB5zR9NyYLg=="], - "@bastani/atomic-natives-linux-x64-gnu": ["@bastani/atomic-natives-linux-x64-gnu@0.9.42", "", { "os": "linux", "cpu": "x64", "libc": "glibc" }, "sha512-3PYdlncGACpv0RCAQND4aoQVgmceItH0kO+4NX9gBGioxV2tyl+lXQBXDrxGrtbwCFnoWo4tHK1VmiNVI00JmA=="], + "@bastani/atomic-natives-linux-x64-gnu": ["@bastani/atomic-natives-linux-x64-gnu@0.9.43", "", { "os": "linux", "cpu": "x64", "libc": "glibc" }, "sha512-axRBq+r8nbh/aUHWpxs5vY1Y5CWAmM3Dbvc2irQzvIwJwlh3kJJ2YGtyqRlOJ865Kug/3kyebASoGnPfgA5mtw=="], - "@bastani/atomic-natives-linux-x64-musl": ["@bastani/atomic-natives-linux-x64-musl@0.9.42", "", { "os": "linux", "cpu": "x64", "libc": "musl" }, "sha512-0KNKhSaqpYmiltI/Hn/OyRdCPu8j3yH+OoxKJOvdUjC7Yz8JbmBgXAS8iCzxW2j3ImVRafq/TDnZjkC8E0mSNA=="], + "@bastani/atomic-natives-linux-x64-musl": ["@bastani/atomic-natives-linux-x64-musl@0.9.43", "", { "os": "linux", "cpu": "x64", "libc": "musl" }, "sha512-OhI/WtyJQ7A1LKMhzkpZZDPvnRACJ83pt3t/TrPBxyNNpjJi8nkZssC26WxCUJUQfAHkMfeXJoHrS2+WveIqNw=="], - "@bastani/atomic-natives-win32-arm64-msvc": ["@bastani/atomic-natives-win32-arm64-msvc@0.9.42", "", { "os": "win32", "cpu": "arm64" }, "sha512-GOZ0bpq4nMyiN1Rf1qvTON7SPfXhSNutEX69/V0nXjZyMW+76F7FBltaPGOuTZwNo/IeYDsSdpRDOK/+nZWBAA=="], + "@bastani/atomic-natives-win32-arm64-msvc": ["@bastani/atomic-natives-win32-arm64-msvc@0.9.43", "", { "os": "win32", "cpu": "arm64" }, "sha512-xVp0zj+aGvpS5N3Uvx4ik8woYo3wOotMK3epeW+sr+6LsySglB+ndxxMs5kCcnfBIu5jYcwU134Ja+KDaYwIkA=="], - "@bastani/atomic-natives-win32-x64-msvc": ["@bastani/atomic-natives-win32-x64-msvc@0.9.42", "", { "os": "win32", "cpu": "x64" }, "sha512-fLS42PRe/2TOtIie06cDqYWAP9dWBQN6AzyG8vI0BjJCA3OfYHj2MSl7alW/j8KdK9tXD1t9i5FC3COVi895bQ=="], + "@bastani/atomic-natives-win32-x64-msvc": ["@bastani/atomic-natives-win32-x64-msvc@0.9.43", "", { "os": "win32", "cpu": "x64" }, "sha512-9pld9tA/dB8IfBe4vWoGMfX2tHWTaVpH5uhoMrzhGB71+3vvYWaWYtyqJ+xeMiQg6gueT3N0ihHpSpo8QPl/9A=="], - "@bastani/pi-ai": ["@bastani/pi-ai@0.9.42", "", { "dependencies": { "@anthropic-ai/sdk": "0.129.0", "@aws-sdk/client-bedrock-runtime": "3.1127.0", "@earendil-works/pi-telemetry": "1.4.0", "@google/genai": "2.21.0", "@smithy/node-http-handler": "4.12.1", "http-proxy-agent": "9.1.0", "https-proxy-agent": "9.1.0", "openai": "7.19.0", "partial-json": "0.1.7", "typebox": "1.3.27" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-ORPzQhHtEMhcQ4Fc4mMS4vP+Gli2IRAyHoKUnVLg/rKMmDJmdsIZtOOyS55NGyP7qoRD7mPMjEl+4JQjv7a7tA=="], + "@bastani/pi-ai": ["@bastani/pi-ai@0.9.43", "", { "dependencies": { "@anthropic-ai/sdk": "0.129.0", "@aws-sdk/client-bedrock-runtime": "3.1127.0", "@earendil-works/pi-telemetry": "1.4.0", "@google/genai": "2.21.0", "@smithy/node-http-handler": "4.12.1", "http-proxy-agent": "9.1.0", "https-proxy-agent": "9.1.0", "openai": "7.19.0", "partial-json": "0.1.7", "typebox": "1.3.27" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-KO+sc350H9Xv9G1LhMr57yuqu/N02s9ch/8KNe0L4VM/iShcuCWOd4bWkP956cVGDJYpd4/INylONAi3RHjLhg=="], "@borewit/text-codec": ["@borewit/text-codec@0.2.2", "", {}, "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ=="], diff --git a/docs/self-hosting.md b/docs/self-hosting.md index 685ee3e31..d5b8a1b0f 100644 --- a/docs/self-hosting.md +++ b/docs/self-hosting.md @@ -75,7 +75,7 @@ each owner's GitHub App user token and does not consume `HARNESS_AUTH`; setting `auto` on loopback passes the startup guard but does not enable host login in that adapter. -`HARNESS=atomic` runs Atomic 0.9.42 in the Chopin server process through its +`HARNESS=atomic` runs Atomic 0.9.43 in the Chopin server process through its headless SDK (`createAgentSession()`). It does not spawn the `atomic` CLI or use RPC mode. @@ -165,6 +165,17 @@ Atomic caveats: [Full Atomic Planner](hosted-agent.md#full-atomic-planner)). The Docker image sets `XDG_STATE_HOME=/var/lib/chopin`; mount a volume there to keep runs and those directories when the container is replaced. +- Local workflow worker pools stay off unless the operator's Atomic settings + set `workflows.localWorkers`. With a pool, Atomic 0.9.43 keeps each worker's + standard error in `worker-logs/` beside the journal, so under + `$XDG_STATE_HOME/chopin/atomic/worker-logs//`, inside the directory + Chopin creates for the journal with access for the server's user only. It + deletes a log when its worker shuts down normally but keeps the logs of + workers that failed; remove them yourself. A child whose worker dies is + replayed on a new worker, up to three attempts; after that the run fails and + its card in Chat says so. The settings `workflows.localWorkers.startupTimeoutMs` + and `leaseMs` set how long a worker may take to start and how long an + unresponsive one keeps its child. - Atomic depends on `typebox` 1.3.27 while Chopin pins 1.3.7. Host tool schemas pass to Atomic as plain JSON Schema, so the two versions never meet. diff --git a/package.json b/package.json index 077145c29..4e19f7aa1 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "@ai-sdk/harness": "1.0.146", "@ai-sdk/mcp": "2.0.72", "@ai-sdk/sandbox-just-bash": "1.0.146", - "@bastani/atomic": "0.9.42", + "@bastani/atomic": "0.9.43", "ai": "7.0.135", "typebox": "1.3.7", "zod": "4.4.3"