Repository navigation
feat: leadline, what your code did in development, as an installable plugin with a box-side helper - #56
Merged
Conversation
…n a worktree
Leadline is a plugin in the listing (Settings → Plugins → Browse), not
built in. It adds Queries, Traces, Logs and Endpoints panels to a worktree,
read from berth-leadline, the helper its manifest carries for boxes, and a
Leadline screen that turns the helper on, off and updates it per box.
- berth.helper in the plugin SDK: status, install, remove and request, bound
to the calling plugin's own id (/v1/plugins/{id}/helper on the laptop
agent, helpers/{plugin}/api/ through a box).
- The consent dialog and a plugin's row in Settings say, by the program's
name, that a plugin with box.helper can install and run it on boxes.
- Send to the agent writes a slow query, an N+1 or a failing endpoint up,
shows the text to be edited, and sends it to the worktree's agent or
starts one. Statements are written by shape, never with values.
- Chart in @berth/plugin/ui: the app's own chart view for plugins.
- Mock mode runs the listing's bundle, installed and allowed, on fixtures
captured from the real helper (scripts/capture-leadline-fixtures.mjs).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and runs on a box
A plugin's berth-plugin.json may declare "box.helper": a program, how to
run it, and the address, size and SHA-256 of its build for each platform.
The manifest is covered by the plugin's consent hash, so the checksums are
what the person allowed.
berthd (internal/box/helpers*.go):
- keeps a helper in <state>/box/helpers/<plugin>/ (bin/<version>/<name>,
data/, install.json, helper.log), takes it only from a paired laptop, and
only if the bytes are the size and SHA-256 sent; checks the file again
each time it starts it
- starts installed helpers before it serves anything, starts one again when
it exits (1s, 2s, 4s … a minute; "failed" after three in a row), stops
them with itself, and ends any an earlier berthd left running
- GET /v1/helpers, GET|PUT|DELETE /v1/helpers/{plugin}, GET …/log, and
ANY /v1/helpers/{plugin}/api/…, relayed to the helper's loopback address
with that as the Host and no Origin; 409 helper_off when it is not running
- before a worktree's service starts, asks each running helper with an
attach path and merges the variables it answers, within the manifest's
attach_env; a helper that is down, slow or wrong changes nothing
- berthd helpers, berthd helper log|rm (and berth … BOX)
laptop agent (internal/agent/helpers.go):
- GET|POST|DELETE /v1/plugins/{id}/helper?box=B for a plugin that is
installed and allowed as it is now: downloads the build for the box's
platform, checks it against the manifest, and uploads it over Shipyard's
own connection
berth-leadline:
- POST /api/attach: the attach helper and the proxies in one call
- a helper started on port 0 comes back on the port it had (listen.json),
so what a dev server was told still reaches it after a restart
listing build:
- build-marketplace.mjs carries box.helper into the listing, fills the
assets of a helper built in this repository from its released builds,
and no longer empties site/plugins/ when a build fails
- scripts/release-leadline-helper.sh builds, lists and uploads the four
builds of berth-leadline to a release of their own (not run here)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # app/package.json
berth.helper.request("devl", "GET", "queries") asked the box for
helpers/<id>/api/queries. berthd relays everything after helpers/<id>/api
as the path on the helper, and berth-leadline's API is under /api/, so on a
real box every panel read /queries, got the helper's plain 404, and the
laptop agent reported that as "runs an older berthd that doesn't have this
yet" under a helper that was running. Mock mode answered either path.
The request now goes to helpers/<id>/api/api/<path>, as the SDK's own words
say ("asks the helper for /api/queries") and as the box's test with the
real helper asks. The mock answers only what a real box and helper would.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Against a real agent and box, the plugin misread three answers that mock mode had answered differently: - "off" is all a box says of a helper it does not have, whether it never had it or it was turned off; "none" is a plugin that names no helper. The plugin took "none" for never installed, so a box that had never run Leadline was told that what it recorded before is kept. - "unsupported" is two things: a berthd that cannot run helpers (it never says its platform), and a platform the plugin has no build for. The row sent both to Settings -> Boxes to update the box, which is what every box shows while a helper has no released builds. A box with no build now says that, and nothing about updating. - A download that fails or does not match its checksum is refused by the agent (502) and leaves the box off; "failed" is a program that is on the box and will not start. The confirm already shows the refusal. The mock now answers each of these as the agent and berthd do, with a scenario for each, and the SDK's types and docs say what the states mean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When a helper is removed the box answers with the services it started
while the helper was on and that are still running ("attached"): their
telemetry endpoint and their database URL are the helper's, and nothing
restarts them. The app threw that answer away (berth.helper.remove
resolved with nothing), and the screen said only to restart "any service
that was started while it was on".
remove() now resolves with the status the laptop answers, attached
services included, and Leadline says which to restart: in a notification,
and on the box's row until it is turned on again. Removing its data says
the same.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ffline The laptop agent answers a helper's failed download, a checksum that does not match and a helper that did not answer the relay with 502 and a code of their own (helper_download, helper_mismatch, helper_unreachable). Leadline shows the agent's sentence itself, but anything that reaches the app's own explanations took a 502 for "can't reach the box". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… is removed Turning Leadline off and then removing its data asked the box twice, and the second answer names no service: the helper was already gone. The row took that for "nothing to restart" and dropped the note, while the service went on pointing at the helper. An answer with no services now leaves what the row already knew; turning Leadline on again is what clears it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What you get
Leadline as a plugin you install from Settings → Plugins → Browse (not built in). On a worktree it adds four tabs:
A Leadline screen turns it on or off per box. Nothing leaves the box.
How it works
berth-plugin.jsonnames the program, its arguments and a checksum per platform. The manifest is already covered by the consent hash, and the consent dialog now says the plugin can install and run a program on your boxes, naming it.berthdstores it, re-checks the hash at every start, starts it before any service, restarts it on a crash, stops it on shutdown, and relays its API to the app. When a worktree service starts, the helper is asked for the tracing settings and aDATABASE_URLthrough its proxy; a helper that is down or slow changes nothing.berthdstays small:go list -deps ./cmd/berthd ./cmd/berth | grep leadline/prints nothing.How it was checked
go vet ./...andgo test -race ./...: all packages pass on the merged branch (no Go changed after that run).typecheck:plugins,check:titles,check:csp,check:themes,check:marketplace, unit tests (340 pass),pnpm build,npx tsc -p e2e; docs build.leadline.spec.ts,marketplace.spec.tsand the matching a11y scenes, 36 pass.berthdandberth agentwith their own homes, a local registry, the built app driven by Playwright. Leadline was installed from Browse, allowed, turned on for the box; a service started byberthdsent real traces and logs and ran statements through the proxy; all four tabs showed them; a repeated statement was flagged N+1 and each query was counted once; then Turn off and Remove data.The live run found that, as first merged, no panel could read anything from a real box (the request path to the helper was one segment short and the 404 was reported as an old
berthd). That and four smaller mismatches are fixed in the last five commits, with tests, and the mock now answers only what a real box would.Not covered
pgxclient. SCRAM auth, TLS negotiation and real timings are untested.Before it works for anyone
No helper is released.
scripts/release-leadline-helper.shbuilds the four binaries, uploads them to aleadline-helper-v0.1.0release (not marked latest) and fills the listing's checksums. It has never been run. Until then the listing has no builds and every box says it can't run Leadline.Open decisions
berthd helper rmstops it.internal/boxtests take 6 to 10 minutes under-race, near Go's 10-minute per-package limit.Left out
A database editor, comparing a worktree against
main, metrics, Leadline's overview charts, and a Home widget.🤖 Generated with Claude Code