{"id":44728166,"url":"https://github.com/jftuga/mtool","last_synced_at":"2026-02-15T18:02:39.961Z","repository":{"id":338556797,"uuid":"1158276827","full_name":"jftuga/mtool","owner":"jftuga","description":"Swiss army knife CLI utility written in Go, using exclusively standard library packages","archived":false,"fork":false,"pushed_at":"2026-02-15T04:59:40.000Z","size":35,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-15T11:54:13.079Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jftuga.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-15T04:41:52.000Z","updated_at":"2026-02-15T04:41:56.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jftuga/mtool","commit_stats":null,"previous_names":["jftuga/mtool"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/jftuga/mtool","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jftuga%2Fmtool","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jftuga%2Fmtool/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jftuga%2Fmtool/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jftuga%2Fmtool/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jftuga","download_url":"https://codeload.github.com/jftuga/mtool/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jftuga%2Fmtool/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29486053,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-15T15:33:17.885Z","status":"ssl_error","status_checked_at":"2026-02-15T15:32:53.698Z","response_time":118,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-02-15T18:02:39.329Z","updated_at":"2026-02-15T18:02:39.928Z","avatar_url":"https://github.com/jftuga.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# mtool (multi-tool)\n\n![Code Base: AI Vibes](https://img.shields.io/badge/Code%20Base-AI%20Vibes%20%F0%9F%A4%A0-blue)\n\n`mtool` is a Swiss army knife CLI utility written in Go, using exclusively standard library packages.\n\n## Motivation\n\nThe goal of this project was to write a practical CLI tool in Go that incorporates as many standard library modules as feasible without any third-party dependencies. Rather than contriving artificial usage, each package is pulled in naturally through a set of subcommands that solve real, everyday tasks: serving files, fetching URLs, hashing data, inspecting TLS certificates, benchmarking endpoints, converting images and more.\n\nThe result is a single-binary multi-tool that leverages **94 unique standard library packages**.\n\n## Disclaimer\n\nThis software was developed with the assistance of AI (Anthropic Claude). It is\nprovided \"as is\", without warranty of any kind, express or implied. **Use at your\nown risk.** The author assumes no liability for any damages arising from its use.\n\n## Installation\n\n**Homebrew**\n```bash\nbrew tap jftuga/homebrew-tap\nbrew update\nbrew install jftuga/tap/mtool\n```\n\n**Source**\n```bash\ngit clone https://github.com/jftuga/mtool.git\ncd mtool\ngo build -ldflags=\"-s -w\" -o mtool\n```\n\nRequires Go 1.26 or later. No third-party dependencies.\n\n## Usage\n\n```\nmtool \u003ccommand\u003e [options]\n```\n\nRun `mtool \u003ccommand\u003e -h` for help on any subcommand.\n\n## Subcommands\n\n| Command | Description | Key stdlib packages |\n|---|---|---|\n| `serve` | Start an HTTP/HTTPS file server with directory listing, optional gzip, and self-signed TLS | `net/http`, `html/template`, `compress/gzip`, `compress/flate`, `embed`, `io/fs`, `mime`, `os/signal`, `context`, `syscall`, `crypto/ecdsa`, `crypto/elliptic`, `crypto/x509/pkix` |\n| `fetch` | Fetch a URL and display response details, with cookie support and timing trace | `net/http`, `net/http/httputil`, `net/http/httptrace`, `net/http/cookiejar`, `net/url` |\n| `hash` | Compute hashes of files or stdin | `crypto/md5`, `crypto/sha1`, `crypto/sha256`, `crypto/sha512`, `crypto/sha3`, `crypto/hmac`, `hash`, `hash/adler32`, `hash/crc32`, `hash/crc64`, `hash/fnv`, `encoding/hex` |\n| `encode` | Encode data (base64, base32, hex, ascii85, URL, quoted-printable, UTF-16) | `encoding/base64`, `encoding/base32`, `encoding/ascii85`, `encoding/hex`, `net/url`, `mime/quotedprintable`, `unicode/utf16` |\n| `decode` | Decode data (base64, base32, hex, ascii85, URL, quoted-printable, UTF-16) | `encoding/base64`, `encoding/base32`, `encoding/ascii85`, `encoding/hex`, `net/url`, `mime/quotedprintable`, `unicode/utf16` |\n| `info` | Display system and network information in multiple formats | `runtime`, `runtime/debug`, `encoding/json`, `encoding/xml`, `encoding/csv`, `reflect`, `text/tabwriter`, `net`, `net/netip`, `os/user`, `maps` |\n| `archive` | Create tar.gz or zip archives | `archive/tar`, `archive/zip`, `compress/gzip`, `path/filepath` |\n| `generate` | Generate passwords, tokens, UUIDs, or random data | `crypto/rand`, `math/rand/v2`, `math/big`, `encoding/binary` |\n| `bench` | Benchmark an HTTP endpoint with concurrency and percentile stats | `sync`, `sync/atomic`, `container/heap`, `container/list`, `math`, `sort` |\n| `inspect` | Inspect TLS certificates or DNS records | `crypto/tls`, `crypto/x509`, `encoding/pem`, `net`, `net/netip` |\n| `transform` | Transform text (case, sort, grep, frequency, replace, and more) | `regexp`, `unicode`, `unicode/utf8`, `bufio`, `slices`, `cmp`, `strconv` |\n| `image` | Convert images between PNG, JPEG, and GIF formats with dithering | `image`, `image/png`, `image/jpeg`, `image/gif`, `image/draw`, `image/color/palette` |\n| `encrypt` | Encrypt a file with AES-256-GCM using a password-derived key | `crypto/aes`, `crypto/cipher`, `crypto/pbkdf2`, `crypto/sha256`, `crypto/rand` |\n| `decrypt` | Decrypt a file encrypted with the encrypt command | `crypto/aes`, `crypto/cipher`, `crypto/pbkdf2` |\n| `compress` | Compress or decompress data (gzip, zlib, lzw, bzip2) | `compress/bzip2`, `compress/gzip`, `compress/lzw`, `compress/zlib` |\n\n## Examples\n\n### Serve files over HTTP\n\n```bash\nmtool serve -addr :9000 -dir ./public -gzip\n```\n\n### Serve files over HTTPS with self-signed certificate\n\n```bash\nmtool serve -addr :4443 -dir . -tls\n# Access with: curl -k https://localhost:4443\n```\n\n### Fetch a URL\n\n```bash\nmtool fetch -headers https://example.com\nmtool fetch -trace https://example.com\nmtool fetch -method POST -body '{\"key\":\"val\"}' -output response.json https://api.example.com\n```\n\n### Hash files\n\n```bash\nmtool hash -algo sha256 myfile.txt\necho \"hello\" | mtool hash -algo md5\nmtool hash -algo sha3-256 myfile.txt\nmtool hash -algo sha256 -hmac \"secret-key\" myfile.txt\nmtool hash -algo crc64 myfile.txt\nmtool hash -algo adler32 myfile.txt\nmtool hash -algo fnv64 myfile.txt\n```\n\n### Encode and decode\n\n```bash\necho \"hello world\" | mtool encode -format base64\necho \"aGVsbG8gd29ybGQK\" | mtool decode -format base64\necho \"hello\" | mtool encode -format base32\necho \"hello\" | mtool encode -format ascii85\necho \"foo bar\" | mtool encode -format url\necho \"Héllo wörld\" | mtool encode -format qp\necho \"H=C3=A9llo\" | mtool decode -format qp\necho \"hello\" | mtool encode -format utf16 \u003e output.utf16\nmtool decode -format utf16 output.utf16\n```\n\n### System information\n\n```bash\nmtool info\nmtool info -format json\nmtool info -format xml -env\nmtool info -format csv\n```\n\n### Create archives\n\n```bash\nmtool archive -format zip -output backup.zip src/ docs/ README.md\nmtool archive -format tar.gz myproject/\nmtool archive -format tar.zlib myproject/\nmtool archive -extract backup.zip\nmtool archive -extract -output ./dest archive.tar.gz\nmtool archive -extract archive.tar.bz2\n```\n\n### Generate secrets\n\n```bash\nmtool generate -mode password -length 32\nmtool generate -mode password -length 16 -charset alnum\nmtool generate -mode token -length 64\nmtool generate -mode uuid -count 5\nmtool generate -mode bigint -length 256\n```\n\n### Benchmark an HTTP endpoint\n\n```bash\nmtool bench -n 500 -c 20 https://example.com\nmtool bench -n 1000 -c 50 -method POST https://api.example.com/health\n```\n\n### Inspect TLS certificates\n\n```bash\nmtool inspect -mode tls google.com\nmtool inspect -mode tls -port 8443 internal.example.com\n```\n\n### Inspect DNS records\n\n```bash\nmtool inspect -mode dns github.com\n```\n\n### Transform text\n\n```bash\n# Case conversion\necho \"hello world\" | mtool transform -mode upper\necho \"HELLO WORLD\" | mtool transform -mode lower\n\n# Sort lines\ncat names.txt | mtool transform -mode sort\ncat scores.txt | mtool transform -mode sort -numeric -reverse\ncat data.txt | mtool transform -mode sort -field 3 -numeric\ncat mixed.txt | mtool transform -mode sort -ignore-case\n\n# Search and replace with regex\ncat log.txt | mtool transform -mode grep -pattern \"ERROR|WARN\"\ncat messy.txt | mtool transform -mode replace -pattern \"\\s+\" -replacement \" \"\n\n# Text statistics and word frequency\ncat document.txt | mtool transform -mode count\ncat document.txt | mtool transform -mode freq\n\n# Deduplicate and reverse\ncat dupes.txt | mtool transform -mode uniq\necho \"hello\" | mtool transform -mode reverse\n```\n\n### Convert images\n\n```bash\nmtool image photo.png photo.jpg\nmtool image -quality 75 screenshot.png compressed.jpg\nmtool image photo.jpg photo.gif\nmtool image -format png input.gif output.png\n```\n\n### Encrypt and decrypt files\n\n```bash\nmtool encrypt -password \"my-secret\" document.pdf document.pdf.enc\nmtool decrypt -password \"my-secret\" document.pdf.enc document.pdf\n\n# Or use an environment variable for the password\nexport MTOOL_PASSWORD=\"my-secret\"\nmtool encrypt document.pdf document.pdf.enc\nmtool decrypt document.pdf.enc document.pdf\n```\n\n### Compress and decompress\n\n```bash\nmtool compress -format gzip largefile.txt largefile.txt.gz\nmtool compress -d -format gzip largefile.txt.gz largefile.txt\nmtool compress -format zlib data.bin data.bin.zlib\nmtool compress -d -format zlib data.bin.zlib data.bin\nmtool compress -format lzw data.bin data.bin.lzw\nmtool compress -d -format lzw data.bin.lzw data.bin\nmtool compress -d -format bzip2 data.bz2 data.txt\nmtool compress -level 9 -format gzip archive.tar archive.tar.gz\n```\n\n\u003e **Note:** bzip2 supports decompression only (Go's `compress/bzip2` package provides a reader but no writer).\n\n## Standard Library Packages\n\nThe following 94 packages from the Go standard library are used:\n\n`archive/tar`, `archive/zip`, `bufio`, `bytes`, `cmp`, `compress/bzip2`, `compress/flate`, `compress/gzip`, `compress/lzw`, `compress/zlib`, `container/heap`, `container/list`, `context`, `crypto/aes`, `crypto/cipher`, `crypto/ecdsa`, `crypto/elliptic`, `crypto/hmac`, `crypto/md5`, `crypto/pbkdf2`, `crypto/rand`, `crypto/sha1`, `crypto/sha256`, `crypto/sha3`, `crypto/sha512`, `crypto/tls`, `crypto/x509`, `crypto/x509/pkix`, `embed`, `encoding/ascii85`, `encoding/base32`, `encoding/base64`, `encoding/binary`, `encoding/csv`, `encoding/hex`, `encoding/json`, `encoding/pem`, `encoding/xml`, `errors`, `flag`, `fmt`, `hash`, `hash/adler32`, `hash/crc32`, `hash/crc64`, `hash/fnv`, `html`, `html/template`, `image`, `image/color/palette`, `image/draw`, `image/gif`, `image/jpeg`, `image/png`, `io`, `io/fs`, `log`, `log/slog`, `maps`, `math`, `math/big`, `math/rand/v2`, `mime`, `mime/quotedprintable`, `net`, `net/http`, `net/http/cookiejar`, `net/http/httptrace`, `net/http/httputil`, `net/netip`, `net/url`, `os`, `os/exec`, `os/signal`, `os/user`, `path`, `path/filepath`, `reflect`, `regexp`, `runtime`, `runtime/debug`, `slices`, `sort`, `strconv`, `strings`, `sync`, `sync/atomic`, `syscall`, `text/tabwriter`, `text/template/parse`, `time`, `unicode`, `unicode/utf16`, `unicode/utf8`\n\n## Tests\n\nRun with `go test -v ./...`\n\n| Test | What it verifies |\n|---|---|\n| `TestFormatSize` | Byte formatting across B, KB, MB, GB, TB boundaries |\n| `TestTLSVersionString` | TLS version code to string mapping, including unknown versions |\n| `TestPercentile` | Empty slice, single-element, and various percentile calculations |\n| `TestLatencyHeap` | Min-heap property: pop order is ascending |\n| `TestGeneratePassword` | Correct length, charset constraints (alpha/alnum/full), category coverage for full charset |\n| `TestGenerateToken` | Correct length, hex-only characters, uniqueness across calls |\n| `TestGenerateUUID` | V4 format (version nibble = `4`, variant = `[89ab]`), uniqueness across calls |\n| `TestGenerateBigInt` | Returns decimal digit strings for various bit widths |\n| `TestSortLines` | Alphabetical, reverse, numeric, numeric descending, case-insensitive, field-based, out-of-range field, non-numeric lines in numeric mode |\n| `TestPrintTextStats` | Line/word/letter/digit/byte counts, empty input, no-trailing-newline edge case, unicode |\n| `TestPrintWordFrequency` | Frequency ordering (most frequent first), case-insensitive folding |\n| `TestCreateTarGz` | Round-trip: create tar.gz, read it back, verify file contents |\n| `TestCreateZip` | Round-trip: create zip, read it back, verify file contents |\n| `TestCreateTarGzDirectory` | Recursive directory archiving preserves structure and nested files |\n| `TestLoadDirectoryTemplate` | Embedded template parses and renders with sample data |\n| `TestGenerateSelfSignedCert` | Certificate is self-signed, has correct subject/DNS/IP, valid for ~24h, usable by `tls.Config`, unique serial numbers |\n| `TestInferImageFormat` | Extension-to-format mapping for png/jpg/jpeg/gif, case insensitivity, unknown extensions |\n| `TestEncodeImage_PNG` | PNG encode/decode round-trip preserves dimensions |\n| `TestEncodeImage_JPEG` | JPEG encode/decode round-trip preserves dimensions |\n| `TestEncodeImage_GIF` | GIF encode/decode round-trip preserves dimensions |\n| `TestEncodeImage_Unsupported` | Unsupported format returns an error |\n| `TestImageRoundTrip` | Full PNG-\u003eJPEG-\u003eGIF-\u003ePNG conversion chain via `cmdImage`, verifying file output at each step |\n| `TestDeriveKey` | Deterministic output, correct key length (32 bytes), different passwords/salts produce different keys |\n| `TestEncryptDecryptRoundTrip` | Encrypt then decrypt, verify content matches original, encrypted data differs from plaintext |\n| `TestDecryptWrongPassword` | Decryption fails with incorrect password |\n| `TestEncryptProducesUniqueOutput` | Same file encrypted twice produces different ciphertext (unique salt/nonce) |\n| `TestCompressDecompressGzip` | Gzip round-trip: compress then decompress, verify content matches and compressed size is smaller |\n| `TestCompressDecompressZlib` | Zlib round-trip: compress then decompress, verify content matches and compressed size is smaller |\n| `TestCompressDecompressBzip2` | Bzip2 decompression: compress with system bzip2, decompress with mtool, verify content matches |\n| `TestCompressBzip2RejectsCompress` | Attempting bzip2 compression returns a clear \"decompress only\" error |\n| `TestCompressDecompressLZW` | LZW round-trip with litwidths 6, 7, 8: compress with header, decompress auto-detects litwidth |\n| `TestHashAdler32` | Adler-32 hash produces correct output for known input |\n| `TestHashCRC64` | CRC-64 hash produces correct output for known input |\n| `TestHashFNV` | FNV-32a, FNV-64a, FNV-128a produce correct output lengths for known input |\n| `TestEncodeDecodeQuotedPrintable` | Quoted-printable round-trip: encode then decode, verify non-ASCII is encoded and round-trips correctly |\n| `TestEncodeDecodeUTF16` | UTF-16 round-trip: encode with BOM then decode, verify content matches including non-ASCII characters |\n| `TestEncodeDecodeBase64` | Base64 round-trip: encode then decode, verify content matches |\n| `TestEncodeDecodeBase32` | Base32 round-trip: encode then decode, verify content matches |\n| `TestEncodeDecodeHex` | Hex round-trip: encode verifies known value, decode restores original |\n| `TestEncodeDecodeAscii85` | Ascii85 round-trip: encode then decode, verify content matches |\n| `TestEncodeDecodeURL` | URL encoding round-trip: verifies special characters are percent-encoded and decode restores original |\n| `TestTransformUpper` | Lowercase text converted to uppercase |\n| `TestTransformLower` | Uppercase text converted to lowercase |\n| `TestTransformReverse` | String reversal produces correct output |\n| `TestTransformGrep` | Regex filtering selects only matching lines |\n| `TestTransformReplace` | Regex replacement collapses whitespace correctly |\n| `TestTransformUniq` | Deduplication removes repeated lines, preserves order |\n| `TestHashAlgorithms` | All hash algorithms (md5, sha1, sha256, sha512, sha3-256, sha3-512, crc32) produce correct hex output lengths |\n| `TestHashHMAC` | HMAC differs from plain hash, is deterministic, and different keys produce different output |\n| `TestArchiveExtractTarGz` | Create tar.gz then extract, verify extracted file contents match originals |\n| `TestArchiveExtractZip` | Create zip then extract, verify extracted file contents match originals |\n| `TestCreateTarZlib` | Tar.zlib round-trip: create then extract, verify file contents match |\n| `TestCompressGzipLevels` | Gzip level 9 produces smaller output than level 1 for the same input |\n\n## Personal Project Disclosure\n\nThis program is my own original idea, conceived and developed entirely:\n\n* On my own personal time, outside of work hours\n* For my own personal benefit and use\n* On my personally owned equipment\n* Without using any employer resources, proprietary information, or trade secrets\n* Without any connection to my employer's business, products, or services\n* Independent of any duties or responsibilities of my employment\n\nThis project does not relate to my employer's actual or demonstrably\nanticipated research, development, or business activities. No\nconfidential or proprietary information from any employer was used\nin its creation.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjftuga%2Fmtool","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjftuga%2Fmtool","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjftuga%2Fmtool/lists"}