Skip to content

Instantly share code, notes, and snippets.

@grahama1970
Last active December 27, 2025 18:32
Show Gist options
  • Select an option

  • Save grahama1970/fea7d37de3b39a5fe3265729676bd187 to your computer and use it in GitHub Desktop.

Select an option

Save grahama1970/fea7d37de3b39a5fe3265729676bd187 to your computer and use it in GitHub Desktop.
Durable Async Subagent Completion Logging (Session JSONL)

Durable Async Subagent Completion Logging (Session JSONL)

Goal

When a long-running subagent finishes (success/fail/abort), the main agent should:

  1. Notify the user in the interactive session when idle (push-style, no polling), and
  2. Persist a concise, searchable record even if the interactive session is disconnected/terminated.

Status (PR #323): PR #323 introduces pi.events so hooks can notify the user while the agent is idle. It also mentions PI_ASYNC_RESULT for writing an async result artifact. This proposal adds a durable session-history record by appending subagent lifecycle events to the existing session .jsonl via SessionManager. PR #323 already enables (1) via pi.events + hooks. This adds (2) using the existing SessionManager JSONL session file.

Recommendation: store in the existing session JSONL (Option A)

We should append lifecycle entries to the same session .jsonl file managed by SessionManager:

  • Keeps a single source of truth for “what happened in this session”
  • Avoids introducing a second log file to manage/rotate/sync
  • Remains searchable via jq, rg, etc.
  • Prevents log corruption by keeping a single-writer model (the main process writes session files)

High-level flow

  1. Main agent starts async subagent/chain
  2. A lifecycle event is recorded to the session JSONL (subagent:start)
  3. Subagent runs in background
  4. On completion, record subagent:complete with timing + usage + model + requestedBy
  5. Hook listening for subagent:complete calls pi.send(...) to notify user while idle

Minimal session entry schema (crucial fields only)

Add a new SessionEntry variant, e.g. type: "agent_event" (name flexible), appended as JSONL lines.

agent_event fields (required)

  • type: "agent_event"
  • timestamp: ISO8601 string (when the entry is written)
  • eventType: "subagent:start" | "subagent:complete" | "subagent:error" | "subagent:aborted"
  • jobId: string (correlates start/complete)
  • requestedBy: string (use current user login when available, e.g. grahama1970; otherwise "assistant")

Timing (required for duration)

  • startedAt: ISO8601 string (on start; may also be repeated on complete)
  • completedAt: ISO8601 string (on complete/error/aborted)
  • durationMs: number (on complete/error/aborted)

Model + tokens (required)

  • model: string (provider/model id; whichever representation is already used by the subagent result)
  • usage: object (token counts and cost, if available from the subagent run) usage should reuse the existing usage shape already produced by pi-agent (don’t invent a new token schema).

Identity (recommended)

  • agentName: string (e.g. "scout", "planner", "worker")
  • pid: number (subprocess pid if applicable)
  • mode: "single" | "parallel" | "chain"

Optional (keep small)

  • status: "completed" | "failed" | "aborted"
  • summary: short text suitable for display + log search

Example JSONL entries

Start

{
  "type": "agent_event",
  "timestamp": "2025-12-27T12:00:00.000Z",
  "eventType": "subagent:start",
  "jobId": "job_01...",
  "requestedBy": "grahama1970",
  "agentName": "worker",
  "mode": "chain",
  "pid": 12345,
  "startedAt": "2025-12-27T12:00:00.000Z"
}

Complete

{
  "type": "agent_event",
  "timestamp": "2025-12-27T12:00:12.345Z",
  "eventType": "subagent:complete",
  "jobId": "job_01...",
  "requestedBy": "grahama1970",
  "agentName": "worker",
  "mode": "chain",
  "pid": 12345,
  "startedAt": "2025-12-27T12:00:00.000Z",
  "completedAt": "2025-12-27T12:00:12.345Z",
  "durationMs": 12345,
  "model": "anthropic/claude-sonnet-4-5",
  "usage": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0, "cost": { "total": 0 } },
  "summary": "Subagent finished: <short summary>"
}

Notes / constraints

  • Only log lifecycle events (start/complete/error/aborted). Do not log progress ticks into the session file.
  • Keep payloads small. If a subagent produces large output, store it elsewhere (e.g. subagent session file / artifact) and log only a pointer + summary.
  • User notification remains handled by hooks (pi.events.on("subagent:complete", ...) -> pi.send(...)).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment