Repository navigation
Git That Shit v0.3.0
Automatic pre-disaster snapshots for OpenCode AI coding agent config and state files.
"Oh Shit Git" is what you say after the disaster. Git That Shit is what the tool does before the disaster.
Git That Shit is a safety plugin for OpenCode V2 plus a standalone gts CLI over the same snapshot
engine. Before risky operations it snapshots fragile config and agent-state files into an isolated
shadow git repository, so one malformed edit, one bad command, or one accidental overwrite stays
recoverable. Inspired by etckeeper.
Verified source commit: 6069f916a0fac14439c3335e682f994466961851
Package: @gitdamnit/opencode-git-that-shit@0.3.0
Supported OpenCode: 2.0.x (verified on 2.0.21, depends on @opencode/plugin 2.0.21)
License: Apache-2.0
Highlights
- OpenCode V2 native. Migrated from the V1
@opencode-ai/plugininterface to
Plugin.define({ id, setup }). All eight tools (gts_status,gts_list,gts_diff,
gts_restore,gts_snapshot,gts_prune,gts_config,gts_doctor) are registered through
ctx.tool.transformwith JSON Schema inputs. - Verified snapshots. A snapshot is only reported as a recovery point when its commit is
confirmed to resolve in the shadow repository (git rev-parse --verify <hash>^{commit}). - Real pruning.
gts prune --yesrewrites shadow history to keep the newest N snapshots, always
writing a safetygit bundlefirst and moving the branch atomically. Preview remains the default. - Independent by design. Works alone or alongside Checkpoint Orchestrator and Stranger Danger, in
any load order, with no shared code, state, or initialization.
Installation
npm install @gitdamnit/opencode-git-that-shitThen add the plugin to opencode.json(c):
npm publication is pending for this version. Until
0.3.0is published to npm,npm install
resolves to the latest published version,0.2.2. To use0.3.0now, build from the source
archive attached to this release (npm ci && npm run build) or from the git tagv0.3.0. This
GitHub release does not make0.3.0available through npm.
The gts CLI works without an active OpenCode session:
gts version && gts status && gts list && gts snapshot
gts restore <hash> # dry-run by default
gts restore <hash> --yes # restore, skipping files changed since the snapshot
gts restore <hash> --yes --force # overwrite conflicting files
gts prune --keep 20 --yesSecurity hardening
- Secret redaction. JSON key redaction, YAML/TOML/
.env/.jsonc/shell line redaction,
Authorizationheaders, multiline PEM blocks. The global OpenCode config is redacted before being
stored. Files that cannot be processed safely fail closed and are skipped, never stored raw. - Redacted files are never restored. A snapshot holds
[REDACTED]placeholders, not real
values, so restoring them would destroy live credentials. Restore skips redacted files and
reports them; re-enter secrets manually. - Restore is dry-run by default. Overwriting conflicting files requires
--force. A
pre-restorerecovery snapshot is recorded automatically. - Symlink hardening. Restore refuses symlinked destinations and destinations whose nearest
existing ancestor resolves outside the project, and writes atomically via an
O_EXCL|O_NOFOLLOWtemp file +rename. - Private storage permissions. Git That Shit's own storage uses
0700directories and0600
files (config, manifest, lock, snapshot copies, prune bundles) on POSIX platforms. - Project-scoped locking. Snapshot, restore and prune run under one atomic exclusive lock;
stale locks are reclaimed only when provably stale. - Snapshot-failure safety.
snapshot.failureModeaddsstandard(default: continue with a clear
warning and never claim a recovery point) andstrict(opt-in). - Concurrency and TOCTOU fixes. Lock acquisition is an atomic exclusive create; the entire
snapshot and the restore each run under a single lock; restore no longer executes twice.
Fixed
- Duplicate restore execution; snapshot locking scope; lock TOCTOU.
- Global config copied without redaction.
- Pre-edit snapshots mislabelled after the edit (
filesystem.changeddoes not fire for agent tool
writes — post-edit is now driven byexecute.after). [REDACTED]placeholders overwriting live credentials on restore.- CLI printed a hardcoded
0.1.0;gts snapshotexit code on "no-changes". - Path traversal in tracking; restore silently overwriting user changes.
- Destructive-command previews and manual messages leaking secrets into commit messages, manifests
and logs.
Changed
- Package is ESM with type declarations;
dist/is built on publish and no longer committed. - Runtime dependency set reduced to
@opencode/plugin. - Apache-2.0
LICENSEand aNOTICEattribution file are now shipped. - The npm publish workflow is manual (
workflow_dispatch); publishing a release never triggers an
automatic npm publish.
Upgrade notes
- From 0.2.x: V1 plugin functions do not run under OpenCode V2. Register the plugin by package
name and use the V2 API. Existing shadow repositories are migrated to the canonical
.git-that-shit/git-that-shit/snapshots/location rather than orphaned. - Prune rewrites history. Surviving snapshot hashes change; a safety
git bundleis written first. - Snapshot commit messages now include trigger, type, timestamp, tool and session.
Limitations
- Strict-mode prevention of destructive tool calls is best-effort, not guaranteed. The V2
execute.beforehook cannot veto an operation, hook ordering is unspecified, and
permission.evaluatemay not be available; strict mode fails open with an explicit warning.
The restore path's own strict safety check is enforceable. - Private-storage permissions are POSIX-only; Windows relies on platform ACLs.
- Symlink hardening does not defend against a same-user attacker racing the filesystem.
- Historical shadow commits may retain previously committed secrets; history is not rewritten.
- Pruning and history rewriting have intentional boundaries (safety bundle required first).
- Requires Node.js
>=18and an OpenCode 2.0.x host for the plugin surface. - Not a replacement for project git, not a backup system, not secret management, local git only.
Verification evidence
| Evidence | Result |
|---|---|
Repository suite (bun test on 6069f91) |
322 passed, 0 failed, 24 files, 623 assertions |
| Typecheck / lint / build | pass |
Packaging (npm pack) |
70 files: dist/, LICENSE, NOTICE, package.json, README.md |
| Fresh isolated install of the packed artifact | reports 0.3.0; entry point id gitdamnit.git-that-shit; gts version → 0.3.0 |
| Independent Docker Plugin Test Lab | 145 passed, 0 failed, 0 skipped |
Docker Plugin Test Lab detail: OpenCode v2.0.21, Node v22.23.3, image
opencode-plugin-lab:local = sha256:76ebd805cd548a638b9b1508e5f16e680cd5b082cd3f3561d28f2f2301336ff1.
It verified Git That Shit alone and together with Checkpoint Orchestrator (65bf698) and Stranger
Danger (9cfd813) across load-order permutations, security, concurrency, failure isolation,
shadow-repository snapshots, locking, restore dry runs and actual restores. Source, staged, packed
and installed versions were all 0.3.0 and consistent.
The repository suite covers the engine, CLI and V2 plugin harness (no live host). The Docker lab
covers the live OpenCode V2 host. Neither substitutes for the other; no live provider credentials
were used.
Full in-repo record: docs/RELEASE-0.3.0-EVIDENCE.md, docs/RELEASE-0.3.0.md,
docs/SECURITY.md, docs/INTEROP.md, PROJECT_STATUS.md, DECISION_LOG.md.
{ "$schema": "https://opencode.ai/config.json", "plugins": ["@gitdamnit/opencode-git-that-shit"] }