Twenty-seven commits and ten days. One new table, plugin_ports, which is a plain create — nothing references it, so db:push has no ordering problem to get wrong. The marketplace's nullable release_tag is deliberately out of scope: db:push covers officer_db, and the marketplace runs only on officer-dev, which the rollout skips. @anthropic-ai/sdk is new, so bun install is a step. The lockfile is committed and matches; a host that cannot resolve from it is a finding, not something to force past.
6.5 KiB
2026.09.09.01 — ten days of platform work, and one new table
Twenty-seven commits, deploy/2026.08.30.03..fafc1adb. The fleet is ten days behind; this is a
catch-up release rather than a fix for anything found in the last one.
The larger threads in it, so a host that misbehaves has somewhere to point:
- Plugin ports — the platform can allocate a plugin a stable port and remember it (
518d329c,d9110c37). This is the schema change; see below. - Publishing is a tag — the marketplace reads releases, not working trees (
78e89ebc,19bbbab9). - Plugin routing — a plugin owns the routing under its mount and can declare its own routes
(
89820972,1fe767ea), with:sectiongiven back to the fifteen plugins the splat took it from (eaa92738). - The code editor's tree and file browser are exported for plugins to reuse (
fb530456,5fa3f3ec,da07048f). anthropicViaProxy(fafc1adb) — the boundary through which platform-side code, including a plugin's server routes, reaches Claude on the owner's own subscription.
The schema change — one new table, one nullable column
Verified rather than assumed:
git diff --name-only deploy/2026.08.30.03..master | grep -iE 'schema|databases/'
Two files, and they are not equally in scope:
-
officer_db—plugin_ports, a brand-new table. No foreign key onto it and no existing column pointing at it, so this is not the create-then-constrain shape thatdb:pushcannot do. A plainbun db:pushis enough, and it is a create on every host. -
marketplace_db—plugins.release_tag, a nullable text column. Out of scope for this rollout.bun db:pushcoversofficer_dbonly, and the marketplace runs on exactly one machine:officer-marketplace → officer-dev only (verified 2026-09-09, pm2 jlist on all six)officer-devis the host the rollout skips. So no target needs it, and nothing should improvise a second push to reach it. It is named here so that whenofficer-devis restarted deliberately, the marketplace database is known to be the one outstanding piece.
Dependency change — bun install is required
git diff --name-only deploy/2026.08.30.03..master -- package.json bun.lock # both changed
@anthropic-ai/sdk@^0.71.0 was added (plus its json-schema-to-ts dependency). The lockfile is
committed and matches, so the frozen-lockfile default resolves from it — plain bun install, never
--no-frozen-lockfile. A host that cannot resolve from the lockfile is a finding, not something to
force past.
Every host — the commands
The standard steps in prompts/deploy-commander.md are the rollout (dirty check — TRACKED only,
git fetch origin --tags, git merge --ff-only deploy/2026.09.09.01, bun run plugins:update), plus,
in this order:
bun install
bun db:push < /dev/null
pm2 restart officer
bun install before plugins:update, because the plugin installer runs against the platform's own
resolved modules. db:push after both, because gen-plugin-schemas runs inside it and reads the
plugins as they now are.
< /dev/null on the push is not decoration: stdin closed means a push that wants to ask a question
fails instead of hanging forever in an unattended run. This change should ask nothing — a create of a
table nothing else references — so a prompt here is a finding.
pm2 restart officer only. plugins:update has already restarted the plugin sidecars itself.
Verify it came back — three checks, per host, by query
Exit 0 from db:push is not evidence; drizzle-kit push can fail and still exit 0.
-
The table exists, asked of that host's own database:
psql "$DB_URL" -tAc "select to_regclass('public.plugin_ports')" # → plugin_portsRead the URL from that checkout's
.env— several hosts useOFFICERDEV_POSTGRES_URL, notPOSTGRES_URL. -
pm2 jlist—officerisonlineand itsrestart_timemoved. -
HTTP —
/api/healthon the host's own port.200or401are both healthy. The port is in.envand is 9010 onmacbookpro, 9000 elsewhere.
Per host
| Host | Login | State before | Note |
|---|---|---|---|
alpha |
pastilhas |
19bbbab9, 8 commits past the tag |
Partially pulled at some point; the fast-forward is shorter than the others'. |
fofos |
pastilhas |
fafc1adb — already at master |
Already carries every commit; the merge is a no-op that only moves the tag onto it. Still runs install/push/restart. One untracked file — a note, not a skip. |
macbookpro |
pastilhas |
c97da029 (2026.08.30.03) |
Laptop. Asleep is a SKIP with a note. export PATH=$PATH:/opt/homebrew/bin for bun, and run pm2 as a separate command. Port 9010. |
deadpool-rezio-bridge |
br |
c97da029 (2026.08.30.03) |
Not pastilhas. |
Skipped, deliberately — not failures
officer-dev— the host the rollout runs on. Skipping it entirely is the rule; restartingofficerthere ends the rollout mid-report. It is atfafc1adband therefore not behind in code; what it does still want is the marketplace column above, whenever the owner restarts it.macbruno— unreachable at cut time (connect to host macbruno port 22: Connection timed out, verified 2026-09-09). A Mac, so most likely asleep.- Both Pertento hosts — on the deliberately-skipped list in
docs/servers.mdsince 2026-09-08. Owner's call, no fault on either box.
What "done" looks like
Four hosts attempted: alpha, fofos, macbookpro, deadpool-rezio-bridge. Each at
deploy/2026.09.09.01, plugin_ports present by query, officer back online, health answering on the
right port.
A host that fails does not stop the rollout. It gets its own line saying which step failed and what never ran.
Known and carried, not introduced here
bunx tsgo reports one pre-existing type error in src/servers/sidecar/claude/claude-manager.ts:667
(SdkUserMessage vs SDKUserMessage, from the agent SDK's own types). It is present on master
before this release's commits, it is type-only, and Bun strips types at run time — so it does not
affect the rollout. Named here so it is not discovered mid-deploy and mistaken for something this
release did.