sivchari/kumo

A lightweight AWS service emulator written in Go

Go

1,499

944 commits

updated Oct 9, 2026

See the code

README

kumo logo

Go Version License Release Lint Integration Tests

A lightweight AWS service emulator written in Go.
Works as both a CI/CD testing tool and a local development server with optional data persistence.

Features

  • No authentication required - Perfect for CI environments
  • Single binary - Easy to distribute and deploy
  • Docker support - Run as a container
  • Lightweight - Fast startup, minimal resource usage
  • AWS SDK v2 compatible - Works seamlessly with Go AWS SDK v2
  • Optional data persistence - Survive restarts with KUMO_DATA_DIR

Supported Services (82 services)

Storage

ServiceDescription
DynamoDBNoSQL database
DynamoDB StreamsDynamoDB change data capture
EBSBlock storage
ElastiCacheIn-memory caching
GlacierArchive storage
MemoryDBRedis-compatible database
S3Object storage
S3 ControlS3 account-level operations
S3 TablesS3 table buckets

Compute

ServiceDescription
BatchBatch computing
EC2Virtual machines
Elastic BeanstalkApplication deployment
LambdaServerless functions

Container

ServiceDescription
ECRContainer registry
ECSContainer orchestration
EKSKubernetes service

Database

ServiceDescription
DocumentDBMongoDB-compatible database
NeptuneGraph database
RDSRelational database service
RedshiftData warehousing

Messaging & Integration

ServiceDescription
EventBridgeEvent bus
FirehoseData delivery
KinesisReal-time streaming
MQMessage broker (ActiveMQ/RabbitMQ)
MSK (Kafka)Managed streaming for Kafka
PipesEvent-driven integration
SNSPub/Sub messaging
SQSMessage queuing

Security & Identity

ServiceDescription
ACMCertificate management
CognitoUser authentication
IAMIdentity and access management
KMSKey management
MacieData security and privacy
STSSecurity token service
Secrets ManagerSecret storage
Security LakeSecurity data lake

Monitoring & Logging

ServiceDescription
Amazon Managed Service for PrometheusManaged Prometheus workspaces with data-plane passthrough
CloudTrailAPI audit logging
CloudWatchMetrics and alarms
CloudWatch LogsLog management
X-RayDistributed tracing

Networking & Content Delivery

ServiceDescription
API GatewayAPI management (REST API)
API Gateway v2API management (HTTP/WebSocket API)
App MeshService mesh
CloudFrontCDN
ELBv2Load balancing
Global AcceleratorNetwork acceleration
LocationLocation-based services
Route 53DNS service
Route 53 ResolverDNS resolver

Application Integration

ServiceDescription
AmplifyFull-stack application hosting
AppSyncGraphQL API
Pinpoint SMS Voice v2SMS messaging
SESEmail service
SES v2Email service (v2 API)
SchedulerTask scheduling
Step FunctionsWorkflow orchestration

Management & Configuration

ServiceDescription
BackupCentralized backup service
Cloud Control APIUnified CRUD API for cloud resources
CloudFormationInfrastructure as code
CodeConnectionsSource code connections
ConfigResource configuration
OrganizationsMulti-account management
SSMSystems Manager
Service QuotasService limit management

Analytics & ML

ServiceDescription
AthenaSQL query service
ComprehendNLP service
Data ExchangeData marketplace
Entity ResolutionEntity matching
ForecastTime-series forecasting
GlueETL service
RekognitionImage/video analysis
SageMakerMachine learning

Developer Tools

ServiceDescription
CodeGuru ProfilerApplication profiling
CodeGuru ReviewerAutomated code review

Other Services

ServiceDescription
Cost ExplorerCost analysis
DLMData lifecycle manager
Directory ServiceMicrosoft AD
EMR ServerlessBig data processing
FinSpaceFinancial data management
GameLiftGame server hosting
Resilience HubApplication resilience

Quick Start

Docker

docker run -p 4566:4566 ghcr.io/sivchari/kumo:latest

With data persistence:

docker run -p 4566:4566 \
  -e KUMO_DATA_DIR=/data \
  -v kumo-data:/data \
  ghcr.io/sivchari/kumo:latest

Binary

# Build
make build

# Run
./bin/kumo

# Run with data persistence
KUMO_DATA_DIR=./data ./bin/kumo

Docker Compose

services:
  kumo:
    image: ghcr.io/sivchari/kumo:latest
    ports:
      - "4566:4566"

With data persistence:

services:
  kumo:
    image: ghcr.io/sivchari/kumo:latest
    ports:
      - "4566:4566"
    environment:
      - KUMO_DATA_DIR=/data
    volumes:
      - kumo-data:/data

volumes:
  kumo-data:

Usage Examples

S3

package main

import (
    "context"
    "strings"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/credentials"
    "github.com/aws/aws-sdk-go-v2/service/s3"
)

func main() {
    cfg, _ := config.LoadDefaultConfig(context.TODO(),
        config.WithRegion("us-east-1"),
        config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider("test", "test", "")),
    )

    client := s3.NewFromConfig(cfg, func(o *s3.Options) {
        o.BaseEndpoint = aws.String("http://localhost:4566")
        o.UsePathStyle = true
    })

    // Create bucket
    client.CreateBucket(context.TODO(), &s3.CreateBucketInput{
        Bucket: aws.String("my-bucket"),
    })

    // Put object
    client.PutObject(context.TODO(), &s3.PutObjectInput{
        Bucket: aws.String("my-bucket"),
        Key:    aws.String("hello.txt"),
        Body:   strings.NewReader("Hello, World!"),
    })
}

SQS

package main

import (
    "context"
    "fmt"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/credentials"
    "github.com/aws/aws-sdk-go-v2/service/sqs"
)

func main() {
    cfg, _ := config.LoadDefaultConfig(context.TODO(),
        config.WithRegion("us-east-1"),
        config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider("test", "test", "")),
    )

    client := sqs.NewFromConfig(cfg, func(o *sqs.Options) {
        o.BaseEndpoint = aws.String("http://localhost:4566")
    })

    // Create queue
    result, _ := client.CreateQueue(context.TODO(), &sqs.CreateQueueInput{
        QueueName: aws.String("my-queue"),
    })

    // Send message
    client.SendMessage(context.TODO(), &sqs.SendMessageInput{
        QueueUrl:    result.QueueUrl,
        MessageBody: aws.String("Hello from SQS!"),
    })

    // Receive message
    messages, _ := client.ReceiveMessage(context.TODO(), &sqs.ReceiveMessageInput{
        QueueUrl: result.QueueUrl,
    })

    for _, msg := range messages.Messages {
        fmt.Println(*msg.Body)
    }
}

DynamoDB

package main

import (
    "context"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/credentials"
    "github.com/aws/aws-sdk-go-v2/service/dynamodb"
    "github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
)

func main() {
    cfg, _ := config.LoadDefaultConfig(context.TODO(),
        config.WithRegion("us-east-1"),
        config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider("test", "test", "")),
    )

    client := dynamodb.NewFromConfig(cfg, func(o *dynamodb.Options) {
        o.BaseEndpoint = aws.String("http://localhost:4566")
    })

    // Create table
    client.CreateTable(context.TODO(), &dynamodb.CreateTableInput{
        TableName: aws.String("users"),
        KeySchema: []types.KeySchemaElement{
            {AttributeName: aws.String("id"), KeyType: types.KeyTypeHash},
        },
        AttributeDefinitions: []types.AttributeDefinition{
            {AttributeName: aws.String("id"), AttributeType: types.ScalarAttributeTypeS},
        },
        BillingMode: types.BillingModePayPerRequest,
    })

    // Put item
    client.PutItem(context.TODO(), &dynamodb.PutItemInput{
        TableName: aws.String("users"),
        Item: map[string]types.AttributeValue{
            "id":   &types.AttributeValueMemberS{Value: "user-1"},
            "name": &types.AttributeValueMemberS{Value: "Alice"},
        },
    })
}

Secrets Manager

package main

import (
    "context"
    "fmt"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/credentials"
    "github.com/aws/aws-sdk-go-v2/service/secretsmanager"
)

