sctx

module
v0.4.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 12, 2026 License: MIT

README

sctx

Home  /

 

Token-optimizing command wrapper for AI coding agents.

sctx runs the commands your agent already runs and returns the same information in a fraction of the tokens - exit code intact, errors intact, every omission marked.

For more details and guides, please visit synapctx.com/sctx

 

SynapCTX CI Go Reference GitHub Tag License

 

🔝 back to top

 

Overview

An AI coding agent reads with its context window, and command output is the largest thing it reads that nobody chose. A test run that prints four hundred passing lines, a git status padded with hints, a recursive grep returning the same file forty times - all of it arrives in full, is paid for in full, and almost none of it is what the agent needed.

sctx sits in front of those commands. It parses the output it recognises and re-renders it around the part that carries the signal: the failures, the changed files, the matches grouped by location. Everything else is summarised behind an explicit marker, so the agent can always tell that something was left out.

 

Measured across 6,361 real command runs: 61% of output tokens removed.

Command Output tokens removed Runs measured
rg 91.4% 436
go test 58.2% 613
grep 52.6% 2,209
find 48.1% 141
git diff 26.0% 47
ls 23.3% 319
cat 0.5% 127
make 0.0% 88

 

This table is a snapshot, taken 2026-08-04. The figures move as the ledger grows, and a number written into a README stops moving the moment it is committed - the last snapshot here sat at 46.3% long after the measurement had risen. For the current numbers, refreshed hourly from the same telemetry:

synapctx.com/sctx

 

The last two rows are the design working, not a shortfall. When output holds no redundancy - cat of a source file, a short make run - sctx returns it byte for byte. It compresses what is genuinely repetitive and steps out of the way everywhere else, which is why a file dump saves nothing and a recursive rg saves almost everything.

 

🔝 back to top

 

Why a wrapper rather than a bigger context window

Because the cost is not only money. A context window filled with passing test lines is a context window that no longer holds the file the agent is editing, and quality degrades long before the window is full. Removing output the agent never needed buys attention, not just budget.

And because correctness is not negotiable in this position. A wrapper sits between a developer's command and its result, so sctx is built to fail harmlessly: if a renderer cannot parse something, you get the original bytes; if a command fails, the diagnostics survive and only the noise shrinks. It never returns something an agent could mistake for the whole picture.

 

🔝 back to top

 

Where SynapCTX comes in

sctx is free, MIT-licensed, and complete on its own. Install it, and it works.

It is also the local half of SynapCTX, a context engine for engineering organizations. Connect an account and sctx gains a second job: reporting what it saved, and keeping your working tree visible to the platform's retrieval.

For an individual developer, that means your agent can ask about code across every repository you work in - not just the one that is open - and get answers about the version in front of you rather than the last commit.

For an organization, it means the same knowledge graph and the same memory serve every developer's agent. Savings roll up per repository and per developer. Decisions recorded once are recalled by a teammate's agent months later. And questions that only a whole-estate view can answer - every caller of a function, every consumer of an endpoint, across repositories nobody has checked out - become answerable rather than guessed at.

The boundary is deliberate: nothing in this repository requires an account, and nothing about sctx degrades without one. What an account adds, and the live savings figures, are on synapctx.com/sctx.

 

🔝 back to top

 

Quick look

sctx go test ./...      # the failures and the counts, not 400 passing lines
sctx git status         # the changed files, not the hints
sctx grep -rn foo .     # matches grouped by file, with explicit +N markers
sctx gain               # what it has saved you so far

Nothing else changes. The exit code is the command's own, stdout and stderr keep their meaning, and a pipeline behaves as it did before.

 

🔝 back to top

 

Install

Homebrew - macOS and Linux:

brew install synapctx/tap/sctx

Go - any platform with a Go 1.26+ toolchain:

go install github.com/synapctx/sctx/cmd/sctx@latest

Binary - download the archive for your platform from Releases.

macOS and Linux:

tar -xzf sctx_<version>_<os>_<arch>.tar.gz
sudo install -m 0755 sctx sctxd /usr/local/bin/

Windows (PowerShell):

Expand-Archive sctx_<version>_windows_amd64.zip -DestinationPath $env:LOCALAPPDATA\Programs\sctx
# then add that directory to your PATH

Prebuilt archives cover macOS (Apple Silicon, Intel), Linux (x86-64, arm64) and Windows (x86-64, arm64). They are statically linked and depend on nothing at runtime.

Keep sctx and sctxd in the same directory. sctx watch looks for its helper beside its own executable, so a matched pair always wins over an older copy elsewhere on PATH.

 

Confirm the install and see the effective configuration:

sctx version
sctx doctor

 

Upgrading

# Homebrew
brew upgrade sctx

# Go
go install github.com/synapctx/sctx/cmd/sctx@latest

Configuration and the local savings ledger live in ~/.config/sctx and are untouched by an upgrade.

 

Uninstalling

# Optional: removes the savings ledger and any API keys
brew uninstall sctx
rm -rf ~/.config/sctx

 

🔝 back to top

 

Getting started

sctx works the moment it is installed - put it in front of any command:

sctx go build ./...

To have it applied automatically, run:

sctx setup

 

This detects which AI coding agents are present, and for each one adds a short instruction file describing what sctx is and when to use it. For Claude Code it also registers a hook, so commands are wrapped as they are issued: you and your agent keep writing go test ./..., and the compact output is what arrives. When you have connected a SynapCTX account, it also registers every configured organization as a Streamable HTTP MCP server for OpenAI Codex. Instructions and tool access are checked separately, so setup cannot report Codex ready while its MCP server list is empty.

sctx setup                 # report what is installed, and what is missing
sctx setup --install       # apply it
sctx setup --list-agents   # every agent sctx knows how to configure
sctx setup --agent <id>    # configure one explicitly

Two rules govern what it writes. It only adds configuration where an agent has already established its own, so nothing appears for a tool you do not use. And it never overwrites content you have edited - a customised instruction file is left as you wrote it, and only a missing reference is repaired.

Codex MCP entries live in a clearly marked block in ~/.codex/config.toml. Everything outside that block is preserved, the file is kept mode 0600, and a same-named registration outside the block is reported as a conflict rather than overwritten. The block contains the organization API keys already held in ~/.config/sctx/config.toml; setup output and status never print them.

Restart the agent after setup changes anything. For the VS Code Codex extension, restart the extension (or VS Code) before opening the next session; a new chat in an already-running extension may still use the old MCP inventory.

If no agent is detected, sctx setup reports what it looked for and writes nothing.

 

🔝 back to top

 

Command coverage

Dedicated renderers:

go  ·  git  ·  grep / rg  ·  ls / find / tree  ·  cat / head / tail  ·  diff  ·  ps  ·  du  ·  make  ·  docker  ·  kubectl  ·  gh  ·  golangci-lint  ·  pytest  ·  ruff  ·  mypy  ·  pip  ·  npm / pnpm / yarn  ·  brew  ·  mongosh  ·  rsync  ·  jq / curl  ·  ssh

Any other command is passed through exactly as produced, with one exception: if its output is JSON, it is compacted. That restraint is deliberate - guessing at the structure of an unfamiliar format is how a wrapper starts hiding things - so an uncovered command costs you nothing and risks nothing.

ssh is a special case worth knowing about. Its output is whatever ran on the far end, so sctx reads the remote command from the invocation and applies that command's renderer - sctx ssh <host> '<command>' compresses as though the command had run locally. It declines for interactive sessions, and for anything compound, where two programs' output cannot be rendered as one.

 

🔝 back to top

 

Guarantees

These are the properties that make a wrapper safe to leave in place, and each is enforced by tests rather than convention.

Exit codes are exact never inferred from the text, never rewritten
Errors survive compression when a command fails, the noise shrinks and every diagnostic remains
Elisions are always marked …+12 more, ×3. No marker means nothing was removed
Failure degrades, never suppresses an unparseable format falls back to the original output; so does an internal error
Savings are measured conservatively the figure in sctx gain is a floor, not a flattering estimate
Nothing blocks your command accounting and reporting are off the critical path and cannot delay or fail a run

 

🔝 back to top

 

Commands

Command Purpose
sctx <cmd> [args...] run a command with token-optimized output
sctx -- <cmd> run a command that shares a name with an sctx subcommand
sctx gain savings report, overall and per command
sctx setup configure the AI coding agents you use
sctx doctor show the effective configuration
sctx init connect this installation to a SynapCTX account
sctx watch keep uncommitted code visible to your agent (requires an account)
sctx telemetry inspect or change what is shared
sctx flush send any queued usage events now
sctx version print the version

sctx gain accepts --project to scope to the current repository, --since for a time window, and --format json for machine-readable output.

 

🔝 back to top

 

Connecting a SynapCTX account

Optional, and additive. Nothing about the behaviour above changes.

sctx init

The API key is read from a prompt, or from stdin when piped. It is never accepted as a command-line argument, where it would be visible to any process able to list the process table.

One installation can hold a key per organization - run sctx init once for each, and sctx doctor will list them. Work in a repository is attributed to that repository's organization automatically; sctx init --default chooses which organization to credit for work outside any repository.

With an account connected:

  • Savings become visible across a team in the SynapCTX console, per repository and per developer, rather than only in your local ledger.
  • sctx watch becomes available, described below.

 

🔝 back to top

 

sctx watch - uncommitted code your agent can see

An index of a codebase is built from commits, which makes it reliably wrong about one thing: the code you are changing right now. An agent asking about a function you refactored ten minutes ago is answered from the version before you touched it.

sctx watch closes that gap. It watches your working trees and sends the structure of uncommitted code - symbol names, signatures and doc comments - so retrieval answers with the version in front of you.

sctx watch                  # watches ~/git/github.com by default
sctx watch --root ~/work    # or wherever your checkouts live

 

Sent symbol names, signatures, doc comments, content hashes
Never sent function bodies, file contents, anything .gitignored
Who can see it only you. It is never shared with teammates, and it expires
How to stop stop the command. It runs in the foreground and installs nothing

 

That summary is printed every time, before anything is sent. Results originating from your working tree are labelled UNCOMMITTED in the answer, so they are never mistaken for code on a branch.

This is the only command that requires an account, because there is nowhere to send working-tree structure without one. It runs a companion binary, sctxd, included in the Homebrew and release installs.

 

🔝 back to top

 

Configuration

sctx resolves settings from the environment first, then ~/.config/sctx/config.toml (written by sctx init), then built-in defaults.

The file is optional. A missing one is normal, and a malformed one produces a single warning and is ignored - configuration problems cannot break a command.

 

Variable Default Purpose
SCT__FORCE_TIER (unset) pin the compression level: aggressive, relaxed, verbatim, off
SCT__TELEMETRY_ENABLED (unset) force sharing on or off, overriding the saved answer
SCT__MAX_OUTPUT_BYTES 8388608 output above this size is buffered to disk rather than memory
SCT__STATS_DB_PATH ~/.config/sctx/stats.db local savings ledger
SCT__SPOOL_DIR ~/.config/sctx/spool queue for usage events awaiting delivery
SCT__TELEMETRY_ENDPOINT http://127.0.0.1:6221/v1/telemetry/exec usage-event destination; sctx init sets this to https://sctx.synapctx.com/v1/telemetry/exec
SCT__WORKSPACE_PROXY_URL http://127.0.0.1:6220 destination for sctx watch; https://mcp.synapctx.com for the hosted platform
SCT__WATCH_HELPER (unset) path to sctxd, if it is not installed alongside sctx

 

🔝 back to top

 

Privacy

Without an API key, nothing leaves the machine. The default destination is a loopback address, and delivery without a key is refused rather than attempted.

With an account, two distinct things may be shared, and consent is asked for them separately because they are not the same request:

  • Your savings - command names and token counts, so your own console can report what sctx saved. Covered by holding an account.
  • Coverage gaps - the name alone of a command no renderer matched, so the most-needed renderer is built next. Opt-in, because its value comes from pooling across users and an account is not agreement to that. sctx setup asks once, and an empty answer declines.

 

Paths, filenames, arguments and command output are never transmitted. The queue is inspectable, unrendered, at any time:

sctx telemetry             # what is currently shared
sctx telemetry --preview   # the exact queued events, raw
sctx telemetry --disable   # stop sharing, and delete anything queued

 

🔝 back to top

 

Building from source

git clone https://github.com/synapctx/sctx.git
cd sctx
make build     # ./bin/sctx
make test
make install   # ~/.local/bin/sctx

Requires Go 1.26 or newer. There are no code-generation steps, no external services and no private dependencies involved in building or testing.

 

🔝 back to top

 

Adding a renderer

A renderer is a self-contained package, and new tools are the most useful contribution anyone can make.

Implement format.Formatter (see internal/domain/format/format.go) in a new package under internal/adapters/format/<tool>/, register it in cmd/sctx/main.go, and add the command to the rewrite table in internal/adapters/hook/rewrite.go so the agent integration picks it up.

Four rules, and they are the whole review:

  1. Return format.ErrTierInapplicable when a compression level does not apply, so the next one is tried.
  2. Never emit an empty body for non-empty input.
  3. Mark every omission with an explicit +N.
  4. When the command failed, compress the noise and keep the error.

Build fixtures by running the real tool, on the platform it will run on. Implementations of the same utility differ more than they appear to - GNU and BSD variants disagree on wording, ordering and diagnostics - and a renderer written from memory tends to decline on exactly the systems that matter.

 

🔝 back to top

 

Contributing

Issues and pull requests are welcome. Please include tests, and run make test and make vet before submitting.

 

🔝 back to top

 

Security

If you discover a security vulnerability, please report it privately to security@synapctx.com rather than opening a public issue.

 

🔝 back to top

 

License

MIT - see LICENSE.txt.

 

🔝 back to top

 

 


SynapCTX

Website  |  sctx  |  LinkedIn  |  BlueSky  |  GitHub

© SynapCTX. All rights reserved.

 

Directories

Path Synopsis
cmd
sctx command
sctx is the SynapCTX token-optimizing command wrapper: it runs developer commands and re-renders their output in a token-minimal form for AI agents, accounting the savings locally (`sctx gain`) and org-wide via the SynapCTX platform.
sctx is the SynapCTX token-optimizing command wrapper: it runs developer commands and re-renders their output in a token-minimal form for AI agents, accounting the savings locally (`sctx gain`) and org-wide via the SynapCTX platform.
internal
adapters/exec/osproc
Package osproc runs wrapped commands via os/exec with exact exit-code fidelity, signal forwarding to the child, and bounded-memory output capture.
Package osproc runs wrapped commands via os/exec with exact exit-code fidelity, signal forwarding to the child, and bounded-memory output capture.
adapters/format/brew
Package brew implements a format.Formatter for the Homebrew CLI, covering `brew install` and `brew upgrade`.
Package brew implements a format.Formatter for the Homebrew CLI, covering `brew install` and `brew upgrade`.
adapters/format/collapse
Package collapse holds the line-run collapsing that several formatters share: runs of blank lines, runs of identical lines, and runs of log lines that are identical once a leading timestamp is stripped.
Package collapse holds the line-run collapsing that several formatters share: runs of blank lines, runs of identical lines, and runs of log lines that are identical once a leading timestamp is stripped.
adapters/format/docker
Package docker implements a format.Formatter for the docker CLI.
Package docker implements a format.Formatter for the docker CLI.
adapters/format/du
Package du implements a format.Formatter for `du`.
Package du implements a format.Formatter for `du`.
adapters/format/filediff
Package filediff implements a format.Formatter for the `diff` CLI.
Package filediff implements a format.Formatter for the `diff` CLI.
adapters/format/fs
Package fs formats the output of common filesystem inspection commands (ls, find, tree) into token-minimal representations for AI agents.
Package fs formats the output of common filesystem inspection commands (ls, find, tree) into token-minimal representations for AI agents.
adapters/format/generic
Package generic is the fallback formatter for commands no dedicated formatter claims.
Package generic is the fallback formatter for commands no dedicated formatter claims.
adapters/format/gh
Package gh implements a format.Formatter for the GitHub CLI (gh).
Package gh implements a format.Formatter for the GitHub CLI (gh).
adapters/format/git
Package git implements a format.Formatter for the git CLI.
Package git implements a format.Formatter for the git CLI.
adapters/format/golangcilint
Package golangcilint implements a format.Formatter for golangci-lint.
Package golangcilint implements a format.Formatter for golangci-lint.
adapters/format/gotest
Package gotest formats output from the `go` CLI (test, build, vet, and other subcommands) into a token-minimal rendering.
Package gotest formats output from the `go` CLI (test, build, vet, and other subcommands) into a token-minimal rendering.
adapters/format/grep
Package grep formats grep and ripgrep match output.
Package grep formats grep and ripgrep match output.
adapters/format/jsoncompact
Package jsoncompact is the content-sniff fallback formatter: when no argv-matched formatter claims a command but its stdout is valid JSON (e.g.
Package jsoncompact is the content-sniff fallback formatter: when no argv-matched formatter claims a command but its stdout is valid JSON (e.g.
adapters/format/kubectl
Package kubectl implements a format.Formatter for the kubectl CLI.
Package kubectl implements a format.Formatter for the kubectl CLI.
adapters/format/makefmt
Package makefmt implements a format.Formatter for GNU make.
Package makefmt implements a format.Formatter for GNU make.
adapters/format/mongosh
Package mongosh implements a format.Formatter for `mongosh` (the MongoDB Shell).
Package mongosh implements a format.Formatter for `mongosh` (the MongoDB Shell).
adapters/format/mypy
Package mypy implements a format.Formatter for mypy (Python static type checker) output.
Package mypy implements a format.Formatter for mypy (Python static type checker) output.
adapters/format/npm
Package npm implements a format.Formatter for the npm, pnpm, and yarn JavaScript package-manager CLIs.
Package npm implements a format.Formatter for the npm, pnpm, and yarn JavaScript package-manager CLIs.
adapters/format/pip
Package pip implements a format.Formatter for pip/pip3 output.
Package pip implements a format.Formatter for pip/pip3 output.
adapters/format/psproc
Package psproc implements a format.Formatter for `ps`.
Package psproc implements a format.Formatter for `ps`.
adapters/format/pytest
Package pytest formats output from the `pytest` CLI into a token-minimal rendering.
Package pytest formats output from the `pytest` CLI into a token-minimal rendering.
adapters/format/read
Package read implements a shared format.Formatter for cat, head, and tail: three thin instances over one set of internals, since these commands render identically (JSON/JSONL-sniff delegation on the aggressive tier, generic blank/dupe/timestamped-repeat collapsing on the relaxed tier).
Package read implements a shared format.Formatter for cat, head, and tail: three thin instances over one set of internals, since these commands render identically (JSON/JSONL-sniff delegation on the aggressive tier, generic blank/dupe/timestamped-repeat collapsing on the relaxed tier).
adapters/format/rsync
Package rsync implements a format.Formatter for `rsync`.
Package rsync implements a format.Formatter for `rsync`.
adapters/format/ruff
Package ruff implements a format.Formatter for ruff, the Python linter/formatter.
Package ruff implements a format.Formatter for ruff, the Python linter/formatter.
adapters/format/ssh
Package ssh implements a format.Formatter for `ssh` by delegating to the formatter for the REMOTE command.
Package ssh implements a format.Formatter for `ssh` by delegating to the formatter for the REMOTE command.
adapters/hook
This file implements `sctx hook claude`, the Claude Code PreToolUse Bash hook: it reads a tool-call JSON payload on stdin and, when the command matches a known rewrite rule (see rewrite.go), prints an "updatedInput" JSON directive on stdout that prefixes the command with "sctx ".
This file implements `sctx hook claude`, the Claude Code PreToolUse Bash hook: it reads a tool-call JSON payload on stdin and, when the command matches a known rewrite rule (see rewrite.go), prints an "updatedInput" JSON directive on stdout that prefixes the command with "sctx ".
adapters/stats/sqlite
Package sqlite persists run accounting in a single local SQLite database (pure-Go driver, WAL mode) so concurrent sctx invocations can record safely and `sctx gain` can aggregate cheaply.
Package sqlite persists run accounting in a single local SQLite database (pure-Go driver, WAL mode) so concurrent sctx invocations can record safely and `sctx gain` can aggregate cheaply.
adapters/telemetry/spool
Package spool implements offline-safe telemetry: Emit appends one JSONL line to a local spool file and returns immediately; Flush opportunistically POSTs the spooled batch to the developer-mcp-proxy under a strict deadline.
Package spool implements offline-safe telemetry: Emit appends one JSONL line to a local spool file and returns immediately; Flush opportunistically POSTs the spooled batch to the developer-mcp-proxy under a strict deadline.
application/report
Package report renders the `sctx gain` token-savings report from the local stats store.
Package report renders the `sctx gain` token-savings report from the local stats store.
application/run
Package run orchestrates the wrap-a-command use case: resolve a formatter, execute the child, render its output through the tier chain, account tokens, and emit stats plus telemetry.
Package run orchestrates the wrap-a-command use case: resolve a formatter, execute the child, render its output through the tier chain, account tokens, and emit stats plus telemetry.
domain/exec
Package exec defines the port for running a wrapped command with exact exit-code fidelity and bounded-memory output capture.
Package exec defines the port for running a wrapped command with exact exit-code fidelity and bounded-memory output capture.
domain/format
Package format defines the formatter port: how sctx re-renders a wrapped command's output in a token-minimal form, and the tier model used to degrade safely when a structured parse is not possible.
Package format defines the formatter port: how sctx re-renders a wrapped command's output in a token-minimal form, and the tier model used to degrade safely when a structured parse is not possible.
domain/stats
Package stats defines the local token-savings accounting model behind `sctx gain`.
Package stats defines the local token-savings accounting model behind `sctx gain`.
domain/telemetry
Package telemetry defines the fire-and-forget usage-event port feeding the SynapCTX platform (org-wide savings on the management console).
Package telemetry defines the fire-and-forget usage-event port feeding the SynapCTX platform (org-wide savings on the management console).
platform/agentsetup
Package agentsetup inspects and repairs the agent-side delivery path of a SynapCTX install: the instruction files that tell a coding agent when to reach for `sctx` and SynapCTX, plus the Codex MCP registrations that make those tools exist.
Package agentsetup inspects and repairs the agent-side delivery path of a SynapCTX install: the instruction files that tell a coding agent when to reach for `sctx` and SynapCTX, plus the Codex MCP registrations that make those tools exist.
platform/config
Package config binds SCT__ environment variables (naming conventions) to the CLI configuration.
Package config binds SCT__ environment variables (naming conventions) to the CLI configuration.
platform/gitrepo
Package gitrepo detects the "org/repo" identity of the git repository containing a directory, purely by parsing on-disk git metadata (no shelling out to git) so telemetry can attribute events per repository without adding startup latency.
Package gitrepo detects the "org/repo" identity of the git repository containing a directory, purely by parsing on-disk git metadata (no shelling out to git) so telemetry can attribute events per repository without adding startup latency.
platform/iospill
Package iospill provides a bounded-memory output capture: bytes are held in memory up to a threshold and spill to a temporary file beyond it, so a wrapped command with gigabytes of output cannot exhaust memory.
Package iospill provides a bounded-memory output capture: bytes are held in memory up to a threshold and spill to a temporary file beyond it, so a wrapped command with gigabytes of output cannot exhaust memory.
platform/progkey
Package progkey derives the program key that identifies a command in telemetry: either "program" or "program subcommand", never anything more.
Package progkey derives the program key that identifies a command in telemetry: either "program" or "program subcommand", never anything more.
platform/tokenizer
Package tokenizer estimates token counts from byte lengths.
Package tokenizer estimates token counts from byte lengths.
pkg
agentdoc
Package agentdoc holds the instruction documents `sctx setup` installs, the table of coding agents it knows how to teach, and the pure text rendering that turns the two into the block written to an agent's instruction file.
Package agentdoc holds the instruction documents `sctx setup` installs, the table of coding agents it knows how to teach, and the pure text rendering that turns the two into the block written to an agent's instruction file.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL