2 Commits
Author SHA1 Message Date
pastilhasandClaude Opus 5 f67bb44b7e fold the upstream source reading into the assessment
The first pass was written from the running server's own OpenAPI document and live probes. This
adds what the source at tag v1.18.16 says, which changes three things.

The names are transitional at BOTH ends. session.next.* is the event family of the rewritten
event-sourced engine, landed in 1.15.0 (PR #27415); on the v2 branch all 36 events have already
dropped the .next. and some are renamed outright — agent.switched becomes agent.selected,
prompted becomes prompt.promoted. Those renames are v2-branch only and the 1.x line we run still
emits the old names, so the guidance is to code against them but keep one mapping table. The
schema package's own AGENTS.md says the V2 suffix is going too.

Upstream calls the /api surface EXPERIMENTAL in its own title — "Experimental HttpApi surface for
selected instance routes", version 0.0.1 — while /session/* is what the public docs document and
is not deprecated. Worth writing down plainly: the internal direction is unambiguous, the external
commitment is nil, and we would be building on a surface its authors have not committed to.

The SDK is generated from the exact document we probed: the build script runs opencode's own
generate and feeds it to hey-api, and @opencode-ai/sdk/v2 exposes the whole /api surface, takes a
directory and injects it as both the header and the location query param. That is our hand-rolled
SSE reader, both envelope unwrappers, three type sets and the model-id splitting, deleted.

Also corrected by reading rather than guessing: permissions v2 is a real contract change (rules,
requests and the reply all change shape, and free-text replies are gone) while questions v2 is a
pure re-homing with identical fields — so they are not one piece of work. And the durable cursor's
replay-then-live is gap-free by construction: it re-reads the database on every wake instead of
draining a buffer, with the prompt response's admittedSeq as the first cursor.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 04:21:17 +01:00
pastilhasandClaude Opus 5 d86d3ed1c0 assess opencode's newer api, and find two live defects while doing it
Tonight's brief was to read everything about "OpenCode API 2.0" and write down what moving to
it would change and what it would buy. Two things fell out of the measuring that are not
migration concerns at all — they are broken in production right now:

The two surfaces are MUTUALLY BLIND. A session created through /api reads as [] on the legacy
GET /session/{id}/message, and a legacy session 500s on GET /api/session/{id}/message. We run
turns through /api since Phase D and read transcripts through legacy, so every opencode
conversation created since 2026-08-10 opens empty — the row carries its title and directory
from the session record, and the transcript underneath it is nothing.

GET /api/session defaults to 50 rows and hands back a cursor.next. We send neither limit nor
cursor, so the oldest sessions silently stop appearing once the store passes 50. The local
store is at exactly 50 today. That is this morning's commit.

On the name: there is no "2.0" in the running server, and "API 2.0" turns out to mean two
different things. The /api/* surface in 1.18.16 has operation ids literally called v2.*, and
we already run every turn on it — so it is not something to adopt, it is something to finish.
OpenCode 2.0 the product is a separate beta (binary opencode2, npm @next) whose docs warn it
may wipe data, and which REMOVES the two durable routes the restart-recovery work would depend
on, in favour of an experimental/ path. Worth knowing before building on them.

Verified by driving a real turn end to end: the durable event log replays from a cursor
(?after=5 returned exactly 6-10, and the SSE at ?after=7 replayed 8,9,10 then held the socket),
which is the answer to the gap Phase B left open. But deltas are live-only BY SCHEMA — the
durable oneOf has 28 members and omits text.delta, tool.input.delta, reasoning.delta,
compaction.delta — so both streams are needed, not one.

Also reproduced a second silent-failure mode with the same signature as the missing credential:
a session with no model, on a serve with no configured default, sits at admitted -> prompted
forever. Our runner only sets a model when one was asked for.

Probes cleaned up after themselves; the session store is back to the 50 rows it started with.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 04:17:33 +01:00