Skip to content

core: defer self-authored AGENTS.md updates until the next turn #36483

Open

Description

@kitlangton

Summary

When an agent edits the AGENTS.md currently supplying its own instructions, OpenCode immediately injects the changed file back into the same active turn as an Instructions updated system update. This makes the agent observe and potentially react to its own in-flight policy mutation.

Environment

  • opencode version: 0.0.0-next-15354
  • OS: Darwin 25.5.0, arm64
  • Terminal: WarpTerminal (TERM=xterm-256color, COLORTERM=truecolor)
  • Shell: /bin/zsh
  • Install/channel: next
  • Active plugins: share-with-team.ts, debug-workspace-plugin.ts, @warp-dot-dev/opencode-warp

Reproduction

  1. Open a workspace whose root AGENTS.md is loaded into the active session instructions.
  2. Ask the active agent to edit that same AGENTS.md through an edit or patch tool call.
  3. Observe the tool result and subsequent messages within the same turn.
  4. OpenCode renders Instructions updated and injects a <system-update> containing the newly edited AGENTS.md before the turn has completed.

Expected Behavior

An instruction-file mutation authored by the currently executing agent should be deferred until a safe turn boundary, ideally the next user turn or next assistant invocation. The current turn should continue under the instruction snapshot with which it started.

Updates caused externally by the user, filesystem watcher, or another agent may still need immediate handling; the important distinction is that OpenCode knows the mutation originated from the active agent's own tool call.

Actual Behavior

The changed AGENTS.md is immediately re-injected into the active conversation as a system update. The TUI displays Instructions updated: core/instructions directly beneath the patch result, and the agent receives replacement ambient instructions while it is still carrying out the task that edited them.

Additional Context

  • Reproduced while changing a deployment runbook in the workspace root AGENTS.md.
  • The behavior is subtle rather than a crash: cache behavior remains intact, but instruction causality becomes surprising and the active agent can change its own governing context mid-turn.
  • Screenshot captured the patch result immediately followed by Instructions updated: core/instructions.
  • Related: V2: route progressive AGENTS.md through durable Instructions #34341 tracks routing progressive AGENTS.md through durable instructions. This issue is specifically about deferring self-authored instruction mutations until a safe turn boundary.

Activity

  1. HOYALIM commented on Jul 13, 2026

    @HOYALIM

    I reproduced this deterministically on current dev in packages/core/test/session-runner.test.ts: a local tool mutates the active SystemContext during the first provider turn, and the second provider turn in the same SessionRunner.run receives the changed context. The smallest implementation is to freeze the admitted context generation for one runner drain and reconcile on the next run, but that also defers unrelated external context changes that arrive mid-drain. The narrower self-authored-only behavior would require mutation-origin plumbing that does not exist today. Which contract do you want: run-level context isolation, or explicit mutation causality before implementation?

  2. xixi-box commented on Aug 28, 2026

    @xixi-box

    Hi! I'd like to work on this issue and have started investigating it on the current dev branch. I'm happy to implement the contract the maintainers prefer once the run-level isolation vs. explicit mutation-causality question above is clarified.

    Could a maintainer please assign this issue to me? I'll keep the change focused and include a regression test.

  3. opencodejr commented on Oct 28, 2026

    @opencodejr

    Thanks for the detailed write-up. I looked at how instruction sync works on the latest dev (77a0fd6f3), and as far as I can tell this is the current design working as intended:

    • SessionRunner.prepareContext (packages/core/src/session/runner/llm.ts) calls InstructionState.prepare before every model step and retry, not just at turn boundaries. Its comment says each step must read the settled context.
    • InstructionState.observe/commit (packages/core/src/session/instruction-state.ts) compare the current sources with the stored ones and publish session.instructions.updated with the rendered update. That becomes the Instructions updated: <keys> notice, and the tests check for these chronological updates.
    • Nothing tracks whether a change came from the active agent's own edit/patch tool call, and nothing holds the change back until the next turn.

    So when the agent edits the AGENTS.md it's running under, the next step in the same turn picks up the change as designed. What you're describing, keeping the turn's starting instruction snapshot and applying self-authored changes at the next turn boundary, would need a new mechanism. It may fit better tracked as a feature/design change, alongside #34341, than as a bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions