Skip to main content

EXTENSIONS

Selection
18 results
label:self-hosted

Traefik

@sntxrr/traefik · v2026.10.25.1

Keep Traefik reverse proxies, the images beside them (CrowdSec and others) and every plugin they load current, through pull requests to the repository each proxy is deployed from -- never by touching a running proxy. `inspect` reads the live proxy over SSH or its API: running version, router and middleware status, and whether plugins failed to load since this start. `check` compares the repository's pins with what is running and with upstream releases, and reports what is behind plus how the deployment is exposed: plugins downloaded from the catalog at every start (a failed download disables every plugin, and with them every router that uses one), pins that never deployed, an insecure API published on a host port, routers that are down. `bump`, dry-run by default, opens one pull request per component: an image tag, a remote plugin's version, or a re-vendored local plugin with its commit and tarball checksum recorded. It defers to an open Dependabot PR that already reaches the target, names one that falls short as superseded, refuses major upgrades unless asked, and refuses deployments that still download plugins at startup unless asked. Plugin middleware configuration, which can carry a CrowdSec LAPI key, is never read into a resource, and neither is a plugin middleware's error text or a partial API response; the container's environment is never read. Unknown is never current: health is null while routers or the plugin-failure log could not be read, and an uncomparable version is a finding.

upd Oct 255 pullsA100/100

Shoko

@magistr/shoko · v2026.10.25.10

Shoko anime metadata server API — series, episodes, files, and metadata.

upd Oct 2540 pullsA100/100

Seanime

@magistr/seanime · v2026.10.25.10

Seanime self-hosted anime server API — library, search, downloads, playback.

upd Oct 2536 pullsA100/100

Ryot

@magistr/ryot · v2026.10.25.10

Import a film history into a self-hosted Ryot

upd Oct 2515 pullsA100/100

Headphones

@magistr/headphones · v2026.10.25.10

Headphones music-download automation API for swamp — manage artists, albums,

upd Oct 2536 pullsA100/100

Gonic

@magistr/gonic · v2026.10.25.10

Gonic Subsonic-compatible music server API for swamp — browse, search,

upd Oct 2540 pullsA100/100

Dawarich

@magistr/dawarich · v2026.10.25.10

Dawarich self-hosted location-tracking API for swamp — read points, visits,

upd Oct 2543 pullsA100/100

Uptime Kuma

@sntxrr/uptime-kuma · v2026.10.25.1

Read-only Uptime Kuma monitor history for triage: the last N heartbeats of one monitor -- status, time, message, ping -- plus a summary of the current status, since when, and how many times it changed in the window. Kuma has no REST endpoint for heartbeat history, and its socket.io API needs the instance's only kind of login, an administrator, so any credential that can read history can also delete monitors and read notifier secrets. This model instead reads kuma.db over SSH with the host's python3, opening the database mode=ro with PRAGMA query_only=ON so SQLite itself refuses any write, and selects named columns from the monitor and heartbeat tables only: never notifier settings, credentials, monitor URLs or hostnames, or heartbeat response bodies. Monitors are found by id or by name (exact, else a unique case-insensitive substring; ambiguity is an error listing the candidates). It needs no Kuma login, never enters the container, never copies the database off the host, and has no write method.

upd Oct 2513 pullsA100/100

Docker Ps

@sntxrr/docker-ps · v2026.10.25.1

A read-only container listing of a Docker host over SSH, narrow enough to hand to an unattended triage agent. It answers the first question an alert usually raises -- what is running on that host, and which container holds that port -- with name, image, state, status, published ports and creation time per container. It runs `docker ps` with an explicit, per-field `--format` template and rebuilds each row from those fields alone, so no environment variable and no label value ever leaves the host: `docker inspect` returns every container's environment, which is where compose files keep database passwords and API tokens, and `docker ps --format '{{json .}}'` includes the Labels field. The type has exactly one method and no free-form command or format argument, so a model instance exposes no write verb at all. Host key checking stays on by default.

upd Oct 2513 pullsA100/100

Log Tail

@sntxrr/log-tail · v2026.10.25.1

Read the last lines of a log chosen by NAME from an allowlist fixed in the model definition, with secret values redacted. Built for an alert-triage agent that has no shell: an alert names a log, the cause is usually one line near its end, and the alternatives are a human tailing it for the agent or a general file-read tool that can read anything. The caller passes a name, never a path; the name-to-path map lives in the definition, where only its owner can change it. A name is matched with Object.hasOwn and a name that is not name-shaped is never echoed, because `--input name=@file` would otherwise turn a refusal into a read. The configured path must be absolute, normalised, a regular file, not a symlink and equal to its own realpath, and the opened file's device and inode must match the lstat taken before the open, so a symlink swapped in between is refused rather than followed. Output is capped at 200 lines. Redaction drops values and keeps names (`password=[REDACTED]`) across key=value, JSON, YAML, CLI flags, URL userinfo, Authorization headers and bare token shapes, and fails closed: a line mentioning a password manager CLI or a private key is withheld whole, a line still credential-shaped after redaction is withheld whole, and an error in redaction fails the method. Both methods are read-only.

upd Oct 2513 pullsA100/100

Docker Reclaim

@sntxrr/docker-reclaim · v2026.10.24.2

Measure what a Docker host's disk is actually spent on, plan what can be freed without destroying a rollback target, and free it. The command people reach for is the wrong one: `docker image prune` — dangling or `-a` — never touches the BUILD CACHE, and on a host that builds its own images the build cache is usually most of the footprint. On the host this was written against it was 59.5GB of a 77GB reclaim, which no amount of image pruning would have recovered. Three behaviours are deliberate because each one corresponds to a way the obvious command does damage or lies. `docker image prune -a` removes every image no container references, which is precisely the set of previous versions a rollback needs; this model instead protects the newest `keepVersions` tags of each repository and removes specific image IDs, so reclaiming space does not quietly cost you the ability to go back. `docker builder prune -af` deletes the cache that makes the next build fast, and cache that is minutes old is the most valuable cache there is; pruning is therefore age-filtered via `--filter until=`, so a scheduled run takes cold layers and leaves the working set. The prune runs with `-a` and the age filter as its guard, because without `-a` BuildKit leaves out records shared with the image store, and on a Docker engine an age-filtered prune then frees almost nothing. The prune names the engine's own builder (`--builder "$(docker context show)"`) rather than whichever buildx builder is current, and an `engine-builder` pre-flight check refuses `reclaim` unless that builder uses the docker driver, so cache is never pruned on an engine the model did not measure. And Docker reports sizes as rounded human strings where 1000 versus 1024 is a real 7% at terabyte scale, so parsing is explicit and unit-aware and the freed figure is measured by observing free space before and after rather than by summing estimates. Each method writes its own data instance — `usage`, `plan`, `reclaim` — so an expression always gets the schema it expects rather than whichever method ran last. `observe` and `plan` are read-only and safe to schedule at any frequency; `reclaim` is dry-run unless passed `apply: true`, and even then never removes an image that any container references, running or stopped. Host key checking is left ON by default — `StrictHostKeyChecking=no` is available but is not the default, because a model whose entire purpose is running destructive commands as a privileged user is the last place to accept an unverified host key. For a Docker engine on the machine swamp itself runs on, such as Docker Desktop on a workstation, set `sshHost: local`: each command runs through `sh -c` as the invoking user, with no SSH server required, and the commands and protections are identical to the SSH path.

upd Oct 2484 pullsA100/100

Swamp Version

@sntxrr/swamp-version · v2026.10.14.1

Read the swamp version a host or container is running and report how far it has drifted behind the published channel. Read-only — it never updates, installs, or restarts anything; it tells you a newer build exists and stops there. Fills the gap `swamp update --check` leaves: that answers for the binary invoking it, on the platform invoking it, which is no help when the install you care about is a pinned binary inside a container on another host. `sync` records what a target reports about itself — its version and, via `uname`, the artifact platform it runs on. `drift` resolves the newest build published on a channel for THAT platform and reports status (`current`/`behind`/`ahead`) plus the lag in hours. `repoDrift` covers the second, independent axis a `swamp serve` install goes stale on — the git checkout it serves. A container can run the newest published binary while serving a branch it last fetched weeks ago, because a serve entrypoint typically fetches at boot only; `drift` reports `current` throughout and so does every healthcheck. It fetches before comparing, which is load-bearing rather than tidy: a checkout's own `origin/<ref>` is frozen at its last boot, so trusting it reports a badly stale target as up to date. It then reports the exact number of commits behind — enumerable here, unlike the binary axis, because git has the list — the lag in hours, and `current`/`behind`/`ahead`/`diverged`, keeping `diverged` distinct because the fix for `behind` is a restart and a restart hard-resets, destroying the very commits that make a checkout diverged. Targets are reached three ways: the local binary, `docker exec` (optionally through a named docker context, so one host can check a container on another), or SSH with BatchMode so an unattended run fails fast instead of hanging on a password prompt. The channel is resolved by a single HEAD against the `stable` alias, reading the resolved version out of its website-redirect metadata — one request rather than the ~90 MB the archive weighs — and the same pass verifies the platform-specific archive is actually fetchable, which is the precondition for pinning a rebuild to it. Versions are compared numerically because the build ordinal in `YYYYMMDD.HHMMSS.N` is not zero-padded: as strings `20260808.001107.10` sorts below `...9`, so a string compare reports a target one build behind as up to date the day a tenth build ships. `hoursBehind` is derived from the timestamps embedded in each version and is documented as a lag, not a count of missed builds — swamp publishes no release list, so the builds in between cannot be enumerated and this extension does not pretend otherwise. An unreachable target, an unparseable version at either end, a channel alias that answers without its redirect header, and a resolved archive that 404s are all raised as errors rather than folded into a reassuring `current`.

upd Oct 1443 pullsA100/100

Openwebui

@sntxrr/openwebui · v2026.10.14.1

Read a running OpenWebUI instance and report how far its version has drifted behind upstream. Both methods are strictly read-only — this extension never upgrades the instance, edits its settings, manages users, or touches the container; it tells you an update is available and stops there. `sync` records what the instance reports about itself: version plus the feature flags that decide what automation can reach it, including `enable_api_keys`, which when false blocks every token-authenticated integration and cannot be worked around with any credential — reported as `null` rather than `false` when the instance withholds it, which OpenWebUI has done for unauthenticated callers since v0.9.6, because absent is not the same as off. `drift` compares the running version against the repo's published GitHub releases and reports status (`current`/`behind`/`ahead`), how many releases were missed, and which ones. Needs no credentials at all: both endpoints it uses answer before login. Versions are compared numerically because OpenWebUI's break lexical ordering in both directions — `0.8.12` sorts above `0.11.0` and below `0.8.9` as strings — so a string compare reports an instance eleven releases behind as up to date. An exhausted GitHub rate limit, a missing repo, and an unparseable running version are all raised as errors rather than folded into a reassuring `current`, and a release page that fills up before reaching the running version is reported as `truncated` rather than passed off as a total.

upd Oct 1428 pullsA100/100

Openobserve

@sntxrr/openobserve · v2026.10.14.1

Operate a self-hosted OpenObserve instance from swamp, and decide safely whether a newer upstream release should be rolled out to it. OpenObserve publishes release candidates into the same tag namespace as stable releases -- on 2026-08-29 the newest tag was v1.0.0-rc1, published eleven days AFTER the newest stable v0.92.2 -- so anything that reads the tag list and sorts it pins an RC. That is worse here than for a stateless app: OpenObserve is a log store, and an RC that migrates the on-disk schema is not undone by re-pinning the previous tag, because the previous binary can no longer read what the new one wrote. The `check_update` method reads GitHub *releases* rather than tags, excludes drafts and prereleases (by the GitHub flag OR a semver prerelease suffix, since the flag is hand-set and occasionally wrong), applies real semver precedence so a prerelease sorts before its own release, and reports the newer prereleases it skipped so a pending major stays visible without being auto-applied. It then confirms the candidate tag actually resolves in the registry before offering the update -- a GitHub release and a pushed image are separate events, and proposing a bump whose image does not exist yet fails the deploy at `compose pull`, after the running container has already been stopped. The `health` method probes /healthz, treating a refused connection as a health result rather than a model error so a down instance is distinguishable from a broken check.

upd Oct 1464 pullsA100/100

Nextcloud

@sntxrr/nextcloud · v2026.10.14.1

Health, version drift, setup checks, app updates and compatibility, verified backups and occ maintenance for a self-hosted Nextcloud. `sync` reads status.php and, with a serverinfo token, storage and user statistics; `drift` compares the running version against stable GitHub releases and reports the patch target and the next major separately, because Nextcloud refuses to skip a major and the newest release is often not a legal target; `setupchecks` records the admin overview's warnings as data; `talkBots` flags a Nextcloud Talk bot that is not enabled, whose webhook delivery errors rose since the last reading (Talk drops a message whose delivery fails and never resets the count, so the rise is the signal, not the total), or that is expected and missing; `apps` lists app store updates and, given a targetVersion, which enabled store apps have no release for it. `backup` dumps MySQL/MariaDB and archives the web-root directories an upgrade changes onto the machine swamp runs on, then reads both back (dump completion line and table count, tar header checksums and gzip CRC) and renames a backup that fails `.FAILED`; the database password stays in the container's environment and never reaches a command line. `maintenance`, `dbRepair`, `updateApps` and `backup` change state and are dry runs unless apply=true; each apply path re-reads the state afterwards and fails if the change did not take. occ runs through `docker exec`, locally or on a host over SSH with BatchMode. Four behaviours shape the implementation. Nextcloud 34 enforces trusted_domains on status.php and answers HTTP 400/code 15 when probed by IP, and Deno's fetch silently drops a Host header override, so baseUrl must be a trusted name and the error is named rather than reported as a bare 400. `occ setupchecks` exits 1 whenever any check warns, so exit 1 with a JSON report is data, not failure. Prerelease tags are spelled inconsistently (`rc2` and `RC2` both exist), so any suffixed tag is excluded, not parsed. And updates.nextcloud.com answers an empty 200 both for `nothing to offer` and for a query it did not understand, so it is not used. A failure to measure is raised, never reported as healthy, current or `no updates`.

upd Oct 1469 pullsA100/100

N8n

@sntxrr/n8n · v2026.10.14.1

Read a running n8n deployment and report how far its pinned version has drifted behind the channel n8n itself calls stable, and which active workflows have no usable error workflow attached. All three methods are strictly read-only — this extension never upgrades n8n, edits a workflow, touches a credential, or restarts a container; it tells you an update exists and stops there. `audit_error_workflows` takes an optional n8n API key (used by no other method), because n8n has no instance-wide default error workflow and only the authenticated public API discloses each workflow's `settings.errorWorkflow`; it flags missing or wrong handlers and a handler that is inactive or archived, and never attaches one. `drift` takes the running version as an argument rather than reading it, because n8n does not disclose one: its `/rest/settings` answers 200 unauthenticated but with `settingsMode: public`, a reduced payload carrying no version field at all, and `versionCli` reaches authenticated callers only — so the version comes from the pinned image tag on the host, which is what the deployment actually is rather than what a process predating the current pin believes itself to be. The upgrade target is npm's dist-tag, never the newest published release: n8n ships its in-progress minor into the same GitHub release namespace flagged `prerelease: true` and promotes that line later, so on 2026-09-05 the newest release was 2.38.3 while stable was 2.37.10, and the 2.37 line had itself been prerelease through 2.37.6. GitHub releases are still read, but only to enumerate the stable releases that were missed and to link the notes, since the `prerelease` flag is the historical record of which line was stable when and dist-tags do not retain it. Image existence is verified against `registry-1.docker.io` rather than the `docker.n8n.io` mirror the pin names: that mirror 404s its own token endpoint, delegates auth to Docker Hub, and then answers 429 to every manifest request for tags that exist and tags that do not alike, so it cannot return a usable answer — and a 429 is raised as indeterminate rather than folded into `absent`, which would suppress every update forever while the check looked healthy. An exhausted GitHub rate limit, an unreachable registry, and an unparseable running version are all raised as errors rather than reported as a reassuring `current`.

upd Oct 1465 pullsA100/100

Backrest

@sntxrr/backrest · v2026.10.14.1

Keep a Backrest server's snapshot index current for restic repositories it does not itself back up, and report how fresh each one is. Backrest indexes snapshots only for repositories it runs backups for; one that is merely configured — the normal shape when restic runs from systemd timers on each host and Backrest is only the console — is never indexed at all, and reports no error while doing so. The repository simply stays empty in the UI, which reads as `no backups` for a host whose backups are in fact current. `sync` reads the operation log and reports each repository's newest indexed snapshot. `reindex` triggers Backrest's own TASK_INDEX_SNAPSHOTS for every configured repository, waits for them to appear, and reports the same shape; it reads repositories and never creates, forgets or prunes a snapshot, so it is safe to schedule. Four server behaviours shape the implementation because each one silently produces a wrong answer if ignored. GetOperations' repoId selector does not filter — a selector matching nothing returns the ENTIRE operation log rather than an empty set, so a per-repository query makes every repository report the whole fleet's totals; operations are therefore fetched once and grouped on each operation's own repoId. A failed index task leaves no trace in the operation log, only successes being recorded, so a repository the server cannot read is indistinguishable through the API from one whose task has not run yet — both are reported as `unindexed` with the reason named as the server log rather than invented. The task queue is serial, so triggering N repositories enqueues N tasks behind each other and one whose credentials were revoked does not fail fast but retries with exponential backoff for six minutes or more while everything behind it waits, which is why the wait is a deadline over the whole set rather than a per-task timeout. And a repository with no indexed snapshot at all is a different failure from one whose snapshots have stopped advancing — the first is a credential this server holds that no longer exists, the second is a backup that has stopped running — so they are counted separately as `unindexed` and `stale` instead of being folded into one unhelpful total. Because it reaches repositories through the server's own stored credentials rather than the ones the backup hosts use, disagreement with a host-side view is informative: it means exactly one of the two credential sets has gone bad.

upd Oct 1470 pullsA100/100

Sops Age

@zocc/sops-age · v2026.05.22.1

SOPS + age vault for swamp: encrypt secrets at rest with AES-256-GCM via Mozilla SOPS and age. Zero network dependency — fully local, file-based. Works with existing SOPS workflows and zo.space secrets dashboards.

upd May 22624 pullsA93/100