no enrichment — and the log would die with the laptop instead of living on
the boat.
The deciding argument
A ship's log belongs to the ship. Storing it in SQLite on the agent machine
was always slightly wrong; we just hadn't said it out loud. signalk-logbook
puts the entries on the vessel's own server as human-readable YAML — files
that remain trivially parseable decades from now even if every tool in this
post is abandoned.
That reframing also clarified what was actually ours: not entry storage,
but the agent-facing tool surface and (on the roadmap) USCG/Transport Canada
sea-time accounting — which nothing in the ecosystem does. So logbook-mcp
became ~200 lines of stateless glue: mark_moment and read_entries over
the plugin's REST API, with sea-service form export later derived from
the plugin's entries instead of kept in a parallel store. One source of
truth; the only code we maintain is the genuinely novel part.
What adoption actually cost: four undocumented quirks
Adopting someone else's plugin is not free. The OpenAPI spec got us 80% of
the way; live integration against the real server found the rest:
-
POST /logs returns a bare 201 with no body. You don't get the
created entry back — so confirming "what did I just write?" means
re-fetching the day and taking the newest entry (with a previous-UTC-day
fallback for midnight races).
-
The "optional"
ago field is mandatory in practice. The spec marks
it optional; the code calls buffer.get(req.body.ago) whenever its
15-minute state buffer is non-empty, and buffer.get(undefined) throws.
Send ago: 0 always.
-
Author attribution reads a cookie, not the Authorization header. The
plugin derives the entry author from
parseJwt(req.cookies.JAUTHENTICATION).
Our client sends the token both ways: header for the server's auth gate,
cookie for the plugin.
-
All
/plugins/* REST routes are admin-gated. signalk-server's
adminAuthenticationMiddleware guards every plugin route — device access
tokens and read/write user tokens get 401 no matter what permissions you
grant them. The agent's token must belong to an admin user. We verified
this in the server source after two very confusing rounds of token
provisioning.
None of these are complaints — they're the normal cost of integrating with
real software, and they're all documented now (in our
SPEC and
in this post, which is the writeup we wish we'd found). The total was still
a fraction of what maintaining our own store, schema migrations, UI, and
auto-entry pipeline would cost.
Where the line actually is
The audit's useful output wasn't "adopt" — it was a cleaner boundary:
-
Theirs: entry storage, enrichment, semi-automatic entries, the
curation UI. Commodity for us; their core competence.
-
Ours: the agent tool surface (validated schemas, TTS-safe
display strings,
honest error states that never claim an unrecorded moment was logged),
and the sea-time/licensing layer nothing else provides.
If you're holding working code you built before you knew the ecosystem,
the audit is still worth running. The sunk cost is real but small; ours
was one evening, and we traded a database for two hundred lines of glue
and a log that lives where it should — on the boat.