Dmnmd
Decision Model & Notation in Markdown table format
Install / Use
/learn @smucclaw/DmnmdREADME
dmnmd: A Command-Line Interface to DMN Decision Tables In Plain Text
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
node-connect
345.4kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
104.6kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
345.4kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
345.4kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
