daemon

package
v1.10.0 Latest Latest
Warning

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

Go to latest
Published: Mar 25, 2026 License: MIT Imports: 50 Imported by: 0

Documentation

Overview

Package daemon implements the long-running ttal manager-plane process.

The daemon starts all agent sessions (tmux for Claude Code), bridges messages between Telegram and agent runtimes via a Unix socket, watches JSONL output files to forward agent responses to Telegram, and manages the worker lifecycle through fsnotify-based cleanup and PR watchers. It is managed by launchd and handles all inter-agent and human-agent messaging for every configured team from a single process.

Plane: manager

Index

Constants

View Source
const (
	AdvanceStatusAdvanced   = "advanced"
	AdvanceStatusNeedsLGTM  = "needs_lgtm"
	AdvanceStatusRejected   = "rejected"
	AdvanceStatusError      = "error"
	AdvanceStatusNoPipeline = "no_pipeline"
	AdvanceStatusComplete   = "complete"
)

Advance status constants.

Variables

This section is empty.

Functions

func AskAgent added in v1.10.0

func AskAgent(ctx context.Context, req ask.Request, onEvent func(ask.Event)) error

AskAgent sends an ask request to the daemon and streams NDJSON events via the callback. Blocks until the stream completes (done or error terminal event received).

Uses no total deadline since agent loops run for many minutes. The NDJSON stream keeps the connection alive — idle timeouts aren't a concern. Lifecycle is controlled by context cancellation (e.g. Ctrl-C → SIGINT).

func Breathe added in v1.4.0

func Breathe(req BreatheRequest) error

Breathe sends a breathe request to the daemon, asking it to restart an agent's CC session with a fresh context window and the provided handoff prompt.

func CloseWindow added in v1.8.0

func CloseWindow(req CloseWindowRequest) error

CloseWindow asks the daemon to close a tmux window. Fire-and-forget: errors are returned but callers should treat them as non-fatal.

func Install

func Install() error

Install installs the launchd plist and creates a config template if needed.

func IsRunning

func IsRunning() (bool, int, error)

IsRunning checks whether the daemon is running by inspecting the pid file. Uses fixed path at ~/.ttal/daemon.pid.

func Restart

func Restart() error

Restart performs an atomic daemon restart using launchctl kickstart -k. This kills the running process and lets launchd relaunch it immediately, avoiding the race condition in a Stop+Start (bootout+bootstrap) sequence.

func Run

func Run() error

Run starts the daemon in the foreground. This is what launchd calls. Config-driven: loads all teams from config.toml, no database required.

func Send

func Send(req SendRequest) error

Send connects to the daemon socket and sends a message via HTTP. Returns an error if the daemon is not running or if delivery fails.

func SocketPath

func SocketPath() (string, error)

SocketPath returns the path to the daemon unix socket. TTAL_SOCKET_PATH overrides the default. Delegates to config.SocketPath() to keep a single source of truth.

func Start

func Start() error

Start boots the daemon launchd service.

func Stop

func Stop() error

Stop stops the daemon launchd service.

func Uninstall

func Uninstall() error

Uninstall removes the launchd plist and cleans up daemon files.

Types

type AdvanceRequest added in v1.7.0

type AdvanceRequest struct {
	TaskUUID  string `json:"task_uuid"`
	AgentName string `json:"agent_name"` // from TTAL_AGENT_NAME env in caller session
	Team      string `json:"team"`       // TODO: remove after in-flight request compat window (~2026 Q3)
}

AdvanceRequest is the request body for POST /pipeline/advance.

type AdvanceResponse added in v1.7.0

type AdvanceResponse struct {
	Status   string `json:"status"`
	Message  string `json:"message"`
	Stage    string `json:"stage"`              // new stage name if advanced
	Reviewer string `json:"reviewer,omitempty"` // reviewer agent name if NeedsLGTM
	Assignee string `json:"assignee,omitempty"` // stage assignee role (e.g. "designer", "worker")
	Agent    string `json:"agent,omitempty"`    // resolved agent name (e.g. "mira", "kestrel")
}

AdvanceResponse is the response body for POST /pipeline/advance.

func AdvanceClient added in v1.7.0

func AdvanceClient(req AdvanceRequest) (AdvanceResponse, error)

AdvanceClient sends an advance request to the daemon and blocks until response.

type AskHumanRequest added in v1.3.0

type AskHumanRequest struct {
	Question  string   `json:"question"`
	Options   []string `json:"options,omitempty"`
	AgentName string   `json:"agent_name,omitempty"` // from TTAL_AGENT_NAME
	Session   string   `json:"session,omitempty"`    // from tmux session name
}

AskHumanRequest is the CLI → daemon POST body for POST /ask/human.

type AskHumanResponse added in v1.3.0

type AskHumanResponse struct {
	OK      bool   `json:"ok"`
	Answer  string `json:"answer,omitempty"`
	Skipped bool   `json:"skipped,omitempty"`
	Error   string `json:"error,omitempty"`
}

AskHumanResponse is the daemon → CLI JSON response for /ask/human.

func AskHuman added in v1.3.0

func AskHuman(req AskHumanRequest) (AskHumanResponse, error)

AskHuman sends a question to a human via Telegram and blocks until answered. Returns the response with the human's answer, or Skipped=true on timeout/skip.

type BotCommand

type BotCommand struct {
	Command      string `json:"command"`
	Description  string `json:"description"`
	OriginalName string `json:"-"` // original name before sanitization (for dispatch to agent)
}

BotCommand represents a bot command for the menu.

func AllCommands

func AllCommands(discovered []BotCommand) []BotCommand

AllCommands returns the full command list: static commands + discovered dynamic commands.

func DiscoverCommands

func DiscoverCommands() []BotCommand

DiscoverCommands reads command-category skills from the default skill registry.

type BreatheRequest added in v1.4.0

type BreatheRequest struct {
	Team        string `json:"team,omitempty"`         // defaults to "default"
	Agent       string `json:"agent"`                  // agent name
	Handoff     string `json:"handoff"`                // handoff prompt content
	SessionName string `json:"session_name,omitempty"` // current tmux session name (if known)
}

BreatheRequest asks the daemon to restart an agent with a fresh context window.

type CloseWindowRequest added in v1.8.0

type CloseWindowRequest struct {
	Session string `json:"session"` // tmux session name
	Window  string `json:"window"`  // tmux window name (reviewer agent name from pipelines.toml)
}

CloseWindowRequest asks the daemon to close a tmux window. Used by ttal comment lgtm to auto-close the reviewer's window after LGTM.

type CommentAddRequest added in v1.7.0

type CommentAddRequest struct {
	Target string `json:"target"` // taskwarrior task UUID
	Author string `json:"author"`
	Body   string `json:"body"`
	// Optional PR context for mirroring to remote PR
	ProviderType string `json:"provider_type,omitempty"`
	Owner        string `json:"owner,omitempty"`
	Repo         string `json:"repo,omitempty"`
	PRIndex      int64  `json:"pr_index,omitempty"`
	ProjectAlias string `json:"project_alias,omitempty"` // for per-project GitHub token resolution
}

CommentAddRequest asks the daemon to add a comment to a task.

type CommentAddResponse added in v1.7.0

type CommentAddResponse struct {
	OK    bool   `json:"ok"`
	Error string `json:"error,omitempty"`
	ID    string `json:"id,omitempty"`
	Round int    `json:"round,omitempty"`
}

CommentAddResponse is the daemon's response for a comment add.

func CommentAdd added in v1.7.0

func CommentAdd(req CommentAddRequest) (CommentAddResponse, error)

CommentAdd asks the daemon to add a comment to a task.

type CommentEntry added in v1.7.0

type CommentEntry struct {
	Author    string `json:"author"`
	Body      string `json:"body"`
	Round     int    `json:"round"`
	CreatedAt string `json:"created_at"`
}

CommentEntry is a single comment in a CommentListResponse.

type CommentGetRequest added in v1.7.0

type CommentGetRequest struct {
	Target string `json:"target"` // taskwarrior task UUID
	Round  int    `json:"round"`
}

CommentGetRequest asks the daemon to get comments for a specific round. Team is omitted — daemon injects from mcfg.DefaultTeamName(), consistent with CommentListRequest.

type CommentGetResponse added in v1.7.0

type CommentGetResponse struct {
	OK       bool           `json:"ok"`
	Error    string         `json:"error,omitempty"`
	Comments []CommentEntry `json:"comments,omitempty"`
}

CommentGetResponse is the daemon's response for a comment get.

func CommentGet added in v1.7.0

func CommentGet(req CommentGetRequest) (CommentGetResponse, error)

CommentGet asks the daemon for comments at a specific round.

type CommentListRequest added in v1.7.0

type CommentListRequest struct {
	Target string `json:"target"` // taskwarrior task UUID
}

CommentListRequest asks the daemon to list comments on a task.

type CommentListResponse added in v1.7.0

type CommentListResponse struct {
	OK       bool           `json:"ok"`
	Error    string         `json:"error,omitempty"`
	Comments []CommentEntry `json:"comments,omitempty"`
}

CommentListResponse is the daemon's response for a comment list.

func CommentList added in v1.7.0

func CommentList(req CommentListRequest) (CommentListResponse, error)

CommentList asks the daemon to list comments on a task.

type PRCIFailureDetail added in v1.6.0

type PRCIFailureDetail struct {
	JobName      string `json:"job_name"`
	WorkflowName string `json:"workflow_name"`
	HTMLURL      string `json:"html_url"`
	LogTail      string `json:"log_tail"`
}

PRCIFailureDetail is a single CI failure entry.

type PRCIFailureDetailsResponse added in v1.6.0

type PRCIFailureDetailsResponse struct {
	OK      bool                `json:"ok"`
	Error   string              `json:"error,omitempty"`
	Details []PRCIFailureDetail `json:"details,omitempty"`
}

PRCIFailureDetailsResponse is the daemon's response for GetCIFailureDetails.

func PRGetCIFailureDetails added in v1.6.0

PRGetCIFailureDetails asks the daemon to fetch CI failure details.

type PRCIStatus added in v1.6.0

type PRCIStatus struct {
	Context     string `json:"context"`
	State       string `json:"state"`
	Description string `json:"description"`
	TargetURL   string `json:"target_url"`
}

PRCIStatus is a single CI check status.

type PRCIStatusResponse added in v1.6.0

type PRCIStatusResponse struct {
	OK       bool         `json:"ok"`
	Error    string       `json:"error,omitempty"`
	State    string       `json:"state,omitempty"`
	Statuses []PRCIStatus `json:"statuses,omitempty"`
}

PRCIStatusResponse is the daemon's response for GetCombinedStatus.

func PRGetCombinedStatus added in v1.6.0

func PRGetCombinedStatus(req PRGetCombinedStatusRequest) (PRCIStatusResponse, error)

PRGetCombinedStatus asks the daemon to fetch CI status for a commit.

type PRCheckMergeableRequest added in v1.6.0

type PRCheckMergeableRequest struct {
	ProviderType string `json:"provider_type"`
	Owner        string `json:"owner"`
	Repo         string `json:"repo"`
	Index        int64  `json:"index"`
	ProjectAlias string `json:"project_alias,omitempty"` // for per-project GitHub token resolution
}

PRCheckMergeableRequest asks the daemon to check if a PR is mergeable.

type PRCreateRequest added in v1.6.0

type PRCreateRequest struct {
	ProviderType string `json:"provider_type"` // "forgejo" or "github"
	Owner        string `json:"owner"`
	Repo         string `json:"repo"`
	Head         string `json:"head"` // source branch
	Base         string `json:"base"` // target branch
	Title        string `json:"title"`
	Body         string `json:"body"`
	ProjectAlias string `json:"project_alias,omitempty"` // for per-project GitHub token resolution
}

PRCreateRequest asks the daemon to create a PR via the authenticated provider.

type PRGetCIFailureDetailsRequest added in v1.6.0

type PRGetCIFailureDetailsRequest struct {
	ProviderType string `json:"provider_type"`
	Owner        string `json:"owner"`
	Repo         string `json:"repo"`
	SHA          string `json:"sha"`
	ProjectAlias string `json:"project_alias,omitempty"` // for per-project GitHub token resolution
}

PRGetCIFailureDetailsRequest asks the daemon to fetch CI failure details.

type PRGetCombinedStatusRequest added in v1.6.0

type PRGetCombinedStatusRequest struct {
	ProviderType string `json:"provider_type"`
	Owner        string `json:"owner"`
	Repo         string `json:"repo"`
	SHA          string `json:"sha"`
	ProjectAlias string `json:"project_alias,omitempty"` // for per-project GitHub token resolution
}

PRGetCombinedStatusRequest asks the daemon to fetch CI status for a commit.

type PRGetPRRequest added in v1.6.0

type PRGetPRRequest struct {
	ProviderType string `json:"provider_type"`
	Owner        string `json:"owner"`
	Repo         string `json:"repo"`
	Index        int64  `json:"index"`
	ProjectAlias string `json:"project_alias,omitempty"` // for per-project GitHub token resolution
}

PRGetPRRequest asks the daemon to fetch a PR (for HeadSHA resolution in CI commands).

type PRGetPRResponse added in v1.6.0

type PRGetPRResponse struct {
	OK        bool   `json:"ok"`
	Error     string `json:"error,omitempty"`
	HeadSHA   string `json:"head_sha,omitempty"`
	Merged    bool   `json:"merged,omitempty"`
	Mergeable bool   `json:"mergeable,omitempty"`
	Title     string `json:"title,omitempty"`
}

PRGetPRResponse is the daemon's response for GetPR.

func PRGetPR added in v1.6.0

func PRGetPR(req PRGetPRRequest) (PRGetPRResponse, error)

PRGetPR asks the daemon to fetch a PR.

type PRMergeRequest added in v1.6.0

type PRMergeRequest struct {
	ProviderType string `json:"provider_type"`
	Owner        string `json:"owner"`
	Repo         string `json:"repo"`
	Index        int64  `json:"index"`
	DeleteBranch bool   `json:"delete_branch"`
	ProjectAlias string `json:"project_alias,omitempty"` // for per-project GitHub token resolution
}

PRMergeRequest asks the daemon to squash-merge a PR.

type PRModifyRequest added in v1.6.0

type PRModifyRequest struct {
	ProviderType string `json:"provider_type"`
	Owner        string `json:"owner"`
	Repo         string `json:"repo"`
	Index        int64  `json:"index"`
	Title        string `json:"title,omitempty"`
	Body         string `json:"body,omitempty"`
	ProjectAlias string `json:"project_alias,omitempty"` // for per-project GitHub token resolution
}

PRModifyRequest asks the daemon to edit a PR title/body.

type PRResponse added in v1.6.0

type PRResponse struct {
	OK            bool   `json:"ok"`
	Error         string `json:"error,omitempty"`
	PRURL         string `json:"pr_url,omitempty"`
	PRIndex       int64  `json:"pr_index,omitempty"`
	HeadSHA       string `json:"head_sha,omitempty"`
	AlreadyMerged bool   `json:"already_merged,omitempty"`
}

PRResponse is the daemon's response for PR operations.

func PRCheckMergeable added in v1.6.0

func PRCheckMergeable(req PRCheckMergeableRequest) (PRResponse, error)

PRCheckMergeable asks the daemon to check if a PR is mergeable.

func PRCreate added in v1.6.0

func PRCreate(req PRCreateRequest) (PRResponse, error)

PRCreate asks the daemon to create a PR via the authenticated provider.

func PRMerge added in v1.6.0

func PRMerge(req PRMergeRequest) (PRResponse, error)

PRMerge asks the daemon to squash-merge a PR.

func PRModify added in v1.6.0

func PRModify(req PRModifyRequest) (PRResponse, error)

PRModify asks the daemon to edit a PR title/body.

type SendRequest

type SendRequest struct {
	From    string `json:"from,omitempty"`
	To      string `json:"to,omitempty"`
	Team    string `json:"team,omitempty"`
	Message string `json:"message"`
}

SendRequest is the JSON message sent to the daemon. Direction is determined by which fields are set:

From only:       agent → human via Telegram
To only:         system/hook → agent via tmux
From + To:       agent → agent via tmux with attribution

Team disambiguates when agent names collide across teams.

type SendResponse

type SendResponse struct {
	OK    bool   `json:"ok"`
	Error string `json:"error,omitempty"`
}

SendResponse is the JSON reply from the daemon.

type StatusResponse

type StatusResponse struct {
	OK     bool                 `json:"ok"`
	Agents []status.AgentStatus `json:"agents,omitempty"`
	Error  string               `json:"error,omitempty"`
}

StatusResponse returns agent status data.

func QueryStatus

func QueryStatus(team, agent string) (*StatusResponse, error)

QueryStatus connects to the daemon and queries agent status via HTTP.

type StatusUpdateRequest

type StatusUpdateRequest struct {
	Type                string  `json:"type"`                  // "statusUpdate"
	Team                string  `json:"team,omitempty"`        // team name (defaults to "default")
	Agent               string  `json:"agent"`                 // agent name
	ContextUsedPct      float64 `json:"context_used_pct"`      // percentage of context used
	ContextRemainingPct float64 `json:"context_remaining_pct"` // percentage remaining
	ModelID             string  `json:"model_id"`              // model identifier
	SessionID           string  `json:"session_id"`            // session identifier
}

StatusUpdateRequest writes agent context status to the daemon. Wire format: {"type":"statusUpdate","agent":"kestrel","context_used_pct":45.2,...}

type TaskCompleteRequest added in v1.0.0

type TaskCompleteRequest struct {
	Type     string `json:"type"` // "taskComplete"
	TaskUUID string `json:"task_uuid"`
	Team     string `json:"team,omitempty"`     // defaults to "default"
	Spawner  string `json:"spawner,omitempty"`  // "team:agent", optional
	Desc     string `json:"desc,omitempty"`     // task description for the notification message
	PRID     string `json:"pr_id,omitempty"`    // PR number for the notification message
	PRTitle  string `json:"pr_title,omitempty"` // PR title (preferred over Desc for notifications)
}

TaskCompleteRequest notifies the daemon that a task has been marked done. Wire format: {"type":"taskComplete","task_uuid":"...","team":"default",...}

type UsageData added in v1.0.0

type UsageData struct {
	SessionUsage   *float64  `json:"sessionUsage,omitempty"`
	SessionResetAt string    `json:"sessionResetAt,omitempty"`
	WeeklyUsage    *float64  `json:"weeklyUsage,omitempty"`
	WeeklyResetAt  string    `json:"weeklyResetAt,omitempty"`
	FetchedAt      time.Time `json:"fetchedAt"`
	Error          string    `json:"error,omitempty"`
}

UsageData holds the parsed Claude.ai usage response.

Jump to

Keyboard shortcuts

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