tick

package
v0.19.0 Latest Latest
Warning

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

Go to latest
Published: Jul 2, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ActivityCreate        = "create"
	ActivityUpdate        = "update"
	ActivityClose         = "close"
	ActivityReopen        = "reopen"
	ActivityNote          = "note"
	ActivityApprove       = "approve"
	ActivityReject        = "reject"
	ActivityBlock         = "block"
	ActivityUnblock       = "unblock"
	ActivityAssign        = "assign"
	ActivityAwaiting      = "awaiting"
	ActivityStart         = "start"          // logged when task is claimed by pool worker
	ActivityStaleRecovery = "stale_recovery" // logged when stale task is reset
)

Activity actions

View Source
const (
	StatusOpen       = "open"
	StatusInProgress = "in_progress"
	StatusClosed     = "closed"
)

Status values.

View Source
const (
	TypeBug     = "bug"
	TypeFeature = "feature"
	TypeTask    = "task"
	TypeEpic    = "epic"
	TypeChore   = "chore"
)

Type values.

View Source
const (
	RequiresApproval = "approval"
	RequiresReview   = "review"
	RequiresContent  = "content"
)

Requires values (pre-declared gates).

View Source
const (
	AwaitingWork       = "work"
	AwaitingApproval   = "approval"
	AwaitingInput      = "input"
	AwaitingReview     = "review"
	AwaitingContent    = "content"
	AwaitingEscalation = "escalation"
	AwaitingCheckpoint = "checkpoint"
)

Awaiting values (current wait state).

View Source
const (
	VerdictApproved = "approved"
	VerdictRejected = "rejected"
)

Verdict values (human response to awaiting state).

View Source
const (
	RoleReview   = "review"
	RoleCloseout = "closeout"
)

Role values (process ticks in an epic's EPIC-SKELETON). A runnable epic ends with two process ticks: a final-review tick (role=review) blocked by every last-wave implementation tick, and a close-out tick (role=closeout) blocked by the final-review tick. The role is structural so orchestrators can detect a missing skeleton mechanically (tk graph --json → missing_process_ticks) instead of matching tick titles.

View Source
const LearningsCap = 150

LearningsCap is the maximum recommended line count for .tick/learnings.md.

View Source
const TargetDateLayout = "2006-01-02"

TargetDateLayout is the canonical format for the optional TargetDate field: a precise ISO calendar day with no time-of-day component.

Variables

Valid values for workflow fields (for validation and documentation).

Functions

func CheckLearningsCap added in v0.13.0

func CheckLearningsCap(tickDir string) (lines int, over bool, err error)

CheckLearningsCap counts the lines in <tickDir>/learnings.md and reports whether the file exceeds LearningsCap.

If the file does not exist, (0, false, nil) is returned. An empty file is treated as 0 lines (over = false). Lint errors (unexpected OS errors) are swallowed: (0, false, nil).

func HandleClose added in v0.1.18

func HandleClose(t *Tick, reason string) (routed bool)

HandleClose processes a close request for a tick. If the tick has a required gate (Requires field set), it routes to human instead of closing. Returns (routed bool) indicating whether the tick was routed to human instead of closed.

When routed:

  • Sets Awaiting = Requires
  • Adds note explaining work is complete, awaiting specified review
  • Does NOT close the tick

When closing:

  • Sets Status = closed
  • Sets ClosedAt = now
  • Sets ClosedReason = reason

The Requires field persists, so if human rejects and agent completes again, it will route to human again.

func ProcessVerdict added in v0.1.18

func ProcessVerdict(t *Tick) (closed bool, err error)

ProcessVerdict processes a verdict on an awaiting tick and returns whether the tick was closed. This is the core state machine for agent-human workflow.

Logic:

  • Terminal states (work, approval, review, content): close on approved
  • Non-terminal states (input, escalation): close on rejected (can't/won't proceed)
  • Checkpoint: never closes, always returns to agent

After processing, Awaiting and Verdict are cleared regardless of outcome.

Types

type Activity added in v0.2.1

type Activity struct {
	Timestamp time.Time              `json:"ts"`
	TickID    string                 `json:"tick"`
	Action    string                 `json:"action"`
	Actor     string                 `json:"actor"`
	Epic      string                 `json:"epic,omitempty"`
	Data      map[string]interface{} `json:"data,omitempty"`
}

Activity represents a single activity log entry.

type IDGenerator

type IDGenerator struct {
	// contains filtered or unexported fields
}

IDGenerator produces random base36 tick IDs.

func NewIDGenerator

func NewIDGenerator(rng *rand.Rand) *IDGenerator

NewIDGenerator returns a generator. If rng is nil, a time-based source is used.

func (*IDGenerator) Generate

func (g *IDGenerator) Generate(exists func(string) bool, length int) (string, int, error)

Generate returns a new ID, possibly bumping the length to 4 on collisions. The returned length indicates the ID length used.

type Store

type Store struct {
	Root string
}

Store handles tick file persistence.

func NewStore

func NewStore(root string) *Store

NewStore creates a store rooted at the .tick directory.

func (*Store) Delete

func (s *Store) Delete(id string) error

Delete removes a tick file by ID.

func (*Store) Ensure

func (s *Store) Ensure() error

Ensure creates the issues directory if needed.

func (*Store) LastActivityForTick added in v0.13.0

func (s *Store) LastActivityForTick(tickID string) (*time.Time, error)

LastActivityForTick returns the maximum activity timestamp for a single tick ID, or nil if the log is missing or has no valid entries for the tick. Implemented via LastActivityForTicks.

func (*Store) LastActivityForTicks added in v0.13.0

func (s *Store) LastActivityForTicks(ids []string) (map[string]*time.Time, error)

LastActivityForTicks scans activity.jsonl once and returns the maximum timestamp found for each of the requested tick IDs. IDs with no (valid) entries are absent from the result map. A missing log file yields an empty map and no error; malformed lines are skipped. Errors are returned only for genuine I/O failures.

func (*Store) List

func (s *Store) List() ([]Tick, error)

List loads all ticks under .tick/issues.

func (*Store) LogActivity added in v0.2.1

func (s *Store) LogActivity(tickID, action, actor, epic string, data map[string]interface{}) error

LogActivity appends an activity entry to the activity log.

func (*Store) Read

func (s *Store) Read(id string) (Tick, error)

Read loads a tick by ID.

func (*Store) ReadActivity added in v0.2.1

func (s *Store) ReadActivity(limit int) ([]Activity, error)

ReadActivity reads the last N activity entries.

func (*Store) Write

func (s *Store) Write(t Tick) error

Write saves a tick to disk using an atomic rename. Automatically logs the activity based on what changed.

func (*Store) WriteAs added in v0.2.1

func (s *Store) WriteAs(t Tick, actor string) error

WriteAs saves a tick and logs activity with the specified actor. If actor is empty, uses t.Owner. Auto-detects the action type.

type Tick

type Tick struct {
	ID          string   `json:"id"`
	Title       string   `json:"title"`
	Description string   `json:"description,omitempty"`
	Notes       string   `json:"notes,omitempty"`
	Status      string   `json:"status"`
	Priority    int      `json:"priority"`
	Type        string   `json:"type"`
	Owner       string   `json:"owner"`
	Labels      []string `json:"labels,omitempty"`
	BlockedBy   []string `json:"blocked_by,omitempty"`
	// After expresses preferred ordering only (work these targets first if
	// feasible); it never gates readiness — that is BlockedBy. Entries are
	// tick IDs; consumers ignore missing or closed targets.
	After  []string `json:"after,omitempty"`
	Parent string   `json:"parent,omitempty"`
	// TargetDate is an optional precise ISO calendar day (e.g. "2026-09-30"):
	// no time-of-day, no timezone, no fuzziness. Absent (empty) is the common
	// case. It feeds the derived overdue / on-track signal (later ticks) and
	// never gates execution.
	TargetDate string `json:"target_date,omitempty"`
	// Role marks a process tick in an epic's EPIC-SKELETON: "review" for the
	// final-review tick, "closeout" for the close-out/retro tick. Empty (the
	// common case) means a normal work tick. Structural, not title-derived —
	// tk graph --json reports missing_process_ticks from this field.
	Role               string     `json:"role,omitempty"`
	DiscoveredFrom     string     `json:"discovered_from,omitempty"`
	AcceptanceCriteria string     `json:"acceptance_criteria,omitempty"`
	DeferUntil         *time.Time `json:"defer_until,omitempty"`
	ExternalRef        string     `json:"external_ref,omitempty"`
	Manual             bool       `json:"manual,omitempty"`
	BaseBranch         string     `json:"base_branch,omitempty"`
	Requires           *string    `json:"requires,omitempty"`
	Awaiting           *string    `json:"awaiting,omitempty"`
	Verdict            *string    `json:"verdict,omitempty"`
	CreatedBy          string     `json:"created_by"`
	CreatedAt          time.Time  `json:"created_at"`
	UpdatedAt          time.Time  `json:"updated_at"`
	StartedAt          *time.Time `json:"started_at,omitempty"`
	ClosedAt           *time.Time `json:"closed_at,omitempty"`
	ClosedReason       string     `json:"closed_reason,omitempty"`
}

Tick represents a single work item on disk.

func (*Tick) ClearAwaiting added in v0.1.18

func (t *Tick) ClearAwaiting()

ClearAwaiting clears the awaiting state and the legacy Manual field.

func (*Tick) GetAwaitingType added in v0.1.18

func (t *Tick) GetAwaitingType() string

GetAwaitingType returns the awaiting type, handling backwards compatibility with Manual. Returns empty string if not awaiting human action.

func (*Tick) HasRequiredGate added in v0.1.18

func (t *Tick) HasRequiredGate() bool

HasRequiredGate returns true if tick has a pre-declared approval gate.

func (*Tick) IsAwaitingHuman added in v0.1.18

func (t *Tick) IsAwaitingHuman() bool

IsAwaitingHuman returns true if tick is waiting for human action. This includes ticks with Awaiting set or legacy Manual flag.

func (*Tick) IsTerminalAwaiting added in v0.1.18

func (t *Tick) IsTerminalAwaiting() bool

IsTerminalAwaiting returns true if approved verdict should close the tick. Terminal awaiting types: approval, review, content, work Non-terminal awaiting types: input, escalation, checkpoint

func (*Tick) Release added in v0.10.0

func (t *Tick) Release()

Release transitions the tick back to open status, clearing the started timestamp. Used when work on a tick is abandoned or failed and needs to be picked up again. Sets Status=open, StartedAt=nil, UpdatedAt=now.

func (*Tick) SetAwaiting added in v0.1.18

func (t *Tick) SetAwaiting(value string)

SetAwaiting sets the awaiting state and clears the legacy Manual field. Pass empty string to clear the awaiting state. This ensures migration from Manual to Awaiting field.

func (*Tick) Start added in v0.10.0

func (t *Tick) Start()

Start transitions the tick to in_progress status and records when work started. Sets Status=in_progress, StartedAt=now, UpdatedAt=now.

func (Tick) Validate

func (t Tick) Validate() error

Validate checks required fields and enum values.

Jump to

Keyboard shortcuts

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