agentleFS
tkollehtkolleh/skills/morphir/SKILL.md

morphir

Skill1 starsChanged 3 months agoMITView on GitHub

Translate pure business/decision logic (Scala, Java, or similar) into Morphir IR via hand-authored Elm, then verify the translation with a hand-traced decision table against the source code. Trigger on: "model this in Morphir", "translate this logic to Morphir IR", "morphir-elm", "decision table verification", "verify this Elm model against the source", "morphir-elm make/gen/develop", or when a codebase's pure rule/eligibility/comparison logic needs a formal, language-agnostic representation for review or downstream generation. Covers `morphir.json` project shape, `morphir-elm` CLI subcommands and their traps, and the decision-table technique for verifying an Elm model's behavior matches its source — a fixture-based equivalence check, not exhaustive state-space search. Do not use for parsing/checking a domain spec's own syntax (that's a spec-authoring tool's job, not this skill's), for exhaustive state-space model-checking of a specification (see `alloy-structural-analysis` if that toolchain is available — a different, complementary kind of verification), or for modeling effectful code (I/O, database access, network calls) — Morphir's guarantees are about pure functions, and effectful code needs heavy hand-waving to represent that isn't worth the cost.

The file

We split this skill into the rules it gives an agent

1 rule. About 0 are common, 1 is distinctive, and 0 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Done when: every fixture in the table has traced outcomes recorded for both the model and the source, and every divergence is either …

    line 76

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Morphir

Translates pure business/decision logic into Morphir IR by hand-authoring an equivalent Elm model, then verifies the translation is behaviorally faithful using a hand-traced decision table — not by trusting morphir-elm gen/test/develop round-trips, which are not reliable correctness signals for this purpose (see Phase 3).

This is a narrower, complementary technique to exhaustive state-space model-checking (e.g. an Alloy-based toolchain, if one is part of the project's workflow): it doesn't search a state space for a counterexample to a claimed property, it checks that a hand-authored model produces the same output as the source code on a curated set of concrete fixtures. That's a weaker guarantee in the abstract (untested inputs are unverified) but a much cheaper and more approachable one to produce and review by hand, and it's the right tool when the actual goal is "does this Elm model faithfully represent this Scala/Java function," not "does this system ever reach a bad state."

Work phases A → D in order.


Phase A — Scope: pure logic only

Before modeling anything, confirm the candidate function is actually pure — no I/O, no database access, no network calls, no mutable shared state. Morphir's IR and Elm's own language design both assume purity; effectful code doesn't benefit from being forced into this shape.

  1. Identify candidate functions: decision/rule logic, eligibility checks, value comparison, tree/policy evaluation, matching, and similar branch-heavy logic with no external dependency in the signature or body are the strongest candidates.
  2. For each candidate, confirm purity by reading the function body directly, or by using structural search (ast-grep) or symbol/call-graph tools (serena) to rule out effect types (e.g. IO/Task/Future/ZIO/DAO calls) anywhere in the call path the function actually exercises. A function only called from effectful code still qualifies if the function itself is pure — don't over-exclude based on caller context.
  3. Scope to one Morphir project per codebase area (one morphir.json, multiple exposedModules) rather than one project per function — the incremental cost of adding a module to an existing project is much lower than standing up a new one each time.

Done when: the candidate function is confirmed pure, and it's clear which existing (or new) Morphir project it belongs to.


Phase B — Author (Scala/Java → Elm)

Translate the source function into an Elm module 1:1 — same branching structure, same short-circuit order. Order matters for behavioral fidelity: if the source short-circuits a guard before evaluating a later condition, the Elm model must preserve that exact evaluation order, not just the same eventual output on totally-evaluated inputs.

Full mechanics — project shape, CLI subcommands, and every verified toolchain trap — in references/morphir-elm-cli.md. Read it before a first morphir-elm invocation; skimming it after hitting an error costs more time than reading it up front.

Key points to keep in mind while authoring:

  • morphir-elm bundles its own Elm frontend — no separate elm binary is required or expected on PATH.
  • morphir.json's exposedModules entries are relative to the project's name field, not fully-qualified paths — see the reference for the exact shape.
  • morphir-elm gen's Scala/TypeScript/etc. output is not meant to be diffed against hand-written source for a correctness check — the compiled output routes through Morphir SDK wrappers and always diverges textually from idiomatic hand-written code, even when behaviorally identical. Don't design a verification step around comparing generated code to the original; that's what Phase C's decision table is for instead.

Done when: an Elm module exists compiling into the project's IR (morphir-elm make exits 0) for every candidate function scoped in Phase A.


Phase C — Verify (decision table)

This is the actual correctness gate — not morphir-elm make's exit code (which only confirms the Elm parses, not that it's behaviorally correct), and not gen's output (see Phase B).

Build a decision table: a set of concrete input fixtures, each hand-traced through both the Elm model and the cited source file:line, side by side. Any divergence is a finding to report explicitly — never silently adjust the Elm to match the source without flagging it, since the source could be the buggy side, not the model. Full format, fixture-selection guidance (happy path, every branch/guard, short-circuit cases, boundary/empty cases), and a worked example in references/decision-table-methodology.md. A starter template is at references/templates/decision-table-template.md, and a starter Elm module skeleton (with the project-shape and type-variable-casing reminders inline) is at references/templates/starter-module.elm.

Done when: every fixture in the table has traced outcomes recorded for both the model and the source, and every divergence is either resolved (with the resolution direction stated) or explicitly filed as an open finding — never silently dropped.


Phase D — Report

State plainly, for everything modeled in this pass:

  • Which functions were modeled, and where the Elm lives.
  • The decision table's fixture count and pass/divergence outcome for each.
  • Any divergence found, which side (model or source) is suspected wrong, and why — this is a judgment call to report, not to silently resolve. If the project has a dedicated spec-vs-code drift tool as part of its workflow, hand divergences needing that judgment off to it rather than re-deriving the call here.
  • Anything explicitly left out of scope (effectful code, functions not yet swept) so a future pass doesn't have to re-derive what's already been ruled out.

Done when: the user has a clear picture of what's modeled, what's verified clean, and what's still open — nothing silently skipped.


Running morphir-elm develop

morphir-elm develop serves a web UI for browsing a project's IR, but it's a long-running foreground process with no built-in shutdown mode — launching it detached silently orphans it, leaving it bound to its port. Use the morphir-develop executable (assumed available on PATH — not bundled with this skill) instead of invoking morphir-elm develop directly: it wraps the server with guaranteed cleanup (SIGINT/SIGTERM/normal-exit all kill the server and confirm the port is free) and warns if the project's morphir-ir.json looks older than its .elm sources. Run morphir-develop --help for usage; its one known limitation is that kill -9 on the wrapper itself can't run its cleanup trap, requiring a manual lsof -i :<port> -sTCP:LISTEN + kill to recover.


Anti-patterns

  • Modeling effectful code (I/O, DB, network) in Morphir/Elm — Morphir's guarantees are about pure functions only.
  • Treating morphir-elm make's exit code as a correctness signal — it only confirms the Elm parses into IR, not that the IR is behaviorally correct.
  • Diffing morphir-elm gen's generated output against hand-written source code as a correctness check — the output always diverges textually even when correct.
  • Silently "fixing" the Elm model to match the source on a decision-table divergence without flagging it as a finding — the source may be the buggy side.
  • Losing short-circuit/evaluation order during translation because the eventual output happened to match on the fixtures tried so far.
  • Standing up a new Morphir project per function instead of adding modules to an existing project for the same codebase area.
  • Launching morphir-elm develop detached without the cleanup wrapper, orphaning it on the port.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.