How Agents View Detects Session Termination Status: Parsing Logic Explained

Agents View derives session termination status by analyzing the final task-lifecycle event in an agent's JSONL log file, not from external system signals.

The open-source project kenn-io/agentsview implements a sophisticated detection method for session termination status that inspects agent-specific log files at parse time. Instead of relying on explicit shutdown signals or process exit codes, the system reads the last recorded event to determine whether a session ended cleanly, is awaiting user input, or was interrupted mid-task.

How Termination Status Is Derived

During the parsing phase, each agent-specific parser scans the entire JSONL file to identify the most recent task-related event. This event-driven detection ensures the status reflects the actual final state of the agent when the log was written.

Codex Parser Implementation

In internal/parser/codex.go, the parser tracks the most recent task event using the lastTaskEvent field within the codexSessionBuilder struct. As the parser processes each line, it updates this field whenever it encounters task lifecycle events like task_started or task_complete.

After scanning the complete file, the parser calls classifyCodexTermination(b.lastTaskEvent) to map the final event to a normalized status:

  • task_complete → "awaiting_user" (agent finished and is waiting for user input)
  • task_started without subsequent task_complete → "working" (agent was still active when file closed)
  • No task events → "clean" (normal session termination without special lifecycle markers)

The relevant logic appears around lines 77-81 where lastTaskEvent is documented, with the classification call at line 1388.

// Inside internal/parser/codex.go after scanning completes
sess := &ParsedSession{
    // ... other fields ...
    TerminationStatus: classifyCodexTermination(b.lastTaskEvent),
}

Claude Parser Implementation

The Claude parser follows a similar pattern in internal/parser/claude.go, extracting the termination attribute from Claude's JSON output. The parser converts raw termination strings into the normalized TerminationStatus enum through a classification function.

func classifyClaudeTermination(raw string) TerminationStatus {
    switch raw {
    case "clean":
        return TerminationClean
    case "awaiting_user":
        return TerminationAwaitingUser
    // ... other mappings ...
    default:
        return TerminationUnknown
    }
}

Database Storage and API Filtering

Once derived, the termination status persists to the database and becomes queryable through the REST API.

Schema Definition

The termination_status column is defined in internal/postgres/schema.go at line 82 as a TEXT field with a dedicated index for efficient filtering:

CREATE TABLE sessions (
    -- ... other columns ...
    termination_status TEXT,
    -- ...
);
CREATE INDEX idx_sessions_termination_status ON sessions(termination_status);

API Query Parameters

The API exposes this field through query parameters defined in internal/server/huma_routes_sessions.go. Clients can filter sessions using values like ?termination=clean or ?termination=active.

type SessionListFilters struct {
    Termination string `query:"termination" doc:"Filter by termination reason"`
}

Incremental Agent Handling

For agents operating in incremental mode, the detection method for session termination status operates differently. Rather than re-deriving the status on every partial update, the parsediff component treats the stored value as informational only.

In internal/sync/parsediff_report.go, the constant FieldTerminationStatus = "termination_status" at line 121 ensures that termination status changes between incremental updates do not trigger false positive diffs. This prevents spurious synchronization cycles when only the termination state has shifted during active processing.

Summary

  • Event-driven parsing: Agents View determines termination status by inspecting the last task event in JSONL logs, not external signals.
  • Codex implementation: Uses lastTaskEvent tracking and classifyCodexTermination() to map final states to "awaiting_user", "working", or "clean".
  • Claude implementation: Extracts and normalizes the termination field from Claude's JSON output.
  • Database persistence: Stores status in the termination_status column with proper indexing in internal/postgres/schema.go.
  • Incremental handling: The parsediff component mirrors existing values to avoid unnecessary updates during incremental processing.

Frequently Asked Questions

How does Agents View detect if a Codex session ended cleanly?

Agents View scans the entire Codex JSONL log to find the last task event. If the final event is task_complete, the status becomes "awaiting_user". If task_started appears without a matching completion event, the status is "working". When no task events exist, the session is marked as "clean".

Where is the termination status stored in the database?

The status is stored in the termination_status column of the sessions table, defined in internal/postgres/schema.go. The schema includes an index idx_sessions_termination_status to optimize query performance when filtering by termination state.

Can I filter sessions by termination status via the API?

Yes. The API supports filtering through the termination query parameter, as implemented in internal/server/huma_routes_sessions.go. You can pass values like ?termination=clean or ?termination=awaiting_user to retrieve specific session subsets.

Why doesn't the termination status change during incremental updates?

For incremental agents, the termination status is treated as informational only to prevent spurious diffs. The parsediff component in internal/sync/parsediff_report.go maintains the existing termination_status value rather than re-deriving it on every partial file update, ensuring stable synchronization.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →