thingscloud

package module
v0.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 20, 2026 License: MIT Imports: 12 Imported by: 0

README

things cloud sdk

Things comes with a cloud based API, which can be used to synchronize data between devices. This is a Go SDK to interact with that API, opening the API so that you can enhance your Things experience on iOS and Mac.

Go

Maintained Fork

This fork is maintained by pdurlej as an automation-friendly Things Cloud SDK, with a practical focus on safe OpenClaw and Things integrations. It keeps the cloud API path explicit, favors typed state/change queries, and ships CLI behavior suitable for agent workflows.

The Go module path for this fork is:

github.com/pdurlej/things-cloud-sdk

Getting Started

Installation
go get github.com/pdurlej/things-cloud-sdk
Quick Start

1. Set up your credentials:

export THINGS_USERNAME='your@email.com'
export THINGS_PASSWORD='yourpassword'

Or use a config file:

{
  "username": "your@email.com",
  "password": "yourpassword",
  "token": "optional-password-alias",
  "cache": "/path/to/things-cli-state.json"
}

The default path is ~/.things-cloud.json. Set THINGS_CONFIG=/path/to/config.json to override it. Environment variables still take precedence.

2. Create a simple Go program:

package main

import (
    "fmt"
    "os"
    things "github.com/pdurlej/things-cloud-sdk"
)

func main() {
    client := things.New(
        things.APIEndpoint,
        os.Getenv("THINGS_USERNAME"),
        os.Getenv("THINGS_PASSWORD"),
    )

    // Verify credentials
    resp, err := client.Verify()
    if err != nil {
        panic(err)
    }
    fmt.Printf("✓ Connected: %s\n", resp.Email)

    // Get or create a history
    histories, _ := client.Histories()
    var historyID string
    if len(histories) > 0 {
        historyID = histories[0].ID
    } else {
        hist, _ := client.CreateHistory()
        historyID = hist.ID
    }

    // Create a task
    task := things.Task{
        UUID:  things.GenerateUUID(),
        Title: things.String("My first task from the SDK!"),
    }

    items := []things.Item{things.NewCreateTaskItem(task)}
    client.Write(historyID, items, -1)
    fmt.Printf("✓ Created task: %s\n", *task.Title)
}

3. Run it:

go run main.go
CLI Quick Start

Install and use the command-line tool:

# Install the preferred CLI
go install github.com/pdurlej/things-cloud-sdk/cmd/things-cloud-cli@latest

# Or install the backward-compatible alias
go install github.com/pdurlej/things-cloud-sdk/cmd/things-cli@latest

# Create a task
things-cloud-cli create "Buy groceries" --when today

# List today's tasks
things-cloud-cli list --today

# Compact task JSON for OpenClaw-style agents
things-cloud-cli today --simple

# Complete a task
things-cloud-cli complete <task-uuid>

Features

  • Verify Credentials — validate account access
  • Account Management — signup, confirmation, password change, deletion
  • History Management — list, create, delete, sync histories
  • Item Read/Write — full event-sourced CRUD for tasks, areas, tags, checklist items (supports batching multiple items in one request)
  • Task Types — tasks, projects, and headings (action groups within projects)
  • Structured Notes — full-text and delta patch support for task notes
  • Recurring Tasks — neverending, end on date, end after N times
  • Tombstone Deletion — explicit deletion records via Tombstone2 entities
  • Device Registration — register app instances for APNS push notifications
  • Alarm/Reminders — alarm time offset support on tasks
  • State Aggregation — in-memory state built from history items, with queries for projects, headings, subtasks, areas, tags, and checklist items
  • Persistent Sync Engine — SQLite-backed incremental sync with semantic change detection

CLI

things-cloud-cli is the preferred command-line tool for interacting with Things Cloud directly. things-cli remains available as a backward-compatible alias. things-mcp exposes a small stdio MCP server for agent integrations.

Setup
export THINGS_USERNAME='your@email.com'
export THINGS_PASSWORD='yourpassword'
go build -o things-cli ./cmd/things-cli/
go build -o things-cloud-cli ./cmd/things-cloud-cli/
go build -o things-mcp ./cmd/things-mcp/

You can also put credentials in ~/.things-cloud.json:

{
  "username": "your@email.com",
  "password": "yourpassword",
  "token": "optional-password-alias",
  "cache": "/path/to/things-cli-state.json"
}
Commands
# Read
things-cli list [--today] [--inbox] [--anytime] [--someday] [--upcoming] [--search QUERY] [--area NAME] [--project NAME] [--simple|--format full|simple]
things-cli today [--simple]
things-cli inbox [--simple]
things-cli anytime [--simple]
things-cli someday [--simple]
things-cli upcoming [--simple]
things-cli search <query> [--simple]
things-cli show <uuid> [--simple]
things-cli areas
things-cli projects
things-cli tags

# Optional read-state cache location
export THINGS_CLI_CACHE=/path/to/things-cli-state.json

# Create
things-cli create "Title" [--note ...] [--when today|anytime|someday|inbox] \
  [--deadline YYYY-MM-DD] [--scheduled YYYY-MM-DD] \
  [--project UUID] [--heading UUID] [--area UUID] \
  [--tags UUID,...] [--type task|project|heading] [--dry-run]
things-cli create-area "Name"
things-cli create-tag "Name" [--shorthand KEY] [--parent UUID]

# Modify
things-cli edit <uuid> [--title ...] [--note ...] [--when ...] [--deadline ...] [--dry-run]
things-cli complete <uuid> [--dry-run]
things-cli trash <uuid> [--dry-run]
things-cli purge <uuid> [--dry-run]
things-cli move-to-today <uuid> [--dry-run]

# Batch (all operations in one HTTP request - much faster!)
echo '[{"cmd":"complete","uuid":"abc"},{"cmd":"trash","uuid":"def"}]' | things-cli batch [--dry-run]
MCP Server

things-mcp reads MCP JSON-RPC messages from stdin and writes responses to stdout. It uses THINGS_USERNAME and THINGS_PASSWORD from the environment and exposes:

  • list_tasks
  • search_tasks
  • list_projects
  • list_areas
  • list_tags
  • create_task
  • complete_task
  • edit_task
  • trash_task
  • move_task_to_today
  • add_checklist
go install github.com/pdurlej/things-cloud-sdk/cmd/things-mcp@latest
things-mcp
Examples
# Create a project with tasks
things-cli create "My Project" --type project --when anytime
# → {"status":"created","uuid":"BXmAcvS6yK1eDhW31MuZrL","title":"My Project"}

things-cli create "First Task" --project BXmAcvS6yK1eDhW31MuZrL --when today --note "Details here"

# Preview the write payload without sending it to Things Cloud
things-cli create "Draft from agent" --when today --dry-run

# Create an area and assign tasks
things-cli create-area "Work"
things-cli create "Review PR" --area <area-uuid> --when today --deadline 2026-02-15

# Batch operations (50 ops in ~2 sec instead of ~2-3 min)
echo '[
  {"cmd": "create", "title": "Task 1"},
  {"cmd": "create", "title": "Task 2"},
  {"cmd": "move-to-project", "uuid": "abc123", "project": "proj-uuid"},
  {"cmd": "complete", "uuid": "def456"}
]' | things-cli batch

Advanced SDK Usage

Working with Histories and Items
package main

import (
    "fmt"
    "os"
    things "github.com/pdurlej/things-cloud-sdk"
)

func main() {
    client := things.New(
        things.APIEndpoint,
        os.Getenv("THINGS_USERNAME"),
        os.Getenv("THINGS_PASSWORD"),
    )

    // Create a history
    history, _ := client.CreateHistory()

    // Create a project with tasks
    project := things.Task{
        UUID:     things.GenerateUUID(),
        Title:    things.String("My Project"),
        TaskType: things.TaskTypePtr(things.TaskTypeProject),
        Status:   things.Status(things.TaskStatusPending),
        Schedule: things.Schedule(things.TaskScheduleAnytime),
    }

    task1 := things.Task{
        UUID:      things.GenerateUUID(),
        Title:     things.String("First task"),
        ProjectID: things.String(project.UUID),
        Schedule:  things.Schedule(things.TaskScheduleAnytime),
    }

    task2 := things.Task{
        UUID:      things.GenerateUUID(),
        Title:     things.String("Second task"),
        ProjectID: things.String(project.UUID),
        Schedule:  things.Schedule(things.TaskScheduleAnytime),
    }

    // Write all items in one batch
    items := []things.Item{
        things.NewCreateTaskItem(project),
        things.NewCreateTaskItem(task1),
        things.NewCreateTaskItem(task2),
    }

    client.Write(history.ID, items, -1)
    fmt.Println("✓ Created project with 2 tasks")
}

See the example/ directory for more complete examples including history sync, task creation, and state aggregation.

Persistent Sync Engine

The sync package provides a SQLite-backed sync engine that tracks "what changed since last sync" — perfect for building agents, automations, or dashboards that react to Things changes.

package main

import (
    "fmt"
    "os"
    things "github.com/pdurlej/things-cloud-sdk"
    "github.com/pdurlej/things-cloud-sdk/sync"
)

func main() {
    client := things.New(
        things.APIEndpoint,
        os.Getenv("THINGS_USERNAME"),
        os.Getenv("THINGS_PASSWORD"),
    )

    // Open persistent sync database
    syncer, _ := sync.Open("things.db", client)
    defer syncer.Close()

    // Fetch changes since last sync
    changes, _ := syncer.Sync()
    // Or skip the server-index preflight when a local sync DB already exists:
    // changes, _ := syncer.QuickSync()

    for _, c := range changes {
        switch v := c.(type) {
        case sync.TaskCreated:
            fmt.Printf("New task: %s\n", v.Task.Title)
        case sync.TaskCompleted:
            fmt.Printf("Completed: %s\n", v.Task.Title)
        case sync.TaskMovedToToday:
            fmt.Printf("Moved to Today: %s\n", v.Task.Title)
        }
    }

    // Query current state
    state := syncer.State()
    inbox, _ := state.TasksInInbox(sync.QueryOpts{})
    projects, _ := state.AllProjects(sync.QueryOpts{})
}
Semantic Change Types

The sync engine detects 40+ semantic change types:

