Overview
GetMyTwin is a structural observability tool for AI systems. You describe an architecture — agents, tools, models, flows — and the engine produces a living visual twin, a fragility index, knockout simulations, system-health metrics, and recommendations.
Two readings: structure (FI, SPOFs, bridges, system health) and economics (cost per route, token hotspots, expensive loops). The same architecture, two lenses.
Key concepts
- tri(e)
- Shared neighbours of an edge's endpoints. tri = 0 → no redundancy.
- Fragility Index (FI)
100 × (AF + 0.5 × F) / total_edges. Lower is better.- Resilience
100 − FI. The number we surface in the UI.- SPOF
- Node whose removal raises FI by > 15 points.
- Bridge
- Edge whose removal disconnects the graph (Tarjan).
- Cognitive Load
- Per-node connection density vs. the busiest node.
- Routing Entropy
- Shannon entropy of betweenness centrality — path diversity.
- Isolation Risk
- Per-node share of always-fragile / bridge connections.
Quick start
- Open getmytwin.io and paste any supported format into the textarea — or pick an example.
- The format is auto-detected (within ~500 ms). A chip below the textarea shows what we found.
- Click Analyze architecture → land on
/twin/[id]. - Hover any node for cognitive-load / isolation-risk; click a node for a knockout simulation; apply recommendations to see the graph reshape in real time.
- Toggle Cost Overlay for a tokens / dollars heat map, or Chaos Mode for a random-failure simulation.
- Hit View full report for the printable PDF view, or Compare before / after to share a diff URL.
GetMyTwin YAML — full reference
The native format. Every field except name on a node is optional. Unknown nodes referenced by an edge are auto-created.
Minimal example
system:
name: My System
agents:
- id: planner
tools: [search, db]
flows:
- from: user
to: plannerTop-level shape
| Field | Type | Notes |
|---|---|---|
system.name | string | Display title. |
system.traffic.requests_per_day | number | Optional — unlocks daily / monthly cost estimates. |
agents[] | list | Smart routing nodes. |
tools[] | list | External services / DBs. |
models[] | list | LLMs (optional). |
data[] | list | Data stores (optional). |
flows[] | list | Edges between nodes — { from, to }. |
Node fields
| Field | Type | Notes |
|---|---|---|
id | string | Required. Used as graph key. |
label | string | Display name (defaults to titlecased id). |
tools | string[] | Agents only — automatically creates the agent → tool edges. |
cost | object | See Cost annotations. |
role | string | Models — free-form description. |
Customer Support example (annotated)
system:
name: Customer Support AI
traffic:
requests_per_day: 500
agents:
- id: triage_agent
tools: [crm, email, vector_db]
cost:
tokens_per_call: 2500
model: gpt-4
avg_latency_ms: 800
cost_per_call_usd: 0.030
- id: refund_agent
tools: [stripe, crm]
- id: legal_agent
tools: [policy_db]
tools:
- id: crm
- id: stripe
- id: policy_db
flows:
- from: user
to: triage_agent
- from: triage_agent
to: refund_agent
- from: triage_agent
to: legal_agentuser is created implicitly the first time it's referenced. Edges are undirected for the structural analysis; cost route enumeration follows the order of the flows block.
Cost annotations
Every node can carry a cost block. Anything missing falls back to a default keyed on type + model hint, marked in the UI with an italic ~ prefix.
Schema
cost:
tokens_per_call: 2500 # integer
cost_per_call_usd: 0.030 # float
avg_latency_ms: 800 # integer
model: gpt-4 # optional hint (drives defaults)Traffic (for daily / monthly estimates)
system:
name: ...
traffic:
requests_per_day: 500Default estimates
Picked when no explicit cost is provided. The model hint matches on substring (haiku, sonnet, mini, gpt-4, gpt-5).
| Match | Tokens / call | $ / call | Latency |
|---|---|---|---|
| agent (default) | 2,000 | $0.020 | 600 ms |
| agent + gpt-4 / gpt-5 | 3,000 | $0.030 | 800 ms |
| agent + mini | 1,500 | $0.005 | 300 ms |
| agent + claude-sonnet | 2,500 | $0.020 | 600 ms |
| agent + claude-haiku | 1,000 | $0.003 | 200 ms |
| tool (default) | 0 | $0.005 | 200 ms |
| tool id contains db / sql / postgres | 0 | $0.001 | 50 ms |
| tool id contains vector / embedding | 0 | $0.002 | 80 ms |
| tool id contains api / webhook / http | 0 | $0.010 | 500 ms |
| tool id contains email / mail / smtp | 0 | $0.003 | 300 ms |
What the engine derives
- Per-request stats: average tokens, cost, latency across enumerated routes (capped at 50).
- Daily / monthly: requires
traffic.requests_per_day. - Token hotspots: route-weighted contribution percentage. Tiers at 25 / 50 / 75 %.
- Expensive loops: 3-cycles whose total per-iteration cost ≥ $0.01.
Multi-format import
Drop any of the formats below into the textarea and detection takes over. Non-native formats don't carry cost data, so the cost overlay falls back to defaults.
LangGraph (JSON)
{
"name": "Research Assistant",
"entry_point": "supervisor",
"nodes": [
{ "id": "supervisor", "type": "agent", "data": { "name": "Supervisor" } },
{ "id": "researcher", "type": "agent" },
{ "id": "web_search", "type": "tool" }
],
"edges": [
{ "source": "supervisor", "target": "researcher" },
{ "source": "researcher", "target": "web_search" }
]
}entry_point is wired up as user → entry. Node types map to GetMyTwin types (agent / tool / model / data / external) by keyword.
LangGraph (Python)
graph.add_node("supervisor", supervisor_fn)
graph.add_node("researcher", researcher_fn)
graph.add_edge("supervisor", "researcher")
graph.add_conditional_edges("researcher", router, {
"search": "web_search",
"answer": END,
})
graph.set_entry_point("supervisor")Regex-only — we do not execute your Python. Node names are inferred from id substrings (db, llm, agent, …).
CrewAI (YAML)
crew:
name: Content Pipeline
agents:
- role: Researcher
tools: [web_search, scrape]
llm: gpt-4
- role: Writer
tools: [file]
llm: gpt-4
tasks:
- description: Gather sources
agent: Researcher
- description: Draft article
agent: Writer
context:
- Gather sourcesagents[].role → agent node; agents[].tools[] → tool nodes; agents[].llm → model node connected to the agent; tasks[].context → resolves to agent → agent dependency edges.
OpenAI Agents SDK
# Python
triage = Agent(
name="Triage",
model="gpt-4.1",
tools=[search, calendar],
handoffs=[billing, support],
)// JSON
{
"agents": [{
"name": "Triage",
"model": "gpt-4.1",
"tools": ["search", "calendar"],
"handoffs": ["billing", "support"]
}]
}tools → tool nodes. model → model node attached to the agent. handoffs → agent-to-agent edges.
MCP server config (JSON)
{
"mcpServers": {
"filesystem": { "command": "npx", "args": ["..."] },
"github": { "command": "npx", "args": ["..."] }
}
}Renders as an implicit MCP Client agent connected to each server. Star topology — every edge is always-fragile, making MCP setups a textbook case for the "add a fallback" recommendation.
Tips & FAQ
Tips
- Auto-detection: paste any supported format and GetMyTwin figures out which one it is on its own.
- File upload: click Browse file or drag-drop a
.yaml,.yml,.json,.py, or.txtfile. - Maximum file size: 500 KB.
- Cost data is optional but enables the Cost Overlay, hotspot detection, and loop-guard recommendations.
FAQ
Is my YAML stored anywhere?
Analyses live in process memory only. They survive page reloads while the server is up but are wiped on every deploy. Auth tables (User / VerificationToken) are the only persisted data. There is no team or sharing layer — the only persistence vector is the session id in your URL.
What's the difference between an SPOF and a bridge?
A bridge is an edge whose removal disconnects the graph. A SPOF is a node whose removal raises the FI by > 15 points (which usually also disconnects the graph, but doesn't have to). Bridges are about connectivity; SPOFs are about resilience.
How does "Apply" recompute the FI?
Every recommendation carries a structural change payload (nodes + edges to add). The client merges all applied changes into the original architecture, re-runs the FI engine in the browser, and rerenders. The diff page (/diff/[id]) does the same off the URL params.
How are costs estimated when I don't provide them?
See the Cost annotations table. We match on node type and on substrings in the id (or the cost.model hint). Anything filled from defaults renders as italic ~$value in the UI.
Why is the Chaos Mode mutually exclusive with Cost Overlay?
Both modes re-skin the graph — Chaos colors edges grey-dashed as they fail, Cost colors them by route price. Showing both at once would muddle the visual signal, so toggling one resets the other.
What about graphs without a `user` node?
The cost engine picks degree-1 leaves as fallback sources. For MCP / star topologies, the central client node is picked. Structural analyses (FI, SPOF, bridges) don't depend on a user node at all.
My format isn't detected correctly.
Use the Change format dropdown below the textarea to force a specific format. Auto-detection is a best effort — for ambiguous inputs (e.g. JSON shaped like both CrewAI and OpenAI Agents) it falls back to a reasonable guess that you can override manually.
Can I mix formats in a single input?
No — each input is parsed as a single format. Use GetMyTwin YAML if you want the richest feature set (cost annotations, traffic, model hints). Other formats are great for instant imports but lose cost data, which then falls back to defaults.
How are connections created?
Two sources, merged and deduplicated:
agents[].tools— every tool listed under an agent produces an agent → tool edge automatically.flows[]— explicit{ from, to }pairs add edges between any two nodes.
Edges are treated as undirected by the structural engine. The cost engine uses flow order for route enumeration.
What's the maximum graph size?
GetMyTwin handles graphs up to roughly 200 nodes comfortably. Larger graphs may slow down the visualization (React Flow layout + Brandes betweenness centrality both have quadratic behaviour on dense inputs).