Skip to content

Research: AI agent state persistence compatibility #1329

Description

@mafredri

Scope: Research and document how each AI agent module handles state persistence to inform implementation of pause/resume functionality.

Deliverables:

  • Compatibility matrix documenting state persistence support for all 11 AI agent modules
  • Documentation of state storage mechanisms for each agent (file paths, formats, flags)
  • UX considerations and limitations for each agent type
  • Recommendations for module configuration defaults

Agents to research (11 total):

  • coder/modules/claude-code - Known: --continue flag + .claude/ directory (full support baseline)
  • coder/modules/aider
  • coder/modules/goose
  • coder/modules/amazon-q
  • coder-labs/modules/auggie
  • coder-labs/modules/codex
  • coder-labs/modules/copilot
  • coder-labs/modules/cursor-cli
  • coder-labs/modules/gemini
  • coder-labs/modules/opencode
  • coder-labs/modules/sourcegraph-amp

Research questions for each agent:

  • Does the agent have native session persistence?
  • Where does it store state (file paths, formats)?
  • Does it have resume/continue flags?
  • What happens when state files are present vs. absent on startup?
  • What UX issues arise when AgentAPI shows history but agent has no memory?

Compatibility levels (from RFC):

  • Full support: Session persistence + resume flag + status reporting
  • Partial support: Status reporting only, context lost on resume
  • No support: Agent cannot persist state

Acceptance criteria:

  • All 11 agents researched and documented
  • Compatibility matrix created showing support level for each agent
  • State storage mechanisms documented (paths, formats, flags)
  • UX considerations documented for each compatibility level
  • Recommendations provided for enable_state_persistence defaults per agent
  • Template requirements documented (persistent storage needs)

Blocks:

References:

Activity

  1. self-assigned this
    on Feb 4, 2026
  2. mafredri commented on Feb 20, 2026

    @mafredri
    MemberAuthor

    Compatibility matrix and storage guidelines draft PR available at: coder/coder#22222

  3. mafredri commented on Feb 20, 2026

    @mafredri
    MemberAuthor

    Implementation guide for bringing each AI agent module to full pause/resume support.

    • Foundation: PR #736 adds enable_state_persistence, state_file_path, pid_file_path to the agentapi base module.

    Status

    Agent Module Path State Work Required Effort
    Claude Code coder/modules/claude-code Done None Done
    Codex coder-labs/modules/codex Done Add --type codex Trivial
    Copilot coder-labs/modules/copilot Done Update session dir check (minor) Trivial
    OpenCode coder-labs/modules/opencode Needs update Change continue default to true Trivial
    Auggie coder-labs/modules/auggie Needs update Change two defaults to true, add --type Small
    Aider coder/modules/aider Needs update Change report_tasks default, fix --type conditional Small
    Goose coder/modules/goose Needs update Wire --resume, add --type Small
    Gemini coder-labs/modules/gemini Needs update Wire --resume, add --type Small
    Amazon Q coder/modules/amazon-q Needs update Wire --resume, add --type. Deprecated upstream. Small
    Cursor CLI coder-labs/modules/cursor-cli Needs update Wire --resume with chat ID capture Medium
    Sourcegraph Amp coder-labs/modules/sourcegraph-amp Needs update Wire amp threads continue with thread ID capture Medium

    Priority 1: Default changes (Trivial)

    OpenCode

    File: registry/coder-labs/modules/opencode/main.tf, line 116

    variable "continue" {
      # Change default from false to true
      default     = true
    }

    The module's start.sh already handles this: when ARG_CONTINUE=true, it passes --continue to opencode. No script changes needed.

    File: registry/coder-labs/modules/opencode/scripts/start.sh (no changes, for reference)

    • Line 14: ARG_CONTINUE=${ARG_CONTINUE:-false} (receives from main.tf)
    • Line 48: OPENCODE_ARGS+=(--continue) (already wired)

    Copilot (minor)

    File: registry/coder-labs/modules/copilot/scripts/start.sh, check_existing_session() function

    Currently checks only the legacy path:

    local session_dir="$HOME/.copilot/history-session-state"

    Update to also check the new path (v0.0.342+):

    local legacy_dir="$HOME/.copilot/history-session-state"
    local new_dir="$HOME/.copilot/session-state"
    if { [ -d "$legacy_dir" ] && [ -n "$(ls "$legacy_dir"/session_*_*.json 2>/dev/null)" ]; } || \
       { [ -d "$new_dir" ] && [ -n "$(ls "$new_dir"/*.json 2>/dev/null)" ]; }; then

    Alternatively, simplify by always passing --continue since Copilot gracefully starts a new session when none exists.

    Auggie

    File: registry/coder-labs/modules/auggie/main.tf

    Two variables need default changes:

    variable "continue_previous_conversation" {
      # Line 114, change default from false to true
      default     = true
    }
    
    variable "report_tasks" {
      # Line 142, change default from false to true
      default     = true
    }

    The module's start.sh already handles continue_previous_conversation: when true, it passes --continue to auggie (line 83). No script changes needed for the default flip.

    Caveat: Headless --continue behavior is unverified. Test in an agentapi-wrapped workspace before shipping.

    Priority 2: Resume flag wiring (Small)

    Goose

    File: registry/coder/modules/goose/scripts/start.sh

    Current launch (line 33-35):

    agentapi server --term-width 67 --term-height 1190 -- \
      bash -c "$(printf '%q ' "$GOOSE_CMD" "${GOOSE_ARGS[@]}")"

    Required changes:

    1. Add session existence check before setting args
    2. On resume: use --resume --name "coder-task" instead of --instructions
    3. On cold start: use current behavior plus --name "coder-task" to create a named session
    SESSION_NAME="coder-task"
    SESSION_DB="$HOME/.local/share/goose/sessions/sessions.db"
    
    if [ -f "$SESSION_DB" ] && sqlite3 "$SESSION_DB" \
        "SELECT 1 FROM sessions WHERE name='$SESSION_NAME' LIMIT 1" 2>/dev/null | grep -q 1; then
      echo "Resuming existing Goose session: $SESSION_NAME"
      GOOSE_ARGS=(run --resume --name "$SESSION_NAME" --interactive)
    elif [ ! -z "$GOOSE_TASK_PROMPT" ]; then
      # ... existing prompt logic, add --name "$SESSION_NAME" ...
      GOOSE_ARGS=(run --interactive --name "$SESSION_NAME" --instructions "$PROMPT_FILE")
    else
      GOOSE_ARGS=(--name "$SESSION_NAME")
    fi

    Note: Prompt re-delivery -- when resuming, skip --instructions to avoid re-sending the task prompt into an active conversation.

    Gemini

    File: registry/coder-labs/modules/gemini/scripts/start.sh

    Current launch (last 2 lines):

    agentapi server --term-width 67 --term-height 1190 -- \
      bash -c "$(printf '%q ' gemini "${GEMINI_ARGS[@]}")"

    Required changes:

    1. Check for existing sessions before adding --resume
    2. Guard against dead-loop bug (google-gemini/gemini-cli#15892) when no sessions exist
    GEMINI_SESSION_DIR="$HOME/.gemini/tmp"
    
    # Check if any chat session files exist
    if [ -d "$GEMINI_SESSION_DIR" ] && find "$GEMINI_SESSION_DIR" -path "*/chats/*.json" -print -quit 2>/dev/null | grep -q .; then
      echo "Resuming latest Gemini session"
      GEMINI_ARGS=(--resume "latest")
      # Skip --prompt-interactive on resume to avoid re-sending task prompt
    elif [ -n "$GEMINI_TASK_PROMPT" ]; then
      # ... existing prompt logic ...
    fi

    Critical: The --resume "latest" flag causes a dead loop when called with no existing sessions. The existence check is mandatory, not optional.

    Amazon Q

    File: registry/coder/modules/amazon-q/scripts/start.sh

    Current launch (last line):

    agentapi server ${ARG_SERVER_PARAMETERS} --term-width 67 --term-height 1190 -- "$Q_CMD" "${ARGS[@]}"

    Required changes:

    1. Check for existing conversation state
    2. Add --resume flag on resume, skip prompt re-delivery
    # Amazon Q stores per-directory conversation state
    # Check if prior conversation exists for this workdir
    if "$Q_CMD" chat --resume --trust-all-tools 2>&1 | head -1 | grep -q "Resuming"; then
      # Use --resume instead of appending prompt
      ARGS=(chat --resume)
      if [ "$ARG_TRUST_ALL_TOOLS" = "true" ]; then
        ARGS+=(--trust-all-tools)
      fi
    fi

    Warning: Amazon Q Developer CLI is deprecated in favor of Kiro CLI. Assess longevity before investing significant effort.

    Aider (status reporting only)

    File: registry/coder/modules/aider/main.tf, line 45

    variable "report_tasks" {
      # Change default from false to true
      default     = true
    }

    File: registry/coder/modules/aider/scripts/start.sh, start_agentapi() function

    Current code has a conditional --type bug (lines 46-49):

      if [ -n "$initial_prompt" ]; then
        echo "Starting agentapi with initial prompt"
        agentapi server -I="$initial_prompt" --type aider --term-width=67 --term-height=1190 -- aider --model $ARG_MODEL --yes-always
      else
        agentapi server --term-width=67 --term-height=1190 -- aider --model $ARG_MODEL --yes-always
      fi

    Fix: add --type aider to the else branch:

        agentapi server --type aider --term-width=67 --term-height=1190 -- aider --model $ARG_MODEL --yes-always

    No resume work: Aider lacks viable session resume. --restore-chat-history is lossy and crashes on large histories. Blocked on upstream.

    Priority 3: Resume with ID capture (Medium)

    Cursor CLI

    File: registry/coder-labs/modules/cursor-cli/scripts/start.sh

    Current launch (line 67):

    agentapi server --type cursor --term-width 67 --term-height 1190 -- "$CURSOR_CMD" "${ARGS[@]}"

    Cursor supports --resume [chatId] and agent resume, but requires a chat ID from the prior session. The module needs:

    1. Chat ID capture: After initial launch, capture the chat ID. Possible approaches:
      • Parse cursor-agent ls output for the most recent chat
      • Monitor ~/.cursor/chats/ for new directories
      • Capture from process stdout (format undocumented)
    2. ID persistence: Write captured chat ID to a file (e.g., $HOME/.cursor-cli-module/last-chat-id)
    3. Resume logic: On restart, if the ID file exists, pass --resume <chatId>
    CHAT_ID_FILE="$HOME/$ARG_MODULE_DIR_NAME/last-chat-id"
    
    if [ -f "$CHAT_ID_FILE" ]; then
      CHAT_ID=$(cat "$CHAT_ID_FILE")
      echo "Resuming Cursor session: $CHAT_ID"
      # Replace prompt args with resume
      ARGS=(--resume "$CHAT_ID")
      # Re-add global flags (--model, -f)
    fi

    Open question: Exact mechanism for capturing chat ID. Requires testing cursor-agent ls output format and ~/.cursor/chats/ directory structure.

    Sourcegraph Amp

    File: registry/coder-labs/modules/sourcegraph-amp/scripts/start.sh

    Amp stores threads entirely server-side. Resume requires a thread ID.

    1. Thread ID capture: After initial launch, capture from one of:
      • AMP_THREAD_ID env var (if Amp sets it)
      • --stream-json output parsing
      • amp threads list after first run
    2. ID persistence: Write thread ID to a file (e.g., $HOME/.amp-module/last-thread-id)
    3. Resume logic: Use amp threads continue <threadId> instead of piping prompt to amp
    THREAD_ID_FILE="$HOME/.amp-module/last-thread-id"
    
    if [ -f "$THREAD_ID_FILE" ]; then
      THREAD_ID=$(cat "$THREAD_ID_FILE")
      echo "Continuing Amp thread: $THREAD_ID"
      agentapi server --type amp --term-width=67 --term-height=1190 -- \
        amp threads continue "$THREAD_ID" "${ARGS[@]}"
    else
      # ... existing launch logic ...
    fi

    Constraint: Requires network connectivity to Sourcegraph servers. Air-gapped environments cannot use thread resume.

    Priority 4: --type flag cleanup

    Modules launching agentapi server without --type:

    Module File Current Command Add Flag
    Goose coder/modules/goose/scripts/start.sh:33 agentapi server --term-width 67 ... --type goose
    Amazon Q coder/modules/amazon-q/scripts/start.sh:66 agentapi server ${ARG_SERVER_PARAMETERS} --term-width 67 ... --type amazon-q
    Gemini coder-labs/modules/gemini/scripts/start.sh:76 agentapi server --term-width 67 ... --type gemini
    Codex coder-labs/modules/codex/scripts/start.sh:216 agentapi server --term-width 67 ... --type codex
    Auggie coder-labs/modules/auggie/scripts/start.sh:101 agentapi server --term-width 67 ... --type auggie

    Additionally, Aider conditionally omits --type aider (see Priority 2 above).

    These should be bundled with the resume flag changes for each module.

    Cross-cutting: Prompt re-delivery on resume

    Several modules pass ai_prompt / task_prompt on every startup via agentapi -I or as a CLI argument. When resume is added, the prompt must be conditionally skipped to avoid re-sending the task into an already-active conversation.

    Module How prompt is passed Skip logic needed
    Goose --instructions "$PROMPT_FILE" arg to goose run Yes: omit --instructions when resuming
    Gemini --prompt-interactive "$PROMPT" arg to gemini Yes: omit --prompt-interactive when resuming
    Amazon Q Prompt appended directly to ARGS array Yes: don't append prompt when resuming
    Auggie --instruction "$PROMPT" arg to auggie Yes: omit --instruction when resuming
    OpenCode agentapi -I "$PROMPT" Yes: omit -I when resuming with --continue

    Modules that already handle this correctly:

    • Claude Code: Prompt only sent on new sessions.
    • Codex: Prompt only sent on new sessions.
    • Copilot: Prompt skipped when check_existing_session() returns true (uses --continue without -I).

    Not actionable (blocked on upstream)

    Aider session resume

    Aider's --restore-chat-history flag reads from .aider.chat.history.md in the working directory. This is not viable for production use:

    • Reconstruction is lossy (markdown log, not structured state)
    • Frequently crashes on large histories
    • Does not restore file context
    • Summarizes entire cross-session history rather than targeting the last session

    Aider also lacks MCP support (TODO at registry/coder/modules/aider/scripts/start.sh:53). Status reporting relies on text-based output parsing via --type aider.

    What to monitor: MCP support in Aider-AI/aider. When added, implement coder_report_task MCP tool config and re-evaluate session persistence.

    Recommendation: Keep enable_state_persistence = false for Aider. It is the only agent where this is the correct long-term setting.

  4. added a commit that references this issue on Mar 4, 2026
    13411c8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions