mime-todo-spec/dist/markdown
Tiara Rodney e6901e4f6e
new
2026-02-10 20:57:47 +01:00
..
AGENTS.md new 2026-02-10 20:57:47 +01:00
LICENSE new 2026-02-10 20:27:04 +01:00
README.md new 2026-02-10 20:27:04 +01:00

Introduction

This document defines the canonical format, semantics, and processing rules for the repository-root TODO file. The file is a human-friendly, append-only (allowing modifications) issue tracker that is parsed by TypeScript tooling using a MIME envelope added at parse time.

The raw TODO file is not a MIME document. A preprocessor wraps it into a valid multipart/mixed MIME message before parsing.

Raw File Structure

The raw TODO file consists of a sequence of parts, each beginning with:

--ISSUE
Content-Type: <mime-type>

Valid part types are:

  • application/sprints — defines sprint metadata
  • application/issue — defines a single issue

Parts may appear in any order in the raw file. The preprocessor will reorder them so that the application/sprints part appears first.

MIME Envelope (Added by Preprocessor)

Before parsing, the preprocessor wraps the raw file into a MIME multipart message.

Prolog added by the preprocessor:

MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="ISSUE"

Each raw --ISSUE boundary becomes a MIME boundary. The preprocessor extracts each parts Content-Type and body, reorders parts, and emits a final closing boundary:

--ISSUE--

The resulting MIME message is parsed using a standard MIME parser.

Part: application/sprints

This part defines sprint metadata.

The body MUST begin with:

Sprints:

followed by one or more sprint entries.

Sprint Entry Forms

Both compact and expanded forms are valid.

Compact form:

- Name: Sprint 1
  Range: 2026-02-01..2026-02-14

Expanded form:

-
  Name: Sprint 1
  Range: 2026-02-01..2026-02-14

Sprint Entry Grammar

A sprint entry begins at a line matching:

^\s*-\s*(Name:.*)?$

Keyvalue lines inside an entry match:

^\s+[A-Za-z][A-Za-z0-9]*:\s*(.*)$

Required keys:

  • Name: <string>
  • Range: <YYYY-MM-DD>..<YYYY-MM-DD>

The Range defines a closed interval [start, end].

Part: application/issue

Each issue is represented as a structured block with strict field ordering.

Required Field Order

The following fields MUST appear in exactly this order:

ID: <integer>
Type: <feature|bugfix|hotfix>
Title: <short title>
Status: <open|in-progress|done|hold|cancelled>
Priority: <low|medium|high>
Created: <YYYY-MM-DD>
Relationships: <comma-separated list or empty>
DueStart: <YYYY-MM-DD>        # OPTIONAL
DueEnd: <YYYY-MM-DD>          # OPTIONAL
Description: <first line>
             <continuation lines>

Field Semantics

  • ID: unique integer, strictly increasing.

  • Type: one of feature, bugfix, hotfix. * feature and bugfix issues target the integration branch (develop). * hotfix issues target the stable branch (main or master).

  • Status: one of open, in-progress, done, hold, cancelled.

  • Priority: one of low, medium, high.

  • Created: ISO date.

  • Relationships: * Empty:

    Relationships:
    
    • Or list:
      Relationships: dependsOn:43, relatesTo:10
      
    • Valid kinds: dependsOn, relatesTo, blocks, causedBy.
  • DueStart / DueEnd: * Optional. * If only one is present, the other is implicitly equal to it.

Description Block

  • The first line appears on the same line as Description:.
  • Continuation lines: * Must begin with whitespace. * Must align indentation consistently.
  • No blank lines allowed inside the description block.

Body

Any lines after the description block are considered free-form body text. The body MUST NOT contain another ID: field or a MIME boundary.

Git Workflow Rules

Branch Naming

Branches for issues MUST follow:

<Type>/<ID>

Examples:

feature/12
bugfix/7

Modification Rules

  • All edits to TODO MUST occur on develop.
  • Feature/bugfix/hotfix branches MUST rebase changes from develop.

Branch Lifecycle

  • A branch MUST NOT exist before its issue is created.
  • A branch MUST be named exactly <Type>/<ID>.
  • A branch MAY merge only when the issue status is done.

Sprint Membership Logic

Given:

  • Sprint interval [S_start, S_end]
  • Issue interval [I_start, I_end]

Normalization

  • Only DueEndI_start = I_end = DueEnd
  • Only DueStartI_start = I_end = DueStart
  • Neither → issue is not sprint-bound

Membership Condition

An issue belongs to a sprint if:

I_start ≤ S_end AND I_end ≥ S_start

Current Sprint for Date D

  1. All sprints where S_start ≤ D ≤ S_end.
  2. If multiple match, choose the one with the latest S_start.
  3. If none match, no active sprint.

Preprocessor Requirements

The preprocessor MUST:

  • Read the raw TODO file.

  • Split into parts using --ISSUE.

  • Extract each parts Content-Type and body.

  • Reorder parts so that: * application/sprints appears first (if present) * All application/issue parts follow in original order

  • Emit a MIME message with: * MIME-Version: 1.0 * Content-Type: multipart/mixed; boundary="ISSUE" * Each part wrapped as:

    --ISSUE
    Content-Type: <type>
    
    <body>
    
    • Final boundary:
      --ISSUE--
      

Parser Requirements

The parser MUST:

  • Use a MIME parser to extract parts.
  • Dispatch based on Content-Type: * application/sprints → sprint parser * application/issue → issue parser
  • Enforce: * Field order * Required fields * Description indentation rules * Sprint entry grammar
  • Produce a TodoFile object:
    {
      sprints: Sprint[],
      issues: Issue[]
    }
    

Error Handling

The parser MUST reject:

  • Missing or malformed Content-Type headers
  • Unknown MIME types
  • Missing required issue fields
  • Incorrect field order
  • Invalid sprint ranges
  • Invalid date formats
  • Multiple application/sprints parts
  • Duplicate issue IDs

Errors SHOULD include line numbers when possible.

Extensibility

Future part types MAY be added using:

application/<subtype>

Examples:

  • application/metadata
  • application/changelog
  • application/epilog

The preprocessor MUST preserve unknown part types but MUST NOT reorder them.