Skip to content

7. Process Model Reference

7.1 ProcessState State Machine

Created ──→ Running ──→ Zombie ──→ Dead
   │           │           │
   │  Start()  │ Terminate │  Reap()
   │  Begin    │ Complete/ │  Wait reaps
   │  reasoning│ Error/    │  Resource
   │           │ Timeout/  │  release
   │           │ Kill      │
ConstantValueString RepresentationDescription
StateCreated0"created"Process object allocated, reasoning not started
StateRunning1"running"Reasoning loop executing
StateZombie2"zombie"Reasoning finished, awaiting resource reclamation
StateDead3"dead"All resources released

7.2 State Transition Rules

Valid Transitions:

Source StateTarget StateTrigger Condition
CreatedRunningStart() — reasoning goroutine starts
RunningZombieTerminate() — completed/error/timeout/Kill
ZombieDeadReap() — Wait reclaims

Invalid Transitions: All other combinations are invalid. Attempting an invalid transition returns *SyscallError (INTERNAL).

StateDead has no valid subsequent state.

7.3 ExitStatus Structure

go
type ExitStatus struct {
    Code   int    // 0 = normal exit, non-zero = abnormal
    Reason string // Human-readable exit reason
    Err    error  // Underlying error (nil on normal exit)
}

Common Exit Reasons:

CodeReasonDescription
0"completed"Normal completion
1"unexpected exit"Unexpected exit
1"max steps exceeded"Exceeded maximum reasoning steps
1Error descriptionError during reasoning
2"budget_exceeded"Token budget exceeded

7.4 Resource Release Order

reapProcess performs resource release in the following strict order (idempotency guaranteed via sync.Once):

StepOperationDescription
0handleOrphanChildrenHandle orphan child processes: Running children are reparented to PID 0; Zombie children are pushed to reapCh
1Cancel()Cancel process context (idempotent)
2wg.Wait()Wait for reasoning goroutine to complete (goroutine internally defers CloseAll to close all FDs)
3close(DebugChan)Set proc.DebugChan to nil first (under lock), then close the channel
4CtxFree(CtxID)Release context space
5Reap()State transition Zombie -> Dead
6RemoveProcess(pid)Remove from the process table

7.5 Signal Definitions

ConstantValueBlockableDescription
SIGTERM1YesTermination signal (graceful shutdown)
SIGKILL2NoForce kill
SIGINT3YesInterrupt signal
SIGPAUSE4YesPause reasoning loop
SIGRESUME5YesResume paused reasoning loop

Signal Delivery: Uses resolveSignalDisposition to atomically determine the dispatch path within a single lock hold (blocked → pending / handler / default), avoiding TOCTOU races.

SIGPAUSE/SIGRESUME: reasonStep calls proc.WaitIfPaused() at the start of each step; if resumeCh is non-nil, it blocks until Resume closes the channel. If the process context is cancelled while paused (e.g., killed), the process exits with code 1 and reason "context cancelled while paused".

SignalTree: SignalTree(pid, signal) delivers a signal to the target process and all its living descendants recursively, skipping zombie/dead processes. Returns the count of affected processes. Used by the dashboard p key for tree-wide pause/resume.

7.6 Pause State

When a process receives SIGPAUSE, it enters a paused state while remaining in StateRunning:

FieldTypeDescription
resumeChchan struct{}nil = not paused; non-nil = paused, closed on Resume
pausedAttime.TimeTimestamp when Pause() was called; zero when not paused

Key behaviors:

  • Elapsed time freezing: The dashboard tree freezes the elapsed timer at PausedAt - CreatedAt while a process is paused, preventing the timer from ticking during intentional idle periods.
  • Heartbeat monitor: The heartbeat monitor explicitly skips paused processes. Since paused processes stop sending heartbeats (the reasoning loop is blocked), without this check the monitor would incorrectly flag them as stalled.
  • Idempotent: Pause() is idempotent (no-op if already paused); Resume() is idempotent (no-op if not paused).
  • Display: Paused processes show (or [P] in ASCII mode) instead of the normal running state badge.

Released under the MIT License.