init
diff --git a/loop/todo.go b/loop/todo.go
new file mode 100644
index 0000000..e639857
--- /dev/null
+++ b/loop/todo.go
@@ -0,0 +1,61 @@
+package loop
+
+import (
+	"fmt"
+	"strings"
+	"sync"
+
+	"github.com/invopop/jsonschema"
+)
+
+type Comment struct {
+	Author  string `json:"author"`
+	Comment string `json:"comment"`
+}
+
+func (c Comment) String() string {
+	return fmt.Sprintf("%s: %s", c.Author, c.Comment)
+}
+
+type ToDo struct {
+	ID          string    `json:"id"`
+	Title       string    `json:"title"`
+	Description string    `json:"description"`
+	Items       []*ToDo   `json:"items"`
+	Done        bool      `json:"done"`
+	AssignedTo  string    `json:"assignedTo"`
+	Discussion  []Comment `json:"discussion"`
+	lock        sync.Locker
+}
+
+const tmpl = `%s: %s
+%s
+%s
+%s`
+
+func (t ToDo) String() string {
+	var comments []string
+	for _, c := range t.Discussion {
+		comments = append(comments, fmt.Sprintf("\t - %s", c.String()))
+	}
+	var items []string
+	for _, i := range t.Items {
+		items = append(items, fmt.Sprintf("\t%s", i.String()))
+	}
+	return fmt.Sprintf(tmpl, t.ID, t.Title, t.Description, strings.Join(comments, "\n"), strings.Join(items, "\n"))
+}
+
+func ToDoJSONSchema() string {
+	reflector := jsonschema.Reflector{
+		AllowAdditionalProperties:  false,
+		RequiredFromJSONSchemaTags: true,
+		DoNotReference:             false,
+	}
+	var v ToDo
+	s := reflector.Reflect(v)
+	b, err := s.MarshalJSON()
+	if err != nil {
+		panic(err)
+	}
+	return string(b)
+}