# Stegstr > Stegstr hides encrypted messages and Nostr posts inside ordinary JPEG photos so they survive the recompression and resizing that WhatsApp, Telegram and Instagram apply. Free, MIT-licensed, no account. Web version, desktop app (macOS/Windows/Linux), two command-line tools, an MCP server, and an in-app scripting API. Source: https://github.com/brunkstr/Stegstr ## Fastest path (no install, Node 18+) git clone https://github.com/brunkstr/Stegstr.git && cd Stegstr node dist-cli/stegstr.mjs embed cover.jpg -o out.jpg --payload "hello" --json node dist-cli/stegstr.mjs detect out.jpg --json Commands: embed, detect, capacity, modes, selftest. Every command takes --json. Exit codes: 0 success, 1 nothing found, 2 bad usage. embed verifies its own output before exit 0. Modes: locator (48 B, most robust, pointer resolved over relays), standard (163 B, default), bulk (1,217 B, lossless channels only). Minimum short edge: 320 / 384 / 960 px. Use detailed photos; flat graphics carry little. ## Rust CLI and MCP server (build once: cd src-tauri && cargo build --release --bin stegstr-cli) stegstr-cli detect image.jpg --json # decode + decrypt -> {"version":1,"events":[...]} stegstr-cli decode image.jpg --json # raw payload, format auto-detected stegstr-cli embed cover.jpg -o out.jpg --payload "hello" --robust --json stegstr-cli post "text" --output bundle.json --json stegstr-cli calibrate --sent a.jpg --received b.jpg --name whatsapp --json stegstr-cli mcp # MCP over stdio: tools embed, decode, detect, calibrate --json emits exactly one JSON object; schemas in schema/cli/. Exit codes: 0 ok, 1 usage/other, 2 capacity exceeded, 3 no payload, 4 decryption failed, 5 malformed input. Never prompts. MCP client config: {"mcpServers":{"stegstr":{"command":"/path/to/stegstr-cli","args":["mcp"]}}} ## In the app or the web version: window.stegstr modes(); capacity(blob, mode); encode(blob, payloadTextOrBytes, mode) -> JPEG Blob; decode(blob) -> string|null; decodeDetailed(blob) ## Facts an agent should know - Hiding methods: robust (default; survives recompression AND resizing), qim (JPEG, platform-targeted), dot (PNG, lossless, largest capacity, does not survive recompression). Detect tries all of them and verifies. - Not survived: rotation, crops beyond ~2% per edge, screenshots. - Payloads are AES-256-GCM encrypted; decrypted payload is a Nostr bundle {"version":1,"events":[NIP-01 events]} (schema/bundle.schema.json). - Default relay when Network is on: wss://relay.stegstr.com (public relays optional). Network is off by default; local mode sends nothing. Relay list: https://stegstr.com/config/relay.json - Media uploads (profile pictures, attachments) go to nostr.build, NIP-98 signed, stored unencrypted. - Web version (https://stegstr.com/app/) embeds and detects only; relay publishing is desktop-only. - Adding a hiding method: docs/codecs.md in the repository (registry + verification bar). ## Pages - https://stegstr.com/wiki/for-agents.html — full agent guide - https://stegstr.com/wiki/cli.html — CLI reference - https://stegstr.com/downloads.html — desktop builds with SHA256SUMS - https://stegstr.com/privacy.html — relay and upload privacy - https://stegstr.com/wiki/lightning.html — Lightning via Nostr Wallet Connect (Settings → Lightning wallet), notes carry ["bolt11", invoice] and ["cashu", token] tags (also recognised inline in content); Zap pays the author's lud16; Cashu tokens can be checked (NUT-07) and redeemed into the connected wallet (mint melt) - https://stegstr.com/leaderboard/ — the contest this app came from - https://stegstr.com/publicity/ — publicity contest: referral links stegstr.com/r/CODE, scored on real use of Stegstr on relay.stegstr.com by identities arriving through a link (formula unpublished); the app and `stegstr-cli post --ref CODE` add the tag ["r","https://stegstr.com/r/CODE"]