Tidigar Markdown specification

Try it in the Markdown import tool: edit the example and create an interactive roadmap in your browser.

Status: public pre-release specification, version 1. It defines a Markdown form of a complete Tidigar roadmap that people can read, write and review, and that converts to the JSON project and back without losing anything.

License: published by Hamacher Software AB under CC BY 4.0. Anyone may implement the formats it describes, in any software, without asking.

The keywords MUST, MUST NOT, SHOULD and MAY are normative. The roadmap model, its field rules and limits are defined in the Tidigar Roadmap Interoperability Specification; this document only defines the Markdown form. A document is valid when the project it describes is valid.

Why Markdown

Example

The roadmap below has two dimensions, three activities with dependencies, a milestone, a period, two saved views and an activity description.

---
format: tidigar-markdown
version: 1
projectId: website-relaunch
year: 2027
schedule: calendar-days
---

# Website relaunch

```text
A small plan from content audit to launch.
```

## Dimensions

| Dimension ID | Dimension | Value ID    | Value       | Color   |
| ------------ | --------- | ----------- | ----------- | ------- |
| team         | Team      | design      | Design      | #3575e5 |
|              |           | development | Development | #16a34a |
| status       | Status    | planned     | Planned     | #94a3b8 |
|              |           | done        | Done        | #22c55e |

## Activities

| ID     | Activity       | Start      | End        | Progress | Team        | Status  | After  |
| ------ | -------------- | ---------- | ---------- | -------- | ----------- | ------- | ------ |
| audit  | Content audit  | 2027-01-04 | 2027-01-15 | 100      | Design      | Done    |        |
| visual | New design     | 2027-01-18 | 2027-02-12 | 50       | Design      | Planned | audit  |
| build  | Build and test | 2027-02-15 | 2027-03-26 | 0        | Development | -       | visual |

## Milestones

| ID     | Milestone | Date       | After |
| ------ | --------- | ---------- | ----- |
| launch | Launch    | 2027-03-29 | build |

## Periods

| ID     | Period | Start      | End        | Color   | Vacation |
| ------ | ------ | ---------- | ---------- | ------- | -------- |
| easter | Easter | 2027-03-25 | 2027-03-29 | #f5c38b | yes      |

## Views

### board

| Field | Value         |
| ----- | ------------- |
| name  | Board by team |
| col   | Status        |
| row   | Team          |

### plan

| Field                    | Value        |
| ------------------------ | ------------ |
| name                     | Plan by team |
| view                     | timeline     |
| group                    | Team         |
| color                    | Team         |
| timelineDependencyArrows | every        |
| timelineStart            | 2027-01-01   |
| timelineEnd              | 2027-04-30   |

## Descriptions

### visual

```text
Two concepts, one review with the client.
```

It describes this project:

{
  "manifest": {
    "projectId": "2c97e3f7-49a9-5e59-b42f-abb427f7048f",
    "formatVersion": 1,
    "name": "Website relaunch",
    "description": "A small plan from content audit to launch.",
    "dimensions": [
      {
        "id": "c1335d68-c807-57b2-ab1d-f6049c04da2e",
        "name": "Team",
        "options": [
          {
            "id": "30e42f43-d994-5baf-8dd1-926427a4aa43",
            "name": "Design",
            "color": "#3575e5"
          },
          {
            "id": "a7b044b4-6b44-584f-b7f6-e83a977840af",
            "name": "Development",
            "color": "#16a34a"
          }
        ]
      },
      {
        "id": "fc015fe9-21a9-5e13-99c9-47b57b41e473",
        "name": "Status",
        "options": [
          {
            "id": "7e95cfbc-93f3-5db8-a04e-e004103e08a5",
            "name": "Planned",
            "color": "#94a3b8"
          },
          {
            "id": "48757e42-b696-520f-bae6-77a57b7838c4",
            "name": "Done",
            "color": "#22c55e"
          }
        ]
      }
    ],
    "year": 2027,
    "schedule": "calendar-days"
  },
  "items": [
    {
      "id": "9e13d792-910c-52ed-b1e2-83452b9ba6c8",
      "projectId": "2c97e3f7-49a9-5e59-b42f-abb427f7048f",
      "title": "Content audit",
      "description": "",
      "progress": 100,
      "start": "2027-01-04",
      "end": "2027-01-15",
      "values": {
        "c1335d68-c807-57b2-ab1d-f6049c04da2e": "30e42f43-d994-5baf-8dd1-926427a4aa43",
        "fc015fe9-21a9-5e13-99c9-47b57b41e473": "48757e42-b696-520f-bae6-77a57b7838c4"
      },
      "dependsOn": []
    },
    {
      "id": "01d963a6-4d45-51bb-87f5-8f7014560b23",
      "projectId": "2c97e3f7-49a9-5e59-b42f-abb427f7048f",
      "title": "New design",
      "description": "Two concepts, one review with the client.",
      "progress": 50,
      "start": "2027-01-18",
      "end": "2027-02-12",
      "values": {
        "c1335d68-c807-57b2-ab1d-f6049c04da2e": "30e42f43-d994-5baf-8dd1-926427a4aa43",
        "fc015fe9-21a9-5e13-99c9-47b57b41e473": "7e95cfbc-93f3-5db8-a04e-e004103e08a5"
      },
      "dependsOn": ["9e13d792-910c-52ed-b1e2-83452b9ba6c8"]
    },
    {
      "id": "877d07dd-4ac6-53d7-a4fa-351b630cf19d",
      "projectId": "2c97e3f7-49a9-5e59-b42f-abb427f7048f",
      "title": "Build and test",
      "description": "",
      "progress": 0,
      "start": "2027-02-15",
      "end": "2027-03-26",
      "values": {
        "c1335d68-c807-57b2-ab1d-f6049c04da2e": "a7b044b4-6b44-584f-b7f6-e83a977840af",
        "fc015fe9-21a9-5e13-99c9-47b57b41e473": ""
      },
      "dependsOn": ["01d963a6-4d45-51bb-87f5-8f7014560b23"]
    }
  ],
  "sharedViews": [
    {
      "id": "9b5cc976-30a0-5573-a829-2a1619bcb91b",
      "projectId": "2c97e3f7-49a9-5e59-b42f-abb427f7048f",
      "name": "Board by team",
      "view": "grid",
      "row": "c1335d68-c807-57b2-ab1d-f6049c04da2e",
      "col": "fc015fe9-21a9-5e13-99c9-47b57b41e473",
      "color": "",
      "colorOverrides": {},
      "group": "",
      "resolution": "month",
      "timelineScaleRows": 3,
      "timelineShowWeeks": true,
      "timelineShowQuarters": true,
      "timelineShowToday": false,
      "timelineShowPeriodNames": false,
      "textMode": "beside",
      "filters": {},
      "query": "",
      "hideEmptyRows": true,
      "hideEmptyColumns": true,
      "hideEmptyTimelineGroups": true,
      "timelineActivityRows": "single",
      "hideTimelineLabels": true,
      "timelineMilestoneMode": "label",
      "timelineWeekDays": "work",
      "timelineDependencyArrows": "grouped",
      "flowDirection": "auto",
      "timelineStart": "2027-01-01",
      "timelineEnd": "2027-12-31",
      "listColumns": [
        "title",
        "start",
        "end",
        "c1335d68-c807-57b2-ab1d-f6049c04da2e",
        "fc015fe9-21a9-5e13-99c9-47b57b41e473"
      ],
      "listColumnOrder": [
        "title",
        "start",
        "end",
        "c1335d68-c807-57b2-ab1d-f6049c04da2e",
        "fc015fe9-21a9-5e13-99c9-47b57b41e473"
      ]
    },
    {
      "id": "a49042f2-ea81-57c9-9b7d-6ea1abeb2a39",
      "projectId": "2c97e3f7-49a9-5e59-b42f-abb427f7048f",
      "name": "Plan by team",
      "view": "timeline",
      "row": "",
      "col": "",
      "color": "c1335d68-c807-57b2-ab1d-f6049c04da2e",
      "colorOverrides": {},
      "group": "c1335d68-c807-57b2-ab1d-f6049c04da2e",
      "resolution": "month",
      "timelineScaleRows": 3,
      "timelineShowWeeks": true,
      "timelineShowQuarters": true,
      "timelineShowToday": false,
      "timelineShowPeriodNames": false,
      "textMode": "beside",
      "filters": {},
      "query": "",
      "hideEmptyRows": true,
      "hideEmptyColumns": true,
      "hideEmptyTimelineGroups": true,
      "timelineActivityRows": "single",
      "hideTimelineLabels": true,
      "timelineMilestoneMode": "label",
      "timelineWeekDays": "work",
      "timelineDependencyArrows": "every",
      "flowDirection": "auto",
      "timelineStart": "2027-01-01",
      "timelineEnd": "2027-04-30",
      "listColumns": [
        "title",
        "start",
        "end",
        "c1335d68-c807-57b2-ab1d-f6049c04da2e",
        "fc015fe9-21a9-5e13-99c9-47b57b41e473"
      ],
      "listColumnOrder": [
        "title",
        "start",
        "end",
        "c1335d68-c807-57b2-ab1d-f6049c04da2e",
        "fc015fe9-21a9-5e13-99c9-47b57b41e473"
      ]
    }
  ],
  "milestones": [
    {
      "id": "16eecb5f-205d-5e32-83c4-04410e23eefa",
      "projectId": "2c97e3f7-49a9-5e59-b42f-abb427f7048f",
      "title": "Launch",
      "date": "2027-03-29",
      "dependsOn": ["877d07dd-4ac6-53d7-a4fa-351b630cf19d"]
    }
  ],
  "periodIndicators": [
    {
      "id": "49c26a40-ddf7-5d35-80fb-f66a18f338f8",
      "projectId": "2c97e3f7-49a9-5e59-b42f-abb427f7048f",
      "title": "Easter",
      "start": "2027-03-25",
      "end": "2027-03-29",
      "color": "#f5c38b",
      "vacation": true
    }
  ]
}

Document structure

A document is UTF-8 text with lines separated by LF; a CR before an LF is ignored outside text blocks. In this order it holds:

  1. The front matter.
  2. The name as a level-one heading, # Name.
  3. Optionally the project description as a text block.
  4. Sections, each a level-two heading followed by its content: ## Dimensions, ## Activities, ## Milestones, ## Periods, ## Views and ## Descriptions. A writer emits them in this order and leaves out empty ones; a reader accepts any order. A missing section is an empty collection. A section MUST NOT appear twice.

Blank lines and single-line HTML comments (<!-- … -->) may appear between these parts. Any other content is an error, so a mistake is not silently dropped.

Front matter

The document starts with a line ---, then one key: value per line, then ---.

KeyRequiredValue
formatyestidigar-markdown
versionyes1. Readers MUST reject other versions.
projectIdyesThe project ID, or a key (see IDs and keys)
yearyesThe project year, four digits
shareLinkCreatedAtnoUTC ISO 8601 YYYY-MM-DDTHH:mm:ssZ; omitted when unknown
schedulenocalendar-days or work-days; calendar-days when left out
refPrefixnoThe prefix of reference keys, such as LPP; none when left out

The model format version is 1, implied by Markdown version 1. Every record of the document belongs to the project, so no record repeats the project ID.

Text

Names, titles and other short text are written in table cells and headings with these escapes, so any text survives:

Any other backslash sequence is an error. A reader trims spaces and tabs at both ends of every cell and list entry, so a writer escapes spaces there with \s and tabs with \t.

A text block holds a description exactly as it is, over any number of lines. It is a fenced code block with the info string text: a fence of at least three backticks, longer than any run of backticks in the text, then the text, then the same fence on its own line. Both fence lines may end with CRLF; the carriage return on a fence line is ignored. Carriage returns inside the text are preserved.

IDs and keys

Every record has an ID column or heading. It holds either a UUID, used as it is, or a key of 1 to 64 letters, digits, _ and -, starting with a letter or digit. A key becomes a name-based version 5 UUID (RFC 9562):

So the same document always gives the same IDs. In the example, the project key website-relaunch becomes 2c97e3f7-49a9-5e59-b42f-abb427f7048f and the activity key audit becomes 9e13d792-910c-52ed-b1e2-83452b9ba6c8. IDs, keys included, MUST be unique across the whole document. A writer emits UUIDs.

References

Cells that point at a dimension or a value hold a reference: the record's ID or key, or its name. A reader first matches IDs and keys, then names; a name MUST belong to exactly one record among the candidates.

A writer uses the name only when nothing else could be meant: it is not empty, is unique, has no spaces at either end, contains none of \ | , = . or control characters, is not a UUID, and is not, in any letter case, -, title, duration, start, end, dependsOn or a fixed column of the Activities table. Otherwise it writes the ID.

In cells that hold a value, an empty cell and - differ: an empty cell leaves the field out, while - sets it to no value ("" in JSON).

Dimensions

One table, with one row per value. A row with a Dimension ID starts a dimension; the rows after it with an empty Dimension ID and Dimension add values to it. A dimension without values is a row with only Dimension ID and Dimension.

ColumnHolds
Dimension IDThe dimension's ID or key
DimensionIts name, as text; may be empty
Value IDThe value's ID or key
ValueThe value's name, as text; may be empty
ColorThe value's color, #rrggbb

Activities

One row per activity, in order.

ColumnRequiredHolds
IDyesThe activity's ID or key
RefnoThe activity's reference key, as text; none when empty or left out
ActivityyesThe title, as text
StartyesThe first day, YYYY-MM-DD
EndyesThe last day
Progressno0, 25, 50, 75 or 100; 0 when empty or left out
AfternoThe activities and fixed milestones it depends on: IDs or keys, separated by commas; an activity may be followed by a share such as (50%)

Every other column is a dimension: its heading is a reference to the dimension, and its cells are references to values of that dimension, - or empty. A writer emits a column for every dimension, between Progress and After, and emits Ref after ID only when an activity has a reference key; the Milestones table does the same. Dependencies may name any activity of the table and any fixed milestone of the Milestones table.

A dependency on an activity may be followed by (0%), (25%), (50%) or (75%): how much of that activity’s planned duration has passed when this one may start, as in a (50%). Without a share, or with (100%), this activity starts after the other one ends. This is independent of reported Progress. Scheduling counts the chosen share of inclusive days (work days in a work-day roadmap), rounded up; 0% permits the same start. The latest threshold applies to multiple dependencies. Stored dates must not precede the predecessor’s start for a partial share. Fixed milestones cannot have a partial share.

Milestones

ColumnRequiredHolds
IDyesThe milestone's ID or key
RefnoThe milestone's reference key, as text; none when empty or left out
MilestoneyesThe title, as text
DateyesThe day, YYYY-MM-DD
AfternoThe activities it depends on, separated by commas
Fixednoyes or no; no when empty or left out
SourcenoAnother plan's milestone as plan ID/milestone ID; none when empty or left out

A fixed milestone is an event on a set date that activities wait for; its After is empty. A milestone with a Source is an incoming milestone: a copy of the named plan's milestone, and always fixed. A writer emits Source last, and only when a milestone has one.

Periods

ColumnRequiredHolds
IDyesThe period's ID or key
PeriodyesThe title, as text
StartyesThe first day
EndyesThe last day
Coloryes#rrggbb
Vacationnoyes or no; yes when empty or left out

Views

Each saved view is a level-three heading with its ID or key, followed by a table with the columns Field and Value, one row per field. name is required; every other field takes the model's default when left out, and a writer leaves out fields that equal their default.

FieldValue
name, queryText
row, col, groupA dimension reference, assignee for the assignee axis, or - for none
color, flowGroup, timelineSummarizeByA dimension reference, or - for none
view, resolution, textMode, timelineActivityRows, timelineMilestoneMode, timelineWeekDays, timelineDependencyArrows, flowDirection, flowArrows, flowShapesThe value as in JSON
presentationStylestandard, minimal, airy, contrast or terminal
timelineScaleRows1, 2 or 3
timelineShowWeeks, timelineShowQuarters, timelineWeekNumbers, timelineShowToday, timelineShowPeriodNames, hideEmptyRows, hideEmptyColumns, hideEmptyTimelineGroups, hideUnconnectedActivities, flowGroupMilestones, hideEmptyFlowGroups, flowHideDates, showAssignee, showRefs, timelineMilestonesBesideWorkyes or no
timelineStart, timelineEndYYYY-MM-DD
filtersdimension=value entries separated by commas; the value may be -
colorOverridesdimension.value=#rrggbb entries separated by commas
listColumns, listColumnOrdertitle, duration, start, end, dependsOn and dimension references, separated by commas; - for none

The derived field hideTimelineLabels is not written. Views never record which timeline summaries are collapsed; a reader skips a timelineCollapsedSummaries row that an older document may still hold. A dimension whose name is assignee is referenced by its ID. The assignee axis and showAssignee are meaningful only in a plan stored in Tidigar Business; the document never holds assignments or people.

Descriptions

Each activity with a description is a level-three heading with the activity's ID or key, followed by a text block holding the description. An activity without one is left out.

Writing

A writer SHOULD produce exactly what this specification describes, in the order shown, so that its output converts back to the same text: tables padded to their widest cell, UUIDs as IDs, names as references where allowed, default view fields left out, and a final line feed. Alignment and spacing have no meaning to a reader.

Tools that reformat Markdown can change text. A document converted to JSON and back, rather than reformatted, keeps every character.