{"slug": "show-hn-awsmux-multi-account-aws-cli-up-to-5-4x-faster-7-4x-fewer-tokens", "title": "Show HN: Awsmux – Multi-account AWS CLI, up to 5.4x faster, 7.4x fewer tokens", "summary": "Awsmux, a multi-account AWS CLI tool, runs commands across hundreds of accounts in parallel with up to 5.4x faster execution and 7.4x fewer output tokens compared to raw-shell AWS CLI, according to a benchmark by developer Hardik. In a 150-session test using Claude Opus 4.8 agents across a 100-account fleet, awsmux was 1.3x to 2.9x cheaper and 2.3x to 5.4x faster, with a flat 4 turns regardless of fleet size. The tool includes an approval boundary that prevents even AI agents with admin credentials from executing mutations without approval.", "body_md": "**Run one AWS CLI command across your whole fleet in parallel:\nhundreds of accounts in seconds, safely.**\n\nOne command fanned out across every account and region at once (100\nparallel workers by default, `--concurrency`\n\nraises it), identities\nverified before anything runs, results\nmerged into one stream. No more shell loops that take a coffee break to\ncrawl the fleet. And anything that mutates is stopped by an approval\nboundary that even an AI agent with your admin credentials cannot talk\nits way past. The demo above is a real terminal against the bundled\n100-account sandbox fleet; replay it yourself in one command with\n`make build fleet-up`\n\n.\n\n**And it is measurably cheaper and faster for agents. In a 150-session,\nthree-arm benchmark (identical Claude Opus 4.8 agents, identical\nprompts, same 100-account fleet), the awsmux arm was cheaper and faster\nthan a raw-shell aws CLI arm in every cell: 1.3x to 2.9x cheaper, 2.3x\nto 5.4x faster, and up to 7.4x fewer output tokens, at a flat 4 turns\nwhatever the fleet size (the CLI arm matched that only at 10 accounts,\nthen grew to 10.5; cost and output-token differences are all\nHolm-adjusted p < 0.05). 138 of the 150 sessions passed environment\nvalidation, and all 12 exclusions were awsmux's own fault: an MCP\nstartup race under concurrency, so they fell entirely in the\nMCP-bearing arms.**\n\n| task | fleet | cost per run (cli vs awsmux) | wall time |\n|---|---|---|---|\n| enumerate all VPCs | 10 accounts | $0.090 vs $0.068 (1.3x) | 34s vs 13s |\n| enumerate all VPCs | 50 accounts | $0.239 vs $0.120 (2.0x) | 84s vs 23s |\n| enumerate all VPCs | 100 accounts | $0.274 vs $0.193 (1.4x) | 94s vs 41s |\n| find the world-open group | 50 accounts | $0.229 vs $0.079 (2.9x) | 75s vs 14s |\n| find the world-open group | 100 accounts | $0.152 vs $0.098 (1.5x) | 90s vs 17s |\n\nFull design, statistics, and caveats:\n[docs/BENCHMARK.md](/0hardik1/awsmux/blob/main/docs/BENCHMARK.md).\n\nPrerequisites: Go, Docker, and the aws CLI.\n\n```\nmake build fleet-up && source .tmp/fleet/env.sh\n```\n\nThat builds `./bin/awsmux`\n\n, boots a pinned LocalStack container, and\nprovisions a fictional 100-account fleet (10 teams, prod and stage, 5\nshards, 3 regions) to break for fun. The real aws CLI talks to a real\nemulated AWS on localhost, every profile is its own account (plus one\nplanted `admin-legacy`\n\nduplicate for `--dedupe`\n\nto catch), and what you\nchange actually persists. Zero credentials, zero real AWS, zero risk.\n\n```\n./bin/awsmux targets --profiles 'payments-*'     # verified identities, per account\n./bin/awsmux run --dedupe --format jsonl -- ec2 describe-vpcs --query 'Vpcs[].VpcId'\n                                                 # all 100 accounts in a few seconds\n./bin/awsmux run --profiles '*-prod-*' -- ec2 describe-security-groups \\\n  --filters Name=ip-permission.cidr,Values=0.0.0.0/0   # find the world-open group\n./bin/awsmux plan --profiles payments-prod-1 -- ec2 revoke-security-group-ingress \\\n  --group-name legacy-bastion --protocol tcp --port 22 --cidr 0.0.0.0/0\n```\n\nThat last one is destructive, so it will not just run: you get an immutable plan to approve first. Apply it with the token and re-run the hunt; the finding disappears for real, because the sandbox is a real (emulated) AWS. Try editing the plan file between approve and apply and watch the hash check refuse it.\n\n`make e2e`\n\nbuilds the binary, provisions the fleet, and smoke-tests\nthese same beats end to end, from STS-verified discovery through the\napproval gate to a plan / approve / apply roundtrip and a tampered plan\nrefused by its hash (full list in\n[docs/ARCHITECTURE.md](/0hardik1/awsmux/blob/main/docs/ARCHITECTURE.md#test-fleet));\n`make fleet-down`\n\nremoves the container.\n\nSame commands, pointed at your own AWS setup instead of the sandbox\nenvironment. Zero configuration of its own: awsmux discovers profiles\nfrom your existing shared config file (`~/.aws/config`\n\n) and shared\ncredentials file (`~/.aws/credentials`\n\n), honoring `AWS_CONFIG_FILE`\n\nand\n`AWS_SHARED_CREDENTIALS_FILE`\n\n. SSO, static keys, and\n`credential_process`\n\nprofiles all work unchanged, because awsmux always\nexecutes through the aws CLI and verifies every identity with STS\nbefore running anything:\n\n```\nawsmux doctor                       # first run? verify aws CLI, files, profiles\nawsmux targets --regions us-east-1,us-west-2\n\nawsmux run --profiles 'prod-*' --exclude '*-sandbox' --format jsonl \\\n  -- ec2 describe-instances --query 'Reservations[].Instances[].InstanceId'\n\nawsmux plan -- ssm put-parameter --name /app/flag --value on --type String\nawsmux approve plan-01k...          # prints a one-time token, never stored\nawsmux apply plan-01k... --approval-token <token>\n```\n\nNot seeing your profiles? `awsmux doctor`\n\nshows exactly which files\nwere checked, how many profiles each contributed, and whether the aws\nCLI and state directory are usable. `awsmux targets`\n\nreports where each\nprofile came from (a `SOURCE`\n\ncolumn in table mode, a `source`\n\nfield in\njsonl: `config`\n\n, `credentials`\n\n, or `both`\n\n).\n\nUseful flags on `run`\n\n, and on `apply`\n\n/ `replay`\n\ntoo unless noted:\n`--concurrency`\n\n(default 100: fleet-wide fan-out is the point; each\nin-flight target is one aws CLI subprocess), `--timeout 30s`\n\n,\n`--max-errors N`\n\n, `--stop-on-access-denied`\n\n, `--output-dir`\n\n(one result\nfile per target; not on `replay`\n\n), `--interactive`\n\n(checkbox target\npicker; `run`\n\nonly). Target selection (`--profiles`\n\n, `--exclude`\n\n,\n`--regions`\n\n, `--preflight`\n\n, `--dedupe`\n\n) applies to `run`\n\n, `plan`\n\n, and\n`targets`\n\n; `--dedupe`\n\ncollapses targets that resolve to the same\naccount, principal, and region, and it runs the STS preflight to find\nthem even under `--preflight=false`\n\n. Every run lands in\n`awsmux history`\n\nand can be re-run with `awsmux replay`\n\n, which\nre-selects its targets from the stored execution.\n\nTwo commands, zero configuration:\n\n```\ngo install github.com/0hardik1/awsmux@latest\nclaude mcp add --scope user awsmux -- awsmux mcp\n```\n\nThere is nothing to configure. `awsmux mcp`\n\nserves the agent interface\nover stdio via the Model Context Protocol: no port, no daemon, no\nconfig file, no credentials of its own. It discovers the same profiles\nyour terminal already has (shared config and credentials files; SSO,\nstatic keys, and `credential_process`\n\nall pass straight through) and\nverifies every identity with STS before anything runs. It even locates\nthe aws CLI in well-known install locations when an MCP client spawns\nit with a bare GUI PATH. Check the connection with `/mcp`\n\ninside\nClaude Code, then ask the agent \"which AWS accounts can you see?\"\n(Drop `--scope user`\n\nto register for the current project only. No Go\ntoolchain? `git clone`\n\n+ `make build`\n\ngives you `./bin/awsmux`\n\n.)\n\n**Claude Desktop**: Settings > Developer > Edit Config, then add to\n`claude_desktop_config.json`\n\n(GUI apps do not read your shell PATH,\nso use the absolute path from `which awsmux`\n\n):\n\n```\n{\n  \"mcpServers\": {\n    \"awsmux\": { \"command\": \"/absolute/path/to/awsmux\", \"args\": [\"mcp\"] }\n  }\n}\n```\n\n**Other MCP clients** (Cursor, Windsurf, Zed, ...): same shape\neverywhere, a stdio server with command `awsmux`\n\nand args `[\"mcp\"]`\n\n.\n\nThe agent gets five structured tools (`list_aws_targets`\n\n,\n`plan_aws_operation`\n\n, `execute_aws_plan`\n\n, `get_aws_execution`\n\n,\n`cancel_aws_execution`\n\n) instead of a raw shell, and it uses them on\nits own: once registered there is nothing to invoke, you just ask\n(\"find every security group open to the world in prod\") and the model\nreaches for the tools automatically. Read-only operations execute\nfreely. Anything else comes back as a plan: the agent hands you a plan\nID, you run `awsmux approve <plan-id>`\n\nin your own terminal, and you\npaste the one-time token back into the chat for the agent to apply.\nThe token binds to the plan's sha256 hash, so the agent cannot alter\nan approved plan or execute it twice.\n\nWant to watch an agent hit the boundary with zero blast radius?\nRegister the sandbox fleet instead: after `make build fleet-up`\n\n, point\nthe server at the fleet's config via environment variables (values\nprinted in `.tmp/fleet/env.sh`\n\n):\n\n```\nclaude mcp add awsmux-fleet \\\n  --env AWS_CONFIG_FILE=$PWD/.tmp/fleet/aws-config \\\n  --env AWS_SHARED_CREDENTIALS_FILE=$PWD/.tmp/fleet/aws-credentials \\\n  --env AWSMUX_HOME=$PWD/.tmp/fleet/home \\\n  -- $PWD/bin/awsmux mcp\n```\n\nThe agent gets the 100-account LocalStack fleet over MCP; let it break anything it likes.\n\nThe cost and speed numbers in the table at the top come from exactly this setup. One more result from the same benchmark: when an agent was handed both a shell and the MCP tools, it picked awsmux on its own and kept nearly all of the margin.\n\n| Class | Examples | Policy |\n|---|---|---|\n`read_only` |\ndescribe-, list-, get-*, s3 ls |\nruns freely |\n`mutating` |\ncreate-, put-, update-*, s3 cp, s3 presign |\n`--yes` , interactive confirm, or approved plan |\n`destructive` |\ndelete-, terminate-, revoke-*, s3 rm, s3 mv |\nnever `--yes` ; typed confirm or plan/approve/apply |\n`unknown` |\nanything unrecognized | treated as mutating |\n\nWhere the verb convention lies, awsmux overrides it. sts calls that\nmint credentials (assume-role*, assume-root, get-session-token,\nget-federation-token), s3api operations that write a local outfile\n(get-object, get-object-torrent, select-object-content), and `s3 presign`\n\n(the URL it prints is a bearer credential for the object) are\nall `mutating`\n\ndespite their read-style names, and `s3 mv`\n\nis\n`destructive`\n\nbecause it deletes the source. Where the risk lives in an\nargument rather than the name, the argument decides: `s3 sync`\n\nis\n`mutating`\n\n, but `s3 sync --delete`\n\nis `destructive`\n\n.\n\nStable exit codes for CI and agents: 0 all succeeded, 1 some failed, 2 selection/config error, 3 approval required or rejected, 4 stopped by threshold.\n\nA scanner pages: SSH is open to the world somewhere in the fleet. Your\nagent sweeps 14 verified accounts in one read-only call, finds\n`sg-0a1b2c3d`\n\nin payments-prod, and proposes the revoke. The revoke is\ndestructive, so the engine hands back a plan instead of running it. You\nread the plan on your phone: exact command, exact account, verified\nprincipal, hash. You approve, paste one token, and go back to sleep\nwhile the fix lands in history with the hash attached.\n\nYou can replay this exact story against a fleet of fakes right now:\n`make build fleet-up`\n\n.\n\n| awsmux | awsrun | aws-vault / granted / awsume | |\n|---|---|---|---|\n| Fleet execution across accounts | yes | yes | no (credential tools) |\n| STS identity preflight per target | yes | no | n/a |\n| Risk classification + approval boundary | yes | prompt only | n/a |\n| Agent interface (MCP) | yes | no | no |\n100-account LocalStack test fleet (`make fleet-up` ) |\nyes | no | no |\n| History + replay | yes | no | no |\n| Runtime | single Go binary | Python + plugins | Go / varies |\n\nThe credential tools are complementary: awsmux happily executes through profiles they manage.\n\n[Architecture](/0hardik1/awsmux/blob/main/docs/ARCHITECTURE.md): the engine, the plan boundary, the executor, test-fleet internals.[Benchmark](/0hardik1/awsmux/blob/main/docs/BENCHMARK.md): the three-arm agent-cost methodology and results behind the table above.\n\n```\nmake setup                 # git hooks + pre-warm the pinned linter\nmake build test lint       # or: go build ./... && go vet ./... && go test ./...\nmake fleet-up e2e          # LocalStack fleet + end-to-end smoke test\nmake fleet-down clean\n```\n\nCI runs `go test`\n\nand `make build`\n\non ubuntu and macos, gofmt + go vet,\ngolangci-lint repo-wide, the LocalStack e2e smoke test on ubuntu, and a\nConventional Commits check on PR titles (the commit-msg hook enforces\nthe same convention locally).\n\nThe demo GIF at the top is a real Ghostty session against the\nLocalStack fleet, recorded with [Kap](https://getkap.co).\n\nDependencies: stdlib plus cobra. Roadmap: organization-aware discovery\n(`--ou`\n\nplus role assumption), policy packs, Homebrew tap and release\nbinaries.\n\nLicensed under [Apache-2.0](/0hardik1/awsmux/blob/main/LICENSE).", "url": "https://wpnews.pro/news/show-hn-awsmux-multi-account-aws-cli-up-to-5-4x-faster-7-4x-fewer-tokens", "canonical_source": "https://github.com/0hardik1/awsmux", "published_at": "2026-07-25 20:09:06+00:00", "updated_at": "2026-07-25 20:22:26.133525+00:00", "lang": "en", "topics": ["developer-tools", "ai-agents", "ai-infrastructure"], "entities": ["Awsmux", "AWS CLI", "Claude Opus 4.8", "Hardik", "LocalStack"], "alternates": {"html": "https://wpnews.pro/news/show-hn-awsmux-multi-account-aws-cli-up-to-5-4x-faster-7-4x-fewer-tokens", "markdown": "https://wpnews.pro/news/show-hn-awsmux-multi-account-aws-cli-up-to-5-4x-faster-7-4x-fewer-tokens.md", "text": "https://wpnews.pro/news/show-hn-awsmux-multi-account-aws-cli-up-to-5-4x-faster-7-4x-fewer-tokens.txt", "jsonld": "https://wpnews.pro/news/show-hn-awsmux-multi-account-aws-cli-up-to-5-4x-faster-7-4x-fewer-tokens.jsonld"}}