Documentation
¶
Overview ¶
Package job owns the on-disk representation of a monitored agent run.
Every run gets a directory under the codexmon home (default ~/.codexmon/jobs/<id>):
spec.json immutable launch spec (agent, args, cwd, thresholds) read by the worker status.json live status, rewritten by the monitor at least once per second events.jsonl raw agent event-stream lines (when JSON monitoring is on) output.log merged human-readable stdout/stderr log result.txt final agent message / review output cancel marker file; its presence asks the monitor to stop
status.json is the contract `codexmon status/wait/list/tail` reads, so it is written atomically (temp file + rename) to avoid torn reads by a poller.
Index ¶
- Variables
- func AutoPrune() (int, error)
- func CancelRequested(dir string) bool
- func Dir(id string) (string, error)
- func Home() (string, error)
- func NewID() string
- func Paths(dir string) (spec, status, eventsFile, logFile, resultFile, cancel string)
- func Prune(opts PruneOptions) (removed int, err error)
- func RequestCancel(dir string) error
- func ValidID(id string) bool
- func WriteSpec(dir string, s *Spec) error
- func WriteStatus(dir string, s *Status) error
- type Health
- type PruneOptions
- type Spec
- type State
- type Status
- type Thresholds
Constants ¶
This section is empty.
Variables ¶
var ErrNoJobs = errors.New("no codexmon jobs found")
ErrNoJobs is returned by Latest when no jobs exist.
Functions ¶
func AutoPrune ¶ added in v0.4.0
AutoPrune applies DefaultPruneOptions. Launch paths call it best-effort so the jobs directory stays bounded (logs are capped per job, but the number of jobs would otherwise grow forever, and every list/status scan reads them all).
func CancelRequested ¶
CancelRequested reports whether the cancel marker exists.
func Dir ¶
Dir returns (and creates) the directory for a job id. Directories are 0700: codex prompts, output, and review text may contain secrets.
func NewID ¶
func NewID() string
NewID returns a sortable, unique job id like "cdx-20260603-150405-9f3a1c".
func Prune ¶ added in v0.4.0
func Prune(opts PruneOptions) (removed int, err error)
Prune deletes old terminal job directories and returns how many were removed. Active (queued/running) jobs are never removed — a status that *claims* active but whose worker is dead reconciles to terminal via ReadStatus first, so it ages out like any other finished job. A directory with no readable status (half-initialized or corrupt) is removed once its mtime is older than MaxAge, so a crashed launch cannot linger forever.
func RequestCancel ¶
RequestCancel writes the cancel marker the monitor polls for.
func WriteStatus ¶
WriteStatus atomically writes status.json.
Types ¶
type Health ¶
type Health string
Health is the liveness verdict derived from idle time while running.
type PruneOptions ¶ added in v0.4.0
type PruneOptions struct {
MaxAge time.Duration // remove terminal jobs that ended longer ago than this
MaxCount int // keep at most this many terminal jobs (newest first)
All bool // remove all terminal jobs
}
PruneOptions bound which terminal jobs Prune removes. A zero or negative limit disables that dimension; All removes every terminal job regardless.
func DefaultPruneOptions ¶ added in v0.4.0
func DefaultPruneOptions() PruneOptions
DefaultPruneOptions returns the retention policy: the defaults above, overridable via CODEXMON_KEEP_DAYS and CODEXMON_KEEP_JOBS (0 disables that limit; non-numeric or negative values are ignored).
type Spec ¶
type Spec struct {
ID string `json:"id"`
Agent string `json:"agent"` // which agent to run (codex/claude/cursor)
AgentBin string `json:"agent_bin"` // resolved path to the agent binary
Args []string `json:"args"`
Cwd string `json:"cwd"`
JSONMode bool `json:"json_mode"`
ForwardStdin bool `json:"forward_stdin"`
Thresholds Thresholds `json:"thresholds"`
Title string `json:"title"`
// Env, when non-empty, fully REPLACES the agent's environment (it is not
// merged with the parent's). codexmon never sets it — the agent inherits the
// launcher's environment — so it exists only for tests/advanced use; a
// hand-edited spec.json that sets it must include PATH/HOME/etc.
Env []string `json:"env,omitempty"`
}
Spec is the immutable launch description persisted for the detached worker.
type State ¶
type State string
State is the lifecycle of a job. queued/running are active; the rest terminal.
type Status ¶
type Status struct {
ID string `json:"id"`
State State `json:"state"`
Health Health `json:"health"`
Phase string `json:"phase"`
Agent string `json:"agent"` // which agent ran (codex/claude/cursor)
AgentBin string `json:"agent_bin"` // resolved path to the agent binary
Args []string `json:"args"` // args passed to the agent
Cwd string `json:"cwd"`
JSONMode bool `json:"json_mode"` // true when monitoring the JSON event stream
WorkerPID int `json:"worker_pid"` // process that owns the agent child
AgentPID int `json:"agent_pid"` // agent process group leader
StartedAt time.Time `json:"started_at"`
UpdatedAt time.Time `json:"updated_at"`
EndedAt *time.Time `json:"ended_at,omitempty"` // nil until terminal
LastEventAt *time.Time `json:"last_event_at,omitempty"` // nil until first event
ElapsedSec float64 `json:"elapsed_sec"`
IdleSec float64 `json:"idle_sec"`
EventCount int `json:"event_count"`
LastEvent string `json:"last_event"`
ThreadID string `json:"thread_id,omitempty"`
Usage *agent.Usage `json:"usage,omitempty"`
ExitCode *int `json:"exit_code,omitempty"`
Error string `json:"error,omitempty"`
// ResultPreview is a truncated copy of the final output for at-a-glance
// status; the full text lives in result.txt (ResultFile).
ResultPreview string `json:"result_preview,omitempty"`
// Result is the final output, capped at 4 MiB — past the cap it ends with
// a truncation notice naming ResultFile, which always holds the full text.
// It is never persisted in status.json (the file is rewritten every
// second; ResultFile holds the text once) — the CLI fills it from
// ResultFile when emitting terminal JSON for wait/run, so a consumer gets
// the whole answer in one call.
Result string `json:"result,omitempty"`
Thresholds Thresholds `json:"thresholds"`
Dir string `json:"dir"`
EventsFile string `json:"events_file,omitempty"`
LogFile string `json:"log_file"`
ResultFile string `json:"result_file"`
// Title is a short human label (e.g. "codex exec review").
Title string `json:"title"`
}
Status is the full, serialized state of a job. It is both the live status file and the structure emitted by `--json`.
func ReadStatus ¶
ReadStatus reads status.json for a job directory. If the status still claims to be active but the owning worker process is gone, it is reconciled to a terminal failed state — otherwise a crashed worker would leave the job reported as "running"/"healthy" forever, the exact misread codexmon must avoid. Reconciliation is applied to the returned value only; callers that want it persisted should WriteStatus it back.
func ReadStatusByID ¶
ReadStatusByID resolves a job id to its status.
type Thresholds ¶
type Thresholds struct {
HeartbeatSec float64 `json:"heartbeat_sec"`
SlowAfterSec float64 `json:"slow_after_sec"`
StalledSec float64 `json:"stalled_sec"` // idle ceiling when nothing is in flight
ToolStuckSec float64 `json:"tool_stuck_sec"` // max time a single MCP/tool call may run
WallSec float64 `json:"wall_sec"`
}
Thresholds are the watchdog limits, in seconds. A zero value disables that check.