Appendix
Every workload type, fault kind, guard policy, AWS limit, environment variable and CLI flag, in one place.
Reference tables that would clutter a chapter. Everything here was generated from the live registries or read from the code, not typed out by hand.
The workload and fault tables came from:
from proteus.web.catalog_view import build_catalog
catalog = build_catalog()
len(catalog["archetypes"]), len(catalog["profiles"]), len(catalog["faults"])
# (12, 56, 14)
That is the same call the GUI palette makes, so these tables and the palette cannot disagree.
Workload types#
68 in total, from two layers.
Archetypes — 12#
Hand-written, with bespoke internal behavior: a Kafka consumer's lag responds to its producer's rate, a noisy neighbor hurts its victim more than itself. The metrics count is measured, not declared — each generator is asked for representative ticks and the distinct metric names are counted. Same for signals: an archetype claims a signal only if its generator really yielded a record for it.
Archetypes publish into the custom namespace proteus/{model-name} and carry their
AWS counterpart in attributes. The AWS namespaces column lists the namespaces
their metrics are mapped onto, where a mapping is confirmed.
| Kind | Label | AWS namespaces mapped | Metrics | Signals |
|---|---|---|---|---|
alb |
ALB | — (custom namespace only) | 16 | metrics, traces, logs |
nginx-web |
Nginx Web | — (custom namespace only) | 7 | metrics, traces, logs |
app-service |
App Service | — (custom namespace only) | 19 | metrics, traces, logs |
lambda |
Lambda | — (custom namespace only) | 11 | metrics, traces, logs |
rds-postgres |
RDS Postgres | — (custom namespace only) | 15 | metrics, traces, logs |
elasticache |
Elasticache | — (custom namespace only) | 10 | metrics, traces, logs |
kafka |
Kafka | — (custom namespace only) | 11 | metrics, traces, logs |
opensearch |
Opensearch | — (custom namespace only) | 10 | metrics, traces, logs |
eks-workload |
EKS Workload | ContainerInsights |
28 | metrics, traces, logs |
ecs-workload |
ECS Workload | AWS/ECS, ECS/ContainerInsights |
29 | metrics, traces, logs |
bedrock-agent |
Bedrock Agent | AWS/Bedrock, AWS/Bedrock/Guardrails |
17 | metrics, traces, logs |
browser-rum |
Browser RUM | — (custom namespace only) | 7 | metrics, rum |
180 distinct metric names across the twelve, of which 45 carry a confirmed AWS
counterpart through proteus.aws_metric and proteus.aws_namespace attributes.
browser-rum is the only archetype that emits RUM and the only one that does not
emit traces. It is also the only one whose runtime is browser.
A thirteenth archetype, custom, exists in the schema but is not a workload — it is
the delegation mechanism that renders whichever profile a service's kind names. It
is deliberately absent from the palette, because probing it with no kind yields a
tile with no metrics and no signals, which looks broken.
Profiles — 56#
Declarative. Each covers one distinct AWS namespace, and adding an AWS service is a data edit rather than new code. 393 metric specifications across the 56.
20 of the 393 specs name no AWS counterpart. That null is load-bearing, not an oversight: an invented AWS metric name reads as authoritative and sends an operator hunting an alarm that cannot exist. Null means "no confirmed counterpart", never "not looked up yet". Where a profile has unmapped specs, the count is noted below.
| Kind | Label | AWS namespace | Metrics |
|---|---|---|---|
apigateway-api |
API Gateway REST API | AWS/ApiGateway |
7 |
apprunner-service |
App Runner service | AWS/AppRunner |
8 |
appsync-api |
AppSync GraphQL API | AWS/AppSync |
5 |
athena-workgroup |
Athena workgroup | AWS/Athena |
6 |
aurora-cluster |
Aurora Cluster | AWS/RDS |
10 |
autoscaling-group |
Auto Scaling group | AWS/AutoScaling |
6 |
backup-vault |
AWS Backup vault | AWS/Backup |
5 |
batch-queue |
AWS Batch job queue | AWS/Batch |
6 (6 unmapped) |
beanstalk-environment |
Elastic Beanstalk environment | AWS/ElasticBeanstalk |
9 |
bedrock-model |
Bedrock model invocation | AWS/Bedrock |
8 |
clb |
Classic Load Balancer | AWS/ELB |
8 |
clientvpn-endpoint |
Client VPN endpoint | AWS/ClientVPN |
6 |
cloudfront-distribution |
CloudFront distribution | AWS/CloudFront |
9 |
cognito-userpool |
Cognito user pool | AWS/Cognito |
7 |
connect-instance |
Amazon Connect instance | AWS/Connect |
7 |
directconnect-connection |
Direct Connect connection | AWS/DX |
7 |
documentdb-cluster |
DocumentDB Cluster | AWS/DocDB |
9 |
dynamodb-table |
DynamoDB Table | AWS/DynamoDB |
11 |
ebs-volume-standalone |
EBS volume | AWS/EBS |
8 |
ec2-instance |
EC2 instance | AWS/EC2 |
14 |
efs-filesystem |
EFS File System | AWS/EFS |
7 |
emr-cluster |
EMR cluster | AWS/ElasticMapReduce |
10 |
eventbridge-bus |
EventBridge bus | AWS/Events |
6 |
fargate-task |
Fargate task | ECS/ContainerInsights |
9 |
firehose-stream |
Firehose delivery stream | AWS/Firehose |
5 |
fsx-filesystem |
FSx File System | AWS/FSx |
6 |
globalaccelerator |
Global Accelerator | AWS/GlobalAccelerator |
5 |
glue-job |
Glue job | Glue |
7 |
keyspaces-table |
Keyspaces Table | AWS/Cassandra |
6 |
kinesis-stream |
Kinesis data stream | AWS/Kinesis |
6 |
kms-key |
KMS key | AWS/KMS |
3 (2 unmapped) |
lambda-provisioned |
Lambda provisioned concurrency | AWS/Lambda |
5 |
lightsail-instance |
Lightsail instance | AWS/Lightsail |
6 |
mediaconvert-queue |
MediaConvert queue | AWS/MediaConvert |
5 |
memorydb-cluster |
MemoryDB Cluster | AWS/MemoryDB |
8 (1 unmapped) |
mq-broker |
Amazon MQ broker | AWS/AmazonMQ |
8 |
mwaa-environment |
MWAA environment | AWS/MWAA |
8 (2 unmapped) |
nat-gateway |
NAT gateway | AWS/NATGateway |
8 |
neptune-cluster |
Neptune Cluster | AWS/Neptune |
7 (1 unmapped) |
nlb |
Network Load Balancer | AWS/NetworkELB |
9 (1 unmapped) |
redshift-cluster |
Redshift Cluster | AWS/Redshift |
10 |
route53-healthcheck |
Route 53 health check | AWS/Route53 |
6 |
s3-bucket |
S3 Bucket | AWS/S3 |
11 |
sagemaker-endpoint |
SageMaker endpoint | AWS/SageMaker |
12 |
secretsmanager |
Secrets Manager | AWS/SecretsManager |
3 (2 unmapped) |
shield-protection |
Shield Advanced protection | AWS/DDoSProtection |
4 |
sns-topic |
SNS topic | AWS/SNS |
5 (1 unmapped) |
sqs-queue |
SQS queue | AWS/SQS |
8 (1 unmapped) |
ssm-managed-instance |
SSM managed instance | AWS/SSM-RunCommand |
3 |
stepfunctions-statemachine |
Step Functions state machine | AWS/States |
7 |
synthetics-canary |
CloudWatch Synthetics canary | CloudWatchSynthetics |
7 |
timestream-database |
Timestream Database | AWS/Timestream |
6 (1 unmapped) |
transit-gateway |
Transit Gateway | AWS/TransitGateway |
7 |
vpc-endpoint |
VPC endpoint (PrivateLink) | AWS/PrivateLinkEndpoints |
5 |
vpn-connection |
Site-to-Site VPN connection | AWS/VPN |
3 |
waf-webacl |
WAF web ACL | AWS/WAFV2 |
6 (2 unmapped) |
Note The namespace column is what the metric stands in for, carried as an attribute. Proteus never publishes into any of these — a namespace beginning
AWS/is reserved and every request to it is rejected. See the reserved-prefix rule.
Runtimes and infra kinds#
Six runtimes: eks, ecs, ec2, lambda, managed, browser.
Eight infra kinds — the shared resources faults can contend over:
| Kind | Capacity keys in the default estate |
|---|---|
load-balancer |
lcu |
rds-instance |
iops, max_connections, mem_gib, storage_gib, vcpu |
cache-cluster |
mem_gib, nodes, vcpu |
kafka-cluster |
mem_gib, nodes, partitions, vcpu |
opensearch-domain |
mem_gib, nodes, shards, storage_gib, vcpu |
eks-nodegroup |
mem_gib, nodes, vcpu |
ecs-cluster |
mem_gib, vcpu |
ebs-volume |
iops, storage_gib |
Fault kinds#
14, each with a severity in 0..1 and a time window. All compose through a single
FaultEffect seam, so a fault does not need to know which archetype it lands on.
Faults ramp rather than step, and reach other services by contention through shared
infrastructure - not along depends_on. See the deep dive on faults.
Targets is the drop-target class the GUI palette enforces.
| Kind | What it does | Targets | Tunable params |
|---|---|---|---|
cpu-saturation |
CPU pinned near 100%: latency degrades superlinearly, with throttling in the logs. | service | cpu_add, latency_mult, error_rate_add |
oom-kill |
Memory exceeds the limit, pods are OOM-killed and restart; traffic dips in bursts. | service | mem_add, restarts_per_min, rps_mult, pulse_period_s |
disk-full |
The volume fills and writes fail with ENOSPC. | service | disk_used_add, error_rate_add |
slow-query |
A query plan regresses: latency only, with flat CPU and flat errors. | service | latency_mult, statement |
connection-pool-exhaustion |
All pool connections are checked out: callers queue, then time out waiting. | service | pool_size, latency_mult, error_rate_add |
thread-pool-rejection |
The work queue is full: errors dominate while latency barely moves. | service | error_rate_add, latency_mult |
queue-depth |
Consumers fall behind: lag and queue depth climb, latency rises moderately, errors flat. | service | lag_msgs, depth_msgs, latency_mult |
cache-stampede |
Cache hit ratio collapses and the miss storm multiplies downstream load. | service | cache_hit_mult, downstream_rps_mult, latency_mult |
shard-hotspot |
Load skews onto one shard: it runs hot and rejects work from a full queue. | service | latency_mult, cpu_add, error_rate_add, shard |
dependency-timeout |
A downstream call hangs to its timeout ceiling, then errors. | service | timeout_ms, error_rate_add, max_latency_mult, target_dependency |
network-packet-loss |
Packets drop; retries stretch latency and leak a moderate error rate. | service | packet_loss_add, latency_mult, error_rate_add |
noisy-neighbor |
A co-tenant saturates shared infrastructure; victims slow with no local cause. | infra | aggressor_tenant, cpu_add, latency_mult, error_rate_add, aggressor_cpu_add, aggressor_latency_mult |
page-load-latency |
Front-end page loads slow sharply with a flat error rate. | service | latency_mult, rps_mult |
agent-quality-regression |
Agent answer quality drops while latency, errors, CPU and tokens stay healthy. | service | eval_score_mult |
noisy-neighbor is the only infra-targeted kind. Aimed at a service it has no
aggressor and is deliberately inert, so the palette will not offer it as a service
drop target. Its two aggressor_* parameters are what make it asymmetric — the
aggressor's CPU climbs while the victim's latency doubles — because a symmetric
version is not findable, and finding it is the exercise.
Two pairs are deliberately hard to tell apart without reading more than one signal:
slow-query is latency with flat CPU and flat errors, while
thread-pool-rejection is errors with barely-moved latency. agent-quality-regression
is the hardest of all, because every conventional signal stays healthy.
Guard policies#
Five. Set with --guard; the default is estimate-confirm.
| Policy | Allowed | Confirmation | Sends | Network | Notes |
|---|---|---|---|---|---|
estimate-confirm |
yes | required | yes | yes | The default. Shows the projection, requires an explicit yes. |
budget-ceiling |
only under the cap | required | yes | yes | Refuses if the monthly ledger total plus this run exceeds --cap. |
warn-only |
yes | none | yes | yes | Prints the projection and proceeds. |
paranoid |
yes | none | no | none | Renders and costs everything, sends nothing, makes no network call at all. |
unlimited |
yes | none | yes | yes | No spend check. Prints a banner saying so. |
--cap defaults to $50 and applies to budget-ceiling only. --dry-run on
seed, live or firehose forces paranoid.
paranoid also disables the live pricing lookup and falls back to the built-in rate
table. That is not an oversight: the projection runs before the guard can refuse
anything, so a cold or stale pricing cache under paranoid would make an outbound
AWS call before anything had a chance to stop it. A slightly staler cost figure buys
a promise that actually holds.
Two policies print a banner, because both are surprising in opposite directions:
PARANOID GUARD: telemetry will be rendered and costed but NOTHING will be sent to AWS.
UNLIMITED GUARD: every projected record will be sent to AWS with no spend check and
no confirmation. You are responsible for the bill.
AWS ingestion limits#
Endpoints are HTTP only, no gRPC. OTLP 1.x, binary or JSON, gzip or none.
| Signal | Endpoint | SigV4 service | Notes |
|---|---|---|---|
| metrics | https://monitoring.{region}.amazonaws.com/v1/metrics |
monitoring |
— |
| logs | https://logs.{region}.amazonaws.com/v1/logs |
logs |
Requires x-aws-log-group and x-aws-log-stream headers |
| traces | https://xray.{region}.amazonaws.com/v1/traces |
xray |
Needs Transaction Search with destination CloudWatchLogs, or every request is rejected |
| RUM | https://dataplane.rum.{region}.amazonaws.com/appmonitors/{id}/ |
rum |
Needs a real app monitor id, from the stack outputs |
Per-request limits:
| metrics | logs | traces | RUM | |
|---|---|---|---|---|
| Max records | 1,000 datapoints | 10,000 events | 10,000 spans | no published cap |
| Max uncompressed | 5 MB | 1 MB (20 MB in some regions) | 5 MB | no published cap |
| Max time gap per request | — | 24 h | 24 h | — |
| Earliest timestamp | −14 d | −14 d | −14 d | — |
| Latest timestamp | +10 min | +2 h | +2 h | — |
| TPS per account/region | 500 | 5,000 | — | — |
The 1,000-datapoint metrics cap is the tightest constraint in the system, and the
+10-minute metrics future window is the tightest of the three. Proteus uses the
tightest of each so one window is safe for every signal: −14 d to +10 min.
What Proteus actually batches at, deliberately under each ceiling:
| metrics | logs | traces | RUM | |
|---|---|---|---|---|
| Records per request | 1,000 | 10,000 | 10,000 | 200 |
| Bytes per request | 4,000,000 | 800,000 | 4,000,000 | 256,000 |
| Hours per request | — | 23 | 23 | — |
Logs are capped at 1 MB in most regions and 20 MB in a handful — us-east-1,
us-west-2, eu-west-1 "and others". Because the full list is not documented, the
conservative 1 MB is used everywhere; the record cap binds first anyway.
Other limits that shaped the code:
- Metrics: 150 labels max per datapoint, 1,024 characters max per attribute value, 40 KB max metadata per series, 1M new series per 10-minute window.
- Traces: 200 KB max single span, 16 KB max per unique resource+scope.
- Logs: 1 MB max single event.
- CloudFormation: 51,200 bytes inline template, 1,000,000 bytes via S3.
The reserved AWS/ prefix#
You cannot publish to a namespace beginning AWS/. It is reserved and the
request is rejected. ContainerInsights and ECS/ContainerInsights are reserved
too.
So synthetic metrics go to the custom namespace proteus/{model-name} and carry
their AWS counterpart in two attributes:
| Attribute | Holds |
|---|---|
proteus.aws_metric |
The metric an operator would normally alarm on |
proteus.aws_namespace |
The namespace it would normally live in |
That lets the GUI say "this stands for pod_cpu_utilization_over_pod_limit in
ContainerInsights" without ever writing into a reserved namespace. The rule is
enforced in code — a profile spec whose name begins AWS/ raises at render — and
asserted by the test suite against rendered records.
Environment variables#
Three are read by the tool. All are resolved at call time, never captured into a module-level constant, so a test or a side-by-side estate can isolate itself.
| Variable | Read by | Default | Effect |
|---|---|---|---|
PROTEUS_HOME |
world model store, pricing cache, spend ledger, hunt ledger, GUI layout | ~/.proteus |
The state directory. Point it elsewhere to keep several estates side by side. |
PROTEUS_REGION |
every command's --region default |
falls back to AWS_REGION, then us-west-2 |
The default region for both the boto3 session and the OTLP endpoints. |
PROTEUS_MODEL |
chat and hunt |
a cross-region inference profile | The Bedrock model id or inference profile to use. |
AWS_REGION is consulted as a fallback for PROTEUS_REGION. Standard AWS
credential variables and AWS_PROFILE work as usual, since credentials are resolved
by boto3 — --profile is the explicit override.
Note
PROTEUS_VERSIONis not an environment variable, despite appearing in the code. It is a constant resolved from installed package metadata, surfaced as the stack'sProteusVersionoutput and as a resource tag. Setting it in your shell does nothing.
proteus about prints the resolved state directory and region, which is the fastest
way to find out that PROTEUS_HOME is set somewhere you forgot about.
State directory#
Contents of $PROTEUS_HOME (default ~/.proteus):
| Path | Holds |
|---|---|
world.json |
The current world model |
world.<timestamp>.bak.json |
Automatic backups, written before any overwrite |
layout.json |
Canvas node positions from the GUI |
pricing-{region}.json |
Cached AWS Pricing API rate card, one per region, 24-hour freshness |
spend.json |
The budget-ceiling monthly spend ledger, in estimated dollars |
hunts/ |
Sealed hunt answers and guess history |
Warning Nothing in this directory belongs in git. It holds your sealed hunt answers, so committing it gives away every exercise.
teardowndoes not touch it — delete it yourself for a genuinely clean machine.
CLI surface#
18 top-level commands. Every flag below was read from --help on this build.
| Command | What it does | Touches AWS |
|---|---|---|
doctor |
Check prerequisites and whether an existing deployment is still live. | read-only |
plan |
Build a world model from a preset and write it to disk. | no |
bootstrap |
Deploy the CloudFormation stack the synthetic telemetry depends on. | writes |
teardown |
Delete the stack. Shows exactly what will go first. | deletes |
seed |
Backfill history so the console is populated before you present. | sends telemetry |
live |
Stream telemetry with current timestamps while you narrate. | sends telemetry |
firehose |
Push data as fast as the quotas allow, to watch it arrive live. | sends telemetry |
serve |
Start the web GUI: compose the estate, drag faults, watch the cost, inject. | only when you press inject |
about |
Show the banner, version and where state lives. | no |
show |
Print the current estate: services, dependencies, infra and active faults. | no |
faults |
List the fault kinds this build can inject. | no |
import-cfn |
Build a world model from your own CloudFormation template. | no |
import-live |
Clone a real AWS account into a world model: topology plus observed baselines. | read-only, and bills for GetMetricData |
rename |
Rename services or infra nodes by pattern, rewriting every reference. | no |
chat |
Edit the estate in plain language. The AI edits the model, never the data. | Bedrock only |
hunt |
Hunt the injected fault. Four subcommands. | Bedrock only |
docs |
Build and preview the documentation site. | no |
site |
Assemble the product website and documentation. | no |
docs and site build this documentation rather than any telemetry. They are listed
because they appear in proteus --help, and a surface table that omits a command a
reader can see is worse than no table.
Shared options#
--model <path> (world model path) appears on doctor, plan, import-cfn,
import-live,
bootstrap, teardown, seed, live, firehose, serve, show, chat and
hunt start. It is absent from rename, which reads and writes the default model
path only.
--profile <str> (AWS profile) appears on every command that needs credentials:
doctor, bootstrap, teardown, seed, live, firehose, serve, chat,
hunt start, hunt guess, import-live. It is absent from import-cfn, which is the flag-level
consequence of that command making no AWS call at all.
--region <str> appears on the same set plus plan, import-cfn and
import-live. Default is
PROTEUS_REGION → AWS_REGION → us-west-2.
--stack <str> (stack name override) appears on doctor, bootstrap, teardown,
seed, live and firehose. Without it, the name is proteus-{model-name}.
Per-command options#
proteus doctor
| Option | Type | Default | Meaning |
|---|---|---|---|
--days |
int | 14 |
Backfill horizon the checks should assume. |
proteus plan
| Option | Type | Default | Meaning |
|---|---|---|---|
--preset |
str | northwind-rx |
One of ai-chatbot, alb-fleet, minimal, ml-pipeline, northwind-rx, three-tier, web-server. Shapes and counts: The seven presets. |
--seed |
int | 1337 |
RNG seed; identical seeds give identical data. |
--force / --no-force |
flag | no-force |
Overwrite an existing world model. |
proteus rename {selector} {pattern}
Offline. Both arguments are required. Renames services by default, infra nodes with
--infra, and rewrites every reference to the old name as it goes.
| Option | Type | Default | Meaning |
|---|---|---|---|
--infra |
flag | off | Rename infrastructure nodes instead of services. |
--seed |
int | the model's own seed | Seed for # and {rand} placeholders. |
--start |
int | 1 |
First value for a counter placeholder. |
--dry-run |
flag | off | Print the plan and change nothing. |
--yes |
flag | off | Apply without confirming. |
Name patterns#
The {pattern} argument. Two grammars, equivalent where they overlap — webserver00 is
webserver{n:02}, and cache-## is cache-{rand:2}.
| Form | Example | Result |
|---|---|---|
| zero run | webserver00 |
webserver01, webserver02, … |
| zero run | web-000 |
web-001, web-002, … |
# run |
cache-## |
two random digits |
{n} |
web-{n} |
web-1, web-2, … |
{n:02} |
web-{n:02} |
web-01, web-02, … |
{rand:2} |
cache-{rand:2} |
two random digits |
{1..12} |
web-{1..12} |
web-1 … web-12, exactly 12 names |
{01..12} |
web-{01..12} |
web-01 … web-12; a padded bound pads the output |
{lit:00} |
web-{lit:00}-{n} |
web-00-1, web-00-2, … |
| escape | web-\0\0 |
literal web-00 |
The counter rule, exactly: a maximal run of digits is a counter if and only if it consists entirely of zeros and is two or more characters long.
Read that as written rather than as a rule about what precedes the zeros, because the two readings differ in one case and agree everywhere a reader would think to check:
| Pattern | Digit run | Result | The lookbehind misreading gives |
|---|---|---|---|
svc-100 |
100 |
literal svc-100 |
literal — agrees |
port-8080 |
8080 |
literal port-8080 |
literal — agrees |
web-0010 |
0010 |
literal web-0010 |
web-0110 — wrong |
web-0010 is the only case that separates them: the rule looks at the whole run 0010,
which is not entirely zeros, so nothing in it is a placeholder. A single 0 is likewise
literal, so web0 and s3-bucket-0 keep their names. To put a counter after a digit,
write it explicitly: svc-1{n:02} gives svc-101, svc-102, …
A pattern may hold one counter. web-00-shard-00 is refused, in either spelling,
because two counters could reasonably move together, nest, or count independently. Ranges
are exempt — they carry their own values, so web-{1..3}b{1..3} yields web-1b1,
web-2b2, web-3b3.
Random placeholders seed from the model's own seed unless --seed overrides it, so a
rename is reproducible from the world model alone.
Selectors#
The {selector} argument, matched against existing names.
| Form | Example | Matches |
|---|---|---|
| glob | web* |
web, webs, web-tier, webserver01 |
| glob | ? |
exactly one character |
| regex | /^api-\d+$/ |
api-1, api-42; not api-x or xapi-1 |
Globs are full matches, so web* does not match myweb-tier — use *web*. Every
other character is literal: web.server matches only web.server, and [abc] is three
literal characters rather than a character class. Regexes are wrapped in slashes and
matched with re.fullmatch, which makes ^ and $ redundant but harmless. ** is an
alias for * and nothing more — service names are flat, with no separator to cross, so
web**.server and web*.server select the same names. Zero matches is an empty result
rather than an error.
proteus import-cfn <template>
Makes no AWS call. The template argument is required and is never modified.
| Option | Type | Default | Meaning |
|---|---|---|---|
--name |
str | the template's file name | Estate name. |
--seed |
int | 1337 |
RNG seed; identical seeds give identical data. |
--include |
str | — | Expand a nested stack: LogicalId=path/to/child.yaml. Repeatable. LogicalId/ChildId for a grandchild. |
--force / --no-force |
flag | no-force |
Overwrite an existing world model. |
--strict |
flag | off | Exit non-zero if any resource type could not be mapped. For CI. |
--dry-run |
flag | off | Print the report and write nothing. |
proteus import-live
Reads a real account. Read-only — only Describe, List and Get, enforced by a
client wrapper that raises before boto3 sees the call. GetMetricData is the only
billed call. See the walkthrough
for the limitation that is not visible in its output.
| Option | Type | Default | Meaning |
|---|---|---|---|
--days |
float | 14.0 |
How far back to read CloudWatch for the baselines. |
--services |
str | all | Comma-separated subset to probe. Anything not probed is absent from the replica and reported as such. |
--name |
str | live-<account>-<region> |
Estate name. |
--seed |
int | 1337 |
RNG seed; identical seeds give identical data. |
--force / --no-force |
flag | no-force |
Overwrite an existing world model. |
--discover-only |
flag | off | Stop after discovery. Requests no metric data, so it costs nothing and every baseline is an archetype default. |
--no-census |
flag | off | Skip the tagging-API census and probe every selected service regardless. Slower, and the only way to reach a resource the tagging API does not return. |
--strict |
flag | off | Exit non-zero if anything could not be mapped or replicated. For CI. |
--dry-run |
flag | off | Print the report and write no world model. |
--yes |
flag | off | Answer both cost disclosures. Read them first. |
proteus bootstrap
| Option | Type | Default | Meaning |
|---|---|---|---|
--log-retention-days |
int | 14 |
Must be at least the backfill horizon or backdated logs are dropped. |
--seed-days |
float | 14.0 |
Backfill horizon you intend to seed. Synthesis refuses if retention is shorter. |
--print |
flag | off | Print the template, deploy nothing. |
proteus teardown
| Option | Type | Default | Meaning |
|---|---|---|---|
--yes |
flag | off | Skip the confirmation prompt. |
proteus seed
| Option | Type | Default | Meaning |
|---|---|---|---|
--days |
float | 14.0 |
How far back to backfill (max 14). |
--interval |
float | 60.0 |
Sampling interval in seconds. |
--guard |
policy | estimate-confirm |
Cost guard policy. |
--cap |
float | 50.0 |
Monthly cap in USD for budget-ceiling. |
--dry-run |
flag | off | Render and size, send nothing. Forces paranoid. |
--yes |
flag | off | Skip the confirmation prompt. |
proteus live
| Option | Type | Default | Meaning |
|---|---|---|---|
--minutes |
float | 30.0 |
How long to stream before stopping. |
--interval |
float | 60.0 |
Sampling interval in seconds. |
--tick |
float | 30.0 |
Seconds between send cycles. |
--guard |
policy | estimate-confirm |
Cost guard policy. |
--cap |
float | 50.0 |
Monthly cap in USD for budget-ceiling. |
--dry-run |
flag | off | Render and size, send nothing. |
--yes |
flag | off | Skip the confirmation prompt. |
proteus firehose — the same options as live with denser defaults:
--minutes 10.0, --interval 10.0, --tick 10.0.
proteus serve
| Option | Type | Default | Meaning |
|---|---|---|---|
--port |
int | 8787 |
Port to listen on, bound to 127.0.0.1 only. |
--open-browser / --no-open-browser |
flag | open-browser |
Open the default browser on start. |
proteus chat takes an optional positional message. Omit it for a REPL; a
blank line exits.
proteus hunt has four subcommands:
| Subcommand | Arguments | Options |
|---|---|---|
start |
— | --difficulty (easy/medium/hard, default medium), --region, --profile, --model |
guess |
<hunt-id> <answer...> (both required) |
--region, --profile |
reveal |
<hunt-id> (required) |
— (offline) |
list |
— | — (offline) |
proteus show, proteus faults and proteus about take no options beyond
--model on show.
Glossary#
Estate. The modeled distributed system as a whole: its services, their
dependencies, the infrastructure they share, and the tenants that share it. What
proteus show prints.
World model. The estate as data — a single JSON document at
$PROTEUS_HOME/world.json, defined by proteus/model/schema.py. It is the only
thing chat and hunt ever edit. Everything downstream is derived from it plus a
seed, which is what makes runs reproducible. Carries a revision and a
fingerprint, and the deployed stack records the fingerprint it was built from.
Archetype. One of the 12 hand-written workload types, with bespoke internal logic. A Kafka consumer's lag responds to its producer's rate because the archetype knows about both.
Profile. One of the 56 declarative workload types, each covering one AWS
namespace. A profile declares its metrics rather than computing them, so adding an
AWS service is a data edit. Reached through the custom archetype.
Tenant. A logical customer sharing infrastructure with other tenants. What makes
noisy-neighbor possible: one tenant's aggression is another's unexplained latency.
Rendered as node color on the GUI canvas.
Fault. An injected failure: one of the 14 kinds, aimed at a service or an infra
node, with a severity in 0..1 and a start and end time. Ramps rather than steps. Reaches other
services through shared infrastructure, not along depends_on.
Effect. The FaultEffect seam through which a fault reaches a workload. A fault
composes effects — a latency multiplier, a CPU addend, an error-rate addend — so it
does not need to know which archetype it lands on. Frozen contract; see
Faults.
Tick. One instant of rendering for one service: a timestamp, an interval, the service, the model, the composed fault effect, and a seeded RNG. Generators receive ticks and yield records.
Window. A start, an end, and a sampling interval. Every render takes one.
Clamped to the ingestible range, −14 d to +10 min.
Signal. One of the four telemetry types: metrics, logs, traces, rum.
Each has its own endpoint, its own per-request caps, and its own emitter.
Record. A signal-neutral intermediate — MetricPoint, LogRecord,
SpanRecord, RumEvent. The renderer produces records; emitters translate records
into wire calls. This split is what makes faults testable without reading a console.
Seed. The RNG seed on the world model, default 1337. Same model plus same seed
plus same window gives byte-identical telemetry.
seed (the command). Backfill: telemetry with backdated timestamps, up to 14
days, so the console is populated before you present. Not to be confused with the RNG
seed above.
live. Stream telemetry with current timestamps, in cycles, while you narrate.
firehose. live with a much denser interval, to watch data arrive. Self-throttles
below the account TPS ceilings so the run slows rather than collecting HTTP 429s.
Hunt. A fault-finding exercise. hunt start injects a hidden fault and seals the
answer; you find it in CloudWatch Omni; hunt guess grades you on root cause,
affected service and time window. The answer is withheld from show, from chat,
from hunt list, and from the grader's own hint until you score 70 overall.
Guard. The cost policy that gates every injection. Five policies; all injecting commands go through one code path, so no mode can skip it.
Projection. The pre-flight estimate: record counts per signal, uncompressed wire bytes, request count, new metric series, and a dollar figure at list price. Deliberately pessimistic.