elm-call-rpc
SkillDev toolsCall a Rellm gRPC RPC (from protos/*.proto) from Elm SPA code (frontends/elm-spa). Use when writing or wiring up a new fetch/mutation against the backend from a page or Shared panel.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the elm-call-rpc skill
What this skill tells your AI
The instructions your AI receives, as published by jonlatane/jonline in .claude/skills/elm-call-rpc/SKILL.md and read by ahel’s review.
Basic shape
Each RPC (protos/rellm.proto's service Rellm) has a generated Grpc.Rpc req res value in Proto.Rellm.Rellm (e.g. Rellm.updatePost, Rellm.createPost, Rellm.getPosts), from the anmolitor/elm-grpc package (Grpc module).
Grpc.new Rellm.updatePost requestValue
|> Grpc.setHost (AccountsPanel.serverUrl server)
|> Grpc.addHeader "authorization" token -- only for authenticated calls
|> Grpc.toTask -- : Task Grpc.Error res
Use Grpc.toTask when chaining (Task.andThen) or Task.attempting yourself; Grpc.toCmd if you just want a Cmd msg directly.
Many RPCs (CreatePost, UpdatePost, ...) take/return the whole resource message directly (Post -> Post), not a separate FooRequest/FooResponse pair — check the actual rpc line in the .proto file rather than assuming a request wrapper exists.
Auth / token refresh: use Shared.MaybeAccountRequest
Don't call Grpc.addHeader "authorization" with a token you're holding onto — it may have expired. Instead:
MaybeAccountRequest.perform : connection -> Maybe Account -> (Maybe String -> Task Grpc.Error b) -> Task Grpc.Error ( Maybe Account, b )— anonymous if givenNothing, otherwise refreshes the access token first if expired/expiring (via theAccessTokenRPC), then calls yourreqwith the current token. Returns the (possibly-refreshed)Accountback so you can persist it.MaybeAccountRequest.performWithAccount— same, but takes/returns a concreteAccount(notMaybe) — use once you've already confirmed a signed-in account exists (e.g. after your own permission check), so you're not re-handlingNothingat the call site.- Always propagate the refreshed account back, e.g.
Effect.fromShared (Shared.AccountsPanelMsg (AccountsPanel.AccountRefreshed account))from a page, or as theMaybe AccountsPanel.MsgaShared-level panel'supdatereturns. Skipping this silently drops a rotated refresh token, breaking future requests once the old one expires. Grep any existingfetchX/GotXResulthandler (Components/Posts.elm,Shared/StarredPostsPanel.elm,Shared/MarkdownPanel.elm) for the pattern. connectionis{ host : String, port_ : Int, tls : Bool }, built from aServeras{ host = server.backendHost, port_ = server.port_, tls = server.tls }—backendHost, notfrontendHost(the latter is the public-facing name; the gRPC API actually lives atbackendHost, often a CDN).
Read-modify-write safety
Some RPCs take and unconditionally apply a whole record server-side — e.g. UpdatePost (backend/src/rpcs/posts/update_post.rs) overwrites visibility/media/embed_link/shareable/etc. from whatever Post you send, not just the field you intended to change. If you're changing one field of something fetched a while ago (user was editing in a text box, a panel sat open, etc.), re-fetch it fresh immediately before submitting and overlay only your change onto that fresh copy — don't resubmit a possibly-stale in-hand snapshot. See Shared/MarkdownPanel.elm's saveTask (Task.andThens a fresh GetPosts into the eventual UpdatePost) for the pattern. Check the corresponding backend/src/rpcs/**/*.rs handler when in doubt about which fields get blindly overwritten vs. merged.
Errors
AccountsPanel.grpcErrorToString : Grpc.Error -> String is the shared formatter (Grpc.BadUrl/Timeout/NetworkError/BadStatus { errMessage }/BadBody) used for displaying RPC failures — use it instead of writing a new Grpc.Error -> String case expression.
Signals
- GitHub stars
- 65
- Forks
- 5
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
elm-call-rpc- Source
- github.com/jonlatane/jonline