func main() {
    cfg, _ := config.LoadDefaultConfig(context.TODO(),
        config.WithRegion("us-east-1"),
        config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider("test", "test", "")),
    )

    client := secretsmanager.NewFromConfig(cfg, func(o *secretsmanager.Options) {
        o.BaseEndpoint = aws.String("http://localhost:4566")
    })

    // Create secret
    client.CreateSecret(context.TODO(), &secretsmanager.CreateSecretInput{
        Name:         aws.String("my-secret"),
        SecretString: aws.String(`{"username":"admin","password":"secret123"}`),
    })

    // Get secret
    result, _ := client.GetSecretValue(context.TODO(), &secretsmanager.GetSecretValueInput{
        SecretId: aws.String("my-secret"),
    })

    fmt.Println(*result.SecretString)
}

Configuration

Environment variables:

VariableDefaultDescription
KUMO_HOST0.0.0.0Server bind address
KUMO_PORT4566Server port
KUMO_LOG_LEVELinfoLog level (debug, info, warn, error)
KUMO_DATA_DIR(unset)Directory for persistent storage. When unset, data is in-memory only.

Logging

kumo logs all requests with structured fields. The log level controls the amount of detail:

INFO (default)

Each request is logged with method, path, status, duration, and API action name:

level=INFO msg=request method=POST path=/ status=200 duration=61µs request_id=... target=secretsmanager.CreateSecret
level=INFO msg=request method=PUT path=/my-bucket pattern=/{bucket} status=200 duration=30µs request_id=...
  • target -- appears for JSON/Query protocol services (Secrets Manager, DynamoDB, SQS, etc.)
  • action -- appears for Query protocol services (EC2, SNS, etc.) when Action is in the URL query string

DEBUG

In addition to INFO output, the full request body is logged:

level=DEBUG msg="request body" request_id=... body={"Name":"my-secret","SecretString":"..."}

Enable with:

KUMO_LOG_LEVEL=debug ./bin/kumo

Data Persistence

By default kumo runs as a pure in-memory emulator -- all data is lost when the process stops. This is ideal for CI/CD pipelines where each test run starts from a clean state.

For local development, set KUMO_DATA_DIR to enable persistent storage:

KUMO_DATA_DIR=./data ./bin/kumo

When enabled:

  • On startup, each service loads its previous state from $KUMO_DATA_DIR/{service}.json.
  • On graceful shutdown (SIGTERM/SIGINT), each service saves its current state.
  • The data directory is created automatically if it does not exist.
  • Writes are atomic (tmp file + rename) to prevent corruption on crash.
  • Ephemeral state (SQS in-flight messages, S3 multipart uploads) is not persisted.
$KUMO_DATA_DIR/
  s3.json
  sqs.json
  dynamodb.json
  iam.json
  ...

kumo-specific Endpoints

kumo provides additional endpoints under the /kumo/ prefix for testing purposes. These are not part of any AWS API but are useful for verifying application behavior in tests.

MethodPathDescription
GET/kumo/ses/v2/sent-emailsRetrieve a list of emails sent via the SES v2 SendEmail API
GET/kumo/pinpointsmsvoicev2/sent-messagesRetrieve a list of SMS messages sent via the Pinpoint SMS Voice v2 SendTextMessage API

Example: Retrieving sent emails

curl http://localhost:4566/kumo/ses/v2/sent-emails

Response:

{
  "SentEmails": [
    {
      "MessageId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "FromEmailAddress": "sender@example.com",
      "Destination": {
        "ToAddresses": ["recipient@example.com"]
      },
      "Subject": "Hello",
      "Body": "Hello, World!",
      "SentAt": "2025-01-01T00:00:00Z"
    }
  ]
}

Example: Retrieving sent SMS messages

curl http://localhost:4566/kumo/pinpointsmsvoicev2/sent-messages

Response:

{
  "SentTextMessages": [
    {
      "MessageId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "DestinationPhoneNumber": "+1234567890",
      "OriginationIdentity": "+0987654321",
      "MessageBody": "Hello!",
      "SentAt": "2025-01-01T00:00:00Z"
    }
  ]
}

Development

# Run tests
make test

# Run integration tests
make test-integration

# Lint
make lint

# Build
make build

Contributing

Contributions are welcome! Please see the issues for planned features and improvements.

License

MIT License

aws
cicd
cloud
continuous-integration
developer-tools
go
localstack
testing

sivchari/kumo

A lightweight AWS service emulator written in Go

Go

1,499

944 commits

updated Oct 9, 2026

See the code

README

kumo logo

Go Version License Release Lint Integration Tests

A lightweight AWS service emulator written in Go.
Works as both a CI/CD testing tool and a local development server with optional data persistence.

Features

  • No authentication required - Perfect for CI environments
  • Single binary - Easy to distribute and deploy
  • Docker support - Run as a container
  • Lightweight - Fast startup, minimal resource usage
  • AWS SDK v2 compatible - Works seamlessly with Go AWS SDK v2
  • Optional data persistence - Survive restarts with KUMO_DATA_DIR

Supported Services (82 services)

Storage

ServiceDescription
DynamoDBNoSQL database
DynamoDB StreamsDynamoDB change data capture
EBSBlock storage
ElastiCacheIn-memory caching
GlacierArchive storage
MemoryDBRedis-compatible database
S3Object storage
S3 ControlS3 account-level operations
S3 TablesS3 table buckets

Compute

ServiceDescription
BatchBatch computing
EC2Virtual machines
Elastic BeanstalkApplication deployment
LambdaServerless functions

Container

ServiceDescription
ECRContainer registry
ECSContainer orchestration
EKSKubernetes service

Database

ServiceDescription
DocumentDBMongoDB-compatible database
NeptuneGraph database
RDSRelational database service
RedshiftData warehousing

Messaging & Integration

ServiceDescription
EventBridgeEvent bus
FirehoseData delivery
KinesisReal-time streaming
MQMessage broker (ActiveMQ/RabbitMQ)
MSK (Kafka)Managed streaming for Kafka
PipesEvent-driven integration
SNSPub/Sub messaging
SQSMessage queuing

Security & Identity

ServiceDescription
ACMCertificate management
CognitoUser authentication
IAMIdentity and access management
KMSKey management
MacieData security and privacy
STSSecurity token service
Secrets ManagerSecret storage
Security LakeSecurity data lake

Monitoring & Logging

ServiceDescription
Amazon Managed Service for PrometheusManaged Prometheus workspaces with data-plane passthrough
CloudTrailAPI audit logging
CloudWatchMetrics and alarms
CloudWatch LogsLog management
X-RayDistributed tracing

Networking & Content Delivery

ServiceDescription
API GatewayAPI management (REST API)
API Gateway v2API management (HTTP/WebSocket API)
App MeshService mesh
CloudFrontCDN
ELBv2Load balancing
Global AcceleratorNetwork acceleration
LocationLocation-based services
Route 53DNS service
Route 53 ResolverDNS resolver

Application Integration

ServiceDescription
AmplifyFull-stack application hosting
AppSyncGraphQL API
Pinpoint SMS Voice v2SMS messaging
SESEmail service
SES v2Email service (v2 API)
SchedulerTask scheduling
Step FunctionsWorkflow orchestration

Management & Configuration

ServiceDescription
BackupCentralized backup service
Cloud Control APIUnified CRUD API for cloud resources
CloudFormationInfrastructure as code
CodeConnectionsSource code connections
ConfigResource configuration
OrganizationsMulti-account management
SSMSystems Manager
Service QuotasService limit management

Analytics & ML

ServiceDescription
AthenaSQL query service
ComprehendNLP service
Data ExchangeData marketplace
Entity ResolutionEntity matching
ForecastTime-series forecasting
GlueETL service
RekognitionImage/video analysis
SageMakerMachine learning

Developer Tools

ServiceDescription
CodeGuru ProfilerApplication profiling
CodeGuru ReviewerAutomated code review

Other Services

ServiceDescription
Cost ExplorerCost analysis
DLMData lifecycle manager
Directory ServiceMicrosoft AD
EMR ServerlessBig data processing
FinSpaceFinancial data management
GameLiftGame server hosting
Resilience HubApplication resilience

Quick Start

Docker

docker run -p 4566:4566 ghcr.io/sivchari/kumo:latest

With data persistence:

docker run -p 4566:4566 \
  -e KUMO_DATA_DIR=/data \
  -v kumo-data:/data \
  ghcr.io/sivchari/kumo:latest

Binary

# Build
make build

# Run
./bin/kumo

# Run with data persistence
KUMO_DATA_DIR=./data ./bin/kumo

Docker Compose

services:
  kumo:
    image: ghcr.io/sivchari/kumo:latest
    ports:
      - "4566:4566"

With data persistence:

services:
  kumo:
    image: ghcr.io/sivchari/kumo:latest
    ports:
      - "4566:4566"
    environment:
      - KUMO_DATA_DIR=/data
    volumes:
      - kumo-data:/data

volumes:
  kumo-data:

Usage Examples

S3

package main

import (
    "context"
    "strings"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/credentials"
    "github.com/aws/aws-sdk-go-v2/service/s3"
)

func main() {
    cfg, _ := config.LoadDefaultConfig(context.TODO(),
        config.WithRegion("us-east-1"),
        config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider("test", "test", "")),
    )

    client := s3.NewFromConfig(cfg, func(o *s3.Options) {
        o.BaseEndpoint = aws.String("http://localhost:4566")
        o.UsePathStyle = true
    })

    // Create bucket
    client.CreateBucket(context.TODO(), &s3.CreateBucketInput{
        Bucket: aws.String("my-bucket"),
    })

    // Put object
    client.PutObject(context.TODO(), &s3.PutObjectInput{
        Bucket: aws.String("my-bucket"),
        Key:    aws.String("hello.txt"),
        Body:   strings.NewReader("Hello, World!"),
    })
}

SQS

package main

import (
    "context"
    "fmt"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/credentials"
    "github.com/aws/aws-sdk-go-v2/service/sqs"
)

func main() {
    cfg, _ := config.LoadDefaultConfig(context.TODO(),
        config.WithRegion("us-east-1"),
        config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider("test", "test", "")),
    )

    client := sqs.NewFromConfig(cfg, func(o *sqs.Options) {
        o.BaseEndpoint = aws.String("http://localhost:4566")
    })

    // Create queue
    result, _ := client.CreateQueue(context.TODO(), &sqs.CreateQueueInput{
        QueueName: aws.String("my-queue"),
    })

    // Send message
    client.SendMessage(context.TODO(), &sqs.SendMessageInput{
        QueueUrl:    result.QueueUrl,
        MessageBody: aws.String("Hello from SQS!"),
    })

    // Receive message
    messages, _ := client.ReceiveMessage(context.TODO(), &sqs.ReceiveMessageInput{
        QueueUrl: result.QueueUrl,
    })

    for _, msg := range messages.Messages {
        fmt.Println(*msg.Body)
    }
}

DynamoDB

package main

import (
    "context"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/credentials"
    "github.com/aws/aws-sdk-go-v2/service/dynamodb"
    "github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
)

func main() {
    cfg, _ := config.LoadDefaultConfig(context.TODO(),
        config.WithRegion("us-east-1"),
        config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider("test", "test", "")),
    )

    client := dynamodb.NewFromConfig(cfg, func(o *dynamodb.Options) {
        o.BaseEndpoint = aws.String("http://localhost:4566")
    })

    // Create table
    client.CreateTable(context.TODO(), &dynamodb.CreateTableInput{
        TableName: aws.String("users"),
        KeySchema: []types.KeySchemaElement{
            {AttributeName: aws.String("id"), KeyType: types.KeyTypeHash},
        },
        AttributeDefinitions: []types.AttributeDefinition{
            {AttributeName: aws.String("id"), AttributeType: types.ScalarAttributeTypeS},
        },
        BillingMode: types.BillingModePayPerRequest,
    })

    // Put item
    client.PutItem(context.TODO(), &dynamodb.PutItemInput{
        TableName: aws.String("users"),
        Item: map[string]types.AttributeValue{
            "id":   &types.AttributeValueMemberS{Value: "user-1"},
            "name": &types.AttributeValueMemberS{Value: "Alice"},
        },
    })
}

Secrets Manager

package main

import (
    "context"
    "fmt"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/credentials"
    "github.com/aws/aws-sdk-go-v2/service/secretsmanager"
)

func main() {
    cfg, _ := config.LoadDefaultConfig(context.TODO(),
        config.WithRegion("us-east-1"),
        config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider("test", "test", "")),
    )

    client := secretsmanager.NewFromConfig(cfg, func(o *secretsmanager.Options) {
        o.BaseEndpoint = aws.String("http://localhost:4566")
    })

    // Create secret
    client.CreateSecret(context.TODO(), &secretsmanager.CreateSecretInput{
        Name:         aws.String("my-secret"),
        SecretString: aws.String(`{"username":"admin","password":"secret123"}`),
    })

    // Get secret
    result, _ := client.GetSecretValue(context.TODO(), &secretsmanager.GetSecretValueInput{
        SecretId: aws.String("my-secret"),
    })

    fmt.Println(*result.SecretString)
}

Configuration

Environment variables:

VariableDefaultDescription
KUMO_HOST0.0.0.0Server bind address
KUMO_PORT4566Server port
KUMO_LOG_LEVELinfoLog level (debug, info, warn, error)
KUMO_DATA_DIR(unset)Directory for persistent storage. When unset, data is in-memory only.

Logging

kumo logs all requests with structured fields. The log level controls the amount of detail:

INFO (default)

Each request is logged with method, path, status, duration, and API action name:

level=INFO msg=request method=POST path=/ status=200 duration=61µs request_id=... target=secretsmanager.CreateSecret
level=INFO msg=request method=PUT path=/my-bucket pattern=/{bucket} status=200 duration=30µs request_id=...
  • target -- appears for JSON/Query protocol services (Secrets Manager, DynamoDB, SQS, etc.)
  • action -- appears for Query protocol services (EC2, SNS, etc.) when Action is in the URL query string

DEBUG

In addition to INFO output, the full request body is logged:

level=DEBUG msg="request body" request_id=... body={"Name":"my-secret","SecretString":"..."}

Enable with:

KUMO_LOG_LEVEL=debug ./bin/kumo

Data Persistence

By default kumo runs as a pure in-memory emulator -- all data is lost when the process stops. This is ideal for CI/CD pipelines where each test run starts from a clean state.

For local development, set KUMO_DATA_DIR to enable persistent storage:

KUMO_DATA_DIR=./data ./bin/kumo

When enabled:

  • On startup, each service loads its previous state from $KUMO_DATA_DIR/{service}.json.
  • On graceful shutdown (SIGTERM/SIGINT), each service saves its current state.
  • The data directory is created automatically if it does not exist.
  • Writes are atomic (tmp file + rename) to prevent corruption on crash.
  • Ephemeral state (SQS in-flight messages, S3 multipart uploads) is not persisted.
$KUMO_DATA_DIR/
  s3.json
  sqs.json
  dynamodb.json
  iam.json
  ...

kumo-specific Endpoints

kumo provides additional endpoints under the /kumo/ prefix for testing purposes. These are not part of any AWS API but are useful for verifying application behavior in tests.

MethodPathDescription
GET/kumo/ses/v2/sent-emailsRetrieve a list of emails sent via the SES v2 SendEmail API
GET/kumo/pinpointsmsvoicev2/sent-messagesRetrieve a list of SMS messages sent via the Pinpoint SMS Voice v2 SendTextMessage API

Example: Retrieving sent emails

curl http://localhost:4566/kumo/ses/v2/sent-emails

Response:

{
  "SentEmails": [
    {
      "MessageId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "FromEmailAddress": "sender@example.com",
      "Destination": {
        "ToAddresses": ["recipient@example.com"]
      },
      "Subject": "Hello",
      "Body": "Hello, World!",
      "SentAt": "2025-01-01T00:00:00Z"
    }
  ]
}

Example: Retrieving sent SMS messages

curl http://localhost:4566/kumo/pinpointsmsvoicev2/sent-messages

Response:

{
  "SentTextMessages": [
    {
      "MessageId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "DestinationPhoneNumber": "+1234567890",
      "OriginationIdentity": "+0987654321",
      "MessageBody": "Hello!",
      "SentAt": "2025-01-01T00:00:00Z"
    }
  ]
}

Development

# Run tests
make test

# Run integration tests
make test-integration

# Lint
make lint

# Build
make build

Contributing

Contributions are welcome! Please see the issues for planned features and improvements.

License

MIT License

aws
cicd
cloud
continuous-integration
developer-tools
go
localstack
testing

Project health

Latest release

v0.32.0 · Oct 5, 2026

Releases this year

46

Significant stargazers

(top 24 of 26)

Rui Chen

931 followers · starred Apr 2026

Alec Thomas

1,436 followers · starred Mar 2026

Dhruv Thakur

170 followers · starred Apr 2026

Kujtim Hoxha

572 followers · starred Apr 2026