The whole cloud, on your machine.

A local emulator of AWS, Google Cloud and Azure, for development and tests. One binary, one port, ready in about 30 ms on an Apple M5, with nothing to sign up for.

InstallRead the docsMIT licensed · open source
brew install nrndev/tap/pogi

On macOS. Linux, Go, Docker and Windows are below.

355 services: 145 with real behavior, 210 Thin (pogi stores the resources, but nothing runs behind them). See coverage

One port. Every cloud.

Set one endpoint and your SDKs find it. AWS, Google Cloud, Azure and the console all answer on 7644.

localhost:7644
  • AWSS3 PutObject photos/cat.jpg200
  • Google CloudPub/Sub Publish topics/uploads200
  • AzureBlob Storage PutBlob media/cat.jpg200

Everything stays on localhost.

eval "$(pogi env)" points your SDKs here. 7644 spells “pogi” on a phone keypad.

Break a call on purpose.

One command adds a rule, and the next call fails the way a real cloud fails.

terminal
$ pogi chaos add --service sqs --op SendMessage --status 503 --code ServiceUnavailable added rule 1986a4aa $ aws sqs send-message --queue-url http://localhost:7644/000000000000/orders --message-body hi aws: [ERROR]: An error occurred (ServiceUnavailable) when calling the SendMessage operation (reached max retries: 2): injected by pogi chaos rule 1986a4aa $ pogi chaos ls ID SERVICE OP RATE LATENCY ERROR HITS 1986a4aa sqs SendMessage 100% 0ms 503 ServiceUnavailable 3

Start a fresh pogi for each test.

It starts fast enough to throw away after every test.

Start-up time

about30 ms

Timed to ready, after the first launch.

Writes per second

about20,000

DynamoDB PutItem, 8 at a time.

Memory under load

about150 MB

About 75 MB at idle.

One call, start to finish

about0.1 ms

DynamoDB PutItem, one at a time.

*Apple M5 with 32 GB of memory, pogi v0.2.0 release build. How we measured →

Your tools already speak it.

Point them at pogi once, through environment variables. Your AWS code stays the same.

  1. Your SDKs, on all three cloudsAWS, Google Cloud and Azure clients read the endpoints from your environment.
  2. Terraformpogi writes the provider block with every endpoint.
  3. AWS CDKBootstrap and deploy as usual, without a wrapper script.
  4. CIRun the same binary or the Docker image, with a fresh pogi for each job.

355 services: 144 AWS (90 with real behavior, 54 Thin), 108 Google Cloud (25 with real behavior, 83 Thin) and 103 Azure (30 with real behavior, 73 Thin). A Thin service keeps your resources, but nothing runs behind them. See coverage

Moving from LocalStack? Point at port 7644, or keep 4566 with pogi start --port 4566. Read the migration guide

Terminal
$ eval "$(pogi env)"
$ python upload.py
$ pogi tf > pogi_override.tf
$ terraform apply
$ cdk bootstrap
$ cdk deploy
$

Built to test against.

Real engines under the API, and tools around them. Each one has its own page.

  • 01

    Real engines, not mocks

    Lambda runs your code. RDS and Cloud SQL are real PostgreSQL and MySQL. EKS, GKE and AKS are real Kubernetes. ECS and Cloud Run run real containers. The databases, clusters and containers need Docker; the core services do not.

  • 02

    Least-privilege IAM, written for you

    Least privilege means each identity may make only the calls it needs. Record mode watches your calls and writes that policy. Strict mode then blocks any call the policy does not allow.

  • 03

    Every call and flow, traced

    The console shows calls live, follows a request across services, and draws how your resources are wired.

  • 04

    The bill before you deploy

    Price a Terraform plan, and see on a diagram what the plan changes.

  • 05

    Break things on purpose

    Rules add latency, errors or throttling to the calls you choose.

  • 06

    Built for AI agents

    pogi mcp is an MCP server (MCP is the protocol AI coding agents use to call tools), so an agent can look inside pogi and control it. pogi agents init adds a short brief about pogi to AGENTS.md.

See what your code just did.

Calls, flows (one request followed across services) and connections, live in your browser at localhost:7644/_pogi/.

Calls, live

The calls your code makes on AWS, Google Cloud and Azure, as they happen.

localhost:7644/_pogi/

Activity

Calls to all services, newest first.

TimeServiceOperationStatus
  • 14:26:21.311Cloud Storage objects.getobjects.get200
  • 14:26:21.301Blob Storage GetBlobGetBlob200
  • 14:26:21.288DynamoDB GetItemGetItem200
  • 14:26:21.272Pub/Sub PublishPublish200
  • 14:26:20.996Cloud Storage objects.getobjects.get200
  • 14:26:20.987Blob Storage GetBlobGetBlob200

Flows, traced

Each upload is traced end to end, from S3 through Pub/Sub to Azure Blob Storage. One took 6 steps in 19 ms.

localhost:7644/_pogi/

Flows 1-6cf92f35-77b34da6a3ce929d0e0e4711

PutObject /photos/uploads/6cf92.jpg

2026-10-13 14:25:14 · 6 steps · 19 ms

  1. S3 PutObject0.1 ms
  2. SQS deliver → thumbnails0.0 ms
  3. Pub/Sub Publish0.1 ms
  4. Blob Storage PutBlob0.0 ms
  5. Event Grid deliver → events0.0 ms
  6. Pub/Sub deliver → thumbsno time captured

Times are per step. The 19 ms runs from the first call to the last step, including the wait between deliveries.

How it's wired

The map draws each cloud's resources and the messages moving between them.

localhost:7644/_pogi/
Map. On AWS, the S3 bucket photos sends a notification to the SQS queue thumbnails. On Google Cloud, the Pub/Sub topic uploads feeds thumbs through a subscription. On Azure, the storage resource pogistore feeds the storage resource events through a subscription.

Least privilege, written for you.

pogi records what your code calls, writes the smallest IAM (who may do what) policy that allows it, and attaches it. On AWS, Google Cloud and Azure.

Record

Run your code as a real IAM user. pogi records the actions it calls and writes the matching policy.

localhost:7644/_pogi/

uploader · 5 calls recorded, one identity on each cloud

  • s3:PutObject photos/*would deny
  • sqs:SendMessage thumbnailswould deny
  • dynamodb:PutItem table/orderswould deny
  • pubsub.topics.publish topics/uploadswould deny
  • .../containers/blobs/write containers/mediawould deny

Strict mode blocks

Turn on strict mode (deny anything not allowed) and calls without a policy fail, with the same AccessDenied error AWS returns.

localhost:7644/_pogi/

StrictCalls without an allowing policy fail.

An error occurred (AccessDenied) when calling the PutObject operation: User: arn:aws:iam::000000000000:user/uploader is not authorized to perform: s3:PutObject on resource: arn:aws:s3:::photos/cat.jpg because no identity-based policy allows the s3:PutObject action

Attach

Review the policy pogi wrote, then attach it in one step.

localhost:7644/_pogi/
{
  "Version": "2012-10-17",
  "Statement": [
    { "Effect": "Allow", "Action": "dynamodb:PutItem",
      "Resource": "arn:aws:dynamodb:us-east-1:000000000000:table/orders" },
    { "Effect": "Allow", "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::photos/*" },
    { "Effect": "Allow", "Action": "sqs:SendMessage",
      "Resource": "arn:aws:sqs:us-east-1:000000000000:thumbnails" }
  ]
}

Attached to user/uploaderas the policy pogi-uploader

  • roles/pubsub.publisher on projects/pogi/topics/uploads
  • Role pogi-uploader · custom role, new. Assigned to uploader at .../containers/media

Calls pass

The same calls pass. Least privilege, without guessing.

5 of 5 callsallowed

The rest of your toolkit, built in.

before-tests

Saved
9s ago
Size
50.9 MB

Snapshots for your test runs.

Save your resources once, then restore it with one command before each run.

  • Your sign-in code is 482913sms10s ago
  • Your order o-1042 has shippedemail · ses10s ago

Emails and SMS, caught.

Messages your code sends land in a local inbox, never a real phone.

$13.60

Estimated monthly cost

≈ $0.45 / day · on-demand · no free tier

  • AWS

    $1.73

  • Google Cloud

    $0.63

  • Azure

    $11.24

Know the cost before you deploy.

A real-cloud cost estimate from your resources and traffic.

Learn more about the bill before you deploy

Open source, MIT licensed.

Read the code, report a bug, or send a fix.

Install, start, point your tools.

Nothing to sign up for. Pick your platform and paste.

By default pogi listens only on your own machine (127.0.0.1) and accepts any keys. It is for development and tests, not a shared server: never give it real cloud credentials.

  1. 1

    Install

    brew install nrndev/tap/pogi
  2. 2

    Start

    pogi startReady.
  3. 3

    Point your tools at it

    # In a second terminal.# sets the endpoint and test keyseval "$(pogi env)"aws s3 mb s3://my-bucketmake_bucket: my-bucket
  4. 4

    Open the console

Binaries for macOS, Linux and Windows are on the releases page. pogi also has a CLI, a terminal UI and an MCP server, so AI coding assistants can drive it; see the docs.

Install it, start it, open the console.