npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

opencode-git-add

v0.9.0

Published

opencode plugin: git add . at the start of each main-session turn (subagent turns skipped), so the unstaged diff always shows only the in-progress turn's changes

Readme

opencode-git-add

An opencode plugin that runs git add . at the start of every new conversation turn, in any git repository.

Motivation

Zed's per-turn agent diff view (the accordion above the agent panel showing what the agent changed in each turn) no longer exists for external ACP-connected agents.

In zed-industries/zed#54918 ("Agents' turn diffs disappeared from Zed"), the Zed team confirmed this is unlikely to come back. The blocker is at the ACP protocol level: the agent's changes are not attributable to a specific turn, because agents typically write directly through the filesystem and ACP cannot distinguish user edits from agent edits.

The maintainers pointed to zed-industries/zed#26560 ("Staged and Unstaged diffs") as the viable alternative: a long-requested feature to view unstaged diffs separately in the git panel.

This plugin implements the workflow that makes #26560 usable for reviewing a single turn's changes:

  1. While a turn is running, the agent's changes accumulate as unstaged changes in the working tree.
  2. When the turn finishes, you review its diff in the editor's unstaged diff view — nothing has been touched yet.
  3. When you start the next turn, the plugin stages everything at that moment (git add .), freezing the previous turn's changes out of the unstaged view.
  4. The unstaged diff now holds only the new turn's changes again — the per-turn review surface that the agent panel diff used to provide.

Timing matters: staging happens at the start of the next turn, never at the end of the current one. Staging right after a turn finishes would make the changes you want to review disappear into the staged set before you had a chance to look at them.

Who is this for

The plugin fits jujutsu users naturally: jj has no staging area, so staging has no meaning there and auto-running git add . interferes with nothing — the plugin simply leaves a clean snapshot boundary between turns.

Plain git users who rely on the staging area should be aware: if you curate commits by selectively staging files (e.g. git add <file> before committing only some changes), this plugin will destroy that workflow, because everything gets staged automatically at the start of every turn. It is only a good fit if you always commit everything at once anyway.

Why a plugin instead of config

opencode's opencode.json has no native hook/event support (see the config schema). Timing hooks like "at the start of each turn" are only possible through the plugin hook system. This plugin uses the chat.message hook, which fires exactly once per prompt submission — before the message is persisted and before any tool runs.

Installation

npm (this package)

Add it to the plugin array in opencode.json:

{
  "$schema": "https://opencode.ai/config.json",
  "plugin": ["opencode-git-add"]
}

Optional configuration, as an options tuple (see plugins docs):

{
  "plugin": [
    [
      "opencode-git-add",
      {
        "skipSessionTitlePatterns": ["^my-plugin-"]
      }
    ]
  ]
}

skipSessionTitlePatterns takes an array of regex strings; sessions whose title matches any of them are skipped. It is empty by default — the injected-message check below already covers every known source (magic-context, slim and opencode's own task machinery all mark their injected parts synthetic/ignored), so this option is only needed for exotic sessions whose messages cannot be inspected.

Manual

Drop git-add.ts into the global plugin directory (applies to all projects), or into a project's .opencode/plugins/:

mkdir -p ~/.config/opencode/plugins
cp git-add.ts ~/.config/opencode/plugins/

Restart opencode afterwards — configuration is only loaded at startup. No changes to opencode.json are required when installing manually.

Behavior

  • Trigger: the chat.message hook — the moment you submit a new prompt and a new turn begins. opencode fires it exactly once per submission, before the message is persisted and before the agent starts doing anything, and never re-fires it when the message row is later updated (e.g. diff-summary recomputation). Earlier versions listened to the message.updated bus event instead, which opencode re-broadcasts on every summary update — combined with plugin-injected synthetic messages, that could cause spurious mid-turn staging (fixed in v0.7.0).
  • Main sessions only: subagent sessions are skipped. A session is a subagent when it has a parent session (parentID in the session DB) — opencode's task tool creates child sessions that way, and this structural signal also covers child sessions whose titles never follow a convention (e.g. magic-context compartments). Earlier versions additionally skipped sessions whose title matched <description> (@<agent> subagent); that title-convention check is redundant and gone, because the session store contains no subagent session without a parentID. If the session cannot be resolved (e.g. an API hiccup), the plugin skips and logs a warning instead of staging at a wrong moment.
  • No injected messages: opencode plugins can inject user-role messages into a session via the server API (e.g. magic-context's progress notices and summary posts), and those fire chat.message too. The hook carries the message's parts inline, so the plugin skips staging synchronously when every part carries the synthetic or ignored flag (or when there are no parts to inspect) — real user input always has at least one unflagged text part.
  • Dedup: the same message ID only triggers once, and skipped messages never record into the dedup set, so injected messages cannot interfere with real turns.
  • Guard: runs only when a .git directory exists in the plugin's working directory (this includes jujutsu colocated working copies). Non-git directories are skipped.
  • Action: git add . in the working directory, without recursing into nested projects.
  • Never blocks your message: staging is a convenience, not a gate. If git add . fails (most commonly a concurrent git process holding .git/index.lock, which exits 128), the plugin retries up to 3 times with 500ms between attempts, then reports a warning and lets the turn proceed anyway — a transient git failure can never kill your submitted message. The failing git stderr is journaled for diagnosis (see Debugging).

Verification

scripts/verify.ts covers 14 scenarios: main-session user message with real parts in a plain git repo → staged; subagent-style session title without a parentID → still staged (only the session-DB parentID classifies a child session); session with a parentID (task-tool subagents, magic-context compartments) → skipped; session lookup 404 / rejected → skipped without error; only .jj → skipped; injected messages (synthetic-only parts, ignored-only parts, empty parts) → skipped; same message id fired twice → staged only once; a skipped synthetic message followed by a real message → still staged (dedup cannot be poisoned); user-configured skipSessionTitlePatterns → skipped; mixed synthetic + real parts → staged; git add . failing while .git/index.lock is held → hook retries, does not throw, stages nothing, and a later turn stages normally once the lock is gone. Run with:

bun scripts/verify.ts

License

MIT

Debugging

The hook journals every event it sees and the decision taken to /tmp/opencode-git-add.log (append-only, safe to leave on). When a staging failure is retried, the failing attempt count, exit code and git stderr are journaled too. When reporting a misbehaviour, include that file — it shows exactly which events fired, in what order, whether staging ran, and why it failed.