daemon

package
v0.5.7 Latest Latest
Warning

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

Go to latest
Published: Jul 28, 2026 License: AGPL-3.0 Imports: 85 Imported by: 0

Documentation

Index

Constants

View Source
const (
	WorkflowStatusRunning       = "running"
	WorkflowStatusPaused        = "paused"
	WorkflowStatusBlocked       = "blocked"
	WorkflowStatusBudgetLimited = "budget_limited"
	WorkflowStatusComplete      = "complete"
)

Workflow run statuses. A run is "running" while executeWorkflow owns it, "paused" when interrupted (user cancel or daemon death — both resume the same way), "blocked" when a step error was routed or aborted the run, "budget_limited" once the budget tripped, and "complete" on normal end (completed runs are cleared from the thread rather than kept around).

View Source
const CurrentConfigVersion = 1

CurrentConfigVersion is the expected version number for settings.json files. Bump this when the config format changes in a breaking way.

View Source
const FeatureReadAgentsMD = "read_agents_md"

FeatureReadAgentsMD enables loading AGENTS.md files into the system prompt.

View Source
const FeatureReadClaudeMD = "read_claude_md"

FeatureReadClaudeMD enables loading CLAUDE.md files into the system prompt.

View Source
const FeatureToolOrchestrator = "tool_orchestrator"

FeatureToolOrchestrator is the feature flag name for the tool orchestrator mode.

View Source
const StatusOKRecord = "ok"

StatusOKRecord is the job_status value marking a successful run record.

Variables

View Source
var (
	ErrStreamIdleTimeout = llm.ErrStreamIdleTimeout
	ErrThinkingStall     = llm.ErrThinkingStall
)

ErrStreamIdleTimeout / ErrThinkingStall — re-exported from llm so retry loops can `errors.Is(err, ErrThinkingStall)` without importing llm.

View Source
var ErrMaxTokens = errors.New("max_tokens")

ErrMaxTokens is returned when the LLM response was truncated due to the output token limit.

View Source
var ErrThreadBusy = errors.New("thread busy")

ErrThreadBusy is returned by Attach when the requested thread is already open in another connection (exclusive single-writer ownership). Callers can retry later (the owner may disconnect) or restore/attach a different thread.

View Source
var ErrThreadNotFound = errors.New("thread not found")

ErrThreadNotFound is returned by Attach when the daemon has no persisted record for the requested ID (e.g. it was lost in a daemon restart before its first flush). Callers should orphan the thread rather than retry.

View Source
var ErrVersionMismatch = errors.New("version mismatch")

ErrVersionMismatch is returned by Connect/Attach when the daemon refused the thread because the client and daemon builds differ. The wrapped message carries both versions and the remediation command.

Functions

func AllowedWritePaths

func AllowedWritePaths(cwd string) []string

AllowedWritePaths returns the paths the sandbox permits writing to, given the working directory. Useful for user-facing descriptions.

func CloseIdleHTTPConnections

func CloseIdleHTTPConnections()

CloseIdleHTTPConnections drops all pooled connections in the shared transport. Called between retries in AgentRunner.Send and streamWithRetry so a poisoned conn doesn't get reused on the next attempt.

func ExcludeTools

func ExcludeTools(tools []llm.ToolParam, names ...string) []llm.ToolParam

ExcludeTools removes tools with the given names from a tool list.

func FilterToolSchemas

func FilterToolSchemas(allowed []string) []llm.ToolParam

FilterToolSchemas returns only the tool schemas whose names appear in the allowed list, using the package-level default timeout bounds. Threads that want the schemas to reflect their configured tool_timeouts should use FilterToolSchemasWithBounds instead. If allowed is nil, returns all tools.

func FilterToolSchemasWithBounds

func FilterToolSchemasWithBounds(allowed []string, def, max time.Duration) []llm.ToolParam

FilterToolSchemasWithBounds is the bounds-aware variant of FilterToolSchemas. The bash/glob_files timeout descriptions are rendered against the given floor and cap so the LLM sees the actual, configurable window instead of the hard-coded defaults.

func FormatEditDiff

func FormatEditDiff(oldStr, newStr string, lineOffset int) string

FormatEditDiff builds a structured side-by-side diff by running the system `diff -U3` command on the old and new strings and parsing its unified output. The result uses tagged rows consumed by renderDiffDetail in chat.go:

"H <text>\n"                  — header line (summary)
"C <leftN> <rightN> <text>\n" — context line present on both sides
"R <leftN> <text>\n"          — removed line (left side only)
"A <rightN> <text>\n"         — added line (right side only)

lineOffset is the 0-based line index of oldStr's first line within the real file, computed before the write so the numbers reflect actual file positions.

func GetToolSchema

func GetToolSchema(name string) *llm.ToolParam

GetToolSchema returns a single tool schema by name, or nil if not found.

func IsReadOnlyTool

func IsReadOnlyTool(name string) bool

IsReadOnlyTool returns true if the tool name is read-only (safe for planning).

func LandlockExecMain

func LandlockExecMain(argv []string)

LandlockExecMain is the entry point for the hidden `vixd landlock-exec` subcommand. cmd/vixd/main.go dispatches to it on argv[1]=="landlock-exec" before any normal startup happens — the helper is fork-light: no daemon, no telemetry, no socket. It applies Landlock to itself, then execve's the rest of argv.

Failures are fatal and printed to stderr (which the parent's exec.Cmd captures and surfaces back to the LLM via the bash tool).

func LoadCustomAgents

func LoadCustomAgents(dir string) map[string]SubagentConfig

LoadCustomAgents parses .vix/agents/*.md files into SubagentConfig entries.

func LogError

func LogError(format string, args ...any)

func LogInfo

func LogInfo(format string, args ...any)

func LogLLMCall

func LogLLMCall(
	model string,
	system []llm.SystemBlock,
	messages []llm.MessageParam,
	tools []llm.ToolParam,
	response *llm.Message,
)

LogLLMCall logs an LLM call and response to {logDir}/{datetime}.json using the provider-neutral types so every adapter produces the same log shape.

func LogWarn

func LogWarn(format string, args ...any)

func PatchSpawnAgentDescription

func PatchSpawnAgentDescription(tools []llm.ToolParam, customAgents map[string]SubagentConfig)

PatchSpawnAgentDescription updates the spawn_agent tool description in the given tool list based entirely on the loaded agent definitions.

func PersistAllowedDirectory

func PersistAllowedDirectory(configPath string, dirs []string) error

PersistAllowedDirectory appends directories to the allowed_directories list in a settings.json file. Uses map[string]any for round-trip safety so that unknown fields are preserved.

func ProtectDaemon

func ProtectDaemon()

ProtectDaemon lowers the current process's OOM score so the kernel prefers killing child processes (which should be set to 1000) first.

func ReadOnlyToolSchemas

func ReadOnlyToolSchemas() []llm.ToolParam

ReadOnlyToolSchemas returns only the read-only tool schemas (for plan exploration).

func RegisterBuiltinHandlers

func RegisterBuiltinHandlers(s *Server)

RegisterBuiltinHandlers registers ping, init, and force_init handlers.

func RegisterCredentialHandlers added in v0.4.3

func RegisterCredentialHandlers(s *Server)

RegisterCredentialHandlers wires the daemon-owned credential RPCs.

func RegisterLocalProviderHandlers added in v0.5.0

func RegisterLocalProviderHandlers(s *Server)

RegisterLocalProviderHandlers wires the local-provider discovery RPC.

func RegisterToolHandlers

func RegisterToolHandlers(s *Server)

func SandboxAvailable

func SandboxAvailable() bool

SandboxAvailable reports whether a sandbox mechanism was detected.

func SandboxName

func SandboxName() string

SandboxName returns a human-readable name for the active sandbox.

func SetClientVersion added in v0.5.0

func SetClientVersion(v string)

SetClientVersion records the process-wide client build version used by all subsequently created ThreadClients. Call once at startup, before any connection is opened.

func SetLLMLogDir

func SetLLMLogDir(dir string)

SetLLMLogDir sets the directory for LLM call logs.

func SetTmpLogDir

func SetTmpLogDir(dir string)

SetTmpLogDir sets the directory used for daemon log files. Empty string restores the os.TempDir() default.

func SkillToolSchema added in v0.4.1

func SkillToolSchema() llm.ToolParam

SkillToolSchema returns the neutral schema for the `skill` tool, which loads a named skill's full instructions (and a listing of its bundled files) on demand — the second level of progressive disclosure. It is only added to a thread's tool list when at least one skill is loaded.

func StartPprofServer

func StartPprofServer(ctx context.Context, port int)

StartPprofServer starts a pprof HTTP server on 127.0.0.1:<port>. Routes are registered by the net/http/pprof side-effect import. Blocks until ctx is cancelled; call in a goroutine.

func StartWebServer

func StartWebServer(ctx context.Context, s *Server, port int)

StartWebServer starts the local web UI HTTP server on 127.0.0.1:<port>. It blocks until srv.ListenAndServe returns (call in a goroutine).

func SummarizeToolInput

func SummarizeToolInput(name string, input map[string]any) string

SummarizeToolInput returns a one-line human summary of tool input.

func TmpLogDir

func TmpLogDir() string

TmpLogDir returns the configured daemon log directory, or os.TempDir() if SetTmpLogDir has not been called.

func ToolSchemas

func ToolSchemas() []llm.ToolParam

ToolSchemas returns the tool definitions in the provider-neutral llm.ToolParam shape, using the package-level default timeout bounds. Threads that want bounds-aware descriptions should use ToolSchemasWithBounds instead.

func ToolSchemasWithBounds

func ToolSchemasWithBounds(def, max time.Duration) []llm.ToolParam

ToolSchemasWithBounds returns the neutral tool definitions with the bash/glob_files timeout descriptions rendered against the given floor and cap.

Passing zero for either value falls back to the package-level defaults.

func VfsEdit

func VfsEdit(cwd string, allowedDirs []string, homeVixDir, path, oldString, newString string, keepComments bool) (message string, lineOffset int, err error)

VfsEdit performs an edit on a VFS-managed file. The model supplies oldString in the minified representation (as returned by read_minified_file). VfsEdit minifies the current file content while keeping a position map, matches oldString against the minified text, projects the matched span back onto exact byte offsets in the original source, and splices newString into those bytes — touching only the matched region and leaving all surrounding whitespace, indentation, comments, and formatting untouched. The on-disk file is never rewritten in minified form.

homeVixDir is retained for signature compatibility with the other Vfs helpers; the splice path needs no formatter.

Unlike editFileImpl, there is no fallback on failure — errors are surfaced directly (callers fall back to editFileImpl on errVFSUnsupported).

func VfsRead

func VfsRead(cwd string, allowedDirs []string, path string, offset, limit *int, keepComments bool) (string, error)

VfsRead reads a file, optionally extracts a line range, then minifies via Tree-sitter. offset/limit are 1-based line numbers. nil means whole file. Falls back to returning raw content if minification is not supported.

func VfsWrite

func VfsWrite(cwd string, allowedDirs []string, homeVixDir, path, content string) (string, error)

VfsWrite writes minified content to a VFS-managed file, then runs the formatter to restore valid source. Creates parent directories if needed.

The caller is expected to provide content in the same minified form that read_minified_file returns. After writing, the language's formatter expands it back into properly formatted code.

Unlike writeFileImpl, there is no fallback on failure — errors are surfaced directly.

func WorkflowSignalToolSchema added in v0.4.5

func WorkflowSignalToolSchema() llm.ToolParam

WorkflowSignalToolSchema returns the workflow_signal tool definition. It is appended to a workflow agent step's tool list when the step declares "signal": true, and is intercepted by the workflow engine rather than the thread tool dispatcher: the agent uses it to declare the run complete or blocked, and the workflow's next_steps route on $(workflow.signal.status).

Types

type AgentRunner

type AgentRunner struct {
	Config   SubagentConfig
	LLM      LLM
	Messages []llm.MessageParam
	System   []llm.SystemBlock
	Tools    []llm.ToolParam
	MaxTurns int

	// ToolTimeouts carries the parent thread's configured tool-call floor/cap
	// so this runner's tool dispatches honour the same settings.json bounds as
	// the main agent. Populated at construction in NewAgentRunner; zero values
	// fall back to package defaults in the dispatcher.
	ToolTimeouts ToolTimeouts

	// Per-Send() accumulated usage (reset at start of each Send call)
	LastInputTokens         int64
	LastOutputTokens        int64
	LastCacheCreationTokens int64
	LastCacheReadTokens     int64
	LastElapsed             time.Duration
	// contains filtered or unexported fields
}

AgentRunner is a persistent agent with maintained history.

func NewAgentRunner

func NewAgentRunner(config SubagentConfig, cred config.Credential, parentModel, cwd string, plugins PluginSource, toolTimeouts ToolTimeouts, searchDirs ...string) (*AgentRunner, error)

NewAgentRunner creates a persistent agent for a workflow. searchDirs is the ordered set of .vix root directories to resolve system prompt includes from, in precedence order (highest first). toolTimeouts carries the parent thread's tool_timeouts bounds so the runner's tool dispatches honour the same settings.json floor/cap.

func (*AgentRunner) Clone

func (a *AgentRunner) Clone(cred config.Credential) (*AgentRunner, error)

Clone creates a deep copy of the agent runner (for fork_from).

func (*AgentRunner) Send

func (a *AgentRunner) Send(
	ctx context.Context,
	userPrompt string,
	executeTool func(name string, params map[string]any, cwd string) (*ToolResult, error),
	streamCallback func(delta string),
	cwd string,
	hooks *TurnHooks,
) (string, error)

Send sends a message to the agent, runs the LLM loop with tool dispatch, and returns the text output. Conversation history is preserved across calls.

type BackgroundTask

type BackgroundTask struct {
	ID     string
	Name   string
	Done   chan struct{}
	Result *SubagentResult
	// contains filtered or unexported fields
}

BackgroundTask tracks an in-flight or completed background subagent.

type BackgroundTaskRegistry

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

BackgroundTaskRegistry manages background subagent tasks.

func (*BackgroundTaskRegistry) Cancel

func (r *BackgroundTaskRegistry) Cancel(id string)

Cancel cancels a single in-flight background task by ID. No-op if the task is unknown or already finished.

func (*BackgroundTaskRegistry) CancelAll

func (r *BackgroundTaskRegistry) CancelAll()

CancelAll cancels every in-flight background task in the registry. Completed tasks are unaffected (their cancel funcs are no-ops).

func (*BackgroundTaskRegistry) Load

func (*BackgroundTaskRegistry) SpawnBackground

func (r *BackgroundTaskRegistry) SpawnBackground(
	ctx context.Context,
	config SubagentConfig,
	prompt string,
	cred vixconfig.Credential,
	parentModel string,
	plugins PluginSource,
	executeTool func(name string, params map[string]any, cwd string) (*ToolResult, error),
	cwd string,
	toolTimeoutDefault time.Duration,
	toolTimeoutMax time.Duration,
	searchDirs ...string,
) string

SpawnBackground launches a subagent in a goroutine and returns a task ID. The task gets its own cancellable context derived from the parent ctx, so it can be cancelled individually (via Cancel) or in bulk (via CancelAll) without affecting the parent.

func (*BackgroundTaskRegistry) Store

func (r *BackgroundTaskRegistry) Store(task *BackgroundTask)

func (*BackgroundTaskRegistry) WaitForTask

func (r *BackgroundTaskRegistry) WaitForTask(ctx context.Context, id string, timeout time.Duration) (*SubagentResult, error)

WaitForTask blocks until the task completes or the context is cancelled.

type BashJob

type BashJob struct {
	ID      string
	PID     int
	PGID    int
	LogPath string
	RCPath  string
	PIDPath string

	Done chan struct{} // closed after the reaper goroutine writes the rc file
	// contains filtered or unexported fields
}

BashJob is a single detached bash command spawned via bash tool `background: true`. The daemon keeps ownership of log/rc file handles and a cancel hook so the whole process group can be SIGKILLed at thread shutdown (or when the job's own deadline fires). The LLM polls via ordinary `bash` calls against LogPath / RCPath — no new tool surface needed.

type BashJobRegistry

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

BashJobRegistry owns the bash-tool background jobs for one thread. It does not cross threads — a thread shutdown reaps its own jobs via KillAll(). sync.Map because writes (Store on spawn, Delete on reap) are both O(jobs ever spawned) and reads are rare (only iteration in KillAll).

func (*BashJobRegistry) Delete

func (r *BashJobRegistry) Delete(id string)

func (*BashJobRegistry) KillAll

func (r *BashJobRegistry) KillAll()

KillAll cancels every job in the registry and waits up to 2s per job for its reaper goroutine to finish. Called from server.go when a thread ends.

func (*BashJobRegistry) Load

func (r *BashJobRegistry) Load(id string) (*BashJob, bool)

func (*BashJobRegistry) Store

func (r *BashJobRegistry) Store(j *BashJob)

type BashStepTimeouts

type BashStepTimeouts struct {
	Default time.Duration
	Max     time.Duration
}

BashStepTimeouts is the resolved form of the bash_step_timeouts block, consumed by resolveBashStepTimeout when scheduling workflow bash steps.

type BudgetState added in v0.4.5

type BudgetState struct {
	TokensUsed     int64 `json:"tokens_used"`
	ElapsedSeconds int64 `json:"elapsed_seconds"`
}

BudgetState is the live usage accumulated by a run, persisted with it.

type Client

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

Client communicates with the vix daemon over a Unix socket. Used for one-shot commands (ping, brain context, etc.)

func NewClient

func NewClient(path string) *Client

NewClient creates a new daemon client.

func (*Client) AuthorizeMCP added in v0.5.7

func (c *Client) AuthorizeMCP(name string) (string, error)

AuthorizeMCP starts the interactive OAuth flow for an MCP server and returns the authorization URL to open in a browser. The exchange completes asynchronously in the daemon; poll ListMCPServers for the resulting auth state.

func (*Client) CreateMessageThread added in v0.5.7

func (c *Client) CreateMessageThread(spec json.RawMessage) (string, error)

CreateMessageThread asks the daemon to create a Vix-initiated message thread from spec (a raw MessageThreadSpec JSON object). Returns the new thread id. Backs `vix thread create`.

func (*Client) DaemonVersion added in v0.5.0

func (c *Client) DaemonVersion() (string, error)

DaemonVersion returns the running daemon's build version, as reported by the ping handler. Daemons predating the version field report "" — callers must treat that as a mismatch with any released client.

func (*Client) DeleteProviderMethodKey added in v0.4.3

func (c *Client) DeleteProviderMethodKey(provider, methodID string) (CredStatus, error)

DeleteProviderMethodKey removes a provider method's stored key daemon-side.

func (*Client) DismissThread added in v0.5.7

func (c *Client) DismissThread(cwd, configDir, id string) error

DismissThread archives a persisted thread record (open/ → closed/) without

func (*Client) ExecuteTool

func (c *Client) ExecuteTool(name string, params map[string]any, cwd string) (*ToolResult, error)

ExecuteTool sends a tool execution request to the daemon.

func (*Client) ExecuteToolConfirmed

func (c *Client) ExecuteToolConfirmed(name string, params map[string]any, cwd string) (*ToolResult, error)

ExecuteToolConfirmed re-sends a tool request with the confirmed flag.

func (*Client) ListHooks added in v0.5.3

func (c *Client) ListHooks() ([]protocol.HookSummary, error)

ListHooks returns the lifecycle hooks (enabled and disabled) for the Jobs & Triggers tab.

func (*Client) ListJobs added in v0.5.3

func (c *Client) ListJobs() ([]protocol.JobSummary, error)

ListJobs returns the scheduled jobs (enabled and disabled) for the Jobs & Triggers tab. Jobs are daemon-global, so no cwd filter is applied.

func (*Client) ListMCPServers added in v0.5.6

func (c *Client) ListMCPServers() ([]protocol.MCPServerSummary, error)

ListMCPServers returns the configured MCP servers (with status, type, and tool count) for the MCP tab. MCP config is home-only, so no cwd filter is applied.

func (*Client) ListThreadDirs added in v0.5.7

func (c *Client) ListThreadDirs(cwd, configDir string) ([]protocol.DirUsage, error)

ListThreadDirs returns the working directories used by open user threads, ranked by thread count (then recency), for the welcome screen's recent- directories list. Unlike ListThreads it is not cwd-scoped.

func (*Client) ListThreads added in v0.5.7

func (c *Client) ListThreads(cwd, configDir string) ([]protocol.ThreadSummary, error)

ListThreads returns the persisted open threads for cwd, so the TUI can reopen them on launch. Threads are stored globally (~/.vix/threads) and filtered by cwd daemon-side.

func (*Client) LocalProviderStatus added in v0.5.0

func (c *Client) LocalProviderStatus() (map[string]LocalProviderState, error)

LocalProviderStatus probes the local providers daemon-side and returns the per-provider reachability + live model lists, keyed by provider id.

func (*Client) LogoutMCP added in v0.5.7

func (c *Client) LogoutMCP(name string) error

LogoutMCP deletes the stored OAuth token for an MCP server.

func (*Client) Ping

func (c *Client) Ping() bool

Ping checks if the daemon is running.

func (*Client) ProviderCredStatus added in v0.4.3

func (c *Client) ProviderCredStatus() (CredStatus, error)

ProviderCredStatus reads the credential status of all providers.

func (*Client) RunJob added in v0.5.1

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

RunJob asks the daemon to fire the job with the given id immediately, out of band from its schedule. Returns the run's thread id. Backs `vix job run`.

func (*Client) SetAuthToken

func (c *Client) SetAuthToken(token string)

SetAuthToken stores the shared-secret token used to authenticate every request. Must be called before any RPC if the daemon was started with -auth-token-path.

func (*Client) SetHookEnabled added in v0.5.3

func (c *Client) SetHookEnabled(id string, enabled bool) error

SetHookEnabled enables or disables a lifecycle hook by id (Space toggle in the Jobs & Triggers tab).

func (*Client) SetJobEnabled added in v0.5.3

func (c *Client) SetJobEnabled(id string, enabled bool) error

SetJobEnabled enables or disables a scheduled job by id (Space toggle in the Jobs & Triggers tab).

func (*Client) SetMCPEnabled added in v0.5.6

func (c *Client) SetMCPEnabled(name string, enabled bool) error

SetMCPEnabled enables or disables an MCP server by name (Space toggle in the MCP tab).

func (*Client) SetProviderAuthDefault added in v0.4.3

func (c *Client) SetProviderAuthDefault(provider, methodID string) (CredStatus, error)

SetProviderAuthDefault sets (methodID non-empty) or clears (empty) a provider's default credential method daemon-side.

func (*Client) StopDaemon added in v0.5.0

func (c *Client) StopDaemon() error

StopDaemon asks the daemon to perform a coordinated shutdown (every attached vix instance is told to quit, then the daemon exits). Exempt from the version gate so it works across mismatched builds.

func (*Client) StoreProviderMethodKey added in v0.4.3

func (c *Client) StoreProviderMethodKey(provider, methodID, key, baseURL string) (CredStatus, error)

StoreProviderMethodKey stores a provider method's key (and optional base URL) daemon-side and returns the refreshed status.

func (*Client) TriggerHook added in v0.5.1

func (c *Client) TriggerHook(id string) (threadID, fireID string, err error)

TriggerHook asks the daemon to fire the hook with the given id immediately, out of band from its event. Returns the run's thread id (empty for command hooks, which have no thread) and the fire id. Backs `vix hook trigger`.

func (*Client) ValidateAttachment added in v0.5.6

func (c *Client) ValidateAttachment(threadID, path string) (status, reason string, err error)

ValidateAttachment asks the daemon whether a user-attached file (text or PDF) can be turned into prompt text for the given thread. It returns a status — "ok" (add a chip), "invalid" (alert + drop), or "error" — and a human-readable reason.

type Compaction added in v0.4.0

type Compaction struct {
	Threshold      float64 // (0,1]; default 0.8
	Auto           bool    // default true
	KeepLastNTurns int     // -1 = use ratio; >0 = keep exactly N trailing turns
	KeepRatio      float64 // default 0.25; used when KeepLastNTurns <= 0
}

Compaction is the resolved (validated, defaulted) form of the `compaction` block, stored on ProjectConfig and consumed by the auto-compaction logic and the /compact command in thread.go.

type CredStatus added in v0.4.3

type CredStatus struct {
	Backend   string
	Providers map[string]config.ProviderAuthStatus
}

CredStatus bundles the per-provider credential statuses with the active storage backend ("keyring" | "file").

type HandlerFunc

type HandlerFunc func(data map[string]any) (map[string]any, error)

HandlerFunc is the type for daemon request handlers.

type InputDef

type InputDef = wf.InputDef

The workflow data model (definitions, steps, budget) and its loader/validator live in the standalone internal/workflow package so the daemon, jobs, and hooks packages can all share one definition without import cycles. These aliases re-expose the moved types under their historical daemon names so the large execution engine below compiles unchanged. WorkflowBudget is aliased here too (its struct moved out of workflow_state.go).

type InstanceClient added in v0.4.2

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

InstanceClient is a long-lived control connection that registers the running vix process as an "instance" with the daemon. The daemon counts these to know how many vix processes are attached (independently of threads). The client sends a single instance.register command and then holds the connection open for the process lifetime; closing it (clean exit or process death) tells the daemon this instance is gone.

func RegisterInstance added in v0.4.2

func RegisterInstance(socketPath, authToken, mode string) (*InstanceClient, error)

RegisterInstance dials the daemon and registers this process as an attached instance, returning a handle whose Close ends the registration. mode is advisory ("tui" | "headless"). On any failure it returns an error and the caller may simply proceed without registration — the count is observability only (web UI vitals, logging).

func (*InstanceClient) Close added in v0.4.2

func (ic *InstanceClient) Close()

Close ends the instance registration, signalling the daemon that this process has detached.

func (*InstanceClient) ReadEvent added in v0.5.6

func (ic *InstanceClient) ReadEvent() (protocol.ThreadEvent, error)

ReadEvent blocks until the daemon pushes the next process-level event (threads_changed, jobs_changed, quit) on the control channel, decoding one newline-delimited ThreadEvent frame. It returns an error when the connection closes, which the caller treats as the end of the control stream.

type LLM

type LLM = llm.Client

LLM is the daemon-side alias for llm.Client. All callers use this type; the underlying adapter is provider-dependent (Anthropic, OpenAI, ...).

type LocalModel added in v0.5.0

type LocalModel struct {
	Spec        string `json:"spec"`         // prefixed, e.g. "ollama/qwen3:8b"
	DisplayName string `json:"display_name"` // bare server-side id
	// ContextWindow is the serving context in tokens (Ollama: the model's
	// trained context_length from /api/show; llama.cpp: n_ctx from /props).
	// 0 means unknown.
	ContextWindow int64 `json:"context_window,omitempty"`
	// Loaded marks a model currently held in memory (Ollama /api/ps).
	Loaded bool `json:"loaded,omitempty"`
}

LocalModel is one live-discovered model on a local provider's server.

type LocalProviderState added in v0.5.0

type LocalProviderState struct {
	Provider  string       `json:"provider"`
	BaseURL   string       `json:"base_url"`
	Reachable bool         `json:"reachable"`
	Models    []LocalModel `json:"models"`
}

LocalProviderState is the probe result for one local provider.

type MessageThreadSpec added in v0.5.7

type MessageThreadSpec struct {
	// Message is the assistant text shown to the user. Required unless
	// MessageFile is set (exactly one of the two).
	Message string `json:"message"`
	// MessageFile is an absolute path whose contents become the message text.
	// Set this instead of Message to avoid encoding multi-line content in JSON
	// (e.g. a hook delivering markdown). The file must exist and be non-empty.
	MessageFile string `json:"message_file,omitempty"`
	// CWD is the project the conversation is scoped to. Required; must be an
	// existing directory. The thread surfaces in any TUI launched there.
	CWD string `json:"cwd"`
	// Title is the Threads-tab display title. Optional; empty falls back to
	// the first message.
	Title string `json:"title,omitempty"`
	// Unread controls the unread dot. Optional; defaults to true.
	Unread *bool `json:"unread,omitempty"`
	// Trigger records provenance (e.g. the hook that created it). Optional.
	Trigger *protocol.TriggerInfo `json:"trigger,omitempty"`
}

MessageThreadSpec is the public, stable schema for creating a Vix-initiated message thread — a one-message conversation that lands in the Threads tab under "Vix-initiated". It is the payload of the message.create RPC and the `vix thread create` CLI. Deliberately a small surface (not the internal threadRecord) so the on-disk format can evolve independently.

type PluginConfig

type PluginConfig = llm.PluginConfig

PluginConfig is the daemon-side alias for llm.PluginConfig. Kept as a type alias so the existing plugin loader code (which produces this type) works unchanged.

type PluginSource added in v0.5.0

type PluginSource = llm.PluginSource

PluginSource is the daemon-side alias for llm.PluginSource — the callback NewFromModel invokes at client-construction time to obtain the plugin config for a specific provider/model/credential.

func NewPluginSource added in v0.5.0

func NewPluginSource(dirs []string, version string) PluginSource

NewPluginSource returns a PluginSource that discovers and runs the executable plugin files in dirs every time an LLM client is built. Each plugin receives the target provider, model, and credential metadata (never the secret itself) as a JSON object on stdin — {"version", "model", "provider", "credential_source"} — so a plugin can emit "{}" for providers/credentials it does not target.

type ProjectConfig

type ProjectConfig struct {
	Agent              string
	AllowedDirectories []string
	DenyPaths          []string
	// DenyPathsRel holds the raw (tilde-expanded) relative deny_list.paths
	// entries, preserved so the thread can additionally resolve them against
	// the working directory. See the resolution loop in LoadProjectConfig and
	// the seeding logic in Thread for why both interpretations are unioned.
	DenyPathsRel     []string
	DenyURLs         []string
	Features         map[string]bool
	ToolTimeouts     ToolTimeouts
	BashStepTimeouts BashStepTimeouts
	Compaction       Compaction
	MCPServers       []mcp.ServerConfig
}

ProjectConfig holds parsed values from settings.json.

func LoadProjectConfig

func LoadProjectConfig(configPaths ...string) ProjectConfig

LoadProjectConfig reads config from one or more paths (applied in order, later overrides earlier) and returns agent name, workflows, and features.

func (ProjectConfig) HasFeature

func (c ProjectConfig) HasFeature(name string) bool

HasFeature returns whether the named feature flag is enabled.

type ProviderCredEntry added in v0.4.3

type ProviderCredEntry struct {
	Provider string                    `json:"provider"`
	Status   config.ProviderAuthStatus `json:"status"`
}

ProviderCredEntry pairs a provider id with its credential status. Defined in the daemon package so the handler (producer) and Client method (consumer) share the wire shape without a protocol-package dependency.

type Server

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

Server is the Unix socket daemon server with a handler registry.

func NewServer

func NewServer(sockPath string, cred config.Credential, threadID, model string, daemonConfig *config.DaemonConfig, plugins PluginSource) *Server

NewServer creates a new daemon server.

func (*Server) BeginMCPAuth added in v0.5.7

func (s *Server) BeginMCPAuth(name string) (string, error)

BeginMCPAuth starts the interactive OAuth flow for the named server and returns the authorization URL to open in a browser.

When the mission-control web server is running (webPort > 0), the flow uses its fixed callback route (/mcp/oauth/callback) — a single stable redirect URI that works for every OAuth MCP server. Otherwise it falls back to a self-hosted ephemeral loopback listener. Either way the exchange completes asynchronously and the daemon broadcasts event.mcp_changed on success.

func (*Server) BroadcastEvent added in v0.4.3

func (s *Server) BroadcastEvent(ev protocol.ThreadEvent)

BroadcastEvent pushes ev onto every live thread's event channel (best-effort, non-blocking). Used to reach all attached TUIs at once — e.g. the coordinated quit-all that follows an in-app update.

func (*Server) BroadcastToInstances added in v0.5.6

func (s *Server) BroadcastToInstances(ev protocol.ThreadEvent)

BroadcastToInstances pushes ev to every live instance control connection (best-effort, non-blocking, once per window). Process-level events (threads_changed, jobs_changed, quit) travel this path so they reach every window exactly once — including a launch-time draft that has no thread yet.

func (*Server) CreateJob added in v0.5.1

func (s *Server) CreateJob(spec jobs.Spec) (string, error)

CreateJob persists and schedules a new job from the web UI. It assigns a unique id derived from the job name when the spec doesn't carry one, then validates + writes via the scheduler and notifies web subscribers so the Jobs tab refreshes. Returns the assigned id.

func (*Server) DefaultCWD added in v0.5.1

func (s *Server) DefaultCWD() string

DefaultCWD returns vixd's own working directory, offered to the web UI as the default working directory for newly created jobs.

func (*Server) EnableHooks added in v0.5.1

func (s *Server) EnableHooks()

EnableHooks builds the lifecycle-hooks registry from ~/.vix/hooks. Safe to call once before ListenAndServe; the config watcher hot-reloads the spec directory. No-op when the home directory is unavailable.

func (*Server) EnableJobScheduler added in v0.5.0

func (s *Server) EnableJobScheduler()

EnableJobScheduler constructs the scheduled-jobs engine over the global job store (~/.vix/jobs). Must be called before ListenAndServe, which starts the timer loop; the config watcher hot-reloads the spec directory. No-op when the home directory is unavailable.

func (*Server) GetHandler

func (s *Server) GetHandler(command string) HandlerFunc

GetHandler returns the handler for the given command, or nil.

func (*Server) HookSummaries added in v0.5.3

func (s *Server) HookSummaries() []protocol.HookSummary

HookSummaries projects the lifecycle hooks into the lightweight wire form consumed by the TUI's Jobs & Triggers tab (hook.list RPC). LastStatus is taken from the most recent run record.

func (*Server) Hooks added in v0.5.1

func (s *Server) Hooks() []hooks.HookSnapshot

Hooks returns a snapshot of the lifecycle hooks for external consumers (the web UI). Empty when the hooks engine is disabled (no home directory / feature off).

func (*Server) JobRunner added in v0.5.0

func (s *Server) JobRunner() jobs.Runner

JobRunner returns the jobs.Runner executing runs in-process: an isolated headless thread per run, mirroring `vix -p [-w workflow]` semantics.

func (*Server) JobSummaries added in v0.5.3

func (s *Server) JobSummaries() []protocol.JobSummary

JobSummaries projects the scheduled jobs into the lightweight wire form consumed by the TUI's Jobs & Triggers tab (job.list RPC).

func (*Server) Jobs added in v0.5.0

func (s *Server) Jobs() []jobs.JobSnapshot

Jobs returns a snapshot of the scheduled jobs for external consumers (the web UI). Empty when the scheduler is disabled (no home directory / feature off).

func (*Server) ListenAndServe

func (s *Server) ListenAndServe(ctx context.Context) error

ListenAndServe starts the Unix socket server and blocks until ctx is cancelled.

func (*Server) LogAccess

func (s *Server) LogAccess(toolName string, params map[string]any)

LogAccess logs a tool access event. Safe to call even if accessDB is nil.

func (*Server) LogoutMCP added in v0.5.7

func (s *Server) LogoutMCP(name string) error

LogoutMCP deletes the stored OAuth token for the named server and refreshes attached MCP tabs.

func (*Server) MCPServerSummaries added in v0.5.6

func (s *Server) MCPServerSummaries() []protocol.MCPServerSummary

MCPServerSummaries lists every configured MCP server for the MCP tab. Disabled servers are reported without a probe; enabled servers are dialed (with a bounded timeout) to report connection status and tool count. OAuth servers without a stored token are reported as "needs_auth" without a probe. Order follows the settings.json declaration order.

func (*Server) QuitAll added in v0.4.3

func (s *Server) QuitAll()

QuitAll tells every attached vix instance to quit, then shuts the daemon down. Invoked after an in-app update so all old processes exit and the freshly-installed binaries take effect on relaunch (brew keep_alive restart or vix auto-spawn). The short delay lets the per-instance writer goroutines flush the quit event onto their sockets before the context is cancelled.

func (*Server) RegisterHandler

func (s *Server) RegisterHandler(command string, handler HandlerFunc)

RegisterHandler registers a handler for the given command.

func (*Server) RunJob added in v0.5.1

func (s *Server) RunJob(id string) (string, error)

RunJob fires the job with the given id immediately, out of band from the schedule, mirroring `vix job run <id>`. It generates the run's thread id up front and returns it once the run has been accepted; the run itself proceeds in the background (its outcome lands under "Vix-initiated" threads and the run log). Errors surface synchronously for an unknown id, a run already in flight, or a disabled jobs engine.

func (*Server) SetHookEnabled added in v0.5.3

func (s *Server) SetHookEnabled(id string, enabled bool) error

SetHookEnabled enables or disables a lifecycle hook by id, persisting the change to its hook.json and notifying attached clients. Errors when the hooks engine is disabled or the spec cannot be patched.

func (*Server) SetJobEnabled added in v0.5.3

func (s *Server) SetJobEnabled(id string, enabled bool) error

SetJobEnabled enables or disables a scheduled job by id, persisting the change to its job.json and notifying attached clients. Errors when the jobs engine is disabled or the spec cannot be patched.

func (*Server) SetMCPEnabled added in v0.5.6

func (s *Server) SetMCPEnabled(name string, enabled bool) error

SetMCPEnabled toggles the `enabled` field of the named MCP server in the home settings.json (a surgical in-place edit that preserves every other key) and notifies attached instances so the MCP tab refreshes. The change takes effect for threads started afterwards. Errors when the server is not found.

func (*Server) SetUpdateStatus added in v0.4.3

func (s *Server) SetUpdateStatus(current, latest, url, method string)

SetUpdateStatus records the result of the daily release check so it can be emitted to every thread at init. Safe for concurrent use.

func (*Server) SetVersion added in v0.5.0

func (s *Server) SetVersion(v string)

SetVersion records the daemon build version. Threads started by clients whose version differs are refused (hard gate, see handleThread). Must be called before ListenAndServe. Leaving it unset (in-process test embeddings) disables the gate.

func (*Server) SetWebPort added in v0.5.7

func (s *Server) SetWebPort(p int)

SetWebPort records the local web UI port (vixd's --web-port), or 0 when the web UI is disabled. Used to build whiteboard links handed to clients via event.thread_started. Call before ListenAndServe.

func (*Server) Shutdown

func (s *Server) Shutdown()

Shutdown gracefully closes all server resources.

func (*Server) Subscribe

func (s *Server) Subscribe() chan struct{}

Subscribe registers a new web-UI subscriber and returns a notification channel.

func (*Server) Threads added in v0.5.7

func (s *Server) Threads() []ThreadInfo

Threads returns a snapshot of live threads plus persisted open threads.

func (*Server) TriggerHook added in v0.5.1

func (s *Server) TriggerHook(id string) (string, string, error)

TriggerHook fires the hook with the given id immediately, out of band from its event (backs `vix hook trigger <id>`). A manual trigger has no triggering action to veto, so it always runs fire-and-forget regardless of the hook's mode, even when the hook is disabled. It synthesizes a minimal context envelope and returns the run's thread id (empty for command hooks) and the fire id. Errors surface synchronously for an unknown id or a disabled engine.

func (*Server) Unsubscribe

func (s *Server) Unsubscribe(ch chan struct{})

Unsubscribe removes a previously registered subscriber channel.

func (*Server) UpdateStatus added in v0.4.3

func (s *Server) UpdateStatus() (current, latest, url, method string)

UpdateStatus returns the last recorded release-check result.

func (*Server) Version added in v0.5.0

func (s *Server) Version() string

Version returns the daemon build version recorded via SetVersion.

type ServerVitals

type ServerVitals struct {
	CPUPercent   float64 `json:"cpu_percent"`
	CPUAvailable bool    `json:"cpu_available"`
	RAMUsed      uint64  `json:"ram_used"`
	RAMTotal     uint64  `json:"ram_total"`
	DiskUsed     uint64  `json:"disk_used"`
	DiskTotal    uint64  `json:"disk_total"`
}

ServerVitals holds a snapshot of host and daemon resource usage.

type SignalState added in v0.4.5

type SignalState struct {
	Status string `json:"status,omitempty"` // "complete" or "blocked"
	Note   string `json:"note,omitempty"`
}

SignalState carries the last workflow_signal emitted by an agent step. It is cleared whenever a step with signal=true starts, so each signal is only visible to the routing decisions that immediately follow it.

type StepAgentState added in v0.4.5

type StepAgentState struct {
	Config   SubagentConfig     `json:"config"`
	Messages []llm.MessageParam `json:"messages"`
}

StepAgentState is the serializable snapshot of a step's AgentRunner: everything needed to rebuild it with NewAgentRunner plus its conversation.

type StepOption

type StepOption = wf.StepOption

The workflow data model (definitions, steps, budget) and its loader/validator live in the standalone internal/workflow package so the daemon, jobs, and hooks packages can all share one definition without import cycles. These aliases re-expose the moved types under their historical daemon names so the large execution engine below compiles unchanged. WorkflowBudget is aliased here too (its struct moved out of workflow_state.go).

type StepRef

type StepRef = wf.StepRef

The workflow data model (definitions, steps, budget) and its loader/validator live in the standalone internal/workflow package so the daemon, jobs, and hooks packages can all share one definition without import cycles. These aliases re-expose the moved types under their historical daemon names so the large execution engine below compiles unchanged. WorkflowBudget is aliased here too (its struct moved out of workflow_state.go).

type StepResult

type StepResult struct {
	Output string            `json:"output"`
	Parsed map[string]any    `json:"parsed,omitempty"` // nil if json_output was false, parse failed, or the root wasn't an object
	Value  any               `json:"value,omitempty"`  // full parsed JSON (object OR array) when json_output succeeded; the typed value that crosses edges
	Params map[string]string `json:"params,omitempty"` // input params received by this step
}

StepResult holds output from a completed workflow step.

type StreamOpts

type StreamOpts = llm.StreamOpts

StreamOpts is the daemon-side alias for llm.StreamOpts.

type SubagentConfig

type SubagentConfig struct {
	Name         string   `json:"name"`
	Description  string   `json:"description,omitempty"` // short description for LLM tool listing
	Model        string   `json:"model,omitempty"`       // empty = inherit parent model
	Effort       string   `json:"effort,omitempty"`      // "adaptive", "low", "medium", "high", "max", or "" (inherit)
	Tools        []string `json:"tools,omitempty"`       // tool name filter; nil = all tools
	MaxTurns     int      `json:"max_turns,omitempty"`   // 0 = default (20)
	MaxTokens    int      `json:"max_tokens,omitempty"`  // per-LLM-call output token cap; 0 = default (32768)
	SystemPrompt string   `json:"system_prompt,omitempty"`
}

SubagentConfig defines how a subagent behaves.

type SubagentResult

type SubagentResult struct {
	Output              string
	IsError             bool
	InputTokens         int64
	OutputTokens        int64
	CacheCreationTokens int64
	CacheReadTokens     int64
	Elapsed             time.Duration
}

SubagentResult holds the output of a completed subagent run.

func RunSubagent

func RunSubagent(
	ctx context.Context,
	config SubagentConfig,
	prompt string,
	cred vixconfig.Credential,
	parentModel string,
	plugins PluginSource,
	executeTool func(name string, params map[string]any, cwd string) (*ToolResult, error),
	cwd string,
	hooks *TurnHooks,
	toolTimeoutDefault time.Duration,
	toolTimeoutMax time.Duration,
	searchDirs ...string,
) (*SubagentResult, error)

RunSubagent executes a subagent with its own conversation, tools, and LLM instance. It blocks until the subagent completes or the context is cancelled. executeTool is called directly (in-process, no socket round-trip). searchDirs is the ordered set of .vix root directories to resolve system prompt includes from, in precedence order (highest first).

toolTimeoutDefault and toolTimeoutMax propagate the parent thread's tool_timeouts bounds so tool calls made by the subagent honour the same floor/cap as the rest of the thread. Passing zero for either falls back to package-level defaults (defaultToolTimeoutDefault / defaultToolTimeoutMax).

type ThinkingStallError

type ThinkingStallError = llm.ThinkingStallError

ThinkingStallError is the daemon-side alias for llm.ThinkingStallError.

type Thread added in v0.5.7

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

Thread manages a single agent thread over a persistent socket connection.

func NewThread added in v0.5.7

func NewThread(id string, server *Server, llmClient LLM, model, cwd, configDir string, forceInit bool, enableAutomaticWritePermission bool, enableAutomaticDirectoryAccess bool, headless bool, parentCtx context.Context) *Thread

NewThread creates a new agent thread.

func (*Thread) AddUserMessage added in v0.5.7

func (s *Thread) AddUserMessage(text string, attachments ...protocol.Attachment)

AddUserMessage appends a user message to the conversation, optionally with attachments. "image" attachments become vision blocks; "file" attachments (their extracted text already stashed in Data by handleInput) become text blocks delimited with a filename header.

func (*Thread) ReloadWorkflows added in v0.5.7

func (s *Thread) ReloadWorkflows(wfs []*WorkflowDef)

ReloadWorkflows swaps in a freshly-loaded workflow list and re-emits event.workflows_available so the TUI refreshes its slash menu and Shift+Tab cycle live. Called by the daemon config watcher when config/workflow.json changes on disk. A workflow already mid-execution holds its own definition, so this only affects the list of *available* workflows.

func (*Thread) Run added in v0.5.7

func (s *Thread) Run()

Run is the main thread loop. It initializes the brain, then waits for input.

func (*Thread) RunExploration added in v0.5.7

func (s *Thread) RunExploration(ctx context.Context, agentName, prompt string) (*SubagentResult, error)

RunExploration spawns a named agent (looked up from s.customAgents) as a foreground subagent and blocks until it completes or ctx is cancelled. It is intended for external callers such as the web API that need to run an agent on behalf of the thread without going through the normal command loop.

type ThreadClient added in v0.5.7

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

ThreadClient manages a persistent connection to the daemon for agent threads.

func NewThreadClient added in v0.5.7

func NewThreadClient(socketPath string) *ThreadClient

NewThreadClient creates a new thread client (does not connect yet).

func (*ThreadClient) Attach added in v0.5.7

func (sc *ThreadClient) Attach(cwd, configDir, model string, forceInit bool, enableAutomaticWritePermission bool, enableAutomaticDirectoryAccess bool, headless bool, attachThreadID string) error

Attach establishes a persistent connection and resumes the persisted thread with the given ID. On success the daemon replays the conversation via event.replay. Returns ErrThreadNotFound when no record exists on disk.

func (*ThreadClient) Close added in v0.5.7

func (sc *ThreadClient) Close()

Close closes the underlying connection.

func (*ThreadClient) Connect added in v0.5.7

func (sc *ThreadClient) Connect(cwd, configDir, model string, forceInit bool, enableAutomaticWritePermission bool, enableAutomaticDirectoryAccess bool, headless bool) error

Connect establishes a persistent connection and starts an agent thread.

func (*ThreadClient) ConnectFork added in v0.5.7

func (sc *ThreadClient) ConnectFork(cwd, configDir, model string, forceInit bool, enableAutomaticWritePermission bool, enableAutomaticDirectoryAccess bool, headless bool, forkThreadID string, forkTurnIdx int) error

ConnectFork establishes a persistent connection and starts a new agent thread pre-seeded with the conversation history from forkThreadID up to and including the turn at forkTurnIdx (0-based).

func (*ThreadClient) ReadEvent added in v0.5.7

func (sc *ThreadClient) ReadEvent() (protocol.ThreadEvent, error)

ReadEvent reads the next event from the daemon.

func (*ThreadClient) SendCancel added in v0.5.7

func (sc *ThreadClient) SendCancel() error

SendCancel cancels the current work.

func (*ThreadClient) SendClose added in v0.5.7

func (sc *ThreadClient) SendClose() error

SendClose ends the thread.

func (*ThreadClient) SendConfirm added in v0.5.7

func (sc *ThreadClient) SendConfirm(approved bool, persistDirs bool) error

SendConfirm sends tool approval/denial.

func (*ThreadClient) SendInput added in v0.5.7

func (sc *ThreadClient) SendInput(text string, attachments []protocol.Attachment) error

SendInput sends user chat input with optional attachments.

func (*ThreadClient) SendMarkRead added in v0.5.7

func (sc *ThreadClient) SendMarkRead() error

SendMarkRead tells the daemon the user is viewing this thread: the persisted unread flag is cleared. Sent by the TUI when a thread gains focus and when a turn completes while focused.

func (*ThreadClient) SendPlanAction added in v0.5.7

func (sc *ThreadClient) SendPlanAction(action string, text string) error

SendPlanAction sends a plan review decision.

func (*ThreadClient) SendSetModel added in v0.5.7

func (sc *ThreadClient) SendSetModel(model string) error

SendSetModel requests that the daemon switch to a different LLM model.

func (*ThreadClient) SendTrim added in v0.5.7

func (sc *ThreadClient) SendTrim(turnIdx int) error

SendTrim instructs the daemon to trim the conversation history, keeping messages up to and including the turn at turnIdx (0-based).

func (*ThreadClient) SendUpdateQuit added in v0.5.7

func (sc *ThreadClient) SendUpdateQuit() error

SendUpdateQuit tells the daemon an in-app update finished installing: it broadcasts a quit to every attached vix instance and shuts itself down so the freshly-installed binaries take effect on relaunch.

func (*ThreadClient) SendUserAnswer added in v0.5.7

func (sc *ThreadClient) SendUserAnswer(answer string, text string) error

SendUserAnswer sends the user's answer to a question. The text parameter carries additional user input when has_user_input is used.

func (*ThreadClient) SendUserAnswerBatch added in v0.5.7

func (sc *ThreadClient) SendUserAnswerBatch(answers map[string]string) error

SendUserAnswerBatch sends batch answers (question ID → answer) for multi-question mode.

func (*ThreadClient) SendWorkflow added in v0.5.7

func (sc *ThreadClient) SendWorkflow(name, text string) error

SendWorkflow sends a workflow execution request with a prompt.

func (*ThreadClient) SendWorkflowMessage added in v0.5.7

func (sc *ThreadClient) SendWorkflowMessage(text string) error

SendWorkflowMessage enqueues a user message to be injected into the currently running workflow agent as soon as the current LLM turn ends.

func (*ThreadClient) SetAuthToken added in v0.5.7

func (sc *ThreadClient) SetAuthToken(token string)

SetAuthToken stores the shared-secret token used to authenticate every ThreadCommand. Must be called before Connect if the daemon was started with -auth-token-path.

func (*ThreadClient) StartedAt added in v0.5.7

func (sc *ThreadClient) StartedAt() time.Time

StartedAt returns the time the daemon thread was created.

func (*ThreadClient) ThreadID added in v0.5.7

func (sc *ThreadClient) ThreadID() string

ThreadID returns the thread ID assigned by the daemon.

func (*ThreadClient) WhiteboardBase added in v0.5.7

func (sc *ThreadClient) WhiteboardBase() string

WhiteboardBase returns the local web UI origin reported by the daemon in the thread_started event, or "" when the web UI is disabled.

type ThreadInfo added in v0.5.7

type ThreadInfo struct {
	ID            string  `json:"id"`
	CWD           string  `json:"cwd"`
	Model         string  `json:"model,omitempty"`
	Title         string  `json:"title,omitempty"`
	Origin        string  `json:"origin,omitempty"`
	Unread        bool    `json:"unread,omitempty"`
	Attached      bool    `json:"attached"`
	InputTokens   int64   `json:"input_tokens"`
	OutputTokens  int64   `json:"output_tokens"`
	StartedAt     string  `json:"started_at"`      // RFC3339
	LastRequestAt *string `json:"last_request_at"` // RFC3339, null if no request yet
	ParentID      string  `json:"parent_id,omitempty"`
	ForkTurnIdx   int     `json:"fork_turn_idx,omitempty"`
}

ThreadInfo holds a snapshot of a live thread for external consumers.

type ToolResult

type ToolResult struct {
	Output            string
	IsError           bool
	NeedsConfirmation bool
	ToolName          string
	Params            map[string]any
	LineOffset        int
}

ToolResult holds the result of a tool execution from the daemon.

type ToolTimeouts

type ToolTimeouts struct {
	Default time.Duration
	Max     time.Duration
}

ToolTimeouts is the resolved (validated, defaulted) form of the tool_timeouts block, stored on ProjectConfig and consumed by the tool dispatcher in thread.go.

type TurnHooks

type TurnHooks struct {
	OnStreamDelta   func(delta string)
	OnThinkingDelta func(delta string)
	OnStreamDone    func(inputTokens, outputTokens, cacheCreation, cacheRead, elapsedMs int64)
	OnToolCall      func(ev protocol.EventToolCall)
	OnToolResult    func(toolID, name string, input map[string]any, output string, isError bool)
	OnBeforeStream  func(cancel context.CancelFunc)
	// OnRetry is called when a retryable API error is about to be retried.
	// Mirrors thread.streamWithRetry's event.retry emission so workflow-agent
	// retries become visible in the trajectory instead of only vixd.log.
	OnRetry func(attempt, maxRetries, waitSecs int, reason string)
	// OnThinkingStall is called when a thinking block exceeded its stall
	// timeout. The caller appends a nudge message and retries; this hook
	// lets the TUI surface the event.
	OnThinkingStall func(elapsedMs int64, summaryChars int)
}

TurnHooks provides typed callbacks for streaming events between LLM turns. All fields are optional — nil callbacks are skipped.

type WorkflowBudget added in v0.4.5

type WorkflowBudget = wf.Budget

The workflow data model (definitions, steps, budget) and its loader/validator live in the standalone internal/workflow package so the daemon, jobs, and hooks packages can all share one definition without import cycles. These aliases re-expose the moved types under their historical daemon names so the large execution engine below compiles unchanged. WorkflowBudget is aliased here too (its struct moved out of workflow_state.go).

type WorkflowDef

type WorkflowDef = wf.Def

The workflow data model (definitions, steps, budget) and its loader/validator live in the standalone internal/workflow package so the daemon, jobs, and hooks packages can all share one definition without import cycles. These aliases re-expose the moved types under their historical daemon names so the large execution engine below compiles unchanged. WorkflowBudget is aliased here too (its struct moved out of workflow_state.go).

func LoadWorkflowsFile added in v0.4.2

func LoadWorkflowsFile(path string) []*WorkflowDef

LoadWorkflowsFile reads a config/workflow.json file and returns its validated workflow list. Thin wrapper over workflow.Load kept under the historical name used across the daemon and its tests.

type WorkflowRun

type WorkflowRun struct {
	Def         *WorkflowDef
	StepAgents  map[string]*AgentRunner // step_id -> runner used
	StepResults map[string]*StepResult  // step_id -> result
	State       *WorkflowRunState       // live persisted position/accounting for this run

	// Barriers holds the per-branch outputs collected by a fan_out node,
	// keyed by barrier_id, in element order. The matching fan_in reads it to
	// bind its `as` results list. In-memory only: an interrupted run re-runs
	// the whole fan_out block on resume (atomic-block semantics), and fan_out
	// also persists the joined list as a StepResult so a resume landing on the
	// fan_in can still recover it.
	Barriers map[string][]branchResult
	// contains filtered or unexported fields
}

WorkflowRun tracks a running workflow.

type WorkflowRunState added in v0.4.5

type WorkflowRunState struct {
	Name         string                    `json:"name"`
	Status       string                    `json:"status"`
	Prompt       string                    `json:"prompt"`                // the original $(workflow.prompt)
	CurrentRef   *StepRef                  `json:"current_ref,omitempty"` // resume cursor: step about to execute
	Iteration    int                       `json:"iteration"`             // total iterations across resumes
	StepResults  map[string]*StepResult    `json:"step_results,omitempty"`
	StepAgents   map[string]StepAgentState `json:"step_agents,omitempty"`
	Budget       BudgetState               `json:"budget"`
	Signal       SignalState               `json:"signal"`
	BudgetRouted bool                      `json:"budget_routed,omitempty"` // OnExceeded already taken
	ErrorRouted  bool                      `json:"error_routed,omitempty"`  // an on_error route already taken
}

WorkflowRunState is the persisted position of a workflow run. It is snapshotted once per engine loop iteration so an interrupted run (user cancel or daemon restart) can resume from its cursor with all step results and per-step agent conversations intact.

func (*WorkflowRunState) Resumable added in v0.4.5

func (st *WorkflowRunState) Resumable() bool

Resumable reports whether an interrupted run can be continued. Completed runs are cleared rather than kept, so anything still stored that isn't actively running again is fair game.

type WorkflowStepDef

type WorkflowStepDef = wf.StepDef

The workflow data model (definitions, steps, budget) and its loader/validator live in the standalone internal/workflow package so the daemon, jobs, and hooks packages can all share one definition without import cycles. These aliases re-expose the moved types under their historical daemon names so the large execution engine below compiles unchanged. WorkflowBudget is aliased here too (its struct moved out of workflow_state.go).

Directories

Path Synopsis
lsp
Package hooks implements vixd's lifecycle-hooks engine: user-authored hook specs (~/.vix/hooks/<id>/hook.json) that fire on agent-loop events (a tool about to run, a prompt submitted, a thread starting, …) rather than on a timer.
Package hooks implements vixd's lifecycle-hooks engine: user-authored hook specs (~/.vix/hooks/<id>/hook.json) that fire on agent-loop events (a tool about to run, a prompt submitted, a thread starting, …) rather than on a timer.
Package jobs implements vixd's scheduled-jobs engine: user-authored job specs (~/.vix/jobs/<id>/job.json) fired by a single timer loop, each run executing a prompt — optionally through a workflow — in an isolated thread.
Package jobs implements vixd's scheduled-jobs engine: user-authored job specs (~/.vix/jobs/<id>/job.json) fired by a single timer loop, each run executing a prompt — optionally through a workflow — in an isolated thread.
Package llm provides a provider-neutral interface for LLM interactions across Anthropic, OpenAI (Responses API), OpenRouter, MiniMax, and Xiaomi MiMo.
Package llm provides a provider-neutral interface for LLM interactions across Anthropic, OpenAI (Responses API), OpenRouter, MiniMax, and Xiaomi MiMo.
Package pdf is a self-contained, dependency-free PDF reader that extracts a text-based PDF's content and renders it as Markdown for LLM consumption.
Package pdf is a self-contained, dependency-free PDF reader that extracts a text-based PDF's content and renders it as Markdown for LLM consumption.

Jump to

Keyboard shortcuts

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