elm-call-rpc

SkillDev tools

Call 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.

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 given Nothing, otherwise refreshes the access token first if expired/expiring (via the AccessToken RPC), then calls your req with the current token. Returns the (possibly-refreshed) Account back so you can persist it.
  • MaybeAccountRequest.performWithAccount — same, but takes/returns a concrete Account (not Maybe) — use once you've already confirmed a signed-in account exists (e.g. after your own permission check), so you're not re-handling Nothing at the call site.
  • Always propagate the refreshed account back, e.g. Effect.fromShared (Shared.AccountsPanelMsg (AccountsPanel.AccountRefreshed account)) from a page, or as the Maybe AccountsPanel.Msg a Shared-level panel's update returns. Skipping this silently drops a rotated refresh token, breaking future requests once the old one expires. Grep any existing fetchX/GotXResult handler (Components/Posts.elm, Shared/StarredPostsPanel.elm, Shared/MarkdownPanel.elm) for the pattern.
  • connection is { host : String, port_ : Int, tls : Bool }, built from a Server as { host = server.backendHost, port_ = server.port_, tls = server.tls }backendHost, not frontendHost (the latter is the public-facing name; the gRPC API actually lives at backendHost, 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