Category Changes
Task Lifecycle TaskCreated, TaskCompleted, TaskUncompleted, TaskTrashed, TaskDeleted
Task Movement TaskMovedToInbox, TaskMovedToToday, TaskMovedToAnytime, TaskMovedToSomeday, TaskMovedToUpcoming
Task Organization TaskAssignedToProject, TaskAssignedToArea, TaskTagsChanged
Task Details TaskTitleChanged, TaskNoteChanged, TaskDeadlineChanged, TaskCanceled, TaskRestored
Projects ProjectCreated, ProjectCompleted, ProjectTitleChanged, ProjectTrashed, ProjectRestored, ProjectDeleted
Headings HeadingCreated, HeadingTitleChanged, HeadingDeleted
Areas & Tags AreaCreated, AreaRenamed, AreaDeleted, TagCreated, TagRenamed, TagShortcutChanged, TagDeleted
Checklists ChecklistItemCreated, ChecklistItemCompleted, ChecklistItemUncompleted, ChecklistItemTitleChanged, ChecklistItemDeleted
Persistence Fallbacks LoggedChange, UnknownChange
State Queries
state := syncer.State()

// Query by location
inbox, _ := state.TasksInInbox(sync.QueryOpts{})
today, _ := state.TasksInToday(sync.QueryOpts{})
anytime, _ := state.TasksInAnytime(sync.QueryOpts{})
someday, _ := state.TasksInSomeday(sync.QueryOpts{})
upcoming, _ := state.TasksInUpcoming(sync.QueryOpts{})

// Query by container
tasks, _ := state.TasksInProject(projectUUID, sync.QueryOpts{})
tasks, _ := state.TasksInArea(areaUUID, sync.QueryOpts{})
tasks, _ := state.TasksUnderHeading(headingUUID, sync.QueryOpts{})
headings, _ := state.HeadingsInProject(projectUUID, sync.QueryOpts{})

// Query by tag or text
tasks, _ := state.TasksWithTag(tagUUID, sync.QueryOpts{})
tasks, _ := state.SearchTasks("invoice", sync.QueryOpts{})

// List all
projects, _ := state.AllProjects(sync.QueryOpts{})
headings, _ := state.AllHeadings(sync.QueryOpts{})
areas, _ := state.AllAreas(sync.QueryOpts{})
tags, _ := state.AllTags(sync.QueryOpts{})
Change Log Queries
// Changes in last hour
changes, _ := syncer.ChangesSince(time.Now().Add(-1 * time.Hour))

// Changes for a specific task
changes, _ := syncer.ChangesForEntity(taskUUID)

// Changes since server index
changes, _ := syncer.ChangesSinceIndex(150)

Local SQLite Reader

The local package provides a read-only adapter for local Things SQLite databases. This is separate from cloud writes and is intended for fast local inspection on macOS setups that already grant database access.

reader, _ := local.OpenDefault()
defer reader.Close()

tasks, _ := reader.Tasks(context.Background(), local.Query{
    Search: "invoice",
})

Wire Format Notes

Key findings from reverse engineering the Things Cloud sync protocol:

  • UUIDs must be Base58-encoded (Bitcoin alphabet: 123456789ABCDEFGH...). Standard UUID strings or other encodings will crash Things.app during sync.
  • md (modification date) must be null on creates. Set timestamps only on updates.
  • Schedule field (st): 0 = Inbox, 1 = Anytime/Today (with sr/tir dates = Today), 2 = Someday/Upcoming (with dates = Upcoming).
  • Status field (ss): 0 = Pending, 2 = Canceled, 3 = Completed. Don't confuse with st (schedule)!
  • Headings (tp=2) must have st=1 (anytime). st=0 (inbox) crashes Things.app.
  • Tasks in projects, headings, or areas should default to st=1 (anytime) — they've been triaged out of inbox.
  • Kind strings: Task6, Tag4, ChecklistItem3, Area3, Tombstone2

See docs/client-side-bugs.md for the full investigation and crash analysis.

Architecture

The SDK models all changes as immutable Items (events). A History is a sync stream identified by a UUID. The client pushes/pulls Items through Histories, inspired by operational transformations and Git's internals.

TODO

  • Repeat after completion metadata helpers
  • Persistent state storage (see sync package)

Note

As there is no official API documentation available all requests need to be reverse engineered, which takes some time. Feel free to contribute and improve & extend this implementation.

Documentation

Index

Examples

Constants

View Source
const (
	// APIEndpoint is the public culturedcode https endpoint
	APIEndpoint = "https://cloud.culturedcode.com"
)
View Source
const NoteTypeDelta = 2

NoteTypeDelta indicates a note with incremental patches

View Source
const NoteTypeFullText = 1

NoteTypeFullText indicates a note with complete text

View Source
const ThingsUserAgent = "ThingsMac/32209501"

ThingsUserAgent is the http user-agent header set by things for mac

Variables

View Source
var (
	// ErrUnauthorized is returned by the API when the credentials are wrong
	ErrUnauthorized = errors.New("unauthorized")
)

Functions

func ApplyPatches added in v0.2.1

func ApplyPatches(original string, patches []NotePatch) string

ApplyPatches applies a series of text patches to an original string

func String added in v0.2.1

func String(str string) *string

String returns a pointer to a string

Types

type AccountService

type AccountService service

AccountService allows account specific interaction with thingscloud

func (*AccountService) AcceptSLA added in v0.2.1

func (s *AccountService) AcceptSLA() error

func (*AccountService) ChangePassword

func (s *AccountService) ChangePassword(newPassword string) (*Client, error)

ChangePassword allows you to change your account password. Because things does not work with sessions you need to create a new client instance after executing this method

func (*AccountService) Confirm

func (s *AccountService) Confirm(code string) error

Confirm finishes the account creation by providing the email token send by thingscloud

func (*AccountService) Delete

func (s *AccountService) Delete() error

Delete deletes your current thingscloud account. This cannot be reversed

func (*AccountService) SignUp

func (s *AccountService) SignUp(email, password string) (*Client, error)

SignUp creates a new thingscloud account and returns a configured client

type AccountStatus

type AccountStatus string

AccountStatus describes possible thingscloud account statuses

const (
	// AccountStatusActive is for active accounts
	AccountStatusActive AccountStatus = "SYAccountStatusActive"
)

type AppInstanceRequest added in v0.2.1

type AppInstanceRequest struct {
	AppInstanceID string `json:"-"`
	HistoryKey    string `json:"history-key"`
	APNSToken     string `json:"apns-token"`
	AppID         string `json:"app-id"`
	Dev           bool   `json:"dev"`
}

AppInstanceRequest describes the payload for registering a device for push notifications

type Area

type Area struct {
	UUID  string
	Title string
	Tags  []*Tag
	Tasks []*Task
}

Area describes an Area inside things. An Area is a container for tasks 0|uuid|TEXT|0||1 1|title|TEXT|0||0 2|visible|INTEGER|0||0 3|index|INTEGER|0||0

type AreaActionItem

type AreaActionItem struct {
	Item
	P AreaActionItemPayload `json:"p"`
}

AreaActionItem describes an event on an Area

func (AreaActionItem) UUID

func (item AreaActionItem) UUID() string

UUID returns the UUID of the modified Area

type AreaActionItemPayload

type AreaActionItemPayload struct {
	IX     *int     `json:"ix,omitempty"`
	Title  *string  `json:"tt,omitempty"`
	TagIDs []string `json:"tg,omitempty"`
}

AreaActionItemPayload describes the payload for modifying Areas

type Boolean

type Boolean bool

Boolean allows integers to be parsed into booleans, where 1 means true and 0 means false

func (*Boolean) MarshalJSON

func (b *Boolean) MarshalJSON() ([]byte, error)

MarshalJSON takes a boolean and serializes it as an integer

func (*Boolean) UnmarshalJSON

func (b *Boolean) UnmarshalJSON(bs []byte) error

UnmarshalJSON takes an int and creates a boolean instance

type CheckListActionItem

type CheckListActionItem struct {
	Item
	P CheckListActionItemPayload `json:"p"`
}

CheckListActionItem describes an event on a check list item

func (CheckListActionItem) UUID

func (item CheckListActionItem) UUID() string

UUID returns the UUID of the modified CheckListItem

type CheckListActionItemPayload

type CheckListActionItemPayload struct {
	CreationDate     *Timestamp      `json:"cd,omitempty"`
	ModificationDate *Timestamp      `json:"md,omitempty"`
	Index            *int            `json:"ix"`
	Status           *TaskStatus     `json:"ss,omitempty"`
	Title            *string         `json:"tt,omitempty"`
	CompletionDate   *Timestamp      `json:"sp,omitempty"`
	TaskIDs          *[]string       `json:"ts,omitempty"`
	Leavable         *bool           `json:"lt,omitempty"`
	ExtensionData    json.RawMessage `json:"xx,omitempty"`
}

CheckListActionItemPayload describes the payload for modifying CheckListItems

type CheckListItem

type CheckListItem struct {
	UUID             string
	CreationDate     time.Time
	ModificationDate *time.Time
	Status           TaskStatus
	Title            string
	Index            int
	CompletionDate   *time.Time
	TaskIDs          []string
}

CheckListItem describes a check list item 0|uuid|TEXT|0||1 1|userModificationDate|REAL|0||0 2|creationDate|REAL|0||0 3|title|TEXT|0||0 4|status|INTEGER|0||0 5|stopDate|REAL|0||0 6|index|INTEGER|0||0 7|task|TEXT|0||0

type Client

type Client struct {
	Endpoint string
	EMail    string

	ClientInfo ClientInfo
	Debug      bool

	Accounts *AccountService
	// contains filtered or unexported fields
}

Client is a culturedcode cloud client. It can be used to interact with the things cloud to manage your data.

func New

func New(endpoint, email, password string) *Client

New initializes a things client

func (*Client) CreateHistory

func (c *Client) CreateHistory() (*History, error)

CreateHistory requests a new history key

func (*Client) Histories

func (c *Client) Histories() ([]*History, error)

Histories requests all known history keys

Example
client := New(APIEndpoint, os.Getenv("THINGS_USERNAME"), os.Getenv("THINGS_PASSWORD"))

histories, err := client.Histories()
if err != nil {
	log.Printf("Failed loading histories: %q", err.Error())
}

for _, history := range histories {
	if err := history.Sync(); err != nil {
		log.Printf("Failed syncing history: %q", err.Error())
	}
}

