Documentation
¶
Overview ¶
Package friend is what a friend's machinery runs to be part of the team (docs/SPEC-FRIEND.md; the model is tla/Friend.tla). One daemon per friend parks on the friend's nova-bus stream and pushes each message into the running session as a turn, beats to the sprint server while it does, and keeps the connection with the coordinator symmetric: a ping every window from the coordinator, answered at once by the daemon and as a turn by the session; no ping for a window and the session is told the coordinator is silent. The rules live here, apart from the transport: Machine is the state the daemon owns, stepped by the events and the clock the daemon hands it, so every rule is tested with no socket and no real time.
Index ¶
- Constants
- Variables
- func AdapterRemedy(harness string) string
- func AgeString(d time.Duration) string
- func AgentAPI(out string) (json.RawMessage, error)
- func Ago(d time.Duration) string
- func AllowDirs(dir string, paths []string) (bool, error)
- func AppRunning(listing, username string, app App) bool
- func BatchFor(seat string, msgs []bus.Message, notice, pongCommand string) string
- func BatchTakeArgv(friend string, n int, epoch uint64) []string
- func BenchRule(friend, card string) string
- func BriefFix(brief string) string
- func BusLogEntries(ctx context.Context, st bus.Store, friend string, since time.Time) (realCount int, lastReal time.Time, err error)
- func CappedWords(limit time.Duration, tier string, overrun time.Duration) string
- func CardText(job LaneJob, n, width int, sendLine, pong, notice string, seat string, ...) string
- func CheckFolderRoute(harness, session, adapter, deliveryDir string) error
- func ClaimLane(dir, job, who string, now time.Time) (holder string, err error)
- func ClaudeAsyncBashHook(input []byte) []byte
- func ClaudeInstallLine(harness, friend, wake string) string
- func ClaudeWaitLine(friend, wake string) string
- func ClaudeWakePath(stateDir, friend string) string
- func ClearPause(stateDir string) (bool, error)
- func CodexAddRoot(text, root string) (string, error)
- func CodexControlSocket(home string) string
- func CodexDequeue(ctx context.Context, s CodexAppServer, thread, id string) (deleted bool, err error)
- func CodexRoots(text string) (roots []string, found bool, err error)
- func ContextFull(reason string) bool
- func CopyExecutable(src, dst string) error
- func CostLine(t LaneTokens, rp RoutePrice, model string) (report, tokens, cost string)
- func CostOf(t cardcost.Tokens, rp RoutePrice, model string) string
- func DSHArgs(session string) []string
- func DSHNoPresetRemedy(dir string) string
- func DSHSessionKey(dir string) string
- func DaemonStateDir(home, dir, friend string, mkdir func(string) error) (state, why string)
- func DeadLaneReport(friend, job, end string) string
- func DefaultDenySelf(home, seat string) []string
- func DefaultReadWork(dir string) (inboxCount, outboxCount int, newestName string, newestAt time.Time, err error)
- func DefaultStateDir(home, friend string) string
- func EndReport(friend string, lane int, c Card, end LaneEnd, head, branch string) string
- func Envelope(seat string, msgs []bus.Message, now time.Time, me string, limit int, ...) (text string, shown int)
- func ExitTimeout(plist string) time.Duration
- func FaultDownText(friend, reason string, until time.Time) (subject, body string)
- func FaultWords(fault, first string) string
- func FindStateDir(home, dir, friend string) string
- func FinishArgv(friend string, c Card, report, head, branch string) []string
- func FinishNote(friend, job, verdictLine, cost string, wall time.Duration) (subject, body string)
- func FixAddressed(report, fix string) (missing []string, ok bool)
- func FixKeyWords(fix string) []string
- func FlockHeld(path string) bool
- func FolderCheckLine(friend, dir, state string) string
- func FriendCardsArgv(friend string) []string
- func FundsJudgmentText(friend, reason string) (subject, body string)
- func GeminiArgs(session, text string) []string
- func GitHubURL(repo string) string
- func GoRefusal(name string) string
- func GoShimName(argv0 string) (string, bool)
- func GoShims(dir, self string) error
- func GrokInstallLine(harness, session string) string
- func GrokMonitorLine(wake string) string
- func GrokWakePath(home, stateDir, friend string) string
- func HarnessFirstError(out string) string
- func Head(s string, n int) string
- func HeldVia(friend string, ask func(ctx context.Context, argv []string) (string, error), ...) func(context.Context) (Row, error)
- func HostPrompt(harness, override string) (re *regexp.Regexp, src string, err error)
- func InLane(ctx context.Context) bool
- func Install(ctx context.Context, a Agent, uid int, run Launchctl, ...) (path string, ran []string, err error)
- func InstalledBinary(home string) string
- func IsPresentRequest(friend string, m bus.Message) bool
- func IsRealMessage(subject string) bool
- func IsWake(text string) bool
- func JobDir(dir, job string) string
- func JobText(dir string, p Packet, sha string) string
- func Known(harness string) bool
- func LaneCap(tier string, caps map[string]time.Duration) time.Duration
- func LaneContext(ctx context.Context) context.Context
- func LaneDirOf(ctx context.Context, def string) string
- func LaneMarkEnded(who string) string
- func LaneMarkRunning(who string, at time.Time) string
- func LaneSeed(friend string, n, width int, agents, memory string) string
- func LaneTakeArgv(member string, n int) []string
- func LanguageServer(ps, username string) (pid, token string, err error)
- func LastLines(s string, n int) string
- func LastResult(stateDir string) (at time.Time, exit int, err error)
- func LimitAlikeText(friend, line string) (subject, body string)
- func LimitDownText(friend string, until time.Time, reason string) (subject, body string)
- func LimitUnreadText(friend string, rest time.Duration, text string) (subject, body string)
- func LimitUpText(friend string) (subject, body string)
- func ListenPorts(lsof string) []string
- func Load1Of(out string) (float64, bool)
- func LockPath(home, thread string) string
- func LogPath(stateDir string) string
- func NewestCodexSession(home, dir string) (string, error)
- func NewestConversation(rows string, dirs ...string) (string, error)
- func NewestDSHSession(sessions, dir string) (string, error)
- func NewestWrite(fsys fs.FS, roots []string, now func() time.Time, lim ActivityLimits) time.Time
- func NotHers(card, job, friend string, running func() map[string]string) string
- func NotificationCategory(text string) string
- func NotificationKey(text string) string
- func OutboxFinishArgv(friend string, c Card, verdict, head, branch, report string) []string
- func PacingJudgmentText(friend string, paced, width int, pacing float64, use string) (subject, body string)
- func PacingOf(setting float64) float64
- func PacingText(pacing float64) string
- func ParseJob(job string) (id string, epoch, gen int, ok bool)
- func ParseLaneCaps(answer string) (caps map[string]time.Duration, ok bool)
- func ParseMachine(answer string) (state string, ok bool)
- func ParsePing(text string) (nonce, seat string, since time.Time, ok bool)
- func ParsePong(text string) (nonce string, queue, working, width int, ok bool)
- func ParseProfile(answer string) (profile string, ok bool)
- func ParseReadSlots(answer string) (n int, ok bool)
- func ParseRow(answer string) (mode string, width int, ok bool)
- func ParseShown(data []byte) (map[string]ShownEntry, error)
- func PauseBeat(marker, model string, now time.Time) (until time.Time, reason string)
- func PermissionRejection(out string) string
- func PingText(seat string, since time.Time, nonce string) string
- func PlanBinary(binary, home string) (path string, copy bool, err error)
- func PlatformPermitted(context.Context, Exec) (bool, error)
- func PlistArgs(plist string) []string
- func PlistDriftLine(plist string, running []string) string
- func PongLine(nonce string, queue, working, width int) string
- func PongNonce(body string) (nonce string, ok bool)
- func PongRequest(text string) (kind, nonce string, only bool)
- func PresentText(friend, seat string, at time.Time, queue []QueueLine, skipped Skipped, ...) string
- func ProgressArgv(friend string, cards []Card) [][]string
- func PromptPattern(s string) *regexp.Regexp
- func ProviderLimit(session, out string) error
- func ProviderRefusal(out string) (reason string, ok bool)
- func PublishCost(outbox string, t LaneTokens, rp RoutePrice, model string) error
- func PushedHead(dir string, c Card) (head, branch string)
- func Pushing() []string
- func QuoteWhy(s string) string
- func Quoted(m bus.Message) string
- func RateJudgmentText(friend string, cap, width int, reason string) (subject, body string)
- func Read(readJSON []byte, id string) bool
- func ReadBeginArgv(friend string, r AskedRead) []string
- func ReadPause(stateDir string) string
- func ReadPrompt(friend, jobDir string) string
- func ReadQueue(dir string) (queue, working int, err error)
- func ReadQueueArgv(friend string) []string
- func ReadReturnArgv(friend string, r AskedRead, reason, usage string) []string
- func ReadText(friend, jobDir string, r AskedRead) string
- func ReadVerdict(result string) (verdict, finding string)
- func ReadVerdictArgv(friend string, r AskedRead, verdict, finding, usage string) []string
- func ReaderOf(friend string) string
- func RealExec(ctx context.Context, dir, name string, args []string, stdin string) (string, int, error)
- func Record(stateDir, line string) error
- func RescueStray(job LaneJob) []string
- func ResentLine(d AntigravityDelivery) string
- func ResumeArgs(session, text string) []string
- func ReworkedBrief(brief string) string
- func RowConfigDir(answer string) string
- func RunWall(args, env []string, stdin io.Reader, stdout, stderr io.Writer) int
- func RunnerEnded(log, job string) (end string, dead bool)
- func RunnerLog(dir string) string
- func RunsCards(harness string) bool
- func SessionCheckFile(dir, nonce string) string
- func SessionCheckText(nonce, pong, to string) string
- func SessionCost(export string) (float64, error)
- func SessionMissing(firstError string) bool
- func SnapEpoch(dir string, row Row, keep map[string]bool, asked, now time.Time, ...) (int, error)
- func StageJudgmentText(friend string, n *NotStageable) (subject, body string)
- func Staged(dir, job string) bool
- func StaleNonce(sent, storeNow time.Time, window time.Duration) bool
- func StateDirIn(dir string) string
- func StopReturnArgv(row, card string, gen int, epoch string, lane int) []string
- func SupersededNotices(owed []Notice) map[string]string
- func SupersededReason(at time.Time) string
- func TakeArgv(friend, card, reason string) []string
- func TakeBackNote(friend, card, job, why string) (subject, body string)
- func Text(m bus.Message) string
- func TextLimit(d Deliverer) int
- func TmuxFor(d Deliverer, name, stateDir string) error
- func TmuxSession(name string) string
- func TokenCapOf(answer string) (int64, bool)
- func TokenCapReport(friend string, c int64, tokens int64, turns int, last string) string
- func TokensSQL(session string) (string, error)
- func TypeScript(bundle, text string) string
- func TypedLine(text string) string
- func UUIDv7Time(id string) (time.Time, bool)
- func UnaddressedLand(by, report, brief string) (held string)
- func UnaddressedText(by, fix string, missing []string) string
- func Undriven(d Deliverer, harness string) (why, remedy string, ok bool)
- func Uninstall(ctx context.Context, a Agent, uid int, run Launchctl, ...) (ran []string, err error)
- func WaitReleased(ctx context.Context, run Launchctl, target string, timeout, poll time.Duration, ...) (time.Duration, error)
- func WakeLine(text string) string
- func WakeOf(active, listing, dir, wake string) (string, error)
- func WakePingText(seat string, since time.Time, nonce string) string
- func WakeTargets(me string, rows []WakeRow, never []string) []string
- func WakeText(nonce string) string
- func WakeTurnText(pongCommand string) string
- func WatchPath(stateDir string) string
- func WithCost(report, line string) string
- func WithLaneDir(ctx context.Context, dir string) context.Context
- func WithOutputSeen(ctx context.Context, seen func()) context.Context
- func WithOutputTail(ctx context.Context, tail func([]byte)) context.Context
- func WorkspaceConversations(rows string, dirs ...string) ([]string, error)
- func WriteHost(stateDir string, h Hosted) error
- func WriteLanes(stateDir string, s LaneState) error
- func WriteNotificationState(dir string, s NotificationState) error
- func WritePause(stateDir, message string, at time.Time) error
- func WritePong(stateDir string, p Pong) error
- func WritePresence(stateDir string, s PresenceStatus) error
- func WriteStatus(stateDir string, s Status) error
- func WriteWatch(stateDir string, w Watch) error
- type ActivityLimits
- type Agent
- type AgentAPIRefusal
- type Aliver
- type Antigravity
- type AntigravityDelivery
- type AntigravityLedger
- type App
- type AskedRead
- type BeatWords
- type BusFacts
- type Card
- type CardRunner
- type CardUsage
- type Change
- type CheckReport
- type CheckResult
- type CheckSeams
- type CheckSummary
- type Claude
- type ClaudeWake
- type Codex
- type CodexAppServer
- type CodexQueued
- type Conformance
- type CopyFile
- type Courier
- type DSH
- type Daemon
- type DaemonFacts
- type DeafChange
- type DealNotice
- type Deferred
- type Deliverer
- type Entry
- type Evidence
- type Exec
- type FaultWatch
- type Folder
- type FolderCheck
- type FreshTurn
- type FriendCheck
- type GUIWindow
- type Gemini
- type Grok
- type HarnessFacts
- type HarnessSettings
- type HarnessWatch
- type HeldAnswer
- type HeldCard
- type HostRefused
- type HostResult
- type HostSpec
- type Hosted
- type InPlace
- type InboxCounts
- type Keepalive
- func (k *Keepalive) Failed(friend, why string)
- func (k *Keepalive) Friends(now time.Time, names []string)
- func (k *Keepalive) Names() []string
- func (k *Keepalive) Pong(friend, nonce string, now time.Time) bool
- func (k *Keepalive) Sent(friend, nonce string, at time.Time)
- func (k *Keepalive) Step(now time.Time) []Change
- type LaneEnd
- type LaneGovernor
- func (g *LaneGovernor) Cap(width int) int
- func (g *LaneGovernor) Clean(now time.Time)
- func (g *LaneGovernor) Held() string
- func (g *LaneGovernor) Hold(reason string) bool
- func (g *LaneGovernor) PauseUntil(until time.Time, reason string, now ...time.Time) string
- func (g *LaneGovernor) Paused(now time.Time) bool
- func (g *LaneGovernor) RateLimit(now, started time.Time, width int, reason string) (line string, judge bool)
- func (g *LaneGovernor) Release()
- func (g *LaneGovernor) Step(now time.Time, width int) []string
- type LaneHarness
- type LaneHold
- type LaneJob
- type LaneMark
- type LaneRules
- func (r LaneRules) Judge(id, stream, tier string) (LaneVerdict, string)
- func (r LaneRules) LaneWidthUnderLoad(width int, load float64) (n int, held bool)
- func (r LaneRules) Over(row LaneRules) LaneRules
- func (r LaneRules) OverTokenCap(tokens int64) bool
- func (r LaneRules) ProviderStop(err error) (message string, stop bool)
- type LaneState
- type LaneTokens
- type LaneTurn
- type LaneVerdict
- type Launchctl
- type Limit
- type LimitHit
- type Limits
- func (l *Limits) Beat(beat func(ctx context.Context) error) func(ctx context.Context) error
- func (l *Limits) BeatOrDown(beat func(ctx context.Context) error, ...) func(ctx context.Context) error
- func (l *Limits) Gate(d Deliverer) Deliverer
- func (l *Limits) Kind() string
- func (l *Limits) Limited() (until time.Time, reason string, limited bool)
- func (l *Limits) Refuse(kind, reason string, until time.Time)
- func (l *Limits) Watch(run Exec) Exec
- func (l *Limits) WindowUse() string
- type Liveness
- type LogFacts
- type Machine
- func (m *Machine) IdleStep(now, active time.Time, cards int, after time.Duration) (wake, note bool)
- func (m *Machine) Ping(now time.Time, seat string, since time.Time, nonce string) []Push
- func (m *Machine) Pong(now time.Time, nonce string) (current bool)
- func (m *Machine) Tick(now time.Time) []Push
- type Mailbox
- type NoReport
- type NotServed
- type NotStageable
- type Notice
- type NotificationBatch
- type NotificationPolicy
- type NotificationState
- type OSFS
- type OpenCode
- func (o *OpenCode) Alive(context.Context) Liveness
- func (o *OpenCode) CheckRun(ctx context.Context) error
- func (o *OpenCode) Deliver(ctx context.Context, text string) (int, error)
- func (o *OpenCode) DeliverFresh(ctx context.Context, text string) (int, error)
- func (o *OpenCode) DeliverTo(ctx context.Context, id, text string) (LaneTurn, error)
- func (o *OpenCode) OpenSession(ctx context.Context, seed string) (string, error)
- func (*OpenCode) ReadOnReturn()
- func (o *OpenCode) RunRead(ctx context.Context, model, prompt string) (LaneTurn, error)
- type OpenCodePriced
- type OutOfFunds
- type Pacer
- type Packet
- type Pong
- type Presence
- type PresenceStatus
- type PresentPlan
- type ProviderRefused
- type Push
- type PushProver
- type Queue
- type QueueLine
- type RateLimited
- type ReadHarness
- type ReadOnReturn
- type ReadPacket
- type Refused
- type RoutePrice
- type Row
- type SessionCheck
- func (s *SessionCheck) Beat(beat func(ctx context.Context) error) func(ctx context.Context) error
- func (s *SessionCheck) BeatAlways(beat func(ctx context.Context) error) func(ctx context.Context) error
- func (s *SessionCheck) BeatOr(beat func(ctx context.Context) error, ...) func(ctx context.Context) error
- func (s *SessionCheck) DaemonStore() bus.Store
- func (s *SessionCheck) Gate(inner Deliverer) Deliverer
- func (s *SessionCheck) Present() (bool, string)
- func (s *SessionCheck) Proof() (proven bool, nonce string)
- func (s *SessionCheck) Said(w BeatWords)
- func (s *SessionCheck) Step(ctx context.Context)
- func (s *SessionCheck) Words() BeatWords
- type SessionRefused
- type SessionTurns
- type Setting
- type SettingsFS
- type ShownEntry
- type Skipped
- type Spender
- type Stager
- type Started
- type Status
- type StopReturn
- type Stub
- type Task
- type Tmux
- type TokenCapped
- type Tokens
- type TurnRecord
- type Usage
- type UsageLimited
- type Verdict
- type VerdictFacts
- type WakeRow
- type Wall
- type Watch
- type WindowRefused
- type WindowUse
- type WorkFacts
Constants ¶
const ( AntigravityPoll = 500 * time.Millisecond AntigravityLandBudget = 30 * time.Second )
AntigravityPoll is how often the mailbox is read while waiting for the sent message to appear in it, and AntigravityLandBudget how long: past it the message agentapi took is in the ledger as delivered, its id read off the mailbox when it lands (Follow).
const ( PongCheck = "session check" // the presence's nonce (SessionCheckText) PongWake = "wake" // the coordinator's challenge nonce (a wake turn, an idle wake, a turn's head) )
The kinds of pong request (PongRequest): each its own series of nonces.
const ( TmuxPoll = 500 * time.Millisecond TmuxAcceptWithin = time.Minute )
Timing of a typed delivery: the pane is polled each TmuxPoll for up to TmuxAcceptWithin for the prompt line to go (the turn started).
const ( RuleSession = "session" RuleApp = "app" )
The rules a Liveness is read by, as the record and the status say them (alive=session|app).
const ( AntigravityFollowEvery = 10 * time.Second AntigravityReadBound = SessionBound AntigravityStopped = 3 AntigravitySwitchHold = 10 * time.Minute AntigravityKeptRead = 64 )
The ledger's rules. AntigravityReadBound is the check period: a delivery unread past it, with nothing read since, is a session down (Deliver refuses). A conversation that has left AntigravityStopped deliveries unread past it, and read nothing since the oldest, stopped reading; delivery moves to a conversation that read a delivery since, and never moves again within AntigravitySwitchHold. Follow looks every AntigravityFollowEvery. AntigravityKeptRead bounds the deliveries kept once read or sent again (the newest); one unread is never dropped.
const ( VerdictOK = "ok" VerdictBroken = "broken" VerdictDeaf = "deaf" VerdictSilent = "silent" VerdictDown = "down" VerdictUntrue = "untrue" )
Verdict constants for the friend health check.
const ( StageDeliver = "deliver" StageAct = "act" StageReply = "reply" )
The stages of the delivery check, in the order they are passed: the adapter took the text (deliver), the session ran the pong line it carries (act: the pong file holds the nonce), and the pong is on the bus (reply).
const ( DefaultCheckWithin = SessionBound CheckPoll = time.Second )
DefaultCheckWithin is how long the check waits for the session's pong by default: the session check's own bound (SessionBound). CheckPoll is how often it reads the bus and the pong file meanwhile.
const ( StatusErrorEvery = time.Minute DeferredSaidEvery = time.Minute )
StatusErrorEvery bounds how often a status file that cannot be written is said in the record: the loop goes on beating and delivering without it. DeferredSaidEvery bounds how often a deferral still in hand is said.
const ( MaxBatch = 32 BatchBytes = 256 << 10 )
MaxBatch bounds the messages a one-shot lane takes with its card; batch delivery reads every pending message before Envelope applies TextLimit. BatchBytes bounds how much text: the rest waits for the next turn, oldest first. A turn's text travels as one argument to some harnesses (opencode run), under the platform's argument limit.
const ( DaemonPongSubject = "daemon-pong" PongSubject = "pong" PingPrefix = "PING " )
The subjects of the daemon's own messages on the bus.
const ( SessionOK = "ok" SessionBroken = "broken" )
The session's state, as the status file says it.
const ( PushProved = "proved" PushUnproven = "unproven" )
The push proof's words in the status file.
const ( FromCards = "friend cards" FromView = "the worker view" )
The sources of a Row.
const ( ViewEvery = 15 * time.Second ServedEvery = time.Minute )
ViewEvery is how often the worker view is read while friend cards is refused: it runs on the server's line (serveView takes the tick's lock), so it is read about as often as friend sync's loop runs, never every loop. ServedEvery is how often friend cards is asked again.
const ( PingEvery = time.Second DownAfter = 10 * time.Second RowsEvery = time.Minute // how often the friend rows are read again )
The coordinator's side of the connection (docs/SPEC-FRIEND.md, "The coordinator's ping"): the coordinator is the server, it pings every friend row each PingEvery, and a friend is down once DownAfter passes with no pong.
const ( PeerUp = "up" // a pong to a ping of the last DownAfter PeerDown = "down" // none for DownAfter )
What the coordinator knows of a friend's connection.
const ( NoGoRoot = "/NO-GO-ON-THIS-MACHINE-run-it-on-a-bench-over-ssh" ShimDirName = "shims" )
The go refusal: no go command runs on the machine that runs the lanes (the owner's rule: it is not a build machine). A lane's PATH carries go and gofmt that refuse, and GOROOT points nowhere.
const ( FaultRepeats = 3 FaultWithin = 10 * time.Minute FaultDownFor = 15 * time.Minute )
The bound on a harness fault: the same fault FaultRepeats times within FaultWithin on one row marks the row down for FaultDownFor, once, with one judgment to the seat.
const ( ModeBatch = "batch" ModeOneShot = "one-shot" )
The delivery modes (pkg/config FriendModes, the friend row's mode).
const ( ReleasePoll = 250 * time.Millisecond DefaultExitTimeout = 20 * time.Second )
ReleasePoll is how often Install asks launchd, after the bootout, whether it still holds the old service; DefaultExitTimeout is how long it asks, the launchd default for a plist with no ExitTimeOut (the time launchd gives a daemon to exit before it kills it).
const ( KindLimit = "limit" KindCredits = "credits" )
The kinds of a limit: the harness's usage window is spent, or the balance that pays for it is empty.
const ( Connected = "connected" // a ping arrived within the window Silent = "silent" // no ping for a window; the session was told once )
The connection: what the daemon knows of the coordinator.
const ( Quiet = "quiet" // nothing asked, or the last ping was answered Challenged = "challenged" // a ping was pushed in; no pong yet Deaf = "deaf" // challenged for a window with no pong )
The challenge: what the daemon knows of its own session.
const ( Awake = "awake" // a write within IdleAfter, or no card held Woken = "woken" // idle for IdleAfter holding cards; one wake turn given Noted = "noted" // idle IdleAfter more after the wake; the coordinator told once )
The idle watch: what the daemon knows of a session holding cards (docs/SPEC-FRIEND.md, idle wake).
const ( NotificationStateFile = "notifications.json" NotificationReadyText = "" /* 188-byte string literal not displayed */ NotificationBatchPrefix = "NOVA-FRIEND NOTIFICATION " NotificationWindow = 30 * time.Second NotificationRetryMax = time.Minute )
Notifications use the one receiver and the bus's pending entries, never a second consumer or a card scheduler (docs/SPEC-FRIEND.md, notifications; tla/FriendNotifications.tla).
const ( LaneMarkEvery = 30 * time.Second LaneMarkStale = 5 * LaneMarkEvery )
LaneMarkStale is how long a running mark stands unrefreshed: a lane refreshes its mark every LaneMarkEvery while its card runs, so one older than this is a lane gone with its daemon, and a new lane may claim the card.
const ( WindowFiveHour = "five_hour" WindowSevenDay = "seven_day" )
The windows a Claude subscription reports, in its own spelling.
const ( SessionQuiet = 10 * time.Minute SessionBound = 5 * time.Minute // ProveEvery is how long after the last check went in the next goes in while the // session is up, whatever else it says on the bus, timed from the ask: the sprint // server counts only an answered check, for sprint.FriendProofLive (fifteen // minutes), so a session that answers within SessionBound is proved again before // the last proof lapses (ProveEvery + SessionBound < FriendProofLive). ProveEvery = 8 * time.Minute // ReaskAfter is how long an unanswered check waits before it is asked again when the // session has not read it: a queueing harness keeps every copy, so a check is asked // again early only once the session has read the last (Presence.Read). ReaskAfter = time.Hour NoSessionAnswer = "no session answer" NotYetAnswered = "no session answer yet" // the daemon started; nothing has answered SessionCheckPrefix = "SESSION CHECK " PresenceFile = "presence.json" LogBatch = 1000 // log entries read per step; the rest the next )
Presence is whether the friend's SESSION is alive, never its daemon (docs/SPEC-FRIEND.md, presence). The finding of 2026-10-04: three friends read up with eight cards each while their harness apps were not running, because the daemon answered every ping itself. The proof is the session's: after SessionQuiet with no bus message from the session, the daemon delivers a session check carrying a fresh nonce through the adapter, the way a card goes in; only the session's own reply carrying that nonce counts; SessionBound with none and the friend is down, NoSessionAnswer; the next answer, or any bus message the session writes, brings it back up. The daemon's pong stays the daemon's and never counts.
const ( PresenceUp = "up" PresenceDown = "down" )
The presence, as the presence file says it.
const ( PushRenewEvery = time.Minute PushWriteBudget = 5 * time.Second )
PushRenewEvery is how often the daemon renews its friend's push proof on the bus while the session stays up: well inside bus.PushFresh, so a live daemon's proof never reads stale, and a dead one's does within PushFresh. PushWriteBudget bounds one write of it.
const ( RateBackoffFirst = 30 * time.Second // the first pause after a rate limit RateBackoffMax = 10 * time.Minute // the pause doubles up to this RateRaiseEvery = 10 * time.Minute // a clean stretch this long raises the cap one lane RateJudgeWithin = time.Hour // RateJudgeAfter lowerings within this are one judgment RateJudgeAfter = 3 )
The lane governor's numbers.
const ( OneThingLeft = "THE ONE THING LEFT: " ReaderFoundLabel = "The reader found: " )
The labels of a reworked brief's first lines, and of the server's lines it is made from.
const ( HeldByDaemon = "the daemon" HeldByFriendSync = "friend sync" )
The holders of an unaddressed LAND, as UnaddressedText names them.
const ( KindDir = "directory" KindFile = "file" KindMissing = "missing" KindSymlink = "symlink" // shown as "symlink to <target>" )
The kinds a path is, as a setting shows it.
const ( JobsDir = "jobs" MirrorsDir = "mirrors" JobFile = "JOB.md" )
The directories under her working directory that staging writes.
const ( StageRetryEvery = time.Minute MirrorFreshFor = 10 * time.Second MirrorCloneBudget = 30 * time.Minute )
StageRetryEvery is how long a job whose stage failed waits before it is staged again; a judgment stands, said once, until a stage of its repository or card succeeds. MirrorFreshFor is how long a fetched mirror serves stages without fetching again, so a burst of cards on one repository is one fetch. MirrorCloneBudget bounds a mirror's fetch: the first, of the whole repository, is the one slow step (every later one fetches only what is new).
const ( FinishedJobsKept = 8 PrunePerPass = 4 )
FinishedJobsKept is how many finished jobs' worktrees the daemon's cleanup keeps, the newest staged; the rest are pruned (Stager.Prune), at most PrunePerPass a cleanup, so the loop that runs it is held a few seconds at most.
const ( StatusFile = "status.json" PongFile = "pong.json" LogFile = "deliver.log" WatchFile = "watch.json" QueueFile = "inbox/QUEUE.json" )
The friend's files, one writer each. The state files live in the state directory (DefaultStateDir under the home directory, or --state-dir), never on the friend's volume: a background process on this platform may not touch a removable volume without the person's permission (measured 2026-10-04, "operation not permitted" on the mkdir). The daemon writes Status and the log; the pong verb writes Pong. The queue file is the coordinator's and the session's, under the working directory (SPEC-FRIEND.md, the files).
const ( StatusEvery = 5 * time.Second DaemonStale = 30 * time.Second )
DaemonStale is how old the status file may be while the daemon counts as up: it rewrites the file at least every StatusEvery.
const ( HarnessUnknown = "" HarnessRunning = "running" )
The harness evidence: whether the harness's process was seen in the process table. Advisory, shown and never deciding: a session run from its command line has no app to see, and an app that runs answers nothing. HarnessNotSeen is defined in alive.go ("not-seen").
const AccessibilityCheckScript = "use framework \"ApplicationServices\"\nreturn (current application's AXIsProcessTrusted() as boolean) as text\n"
AccessibilityCheckScript asks whether this process is trusted. It calls AXIsProcessTrusted and never AXIsProcessTrustedWithOptions, so it cannot prompt.
const AccessibilityRemedy = "grant Accessibility to this binary in System Settings, Privacy and Security, Accessibility; nova-friend does not ask"
AccessibilityRemedy is what a person does when the window step cannot type. The permission is granted to this binary. The tool never asks for it.
const ActedKept = 4096
ActedKept is how many message ids the daemon remembers it pushed into a turn that ended acted: a second delivery of one (the claim hands a message in again when its ack was lost) is dropped and acked, never pushed in twice. Past the memory, the message's receipt says acted all the same (Entry.Stage; docs/SPEC-BUS.md, message-receipts; tla/Bus2Receipts.tla, Take).
const ActivityEvery = 10 * time.Second
ActivityEvery is how often the daemon walks: the beat goes every BeatEvery and carries the last walk's answer in between.
const AliveEvery = 30 * time.Second
AliveEvery is how often the daemon asks the adapter whether its harness is alive (SPEC-FRIEND.md, the harness check): the session's last turn for a headless harness, the app in the process table for one with no headless route; an advisory fact for the status, never presence.
const AliveWithin = SessionQuiet + SessionBound
AliveWithin is how recent the session's last turn ending exit 0 must be for a headless harness to be alive: a quiet session is sent a session check every SessionQuiet, which has SessionBound to end, so a live session that gets no other turn still ends one within this.
const AnswerBound = 2 * Window
AnswerBound is how old the session's last answer may be while the friend is up: two windows, a ping each window and a challenge open for less than one, so a session answering every ping is never older than this.
const AntigravityData = ".gemini/antigravity"
AntigravityData is the harness's app data directory, under the home.
const AntigravityLedgerFile = "antigravity-ledger.json"
AntigravityLedgerFile is the ledger's file in the daemon's state directory.
const AntigravityOpen = "" /* 143-byte string literal not displayed */
AntigravityOpen is what a friend whose Antigravity refuses does.
const AntigravityTitle = "nova-friend"
AntigravityTitle heads every message nova-friend sends.
const BatchTakeEvery = 15 * time.Second
BatchTakeEvery is how often a batch-mode daemon asks the server to take her ready cards.
const BeatEvery = time.Second
BeatEvery is how often the daemon beats to the sprint server while its loop runs: the sprint's own number (internal/sprint FriendBeatEvery, one second; a friend is down after fifteen without one). It is also the loop's read block: one read of the stream per beat.
const BootstrapTries = 5
BootstrapTries is how many times a bootstrap is sent while launchd is still tearing the old agent down (it answers EIO, "Input/output error", for a second or so after the bootout, measured 2026-10-04).
const CapTailLines = 40
CapTailLines is how many of the lane's last output lines a capped card's report quotes.
const CardTurns = 2
CardTurns is how many turns a one-shot lane gives one card: a turn that ends without the card's RESULT.md hands the same card again once, then the card is reported to the coordinator and set aside.
const CodexAppServerBudget = 5 * time.Second
CodexAppServerBudget bounds one connection's dial, handshake and calls.
const CodexCheckRequeue = ReaskAfter - RecheckEvery
CodexCheckRequeue is how long a request for a pong stands unread in the queue before the same request is queued again in its place: the session check's re-ask (ReaskAfter) less one recheck, so the re-ask at the hour always finds the old one past its age and the session check is never held two hours.
const CodexWritableRoots = "sandbox_workspace_write.writable_roots"
CodexWritableRoots is the setting in CODEX_HOME/config.toml that lets a workspace-write sandbox write the friend's directory: [sandbox_workspace_write] writable_roots. The friend's directory is written there by its real path; a symlink there took no writes for ten hours on 2026-10-05.
const DSHPreset = "standard"
DSHPreset is the agent preset a friend's DeepSeek Harness opens new sessions under. A session under "minimal" makes every headless turn exit 1 before any write (measured 2026-10-04 and 2026-10-05, docs/SPEC-FRIEND.md, the dsh row); the owner set the desktop profile's selected default to "standard" by hand on 2026-10-04, and install now writes it. A session keeps the preset it was opened under: one opened under minimal stays so.
const (
DSHPresetEntry = "agent-preset-registry"
)
The patch entry that holds it: the desktop profile's patch layer, DSH_HOME/profiles/desktop/cordis.patch.yml, a YAML list of loader patch entries; the preset registry's config keys default and selectedDefault.
const DSHProgram = "/Applications/DeepSeek Harness.app/Contents/Resources/runtime/cli/bin/dsh"
DSHProgram is where the DeepSeek Harness desktop app ships its CLI on this platform; the app installs no link on PATH.
const DefaultBrokenAfter = 3
DefaultBrokenAfter is how many turns in a row the provider must refuse with the same reason before the session is broken (--broken-after).
const DefaultIdleAfter = 10 * time.Minute
DefaultIdleAfter is how long a session holding cards may write nothing before its daemon wakes it, and again before the coordinator is told (the friend row's idle setting, ten minutes when the row says none).
const DefaultLimitWait = time.Hour
DefaultLimitWait is how long a harness that refused at its limit and named no reset is down before a wake is tried.
const DefaultLoadWidth = 3
DefaultLoadWidth is how many lanes run while the load is above the row's bound.
const DefaultPacing = 0.80
DefaultPacing is the fraction of each subscription window the sprint may spend when the row names no pacing.
const DefaultReadSlots = 2
DefaultReadSlots is how many reads a friend runs at once when her row says none.
const DefaultSilentStop = 20 * time.Minute
DefaultSilentStop is how long a turn may print nothing before the daemon stops it (--silent-stop): a turn that prints keeps running however long it takes (the finding of 2026-10-04: a fixed ten-minute cap killed a friend's real work mid-turn).
const DefaultTokenCap int64 = 6_000_000
DefaultTokenCap is a card's token cap where the friend row names none.
const FinishWait = 10 * time.Second
FinishWait bounds a lane's finish to the sprint server; one not answered is left to friend sync, which reads the REPORT.md the lane wrote.
const HarnessFaultNoReport = "harness-fault: no report"
HarnessFaultNoReport is the fault of a lane run that exited 0 and left no REPORT.md or RESULT.md: the harness's, never the worker's failed attempt.
const HarnessNotSeen = "not-seen"
What the status says of the harness (Status.HarnessSeen): seen running, or not seen; HarnessUnknown when the adapter cannot tell. A harness run from its command line (dsh headless, codex exec, opencode run, gemini) is read by its session's last turn, never by an app: not seen is never down.
const HoldersBudget = 10 * time.Second
HoldersBudget bounds the current ownership view asked for an old report.
const HostFile = "host.json"
HostFile is the friend's host state in its state directory.
const IdleWalkEvery = time.Minute
IdleWalkEvery is how often the idle watch reads the session's newest write and the cards she holds.
const InboxEvery = BeatEvery
InboxEvery is how often the daemon reconciles her inbox with her row: every loop.
const KillDelay = 5 * time.Second
KillDelay is how long a signalled group gets to end before SIGKILL.
const LaneIdleAsk = 15 * time.Second
LaneIdleAsk is how long a lane the server gave nothing waits before it asks again.
const LaneMarkFile = "LANE"
LaneMarkFile is a job's lane mark, under jobs/<job>/.
const LaneOpenRetry = time.Minute
LaneOpenRetry is how long a lane whose session could not be opened waits before it tries again.
const LanesFile = "lanes.json"
LanesFile is the lanes' state in the state directory.
const LimitFile = "limit.json"
LimitFile is the friend's limit, in the state directory: the provider's limit the session is at and when it resets. The daemon is its one writer; no file is no limit.
const LimitTail = 2048
LimitTail is how much of the end of a command's output is read for a limit line: a harness says it last, and the body of a reply that only talks about limits is far from the tail.
const MachineStoppedWord = "STOPPED"
MachineStoppedWord is the machine's state word that cancels jobs.
const MaxDeliveries = 3
MaxDeliveries is how many times a message is handed into the session before the daemon gives up on it: a turn that fails leaves the message pending and the bus hands it in again once its claim opens (bus.ClaimAfter); the last failure acks it, with the failure on the record, so a message the session cannot take never comes back for ever. A turn the provider refused (ProviderRefused) counts toward nothing here: the session is at fault, not the message, and BrokenAfter says what happens instead.
const MaxFixKeyWords = 8
MaxFixKeyWords bounds the key words a report is grepped for: a long fix is checked by its first ones.
const OpenCodeConfig = "opencode.json"
OpenCodeConfig is the project config file opencode reads in its directory.
const OutboxRetry = time.Minute
OutboxRetry is how long a finish the server did not answer, or refused, waits before it is sent again; the report stays where it is, and friend sync may finish it first.
const OutputKept = 2048
OutputKept bounds how much of a turn's output the daemon keeps in its record: the head, enough to see what the session did with the message.
const PauseBeatAhead = time.Hour
PauseBeatAhead is how far ahead the friend's down beat sets its --until while the pause marker stands. Every beat sends it again, so it never lapses while she is paused; once a person clears the marker the next beat goes without --until and withdraws it.
const PauseFile = "PAUSED"
PauseFile is the marker in the state directory that holds the lanes down: it outlives the daemon, and nothing resumes until a person removes it (nova-friend resume).
const PresentSubject = "present"
PresentSubject is the subject of a friend's own request for the present: a message from her to herself with this subject (nova-bus send --as <me> --to <me> --subject present).
const PresentTextRule = "nova-friend: PRESENT"
PresentTextRule heads a present's text, so a session and a test know it at a glance.
const ProgressEvery = 3 * time.Minute
ProgressEvery is how often the daemon stamps progress on a card whose lane turn prints: the sprint's own number (internal/sprint ProgressEvery, inside the late rule's ten-minute window; docs/SPEC-SPRINT.md section 8, the rules table's row late).
const ReadAskEvery = 10 * time.Second
ReadAskEvery is how often the daemon asks its reader queue, which is the reader's beat.
const ReadBodyKept = 3500
ReadBodyKept bounds the body of a read's RESULT.md recorded as its finding.
const RecheckEvery = 10 * time.Second
RecheckEvery is how long the daemon waits before trying a deferred delivery again (Deferred: the session cannot take a turn now and nothing is wrong). The message stays in the daemon's hand meanwhile: it is never put back on the bus, never counted toward MaxDeliveries, never acked.
const ReportCap = 64 * 1024
ReportCap bounds the REPORT.md the daemon reads (friend sync's own cap): a verdict, a head and 600 characters need far less, and a larger report is noted and never read whole.
const ReportChars = 600
ReportChars is how much of a failed report rides on its finish.
const ReportWait = 2 * time.Minute
ReportWait is how long a lane the server says holds a card whose outbox has the report of a run before that no outbox step can ever finish (a RESULT.md alone, a REPORT.md with no Verdict: a run cut between its writes) waits before it finishes it failed itself. A report with a Verdict is the outbox step's alone, whatever it waits on (a LAND's head not yet origin's tip, a tip that cannot be read, a finish not taken): the lane never finishes it.
const RestLine = "and %d more: nova-bus recv --as %s --all"
RestLine is the envelope's line for the messages that did not fit in it: how many, and the command that prints every pending message whole.
const ResumeLabel = "answered by resume, not by the open chat"
ResumeLabel is the line the record carries for a turn answered by resume.
const RetiredDir = "inbox/retired"
RetiredDir is where a job whose card left her row goes, under her working directory.
const RetiredEpochs = "retired"
RetiredEpochs is the folder under the friend's working directory that keeps the items the epochs retired, named for its epoch: retired/epoch-<n>/inbox/<job> and retired/epoch-<n>/outbox/<job>.
const RunnerLogCap = 4 << 20
RunnerLogCap bounds the runner log the daemon reads: its last RunnerLogCap bytes.
const SeatCacheFor = 10 * time.Second
SeatCacheFor is how long the daemon keeps the seat holder it read from the sprint server: the authority of a message is never older than this (docs/SPEC-FRIEND.md, bus-authority-labels.w3).
const ServedBy = "daemon-writes-every-taken-card3"
ServedBy is the card that adds friend cards to the sprint server: a daemon whose server refuses the verb names it, so whoever reads the line knows which server change is missing.
const SessionCheckFilePrefix = "SESSION-CHECK-"
SessionCheckFilePrefix names the file a claude friend's session check is written as by the folder adapter: <dir>/inbox/SESSION-CHECK-<nonce>, the shape the seat's own folder adapter uses (internal/sprint, PROOF-<nonce>).
const SessionLimited = "limited"
SessionLimited is the status file's session while the harness is down at its limit: `session=limited kind=<k> until=<RFC3339>`.
const StaleAfter = 30 * time.Minute
StaleAfter is the stale bound: a delivery after this long with none is a present.
const StaleTurnLock = time.Minute
StaleTurnLock is how long the turn lock may be held while a headless adapter's own turn record says no turn runs before the session check goes in by the record (docs/SPEC-FRIEND.md, presence: the headless case): one step's race with a turn on its way into the adapter is never read as a stale lock.
const StopReturnReason = "owned process stopped"
StopReturnReason is the reason every stop-return names.
const StopReturnRetry = StatusErrorEvery
StopReturnRetry is how long a refused stop-return waits before it is sent again: the store's verb may be absent, and the lane step runs every second.
const StopReturnsKept = 200
StopReturnsKept bounds the stop-returns the lane state keeps once sent: the record of the acks, newest last.
const SupersedeChunk = 256
SupersedeChunk bounds the entries one ack of the superseded carries.
const SupersededShown = 64
SupersededShown bounds the ids the bus message names; the record says how many in all.
const TailKept = 64 << 10
TailKept bounds the output a lane's turn keeps for its tail: its last TailKept bytes.
const TakeRetry = 5 * time.Second
TakeRetry is how long a lane waits after a refused ask, or an answer it cannot run yet (its brief not in her inbox, its job not staged), before it asks again.
const TakeWait = 10 * time.Second
TakeWait bounds one ask to the sprint server.
const TipBudget = 10 * time.Second
TipBudget bounds the one ls-remote of Tip.
const TmuxPrefix = "friend-"
TmuxPrefix starts the name of every hosted session: friend-<name>.
const TokenPoll = 15 * time.Second
TokenPoll is how often a lane reads a running card's usage where the harness prints none as it runs (an OpenCode turn: its session's export).
const TokenPollEvery = 15 * time.Second
TokenPollEvery is how often a running card's tokens are read for the cap.
const ViewWhy = "the server does not serve friend cards, and the worker view names the card and its job with no brief"
ViewWhy is why a card the worker view names has no brief written for it.
const WakeMark = "wake=1"
WakeMark marks a ping as a wake check (nova-friend ping --wake): a line of its own in the ping's body.
const WallVerb = "wall"
WallVerb is nova-friend's verb that runs one command inside a lane's wall: `nova-friend wall --profile <p> --dir <d> --deny <self>... [--config-dir <c>] [--job <j>]... [--read <r>]... -- <command> <args>` (docs/SPEC-FRIEND.md, buds-in-the-wall-r.w5).
const Window = 3 * time.Minute
Window is how long either side waits before it decides the other is gone: the coordinator for a session pong, the daemon for a ping. One number on both sides (the contract of 2026-10-04: "3 minutes to start").
Variables ¶
var ActivityRoots = []string{"outbox", "inbox", "jobs", "."}
ActivityRoots are the places the walk reads, in this order, under her working directory: the outbox (her results), the inbox (the cards she was dealt), then the jobs and the rest of the directory, so a large clone cannot use the bound up before the outbox is read.
var AntigravityApp = App{Bundle: "/Applications/Antigravity.app", Name: "Antigravity"}
AntigravityApp is the desktop app the Antigravity adapter delivers into on macOS: the one harness with no headless route, so the one app check.
var AppBundles = map[string]string{
"claude": "com.anthropic.claudefordesktop",
"codex": "com.openai.codex",
"cursor": "com.todesktop.230313mzl4w4u92",
"antigravity": "com.google.antigravity",
"windsurf": "com.exafunction.windsurf",
"zed": "dev.zed.Zed",
"warp": "dev.warp.Warp-Stable",
}
AppBundles is the bundle identifier the window step looks up for a GUI harness. These are lookup ids, not a measured survey of installed apps. A harness with no entry, and not tmux, has no window.
var ClaudeTrim = []string{"--strict-mcp-config", "--disable-slash-commands", "--no-chrome", "--tools", "Bash", "Read", "Write", "Edit", "Grep", "Glob"}
ClaudeTrim is the trimmed call of a headless Claude Code run (the owner's finding of 2026-10-04: no MCP servers, no slash commands, no browser, six tools, which cut the context of each call from about 50k tokens to 12.7k). --tools takes every argument after it, so it is last, after the prompt.
var DefaultActivityLimits = ActivityLimits{Files: 2000, Time: 50 * time.Millisecond}
DefaultActivityLimits is what the daemon walks with: two thousand files, fifty milliseconds.
var DefaultLaneCaps = map[string]time.Duration{ "flash": 15 * time.Minute, "pro": 45 * time.Minute, "heavy": 90 * time.Minute, "frontier": 150 * time.Minute, }
DefaultLaneCaps is the wall cap of a lane's card by its tier, where the row names none.
var ErrBinaryOnRemovableVolume = errors.New("binary on a removable volume: launchd starts it and it does nothing")
ErrBinaryOnRemovableVolume is the refusal when the agent's binary is on a removable volume and cannot be copied under the home (docs/SPEC-FRIEND.md). launchd starts that binary and it does nothing.
var ErrLanguageServerNotRunning = errors.New("no antigravity language server is running: is Antigravity open?")
ErrLanguageServerNotRunning is returned when no Antigravity language server is running.
var ErrNoConfigDir = errors.New("harness claude wants --config-dir (or CLAUDE_CONFIG_DIR): the friend's own Claude config directory, written into the agent")
ErrNoConfigDir is the refusal of claude settings with no config directory: a friend on Claude Code has her own CLAUDE_CONFIG_DIR, and install writes it into the agent (run --config-dir) rather than a unit carrying it by hand.
var ErrNoSession = errors.New("no grok session is open")
ErrNoSession is WakeOf's refusal when no grok window is open in the directory.
var ErrNotDue = errors.New("not due")
ErrNotDue is a Held that did not ask this pass (the worker view is read once a ViewEvery): nothing is reconciled and nothing is said.
var ErrNotRealDir = errors.New("not a real directory")
ErrNotRealDir is the refusal when a path a harness setting names is a symlink or not a directory: a harness that resolves it works elsewhere or refuses (Codex took no writes into a symlinked writable root, 2026-10-05). Install never replaces a symlink; the remedy is to name the real path.
var ErrSessionInNoDB = errors.New("no opencode database read holds the session")
ErrSessionInNoDB is a session that none of the databases read holds: its tokens are unread, never zero.
var GoShimNames = []string{"go", "gofmt"}
GoShimNames are the commands the shims stand in for.
var Harnesses = append([]string{"opencode", "codex", "claude", "antigravity", "dsh", "gemini", "grok", "tmux"}, RefusedHarnesses...)
Harnesses are the harness names run and install take, in the order the help lists them; OpenCode, Codex, Antigravity, DSH, Gemini, Grok and tmux (a TUI hosted by nova-friend host) have a deliver command, the rest refuse honestly (Stub), the surveyed ones with their reason.
var HostPrompts = map[string]string{
"opencode": `^\s*[┃>]?\s*Ask anything`,
"grok": genericPrompt,
"aider": `^(\S+ )?>\s*$`,
}
HostPrompts is each hostable harness's idle prompt pattern, matched against the last non-empty line of the captured pane. It is data: --prompt on host overrides it for a harness that draws its prompt differently.
var OpenCodeRunFlags = []string{"--session", "--model"}
OpenCodeRunFlags are the flags of `opencode run` the adapter passes: the session of a turn, and the model of a read. The directory is never one: it is the process's working directory.
var PSArgs = []string{"-axww", "-o", "user=,pid=,args="}
PSArgs is the process listing every check reads: user, pid and the whole command line, never cut.
var ReadModels = map[string]string{
"frontier": "claude-fable-5-1",
"heavy": "claude-opus-5-5",
"pro": "claude-sonnet-5-5",
"flash": "claude-haiku-4-5-20251001",
}
ReadModels is the model of each tier for a claude account's reads, the table the bud runners carried.
var Refusals = map[string]string{
"copilot": "not installed here; the route is `copilot -p <text> --resume <id>`, after `copilot login`",
"cursor": "not installed here; the route is `agent -p --resume <chatId> <text>`, after `agent login`",
"amp": "not installed here; the route is `amp -x --thread-id <id> <text>`, with AMP_API_KEY",
"goose": "not installed here; the route is `goose run -n <name> -r -t <text>`, with a provider key",
"kiro": "not installed here; the route is `kiro-cli chat --resume-id <id> <text>`, after `kiro-cli login`",
"cline": "not installed here; the route is `cline --id <session> <text>` to the hub at 127.0.0.1:25463, after `cline auth`",
"aider": "no route: aider keeps no session to adopt, only a history file replayed into a new process",
"roo": "no route: Roo Code's sendMessage API lives inside VS Code, reachable only from another extension",
"windsurf": "no route: nothing documented reaches a running Cascade conversation from outside the app",
"zed": "no route: Zed is an ACP client; nothing documented reaches a running thread from outside",
"warp": "no route: `oz run message send` reaches cloud runs only; `oz agent run` starts a new run",
}
Refusals are the harnesses of the survey of 2026-10-04 (SPEC-FRIEND.md, the harness survey) with no adapter: each the one-line reason, the route the vendor documents where there is one, and what would make it real. None of them is installed on this machine; one with a route gets its adapter the day its binary and login are there.
var RefusedHarnesses = []string{"copilot", "cursor", "amp", "goose", "kiro", "cline", "aider", "roo", "windsurf", "zed", "warp"}
RefusedHarnesses lists Refusals in a fixed order, for the registry.
Functions ¶
func AdapterRemedy ¶
AdapterRemedy is what a friend on a harness with no deliver command does: the adapter card that gives it one, or a harness that has one.
func AgentAPI ¶
func AgentAPI(out string) (json.RawMessage, error)
AgentAPI reads what agentapi printed: its response, or its error (printed at exit 0 like a response).
func AllowDirs ¶
AllowDirs writes into dir's opencode.json that a tool call may touch each of paths and everything under it without a prompt (permission external_directory, a pattern map of path globs to allow), merged into what the file holds, written only when it changes. A headless opencode run auto-rejects a call that would prompt, and the turn ends there (measured 2026-10-04: a friend's working directory reached through its symlink in the home directory). It answers whether it wrote.
func AppRunning ¶
AppRunning says whether listing (ps with PSArgs) has a process of username that is app's main executable: its command line starts inside the bundle and names an executable called app.Name whose path, cleaned, is the bundle's Contents/MacOS/<Name>, so a launch through another spelling of the path (Contents/Resources/../MacOS/<Name>, the finding of 2026-10-06) is the app, and a helper or a longer name is not. ps keeps no argv boundaries, so every place the name ends (a blank, or the line's end) is tried.
func BatchFor ¶
BatchFor is one turn's text: the pong line to run first while a challenge is open, the daemon's word about the coordinator, then every message, oldest first, each as nova-bus recv prints it under a numbered rule, and each labelled by its sender's authority (authored). A single message with nothing else is its authored text alone.
func BatchTakeArgv ¶ added in v1.2.7
BatchTakeArgv is a batch-mode daemon's take of up to n of her ready cards: `take --as friend.<name> --max <n> --epoch <e>`, the server choosing which, in its order, cut to her room. The server refuses every worker's verb sent to it that names no epoch ("a worker's verb sent to the server names the epoch its worker holds"), so the take names the epoch her ready cards were handed at, the newest one her row last said.
func BenchRule ¶
BenchRule is the sentence every read prompt carries: the machine the friend runs on runs no go command, a Linux bench does.
func BriefFix ¶
BriefFix is the fix a brief's prelude asks of its attempt: its THE ONE THING LEFT line, else the server's 'The coordinator asks:' line, on one line; "" for a brief that asks none.
func BusLogEntries ¶
func BusLogEntries(ctx context.Context, st bus.Store, friend string, since time.Time) (realCount int, lastReal time.Time, err error)
BusLogEntries reads the bus store log for real messages from friend since since (docs/SPEC-FRIEND.md "Check": the facts, bus).
func CappedWords ¶
CappedWords is how a capped card's end names the cap, the words the sprint reads off its failed finish (internal/sprint ParseLaneCap): `capped at <cap> (tier <tier>, overrun <d>)`, overrun the card's wall past the cap when the lane ended it.
func CardText ¶
func CardText(job LaneJob, n, width int, sendLine, pong, notice string, seat string, msgs []bus.Message) string
CardText is one lane turn: the card and its three steps, every path absolute, the brief's text inline (a model that reads a path relative still has it), then what else rides along (the pong line first, the word about the coordinator, the bus messages waiting, each labelled by its sender's authority against seat).
func CheckFolderRoute ¶
CheckFolderRoute keeps the harness and session identity independent of the delivery route. The target must already be watched; the daemon never makes it.
func ClaimLane ¶
ClaimLane claims the job's card for the lane who at now: the mark is created when there is none (only one creator can win), taken over when the one there is stale, and kept when it is who's own. holder is the lane that holds it instead ("" when claimed).
func ClaudeAsyncBashHook ¶
ClaudeAsyncBashHook is the pure PreToolUse response for an opt-in Claude Code project hook (docs/CLAUDE-ASYNC-BASH-CANDIDATE.md). Every Bash call requests a native background task so an omitted timeout cannot hold the session when background tasks are enabled. The response changes only tool input; permission rules still decide whether the command may run.
func ClaudeInstallLine ¶
ClaudeInstallLine is the NOTE install prints for harness claude; every other harness gets none.
func ClaudeWaitLine ¶
ClaudeWaitLine is the one line a claude session runs as a background task (docs/SPEC-FRIEND.md, the Claude paragraph): the session's own blocking read of the bus, re-armed with the cursor it printed each time it returns. Claude Code has no command that puts a turn into a running session from outside; a background task's exit re-invokes the session. It is a command run once inside the session, not a flag, an environment variable or a wrapper at app start. wake is the file the daemon appends one line to per message, so a wait that missed nothing still returns.
func ClaudeWakePath ¶
ClaudeWakePath is the wake file of a claude friend: <state>/<friend>.wake, in the daemon's state directory, named on the line the session runs.
func ClearPause ¶
ClearPause is a person bringing the lanes up: the marker removed; whether one was there.
func CodexAddRoot ¶
CodexAddRoot is the text with root added to writable_roots: the key's lines replaced by one line holding every root there and root, the key added under its table when absent, the table appended when absent.
func CodexControlSocket ¶
CodexControlSocket is the app-server's control socket under home (CODEX_HOME).
func CodexDequeue ¶
func CodexDequeue(ctx context.Context, s CodexAppServer, thread, id string) (deleted bool, err error)
CodexDequeue withdraws one queued submission from thread's queue; deleted is false when it was no longer there (the session took it).
func CodexRoots ¶
CodexRoots is writable_roots in a Codex config.toml's text; found is false when the key is absent.
func ContextFull ¶ added in v1.2.7
ContextFull says a provider refusal's reason is one of those wordings.
func CopyExecutable ¶
CopyExecutable copies src onto dst and keeps it executable. dst is replaced only after the copy is complete, so a failure leaves a previous dst in place (docs/SPEC-FRIEND.md).
func CostLine ¶
func CostLine(t LaneTokens, rp RoutePrice, model string) (report, tokens, cost string)
CostLine is the Cost: line a REPORT.md carries under its Head: line, and the tokens: and cost: lines a RESULT.md does. The card is priced by the route row; opencode's own figure is kept beside it.
func CostOf ¶
func CostOf(t cardcost.Tokens, rp RoutePrice, model string) string
CostOf prices a card's tokens at the route row, rounded up to the cent; with no row, or a sheet that cannot price them, "unpriced (<why>)": never a guess.
func DSHArgs ¶
DSHArgs is the argument list of one delivery; the text travels on stdin ("-"), so it is never parsed as an argument.
func DSHNoPresetRemedy ¶
DSHNoPresetRemedy is what a friend whose dsh session runs under an agent preset does: nova-friend install and run refuse that session with it (PushProof), since no delivery into it can succeed.
func DSHSessionKey ¶
DSHSessionKey is the store's directory for the sessions of dir: the path with every separator a dash, one more dash in front and two behind (measured 2026-10-04 on the store: /Volumes/nova/ai/zhi is --Volumes-nova-ai-zhi--).
func DaemonStateDir ¶
DaemonStateDir is where a daemon run with no --state-dir keeps its files: StateDirIn(dir), made by mkdir; when that is refused (a background process on macOS may not touch a removable volume without the person's permission), DefaultStateDir, and why names the refusal for the record.
func DeadLaneReport ¶
DeadLaneReport is the REPORT.md the daemon writes for a dead lane: Verdict FAIL, and the runner's END line.
func DefaultDenySelf ¶ added in v1.2.7
DefaultDenySelf is the coordinator's self a lane wall denies when the daemon was given no --deny-self (nor NOVA_FRIEND_DENY_SELF): the seat's working root on this machine, <home>/<seat>-working, which holds the seat's self repository and its copies. A wall that denies nothing is refused (sandbox bad_profile, exit 125 for every lane), so a friend installed without the flag must not run lane-less. nil when the seat is unknown or is no plain name; the wall then refuses as it always did.
func DefaultReadWork ¶
func DefaultReadWork(dir string) (inboxCount, outboxCount int, newestName string, newestAt time.Time, err error)
DefaultReadWork reads directory entries of inbox/ and outbox/ under dir (docs/SPEC-FRIEND.md "Check": the facts, work).
func DefaultStateDir ¶
DefaultStateDir is the home directory's state directory for friend, ~/.nova-friend/<friend>: where a daemon from before the state moved under --dir kept its files, and where one goes when its directory refuses them (DaemonStateDir).
func EndReport ¶
EndReport is the REPORT.md a lane writes for a card whose run ended without one: HOLD with the pushed head when the friend's branch has one (friend sync keeps a HOLD's head when it is origin's tip), else FAIL; one paragraph naming the lane, how the run ended and the head. A card the lane ended at its cap is a HOLD, head or none, and its report quotes the last lines of the lane's output after the paragraph, each indented four spaces (lane_cap.go).
func Envelope ¶
func Envelope(seat string, msgs []bus.Message, now time.Time, me string, limit int, notice, pongCommand string) (text string, shown int)
Envelope is the one turn that carries every pending message when the session is free (docs/SPEC-FRIEND.md, the loop): the pong line first while a challenge is open, the daemon's word about the coordinator, a count, then each message oldest first as `[i/n] <id> from=<f> at=<RFC3339> age=<m>m subject=<s>` and its body, the age taken at now. With limit above zero the text, rest block included, stays within it: a message goes in only while the RestLine for those after it still fits (the first always goes in, even when it alone passes the limit), and the rest are named under RestLine for me by as many of their lines as fit after the count. It answers the text and how many messages it carries, a prefix of msgs: exactly those are acked when the turn is accepted. A single message with nothing else is its authored text alone. Every message retains its sender's authority label (docs/SPEC-FRIEND.md, bus-authority-labels.w3). A function of its arguments.
func ExitTimeout ¶
ExitTimeout is the plist's ExitTimeOut, DefaultExitTimeout when it has none.
func FaultDownText ¶
FaultDownText is the one judgment the seat is told when a row's lanes hit the same harness fault FaultRepeats times within FaultWithin: the subject and the body, naming the reason the row is down with and until when.
func FaultWords ¶
FaultWords is a harness fault as the record and the row say it: the fault and the harness's first error line ("the harness printed no error line" when it printed none).
func FindStateDir ¶
FindStateDir is where a reader looks for friend's state when no --state-dir names it: StateDirIn(dir) when a daemon has written its status there, else the home directory's (a daemon from before the move, or one whose directory refused it).
func FinishArgv ¶
FinishArgv is the sprint server's failed finish of a card whose run ended without the friend's report: `finish --as friend.<name> <card>@<gen> --epoch <n> --failed [--head <sha>] [--branch <b>] --report <text>`, the report as friend sync words it ("friend <name> <verdict>: <paragraph>").
func FinishNote ¶
FinishNote is the bus note to the coordinator at a lane's finish: the subject and body.
func FixAddressed ¶
FixAddressed says a report addresses fix: it names (case-insensitively, anywhere) at least half of the fix's key words, rounded up; a fix with none is addressed. missing is the key words it does not name.
func FixKeyWords ¶
FixKeyWords is what a report on fix is grepped for: its distinct words of four or more letters, digits or underscores, lower case, the empty ones (fixStopWords) left out, the first MaxFixKeyWords of them.
func FlockHeld ¶
FlockHeld says whether another process holds an exclusive flock on path: the probe codex itself makes for a thread's writer lock (try_lock, and WouldBlock means an active writer). A path that does not exist is held by nobody.
func FolderCheckLine ¶
FolderCheckLine is the NOTE install and run print for a claude friend: where her session check lands, and what a live session runs to answer it.
func FriendCardsArgv ¶
FriendCardsArgv is the worker verb the daemon sends the sprint server for her held cards.
func FundsJudgmentText ¶
FundsJudgmentText is what the coordinator is told when a friend's provider is out of funds: one judgment.
func GeminiArgs ¶
GeminiArgs is the argument list of one delivery: the frame, apart from the transport.
func GoShimName ¶
GoShimName says whether argv0 names a shim (this binary run as go or gofmt, by symlink).
func GoShims ¶
GoShims makes dir hold a go and a gofmt that are this binary (self) by symlink, so that run by those names it refuses (GoShimName, GoRefusal): no script, nothing to drift. Links already right are kept.
func GrokInstallLine ¶
GrokInstallLine is the NOTE install prints for harness grok. Every other harness gets none. session is --session, the wake file, empty when the session chooses the path.
func GrokMonitorLine ¶
GrokMonitorLine is the one line the open session runs so a delivery is a turn in that window. An empty wake is the placeholder the session replaces with its own absolute path. It is a command run in the session, not a flag or a wrapper at app start.
func GrokWakePath ¶
GrokWakePath is the wake file install names for a grok friend when --session names none: <state>/<friend>.wake, under the daemon's state directory, so no unit carries a path typed by hand.
func HarnessFirstError ¶
HarnessFirstError is the first line of a harness's output that says an error, one line, at most 200 bytes; "" when none does.
func HeldVia ¶
func HeldVia(friend string, ask func(ctx context.Context, argv []string) (string, error), view func(ctx context.Context) (string, error), now func() time.Time) func(context.Context) (Row, error)
HeldVia is the daemon's Held over the sprint server: friend cards <friend> (ask), its answer read by ParseHeld, which carries each card's brief. While the server refuses that verb (a server that does not serve it yet: Refused), the worker view (view, GET /api/view/worker?as=<friend>) says which work cards are on her row and the job each is delivered as, with no brief: her inbox is counted against it and a job whose work card left is retired, and a held card with no BRIEF.md is said missing and not written. The view is read once a ViewEvery (ErrNotDue between), and friend cards asked again once a ServedEvery, each refusal said in the Row's Note; with view nil a refusal is NotServed, once a ServedEvery (ErrNotDue between); an ask the server did not answer is its error.
func HostPrompt ¶
HostPrompt is the idle prompt pattern a hosted harness gets: override when given, else the harness's own from HostPrompts; src is its source text, as saved in the friend's state. A harness with none and no override is refused with the names there are.
func Install ¶
func Install(ctx context.Context, a Agent, uid int, run Launchctl, write func(path string, data []byte) error, wait func()) (path string, ran []string, err error)
Install writes the plist and loads it. A binary on /Volumes is copied under the home first (PlanBinary); a copy that cannot be made is refused and nothing is written (docs/SPEC-FRIEND.md). Then a bootout of whatever that label runs now (nothing loaded is fine), a wait until launchd no longer holds the label (WaitReleased), then a bootstrap into the user's domain, sent again after wait() while launchd answers EIO, so running it again replaces the agent with the same result. It answers the plist's path and the commands it ran.
func InstalledBinary ¶
InstalledBinary is the copy of a removable-volume binary, under the home, off /Volumes (docs/SPEC-FRIEND.md).
func IsPresentRequest ¶
IsPresentRequest says m is the friend's own request for the present.
func IsRealMessage ¶
IsRealMessage reports whether a message subject is a real turn message (not ping, pong, daemon-pong or keepalive) (docs/SPEC-FRIEND.md "Check": the facts, bus).
func IsWake ¶
IsWake says whether a ping's text asks for a wake check: one of its lines is WakeMark (docs/SPEC-FRIEND.md, session-pong.w1).
func JobText ¶
JobText is a staged job's JOB.md: the card-contract shape (docs/SPEC-CARD-CONTRACT.md), the checkout, the branch, the outbox report and the finish.
func LaneCap ¶
LaneCap is the wall cap of a card of tier: the row's (caps) when it names one above zero, else DefaultLaneCaps'; a tier neither names (none was read for the card) is capped at the longest default, frontier's, so a card whose tier is unknown is never cut shorter than it could be owed.
func LaneContext ¶
LaneContext is ctx marked as a lane's.
func LaneDirOf ¶
LaneDirOf is the job directory ctx carries, else def: a harness's run in a lane goes there.
func LaneMarkEnded ¶
LaneMarkEnded is the mark of a finished card: "ended: card finished by <who>".
func LaneMarkRunning ¶
LaneMarkRunning is the mark of a running lane: "running: <who> at <RFC3339>".
func LaneSeed ¶
LaneSeed is the first turn of a lane's new session: who the friend is, from her own files, and what each later turn will be.
func LaneTakeArgv ¶ added in v1.2.7
LaneTakeArgv is lane n's ask of the sprint server: what it holds, else its next card. It names the worker's row and the lane and nothing else: no card, no epoch.
func LanguageServer ¶
LanguageServer finds the antigravity language server in `ps -axo user=,pid=,args=` belonging to username: its pid and CSRF token.
func LastResult ¶
LastResult is the newest turn's line of the daemon's log (the line a turn's end writes, "<RFC3339> subject=... exit=<n>"): when it ended and its exit. No log, or no turn in it, is the zero time.
func LimitAlikeText ¶
LimitAlikeText is the one judgment the coordinator is told when three lanes in a row ended with the same first error line and none names a limit or a credit or quota refusal the daemon's table knows (cmd/nova-friend/limit.go, RefusalWatch): the line, so the wording is added or the cause is found, never a silent fourth retry.
func LimitDownText ¶
LimitDownText is what the seat is told when friend's harness hits its limit: the subject, and a body with the line that shows why and until when on her row (nova-sprint friend down --reason --until).
func LimitUnreadText ¶
LimitUnreadText is the one judgment the coordinator is told when friend's harness refused at its limit with a text that names no reset this reads: the text, the rest she is held for, and the line that sets the true reset.
func LimitUpText ¶
LimitUpText is what the seat is told when friend's session answered the wake after the reset.
func ListenPorts ¶
ListenPorts reads the ports out of `lsof -Fn` (one n<host>:<port> line per socket), in the listing's order.
func Load1Of ¶
Load1Of reads the one-minute load off `sysctl -n vm.loadavg` ("{ 1.23 1.50 1.60 }") or /proc/loadavg ("1.23 1.50 1.60 1/300 12345").
func LockPath ¶
LockPath is the writer lock codex holds on thread while a process has it open for writing, under home (CODEX_HOME).
func LogPath ¶
LogPath is the daemon's own log in the state directory: one line per delivery (launchd's own log is elsewhere: Plist).
func NewestCodexSession ¶
NewestCodexSession resolves the saved thread before probing its writer lock (SPEC-FRIEND.md, Codex). Only the index and first session_meta line are read.
func NewestConversation ¶
NewestConversation picks the first conversation of the summaries query (newest first, as `sqlite3 -json` printed it) whose workspaces hold one of dirs.
func NewestDSHSession ¶
NewestDSHSession is the most recently modified session of dir under the sessions root: the directory names are the session ids.
func NewestWrite ¶
NewestWrite is the newest modification time of a file under the roots of fsys, zero when there is none (a root that is not there, an empty tree). It reads at most lim.Files files and runs at most lim.Time by now's clock, never descends into activitySkip, and reads a root named earlier once.
func NotHers ¶
NotHers is the refusal of a report on a card that is no longer hers: never finished, with the line naming who holds it now, as the beat's running list says (a card id or job to the friend whose lane runs it), else that no row the daemon reads names one.
func NotificationCategory ¶
NotificationCategory bounds unread useful input to one batch of each category; report backpressure cannot consume the urgent category's capacity.
func NotificationKey ¶
NotificationKey is the durable enqueue family: one global ready wake, or a batch's immutable message-id fingerprint. Only exact notifier prefixes participate.
func OutboxFinishArgv ¶
OutboxFinishArgv is the finish a friend's report gives her card c (its job's card, epoch and generation): LAND with a full sha Head finishes at that head with the report's first paragraph, as friend sync words it; any other verdict (HOLD, FAIL, a LAND with no full sha Head) is --failed, with a HOLD's or FAIL's full sha Head kept, and the report's first ReportChars characters. The branch is the brief's.
func PacingJudgmentText ¶
func PacingJudgmentText(friend string, paced, width int, pacing float64, use string) (subject, body string)
PacingJudgmentText is what the coordinator is told when a friend's lanes are paced below half her row's width: one judgment.
func PacingOf ¶
PacingOf is the pacing a row's setting gives: the setting when it is a fraction in (0, 1], else DefaultPacing.
func PacingText ¶
PacingText is a pacing fraction as a percent: "80%".
func ParseJob ¶
ParseJob reads a friend's job directory name, <id>~<epoch> with .g<gen> after it from the card's second generation (nova-sprint friendJobOf); gen is 1 when it has none.
func ParseLaneCaps ¶
ParseLaneCaps reads the row's lane caps off her beat's answer (row_lane_caps=flash:15m,pro:45m,heavy:1h30m,frontier:2h30m, beside row_mode and row_width); ok is false when the answer carries none, or one with a pair that is no tier:duration above zero.
func ParseMachine ¶
ParseMachine reads the machine's word off a beat's answer (`machine=RUNNING` or `machine=STOPPED`); ok false when the answer carries none (a server before the word).
func ParsePing ¶
ParsePing reads the nonce, seat and since off a ping's text; ok is false when the text is no ping. A ping with no seat line is from an unnamed coordinator: the nonce still counts.
func ParseProfile ¶
ParseProfile reads the friend's wall profile off her beat's answer (row_profile=<name>, beside row_mode and row_width); ok is false when the answer carries none.
func ParseReadSlots ¶
ParseReadSlots reads the friend's read slots off her beat's answer (row_read_slots=<n>, beside row_mode and row_width); ok is false when the answer carries none.
func ParseRow ¶
ParseRow reads the friend's row off her beat's answer (nova-sprint friend beat prints row_mode=<mode> row_width=<n>, as friend sync last wrote her nova-config row); ok is false when the answer carries none.
func ParseShown ¶
func ParseShown(data []byte) (map[string]ShownEntry, error)
ParseShown parses JSON representing shown state.
func PauseBeat ¶
PauseBeat is the friend's beat while the pause marker (its line, ReadPause) stands: down until PauseBeatAhead from now, with the provider's exact message as the reason. `friend beat <friend> --until <t> --reason <r>` is a worker's verb the sprint server serves; while her last beat says so she is down and the dealer deals her nothing (docs/SPEC-SPRINT.md).
func PermissionRejection ¶
PermissionRejection is the first line of out that says a permission was refused, one line, at most 200 bytes; empty when none does.
func PingText ¶
pingText is the ping as the session reads it: the nonce, the seat, and the one line to run, so a small model gets it right.
func PlanBinary ¶
PlanBinary is the path the plist will name. A binary off /Volumes is itself. A binary on /Volumes is copied to InstalledBinary before the plist is written; a home that is empty or itself on /Volumes is refused, because a copy there would stay on the wall (docs/SPEC-FRIEND.md).
func PlatformPermitted ¶
PlatformPermitted is false where the platform cannot hold the permission. It does not call run and it does not ask. The window step then refuses with the same remedy as a missing grant (docs/SPEC-FRIEND.md, Reach).
func PlistArgs ¶
PlistArgs is the ProgramArguments array of a launchd plist, in order; nil when the plist has none or cannot be read as XML.
func PlistDriftLine ¶
PlistDriftLine is the line a daemon says on start when its own arguments (running, after the program's name) differ from the installed plist's: a launchctl kickstart restarts the agent launchd loaded, with the arguments it read then, so an edit to the plist is lost until it is booted out and bootstrapped again (the finding of 2026-10-05). The daemon's part of each is compared, from its verb "run" on (the secrets wrap and the binary's path are the plist's own). Empty when there is no plist, it names no run, or the two agree.
func PongLine ¶
PongLine is the session pong as it travels on the bus: pong <nonce> queue=<n> working=<n> width=<n>.
func PongNonce ¶
PongNonce is the nonce a pong body answers: a daemon-pong's or a session pong's; ok is false when the body is neither.
func PongRequest ¶
PongRequest reads a delivery's text for the pong it asks for: its kind (PongCheck for a session check, else PongWake), the nonce of its pong command, and whether it asks for nothing else (a session check, a wake turn, an idle wake, which a newer request of its kind supersedes). A delivery carrying a bus message is never only a request.
func PresentText ¶
func PresentText(friend, seat string, at time.Time, queue []QueueLine, skipped Skipped, note *bus.Message, notice, pongCommand string) string
PresentText is the present turn's text: the pong line first while a challenge is open, the daemon's word about the coordinator, then who she is and who has the seat, her live queue, the skipped line, and the newest coordinator note (as the session reads it under the seat's authority), or that there is none.
func ProgressArgv ¶
ProgressArgv is the sprint server's verbs that stamp progress on the cards, one for the cards of each epoch, in the order of the epochs: `progress --as friend.<friend> <card>... --epoch <n>`, her row as the holder, as FinishArgv names it. Only the holder's stamp is taken: the server refuses one for a card she does not work, and one sent as her bare name (held by friend.<name>, not <name>).
func PromptPattern ¶
PromptPattern compiles a prompt pattern, panicking on a bad constant.
func ProviderLimit ¶
ProviderLimit reads the tail of a lane turn's output (the last LimitTail bytes: a harness says it last) for a rate limit or out of funds, out of funds first: OutOfFunds, RateLimited, or nil. A line with its reset beside it ("Insufficient AI Credits ... will refresh 6:52 PM") is the harness's own limit (Limits: down until the reset, then woken), never out of funds here.
func ProviderRefusal ¶
ProviderRefusal reads a failed turn's output for a provider's refusal: the error type and the head of its message, one line; ok is false when the output carries none, or only a transient one.
func PublishCost ¶
func PublishCost(outbox string, t LaneTokens, rp RoutePrice, model string) error
PublishCost writes the card's cost into its outbox: the Cost: line into REPORT.md, which friend sync reads, and the tokens: and cost: lines onto RESULT.md when it is there. A report not there is not made.
func PushedHead ¶
PushedHead is the head the friend pushed for card c: the branch its brief's STATUS line names, read as origin's remote-tracking ref in a clone under dir's jobs/<job>/ (a push writes it; no network is asked). Empty when the brief names no branch or no clone holds the ref; branch is the brief's either way.
func Pushing ¶
func Pushing() []string
Pushing is the harnesses whose adapter has a deliver command, in the order of Harnesses.
func Quoted ¶
Quoted is a message from a sender that is not the seat holder, as the session reads it: a fixed header saying who sent it and that it is data, then every line of the message behind "> ", so no line of it can stand as the daemon's own or as an instruction (docs/SPEC-FRIEND.md, bus-authority-labels.w3).
func RateJudgmentText ¶
RateJudgmentText is what the coordinator is told when a friend's lane cap was lowered RateJudgeAfter times within RateJudgeWithin: one judgment.
func ReadBeginArgv ¶
ReadBeginArgv begins an asked read.
func ReadPrompt ¶
ReadPrompt is the one turn a read runs: do READ.md, stop when RESULT.md is written.
func ReadQueue ¶
ReadQueue is the queue file's counts; a file that is not there counts zero, and a file that is no queue is an error the caller shows.
func ReadQueueArgv ¶
ReadQueueArgv is the sprint verb that is the reader's beat and answers its queue.
func ReadReturnArgv ¶
ReadReturnArgv returns a read that has no verdict, with why.
func ReadVerdict ¶
ReadVerdict reads a read's RESULT.md: its verdict (ok or broken; "" when there is none), and the finding recorded with it, the report line then the body.
func ReadVerdictArgv ¶
ReadVerdictArgv records a read's verdict (ok or broken) with its finding and usage.
func RealExec ¶
func RealExec(ctx context.Context, dir, name string, args []string, stdin string) (string, int, error)
RealExec runs the command through os/exec: the program directly, never a shell, so a message's text is never interpolated. No clock bounds it: a turn that prints keeps running however long it takes, and the daemon stops one silent past its SilentStop by cancelling ctx (the finding of 2026-10-04: a fixed ten-minute cap killed real work mid-turn). Every write to stdout or stderr is said to the watch in ctx (WithOutputSeen). The command is its own session leader (Setsid), and on a cancel the whole group is signalled, SIGTERM then SIGKILL after KillDelay: a harness that forks (opencode run does) leaves no orphan behind a stop. On a nonzero exit the output carries the head of stderr after stdout: a harness says why it refused there (dsh does).
func Record ¶
Record appends one line to the daemon's log; a log that cannot be written is not a reason to stop delivering, so the error is answered for the status file and nothing else.
func RescueStray ¶
RescueStray moves a report a run wrote under a relative spelling of the outbox (the job directory joined with the outbox path less its leading slash: the stray tree of 2026-10-07) into the outbox, REPORT.md and RESULT.md each when the outbox lacks it; it answers the files moved.
func ResentLine ¶
func ResentLine(d AntigravityDelivery) string
ResentLine heads a delivery sent again into the conversation that reads.
func ResumeArgs ¶
ResumeArgs is the codex command line that resumes session (empty: the newest thread of the working directory) with text as its next turn.
func ReworkedBrief ¶
ReworkedBrief is a reworked card's brief with its fix first: STATUS; THE ONE THING LEFT, the fix; The reader found, the finding (or why the attempt exists when no reader found anything); the carried head and the branch it is carried onto; how the report is checked; then the rest of the prelude as the server wrote it, and the card with its STOP the fix alone. A brief that asks no fix, and one already reworked, are answered as they are.
func RowConfigDir ¶
RowConfigDir reads the friend row's config_dir off her beat's answer (row_config_dir=<dir>, the directory her claude lanes run with as CLAUDE_CONFIG_DIR); empty when the answer carries none.
func RunWall ¶
RunWall is the wall verb: args are its flags, "--", and the command; env is the environment the command gets inside the wall (its HOME is the one the deny list is under). It prints nothing on stdout but the command's own, so a harness's answer is read through it as it is; a refusal is one WALL REFUSED line per problem on stderr and sandbox.ExitRefused. The answer is the command's exit.
func RunnerEnded ¶
RunnerEnded reads a runner's log for the job: dead is true when the job's last event is an END whose last word is report=no and no LIMIT came after the START before it; end is that END line.
func RunnerLog ¶
RunnerLog is the log of the runner beside her working directory dir, its last RunnerLogCap bytes: dir's runner.log, else the one in the directory her working directory (its links resolved) is in; "" when there is none.
func RunsCards ¶
RunsCards says harness runs each card as a process of its own (a CardRunner) when its row is one-shot: it has no session to push a turn into, so install and run owe it no deliver-command refusal; its session check goes in by the folder (FolderCheck) for a live session to answer. NewDeliverer answers its batch adapter, the wake file (ClaudeWake); NewClaude is the one that runs cards.
func SessionCheckFile ¶
SessionCheckFile is the path a check carrying nonce is written to for the friend whose directory is dir.
func SessionCheckText ¶
SessionCheckText is the check as the session reads it: the nonce, and the one line to run with nothing to fill in, sent to to (the seat, else the coordinator; the pong verb's own default when empty).
func SessionCost ¶
SessionCost is the cost of a session from its export: the sum of its assistant messages' costs. The export may be preceded by a line of its own (opencode says what it exports on stderr); the JSON starts at the first '{'.
func SessionMissing ¶ added in v1.2.7
SessionMissing says a turn's first error line says the session is gone.
func SnapEpoch ¶ added in v1.2.7
func SnapEpoch(dir string, row Row, keep map[string]bool, asked, now time.Time, record func(string)) (int, error)
SnapEpoch moves every older-epoch inbox and outbox item under dir to the retired folder named for its epoch, at the sprint's epoch now (Row.Epoch, her row's answer): every inbox and outbox job whose name parses to an epoch older than it (ParseJob), that no lane runs (keep) and that no card on her row holds (row.Cards), and whose directory stood before the ask began (asked, as the inbox's retire guards friend sync's write), is moved whole, so finished work is kept, never deleted, and the live folders start the new epoch empty. A job whose name parses to no epoch, and one that is no single path element, is never moved (a job any other hand put there: docs/SPEC-FRIEND.md, the inbox). record gets one line per move; the first error is answered, the rest still moved. It answers how many moved. Zero is a sprint epoch of no card's naming: nothing is retired on it.
func StageJudgmentText ¶
func StageJudgmentText(friend string, n *NotStageable) (subject, body string)
StageJudgmentText is what the coordinator is told of a stage that waits on a person: one judgment, with its remedy.
func StaleNonce ¶
StaleNonce says a challenge sent at sent is past the window at storeNow, both the store's clock: dropped, never answered.
func StateDirIn ¶
StateDirIn is the daemon's state directory under the friend's working directory, <dir>/.nova-friend: inside the directory her session may write, so a sandboxed session's pong lands where the daemon reads it (the finding of 2026-10-05).
func StopReturnArgv ¶
StopReturnArgv is the store's verb for one stop-return, as the wire of 2026-10-08 says it.
func SupersededNotices ¶
SupersededNotices is the supersede rule (docs/SPEC-FRIEND.md, the loop): of the daemon's own notices not yet in a turn, oldest first, each of which a newer one exists maps to the newest's id. Those are dropped, never delivered, and each is recorded with superseded=<that id>. It reads only the notices the daemon itself raised, never a message on the bus. A function of its argument.
func SupersededReason ¶
SupersededReason is the reason a message the present replaced is acked with.
func TakeArgv ¶
TakeArgv is the coordinator's verb that takes a dealt, unstarted card back from the friend for the dealer: `friend take <friend> <card> --reason <why>`. The sprint server does not serve it to a friend's daemon (it is the coordinator's class, and the server runs only the workers' verbs), so the lanes never send it: they ask the coordinator (TakeBackNote).
func TakeBackNote ¶
TakeBackNote is the bus note that asks the coordinator to take a card back for the dealer: the subject, and a body naming the card, why, and the exact verb to run (TakeArgv).
func Text ¶
Text is a message as the session reads it, the shape nova-bus recv prints: the header line, a blank line, the body ending in a newline.
func TextLimit ¶
TextLimit is the most bytes of text d takes as one turn: its own TextLimit() when it has one above zero, else BatchBytes. The daemon's envelope is cut to it (Envelope).
func TmuxFor ¶
TmuxFor points a Tmux deliverer at the friend's hosted session: the session and prompt host saved in stateDir, else friend-<name> and the generic prompt. Any other deliverer is left alone.
func TmuxSession ¶
TmuxSession is the tmux session that hosts the friend name.
func TokenCapOf ¶
TokenCapOf reads the row's token cap off her beat's answer (row_token_cap=<n>, beside row_mode and row_width; 0 is no cap); ok is false when the answer carries none, or one that is no whole number at or above zero.
func TokenCapReport ¶
TokenCapReport is the REPORT.md of a card whose lane was stopped at the per-card token cap: HOLD with no head, one paragraph naming the cap, the tokens and turns it had spent and the last step; the card goes to a bud and whatever was pushed is a draft only.
func TokensSQL ¶
TokensSQL is the query for the tokens of a session and its children from opencode's database.
func TypeScript ¶
TypeScript is the osascript that brings bundle frontmost, types text and submits it with Return (key code 36). It never asks for permission.
func TypedLine ¶
TypedLine is text as the one line a TUI is typed: each newline shown as " ⏎ ", as the Grok adapter does (SPEC-FRIEND.md, "Hosted in tmux").
func UUIDv7Time ¶
UUIDv7Time is when a UUIDv7 (Codex's ids) was made: its first 48 bits, Unix milliseconds; ok is false for an id that carries no time.
func UnaddressedLand ¶
UnaddressedLand is the one fix check of a LAND, the daemon's outbox pass's and friend sync's (cmd/nova-sprint, friendFinish, the finish of friend sync, friend reconcile and collect): held is UnaddressedText when report does not address the fix brief asks (BriefFix, in either form), "" when it does or when brief asks none. A held LAND is finished as a HOLD, its head kept.
func UnaddressedText ¶
UnaddressedText is the first words of the finish the holder by (the daemon, or friend sync) sends for a LAND whose report does not address THE ONE THING LEFT.
func Undriven ¶
Undriven says nova-friend can push nothing into a session of harness through d: a Stub, with why and the remedy (AdapterRemedy); ok is false for an adapter with a deliver command.
func Uninstall ¶
func Uninstall(ctx context.Context, a Agent, uid int, run Launchctl, remove func(path string) error) (ran []string, err error)
Uninstall boots the agent out and removes its plist; an agent that is not there is fine.
func WaitReleased ¶
func WaitReleased(ctx context.Context, run Launchctl, target string, timeout, poll time.Duration, sleep func(time.Duration)) (time.Duration, error)
WaitReleased waits until launchd no longer holds the service target (gui/<uid>/<label>) after its bootout: `launchctl print <target>` asked every poll, until it no longer finds the service (anything but exit 0 with the service's own `<target> = {` block), at most timeout. A bootstrap sent while launchd is still removing the old service is refused with "37: Operation already in progress" for as long as the old daemon takes to exit (about 5 s, the seat's adopt runs of 2026-10-07), more than BootstrapTries one second apart. It answers how long it waited, and on timeout an error naming the label and the seconds.
func WakeLine ¶
WakeLine is text as the one line a monitor event is: the monitor makes an event per line, and a flood of lines is how the harness stops a monitor (its guide's "Volume Control"), so a newline in the text becomes " ⏎ ".
func WakeOf ¶
WakeOf is the wake file a delivery goes to: the file a `tail` tails under the grok session open in dir, from the harness's active_sessions.json (pid and cwd per open window) and the process listing (`ps -axww -o pid=,ppid=,args=`). A named wake must be that file. A session whose pid is not in the listing is a stale record, not a session. No window in dir is ErrNoSession.
func WakePingText ¶
WakePingText is a wake check as the coordinator sends it: the ping, and WakeMark. The daemon answers it at once as any ping and, the session being free, pushes the pong line in as its own turn, so the session is asked even with no message waiting (docs/SPEC-FRIEND.md, session-pong.w1; tla/Friend.tla, WakeTurn).
func WakeTargets ¶
WakeTargets is the friends a wake pass pings (docs/SPEC-FRIEND.md, "The wake ping loop"): the rows whose status is up, never the coordinator itself and never a friend in never, sorted. A friend held or down is not asked: a hold is the coordinator's word and a down friend has no daemon to push the ping in.
func WakeText ¶
WakeText is the turn that wakes a session after its reset: one word back, the nonce, so only a session that ran this turn answers it.
func WakeTurnText ¶
WakeTurnText is a wake turn's whole text: the exact pong line, and nothing else (docs/SPEC-FRIEND.md, session-pong.w1).
func WithCost ¶
WithCost is report with line under its Head: line (at the end when it has none); a report that already carries a Cost: line is returned as it is.
func WithLaneDir ¶
WithLaneDir is ctx carrying dir, the job directory the lane's harness runs in (LaneJob.Dir).
func WithOutputSeen ¶
WithOutputSeen is ctx carrying seen, called each time the command a delivery runs prints to stdout or stderr: a turn that prints is working, and only a turn silent past the daemon's SilentStop is stopped.
func WithOutputTail ¶
WithOutputTail is ctx carrying tail, handed each write the command a delivery runs prints to stdout or stderr.
func WorkspaceConversations ¶
WorkspaceConversations is every conversation of the summaries query, in its order (newest first), whose workspaces hold one of dirs.
func WriteLanes ¶
WriteLanes is the lanes' state written whole to stateDir.
func WriteNotificationState ¶
func WriteNotificationState(dir string, s NotificationState) error
func WritePause ¶
WritePause records the exact provider message that held the friend down.
func WritePresence ¶
func WritePresence(stateDir string, s PresenceStatus) error
WritePresence writes the presence file, whole.
func WriteStatus ¶
WriteStatus is the daemon's write of its state.
func WriteWatch ¶
WriteWatch saves the cursor atomically (write a temporary file, rename it over the old), so a run killed in the middle leaves the old cursor whole.
Types ¶
type ActivityLimits ¶
ActivityLimits bounds one walk: the files it reads the time of (a directory costs time, not files) and the time it may take on the clock it is given. A walk that reaches either answers with the newest write it has read.
type Agent ¶
type Agent struct {
Friend, Harness, Dir, Session string
Adapter, DeliveryDir string // explicit Codex folder route; session remains the real harness session
StateDir string // the daemon's state files, when not the default under Home
Width int
Binary string // this tool, by absolute path
Copy CopyFile // places a removable-volume binary under Home; nil refuses it
Redis, Server string // the bus store and the sprint server
Home, Path string // the environment the agent runs in
LaunchdLog string // launchd's own stdout and stderr path, off the friend's volume
// Secrets are the names of the secrets the daemon needs in its environment
// (never values); with any, the command is wrapped in nova-secrets exec as
// the seat Seat, with SecretsTool and Sops by absolute path, the store under
// Home/nova-bench/secrets and the key under Home/.config/nova-secrets.
Secrets []string
Seat, SecretsTool, Sops string
// Coordinator, SilentStop and BrokenAfter are the daemon's flags of the
// same names, written only when set and not the default.
Coordinator string
SilentStop time.Duration
BrokenAfter int
// ConfigDir is the friend's harness config directory (CLAUDE_CONFIG_DIR),
// the daemon's --config-dir, written only when set.
ConfigDir string
// DenySelf is the coordinator's self the daemon's lane wall never writes inside, the
// daemon's --deny-self, written only when set (the daemon's default, DefaultDenySelf,
// stands when it is not).
DenySelf string
// WallReads is what the harness reads inside the lane's wall beyond the system roots and its
// own directory (a pinned harness shim under the home), the daemon's --wall-reads, written only
// when set.
WallReads string
// Command, when set, is what the agent runs in place of the daemon: this tool's
// own verb and flags, after Binary (the wake ping loop, nova-friend ping-install).
Command []string
// Sleep is how Install waits between two looks at the old service after the
// bootout (ReleasePoll); nil is time.Sleep. A test passes its own clock.
Sleep func(time.Duration)
// NotificationsOnly has its own agent label and carries its policy through install
// (SPEC-FRIEND.md, notifications); it never replaces the native scheduler.
NotificationsOnly bool
NotifyKinds string
NotifyWindow time.Duration
}
Agent is one friend's launchd agent: the daemon as launchd runs it, never started by the model (SPEC-FRIEND.md, the daemon).
func (Agent) Args ¶
Args is the daemon's command line: with Secrets, nova-secrets exec opens exactly those names for the daemon (--only) and refuses to start it without every one (--require), then the daemon itself after the --.
func (Agent) BinaryPlan ¶
BinaryPlan isolates notification executables by content hash (SPEC-FRIEND.md, notifications), so installing or rolling one back never overwrites the native binary.
func (Agent) Plist ¶
Plist is the agent's plist: RunAtLoad and KeepAlive, so it starts at login and is restarted when it dies (pending messages redeliver first, nova-bus's rule). launchd opens its own log itself, before the daemon runs, and cannot open one on a network volume (EX_CONFIG, measured 2026-10-03), so that log is LaunchdLog, under the home directory, and so are the daemon's state files and record (DefaultStateDir).
type AgentAPIRefusal ¶
type AgentAPIRefusal string
AgentAPIRefusal is the error agentapi printed in its JSON, at exit 0: the harness said no (a wrong conversation, a missing token).
func (AgentAPIRefusal) Error ¶
func (r AgentAPIRefusal) Error() string
type Aliver ¶
Aliver is an adapter that can say whether its harness is alive, by the cheapest true signal it has: for a harness with a headless program, the session's own last turn (SessionTurns); for one with none, its app in the process table.
type Antigravity ¶
type Antigravity struct {
Dir, Session string
Run Exec
Out io.Writer // the daemon's record, when set
Home string // the user's home ($HOME when empty): app data under Home/.gemini/antigravity
User string // daemon's username (current process user when empty)
FS fs.FS // rooted at Home (os.DirFS(Home) when nil): the mailbox is read through it
Wait func(context.Context) bool // one poll interval; false once ctx has ended (real time when nil)
Now func() time.Time // the daemon's clock, every time in the ledger (time.Now when nil)
State string // the daemon's state directory: the ledger's file (AntigravityLedgerFile); "" keeps it in memory
// contains filtered or unexported fields
}
Antigravity delivers through the harness's own agent-message channel: `agentapi send-message --title=nova-friend <conversation> <text>`, a client of the running language server (the wrapper under ~/.gemini/antigravity/bin, which execs the app's language_server). The server writes the text into the conversation's mailbox (~/.gemini/antigravity/brain/<conversation>/.system_generated/messages/) as a high-priority message and its watcher starts a turn on it; the session marks the message read in read.json there as it takes it. Measured 2026-10-04 08:52 ET: sent at :28, the turn's first step at :32, the friend's "got it" on nova-bus2 at :35.
The server's address and CSRF token are read off the language_server process each delivery (ps, then lsof for its listening ports; the one that answers get-conversation-metadata is the plaintext one). The conversation is the live one (Follow), else the one named by Session, else the newest root conversation whose workspace is Dir, from the harness's conversation_summaries.db (read immutable, through sqlite3).
The mailbox queues: a turn the message starts runs on, and a second message waits in the mailbox for it, the harness's own order for its agents. So Deliver answers 0 once agentapi has taken the message into the mailbox, and never waits for the session to read it (the finding of 2026-10-05 and 06: a delivery that waited two minutes for the read held every other message and the session check behind it while the friend worked through a long turn, and three such waits gave a message up that was already in her mailbox). Every delivery is kept in the ledger (antigravity_ledger.go): who read it, and what to send again if its conversation stops reading. agentapi exits 0 on an error too (a wrong conversation, a missing token): the JSON it prints is the truth, never its exit code. What the harness refuses (no language server, no token, no conversation, no port that answers for it, no mailbox), and a session that has read nothing delivered for the check period, is a SessionRefused naming why, never a Deferred: the daemon marks the session broken with the reason, said once, and keeps every message pending on the bus.
func (*Antigravity) Alive ¶
func (a *Antigravity) Alive(ctx context.Context) Liveness
Alive: the Antigravity app, whose language server Deliver reaches: no headless route, so the app check, by its bundle and its name.
func (*Antigravity) Deliver ¶
Deliver: find the server and the conversation; refuse while the conversation has read nothing delivered for the check period (the session is down: the message stays pending on the bus); send; and answer 0 once agentapi has taken the message into the mailbox, kept in the ledger.
func (*Antigravity) Follow ¶
func (a *Antigravity) Follow(ctx context.Context, now time.Time)
Follow reads, at most every AntigravityFollowEvery, who has read the deliveries (observe), and moves delivery to the conversation that reads: when the live conversation has left AntigravityStopped deliveries unread past AntigravityReadBound and read nothing since the oldest of them, a conversation the daemon delivered to that read one of those deliveries since then is the live one (the one that read last), said once ("antigravity: live conversation is now <id> (the named one stopped reading)"), and never moved again within AntigravitySwitchHold. Every delivery the old conversation left unread is sent again into the new one, headed by ResentLine; one whose send fails is sent again at the next look.
func (*Antigravity) Live ¶
func (a *Antigravity) Live() string
Live is the conversation deliveries go to: the one delivery was moved to, else the one the last delivery went to, else the one named by Session; "" before the first delivery when none is named.
func (*Antigravity) ReadOnReturn ¶
func (*Antigravity) ReadOnReturn()
type AntigravityDelivery ¶
type AntigravityDelivery struct {
ID string `json:"id"`
Conversation string `json:"conversation"`
DeliveredAt time.Time `json:"delivered_at"`
ReadAt time.Time `json:"read_at,omitzero"`
ResentTo string `json:"resent_to,omitempty"`
Text string `json:"text,omitempty"`
}
AntigravityDelivery is one delivery: its message id in the conversation's mailbox ("" until it lands), when it went in and when the daemon saw it read, the conversation it was sent again into, and its text while it may be sent again.
type AntigravityLedger ¶
type AntigravityLedger struct {
Followed string `json:"followed,omitempty"`
From string `json:"from,omitempty"`
Since time.Time `json:"since,omitzero"`
Deliveries []AntigravityDelivery `json:"deliveries"`
}
AntigravityLedger is the ledger's file: the conversation delivery follows (Followed, moved to while the named session was From, at Since) and every delivery, oldest first.
type App ¶
type App struct{ Bundle, Name string }
App is a desktop app as the process table shows it: its bundle and the name of its main executable (Contents/MacOS/<Name>).
type AskedRead ¶
type AskedRead struct {
ID string
Epoch string
Gen int // the read card's generation as the queue carries it (0: a queue before it); a stop-return names it
Packet ReadPacket
Col string // its column on the reader queue (asked, reading)
Lane int // the read lane the server says holds it (take --as reader-<friend> --lane <n>); 0 none
}
AskedRead is one card of the reader queue in the asked column.
func ParseReadQueue ¶
ParseReadQueue reads `queue --as reader-<friend> --json`: the asked reads, in the queue's order, each with the queue's epoch.
func ParseReadQueueAll ¶ added in v1.2.7
ParseReadQueueAll is every read on the reader queue, whatever its column, each with the queue's epoch: a read lane that holds a read begun before it finds its packet here.
type BeatWords ¶
type BeatWords struct {
Run, Check, Pong string
// StopReturns is how many stop-returns the lanes owe (stop.go, OwedStopReturns): the
// beat carries it (friend beat --stop-returns) while it is above zero.
StopReturns int
}
BeatWords are a beat's proof words (nova-sprint friend beat --run, --check, --pong): the daemon's run, the check it put into the session, and the check its session answered, each "" when there is none to say. The sprint server counts an answer only when it names a check this run asked (sprint.ProveBeat).
type BusFacts ¶
type BusFacts struct {
Friend string `json:"friend"`
RealSince int `json:"real_since"`
LastReal string `json:"last_real"` // RFC3339 or "-"
}
BusFacts carries facts about real messages on the bus.
type Card ¶
type Card struct {
ID string `json:"id"`
Brief string `json:"brief"`
Outbox string `json:"outbox"`
// Lane, ServerEpoch and ServerGen are what the server's answer to a lane's ask named
// (lane_take.go): the lane that holds the card, the epoch and the generation it holds it
// at. A card a lane holds is reported by these, never by its directory's name.
Lane int `json:"lane,omitempty"`
ServerEpoch string `json:"server_epoch,omitempty"`
ServerGen int `json:"server_gen,omitempty"`
}
Card is one card a lane hands: its id (the queue file's), its brief, and the outbox directory its REPORT.md and RESULT.md go to.
func NextCard ¶
NextCard is the first card of dir's queue file (inbox/QUEUE.json, in its order) that is queued, delivered (inbox/<id>~<epoch>/BRIEF.md), not done (no outbox/<id>~<epoch>/RESULT.md, and no REPORT.md: a card with a report is friend sync's to finish) and not skipped (held by another lane, or set aside); found is false when there is none.
func (Card) Epoch ¶
Epoch is the sprint epoch alone, without the job's generation (docs/FRIENDS.md): the server's, when its answer named one, else the job directory's.
func (Card) Gen ¶
Gen is the card's generation, its directory's .g<gen> (friend sync names a card dealt again to the same friend <id>~<epoch>.g<gen>); 1 when it has none.
type CardRunner ¶
type CardRunner interface {
Deliverer
// RunCard runs card c to its end: its exit, and an error naming what the
// outbox lacks when the run wrote no REPORT.md or RESULT.md there.
RunCard(ctx context.Context, c Card) (LaneTurn, error)
// Refusal is why no card can run now, with its remedy; empty when one can.
Refusal() string
}
CardRunner is a Deliverer whose one-shot lane runs each card as a process of its own: no session to open or keep, the card's brief the whole prompt, no bus message riding along, and the card's result read from its outbox, never from the process's output (docs/SPEC-FRIEND.md, one-shot lanes; the owner, 2026-10-04: four Claude accounts as heavy-tier friends). Claude is one.
type CardUsage ¶
CardUsage is a running card's tokens so far, read from its harness's own record. A test hands a fake; a lane hands the harness's stream or export.
type Change ¶
type Change struct {
Friend string
State string // PeerUp or PeerDown
LastPong time.Time // zero when the friend never answered
Reason string // why down: no pong, or the ping could not be sent
}
Change is one friend's connection changing state, the one line the keepalive says: never one per ping.
type CheckReport ¶
type CheckReport struct {
Friends []FriendCheck `json:"friends"`
Summary CheckSummary `json:"summary"`
}
CheckReport is the top-level report for JSON serialization.
func (CheckReport) Lines ¶
func (cr CheckReport) Lines() []string
Lines renders all output lines for the full report.
type CheckResult ¶
type CheckResult struct {
Harness string `json:"harness"`
Nonce string `json:"nonce"`
Stage string `json:"stage,omitempty"`
Why string `json:"why,omitempty"`
Took time.Duration `json:"took"`
}
CheckResult is one run of the check: Stage empty is a pass.
func PushProof ¶
func PushProof(ctx context.Context, c Conformance) (res CheckResult, remedy string, undriven bool)
PushProof runs the check c once as the push proof: an undriven harness is refused before anything is delivered; otherwise the round trip runs, and a failure whose delivery the adapter answered with a Deferred carrying a Remedy (a session it cannot drive) answers that remedy with undriven set. remedy is empty for any other failure: the caller names its own.
func (CheckResult) Line ¶
func (r CheckResult) Line() string
Line is the result as nova-friend check prints it.
type CheckSeams ¶
type CheckSeams struct {
Now func() time.Time
Home string
Launchctl Launchctl
ReadStatus func(friend string) (Status, bool, error)
ReadPresence func(friend string) (PresenceStatus, bool, error)
ReadPong func(friend string) (Pong, bool, error)
ReadLog func(friend string) ([]string, error)
BusLog func(ctx context.Context, friend string, since time.Time) (realCount int, lastReal time.Time, err error)
ReadWork func(friend string, dir string) (inboxCount, outboxCount int, newestName string, newestAt time.Time, err error)
ListFriends func() ([]string, error)
HarnessDir func(friend string) (harness, dir string, err error)
}
CheckSeams provides external dependencies for friend check facts.
type CheckSummary ¶
type CheckSummary struct {
Friends int `json:"friends"`
OK int `json:"ok"`
Broken int `json:"broken"`
Deaf int `json:"deaf"`
Silent int `json:"silent"`
Down int `json:"down"`
Untrue int `json:"untrue"`
}
CheckSummary is the counts across all checked friends.
func ComputeSummary ¶
func ComputeSummary(checks []FriendCheck) CheckSummary
ComputeSummary aggregates verdicts across friends (docs/SPEC-FRIEND.md "Check": the summary).
func (CheckSummary) Line ¶
func (s CheckSummary) Line() string
Line renders the CHECK OK summary line.
type Claude ¶
type Claude struct {
Stub
Friend, Dir string
// ConfigDir is the friend row's config_dir as the daemon last read it;
// nil or empty refuses every card.
ConfigDir func() string
Run Exec
Program string // "claude" when empty
Out io.Writer // where the run's output goes, when set: the daemon's record
Now func() time.Time // time.Now when nil: the clock a limit's reset is read against
// TokenCap is the friend row's per-card token cap as the daemon last read
// it (TokenCapOf; 0 none); nil is DefaultTokenCap (tokencap.go).
TokenCap func() int64
// contains filtered or unexported fields
}
Claude is the claude harness: no deliver command in batch (Stub, passive: the daemon reads nothing for it), and in one-shot mode each card run as `env CLAUDE_CONFIG_DIR=<dir> claude -p <brief> --output-format stream-json --verbose` and the trim (ClaudeTrim) in Dir with stdin from /dev/null, priced and its limit read from its stream-json (adapter_claude.go). The config directory is the friend row's config_dir, so each friend is its own account's login and settings (its permission mode among them); stream-json prints as the run works, so the daemon's silence watch sees a working run.
func NewClaude ¶
NewClaude is the claude harness's card runner over run, in the friend's directory dir, its runs' output going to out when set.
func (*Claude) Refusal ¶
Refusal names the missing config_dir and its remedy: a claude friend in one-shot mode runs only as her own account.
func (*Claude) RunRead ¶
RunRead is one read of the friend's reader row (ReadHarness; docs/SPEC-FRIEND.md, the reader row): a card run's call with the prompt for the brief and the model of the read's tier ("" is the account's own) before the trim, as her own account, priced and its limit read as a card's run is.
type ClaudeWake ¶
type ClaudeWake struct {
Dir, Name string
Now func() time.Time // time.Now when nil
Out io.Writer // the daemon's record, when set
}
ClaudeWake is the claude adapter: Claude Code has no command that puts a turn into a running session from outside, so Deliver puts nothing in. It appends one line per push to the wake file in Dir, the friend's state directory (ClaudeWakePath(Dir, Name)): the clock, then the pushed text on one line, which carries the nonce or message id and the path of what was pushed. The session's own wait (ClaudeWaitLine), running as a background task, returns when the file grows, and its exit re-invokes the session. The file is made when absent, synced, and never truncated; a missing Dir is a refusal naming it, and nothing is made. Name is the session's name for the file, else the friend of Dir's status file. It is Passive: the daemon takes nothing off the stream for claude.
func (*ClaudeWake) Alive ¶
func (c *ClaudeWake) Alive(context.Context) Liveness
Alive: a claude session is reached only through its own wait on the wake file, and no process says which window runs it.
func (*ClaudeWake) Passive ¶
func (*ClaudeWake) Passive()
Passive marks the claude adapter: the session's own wait reads the stream.
type Codex ¶
type Codex struct {
Dir, Session string
// QueueOnly keeps notification delivery in the existing app, never a competing exec resume (SPEC-FRIEND.md, notifications).
QueueOnly bool
Run Exec
Program string // "codex" when empty
Home string // CODEX_HOME; $CODEX_HOME or ~/.codex when empty
Held func(lock string) bool // whether the thread's writer lock is held; FlockHeld when nil
Env func(string) string // getenv; os.Getenv when nil
Out io.Writer // where the turn's output goes, when set: the daemon's record
// App connects to the Codex app-server, through which the thread's queue is read and
// withdrawn from (DialCodexAppServer under the home when nil); Now is the clock a queued
// request's age is read by (time.Now when nil).
App func(ctx context.Context) (CodexAppServer, error)
Now func() time.Time
// contains filtered or unexported fields
}
Codex uses the writer lock to choose its first delivery route. An open chat receives codex queue; a closed chat uses exec resume. A failed route tries the other once, then defers without losing the message (SPEC-FRIEND.md, Codex). Queue acceptance is not a completed answer: the app may start the queued input only after its current turn ends. Without a named session, resolve the newest saved thread for Dir first.
A delivery during a turn is queued, never steered: the open chat's turn runs in the Codex app's own server, which takes no request from outside (CodexAppServer). So the open chat's queue holds at most one request for a pong of each kind (PongRequest): a session check (the presence nonce) and a wake (a wake turn or an idle wake: the coordinator's challenge nonce), each its own series, so one kind never withdraws the other. Before such a delivery is queued the thread's queue is read: a request of the same kind for the same nonce still unread inside CodexCheckRequeue stands for this one, and nothing is queued twice; else the new request is queued first, and only once it is in is every request of its kind it supersedes withdrawn (an older nonce, or the same nonce queued CodexCheckRequeue ago or more), so a queue that fails leaves the old request standing. A queued message that carries anything else (a bus message) is never withdrawn. A message is known by its text's shape: a person who types the exact shape of a pong request into the chat has it treated as one.
type CodexAppServer ¶
type CodexAppServer interface {
Call(ctx context.Context, method string, params, result any) error
Close() error
}
CodexAppServer is one connection to the app-server: one JSON-RPC call at a time.
func DialCodexAppServer ¶
func DialCodexAppServer(ctx context.Context, home string) (CodexAppServer, error)
DialCodexAppServer connects to the app-server under home and initializes the session.
func NewCodexAppServer ¶
NewCodexAppServer speaks the WebSocket handshake and the app-server's initialize over conn.
type CodexQueued ¶
type CodexQueued struct {
ID, Text string
}
CodexQueued is one message on a thread's queue: its queued submission id and its text.
func CodexQueue ¶
func CodexQueue(ctx context.Context, s CodexAppServer, thread string) ([]CodexQueued, error)
CodexQueue is thread's queue, oldest first (thread/queue/list, every page).
type Conformance ¶
type Conformance struct {
Friend, Harness string
Deliver Deliverer
Store bus.Store
Within time.Duration
Now func() time.Time
Wait func(ctx context.Context) bool // one CheckPoll; false once ctx has ended
Nonce func() string
Text func(nonce string) string // the session check as the session reads it (SessionCheckText)
Pong func() (Pong, bool, error) // the pong file the pong verb writes: the session ran the line
}
Conformance is the one promise every harness adapter makes, checked end to end (docs/SPEC-FRIEND.md, delivery-conformance-r.w1; the presence model's Ask then Answer within the bound, tla/FriendPresence.tla): a session check carrying a fresh nonce goes in through the adapter, the session runs the exact pong line it carries, and a pong with that nonce from the friend is on the bus within Within. The unit tier runs it over a fake Exec and bus's Fake; nova-friend check and install run it against the live session.
func (*Conformance) Run ¶
func (c *Conformance) Run(ctx context.Context) CheckResult
Run delivers the check and reads for its pong until Within has passed. A Stub's refusal, a Deferred and a nonzero exit are stage deliver, each with the adapter's own reason.
type CopyFile ¶
CopyFile copies src onto dst. CopyExecutable is the one install uses; a test passes its own, and nil refuses a removable-volume binary.
type Courier ¶
type Courier struct {
// Bus is the bus every send goes on; Open, when set, dials one for each
// send instead (the server's way: one connection per note) and its
// failure is watched like a send's.
Bus *bus.Bus
Open func(ctx context.Context) (*bus.Bus, func(), error)
Watch *bus.Watch
Now func() time.Time
}
Courier is how the sprint server sends its notes to friends: each send on the bus, its result watched, so a store that refuses the login or cannot be reached is one alarm to the coordinator, raised at the first failure and cleared at the next success, and never only a log line (the finding of 2026-10-04: 54 failures in 30 minutes, WRONGPASS for the server's bus user, and nothing said so; docs/SPEC-FRIEND.md, fr-delivery-receipts.w1). Every note is owed its friend's receipt like any message to her (docs/SPEC-BUS.md, fr-delivery-receipts.w1).
type DSH ¶
type DSH struct {
Dir, Session string
Run Exec
Program string // DSHProgram when empty
Sessions string // the sessions root; DSH_HOME/sessions, else ~/.dsh/sessions, when empty
Out io.Writer // where the turn's output goes, when set: the daemon's record
// contains filtered or unexported fields
}
DSH delivers through `dsh headless --session-id <id> -` run in Dir, the text on stdin: the headless profile adopts the persisted session (the same session directory under ~/.dsh/sessions/<key>/<id>, its record grows by one turn; measured 2026-10-04, v0.2.0-rc.2) and exits when the turn ends. An unknown id, a session recorded in another directory, and a missing provider key each exit 1. Without a session named, the newest session of Dir from the store (DSH_HOME, else ~/.dsh). The desktop app the friend sits in shares the store. Measured 2026-10-04 and 2026-10-05 (docs/SPEC-FRIEND.md, the dsh row): a session under an agent preset is refused by the one-shot runner whatever the text, exit 1 before any write, its transcript hash unchanged (the runner adopts only a session with no preset, and a session never returns to none). Measured 2026-10-06: the same refusal also comes with exit 0. The refusal, and MISSING_CREDENTIAL, are read from the output whatever the exit (DSHRefusal): a SessionRefused, so the message stays pending instead of being given up after three refusals, and the daemon marks the session broken at once until a turn succeeds. On the survey machine, deliver.log records 1339+ deferred deliveries against Zhi's real open session, and the desktop app exposes no local listener or IPC socket. No route into the open desktop session exists, so Route answers defer; the session reads the bus itself with nova-bus wait or nova-bus recv.
func (*DSH) Alive ¶
Alive: the session's last turn (dsh headless --session-id); the DeepSeek Harness app is not read: a headless friend needs no window.
func (*DSH) ReadOnReturn ¶
func (*DSH) ReadOnReturn()
func (*DSH) Route ¶
Route is what status and check say: push. Every delivery goes into the friend's session as a headless turn (dsh headless --session-id), the session check included; none waits on the open desktop app, which no route reaches (docs/SPEC-FRIEND.md, the dsh row). line is that turn's command.
type Daemon ¶
type Daemon struct {
Friend, Harness, Dir string
Width int
Store bus.Store
Deliver Deliverer
Beat func(ctx context.Context, active time.Time) error // one beat to the sprint server, carrying the session's last activity (zero: none known)
StepBeatForTests bool // deterministic fake-clock seam; production has one independent beat caller
HarnessStatus func() (seen, rule string) // the beat worker's advisory harness observation; only the loop writes Status
// Activity is the newest write of the session's files and Cards the ids of
// the cards she holds, oldest first (nil: the queue file's queued and working
// tasks under Dir). Activity is read by the independent beat cadence at
// ActivityEvery; Cards is read by the idle walk at IdleWalkEvery. IdleAfter is her
// row's idle setting, read each step (nil or zero: DefaultIdleAfter). They
// drive the idle wake (IdleStep); a nil Activity knows no write, and the
// watch is off.
// The same Activity, run at most once an ActivityEvery, is carried on each beat.
Activity func() time.Time
Cards func() []string
IdleAfter func() time.Duration
Now func() time.Time
// Pause waits d when the store did not: after a read that answered at
// once (blocked false: an error, or a store that does not block), and
// while a delivery runs and the loop only peeks.
Pause func(ctx context.Context, d time.Duration)
Record func(line string) // one line per delivery, to the daemon's log
// MachineStopped says the machine's word, as the owner last read it off the beat's
// answer (ParseMachine), is STOPPED: the lanes cancel what runs, owe and send
// stop-returns, and start nothing (stop.go). nil: never stopped.
MachineStopped func() bool
// StopReturn sends one stop-return (StopReturnArgv) to the sprint server; nil sends it
// through Sprint.
StopReturn func(ctx context.Context, argv []string) error
// Pong is the session's recorded answer, read each step while a
// challenge is open (ReadPong over the state files).
Pong func() (Pong, bool, error)
// Limited is the harness's limit now: its kind and reset, and whether there is one
// (Limits.Limited, Limits.Kind); nil: none. While there is one the status says
// session=limited with them, and the turns the Gate defers stay pending.
Limited func() (kind string, until time.Time, limited bool)
// Status receives the daemon's state whenever it changes, and every
// StatusEvery (WriteStatus over the state files).
Status func(Status) error
// PongCommand is the exact pong line for this friend and nonce (the
// binary by path, --as, --dir, --redis), put at the head of a turn while
// a challenge is open, so a small model has one line to run and nothing
// to fill in.
PongCommand func(nonce string) string
// SilentStop is how long a running turn may print nothing before it is
// stopped (DefaultSilentStop when zero); BrokenAfter how many turns in a
// row the provider refuses the same way before the session is broken
// (DefaultBrokenAfter when zero); Coordinator who is told of a broken
// session when no ping has named the seat.
SilentStop time.Duration
BrokenAfter int
Coordinator string
// Row is the friend's nova-config row as the daemon last read it (from
// its beat): her delivery mode (ModeBatch or ModeOneShot) and width,
// read every step so a change takes effect without a restart; nil, or
// empty answers, deliver in batch at Width.
Row func() (mode string, width int)
// Pacing is the row's pacing as the daemon last read it: the fraction of each
// subscription window the lanes may spend, read every step; nil, or out of
// (0, 1], is DefaultPacing (pacing.go). No beat carries the row's pacing yet,
// so nova-friend leaves it nil.
Pacing func() float64
// LaneCaps is the row's wall cap of a lane's card by its tier as the daemon last read
// it (ParseLaneCaps off its beat), read every step; nil, or a tier it names none for,
// is DefaultLaneCaps (lane_cap.go).
LaneCaps func() map[string]time.Duration
// LoadLanes and SaveLanes keep the one-shot lanes' state (ReadLanes,
// WriteLanes over the state files); nil keeps it in memory only.
LoadLanes func() (LaneState, error)
SaveLanes func(LaneState) error
// CardDone is the one bus line a lane's session sends when its card is
// done (nova-bus send by path, as this friend, to the coordinator).
CardDone func(card, to string) string
// Progress stamps progress on the cards whose lane turn printed (ProgressArgv to the
// sprint server); nil stamps none.
Progress func(ctx context.Context, cards []Card) error
// Finish sends one finish verb to the sprint server: a lane's card whose run ended with
// no REPORT.md (FinishArgv, lane_end.go), and every working card on her row whose job's
// REPORT.md says a verdict, whoever wrote its brief (OutboxFinishArgv, outbox.go). Nil,
// or a finish not answered, leaves it to friend sync, which reads the same REPORT.md.
Finish func(ctx context.Context, argv []string) error
// Take sends one take to the sprint server (LaneTakeArgv, BatchTakeArgv), its refusal an
// error: a lane starts a card only once the server has it working on her row (lane_take.go).
// Nil (a test's world) takes nothing, and a lane runs any card on her row as before.
Take func(ctx context.Context, argv []string) (string, error)
// The lanes' parity with the runner scripts they replace (lane_parity.go); Rules nil
// turns every one off. Rules is her row's lane rules as her beat last answered them,
// Load the machine's one-minute load (nil: no load rule), Tokens a session's tokens
// from opencode's database (nil: no cost and no token cap), Route the store's route row
// for her model and Model its name, LaneHold the pause marker's line (the lanes held
// down by a provider failure until a person clears it) and LaneHoldDown writes it: her
// beat then says her down with its message (PauseBeat).
Rules func() LaneRules
Load func() float64
Tokens func(ctx context.Context, session string) (LaneTokens, error)
Route func() RoutePrice
Model string
LaneHold func() string
LaneHoldDown func(ctx context.Context, message string) error
// FaultDown marks her row down until until with reason: the same harness fault
// FaultRepeats times within FaultWithin on her lanes (lane_parity.go); her beat says
// her down with them until then (friend beat --until --reason). Nil: her lanes are
// held here alone.
FaultDown func(until time.Time, reason string)
// Held is every card on her row as the sprint server says it (HeldVia: friend cards
// <friend>, else the worker view), asked once an InboxEvery; her inbox is reconciled with
// the answer (SyncInbox, inbox.go). Nil leaves her inbox to friend sync alone.
Held func(ctx context.Context) (Row, error)
// Sprint sends one verb to the sprint server and answers what it printed: the reader row's
// queue, begin, verdict and return (read_lanes.go). Nil runs no reads. ReadSlots is the
// row's read slots, read each step (nil: DefaultReadSlots), and ReadModel the model of a
// read's tier ("": the harness's own).
Sprint func(ctx context.Context, argv []string) (string, error)
ReadSlots func() int
ReadModel func(tier string) string
// Stage stages a held work card's job (Stager.Stage: jobs/<job>/repo and its JOB.md) and
// answers the commit staged (stage.go); nil stages none, and a lane is handed a card with
// its brief alone.
Stage func(ctx context.Context, p Packet) (string, error)
// Prune removes finished jobs' worktrees past FinishedJobsKept (Stager.Prune), given the
// jobs that are live (held on her row, run by a lane, being staged), after each inbox
// cleanup, and answers the jobs it removed; nil prunes none.
Prune func(ctx context.Context, live map[string]bool) ([]string, error)
// Tip is origin's tip of a branch of a repository (owner/name), "" when origin has no
// such branch (Stager.Tip: one git ls-remote): a report's LAND finishes only at that tip,
// as nova-sprint collect's does (outbox.go). Nil reads none, and a LAND finishes at its
// Head.
Tip func(ctx context.Context, repo, branch string) (string, error)
// Running is the beat's running list as the sprint server last said it, every friend's:
// a card id or job to the friend whose lane runs it. A lane is never started for a card
// it names another friend running, and a lane whose card left her row names its friend
// on the job's lane mark (one_lane.go). Nil says none; the lane marks still hold.
Running func() map[string]string
// Holders reads the server's current card-to-holder map (view cards), once
// per outbox pass that finds a report outside her row. Nil uses Running's
// known holders; an error refuses with the explicit unknown-holder remedy.
Holders func(ctx context.Context) (map[string]string, error)
// Mailbox is the adapter under Deliver when her harness's session queues what is
// delivered (Antigravity: a mailbox): a delivery goes in at once, whatever turn runs, so
// nothing is ever deferred for a turn under way; each step the daemon hands it the
// clock, off the loop, and it follows the conversation that reads (Antigravity.Follow),
// which the status says (session_live). Nil for every other harness.
Mailbox Mailbox
// Queued is her harness's own queue of deliveries not yet taken, as the adapter last read
// it (Codex.Queued), on the status each flush; nil, or not known, says none.
Queued func() (int, bool)
// Seat is the coordinator seat holder as the sprint server says it. An
// error, an empty name or a nil Seat is the seat unknown, and while it is
// unknown no message is delivered as an instruction (BatchFor).
Seat func(ctx context.Context) (string, error)
// Proof is whether the push is proved this run and, while it is not, the nonce
// its session check carries (SessionCheck.Proof); nil is proved (a harness that
// runs each card as a process of its own has no session to prove). Until it is
// proved the daemon delivers nothing into the session: no batch turn, no dealt
// brief, no wake, no idle wake, no lane, no read; it beats, answers pings and
// keeps every message pending (docs/SPEC-FRIEND.md, The push proof). The status
// says push=unproven with the nonce and since when.
Proof func() (proven bool, nonce string)
// Sent is the session's proof the sprint server last took on her beat (friend
// beat --pong answered with it), zero before any; the status carries it.
Sent func() time.Time
// Session is the id of the session the daemon delivers into, read each step; a change of
// it is a new session, owed the present (present.go). Nil reads none: the daemon's start
// and the stale bound still bring the present.
Session func() string
// NotificationOnly uses the notification receiver without any sprint or job hooks (SPEC-FRIEND.md, notifications).
NotificationOnly bool
NotificationStateDir string
Notifications *NotificationPolicy
// contains filtered or unexported fields
}
Daemon is one friend's loop: the recv loop over the friend's stream with the deliver adapter, the beat, and the Machine stepped by what arrives. Everything it reaches outside itself is a field, so a test runs it over bus's Fake, a fake harness and its own clock.
func (*Daemon) LiveQueue ¶
LiveQueue is her live queue: her row as the server last said it (each card, its column and its inbox/<job>/BRIEF.md), else the queued and working tasks of inbox/QUEUE.json.
func (*Daemon) OwedStopReturns ¶
OwedStopReturns is how many stop-returns the lanes owe now: the beat carries it.
func (*Daemon) Run ¶
Run is the loop until ctx ends. Each step: the clock; the friend's row (Row: her delivery mode and width); every pending message read off the stream when nothing waits on it (a ping is answered by the daemon at once and acked, never pushed in), else one peek, so a ping arriving during a long turn is still answered at once; each running turn's output watched, and a turn silent past SilentStop stopped; the turns' results (exit 0 acks every message a turn carried); then, in batch mode, one turn with every waiting message when the session is free, else an owed wake check pushed in as its own turn holding only the pong line (startWake), and in one-shot mode, each free lane handed its next card with the waiting messages riding along (lanes.go); an independent beat carrying the session's proof; the session's pong; the status. The daemon's own words about the coordinator collapse to the latest and ride in a turn that carries messages or a card, never alone.
type DaemonFacts ¶
type DaemonFacts struct {
Friend string `json:"friend"`
Agent string `json:"agent"` // loaded, not-loaded, none
PID string `json:"pid"` // numeric string or "-"
Status string `json:"status"` // ok, stale, none
Connection string `json:"connection"` // string or "-"
Challenge string `json:"challenge"` // string or "-"
PongAge string `json:"pong_age"` // e.g. "4s" or "-"
Presence string `json:"presence"` // up, asleep, down
SeenAge string `json:"seen_age"` // e.g. "4s" or "-"
// Proof is the session's proof as the server has it from her daemon: pending
// while the push is unproven (ProofAge since the daemon started waiting), sent
// once the server took one on her beat (ProofAge the proof's age), none before.
Proof string `json:"proof"` // pending, sent, none
ProofAge string `json:"proof_age"` // e.g. "4s" or "-"
}
DaemonFacts carries facts about the launchd agent and daemon.
type DeafChange ¶
type DeafChange struct {
// contains filtered or unexported fields
}
DeafChange remembers who was last reported deaf, so the coordinator is told once per change and never once per pass.
func (*DeafChange) Report ¶
func (d *DeafChange) Report(deaf []string) []string
Report takes the friends whose session did not answer this pass and answers the sorted names to tell the coordinator, or none when the set is empty or the same as the one last reported. A set that empties is remembered, so the next deaf friend is a change again.
type DealNotice ¶
type DealNotice struct {
Friend string `json:"friend"`
Cards []string `json:"cards,omitempty"`
Truncated bool `json:"truncated,omitempty"`
Entry string `json:"entry,omitempty"`
Message bus.Message `json:"message,omitempty"`
}
DealNotice is the newest deal notice owed a friend: the friend it is keyed by, the cards it names, whether that list is a truncated subset, and the bus entry and message it stands for (SPEC-FRIEND.md, notifications). A newer notice replaces it; it is withdrawn when all its cards are taken, and a truncated list is never withdrawn because a card it omits may still be held.
type Deferred ¶
type Deferred struct{ Reason, Remedy string }
Deferred is a Deliverer's answer when the session cannot take a turn now and nothing has failed (for example, neither Codex queue nor resume can accept it). The daemon keeps the message in hand, tries again after RecheckEvery, counts nothing toward MaxDeliveries and acks nothing, so a chat open all day loses no message. Remedy is set when no retry can succeed, because the adapter cannot drive the session at all (dsh: a session under an agent preset): what the friend does instead, which nova-friend install and run refuse with (PushProof).
type Deliverer ¶
Deliverer pushes one text into the friend's running session as a turn and normally blocks until the turn ends. Codex queue instead confirms enqueue acceptance; the app runs it after the active turn ends. Exit 0 acks the bus message (SPEC-FRIEND.md, the deliver command and Codex).
func NewDeliverer ¶
NewDeliverer is the adapter for harness, in the friend's directory, into session (empty: the newest session of that directory where the harness can name one). An unknown harness is refused with the names there are.
type Entry ¶
type Entry struct {
Kind string // KindDir, KindFile, KindSymlink or KindMissing
Target string // a symlink's target
}
Entry is what a path is, the path itself and never what a symlink names.
type Evidence ¶
type Evidence struct {
Harness string // HarnessRunning, HarnessNotSeen or HarnessUnknown; shown, never deciding
DaemonUp bool // the daemon's status file is fresh; shown, never deciding up
LastAnswer time.Time // the session's last pong; zero is never
Limit string // the limit's name, when the provider said one
LimitUntil time.Time // the limit's reset; zero, or past, is no limit
Undelivered int // messages waiting on the friend's stream; negative is not counted
BusBlocked string // why the bus cannot deliver to the friend; empty when it can
LastResult time.Time // the end of the last turn; zero is none yet
LastExit int // that turn's exit
}
Evidence is what a friend's status is decided from.
type Exec ¶
type Exec func(ctx context.Context, dir, name string, args []string, stdin string) (stdout string, exit int, err error)
Exec runs one command for an adapter: the program, its arguments and its working directory, with the text on stdin, answering what it printed and its exit code. The daemon passes the real one (RealExec); a test its own.
func ShimExec ¶
ShimExec is run with the shim directory first on the PATH of every lane child and GOROOT pointing nowhere: a command whose context is a lane's runs as `env PATH=<shims>:<path> GOROOT=<nowhere> <name> <args>`; any other runs as it was. Put it outside Wall.Exec so the env runs inside the wall.
type FaultWatch ¶
type FaultWatch struct {
// contains filtered or unexported fields
}
FaultWatch counts one row's harness faults: the FaultRepeats-th of the same fault within FaultWithin is one down until FaultDownFor later; a fault while that down stands adds nothing, and the count starts again once it has passed. The zero value is ready; it reads no clock of its own.
type Folder ¶
type Folder struct {
Dir, Session, Friend, WorkDir string
}
Folder is an explicit delivery route for a real Codex session whose watcher reads Dir. Writing a file is acceptance by the folder, never a session pong. The native proof still requires the session's own nonce-bearing bus reply.
type FolderCheck ¶
type FolderCheck struct {
Friend, Dir string
}
FolderCheck is the claude harness's session-check adapter (docs/SPEC-FRIEND.md, The push proof; the owner, 2026-10-08: "why not, can we fix the harness to do this?"). Claude Code has no command that puts a turn into a running session from outside, and a claude friend's cards run as processes of their own; what a live session can do is watch a folder. So the daemon's SESSION CHECK goes in as one file, <Dir>/inbox/SESSION-CHECK-<nonce>, holding the check's text (the pong command the session runs: nova-friend pong --as <friend> --nonce <nonce>), and the session that answers it proves the push as any session does: its pong on the bus brings the presence up, the proof on bus2:push follows, and the daemon's next beat carries the pong, so the sprint records the session proof natively. One check stands at a time: the file of an earlier nonce is removed when the next is written, so a session in a long turn finds one check, never a pile. The adapter is not passive (the check does go somewhere a session reads) and never ReadOnReturn (a file written is not a file read), so an unanswered check is asked again with the same nonce on the daemon's cadence. A friend with no live session (per-card lanes only, mode batch) answers nothing: her presence reads down with the check's nonce, her cards' finishes stand for her at the server, and nothing refuses her messages on it. The write holds no turn of the session, so the check goes in in place (InPlace; SessionCheck.ask): the file is on disk before the beat ever says the check.
func (*FolderCheck) Deliver ¶
Deliver writes the check text as <Dir>/inbox/SESSION-CHECK-<nonce>, the nonce read off the text's first line (SessionCheckPrefix), removing the file of any earlier check. A text that is no session check is refused.
func (*FolderCheck) InPlace ¶
func (*FolderCheck) InPlace()
InPlace: a file write holds no turn; see InPlace.
type FreshTurn ¶ added in v1.2.7
FreshTurn is a deliverer whose check goes in as a fresh turn of its own, a session of its own that no listing is read for and none is grown: the presence of a one-shot friend (docs/SPEC-FRIEND.md, presence: a tiny fresh turn per check). A one-shot friend has no long-lived session by design, so a session that is full or missing is never the reason she is down.
type FriendCheck ¶
type FriendCheck struct {
Friend string `json:"friend"`
Daemon DaemonFacts `json:"daemon"`
Harness HarnessFacts `json:"harness"`
Bus BusFacts `json:"bus"`
Work WorkFacts `json:"work"`
Verdict VerdictFacts `json:"verdict"`
}
FriendCheck is the full fact sheet for one friend.
func CheckFriend ¶
func CheckFriend(ctx context.Context, friendName string, seams CheckSeams, since time.Duration, shown *ShownEntry) FriendCheck
CheckFriend gathers the facts through the seams over the window and decides the verdict for one friend (docs/SPEC-FRIEND.md "Check").
func (FriendCheck) Lines ¶
func (fc FriendCheck) Lines() []string
Lines renders the five CHECK lines for one friend.
type GUIWindow ¶
GUIWindow types one message into a GUI harness's composer and submits it. Permitted, when set, answers whether the accessibility permission is held. Nil asks the platform (PlatformPermitted), which never prompts.
type Gemini ¶
type Gemini struct {
Dir, Session string
Run Exec
Program string // "gemini" when empty
Out io.Writer // where the turn's output goes, when set: the daemon's record
// contains filtered or unexported fields
}
Gemini delivers through `gemini --skip-trust --resume <id> --prompt=<text>` in Dir, which resumes the persisted session (the same session id and the same chat file under ~/.gemini/tmp/<project>/chats/, read from the CLI's ChatRecordingService.initialize on 2026-10-04, v0.46.0) and blocks for the whole turn. Without a session named, "latest": the CLI's own newest session of the project that Dir is, so a friend who starts a fresh session is still reached. --skip-trust trusts Dir for this process only; the friend's own session already trusts it. The text goes as --prompt=<text>, one argument, so a message beginning with a dash is never read as a flag. Exit codes are the CLI's: 42 when the session is not found, 55 untrusted, 1 an error.
func (*Gemini) Alive ¶
Alive: the session's last turn (gemini --resume); before the first, a runner that cannot be found is not running.
func (*Gemini) ReadOnReturn ¶
func (*Gemini) ReadOnReturn()
type Grok ¶
type Grok struct {
Dir string // the friend's directory: the session's cwd
Wake string // the wake file, when named; else the one the session's monitor tails
Run Exec // runs ps
Out io.Writer // the daemon's record, when set
Home string // the grok home, ~/.grok when empty
// contains filtered or unexported fields
}
Grok delivers into the Grok Build TUI (xAI's `grok`), which has no deliver verb, no leader socket unless leader mode is on, and no way to send into an open window: `grok -p <text> --resume <id>` runs the turn in a second process over the same transcript, not in the window the friend is in. What the window has is the monitor tool: a background task whose every new output line "becomes a notification delivered to the conversation" and wakes the agent for a turn (the harness's own guide, ~/.grok/docs/user-guide/20-background-tasks.md). The friend's session runs one over a wake file, `tail -n 0 -F <file>.wake`, and a line appended to that file arrives in the session as a <monitor-event> user turn (measured 2026-10-04 in a friend's session: a user_message_chunk at a new promptIndex in its updates.jsonl). So Deliver appends the text, as one line, to the wake file the open session's monitor is tailing. A backlog is many Deliver calls. Lines written with no gap are the flood that stops the monitor, so each line after the first waits out what remains of wakePace. It is accepted (exit 0) once the line is in the file and the tail was running under that session; the turn runs after Deliver returns, since nothing hands its end back. While no monitor runs (no window, or a window with no tail) Deliver defers: nothing is written, the message stays pending, and the reason carries the one line the session runs. A wake path that is not absolute is a refusal and nothing is written.
func (*Grok) Alive ¶
Alive: a grok window (the TUI process) open in Dir: a pid of the harness's active_sessions.json with Dir as its cwd, in the process table. A window with no monitor is still running; delivery defers on its own.
func (*Grok) Route ¶
Route is what status says. push: a tail of an absolute .wake file runs under the open window's pid, so a delivery now is a turn in that window. defer: no such tail; line is the monitor line the session runs. A listing or session file that cannot be read is defer, never a silent push, and err says why.
type HarnessFacts ¶
type HarnessFacts struct {
Friend string `json:"friend"`
Harness string `json:"harness"`
Route string `json:"route"` // push, mailbox, queue or passive
Last string `json:"last"` // RFC3339 or "-"
LastExit string `json:"last_exit"`
FailedOfLast20 int `json:"failed_of_last20"`
Deferred int `json:"deferred"`
Delivered int `json:"delivered"` // deliveries in the window (JSON only)
Failed int `json:"failed"` // of those, the ones that failed (JSON only)
Broken string `json:"broken"` // RFC3339 or "-"
Reason string `json:"reason"` // one line or "-"
SessionLive string `json:"session_live"` // the conversation a mailbox harness delivers into, or "-"
Queued string `json:"queued"` // the harness's own queue not yet taken (codex), or "-"
}
HarnessFacts carries facts about the harness, deliveries and breaks: every delivery count is of the --since window (docs/SPEC-FRIEND.md "Check").
func (HarnessFacts) Line ¶
func (hf HarnessFacts) Line() string
Line renders the CHECK HARNESS line.
type HarnessSettings ¶
type HarnessSettings struct {
Harness, Friend, Dir string
Home string // the friend's home: ~ of every default below
StateDir string // the daemon's state directory; DefaultStateDir when empty (grok's default wake file)
Wake string // grok: the wake file the session's monitor tails; <state>/<friend>.wake when empty
ConfigDir string // claude: CLAUDE_CONFIG_DIR, the friend's own config directory
Model string // opencode: the model, provider/model; empty leaves it alone
CodexHome string // codex: CODEX_HOME; Home/.codex when empty
DSHHome string // dsh: DSH_HOME; Home/.dsh when empty
FS SettingsFS
}
HarnessSettings is what install writes for one friend's harness and what check compares: the friend's directory and, per harness, the flags that name a setting. The writer of each harness is one small function (settings_<harness>.go).
func (HarnessSettings) Check ¶
func (h HarnessSettings) Check() ([]Setting, error)
Check is every setting with what is there now; nothing is written.
func (HarnessSettings) Plan ¶
func (h HarnessSettings) Plan() ([]Setting, error)
Plan is what Write would write, with Write's refusals; nothing is written (install --dry-run).
func (HarnessSettings) WakePath ¶
func (h HarnessSettings) WakePath() string
WakePath is the wake file these settings name for grok.
func (HarnessSettings) Write ¶
func (h HarnessSettings) Write() ([]Setting, error)
Write makes every setting what install wants and answers the ones it wrote. Every path is checked first: a symlink, the wrong kind, or a missing path install does not make is refused (ErrNotRealDir) and nothing is written. Each write is read back; a setting that still differs is an error naming it.
type HarnessWatch ¶
type HarnessWatch struct {
Alive Aliver
Every time.Duration
Now func() time.Time
// contains filtered or unexported fields
}
HarnessWatch is the harness check beside the daemon's beat (SPEC-FRIEND.md, the harness check). Every Every (AliveEvery when zero) it asks Alive and keeps the answer on the daemon's status (Status.HarnessSeen), saying each change on the record. It is advisory: it never holds the beat back and never makes the friend down. Presence is the session's (SessionCheck): the finding of 2026-10-05 was a friend run from the dsh command line, answering every session check for three hours, held down because no app was in the process table. An adapter that cannot tell changes nothing. The model is app in tla/FriendPresence.tla, read by no rule (SessionShownUp; the witness appholds is this finding).
func WatchHarness ¶
func WatchHarness(d *Daemon, adapter Deliverer) *HarnessWatch
WatchHarness puts a HarnessWatch over adapter beside d's beat; call it once d is built and before Run. Pass the bare adapter, the one NewDeliverer returned: the gates in front of it (SessionCheck.Gate, Limits.Gate) are Deliverers that answer no Alive. A nil adapter is d's Deliver. Alive is optional by assertion: an adapter that is no Aliver cannot tell.
func (*HarnessWatch) Beat ¶
Beat is the daemon's beat, with the harness check beside it: it runs the check when one is due, then beats, whatever the check read.
func (*HarnessWatch) Status ¶
func (w *HarnessWatch) Status() (string, string)
Status returns the last advisory observation without sharing the daemon's mutable Status with the independent beat worker.
type HeldAnswer ¶
HeldAnswer is the server's answer to friend cards <friend>: every card on her row, the ready ones dealt behind her working ones and her reads among them.
type HeldCard ¶
type HeldCard struct {
Card string `json:"card"`
Job string `json:"job"`
Col string `json:"col"`
Kind string `json:"kind,omitempty"`
Branch string `json:"branch,omitempty"`
Tier string `json:"tier,omitempty"`
Stream string `json:"stream,omitempty"`
Attempt int `json:"attempt,omitempty"`
Gen int `json:"gen,omitempty"`
Epoch uint64 `json:"epoch"`
Repo string `json:"repo,omitempty"`
Base string `json:"base,omitempty"`
Brief string `json:"brief"`
// Lane is the lane of her row the server says holds the card (take --lane), 0 for none.
Lane int `json:"lane,omitempty"`
Why string `json:"-"`
}
HeldCard is one card on the friend's row as the server answers it: the card, the job it is delivered as (inbox/<job>), its column (ready or working) and its BRIEF.md whole, with its packet (its kind, work or read, the branch it is pushed to, its tier, attempt, generation and epoch, and the repository and base its checkout is staged from: PacketOf reads the brief's REPO: and BASE: lines when the server sends neither); Why is, for a card the answer sends no brief for, why not (the worker view's, ParseView).
type HostRefused ¶
type HostRefused struct{ Session string }
HostRefused is host's refusal: the session runs already.
func (HostRefused) Error ¶
func (h HostRefused) Error() string
type HostResult ¶
type HostResult struct {
Session, Attach, Line string
}
HostResult is what host started (or, on a dry run, would start).
type HostSpec ¶
HostSpec is one host: the friend, its directory, the launch command and whether to only print.
type Hosted ¶
type Hosted struct {
Session string `json:"session"`
Harness string `json:"harness"`
Prompt string `json:"prompt"`
}
Hosted is what host saves so run and install need no flag: the tmux session, the harness it hosts and the idle prompt pattern (source text).
type InPlace ¶
type InPlace interface {
InPlace()
}
InPlace marks a Deliverer whose delivery holds no turn of the session (a file write): SessionCheck.ask runs it in place, never on its Go scheduler, so the check is delivered before ask returns and before any beat names it.
type InboxCounts ¶
type InboxCounts struct {
Held, Inbox, Missing int
}
InboxCounts is what one reconcile found: the cards held on her row, the sprint jobs in her inbox, and the held cards whose BRIEF.md is still not there after it.
func SyncInbox ¶
func SyncInbox(dir string, row Row, keep map[string]bool, asked, now time.Time, record func(string)) (InboxCounts, error)
SyncInbox reconciles her inbox under dir with row, the cards on her row as the server answered an ask begun at asked: each held card's inbox/<job>/BRIEF.md is written when it is not there (written whole, never over a file there; a rework's with its fix first, ReworkedBrief), and each sprint job in the inbox that no held card names, that no lane runs (keep), whose kind the answer covers (row.Reads), and whose BRIEF.md was written before asked, is moved to inbox/retired/. A brief written since the ask began is friend sync's for a card dealt after the server answered, and the next pass decides it (without this, the TLA+ model InboxReconcile retires a held card's brief: docs/SPEC-FRIEND.md). asked is the wall clock, as the file times are; zero retires none. record gets one line per write and per retirement, and one per held card it could not write. The counts are what the inbox holds after the pass.
type Keepalive ¶
type Keepalive struct {
DownAfter time.Duration // DownAfter unless a test shortens it
// contains filtered or unexported fields
}
Keepalive is the coordinator's state: per friend, the nonces it sent and when, and the last pong to one of them. It is stepped with the clock the loop reads; the loop owns the transport (cmd/nova-friend serve), so every rule is tested with no socket and no real time.
func NewKeepalive ¶
func NewKeepalive() *Keepalive
NewKeepalive is the coordinator's state with no friend yet.
func (*Keepalive) Friends ¶
Friends sets who is pinged to the friend rows read at now: a new row is pinged from now, and one no longer read is forgotten.
func (*Keepalive) Pong ¶
Pong records a pong from friend with nonce, read at now (the coordinator's clock, never the store's). Only a nonce sent to that friend in the last DownAfter answers, and only once: a stale, replayed or other friend's nonce changes nothing. It answers whether the pong counted.
type LaneEnd ¶
type LaneEnd struct {
Exit int
Err string // the harness's error, when the run did not end with an exit
Wall time.Duration // the run's wall, its start to its end
Cap string // the cap that stopped it, when one did
Rejected string // a permission the harness refused
Turns int // the turns the card had in the lane
Restart time.Time // not zero: the run was found gone by a daemon starting up at this time
Started time.Time // when the lane began the card
NoReport bool // the run wrote RESULT.md and no REPORT.md
// Capped is the card's wall cap by its tier when the lane ended the card at it
// (lane_cap.go), Tier that tier, Overrun the card's wall past the cap at its end, and
// Tail the last CapTailLines lines of the lane's output.
Capped time.Duration
Tier string
Overrun time.Duration
Tail string
}
LaneEnd is how a card's last run in a lane ended, as its finish says it.
type LaneGovernor ¶
type LaneGovernor struct {
Rand func() float64 // pseudo-random in [0, 1); nil is math/rand/v2.Float64 (docs/SPEC-FRIEND.md #rate-limit-backs-off-not-down.w1)
Now func() time.Time // clock; nil is time.Now
// contains filtered or unexported fields
}
LaneGovernor is the lanes' live cap under rate limits, and their hold when out of funds. Its zero value is the row's width, never paused. RateLimit lowers the cap by a quarter (at least one lane, never below one) and pauses new turns for the backoff, which doubles from RateBackoffFirst to RateBackoffMax; turns that started before the last lowering are the same episode and change nothing. Step resumes after the pause and raises the cap one lane per clean RateRaiseEvery, measured: a turn ended clean in it (Clean). Back at the row's width the backoff starts over. Each change is one line.
func (*LaneGovernor) Cap ¶
func (g *LaneGovernor) Cap(width int) int
Cap is the live cap at width: the row's width unless a rate limit has lowered it, never above the row.
func (*LaneGovernor) Clean ¶
func (g *LaneGovernor) Clean(now time.Time)
Clean is a lane turn that ended at now without a rate limit: the measurement a raise waits for.
func (*LaneGovernor) Held ¶
func (g *LaneGovernor) Held() string
Held is why the lanes are held, out of funds; "" when they are not.
func (*LaneGovernor) Hold ¶
func (g *LaneGovernor) Hold(reason string) bool
Hold is out of funds: the lanes start nothing more until the daemon restarts. It answers whether this is the first hold, the one to say.
func (*LaneGovernor) PauseUntil ¶
PauseUntil is a usage limit with its reset: no new turn or open before until, jittered by adding up to 20% of the remaining wait, never earlier than the reported reset itself (docs/SPEC-FRIEND.md #rate-limit-backs-off-not-down.w1). The cap is left alone. It answers the line that says it, empty when the pause already reaches until.
func (*LaneGovernor) Paused ¶
func (g *LaneGovernor) Paused(now time.Time) bool
Paused says whether no new turn or open may start now: a backoff under way, or out of funds.
func (*LaneGovernor) RateLimit ¶
func (g *LaneGovernor) RateLimit(now, started time.Time, width int, reason string) (line string, judge bool)
RateLimit is a rate limit met at now by a turn (or open) started at started, at the row's width: the line that says the change, and whether it is a judgment (the RateJudgeAfter-th lowering within RateJudgeWithin). A turn started before the last lowering is the same episode: no line. Every lane resume after a rate limit is spread by a jitter of +/-20% of the pause (docs/SPEC-FRIEND.md #rate-limit-backs-off-not-down.w1).
func (*LaneGovernor) Release ¶
func (g *LaneGovernor) Release()
Release lifts a hold: a person brought the lanes up (the pause marker is gone).
func (*LaneGovernor) Step ¶
func (g *LaneGovernor) Step(now time.Time, width int) []string
Step is the governor at now and the row's width: the pause's end said once, and a clean RateRaiseEvery with a clean turn in it raising the cap one lane; back at the width, the cap is the row's again and the backoff starts over. It answers the lines of what changed.
type LaneHarness ¶
type LaneHarness interface {
Deliverer
// OpenSession starts a new session of the friend with seed as its first
// turn, and answers the new session's id.
OpenSession(ctx context.Context, seed string) (session string, err error)
// DeliverTo pushes text into session as one turn and blocks until it
// ends: its exit, and a permission the harness refused without asking,
// read from the turn's output (empty when none). A rate limit is
// RateLimited and out of funds OutOfFunds (ProviderLimit); a provider's
// refusal is ProviderRefused, as Deliver answers it.
DeliverTo(ctx context.Context, session, text string) (LaneTurn, error)
}
LaneHarness is a Deliverer that can open a session of the friend and deliver into a session it names: what a one-shot lane needs, each lane its own session in the same harness and directory (docs/SPEC-FRIEND.md, one-shot lanes; the owner, 2026-10-04: "so [she] can still be wide, it's just 8 [of her]"). OpenCode is one.
type LaneHold ¶ added in v1.2.7
LaneHold is the server's answer to a lane's ask: the lane, the epoch the server holds, and the card the lane holds there (Card "" for none) at its generation, its kind (work or read) and its job (<id>~<epoch>, .g<gen> from the second generation).
func ParseLaneHold ¶ added in v1.2.7
ParseLaneHold reads the server's LANE line for member's lane n out of an ask's answer. An answer with no such line, or one naming another member or lane, is a refusal: the lane runs nothing (the fault of 2026-10-10 21:42Z: a take answered OK and the lane said "took" while the server still showed the card ready).
type LaneJob ¶
type LaneJob struct {
Dir string // <friend dir>/jobs/<job>: the harness's working directory
Card Card // Brief and Outbox absolute
Brief string // the brief's text, inline in the prompt; "" when it is not read yet
}
LaneJob is a card as its lane hands it to the harness: the job directory the harness runs in, the card with its brief and outbox absolute, and the brief's text, which the prompt carries.
func LaneJobOf ¶
LaneJobOf is card c of the friend's working directory dir as its lane hands it: every path made absolute by abs (filepath.Abs in the daemon), the job directory dir/jobs/<job>. A path abs cannot make absolute is refused: the error is one REFUSED line naming the path, and the lane does not start.
type LaneMark ¶
LaneMark is a job's lane mark as read: Who runs it (Ended false) or ended it (Ended true), and At, when a running mark was last refreshed.
func ReadLaneMark ¶
ReadLaneMark is the job's lane mark; found is false when there is none or it says neither word.
type LaneRules ¶
type LaneRules struct {
Tiers []string // row_tiers=flash,pro: the tiers she works; a dealt card of another tier is taken back; none: every tier
Streams []string // row_streams=security*,fp-sec*: patterns a card's stream or id must match; none: every card
TokenCap int64 // row_token_cap=<n>: tokens one card may spend, all kinds; 0 none
LoadMax float64 // row_load_max=<load>: above this one-minute load the lanes are held to LoadWidth; 0 none
LoadWidth int // row_load_width=<n>: lanes while the load is above LoadMax; DefaultLoadWidth when unset
PauseOn string // row_pause_on=funds|any: funds (the default) holds only for out of funds; any holds for a rate limit too
RefuseGo bool // row_refuse_go=1: the lane's PATH carries go and gofmt that refuse
}
LaneRules is what a friend's row says about which cards her lanes take and how hard they run: the zero value is no filter, no cap, no load rule, and a rate limit that backs off.
func LaneRulesOf ¶
LaneRulesOf reads the lane rules off the friend's beat answer; a word it does not know is ignored and a value that does not parse leaves the field unset.
func (LaneRules) Judge ¶
func (r LaneRules) Judge(id, stream, tier string) (LaneVerdict, string)
Judge is the card filter: a card of a tier outside Tiers (an unknown tier is outside) is taken back; a card whose stream and id match none of Streams is skipped; any other runs. The reason is a sentence for the record and for friend take.
func (LaneRules) LaneWidthUnderLoad ¶
LaneWidthUnderLoad is how many lanes may start with the machine's one-minute load at load: the row's width, held to LoadWidth while the load is above the row's LoadMax (a width at or below LoadWidth is never raised). held says it was lowered.
func (LaneRules) Over ¶
Over is r with every field row sets in place of its own: the flags give the defaults and the friend row, as her beat answers it, wins.
func (LaneRules) OverTokenCap ¶
OverTokenCap says a card has spent its cap; a rule with no cap is never over.
func (LaneRules) ProviderStop ¶
ProviderStop is the provider failure that stops every lane, and the message to hold the friend down with, as the provider said it: out of funds (402) always; a rate limit (429) only when the row says pause_on=any (otherwise it backs off, rate-limit-backs-off-not-down).
type LaneState ¶
type LaneState struct {
Sessions map[int]string `json:"sessions"`
Epoch uint64 `json:"epoch,omitempty"`
GivenUp []string `json:"given_up,omitempty"`
Started map[string]Started `json:"started,omitempty"`
// StopReturns is every card the machine's stop took out of a lane and the stop-return
// owed or taken for it (stop.go): a daemon starting up sends what is owed first.
StopReturns []StopReturn `json:"stop_returns,omitempty"`
}
LaneState is what the lanes keep across restarts, in the state directory (lanes.json): each lane's session, so a lane is the same friend's session for its life, the cards set aside after CardTurns, so a restart does not hand them again, and the cards a lane has begun and not ended, so a restart finishes each (a lane's end, lane_end.go). Epoch is the sprint's epoch the sessions were opened under (epoch.go): her row's past it forgets every session, so a full or stale session never carries across a clear.
type LaneTokens ¶
type LaneTokens struct {
cardcost.Tokens
USD string // opencode's own reported cost, a decimal; "" unknown
Sessions int
}
LaneTokens is what a session and its children spent, as opencode's own database says it, and what opencode itself priced it at.
func TokensFromOpenCode ¶
TokensFromOpenCode reads a session's tokens (and its children's) from opencode's own database through the sqlite3 CLI, read only (the tree has no sqlite driver).
func TokensFromOpenCodeIn ¶ added in v1.2.7
func TokensFromOpenCodeIn(ctx context.Context, run Exec, dbs []string, session string) (LaneTokens, error)
TokensFromOpenCodeIn reads a session's tokens from the first of dbs that holds it (a row for the session or a child). A lane's opencode runs inside the wall with the wall's HOME (the friend's config directory, else her working directory: sandbox.LaneProfile), so it writes its sessions under that HOME, not the daemon's; a batch turn writes under the daemon's (--db). A session in none of them is ErrSessionInNoDB, naming each database and why, never the all-zero tokens the sums give for no row (2026-10-10: every walled opencode lane read zero tokens from the daemon's database, and its runs were judged empty).
func TokensOf ¶
func TokensOf(out string) (LaneTokens, error)
TokensOf reads the one row TokensSQL prints (sqlite3's default, | between columns).
func (LaneTokens) Sub ¶
func (t LaneTokens) Sub(base LaneTokens) LaneTokens
Sub is the tokens spent after base: a lane's session serves many cards, so a card's are the session's totals at its end less its totals at its start.
type LaneTurn ¶
type LaneTurn struct {
Exit int
Rejected string // the line of the output where the harness refused a permission, if any
// Windows is the subscription windows' use the harness reported in the turn
// (a Claude Code run's rate_limit_event lines, ReadRateLimitEvents); nil when
// it reported none. The lanes are paced by it (pacing.go).
Windows []WindowUse
// FirstError is the first line of the turn's output that says an error
// (HarnessFirstError), "" when none does: a run that exits 0 with no report
// is a harness fault said with it (lanes.go, faultTurn).
FirstError string
}
LaneTurn is how one lane turn ended.
type LaneVerdict ¶
type LaneVerdict int
LaneVerdict is what the rules say of a dealt card.
const ( LaneRun LaneVerdict = iota // the lanes may run it LaneSkip // not hers to run: left on her row, never started LaneTake // outside her tiers: taken back for the dealer (friend take) )
type Launchctl ¶
Launchctl runs launchctl with args and answers what it printed; the installer passes the real one, a test its own.
type Limit ¶
Limit is what a command's output says of the harness's limit: Limited, until when and why; Usage when the output measured it; Overage when the harness is spending paid overage (a limit only if the owner does not allow it, Limits.AllowOverage).
func ReadLimit ¶
ReadLimit reads a command's output at now for the harness's limit: the last rate_limit_event anywhere in it (Claude Code), else a limit line in its tail with the reset beside it (a clock time, today or else tomorrow in now's zone or the zone it names, on the date it names; "in N hours"; an epoch after "limit reached|"; resetOfText). found is whether the output said anything of the limit at all. A provider's transient rate_limit_error is no limit (ProviderRefusal passes it).
type LimitHit ¶
LimitHit is a limit read from a failed turn's output: its kind, the reset (the text's own when Named, else now plus the rest), and the line.
func ParseLimit ¶
ParseLimit reads the tail of a failed turn's output (the last LimitTail bytes: a harness says it last) for harness's own wording of a usage limit or an empty balance: the kind, and the reset when the line names one, else now plus rest (DefaultLimitWait when rest is zero). A harness it has no words for, or a text it does not recognise, is not a limit. A reset that is not after now is no reset. The newest matching line wins.
type Limits ¶
type Limits struct {
Now func() time.Time
Nonce func() string // six random characters when nil
Down func(until time.Time, reason string)
Up func(nonce string)
// Unread is the judgment when a limit's text names no reset this reads: the
// friend is held for Rest and the text goes to the coordinator, once until
// a wake is answered, so the reset is set by a person (friend down --until)
// and not guessed again each Rest (usage-limit-reset-read-from-the-message-b.w1).
Unread func(text string)
// Harness is the harness whose own wording a failed turn is read in
// (ParseLimit), and Rest how long it is down when the text names no
// reset (DefaultLimitWait when zero): --limit-rest.
Harness string
Rest time.Duration
// AllowOverage is the owner's word that this friend may spend paid
// overage; without it a harness on overage reads down.
AllowOverage bool
// Pacing is the row's pacing (the fraction of each subscription window the
// sprint may spend), read at each batch turn; nil, or out of (0, 1], is
// DefaultPacing. Every output's rate_limit_event feeds the pacer, and a batch
// turn while a window is at the pacing is Deferred until it resets
// (pacing.go).
Pacing func() float64
// contains filtered or unexported fields
}
Limits is one friend's harness limit: up, or down until a reset, then waking until a turn answers the current nonce (tla/FriendLimit.tla is owed). Watch reads every command's output for it; Gate holds deliveries while it is down and wakes the session after the reset. The hooks say the change to the sprint: Down once per limit with its reset (friend down --until), Up when a wake answered.
func (*Limits) Beat ¶
Beat is beat held back while the harness is at its limit: no beat goes to the sprint server, so her row reads down, from the turn that hit the limit until a wake after the reset answers its nonce (Gate). A reset that passes with no answer (the wake never reached a session, say) keeps her down: only the session's answer brings her up, never a process seen or not seen in the process table (HarnessWatch is advisory).
func (*Limits) BeatOrDown ¶
func (l *Limits) BeatOrDown(beat func(ctx context.Context) error, down func(ctx context.Context, until time.Time, reason string) error) func(ctx context.Context) error
BeatOrDown is beat while the harness answers, and down while it is at its limit (limits-mean-down-w-r5.w1~15): her beat says down with the until and the reason (nova-sprint friend beat --until --reason), so her row reads down and why rather than going silent, until a wake after the reset is answered. A nil down holds the beat back as Beat does; a down the sprint server refuses is an error, and her row reads down by the lapse as before.
func (*Limits) Gate ¶
Gate is d held by the limit: a delivery while the harness is down is Deferred without running it (the daemon keeps the message in hand, counted toward nothing); the first after the reset is a wake turn (WakeText) whose output must carry its nonce, a fresh one each try, before the message goes in; a turn that hits a limit is Deferred too. A passive d is d. A LaneHarness stays one (gatedLanes): its batch Deliver is held, and its lanes are not.
func (*Limits) Refuse ¶
Refuse is a credit or quota refusal a caller read where this harness's own wording parse (ParseLimit) and the limit tail found none: the daemon's per-harness table in cmd/nova-friend/limit.go reads a lane's evidence and hands the hit here (docs/SPEC-FRIEND.md, every harness's credit and quota refusal). It takes the same state and hooks see takes for a limit a harness's own wording names: the friend is down until the refusal's until, her turns and beats are held, Down says it to the sprint once, and status reads session=limited limit_kind=kind limit_until=until. A refusal equal to the one that already holds her is not a second down.
type Liveness ¶
Liveness is an adapter's answer about its harness: Known false when the adapter cannot tell (its friend relies on the session check alone), else Running; Why says what was read, and Rule which rule read it: RuleSession (the session's own last turn), RuleApp (a desktop app in the process table), or empty for another signal (a window, a tmux session, a runner on the path).
type LogFacts ¶
type LogFacts struct {
Last string // RFC3339 of the newest delivery in the window, or "-"
LastExit string // its exit, or "-"
FailedOfLast20 int // failures among the newest 20 deliveries in the window
Deferred int // deferrals in the window
Delivered int // deliveries in the window
Failed int // of those, the ones that exited non-zero
}
LogFacts is what the daemon's log says inside a window.
type Machine ¶
type Machine struct {
Window time.Duration // Window unless a test shortens it
Connection string // Connected or Silent
LastPing time.Time // when the last ping arrived; the start, before any
Seat string // the coordinator the last ping named
SeatSince time.Time // since when, as the ping said
SilentFrom time.Time // when the coordinator went silent, while Silent
Challenge string // Quiet, Challenged or Deaf
Nonce string // the nonce of the current challenge
Asked time.Time // when it was pushed in
LastPong time.Time // when the session last answered a current nonce
Pongs int // session pongs seen, in all
Idle string // Awake, Woken or Noted
IdleSince time.Time // when the idle measure starts, if no write is newer: the start, or when a card was first held
WokenAt time.Time // when the wake turn was given, while Woken or Noted
WokenSeen time.Time // the newest write the wake was given on; a newer one answers it
}
Machine is the daemon's state. The daemon steps it with the clock it reads (Tick), the pings that arrive (Ping) and the pongs the session records (Pong); each step answers the pushes the session is owed, in order. The daemon owns the transport around it.
func Start ¶
Start is the daemon's state as it comes up at now: connected, with the start standing in for the last ping (a coordinator that never pings is silent one window after the start), and nothing asked of the session.
func (*Machine) IdleStep ¶
IdleStep is the idle watch at now, with active the session's newest write (zero: none known), cards the cards she holds and after the idle setting (docs/SPEC-FRIEND.md, idle wake): holding no card is awake, and the measure starts again when one is held; a write newer than the one the wake was given on is awake again; awake with no write for after is one wake turn; woken for after with no write is one note to the coordinator; noted says nothing more until a write or no card ends it.
func (*Machine) Ping ¶
Ping is a ping arriving at now from seat (held since since) with nonce: the connection is back if it was silent (the session is told once), and the session is challenged with this nonce, whatever it was before, so only the newest nonce counts (tla/Friend.tla: Ping). The ping itself goes into the session as the message it arrived in; the daemon delivers that, so the pushes here are only the daemon's own words.
type Mailbox ¶
Mailbox is a harness whose session queues what is delivered: Follow reads who read the deliveries and moves delivery to the conversation that reads, sending again what the old one left unread; Live is the conversation deliveries go to.
type NoReport ¶
type NoReport struct {
Run string // the harness as the run names it, "claude -p"
Exit int
Outbox string
Lacks []string // the files the outbox lacks
}
NoReport is a card runner's run that ended with its outbox holding neither REPORT.md nor RESULT.md (the Claude lane's), its words as the run says them.
type NotServed ¶
type NotServed struct{ Why string }
NotServed is a sprint server that refused friend cards (Refused) where the daemon has no worker view to fall back on; it is said once a ServedEvery, each time the verb is asked again.
type NotStageable ¶
type NotStageable struct {
Repo, Card, Why, Remedy string
Job string // the job it was staging, when there was one
}
NotStageable is a stage that waits on a person: her account cannot reach the repository (Card empty: every card on it waits), or the card's packet names what is not there. It is one judgment to the coordinator, its Remedy what clears it.
func (*NotStageable) Error ¶
func (n *NotStageable) Error() string
type Notice ¶
Notice is one of the daemon's own words about the coordinator (a Push of Machine's), with the id the daemon gives it when it is said: the record names a dropped notice and its successor by these ids.
type NotificationBatch ¶
type NotificationBatch struct {
Text string `json:"text"`
Entries []string `json:"entries,omitempty"`
Messages []bus.Message `json:"messages,omitempty"`
Ready bool `json:"ready,omitempty"`
Accepted bool `json:"accepted,omitempty"`
}
NotificationBatch is the immutable input kept before enqueue. Accepted means the queue took it, not that the model processed it; recovery then retries only receipts.
type NotificationPolicy ¶
NotificationPolicy selects model notifications. Requests and blockers always keep their payloads; report is on by default; transport ack and routine status are audited.
type NotificationState ¶
type NotificationState struct {
Pending *NotificationBatch `json:"pending,omitempty"`
// Report retains the legacy JSON key for the one deferred report or notice batch.
Report *NotificationBatch `json:"report,omitempty"`
ReportRetryAt time.Time `json:"report_retry_at,omitzero"`
Deals map[string]*DealNotice `json:"deals,omitempty"`
Ready bool `json:"ready,omitempty"`
ReadyDue time.Time `json:"ready_due,omitzero"`
NextReady time.Time `json:"next_ready,omitzero"`
RetryAt time.Time `json:"retry_at,omitzero"`
Failures int `json:"failures,omitempty"`
Audited int `json:"audited"`
LastID string `json:"last_id,omitempty"`
}
NotificationState is bounded to one active batch, one deferred nonurgent batch and a ready bit. The bus remains the source of every message; filtered entries retain their audit there.
func ReadNotificationState ¶
func ReadNotificationState(dir string) (s NotificationState, err error)
ReadNotificationState and WriteNotificationState use the existing fsynced atomic state writer (SPEC-FRIEND.md, notifications), under the notification-only directory.
type OpenCode ¶
type OpenCode struct {
Dir, Session string
Run Exec
Program string // "opencode" when empty
Out io.Writer // where the turn's output goes, when set: the daemon's record
// Allow is every other path the friend's directory is reached by (a
// symlink in the home directory): with Dir and its real path, allowed in
// the project config before a turn (AllowDirs), so a headless run never
// auto-rejects a tool call there. Nil: the config is left alone.
Allow []string
// Standalone passes --standalone to every run: opencode 2.0.25 (the
// background service, 2026-10-09) makes `opencode run` attach to a shared
// background service (`opencode serve --service`, started once, detached)
// instead of a private server, so a sealed provider key (nova-secrets exec)
// reaches no provider ("Incorrect API key provided"); --standalone keeps the
// run in this process, with this environment. CheckRun sets it when the
// installed run lists the flag, so an older opencode is never handed it.
Standalone bool
// contains filtered or unexported fields
}
OpenCode delivers through `opencode run --session <id> <text>` run with Dir as its working directory (the process's, never a flag: opencode v2.0.20's run has no --dir, and every delivery that passed one exited 1, "Unrecognized flag: --dir", 2026-10-06), which blocks for the whole turn; without a session named, the newest session whose directory is Dir, from `opencode session list --format json`, so a friend who starts a fresh session is still reached. CheckRun, at the daemon's start, refuses an opencode whose run lacks a flag the adapter passes.
func (*OpenCode) Alive ¶
Alive: the session's last turn (opencode run, a batch's or a lane's); before the first, a runner that cannot be found is not running.
func (*OpenCode) CheckRun ¶
CheckRun reads the installed opencode once, at the daemon's start: its version (`opencode --version`) and its run verb's flags (`opencode run --help`), and is a one-line refusal naming the version when the help lacks a flag the adapter passes (OpenCodeRunFlags), so the next change of the CLI is a named refusal and not a silent exit 1 on every delivery (the finding of 2026-10-06: --dir, gone from run in v2.0.20). A help that lists no flag at all, or that cannot be read, cannot tell, and is nil: the deliveries say what they meet.
func (*OpenCode) DeliverFresh ¶ added in v1.2.7
DeliverFresh is one fresh turn of the friend's opencode, a session of its own that no listing is read for and none is grown: `opencode run <text>` in Dir with no --session. It is the daemon's presence check for a one-shot friend (docs/SPEC-FRIEND.md, presence: a tiny fresh turn per check; FriendPresence.tla, OneShotNeverDownBySession), so a session that is full or missing is never the reason she is down. Its output is read as a lane turn's is.
func (*OpenCode) DeliverTo ¶
DeliverTo is one card's turn in a lane's session: `opencode run --session <id> <text>` in Dir, its output read for a refused permission, and its tail for a rate limit or out of funds (ProviderLimit, whatever the exit: the lanes heed it only when the card has no RESULT.md) before a provider's refusal of the session.
A lane's turn runs in the card's job directory, the one its context carries (WithLaneDir), so a path the model reads relative is read inside the job; with none it runs in Dir.
func (*OpenCode) OpenSession ¶
OpenSession runs the seed as the first turn of a new session in Dir (`opencode run <seed>` in Dir, no --session) and answers the session that appeared in the listing of Dir, the newest the listing before it did not hold. The lanes' directories are allowed in the project config first.
func (*OpenCode) ReadOnReturn ¶
func (*OpenCode) ReadOnReturn()
type OpenCodePriced ¶
type OpenCodePriced struct {
*OpenCode
// Friend is the friend's name, as a capped card's report says it.
Friend string
// TokenCap is the friend row's per-card token cap as the daemon last read
// it (TokenCapOf; 0 none); nil is DefaultTokenCap.
TokenCap func() int64
// Tick is the clock a running turn's usage is polled on (every TokenPoll);
// a real ticker when nil.
Tick func(time.Duration) (<-chan time.Time, func())
// contains filtered or unexported fields
}
OpenCodePriced is an OpenCode friend's lanes with every run priced from opencode's own session record (docs/SPEC-FRIEND.md, the Claude lanes, the OpenCode lane): after each turn `opencode export <session>` is read, and the run's cost is what the session's assistant messages gained since the last read (each message's cost is opencode's own figure), said on the record as one line per run. The daemon wraps the friend's OpenCode in it; a bare OpenCode runs no export. A card's turn is capped by its tokens, read from the same record (tokencap.go).
func (*OpenCodePriced) DeliverTo ¶
DeliverTo is OpenCode's under the card's token cap (deliverCapped), then the run priced, whatever it answered.
func (*OpenCodePriced) OpenSession ¶
OpenSession is OpenCode's, then the first run priced.
func (*OpenCodePriced) SpendLine ¶
func (p *OpenCodePriced) SpendLine() string
SpendLine is every run's cost so far and, when the last run stopped at a usage limit, its reset: `spend: harness=opencode runs=<n> cost_usd=<sum> [limited_until=<t>]`. An API friend has no five-hour or weekly window to read; her limit is what the run said (Spender).
func (*OpenCodePriced) Spent ¶
func (p *OpenCodePriced) Spent() float64
Spent is the cost of every run priced so far, in US dollars.
type OutOfFunds ¶
type OutOfFunds struct{ Session, Reason string }
OutOfFunds is a lane's answer when the provider refused for want of funds or credit (a 402, insufficient balance): the lanes hold until the daemon restarts, and the coordinator is told once (LaneGovernor.Hold).
func (OutOfFunds) Error ¶
func (o OutOfFunds) Error() string
type Pacer ¶
type Pacer struct {
// contains filtered or unexported fields
}
Pacer is a friend's lanes paced by her subscription windows. Its zero value knows no window and paces nothing.
func (*Pacer) Observe ¶
Observe takes a turn's report: each window replaces its last report. A report with no utilization (under the harness's warning threshold) keeps the use last read for the same reset, since use does not fall within a window.
func (*Pacer) Step ¶
Step is the pacer at now: the effective width, the line that says a change of it (empty when none), and whether this step owes the coordinator the judgment (paced below half her row, said once until she is back at half or more).
func (*Pacer) Use ¶
Use is the live windows' use as the table says it: "5h 62% 7d 31%", empty when none is live.
func (*Pacer) Width ¶
Width is the lanes' effective width at now for the row's width and the pacing fraction, and the window that decided it ("" when none did). A window at or past the pacing, or that the harness rejected, allows none until it resets; below it, the width is the row's scaled by the share of the paced budget left, rounded up: the lanes thin as the window fills.
type Packet ¶
Packet is what a held work card says about its checkout: the repository (owner/name), the base it starts at (a branch, a tag or a full sha) and its pin (BaseSha, the commit a `BASE: <ref>@<sha40>` names; "" when unpinned), the branch its work is pushed to, and its attempt.
type Pong ¶
type Pong struct {
Nonce string `json:"nonce"`
At time.Time `json:"at"`
To string `json:"to"`
Queue int `json:"queue"`
Working int `json:"working"`
Width int `json:"width"`
}
Pong is the session's last answer, as the pong verb records it beside sending it: the proof the daemon forwards.
type Presence ¶
type Presence struct {
Quiet, Bound time.Duration
Up bool
Reason string // why it is down; empty while up
LastHeard time.Time // the session's last bus message, or its last answer, while up
Nonce string // the latest check's nonce, until the session answers it
Asked time.Time // when the latest check went in
Open bool // the latest check is unanswered and within the bound
Owed bool // a check is due and has not gone in
Checks int
Answers int
Answered string // the nonce the session last answered
// Read is the latest check read by the session: its headless turn ended, or the
// adapter saw the session take it (ReadOnReturn). Until then it is asked again only
// after ReaskAfter, so a session that queues checks never holds a pile of them.
Read bool
// Proven is the push proved this run: the session answered a check or wrote on
// the bus since the daemon started. Until then the daemon delivers nothing
// (docs/SPEC-FRIEND.md, The push proof); once proved it stays proved for the run.
Proven bool
}
Presence is the session's proof of life, stepped by the clock and the bus messages the daemon hands it, so every rule is tested with no socket and no real time. It starts down with a check owed: a daemon that came up proves nothing about the session.
func StartPresence ¶
func StartPresence() *Presence
StartPresence is the presence as the daemon comes up at now: down, not yet answered, a check owed at once.
func (*Presence) Answer ¶
Answer is the session's reply carrying nonce, at now: the latest check's nonce makes the friend up, late or not; any other, or one already answered, changes nothing (current false).
func (*Presence) Ask ¶
Ask is the check with nonce going into the session at now: the bound runs from here.
func (*Presence) Heard ¶
Heard is a bus message the session wrote, at now: the session is alive, so the friend is up (rose: it was down). A check still open stays open, its answer still owed: only an answered check proves her session to the sprint server. The daemon's own messages never reach here (SessionCheck.read).
func (*Presence) Tick ¶
Tick is the clock at now: an open check past the bound makes the friend down, NoSessionAnswer, unless the session wrote on the bus since it went in, and so does silence for SessionQuiet plus SessionBound with it unanswered; a check is owed ProveEvery after the last check went in while up and SessionQuiet after it while down, and an unanswered one the session has not read is asked again only after ReaskAfter.
type PresenceStatus ¶
type PresenceStatus struct {
Friend string `json:"friend"`
At time.Time `json:"at"`
Presence string `json:"presence"` // PresenceUp or PresenceDown
Reason string `json:"reason,omitempty"`
LastHeard time.Time `json:"last_heard"`
Nonce string `json:"nonce,omitempty"`
Asked time.Time `json:"asked"`
Checks int `json:"checks"`
Answers int `json:"answers"`
Answered string `json:"answered,omitempty"` // the nonce the session last answered
}
PresenceStatus is the presence file: what status reads.
func ReadPresence ¶
func ReadPresence(stateDir string) (s PresenceStatus, found bool, err error)
ReadPresence is the presence file; found is false when no daemon wrote one.
type PresentPlan ¶
type PresentPlan struct {
Superseded []string
Note *bus.Entry
Fresh []bus.Entry
Requests int // the friend's own present requests, acked with the rest and counted as nothing
Skipped Skipped
}
PresentPlan is the present's decision over the backlog: the entries acked superseded, the newest coordinator note carried in the turn (nil: none), the pings still inside the challenge window (answered by the daemon as any ping, never superseded), and the counts.
func PlanPresent ¶
func PlanPresent(friend, seat string, backlog []bus.Entry, storeNow time.Time, window time.Duration) PresentPlan
PlanPresent is the present's decision over backlog, every message waiting on her stream, oldest first, at the store's time storeNow, with seat the coordinator (the seat holder, else who she reports to; "" unknown). A PING inside window is fresh, answered by the daemon and kept off the skipped line; a SESSION CHECK is never fresh (a run before this one asked it, and its nonce answers nothing this daemon asked). Of the rest the newest from seat that is no deal is the note the present carries; everything else is superseded.
type ProviderRefused ¶
type ProviderRefused struct{ Session, Reason string }
ProviderRefused is a Deliverer's answer when the turn reached the session's model provider and the provider refused the request itself (an invalid_request_error, an authentication_error): the session is at fault, not the message. The daemon counts it toward nothing a message owns; the same refusal on BrokenAfter turns in a row marks the session broken (the finding of 2026-10-04: a friend's session refused every turn for two hours and nothing said so).
func (ProviderRefused) Error ¶
func (p ProviderRefused) Error() string
type Push ¶
Push is text the daemon owes the session as a turn: the ping (with the pong line to run), or a word about the coordinator.
type PushProver ¶
type PushProver struct {
Friend, Harness string
Store bus.Store // the store itself, never the daemon's (DaemonStore)
Deliver Deliverer // the adapter the check goes in by
Now func() time.Time
Record func(line string) // nil records nothing
// contains filtered or unexported fields
}
PushProver records the friend's inbox push proof on the bus (bus.PushKey; docs/SPEC-BUS.md, bus-requires-inbox-push-proof) from the daemon's presence, as the SessionCheck saves it: nova-bus names shows it, and send and recv say it as a NOTE beside a message to or from a name without one, never a refusal. The proof is the SESSION CHECK round trip: the check carried into the session by the deliver adapter and the session's pong carrying its nonce (SessionCheck, presence.go). While the presence is up the proof is up and renewed every PushRenewEvery; when the presence is down (a check unanswered within its bound, or a daemon that has not yet been answered) the proof is written down at once, so a sender is told the moment the daemon knows. A passive harness (no deliver command: the check only goes on the stream) pushes nothing into the session and is written down whatever its pongs say.
func (*PushProver) Save ¶
func (p *PushProver) Save(inner func(PresenceStatus) error) func(PresenceStatus) error
Save is inner with the proof written first: what the SessionCheck's Save is set to, so each presence the daemon saves is also the bus's proof. A failed write is recorded and tried again at the next save; it never stops the presence file.
func (*PushProver) Step ¶
func (p *PushProver) Step(s PresenceStatus)
Step writes the proof the presence s says, when it differs from the last one written or the last up one is PushRenewEvery old.
type Queue ¶
type Queue struct {
Tasks []Task `json:"tasks"`
}
Queue is the friend's queue file: one record per task; the coordinator writes assignments into it, the session marks them working or done.
type QueueLine ¶
type QueueLine struct {
Card, Col, Brief string
}
QueueLine is one card of her live queue as the present names it.
type RateLimited ¶
type RateLimited struct{ Session, Reason string }
RateLimited is a lane's answer when the provider rate-limited the turn (a 429, "rate limit reached", "too many requests", "input token limit exceeded"): the turn's card stays in hand, counted toward nothing, and the lanes back off (LaneGovernor.RateLimit).
func (RateLimited) Error ¶
func (r RateLimited) Error() string
type ReadHarness ¶
ReadHarness is a harness that runs one read as a one-shot of its own: a new session with the prompt as its only turn, on model ("" is the harness's own), blocking until it ends. A harness without it runs the prompt as the seed of a new lane session (LaneHarness).
type ReadOnReturn ¶
type ReadOnReturn interface{ ReadOnReturn() }
ReadOnReturn is an adapter whose delivery returns exit 0 only once the session has taken the text: a headless turn that ran (dsh, gemini, opencode run), or a message the session marked read (antigravity's read.json). A check it delivered is read, and may be asked again on the check cadence.
type ReadPacket ¶
type ReadPacket struct {
Tier string `json:"tier"`
Head string `json:"head"`
WorkBranch string `json:"work_branch"`
Attempt int `json:"attempt"`
Brief string `json:"brief"`
Report string `json:"report"`
}
ReadPacket is what the reader queue says of one asked read.
type Refused ¶
type Refused struct{ Why string }
Refused is the sprint server's refusal of a verb it answered (a non-zero exit), as against a server that did not answer: a refused friend cards is a server that does not serve it yet.
type RoutePrice ¶
RoutePrice is the store's route row for the friend's exact provider/model: its name and price sheet; Found is false when there is none.
func RoutePriceOf ¶
func RoutePriceOf(routesJSON, provider, model string) RoutePrice
RoutePriceOf finds the route row for provider/model in the sprint's `routes --json` answer: the first object anywhere in it that has a prices object and this provider and model. A route that does not say reasoning_as_output bills reasoning as output.
type Row ¶
Row is one answer of what is on her row: the cards, whether her reads are among them (a job no card names is retired only when the answer covers its kind: the worker view lists her work cards and none of her reads), where the answer came from, and Note, a line the daemon says with it ("" for none: the server's refusal of friend cards, once a ServedEvery). Epoch is the sprint's epoch as the answer said it: the highest on her row, every card on her row being dealt at the sprint's current epoch, and on a view answer the view's own; zero when the answer names no card and the epoch is unknown (an empty row: nothing is retired on it, and the next deal names the new one).
type SessionCheck ¶
type SessionCheck struct {
Friend string
Store bus.Store // the store itself; the daemon is handed DaemonStore
// Deliver is the adapter the check goes in by, as Gate wrapped it.
Deliver Deliverer
Now func() time.Time
Nonce func() string // a fresh nonce per check
Text func(nonce string) string // the check as the session reads it: the one answer line to run
Record func(line string) // nil records nothing
Save func(PresenceStatus) error
Go func(func()) // runs a check's delivery; nil is a goroutine
// Run is this daemon's run, its generation, said with every check and answer
// on the beat: the server counts an answer only to a check the same run asked.
Run string
// Keep is the nonce of a check the daemon's last run put into the session and
// never saw answered (its presence file's nonce): every check carries it until
// the push is proved, so the session's late answer to the check already queued
// in it proves the push, whatever restarts came between. "" starts fresh.
Keep string
// Mode is the friend's delivery mode as the daemon reads it (ModeBatch or
// ModeOneShot; "" while it has not read it: before the first up beat, or with
// no --mode): her check goes in as a fresh turn of its own (FreshTurn) in
// one-shot mode, never into a growing session, so a full or missing session
// is never the reason she is down. "" tries the session and falls back to a
// fresh turn when the session's deliver is refused full or missing, so a
// one-shot friend whose beat never comes still reads up. nil is a batch friend.
Mode func() string
// contains filtered or unexported fields
}
SessionCheck is the daemon's side of presence: it reads the bus log for the session's messages, steps the Presence, puts the check into the session through the adapter (Gate) or, for a harness with no deliver command, on the friend's own stream, and holds the beat back while the session is down (Beat). The daemon's own sends go through DaemonStore, so a message the daemon wrote never passes for the session's.
func (*SessionCheck) Beat ¶
Beat is beat held back while the session is down: the sprint server's friend is up only while her session answers. Each call steps the check first.
func (*SessionCheck) BeatAlways ¶
func (s *SessionCheck) BeatAlways(beat func(ctx context.Context) error) func(ctx context.Context) error
BeatAlways is beat with the check stepped first and never held back: a claude friend's (docs/SPEC-FRIEND.md, The push proof), whose cards run as processes of their own and whose presence at the server is their finishes; her session check goes in by the folder (FolderCheck) and its answer rides the beat (Words), so a live session proves the push and no session refuses nothing.
func (*SessionCheck) BeatOr ¶
func (s *SessionCheck) BeatOr(beat func(ctx context.Context) error, down func(ctx context.Context, until time.Time, reason string) error) func(ctx context.Context) error
BeatOr is beat while the session is up, and while it is down the beat that says so (down: until when the daemon next expects an answer, and why: the push unproven with the check's nonce, or no session answer to it), so the sprint server reads her down with the daemon's reason the second it knows (docs/SPEC-FRIEND.md, presence). A nil down holds the beat back instead. Each call steps the check first.
func (*SessionCheck) DaemonStore ¶
func (s *SessionCheck) DaemonStore() bus.Store
DaemonStore is the store the daemon sends through: each message it adds is remembered as the daemon's.
func (*SessionCheck) Gate ¶
func (s *SessionCheck) Gate(inner Deliverer) Deliverer
Gate is inner with the session's turns holding the turn shared, so a check never goes into a session in the middle of a turn. A passive harness (no deliver command) is answered as it is: its check goes on the stream. A harness that opens a session per lane keeps its lanes.
func (*SessionCheck) Present ¶
func (s *SessionCheck) Present() (bool, string)
Present is whether the session is up, and why not.
func (*SessionCheck) Proof ¶
func (s *SessionCheck) Proof() (proven bool, nonce string)
Proof is whether the push is proved this run (the session answered a check, or wrote on the bus, since the daemon started), and while it is not, the nonce the check carries. The daemon delivers nothing until it is.
func (*SessionCheck) Said ¶
func (s *SessionCheck) Said(w BeatWords)
Said is w carried by a beat the server took: each word said is not said again.
func (*SessionCheck) Step ¶
func (s *SessionCheck) Step(ctx context.Context)
Step is one look: the session's messages since the last, the clock, and the check when it is owed.
func (*SessionCheck) Words ¶
func (s *SessionCheck) Words() BeatWords
Words is what the next beat says: the check asked and the check answered that no beat has carried yet. A beat the server took clears them (Said).
type SessionRefused ¶
type SessionRefused struct{ Session, Reason, Detail, Remedy string }
SessionRefused is a Deliverer's answer when the turn's output says the session cannot take a turn at all, whatever the exit code (dsh: a session under an agent preset, a missing provider key; DSHRefusal): a failed delivery, never a delivered one. Reason is one line naming the session and why, what the status and the friend's row say; Detail what to do; Remedy as in Deferred. The daemon marks the session broken with Reason on the first such turn, keeps every message pending and tries again every RecheckEvery, and a turn that succeeds clears it (docs/SPEC-FRIEND.md, "A turn the session cannot take"). As a Deferred it is the same message kept, so a reader of Deferred (PushProof, the check) still sees its remedy.
func DSHRefusal ¶
func DSHRefusal(session, dir, out string) (SessionRefused, bool)
DSHRefusal reads one headless turn's output, whatever its exit code, for an answer that the session cannot take a turn at all: the agent preset refusal, or MISSING_CREDENTIAL. Either is a failed delivery (SessionRefused), never a delivered turn: the finding of 2026-10-06, Zhi's session under preset "minimal" printed the refusal and exited 0, and four hours of messages counted as delivered while her row read up. The reason is fixed text; the output itself, which may name a credential, is never carried.
func (SessionRefused) As ¶
func (s SessionRefused) As(target any) bool
As answers a SessionRefused as the Deferred it also is: the message stays pending, and a session it cannot drive carries its Remedy.
func (SessionRefused) Error ¶
func (s SessionRefused) Error() string
type SessionTurns ¶
type SessionTurns struct {
// contains filtered or unexported fields
}
SessionTurns is a headless adapter's record of its own last turn into the session (a delivery, a session check, a lane's turn): when it ended, into which session, and how. A harness with a headless program (dsh headless, gemini --resume, opencode run, codex exec) is alive on its session's word: the last turn ended exit 0 within AliveWithin; no desktop app is read (the finding of 2026-10-06: zhi's deliveries through dsh headless answered in 4 s while the DeepSeek Harness app was closed, and the app check said "harness not running"). A deferred turn (nothing ran) is not a turn. The clock is the daemon's, set by WatchHarness; time.Now until then.
func (*SessionTurns) TurnUnderWay ¶
func (s *SessionTurns) TurnUnderWay() (bool, time.Time)
TurnUnderWay is the record's word: a turn has begun and not ended, since the latest's start.
type Setting ¶
type Setting struct {
Harness, File, Name, Want, Have string
}
Setting is one setting a harness needs: the file (or directory) it lives in, its name, the value install writes and the value there now. A setting whose Have is not its Want has drifted.
type SettingsFS ¶
type SettingsFS interface {
Lstat(path string) (Entry, error)
ReadFile(path string) ([]byte, error)
WriteFile(path string, data []byte, perm fs.FileMode) error // whole, atomically
MkdirAll(path string, perm fs.FileMode) error
}
SettingsFS is the filesystem the settings are read and written through: OSFS for install and check, friendtest.MemFS (the in-memory twin) for a test.
type ShownEntry ¶
ShownEntry is the shown status of a friend (passed via --shown).
func LookupShown ¶
func LookupShown(shown map[string]ShownEntry, friend string) *ShownEntry
LookupShown returns the ShownEntry for friend, checking friend name then wildcard.
type Skipped ¶
type Skipped struct {
Deals, Pings, Notes int
}
Skipped is what one present superseded, by kind: the deals (card ... dealt), the pings (PING and SESSION CHECK whose nonce is past the challenge window), and every other note.
type Spender ¶
type Spender interface {
SpendLine() string
}
Spender is a lane harness that prices its runs (docs/SPEC-FRIEND.md, the Claude lanes, on the beat): SpendLine is what its runs have cost so far and the limit it last read, one line the daemon says on its beat when it changed; empty before any run.
type Stager ¶
type Stager struct {
Dir string
URL func(repo string) string
Env []string
// contains filtered or unexported fields
}
Stager stages jobs under Dir, her working directory, with the git credentials of the process that runs it (the daemon's: her account's). URL names a repository's remote (nil: GitHubURL); Env is git's whole environment (nil: the daemon's own, with GIT_TERMINAL_PROMPT=0, so git never waits on a prompt no one answers).
func (*Stager) Prune ¶
Prune removes the worktrees of finished jobs past kept, the oldest staged first (by its JOB.md), at most PrunePerPass of them, and answers the jobs it removed; a job whose mirror a stage holds is left for the next pass, never waited on. A job is finished when it is not live (held on her row, run by a lane, being staged: the caller's live) and its brief is not in her inbox (the inbox cleanup retired it); only a job whose checkout is a worktree of one of her mirrors is ever pruned, never a clone or anything another hand staged. A pruned job is gone whole (jobs/<job>), its worktree removed from the mirror; its branch stays in the mirror, so any commit on it is kept, and a stage of the job again takes the branch as it stands.
func (*Stager) Stage ¶
Stage stages p's job: the mirror of its repository fetched (cloned the first time), a git worktree of it at the base on the card's branch at jobs/<job>/repo, whose origin is the repository itself (the mirror's origin), and jobs/<job>/JOB.md. It answers the commit the checkout is at. A job already staged is left as it is; a checkout is never half there (the worktree is added beside, under jobs/<job>/.staging, and moved in whole), and JOB.md is written last, so a lane never meets a checkout not ready. A branch the mirror already holds (a pruned job's, staged again) is checked out as it stands, never reset to the base.
type Started ¶
Started is a card a lane began, kept in the lane state until the lane is done with it: a daemon that starts up and finds one finishes it, for the run that held it is gone.
type Status ¶
type Status struct {
Friend string `json:"friend"`
Harness string `json:"harness"`
Started time.Time `json:"started"`
At time.Time `json:"at"` // when this was written
Connection string `json:"connection"`
LastPing time.Time `json:"last_ping"`
Seat string `json:"seat"`
SeatSince time.Time `json:"seat_since"`
Challenge string `json:"challenge"`
Nonce string `json:"nonce"`
LastPong time.Time `json:"last_pong"` // the session's pong, the only answer that ends a challenge
Pongs int `json:"pongs"`
// LastDaemonPong is when the daemon last answered a ping itself: transport,
// never the session (docs/SPEC-FRIEND.md, session-pong.w1).
LastDaemonPong time.Time `json:"last_daemon_pong"`
Delivered int `json:"delivered"` // messages acked this run
Beats int `json:"beats"`
LastBeat time.Time `json:"last_beat"`
BeatError string `json:"beat_error,omitempty"`
Envelope int `json:"envelope"` // messages the last envelope carried (docs/SPEC-FRIEND.md, the loop)
EnvelopeBytes int `json:"envelope_bytes"` // its text's size: at most the deliverer's text limit, the first message always in
// Push is the push proof this run (PushProved, or PushUnproven while the
// session has not answered its check: nothing is delivered), PushNonce the
// check's nonce and PushSince when the daemon started waiting, while unproven;
// empty for a harness with no session to prove. ProofSent is the session's
// proof (the presence file's last_heard) the sprint server last took on her
// beat, zero before any (docs/SPEC-FRIEND.md, The push proof).
Push string `json:"push,omitempty"`
PushNonce string `json:"push_nonce,omitempty"`
PushSince time.Time `json:"push_since,omitzero"`
ProofSent time.Time `json:"proof_sent,omitzero"`
// HarnessSeen is what the harness check last read (HarnessRunning,
// HarnessNotSeen, or empty: cannot tell). Advisory: it
// never makes the friend down (alive.go, HarnessWatch).
HarnessSeen string `json:"harness_seen,omitempty"`
// HarnessAlive is the rule the harness check read it by: RuleSession (the
// session's last turn) or RuleApp (the app in the process table); empty
// for another signal, or before a check.
HarnessAlive string `json:"alive,omitempty"`
StoreError string `json:"store_error,omitempty"`
Width int `json:"width"`
// Session is SessionOK, or SessionBroken once the provider refused BrokenAfter
// turns in a row the same way; empty for a passive harness.
Session string `json:"session,omitempty"`
SessionID string `json:"session_id,omitempty"`
SessionReason string `json:"session_reason,omitempty"`
// SessionLive is the conversation a mailbox harness delivers into (Daemon.Mailbox):
// the one that reads, as the daemon last followed it; empty for every other harness.
SessionLive string `json:"session_live,omitempty"`
// Queued is her harness's own queue of deliveries not yet taken, as the last delivery
// read it (codex: the open chat's queue), when QueueKnown.
Queued int `json:"queued,omitempty"`
QueueKnown bool `json:"queue_known,omitempty"`
BrokenAt time.Time `json:"broken_at,omitempty"`
// While the harness is at its usage limit or out of credits Session is
// SessionLimited, LimitKind says which (KindLimit or KindCredits) and
// LimitUntil is the reset (docs/SPEC-FRIEND.md, limits-mean-down-w-r.w1~15).
LimitKind string `json:"limit_kind,omitempty"`
LimitUntil time.Time `json:"limit_until,omitzero"`
// Mode is how the daemon delivers now (batch or one-shot), and Lanes the
// one-shot lanes as n:session:card/turn, empty in batch.
Mode string `json:"mode,omitempty"`
Lanes string `json:"lanes,omitempty"`
// Paced is the lanes' effective width under the subscription windows' pacing
// (pacing.go), nil before the lanes have stepped; Window is the windows' use
// as the harness last reported it ("5h 62% 7d 31%", empty when none is live),
// and Pacing the row's pacing as a percent.
Paced *int `json:"paced,omitempty"`
Window string `json:"window,omitempty"`
Pacing string `json:"pacing,omitempty"`
// Held, InboxJobs and Missing are the last inbox reconcile's counts (SyncInbox): the
// cards on her row, the sprint jobs in her inbox, and the held cards with no BRIEF.md
// after it; HeldKnown is false until the server has answered once, and InboxError is
// why the last reconcile did not finish, empty when it did.
HeldKnown bool `json:"held_known,omitempty"`
Held int `json:"held"`
InboxJobs int `json:"inbox"`
Missing int `json:"missing"`
InboxError string `json:"inbox_error,omitempty"`
// HeldFrom is where the last answer came from: friend cards, or the worker view while the
// server does not serve it (no brief is written from the view).
HeldFrom string `json:"held_from,omitempty"`
}
Status is what the daemon knows, as status reads it: one file, rewritten whole, so a reader never sees half a state.
type StopReturn ¶
type StopReturn struct {
Lane int `json:"lane"`
// ServerLane is the lane the server says holds the card (take --lane), named on the
// stop-return so another lane's card is refused; 0 when no lane holds it
ServerLane int `json:"server_lane,omitempty"`
Job string `json:"job"`
Row string `json:"row"` // the owner row the return is sent as: friend.<name>, or the reader row
Card string `json:"card"` // the card id
Gen int `json:"gen"`
Epoch string `json:"epoch"`
Pid int `json:"pid,omitempty"` // the process signalled, when the harness said it (0: its group, by the lane's context)
Exit int `json:"exit"` // how the run ended; -1 while it has not
Ended bool `json:"ended"` // the run has ended: the return may be sent
At time.Time `json:"at"` // when the stop cancelled it
Tries int `json:"tries,omitempty"` // stop-returns sent and refused
Result string `json:"result,omitempty"`
// NextTry is when a refused stop-return is sent again (StopReturnRetry), and Refusal
// the refusal last said for it, said once while its text stands.
NextTry time.Time `json:"next_try,omitzero"`
Refusal string `json:"refusal,omitempty"`
}
StopReturn is one card the machine's stop took out of a lane: the evidence (the lane, the job, the card at its generation, the epoch, the process's end) and the stop-return owed for it, Result "" while it is owed and the server's answer once it took it.
func (StopReturn) Owed ¶
func (s StopReturn) Owed() bool
Owed says the stop-return has not been taken by the server.
type Stub ¶
type Stub struct{ Harness, Reason string }
Stub is a harness with no deliver command yet: it refuses every delivery with the way a session of that harness still reads the bus, so the tool is honest. It is Passive: the daemon takes nothing off the stream for it (the session's own blocking read does), only peeks, so a ping is still answered by the daemon at once and the beat is real.
type Task ¶
type Task struct {
Gen int `json:"gen,omitempty"` // assignment generation; absent means 1 (docs/FRIENDS.md)
Job string `json:"job,omitempty"` // delivered inbox directory, when recorded
ID string `json:"id"`
State string `json:"state"` // queued, working, done
Deliverable string `json:"deliverable,omitempty"`
}
Task is one record of the queue file.
type Tmux ¶
type Tmux struct {
Dir string // the friend's directory, the working directory of each tmux call
Session string // the tmux session, friend-<name>
Prompt *regexp.Regexp // the idle prompt, matched against the last non-empty line
Run Exec
Out io.Writer
Now func() time.Time // time.Now when nil
Sleep func(ctx context.Context, d time.Duration) // a real wait when nil
}
Tmux delivers into a TUI hosted in a tmux pane. Deliver captures the pane (`tmux capture-pane -p -t <session>`); when its last non-empty line matches the idle prompt it types the text literally (`send-keys -l`), then Enter as a second call, and is accepted once the prompt line has gone, the turn having started. While the prompt is absent a turn runs: Deferred, so no second turn lands beside one. A missing session is Deferred with the host line, never a failure.
func (*Tmux) Alive ¶
Alive: the hosted tmux session exists (`tmux has-session`); the TUI inside it may still be at any state, which the session check alone answers.
type TokenCapped ¶
type TokenCapped struct {
Cap int64
At Tokens // the card's usage when the lane stopped it
Card string
Wrote bool // the lane wrote the card's REPORT.md (false: hers stood, or none could be written)
}
TokenCapped is a card's turn the lane stopped at its token cap.
func (TokenCapped) Error ¶
func (e TokenCapped) Error() string
type Tokens ¶
type Tokens struct {
Input, CacheRead, CacheWrite, Output, Reasoning int64
}
Tokens is a card's tokens as the harness's own usage record counts them.
func SessionTokens ¶
SessionTokens is a session's tokens from its export: its assistant messages' tokens summed. An export with no message carrying them answers errNoTokenShape, and the cap is not applied; its price (SessionCost) stands as it is.
type TurnRecord ¶
TurnRecord is a headless adapter's own record of its turns: one that delivers by running a one-shot program into the session (dsh headless, gemini --resume), each turn a process that starts and ends. A turn runs while one has begun and not ended, since the latest's start.
type Usage ¶
type Usage struct {
FiveHour, SevenDay float64
FiveHourResets, SevenDayResets time.Time
At time.Time
}
Usage is a harness's measured utilization of its five-hour and weekly windows, each a fraction (1 is the window spent), with when each resets and when it was measured (zero: never).
type UsageLimited ¶
UsageLimited is a lane's answer when the harness account itself is at its usage limit (a Claude Code rate_limit_event rejected, adapter_claude.go): unlike a rate limit it names its reset, so the lanes stop taking until Until (LaneGovernor.PauseUntil) and no cap is lowered; the card stays in the lane's hand, counted toward nothing.
func (UsageLimited) Error ¶
func (u UsageLimited) Error() string
type Verdict ¶
type Verdict struct {
Status string `json:"status"` // up or down
Reason string `json:"reason"`
Evidence []string `json:"evidence"`
}
Verdict is a friend's status, the one reason that decided it, and every piece of evidence as a person reads it.
func FriendStatus ¶
FriendStatus decides a friend's status from evidence, in order: at a limit is down until the reset; no session answer within bound is down; a bus that cannot deliver to her is down; otherwise up. The harness's process is shown and decides nothing (the finding of 2026-10-05). Times are shown in loc.
type VerdictFacts ¶
type VerdictFacts struct {
Friend string `json:"friend"`
Verdict string `json:"verdict"` // ok, broken, deaf, silent, down, untrue
Shown string `json:"shown"` // state/working (e.g. "up/8") or "-"
Why string `json:"why"`
}
VerdictFacts carries the health check verdict and explanation.
func DecideVerdict ¶
func DecideVerdict(df DaemonFacts, hf HarnessFacts, bf BusFacts, wf WorkFacts, shown *ShownEntry, window time.Duration) VerdictFacts
DecideVerdict is the pure function deciding a friend verdict from facts; every count and age is of the window (docs/SPEC-FRIEND.md "Check": the verdicts). The facts decide first, in this order:
- broken when the session is marked broken, or deliveries in the window are all failures (delivered > 0 and failed == delivered)
- deaf when a delivery in the window succeeded and neither a session pong nor a real message came back in the window
- silent when no delivery was due in the window and nothing came back
- down by presence
- else ok
Then --shown: when it says up or working and the facts verdict is not ok, the verdict stays the facts' and the why leads with "untrue:", the claim and the facts' reason; when the facts verdict is ok but the friend is asleep or its agent is not loaded, the verdict is untrue.
func (VerdictFacts) Line ¶
func (vf VerdictFacts) Line() string
Line renders the CHECK VERDICT line.
type WakeRow ¶
type WakeRow struct{ Name, Status string }
WakeRow is one row of the friends table as the sprint server's coordinator view gives it: the friend's name and her status (up, down or held).
type Wall ¶
type Wall struct {
Profile string // the row's profile; "" is sandbox.ProfileFriend
Self []string // the program that runs the wall verb, and its arguments before the verb: this nova-friend
Dir string // the friend's working directory
ConfigDir string // her CLAUDE_CONFIG_DIR; "" none
Jobs []string // her job directories outside Dir
Reads []string // what her harness reads beyond the system roots and its own directory
Deny []string // the coordinator's self, never written inside the wall (sandbox.LaneProfile.Deny)
}
Wall is the wall every child of a lane runs inside: the wall profile its friend row names (sandbox.LaneProfile), over the friend's directories.
func (Wall) Args ¶
Args is the wall verb and its flags, up to and with the "--" the command follows.
func (Wall) Exec ¶
Exec is run with every lane's child inside the wall: a command whose context is a lane's (LaneContext) runs as `<Self> wall <flags> -- <name> <args>`, in the same directory and with the same stdin; any other runs as it was. With no Self the lane's command is refused, never run unwalled.
type Watch ¶
Watch is the cursor of the coordinator's watch (docs/SPEC-FRIEND.md, Watch): the last stream entry id it has seen and the wake file's offset it has read to, so the next run misses nothing and takes no flag.
type WindowRefused ¶
type WindowRefused struct{ Remedy string }
WindowRefused is the window step's answer when the accessibility permission is absent (docs/SPEC-FRIEND.md, Reach). Remedy is what a person grants.
func (WindowRefused) Error ¶
func (w WindowRefused) Error() string
type WindowUse ¶
type WindowUse struct {
Window string `json:"window"`
Used float64 `json:"used"`
Status string `json:"status,omitempty"`
Resets time.Time `json:"resets,omitzero"`
At time.Time `json:"at,omitzero"`
}
WindowUse is one subscription window as the harness last reported it: its name, the fraction used (0 when the report named none: under the harness's warning threshold), the harness's status (allowed, allowed_warning, rejected), when it resets (zero: not said) and when it was read.
func ReadRateLimitEvents ¶
ReadRateLimitEvents is the windows a headless run's stream-json output reported in its rate_limit_event lines (rateLimitEvent, limit.go: the unifiedWindows of each window, or the older shape's one window), the last word of each window, in the order the windows were first named, each read at at. A rejected event marks rejected the windows it spent (at 1), or every window it names when none is at 1. A line that is not such an event is skipped.
Source Files
¶
- activity.go
- adapter.go
- adapter_antigravity.go
- adapter_claude.go
- adapter_claude_folder.go
- adapter_claude_lanes.go
- adapter_codex.go
- adapter_dsh.go
- adapter_folder.go
- adapter_gemini.go
- adapter_grok.go
- adapter_opencode_lanes.go
- adapter_refused.go
- adapter_tmux.go
- alive.go
- antigravity_ledger.go
- check.go
- claude_async_hook.go
- codex_appserver.go
- codex_session.go
- conformance.go
- daemon.go
- deliver.go
- epoch.go
- group_unix.go
- inbox.go
- keepalive.go
- lane_cap.go
- lane_end.go
- lane_parity.go
- lane_take.go
- lanes.go
- launchd.go
- limit.go
- limits.go
- lock_unix.go
- machine.go
- notifications.go
- one_lane.go
- outbox.go
- pacing.go
- presence.go
- present.go
- pushproof.go
- pushproof_start.go
- ratelimit.go
- read_lanes.go
- renew.go
- rework.go
- settings.go
- settings_claude.go
- settings_codex.go
- settings_dsh.go
- settings_grok.go
- settings_opencode.go
- stage.go
- state.go
- status.go
- stop.go
- tokencap.go
- wakeping.go
- window.go
- window_other.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package friendtest holds the test doubles of pkg/friend that tests in other packages share.
|
Package friendtest holds the test doubles of pkg/friend that tests in other packages share. |