Documentation

Complete reference for Mad Sam Notation — from first install to advanced usage. Everything you need to master MSN, its CLI, parser API, and ecosystem.

Getting Started

What is MSN?

Mad Sam Notation (MSN) is a token-efficient hierarchical data language that compiles directly to JSON. It was designed to minimize token usage in AI/LLM workflows while remaining human-readable and writable.

Key characteristics:

- Uses dash prefixes to represent hierarchy depth — no brackets, braces, or commas

- Up to 60% fewer tokens than equivalent JSON

- Automatic type inference for numbers, booleans, null, and strings

- Full JSON compatibility — every MSN file compiles to valid JSON

- Unlimited nesting depth — just keep adding dashes

- Comments are first-class citizens

- MIT licensed and fully open source

MSN files use the .msn extension and the MIME type application/x-msn. All files MUST be encoded in UTF-8.

Installation

CLI Tool — for compiling, validating, and formatting MSN files from the terminal:

bash
npm install -g @madsn/cli

Parser Library — for integrating MSN into your Node.js / TypeScript projects:

bash
npm install @madsn/parser

Validator — standalone validation of MSN syntax:

bash
npm install @madsn/validator

Formatter — auto-format MSN source files:

bash
npm install @madsn/formatter

VS Code Extension — search for "MSN" in the VS Code extensions marketplace, or install msn-vscode for syntax highlighting and language support.

Quick Start

1. Create a file called config.msn:

msn
- name: My Application
- version: 1.0.0
- server
-- host: localhost
-- port: 3000

2. Compile with the CLI:

bash
msn compile config.msn

Output:

json
{
  "name": "My Application",
  "version": "1.0.0",
  "server": {
    "host": "localhost",
    "port": 3000
  }
}

3. Or use the library in code:

typescript
import { compile } from "@madsn/parser";
import { readFileSync } from "fs";

const source = readFileSync("config.msn", "utf-8");
const result = compile(source);
console.log(result);
// { name: "My Application", version: "1.0.0", server: { host: "localhost", port: 3000 } }

4. Save to a file:

bash
msn compile config.msn --output config.json
Language Syntax

Line Structure

Every MSN line follows one of these patterns:

PatternMeaning
- key: valueKey-value pair
- keyContainer (creates nested object)
-- * valueArray item (simple value)
-- *Array object marker (children become object properties)
# commentComment (ignored during compilation)
*(blank line)*Ignored

Rules:

- Every data line MUST start with one or more dashes -

- There MUST be a space after the dash prefix

- Lines not starting with - or # (excluding blank lines) are invalid

Depth & Nesting

The number of dashes determines the depth level. Each additional dash increases the nesting depth by one.

msn
- root                 # depth 1 (1 dash)
-- child               # depth 2 (2 dashes)
--- grandchild: value  # depth 3 (3 dashes)
---- deep: value       # depth 4 (4 dashes)

Compiles to:

json
{
  "root": {
    "child": {
      "grandchild": "value",
      "deep": "value"
    }
  }
}

Depth Rules:

1. Depth can increase by at most 1 per line (you can't jump from 1 dash to 3 dashes)

2. Depth can decrease by any amount (closing multiple levels at once)

3. A line with N dashes is a child of the nearest preceding line with N-1 dashes

4. There is no limit to nesting depth — just keep adding dashes

Example — decreasing depth:

msn
- server
-- ssl
--- enabled: true
--- cert: /path/to/cert.pem
-- host: localhost
- database
-- host: db.example.com

Notice how -- host: localhost drops back to depth 2, closing the ssl object. Then - database drops to depth 1, closing server.

Key-Value Pairs

A key-value pair is written as dashes, a space, the key, a colon, a space, and the value:

msn
- name: John
- age: 30
- active: true
- score: 95.5
- data: null

Compiles to:

json
{
  "name": "John",
  "age": 30,
  "active": true,
  "score": 95.5,
  "data": null
}

Rules:

1. The colon : separates the key from the value

2. There MUST be a space after the colon

3. Keys MUST NOT contain colons (unless the value part is used correctly)

4. Keys are case-sensitive

5. Leading/trailing whitespace in values is trimmed

Type Inference

MSN automatically infers types from values — no explicit typing needed:

MSN ValueJSON TypeJSON OutputExample
42number42- count: 42
3.14number3.14- pi: 3.14
-7number-7- offset: -7
truebooleantrue- active: true
falsebooleanfalse- debug: false
nullnullnull- data: null
hellostring"hello"- name: hello
"42"string"42"- code: "42"

Rules:

1. Unquoted integers and floats become number

2. true and false become boolean

3. null becomes null

4. Everything else becomes string

5. Values wrapped in double quotes are always treated as string (use this to force a number to be a string)

6. Leading/trailing whitespace is trimmed before inference

Containers (Objects)

A key without a value creates a container — a nested object whose properties are defined by its children:

msn
- database
-- host: localhost
-- port: 5432
-- credentials
--- username: admin
--- password: secret

Compiles to:

json
{
  "database": {
    "host": "localhost",
    "port": 5432,
    "credentials": {
      "username": "admin",
      "password": "secret"
    }
  }
}

Containers can be nested to any depth. Any line with only a key (no colon, no value) signals that the following deeper lines are its children.

Arrays

Use an asterisk * after the dash prefix to create array items:

Simple arrays — values on the same line as *:

msn
- colors
-- * red
-- * green
-- * blue

Compiles to:

json
{
  "colors": ["red", "green", "blue"]
}

Rules:

1. Array items use * after the dash prefix: -- * value

2. There MUST be a space after the *

3. All array items under a parent MUST be at the same depth

4. Array items inherit type inference (-- * 42 becomes the number 42)

5. Array items and key-value pairs SHOULD NOT be mixed under the same parent

Array Objects

A bare * with no value creates an array object entry. Children at a deeper level become the properties of that object:

msn
- users
-- *
--- name: Alice
--- age: 30
--- role: admin
-- *
--- name: Bob
--- age: 25
--- role: user

Compiles to:

json
{
  "users": [
    { "name": "Alice", "age": 30, "role": "admin" },
    { "name": "Bob", "age": 25, "role": "user" }
  ]
}

Nested array objects — arrays of objects can contain their own nested objects:

msn
- services
-- *
--- name: web
--- config
---- port: 80
---- ssl: true
-- *
--- name: api
--- config
---- port: 3000
---- ssl: false

Compiles to:

json
{
  "services": [
    { "name": "web", "config": { "port": 80, "ssl": true } },
    { "name": "api", "config": { "port": 3000, "ssl": false } }
  ]
}

Multiline Values

MSN supports two multiline modes using the pipe | and angle bracket > characters:

Literal Block (|) — preserves line breaks:

msn
- description: |
-- This is line one.
-- This is line two.
-- This is line three.

Produces: "This is line one.\nThis is line two.\nThis is line three."

Folded Block (>) — joins lines with spaces:

msn
- summary: >
-- This is a long paragraph
-- that will be joined into
-- a single line with spaces.

Produces: "This is a long paragraph that will be joined into a single line with spaces."

Rules:

1. | preserves line breaks (literal block)

2. > folds lines into a single line joined by spaces (folded block)

3. Continuation lines MUST be at depth N+1 relative to the key

4. Continuation lines are treated as text, not as key-value pairs

Comments

Lines starting with # are comments and are ignored during compilation:

msn
# Full line comment
- app
-- name: my-app    # inline comment
-- debug: false
# Another comment between entries
-- port: 3000

Rules:

1. Lines starting with # (after optional whitespace) are full-line comments

2. # after a value (preceded by a space) starts an inline comment

3. Comments are stripped during parsing and do not appear in output

4. # inside quoted strings is NOT treated as a comment

API Reference

Parser API (@madsn/parser)

The core parser package provides tokenization, parsing, AST construction, and compilation to JSON.

compile(source: string): JsonValue

Compiles MSN source text to a JSON-compatible JavaScript value (object, array, string, number, boolean, or null).

typescript
import { compile } from "@madsn/parser";

const result = compile(`
- name: My App
- version: 1.0.0
- server
-- host: localhost
-- port: 3000
`);
console.log(result);
// { name: "My App", version: "1.0.0", server: { host: "localhost", port: 3000 } }

compileToString(source: string, indent?: number): string

Compiles MSN source and returns a formatted JSON string.

typescript
import { compileToString } from "@madsn/parser";

const json = compileToString("- name: hello\n- count: 42", 2);
// '{ "name": "hello", "count": 42 }'

class Lexer

Tokenizes MSN source code into a stream of typed tokens.

typescript
import { Lexer } from "@madsn/parser";

const lexer = new Lexer("- name: hello");
const tokens = lexer.tokenize();
// [{ type: "KEY_VALUE", depth: 1, key: "name", value: "hello", ... }]

class Parser

Parses MSN source into an Abstract Syntax Tree (AST).

typescript
import { Parser } from "@madsn/parser";

const parser = new Parser();
const ast = parser.parse("- name: hello");
// { type: "root", children: [{ type: "value", key: "name", value: "hello", ... }] }

class Compiler

Converts MSN source to JSON (combines Lexer + Parser + AST evaluation).

typescript
import { Compiler } from "@madsn/parser";

const compiler = new Compiler();
const obj = compiler.compile("- name: hello");
const str = compiler.compileToString("- name: hello", 2);

inferType(value: string): string | number | boolean | null

Infers the JSON type from a raw string value.

typescript
import { inferType } from "@madsn/parser";

inferType("42");      // 42 (number)
inferType("true");    // true (boolean)
inferType("null");    // null
inferType("hello");   // "hello" (string)
inferType('"42"');    // "42" (forced string)

Validator API (@madsn/validator)

The validator checks MSN syntax and returns an array of errors and warnings.

validate(source: string): ValidationError[]

Validates MSN syntax and returns errors.

typescript
import { validate } from "@madsn/validator";

const errors = validate("- name: hello");
// [] (no errors)

const bad = validate("name: hello");
// [{ message: "Line must start with dashes", line: 1, severity: "error" }]

validateIndentation(source: string): ValidationError[]

Checks for indentation-related issues (warnings about inconsistent spacing, depth jumps, etc.).

validateAll(source: string): ValidationError[]

Runs all validation checks — syntax errors, indentation warnings, and structural issues.

ValidationError type:

typescript
interface ValidationError {
  message: string;
  line: number;
  column?: number;
  severity: "error" | "warning";
}

Formatter API (@madsn/formatter)

The formatter normalizes MSN source code for consistent style.

format(source: string, options?: FormatOptions): string

Formats MSN source text — trims whitespace, normalizes dash spacing, ensures consistent style.

typescript
import { format } from "@madsn/formatter";

const formatted = format("  -  name:  hello  ");
// "- name: hello\n"

FormatOptions:

OptionTypeDefaultDescription
finalNewlinebooleantrueAdd a newline at the end of the file
removeBlankLinesbooleanfalseRemove blank lines between entries
typescript
import { format } from "@madsn/formatter";

const formatted = format(source, {
  finalNewline: true,
  removeBlankLines: false,
});

TypeScript Types

All packages export TypeScript types for full type safety.

Token — represents a single lexer token:

typescript
interface Token {
  type: TokenType;
  depth: number;
  key?: string;
  value?: string;
  raw: string;
  line: number;
  multilineMode?: "|" | ">";
}

ASTNode — a node in the abstract syntax tree:

typescript
interface ASTNode {
  type: "object" | "array" | "value" | "array-item" | "root";
  key?: string;
  value?: JsonValue;
  children: ASTNode[];
  line?: number;
  depth?: number;
}

JsonValue — any valid JSON value:

typescript
type JsonValue =
  | string
  | number
  | boolean
  | null
  | JsonValue[]
  | { [key: string]: JsonValue };

ValidationError — returned by the validator:

typescript
interface ValidationError {
  message: string;
  line: number;
  column?: number;
  severity: "error" | "warning";
}
CLI Reference

CLI Installation

Install the MSN CLI globally:

bash
npm install -g @madsn/cli

Verify the installation:

bash
msn --version
msn --help

CLI Commands

msn compile — Compile an MSN file to JSON

bash
msn compile config.msn
msn compile config.msn --indent 4
msn compile config.msn --output config.json

msn parse — Parse an MSN file and output the AST (useful for debugging)

bash
msn parse config.msn

msn validate — Validate an MSN file for syntax errors

bash
msn validate config.msn

msn format — Auto-format an MSN file

bash
msn format config.msn
msn format config.msn --output formatted.msn

CLI Options & Stdin

Options:

OptionDescription
-o, --output Write output to a file instead of stdout
-i, --indent JSON indentation level (default: 2)
--stdinRead MSN input from stdin instead of a file
-h, --helpShow help information
-v, --versionShow the installed version

Reading from stdin:

bash
cat config.msn | msn compile --stdin
echo "- name: test" | msn compile --stdin

Piping output:

bash
msn compile config.msn | jq '.server.port'
msn compile config.msn > output.json
Specification

JSON Mapping

MSN maps to JSON with these correspondences:

MSN ConstructJSON Equivalent
- key: value{ "key": value }
- key (with children){ "key": { ... } }
-- * value[ value, ... ]
-- * (with children)[ { ... }, ... ]
`- key: \` (multiline){ "key": "line1\nline2" }
- key: > (folded){ "key": "line1 line2" }
# comment*(omitted)*

Formal Grammar (EBNF)

The formal grammar of MSN in Extended Backus-Naur Form:

ebnf
document    = { line } ;
line        = comment | entry | blank ;
comment     = { whitespace } , "#" , { any_char } ;
entry       = dashes , " " , ( array_item | key_value | container ) , [ inline_comment ] ;
dashes      = "-" , { "-" } ;
array_item  = "* " , ( value | "" ) ;
key_value   = key , ": " , value ;
container   = key ;
key         = identifier ;
value       = string | number | boolean | null_val | multiline_marker ;
string      = quoted_string | unquoted_string ;
number      = integer | float ;
boolean     = "true" | "false" ;
null_val    = "null" ;
multiline_marker = "|" | ">" ;
inline_comment   = " #" , { any_char } ;

Error Handling

MSN parsers MUST report errors for:

1. Invalid line start — Lines not starting with - or # (excluding blank lines)

2. Depth jump — Depth increase greater than 1 between consecutive non-comment lines

3. Missing space after dashes — e.g. -name: value instead of - name: value

4. Missing space after colon — e.g. - name:value instead of - name: value

5. Mixed children — Array items and key-value pairs at the same depth under the same parent

6. Invalid multiline continuation — Continuation lines at wrong depth (must be exactly N+1)

Example error messages:

Error on line 3: Depth increased by 2 (from 1 to 3). Maximum increase is 1.
Error on line 5: Line must start with dashes (-).
Error on line 8: Missing space after colon in key-value pair.
Warning on line 12: Mixed array items and key-value pairs under the same parent.
Ecosystem

Project Structure

The MSN monorepo is organized into focused packages:

msn/
├── packages/
│   ├── parser/              Core parser (lexer, parser, compiler)
│   ├── cli/                 Command-line interface
│   ├── validator/           Syntax validation
│   ├── formatter/           Auto-formatting
│   └── vscode-extension/    VS Code language support
├── tests/                   Full test suite (Vitest)
├── docs/                    Documentation source
├── examples/                Example MSN files
├── spec/                    Language specification
├── playground/              Interactive web playground (standalone)
└── website/                 Official website (Next.js)

Packages overview:

PackagenpmPurpose
@madsn/parsernpm i @madsn/parserCore tokenizer, parser, and compiler
@madsn/clinpm i -g @madsn/cliTerminal commands: compile, parse, validate, format
@madsn/validatornpm i @madsn/validatorSyntax and structure validation
@madsn/formatternpm i @madsn/formatterAuto-format MSN source files
msn-vscodeVS Code MarketplaceSyntax highlighting, language config

VS Code Extension

The MSN VS Code extension provides:

- Syntax highlighting — full TextMate grammar for .msn files

- Language configuration — bracket matching, auto-closing, comment toggling

- File icon — recognizable icon for .msn files in the explorer

Installation:

Search for "MSN" in the VS Code extensions marketplace, or install via the command palette.

Features:

- Comments toggle with Ctrl+/

- Bracket matching for multiline blocks

- Auto-indentation for nested structures

- Recognized .msn file association

Contributing to the extension:

The extension source is in packages/vscode-extension/. The TextMate grammar is defined in syntaxes/msn.tmLanguage.json.

Contributing

How to Contribute

MSN is fully open source under the MIT License. We welcome contributions of all kinds — code, documentation, bug reports, and ideas.

Step-by-step:

1. Fork the repository at github.com/sammadijaz/msn

2. Clone your fork locally:

bash
   git clone https://github.com/YOUR_USERNAME/msn.git
   cd msn

3. Install dependencies:

bash
   npm install

4. Build all packages:

bash
   npm run build

5. Create a branch:

bash
   git checkout -b feature/your-feature-name

6. Make changes, write tests, update docs

7. Run tests:

bash
   npm test

8. Submit a pull request with a clear description

Coding standards:

- TypeScript strict mode

- No any types without justification

- Write tests for all new features

- Follow the existing code style

Contribution Areas

Core Parser — Improve the lexer, parser, and compiler. Add error recovery, source maps, streaming support. *(Intermediate)*

CLI Tool — Add new commands, improve error messages, add watch mode, support config files. *(Beginner)*

VS Code Extension — Improve syntax highlighting, add IntelliSense, auto-completion, go-to-definition. *(Intermediate)*

Documentation — Write tutorials, improve API docs, add more examples, translate docs. *(Beginner)*

Playground — Improve the web playground with better error display, shareable URLs, themes. *(Beginner)*

Language Ports — Port the parser to other languages: Python, Rust, Go, Java, C#. *(Advanced)*

Reporting issues:

Please include the MSN input, expected output, actual output, Node.js version, and OS information.