Structured Tasks provides a machine-readable JSON intermediate representation (IR) for project task lists, with deterministic Markdown generation. It is modeled after Structured Changelog.
- JSON IR - Machine-readable task list format with rich metadata
- Deterministic output - Same JSON always produces identical Markdown
- Two-dimensional categorization - Area (project component) + Type (change type)
- Multiple grouping strategies - Group by area, type, phase, status, quarter, or priority
- Phased task lists - Support for large projects with phases and area sub-sections
- Rich content support - Code blocks, tables, diagrams, lists, and blockquotes
- Type validation - Integrates with structured-changelog for type consistency
- Dependency tracking - Item dependencies with graph generation
- Validation - Schema validation with detailed error messages
- Statistics - Track progress and completion rates
brew tap grokify/tap
brew install structured-tasksThis installs the stasks CLI (also available as structured-tasks).
go install github.com/grokify/structured-tasks/cmd/stasks@latestgo get github.com/grokify/structured-tasks{
"irVersion": "1.0",
"project": "my-project",
"areas": [
{"id": "core", "name": "Core Features", "priority": 1}
],
"items": [
{
"id": "feature-1",
"title": "User Authentication",
"description": "Add OAuth2 login support",
"status": "completed",
"version": "1.0.0",
"area": "core",
"type": "Added",
"priority": "high"
},
{
"id": "feature-2",
"title": "API Rate Limiting",
"description": "Add configurable rate limits",
"status": "planned",
"targetQuarter": "Q2 2026",
"area": "core",
"type": "Added",
"priority": "medium",
"dependsOn": ["feature-1"]
}
]
}stasks generate -i TASKS.json -o TASKS.mdstasks validate TASKS.jsonstasks stats TASKS.jsonstasks deps TASKS.json --format mermaidValidate a TASKS.json file against the schema.
stasks validate TASKS.jsonGenerate TASKS.md from TASKS.json.
stasks generate -i TASKS.json -o TASKS.mdOptions:
| Flag | Default | Description |
|---|---|---|
-i, --input |
TASKS.json | Input JSON file |
-o, --output |
stdout | Output Markdown file |
--group-by |
area | Grouping: area, type, phase, status, quarter, priority |
--checkboxes |
true | Use [x]/[ ] checkbox syntax |
--emoji |
true | Include emoji status indicators |
--legend |
false | Show legend table |
--no-intro |
false | Omit introductory paragraph (intro shown by default) |
--toc |
false | Show table of contents with progress counts |
--toc-depth |
1 | TOC depth: 1 = sections only, 2 = sections + items |
--overview |
true | Show summary table with all items |
--area-subheadings |
false | Show area sub-sections within phases |
--numbered |
false | Number items |
--no-rules |
false | Omit horizontal rules between sections |
Show task list statistics.
stasks stats TASKS.jsonOutput:
Task List: my-project
Total items: 10
By Status:
✅ Completed: 4 (40%)
🚧 In Progress: 2 (20%)
📋 Planned: 3 (30%)
💡 Under Consideration: 1 (10%)
By Priority:
High Priority: 3 (30%)
Medium Priority: 5 (50%)
Low Priority: 2 (20%)
By Area:
Core Features: 6
Improvements: 4
By Type:
Added: 5
Changed: 3
Fixed: 2
Progress: 40% complete
Generate dependency graph in Mermaid or DOT format.
stasks deps TASKS.json --format mermaid| Field | Type | Required | Description |
|---|---|---|---|
irVersion |
string | Yes | Schema version ("1.0") |
project |
string | Yes | Project name |
repository |
string | No | Repository URL |
generatedAt |
datetime | No | Generation timestamp |
legend |
object | No | Custom status legend |
areas |
array | No | Project areas/components |
phases |
array | No | Development phases |
items |
array | No | Roadmap items |
sections |
array | No | Freeform content sections |
versionHistory |
array | No | Version milestones |
dependencies |
object | No | External/internal dependencies |
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | Yes | Unique identifier |
title |
string | Yes | Item title |
description |
string | No | Item description |
status |
enum | Yes | completed, inProgress, planned, future |
version |
string | No | Version where completed |
completedDate |
date | No | Completion date |
targetQuarter |
string | No | Target quarter (e.g., "Q2 2026") |
targetVersion |
string | No | Target version |
area |
string | No | Area ID (project component) |
type |
string | No | Change type (aligns with structured-changelog) |
phase |
string | No | Phase ID |
priority |
enum | No | critical, high, medium, low |
order |
int | No | Explicit sort order within groups |
dependsOn |
array | No | IDs of dependencies |
tasks |
array | No | Sub-tasks with completion status |
content |
array | No | Rich content blocks |
Items can be categorized along two orthogonal dimensions:
| Dimension | Field | Purpose | Example Values |
|---|---|---|---|
| Area | area |
WHERE in the project | "core", "api", "ui", "backend" |
| Type | type |
WHAT kind of change | "Added", "Changed", "Fixed", "Security" |
- Area is user-defined and groups items by project component
- Type aligns with structured-changelog change types and is validated against the registry
This allows grouping by area for task lists (--group-by area) while preserving type information for changelog integration when items are completed.
| Type | Fields | Description |
|---|---|---|
text |
value | Markdown text |
code |
value, language | Code block |
diagram |
value, format | ASCII or Mermaid diagram |
table |
headers, rows | Markdown table |
list |
items | Bullet list |
blockquote |
value | Blockquote/callout (renders with > prefix) |
For large projects with multiple development phases (like omnistorage), use the combination of phases and areas to create hierarchical task lists.
Phase 1: Foundation ✅
├── Core Package
│ ├── [x] interfaces.go
│ └── [x] options.go
├── Format Layer
│ └── [x] ndjson/writer.go
└── Backend Layer
└── [x] file/backend.go
Phase 2: Extended Interfaces ✅
├── Core Interfaces
│ └── [x] extended.go
└── Utilities
└── [x] copy.go
{
"irVersion": "1.0",
"project": "my-large-project",
"phases": [
{"id": "phase-1", "name": "Phase 1: Foundation", "status": "completed", "order": 1},
{"id": "phase-2", "name": "Phase 2: Extended Interfaces", "status": "completed", "order": 2},
{"id": "phase-3", "name": "Phase 3: Cloud Storage", "status": "inProgress", "order": 3}
],
"areas": [
{"id": "core", "name": "Core Package", "priority": 1},
{"id": "format", "name": "Format Layer", "priority": 2},
{"id": "backend", "name": "Backend Layer", "priority": 3},
{"id": "utils", "name": "Utilities", "priority": 4}
],
"items": [
{
"id": "interfaces",
"title": "`interfaces.go` - Backend, RecordWriter, RecordReader interfaces",
"status": "completed",
"phase": "phase-1",
"area": "core",
"type": "Added"
},
{
"id": "ndjson-writer",
"title": "`format/ndjson/writer.go` - NDJSON RecordWriter",
"status": "completed",
"phase": "phase-1",
"area": "format",
"type": "Added"
}
],
"sections": [
{
"id": "design-philosophy",
"title": "Design Philosophy",
"order": 0,
"content": [
{"type": "text", "value": "This project uses **interface composition** to support both simple and advanced use cases."},
{"type": "blockquote", "value": "**Note:** Cloud provider backends with large SDK dependencies are in separate repos."}
]
}
]
}When using phases, enable area sub-headings to show logical groupings within each phase:
stasks generate -i TASKS.json -o TASKS.md \
--group-by phase \
--area-subheadings \
--tocThis produces output like:
## Phase 1: Foundation ✅
Core interfaces and essential implementations.
### Core Package
- [x] `interfaces.go` - Backend, RecordWriter, RecordReader interfaces
- [x] `options.go` - WriterOption, ReaderOption, configs
### Format Layer
- [x] `format/ndjson/writer.go` - NDJSON RecordWriter
- [x] `format/ndjson/reader.go` - NDJSON RecordReader
---
## Phase 2: Extended Interfaces ✅
...- Phases define sequential development stages with their own status
- Areas define logical groupings within phases (components, layers)
- Items have both
phaseandareafields for two-dimensional organization - Use
--group-by phase --area-subheadingsfor hierarchical output - Items render as compact task lists under area sub-headings
- Use
blockquotecontent type for notes and callouts
package main
import (
"fmt"
"github.com/grokify/structured-tasks/tasks"
"github.com/grokify/structured-tasks/renderer"
)
func main() {
// Parse task list
tl, err := tasks.ParseFile("TASKS.json")
if err != nil {
panic(err)
}
// Validate
result := tasks.Validate(tl)
if !result.Valid {
for _, e := range result.Errors {
fmt.Printf("Error: %s: %s\n", e.Field, e.Message)
}
return
}
// Get statistics
stats := tl.Stats()
fmt.Printf("Progress: %.0f%% complete\n", stats.CompletedPercent())
// Render to Markdown
opts := renderer.DefaultOptions()
opts.GroupBy = renderer.GroupByPriority
opts.ShowTOC = true
output := renderer.Render(tl, opts)
fmt.Println(output)
}- Structured Changelog - Machine-readable changelogs
- Keep a Changelog - Changelog format inspiration
MIT License - see LICENSE for details.