sentra

module
v0.6.1 Latest Latest
Warning

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

Go to latest
Published: Sep 11, 2026 License: MIT

README ΒΆ

✦ S E N T R A ✦

Encrypted, deduplicated, agent-aware backups for S3 β€” driven from a synthwave terminal.

CI License MIT XChaCha20-Poly1305

The default surface is a full-screen TUI β€” a seven-view rail, a first-run wizard, and every human workflow at your fingertips.


What is Sentra?

Sentra is a single Go binary (sentra) that backs up local directories to S3 or any S3-compatible store as encrypted, content-addressed snapshots. It runs equally well as a scriptable CLI or a full-screen TUI, and it ships with a built-in agent that audits your repository and surfaces recommendations.

  • πŸ”’ Client-side encryption. New blobs are sealed with XChaCha20-Poly1305 using a per-blob 24-byte random nonce; the data key is derived from your passphrase with Argon2id. The bucket only ever sees ciphertext.
  • 🧩 Content-defined dedup. FastCDC chunking + SHA-256 content addressing. A 50 GiB tree with one changed file uploads roughly 1 MiB on the next snapshot.
  • πŸ—‚οΈ Versioned snapshots. Each snapshot is an immutable, encrypted manifest pointing at chunk hashes. Restore re-derives and verifies every hash, so it is exact-byte by construction.
  • πŸ€– A hybrid agent. Local heuristics run first; the optional LLM sees summaries only β€” never file contents or secret values. Recommendations are read-only by default (prune candidates, ignore-list additions, secret findings, retention drift).
  • πŸ”Œ MCP built in. sentra mcp serves your snapshots to Claude β€” or any MCP client β€” over stdio: metadata only, with two-phase confirm-gated mutations. Inside the TUI, ctrl+a opens a built-in assistant chat with the same guarantees.
  • πŸŒ† A synthwave TUI. sentra ui β€” or just sentra β€” opens a Bubbletea app that lands on a first-run wizard, an unlock gate, or the dashboard depending on your state.

A quick tour


Snapshots β€” sort, filter, drill in; r restores and d diffs the highlighted row.

Backup β€” a three-step wizard: pick a folder (with jump-to places), choose a schedule, confirm with a tag.

First-run wizard β€” guided setup for AWS or any S3-compatible store.

Settings β€” config summary plus scheduled backups, recovery kit, passphrase, and setup.

Backup, step 2 β€” one-shot, or a cadence that installs a named policy and an OS timer; it then shows up under Schedules.

Install

go install
go install github.com/markgustetic/sentra/cmd/sentra@latest

Builds from source with your Go toolchain (1.27+); sentra version reports the module version and commit from the embedded build info.

Homebrew (from tagged releases)
brew install markgustetic/tap/sentra
Prebuilt binaries (signed) (from tagged releases)

Download platform archives (macOS and Linux, amd64/arm64) from the releases page. Each release ships a checksums.txt plus a cosign keyless signature (checksums.txt.sig and checksums.txt.pem) and a syft SBOM per archive. The certificate identity is the exact release-workflow path bound to a tag ref β€” substitute the version you downloaded:

cosign verify-blob \
  --certificate checksums.txt.pem \
  --signature  checksums.txt.sig \
  --certificate-identity 'https://github.com/markgustetic/sentra/.github/workflows/release.yml@refs/tags/<version>' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  checksums.txt

Quickstart

πŸš€ Fastest: kick the tires with local MinIO (no AWS account)

sentra local starts a local MinIO via docker compose, points Sentra at a throwaway .sentra-local.yaml (never your real config), and opens the TUI with the first-run wizard pre-filled for MinIO. It runs docker compose in the current directory, so run it from a clone of this repo (which carries the docker-compose.yaml):

git clone https://github.com/markgustetic/sentra && cd sentra
just local            # builds the binary and opens the TUI (needs Docker)

just local-reset wipes everything back to a clean first run.

πŸͺ£ Real storage: the setup wizard

For AWS S3 or any S3-compatible store, let the wizard do the work:

sentra setup

It walks you through the backend choice, can create or verify the bucket, block public access, enable default encryption, write sentra.yaml, and initialize the encrypted repo β€” all in one flow, reviewing a non-secret plan before it touches anything.

  • AWS S3 β†’ sign in with AWS CLI browser login (the default), IAM Identity Center / SSO, an existing profile/role, or write config only. After a browser or SSO sign-in the wizard offers to create a dedicated backup user β€” a scoped IAM user whose static keys never expire β€” and switches your config to it, so scheduled backups survive the night. Browser login alone is for trying Sentra: its session expires within hours. Need an admin to grant permissions first? The wizard can print the least-privilege IAM policy and stop:

    sentra setup iam-policy --bucket my-backups --prefix sentra/
    
  • S3-compatible or existing bucket (MinIO, LocalStack, Cloudflare R2, Wasabi, …) β†’ enter the bucket, region, and endpoint_url and you're set.

When it initializes the repo, Sentra asks you to set a repository passphrase (unless --passphrase-file or SENTRA_PASSPHRASE supplies one). Choose Save in keychain and Sentra stores it in your OS keyring, writing only passphrase.use_keyring: true to sentra.yaml β€” never the secret itself.

[!NOTE] No secrets are ever written to sentra.yaml, logs, setup drafts, or recovery kits. Not the passphrase, not wrapped keys, not AWS credentials.

πŸ“Έ Take a snapshot
sentra backup ./Documents --tag weekly

Repeating a backup? Save the path and maintenance choices as a policy, then install it into your OS user scheduler (launchd on macOS, systemd user timers on Linux β€” no resident daemon):

sentra policy add home --path ./Documents --tag home --schedule daily@03:00 --check --prune dry-run
sentra policy run home
sentra schedule install home
sentra schedule status home

schedule install writes the LaunchAgent plist (macOS) or the systemd user service + timer (Linux) and loads it right away β€” launchctl bootstrap gui/$UID … or systemctl --user enable --now … β€” so nothing waits for your next login. schedule status asks the OS whether the timer is actually loaded, and when it is not (a headless SSH session has no user session to load into) it prints the exact command to run once you have one. schedule uninstall unloads the timer before removing its files.

A slot that passes while the machine is asleep fires when it wakes, on both platforms. One that passes while it is shut down is caught up at your next login: the timer also runs sentra policy run --if-due at load, which backs up only if no snapshot of the policy exists since its most recent scheduled slot and otherwise exits with "not due until …". Loading at install counts too, so a brand-new schedule takes its first backup right after schedule install. schedule status and the Schedules view show the computed next slot, not the catch-up.

Want a reviewed, two-step run? Write a JSON plan, inspect it, then apply:

sentra backup plan  ./Documents --tag weekly --out weekly-plan.json
sentra backup apply weekly-plan.json
πŸ” List, restore, verify
sentra snapshots                         # newest first; --json for scripting
sentra restore <snapshot-id> /tmp/out --dry-run   # preview, writes nothing
sentra restore <snapshot-id> /tmp/out --verify    # restore + re-check chunk hashes
sentra check                             # audit manifests, chunk refs, orphans, stale locks
sentra recovery-kit --out sentra-recovery-kit.md  # non-secret restore notes
πŸ€– Ask the agent
sentra agent advise-ignore ./Documents            # suggest .sentraignore patterns (read-only)
sentra agent scan --local-only --root ./Documents # heuristics only, no LLM
sentra agent scan --apply                          # review + apply recommendations interactively
πŸ”Œ Serve it to your AI (MCP)

sentra mcp runs a Model Context Protocol server on stdio, so Claude (or any MCP client) can work with your backups β€” metadata only, never file contents, and every mutation is two-phase: the client gets a plan and a single-use token, and nothing runs until the matching confirm_* call.

claude mcp add sentra -- sentra mcp

Tools: list_snapshots, snapshot_files, find, diff_snapshots, repo_stats, plus plan_backup/confirm_backup and plan_restore/confirm_restore. The passphrase must resolve non-interactively (keyring, SENTRA_PASSPHRASE, or --passphrase-file) β€” stdio belongs to the protocol.

The TUI carries its own assistant with the same boundary: ctrl+a opens a chat overlay (needs ANTHROPIC_API_KEY) whose actions compile into the exact flows the keyboard drives β€” a chat-requested backup raises the same confirm dialog you'd get pressing enter yourself.

The full walkthrough lives in docs/QUICKSTART.md.

The TUI

Bare sentra falls through to sentra ui. Where it lands depends on your state: no sentra.yaml β†’ first-run wizard, configured but locked β†’ unlock gate, otherwise the dashboard. The rail holds seven destinations β€” Dashboard, Backup, Schedules, Snapshots, Maintenance, Settings, Help β€” and the occasional jobs live one keypress inside them: restore and diff launch from a snapshot row, check/prune/sync/doctor from Maintenance, recovery-kit/ passphrase/setup from Settings. Backup is a three-step wizard: pick the folder, pick a schedule (one-shot, or hourly/daily/weekly/monthly with a time, weekday and editable policy name; a chosen cadence installs a named policy plus a launchd/systemd timer), confirm.

Handy keys (the status bar always shows what's live):

Key Action
↑ / ↓ Β· digits Move the nav rail Β· jump straight to a view
tab Toggle focus between the rail and the content pane
enter Β· esc Trigger the primary action Β· go back
ctrl+p Command palette
ctrl+a Assistant chat β€” ask questions, or say what to do (actions still confirm)
r Β· d (in Snapshots) Restore Β· diff the highlighted snapshot
enter Β· esc (in Backup) Next wizard step Β· back a step
enter Β· e Β· d (in Schedules) Drill into a job's files Β· edit Β· delete (policy + timer)
? Β· q Help Β· quit

Selection is carried by a ▍ glyph, not just color, and the neon strips cleanly under NO_COLOR, a pipe, or a 2-color terminal β€” the synthwave look is a dark-terminal flourish, never a legibility risk.

Commands

Command What it does
sentra ui Launch the full-screen TUI. Bare sentra is equivalent.
sentra local Dev flow: start local MinIO and open the wizard-prefilled TUI.
sentra setup Guided wizard for AWS/S3 config, bucket prep, and repo init.
sentra setup iam-policy Print non-secret AWS IAM JSON for a bucket/prefix.
sentra doctor Check config, AWS access, bucket settings, and repo health β€” read-only.
sentra init Non-interactively create sentra.yaml and the encrypted repo config.
sentra backup <path> Snapshot a directory now. --tag labels it. plan/apply for reviewed runs.
sentra snapshots List snapshots, newest first. --json for scripting.
sentra ls <snap> List a snapshot's tree: files, dirs, symlink targets.
sentra restore <snap> <dest> [path…] Restore a snapshot β€” or just the named files/subtrees. --dry-run previews; --verify validates output.
sentra diff <a> <b> Show added / removed / changed paths between two snapshots.
sentra check Audit manifests, chunk references, orphan blobs, and stale locks. --read-data re-downloads and re-hashes chunks.
sentra stats Dedup factor, logical vs stored bytes, per-snapshot unique footprint.
sentra pin / unpin Protect a snapshot from prune and deletion.
sentra prune Dry-run retention by default; --apply reclaims, --explain shows reasons.
sentra policy … Manage named backup policies (add/list/show/remove/run); removing a policy also uninstalls its OS timer.
sentra schedule … Install user-level OS schedules for named policies.
sentra password Rotate or forget the repository passphrase (passwd is an alias).
sentra sync --dst-config Replicate this repo to a clone destination (additive; --snapshot selects a subset).
sentra recovery-kit Export non-secret recovery notes and restore commands.
sentra agent advise-ignore Suggest first-run .sentraignore patterns without editing files.
sentra agent scan Heuristics + optional LLM. --local-only, --root, --categories, --apply.

Every subcommand resolves the passphrase in this order: --passphrase-file β†’ SENTRA_PASSPHRASE β†’ OS keyring (when passphrase.use_keyring: true) β†’ interactive prompt (TTY only). Keyring entries are scoped to the configured bucket and prefix, so multiple repos can safely share one bucket under different prefixes.

Configuration

Sentra looks for sentra.yaml in the current directory first, then falls back to ~/.config/sentra/sentra.yaml (honoring XDG_CONFIG_HOME). First-run setup writes the home location, so after setting up once you can run sentra from any directory. Pass --config to use a specific file; it must already exist (sentra setup --config <path> creates one).

sentra.yaml holds non-secret settings only. A .sentraignore at the walk root applies gitignore-style globs (a starter ships at .sentraignore.example). The Anthropic provider needs ANTHROPIC_API_KEY; without it every non-agent command still works and sentra agent scan returns a clear error.

repo:
  s3:
    bucket: my-backups            # required
    prefix: sentra/               # optional β€” lets multiple repos share a bucket
    region: us-west-2             # optional β€” falls back to the AWS SDK chain
    profile: default              # optional β€” AWS shared-credentials profile
    endpoint_url: ""              # optional β€” set for MinIO / LocalStack / R2 / Wasabi
    storage_class: ""             # optional β€” e.g. STANDARD_IA or GLACIER_IR

agent:
  provider: anthropic
  model: claude-sonnet-4-6
  max_findings_to_llm: 50         # cap on prompt size

backup:
  ignore_file: .sentraignore
  exclude_caches: true            # honor CACHEDIR.TAG
  concurrency: 0                  # 0 = auto; parallel file scan/upload workers
  max_upload_rate: ""             # optional throttle, e.g. 10MiB

ui:
  hide_splash: false              # skip the launch splash

notify:
  disable_desktop: false          # true silences the after-run desktop notification

retention:
  keep_last: 10
  keep_daily: 7
  keep_weekly: 4
  keep_monthly: 6

passphrase:
  use_keyring: false              # true means future commands read the OS keyring

policies:
  home:
    paths: ["~/Documents"]
    tags:  ["home"]
    schedule: { cadence: daily, at: "03:00" }
    after_backup: { check: true, prune: dry-run }   # prune: off | dry-run | apply
    hooks:                                          # optional, run via `sh -c`
      before: pg_dump mydb > ~/Documents/db.sql     # a failure aborts the run
      after: echo done                              # runs only after a fully successful run
      on_failure: say "backup failed"               # runs when any stage fails
      on_failure_webhook_env: SENTRA_ALERT_URL      # env var NAME holding a URL to POST to
Notifications and hooks

Every backup run announces its result on the desktop β€” Backup complete with the file count and new bytes, or Backup failed with the error β€” whether you ran it from the TUI, from sentra policy run, or the OS timer ran it at 3am with no terminal attached. It is on by default with nothing to set up; switch it off with the Desktop notifications toggle in Settings or notify.disable_desktop: true. macOS posts through osascript, Linux through notify-send; the first notification from a timer on macOS may ask you once to allow notifications from Script Editor. The ad-hoc sentra backup command stays quiet, since its result prints to the terminal you ran it in.

For anything beyond a notification, a policy's hooks run your own commands around the run, and on_failure_webhook_env names an environment variable whose URL receives a {policy, status, error} JSON POST on failure β€” only the variable's name goes in sentra.yaml, never the URL.

Security

Sentra is a backup tool, so it's worth being explicit about what the encryption protects β€” and what it doesn't. The threat model has the full write-up; the load-bearing invariants:

  • Encryption. New blobs use XChaCha20-Poly1305 with a per-blob 24-byte random nonce and the version byte bound as associated data. A nonce is never reused under a key, and the bucket never sees plaintext.
  • Content addressing. A chunk's key is the SHA-256 of its raw (decompressed) plaintext. Restore re-derives and checks it on read, so restore is exact-byte.
  • GC safety. GC computes its live set from the snapshots present in the store under the repo lock β€” never from a caller-supplied set β€” so a blob referenced by any present manifest is never reaped.
  • One repo lock. backup, GC, sync, passwd, and snapshot-apply serialize on an advisory meta/lock (atomic put-if-absent). Release is fail-closed.
  • Agent boundary. The LLM sees summaries only, never file contents or secret values; recommendations are read-only by default.

Protects: file contents, file paths, manifest metadata, snapshot tags. Leaks: object counts and approximate sizes (compress-then-encrypt), S3 access logs. Out of scope: forward secrecy across passphrase compromise, post-quantum key strength.

Architecture

See docs/architecture.md for the storage model, the agent loop, and Mermaid diagrams of the backup, restore, and agent scan flows. In one breath: a snapshot is an encrypted manifest of SHA-256 chunk hashes; chunks are FastCDC-split, zstd-compressed, then sealed; dedup falls out of content addressing; and both the CLI and TUI drive the same core in internal/repo.

Development

Go 1.27+ is required, and the codebase is internal/-only (no public API in v1). Prefer just:

just build        # β†’ bin/sentra
just local        # build + open the TUI against local MinIO (the easy path)
just check        # build, race tests, vet, lint, vuln, tidy/gofmt/diff checks
just test         # go test -race with coverage
just integration  # testcontainers + MinIO (needs Docker; Linux)

The vendored FastCDC is a separate module β€” test it with go test ./third_party/fastcdc-go/... when you touch chunking. CI enforces go mod tidy -diff, gofmt over cmd/ and internal/, go vet, go test -race, the FastCDC module tests, golangci-lint, the integration suite (testcontainers + MinIO), and an every-commit-builds job that checks out and compiles each pushed commit in isolation β€” a green run vouches for the whole series, not just the tip.

Releasing

Push a v* tag to trigger release.yml: goreleaser cross-compiles linux/darwin Γ— amd64/arm64 archives, writes a SHA-256 checksums.txt, signs it with cosign keyless (GitHub OIDC), updates the Homebrew tap, and attaches a syft SBOM per archive. The Homebrew step publishes only when the HOMEBREW_TAP_TOKEN secret (contents: write on markgustetic/homebrew-tap) is present β€” without it the cask is skipped and everything else still ships. GITHUB_TOKEN is provided automatically.

License

MIT.

✦ built to keep your bytes safe, and to look good doing it ✦

Directories ΒΆ

Path Synopsis
cmd
sentra command
internal
agent
Package agent stitches the heuristic registry, LLM provider, and read-only tool runner into a single Scan operation.
Package agent stitches the heuristic registry, LLM provider, and read-only tool runner into a single Scan operation.
agent/action
Package action defines the vocabulary of remediations the Sentra agent can recommend, and a registry that maps each verb to a concrete side-effect.
Package action defines the vocabulary of remediations the Sentra agent can recommend, and a registry that maps each verb to a concrete side-effect.
agent/heuristics
Package heuristics implements local rules that scan a walked tree, snapshot history, and live-blob set, producing structured Finding records the LLM agent can later triage.
Package heuristics implements local rules that scan a walked tree, snapshot history, and live-blob set, producing structured Finding records the LLM agent can later triage.
agent/llm
Package llm defines the provider abstraction the Sentra agent uses to talk to a language model.
Package llm defines the provider abstraction the Sentra agent uses to talk to a language model.
agent/tools
Package tools implements the read-only investigation toolset the Sentra agent advertises to the LLM.
Package tools implements the read-only investigation toolset the Sentra agent advertises to the LLM.
atomicfile
Package atomicfile replaces a file's contents so that readers only ever observe the old file or the complete new one.
Package atomicfile replaces a file's contents so that readers only ever observe the old file or the complete new one.
blobstore
Package blobstore defines the Store interface used to persist encrypted blobs (chunks, manifests, indexes, config) for a sentra repository, plus implementations against in-memory storage and S3.
Package blobstore defines the Store interface used to persist encrypted blobs (chunks, manifests, indexes, config) for a sentra repository, plus implementations against in-memory storage and S3.
chunker
Package chunker provides content-defined chunking and compression primitives for Sentra's content-addressed blob layer.
Package chunker provides content-defined chunking and compression primitives for Sentra's content-addressed blob layer.
cli
config
Package config holds the parsed sentra.yaml document and the passphrase resolver that the CLI commands use to construct a *Repo.
Package config holds the parsed sentra.yaml document and the passphrase resolver that the CLI commands use to construct a *Repo.
crypto
Package crypto provides the symmetric primitives used by sentra: Argon2id passphrase-to-KEK derivation and versioned AEAD blob sealing.
Package crypto provides the symmetric primitives used by sentra: Argon2id passphrase-to-KEK derivation and versioned AEAD blob sealing.
diag
Package diag holds read-only environment diagnostics shared by the `sentra doctor` CLI command and the TUI Doctor view.
Package diag holds read-only environment diagnostics shared by the `sentra doctor` CLI command and the TUI Doctor view.
mcpserver
Package mcpserver exposes an opened Sentra repository as a Model Context Protocol server, so outside agents (Claude, editors, anything speaking MCP) can query snapshots and drive confirm-gated operations within the same guardrails the CLI and TUI enforce.
Package mcpserver exposes an opened Sentra repository as a Model Context Protocol server, so outside agents (Claude, editors, anything speaking MCP) can query snapshots and drive confirm-gated operations within the same guardrails the CLI and TUI enforce.
notify
Package notify posts desktop notifications.
Package notify posts desktop notifications.
policy
Package policy validates Sentra's named backup policy configuration.
Package policy validates Sentra's named backup policy configuration.
progress
Package progress defines the byte-counting reporter interface that long-running repo operations (CreateSnapshot, Restore, BackupPlan) surface progress through.
Package progress defines the byte-counting reporter interface that long-running repo operations (CreateSnapshot, Restore, BackupPlan) surface progress through.
recoverykit
Package recoverykit builds and renders a Sentra "recovery kit": a non-secret record of a repository's identity, storage location, and latest snapshot, plus copyable check/list/restore commands.
Package recoverykit builds and renders a Sentra "recovery kit": a non-secret record of a repository's identity, storage location, and latest snapshot, plus copyable check/list/restore commands.
repo
Package repo is the integration layer that stitches the crypto, chunker, walker, and blobstore packages into a working snapshot lifecycle: init / open the repository, create snapshots from a directory tree, list them, and restore a snapshot back to disk.
Package repo is the integration layer that stitches the crypto, chunker, walker, and blobstore packages into a working snapshot lifecycle: init / open the repository, create snapshots from a directory tree, list them, and restore a snapshot back to disk.
scheduler
Package scheduler renders and installs user-level OS scheduler entries (launchd plists on darwin, systemd user units on linux) that run `sentra policy run`.
Package scheduler renders and installs user-level OS scheduler entries (launchd plists on darwin, systemd user units on linux) that run `sentra policy run`.
tui
Package tui is the Bubbletea-based dashboard launched by `sentra ui` (and by bare `sentra` with no subcommand).
Package tui is the Bubbletea-based dashboard launched by `sentra ui` (and by bare `sentra` with no subcommand).
ui
Package ui provides the shared Charm-expressive theme used by both inline-mode CLI output and the TUI.
Package ui provides the shared Charm-expressive theme used by both inline-mode CLI output and the TUI.
walker
Package walker provides filesystem traversal with .sentraignore support and a concurrent stat pipeline.
Package walker provides filesystem traversal with .sentraignore support and a concurrent stat pipeline.
third_party
fastcdc-go
Package fastcdc is a Go implementation of the FastCDC content defined chunking algorithm.
Package fastcdc is a Go implementation of the FastCDC content defined chunking algorithm.

Jump to

Keyboard shortcuts

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