Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/ADRs/0021-jsonl-reasoning-trace-exposure.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ Date: 2026-04-15

Accepted

Platform resume of a prior run (new ephemeral sandbox + JSONL conversation
tree) is decided in
[ADR 0094](0094-resume-agent-sessions-from-jsonl-transcripts.md). This ADR
still governs JSONL exposure; 0094 governs using that JSONL as the next
run's starting conversation.

## Context

The retro agent needs access to the raw JSONL conversation transcripts that
Expand Down
110 changes: 110 additions & 0 deletions docs/ADRs/0094-resume-agent-sessions-from-jsonl-transcripts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
---
title: "94. Resume agent sessions from JSONL transcripts"
status: Accepted
relates_to:
- agent-infrastructure
- security-threat-model
- cross-run-memory
topics:
- session
- transcript
- sandbox
- dispatch
- jsonl
---

# 94. Resume agent sessions from JSONL transcripts

Date: 2026-08-27

## Status

Accepted

Builds on JSONL exposure
([ADR 0021](0021-jsonl-reasoning-trace-exposure.md)), ephemeral sandboxes
([ADR 0016](0016-unidirectional-control-flow.md),
[ADR 0036](0036-agent-execution-sandbox.md)), and is distinct from the
Comment on lines +24 to +27

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

6. Related adrs outside context 📜 Skill insight ⚙ Maintainability

ADR 0094 says it builds on ADRs 0021, 0016, 0036, and 0086, but places those links before the
Context heading rather than in Context. The required related-ADR cross-references are therefore
absent from the specified section.
Agent Prompt
## Issue description
Related ADR cross-references are placed under the Status area instead of the Context section.

## Issue Context
Rule 1062094 requires explicit related-ADR links in Context when an ADR builds on or relates to earlier decisions.

## Fix Focus Areas
- docs/ADRs/0094-resume-agent-sessions-from-jsonl-transcripts.md[24-34]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

conversation surface
([ADR 0086](0086-conversation-surface-for-agent-participation.md)).

Motivated by the 2026-08-26 contributors meeting and
[#459](https://github.com/fullsend-ai/fullsend/issues/459).

## Context

Every fullsend dispatch starts a new ephemeral sandbox and rebuilds agent
context from the work item. That is the right isolation default, but it is
expensive for small follow-ups: a `/fs-fix` that changes one line still pays
the full cold-start token cost.

Keeping the GitHub Action alive until a human replies is not viable (job
timeouts, idle compute). Cross-run memory is a different problem
([cross-run-memory.md](../problems/cross-run-memory.md)). Re-injecting forge
comments is also not a conversation tree.

JSONL transcripts are already extracted
([ADR 0021](0021-jsonl-reasoning-trace-exposure.md)). Runtimes already resume
from them (`claude --resume`, Pi's session tree). Loading a CI artifact into
a local OpenShell sandbox has been demonstrated.

## Options

### A. Keep the process alive

Hold the runner until the human replies. Rejected: timeouts, idle cost, and
it does not survive "an hour later."

### B. Cross-run memory / third-party session store

Persist lessons or session blobs in a new store. Rejected: poisoning,
staleness, and a second instruction channel. Resume is not memory.

### C. Re-inject forge comments only

The next run reads issue/PR comments as today. Loses tool-call history and
KV-cache continuity. Already the default; not a continuation.

### D. Restore the JSONL conversation tree into a new sandbox (chosen)

Start a new ephemeral run whose runtime session is the prior transcript
(optionally forked at a turn). Sandbox filesystem and process state are not
restored; the repo is cloned fresh.

## Decision

Adopt **Option D**.

Session continuation means: **replay a prior run's JSONL transcript as the
starting conversation of a new ephemeral sandbox**, scoped to the **same
agent** and **same work item**.
Comment on lines +78 to +80

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

7. Resume ignores runtime compatibility 🐞 Bug ≡ Correctness

ADR 0094 permits continuation based only on the same agent and work item, but a run can override
that agent's runtime while Claude and Pi transcripts use incompatible, runtime-specific formats. A
follow-up dispatched under a different runtime therefore satisfies the documented resume scope but
cannot restore the prior conversation tree.
Agent Prompt
## Issue description
Session continuation is scoped only to the same agent and work item, although transcript formats are runtime-specific and the runtime can be overridden per run. This makes a documented cross-runtime resume impossible.

## Issue Context
Require the resumed run to use the source run's runtime/transcript format, or define an explicit compatible import/normalization contract. Record and validate source-runtime metadata when selecting a transcript.

## Fix Focus Areas
- docs/ADRs/0094-resume-agent-sessions-from-jsonl-transcripts.md[78-95]
- docs/architecture.md[299-302]
- docs/architecture.md[319-322]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


- The sandbox stays ephemeral. No process, volume, or third-party memory
store survives the first run.
- The transcript is an **input**, like issue text: untrusted, access-controlled
by [ADR 0021](0021-jsonl-reasoning-trace-exposure.md). Suppressed JSONL
cannot be resumed.
- Provider prompt-cache hits are an optimization, not a requirement. Resume
must work even when the cache is cold.
- Scratch remains the default for unlabeled dispatch. Compacting, starting
from scratch, and resuming are distinct patterns; this ADR only adds
resume.
- Cross-role consumption of another agent's JSONL is not resume; it stays
under [cross-run-memory.md](../problems/cross-run-memory.md).
- Exact trigger UX (slash flag vs dedicated command) and local vs CI
packaging are follow-on implementation. Both surfaces use this model.
Local resume is tracked in
[#459](https://github.com/fullsend-ai/fullsend/issues/459).

## Consequences

- Cheap follow-ups (`/fs-fix` "remove that line", interactive skills that
wait on a human reply) can reuse the prior conversation instead of
rebuilding context.
- Injection surface grows by one hop: a poisoned first run's transcript
becomes context for the second. Same-agent, same-work-item, explicit
trigger, and ADR 0021 access control bound that hop.
Comment on lines +104 to +106

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

5. Consequences use multi-sentence bullets 📜 Skill insight ⚙ Maintainability

The injection-surface consequence contains two sentences in one bullet, contrary to the
one-sentence-per-bullet requirement. This makes ADR 0094's Consequences section structurally
noncompliant.
Agent Prompt
## Issue description
ADR 0094 contains consequence bullets with multiple sentences.

## Issue Context
Rule 1062091 requires three to five consequence bullets, each consisting of exactly one sentence; preserve the substance while combining or trimming sentences.

## Fix Focus Areas
- docs/ADRs/0094-resume-agent-sessions-from-jsonl-transcripts.md[104-108]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

- Rebuilt sandboxes may differ (image, tools, HEAD). Agents must tolerate
that; pinning the environment is a later choice.
- Long sessions may still need compaction — a later choice, not a
requirement of resume.
15 changes: 13 additions & 2 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ the dedicated org-level `<org>/.fullsend` config repo is deprecated
- Dispatch version-skew resolution: per-repo `reusable-dispatch.yml` inlines stage workflow jobs directly, eliminating `@v0` references to `reusable-{stage}.yml` ([ADR 0062](ADRs/0062-dispatch-version-skew.md)).
- Ready-made configuration presets: `fullsend github setup --config <path-or-url>` installs a vendor preset as `.fullsend/config.base.yaml` and a stub `.fullsend/config.yaml` overlay in the target repository; mint URL, inference backend, and related settings live in configuration files resolved through accessor methods, not CLI flags. Shared-infrastructure presets will reduce per-adopter enrollment (target state): mint via `job_workflow_ref` trust per [ADR 0059](ADRs/0059-public-mint-mode-with-wildcard-allowlists.md); inference authorization model undecided ([ADR 0069](ADRs/0069-ready-made-configuration-presets.md)); enrollment remains required until follow-on ADRs land.
- GitLab event dispatch: two-path model — native CI triggers (`merge_request_event`) for MR events, cron-based polling for issues/comments/labels. No external infrastructure (no webhook bridge). Bot PAT stored as a protected CI/CD variable. Per-repo only ([ADR 0067](ADRs/0067-gitlab-cron-polling-event-dispatch.md)).
- Do not hold CI jobs open for human follow-ups. Session continuation starts a **new** ephemeral run whose runtime session is the prior JSONL transcript ([ADR 0094](ADRs/0094-resume-agent-sessions-from-jsonl-transcripts.md)).

**Open questions:**

Expand All @@ -84,10 +85,12 @@ each target repository's **`.fullsend/`** directory
- ~~How granular is network regulation? Allowlist of endpoints, or coarser controls?~~ Decided in [ADR 0065](ADRs/0065-provider-backed-policy-composition.md): network access is granted through provider profiles with per-endpoint allowlists.
- Does the sandbox provide a pre-built environment (tools, language runtimes, repo clones), or does the agent set up its own workspace within the sandbox?
- ~~Is the sandbox the same for all agent roles, or does each role get a differently-scoped sandbox?~~ Decided in [ADR 0020](ADRs/0020-composable-single-responsibility-agents-with-individual-sandboxes.md): each agent gets its own sandbox with policies designed for its responsibility.
- Should a resumed run pin sandbox image and tooling so the rebuilt environment matches the prior run? (Filesystem state is not restored; [ADR 0094](ADRs/0094-resume-agent-sessions-from-jsonl-transcripts.md).)

**Decided:**

- Provider-backed policy composition: network access is granted through provider profiles declared in harness files. Policy files define only non-composable sandbox restrictions (filesystem, landlock, process). A single `base.yaml` replaces per-agent policy files in the scaffold. Inline `network_policies` continue to work but providers are the recommended approach ([ADR 0065](ADRs/0065-provider-backed-policy-composition.md)).
- Session continuation restores a prior JSONL conversation tree into a **new** sandbox; filesystem and process state still do not persist ([ADR 0094](ADRs/0094-resume-agent-sessions-from-jsonl-transcripts.md)).

## Agent Harness

Expand Down Expand Up @@ -293,6 +296,10 @@ The existing design principle is that [the repo is the coordinator](problems/age
`admin`) using source-native role resolution; the resolved role feeds the
same authorization gate with no cross-system identity verification
([ADR 0054](ADRs/0054-require-authorization-on-all-agent-dispatch-paths.md)).
- Session continuation: an authorized dispatch may start a new run whose
runtime session is a prior JSONL transcript for the same agent and work
item. Scratch remains the default. Exact slash-command UX is follow-on
([ADR 0094](ADRs/0094-resume-agent-sessions-from-jsonl-transcripts.md)).

**Open questions:**

Expand All @@ -309,6 +316,10 @@ The existing design principle is that [the repo is the coordinator](problems/age
[ADR 0086](ADRs/0086-conversation-surface-for-agent-participation.md))?
- How should concurrent agent runs that touch the same conversation thread be
coordinated ([ADR 0086](ADRs/0086-conversation-surface-for-agent-participation.md))?
- How does the operator select which transcript or turn to resume from
(latest run on the work item, explicit run ID, conversation-tree node)?
(Session continuation itself is
[ADR 0094](ADRs/0094-resume-agent-sessions-from-jsonl-transcripts.md).)

## Policy Store

Expand Down Expand Up @@ -353,7 +364,7 @@ Observability is a cross-cutting concern that touches every other component. Eac

**Decided:**

- JSONL reasoning trace exposure: raw JSONL conversation transcripts are extracted from sandboxes and stored with owner-scoped access. Credential scanning acts as an invariant check on [ADR 0017](ADRs/0017-credential-isolation-for-sandboxed-agents.md)'s isolation model. Agents handling data from protected sources beyond the target repo can opt in to JSONL suppression via configuration ([ADR 0021](ADRs/0021-jsonl-reasoning-trace-exposure.md)).
- JSONL reasoning trace exposure: raw JSONL conversation transcripts are extracted from sandboxes and stored with owner-scoped access. Credential scanning acts as an invariant check on [ADR 0017](ADRs/0017-credential-isolation-for-sandboxed-agents.md)'s isolation model. Agents handling data from protected sources beyond the target repo can opt in to JSONL suppression via configuration ([ADR 0021](ADRs/0021-jsonl-reasoning-trace-exposure.md)). Those transcripts are also the payload for session continuation: a later run may replay one as its starting conversation ([ADR 0094](ADRs/0094-resume-agent-sessions-from-jsonl-transcripts.md)).
- Event-driven stage dispatch remains traceable end-to-end in the GitHub Actions UI by using synchronous `workflow_call` dispatch (see [ADR 0041](ADRs/0041-synchronous-workflow-call-event-dispatch.md)).
- Distributed tracing: framework-native OpenTelemetry instrumentation with zero-configuration baseline. Every run produces `run-telemetry.jsonl` locally; optional live OTLP export to any compatible backend. W3C trace context propagation links multi-agent pipelines into unified traces. OTEL GenAI semantic conventions enable LLM-aware backends ([ADR 0050](ADRs/0050-distributed-tracing-instrumentation.md)).
- Eval measurements: the concept of scoring traces ([fail-open](glossary.md#fail-open)). [OTEL primary facts](glossary.md#otel-primary-facts) stay on the run trace (`run-telemetry.jsonl`); [OTEL derived products](glossary.md#otel-derived-products) are the scores (`eval-measurements.jsonl`) ([ADR 0087](ADRs/0087-eval-measurements-online-trace-scoring.md)). See [Eval Measurements](guides/infrastructure/eval-measurements.md).
Expand Down Expand Up @@ -711,7 +722,7 @@ event ──► DISPATCHER
- **Credentials never cross the sandbox boundary.** They exist in the agent runner layer; the sandbox and everything inside it operate without them.
- **Control flows inward (setup) then outward (teardown).** The harness configures the sandbox; the sandbox constrains the runtime. No inner layer can modify an outer layer.
- **Validation gates output.** When configured, no unvalidated output crosses from runner to external system. Exhausted retries are a hard failure, not a fallback.
- **The sandbox is ephemeral.** Created per-run, destroyed after extraction. No state carries between runs.
- **The sandbox is ephemeral.** Created per-run, destroyed after extraction. Sandbox filesystem and process state do not carry between runs. A later run may receive a prior JSONL transcript as input ([ADR 0094](ADRs/0094-resume-agent-sessions-from-jsonl-transcripts.md)); that is not sandbox state.

### MVP embodiment: GitHub + GitHub Actions + OpenShell + Claude Code

Expand Down
2 changes: 1 addition & 1 deletion docs/problems/agent-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ The multi-agent framework space is expanding rapidly, with new entries appearing

## Open questions

- Should agents be stateless (fresh context per task) or stateful (accumulated knowledge of the codebase)? Stateless is safer (no poisoned state persists) but less efficient.
- Should agents be stateless (fresh context per task) or stateful (accumulated knowledge of the codebase)? Stateless is safer (no poisoned state persists) but less efficient. (Per-run sandbox remains ephemeral; replaying a prior JSONL conversation tree for the same agent and work item is decided in [ADR 0094](../ADRs/0094-resume-agent-sessions-from-jsonl-transcripts.md). Accumulated codebase knowledge and cross-run memory remain open — see [cross-run-memory.md](cross-run-memory.md).)
- Should there be one instance of each agent type per repo, per org, or shared? Per-repo is simpler but more expensive. Shared agents need careful isolation. (Infrastructure constrains this — see [agent-infrastructure.md](agent-infrastructure.md).)
- ~~What's the right model for agent identity? Agents need GitHub accounts to post comments and status checks. Separate bot accounts per agent role? A single bot account with role indicated in the comment? GitHub App installations?~~ Decided in [ADR 0007](../ADRs/0007-per-role-github-apps.md): per-role GitHub Apps with manifest-based creation.
- How do we test the interaction model? Can we simulate adversarial scenarios (injection attempts, unauthorized changes, agent disagreements) in a sandbox repo?
Expand Down
2 changes: 1 addition & 1 deletion docs/problems/agent-infrastructure.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ Agents are often discussed as if they run on a developer workstation: fast local

- **CI feedback latency** — Keeping agents out of **local** execution for policy or isolation reasons often leaves only **asynchronous** CI (webhooks, queued pipeline runs). That weakens the tight edit–test–fix loop models assume on a laptop. The gap between “patch pushed” and “signal returned” affects whether an agent can clear syntax and unit failures within a single session; [repo-readiness.md](repo-readiness.md) covers CI maturity and reliable signals more broadly.

- **Workspace and context continuity** — Ephemeral jobs reset filesystem state between runs or stages. Carrying **in-progress repo state, partial edits, and task context** across those boundaries requires explicit design: shared volumes (for example PVCs in Kubernetes), artifact handoff between steps, branches or WIP commits, or external systems (issues, design docs). Without a deliberate handoff story, every run starts cold and context-window limits bite harder.
- **Workspace and context continuity** — Ephemeral jobs reset filesystem state between runs or stages. Carrying **in-progress repo state, partial edits, and task context** across those boundaries requires explicit design: shared volumes (for example PVCs in Kubernetes), artifact handoff between steps, branches or WIP commits, or external systems (issues, design docs). Without a deliberate handoff story, every run starts cold and context-window limits bite harder. (Conversation-tree handoff via JSONL into a new sandbox is decided in [ADR 0094](../ADRs/0094-resume-agent-sessions-from-jsonl-transcripts.md); filesystem/process persistence across runs is still not done.)

- **Compute held open for human latency** — A long-lived pod that **blocks on PR approval, architecture sign-off, or escalation** consumes cluster quota and cost while idle. That misaligns with typical “always-on service” defaults. Better fits include **event-driven** scheduling (wake on comment or approval), aggressive scale-to-zero, or separating **planning** from **execution** so capacity is not reserved across human response times; see [human-factors.md](human-factors.md) and [autonomy-spectrum.md](autonomy-spectrum.md).

Expand Down
4 changes: 3 additions & 1 deletion docs/problems/cross-run-memory.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ Two mechanisms partially address this:

Neither mechanism provides automatic, immediate feedback from one run's outcome to the next run's context. That gap is the problem space.

**Session continuation is not this problem.** Replaying a prior run's JSONL transcript into a new ephemeral sandbox, for the same agent and work item, is decided in [ADR 0094](../ADRs/0094-resume-agent-sessions-from-jsonl-transcripts.md). That restores a conversation tree; it does not promote lessons, observations, or instructions to later unrelated runs. Cross-role consumption of another agent's JSONL remains in this problem space.

## The feedback-loop tension

There are at least three different kinds of memory, and they should not be treated the same way:
Expand Down Expand Up @@ -131,7 +133,7 @@ Retry loops can become flapping when the system does not converge. See [flapping
- Should memory entries be observations only, or can any of them become instructions?
- How should future agents distinguish system-derived facts from agent-authored interpretations?
- Can non-review-gated memory be made safe enough, or should all durable memory promotion go through reviewed repo instructions or skills?
- How should memory interact with separate agent roles? Should triage memory ever influence review behavior directly?
- How should memory interact with separate agent roles? Should triage memory ever influence review behavior directly? (Same-agent JSONL resume is [ADR 0094](../ADRs/0094-resume-agent-sessions-from-jsonl-transcripts.md); cross-role transcript consumption is still this question.)
- What retention model prevents stale memory from dominating: time-based, count-based, outcome-based, or explicit supersession?
- Should the retro agent curate memory by pruning stale entries and proposing durable skill additions, or would that give it too much influence over future runs?
- How should memory interact with structured agent output? Should agent output include an "observations" field that post-scripts can validate and classify?
2 changes: 1 addition & 1 deletion docs/problems/security-threat-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ In fullsend, agents cannot take forge actions directly — credentialed operatio

Another injection variant documented in Shapira et al. (2026) bypasses the immutability principle by storing malicious instructions in an external resource (e.g., a GitHub Gist) that the agent references from its persistent state. The attacker convinces the agent to link to a shared document, then modifies the document after the fact to inject instructions the agent follows in subsequent sessions.

In fullsend's architecture, this is mitigated by several design decisions: agent configuration is immutable from within the sandbox ([ADR 0017](../ADRs/0017-credential-isolation-for-sandboxed-agents.md)), agents cannot modify their own guardrails, and the harness validates agent output against a schema ([ADR 0022](../ADRs/0022-harness-level-output-schema-enforcement.md)). However, the pattern is worth noting because any mechanism that allows agents to fetch and follow external content (URLs in issues, linked documents, referenced specifications) creates a potential injection surface that persists across sessions.
In fullsend's architecture, this is mitigated by several design decisions: agent configuration is immutable from within the sandbox ([ADR 0017](../ADRs/0017-credential-isolation-for-sandboxed-agents.md)), agents cannot modify their own guardrails, and the harness validates agent output against a schema ([ADR 0022](../ADRs/0022-harness-level-output-schema-enforcement.md)). However, the pattern is worth noting because any mechanism that allows agents to fetch and follow external content (URLs in issues, linked documents, referenced specifications) creates a potential injection surface that persists across sessions. Session continuation ([ADR 0094](../ADRs/0094-resume-agent-sessions-from-jsonl-transcripts.md)) replays a prior-run JSONL transcript into a new sandbox for the same agent and work item — it is not persistent agent state, but it does make the first run's transcript an input to the second.

### Open questions

Expand Down
Loading