Documentation
¶
Index ¶
- Constants
- func AgentPrompt(in PromptInput) string
- func AppendLog(sessionDir, stream, text, trigger string, sinkIndex int, now time.Time) error
- func AutoSinkWhy(v *StatusView) string
- func BoolPtr(v bool) *bool
- func CheckedCursor(m *Manifest) string
- func EffectiveAgentRunner(mode Mode, runner string) (effective, mappedFrom string, err error)
- func FilterMessagesAfter(msgs []sessions.ChatMessage, after time.Time) []sessions.ChatMessage
- func FormatMRTitle(source, commitMsg string) string
- func FormatTime(t time.Time) string
- func HasSinkHistory(m *Manifest) bool
- func HubGitUser(opts Opts, hubDir string) (string, error)
- func IsAutoSinkable(v *StatusView) bool
- func IsStaleRunning(m *Manifest, now time.Time) bool
- func LogsPath(sessionDir string) string
- func MRTitlePrefix(source string) string
- func ManifestPath(sessionDir string) string
- func NewestMessageTime(msgs []sessions.ChatMessage) time.Time
- func ParseTime(s string) (time.Time, error)
- func ReconcileStaleRunning(sessionDir string, m *Manifest, now time.Time) (bool, error)
- func Root(stateDir string) string
- func RunDir(sessionDir string, index int) string
- func SanitizeSessionID(id string) string
- func SessionDir(stateDir, marcusSessionID string) string
- func ShowPromptText(in PromptInput) string
- func SingleLineMRTitle(msg string) string
- func StartPingLoop(ctx context.Context, sessionDir string, pid int, nowFn func() time.Time)
- func SunkCursor(m *Manifest) string
- func TipAfterMax(tip, lastSinkMax time.Time) bool
- func TouchPing(sessionDir string, pid int, now time.Time) error
- func UserFromEmail(email string) string
- func WithinAutoSinkWindow(updatedAt, now time.Time, window time.Duration) bool
- func WriteManifest(sessionDir string, m *Manifest) error
- type AgentFunc
- type AutoSinkableRow
- type GitRunner
- type LogLine
- type Manifest
- type MessagesFunc
- type Mode
- type Opts
- type PriorSinkContext
- type PromptInput
- type ResolveGrokFunc
- type ResolveRunnerFunc
- type ResolveSessionDirFunc
- type RunResult
- type SessionMeta
- type ShipCommitFiles
- type ShipGitResult
- type ShipResult
- type SinkedRow
- type StatusResult
- type StatusView
Constants ¶
const ( AutoSinkWindow = 7 * 24 * time.Hour AutoSinkGrace = 10 * time.Minute AutoSinkInterval = time.Hour )
Auto-sink window and timing (daemon scheduler; CLI list uses the same window).
const ( SkipReasonInconclusive = "inconclusive" // no clear conclusion yet — advance checked only SkipReasonNoNew = "no_new" // nothing new vs hub — advance checked only )
Skip reasons when has_new_knowledges is false.
const ( SourceAuto = "auto" SourceUI = "ui" SourceSlash = "slash" )
Marcus sink trigger sources (CLI --source / daemon POST source).
const ( StateReady = "ready" StateSunk = "sunk" StateBehind = "behind" StateRunning = "running" StateFailed = "failed" )
Button / status states for callers (Marcus UI, CLI).
const ( PingInterval = 4 * time.Second StaleAfter = time.Minute )
Heartbeat while status=running. ~4s interval ⇒ 1m ≈ 14 missed pings.
const LogsFileName = "logs.jsonl"
LogsFileName is the unified session debug transcript (append-only JSONL).
const ResultSchemaExample = `` /* 278-byte string literal not displayed */
ResultSchemaExample is the JSON object shape for headless propose-only RunJSON.
const ShipResultExample = `` /* 250-byte string literal not displayed */
ShipResultExample is the example object for the prompt Output section (new knowledges).
const ShipResultSkipExample = `` /* 135-byte string literal not displayed */
ShipResultSkipExample is the skip contract (no hub writes).
const TimeLayout = "2006-01-02 15:04:05 -0700 MST"
TimeLayout is human-readable local time with numeric offset + zone name.
Variables ¶
This section is empty.
Functions ¶
func AgentPrompt ¶
func AgentPrompt(in PromptInput) string
func AppendLog ¶ added in v0.0.162
AppendLog appends one JSONL record. Best-effort; errors are ignored by callers that also tee to a live UI log.
func AutoSinkWhy ¶ added in v0.0.162
func AutoSinkWhy(v *StatusView) string
AutoSinkWhy is a short reason column for --show-auto-sinkable-sessions.
func BoolPtr ¶ added in v0.0.163
BoolPtr returns a *bool for ShipResult literals in tests and helpers.
func CheckedCursor ¶ added in v0.0.165
CheckedCursor is the sinkability watermark. Falls back to sunk for old manifests.
func EffectiveAgentRunner ¶
EffectiveAgentRunner maps shared/prefs runner IDs to the launch family for mode.
Headless uses CLI runners (codex/grok); --open uses TTY (*-tty). Returns mappedFrom when an alias was applied (for notices).
func FilterMessagesAfter ¶
func FilterMessagesAfter(msgs []sessions.ChatMessage, after time.Time) []sessions.ChatMessage
func FormatMRTitle ¶ added in v0.0.162
FormatMRTitle builds merge_request.title: optional source prefix + agent line.
func FormatTime ¶
func HasSinkHistory ¶ added in v0.0.162
HasSinkHistory reports whether a manifest records a completed sink.
func HubGitUser ¶
HubGitUser returns stripped username from git config user.email in hub.
func IsAutoSinkable ¶ added in v0.0.162
func IsAutoSinkable(v *StatusView) bool
IsAutoSinkable reports whether StatusView is eligible for an automatic sink. Enabled covers ready / behind / failed-with-work; sunk / running / unavailable are not.
func IsStaleRunning ¶ added in v0.0.162
IsStaleRunning reports whether a running manifest's last_ping is older than StaleAfter. Empty last_ping while running is treated as stale only after callers have had a chance to write the first ping — if LastPing is empty, use Started-equivalent: treat as stale when we cannot prove a recent ping (conservative: stale).
func MRTitlePrefix ¶ added in v0.0.162
MRTitlePrefix returns the Marcus trigger tag(s) for an MR title, or "" when source is empty/unknown (bare CLI).
func ManifestPath ¶
func NewestMessageTime ¶
func NewestMessageTime(msgs []sessions.ChatMessage) time.Time
func ReconcileStaleRunning ¶ added in v0.0.162
ReconcileStaleRunning rewrites a stale running manifest to failed. Returns true if rewritten.
func SanitizeSessionID ¶
func SessionDir ¶
func ShowPromptText ¶
func ShowPromptText(in PromptInput) string
ShowPromptText is the reviewable prompt (no disk writes).
func SingleLineMRTitle ¶
SingleLineMRTitle flattens a commit message for merge_request.title push option.
func StartPingLoop ¶ added in v0.0.162
StartPingLoop refreshes last_ping every PingInterval until ctx is cancelled.
func SunkCursor ¶ added in v0.0.165
SunkCursor is the content watermark (prompt since). Empty if never shipped.
func TipAfterMax ¶
TipAfterMax reports whether tip is strictly after lastMax (new messages). Unknown tip (zero) cannot claim "after cursor": if a cursor exists, treat as not-after so skip+checked-advance stays non-sinkable when Status cannot load tip. Zero tip and zero cursor returns true only as a degenerate case; BuildStatus uses neverSunk before TipAfterMax when both are empty.
func TouchPing ¶ added in v0.0.162
TouchPing updates last_ping (and pid if > 0) while status is still running.
func UserFromEmail ¶
UserFromEmail strips the domain from an email (devuser@example.com → devuser).
func WithinAutoSinkWindow ¶ added in v0.0.162
WithinAutoSinkWindow reports whether updatedAt is non-zero and within window of now.
func WriteManifest ¶
Types ¶
type AgentFunc ¶
type AgentFunc func(ctx context.Context, opts agentrunapi.RunOpts, jsonSchema string) (jsonResult string, err error)
AgentFunc injects the propose agent (nil → agentrunapi.Run / RunJSON).
type AutoSinkableRow ¶ added in v0.0.162
type AutoSinkableRow struct {
SessionID string `json:"session_id"`
UpdatedAt time.Time `json:"updated_at"`
State string `json:"state"`
Why string `json:"why,omitempty"`
}
AutoSinkableRow is one session the hourly auto-sink would consider.
func FilterAndSortAutoSinkable ¶ added in v0.0.162
func FilterAndSortAutoSinkable( sessions []SessionMeta, now time.Time, window time.Duration, statusFor func(id string) (*StatusView, error), ) ([]AutoSinkableRow, error)
FilterAndSortAutoSinkable returns sinkable sessions within the window, oldest UpdatedAt first. statusFor is called only for non-archived sessions inside the window; nil views or errors skip the row.
func PickOldestAutoSinkable ¶ added in v0.0.162
func PickOldestAutoSinkable( sessions []SessionMeta, now time.Time, window time.Duration, statusFor func(id string) (*StatusView, error), ) (*AutoSinkableRow, error)
PickOldestAutoSinkable returns the first row from FilterAndSortAutoSinkable, or nil when none.
type LogLine ¶ added in v0.0.162
type LogLine struct {
TS string `json:"ts"`
Stream string `json:"stream"` // stdout | stderr
Text string `json:"text"`
SinkIndex *int `json:"sink_index,omitempty"`
Trigger string `json:"trigger,omitempty"` // ui | auto | cli
}
LogLine is one JSON object per line in logs.jsonl.
type Manifest ¶
type Manifest struct {
Version int `json:"version"`
MarcusSessionID string `json:"marcus_session_id"`
GrokSessionID string `json:"grok_session_id,omitempty"`
LastSinkAt string `json:"last_sink_at,omitempty"`
LastSinkMaxMessageTimestamp string `json:"last_sink_max_message_timestamp,omitempty"` // sunk / since
LastCheckedMaxMessageTimestamp string `json:"last_checked_max_message_timestamp,omitempty"` // sinkability
NextSinkIndex int `json:"next_sink_index"`
LastSinkIndex int `json:"last_sink_index"`
Status string `json:"status"`
Error string `json:"error,omitempty"`
Pid int `json:"pid,omitempty"` // info only; not used for liveness
LastPing string `json:"last_ping,omitempty"` // TimeLayout; heartbeat while running
LastPaths []string `json:"last_paths,omitempty"`
LastHubPaths []string `json:"last_hub_paths,omitempty"`
LastBranch string `json:"last_branch,omitempty"`
LastMRURL string `json:"last_mr_url,omitempty"`
LastCommit string `json:"last_commit,omitempty"`
}
Manifest is session-level cursor/status under knowledge-sink/<id>/manifest.json. status (+ last_ping) is the single source of truth for UI and all callers.
Two tip watermarks:
- LastSinkMaxMessageTimestamp (sunk): last tip through which content was shipped; injected as prompt since on the next Run.
- LastCheckedMaxMessageTimestamp (checked): last tip Status/auto-pick already considered; skips advance this without moving sunk.
Empty checked migrates to sunk for older manifests.
func LatchRunning ¶ added in v0.0.162
LatchRunning sets status=running, refreshes last_ping, optional pid (0 = leave / clear).
func LoadManifest ¶
type MessagesFunc ¶
type MessagesFunc func(grokHome, sessionID string, opts *sessions.MessagesOpts) (*sessions.MessagesResult, error)
MessagesFunc injects sessions.Messages for tests (nil → library). Grok tip only.
type Opts ¶
type Opts struct {
StateDir string // required: root that contains knowledge-sink/
HubDir string // knowledge-base-hub checkout (required to run agent); caller sets cwd
SessionID string // Marcus / agent-run session id
GrokSessionID string // optional direct runner session id (skips resolve when set)
Mode Mode // empty → headless
DryRun bool
ShowPrompt bool
// CreateMR: agent applies hub writes + result.json; host commits/pushes/creates MR.
CreateMR bool
// AutoMergeMR implies CreateMR; after MR push, ff-merge and push origin/master.
AutoMergeMR bool
// AllowRunning skips the "already sinking" guard. Daemon uses this after it
// latches manifest status=running for UI before the worker goroutine starts.
AllowRunning bool
// Source tags the Marcus trigger for MR title prefixes (auto|ui|slash).
// Empty → no prefix (bare CLI).
Source string
// SkipSessionDirProbe skips Codex/Grok session-file walks when computing
// Status. For list/auto-pick, a resolved runner session id counts as
// having content (Codex Find was ~0.3–1s per session via full tree scan).
SkipSessionDirProbe bool
// AgentRunner / Model / ModelReasoningEffort are passed to agentrunapi.RunOpts.
// Empty AgentRunner → library default (grok-tty); callers that want Marcus/
// shared prefs should resolve before Run.
AgentRunner string
Model string
ModelReasoningEffort string
// Verbose prints concrete agent-run / Codex argv and post-agent ship
// progress (git commit/push/MR) on Stderr.
Verbose bool
// Stderr receives verbose notices (nil → os.Stderr when Verbose).
Stderr io.Writer
Driver agentdriver.Driver
StoreHome string // agent-run job store; empty → StateDir/knowledge-sink-jobs/<id>
MessagesFn MessagesFunc
AgentFn AgentFunc
ResolveFn ResolveRunnerFunc
ResolveSessionDirFn ResolveSessionDirFunc
GitFn GitRunner
NowFn func() time.Time
}
Opts drives Status and Run.
type PriorSinkContext ¶
type PriorSinkContext struct {
LastSinkAt string
LastCursor string
PriorRunDirs []string // absolute sink-N dirs
LastHubPaths []string
LastPaths []string // relative under session sink dir
HasPrior bool
}
PriorSinkContext is previous sink bookkeeping for dedup / incremental prompts.
type PromptInput ¶
type PromptInput struct {
MarcusSessionID string
Runner string // grok-tty | codex-tty | …
RunnerSessionID string
RunnerSessionDir string // absolute primary source
Since string // sunk cursor (last_sink_max_message_timestamp), optional
SinkIndex int
ProposalPath string // absolute path for proposal.md
Prior PriorSinkContext
// CreateMR mode: agent applies hub writes and emits result.json for host git.
CreateMR bool
ResultJSONPath string // absolute sink-N/result.json
GitUser string // email local-part for branch prefix
BranchDate string // YYYY-MM-DD
}
PromptInput fills AgentPrompt / ShowPromptText.
type ResolveGrokFunc ¶
type ResolveGrokFunc = ResolveRunnerFunc
ResolveGrokFunc is kept as an alias name for older call sites.
type ResolveRunnerFunc ¶
ResolveRunnerFunc resolves Marcus/agent-run session → (runner, runnerSessionID).
type ResolveSessionDirFunc ¶
ResolveSessionDirFunc resolves runner session → absolute session dir (nil → grok/codex libs).
type RunResult ¶
type RunResult struct {
OK bool `json:"ok"`
DryRun bool `json:"dry_run,omitempty"`
ShowPrompt bool `json:"show_prompt,omitempty"`
CreateMR bool `json:"create_mr,omitempty"`
AutoMergeMR bool `json:"auto_merge_mr,omitempty"`
Mode string `json:"mode,omitempty"`
SessionID string `json:"session_id,omitempty"`
GrokSessionID string `json:"grok_session_id,omitempty"`
Runner string `json:"runner,omitempty"`
RunnerSessionDir string `json:"runner_session_dir,omitempty"`
SinkIndex int `json:"sink_index,omitempty"`
DeltaCount int `json:"delta_count,omitempty"`
ProposalPath string `json:"proposal_path,omitempty"`
ResultJSONPath string `json:"result_json_path,omitempty"`
SessionDir string `json:"session_dir,omitempty"` // knowledge-sink/<id>
HubDir string `json:"hub_dir,omitempty"`
Prompt string `json:"prompt,omitempty"`
HubPaths []string `json:"hub_paths,omitempty"` // proposed / committed hub paths
Branch string `json:"branch,omitempty"`
Commit string `json:"commit,omitempty"`
MRURL string `json:"mr_url,omitempty"`
Merged bool `json:"merged,omitempty"`
MergedAt string `json:"merged_at,omitempty"`
Warning string `json:"warning,omitempty"`
LastSinkAt string `json:"last_sink_at,omitempty"`
CursorTimestamp string `json:"cursor_timestamp,omitempty"`
CursorAdvanced bool `json:"cursor_advanced,omitempty"`
HasNewKnowledges *bool `json:"has_new_knowledges,omitempty"`
SkipReason string `json:"skip_reason,omitempty"`
Error string `json:"error,omitempty"`
}
RunResult is Run output (including dry-run / show-prompt).
type SessionMeta ¶ added in v0.0.162
SessionMeta is one Marcus/local-bot session for auto-sink selection.
type ShipCommitFiles ¶
type ShipCommitFiles struct {
Add []string `json:"add,omitempty"`
Update []string `json:"update,omitempty"`
Delete []string `json:"delete,omitempty"`
}
ShipCommitFiles is the agent-written hub path set for --create-mr shipping. add/update paths must exist on disk; delete paths must be absent and still tracked in git. Empty buckets may be omitted; at least one path overall when has_new_knowledges is true.
func (ShipCommitFiles) AllPaths ¶
func (f ShipCommitFiles) AllPaths() []string
AllPaths returns add ∪ update ∪ delete in that order (no dedupe across buckets).
func (*ShipCommitFiles) UnmarshalJSON ¶
func (f *ShipCommitFiles) UnmarshalJSON(data []byte) error
UnmarshalJSON rejects legacy flat string arrays with a clear contract error.
type ShipGitResult ¶
type ShipGitResult struct {
Branch string
Commit string
MRURL string
Merged bool
MergedAt string // short tip of origin/<target> after auto-merge
PushOption bool
Warning string
}
ShipGitResult is the outcome of host-side commit/push/(auto-merge).
func ShipToMR ¶
func ShipToMR(opts Opts, hubDir string, ship *ShipResult, autoMerge bool) (*ShipGitResult, error)
ShipToMR stashes agent edits, branches from origin/master, commits, pushes with merge_request push options, optionally ff-merges into origin/master.
type ShipResult ¶
type ShipResult struct {
// HasNewKnowledges is required. Pointer so missing JSON is distinct from false.
HasNewKnowledges *bool `json:"has_new_knowledges"`
SkipReason string `json:"skip_reason,omitempty"` // inconclusive|no_new when false
GitCommitMsg string `json:"git_commit_msg"`
GitBranchName string `json:"git_branch_name"`
GitCommitFiles ShipCommitFiles `json:"git_commit_files"`
}
ShipResult is the agent-written contract for --create-mr shipping.
func ReadValidateShipResult ¶
func ReadValidateShipResult(path, hubDir string) (*ShipResult, error)
ReadValidateShipResult loads and validates sink-N/result.json against hubDir.
func (*ShipResult) HasNew ¶ added in v0.0.163
func (sr *ShipResult) HasNew() bool
HasNew reports whether the agent marked new knowledges (false if nil/missing).
type SinkedRow ¶ added in v0.0.162
type SinkedRow struct {
SessionID string `json:"session_id"`
LastSinkAt time.Time `json:"last_sink_at"`
Status string `json:"status"` // idle|running|failed (manifest)
LastMRURL string `json:"last_mr_url,omitempty"`
}
SinkedRow is one session that has completed a sink (manifest last_sink_at set).
func ListSinkedSessions ¶ added in v0.0.162
ListSinkedSessions scans stateDir/knowledge-sink/*/manifest.json and returns sessions with last_sink_at set, newest last_sink_at first.
type StatusResult ¶
type StatusResult struct {
OK bool `json:"ok"`
SessionID string `json:"session_id,omitempty"`
GrokSessionID string `json:"grok_session_id,omitempty"` // runner session id (legacy json name)
Sink *StatusView `json:"sink,omitempty"`
SessionDir string `json:"session_dir,omitempty"` // knowledge-sink/<id>
LastSinkAt string `json:"last_sink_at,omitempty"`
LastPaths []string `json:"last_paths,omitempty"`
LastMRURL string `json:"last_mr_url,omitempty"`
Error string `json:"error,omitempty"`
}
StatusResult is Status output.
type StatusView ¶
type StatusView struct {
State string `json:"state"` // unavailable|ready|sunk|behind|running|failed
Label string `json:"label"`
Enabled bool `json:"enabled"`
Help string `json:"help,omitempty"`
Error string `json:"error,omitempty"`
NewCount int `json:"new_count,omitempty"`
}
StatusView is the sink button / status snapshot.