func (*Client) History added in v0.1.1

func (c *Client) History(id string) (*History, error)

History requests a specific history

func (*Client) HistoryWithID added in v0.2.1

func (c *Client) HistoryWithID(id string) *History

HistoryWithID creates a History object with the given ID without making a network call. Use this when you already know the history ID (e.g., from a previous sync).

func (*Client) OwnHistory added in v0.2.1

func (c *Client) OwnHistory() (*History, error)

OwnHistory returns the clients own history

func (*Client) RegisterAppInstance added in v0.2.1

func (c *Client) RegisterAppInstance(req AppInstanceRequest) error

RegisterAppInstance registers a device for push notifications via APNS

func (*Client) Verify

func (c *Client) Verify() (*VerifyResponse, error)

Verify checks that the provided API credentials are valid.

Example
client := New(APIEndpoint, os.Getenv("THINGS_USERNAME"), os.Getenv("THINGS_PASSWORD"))

_, err := client.Verify()
if err != nil {
	log.Printf("Invalid Credentials: %q", err.Error())
}

type ClientInfo added in v0.2.1

type ClientInfo struct {
	DeviceModel string `json:"dm"`
	LocalRegion string `json:"lr"`
	NF          bool   `json:"nf"`
	NK          bool   `json:"nk"`
	AppName     string `json:"nn"`
	AppVersion  string `json:"nv"`
	OSName      string `json:"on"`
	OSVersion   string `json:"ov"`
	PrimaryLang string `json:"pl"`
	UserLocale  string `json:"ul"`
}

ClientInfo represents the device metadata sent in the things-client-info header.

func DefaultClientInfo added in v0.2.1

func DefaultClientInfo() ClientInfo

DefaultClientInfo returns a ClientInfo with default values matching a typical Mac client.

type FrequencyUnit added in v0.1.1

type FrequencyUnit int64

FrequencyUnit describes recurring frequencies

var (
	// FrequencyUnitDaily occurs every n days
	FrequencyUnitDaily FrequencyUnit = 16
	// FrequencyUnitWeekly occurs every n weeks
	FrequencyUnitWeekly FrequencyUnit = 256
	// FrequencyUnitMonthly occurs every n months
	FrequencyUnitMonthly FrequencyUnit = 8
	// FrequencyUnitYearly occurs every n years
	FrequencyUnitYearly FrequencyUnit = 4
)

type History

type History struct {
	ID                     string
	Client                 *Client
	LatestServerIndex      int
	LoadedServerIndex      int
	LatestSchemaVersion    int
	EndTotalContentSize    int
	LatestTotalContentSize int
}

History represents a synchronization stream. It's identified with a uuid v4

func (*History) Delete

func (h *History) Delete() error

Delete destroys a history Note that thingscloud will always return 202, even if the key is unknown

func (*History) Items

func (h *History) Items(opts ItemsOptions) ([]Item, bool, error)

Items fetches changes from thingscloud. Every change contains multiple items which have been modified. The Items method unwraps these objects and returns a list instead.

Note that if a item was changed multiple times it will be present multiple times in the result too.

Example
client := New(APIEndpoint, os.Getenv("THINGS_USERNAME"), os.Getenv("THINGS_PASSWORD"))

histories, err := client.Histories()
if err != nil {
	log.Printf("Failed loading histories: %q", err.Error())
}
history := histories[0]

items, _, err := history.Items(ItemsOptions{})
if err != nil {
	log.Printf("Failed loading items: %q", err.Error())
}

log.Printf("got %d items.", len(items))

func (*History) Sync

func (h *History) Sync() error

Sync ensures the history object is able to write to things

func (*History) Write

func (h *History) Write(items ...Identifiable) error

type Identifiable

type Identifiable interface {
	UUID() string
}

Identifiable abstracts different thingscloud write requests. As we need to provide a map indexed by UUID, all we care about is the ID of the change, not the change itself

type Item

type Item struct {
	UUID           string          `json:"-"`
	P              json.RawMessage `json:"p"`
	Kind           ItemKind        `json:"e"`
	Action         ItemAction      `json:"t"`
	ServerIndex    int             `json:"-"`
	HasServerIndex bool            `json:"-"`
}

Item is an event in thingscloud. Every action inside things generates an Item. Common items are the creation of a task, area or checklist, as well as modifying attributes or marking things as done.

type ItemAction

type ItemAction int

ItemAction describes possible actions on Items

const (
	// ItemActionCreated is used to indicate a new Item was created
	ItemActionCreated ItemAction = iota
	// ItemActionModified is used to indicate an existing Item was modified
	ItemActionModified ItemAction = 1
	// ItemActionDeleted is used as a tombstone for an Item
	ItemActionDeleted ItemAction = 2
)

func (ItemAction) String

func (i ItemAction) String() string

type ItemKind

type ItemKind string

ItemKind describes the different types things cloud supports

