gh-agent-viz

Local Copilot CLI Session Ingestion

This document describes the local Copilot CLI session ingestion feature added to gh-agent-viz.

Overview

gh-agent-viz now supports ingesting local Copilot CLI sessions from ~/.copilot/session-state/*/workspace.yaml in addition to remote agent sessions fetched via the Copilot API (with gh agent-task CLI fallback).

Architecture

Unified Session Model

A new Session type unifies both agent-task and local Copilot sessions:

type Session struct {
    ID         string
    Status     string
    Title      string
    Repository string
    Branch     string
    PRURL      string
    PRNumber   int
    CreatedAt  time.Time
    UpdatedAt  time.Time
    Source     SessionSource  // "agent-task" or "local-copilot"
}

Session Sources

Two session sources are supported via the SessionSource enum:

Tolerant Parsing

The local session parser implements tolerant parsing with fallback behavior:

  1. Primary Parse: Attempt to parse YAML using standard unmarshaling
  2. Fallback Parse: If YAML is malformed, extract key fields line-by-line
  3. Silent Continue: Skip sessions that cannot be parsed at all

This ensures the TUI never crashes due to malformed session files.

Status Mapping

Local session status is derived using DeriveLocalSessionStatus():

Explicit Status Mapping

Input Statuses Normalized Output
completed, finished, done, merged, closed completed
running, in progress, active, open running
failed, error, cancelled, canceled failed
queued, pending, waiting queued

Time-Based Derivation

When no explicit status is provided or status is unknown:

API

FetchLocalSessions()

func FetchLocalSessions() ([]Session, error)

Fetches all local Copilot CLI sessions from ~/.copilot/session-state/. Returns an empty list (not an error) if the directory doesn’t exist.

FetchAllSessions(repo string)

func FetchAllSessions(repo string) ([]Session, error)

Fetches both agent-task (via CAPI or CLI fallback) and local sessions. Filters by repository if specified. This is the recommended API for fetching all available sessions.

Session Conversion

func FromAgentTask(task AgentTask) Session
func (s Session) ToAgentTask() AgentTask

Conversion functions maintain backward compatibility with existing code that expects AgentTask objects.

Testing

All functionality is covered by tests:

Run tests with:

go test ./internal/data/...

File Format

Expected workspace.yaml structure (all fields optional except session_id):

session_id: "abc123-session"
start_time: "2026-02-15T03:10:00Z"
last_activity: "2026-02-15T03:30:00Z"
message_count: 15
status: "completed"
repository: "owner/repo"
branch: "main"
title: "Session title"
conversation_history:
  - role: user
    content: "First message"

UI Changes

Backward Compatibility

All existing agent-task functionality remains unchanged:

Known Limitations

  1. Detail View: Currently only agent-task sessions support the detail view. Local sessions show basic info from the list view only.
  2. Logs: Local sessions don’t support log viewing (no equivalent to gh agent-task view --log)
  3. Browser Open: Cannot open local sessions in browser (no associated PR)

Future Enhancements

Possible future improvements: