> ## Documentation Index
> Fetch the complete documentation index at: https://developer.upsun.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How to slash OpenCode Token costs by 90% on Upsun

> Cut your OpenCode token usage by up to 90% on Upsun with three community plugins: OpenSlimedit, opencode-dcp, and opencode-snip. Step-by-step guide to install and configure them on your existing deployment, with benchmarks, troubleshooting, and best practices.

export const PostMeta = ({data = {}}) => {
  const {author, date} = data;
  const authors = Array.isArray(author) ? author : author ? [author] : [];
  const resolveAuthor = slug => {
    const entry = AUTHOR_MAP[slug] || ({});
    const name = entry.name || slug;
    const github = entry.github || null;
    const linkedin = entry.linkedin || null;
    const url = github ? `https://github.com/${github}` : linkedin || null;
    const avatarUrl = github ? `https://github.com/${github}.png?size=64` : null;
    return {
      name,
      url,
      avatarUrl
    };
  };
  const formattedDate = date ? new Date(date).toLocaleDateString('en-US', {
    year: 'numeric',
    month: 'long',
    day: 'numeric'
  }) : null;
  if (authors.length === 0 && !formattedDate) return null;
  const AUTHOR_MAP = {
    "aaron-collier": {
      "name": "Aaron Collier"
    },
    "aaron-dudenhofer": {
      "name": "Aaron Dudenhofer"
    },
    "aaron-porter": {
      "name": "Aaron Porter"
    },
    "adriaan-odendaal": {
      "name": "Adriaan Odendaal"
    },
    "ajmal": {
      "name": "Ajmal Siddiqui"
    },
    "akalipetis": {
      "name": "Antonis Kalipetis"
    },
    "alexander-varwijk": {
      "name": "Alexander Varwijk"
    },
    "alicia-bevilacqua": {
      "name": "Alicia Bevilacqua"
    },
    "amelie-deguerry": {
      "name": "Amelie Deguerry"
    },
    "anacidre": {
      "name": "Ana Cidre",
      "linkedin": "https://www.linkedin.com/in/ana-cidre"
    },
    "andoni": {
      "name": "Andoni Auzmendi"
    },
    "andrei-taranu": {
      "name": "Andrei (Alex) Taranu",
      "linkedin": "https://www.linkedin.com/in/andrei-alex-taranu/"
    },
    "andrew-baxter": {
      "name": "Andrew Baxter"
    },
    "andrew-melck": {
      "name": "Andrew Melck"
    },
    "antoine-crochet-damais": {
      "name": "Antoine Crochet Damais"
    },
    "augustin-delaporte": {
      "name": "Augustin Delaporte",
      "linkedin": "https://www.linkedin.com/in/augustindelaporte/"
    },
    "branislav-bujisic": {
      "name": "Branislav Bujisic"
    },
    "carl-smith": {
      "name": "Carl Smith"
    },
    "caroline-leroy": {
      "name": "Caroline Leroy"
    },
    "cati-mayer": {
      "name": "Cati Mayer"
    },
    "catplat": {
      "name": "C Trinkwon"
    },
    "ceelolulu": {
      "name": "Celeste van der Watt"
    },
    "chadwcarlson": {
      "name": "Chad Carlson",
      "github": "chadwcarlson",
      "linkedin": "https://www.linkedin.com/in/chadwcarlson"
    },
    "chris-ward": {
      "name": "Chris Ward"
    },
    "chris-yates": {
      "name": "Chris Yates"
    },
    "christian-sieber": {
      "name": "Christian Sieber"
    },
    "christopher-lockheardt": {
      "name": "Christopher Lockheardt"
    },
    "christopher-skene": {
      "name": "Christopher Skene"
    },
    "chuck-morgan": {
      "name": "Chuck Morgan"
    },
    "corey-dockendorf": {
      "name": "Corey Dockendorf"
    },
    "crell": {
      "name": "Crell"
    },
    "damz": {
      "name": "Damz"
    },
    "dan-morrison": {
      "name": "Dan Morrison"
    },
    "davidbonachera": {
      "name": "David Bonachera",
      "github": "davidbonachera",
      "linkedin": "https://www.linkedin.com/in/davidbonachera"
    },
    "dereliahmet1": {
      "name": "Ahmet Faruk Dereli"
    },
    "devicezero": {
      "name": "Jonas Kröger",
      "github": "devicezero",
      "linkedin": "https://www.linkedin.com/in/jonaskroeger/"
    },
    "doug-goldberg": {
      "name": "Doug Goldberg"
    },
    "duncan-naves": {
      "name": "Duncan Naves",
      "github": "duncannaves",
      "linkedin": "https://www.linkedin.com/in/duncan-naves-a94423aa"
    },
    "erika-bustamante": {
      "name": "Erika Bustamante"
    },
    "fabpot": {
      "name": "Fabien Potencier"
    },
    "flovntp": {
      "name": "Florent Huck",
      "github": "flovntp",
      "linkedin": "https://www.linkedin.com/in/florenthuck"
    },
    "fred-plais": {
      "name": "Fred Plais"
    },
    "gauthier-garnier": {
      "name": "Gauthier Garnier"
    },
    "gilzow": {
      "name": "Paul Gilzow"
    },
    "gmoigneu": {
      "name": "Guillaume Moigneu",
      "github": "gmoigneu",
      "linkedin": "https://www.linkedin.com/in/guillaumemoigneu/"
    },
    "gregqualls": {
      "name": "Greg Qualls"
    },
    "guguss": {
      "name": "Augustin Delaporte"
    },
    "haylee-millar": {
      "name": "Haylee Millar"
    },
    "ivana-kotur": {
      "name": "Ivana Kotur"
    },
    "jackrabbithanna": {
      "name": "Mark Hanna"
    },
    "jared-wright": {
      "name": "Jared Wright",
      "github": "jww-sh",
      "linkedin": "https://www.linkedin.com/in/jaredwaynewright"
    },
    "jessica-orozco": {
      "name": "Jessica Orozco"
    },
    "joey-stanford": {
      "name": "Joey Stanford"
    },
    "john-grubb": {
      "name": "John Grubb"
    },
    "jonas-kruger": {
      "name": "Jonas Kruger"
    },
    "kathryn-frazer": {
      "name": "Kathryn Frazer"
    },
    "kemiojo": {
      "name": "Kemi Elizabeth Ojogbede"
    },
    "kieronsambrook-smith": {
      "name": "Kieronsambrook Smith"
    },
    "laurent-arnoud": {
      "name": "Laurent Arnoud",
      "linkedin": "https://www.linkedin.com/in/laurent-arnoud-861b44121/"
    },
    "letoya-boyne": {
      "name": "Letoya Boyne"
    },
    "lolautruche": {
      "name": "Jérôme Vieilledent"
    },
    "lyly-lepinay": {
      "name": "Lyly Lepinay"
    },
    "manauwar-alam": {
      "name": "Manauwar Alam"
    },
    "marc-antoine-porri": {
      "name": "Marc Antoine Porri"
    },
    "maria-antinkaapo": {
      "name": "Maria Antinkaapo"
    },
    "maria-de-anton": {
      "name": "Maria De Anton"
    },
    "mark-dorison": {
      "name": "Mark Dorison"
    },
    "markus-hausammann": {
      "name": "Markus Hausammann"
    },
    "mary-thomas": {
      "name": "Mary Thomas"
    },
    "mathias-bolt-lesniak": {
      "name": "Mathias Bolt Lesniak"
    },
    "mathieu-strauch": {
      "name": "Mathieu Strauch"
    },
    "matthias-van-woensel": {
      "name": "Matthias Van Woensel",
      "linkedin": "https://www.linkedin.com/in/matthias-van-woensel-267a069"
    },
    "maz-mohammadi": {
      "name": "Maz Mohammadi"
    },
    "michael-sharp": {
      "name": "Michael Sharp"
    },
    "mupsi": {
      "name": "Marine Gandy"
    },
    "natalie-harper": {
      "name": "Natalie Harper"
    },
    "ngommenginger": {
      "name": "Nicolas Gommenginger",
      "linkedin": "https://www.linkedin.com/in/nicolas-gommenginger"
    },
    "nicholas-bennison": {
      "name": "Nicholas Bennison"
    },
    "nicholas-vahalik": {
      "name": "Nicholas Vahalik"
    },
    "nick-hardiman": {
      "name": "Nick Hardiman"
    },
    "nickanderegg": {
      "name": "Nickanderegg"
    },
    "nicolas-grekas": {
      "name": "Nicolas Grekas",
      "github": "nicolas-grekas",
      "linkedin": "https://www.linkedin.com/in/nicolasgrekas/"
    },
    "niti-malwade": {
      "name": "Niti Malwade"
    },
    "opensocialteam": {
      "name": "Opensocialteam"
    },
    "ori-pekelman": {
      "name": "Ori Pekelman"
    },
    "otavio-santana": {
      "name": "Otavio Santana"
    },
    "palwandi": {
      "name": "Pawan Alwandi",
      "github": "pawpy",
      "linkedin": "https://www.linkedin.com/in/pawanalwandi"
    },
    "patrick-boest": {
      "name": "Patrick Boest"
    },
    "patrick-dawkins": {
      "name": "Patrick Dawkins",
      "github": "pjcdawkins",
      "linkedin": "https://www.linkedin.com/in/patrickdawkins"
    },
    "patrick-klima": {
      "name": "Patrick Klima"
    },
    "pjcdawkins": {
      "name": "Pjcdawkins"
    },
    "prineet-kaurbhurji": {
      "name": "Prineet Kaurbhurji"
    },
    "quentin-sinig": {
      "name": "Quentin Sinig"
    },
    "ralt": {
      "name": "Florian Margaine",
      "github": "ralt",
      "linkedin": "https://www.linkedin.com/in/florian-margaine-43971136"
    },
    "ramanathanramakrishnamurthy": {
      "name": "Ramanathanramakrishnamurthy"
    },
    "remi-lejeune": {
      "name": "Rémi Lejeune"
    },
    "ribel": {
      "name": "Taras Kruts"
    },
    "robert-douglass": {
      "name": "Robert Douglass"
    },
    "rudy-weber": {
      "name": "Rudy Weber"
    },
    "ryan-hicks": {
      "name": "Ryan Hicks"
    },
    "sabri-helal": {
      "name": "Sabri Helal"
    },
    "savannah-bergeron": {
      "name": "Savannah Bergeron"
    },
    "shannon-vettes": {
      "name": "Shannon Vettes"
    },
    "shawn-ogasawara": {
      "name": "Shawn Ogasawara",
      "linkedin": "https://www.linkedin.com/in/shawn-ogasawara-83a9a0/"
    },
    "shawna-spoor": {
      "name": "Shawna Spoor"
    },
    "shedrack-akintayo": {
      "name": "Shedrack Akintayo"
    },
    "simon-ruggier": {
      "name": "Simon Ruggier"
    },
    "sophie-van-der-kindere": {
      "name": "Sophie Van Der Kindere"
    },
    "stefanos-thampis": {
      "name": "Stefanos Thampis"
    },
    "stephen-weinberg": {
      "name": "Stephen Weinberg"
    },
    "sukhman-virk": {
      "name": "Sukhman Virk"
    },
    "sumaira-nazir": {
      "name": "Sumaira Nazir"
    },
    "sumer": {
      "name": "Sümer Cip"
    },
    "syed-raza": {
      "name": "Syed Raza"
    },
    "tamara-bacchia": {
      "name": "Tamara Bacchia"
    },
    "tara-arnold": {
      "name": "Tara Arnold"
    },
    "theosakamg": {
      "name": "Mickael Gaillard",
      "github": "theosakamg"
    },
    "thomasdiluccio": {
      "name": "Thomas di Luccio"
    },
    "tim-anderson": {
      "name": "Tim Anderson"
    },
    "tom-helmer-hansen": {
      "name": "Tom Helmer Hansen"
    },
    "tylermills": {
      "name": "Tyler Mills"
    },
    "upsun": {
      "name": "Upsun"
    },
    "veronika-tolkachova": {
      "name": "Veronika Tolkachova",
      "linkedin": "https://www.linkedin.com/in/veronika-tolkachova-169167a2"
    },
    "vince-parker": {
      "name": "Vince Parker"
    },
    "vinnie-russo": {
      "name": "Vincenzo Russo"
    },
    "vrobert78": {
      "name": "Vincent Robert",
      "github": "vrobert78",
      "linkedin": "https://www.linkedin.com/in/vincent-robert-498a883"
    },
    "yuriy-babenko": {
      "name": "Yuriy Babenko"
    },
    "yuriy-gerasimov": {
      "name": "Yuriy Gerasimov"
    }
  };
  return <div className="post-meta">
      {(authors.length > 0 || formattedDate) && <div className="post-meta-info">
          {authors.length > 0 && <div className="post-meta-authors">
              {authors.map(slug => {
    const {name, url, avatarUrl} = resolveAuthor(slug);
    const inner = <>
                    {avatarUrl && <img src={avatarUrl} alt={name} className="post-meta-avatar" />}
                    <span className="post-meta-author-name">{name}</span>
                  </>;
    return url ? <a key={slug} href={url} target="_blank" rel="noopener noreferrer" className="post-meta-author">
                    {inner}
                  </a> : <span key={slug} className="post-meta-author">{inner}</span>;
  })}
            </div>}
          {authors.length > 0 && formattedDate && <span className="post-meta-separator" aria-hidden="true">·</span>}
          {formattedDate && <span className="post-meta-date">{formattedDate}</span>}
        </div>}
    </div>;
};

<PostMeta data={{ date: "2026-06-02T10:00:00.000Z", date: "2026-06-02T10:00:00.000Z", date: "2026-06-02T10:00:00.000Z", author: ["flovntp"], image: "/images/posts/ai/opencode-token-optimization/opencode-tokens.png" }} />

> This is **Part 2** of the OpenCode on Upsun series. If you haven't deployed your OpenCode server yet,
> start with [How to Host OpenCode on Upsun](/posts/ai/opencode-on-upsun/).

Running an AI coding agent in server mode is powerful — but token costs add up quickly. Every API call sends tool
schemas, conversation history, and file contents to the model. On a busy session with multiple file reads and command
outputs, you can easily burn 3x the tokens you actually need.

This guide walks you through installing three community plugins that significantly reduce token usage on your existing
OpenCode deployment on Upsun, with minimal changes to your configuration.

## Why tokens accumulate

Before diving into the fixes, it helps to understand where the waste comes from:

* **Tool descriptions** — OpenCode ships with many built-in tools. Their full descriptions are sent with every API
  call, even when most tools are unused in a given step. This compounds across multi-step tasks.
* **Bash output floods** — Commands like `pytest`, `npm install`, or `docker build` dump hundreds of lines into the
  context. The model processes all of it, including passing test names, deprecation warnings, and progress bars.
* **Stale context** — In long sessions, the model replays conversation history and re-reads files that are no longer
  relevant, inflating context size over time.

Three plugins address each of these root causes independently.

<Note>
  These plugins are community-maintained and not officially endorsed by OpenCode.

  **Always:**
  Check their GitHub repositories for the latest updates and compatibility with your OpenCode version.
  Test in a staging environment before deploying to production.
</Note>

## The plugins

<Info>
  Token reduction percentages are sourced from each plugin's official documentation and may vary based on session
  length, model, and usage patterns.
</Info>

### `OpenSlimedit` — tool description compression

[`OpenSlimedit`](https://github.com/ASidorenkoCode/openslimedit) aggressively shortens all built-in tool descriptions,
compacts file read output, and adds line-range editing support. Because tool schemas are sent with every API call,
compressing them saves thousands of input tokens per step — and this compounds across multi-step tasks.

Benchmarks show **11-45% token reduction** across tested models, with zero regressions on Claude Opus 4.6. It works
by modifying descriptions of existing tools only, which avoids the model confusion that affects approaches using
custom tool schemas.

### `opencode-dcp` — dynamic context pruning

[`opencode-dcp`](https://github.com/Opencode-DCP/opencode-dynamic-context-pruning) manages the conversation context
between turns. It exposes a `compress` tool to the model that replaces stale, closed content with high-fidelity
technical summaries before sending requests to the LLM — without modifying your actual session history.

Unlike OpenCode's built-in compaction (which triggers statically when the context hits its limit), DCP lets the model
decide when to compress and which specific messages to target. This results in **50-70% token reduction** on long
sessions.

### `opencode-snip` — bash output filtering

[`opencode-snip`](https://github.com/VincentHardouin/opencode-snip) automatically prefixes shell commands with
[`snip`](https://github.com/edouard-claude/snip), a CLI proxy that filters command output before it reaches the LLM
context window. It handles `git`, `go`, `cargo`, `npm`, `docker`, and more — keeping errors and summaries while
dropping noise.

This delivers **60-90% reduction** on bash-heavy sessions.

## Important considerations

While these plugins are widely used and tested, they may:

* **Modify tool behavior**: `OpenSlimedit` alters tool descriptions.
* **Affect session history**: `opencode-dcp` compresses context, which may remove details the model needs.
* **Introduce latency**: `snip` adds a small overhead to shell commands.

<Warning>
  Recommendation: Start with one plugin at a time, monitor token usage and model behavior, and gradually add others.
  Pin plugin versions in `opencode.json` to avoid breaking changes.
</Warning>

## Installation

OpenCode loads `npm` plugins automatically via `Bun` at startup — no manual `npm install` needed for the plugins
themselves. The only exception is `snip`, a standalone Go binary with **no npm package**: declaring `opencode-snip`
only loads the *plugin*, not the binary it relies on. You install that binary once during the build with the
reusable `install-github-asset.sh` script (Step 2).

### Step 1 — Declare the plugins in `opencode.json`

Add the three plugins to the `plugin` array in your `opencode.json`:

```json title="opencode.json" {2-6} theme={null}
{
  "plugin": [
    "openslimedit@latest",
    "@tarquinen/opencode-dcp@latest",
    "opencode-snip@latest"
  ],
  "mcp": {
    "upsun": {
      "type": "remote",
      "url": "https://mcp.upsun.com/mcp",
      "headers": {
        "upsun-api-token": "${UPSUN_CLI_TOKEN}",
        "enable-write": "true"
      },
      "enabled": true
    }
  }
}
```

OpenCode will install and cache these packages automatically via Bun on the next startup.

### Step 2 — Install the `snip` binary during the build

The three npm plugins are fetched automatically by OpenCode at startup. `snip`, however, is a standalone Go binary
and must be installed during the build. The simplest way on Upsun is the reusable
[`install-github-asset.sh`](/posts/hands-on/install-gh-asset-on-upsun/) script, which pulls a binary straight from its
GitHub releases and installs it globally into `/app/.global/bin` (already on your `PATH`).

Add this to your application's `build` hook in `.upsun/config.yaml`:

```yaml title=".upsun/config.yaml" {6-8} theme={null}
applications:
  app:
    # ...
    hooks:
      build: |
        set -e
        # Install the snip binary (opencode-snip backend) from GitHub releases
        curl -fsS https://raw.githubusercontent.com/upsun/snippets/main/src/install-github-asset.sh | bash /dev/stdin "edouard-claude/snip"
      deploy: |
        set -e
        # Confirm snip is available before OpenCode starts
        snip --version
```

The script auto-detects the right asset (it picks the first release asset whose name contains `linux` + your
architecture, i.e. `snip_<version>_linux_amd64.tar.gz`) and installs the latest release. To pin a version or force a
specific asset, pass them explicitly:

```bash title="Terminal" theme={null}
# install-github-asset.sh "<org/repo>" ["<version>"] ["<asset_name>"]
curl -fsS https://raw.githubusercontent.com/upsun/snippets/main/src/install-github-asset.sh \
  | bash /dev/stdin "edouard-claude/snip" "0.18.0" "snip_0.18.0_linux_amd64.tar.gz"
```

<Note>
  `snip` has **no npm package**, so it cannot be installed via `dependencies`. The `opencode-snip` plugin does not bundle
  the binary either — it only loads the plugin glue. Installing the binary in the build hook is what makes
  `snip` available at runtime.
</Note>

### Step 3 — Deploy

Commit and push:

```bash title="Terminal" theme={null}
git add .upsun/config.yaml opencode.json
git commit -m "Add token optimization plugins + snip binary"
upsun push
```

Upsun will rebuild the container, install the `snip` binary during the build hook, and restart OpenCode. The three
npm plugins are fetched and cached by OpenCode on first startup.

## Which plugin for which problem?

| Problem                                         | Plugin            | Reduction |
| ----------------------------------------------- | ----------------- | --------- |
| High token cost per step (all sessions)         | **OpenSlimedit**  | 11-45%    |
| Long sessions with growing context              | **opencode-dcp**  | 50-70%    |
| Bash-heavy sessions (`npm`, `pytest`, `docker`) | **opencode-snip** | 60-90%    |

All three can run together — they address different layers of token waste and do not conflict with each other.

## Verify the plugins are loaded

Once deployed, connect to your OpenCode instance and press `Ctrl+P` → **View Status** (System category). You should
see all three plugins listed as active.

For opencode-dcp specifically, you can check savings at any point during a session by running:

```bash title="OpenCode prompt" theme={null}
/dcp stats
```

## Troubleshooting

### `snip` binary not found at runtime

If OpenCode logs show `snip: command not found`, the binary was not installed correctly during the build. Check the
build output with:

```bash title="Terminal" theme={null}
upsun activity:log
```

Look for the `install-github-asset.sh` step in the build log. The script auto-selects the asset matching `linux` +
your architecture (`snip_<version>_linux_amd64.tar.gz`). If a new release changes the naming convention, pass the
exact asset name as the third argument:

```bash title=".upsun/config.yaml (build hook)" theme={null}
curl -fsS https://raw.githubusercontent.com/upsun/snippets/main/src/install-github-asset.sh \
  | bash /dev/stdin "edouard-claude/snip" "0.18.0" "snip_0.18.0_linux_amd64.tar.gz"
```

### Check installed plugin

To check installed plugins, connect to your `opencode` container and run the following command:

```bash title="Terminal" theme={null}
upsun ssh -- cat .local/share/opencode/log/2026-05-26T132215.log | grep "loading plugin"

  INFO  2026-05-26T13:25:04 +20ms service=plugin path=openslimedit@latest loading plugin
  INFO  2026-05-26T13:25:04 +19ms service=plugin path=@tarquinen/opencode-dcp@latest loading plugin
  INFO  2026-05-26T13:25:04 +0ms service=plugin path=opencode-snip@latest loading plugin 
```

<Warning>
  Seeing `opencode-snip@latest loading plugin` confirms the **plugin** loaded — it does **not** mean the `snip`
  **binary** is installed. Always confirm the binary separately with `snip --version` (see the deploy hook in Step 2).
</Warning>

### opencode-dcp increases token usage on short sessions

DCP is most effective on sessions longer than 15-20 turns. On short sessions, the overhead of the compress tool
itself can outweigh the savings. Remove it from the `plugin` array if your typical sessions are short:

```json title="opencode.json" theme={null}
{
  "plugin": [
    "openslimedit@latest",
    "opencode-snip@latest"
  ]
}
```

### A plugin causes unexpected tool behavior

Pin to a specific version instead of `@latest` to stabilize your deployment:

```json title="opencode.json" theme={null}
{
  "plugin": [
    "openslimedit@1.2.0",
    "@tarquinen/opencode-dcp@1.2.3",
    "opencode-snip@1.6.1"
  ]
}
```

## What's next?

With token costs under control, you can monitor per-session usage with
[opencode-tokenscope](https://github.com/ramtinJ95/opencode-tokenscope), which provides a breakdown of which tools
and skills consume the most tokens — useful for identifying further optimization opportunities.

## Resources

* [How to Host OpenCode on Upsun](/posts/ai/opencode-on-upsun/) — Part 1
* [OpenSlimedit GitHub repository](https://github.com/ASidorenkoCode/openslimedit)
* [opencode-dcp GitHub repository](https://github.com/Opencode-DCP/opencode-dynamic-context-pruning)
* [opencode-snip GitHub repository](https://github.com/VincentHardouin/opencode-snip)
* [snip GitHub repository](https://github.com/edouard-claude/snip)
* [install-github-asset.sh — install any GitHub release asset on Upsun](/posts/hands-on/install-gh-asset-on-upsun/)
* [OpenCode plugin documentation](https://opencode.ai/docs/plugins/)
* [Upsun documentation](/docs)
