workflow-generator
Scan the current project and produce a complete visual system workflow with concurrency capacity analysis.
Steps
Locate the project root — use the current working directory unless the user specified a path.
Run the analyzer:
python3 ~/.claude/skills/workflow-generator/scripts/analyze.py <project_root> <project_root>/WORKFLOW.html
Optional flags, appended after the two positional args:
--access-log <path> — overlay real request counts (from a combined/common log file) onto
the codebase dependency graph's HTTP-entry edges, instead of import-direction only.
--graph-detail auto|files|dirs — force file-level or directory-level graph nodes. Default
auto aggregates to directories once a project exceeds ~350 source files.
Open the output:
xdg-open <project_root>/WORKFLOW.html 2>/dev/null || open <project_root>/WORKFLOW.html 2>/dev/null || true
Report to the user — include:
- Framework and worker count
- Concurrent request capacity (total I/O + practical throughput)
- Primary bottleneck
- Detected storage and external sources
- Clickable link to
WORKFLOW.html
Output sections
The generated WORKFLOW.html always contains all of the following:
Stat row — 4–6 large-number tiles:
- API Worker Processes (replicas × uvicorn/gunicorn workers)
- Max Concurrent Async I/O (~100 per asyncio worker)
- Max Parallel CPU Tasks (asyncio.Semaphore limit, if detected)
- Rate Limit (nginx / slowapi / express-rate-limit, if detected)
- Practical Throughput (what the real ceiling is after all limits)
- LLM Timeout (if an LLM provider is detected)
System Architecture diagram — adaptive layered CSS flow:
- EXTERNAL SOURCES & CLIENTS — webhook sources (Jira, Slack, ADO, GitHub, Stripe), users
- GATEWAY / REVERSE PROXY — nginx, Caddy, Traefik (with rate limits + worker_connections)
- APPLICATION LAYER — API framework + frontend (Streamlit, React, Next.js, etc.)
- PROCESSING & QUEUE LAYER — Semaphore-guarded CPU tasks, Celery/Bull/Kafka workers
- AI / INTELLIGENCE LAYER — LLM providers, embedding, evaluation framework
- STORAGE & PERSISTENCE — vector DB, relational DB, NoSQL, Redis, S3
Data Flow Paths — step-by-step cards per detected flow:
- Write Path (webhook route + signature-check evidence, if any)
- Read Path (LLM + vector store presence)
- Queue/Background Jobs
- Generic HTTP flow (if nothing else detected)
These cards combine genuinely detected facts (provider names, models, timeouts,
specific routes, real HMAC-verification evidence) with the typical shape of that
kind of component. They are not a trace of an actual request path through the code —
the tool never confirms that a detected webhook source and a detected route are
the same request. Card titles say "(inferred, not traced)" or "(typical pattern)"
for exactly this reason, and individual steps say "not confirmed" wherever the
claim isn't backed by direct evidence.
Concurrency Model table — every layer with model / ceiling / limiting factor (a category label, not a file:line pointer into the user's code)
Bottleneck Analysis — ranked bar cards (CRITICAL → LOW). Severities are derived
from the same min() comparison used for the "Practical Throughput" stat, so this
section and that stat can never disagree with each other.
Codebase Dependency Graph — a force-directed graph of every source file (Python, JS/TS,
Go, Java, Rust, Ruby) as a node and every real, parser-resolved import as an edge; files that
match an already-detected component (an LLM call, a database client, a queue) also get an edge
to that component. Click a node to isolate its neighbors; hover for file details. Large
projects (350+ files) are aggregated to directory-level nodes automatically. Edges are
import-direction only (static, honest) unless --access-log was supplied, in which case
HTTP-entry edges are weighted with real observed request counts — the graph is explicit about
which kind of edge is which so it's never mistaken for a traced request path.
Guided tour — a spotlight walkthrough that dims the page and steps through each section
in turn (Back/Next/Skip), shown automatically the first time a generated report is opened.
Steps for sections that don't apply to a given project (e.g. no detected routes, no graph)
are skipped automatically. Replayable anytime via the ? button next to the theme toggle.
What the analyzer detects
Workers & replicas
| Signal |
Detected from |
uvicorn --workers N |
Dockerfile, docker-compose, Procfile |
gunicorn -w N |
same + gunicorn.conf.py |
replicas: N |
docker-compose |
PM2 instances: N |
ecosystem.config.js |
Celery -c N / concurrency=N |
docker-compose, Python files |
Async concurrency model
| Signal |
Meaning |
asyncio.Semaphore(N) |
Hard cap on concurrent CPU tasks |
run_in_executor |
CPU-bound work offloaded to thread pool |
asyncio.Lock() |
Exclusive section (e.g. dedup store) |
asyncio.gather |
Fan-out async tasks |
async def density > 2 |
asyncio event loop model |
Rate limits
| Source |
Detected signal |
| nginx |
limit_req_zone … rate=Xr/m + limit_req … burst=N |
| slowapi (Python) |
@limiter.limit("N per minute") |
| express-rate-limit |
max: N in config |
External sources
Jira · Azure DevOps · Slack · GitHub · Stripe · Salesforce · Twilio · S3 · Users/clients · Cron/Scheduler
LLM providers
OpenAI (ChatOpenAI / gpt-*) · Anthropic (Claude) · Cohere · AWS Bedrock
Vector stores
Qdrant · Pinecone · Weaviate · ChromaDB · pgvector · FAISS · Milvus
Databases
PostgreSQL · MySQL · MongoDB · SQLite · Redis
Queues
Celery · BullMQ · Kafka · RabbitMQ · RQ · AWS SQS
Evaluation frameworks
TruLens · RAGAS · LangSmith
Concurrency calculation
total_workers = (uvicorn_workers + gunicorn_workers) × replicas
per_worker_io = 100 if asyncio else 1
total_io_concurrent = total_workers × per_worker_io
concurrency_ceiling = min(total_io_concurrent, semaphore × total_workers) # whichever is present
practical_limit is a genuine min() across every throughput-shaped constraint that
was actually detected — not a priority-ordered guess that stops at the first match:
candidates = []
if nginx/Caddy rate limit detected: candidates += gateway_rate (r/m, parsed from config)
if slowapi/express rate limit detected: candidates += app_rate (r/m)
if an LLM provider was detected: candidates += concurrency_ceiling × (60 / timeout)
practical_limit = min(candidates) if candidates else concurrency_ceiling
The LLM term ties the throughput estimate to this project's actually-detected worker
count and async model — it no longer produces the same number regardless of whether
the app runs one sync worker or sixteen async ones. Whichever candidate is tightest is
reported as the bottleneck, and the "Bottleneck Analysis" section ranks the same
candidate list, so the two sections of the page cannot disagree with each other.
This is still a static-analysis heuristic, not a load test — it has no visibility into
CPU/memory limits, downstream database latency, or GC pauses. Treat it as a fast sanity
check on where to look first, not a capacity-planning number to put in an SLA.
Design tokens (dark mode — same as TECH_STACK.html)
| CSS variable |
Value |
--bg |
#0f172a |
--bg3 |
#161e2e |
--border |
#1e293b |
--text |
#f1f5f9 |
--muted |
#64748b |
--mono |
'JetBrains Mono', monospace |
--sans |
'IBM Plex Sans', system-ui, sans-serif |
Accent colors (consistent with WORKFLOW.html reference output):
- Orange
#f97316 — write/ingestion path, external sources
- Blue
#3b82f6 — API layer, relational DBs
- Green
#22c55e — read/query path, user-facing components
- Purple
#a855f7 — processing, Slack, queues
- Pink
#ec4899 — LLM / inference
- Indigo
#818cf8 — vector stores
- Yellow
#eab308 — evaluation, schedulers
- Red
#ef4444 — Redis, bottlenecks
- Cyan
#06b6d4 — embedding, I/O stats
Fallback (script not found)
If ~/.claude/skills/workflow-generator/scripts/analyze.py cannot be found, perform the
analysis manually using your Read and Bash tools, then write WORKFLOW.html directly.
Manual analysis steps:
- Detect framework — grep for
fastapi, flask, django, express, gin, @SpringBoot
- Detect workers — grep
--workers, replicas:, pm2 instances in docker-compose / Procfiles
- Detect gateway — look for
nginx.conf, Caddyfile, traefik.yml
- Extract rate limits —
limit_req_zone, @limiter.limit, express-rate-limit
- Extract async primitives —
asyncio.Semaphore, run_in_executor, asyncio.gather
- Detect LLM —
ChatOpenAI, ChatAnthropic, request_timeout=, max_retries=
- Detect storage — scan docker-compose, .env for
postgres://, redis://, qdrant, pinecone
- Detect queues —
celery, bullmq, kafka, rabbitmq
- Detect external sources —
jira, slack, ado, github, stripe in source + env
Then write WORKFLOW.html using the exact design tokens above and the section structure:
stat-row → architecture diagram → flow cards → concurrency table → bottleneck bars → footer.
Notes
- Always overwrite an existing
WORKFLOW.html — never ask for confirmation
- Works on Python, Node.js, Go, Rust, Java, Ruby projects
- Architecture diagram adapts to what is detected: layers with no components are omitted
- Stat cards show only metrics that could be computed (skip if data unavailable)
- Never scan vendored or generated directories (
node_modules, venv, .venv,
site-packages, dist, build, .git, …) — only the project's own source
- Capacity figures are static-analysis heuristics (e.g. ~100 concurrent tasks per
async worker), not load-test results — present them as estimates
1---2name: workflow-generator3description: FIRE when user intent matches any of the following conditions — EXPLICIT TRIGGERS: /workflow-generator; "generate workflow"; "create workflow diagram"; "show workflow" ARCHITECTURAL VISUALIZATION INTENT: user wants to visualize, diagram, draw, map, or generate a system architecture diagram / component diagram / service topology / service map / architecture overview / system overview / data flow diagram / pipeline diagram for the current project or a specified project path. PHRASING VARIANTS THAT SHOULD ROUTE HERE: "how does this system work", "what talks to what", "show me the components", "map the services", "diagram this", "visualize the stack", "show request flow", "show data flow", "trace the pipeline", "architecture of this project", "system map", "service dependencies", "component graph", "what calls what", "show me the architecture", "draw the architecture", "explain the system design", "infrastructure diagram", "dependency graph", "call graph", "module graph", "what imports what", "import graph". CAPA4---56# workflow-generator78Scan the current project and produce a complete visual system workflow with concurrency capacity analysis.910## Steps11121. **Locate the project root** — use the current working directory unless the user specified a path.13142. **Run the analyzer**:15 ```bash16 python3 ~/.claude/skills/workflow-generator/scripts/analyze.py <project_root> <project_root>/WORKFLOW.html17 ```1819 Optional flags, appended after the two positional args:20 - `--access-log <path>` — overlay real request counts (from a combined/common log file) onto21 the codebase dependency graph's HTTP-entry edges, instead of import-direction only.22 - `--graph-detail auto|files|dirs` — force file-level or directory-level graph nodes. Default23 `auto` aggregates to directories once a project exceeds ~350 source files.24253. **Open the output**:26 ```bash27 xdg-open <project_root>/WORKFLOW.html 2>/dev/null || open <project_root>/WORKFLOW.html 2>/dev/null || true28 ```29304. **Report to the user** — include:31 - Framework and worker count32 - Concurrent request capacity (total I/O + practical throughput)33 - Primary bottleneck34 - Detected storage and external sources35 - Clickable link to `WORKFLOW.html`3637## Output sections3839The generated `WORKFLOW.html` always contains all of the following:40411. **Stat row** — 4–6 large-number tiles:42 - API Worker Processes (replicas × uvicorn/gunicorn workers)43 - Max Concurrent Async I/O (~100 per asyncio worker)44 - Max Parallel CPU Tasks (asyncio.Semaphore limit, if detected)45 - Rate Limit (nginx / slowapi / express-rate-limit, if detected)46 - Practical Throughput (what the real ceiling is after all limits)47 - LLM Timeout (if an LLM provider is detected)48492. **System Architecture diagram** — adaptive layered CSS flow:50 - **EXTERNAL SOURCES & CLIENTS** — webhook sources (Jira, Slack, ADO, GitHub, Stripe), users51 - **GATEWAY / REVERSE PROXY** — nginx, Caddy, Traefik (with rate limits + worker_connections)52 - **APPLICATION LAYER** — API framework + frontend (Streamlit, React, Next.js, etc.)53 - **PROCESSING & QUEUE LAYER** — Semaphore-guarded CPU tasks, Celery/Bull/Kafka workers54 - **AI / INTELLIGENCE LAYER** — LLM providers, embedding, evaluation framework55 - **STORAGE & PERSISTENCE** — vector DB, relational DB, NoSQL, Redis, S356573. **Data Flow Paths** — step-by-step cards per detected flow:58 - Write Path (webhook route + signature-check evidence, if any)59 - Read Path (LLM + vector store presence)60 - Queue/Background Jobs61 - Generic HTTP flow (if nothing else detected)6263 These cards combine genuinely detected facts (provider names, models, timeouts,64 specific routes, real HMAC-verification evidence) with the *typical* shape of that65 kind of component. They are not a trace of an actual request path through the code —66 the tool never confirms that a detected webhook source and a detected route are67 the same request. Card titles say "(inferred, not traced)" or "(typical pattern)"68 for exactly this reason, and individual steps say "not confirmed" wherever the69 claim isn't backed by direct evidence.70714. **Concurrency Model table** — every layer with model / ceiling / limiting factor (a category label, not a file:line pointer into the user's code)72735. **Bottleneck Analysis** — ranked bar cards (CRITICAL → LOW). Severities are derived74 from the same min() comparison used for the "Practical Throughput" stat, so this75 section and that stat can never disagree with each other.76776. **Codebase Dependency Graph** — a force-directed graph of every source file (Python, JS/TS,78 Go, Java, Rust, Ruby) as a node and every real, parser-resolved import as an edge; files that79 match an already-detected component (an LLM call, a database client, a queue) also get an edge80 to that component. Click a node to isolate its neighbors; hover for file details. Large81 projects (350+ files) are aggregated to directory-level nodes automatically. Edges are82 import-direction only (static, honest) unless `--access-log` was supplied, in which case83 HTTP-entry edges are weighted with real observed request counts — the graph is explicit about84 which kind of edge is which so it's never mistaken for a traced request path.85867. **Guided tour** — a spotlight walkthrough that dims the page and steps through each section87 in turn (Back/Next/Skip), shown automatically the first time a generated report is opened.88 Steps for sections that don't apply to a given project (e.g. no detected routes, no graph)89 are skipped automatically. Replayable anytime via the `?` button next to the theme toggle.9091## What the analyzer detects9293### Workers & replicas94| Signal | Detected from |95|---|---|96| `uvicorn --workers N` | Dockerfile, docker-compose, Procfile |97| `gunicorn -w N` | same + gunicorn.conf.py |98| `replicas: N` | docker-compose |99| PM2 `instances: N` | ecosystem.config.js |100| Celery `-c N` / `concurrency=N` | docker-compose, Python files |101102### Async concurrency model103| Signal | Meaning |104|---|---|105| `asyncio.Semaphore(N)` | Hard cap on concurrent CPU tasks |106| `run_in_executor` | CPU-bound work offloaded to thread pool |107| `asyncio.Lock()` | Exclusive section (e.g. dedup store) |108| `asyncio.gather` | Fan-out async tasks |109| `async def` density > 2 | asyncio event loop model |110111### Rate limits112| Source | Detected signal |113|---|---|114| nginx | `limit_req_zone … rate=Xr/m` + `limit_req … burst=N` |115| slowapi (Python) | `@limiter.limit("N per minute")` |116| express-rate-limit | `max: N` in config |117118### External sources119Jira · Azure DevOps · Slack · GitHub · Stripe · Salesforce · Twilio · S3 · Users/clients · Cron/Scheduler120121### LLM providers122OpenAI (ChatOpenAI / gpt-*) · Anthropic (Claude) · Cohere · AWS Bedrock123124### Vector stores125Qdrant · Pinecone · Weaviate · ChromaDB · pgvector · FAISS · Milvus126127### Databases128PostgreSQL · MySQL · MongoDB · SQLite · Redis129130### Queues131Celery · BullMQ · Kafka · RabbitMQ · RQ · AWS SQS132133### Evaluation frameworks134TruLens · RAGAS · LangSmith135136## Concurrency calculation137138```139total_workers = (uvicorn_workers + gunicorn_workers) × replicas140per_worker_io = 100 if asyncio else 1141total_io_concurrent = total_workers × per_worker_io142concurrency_ceiling = min(total_io_concurrent, semaphore × total_workers) # whichever is present143```144145`practical_limit` is a genuine `min()` across every throughput-shaped constraint that146was actually detected — not a priority-ordered guess that stops at the first match:147148```149candidates = []150if nginx/Caddy rate limit detected: candidates += gateway_rate (r/m, parsed from config)151if slowapi/express rate limit detected: candidates += app_rate (r/m)152if an LLM provider was detected: candidates += concurrency_ceiling × (60 / timeout)153practical_limit = min(candidates) if candidates else concurrency_ceiling154```155156The LLM term ties the throughput estimate to this project's actually-detected worker157count and async model — it no longer produces the same number regardless of whether158the app runs one sync worker or sixteen async ones. Whichever candidate is tightest is159reported as the bottleneck, and the "Bottleneck Analysis" section ranks the *same*160candidate list, so the two sections of the page cannot disagree with each other.161162This is still a static-analysis heuristic, not a load test — it has no visibility into163CPU/memory limits, downstream database latency, or GC pauses. Treat it as a fast sanity164check on where to look first, not a capacity-planning number to put in an SLA.165166## Design tokens (dark mode — same as TECH_STACK.html)167168| CSS variable | Value |169|---|---|170| `--bg` | `#0f172a` |171| `--bg3` | `#161e2e` |172| `--border` | `#1e293b` |173| `--text` | `#f1f5f9` |174| `--muted` | `#64748b` |175| `--mono` | `'JetBrains Mono', monospace` |176| `--sans` | `'IBM Plex Sans', system-ui, sans-serif` |177178Accent colors (consistent with `WORKFLOW.html` reference output):179- Orange `#f97316` — write/ingestion path, external sources180- Blue `#3b82f6` — API layer, relational DBs181- Green `#22c55e` — read/query path, user-facing components182- Purple `#a855f7` — processing, Slack, queues183- Pink `#ec4899` — LLM / inference184- Indigo `#818cf8` — vector stores185- Yellow `#eab308` — evaluation, schedulers186- Red `#ef4444` — Redis, bottlenecks187- Cyan `#06b6d4` — embedding, I/O stats188189## Fallback (script not found)190191If `~/.claude/skills/workflow-generator/scripts/analyze.py` cannot be found, perform the192analysis manually using your Read and Bash tools, then write `WORKFLOW.html` directly.193194**Manual analysis steps:**1951961. **Detect framework** — grep for `fastapi`, `flask`, `django`, `express`, `gin`, `@SpringBoot`1972. **Detect workers** — grep `--workers`, `replicas:`, `pm2 instances` in docker-compose / Procfiles1983. **Detect gateway** — look for `nginx.conf`, `Caddyfile`, `traefik.yml`1994. **Extract rate limits** — `limit_req_zone`, `@limiter.limit`, `express-rate-limit`2005. **Extract async primitives** — `asyncio.Semaphore`, `run_in_executor`, `asyncio.gather`2016. **Detect LLM** — `ChatOpenAI`, `ChatAnthropic`, `request_timeout=`, `max_retries=`2027. **Detect storage** — scan docker-compose, .env for `postgres://`, `redis://`, `qdrant`, `pinecone`2038. **Detect queues** — `celery`, `bullmq`, `kafka`, `rabbitmq`2049. **Detect external sources** — `jira`, `slack`, `ado`, `github`, `stripe` in source + env205206Then write `WORKFLOW.html` using the exact design tokens above and the section structure:207stat-row → architecture diagram → flow cards → concurrency table → bottleneck bars → footer.208209## Notes210211- Always overwrite an existing `WORKFLOW.html` — never ask for confirmation212- Works on Python, Node.js, Go, Rust, Java, Ruby projects213- Architecture diagram adapts to what is detected: layers with no components are omitted214- Stat cards show only metrics that could be computed (skip if data unavailable)215- Never scan vendored or generated directories (`node_modules`, `venv`, `.venv`,216 `site-packages`, `dist`, `build`, `.git`, …) — only the project's own source217- Capacity figures are static-analysis heuristics (e.g. ~100 concurrent tasks per218 async worker), not load-test results — present them as estimates