SkillAgentSearch skills...

Dmnmd

Decision Model & Notation in Markdown table format

Install / Use

/learn @smucclaw/Dmnmd
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

dmnmd: A Command-Line Interface to DMN Decision Tables In Plain Text

Haskell

Show me your flowchart and conceal your tables, and I shall continue to be mystified. Show me your tables, and I won't usually need your flowchart; it'll be obvious." -- Fred Brooks, The Mythical Man Month (1975)

Inspiration

Watch this real quick: https://youtu.be/Pe34U9QuhXA ... Wouldn't it be nice to be able to do this in your text editor?

DMNMD embeds DMN in plain text source code or Markdown

The semantics are DMN.

The syntax is Markdown.

The input is plain-text.

The output is JS. (And, in future, XML, Python, English, LegalRuleML...)

The interface is CLI. No mouse needed!

Installing from Source

At the moment, dmnmd is an executable program written in Haskell. In future it may switch to Python.

OS X:

brew install haskell-stack pkg-config pcre; stack upgrade

Linux:

{ yum, apt-get, ... } install haskell-stack pkg-config libpcre3-dev; stack upgrade

Both:

git clone git@github.com:smucclaw/dmnmd.git
cd dmnmd/languages/haskell
stack test
stack build
stack install

In future packaged binaries will be made available.

Examples

This README contains decision tables formatted in plain text, in Markdown table syntax.

The DMN CLI (dmnmd) interpreter parses, evaluates, and translates them into alternative formats.

Example 1: What's for dinner?

This example is taken from Camunda's DMN Tutorial.

| U | Season | Dish | # Annotation | |---|--------|------------------------------|---------------| | 1 | Fall | Spareribs | | | 2 | Winter | Roastbeef | | | 3 | Spring | Steak | | | 4 | Summer | Light Salad and a nice Steak | Hey, why not? |

A plain text version formatted for Markdown looks literally like this:

| U | Season | Dish                         | # Annotation  |
|---|--------|------------------------------|---------------|
| 1 | Fall   | Spareribs                    |               |
| 2 | Winter | Roastbeef                    |               |
| 3 | Spring | Steak                        |               |
| 4 | Summer | Light Salad and a nice Steak | Hey, why not? |

Example 2: How many guests are coming?

| U | Season | Guest Count | Dish (out) | # Annotation | |---|----------------------|-------------|------------------------------|---------------| | 1 | Fall | <= 8 | Spareribs | | | 2 | Winter | <= 8 | Roastbeef | | | 3 | Spring | <= 4 | Dry Aged Gourmet Steak | | | 4 | Spring | [5..8] | Steak | | | 5 | Fall, Winter, Spring | > 8 | Stew | | | 6 | Summer | - | Light Salad and a nice Steak | Hey, why not? |

| U | Season               | Guest Count | Dish (out)                   | # Annotation  |
|---|----------------------|-------------|------------------------------|---------------|
| 1 | Fall                 | <= 8        | Spareribs                    |               |
| 2 | Winter               | <= 8        | Roastbeef                    |               |
| 3 | Spring               | <= 4        | Dry Aged Gourmet Steak       |               |
| 4 | Spring               | [5..8]      | Steak                        |               |
| 5 | Fall, Winter, Spring | > 8         | Stew                         |               |
| 6 | Summer               | -           | Light Salad and a nice Steak | Hey, why not? |

Yeah, DMN allows spaces in variable names. What could possibly go wrong?

But if you think of them as properties in a dictionary, that's not so bad.

XML source

The canonical DMN XML representation of this example is available at https://github.com/camunda/camunda-bpm-examples/blob/master/dmn-engine/dmn-engine-java-main-method/src/main/resources/org/camunda/bpm/example/dish-decision.dmn11.xml

Background

Decision Model & Notation is an XML-based standard from OMG. One accessible tutorial is available here.

To help author DMN, a number of vendors provide graphical user interfaces as part of their conforming implementations. It is also possible to import decision tables authored in a spreadsheet.

What are decision tables? An ancient magic from an earlier age of computing, powerful but little known among developers today. See Hillel Wayne's introduction. It may be making a comeback, though: a handful of packages have appeared on npm in the last few years.

The Unix philosophy emphasizes the value of flat text files. While XML technically qualifies as text, many consider it "unwieldy": hence the popularity of JSON and YAML.

Command-line utilities such as json (on NPM) help manipulate JSON. dmnmd is intended to be the moral equivalent for manipulating DMN in Markdown.

Imports

from Markdown

Supported. This is the native format for dmnmd.

ASCII has its limitations. In graphical decision tables, output columns are separated from input columns by a double bar; most GUI implementations use colour and other formatting to distinguish input, output, and annotation columns. In dmnmd syntax, output columns are optionally labeled with an (out); annotation columns are prefixed with a #. By default, if the columns are unlabeled, the rightmost column will be taken to be the output, and columns to the left will be taken to be inputs. (Leaving out annotation columns.)

You can also prefix output columns with a > character.

Columns are optionally typed using a colon. You will see Column Name : String, Column Name : Number, and Column Name : Boolean. If you omit the type definition, dmnmd will attempt to infer the type.

In some decision tables, the input and outputs are enumerated in a sort of sub-header row. The order matters.

This implementation only supports vertical layout. Horizontal and crosstab layouts may appear in a future version if there is demand.

The above is perhaps best explained by an example; see figure 8.19 of the DMN 1.3 spec.

Example 3: Routing Rules

For hit policy "O", the order of results in the output is determined by the order of the column enums.

The column enums are giving in a subhead row between the top row and body data row "1".

| O | Age | Risk Category | Debt Review :Boolean | > Routing | > Review level | Reason (out) | |---|-----|-------------------|----------------------|------------------------|------------------------|-----------------------------| | | | LOW, MEDIUM, HIGH | | DECLINE, REFER, ACCEPT | LEVEL 2, LEVEL 1, NONE | | | 1 | - | - | - | ACCEPT | NONE | Acceptable | | 2 | <18 | | | DECLINE | NONE | Applicant too young | | 3 | | HIGH | | REFER | LEVEL 1 | High risk application | | 4 | | | True | REFER | LEVEL 2 | Applicant under debt review |

This example comes from the DMM 1.3 specification, page 96.

Note that advanced hit policies are not yet implemented for code generation, only for evaluation.

In the IDE

JetBrains MPS is a language workbench and an IDE from the future. Look how decision tables live right in the IDE: https://www.youtube.com/watch?v=Pe34U9QuhXA

from XML

On the roadmap.

$ dmnmd --from=example1.dmn --to=example1.md

Exports

Interactive evaluation is intended for quick testing in development. For real-world use, you probably want code generation to an operational language like Python or Javascript. Or extraction to SQL or JSON (suitable for NoSQL) or to XML (as OMG intended). Or to natural language!

to Typescript

$ dmnmd README.md --to=ts

By default, generates Typescript.

You can output Javascript instead by saying --to=js

Options:

--props Normally, functions expect as many parameters as there are input columns. with --props, functions expect input in a single props object; a "Props" type is generated.

% stack exec -- dmnmd README.md --to=ts --pick="Example 2" -r
type Props_Example_2 = {
    "Season" : string;
    "Guest Count" : number;
}
type Return_Example_2 = {
    "Dish" : string;
}
export function Example_2 ( props : Props_Example_2 ) : Return_Example_2 {
  if (props["Season"]==="Fall" && props["Guest Count"] <=8.0) { // 1
    return {"Dish":"Spareribs"};
  }
  else if (props["Season"]==="Winter" && props["Guest Count"] <=8.0) { // 2
    return {"Dish":"Roastbeef"};
  }
  else if (props["Season"]==="Spring" && props["Guest Count"] <=4.0) { // 3
    return {"Dish":"Dry Aged Gourmet Steak"};
  }
  else if (props["Season"]==="Spring" && (5.0<=props["Guest Count"] && props["Guest Count"]<=8.0)) { // 4
    return {"Dish":"Steak"};
  }
  else if ((props["Season"]==="Fall" || props["Season"]==="Winter" || props[

Related Skills

View on GitHub
GitHub Stars24
CategoryDevelopment
Updated7mo ago
Forks5

Languages

Grammatical Framework

Security Score

67/100

Audited on Aug 17, 2025

No findings