var (
	// ItemKindChecklistItem identifies a CheckList
	ItemKindChecklistItem  ItemKind = "ChecklistItem"
	ItemKindChecklistItem2 ItemKind = "ChecklistItem2"
	ItemKindChecklistItem3 ItemKind = "ChecklistItem3"
	// ItemKindTask identifies a Task or Subtask
	ItemKindTask      ItemKind = "Task6"
	ItemKindTask4     ItemKind = "Task4"
	ItemKindTask3     ItemKind = "Task3"
	ItemKindTaskPlain ItemKind = "Task"
	// ItemKindArea identifies an Area
	ItemKindArea      ItemKind = "Area2"
	ItemKindArea3     ItemKind = "Area3"
	ItemKindAreaPlain ItemKind = "Area"
	// ItemKindSettings  identifies a setting
	ItemKindSettings ItemKind = "Settings3"
	// ItemKindTag identifies a Tag
	ItemKindTag       ItemKind = "Tag3"
	ItemKindTag4      ItemKind = "Tag4"
	ItemKindTagPlain  ItemKind = "Tag"
	ItemKindTombstone ItemKind = "Tombstone2"
)

type ItemsOptions

type ItemsOptions struct {
	StartIndex int
}

ItemsOptions allows a client to pickup changes from a specific index

type Note added in v0.2.1

type Note struct {
	TypeTag  string      `json:"_t"`
	Type     int         `json:"t"`
	Checksum int64       `json:"ch,omitempty"`
	Value    string      `json:"v,omitempty"`
	Patches  []NotePatch `json:"ps,omitempty"`
}

Note describes a structured note as used by the Things API

type NotePatch added in v0.2.1

type NotePatch struct {
	Replacement string `json:"r"`
	Position    int    `json:"p"`
	Length      int    `json:"l"`
	Checksum    int64  `json:"ch"`
}

NotePatch describes a single text replacement operation

type RepeaterConfiguration added in v0.1.1

type RepeaterConfiguration struct {
	FirstScheduledAt    *Timestamp                    `json:"ia,omitempty"`
	RepeatCount         *int64                        `json:"rc,omitempty"`
	FrequencyUnit       FrequencyUnit                 `json:"fu"`
	FrequencyAmplitude  int64                         `json:"fa"`
	DetailConfiguration []RepeaterDetailConfiguration `json:"of"`
	LastScheduledAt     *Timestamp                    `json:"ed,omitempty"`
	Version             int                           `json:"rrv,omitempty"`
	Type                int                           `json:"tp,omitempty"`
	TimeShift           int                           `json:"ts,omitempty"`
	StartReference      *Timestamp                    `json:"sr,omitempty"`
}

RepeaterConfiguration configures the recurring rules of a task/ project

func NewRepeatAfterCompletion added in v0.2.1

func NewRepeatAfterCompletion(unit FrequencyUnit, amplitude int64, start time.Time) RepeaterConfiguration

NewRepeatAfterCompletion creates a basic repeat-after-completion rule. Callers can customize DetailConfiguration and end conditions before writing.

func (RepeaterConfiguration) ComputeFirstScheduledAt added in v0.1.1

func (c RepeaterConfiguration) ComputeFirstScheduledAt(t time.Time) time.Time

ComputeFirstScheduledAt calculates the first occurrence of a recurring rule based on the pattern This value has to be stored as FirstScheduledAt per thingscloud convention

func (RepeaterConfiguration) IsAfterCompletion added in v0.2.1

func (c RepeaterConfiguration) IsAfterCompletion() bool

IsAfterCompletion reports whether the rule repeats after completion.

func (RepeaterConfiguration) IsNeverending added in v0.1.1

func (c RepeaterConfiguration) IsNeverending() bool

IsNeverending determines if a recurring rule has a specific end

func (RepeaterConfiguration) NextScheduledAt added in v0.1.1

func (c RepeaterConfiguration) NextScheduledAt(repeat int) time.Time

NextScheduledAt returns the next Nth date a rule should occur. Note that things generates these ToDos as necessary.

type RepeaterDetailConfiguration added in v0.1.1

type RepeaterDetailConfiguration struct {
	Day     *int64        `json:"dy,omitempty"`
	Month   *int64        `json:"mo,omitempty"`
	Weekday *time.Weekday `json:"wd,omitempty"`
	MonthOf *int64        `json:"wdo,omitempty"`
}

RepeaterDetailConfiguration configures specifics of a repeater configuration.

type RepeaterType added in v0.2.1

type RepeaterType int

RepeaterType describes whether a repeating task is scheduled from its scheduled date or after the previous completion.

const (
	// RepeaterTypeScheduled repeats from the scheduled date.
	RepeaterTypeScheduled RepeaterType = 0
	// RepeaterTypeAfterCompletion repeats after the task is completed.
	RepeaterTypeAfterCompletion RepeaterType = 1
)

type Setting

type Setting struct{}

Setting describes things settings 0|uuid|TEXT|0||1 1|logInterval|INTEGER|0||0 2|manualLogDate|REAL|0||0 3|groupTodayByParent|INTEGER|0||0

type Tag

type Tag struct {
	UUID         string
	Title        string
	ParentTagIDs []string
	ShortHand    string
}

Tag describes the aggregated state of an Tag 0|uuid|TEXT|0||1 1|title|TEXT|0||0 2|shortcut|TEXT|0||0 3|usedDate|REAL|0||0 4|parent|TEXT|0||0 5|index|INTEGER|0||0

type TagActionItem

type TagActionItem struct {
	Item
	P TagActionItemPayload `json:"p"`
}

