Documentation
¶
Overview ¶
Package state is beekeeper's shared memory on the machine: the supervisor and its relay, grants, holds, registered agents, notes, timers and session records, one JSON document read and rewritten under an exclusive file lock, plus an append-only event log of every change and of every build run. It outlives any session: a restarted supervisor or its successor reads what the previous one knew instead of rebuilding it from prose.
Index ¶
- Constants
- func Due(due, fired, now time.Time) bool
- type Agent
- type Budget
- type CLI
- type Event
- type Grant
- type Hold
- type Merge
- type Note
- type Party
- type Record
- type Relay
- type RelayDue
- type Relief
- type Report
- type ReportPause
- type Role
- type Start
- type State
- func (st *State) BypassStart(session string) (Start, bool)
- func (st *State) GuideRole() Role
- func (s State) MarshalJSON() ([]byte, error)
- func (st *State) SetGuideRole(r Role)
- func (st *State) SetSupervisorRole(r Role)
- func (st *State) SupervisorRole() Role
- func (s *State) UnmarshalJSON(raw []byte) error
- type Store
- func (s *Store) Dir() string
- func (s *Store) Events(n int, keep func(Event) bool) ([]Event, error)
- func (s *Store) Log(events ...Event) error
- func (s *Store) Peek() (*State, error)
- func (s *Store) Read() (*State, error)
- func (s *Store) ReadFile(name string, v any) (found bool, err error)
- func (s *Store) Update(fn func(*State) ([]Event, error)) error
- func (s *Store) WriteFile(name string, v any) error
- type Supervisor
- type Timer
Constants ¶
const ( Waiting = "waiting" Running = "running" Settling = "settling" )
The phases of a Merge.
const ModeBypass = "bypassPermissions"
ModeBypass is Claude Code's bypassPermissions mode.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Agent ¶
type Agent struct {
Party
Registered time.Time `json:"registered"`
Task string `json:"task,omitempty"`
AssignedAt time.Time `json:"assignedAt,omitzero"`
IdleSince time.Time `json:"idleSince,omitzero"`
LastTask string `json:"lastTask,omitempty"`
}
Agent is an empty session registered as spare capacity.
type Budget ¶ added in v0.6.0
type Budget struct {
Remaining int `json:"remaining"`
Limit int `json:"limit"`
Reset time.Time `json:"reset"`
At time.Time `json:"at"`
}
Budget is one reading of the GitHub core budget.
type CLI ¶ added in v0.14.1
type CLI struct {
Supervisor Party `json:"supervisor"`
Since time.Time `json:"since"`
PID int `json:"pid,omitempty"`
Gone time.Time `json:"gone,omitzero"`
}
CLI is what beekeeper saw of the supervisor's CLI process in the term Supervisor and Since name: the PID it ran as and since when it has been gone. A CLI back under the same session within supervisor.restartGrace of Gone is a restart; the grant rule holds whether it comes back or not.
func (*CLI) Of ¶ added in v0.14.1
func (c *CLI) Of(sup *Supervisor) bool
Of reports whether the record is about sup's current term.
type Event ¶
type Event struct {
At time.Time `json:"at"`
By Party `json:"by"`
Verb string `json:"verb"`
Detail string `json:"detail"`
}
Event is one line of events.jsonl. At is written in UTC (RFC 3339 with a trailing Z), so a reader can compare it as a string.
type Grant ¶
type Grant struct {
Resource string `json:"resource"`
To Party `json:"to"`
By Party `json:"by"`
At time.Time `json:"at"`
// UpgradeUnblock is why the supervisor granted a claim that the
// resource's upgrade hold admits: the work that unblocks the upgrade.
UpgradeUnblock string `json:"upgradeUnblock,omitempty"`
}
Grant is the supervisor's word that a session may claim a resource.
type Hold ¶
type Hold struct {
Target string `json:"target"`
Reason string `json:"reason"`
By Party `json:"by"`
At time.Time `json:"at"`
Until time.Time `json:"until,omitzero"`
// Except is what a merge hold lets through: a repository (the tool's own
// during a tool-release window) or one pull request, owner/repo#n.
Except string `json:"except,omitempty"`
// Tool is the binary whose release window this hold is, ToolFrom the
// version it reported when the window opened, ToolPR the pull request
// that opened it, ToolMerged whether it merged and ToolRelease the release
// it produced. The window closes once the tool reports another version
// than ToolFrom and no merge of its repository runs, or once its merge
// ended with nothing merged.
Tool string `json:"tool,omitempty"`
ToolFrom string `json:"toolFrom,omitempty"`
ToolPR int `json:"toolPR,omitempty"`
ToolMerged bool `json:"toolMerged,omitempty"`
ToolRelease string `json:"toolRelease,omitempty"`
// UpgradeTo is the target release of the upgrade an automatic upgrade
// hold stands for.
UpgradeTo string `json:"upgradeTo,omitempty"`
// LiftedBy and LiftedAt record the lift of an upgrade hold: the watch
// keeps a lifted hold, inactive, for as long as its upgrade runs.
LiftedBy *Party `json:"liftedBy,omitempty"`
LiftedAt time.Time `json:"liftedAt,omitzero"`
}
Hold stops work on a target (a repository's merges, "github" for every GitHub call) until it is lifted or Until passes.
type Merge ¶ added in v0.6.0
type Merge struct {
Repo string `json:"repo"`
PR int `json:"pr"`
Lane string `json:"lane"`
By Party `json:"by"`
PID int `json:"pid"`
// Child is a running merge's devctl, in a session of its own: it merges
// on when the gate's caller, or the gate, is gone.
Child int `json:"child,omitempty"`
Phase string `json:"phase"`
// Joined orders the queue; a rerun within the queue TTL keeps it.
Joined time.Time `json:"joined"`
Seen time.Time `json:"seen"`
Started time.Time `json:"started,omitzero"`
// Finished and Exit are when and how the merge's run ended; on a
// waiting merge, the failed attempt whose place it keeps (Retrying).
Finished time.Time `json:"finished,omitzero"`
Exit int `json:"exit,omitempty"`
// Seeded marks a place queued on a session's behalf (lanes queue): it
// survives refusals and keeps the seed TTL until the merge runs.
Seeded bool `json:"seeded,omitempty"`
// Outside marks a merge run outside the gate (lanes settle): waiting, it
// heads its lane until its own devctl pr merge runs or GitHub reports it
// merged; merged, it settles its lane like a gated merge.
Outside bool `json:"outside,omitempty"`
// Checked is when GitHub last reported an outside merge not merged yet.
Checked time.Time `json:"checked,omitzero"`
// Release is the tag the merge released, empty when unknown.
Release string `json:"release,omitempty"`
// Roll names the HelmReleases (namespace/name) that must reach Release
// before the lane frees.
Roll []string `json:"roll,omitempty"`
}
Merge is one devctl pr merge the gate holds in its lane's queue.
type Note ¶
type Note struct {
ID int `json:"id"`
For string `json:"for,omitempty"`
Text string `json:"text"`
Due time.Time `json:"due,omitzero"`
// Default is what happens when nobody answers by Due.
Default string `json:"default,omitempty"`
By Party `json:"by"`
At time.Time `json:"at"`
// Fired is when a watch reported the note due; it reports it once.
Fired time.Time `json:"fired,omitzero"`
}
Note is an open item: a question for a person, a deadline.
type Party ¶
type Party struct {
// Session is the Claude Code session id (CLAUDE_CODE_SESSION_ID).
Session string `json:"session,omitempty"`
// HostSession is the desktop app's id for it (local_…); it survives a
// CLI restart that changes Session.
HostSession string `json:"hostSession,omitempty"`
Name string `json:"name"`
}
Party names a session (or a person) in the state.
type Record ¶ added in v0.9.0
type Record struct {
Session Party `json:"session"`
Issue string `json:"issue"`
Waits string `json:"waits,omitempty"`
By Party `json:"by"`
At time.Time `json:"at"`
// Ended is when a watch saw the session's CLI gone; it reports it once.
Ended time.Time `json:"ended,omitzero"`
}
Record is what a session serves: the issue or epic (owner/repo#n) and what it waits on. Any session can have one, registered agent or not.
type Relay ¶ added in v0.10.0
type Relay struct {
From Party `json:"from"`
To Party `json:"to"`
At time.Time `json:"at"`
Expires time.Time `json:"expires"`
// Taken is when the successor took the role; the record stays so the
// outgoing supervisor learns it has been relieved.
Taken time.Time `json:"taken,omitzero"`
// Reported is when a watch said the relay was taken or expired; it says
// it once.
Reported time.Time `json:"reported,omitzero"`
}
Relay is the supervisor naming its successor: the successor's `supervisor start` takes the role and the grants until Expires; the outgoing supervisor keeps both meanwhile.
type RelayDue ¶ added in v0.16.0
type RelayDue struct {
Supervisor Party `json:"supervisor"`
Since time.Time `json:"since"`
Reported time.Time `json:"reported"`
// Context is the supervisor's context in tokens when it was reported.
Context int64 `json:"contextTokens"`
}
RelayDue is the watch's memory that it reported the relay due to the supervisor's term Supervisor and Since, once: a relay cancelled or expired removes it, so the next quiet moment reports it again.
func (*RelayDue) Of ¶ added in v0.16.0
func (r *RelayDue) Of(sup *Supervisor) bool
Of reports whether the record is about sup's current term.
type Relief ¶ added in v0.14.1
type Relief struct {
Party Party `json:"party"`
// By is the successor whose start took the relay, At when the relay
// was opened and Taken when it was taken.
By Party `json:"by"`
At time.Time `json:"at"`
Taken time.Time `json:"taken"`
}
Relief records a supervisor a relay relieved, so that its `supervisor status` keeps saying so after the successor relays onward, cancels a relay or is relieved in turn.
type Report ¶ added in v0.26.0
type Report struct {
Party
// Unit is the transient user unit its turn runs in.
Unit string `json:"unit"`
// Slot is the start of the interval it reports on.
Slot time.Time `json:"slot"`
Started time.Time `json:"started"`
// Ended is when beekeeper took it off the roster; zero while it runs.
Ended time.Time `json:"ended,omitzero"`
// Outcome is posted, timeout or failed: <why>; empty while it runs.
Outcome string `json:"outcome,omitempty"`
// Skipped is the latest slot skipped while it ran.
Skipped time.Time `json:"skipped,omitzero"`
}
Report is one run of the scheduled status reporter: the session the standby watch started for an interval's slot, until it posted, timed out or failed to start.
type ReportPause ¶ added in v0.28.0
type ReportPause struct {
Final time.Time `json:"final,omitzero"`
Since time.Time `json:"since,omitzero"`
By Party `json:"by"`
}
ReportPause pauses the scheduled reporter until it is resumed: from Since, or, while Final is set, from the start of one final report due then.
func (*ReportPause) FinalDue ¶ added in v0.28.0
func (p *ReportPause) FinalDue(now time.Time) bool
FinalDue reports whether the final report is due at now.
func (*ReportPause) Paused ¶ added in v0.28.0
func (p *ReportPause) Paused() bool
Paused reports whether no scheduled report starts.
type Role ¶ added in v0.20.0
type Role struct {
Holder *Supervisor `json:"holder,omitempty"`
Relay *Relay `json:"relay,omitempty"`
Relieved []Relief `json:"relieved,omitempty"`
CLI *CLI `json:"cli,omitempty"`
RelayDue *RelayDue `json:"relayDue,omitempty"`
// Fed are the keys of what the guide's feed reported: the open notes
// for a person and the sessions waiting on one, each said once.
Fed []string `json:"fed,omitempty"`
// Run is the highest run of the role numbered: "<Role> run <Run>".
Run int `json:"run,omitempty"`
}
Role is a relayed role's record: its holder and term, its last relay, the holders relays relieved, what beekeeper saw of its CLI and the relay due the watch reported. The supervisor's lives in State's own fields (SupervisorRole), the guide's in Guide.
type Start ¶ added in v0.22.0
type Start struct {
Party
Mode string `json:"mode"`
Dir string `json:"dir"`
By Party `json:"by"`
At time.Time `json:"at"`
}
Start is a session `beekeeper agents start` started: the id beekeeper chose and the permission mode it passed, recorded before the session existed. A session cannot add itself: its id is only ever written here by the start that created it.
type State ¶
type State struct {
Supervisor *Supervisor `json:"supervisor,omitempty"`
// Relay is the supervisor's last relay: open, taken or expired.
Relay *Relay `json:"relay,omitempty"`
// Relieved are the supervisors relays relieved, one per party.
Relieved []Relief `json:"relieved,omitempty"`
// SupervisorCLI is what beekeeper saw of the supervisor's CLI.
SupervisorCLI *CLI `json:"supervisorCLI,omitempty"`
// SupervisorRun is the highest supervisor run numbered.
SupervisorRun int `json:"supervisorRun,omitempty"`
// RelayDue is the relay due the watch reported to the supervisor.
RelayDue *RelayDue `json:"relayDue,omitempty"`
// Guide is the guide's role, the supervisor's counterpart for the
// person's decisions.
Guide *Role `json:"guide,omitempty"`
// Grants are queued per resource in the order given.
Grants []Grant `json:"grants,omitempty"`
// Released is when each resource was last released; a grant's TTL runs
// from the later of it and the grant.
Released map[string]time.Time `json:"released,omitempty"`
Holds []Hold `json:"holds,omitempty"`
Agents []Agent `json:"agents,omitempty"`
Notes []Note `json:"notes,omitempty"`
NextNote int `json:"nextNote,omitempty"`
Timers []Timer `json:"timers,omitempty"`
NextTimer int `json:"nextTimer,omitempty"`
// Records say which session serves which issue.
Records []Record `json:"records,omitempty"`
// Starts are the sessions beekeeper started, what the permission hook
// answers for.
Starts []Start `json:"starts,omitempty"`
// BudgetETag makes the budget probe a conditional request (a 304
// costs no budget).
BudgetETag string `json:"budgetETag,omitempty"`
// Budget is the last reading of the GitHub core budget.
Budget *Budget `json:"budget,omitempty"`
// Merges are the wrapped devctl pr merge runs, per lane: waiting in join
// order, running, and settling until the lane's installation rolled them.
Merges []Merge `json:"merges,omitempty"`
// Report is the scheduled status reporter's current or last run.
Report *Report `json:"report,omitempty"`
// ReportPause pauses the scheduled reporter, after one final report.
ReportPause *ReportPause `json:"reportPause,omitempty"`
// contains filtered or unexported fields
}
State is the whole document.
func (*State) BypassStart ¶ added in v0.22.0
BypassStart returns the start of session when beekeeper started it in bypassPermissions.
func (State) MarshalJSON ¶ added in v0.9.0
MarshalJSON encodes the state with the fields it did not know.
func (*State) SetGuideRole ¶ added in v0.20.0
SetGuideRole stores the guide's record, none when it is empty.
func (*State) SetSupervisorRole ¶ added in v0.20.0
SetSupervisorRole stores the supervisor's record.
func (*State) SupervisorRole ¶ added in v0.20.0
SupervisorRole is the supervisor's record.
func (*State) UnmarshalJSON ¶ added in v0.9.0
UnmarshalJSON decodes the state and keeps the fields it does not know.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is the state directory.
func (*Store) Events ¶
Events returns the last n events keep accepts, oldest first (all when n <= 0, every event when keep is nil).
func (*Store) Log ¶ added in v0.11.0
Log appends events that change no state, a build's run for one, under the state lock. It waits at most logWait for the lock, so that a caller on every build's path never queues behind a slow update.
func (*Store) Peek ¶ added in v0.22.0
Peek returns the current state without taking the lock, for a caller that must never wait on it (a permission hook): a write replaces the file in one rename, so the document read is always a whole one.
func (*Store) ReadFile ¶
ReadFile decodes a JSON side file of the store (the last snapshot); found is false when it does not exist yet.
type Supervisor ¶
Supervisor is the session holding the watch.
type Timer ¶ added in v0.9.0
type Timer struct {
ID int `json:"id"`
Due time.Time `json:"due"`
What string `json:"what"`
By Party `json:"by"`
At time.Time `json:"at"`
// Fired is when a watch reported the timer; it reports it once.
Fired time.Time `json:"fired,omitzero"`
}
Timer is a point in time the supervisor has to look at something ("check the rollout after 22:55").