Documentation
¶
Overview ¶
Package config owns daemon paths, ports, and version metadata. All paths derive from a single base dir (default ~/.rmote/agent/) so the daemon and its installer can locate state without env drift.
Index ¶
- Constants
- Variables
- func AgentDir() (string, error)
- func BindAddr() string
- func ConfigPath() (string, error)
- func EnsureDir() error
- func LogPath() (string, error)
- func PIDPath() (string, error)
- func Port() int
- func SecretPath() (string, error)
- type DaemonConfig
- type HostCaps
- type SummarizerConfig
- func (s SummarizerConfig) ActivityInterval() time.Duration
- func (s SummarizerConfig) Defaults() SummarizerConfig
- func (s SummarizerConfig) ResolveBackend(caps HostCaps) string
- func (s SummarizerConfig) ResolvedAgent(caps HostCaps) string
- func (s SummarizerConfig) TitleIdle() time.Duration
- func (s SummarizerConfig) TitleLongIdle() time.Duration
- func (s SummarizerConfig) TitleMinInterval() time.Duration
Constants ¶
const ( BackendAuto = "auto" // resolve from host capability (default) BackendAppleFM = "applefm" // on-device Apple Foundation Model (macOS 26+, free) BackendAgentCLI = "agentcli" // reuse an installed agent CLI in print mode BackendDisabled = "disabled" // no live summary / model title )
Summarizer backend identifiers. Stored lower-case in config JSON.
const ( AgentAuto = "auto" // claude → pi → codex AgentClaude = "claude" AgentPi = "pi" AgentCodex = "codex" )
SummarizerAgent identifies which agent CLI the agentcli backend shells out to. Validated against the catalog allowlist at the server layer (not here, to avoid an import cycle config→agents).
const DefaultPort = 17783
DefaultPort is the daemon's default localhost TCP port. Matches the iOS local-port-forward target. Overridable via RMOTE_AGENT_PORT for conflict cases (rare; default has been chosen to avoid common clashes).
Variables ¶
var IsDarwin = func() bool { return runtime.GOOS == "darwin" }
IsDarwin is a tiny seam for test injection (production checks runtime.GOOS).
var Version = "0.1.0-dev"
Version is the daemon version reported by /api/health. Bumped per release. Overridden at build time via -ldflags="-X github.com/8ugustdev/rmoted/internal/config.Version=…".
Functions ¶
func AgentDir ¶
AgentDir returns the daemon state directory. Override via RMOTE_AGENT_DIR (tests); default ~/.rmote/agent/.
func BindAddr ¶
func BindAddr() string
BindAddr returns the address the daemon should bind. Default "127.0.0.1" (localhost-only — iOS reaches the daemon via SSH local-forward or Tailscale). Override via RMOTE_AGENT_BIND=0.0.0.0 for LAN-attached iOS (QR pairing to the host's LAN IP). Binding non-loopback exposes the daemon to the network — the bearer auth + rate limiting are the security boundary, but the exposure is wider than the SSH-tunnel path.
func ConfigPath ¶
ConfigPath is the daemon config file (~/.rmote/agent/config.json). Respects RMOTE_AGENT_DIR like every other state path.
func EnsureDir ¶
func EnsureDir() error
EnsureDir creates the state dir with mode 0700 if missing. Idempotent. Permissive enough for the user, tight enough that other local users can't read the daemon secret.
func LogPath ¶
LogPath is the daemon's structured log sink (slog JSON, append-only). Rotated by the supervisor (launchd/systemd) — daemon itself does not rotate.
func SecretPath ¶
SecretPath is the file holding the per-install random auth secret (0600). Required on all daemon routes — local TCP bind is permissive, so the secret prevents any local process from subscribing to agent events.
Types ¶
type DaemonConfig ¶
type DaemonConfig struct {
Summarizer SummarizerConfig `json:"summarizer,omitempty"`
}
DaemonConfig is the parsed ~/.rmote/agent/config.json. Today only the summarizer block is defined; future daemon-wide knobs land here. All fields are omitempty so an absent file yields a zero-value config resolved to safe defaults via ResolveBackend / Defaults().
func Load ¶
func Load() (*DaemonConfig, error)
Load reads and validates ~/.rmote/agent/config.json. A missing file is not an error — it returns a zero-value config (resolved later to safe defaults). A present-but-unparseable file IS an error: per advisory (d), malformed JSON must never silently become defaults. The caller (server.New) treats a Load error as degraded mode: log + surface to /api/health, fall back to compiled defaults, never fatal.
Env overrides (RMOTE_SUMMARIZER_*) apply on every path — including the missing-file path — so a host can run purely from env with no file.
type HostCaps ¶
type HostCaps struct {
Darwin bool // runtime.GOOS == "darwin"
AppleFMAvailable bool // rmoted-summarize helper resolves on disk
AgentAvailable bool // the configured/fallback agent CLI is on PATH
AvailableAgentIDs []string
}
HostCaps summarizes what the host can actually run, computed once at startup by the server (which owns agent-binary probing + the Apple-FM helper path). ResolveBackend consults it to turn backend=auto into a concrete choice.
type SummarizerConfig ¶
type SummarizerConfig struct {
Backend string `json:"backend,omitempty"` // auto|applefm|agentcli|disabled
Agent string `json:"agent,omitempty"` // auto|claude|pi|codex (agentcli)
ActivityIntervalSec int `json:"activity_interval_sec,omitempty"` // line-2 debounce floor
TitleIdleSec int `json:"title_idle_sec,omitempty"` // line-1 idle re-derive
TitleLongIdleSec int `json:"title_long_idle_sec,omitempty"` // line-1 long-idle re-derive
TitleMinIntervalSec int `json:"title_min_interval_sec,omitempty"` // no re-derive within this of last
// ConsentOffdevice gates non-applefm backends. Hosted agent CLIs
// (claude/codex/pi) ship PTY tail + hook content off-device to a third
// party; Apple FM runs on-device and needs no consent. Default false →
// agentcli refuses until the user opts in. See docs/system-architecture.
ConsentOffdevice bool `json:"consent_offdevice,omitempty"`
}
SummarizerConfig drives the live-activity one-liner (Line 2) and the model-derived session title (Line 1). Intervals are seconds; the server converts to time.Duration. A zero-value config (no file) resolves to: backend=auto, agent=claude, activity=12s, title-idle=5m, long-idle=30m, min-title=5m, consent=false (non-applefm refuses until set true).
func (SummarizerConfig) ActivityInterval ¶
func (s SummarizerConfig) ActivityInterval() time.Duration
ActivityInterval, TitleIdle, TitleLongIdle, TitleMinInterval are the convenience Duration views used by the server tickers/debouncers.
func (SummarizerConfig) Defaults ¶
func (s SummarizerConfig) Defaults() SummarizerConfig
Defaults returns a fully-resolved SummarizerConfig with every zero field filled. The server calls this after Load so downstream code never sees a zero interval. These mirror the documented defaults in docs/ + the plan.
func (SummarizerConfig) ResolveBackend ¶
func (s SummarizerConfig) ResolveBackend(caps HostCaps) string
ResolveBackend turns backend=auto into a concrete backend given host capability. Locked policy (user 2026-08-12):
- macOS: Apple FM if available, else agentcli (claude).
- Linux/other: agentcli (claude).
- agentcli needs an agent on PATH; if none, disabled.
Explicit (non-auto) backends are returned as-is — no silent fallback. The server separately enforces consent for non-applefm backends.
func (SummarizerConfig) ResolvedAgent ¶
func (s SummarizerConfig) ResolvedAgent(caps HostCaps) string
ResolvedAgent turns agent=auto into a concrete agent ID given what is installed. Preference (user): claude → pi → codex. An explicit agent is returned as-is even if absent — the server then errors+degrades (advisory: no silent fallback).
func (SummarizerConfig) TitleIdle ¶
func (s SummarizerConfig) TitleIdle() time.Duration
func (SummarizerConfig) TitleLongIdle ¶
func (s SummarizerConfig) TitleLongIdle() time.Duration
func (SummarizerConfig) TitleMinInterval ¶
func (s SummarizerConfig) TitleMinInterval() time.Duration