TagActionItem describes an event on a tag

func (TagActionItem) UUID

func (t TagActionItem) UUID() string

UUID returns the UUID of the modified Tag

type TagActionItemPayload

type TagActionItemPayload struct {
	IX            *int            `json:"ix"`
	Title         *string         `json:"tt"`
	ShortHand     *string         `json:"sh"`
	ParentTagIDs  *[]string       `json:"pn"`
	ExtensionData json.RawMessage `json:"xx,omitempty"`
}

TagActionItemPayload describes the payload for modifying Areas

type Task

type Task struct {
	UUID             string
	CreationDate     time.Time
	ModificationDate *time.Time
	Status           TaskStatus
	Title            string
	Note             string
	ScheduledDate    *time.Time
	CompletionDate   *time.Time
	DeadlineDate     *time.Time
	Index            int
	AreaIDs          []string
	ParentTaskIDs    []string
	ActionGroupIDs   []string
	InTrash          bool
	Schedule         TaskSchedule
	Type             TaskType
	TodayIndex       int
	DueOrder         int
	AlarmTimeOffset  *int
	TagIDs           []string
	RecurrenceIDs    []string
	DelegateIDs      []string
}

Task describes a Task inside things. 0|uuid|TEXT|0||1 1|userModificationDate|REAL|0||0 2|creationDate|REAL|0||0 3|trashed|INTEGER|0||0 4|type|INTEGER|0||0 5|title|TEXT|0||0 6|notes|TEXT|0||0 7|dueDate|REAL|0||0 8|dueDateOffset|INTEGER|0||0 9|status|INTEGER|0||0 10|stopDate|REAL|0||0 11|start|INTEGER|0||0 12|startDate|REAL|0||0 13|index|INTEGER|0||0 14|todayIndex|INTEGER|0||0 15|area|TEXT|0||0 16|project|TEXT|0||0 17|repeatingTemplate|TEXT|0||0 18|delegate|TEXT|0||0 19|recurrenceRule|BLOB|0||0 20|instanceCreationStartDate|REAL|0||0 21|instanceCreationPaused|INTEGER|0||0 22|instanceCreationCount|INTEGER|0||0 23|afterCompletionReferenceDate|REAL|0||0 24|actionGroup|TEXT|0||0 25|untrashedLeafActionsCount|INTEGER|0||0 26|openUntrashedLeafActionsCount|INTEGER|0||0 27|checklistItemsCount|INTEGER|0||0 28|openChecklistItemsCount|INTEGER|0||0 29|startBucket|INTEGER|0||0 30|alarmTimeOffset|REAL|0||0 31|lastAlarmInteractionDate|REAL|0||0 32|todayIndexReferenceDate|REAL|0||0 33|nextInstanceStartDate|REAL|0||0 34|dueDateSuppressionDate|REAL|0||0

type TaskActionItem

type TaskActionItem struct {
	Item
	P TaskActionItemPayload `json:"p"`
}

TaskActionItem describes an event on a Task

func (TaskActionItem) UUID

func (t TaskActionItem) UUID() string

UUID returns the UUID of the modified Task

type TaskActionItemPayload

type TaskActionItemPayload struct {
	Index                     *int                   `json:"ix,omitempty"`
	CreationDate              *Timestamp             `json:"cd,omitempty"`
	ModificationDate          *Timestamp             `json:"md,omitempty"` // ok
	ScheduledDate             *Timestamp             `json:"sr,omitempty"`
	CompletionDate            *Timestamp             `json:"sp,omitempty"`
	DeadlineDate              *Timestamp             `json:"dd,omitempty"`  //
	TaskIR                    *Timestamp             `json:"tir,omitempty"` // hm, not sure what tir stands for
	Status                    *TaskStatus            `json:"ss,omitempty"`
	Type                      *TaskType              `json:"tp,omitempty"`
	Title                     *string                `json:"tt,omitempty"`
	Note                      json.RawMessage        `json:"nt,omitempty"`
	AreaIDs                   *[]string              `json:"ar,omitempty"`
	ParentTaskIDs             *[]string              `json:"pr,omitempty"`
	TagIDs                    []string               `json:"tg,omitempty"`
	InTrash                   *bool                  `json:"tr,omitempty"`
	TaskIndex                 *int                   `json:"ti,omitempty"`
	RecurrenceTaskIDs         *[]string              `json:"rt,omitempty"`
	Schedule                  *TaskSchedule          `json:"st,omitempty"`
	ActionGroupIDs            *[]string              `json:"agr,omitempty"`
	Repeater                  *RepeaterConfiguration `json:"rr,omitempty"`
	DueOrder                  *int                   `json:"do,omitempty"`
	Leavable                  *bool                  `json:"lt,omitempty"`
	IsCompletedByChildren     *bool                  `json:"icp,omitempty"`
	IsCompletedCount          *int                   `json:"icc,omitempty"`
	InstanceCreationStartDate *Timestamp             `json:"icsd,omitempty"`
	SubtaskBehavior           *int                   `json:"sb,omitempty"`
	DelegateIDs               *[]string              `json:"dl,omitempty"`
	LastActionItemID          *Timestamp             `json:"lai,omitempty"`
	ReminderDate              *Timestamp             `json:"rmd,omitempty"`
	AlarmTimeOffset           *int                   `json:"ato,omitempty"`
	ActionRequiredDate        *Timestamp             `json:"acrd,omitempty"`
	DeadlineSuppression       *Timestamp             `json:"dds,omitempty"`
	ExtensionData             json.RawMessage        `json:"xx,omitempty"`
}

TaskActionItemPayload describes the payload for modifying Tasks, and also Projects, as projects are special kind of Tasks

type TaskSchedule

type TaskSchedule int

TaskSchedule describes when a task is scheduled

const (
	// TaskScheduleInbox indicates unprocessed tasks in the Inbox (st=0)
	TaskScheduleInbox TaskSchedule = 0
	// TaskScheduleAnytime indicates started tasks; displayed in Today when sr/tir
	// are set to today's date, or in Anytime when sr/tir are null (st=1)
	TaskScheduleAnytime TaskSchedule = 1
	// TaskScheduleSomeday indicates deferred tasks; displayed in Upcoming when
	// sr/tir have a future date, or in Someday when sr/tir are null (st=2)
	TaskScheduleSomeday TaskSchedule = 2

	// TaskScheduleToday is deprecated: use TaskScheduleAnytime with sr/tir dates.
	// The "st" field value 0 actually means Inbox, not Today.
	// Kept for backward compatibility.
	TaskScheduleToday = TaskScheduleInbox
)

func Schedule added in v0.2.1

func Schedule(val TaskSchedule) *TaskSchedule

Schedule returns a pointer to a TaskSchedule

func (TaskSchedule) String

func (i TaskSchedule) String() string

type TaskStatus

type TaskStatus int

TaskStatus describes if a thing is completed or not

const (
	// TaskStatusPending indicates a new task
	TaskStatusPending TaskStatus = iota
	// TaskStatusCompleted indicates a completed task
	TaskStatusCompleted TaskStatus = 3
	// TaskStatusCanceled indicates a canceled task
	TaskStatusCanceled TaskStatus = 2
)

func Status added in v0.2.1

func Status(val TaskStatus) *TaskStatus

Status returns a pointer to a TaskStatus

func (TaskStatus) String

func (i TaskStatus) String() string

type TaskType added in v0.2.1

type TaskType int

TaskType describes the type of a task entity

const (
	TaskTypeTask    TaskType = 0
	TaskTypeProject TaskType = 1
	TaskTypeHeading TaskType = 2
)

func TaskTypePtr added in v0.2.1

func TaskTypePtr(val TaskType) *TaskType

TaskTypePtr returns a pointer to a TaskType

type Timestamp

type Timestamp time.Time

Timestamp allows unix epochs represented as float or ints to be unmarshalled into time.Time objects

func Time added in v0.2.1

func Time(val time.Time) *Timestamp

Time returns a pointer to a Time

func (*Timestamp) Format

func (t *Timestamp) Format(layout string) string

Format returns a textual representation of the time value formatted according to layout

func (*Timestamp) MarshalJSON

func (t *Timestamp) MarshalJSON() ([]byte, error)

MarshalJSON converts a timestamp into a fractional unix epoch (seconds with sub-second precision), matching the format used by the Things Cloud API (e.g. 1770713623.4716659).

func (*Timestamp) Time

func (t *Timestamp) Time() *time.Time

Time returns the underlying time.Time instance

func (*Timestamp) UnmarshalJSON

func (t *Timestamp) UnmarshalJSON(bs []byte) error

UnmarshalJSON takes a unix epoch from float/ int and creates a time.Time instance, preserving sub-second precision.

type TombstoneActionItem added in v0.2.1

type TombstoneActionItem struct {
	Item
	P TombstoneActionItemPayload `json:"p"`
}

TombstoneActionItem describes a tombstone deletion event

func (TombstoneActionItem) UUID added in v0.2.1

func (t TombstoneActionItem) UUID() string

UUID returns the UUID of the TombstoneActionItem

type TombstoneActionItemPayload added in v0.2.1

type TombstoneActionItemPayload struct {
	DeletedObjectID string  `json:"dloid"`
	DeletionDate    float64 `json:"dld"`
}

TombstoneActionItemPayload describes the payload for tombstone deletion records

type VerifyResponse

type VerifyResponse struct {
	SLAVersionAccepted string          `json:"SLA-version-accepted"`
	Issues             json.RawMessage `json:"issues"`
	Email              string          `json:"email"`
	MaildropEmail      string          `json:"maildrop-email"`
	Status             AccountStatus   `json:"status"`
	HistoryKey         string          `json:"history-key"`
}

VerifyResponse contains details about your account

Directories

Path Synopsis
cmd
debug command
debugupdate command
findtask command
fullstate command
list command
rawitem command
rawtask command
recent command
statedebug command
synctest command
things-cli command
things-mcp command
thingsync command
trace command
internal
Package local provides a read-only adapter for local Things SQLite databases.
Package local provides a read-only adapter for local Things SQLite databases.
state
Package sync provides a persistent sync engine for Things Cloud.
Package sync provides a persistent sync engine for Things Cloud.
Package syncutil provides shared utilities for sync-based CLI tools.
Package syncutil provides shared utilities for sync-based CLI tools.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL