Stegstr
For AI agents and scripts

Use Stegstr without a human in the loop

Three programmatic surfaces, all calling the same code the app uses. Machine-readable summaries of this page live at /llms.txt and /agents.txt.

Pick a surface

SurfaceNeedsHiding methodsBest for
Node CLI dist-cli/stegstr.mjsNode 18+, a bare clone. No install, no compiler.Robust (survives resizing)Sandboxes without network, quick embeds, capacity checks
Rust CLI stegstr-cliRust toolchain to build onceQIM (platform-targeted JPEG), Dot (PNG); reads all formatsJSON contracts, exit codes, calibrating a real channel, MCP
MCP server stegstr-cli mcpSame binaryas aboveTool use from an MCP client
window.stegstrThe running app or web versionRobustBrowser automation, devtools, in-page scripting

Node CLI

git clone https://github.com/brunkstr/Stegstr.git && cd Stegstr
node dist-cli/stegstr.mjs selftest --json
node dist-cli/stegstr.mjs modes --json
node dist-cli/stegstr.mjs capacity cover.jpg --mode standard --json
node dist-cli/stegstr.mjs embed cover.jpg -o out.jpg --payload "hello" --mode standard --json
node dist-cli/stegstr.mjs embed cover.jpg -o out.jpg --payload-base64 <b64> --json
node dist-cli/stegstr.mjs detect out.jpg --json
ModePayloadMinimum edgeUse
locator48 bytes320 pxA pointer (event id + key); the content itself syncs over relays. Most robust.
standard163 bytes384 pxA short note carried entirely inside the image. Default.
bulk1,217 bytes960 pxLossless channels only: "send as file", email, disk.

Exit codes: 0 success, 1 nothing found, 2 bad usage. embed decodes its own output before reporting success, so a zero exit means the file carries the payload. Rotation and crops beyond about two percent per edge are not survived; use a detailed photo, not a flat graphic.

Rust CLI

cd Stegstr/src-tauri && cargo build --release --bin stegstr-cli
stegstr-cli detect image.jpg --json                       # decode + decrypt → Nostr bundle JSON
stegstr-cli decode image.jpg --json                       # raw payload, any format auto-detected
stegstr-cli embed cover.jpg -o out.jpg --payload "hello" --robust --json
stegstr-cli embed cover.png -o out.png --payload @bundle.json --encrypt --json
stegstr-cli post "hello from an agent" --output bundle.json --json
stegstr-cli post "hello" --ref K7M2QX --json                   # carries a publicity-contest referral code
stegstr-cli calibrate --sent original.jpg --received returned.jpg --name whatsapp --json

--json emits exactly one JSON object on stdout; schemas are committed under schema/cli/. Exit codes: 0 success, 1 usage or unclassified error, 2 capacity exceeded, 3 no payload found, 4 decryption failure, 5 malformed input. The CLI never prompts.

MCP server

Tools: embed, decode, detect, calibrate, each with a typed input schema, returning the same JSON as the matching CLI command. Client configuration:

{ "mcpServers": { "stegstr": { "command": "/path/to/stegstr-cli", "args": ["mcp"] } } }

In the running app: window.stegstr

const api = window.stegstr;
api.modes();                                    // [{ mode, capacityBytes, minEdge, title, detail }]
await api.capacity(coverBlob, "standard");      // { capacityBytes, width, height, usable, minEdge }
const jpeg = await api.encode(coverBlob, "hello", "standard");   // Blob (JPEG)
await api.decode(jpeg);                          // "hello" | null
await api.decodeDetailed(jpeg);                  // { ok, payload, mode, error }

Available in the desktop app and at stegstr.com/app. The web version embeds and detects only; relay publishing is desktop-only.

Formats

Relays and privacy

The desktop app publishes to wss://relay.stegstr.com by default when Network is on, with public relays as optional secondaries; the list is fetched from https://stegstr.com/config/relay.json. Network is off by default and in local mode nothing is sent. Media uploads (profile pictures, attachments) go to nostr.build, signed with the user's key, and are stored unencrypted. Details: privacy.

Adding a hiding method

Methods are modules behind a registry. The contract and the verification bar are in docs/codecs.md in the repository; a new method is a pull request, not a fork.