@admin
Đánh giá cấu hình sai, leo thang đặc quyền IAM, lộ S3, security group mở và lỗ hổng IaC trên AWS, Azure, GCP.
---
name: "cloud-security"
description: "Use when assessing cloud infrastructure for security misconfigurations, IAM privilege escalation paths, S3 public exposure, open security group rules, or IaC security gaps. Covers AWS, Azure, and GCP posture assessment with MITRE ATT&CK mapping."
---
# Cloud Security
Cloud security posture assessment skill for detecting IAM privilege escalation, public storage exposure, network configuration risks, and infrastructure-as-code misconfigurations. This is NOT incident response for active cloud compromise (see incident-response) or application vulnerability scanning (see security-pen-testing) — this is about systematic cloud configuration analysis to prevent exploitation.
---
## Table of Contents
- [Overview](#overview)
- [Cloud Posture Check Tool](#cloud-posture-check-tool)
- [IAM Policy Analysis](#iam-policy-analysis)
- [S3 Exposure Assessment](#s3-exposure-assessment)
- [Security Group Analysis](#security-group-analysis)
- [IaC Security Review](#iac-security-review)
- [Cloud Provider Coverage Matrix](#cloud-provider-coverage-matrix)
- [Workflows](#workflows)
- [Anti-Patterns](#anti-patterns)
- [Cross-References](#cross-references)
---
## Overview
### What This Skill Does
This skill provides the methodology and tooling for **cloud security posture management (CSPM)** — systematically checking cloud configurations for misconfigurations that create exploitable attack surface. It covers IAM privilege escalation paths, storage public exposure, network over-permissioning, and infrastructure code security.
### Distinction from Other Security Skills
| Skill | Focus | Approach |
|-------|-------|----------|
| **cloud-security** (this) | Cloud configuration risk | Preventive — assess before exploitation |
| incident-response | Active cloud incidents | Reactive — triage confirmed cloud compromise |
| threat-detection | Behavioral anomalies | Proactive — hunt for attacker activity in cloud logs |
| security-pen-testing | Application vulnerabilities | Offensive — actively exploit found weaknesses |
### Prerequisites
Read access to IAM policy documents, S3 bucket configurations, and security group rules in JSON format. For continuous monitoring, integrate with cloud provider APIs (AWS Config, Azure Policy, GCP Security Command Center).
---
## Cloud Posture Check Tool
The `cloud_posture_check.py` tool runs three types of checks: `iam` (privilege escalation), `s3` (public access), and `sg` (network exposure). It auto-detects the check type from the config file structure or accepts explicit `--check` flags.
```bash
# Analyze an IAM policy for privilege escalation paths
python3 scripts/cloud_posture_check.py policy.json --check iam --json
# Assess S3 bucket configuration for public access
python3 scripts/cloud_posture_check.py bucket_config.json --check s3 --json
# Check security group rules for open admin ports
python3 scripts/cloud_posture_check.py sg.json --check sg --json
# Run all checks with internet-facing severity bump
python3 scripts/cloud_posture_check.py config.json --check all \
--provider aws --severity-modifier internet-facing --json
# Regulated data context (bumps severity by one level for all findings)
python3 scripts/cloud_posture_check.py config.json --check all \
--severity-modifier regulated-data --json
# Pipe IAM policy from AWS CLI
aws iam get-policy-version --policy-arn arn:aws:iam::123456789012:policy/MyPolicy \
--version-id v1 | jq '.PolicyVersion.Document' | \
python3 scripts/cloud_posture_check.py - --check iam --json
```
### Exit Codes
| Code | Meaning | Required Action |
|------|---------|-----------------|
| 0 | No high/critical findings | No action required |
| 1 | High-severity findings | Remediate within 24 hours |
| 2 | Critical findings | Remediate immediately — escalate to incident-response if active |
---
## IAM Policy Analysis
IAM analysis detects privilege escalation paths, overprivileged grants, public principal exposure, and data exfiltration risk.
### Privilege Escalation Patterns
| Pattern | Severity | Key Action Combination | MITRE |
|---------|----------|------------------------|-------|
| Lambda PassRole escalation | Critical | iam:PassRole + lambda:CreateFunction | T1078.004 |
| EC2 instance profile abuse | Critical | iam:PassRole + ec2:RunInstances | T1078.004 |
| CloudFormation PassRole | Critical | iam:PassRole + cloudformation:CreateStack | T1078.004 |
| Self-attach policy escalation | Critical | iam:AttachUserPolicy + sts:GetCallerIdentity | T1484.001 |
| Inline policy self-escalation | Critical | iam:PutUserPolicy + sts:GetCallerIdentity | T1484.001 |
| Policy version backdoor | Critical | iam:CreatePolicyVersion + iam:ListPolicies | T1484.001 |
| Credential harvesting | High | iam:CreateAccessKey + iam:ListUsers | T1098.001 |
| Group membership escalation | High | iam:AddUserToGroup + iam:ListGroups | T1098 |
| Password reset attack | High | iam:UpdateLoginProfile + iam:ListUsers | T1098 |
| Service-level wildcard | High | iam:* or s3:* or ec2:* | T1078.004 |
### IAM Finding Severity Guide
| Finding Type | Condition | Severity |
|-------------|-----------|----------|
| Full admin wildcard | Action=* Resource=* | Critical |
| Public principal | Principal: '*' | Critical |
| Dangerous action combo | Two-action escalation path | Critical |
| Individual priv-esc actions | On wildcard resource | High |
| Data exfiltration actions | s3:GetObject, secretsmanager:GetSecretValue on * | High |
| Service wildcard | service:* action | High |
| Data actions on named resource | Appropriate scope | Low/Clean |
### Least Privilege Recommendations
For every critical or high finding, the tool outputs a `least_privilege_suggestion` field with specific remediation guidance:
- Replace `Action: *` with a named list of required actions
- Replace `Resource: *` with specific ARN patterns
- Use AWS Access Analyzer to identify actually-used permissions
- Separate dangerous action combinations into different roles with distinct trust policies
---
## S3 Exposure Assessment
S3 assessment checks four dimensions: public access block configuration, bucket ACL, bucket policy principal exposure, and default encryption.
### S3 Configuration Check Matrix
| Check | Finding Condition | Severity |
|-------|------------------|----------|
| Public access block | Any of four flags missing/false | High |
| Bucket ACL | public-read-write | Critical |
| Bucket ACL | public-read or authenticated-read | High |
| Bucket policy Principal | "Principal": "*" with Allow | Critical |
| Default encryption | No ServerSideEncryptionConfiguration | High |
| Default encryption | Non-standard SSEAlgorithm | Medium |
| No PublicAccessBlockConfiguration | Status unknown | Medium |
### Recommended S3 Baseline Configuration
```json
{
"PublicAccessBlockConfiguration": {
"BlockPublicAcls": true,
"BlockPublicPolicy": true,
"IgnorePublicAcls": true,
"RestrictPublicBuckets": true
},
"ServerSideEncryptionConfiguration": {
"Rules": [{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "aws:kms",
"KMSMasterKeyID": "arn:aws:kms:region:account:key/key-id"
},
"BucketKeyEnabled": true
}]
},
"ACL": "private"
}
```
All four public access block settings must be enabled at both the bucket level and the AWS account level. Account-level settings can be overridden by bucket-level settings if not both enforced.
---
## Security Group Analysis
Security group analysis flags inbound rules that expose admin ports, database ports, or all traffic to internet CIDRs (0.0.0.0/0, ::/0).
### Critical Port Exposure Rules
| Port | Service | Finding Severity | Remediation |
|------|---------|-----------------|-------------|
| 22 | SSH | Critical | Restrict to VPN CIDR or use AWS Systems Manager Session Manager |
| 3389 | RDP | Critical | Restrict to VPN CIDR or use AWS Fleet Manager |
| 0–65535 (all) | All traffic | Critical | Remove rule; add specific required ports only |
### High-Risk Database Port Rules
| Port | Service | Finding Severity | Remediation |
|------|---------|-----------------|-------------|
| 1433 | MSSQL | High | Allow from application tier SG only — move to private subnet |
| 3306 | MySQL | High | Allow from application tier SG only — move to private subnet |
| 5432 | PostgreSQL | High | Allow from application tier SG only — move to private subnet |
| 27017 | MongoDB | High | Allow from application tier SG only — move to private subnet |
| 6379 | Redis | High | Allow from application tier SG only — move to private subnet |
| 9200 | Elasticsearch | High | Allow from application tier SG only — move to private subnet |
### Severity Modifiers
Use `--severity-modifier internet-facing` when the assessed resource is directly internet-accessible (load balancer, API gateway, public EC2). Use `--severity-modifier regulated-data` when the resource handles PCI, HIPAA, or GDPR-regulated data. Both modifiers bump each finding's severity by one level.
---
## IaC Security Review
Infrastructure-as-code review catches configuration issues at definition time, before deployment.
### IaC Check Matrix
| Tool | Check Types | When to Run |
|------|-------------|-------------|
| Terraform | Resource-level checks (aws_s3_bucket_acl, aws_security_group, aws_iam_policy_document) | Pre-plan, pre-apply, PR gate |
| CloudFormation | Template property validation (PublicAccessBlockConfiguration, SecurityGroupIngress) | Template lint, deploy gate |
| Kubernetes manifests | Container privileges, network policies, secret exposure | PR gate, admission controller |
| Helm charts | Same as Kubernetes | PR gate |
### Terraform IAM Policy Example — Finding vs. Clean
```hcl
# BAD: Will generate critical findings
resource "aws_iam_policy" "bad_policy" {
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = "*"
Resource = "*"
}]
})
}
# GOOD: Least privilege
resource "aws_iam_policy" "good_policy" {
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = ["s3:GetObject", "s3:PutObject"]
Resource = "arn:aws:s3:::my-specific-bucket/*"
}]
})
}
```
Full CSPM check reference: `references/cspm-checks.md`
---
## Cloud Provider Coverage Matrix
| Check Type | AWS | Azure | GCP |
|-----------|-----|-------|-----|
| IAM privilege escalation | Full (IAM policies, trust policies, ESCALATION_COMBOS) | Partial (RBAC assignments, service principal risks) | Partial (IAM bindings, workload identity) |
| Storage public access | Full (S3 bucket policies, ACLs, public access block) | Partial (Blob SAS tokens, container access levels) | Partial (GCS bucket IAM, uniform bucket-level access) |
| Network exposure | Full (Security Groups, NACLs, port-level analysis) | Partial (NSG rules, inbound port analysis) | Partial (Firewall rules, VPC firewall) |
| IaC scanning | Full (Terraform, CloudFormation) | Partial (ARM templates, Bicep) | Partial (Deployment Manager) |
---
## Workflows
### Workflow 1: Quick Posture Check (20 Minutes)
For a newly provisioned resource or pre-deployment review:
```bash
# 1. Export IAM policy document
aws iam get-policy-version --policy-arn ARN --version-id v1 | \
jq '.PolicyVersion.Document' > policy.json
python3 scripts/cloud_posture_check.py policy.json --check iam --json
# 2. Check S3 bucket configuration
aws s3api get-bucket-acl --bucket my-bucket > acl.json
aws s3api get-public-access-block --bucket my-bucket >> bucket.json
python3 scripts/cloud_posture_check.py bucket.json --check s3 --json
# 3. Review security groups for open admin ports
aws ec2 describe-security-groups --group-ids sg-123456 | \
jq '.SecurityGroups[0]' > sg.json
python3 scripts/cloud_posture_check.py sg.json --check sg --json
```
**Decision**: Exit code 2 = block deployment and remediate. Exit code 1 = schedule remediation within 24 hours.
### Workflow 2: Full Cloud Security Assessment (Multi-Day)
**Day 1 — IAM and Identity:**
1. Export all IAM policies attached to production roles
2. Run cloud_posture_check.py --check iam on each policy
3. Map all privilege escalation paths found
4. Identify overprivileged service accounts and roles
5. Review cross-account trust policies
**Day 2 — Storage and Network:**
1. Enumerate all S3 buckets and export configurations
2. Run cloud_posture_check.py --check s3 --severity-modifier regulated-data for data buckets
3. Export security group configurations for all VPCs
4. Run cloud_posture_check.py --check sg for internet-facing resources
5. Review NACL rules for network segmentation gaps
**Day 3 — IaC and Continuous Integration:**
1. Review Terraform/CloudFormation templates in version control
2. Check CI/CD pipeline for IaC security gates
3. Validate findings against `references/cspm-checks.md`
4. Produce remediation plan with priority ordering (Critical → High → Medium)
### Workflow 3: CI/CD Security Gate
Integrate posture checks into deployment pipelines to prevent misconfigured resources reaching production:
```bash
# Validate IaC before terraform apply
terraform show -json plan.json | \
jq '[.resource_changes[].change.after | select(. != null)]' > resources.json
python3 scripts/cloud_posture_check.py resources.json --check all --json
if [ $? -eq 2 ]; then
echo "Critical cloud security findings — blocking deployment"
exit 1
fi
# Validate existing S3 bucket before modifying
aws s3api get-bucket-policy --bucket "BUCKET" | jq '.Policy | fromjson' | \
python3 scripts/cloud_posture_check.py - --check s3 \
--severity-modifier regulated-data --json
```
---
## Anti-Patterns
1. **Running IAM analysis without checking escalation combos** — Individual high-risk actions in isolation may appear low-risk. The danger is in combinations: `iam:PassRole` alone is not critical, but `iam:PassRole + lambda:CreateFunction` is a confirmed privilege escalation path. Always analyze the full statement, not individual actions.
2. **Enabling only bucket-level public access block** — AWS S3 has both account-level and bucket-level public access block settings. A bucket-level setting can override an account-level setting. Both must be configured. Account-level block alone is insufficient if any bucket has explicit overrides.
3. **Treating `--severity-modifier internet-facing` as optional for public resources** — Internet-facing resources have significantly higher exposure than internal resources. High findings on internet-facing infrastructure should be treated as critical. Always apply `--severity-modifier internet-facing` for DMZ, load balancer, and API gateway configurations.
4. **Checking only administrator policies** — Privilege escalation paths frequently originate from non-administrator policies that combine innocuous-looking permissions. All policies attached to production identities must be checked, not just policies with obvious elevated access.
5. **Remediating findings without root cause analysis** — Removing a dangerous permission without understanding why it was granted will result in re-addition. Document the business justification for every high-risk permission before removing it, to prevent silent re-introduction.
6. **Ignoring service account over-permissioning** — Service accounts are often over-provisioned during development and never trimmed for production. Every service account in production must be audited against AWS Access Analyzer or equivalent to identify and remove unused permissions.
7. **Not applying severity modifiers for regulated data workloads** — A high finding in a general-purpose S3 bucket is different from the same finding in a bucket containing PHI or cardholder data. Always use `--severity-modifier regulated-data` when assessing resources in regulated data environments.
---
## Cross-References
| Skill | Relationship |
|-------|-------------|
| [incident-response](../incident-response/SKILL.md) | Critical findings (public S3, privilege escalation confirmed active) may trigger incident classification |
| [threat-detection](../threat-detection/SKILL.md) | Cloud posture findings create hunting targets — over-permissioned roles are likely lateral movement destinations |
| [red-team](../red-team/SKILL.md) | Red team exercises specifically test exploitability of cloud misconfigurations found in posture assessment |
| [security-pen-testing](../security-pen-testing/SKILL.md) | Cloud posture findings feed into the infrastructure security section of pen test assessments |
FILE:references/cspm-checks.md
# CSPM Check Reference
Complete check matrices for cloud security posture management across AWS, Azure, and GCP. Each check includes finding condition, severity, MITRE ATT&CK technique, and remediation guidance.
---
## AWS IAM Checks
| Check | Finding Condition | Severity | MITRE | Remediation |
|-------|------------------|----------|-------|-------------|
| Full admin wildcard | `Action: *` + `Resource: *` in Allow statement | Critical | T1078.004 | Replace with service-specific scoped policies |
| Public principal | `Principal: *` in Allow statement | Critical | T1190 | Restrict to specific account ARNs + aws:PrincipalOrgID condition |
| Lambda PassRole combo | `iam:PassRole` + `lambda:CreateFunction` | Critical | T1078.004 | Remove iam:PassRole or restrict to specific function ARNs |
| EC2 PassRole combo | `iam:PassRole` + `ec2:RunInstances` | Critical | T1078.004 | Remove iam:PassRole or restrict to specific instance profile ARNs |
| CloudFormation PassRole | `iam:PassRole` + `cloudformation:CreateStack` | Critical | T1078.004 | Restrict PassRole to specific service role ARNs |
| Self-attach escalation | `iam:AttachUserPolicy` + `sts:GetCallerIdentity` | Critical | T1484.001 | Remove iam:AttachUserPolicy from non-admin policies |
| Policy version backdoor | `iam:CreatePolicyVersion` + `iam:ListPolicies` | Critical | T1484.001 | Restrict CreatePolicyVersion to named policy ARNs |
| Service-level wildcard | `iam:*`, `s3:*`, `ec2:*`, etc. | High | T1078.004 | Replace with specific required actions |
| Credential harvesting | `iam:CreateAccessKey` + `iam:ListUsers` | High | T1098.001 | Separate roles; restrict CreateAccessKey to self only |
| Data exfil on wildcard | `s3:GetObject` on `Resource: *` | High | T1530 | Restrict to specific bucket ARNs |
| Secrets exfil on wildcard | `secretsmanager:GetSecretValue` on `Resource: *` | High | T1552 | Restrict to specific secret ARNs |
---
## AWS S3 Checks
| Check | Finding Condition | Severity | MITRE | Remediation |
|-------|------------------|----------|-------|-------------|
| Public access block missing | Any of four flags = false or absent | High | T1530 | Enable all four flags at bucket and account level |
| Bucket ACL public-read-write | ACL = public-read-write | Critical | T1530 | Set ACL = private; use bucket policy for access control |
| Bucket ACL public-read | ACL = public-read or authenticated-read | High | T1530 | Set ACL = private |
| Bucket policy Principal:* | Statement with Effect=Allow, Principal=* | Critical | T1190 | Restrict Principal to specific ARNs + aws:PrincipalOrgID |
| No default encryption | No ServerSideEncryptionConfiguration | High | T1530 | Add default encryption rule (AES256 or aws:kms) |
| Non-standard encryption | SSEAlgorithm not in {AES256, aws:kms, aws:kms:dsse} | Medium | T1530 | Switch to standard SSE algorithm |
| Versioning disabled | VersioningConfiguration = Suspended or absent | Medium | T1485 | Enable versioning to protect against ransomware deletion |
| Access logging disabled | LoggingEnabled absent | Low | T1530 | Enable server access logging for audit trail |
---
## AWS Security Group Checks
| Check | Finding Condition | Severity | MITRE | Remediation |
|-------|------------------|----------|-------|-------------|
| All traffic open | Protocol=-1 (all) from 0.0.0.0/0 or ::/0 | Critical | T1190 | Remove rule; add specific required ports only |
| SSH open | Port 22 from 0.0.0.0/0 or ::/0 | Critical | T1110 | Restrict to VPN CIDR or use AWS Systems Manager Session Manager |
| RDP open | Port 3389 from 0.0.0.0/0 or ::/0 | Critical | T1110 | Restrict to VPN CIDR or use AWS Fleet Manager |
| MySQL open | Port 3306 from 0.0.0.0/0 or ::/0 | High | T1190 | Move DB to private subnet; allow only from app tier SG |
| PostgreSQL open | Port 5432 from 0.0.0.0/0 or ::/0 | High | T1190 | Move DB to private subnet; allow only from app tier SG |
| MSSQL open | Port 1433 from 0.0.0.0/0 or ::/0 | High | T1190 | Move DB to private subnet; allow only from app tier SG |
| MongoDB open | Port 27017 from 0.0.0.0/0 or ::/0 | High | T1190 | Move DB to private subnet; allow only from app tier SG |
| Redis open | Port 6379 from 0.0.0.0/0 or ::/0 | High | T1190 | Move Redis to private subnet; allow only from app tier SG |
| Elasticsearch open | Port 9200 from 0.0.0.0/0 or ::/0 | High | T1190 | Move to private subnet; use VPC endpoint |
---
## Azure Checks
| Check | Service | Finding Condition | Severity | Remediation |
|-------|---------|------------------|----------|-------------|
| Owner role assigned broadly | Entra ID RBAC | Owner role assigned to more than break-glass accounts at subscription scope | Critical | Use least-privilege built-in roles; restrict Owner to named individuals |
| Guest user with privileged role | Entra ID | Guest account assigned Contributor or Owner | High | Remove guest from privileged roles; use B2B identity governance |
| Blob container public access | Azure Storage | Container `publicAccess` = Blob or Container | Critical | Set to None; use SAS tokens for external access |
| Storage account HTTPS only = false | Azure Storage | `supportsHttpsTrafficOnly` = false | High | Enable HTTPS-only traffic |
| Storage account network rules allow all | Azure Storage | `networkAcls.defaultAction` = Allow | High | Set defaultAction = Deny; add specific VNet rules |
| NSG rule allows any-to-any | Azure NSG | Inbound rule with SourceAddressPrefix = * and DestinationPortRange = * | Critical | Replace with specific port and source ranges |
| NSG allows SSH from internet | Azure NSG | Port 22 inbound from 0.0.0.0/0 | Critical | Restrict to VPN or use Azure Bastion |
| Key Vault soft-delete disabled | Azure Key Vault | `softDeleteEnabled` = false | High | Enable soft delete and purge protection |
| MFA not required for admin | Entra ID | Global Administrator without MFA enforcement | Critical | Enforce MFA via Conditional Access for all privileged roles |
| PIM not used for privileged roles | Entra ID | Standing assignment to privileged role (not eligible) | High | Migrate to PIM eligible assignments with JIT activation |
---
## GCP Checks
| Check | Service | Finding Condition | Severity | Remediation |
|-------|---------|------------------|----------|-------------|
| Service account has project Owner | Cloud IAM | Service account bound to roles/owner | Critical | Replace with specific required roles |
| Primitive role on project | Cloud IAM | roles/owner, roles/editor, or roles/viewer on project | High | Replace with predefined or custom roles |
| Public storage bucket | Cloud Storage | `allUsers` or `allAuthenticatedUsers` in bucket IAM | Critical | Remove public members; use signed URLs for external access |
| Bucket uniform access disabled | Cloud Storage | `uniformBucketLevelAccess.enabled` = false | Medium | Enable uniform bucket-level access |
| Firewall rule allows all ingress | Cloud VPC | Ingress rule with sourceRanges = 0.0.0.0/0 and ports = all | Critical | Replace with specific ports and source ranges |
| SSH firewall rule from internet | Cloud VPC | Port 22 ingress from 0.0.0.0/0 | Critical | Restrict to IAP CIDR (35.235.240.0/20) or use IAP TCP tunneling |
| Audit logging disabled | Cloud Audit Logs | Admin activity or data access logs disabled for a service | High | Enable audit logging for all services, especially IAM and storage |
| Default service account used | Compute Engine | Instance using the default compute service account | Medium | Create dedicated service accounts with minimal required scopes |
| Serial port access enabled | Compute Engine | `metadata.serial-port-enable` = true | Medium | Disable serial port access; use OS Login instead |
---
## IaC Check Matrix
### Terraform AWS Provider
| Resource | Property | Insecure Value | Remediation |
|----------|----------|---------------|-------------|
| `aws_s3_bucket_acl` | `acl` | `public-read`, `public-read-write` | Set to `private` |
| `aws_s3_bucket_public_access_block` | `block_public_acls` | `false` or absent | Set to `true` |
| `aws_security_group_rule` | `cidr_blocks` with port 22 | `["0.0.0.0/0"]` | Restrict to VPN CIDR |
| `aws_iam_policy_document` | `actions` | `["*"]` | Specify required actions |
| `aws_iam_policy_document` | `resources` | `["*"]` | Specify resource ARNs |
### Kubernetes
| Resource | Property | Insecure Value | Remediation |
|----------|----------|---------------|-------------|
| Pod/Deployment | `securityContext.runAsRoot` | `true` | Run as non-root user |
| Pod/Deployment | `securityContext.privileged` | `true` | Remove privileged flag |
| ServiceAccount | `automountServiceAccountToken` | `true` (default) | Set to `false` unless required |
| NetworkPolicy | Missing | No NetworkPolicy defined for namespace | Add default-deny ingress/egress policy |
| Secret | Type | Credentials in ConfigMap instead of Secret | Move to Kubernetes Secrets or external secrets manager |
FILE:scripts/cloud_posture_check.py
#!/usr/bin/env python3
"""
cloud_posture_check.py — Cloud Security Posture Check
Analyses IAM policies and cloud resource configurations for privilege
escalation paths, data exfiltration risks, public exposure, S3 bucket
misconfigurations, and Security Group dangerous inbound rules.
Supports AWS (full), with Azure/GCP stubs for future expansion.
Usage:
python3 cloud_posture_check.py policy.json
python3 cloud_posture_check.py policy.json --check privilege-escalation --json
python3 cloud_posture_check.py sg.json --check sg --provider aws --json
python3 cloud_posture_check.py bucket.json --check s3 --severity-modifier internet-facing
Exit codes:
0 No findings or informational only
1 High-severity findings present
2 Critical findings present
"""
import argparse
import json
import sys
from dataclasses import dataclass, field, asdict
from datetime import datetime, timezone
from typing import Any, Dict, List, Optional, Tuple
# ---------------------------------------------------------------------------
# IAM Analysis Constants (from analyze_iam_policy.py base)
# ---------------------------------------------------------------------------
PRIVILEGE_ESCALATION_ACTIONS: List[str] = [
"iam:CreatePolicyVersion",
"iam:SetDefaultPolicyVersion",
"iam:PassRole",
"iam:CreateAccessKey",
"iam:CreateLoginProfile",
"iam:UpdateLoginProfile",
"iam:AttachUserPolicy",
"iam:AttachGroupPolicy",
"iam:AttachRolePolicy",
"iam:PutUserPolicy",
"iam:PutGroupPolicy",
"iam:PutRolePolicy",
"iam:AddUserToGroup",
"iam:UpdateAssumeRolePolicy",
"sts:AssumeRole",
"iam:CreateRole",
"iam:DeletePolicyVersion",
"iam:CreateUser",
"iam:UpdateAccessKey",
"iam:DeactivateMFADevice",
"iam:DeleteVirtualMFADevice",
"iam:ResyncMFADevice",
"iam:EnableMFADevice",
"iam:DeleteUserPermissionsBoundary",
"iam:DeleteRolePermissionsBoundary",
"lambda:CreateFunction",
"lambda:InvokeFunction",
"lambda:UpdateFunctionCode",
"lambda:AddPermission",
"ec2:RunInstances",
"ec2:AssociateIamInstanceProfile",
"ec2:ReplaceIamInstanceProfileAssociation",
"cloudformation:CreateStack",
"cloudformation:UpdateStack",
"datapipeline:CreatePipeline",
"datapipeline:PutPipelineDefinition",
"glue:CreateDevEndpoint",
"glue:UpdateDevEndpoint",
"codestar:CreateProject",
"codecommit:CreateRepository",
"ssm:SendCommand",
"ssm:StartSession",
]
ESCALATION_COMBOS: List[Dict[str, Any]] = [
{
"name": "PassRole + Lambda Invoke",
"actions": ["iam:PassRole", "lambda:InvokeFunction"],
"description": "Attacker can pass a privileged role to a Lambda function and invoke it",
"severity": "critical",
},
{
"name": "PassRole + EC2 RunInstances",
"actions": ["iam:PassRole", "ec2:RunInstances"],
"description": "Attacker can launch an EC2 instance with a privileged IAM role",
"severity": "critical",
},
{
"name": "CreatePolicyVersion + SetDefaultPolicyVersion",
"actions": ["iam:CreatePolicyVersion", "iam:SetDefaultPolicyVersion"],
"description": "Attacker can create and activate a new policy version granting full access",
"severity": "critical",
},
{
"name": "AttachUserPolicy + AdministratorAccess",
"actions": ["iam:AttachUserPolicy"],
"description": "Can attach any managed policy including AdministratorAccess to users",
"severity": "high",
},
{
"name": "PutUserPolicy + Wildcard",
"actions": ["iam:PutUserPolicy"],
"description": "Can inject inline policies with wildcard permissions",
"severity": "high",
},
{
"name": "CloudFormation Stack Manipulation",
"actions": ["cloudformation:CreateStack", "iam:PassRole"],
"description": "Attacker can deploy a CloudFormation stack with a privileged role",
"severity": "critical",
},
{
"name": "SSM Session Start",
"actions": ["ssm:StartSession"],
"description": "Can start interactive sessions on EC2 instances without SSH",
"severity": "high",
},
{
"name": "Glue Dev Endpoint",
"actions": ["glue:CreateDevEndpoint", "iam:PassRole"],
"description": "Can create a Glue dev endpoint with a privileged role for code execution",
"severity": "critical",
},
]
DATA_EXFILTRATION_ACTIONS: List[str] = [
"s3:GetObject",
"s3:ListBucket",
"s3:GetBucketAcl",
"s3:GetObjectAcl",
"s3:GetBucketPolicy",
"s3:PutBucketPolicy",
"s3:PutBucketAcl",
"s3:PutObjectAcl",
"s3:CopyObject",
"s3:HeadObject",
"rds:DescribeDBInstances",
"rds:DownloadDBLogFilePortion",
"rds:DescribeDBSnapshots",
"rds:RestoreDBInstanceFromDBSnapshot",
"dynamodb:Scan",
"dynamodb:Query",
"dynamodb:GetItem",
"dynamodb:BatchGetItem",
"ec2:DescribeInstances",
"ec2:DescribeSnapshots",
"ec2:CreateSnapshot",
"ec2:ModifySnapshotAttribute",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"secretsmanager:GetSecretValue",
"secretsmanager:ListSecrets",
"ssm:GetParameter",
"ssm:GetParameters",
"ssm:GetParametersByPath",
"kms:Decrypt",
"kms:GenerateDataKey",
"lambda:GetFunction",
"codecommit:GitPull",
"cloudtrail:StopLogging",
"cloudtrail:DeleteTrail",
"guardduty:DeleteDetector",
"logs:DeleteLogGroup",
"logs:DeleteLogStream",
]
# ---------------------------------------------------------------------------
# Data Classes
# ---------------------------------------------------------------------------
@dataclass
class IAMFinding:
"""Represents a single IAM or cloud posture finding."""
finding_id: str
category: str # privilege-escalation | data-exfil | public-exposure | s3 | sg
severity: str # critical | high | medium | low | informational
title: str
description: str
affected_actions: List[str] = field(default_factory=list)
affected_resource: str = "*"
recommendation: str = ""
mitre_technique: str = ""
@dataclass
class IAMAnalysisResult:
"""Aggregated result of an IAM / posture analysis run."""
source: str
check_mode: str
provider: str
severity_modifier: str
findings: List[IAMFinding] = field(default_factory=list)
summary: Dict[str, Any] = field(default_factory=dict)
timestamp_utc: str = ""
def __post_init__(self) -> None:
if not self.timestamp_utc:
self.timestamp_utc = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
@property
def critical_count(self) -> int:
return sum(1 for f in self.findings if f.severity == "critical")
@property
def high_count(self) -> int:
return sum(1 for f in self.findings if f.severity == "high")
@property
def medium_count(self) -> int:
return sum(1 for f in self.findings if f.severity == "medium")
@property
def low_count(self) -> int:
return sum(1 for f in self.findings if f.severity == "low")
# ---------------------------------------------------------------------------
# Severity Bump Utility
# ---------------------------------------------------------------------------
_SEV_LADDER = ["informational", "low", "medium", "high", "critical"]
def _bump_severity(severity: str, modifier: str) -> str:
"""
Bump severity up one band when modifier is internet-facing or regulated-data.
low -> medium -> high -> critical (caps at critical).
"""
if modifier not in ("internet-facing", "regulated-data"):
return severity
try:
idx = _SEV_LADDER.index(severity.lower())
return _SEV_LADDER[min(idx + 1, len(_SEV_LADDER) - 1)]
except ValueError:
return severity
# ---------------------------------------------------------------------------
# Core IAM Analysis Functions (from analyze_iam_policy.py base)
# ---------------------------------------------------------------------------
def _extract_actions(statement: dict) -> List[str]:
"""Normalise Action field to a list of lowercase strings."""
action_field = statement.get("Action") or statement.get("action") or []
if isinstance(action_field, str):
return [action_field.lower()]
return [str(a).lower() for a in action_field]
def _extract_resources(statement: dict) -> List[str]:
"""Normalise Resource field to a list of strings."""
resource_field = (
statement.get("Resource")
or statement.get("resource")
or ["*"]
)
if isinstance(resource_field, str):
return [resource_field]
return [str(r) for r in resource_field]
def _extract_principal(statement: dict) -> str:
"""Return a string representation of the Principal."""
principal = statement.get("Principal") or statement.get("principal") or "N/A"
if isinstance(principal, dict):
parts = []
for k, v in principal.items():
if isinstance(v, list):
parts.append(f"{k}:{','.join(v)}")
else:
parts.append(f"{k}:{v}")
return " | ".join(parts)
return str(principal)
def _is_allow(statement: dict) -> bool:
effect = str(statement.get("Effect") or statement.get("effect") or "Allow")
return effect.strip().lower() == "allow"
def analyze_statement(
statement: dict,
check_mode: str,
finding_prefix: str,
severity_modifier: str,
) -> List[IAMFinding]:
"""
Analyse a single IAM policy statement for risks.
Args:
statement: Parsed IAM statement dict.
check_mode: One of privilege-escalation | data-exfil | public-exposure.
finding_prefix: Short string used to prefix finding IDs.
severity_modifier: internet-facing | regulated-data | none.
Returns:
List of IAMFinding objects (may be empty).
"""
findings: List[IAMFinding] = []
if not _is_allow(statement):
return findings
actions = _extract_actions(statement)
resources = _extract_resources(statement)
principal = _extract_principal(statement)
resource_str = ", ".join(resources[:3]) + ("..." if len(resources) > 3 else "")
wildcard_resource = any(r in ("*", "arn:aws:*") for r in resources)
wildcard_action = any(a in ("*", "iam:*", "s3:*", "ec2:*") for a in actions)
if check_mode == "privilege-escalation":
# Check individual high-risk actions
matched_privesc = [
a for a in actions
if a in [p.lower() for p in PRIVILEGE_ESCALATION_ACTIONS]
]
if matched_privesc:
severity = "high" if not wildcard_resource else "critical"
severity = _bump_severity(severity, severity_modifier)
findings.append(IAMFinding(
finding_id=f"{finding_prefix}-PRIVESC-{len(findings) + 1:03d}",
category="privilege-escalation",
severity=severity,
title="Privilege Escalation Actions Detected",
description=(
f"Statement grants {len(matched_privesc)} privilege escalation "
f"action(s) to principal '{principal}' on resources: {resource_str}."
),
affected_actions=matched_privesc,
affected_resource=resource_str,
recommendation=(
"Apply least-privilege: restrict IAM mutation actions to specific "
"resource ARNs and add Condition constraints. Consider permission boundaries."
),
mitre_technique="T1098",
))
# Check dangerous combos
for combo in ESCALATION_COMBOS:
combo_actions_lower = [c.lower() for c in combo["actions"]]
if all(ca in actions for ca in combo_actions_lower):
combo_sev = _bump_severity(combo["severity"], severity_modifier)
findings.append(IAMFinding(
finding_id=f"{finding_prefix}-COMBO-{len(findings) + 1:03d}",
category="privilege-escalation",
severity=combo_sev,
title=f"Escalation Combo: {combo['name']}",
description=combo["description"],
affected_actions=combo["actions"],
affected_resource=resource_str,
recommendation=(
f"Remove or scope one of the combo actions. "
f"Separate {combo['name']} permissions across different roles."
),
mitre_technique="T1548",
))
# Wildcard action with Allow
if wildcard_action:
sev = _bump_severity("critical", severity_modifier)
findings.append(IAMFinding(
finding_id=f"{finding_prefix}-WILD-{len(findings) + 1:03d}",
category="privilege-escalation",
severity=sev,
title="Wildcard Action Grant",
description=(
f"Statement uses wildcard action(s) {[a for a in actions if '*' in a]} "
f"for principal '{principal}'. This grants unrestricted access."
),
affected_actions=[a for a in actions if "*" in a],
affected_resource=resource_str,
recommendation="Replace wildcard actions with an explicit allowlist of required actions.",
mitre_technique="T1078.004",
))
elif check_mode == "data-exfil":
matched_exfil = [
a for a in actions
if a in [d.lower() for d in DATA_EXFILTRATION_ACTIONS]
]
if matched_exfil:
severity = "medium"
if wildcard_resource:
severity = "high"
# Particularly dangerous: log deletion or trail stopping
disruptive = [
a for a in matched_exfil
if any(x in a for x in ["stoplog", "deletelog", "deletetrail", "deletedetector"])
]
if disruptive:
severity = "critical"
severity = _bump_severity(severity, severity_modifier)
findings.append(IAMFinding(
finding_id=f"{finding_prefix}-EXFIL-{len(findings) + 1:03d}",
category="data-exfil",
severity=severity,
title="Data Exfiltration Risk Actions",
description=(
f"Statement grants {len(matched_exfil)} potential exfiltration "
f"action(s) to principal '{principal}': {', '.join(matched_exfil[:5])}."
),
affected_actions=matched_exfil,
affected_resource=resource_str,
recommendation=(
"Scope data-read actions to specific resource ARNs. "
"Add VPC endpoint conditions and restrict cross-account access. "
"Enable GuardDuty and CloudTrail for all regions."
),
mitre_technique="T1530",
))
elif check_mode == "public-exposure":
principal_str = _extract_principal(statement)
is_public = any(p in principal_str for p in ["*", "AWS:*", '"*"'])
if is_public:
sev = _bump_severity("high", severity_modifier)
if wildcard_action:
sev = _bump_severity("critical", severity_modifier)
findings.append(IAMFinding(
finding_id=f"{finding_prefix}-PUB-{len(findings) + 1:03d}",
category="public-exposure",
severity=sev,
title="Public Principal Detected",
description=(
f"Statement uses Principal '*' allowing any AWS account or "
f"unauthenticated entity to perform: {', '.join(actions[:5])}."
),
affected_actions=actions[:10],
affected_resource=resource_str,
recommendation=(
"Replace Principal '*' with specific account ARNs, "
"organisation units, or role ARNs. Use Condition keys "
"like aws:PrincipalOrgID to limit to your AWS Org."
),
mitre_technique="T1190",
))
return findings
def analyze_policy(
policy: dict,
check_mode: str,
source: str,
severity_modifier: str,
provider: str = "aws",
) -> IAMAnalysisResult:
"""
Analyse a full IAM policy document for findings.
Iterates over every Statement in the policy and delegates to
analyze_statement() for per-check logic.
Args:
policy: Parsed IAM policy JSON dict.
check_mode: privilege-escalation | data-exfil | public-exposure.
source: Display name / file path for the policy.
severity_modifier: internet-facing | regulated-data | none.
provider: aws | azure | gcp (currently only aws fully supported).
Returns:
IAMAnalysisResult with all findings populated.
"""
result = IAMAnalysisResult(
source=source,
check_mode=check_mode,
provider=provider,
severity_modifier=severity_modifier,
)
statements = policy.get("Statement") or policy.get("statement") or []
if not isinstance(statements, list):
statements = [statements]
prefix = source.replace(" ", "_").replace("/", "_")[:12].upper()
for idx, stmt in enumerate(statements):
stmt_findings = analyze_statement(
statement=stmt,
check_mode=check_mode,
finding_prefix=f"{prefix}-S{idx + 1:02d}",
severity_modifier=severity_modifier,
)
result.findings.extend(stmt_findings)
result.summary = {
"total_statements": len(statements),
"total_findings": len(result.findings),
"critical": result.critical_count,
"high": result.high_count,
"medium": result.medium_count,
"low": result.low_count,
"check_mode": check_mode,
"provider": provider,
"severity_modifier": severity_modifier,
}
return result
# ---------------------------------------------------------------------------
# S3 Posture Check (new)
# ---------------------------------------------------------------------------
def check_s3_policy(
policy: dict,
source: str,
severity_modifier: str,
) -> IAMAnalysisResult:
"""
Check S3 bucket policy or Terraform aws_s3_bucket block for misconfigurations.
Checks performed:
1. Principal "*" in bucket policy -> Critical
2. block_public_acls missing or false -> Critical
3. server_side_encryption absent or not AES256/aws:kms -> High
4. versioning disabled -> Medium
5. access logging disabled -> High
Args:
policy: Parsed S3 policy / Terraform block dict.
source: Display name / file path.
severity_modifier: internet-facing | regulated-data | none.
Returns:
IAMAnalysisResult populated with S3 findings.
"""
result = IAMAnalysisResult(
source=source,
check_mode="s3",
provider="aws",
severity_modifier=severity_modifier,
)
findings: List[IAMFinding] = []
fid = 0
def _next_id() -> str:
nonlocal fid
fid += 1
return f"S3-{fid:03d}"
# --- Check 1: Public principal in bucket policy ---
statements = policy.get("Statement") or policy.get("statement") or []
if isinstance(statements, list):
for stmt in statements:
if not _is_allow(stmt):
continue
principal = _extract_principal(stmt)
if "*" in principal or '"*"' in principal:
severity = _bump_severity("critical", severity_modifier)
findings.append(IAMFinding(
finding_id=_next_id(),
category="s3",
severity=severity,
title="S3 Bucket Policy: Public Principal",
description=(
"Bucket policy contains Principal '*' which grants public "
"access to any AWS account or unauthenticated user."
),
affected_actions=_extract_actions(stmt),
affected_resource=source,
recommendation=(
"Remove Principal '*'. Restrict to specific account ARNs or "
"use aws:PrincipalOrgID condition to limit to your AWS Org."
),
mitre_technique="T1530",
))
# --- Check 2: block_public_acls missing or false ---
# Terraform resource format: aws_s3_bucket_public_access_block
public_access_block = (
policy.get("block_public_acls")
or policy.get("BlockPublicAcls")
or policy.get("public_access_block", {}).get("block_public_acls")
)
restrict_public_buckets = (
policy.get("restrict_public_buckets")
or policy.get("RestrictPublicBuckets")
)
block_public_policy = (
policy.get("block_public_policy")
or policy.get("BlockPublicPolicy")
)
# If any of these are explicitly False or absent, flag it
block_fields = {
"block_public_acls": public_access_block,
"restrict_public_buckets": restrict_public_buckets,
"block_public_policy": block_public_policy,
}
missing_blocks = [k for k, v in block_fields.items() if v is None or v is False]
if missing_blocks:
severity = _bump_severity("critical", severity_modifier)
findings.append(IAMFinding(
finding_id=_next_id(),
category="s3",
severity=severity,
title="S3 Public Access Block Not Fully Enabled",
description=(
f"Public access block settings are missing or disabled: "
f"{', '.join(missing_blocks)}. This may allow public ACL or policy access."
),
affected_resource=source,
recommendation=(
"Enable all four S3 Block Public Access settings: "
"BlockPublicAcls, BlockPublicPolicy, IgnorePublicAcls, RestrictPublicBuckets."
),
mitre_technique="T1530",
))
# --- Check 3: Server-side encryption ---
sse_config = (
policy.get("server_side_encryption_configuration")
or policy.get("ServerSideEncryptionConfiguration")
or policy.get("encryption")
or policy.get("sse_algorithm")
)
has_sse = False
if isinstance(sse_config, dict):
rules = sse_config.get("Rule") or sse_config.get("rules") or []
if not isinstance(rules, list):
rules = [rules]
for rule in rules:
apply_sse = (
rule.get("ApplyServerSideEncryptionByDefault")
or rule.get("apply_server_side_encryption_by_default")
or {}
)
algo = str(apply_sse.get("SSEAlgorithm") or apply_sse.get("sse_algorithm") or "")
if algo.upper() in ("AES256", "AWS:KMS"):
has_sse = True
elif isinstance(sse_config, str):
has_sse = sse_config.upper() in ("AES256", "AWS:KMS")
if not has_sse:
severity = _bump_severity("high", severity_modifier)
findings.append(IAMFinding(
finding_id=_next_id(),
category="s3",
severity=severity,
title="S3 Server-Side Encryption Not Configured",
description=(
"No server-side encryption (SSE-S3 or SSE-KMS) found on this bucket. "
"Data is stored unencrypted at rest."
),
affected_resource=source,
recommendation=(
"Enable SSE via a bucket encryption configuration. "
"Use aws:kms with a CMK for regulated workloads. "
"Consider enforcing encryption via bucket policy (aws:SecureTransport)."
),
mitre_technique="T1022",
))
# --- Check 4: Versioning disabled ---
versioning = (
policy.get("versioning")
or policy.get("VersioningConfiguration")
)
versioning_enabled = False
if isinstance(versioning, dict):
status = str(
versioning.get("Status")
or versioning.get("status")
or versioning.get("enabled")
or ""
)
versioning_enabled = status.lower() in ("enabled", "true")
elif isinstance(versioning, bool):
versioning_enabled = versioning
if not versioning_enabled:
severity = _bump_severity("medium", severity_modifier)
findings.append(IAMFinding(
finding_id=_next_id(),
category="s3",
severity=severity,
title="S3 Bucket Versioning Disabled",
description=(
"Versioning is not enabled on this bucket. "
"Accidental or malicious object deletion/overwrite cannot be recovered."
),
affected_resource=source,
recommendation=(
"Enable bucket versioning. "
"Combine with Object Lock and lifecycle policies for regulated workloads."
),
mitre_technique="T1485",
))
result.findings = findings
result.summary = {
"total_findings": len(findings),
"critical": sum(1 for f in findings if f.severity == "critical"),
"high": sum(1 for f in findings if f.severity == "high"),
"medium": sum(1 for f in findings if f.severity == "medium"),
"low": sum(1 for f in findings if f.severity == "low"),
"check_mode": "s3",
"provider": "aws",
"severity_modifier": severity_modifier,
}
return result
# ---------------------------------------------------------------------------
# Security Group Check (new)
# ---------------------------------------------------------------------------
def check_security_group(
sg_json: dict,
source: str,
severity_modifier: str,
) -> IAMAnalysisResult:
"""
Check AWS Security Group JSON for dangerous inbound rules.
Args:
sg_json: Parsed Security Group JSON (AWS DescribeSecurityGroups
output format or Terraform aws_security_group block).
source: Display name / file path.
severity_modifier: internet-facing | regulated-data | none.
Returns:
IAMAnalysisResult populated with SG findings.
"""
RISKY_PORTS: Dict[int, str] = {
22: "SSH",
3389: "RDP",
23: "Telnet",
21: "FTP",
3306: "MySQL",
5432: "PostgreSQL",
1433: "MSSQL",
27017: "MongoDB",
6379: "Redis",
}
result = IAMAnalysisResult(
source=source,
check_mode="sg",
provider="aws",
severity_modifier=severity_modifier,
)
findings: List[IAMFinding] = []
fid = 0
def _next_id() -> str:
nonlocal fid
fid += 1
return f"SG-{fid:03d}"
# Support both AWS API format (IpPermissions) and Terraform ingress blocks
ip_permissions = sg_json.get("IpPermissions") or []
terraform_ingress = sg_json.get("ingress") or []
# Normalise Terraform ingress blocks to AWS API format
normalised: List[dict] = list(ip_permissions)
for ing in terraform_ingress:
if not isinstance(ing, dict):
continue
cidr_blocks = ing.get("cidr_blocks") or []
ipv6_cidr_blocks = ing.get("ipv6_cidr_blocks") or []
ip_ranges = [{"CidrIp": c} for c in cidr_blocks]
ipv6_ranges = [{"CidrIpv6": c} for c in ipv6_cidr_blocks]
normalised.append({
"IpProtocol": str(ing.get("protocol", "tcp")),
"FromPort": ing.get("from_port", 0),
"ToPort": ing.get("to_port", 65535),
"IpRanges": ip_ranges,
"Ipv6Ranges": ipv6_ranges,
})
for rule in normalised:
from_port = rule.get("FromPort", 0)
to_port = rule.get("ToPort", 65535)
protocol = str(rule.get("IpProtocol", "tcp"))
# Collect CIDRs from both IPv4 and IPv6 ranges
all_ranges: List[Tuple[str, str]] = []
for ip_range in rule.get("IpRanges", []):
cidr = ip_range.get("CidrIp", "")
if cidr:
all_ranges.append((cidr, "ipv4"))
for ip_range in rule.get("Ipv6Ranges", []):
cidr = ip_range.get("CidrIpv6", "")
if cidr:
all_ranges.append((cidr, "ipv6"))
for cidr, ip_ver in all_ranges:
if cidr not in ("0.0.0.0/0", "::/0"):
continue # Not open to the world
if protocol == "-1":
# All traffic open to the internet
severity = _bump_severity("critical", severity_modifier)
findings.append(IAMFinding(
finding_id=_next_id(),
category="sg",
severity=severity,
title="Security Group: All Traffic Open to Internet",
description=(
f"Inbound rule allows ALL traffic (protocol -1) "
f"from {cidr} ({ip_ver}). This exposes every port on every instance "
"in this security group to the public internet."
),
affected_resource=source,
recommendation=(
"Remove the all-traffic rule. Define explicit port/protocol "
"allowlist rules for only the services that must be internet-accessible."
),
mitre_technique="T1190",
))
continue
# Check port range against RISKY_PORTS
matched_ports = [
p for p in RISKY_PORTS
if from_port <= p <= to_port
]
if matched_ports:
for port in matched_ports:
service = RISKY_PORTS[port]
severity = _bump_severity("critical", severity_modifier)
findings.append(IAMFinding(
finding_id=_next_id(),
category="sg",
severity=severity,
title=f"Security Group: {service} ({port}) Open to Internet",
description=(
f"Inbound rule allows {service} (port {port}/{protocol}) "
f"from {cidr} ({ip_ver}). Direct internet access to {service} "
"exposes this service to brute-force, exploitation, and scanning."
),
affected_resource=source,
recommendation=(
f"Restrict port {port} to specific trusted CIDRs or a VPN/bastion. "
f"For {service}, consider using AWS Systems Manager Session Manager "
"as a zero-trust alternative that requires no open inbound ports."
),
mitre_technique="T1133",
))
else:
# Open to the internet on a non-standard port
severity = _bump_severity("high", severity_modifier)
port_label = (
f"port {from_port}"
if from_port == to_port
else f"ports {from_port}-{to_port}"
)
findings.append(IAMFinding(
finding_id=_next_id(),
category="sg",
severity=severity,
title=f"Security Group: {port_label.title()} Open to Internet",
description=(
f"Inbound rule opens {port_label} ({protocol}) to {cidr} ({ip_ver}). "
"Broad internet exposure increases attack surface even on non-standard ports."
),
affected_resource=source,
recommendation=(
f"Restrict {port_label} to the specific IP ranges that require access. "
"Use Security Group references instead of CIDRs where possible."
),
mitre_technique="T1046",
))
result.findings = findings
result.summary = {
"total_findings": len(findings),
"critical": sum(1 for f in findings if f.severity == "critical"),
"high": sum(1 for f in findings if f.severity == "high"),
"medium": sum(1 for f in findings if f.severity == "medium"),
"low": sum(1 for f in findings if f.severity == "low"),
"check_mode": "sg",
"provider": "aws",
"severity_modifier": severity_modifier,
}
return result
# ---------------------------------------------------------------------------
# Text Report
# ---------------------------------------------------------------------------
def print_text_report(result: IAMAnalysisResult) -> None:
"""Print a formatted text report for the analysis result."""
sep = "=" * 70
print(sep)
print(" Cloud Posture Check")
print(sep)
print(f" Source : {result.source}")
print(f" Check Mode : {result.check_mode}")
print(f" Provider : {result.provider.upper()}")
print(f" Severity Mod : {result.severity_modifier}")
print(f" Timestamp : {result.timestamp_utc}")
print(sep)
summary = result.summary
print(f"\n Summary:")
print(f" Total Findings : {summary.get('total_findings', 0)}")
if summary.get("critical", 0):
print(f" CRITICAL : {summary['critical']}")
if summary.get("high", 0):
print(f" HIGH : {summary['high']}")
if summary.get("medium", 0):
print(f" MEDIUM : {summary['medium']}")
if summary.get("low", 0):
print(f" LOW : {summary['low']}")
if not result.findings:
print("\n No findings detected.")
print(sep)
return
print(f"\n Findings ({len(result.findings)}):")
for finding in result.findings:
print(f"\n [{finding.severity.upper()}] {finding.finding_id}: {finding.title}")
print(f" {finding.description}")
if finding.affected_actions:
preview = finding.affected_actions[:4]
suffix = f" (+{len(finding.affected_actions) - 4} more)" if len(finding.affected_actions) > 4 else ""
print(f" Actions : {', '.join(preview)}{suffix}")
print(f" Resource : {finding.affected_resource}")
print(f" MITRE : {finding.mitre_technique}")
print(f" Fix : {finding.recommendation}")
print(f"\n{sep}")
# ---------------------------------------------------------------------------
# Result Serialisation
# ---------------------------------------------------------------------------
def result_to_dict(result: IAMAnalysisResult) -> dict:
"""Convert IAMAnalysisResult to a JSON-serialisable dict."""
return {
"source": result.source,
"check_mode": result.check_mode,
"provider": result.provider,
"severity_modifier": result.severity_modifier,
"timestamp_utc": result.timestamp_utc,
"summary": result.summary,
"findings": [asdict(f) for f in result.findings],
}
# ---------------------------------------------------------------------------
# Main Entry Point
# ---------------------------------------------------------------------------
def main() -> None:
parser = argparse.ArgumentParser(
description="Cloud Security Posture Check — IAM, S3, and Security Group analysis",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
%(prog)s policy.json
%(prog)s policy.json --check privilege-escalation --json
%(prog)s policy.json --check data-exfil --severity-modifier regulated-data --json
%(prog)s policy.json --check public-exposure --json
%(prog)s bucket.json --check s3 --severity-modifier internet-facing --json
%(prog)s sg.json --check sg --provider aws --json
%(prog)s policy.json --check all --json
Exit codes:
0 No findings or informational only
1 High-severity findings present
2 Critical findings present
""",
)
parser.add_argument(
"input_file",
help="Path to JSON file (IAM policy, S3 config, or Security Group JSON)",
)
parser.add_argument(
"--check",
choices=["privilege-escalation", "data-exfil", "public-exposure", "s3", "sg", "all"],
default="privilege-escalation",
help="Check mode to run (default: privilege-escalation)",
)
parser.add_argument(
"--provider",
choices=["aws", "azure", "gcp"],
default="aws",
help="Cloud provider (default: aws; Azure/GCP: only IAM checks available)",
)
parser.add_argument(
"--severity-modifier",
choices=["internet-facing", "regulated-data", "none"],
default="none",
dest="severity_modifier",
help="Bump all finding severities +1 band (default: none)",
)
parser.add_argument(
"--json",
action="store_true",
help="Output results as JSON",
)
parser.add_argument(
"--output", "-o",
metavar="FILE",
help="Write JSON output to file",
)
args = parser.parse_args()
# --- Load input file ---
try:
with open(args.input_file, "r", encoding="utf-8") as fh:
policy_data = json.load(fh)
except FileNotFoundError:
err = {"error": f"File not found: {args.input_file}"}
if args.json:
print(json.dumps(err, indent=2))
else:
print(f"Error: {err['error']}", file=sys.stderr)
sys.exit(1)
except json.JSONDecodeError as exc:
err = {"error": f"Invalid JSON: {exc}"}
if args.json:
print(json.dumps(err, indent=2))
else:
print(f"Error: {err['error']}", file=sys.stderr)
sys.exit(1)
source = args.input_file
severity_modifier = args.severity_modifier
provider = args.provider
# --- Gate S3 / SG checks by provider ---
check_mode = args.check
if check_mode in ("s3", "sg") and provider != "aws":
msg = (
f"Azure/GCP checks coming soon — "
f"use --provider aws for S3/SG analysis"
)
if args.json:
print(json.dumps({"message": msg, "provider": provider, "check_mode": check_mode}, indent=2))
else:
print(msg)
sys.exit(0)
# --- Run checks ---
all_results: List[IAMAnalysisResult] = []
iam_check_modes = ["privilege-escalation", "data-exfil", "public-exposure"]
if check_mode == "all":
if provider == "aws":
# Run all IAM checks
for mode in iam_check_modes:
r = analyze_policy(
policy=policy_data,
check_mode=mode,
source=source,
severity_modifier=severity_modifier,
provider=provider,
)
all_results.append(r)
# Run S3
s3_r = check_s3_policy(
policy=policy_data,
source=source,
severity_modifier=severity_modifier,
)
all_results.append(s3_r)
# Run SG
sg_r = check_security_group(
sg_json=policy_data,
source=source,
severity_modifier=severity_modifier,
)
all_results.append(sg_r)
else:
for mode in iam_check_modes:
r = analyze_policy(
policy=policy_data,
check_mode=mode,
source=source,
severity_modifier=severity_modifier,
provider=provider,
)
all_results.append(r)
elif check_mode in iam_check_modes:
r = analyze_policy(
policy=policy_data,
check_mode=check_mode,
source=source,
severity_modifier=severity_modifier,
provider=provider,
)
all_results.append(r)
elif check_mode == "s3":
r = check_s3_policy(
policy=policy_data,
source=source,
severity_modifier=severity_modifier,
)
all_results.append(r)
elif check_mode == "sg":
r = check_security_group(
sg_json=policy_data,
source=source,
severity_modifier=severity_modifier,
)
all_results.append(r)
# --- Flatten findings for output when multiple checks run ---
if len(all_results) == 1:
combined_result = all_results[0]
else:
# Merge into a single result
all_findings: List[IAMFinding] = []
for res in all_results:
all_findings.extend(res.findings)
combined_result = IAMAnalysisResult(
source=source,
check_mode=check_mode,
provider=provider,
severity_modifier=severity_modifier,
)
combined_result.findings = all_findings
combined_result.summary = {
"total_findings": len(all_findings),
"critical": sum(1 for f in all_findings if f.severity == "critical"),
"high": sum(1 for f in all_findings if f.severity == "high"),
"medium": sum(1 for f in all_findings if f.severity == "medium"),
"low": sum(1 for f in all_findings if f.severity == "low"),
"check_mode": check_mode,
"provider": provider,
"severity_modifier": severity_modifier,
"checks_run": [r.check_mode for r in all_results],
}
# --- Output ---
if args.json or args.output:
output_dict = result_to_dict(combined_result)
json_str = json.dumps(output_dict, indent=2)
if args.output:
with open(args.output, "w", encoding="utf-8") as fh:
fh.write(json_str)
if not args.json:
print(f"Results written to {args.output}")
if args.json:
print(json_str)
else:
print_text_report(combined_result)
# --- Exit code ---
if combined_result.critical_count > 0:
sys.exit(2)
if combined_result.high_count > 0:
sys.exit(1)
sys.exit(0)
if __name__ == "__main__":
main()
Bộ định tuyến trung tâm của hệ skill marketing: chọn skill phù hợp và phối hợp nội dung, SEO, CRO, kênh và phân tích trong chiến dịch nhiều bước.
---
name: "marketing-ops"
description: "Central router for the marketing skill ecosystem. Use when unsure which marketing skill to use, when orchestrating a multi-skill campaign, or when coordinating across content, SEO, CRO, channels, and analytics. Also use when the user mentions 'marketing help,' 'campaign plan,' 'what should I do next,' 'marketing priorities,' or 'coordinate marketing.'"
license: MIT
metadata:
version: 1.0.0
author: Alireza Rezvani
category: marketing
updated: 2026-03-06
---
# Marketing Ops
You are a senior marketing operations leader. Your goal is to route marketing questions to the right specialist skill, orchestrate multi-skill campaigns, and ensure quality across all marketing output.
## Before Starting
**Check for marketing context first:**
If `marketing-context.md` exists, read it. If it doesn't, recommend running the **marketing-context** skill first — everything works better with context.
## How This Skill Works
### Mode 1: Route a Question
User has a marketing question → you identify the right skill and route them.
### Mode 2: Campaign Orchestration
User wants to plan or execute a campaign → you coordinate across multiple skills in sequence.
### Mode 3: Marketing Audit
User wants to assess their marketing → you run a cross-functional audit touching SEO, content, CRO, and channels.
---
## Routing Matrix
### Content Pod
| Trigger | Route to | NOT this |
|---------|----------|----------|
| "Write a blog post," "content ideas," "what should I write" | **content-strategy** | Not copywriting (that's for page copy) |
| "Write copy for my homepage," "landing page copy," "headline" | **copywriting** | Not content-strategy (that's for planning) |
| "Edit this copy," "proofread," "polish this" | **copy-editing** | Not copywriting (that's for writing new) |
| "Social media post," "LinkedIn post," "tweet" | **social-content** | Not social-media-manager (that's for strategy) |
| "Marketing ideas," "brainstorm," "what else can I try" | **marketing-ideas** | |
| "Write an article," "research and write," "SEO article" | **content-production** | Not content-creator (production has the full pipeline) |
| "Sounds too robotic," "make it human," "AI watermarks" | **content-humanizer** | |
### SEO Pod
| Trigger | Route to | NOT this |
|---------|----------|----------|
| "SEO audit," "technical SEO," "on-page SEO" | **seo-audit** | Not ai-seo (that's for AI search engines) |
| "AI search," "ChatGPT visibility," "Perplexity," "AEO" | **ai-seo** | Not seo-audit (that's traditional SEO) |
| "Schema markup," "structured data," "JSON-LD," "rich snippets" | **schema-markup** | |
| "Site structure," "URL structure," "navigation," "sitemap" | **site-architecture** | |
| "Programmatic SEO," "pages at scale," "template pages" | **programmatic-seo** | |
### CRO Pod
| Trigger | Route to | NOT this |
|---------|----------|----------|
| "Optimize this page," "conversion rate," "CRO audit" | **page-cro** | Not form-cro (that's for forms specifically) |
| "Form optimization," "lead form," "contact form" | **form-cro** | Not signup-flow-cro (that's for registration) |
| "Signup flow," "registration," "account creation" | **signup-flow-cro** | Not onboarding-cro (that's post-signup) |
| "Onboarding," "activation," "first-run experience" | **onboarding-cro** | Not signup-flow-cro (that's pre-signup) |
| "Popup," "modal," "overlay," "exit intent" | **popup-cro** | |
| "Paywall," "upgrade screen," "upsell modal" | **paywall-upgrade-cro** | |
### Channels Pod
| Trigger | Route to | NOT this |
|---------|----------|----------|
| "Email sequence," "drip campaign," "welcome sequence" | **email-sequence** | Not cold-email (that's for outbound) |
| "Cold email," "outreach," "prospecting email" | **cold-email** | Not email-sequence (that's for lifecycle) |
| "Paid ads," "Google Ads," "Meta ads," "ad campaign" | **paid-ads** | Not ad-creative (that's for copy generation) |
| "Ad copy," "ad headlines," "ad variations," "RSA" | **ad-creative** | Not paid-ads (that's for strategy) |
| "Social media strategy," "social calendar," "community" | **social-media-manager** | Not social-content (that's for individual posts) |
### Growth Pod
| Trigger | Route to | NOT this |
|---------|----------|----------|
| "A/B test," "experiment," "split test" | **ab-test-setup** | |
| "Referral program," "affiliate," "word of mouth" | **referral-program** | |
| "Free tool," "calculator," "marketing tool" | **free-tool-strategy** | |
| "Churn," "cancel flow," "dunning," "retention" | **churn-prevention** | |
### Intelligence Pod
| Trigger | Route to | NOT this |
|---------|----------|----------|
| "Campaign analytics," "channel performance," "attribution" | **campaign-analytics** | Not analytics-tracking (that's for setup) |
| "Set up tracking," "GA4," "GTM," "event tracking" | **analytics-tracking** | Not campaign-analytics (that's for analysis) |
| "Competitor page," "vs page," "alternative page" | **competitor-alternatives** | |
| "Psychology," "persuasion," "behavioral science" | **marketing-psychology** | |
### Sales & GTM Pod
| Trigger | Route to | NOT this |
|---------|----------|----------|
| "Product launch," "feature announcement," "Product Hunt" | **launch-strategy** | |
| "Pricing," "how much to charge," "pricing tiers" | **pricing-strategy** | |
### Cross-Domain (route outside marketing-skill/)
| Trigger | Route to | Domain |
|---------|----------|--------|
| "Revenue operations," "pipeline," "lead scoring" | **revenue-operations** | business-growth/ |
| "Sales deck," "pitch deck," "objection handling" | **sales-engineer** | business-growth/ |
| "Customer health," "expansion," "NPS" | **customer-success-manager** | business-growth/ |
| "Landing page code," "React component" | **landing-page-generator** | product-team/ |
| "Competitive teardown," "feature matrix" | **competitive-teardown** | product-team/ |
| "Email template code," "transactional email" | **email-template-builder** | engineering-team/ |
| "Brand strategy," "growth model," "marketing budget" | **cmo-advisor** | c-level-advisor/ |
---
## Campaign Orchestration
For multi-skill campaigns, follow this sequence:
### New Product/Feature Launch
```
1. marketing-context (ensure foundation exists)
2. launch-strategy (plan the launch)
3. content-strategy (plan content around launch)
4. copywriting (write landing page)
5. email-sequence (write launch emails)
6. social-content (write social posts)
7. paid-ads + ad-creative (paid promotion)
8. analytics-tracking (set up tracking)
9. campaign-analytics (measure results)
```
### Content Campaign
```
1. content-strategy (plan topics + calendar)
2. seo-audit (identify SEO opportunities)
3. content-production (research → write → optimize)
4. content-humanizer (polish for natural voice)
5. schema-markup (add structured data)
6. social-content (promote on social)
7. email-sequence (distribute via email)
```
### Conversion Optimization Sprint
```
1. page-cro (audit current pages)
2. copywriting (rewrite underperforming copy)
3. form-cro or signup-flow-cro (optimize forms)
4. ab-test-setup (design tests)
5. analytics-tracking (ensure tracking is right)
6. campaign-analytics (measure impact)
```
---
## Quality Gate
Before any marketing output reaches the user:
- [ ] Marketing context was checked (not generic advice)
- [ ] Output follows communication standard (bottom line first)
- [ ] Actions have owners and deadlines
- [ ] Related skills referenced for next steps
- [ ] Cross-domain skills flagged when relevant
---
## Proactive Triggers
- **No marketing context exists** → "Run marketing-context first — every skill works 3x better with context."
- **Multiple skills needed** → Route to campaign orchestration mode, not just one skill.
- **Cross-domain question disguised as marketing** → Route to correct domain (e.g., "help with pricing" → pricing-strategy, not CRO).
- **Analytics not set up** → "Before optimizing, make sure tracking is in place — route to analytics-tracking first."
- **Content without SEO** → "This content should be SEO-optimized. Run seo-audit or content-production, not just copywriting."
## Output Artifacts
| When you ask for... | You get... |
|---------------------|------------|
| "What marketing skill should I use?" | Routing recommendation with skill name + why + what to expect |
| "Plan a campaign" | Campaign orchestration plan with skill sequence + timeline |
| "Marketing audit" | Cross-functional audit touching all pods with prioritized recommendations |
| "What's missing in my marketing?" | Gap analysis against full skill ecosystem |
## Communication
All output passes quality verification:
- Self-verify: routing recommendation checked against full matrix
- Output format: Bottom Line → What (with confidence) → Why → How to Act
- Results only. Every finding tagged: 🟢 verified, 🟡 medium, 🔴 assumed.
## Related Skills
- **chief-of-staff** (C-Suite): The C-level router. Marketing-ops is the domain-specific equivalent.
- **marketing-context**: Foundation — run this first if it doesn't exist.
- **cmo-advisor** (C-Suite): Strategic marketing decisions. Marketing-ops handles execution routing.
- **campaign-analytics**: For measuring outcomes of orchestrated campaigns.
FILE:scripts/campaign_tracker.py
#!/usr/bin/env python3
"""Track campaign status across marketing skills — tasks, owners, deadlines."""
import json
import sys
from datetime import datetime, timedelta
from pathlib import Path
SAMPLE_CAMPAIGN = {
"name": "Q1 Product Launch",
"created": "2026-03-01",
"status": "in_progress",
"skills_used": [],
"tasks": [
{"skill": "marketing-context", "task": "Update context for new feature", "owner": "Marketing", "deadline": "2026-03-03", "status": "complete"},
{"skill": "launch-strategy", "task": "Plan launch phases", "owner": "PMM", "deadline": "2026-03-05", "status": "complete"},
{"skill": "content-strategy", "task": "Plan content calendar", "owner": "Content", "deadline": "2026-03-07", "status": "in_progress"},
{"skill": "copywriting", "task": "Write landing page copy", "owner": "Copywriter", "deadline": "2026-03-10", "status": "not_started"},
{"skill": "email-sequence", "task": "Write launch email sequence", "owner": "Email", "deadline": "2026-03-10", "status": "not_started"},
{"skill": "social-content", "task": "Create social media posts", "owner": "Social", "deadline": "2026-03-12", "status": "not_started"},
{"skill": "paid-ads", "task": "Set up ad campaigns", "owner": "Paid", "deadline": "2026-03-12", "status": "not_started"},
{"skill": "ad-creative", "task": "Generate ad variations", "owner": "Creative", "deadline": "2026-03-11", "status": "not_started"},
{"skill": "analytics-tracking", "task": "Set up conversion tracking", "owner": "Analytics", "deadline": "2026-03-08", "status": "in_progress"},
{"skill": "seo-audit", "task": "Optimize landing page SEO", "owner": "SEO", "deadline": "2026-03-09", "status": "not_started"},
]
}
def analyze_campaign(campaign: dict) -> dict:
"""Analyze campaign status and generate report."""
tasks = campaign["tasks"]
today = datetime.now().strftime("%Y-%m-%d")
complete = [t for t in tasks if t["status"] == "complete"]
in_progress = [t for t in tasks if t["status"] == "in_progress"]
not_started = [t for t in tasks if t["status"] == "not_started"]
overdue = [t for t in tasks if t["deadline"] < today and t["status"] != "complete"]
due_soon = [t for t in tasks if today <= t["deadline"] <= (datetime.now() + timedelta(days=3)).strftime("%Y-%m-%d") and t["status"] != "complete"]
total = len(tasks)
progress = round((len(complete) / total) * 100) if total > 0 else 0
# Skills coverage
skills_used = list(set(t["skill"] for t in tasks))
pods_covered = set()
pod_map = {
"content": ["content-strategy", "copywriting", "copy-editing", "social-content", "marketing-ideas", "content-production", "content-humanizer", "content-creator"],
"seo": ["seo-audit", "programmatic-seo", "ai-seo", "schema-markup", "site-architecture"],
"cro": ["page-cro", "form-cro", "signup-flow-cro", "onboarding-cro", "popup-cro", "paywall-upgrade-cro"],
"channels": ["email-sequence", "cold-email", "paid-ads", "ad-creative", "social-media-manager"],
"growth": ["ab-test-setup", "referral-program", "free-tool-strategy", "churn-prevention"],
"intelligence": ["campaign-analytics", "analytics-tracking", "competitor-alternatives", "marketing-psychology"],
"gtm": ["launch-strategy", "pricing-strategy"]
}
for pod, skills in pod_map.items():
if any(s in skills_used for s in skills):
pods_covered.add(pod)
# Blockers
blockers = []
for t in tasks:
if t["status"] == "not_started":
# Check if any dependency is incomplete
deps = [d for d in tasks if d["deadline"] < t["deadline"] and d["status"] != "complete"]
if deps:
blocker_names = [d["task"] for d in deps if d["status"] != "complete"]
if blocker_names:
blockers.append({"task": t["task"], "blocked_by": blocker_names[0]})
return {
"campaign": campaign["name"],
"progress": progress,
"total_tasks": total,
"complete": len(complete),
"in_progress": len(in_progress),
"not_started": len(not_started),
"overdue": [{"task": t["task"], "deadline": t["deadline"], "owner": t["owner"]} for t in overdue],
"due_soon": [{"task": t["task"], "deadline": t["deadline"], "owner": t["owner"]} for t in due_soon],
"pods_covered": sorted(pods_covered),
"pods_missing": sorted(set(pod_map.keys()) - pods_covered),
"skills_used": sorted(skills_used),
"blockers": blockers
}
def print_report(analysis: dict):
"""Print human-readable campaign status."""
print(f"\n{'='*55}")
print(f"CAMPAIGN: {analysis['campaign']}")
print(f"{'='*55}")
bar_len = 30
filled = round(bar_len * analysis["progress"] / 100)
bar = "█" * filled + "░" * (bar_len - filled)
print(f"\nProgress: [{bar}] {analysis['progress']}%")
print(f"Tasks: {analysis['complete']} done / {analysis['in_progress']} active / {analysis['not_started']} pending")
if analysis["overdue"]:
print(f"\n🔴 OVERDUE ({len(analysis['overdue'])}):")
for t in analysis["overdue"]:
print(f" → {t['task']} (due {t['deadline']}, owner: {t['owner']})")
if analysis["due_soon"]:
print(f"\n🟡 DUE SOON ({len(analysis['due_soon'])}):")
for t in analysis["due_soon"]:
print(f" → {t['task']} (due {t['deadline']}, owner: {t['owner']})")
if analysis["blockers"]:
print(f"\n⚠️ BLOCKERS:")
for b in analysis["blockers"]:
print(f" → {b['task']} blocked by: {b['blocked_by']}")
print(f"\n📦 Pods covered: {', '.join(analysis['pods_covered'])}")
if analysis["pods_missing"]:
print(f" Missing: {', '.join(analysis['pods_missing'])}")
print(f"\n🔧 Skills used: {', '.join(analysis['skills_used'])}")
print(f"{'='*55}")
def main():
import argparse
parser = argparse.ArgumentParser(
description="Track campaign status across marketing skills — tasks, owners, deadlines."
)
parser.add_argument(
"input_file", nargs="?", default=None,
help="JSON file with campaign data (default: run with sample data)"
)
parser.add_argument(
"--json", action="store_true",
help="Also output results as JSON"
)
args = parser.parse_args()
if args.input_file:
filepath = Path(args.input_file)
if filepath.exists():
campaign = json.loads(filepath.read_text())
else:
print(f"Error: {filepath} not found", file=sys.stderr)
sys.exit(1)
else:
campaign = SAMPLE_CAMPAIGN
print("[Using sample campaign data — pass a JSON file for real tracking]")
analysis = analyze_campaign(campaign)
print_report(analysis)
if args.json:
print(f"\n{json.dumps(analysis, indent=2)}")
if __name__ == "__main__":
main()
Tối ưu onboarding sau đăng ký, tỷ lệ kích hoạt, trải nghiệm lần đầu và thời gian đạt giá trị: checklist, empty state, khoảnh khắc aha.
---
name: "onboarding-cro"
description: When the user wants to optimize post-signup onboarding, user activation, first-run experience, or time-to-value. Also use when the user mentions "onboarding flow," "activation rate," "user activation," "first-run experience," "empty states," "onboarding checklist," "aha moment," or "new user experience." For signup/registration optimization, see signup-flow-cro. For ongoing email sequences, see email-sequence.
license: MIT
metadata:
version: 1.0.0
author: Alireza Rezvani
category: marketing
updated: 2026-03-06
---
# Onboarding CRO
You are an expert in user onboarding and activation. Your goal is to help users reach their "aha moment" as quickly as possible and establish habits that lead to long-term retention.
## Initial Assessment
**Check for product marketing context first:**
If `.claude/product-marketing-context.md` exists, read it before asking questions. Use that context and only ask for information not already covered or specific to this task.
Before providing recommendations, understand:
1. **Product Context** - What type of product? B2B or B2C? Core value proposition?
2. **Activation Definition** - What's the "aha moment"? What action indicates a user "gets it"?
3. **Current State** - What happens after signup? Where do users drop off?
---
## Core Principles
### 1. Time-to-Value Is Everything
Remove every step between signup and experiencing core value.
### 2. One Goal Per Session
Focus first session on one successful outcome. Save advanced features for later.
### 3. Do, Don't Show
Interactive > Tutorial. Doing the thing > Learning about the thing.
### 4. Progress Creates Motivation
Show advancement. Celebrate completions. Make the path visible.
---
## Defining Activation
### Find Your Aha Moment
The action that correlates most strongly with retention:
- What do retained users do that churned users don't?
- What's the earliest indicator of future engagement?
**Examples by product type:**
- Project management: Create first project + add team member
- Analytics: Install tracking + see first report
- Design tool: Create first design + export/share
- Marketplace: Complete first transaction
### Activation Metrics
- % of signups who reach activation
- Time to activation
- Steps to activation
- Activation by cohort/source
---
## Onboarding Flow Design
### Immediate Post-Signup (First 30 Seconds)
| Approach | Best For | Risk |
|----------|----------|------|
| Product-first | Simple products, B2C, mobile | Blank slate overwhelm |
| Guided setup | Products needing personalization | Adds friction before value |
| Value-first | Products with demo data | May not feel "real" |
**Whatever you choose:**
- Clear single next action
- No dead ends
- Progress indication if multi-step
### Onboarding Checklist Pattern
**When to use:**
- Multiple setup steps required
- Product has several features to discover
- Self-serve B2B products
**Best practices:**
- 3-7 items (not overwhelming)
- Order by value (most impactful first)
- Start with quick wins
- Progress bar/completion %
- Celebration on completion
- Dismiss option (don't trap users)
### Empty States
Empty states are onboarding opportunities, not dead ends.
**Good empty state:**
- Explains what this area is for
- Shows what it looks like with data
- Clear primary action to add first item
- Optional: Pre-populate with example data
### Tooltips and Guided Tours
**When to use:** Complex UI, features that aren't self-evident, power features users might miss
**Best practices:**
- Max 3-5 steps per tour
- Dismissable at any time
- Don't repeat for returning users
---
## Multi-Channel Onboarding
### Email + In-App Coordination
**Trigger-based emails:**
- Welcome email (immediate)
- Incomplete onboarding (24h, 72h)
- Activation achieved (celebration + next step)
- Feature discovery (days 3, 7, 14)
**Email should:**
- Reinforce in-app actions, not duplicate them
- Drive back to product with specific CTA
- Be personalized based on actions taken
---
## Handling Stalled Users
### Detection
Define "stalled" criteria (X days inactive, incomplete setup)
### Re-engagement Tactics
1. **Email sequence** - Reminder of value, address blockers, offer help
2. **In-app recovery** - Welcome back, pick up where left off
3. **Human touch** - For high-value accounts, personal outreach
---
## Measurement
### Key Metrics
| Metric | Description |
|--------|-------------|
| Activation rate | % reaching activation event |
| Time to activation | How long to first value |
| Onboarding completion | % completing setup |
| Day 1/7/30 retention | Return rate by timeframe |
### Funnel Analysis
Track drop-off at each step:
```
Signup → Step 1 → Step 2 → Activation → Retention
100% 80% 60% 40% 25%
```
Identify biggest drops and focus there.
---
## Output Format
### Onboarding Audit
For each issue: Finding → Impact → Recommendation → Priority
### Onboarding Flow Design
- Activation goal
- Step-by-step flow
- Checklist items (if applicable)
- Empty state copy
- Email sequence triggers
- Metrics plan
---
## Common Patterns by Product Type
| Product Type | Key Steps |
|--------------|-----------|
| B2B SaaS | Setup wizard → First value action → Team invite → Deep setup |
| Marketplace | Complete profile → Browse → First transaction → Repeat loop |
| Mobile App | Permissions → Quick win → Push setup → Habit loop |
| Content Platform | Follow/customize → Consume → Create → Engage |
---
## Experiment Ideas
When recommending experiments, consider tests for:
- Flow simplification (step count, ordering)
- Progress and motivation mechanics
- Personalization by role or goal
- Support and help availability
---
## Task-Specific Questions
1. What action most correlates with retention?
2. What happens immediately after signup?
3. Where do users currently drop off?
4. What's your activation rate target?
5. Do you have cohort analysis on successful vs. churned users?
---
## Related Skills
- **signup-flow-cro** — WHEN optimizing the registration and pre-onboarding flow before users ever land in-app. NOT when users have already signed up and activation is the goal.
- **popup-cro** — WHEN using in-product modals, tooltips, or overlays as part of the onboarding experience. NOT for standalone lead capture or exit-intent popups on the marketing site.
- **paywall-upgrade-cro** — WHEN onboarding naturally leads into an upgrade prompt after the aha moment is reached. NOT during early onboarding before value is delivered.
- **ab-test-setup** — WHEN running controlled experiments on onboarding flows, checklists, or step ordering. NOT for initial brainstorming or design.
- **marketing-context** — Foundation skill. ALWAYS load when product/ICP context is needed for personalized onboarding recommendations. NOT optional — load before this skill if available.
---
## Communication
Deliver recommendations following the output quality standard: lead with the highest-leverage finding, provide a clear activation definition, then prioritize experiments by expected impact. Avoid vague advice — every recommendation should name a specific onboarding step, metric, or trigger. When writing onboarding copy or flows, ensure tone matches the product's brand voice (load `marketing-context` if available).
---
## Proactive Triggers
- User mentions low Day-1 or Day-7 retention → immediately ask about their activation event and current post-signup flow.
- User shares a signup funnel with a big drop between "signup" and "first key action" → diagnose onboarding, not acquisition.
- User says "users sign up but don't come back" → frame this as an activation/onboarding problem, not a marketing problem.
- User asks about improving trial-to-paid conversion → check whether activation is defined and being reached before assuming pricing is the blocker.
- User mentions "onboarding emails aren't working" → ask what in-app onboarding exists first; email should support, not replace, in-app experience.
---
## Output Artifacts
| Artifact | Description |
|----------|-------------|
| Activation Definition Doc | Clearly defined aha moment, correlated action, and success metric |
| Onboarding Flow Diagram | Step-by-step post-signup flow with drop-off points and decision branches |
| Checklist Copy | 3–7 onboarding checklist items ordered by value, with completion messaging |
| Email Trigger Map | Trigger conditions, timing, and goals for each onboarding email in the sequence |
| Experiment Backlog | Prioritized A/B test ideas for onboarding steps, sorted by expected impact |
FILE:scripts/activation_funnel_analyzer.py
#!/usr/bin/env python3
"""
Activation Funnel Analyzer for Onboarding CRO
Analyzes user onboarding funnel data to identify drop-off points
and estimate the impact of improving each step.
Usage:
python3 activation_funnel_analyzer.py # Demo mode
python3 activation_funnel_analyzer.py funnel.json # From data
python3 activation_funnel_analyzer.py funnel.json --json # JSON output
Input format (JSON):
{
"steps": [
{"name": "Signup completed", "users": 1000},
{"name": "Email verified", "users": 850},
{"name": "Profile setup", "users": 620},
{"name": "First action", "users": 310},
{"name": "Aha moment", "users": 180},
{"name": "Activated (Day 7)", "users": 120}
]
}
"""
import json
import sys
import os
def analyze_funnel(data):
"""Analyze onboarding funnel for drop-offs and improvement potential."""
steps = data["steps"]
if len(steps) < 2:
return {"error": "Need at least 2 funnel steps"}
total_start = steps[0]["users"]
analysis = []
worst_step = None
worst_drop = 0
for i in range(len(steps)):
step = steps[i]
users = step["users"]
rate_from_start = (users / total_start * 100) if total_start > 0 else 0
if i == 0:
step_analysis = {
"step": step["name"],
"users": users,
"rate_from_start": round(rate_from_start, 1),
"drop_rate": 0,
"dropped_users": 0,
"is_worst": False
}
else:
prev_users = steps[i - 1]["users"]
dropped = prev_users - users
drop_rate = (dropped / prev_users * 100) if prev_users > 0 else 0
step_analysis = {
"step": step["name"],
"users": users,
"rate_from_start": round(rate_from_start, 1),
"drop_rate": round(drop_rate, 1),
"dropped_users": dropped,
"is_worst": False
}
if drop_rate > worst_drop:
worst_drop = drop_rate
worst_step = i
analysis.append(step_analysis)
if worst_step is not None:
analysis[worst_step]["is_worst"] = True
# Calculate improvement potential
final_users = steps[-1]["users"]
overall_conversion = (final_users / total_start * 100) if total_start > 0 else 0
improvements = []
if worst_step is not None:
worst = analysis[worst_step]
# What if we halved the drop-off at the worst step?
current_drop_rate = worst["drop_rate"] / 100
improved_drop_rate = current_drop_rate / 2
prev_users = steps[worst_step - 1]["users"]
gained_users = int(prev_users * (current_drop_rate - improved_drop_rate))
# Propagate improvement through remaining steps
cascade_rate = 1.0
for j in range(worst_step + 1, len(steps)):
if steps[j - 1]["users"] > 0:
cascade_rate *= steps[j]["users"] / steps[j - 1]["users"]
additional_activated = int(gained_users * cascade_rate)
improvements.append({
"action": f"Halve drop-off at '{worst['step']}'",
"current_drop": f"{worst['drop_rate']}%",
"target_drop": f"{worst['drop_rate'] / 2:.1f}%",
"users_saved": gained_users,
"additional_activated": additional_activated,
"impact_on_overall": f"+{(additional_activated / total_start * 100):.1f}pp"
})
# Score
score = min(100, max(0, int(overall_conversion * 5))) # 20% activation = 100
if overall_conversion < 5:
score = max(0, int(overall_conversion * 10))
return {
"steps": analysis,
"summary": {
"total_start": total_start,
"total_activated": final_users,
"overall_conversion": round(overall_conversion, 1),
"worst_step": analysis[worst_step]["step"] if worst_step else None,
"worst_drop_rate": round(worst_drop, 1),
"score": score
},
"improvements": improvements
}
def format_report(result):
"""Format human-readable report."""
lines = []
lines.append("")
lines.append("=" * 65)
lines.append(" ONBOARDING FUNNEL — ACTIVATION ANALYSIS")
lines.append("=" * 65)
lines.append("")
summary = result["summary"]
score = summary["score"]
bar = "█" * (score // 5) + "░" * (20 - score // 5)
lines.append(f" ACTIVATION SCORE: {score}/100")
lines.append(f" [{bar}]")
lines.append(f" Overall: {summary['total_start']} → {summary['total_activated']} ({summary['overall_conversion']}%)")
lines.append("")
# Funnel visualization
lines.append(" FUNNEL:")
max_users = result["steps"][0]["users"]
for step in result["steps"]:
bar_width = int(step["users"] / max_users * 40) if max_users > 0 else 0
bar_char = "█" * bar_width
marker = " ← WORST DROP" if step["is_worst"] else ""
drop_info = f" (-{step['drop_rate']}%)" if step["drop_rate"] > 0 else ""
lines.append(f" {bar_char} {step['users']:>5} | {step['step']}{drop_info}{marker}")
lines.append("")
# Step-by-step breakdown
lines.append(" STEP BREAKDOWN:")
lines.append(f" {'Step':<25} {'Users':>7} {'From Start':>12} {'Drop':>8} {'Lost':>7}")
lines.append(" " + "-" * 62)
for step in result["steps"]:
drop = f"-{step['drop_rate']}%" if step["drop_rate"] > 0 else "—"
lost = f"-{step['dropped_users']}" if step["dropped_users"] > 0 else "—"
lines.append(f" {step['step']:<25} {step['users']:>7} {step['rate_from_start']:>10.1f}% {drop:>8} {lost:>7}")
lines.append("")
# Improvement potential
if result["improvements"]:
lines.append(" 💡 IMPROVEMENT POTENTIAL:")
for imp in result["improvements"]:
lines.append(f" Action: {imp['action']}")
lines.append(f" Drop: {imp['current_drop']} → {imp['target_drop']}")
lines.append(f" Users saved at step: +{imp['users_saved']}")
lines.append(f" Additional activated: +{imp['additional_activated']}")
lines.append(f" Impact on overall rate: {imp['impact_on_overall']}")
lines.append("")
return "\n".join(lines)
SAMPLE_DATA = {
"steps": [
{"name": "Signup completed", "users": 1000},
{"name": "Email verified", "users": 840},
{"name": "Profile setup", "users": 580},
{"name": "First project created", "users": 290},
{"name": "Invited teammate", "users": 145},
{"name": "Aha moment (Day 3)", "users": 95},
{"name": "Activated (Day 7)", "users": 72}
]
}
def main():
use_json = "--json" in sys.argv
args = [a for a in sys.argv[1:] if a != "--json"]
if args and os.path.isfile(args[0]):
with open(args[0]) as f:
data = json.load(f)
else:
if not args:
print("[Demo mode — analyzing sample SaaS onboarding funnel]")
data = SAMPLE_DATA
result = analyze_funnel(data)
if use_json:
print(json.dumps(result, indent=2))
else:
print(format_report(result))
if __name__ == "__main__":
main()
Bộ công cụ chiến lược cho Head of Product: chuỗi OKR, kế hoạch quý, phân tích cảnh quan cạnh tranh, tầm nhìn sản phẩm và đề xuất mở rộng đội ngũ.
---
name: "product-strategist"
description: Strategic product leadership toolkit for Head of Product covering OKR cascade generation, quarterly planning, competitive landscape analysis, product vision documents, and team scaling proposals. Use when creating quarterly OKR documents, defining product goals or KPIs, building product roadmaps, running competitive analysis, drafting team structure or hiring plans, aligning product strategy across engineering and design, or generating cascaded goal hierarchies from company to team level.
---
# Product Strategist
Strategic toolkit for Head of Product to drive vision, alignment, and organizational excellence.
---
## Core Capabilities
| Capability | Description | Tool |
|------------|-------------|------|
| **OKR Cascade** | Generate aligned OKRs from company to team level | `okr_cascade_generator.py` |
| **Alignment Scoring** | Measure vertical and horizontal alignment | Built into generator |
| **Strategy Templates** | 5 pre-built strategy types | Growth, Retention, Revenue, Innovation, Operational |
| **Team Configuration** | Customize for your org structure | `--teams` flag |
---
## Quick Start
```bash
# Growth strategy with default teams
python scripts/okr_cascade_generator.py growth
# Retention strategy with custom teams
python scripts/okr_cascade_generator.py retention --teams "Engineering,Design,Data"
# Revenue strategy with 40% product contribution
python scripts/okr_cascade_generator.py revenue --contribution 0.4
# Export as JSON for integration
python scripts/okr_cascade_generator.py growth --json > okrs.json
```
---
## Workflow: Quarterly Strategic Planning
### Step 1: Define Strategic Focus
| Strategy | When to Use |
|----------|-------------|
| **Growth** | Scaling user base, market expansion |
| **Retention** | Reducing churn, improving LTV |
| **Revenue** | Increasing ARPU, new monetization |
| **Innovation** | Market differentiation, new capabilities |
| **Operational** | Improving efficiency, scaling operations |
See `references/strategy_types.md` for detailed guidance.
### Step 2: Gather Input Metrics
```json
{
"current": 100000, // Current MAU
"target": 150000, // Target MAU
"current_nps": 40, // Current NPS
"target_nps": 60 // Target NPS
}
```
### Step 3: Configure Teams & Run Generator
```bash
# Default teams
python scripts/okr_cascade_generator.py growth
# Custom org structure with contribution percentage
python scripts/okr_cascade_generator.py growth \
--teams "Core,Platform,Mobile,AI" \
--contribution 0.3
```
### Step 4: Review Alignment Scores
| Score | Target | Action if Below |
|-------|--------|-----------------|
| Vertical Alignment | >90% | Ensure all objectives link to parent |
| Horizontal Alignment | >75% | Check for team coordination gaps |
| Coverage | >80% | Validate all company OKRs are addressed |
| Balance | >80% | Redistribute if one team is overloaded |
| **Overall** | **>80%** | <60% needs restructuring |
### Step 5: Refine, Validate, and Export
Before finalizing:
- [ ] Review generated objectives with stakeholders
- [ ] Adjust team assignments based on capacity
- [ ] Validate contribution percentages are realistic
- [ ] Ensure no conflicting objectives across teams
- [ ] Set up tracking cadence (bi-weekly check-ins)
```bash
# Export JSON for tools like Lattice, Ally, Workboard
python scripts/okr_cascade_generator.py growth --json > q1_okrs.json
```
---
## OKR Cascade Generator
### Usage
```bash
python scripts/okr_cascade_generator.py [strategy] [options]
```
**Strategies:** `growth` | `retention` | `revenue` | `innovation` | `operational`
### Configuration Options
| Option | Description | Default |
|--------|-------------|---------|
| `--teams`, `-t` | Comma-separated team names | Growth,Platform,Mobile,Data |
| `--contribution`, `-c` | Product contribution to company OKRs (0-1) | 0.3 (30%) |
| `--json`, `-j` | Output as JSON instead of dashboard | False |
| `--metrics`, `-m` | Metrics as JSON string | Sample metrics |
### Output Examples
#### Dashboard Output (`growth` strategy)
```
============================================================
OKR CASCADE DASHBOARD
Quarter: Q1 2025 | Strategy: GROWTH
Teams: Growth, Platform, Mobile, Data | Product Contribution: 30%
============================================================
🏢 COMPANY OKRS
📌 CO-1: Accelerate user acquisition and market expansion
└─ CO-1-KR1: Increase MAU from 100,000 to 150,000
└─ CO-1-KR2: Achieve 50% MoM growth rate
└─ CO-1-KR3: Expand to 3 new markets
📌 CO-2: Achieve product-market fit in new segments
📌 CO-3: Build sustainable growth engine
🚀 PRODUCT OKRS
📌 PO-1: Build viral product features and market expansion
↳ Supports: CO-1
└─ PO-1-KR1: Increase product MAU to 45,000
└─ PO-1-KR2: Achieve 45% feature adoption rate
👥 TEAM OKRS
Growth Team:
📌 GRO-1: Build viral product features through acquisition and activation
└─ GRO-1-KR1: Increase product MAU to 11,250
└─ GRO-1-KR2: Achieve 11.25% feature adoption rate
🎯 ALIGNMENT SCORES
✓ Vertical Alignment: 100.0%
! Horizontal Alignment: 75.0%
✓ Coverage: 100.0% | ✓ Balance: 97.5% | ✓ Overall: 94.0%
✅ Overall alignment is GOOD (≥80%)
```
#### JSON Output (`retention --json`, truncated)
```json
{
"quarter": "Q1 2025",
"strategy": "retention",
"company": {
"objectives": [
{
"id": "CO-1",
"title": "Create lasting customer value and loyalty",
"key_results": [
{ "id": "CO-1-KR1", "title": "Improve retention from 70% to 85%", "current": 70, "target": 85 }
]
}
]
},
"product": { "contribution": 0.3, "objectives": ["..."] },
"teams": ["..."],
"alignment_scores": {
"vertical_alignment": 100.0, "horizontal_alignment": 75.0,
"coverage": 100.0, "balance": 97.5, "overall": 94.0
}
}
```
See `references/examples/sample_growth_okrs.json` for a complete example.
---
## Reference Documents
| Document | Description |
|----------|-------------|
| `references/okr_framework.md` | OKR methodology, writing guidelines, alignment scoring |
| `references/strategy_types.md` | Detailed breakdown of all 5 strategy types with examples |
| `references/examples/sample_growth_okrs.json` | Complete sample output for growth strategy |
---
## Best Practices
### OKR Cascade
- Limit to 3-5 objectives per level, each with 3-5 key results
- Key results must be measurable with current and target values
- Validate parent-child relationships before finalizing
### Alignment Scoring
- Target >80% overall alignment; investigate any score below 60%
- Balance scores ensure no team is overloaded
- Horizontal alignment prevents conflicting goals across teams
### Team Configuration
- Configure teams to match your actual org structure
- Adjust contribution percentages based on team size
- Platform/Infrastructure teams often support all objectives
- Specialized teams (ML, Data) may only support relevant objectives
## Related Skills
- **Senior PM** (`project-management/senior-pm/`) — Portfolio management and risk analysis inform strategic planning
- **Competitive Teardown** (`product-team/competitive-teardown/`) — Competitive intelligence feeds product strategy
FILE:assets/okr_template.md
# OKR Planning Template
## Planning Info
| Field | Value |
|-------|-------|
| **Quarter** | [Q1/Q2/Q3/Q4 YYYY] |
| **Team** | [Team Name] |
| **Owner** | [Name] |
| **Status** | Planning / Active / Complete |
| **Tracking Cadence** | Weekly check-in, Monthly review |
---
## Company Objective
**[Company-level objective this product work supports]**
_Example: "Become the market leader in our category by delivering exceptional customer value"_
---
## Product Objective 1: [Objective Title]
_[Qualitative, inspirational statement. What does success look like?]_
### Key Results
| # | Key Result | Baseline | Target | Current | Status |
|---|-----------|----------|--------|---------|--------|
| 1.1 | [Measurable outcome] | [Current value] | [Target value] | [Progress] | On Track / At Risk / Off Track |
| 1.2 | [Measurable outcome] | [Current value] | [Target value] | [Progress] | On Track / At Risk / Off Track |
| 1.3 | [Measurable outcome] | [Current value] | [Target value] | [Progress] | On Track / At Risk / Off Track |
### Initiatives
| Initiative | Key Result | Owner | Status | Effort |
|-----------|-----------|-------|--------|--------|
| [Feature/project name] | KR 1.1 | [Name] | Not Started / In Progress / Complete | [T-shirt size] |
| [Feature/project name] | KR 1.2 | [Name] | Not Started / In Progress / Complete | [T-shirt size] |
---
## Product Objective 2: [Objective Title]
_[Qualitative, inspirational statement]_
### Key Results
| # | Key Result | Baseline | Target | Current | Status |
|---|-----------|----------|--------|---------|--------|
| 2.1 | [Measurable outcome] | [Current value] | [Target value] | [Progress] | On Track / At Risk / Off Track |
| 2.2 | [Measurable outcome] | [Current value] | [Target value] | [Progress] | On Track / At Risk / Off Track |
| 2.3 | [Measurable outcome] | [Current value] | [Target value] | [Progress] | On Track / At Risk / Off Track |
| 2.4 | [Measurable outcome] | [Current value] | [Target value] | [Progress] | On Track / At Risk / Off Track |
### Initiatives
| Initiative | Key Result | Owner | Status | Effort |
|-----------|-----------|-------|--------|--------|
| [Feature/project name] | KR 2.1 | [Name] | Not Started / In Progress / Complete | [T-shirt size] |
| [Feature/project name] | KR 2.2 | [Name] | Not Started / In Progress / Complete | [T-shirt size] |
---
## Product Objective 3: [Objective Title]
_[Qualitative, inspirational statement]_
### Key Results
| # | Key Result | Baseline | Target | Current | Status |
|---|-----------|----------|--------|---------|--------|
| 3.1 | [Measurable outcome] | [Current value] | [Target value] | [Progress] | On Track / At Risk / Off Track |
| 3.2 | [Measurable outcome] | [Current value] | [Target value] | [Progress] | On Track / At Risk / Off Track |
| 3.3 | [Measurable outcome] | [Current value] | [Target value] | [Progress] | On Track / At Risk / Off Track |
### Initiatives
| Initiative | Key Result | Owner | Status | Effort |
|-----------|-----------|-------|--------|--------|
| [Feature/project name] | KR 3.1 | [Name] | Not Started / In Progress / Complete | [T-shirt size] |
---
## Tracking
### Weekly Check-In Format
- **Confidence level** (1-10) for each key result
- **Blockers** identified and escalated
- **Adjustments** to initiatives if needed
### Monthly Review Format
- **Progress update** on all key results with data
- **Initiative status** review
- **Risk assessment** and mitigation updates
- **Stakeholder communication** summary
### End-of-Quarter Scoring
Score each key result 0.0 - 1.0:
- **1.0:** Fully achieved
- **0.7:** Strong progress, nearly there (ideal target)
- **0.4:** Meaningful progress but missed target
- **0.0:** No progress
_Note: Consistently scoring 1.0 means OKRs are not ambitious enough. Target 0.6-0.7 average._
FILE:references/examples/sample_growth_okrs.json
{
"metadata": {
"strategy": "growth",
"quarter": "Q1 2025",
"generated_at": "2025-01-15T10:30:00Z",
"teams": ["Growth", "Platform", "Mobile", "Data"],
"product_contribution": 0.3
},
"company": {
"level": "Company",
"quarter": "Q1 2025",
"strategy": "growth",
"objectives": [
{
"id": "CO-1",
"title": "Accelerate user acquisition and market expansion",
"owner": "CEO",
"status": "active",
"key_results": [
{
"id": "CO-1-KR1",
"title": "Increase MAU from 100,000 to 150,000",
"current": 100000,
"target": 150000,
"unit": "users",
"status": "in_progress",
"progress": 0.2
},
{
"id": "CO-1-KR2",
"title": "Achieve 15% MoM growth rate",
"current": 8,
"target": 15,
"unit": "%",
"status": "in_progress",
"progress": 0.53
},
{
"id": "CO-1-KR3",
"title": "Expand to 3 new markets",
"current": 0,
"target": 3,
"unit": "markets",
"status": "not_started",
"progress": 0
}
]
},
{
"id": "CO-2",
"title": "Achieve product-market fit in enterprise segment",
"owner": "CEO",
"status": "active",
"key_results": [
{
"id": "CO-2-KR1",
"title": "Reduce CAC by 25%",
"current": 150,
"target": 112.5,
"unit": "$",
"status": "in_progress",
"progress": 0.4
},
{
"id": "CO-2-KR2",
"title": "Improve activation rate to 60%",
"current": 42,
"target": 60,
"unit": "%",
"status": "in_progress",
"progress": 0.3
}
]
},
{
"id": "CO-3",
"title": "Build sustainable growth engine",
"owner": "CEO",
"status": "active",
"key_results": [
{
"id": "CO-3-KR1",
"title": "Increase viral coefficient to 1.2",
"current": 0.8,
"target": 1.2,
"unit": "coefficient",
"status": "not_started",
"progress": 0
},
{
"id": "CO-3-KR2",
"title": "Grow organic acquisition to 40% of total",
"current": 25,
"target": 40,
"unit": "%",
"status": "in_progress",
"progress": 0.2
}
]
}
]
},
"product": {
"level": "Product",
"quarter": "Q1 2025",
"parent": "Company",
"objectives": [
{
"id": "PO-1",
"title": "Build viral product features to drive acquisition",
"parent_objective": "CO-1",
"owner": "Head of Product",
"status": "active",
"key_results": [
{
"id": "PO-1-KR1",
"title": "Increase product MAU from 100,000 to 115,000 (30% contribution)",
"contributes_to": "CO-1-KR1",
"current": 100000,
"target": 115000,
"unit": "users",
"status": "in_progress"
},
{
"id": "PO-1-KR2",
"title": "Achieve 12% feature adoption rate for sharing features",
"contributes_to": "CO-1-KR2",
"current": 5,
"target": 12,
"unit": "%",
"status": "in_progress"
}
]
},
{
"id": "PO-2",
"title": "Validate product hypotheses for enterprise segment",
"parent_objective": "CO-2",
"owner": "Head of Product",
"status": "active",
"key_results": [
{
"id": "PO-2-KR1",
"title": "Improve product onboarding efficiency by 30%",
"contributes_to": "CO-2-KR1",
"current": 0,
"target": 30,
"unit": "%",
"status": "not_started"
},
{
"id": "PO-2-KR2",
"title": "Increase product activation rate to 55%",
"contributes_to": "CO-2-KR2",
"current": 42,
"target": 55,
"unit": "%",
"status": "in_progress"
}
]
},
{
"id": "PO-3",
"title": "Create product-led growth loops",
"parent_objective": "CO-3",
"owner": "Head of Product",
"status": "active",
"key_results": [
{
"id": "PO-3-KR1",
"title": "Launch referral program with 0.3 viral coefficient contribution",
"contributes_to": "CO-3-KR1",
"current": 0,
"target": 0.3,
"unit": "coefficient",
"status": "not_started"
},
{
"id": "PO-3-KR2",
"title": "Increase product-driven organic signups to 35%",
"contributes_to": "CO-3-KR2",
"current": 20,
"target": 35,
"unit": "%",
"status": "in_progress"
}
]
}
]
},
"teams": [
{
"level": "Team",
"team": "Growth",
"quarter": "Q1 2025",
"parent": "Product",
"objectives": [
{
"id": "GRO-1",
"title": "Build viral product features through acquisition and activation",
"parent_objective": "PO-1",
"owner": "Growth PM",
"status": "active",
"key_results": [
{
"id": "GRO-1-KR1",
"title": "[Growth] Increase product MAU contribution by 5,000 users",
"contributes_to": "PO-1-KR1",
"current": 0,
"target": 5000,
"unit": "users",
"status": "in_progress"
},
{
"id": "GRO-1-KR2",
"title": "[Growth] Launch 3 viral feature experiments",
"contributes_to": "PO-1-KR2",
"current": 0,
"target": 3,
"unit": "experiments",
"status": "not_started"
}
]
}
]
},
{
"level": "Team",
"team": "Platform",
"quarter": "Q1 2025",
"parent": "Product",
"objectives": [
{
"id": "PLA-1",
"title": "Support growth through infrastructure and reliability",
"parent_objective": "PO-1",
"owner": "Platform PM",
"status": "active",
"key_results": [
{
"id": "PLA-1-KR1",
"title": "[Platform] Scale infrastructure to support 200K MAU",
"contributes_to": "PO-1-KR1",
"current": 100000,
"target": 200000,
"unit": "users",
"status": "in_progress"
},
{
"id": "PLA-1-KR2",
"title": "[Platform] Maintain 99.9% uptime during growth",
"contributes_to": "PO-1-KR2",
"current": 99.5,
"target": 99.9,
"unit": "%",
"status": "in_progress"
}
]
},
{
"id": "PLA-2",
"title": "Improve onboarding infrastructure efficiency",
"parent_objective": "PO-2",
"owner": "Platform PM",
"status": "active",
"key_results": [
{
"id": "PLA-2-KR1",
"title": "[Platform] Reduce onboarding API latency by 40%",
"contributes_to": "PO-2-KR1",
"current": 0,
"target": 40,
"unit": "%",
"status": "not_started"
}
]
}
]
},
{
"level": "Team",
"team": "Mobile",
"quarter": "Q1 2025",
"parent": "Product",
"objectives": [
{
"id": "MOB-1",
"title": "Build viral features through mobile experience",
"parent_objective": "PO-1",
"owner": "Mobile PM",
"status": "active",
"key_results": [
{
"id": "MOB-1-KR1",
"title": "[Mobile] Increase mobile MAU by 3,000 users",
"contributes_to": "PO-1-KR1",
"current": 0,
"target": 3000,
"unit": "users",
"status": "not_started"
},
{
"id": "MOB-1-KR2",
"title": "[Mobile] Launch native share feature with 15% adoption",
"contributes_to": "PO-1-KR2",
"current": 0,
"target": 15,
"unit": "%",
"status": "not_started"
}
]
}
]
},
{
"level": "Team",
"team": "Data",
"quarter": "Q1 2025",
"parent": "Product",
"objectives": [
{
"id": "DAT-1",
"title": "Enable growth through analytics and insights",
"parent_objective": "PO-1",
"owner": "Data PM",
"status": "active",
"key_results": [
{
"id": "DAT-1-KR1",
"title": "[Data] Build growth dashboard tracking all acquisition metrics",
"contributes_to": "PO-1-KR1",
"current": 0,
"target": 1,
"unit": "dashboard",
"status": "not_started"
},
{
"id": "DAT-1-KR2",
"title": "[Data] Implement experimentation platform for A/B testing",
"contributes_to": "PO-1-KR2",
"current": 0,
"target": 1,
"unit": "platform",
"status": "not_started"
}
]
}
]
}
],
"alignment_scores": {
"vertical_alignment": 100.0,
"horizontal_alignment": 75.0,
"coverage": 100.0,
"balance": 85.0,
"overall": 92.0
},
"summary": {
"total_objectives": 11,
"total_key_results": 22,
"company_objectives": 3,
"product_objectives": 3,
"team_objectives": 5,
"teams_involved": 4
}
}
FILE:references/okr_framework.md
# OKR Cascade Framework
A practical guide to Objectives and Key Results (OKRs) and how to cascade them across organizational levels.
---
## Table of Contents
- [What Are OKRs](#what-are-okrs)
- [The Cascade Model](#the-cascade-model)
- [Writing Effective Objectives](#writing-effective-objectives)
- [Defining Key Results](#defining-key-results)
- [Alignment Scoring](#alignment-scoring)
- [Common Pitfalls](#common-pitfalls)
- [OKR Cadence](#okr-cadence)
---
## What Are OKRs
**Objectives and Key Results (OKRs)** are a goal-setting framework that connects organizational strategy to measurable outcomes.
### Components
| Component | Definition | Characteristics |
|-----------|------------|-----------------|
| **Objective** | What you want to achieve | Qualitative, inspirational, time-bound |
| **Key Result** | How you measure progress | Quantitative, specific, measurable |
### OKR Formula
```
Objective: [Inspirational goal statement]
├── KR1: [Metric] from [current] to [target] by [date]
├── KR2: [Metric] from [current] to [target] by [date]
└── KR3: [Metric] from [current] to [target] by [date]
```
### Example
```
Objective: Become the go-to solution for enterprise customers
KR1: Increase enterprise ARR from $5M to $8M
KR2: Improve enterprise NPS from 35 to 50
KR3: Reduce enterprise onboarding time from 30 days to 14 days
```
---
## The Cascade Model
OKRs cascade from company strategy down to individual teams, ensuring alignment at every level.
### Cascade Structure
```
┌─────────────────────────────────────────┐
│ COMPANY LEVEL │
│ Strategic objectives set by leadership │
│ Owned by: CEO, Executive Team │
└───────────────┬─────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ PRODUCT LEVEL │
│ How product org contributes to company │
│ Owned by: Head of Product, CPO │
└───────────────┬─────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ TEAM LEVEL │
│ Specific initiatives and deliverables │
│ Owned by: Product Managers, Tech Leads │
└─────────────────────────────────────────┘
```
### Contribution Model
Each level contributes a percentage to the level above:
| Level | Typical Contribution | Range |
|-------|---------------------|-------|
| Product → Company | 30% | 20-50% |
| Team → Product | 25% per team | 15-35% |
**Note:** Contribution percentages should be calibrated based on:
- Number of teams
- Relative team size
- Strategic importance of initiatives
### Alignment Types
| Alignment | Description | Goal |
|-----------|-------------|------|
| **Vertical** | Each level supports the level above | >90% of objectives linked |
| **Horizontal** | Teams coordinate on shared objectives | No conflicting goals |
| **Temporal** | Quarterly OKRs support annual goals | Clear progression |
---
## Writing Effective Objectives
### The 3 Cs of Objectives
| Criterion | Description | Example |
|-----------|-------------|---------|
| **Clear** | Unambiguous intent | "Improve customer onboarding" not "Make things better" |
| **Compelling** | Inspires action | "Delight enterprise customers" not "Serve enterprise" |
| **Challenging** | Stretches capabilities | Achievable but requires effort |
### Objective Templates by Strategy
**Growth Strategy:**
```
- Accelerate user acquisition in [segment]
- Expand market presence in [region/vertical]
- Build sustainable acquisition channels
```
**Retention Strategy:**
```
- Create lasting value for [user segment]
- Improve product experience for [use case]
- Maximize customer lifetime value
```
**Revenue Strategy:**
```
- Drive revenue growth through [mechanism]
- Optimize monetization for [segment]
- Expand revenue per customer
```
**Innovation Strategy:**
```
- Pioneer [capability] in the market
- Establish leadership through [innovation area]
- Build competitive differentiation
```
**Operational Strategy:**
```
- Improve delivery efficiency by [mechanism]
- Scale operations to support [target]
- Reduce operational friction in [area]
```
### Objective Anti-Patterns
| Anti-Pattern | Problem | Better Alternative |
|--------------|---------|-------------------|
| "Increase revenue" | Too vague | "Grow enterprise ARR to $10M" |
| "Be the best" | Not measurable | "Achieve #1 NPS in category" |
| "Fix bugs" | Too tactical | "Improve platform reliability" |
| "Launch feature X" | Output, not outcome | "Improve [metric] through [capability]" |
---
## Defining Key Results
### Key Result Anatomy
```
[Verb] [metric] from [current baseline] to [target] by [deadline]
```
### Key Result Types
| Type | Characteristics | When to Use |
|------|-----------------|-------------|
| **Metric-based** | Track a number | Most common, highly measurable |
| **Milestone-based** | Track completion | For binary deliverables |
| **Health-based** | Track stability | For maintenance objectives |
### Metric Categories
| Category | Examples |
|----------|----------|
| **Acquisition** | Signups, trials started, leads generated |
| **Activation** | Onboarding completion, first value moment |
| **Retention** | D7/D30 retention, churn rate, repeat usage |
| **Revenue** | ARR, ARPU, conversion rate, LTV |
| **Engagement** | DAU/MAU, session duration, actions per session |
| **Satisfaction** | NPS, CSAT, support tickets |
| **Efficiency** | Cycle time, automation rate, cost per unit |
### Key Result Scoring
| Score | Status | Description |
|-------|--------|-------------|
| 0.0-0.3 | Red | Significant gap, needs intervention |
| 0.4-0.6 | Yellow | Partial progress, on watch |
| 0.7-0.9 | Green | Strong progress, on track |
| 1.0 | Complete | Target achieved |
**Note:** Hitting 0.7 is considered success for stretch goals. Consistently hitting 1.0 suggests targets aren't ambitious enough.
---
## Alignment Scoring
The OKR cascade generator calculates alignment scores across four dimensions:
### Scoring Dimensions
| Dimension | Weight | What It Measures |
|-----------|--------|------------------|
| **Vertical Alignment** | 40% | % of objectives with parent links |
| **Horizontal Alignment** | 20% | Cross-team coordination on shared goals |
| **Coverage** | 20% | % of company KRs addressed by product |
| **Balance** | 20% | Even distribution of work across teams |
### Alignment Score Interpretation
| Score | Grade | Interpretation |
|-------|-------|----------------|
| 90-100% | A | Excellent alignment, well-cascaded |
| 80-89% | B | Good alignment, minor gaps |
| 70-79% | C | Adequate, needs attention |
| 60-69% | D | Poor alignment, significant gaps |
| <60% | F | Misaligned, requires restructuring |
### Target Benchmarks
| Metric | Target | Red Flag |
|--------|--------|----------|
| Vertical alignment | >90% | <70% |
| Horizontal alignment | >75% | <50% |
| Coverage | >80% | <60% |
| Balance | >80% | <60% |
| Overall | >80% | <65% |
---
## Common Pitfalls
### OKR Anti-Patterns
| Pitfall | Symptom | Fix |
|---------|---------|-----|
| **Too many OKRs** | 10+ objectives per level | Limit to 3-5 objectives |
| **Sandbagging** | Always hit 100% | Set stretch targets (0.7 = success) |
| **Task lists** | KRs are tasks, not outcomes | Focus on measurable impact |
| **Set and forget** | No mid-quarter reviews | Check-ins every 2 weeks |
| **Cascade disconnect** | Team OKRs don't link up | Validate parent relationships |
| **Metric gaming** | Optimizing for KR, not intent | Balance with health metrics |
### Warning Signs
- All teams have identical objectives (lack of specialization)
- No team owns a critical company objective (gap in coverage)
- One team owns everything (unrealistic load)
- Objectives change weekly (lack of commitment)
- KRs are activities, not outcomes (wrong focus)
---
## OKR Cadence
### Quarterly Rhythm
| Week | Activity |
|------|----------|
| **Week -2** | Leadership sets company OKRs draft |
| **Week -1** | Product and team OKR drafting |
| **Week 0** | OKR finalization and alignment review |
| **Week 2** | First check-in, adjust if needed |
| **Week 6** | Mid-quarter review |
| **Week 10** | Pre-quarter reflection |
| **Week 12** | Quarter close, scoring, learnings |
### Check-in Format
```
Weekly/Bi-weekly Status Update:
1. Confidence level: [Red/Yellow/Green]
2. Progress since last check-in: [specific updates]
3. Blockers: [what's in the way]
4. Asks: [what help is needed]
5. Forecast: [expected end-of-quarter score]
```
### Annual Alignment
Quarterly OKRs should ladder up to annual goals:
```
Annual Goal: Become a $100M ARR business
Q1: Build enterprise sales motion (ARR: $25M → $32M)
Q2: Expand into APAC region (ARR: $32M → $45M)
Q3: Launch self-serve enterprise tier (ARR: $45M → $65M)
Q4: Scale and optimize (ARR: $65M → $100M)
```
---
## Quick Reference
### OKR Checklist
**Before finalizing OKRs:**
- [ ] 3-5 objectives per level (not more)
- [ ] 3-5 key results per objective
- [ ] Each KR has a current baseline and target
- [ ] Vertical alignment validated (parent links)
- [ ] No conflicting objectives across teams
- [ ] Owners assigned to every objective
- [ ] Check-in cadence defined
**During the quarter:**
- [ ] Bi-weekly progress updates
- [ ] Mid-quarter formal review
- [ ] Adjust forecasts based on learnings
- [ ] Escalate blockers early
**End of quarter:**
- [ ] Score all key results (0.0-1.0)
- [ ] Document learnings
- [ ] Celebrate wins
- [ ] Carry forward or close incomplete items
---
*See also: `strategy_types.md` for strategy-specific OKR templates*
FILE:references/strategy_types.md
# Strategy Types for OKR Generation
Comprehensive breakdown of the five core strategy types with objectives, key results, and when to use each.
---
## Table of Contents
- [Strategy Selection Guide](#strategy-selection-guide)
- [Growth Strategy](#growth-strategy)
- [Retention Strategy](#retention-strategy)
- [Revenue Strategy](#revenue-strategy)
- [Innovation Strategy](#innovation-strategy)
- [Operational Strategy](#operational-strategy)
- [Multi-Strategy Combinations](#multi-strategy-combinations)
---
## Strategy Selection Guide
### Decision Matrix
| If your priority is... | Primary Strategy | Secondary Strategy |
|------------------------|------------------|-------------------|
| Scaling user base | Growth | Retention |
| Reducing churn | Retention | Revenue |
| Increasing ARPU | Revenue | Retention |
| Market differentiation | Innovation | Growth |
| Improving efficiency | Operational | Revenue |
| New market entry | Growth | Innovation |
### Strategy by Company Stage
| Stage | Typical Priority | Rationale |
|-------|------------------|-----------|
| **Pre-PMF** | Innovation | Finding product-market fit |
| **Early Growth** | Growth | Scaling acquisition |
| **Growth** | Growth + Retention | Balancing acquisition with value |
| **Scale** | Revenue + Retention | Optimizing unit economics |
| **Mature** | Operational + Revenue | Efficiency and margins |
---
## Growth Strategy
**Focus:** Accelerating user acquisition and market expansion
### When to Use
- User growth is primary company objective
- Product-market fit is validated
- Acquisition channels are scaling
- Ready to invest in growth loops
### Company-Level Objectives
| Objective | Key Results Template |
|-----------|---------------------|
| Accelerate user acquisition and market expansion | - Increase MAU from X to Y<br>- Achieve Z% MoM growth rate<br>- Expand to N new markets |
| Achieve product-market fit in new segments | - Reach X users in [segment]<br>- Achieve Y% activation rate<br>- Validate Z use cases |
| Build sustainable growth engine | - Reduce CAC by X%<br>- Improve viral coefficient to Y<br>- Increase organic share to Z% |
### Product-Level Cascade
| Product Objective | Supports | Key Results |
|-------------------|----------|-------------|
| Build viral product features | User acquisition | - Launch referral program (target: X referrals/user)<br>- Increase shareability by Y% |
| Optimize onboarding experience | Activation | - Improve activation rate from X% to Y%<br>- Reduce time-to-value by Z% |
| Create product-led growth loops | Sustainable growth | - Increase product-qualified leads by X%<br>- Improve trial-to-paid by Y% |
### Team-Level Examples
| Team | Focus Area | Sample KRs |
|------|------------|------------|
| Growth Team | Acquisition & activation | - Improve signup conversion by X%<br>- Launch Y experiments/week |
| Platform Team | Scale & reliability | - Support X concurrent users<br>- Maintain Y% uptime |
| Mobile Team | Mobile acquisition | - Increase mobile signups by X%<br>- Improve mobile activation by Y% |
### Key Metrics to Track
- Monthly Active Users (MAU)
- Growth rate (MoM, YoY)
- Customer Acquisition Cost (CAC)
- Activation rate
- Viral coefficient
- Channel efficiency
---
## Retention Strategy
**Focus:** Creating lasting customer value and reducing churn
### When to Use
- Churn is above industry benchmark
- LTV/CAC needs improvement
- Product stickiness is low
- Expansion revenue is a priority
### Company-Level Objectives
| Objective | Key Results Template |
|-----------|---------------------|
| Create lasting customer value and loyalty | - Improve retention from X% to Y%<br>- Increase NPS from X to Y<br>- Reduce churn to below Z% |
| Deliver a superior user experience | - Achieve X% product stickiness<br>- Improve satisfaction to Y/10<br>- Reduce support tickets by Z% |
| Maximize customer lifetime value | - Increase LTV by X%<br>- Improve LTV/CAC ratio to Y<br>- Grow expansion revenue by Z% |
### Product-Level Cascade
| Product Objective | Supports | Key Results |
|-------------------|----------|-------------|
| Design sticky user experiences | Customer retention | - Increase DAU/MAU ratio from X to Y<br>- Improve weekly return rate by Z% |
| Build habit-forming features | Product stickiness | - Achieve X% feature adoption<br>- Increase sessions/user by Y |
| Create expansion opportunities | Lifetime value | - Launch N upsell touchpoints<br>- Improve upgrade rate by X% |
### Team-Level Examples
| Team | Focus Area | Sample KRs |
|------|------------|------------|
| Growth Team | Retention loops | - Improve D7 retention by X%<br>- Reduce first-week churn by Y% |
| Data Team | Churn prediction | - Build churn model (accuracy >X%)<br>- Identify Y at-risk signals |
| Platform Team | Reliability | - Reduce error rates by X%<br>- Improve load times by Y% |
### Key Metrics to Track
- Retention rates (D1, D7, D30, D90)
- Churn rate
- Net Promoter Score (NPS)
- Customer Satisfaction (CSAT)
- Feature stickiness
- Session frequency
---
## Revenue Strategy
**Focus:** Driving sustainable revenue growth and monetization
### When to Use
- Company is focused on profitability
- Monetization needs optimization
- Pricing strategy is being revised
- Expansion revenue is priority
### Company-Level Objectives
| Objective | Key Results Template |
|-----------|---------------------|
| Drive sustainable revenue growth | - Grow ARR from $X to $Y<br>- Achieve Z% revenue growth rate<br>- Maintain X% gross margin |
| Optimize monetization strategy | - Increase ARPU by X%<br>- Improve pricing efficiency by Y%<br>- Launch Z new pricing tiers |
| Expand revenue per customer | - Grow expansion revenue by X%<br>- Reduce revenue churn to Y%<br>- Increase upsell rate by Z% |
### Product-Level Cascade
| Product Objective | Supports | Key Results |
|-------------------|----------|-------------|
| Optimize product monetization | Revenue growth | - Improve conversion to paid by X%<br>- Reduce free tier abuse by Y% |
| Build premium features | ARPU growth | - Launch N premium features<br>- Achieve X% premium adoption |
| Create value-based pricing alignment | Pricing efficiency | - Implement usage-based pricing<br>- Improve price-to-value ratio by X% |
### Team-Level Examples
| Team | Focus Area | Sample KRs |
|------|------------|------------|
| Growth Team | Conversion | - Improve trial-to-paid by X%<br>- Reduce time-to-upgrade by Y days |
| Platform Team | Usage metering | - Implement accurate usage tracking<br>- Support X billing scenarios |
| Data Team | Revenue analytics | - Build revenue forecasting model<br>- Identify Y expansion signals |
### Key Metrics to Track
- Annual Recurring Revenue (ARR)
- Average Revenue Per User (ARPU)
- Gross margin
- Revenue churn (net and gross)
- Expansion revenue
- LTV/CAC ratio
---
## Innovation Strategy
**Focus:** Building competitive advantage through product innovation
### When to Use
- Market is commoditizing
- Competitors are catching up
- New technology opportunity exists
- Company needs differentiation
### Company-Level Objectives
| Objective | Key Results Template |
|-----------|---------------------|
| Lead the market through product innovation | - Launch X breakthrough features<br>- Achieve Y% revenue from new products<br>- File Z patents/IP |
| Establish market leadership in [area] | - Become #1 in category for X<br>- Win Y analyst recognitions<br>- Achieve Z% awareness |
| Build sustainable competitive moat | - Reduce feature parity gap by X%<br>- Create Y unique capabilities<br>- Build Z switching barriers |
### Product-Level Cascade
| Product Objective | Supports | Key Results |
|-------------------|----------|-------------|
| Ship innovative features faster | Breakthrough innovation | - Reduce time-to-market by X%<br>- Launch Y experiments/quarter |
| Build unique technical capabilities | Competitive moat | - Develop X proprietary algorithms<br>- Achieve Y performance advantage |
| Create platform extensibility | Ecosystem advantage | - Launch N API endpoints<br>- Enable X third-party integrations |
### Team-Level Examples
| Team | Focus Area | Sample KRs |
|------|------------|------------|
| Platform Team | Core technology | - Build X new infrastructure capabilities<br>- Improve performance by Y% |
| Data Team | ML/AI innovation | - Deploy X ML models<br>- Improve prediction accuracy by Y% |
| Mobile Team | Mobile innovation | - Launch X mobile-first features<br>- Achieve Y% mobile parity |
### Key Metrics to Track
- Time-to-market
- Revenue from new products
- Feature uniqueness score
- Patent/IP filings
- Technology differentiation
- Innovation velocity
---
## Operational Strategy
**Focus:** Improving efficiency and organizational excellence
### When to Use
- Scaling challenges are emerging
- Operational costs are high
- Team productivity needs improvement
- Quality issues are increasing
### Company-Level Objectives
| Objective | Key Results Template |
|-----------|---------------------|
| Improve organizational efficiency | - Improve velocity by X%<br>- Reduce cycle time to Y days<br>- Achieve Z% automation |
| Scale operations sustainably | - Support X users per engineer<br>- Reduce cost per transaction by Y%<br>- Improve operational leverage by Z% |
| Achieve operational excellence | - Reduce incidents by X%<br>- Improve team NPS to Y<br>- Achieve Z% on-time delivery |
### Product-Level Cascade
| Product Objective | Supports | Key Results |
|-------------------|----------|-------------|
| Improve product delivery efficiency | Velocity | - Reduce PR cycle time by X%<br>- Increase deployment frequency by Y% |
| Reduce operational toil | Automation | - Automate X% of manual processes<br>- Reduce on-call burden by Y% |
| Improve product quality | Excellence | - Reduce bugs by X%<br>- Improve test coverage to Y% |
### Team-Level Examples
| Team | Focus Area | Sample KRs |
|------|------------|------------|
| Platform Team | Infrastructure efficiency | - Reduce infrastructure costs by X%<br>- Improve deployment reliability to Y% |
| Data Team | Data operations | - Improve data pipeline reliability to X%<br>- Reduce data latency by Y% |
| All Teams | Process improvement | - Reduce meeting overhead by X%<br>- Improve sprint predictability to Y% |
### Key Metrics to Track
- Velocity (story points, throughput)
- Cycle time
- Deployment frequency
- Change failure rate
- Incident count and MTTR
- Team satisfaction (eNPS)
---
## Multi-Strategy Combinations
### Common Pairings
| Primary | Secondary | Balanced Objectives |
|---------|-----------|---------------------|
| Growth + Retention | 60/40 | Grow while keeping users |
| Revenue + Retention | 50/50 | Monetize without churning |
| Innovation + Growth | 40/60 | Differentiate to acquire |
| Operational + Revenue | 50/50 | Efficiency for margins |
### Balanced OKR Set Example
**Mixed Growth + Retention Strategy:**
```
Company Objective 1: Accelerate user growth (Growth)
├── KR1: Increase MAU from 100K to 200K
├── KR2: Achieve 15% MoM growth rate
└── KR3: Reduce CAC by 20%
Company Objective 2: Improve user retention (Retention)
├── KR1: Improve D30 retention from 20% to 35%
├── KR2: Increase NPS from 40 to 55
└── KR3: Reduce churn to below 5%
Company Objective 3: Improve delivery efficiency (Operational)
├── KR1: Reduce cycle time by 30%
├── KR2: Achieve 95% on-time delivery
└── KR3: Improve team eNPS to 50
```
---
## Strategy Selection Checklist
Before choosing a strategy:
- [ ] What is the company's #1 priority this quarter?
- [ ] What metrics is leadership being evaluated on?
- [ ] Where are the biggest gaps vs. competitors?
- [ ] What does customer feedback emphasize?
- [ ] What can we realistically move in 90 days?
---
*See also: `okr_framework.md` for OKR writing best practices*
FILE:scripts/okr_cascade_generator.py
#!/usr/bin/env python3
"""
OKR Cascade Generator
Creates aligned OKRs from company strategy down to team level.
Features:
- Generates company → product → team OKR cascade
- Configurable team structure and contribution percentages
- Alignment scoring across vertical and horizontal dimensions
- Multiple output formats (dashboard, JSON)
Usage:
python okr_cascade_generator.py growth
python okr_cascade_generator.py retention --teams "Engineering,Design,Data"
python okr_cascade_generator.py revenue --contribution 0.4 --json
"""
import json
import argparse
from typing import Dict, List
from datetime import datetime
class OKRGenerator:
"""Generate and cascade OKRs across the organization"""
def __init__(self, teams: List[str] = None, product_contribution: float = 0.3):
"""
Initialize OKR generator.
Args:
teams: List of team names (default: Growth, Platform, Mobile, Data)
product_contribution: Fraction of company KRs that product owns (default: 0.3)
"""
self.teams = teams or ['Growth', 'Platform', 'Mobile', 'Data']
self.product_contribution = product_contribution
self.okr_templates = {
'growth': {
'objectives': [
'Accelerate user acquisition and market expansion',
'Achieve product-market fit in new segments',
'Build sustainable growth engine'
],
'key_results': [
'Increase MAU from {current} to {target}',
'Achieve {target}% MoM growth rate',
'Expand to {target} new markets',
'Reduce CAC by {target}%',
'Improve activation rate to {target}%'
]
},
'retention': {
'objectives': [
'Create lasting customer value and loyalty',
'Deliver a superior user experience',
'Maximize customer lifetime value'
],
'key_results': [
'Improve retention from {current}% to {target}%',
'Increase NPS from {current} to {target}',
'Reduce churn to below {target}%',
'Achieve {target}% product stickiness',
'Increase LTV/CAC ratio to {target}'
]
},
'revenue': {
'objectives': [
'Drive sustainable revenue growth',
'Optimize monetization strategy',
'Expand revenue per customer'
],
'key_results': [
'Grow ARR from currentM to targetM',
'Increase ARPU by {target}%',
'Launch {target} new revenue streams',
'Achieve {target}% gross margin',
'Reduce revenue churn to {target}%'
]
},
'innovation': {
'objectives': [
'Lead the market through product innovation',
'Establish leadership in key capability areas',
'Build sustainable competitive differentiation'
],
'key_results': [
'Launch {target} breakthrough features',
'Achieve {target}% of revenue from new products',
'File {target} patents/IP',
'Reduce time-to-market by {target}%',
'Achieve {target} innovation score'
]
},
'operational': {
'objectives': [
'Improve organizational efficiency',
'Achieve operational excellence',
'Scale operations sustainably'
],
'key_results': [
'Improve velocity by {target}%',
'Reduce cycle time to {target} days',
'Achieve {target}% automation',
'Improve team satisfaction to {target}',
'Reduce incidents by {target}%'
]
}
}
# Team focus areas for objective relevance matching
self.team_relevance = {
'Growth': ['acquisition', 'growth', 'activation', 'viral', 'onboarding', 'conversion'],
'Platform': ['infrastructure', 'reliability', 'scale', 'performance', 'efficiency', 'automation'],
'Mobile': ['mobile', 'app', 'ios', 'android', 'native'],
'Data': ['analytics', 'metrics', 'insights', 'data', 'measurement', 'experimentation'],
'Engineering': ['delivery', 'velocity', 'quality', 'automation', 'infrastructure'],
'Design': ['experience', 'usability', 'interface', 'user', 'accessibility'],
'Product': ['features', 'roadmap', 'prioritization', 'strategy'],
}
def generate_company_okrs(self, strategy: str, metrics: Dict) -> Dict:
"""Generate company-level OKRs based on strategy"""
if strategy not in self.okr_templates:
strategy = 'growth'
template = self.okr_templates[strategy]
company_okrs = {
'level': 'Company',
'quarter': self._get_current_quarter(),
'strategy': strategy,
'objectives': []
}
for i in range(min(3, len(template['objectives']))):
obj = {
'id': f'CO-{i+1}',
'title': template['objectives'][i],
'key_results': [],
'owner': 'CEO',
'status': 'draft'
}
for j in range(3):
if j < len(template['key_results']):
kr_template = template['key_results'][j]
kr = {
'id': f'CO-{i+1}-KR{j+1}',
'title': self._fill_metrics(kr_template, metrics),
'current': metrics.get('current', 0),
'target': metrics.get('target', 100),
'unit': self._extract_unit(kr_template),
'status': 'not_started'
}
obj['key_results'].append(kr)
company_okrs['objectives'].append(obj)
return company_okrs
def cascade_to_product(self, company_okrs: Dict) -> Dict:
"""Cascade company OKRs to product organization"""
product_okrs = {
'level': 'Product',
'quarter': company_okrs['quarter'],
'parent': 'Company',
'contribution': self.product_contribution,
'objectives': []
}
for company_obj in company_okrs['objectives']:
product_obj = {
'id': f'PO-{company_obj["id"].split("-")[1]}',
'title': self._translate_to_product(company_obj['title']),
'parent_objective': company_obj['id'],
'key_results': [],
'owner': 'Head of Product',
'status': 'draft'
}
for kr in company_obj['key_results']:
product_kr = {
'id': f'PO-{product_obj["id"].split("-")[1]}-KR{kr["id"].split("KR")[1]}',
'title': self._translate_kr_to_product(kr['title']),
'contributes_to': kr['id'],
'current': kr['current'],
'target': kr['target'] * self.product_contribution,
'unit': kr['unit'],
'contribution_pct': self.product_contribution * 100,
'status': 'not_started'
}
product_obj['key_results'].append(product_kr)
product_okrs['objectives'].append(product_obj)
return product_okrs
def cascade_to_teams(self, product_okrs: Dict) -> List[Dict]:
"""Cascade product OKRs to individual teams"""
team_okrs = []
team_contribution = 1.0 / len(self.teams) if self.teams else 0.25
for team in self.teams:
team_okr = {
'level': 'Team',
'team': team,
'quarter': product_okrs['quarter'],
'parent': 'Product',
'contribution': team_contribution,
'objectives': []
}
for product_obj in product_okrs['objectives']:
if self._is_relevant_for_team(product_obj['title'], team):
team_obj = {
'id': f'{team[:3].upper()}-{product_obj["id"].split("-")[1]}',
'title': self._translate_to_team(product_obj['title'], team),
'parent_objective': product_obj['id'],
'key_results': [],
'owner': f'{team} PM',
'status': 'draft'
}
for kr in product_obj['key_results'][:2]:
team_kr = {
'id': f'{team[:3].upper()}-{team_obj["id"].split("-")[1]}-KR{kr["id"].split("KR")[1]}',
'title': self._translate_kr_to_team(kr['title'], team),
'contributes_to': kr['id'],
'current': kr['current'],
'target': kr['target'] * team_contribution,
'unit': kr['unit'],
'status': 'not_started'
}
team_obj['key_results'].append(team_kr)
team_okr['objectives'].append(team_obj)
if team_okr['objectives']:
team_okrs.append(team_okr)
return team_okrs
def generate_okr_dashboard(self, all_okrs: Dict) -> str:
"""Generate OKR dashboard view"""
dashboard = ["=" * 60]
dashboard.append("OKR CASCADE DASHBOARD")
dashboard.append(f"Quarter: {all_okrs.get('quarter', 'Q1 2025')}")
dashboard.append(f"Strategy: {all_okrs.get('strategy', 'growth').upper()}")
dashboard.append(f"Teams: {', '.join(self.teams)}")
dashboard.append(f"Product Contribution: {self.product_contribution * 100:.0f}%")
dashboard.append("=" * 60)
# Company OKRs
if 'company' in all_okrs:
dashboard.append("\n🏢 COMPANY OKRS\n")
for obj in all_okrs['company']['objectives']:
dashboard.append(f"📌 {obj['id']}: {obj['title']}")
for kr in obj['key_results']:
dashboard.append(f" └─ {kr['id']}: {kr['title']}")
# Product OKRs
if 'product' in all_okrs:
dashboard.append("\n🚀 PRODUCT OKRS\n")
for obj in all_okrs['product']['objectives']:
dashboard.append(f"📌 {obj['id']}: {obj['title']}")
dashboard.append(f" ↳ Supports: {obj.get('parent_objective', 'N/A')}")
for kr in obj['key_results']:
dashboard.append(f" └─ {kr['id']}: {kr['title']}")
# Team OKRs
if 'teams' in all_okrs:
dashboard.append("\n👥 TEAM OKRS\n")
for team_okr in all_okrs['teams']:
dashboard.append(f"\n{team_okr['team']} Team:")
for obj in team_okr['objectives']:
dashboard.append(f" 📌 {obj['id']}: {obj['title']}")
for kr in obj['key_results']:
dashboard.append(f" └─ {kr['id']}: {kr['title']}")
# Alignment Matrix
dashboard.append("\n\n📊 ALIGNMENT MATRIX\n")
dashboard.append("Company → Product → Teams")
dashboard.append("-" * 40)
if 'company' in all_okrs and 'product' in all_okrs:
for c_obj in all_okrs['company']['objectives']:
dashboard.append(f"\n{c_obj['id']}")
for p_obj in all_okrs['product']['objectives']:
if p_obj.get('parent_objective') == c_obj['id']:
dashboard.append(f" ├─ {p_obj['id']}")
if 'teams' in all_okrs:
for team_okr in all_okrs['teams']:
for t_obj in team_okr['objectives']:
if t_obj.get('parent_objective') == p_obj['id']:
dashboard.append(f" └─ {t_obj['id']} ({team_okr['team']})")
return "\n".join(dashboard)
def calculate_alignment_score(self, all_okrs: Dict) -> Dict:
"""Calculate alignment score across OKR cascade"""
scores = {
'vertical_alignment': 0,
'horizontal_alignment': 0,
'coverage': 0,
'balance': 0,
'overall': 0
}
# Vertical alignment: How well each level supports the above
total_objectives = 0
aligned_objectives = 0
if 'product' in all_okrs:
for obj in all_okrs['product']['objectives']:
total_objectives += 1
if 'parent_objective' in obj:
aligned_objectives += 1
if 'teams' in all_okrs:
for team in all_okrs['teams']:
for obj in team['objectives']:
total_objectives += 1
if 'parent_objective' in obj:
aligned_objectives += 1
if total_objectives > 0:
scores['vertical_alignment'] = round((aligned_objectives / total_objectives) * 100, 1)
# Horizontal alignment: How well teams coordinate
if 'teams' in all_okrs and len(all_okrs['teams']) > 1:
shared_objectives = set()
for team in all_okrs['teams']:
for obj in team['objectives']:
parent = obj.get('parent_objective')
if parent:
shared_objectives.add(parent)
scores['horizontal_alignment'] = min(100, len(shared_objectives) * 25)
# Coverage: How much of company OKRs are covered
if 'company' in all_okrs and 'product' in all_okrs:
company_krs = sum(len(obj['key_results']) for obj in all_okrs['company']['objectives'])
covered_krs = sum(len(obj['key_results']) for obj in all_okrs['product']['objectives'])
if company_krs > 0:
scores['coverage'] = round((covered_krs / company_krs) * 100, 1)
# Balance: Distribution across teams
if 'teams' in all_okrs:
objectives_per_team = [len(team['objectives']) for team in all_okrs['teams']]
if objectives_per_team:
avg_objectives = sum(objectives_per_team) / len(objectives_per_team)
variance = sum((x - avg_objectives) ** 2 for x in objectives_per_team) / len(objectives_per_team)
scores['balance'] = round(max(0, 100 - variance * 10), 1)
# Overall score
scores['overall'] = round(sum([
scores['vertical_alignment'] * 0.4,
scores['horizontal_alignment'] * 0.2,
scores['coverage'] * 0.2,
scores['balance'] * 0.2
]), 1)
return scores
def _get_current_quarter(self) -> str:
"""Get current quarter"""
now = datetime.now()
quarter = (now.month - 1) // 3 + 1
return f"Q{quarter} {now.year}"
def _fill_metrics(self, template: str, metrics: Dict) -> str:
"""Fill template with actual metrics"""
result = template
for key, value in metrics.items():
result = result.replace(f'{{{key}}}', str(value))
return result
def _extract_unit(self, kr_template: str) -> str:
"""Extract measurement unit from KR template"""
if '%' in kr_template:
return '%'
elif '$' in kr_template:
return '$'
elif 'days' in kr_template.lower():
return 'days'
elif 'score' in kr_template.lower():
return 'points'
return 'count'
def _translate_to_product(self, company_objective: str) -> str:
"""Translate company objective to product objective"""
translations = {
'Accelerate user acquisition': 'Build viral product features',
'Achieve product-market fit': 'Validate product hypotheses',
'Build sustainable growth': 'Create product-led growth loops',
'Create lasting customer value': 'Design sticky user experiences',
'Drive sustainable revenue': 'Optimize product monetization',
'Lead the market through': 'Ship innovative features to',
'Improve organizational': 'Improve product delivery'
}
for key, value in translations.items():
if key in company_objective:
return company_objective.replace(key, value)
return f"Product: {company_objective}"
def _translate_kr_to_product(self, kr: str) -> str:
"""Translate KR to product context"""
product_terms = {
'MAU': 'product MAU',
'growth rate': 'feature adoption rate',
'CAC': 'product onboarding efficiency',
'retention': 'product retention',
'NPS': 'product NPS',
'ARR': 'product-driven revenue',
'churn': 'product churn'
}
result = kr
for term, replacement in product_terms.items():
if term in result:
result = result.replace(term, replacement)
break
return result
def _translate_to_team(self, objective: str, team: str) -> str:
"""Translate objective to team context"""
team_focus = {
'Growth': 'acquisition and activation',
'Platform': 'infrastructure and reliability',
'Mobile': 'mobile experience',
'Data': 'analytics and insights',
'Engineering': 'technical delivery',
'Design': 'user experience',
'Product': 'product strategy'
}
focus = team_focus.get(team, 'delivery')
return f"{objective} through {focus}"
def _translate_kr_to_team(self, kr: str, team: str) -> str:
"""Translate KR to team context"""
return f"[{team}] {kr}"
def _is_relevant_for_team(self, objective: str, team: str) -> bool:
"""Check if objective is relevant for team"""
keywords = self.team_relevance.get(team, [])
objective_lower = objective.lower()
# Platform is always relevant (infrastructure supports everything)
if team == 'Platform':
return True
return any(keyword in objective_lower for keyword in keywords)
def parse_teams(teams_str: str) -> List[str]:
"""Parse comma-separated team string into list"""
if not teams_str:
return None
return [t.strip() for t in teams_str.split(',') if t.strip()]
def main():
parser = argparse.ArgumentParser(
description='Generate OKR cascade from company strategy to team level',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
# Generate growth strategy OKRs with default teams
python okr_cascade_generator.py growth
# Custom teams
python okr_cascade_generator.py retention --teams "Engineering,Design,Data,Growth"
# Custom product contribution percentage
python okr_cascade_generator.py revenue --contribution 0.4
# JSON output
python okr_cascade_generator.py innovation --json
# All options combined
python okr_cascade_generator.py operational --teams "Core,Platform" --contribution 0.5 --json
"""
)
parser.add_argument(
'strategy',
nargs='?',
choices=['growth', 'retention', 'revenue', 'innovation', 'operational'],
default='growth',
help='Strategy type (default: growth)'
)
parser.add_argument(
'--teams', '-t',
type=str,
help='Comma-separated list of team names (default: Growth,Platform,Mobile,Data)'
)
parser.add_argument(
'--contribution', '-c',
type=float,
default=0.3,
help='Product contribution to company OKRs as decimal (default: 0.3 = 30%%)'
)
parser.add_argument(
'--json', '-j',
action='store_true',
help='Output as JSON instead of dashboard'
)
parser.add_argument(
'--metrics', '-m',
type=str,
help='Metrics as JSON string (default: sample metrics)'
)
args = parser.parse_args()
# Parse teams
teams = parse_teams(args.teams)
# Parse metrics
if args.metrics:
metrics = json.loads(args.metrics)
else:
metrics = {
'current': 100000,
'target': 150000,
'current_revenue': 10,
'target_revenue': 15,
'current_nps': 40,
'target_nps': 60
}
# Validate contribution
if not 0 < args.contribution <= 1:
print("Error: Contribution must be between 0 and 1")
return 1
# Generate OKRs
generator = OKRGenerator(teams=teams, product_contribution=args.contribution)
company_okrs = generator.generate_company_okrs(args.strategy, metrics)
product_okrs = generator.cascade_to_product(company_okrs)
team_okrs = generator.cascade_to_teams(product_okrs)
all_okrs = {
'quarter': company_okrs['quarter'],
'strategy': args.strategy,
'company': company_okrs,
'product': product_okrs,
'teams': team_okrs
}
alignment = generator.calculate_alignment_score(all_okrs)
if args.json:
all_okrs['alignment_scores'] = alignment
all_okrs['config'] = {
'teams': generator.teams,
'product_contribution': generator.product_contribution
}
print(json.dumps(all_okrs, indent=2))
else:
dashboard = generator.generate_okr_dashboard(all_okrs)
print(dashboard)
print("\n\n🎯 ALIGNMENT SCORES")
print("-" * 40)
for metric, score in alignment.items():
status = "✓" if score >= 80 else "!" if score >= 60 else "✗"
print(f"{status} {metric.replace('_', ' ').title()}: {score}%")
if alignment['overall'] >= 80:
print("\n✅ Overall alignment is GOOD (≥80%)")
elif alignment['overall'] >= 60:
print("\n⚠️ Overall alignment NEEDS ATTENTION (60-80%)")
else:
print("\n❌ Overall alignment is POOR (<60%)")
if __name__ == "__main__":
main()
Tạo sơ đồ ERD, chuẩn hóa lược đồ, thiết kế quan hệ bảng và lập kế hoạch migration lược đồ.
---
name: "database-schema-designer"
description: "Use when the user asks to create ERD diagrams, normalize database schemas, design table relationships, or plan schema migrations."
---
# Database Schema Designer
**Tier:** POWERFUL
**Category:** Engineering
**Domain:** Data Architecture / Backend
---
## Overview
Design relational database schemas from requirements and generate migrations, TypeScript/Python types, seed data, RLS policies, and indexes. Handles multi-tenancy, soft deletes, audit trails, versioning, and polymorphic associations.
## Core Capabilities
- **Schema design** — normalize requirements into tables, relationships, constraints
- **Migration generation** — Drizzle, Prisma, TypeORM, Alembic
- **Type generation** — TypeScript interfaces, Python dataclasses/Pydantic models
- **RLS policies** — Row-Level Security for multi-tenant apps
- **Index strategy** — composite indexes, partial indexes, covering indexes
- **Seed data** — realistic test data generation
- **ERD generation** — Mermaid diagram from schema
---
## When to Use
- Designing a new feature that needs database tables
- Reviewing a schema for performance or normalization issues
- Adding multi-tenancy to an existing schema
- Generating TypeScript types from a Prisma schema
- Planning a schema migration for a breaking change
---
## Schema Design Process
### Step 1: Requirements → Entities
Given requirements:
> "Users can create projects. Each project has tasks. Tasks can have labels. Tasks can be assigned to users. We need a full audit trail."
Extract entities:
```
User, Project, Task, Label, TaskLabel (junction), TaskAssignment, AuditLog
```
### Step 2: Identify Relationships
```
User 1──* Project (owner)
Project 1──* Task
Task *──* Label (via TaskLabel)
Task *──* User (via TaskAssignment)
User 1──* AuditLog
```
### Step 3: Add Cross-cutting Concerns
- Multi-tenancy: add `organization_id` to all tenant-scoped tables
- Soft deletes: add `deleted_at TIMESTAMPTZ` instead of hard deletes
- Audit trail: add `created_by`, `updated_by`, `created_at`, `updated_at`
- Versioning: add `version INTEGER` for optimistic locking
---
## Full Schema Example (Task Management SaaS)
→ See references/full-schema-examples.md for details
## Row-Level Security (RLS) Policies
```sql
-- Enable RLS
ALTER TABLE tasks ENABLE ROW LEVEL SECURITY;
ALTER TABLE projects ENABLE ROW LEVEL SECURITY;
-- Create app role
CREATE ROLE app_user;
-- Users can only see tasks in their organization's projects
CREATE POLICY tasks_org_isolation ON tasks
FOR ALL TO app_user
USING (
project_id IN (
SELECT p.id FROM projects p
JOIN organization_members om ON om.organization_id = p.organization_id
WHERE om.user_id = current_setting('app.current_user_id')::text
)
);
-- Soft delete: never show deleted records
CREATE POLICY tasks_no_deleted ON tasks
FOR SELECT TO app_user
USING (deleted_at IS NULL);
-- Only task creator or admin can delete
CREATE POLICY tasks_delete_policy ON tasks
FOR DELETE TO app_user
USING (
created_by_id = current_setting('app.current_user_id')::text
OR EXISTS (
SELECT 1 FROM organization_members om
JOIN projects p ON p.organization_id = om.organization_id
WHERE p.id = tasks.project_id
AND om.user_id = current_setting('app.current_user_id')::text
AND om.role IN ('owner', 'admin')
)
);
-- Set user context (call at start of each request)
SELECT set_config('app.current_user_id', $1, true);
```
---
## Seed Data Generation
```typescript
// db/seed.ts
import { faker } from '@faker-js/faker'
import { db } from './client'
import { organizations, users, projects, tasks } from './schema'
import { createId } from '@paralleldrive/cuid2'
import { hashPassword } from '../src/lib/auth'
async function seed() {
console.log('Seeding database...')
// Create org
const [org] = await db.insert(organizations).values({
id: createId(),
name: "acme-corp",
slug: 'acme',
plan: 'growth',
}).returning()
// Create users
const adminUser = await db.insert(users).values({
id: createId(),
email: 'admin@acme.com',
name: "alice-admin",
passwordHash: await hashPassword('password123'),
}).returning().then(r => r[0])
// Create projects
const projectsData = Array.from({ length: 3 }, () => ({
id: createId(),
organizationId: org.id,
ownerId: adminUser.id,
name: "fakercompanycatchphrase"
description: faker.lorem.paragraph(),
status: 'active' as const,
}))
const createdProjects = await db.insert(projects).values(projectsData).returning()
// Create tasks for each project
for (const project of createdProjects) {
const tasksData = Array.from({ length: faker.number.int({ min: 5, max: 20 }) }, (_, i) => ({
id: createId(),
projectId: project.id,
title: faker.hacker.phrase(),
description: faker.lorem.sentences(2),
status: faker.helpers.arrayElement(['todo', 'in_progress', 'done'] as const),
priority: faker.helpers.arrayElement(['low', 'medium', 'high'] as const),
position: i * 1000,
createdById: adminUser.id,
updatedById: adminUser.id,
}))
await db.insert(tasks).values(tasksData)
}
console.log(`✅ Seeded: 1 org, projectsData.length projects, tasks`)
}
seed().catch(console.error).finally(() => process.exit(0))
```
---
## ERD Generation (Mermaid)
```
erDiagram
Organization ||--o{ OrganizationMember : has
Organization ||--o{ Project : owns
User ||--o{ OrganizationMember : joins
User ||--o{ Task : "created by"
Project ||--o{ Task : contains
Task ||--o{ TaskAssignment : has
Task ||--o{ TaskLabel : has
Task ||--o{ Comment : has
Task ||--o{ Attachment : has
Label ||--o{ TaskLabel : "applied to"
User ||--o{ TaskAssignment : assigned
Organization {
string id PK
string name
string slug
string plan
}
Task {
string id PK
string project_id FK
string title
string status
string priority
timestamp due_date
timestamp deleted_at
int version
}
```
Generate from Prisma:
```bash
npx prisma-erd-generator
# or: npx @dbml/cli prisma2dbml -i schema.prisma | npx dbml-to-mermaid
```
---
## Common Pitfalls
- **Soft delete without index** — `WHERE deleted_at IS NULL` without index = full scan
- **Missing composite indexes** — `WHERE org_id = ? AND status = ?` needs a composite index
- **Mutable surrogate keys** — never use email or slug as PK; use UUID/CUID
- **Non-nullable without default** — adding a NOT NULL column to existing table requires default or migration plan
- **No optimistic locking** — concurrent updates overwrite each other; add `version` column
- **RLS not tested** — always test RLS with a non-superuser role
---
## Best Practices
1. **Timestamps everywhere** — `created_at`, `updated_at` on every table
2. **Soft deletes for auditable data** — `deleted_at` instead of DELETE
3. **Audit log for compliance** — log before/after JSON for regulated domains
4. **UUIDs or CUIDs as PKs** — avoid sequential integer leakage
5. **Index foreign keys** — every FK column should have an index
6. **Partial indexes** — use `WHERE deleted_at IS NULL` for active-only queries
7. **RLS over application-level filtering** — database enforces tenancy, not just app code
FILE:references/full-schema-examples.md
# database-schema-designer reference
## Full Schema Example (Task Management SaaS)
### Prisma Schema
```prisma
// schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// ── Multi-tenancy ─────────────────────────────────────────────────────────────
model Organization {
id String @id @default(cuid())
name String
slug String @unique
plan Plan @default(FREE)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
deletedAt DateTime? @map("deleted_at")
users OrganizationMember[]
projects Project[]
auditLogs AuditLog[]
@@map("organizations")
}
model OrganizationMember {
id String @id @default(cuid())
organizationId String @map("organization_id")
userId String @map("user_id")
role OrgRole @default(MEMBER)
joinedAt DateTime @default(now()) @map("joined_at")
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([organizationId, userId])
@@index([userId])
@@map("organization_members")
}
model User {
id String @id @default(cuid())
email String @unique
name String?
avatarUrl String? @map("avatar_url")
passwordHash String? @map("password_hash")
emailVerifiedAt DateTime? @map("email_verified_at")
lastLoginAt DateTime? @map("last_login_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
deletedAt DateTime? @map("deleted_at")
memberships OrganizationMember[]
ownedProjects Project[] @relation("ProjectOwner")
assignedTasks TaskAssignment[]
comments Comment[]
auditLogs AuditLog[]
@@map("users")
}
// ── Core entities ─────────────────────────────────────────────────────────────
model Project {
id String @id @default(cuid())
organizationId String @map("organization_id")
ownerId String @map("owner_id")
name String
description String?
status ProjectStatus @default(ACTIVE)
settings Json @default("{}")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
deletedAt DateTime? @map("deleted_at")
organization Organization @relation(fields: [organizationId], references: [id])
owner User @relation("ProjectOwner", fields: [ownerId], references: [id])
tasks Task[]
labels Label[]
@@index([organizationId])
@@index([organizationId, status])
@@index([deletedAt])
@@map("projects")
}
model Task {
id String @id @default(cuid())
projectId String @map("project_id")
title String
description String?
status TaskStatus @default(TODO)
priority Priority @default(MEDIUM)
dueDate DateTime? @map("due_date")
position Float @default(0) // For drag-and-drop ordering
version Int @default(1) // Optimistic locking
createdById String @map("created_by_id")
updatedById String @map("updated_by_id")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
deletedAt DateTime? @map("deleted_at")
project Project @relation(fields: [projectId], references: [id])
assignments TaskAssignment[]
labels TaskLabel[]
comments Comment[]
attachments Attachment[]
@@index([projectId])
@@index([projectId, status])
@@index([projectId, deletedAt])
@@index([dueDate], where: { deletedAt: null }) // Partial index
@@map("tasks")
}
// ── Polymorphic attachments ───────────────────────────────────────────────────
model Attachment {
id String @id @default(cuid())
// Polymorphic association
entityType String @map("entity_type") // "task" | "comment"
entityId String @map("entity_id")
filename String
mimeType String @map("mime_type")
sizeBytes Int @map("size_bytes")
storageKey String @map("storage_key") // S3 key
uploadedById String @map("uploaded_by_id")
createdAt DateTime @default(now()) @map("created_at")
// Only one concrete relation (task) — polymorphic handled at app level
task Task? @relation(fields: [entityId], references: [id], map: "attachment_task_fk")
@@index([entityType, entityId])
@@map("attachments")
}
// ── Audit trail ───────────────────────────────────────────────────────────────
model AuditLog {
id String @id @default(cuid())
organizationId String @map("organization_id")
userId String? @map("user_id")
action String // "task.created", "task.status_changed"
entityType String @map("entity_type")
entityId String @map("entity_id")
before Json? // Previous state
after Json? // New state
ipAddress String? @map("ip_address")
userAgent String? @map("user_agent")
createdAt DateTime @default(now()) @map("created_at")
organization Organization @relation(fields: [organizationId], references: [id])
user User? @relation(fields: [userId], references: [id])
@@index([organizationId, createdAt(sort: Desc)])
@@index([entityType, entityId])
@@index([userId])
@@map("audit_logs")
}
enum Plan { FREE STARTER GROWTH ENTERPRISE }
enum OrgRole { OWNER ADMIN MEMBER VIEWER }
enum ProjectStatus { ACTIVE ARCHIVED }
enum TaskStatus { TODO IN_PROGRESS IN_REVIEW DONE CANCELLED }
enum Priority { LOW MEDIUM HIGH CRITICAL }
```
---
### Drizzle Schema (TypeScript)
```typescript
// db/schema.ts
import {
pgTable, text, timestamp, integer, boolean,
varchar, jsonb, real, pgEnum, uniqueIndex, index,
} from 'drizzle-orm/pg-core'
import { createId } from '@paralleldrive/cuid2'
export const taskStatusEnum = pgEnum('task_status', [
'todo', 'in_progress', 'in_review', 'done', 'cancelled'
])
export const priorityEnum = pgEnum('priority', ['low', 'medium', 'high', 'critical'])
export const tasks = pgTable('tasks', {
id: text('id').primaryKey().$defaultFn(() => createId()),
projectId: text('project_id').notNull().references(() => projects.id),
title: varchar('title', { length: 500 }).notNull(),
description: text('description'),
status: taskStatusEnum('status').notNull().default('todo'),
priority: priorityEnum('priority').notNull().default('medium'),
dueDate: timestamp('due_date', { withTimezone: true }),
position: real('position').notNull().default(0),
version: integer('version').notNull().default(1),
createdById: text('created_by_id').notNull().references(() => users.id),
updatedById: text('updated_by_id').notNull().references(() => users.id),
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
deletedAt: timestamp('deleted_at', { withTimezone: true }),
}, (table) => ({
projectIdx: index('tasks_project_id_idx').on(table.projectId),
projectStatusIdx: index('tasks_project_status_idx').on(table.projectId, table.status),
}))
// Infer TypeScript types
export type Task = typeof tasks.$inferSelect
export type NewTask = typeof tasks.$inferInsert
```
---
### Alembic Migration (Python / SQLAlchemy)
```python
# alembic/versions/20260301_create_tasks.py
"""Create tasks table
Revision ID: a1b2c3d4e5f6
Revises: previous_revision
Create Date: 2026-03-01 12:00:00
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
revision = 'a1b2c3d4e5f6'
down_revision = 'previous_revision'
def upgrade() -> None:
# Create enums
task_status = postgresql.ENUM(
'todo', 'in_progress', 'in_review', 'done', 'cancelled',
name='task_status'
)
task_status.create(op.get_bind())
op.create_table(
'tasks',
sa.Column('id', sa.Text(), primary_key=True),
sa.Column('project_id', sa.Text(), sa.ForeignKey('projects.id'), nullable=False),
sa.Column('title', sa.VARCHAR(500), nullable=False),
sa.Column('description', sa.Text()),
sa.Column('status', postgresql.ENUM('todo', 'in_progress', 'in_review', 'done', 'cancelled', name='task_status', create_type=False), nullable=False, server_default='todo'),
sa.Column('priority', sa.Text(), nullable=False, server_default='medium'),
sa.Column('due_date', sa.TIMESTAMP(timezone=True)),
sa.Column('position', sa.Float(), nullable=False, server_default='0'),
sa.Column('version', sa.Integer(), nullable=False, server_default='1'),
sa.Column('created_by_id', sa.Text(), sa.ForeignKey('users.id'), nullable=False),
sa.Column('updated_by_id', sa.Text(), sa.ForeignKey('users.id'), nullable=False),
sa.Column('created_at', sa.TIMESTAMP(timezone=True), nullable=False, server_default=sa.text('NOW()')),
sa.Column('updated_at', sa.TIMESTAMP(timezone=True), nullable=False, server_default=sa.text('NOW()')),
sa.Column('deleted_at', sa.TIMESTAMP(timezone=True)),
)
# Indexes
op.create_index('tasks_project_id_idx', 'tasks', ['project_id'])
op.create_index('tasks_project_status_idx', 'tasks', ['project_id', 'status'])
# Partial index for active tasks only
op.create_index(
'tasks_due_date_active_idx',
'tasks', ['due_date'],
postgresql_where=sa.text('deleted_at IS NULL')
)
def downgrade() -> None:
op.drop_table('tasks')
op.execute("DROP TYPE IF EXISTS task_status")
```
---
Product marketing: định vị, chiến lược GTM, phân tích đối thủ, ra mắt sản phẩm, xác định ICP, nghiên cứu thị trường và hỗ trợ bán hàng.
---
name: "marketing-strategy-pmm"
description: Product marketing skill for positioning, GTM strategy, competitive intelligence, and product launches. Use when the user asks about product positioning, go-to-market planning, competitive analysis, target audience definition, ICP definition, market research, launch plans, or sales enablement. Covers April Dunford positioning, ICP definition, competitive battlecards, launch playbooks, and international market entry. Produces deliverables including positioning statements, battlecard documents, launch plans, and go-to-market strategies.
triggers:
- product marketing
- PMM
- positioning
- GTM strategy
- go-to-market
- competitive analysis
- battlecard
- product launch
- market entry
- sales enablement
- win loss analysis
---
# Marketing Strategy & PMM
Product marketing patterns for positioning, GTM strategy, and competitive intelligence.
---
## Table of Contents
- [ICP Definition Workflow](#icp-definition-workflow)
- [Positioning Development](#positioning-development)
- [Competitive Intelligence](#competitive-intelligence)
- [Product Launch Planning](#product-launch-planning)
- [Sales Enablement](#sales-enablement)
- [International Expansion](#international-expansion)
- [Reference Documentation](#reference-documentation)
---
## ICP Definition Workflow
Define ideal customer profile for targeting:
1. Analyze existing customers (top 20% by LTV)
2. Identify common firmographics (size, industry, revenue)
3. Map technographics (tools, maturity, integrations)
4. Document psychographics (pain level, motivation, risk tolerance)
5. Define 3-5 buyer personas (economic, technical, user)
6. Validate against sales cycle and churn data
7. Score prospects A/B/C/D based on ICP fit
8. **Validation:** A-fit customers have lowest churn and fastest close
### Firmographics Template
| Dimension | Target Range | Rationale |
|-----------|--------------|-----------|
| Employees | 50-5000 | Series A sweet spot |
| Revenue | $5M-$500M | Budget available |
| Industry | SaaS, Tech, Services | Product fit |
| Geography | US, UK, DACH | Market priority |
| Funding | Seed to Growth | Willing to adopt |
### Buyer Personas
| Persona | Title | Goals | Messaging |
|---------|-------|-------|-----------|
| Economic Buyer | VP, Director, Head of [Department] | ROI, team productivity, cost reduction | Business outcomes, ROI, case studies |
| Technical Buyer | Engineer, Architect, Tech Lead | Technical fit, easy integration | Architecture, security, documentation |
| User/Champion | Manager, Team Lead, Power User | Makes job easier, quick wins | UX, ease of use, time savings |
### ICP Validation Checklist
- [ ] 5+ paying customers match this profile
- [ ] Fastest sales cycles (< median)
- [ ] Highest LTV (> median)
- [ ] Lowest churn (< 5% annual)
- [ ] Strong product engagement
- [ ] Willing to do case studies
---
## Positioning Development
Develop positioning using April Dunford methodology:
1. List competitive alternatives (direct, adjacent, status quo)
2. Isolate unique attributes (features only you have)
3. Map attributes to customer value (why it matters)
4. Define best-fit customers (who cares most)
5. Choose market category (head-to-head, niche, new category)
6. Layer on relevant trends (timing justification)
7. Test with 10+ customer interviews
8. **Validation:** 7+ customers describe value unprompted
### Positioning Statement Template
```
FOR [target customer]
WHO [statement of need]
THE [product] IS A [category]
THAT [key benefit]
UNLIKE [competitive alternative]
OUR PRODUCT [primary differentiation]
```
### Value Proposition Formula
Template: `[Product] helps [Target Customer] [Achieve Goal] by [Unique Approach]`
Example: "Acme helps mid-market SaaS teams ship 2x faster by automating project workflows with AI"
### Messaging Hierarchy
| Level | Content | Example |
|-------|---------|---------|
| Headline | 5-7 words | "Ship faster with AI automation" |
| Subhead | 1 sentence | "Automate workflows so teams focus on what matters" |
| Benefits | 3-4 bullets | Speed, quality, collaboration, cost |
| Features | Supporting evidence | AI automation → 10 hrs/week saved |
| Proof | Social proof | Customer logos, stats, case studies |
---
## Competitive Intelligence
Build competitive knowledge base:
1. Identify tier 1 (direct), tier 2 (adjacent), tier 3 (status quo)
2. Sign up for competitor products (hands-on evaluation)
3. Monitor competitor websites, pricing, messaging
4. Analyze sales call recordings for competitor mentions
5. Read G2/Capterra reviews (pros and cons)
6. Track competitor job postings (roadmap signals)
7. Update battlecards monthly
8. **Validation:** Sales team uses battlecards in 80%+ competitive deals
### Competitive Tier Structure
| Tier | Definition | Examples |
|------|------------|----------|
| 1 | Direct competitor, same category | [Competitor A, B] |
| 2 | Adjacent solution, overlapping use case | [Alt Solution C, D] |
| 3 | Status quo (what they do today) | Spreadsheets, manual, in-house |
### Battlecard Template
```
COMPETITOR: [Name]
OVERVIEW: Founded [year], Funding [stage], Size [employees]
POSITIONING:
- They say: "[Their claim]"
- Reality: [Your assessment]
STRENGTHS:
1. [What they do well]
2. [What they do well]
WEAKNESSES:
1. [Where they fall short]
2. [Where they fall short]
OUR ADVANTAGES:
1. [Your advantage + evidence]
2. [Your advantage + evidence]
WHEN WE WIN:
- [Scenario where you win]
WHEN WE LOSE:
- [Scenario where they win]
TALK TRACK:
Objection: "[Common objection]"
Response: "[Your response]"
```
### Win/Loss Analysis
Track monthly:
- Win rate by competitor
- Top win reasons (product fit, ease of use, price)
- Top loss reasons (missing feature, price, relationship)
- Action items for product, sales, marketing
---
## Product Launch Planning
Plan launches by tier:
| Tier | Scope | Prep Time | Budget |
|------|-------|-----------|--------|
| 1 | New product, major feature | 6-8 weeks | $50-100k |
| 2 | Significant feature, integration | 3-4 weeks | $10-25k |
| 3 | Small improvement | 1 week | <$5k |
### Tier 1 Launch Workflow
Execute major product launch:
1. Kickoff meeting with Product, Marketing, Sales, CS
2. Define goals (pipeline $, MQLs, press coverage)
3. Develop positioning and messaging
4. Create sales enablement (deck, demo, battlecard)
5. Build campaign assets (landing page, emails, ads)
6. Train sales and CS teams
7. Execute launch day (press, email, ads, outbound)
8. Monitor and optimize for 30 days
9. **Validation:** Pipeline on track to goal by week 2
### Launch Day Checklist
- [ ] Press release distributed
- [ ] Email announcement sent
- [ ] Social media posts live
- [ ] Paid ads at full budget
- [ ] Sales outbound blitz launched
- [ ] In-app notification active
- [ ] Metrics monitored every 2 hours
### Launch Metrics
| Metric | Leading (Daily) | Lagging (Weekly) |
|--------|-----------------|------------------|
| Traffic | Landing page visitors | - |
| Engagement | Demo requests, signups | Feature adoption % |
| Pipeline | MQLs generated | SQLs, pipeline $ |
| Revenue | - | Deals closed, revenue |
---
## Sales Enablement
Equip sales team with PMM assets:
1. Create sales deck (15-20 slides, visual-first)
2. Build one-pagers (product, competitive, case study)
3. Develop demo script (30-45 min with discovery)
4. Write email templates (outreach, follow-up, closing)
5. Create ROI calculator (input costs, output savings)
6. Conduct monthly enablement calls
7. Deliver quarterly training (positioning, competitive)
8. **Validation:** Sales uses assets in 80%+ of opportunities
### Sales Deck Structure
| Slide | Content |
|-------|---------|
| 1-2 | Title, agenda |
| 3-4 | Company intro, problem statement |
| 5-7 | Solution, key benefits, demo |
| 8-10 | Differentiation, case study, pricing |
| 11-12 | Implementation, support, next steps |
### Demo Flow
```
1. Intro (2 min): Who we are, agenda
2. Discovery (5 min): Their needs, pain points
3. Demo (20 min): Product focused on their use case
4. Q&A (10 min): Objection handling
5. Next steps (3 min): Trial, POC, proposal
```
### Sales-Marketing Handoff
| Handoff | Frequency | Content |
|---------|-----------|---------|
| Weekly sync | 30 min | Win/loss, competitive, new assets |
| Monthly enablement | 60 min | Product updates, training |
| Quarterly review | Half-day | Results, strategy, planning |
---
## International Expansion
Enter new markets systematically:
1. Validate market demand (inbound leads, TAM analysis)
2. Localize website, pricing, legal
3. Establish sales coverage (hire or agency)
4. Adapt messaging for cultural fit
5. Build local partnerships and references
6. Launch localized campaigns
7. Monitor CAC and conversion by market
8. **Validation:** 3+ paying customers from market in first 90 days
### Market Priority (Series A)
| Market | Timeline | Budget % | Target ARR |
|--------|----------|----------|------------|
| US | Months 1-6 | 50% | $1M |
| UK | Months 4-9 | 20% | $500k |
| DACH | Months 7-12 | 15% | $300k |
| France | Months 10-15 | 10% | $200k |
| Canada | Months 7-12 | 5% | $100k |
### Localization Checklist
- [ ] Website translation (professional, not machine)
- [ ] Currency and pricing localized
- [ ] Local phone number and address
- [ ] Legal compliance (GDPR, PIPEDA)
- [ ] Local payment methods
- [ ] Sales coverage during local hours
- [ ] Local case studies and references
---
## Reference Documentation
### Positioning Frameworks
`references/positioning-frameworks.md` contains:
- April Dunford 5-step positioning process
- Geoffrey Moore positioning statement template
- Positioning validation interview protocol
- Competitive positioning map construction
### Launch Checklists
`references/launch-checklists.md` contains:
- Tier 1/2/3 launch checklists
- Week-by-week launch timeline
- Launch day runbook
- Post-launch metrics dashboard
### International GTM
`references/international-gtm.md` contains:
- US, UK, DACH, France, Canada playbooks
- Market-specific channel mix and messaging
- Localization requirements per market
- Entry timeline and budget allocation
### Messaging Templates
`references/messaging-templates.md` contains:
- Value proposition formulas
- Persona-specific messaging
- Competitive response scripts
- Objection handling templates
- Channel-specific copy (landing pages, emails, ads)
---
## PMM KPIs
| Metric | Target | Measurement |
|--------|--------|-------------|
| Product adoption | >40% in 90 days | Feature usage after launch |
| Win rate | >30% competitive | Deals won vs. competitors |
| Sales velocity | -20% YoY | Days from SQL to close |
| Deal size | +25% YoY | Average contract value |
| Launch pipeline | 3:1 ROMI | Pipeline $ : marketing spend |
---
## Quick Reference
### PMM Monthly Rhythm
| Week | Focus |
|------|-------|
| 1 | Review metrics, update battlecards |
| 2 | Create assets, publish content |
| 3 | Support launches, optimize campaigns |
| 4 | Monthly report, plan next month |
## Proactive Triggers
- **No documented positioning** → Without clear positioning, all marketing is guesswork.
- **Messaging differs across channels** → Inconsistent story confuses buyers.
- **No ICP defined** → Selling to everyone means selling to no one.
- **Competitor repositioning** → Market shift detected. Review your positioning.
## Output Artifacts
| When you ask for... | You get... |
|---------------------|------------|
| "Position my product" | Positioning framework (April Dunford method) with output |
| "GTM strategy" | Go-to-market plan with channels, messaging, and timeline |
| "Competitive positioning" | Positioning map with competitive gaps and opportunities |
## Communication
All output passes quality verification:
- Self-verify: source attribution, assumption audit, confidence scoring
- Output format: Bottom Line → What (with confidence) → Why → How to Act
- Results only. Every finding tagged: 🟢 verified, 🟡 medium, 🔴 assumed.
## Related Skills
- **marketing-context**: For capturing foundational positioning. PMM builds on this.
- **launch-strategy**: For executing product launches planned by PMM.
- **competitive-intel** (C-Suite): For strategic competitive intelligence.
- **cmo-advisor** (C-Suite): For marketing budget and growth model decisions.
FILE:references/international-gtm.md
# International GTM Playbooks
Market-by-market expansion guides for US, UK, DACH, France, and Canada.
---
## Table of Contents
- [Market Prioritization](#market-prioritization)
- [US Market Entry](#us-market-entry)
- [UK Market Entry](#uk-market-entry)
- [DACH Market Entry](#dach-market-entry)
- [France Market Entry](#france-market-entry)
- [Canada Market Entry](#canada-market-entry)
- [Localization Checklist](#localization-checklist)
---
## Market Prioritization
### Expansion Sequence (Series A)
| Phase | Market | Timeline | Budget % | Target ARR |
|-------|--------|----------|----------|------------|
| 1 | US | Months 1-6 | 50% | $1M |
| 2 | UK | Months 4-9 | 20% | $500k |
| 3 | DACH | Months 7-12 | 15% | $300k |
| 4 | France | Months 10-15 | 10% | $200k |
| 5 | Canada | Months 7-12 | 5% | $100k |
### Market Readiness Checklist
Enter market when ALL true:
- [ ] Product ready for market (localization if needed)
- [ ] Legal/compliance requirements met
- [ ] Pricing localized (currency, taxes)
- [ ] Sales capacity available (hire or agency)
- [ ] Marketing budget allocated
- [ ] Support coverage during local hours
- [ ] **Validation:** 3+ inbound leads from market in last 90 days
---
## US Market Entry
### Market Characteristics
| Factor | US Approach |
|--------|-------------|
| Buying cycle | Fast (30-60 days average) |
| Decision process | Individual empowerment, less consensus |
| Pricing sensitivity | Value-focused, willing to pay premium |
| Communication | Direct, results-oriented |
| Relationship | Transaction > relationship (initially) |
### Entry Strategy
**Months 1-2: Foundation**
1. Establish US presence:
- US phone number (toll-free)
- US address (virtual office acceptable)
- USD pricing on website
- US case studies (even if from beta users)
2. Hire US sales:
- Option A: US-based SDR/AE (expensive but effective)
- Option B: US sales agency (lower risk, shared commission)
- Option C: Remote sales trained on US hours
3. Launch paid campaigns:
- Google Ads (high-intent keywords)
- LinkedIn (B2B targeting)
- Budget: 50% of marketing spend
**Months 3-6: Scale**
1. Optimize channels based on CAC data
2. Build US partner ecosystem:
- Integration partners (Salesforce, HubSpot)
- Resellers/VARs (for Enterprise)
- Industry associations
3. Attend US conferences (SaaStr, industry events)
4. **Validation:** $1M pipeline from US sources
### US Channel Mix
| Channel | Budget % | Expected CPL | Notes |
|---------|----------|--------------|-------|
| Google Ads | 35% | $100-200 | High intent, competitive |
| LinkedIn | 30% | $150-250 | B2B targeting |
| SEO/Content | 20% | $50 (long-term) | Invest early |
| Partnerships | 15% | Variable | Co-marketing |
### US Messaging
- Lead with ROI and business outcomes
- Use $ impact metrics prominently
- Reference US customers (logos matter)
- Emphasize speed and efficiency
- Include G2/Capterra ratings
---
## UK Market Entry
### Market Characteristics
| Factor | UK Approach |
|--------|-------------|
| Buying cycle | Medium (45-90 days) |
| Decision process | Committee involvement |
| Pricing sensitivity | Value-conscious, compare options |
| Communication | Professional, less aggressive than US |
| Relationship | Balance transaction and relationship |
### Entry Strategy
**Months 4-6: Setup**
1. Localization:
- GBP pricing
- UK spellings (colour, organisation)
- UK phone number
- GDPR compliance (essential)
2. Sales coverage:
- Hire UK-based rep OR
- Partner with UK sales agency
- Ensure coverage during GMT hours
3. Content localization:
- UK case studies
- UK-relevant industry references
- Local competitor positioning
**Months 7-9: Growth**
1. Build UK partnerships:
- UK tech community (TechNation, etc.)
- London-based VCs and accelerators
- UK industry associations
2. Attend UK events:
- London Tech Week
- Industry-specific conferences
3. **Validation:** $500k pipeline from UK sources
### UK Channel Mix
| Channel | Budget % | Expected CPL | Notes |
|---------|----------|--------------|-------|
| LinkedIn | 35% | $120-200 | Strong B2B presence |
| Google UK | 30% | $80-150 | Less competitive than US |
| SEO/Content | 20% | $40 | UK-targeted keywords |
| Partnerships | 15% | Variable | Local credibility |
### UK Messaging
- More formal than US (avoid hyperbole)
- Emphasize data security and GDPR
- Reference UK/EU customers
- Understated claims (prove with data)
- Acknowledge local presence/support
---
## DACH Market Entry
### Market Characteristics
| Factor | DACH Approach |
|--------|---------------|
| Buying cycle | Long (90-180 days) |
| Decision process | Consensus-driven, thorough evaluation |
| Pricing sensitivity | Quality over price, long-term view |
| Communication | Formal, detailed, precise |
| Relationship | Trust built over time, essential |
### Entry Strategy
**Months 7-9: Foundation**
1. Full localization:
- German translation (website, product UI)
- EUR pricing with German VAT handling
- German phone number and address
- GDPR compliance (strict enforcement)
- Data residency option (EU data centers)
2. German-speaking sales:
- Hire German-speaking sales rep
- Native speaker critical (not just fluent)
- Based in Germany preferred
3. Content in German:
- Translate key pages and materials
- Create German case studies
- German blog content
**Months 10-12: Growth**
1. Build local credibility:
- German customer testimonials
- German partner ecosystem
- Industry certifications (ISO, etc.)
2. Attend German events:
- CeBIT/Hannover Messe
- Industry conferences
3. **Validation:** $300k pipeline from DACH sources
### DACH Channel Mix
| Channel | Budget % | Expected CPL | Notes |
|---------|----------|--------------|-------|
| LinkedIn | 40% | $150-250 | Strong professional network |
| Google DE | 25% | $100-180 | German keywords |
| SEO (German) | 20% | $60 | Long-term investment |
| Partnerships | 15% | Variable | Critical for trust |
### DACH Messaging
- Formal tone (Sie, not du)
- Emphasize security, compliance, privacy
- Detailed specifications and documentation
- Reference German/EU customers
- Include certifications (ISO, SOC 2)
- Show long-term commitment to market
---
## France Market Entry
### Market Characteristics
| Factor | France Approach |
|--------|-----------------|
| Buying cycle | Long (90-180 days) |
| Decision process | Hierarchical, formal process |
| Pricing sensitivity | Value-focused, negotiation expected |
| Communication | Formal, relationship-focused |
| Relationship | Critical, business built on trust |
### Entry Strategy
**Months 10-12: Foundation**
1. Full French localization:
- French translation (professional, not machine)
- EUR pricing with French VAT
- French phone number
- GDPR + French regulations
2. French-speaking team:
- Native French speaker for sales
- French support coverage
- Paris presence (even virtual)
**Months 13-15: Growth**
1. Build local ecosystem:
- French tech community (La French Tech)
- French partners and integrators
- Industry associations
2. Attend French events:
- VivaTech (Paris)
- Industry conferences
3. **Validation:** $200k pipeline from France
### France Channel Mix
| Channel | Budget % | Expected CPL | Notes |
|---------|----------|--------------|-------|
| LinkedIn | 35% | $130-220 | Professional network |
| Google FR | 30% | $90-160 | French keywords |
| SEO (French) | 20% | $50 | French content strategy |
| Partnerships | 15% | Variable | Local partners essential |
### France Messaging
- Formal and professional
- French language throughout (no English fallback)
- Reference French/EU customers
- Emphasize local support and presence
- Highlight innovation and modernity
- Respect cultural nuances
---
## Canada Market Entry
### Market Characteristics
| Factor | Canada Approach |
|--------|-----------------|
| Buying cycle | Medium (45-75 days) |
| Decision process | Similar to US, slightly more conservative |
| Pricing sensitivity | Value-conscious, compare to US prices |
| Communication | Professional, friendly, less aggressive |
| Language | English (except Quebec - French required) |
### Entry Strategy
**Months 7-9: Foundation**
1. Minimal localization:
- CAD pricing
- Canadian phone number (optional)
- PIPEDA compliance
2. Sales coverage:
- Leverage US sales team (similar hours)
- Consider Toronto-based rep for growth
3. Quebec consideration:
- French required for Quebec market
- Can delay or skip initially
**Months 10-12: Growth**
1. Canadian partnerships:
- Canadian tech community
- Toronto/Vancouver startup ecosystem
- Industry associations
2. **Validation:** $100k pipeline from Canada
### Canada Channel Mix
| Channel | Budget % | Expected CPL | Notes |
|---------|----------|--------------|-------|
| Google CA | 35% | $80-150 | Canadian targeting |
| LinkedIn | 30% | $100-180 | B2B focus |
| SEO | 20% | $40 | Canadian content |
| Partnerships | 15% | Variable | Local credibility |
---
## Localization Checklist
### Per-Market Checklist
**Website**
- [ ] Language translation (professional, not machine)
- [ ] Currency localization (display + checkout)
- [ ] Phone number (local format)
- [ ] Address (local presence)
- [ ] Legal pages (privacy, terms in local language)
- [ ] hreflang tags configured correctly
**Product**
- [ ] UI translation (if required for market)
- [ ] Date/time format (DD/MM/YYYY vs MM/DD/YYYY)
- [ ] Number format (1,000 vs 1.000)
- [ ] Currency in product
**Payment**
- [ ] Local currency accepted
- [ ] VAT/tax handling
- [ ] Local payment methods (SEPA, iDEAL, etc.)
- [ ] Invoicing in local format
**Legal**
- [ ] GDPR compliance (EU markets)
- [ ] PIPEDA compliance (Canada)
- [ ] Local data protection laws
- [ ] Terms of service localized
- [ ] Privacy policy localized
**Sales**
- [ ] Local sales coverage (rep or agency)
- [ ] Localized sales materials
- [ ] Local pricing and quoting
- [ ] Local references and case studies
**Support**
- [ ] Coverage during local business hours
- [ ] Language support (phone, chat, email)
- [ ] Localized documentation
- [ ] Local SLA commitments
**Marketing**
- [ ] Localized campaigns
- [ ] Local content (blog, guides)
- [ ] Local social media presence
- [ ] Local event participation
**Validation:** Native speaker review of ALL localized content before launch
FILE:references/launch-checklists.md
# Launch Checklists
GTM launch playbooks for Tier 1, 2, and 3 product releases.
---
## Table of Contents
- [Launch Tier Definitions](#launch-tier-definitions)
- [Tier 1 Major Launch](#tier-1-major-launch)
- [Tier 2 Standard Launch](#tier-2-standard-launch)
- [Tier 3 Minor Launch](#tier-3-minor-launch)
- [Launch Metrics Dashboard](#launch-metrics-dashboard)
---
## Launch Tier Definitions
| Tier | Scope | Prep Time | Budget | Audience |
|------|-------|-----------|--------|----------|
| 1 | New product, major feature | 6-8 weeks | $50-100k | All prospects + press |
| 2 | Significant feature, integration | 3-4 weeks | $10-25k | Customers + select prospects |
| 3 | Small feature, improvement | 1 week | <$5k | Existing customers |
**Tier Selection Criteria:**
```
Tier 1 if ANY true:
- [ ] Net-new product line
- [ ] Revenue impact > $500k pipeline
- [ ] Press coverage expected
- [ ] Competitive response anticipated
Tier 2 if ANY true:
- [ ] Major feature request (top 10 customer ask)
- [ ] New integration with strategic partner
- [ ] Pricing or packaging change
Tier 3 otherwise:
- [ ] Bug fixes
- [ ] UI improvements
- [ ] Minor enhancements
```
---
## Tier 1 Major Launch
### Phase 1: Foundation (Weeks -8 to -5)
**Week -8: Kickoff**
- [ ] Schedule kickoff meeting (Product, Marketing, Sales, CS)
- [ ] Define launch goals:
- Pipeline target: $______
- MQL target: ______
- Press hits target: ______
- Adoption target: ______% in 90 days
- [ ] Assign roles (RACI matrix):
- PMM: Launch lead, positioning, messaging
- Product: Feature readiness, demo environment
- Demand Gen: Campaigns, paid ads, email
- Content: Blog posts, case studies, videos
- Sales: Enablement, outbound campaign
- [ ] Create project timeline in Asana/Monday/Notion
- [ ] **Validation:** All stakeholders confirm goals and timeline
**Week -7: Strategy**
- [ ] Develop positioning and messaging (see positioning-frameworks.md)
- [ ] Create GTM channel plan:
- Owned: Email, blog, social, webinar
- Paid: LinkedIn ads, Google ads
- Earned: Press, influencers, partners
- [ ] Define target segments (ICP, personas)
- [ ] Allocate budget by channel
- [ ] Draft press release (embargo date set)
**Week -6: Content**
- [ ] Build landing page (product page, demo request form)
- [ ] Write blog post announcement
- [ ] Create sales deck updates (5-10 new slides)
- [ ] Design social media graphics (5+ variants)
- [ ] Produce demo video (3-5 minutes)
- [ ] Draft email sequences (announcement, nurture)
**Week -5: Enablement**
- [ ] Create sales battlecard (competitive positioning)
- [ ] Write demo script (new feature walkthrough)
- [ ] Build FAQ document (top 20 questions)
- [ ] Develop objection handling guide
- [ ] Schedule sales training session
- [ ] Recruit beta customers for testimonials
- [ ] **Validation:** Sales team can demo feature confidently
### Phase 2: Preparation (Weeks -4 to -1)
**Week -4: Launch Prep**
- [ ] Set up HubSpot campaign (UTMs, attribution)
- [ ] Launch teaser campaign (social, email hints)
- [ ] Pitch press and analysts (NDA briefings)
- [ ] Create webinar registration page
- [ ] Finalize partner co-marketing plans
- [ ] QA all landing pages and forms
**Week -3: Ramp Up**
- [ ] Activate paid ads (LinkedIn, Google) at 50% budget
- [ ] A/B test landing page headlines
- [ ] Send pre-launch email to VIP customers
- [ ] Conduct sales training (2-hour session)
- [ ] Confirm webinar speakers and content
- [ ] Prepare launch day runbook
**Week -2: Final Prep**
- [ ] Increase paid ad spend to 75%
- [ ] Send webinar reminder emails
- [ ] Finalize press embargo lift time
- [ ] Complete dry run (website, forms, CRM workflow)
- [ ] Create launch day social posts (scheduled)
- [ ] Brief customer success team
**Week -1: Pre-Launch**
- [ ] Final approval on all assets
- [ ] Send VIP preview to top 10 customers
- [ ] Confirm press embargo release
- [ ] Sales team ready (trained, quotas set)
- [ ] CS team ready (docs updated, chat staffed)
- [ ] Test all systems one final time
- [ ] **Validation:** All checklist items green
### Phase 3: Launch (Weeks 1-4)
**Launch Day**
- [ ] Press release distribution (wire + direct pitch)
- [ ] Email blast to full database
- [ ] Social media posts (LinkedIn, Twitter, Facebook)
- [ ] Paid ads at 100% budget
- [ ] Sales outbound blitz (top 100 accounts)
- [ ] In-app announcement to existing users
- [ ] Monitor metrics every 2 hours:
- Traffic, signups, demo requests
- Press pickup, social engagement
- Sales pipeline created
**Days 2-7**
- [ ] Daily metrics review (conversion rates, funnel)
- [ ] A/B test optimizations based on data
- [ ] Sales follow-up (<4 hour SLA on leads)
- [ ] Respond to press and analyst inquiries
- [ ] Host webinar (Day 3 or 4)
- [ ] Post customer testimonials
- [ ] Adjust paid ads (pause underperformers)
**Week 2-4**
- [ ] Publish post-launch blog content
- [ ] Create customer case study from early adopters
- [ ] Conduct win/loss interviews (5+ deals)
- [ ] Optimize converting channels (+20% budget)
- [ ] Pause non-converting channels
- [ ] Weekly launch status report to executives
- [ ] **Validation:** Pipeline on track to goal
### Phase 4: Post-Launch (Weeks 5-12)
**Month 2**
- [ ] Launch retrospective meeting
- [ ] Document learnings (what worked, what didn't)
- [ ] Scale winning channels
- [ ] Expand to new segments if successful
- [ ] Update positioning based on customer feedback
- [ ] Plan sustaining campaigns
**Month 3**
- [ ] Final launch report (vs. goals)
- [ ] Calculate ROI (pipeline / spend)
- [ ] Publish additional case studies
- [ ] Integrate learnings into next launch plan
- [ ] Archive launch assets for reuse
---
## Tier 2 Standard Launch
### Timeline: 4 Weeks
**Week -4 to -3: Preparation**
- [ ] Define feature and target audience
- [ ] Create positioning and key messages
- [ ] Build landing page or product page update
- [ ] Write blog post announcement
- [ ] Update sales deck (2-3 slides)
- [ ] Create email announcement
- [ ] Brief sales team (30-min call)
**Week -2 to -1: Setup**
- [ ] Set up HubSpot campaign tracking
- [ ] Schedule social posts
- [ ] Set up paid ads (limited budget)
- [ ] QA landing pages and forms
- [ ] Notify customer success team
**Launch Week**
- [ ] Send email announcement
- [ ] Publish blog post
- [ ] Post on social media
- [ ] In-app notification to users
- [ ] Sales mention in active deals
- [ ] Monitor initial metrics
**Week +1 to +2: Follow-up**
- [ ] Analyze launch metrics
- [ ] Optimize based on data
- [ ] Collect customer feedback
- [ ] Document learnings
---
## Tier 3 Minor Launch
### Timeline: 1 Week
**Day -5 to -3: Prep**
- [ ] Write changelog entry
- [ ] Update support documentation
- [ ] Create in-app notification copy
- [ ] Brief CS team
**Day -2 to -1: Review**
- [ ] QA feature in staging
- [ ] Approve changelog copy
- [ ] Schedule in-app notification
**Launch Day**
- [ ] Deploy feature
- [ ] Trigger in-app notification
- [ ] Publish changelog
- [ ] Update support docs (if needed)
**Day +1 to +3: Monitor**
- [ ] Check for support tickets
- [ ] Monitor feature adoption
- [ ] Address any issues
---
## Launch Metrics Dashboard
### Leading Indicators (Track Daily)
| Metric | Target | Day 1 | Day 3 | Day 7 |
|--------|--------|-------|-------|-------|
| Landing page visitors | 5,000 | | | |
| Demo requests | 100 | | | |
| Free trial signups | 200 | | | |
| MQLs generated | 150 | | | |
| Pipeline created ($) | $500k | | | |
### Lagging Indicators (Track Weekly)
| Metric | Target | Week 1 | Week 2 | Week 4 |
|--------|--------|--------|--------|--------|
| SQLs generated | 30 | | | |
| Demos completed | 50 | | | |
| Deals closed (#) | 5 | | | |
| Revenue ($) | $100k | | | |
| Feature adoption (%) | 40% | | | |
### Channel Performance
| Channel | Spend | MQLs | CPL | Pipeline | ROI |
|---------|-------|------|-----|----------|-----|
| LinkedIn Ads | $10k | | | | |
| Google Ads | $5k | | | | |
| Email | $0 | | | | |
| Organic | $0 | | | | |
| Webinar | $2k | | | | |
| **Total** | **$17k** | | | | |
### Post-Launch Report Template
```
LAUNCH: [Product/Feature Name]
DATE: [Launch Date]
OWNER: [PMM Name]
EXECUTIVE SUMMARY:
- Goal: $500k pipeline in 30 days
- Actual: $[X] pipeline (X% of goal)
- Status: ✅ On Track / ⚠️ Behind / ❌ Missed
KEY RESULTS:
| Metric | Goal | Actual | % of Goal |
|--------------|---------|---------|-----------|
| MQLs | 150 | | |
| SQLs | 30 | | |
| Pipeline | $500k | | |
| Feature Adoption | 40% | | |
TOP PERFORMING:
1. [Channel/Tactic] - [Result]
2. [Channel/Tactic] - [Result]
UNDERPERFORMING:
1. [Channel/Tactic] - [Result] - [Action taken]
LEARNINGS:
1. [What worked and why]
2. [What didn't work and why]
3. [What we'd do differently]
NEXT STEPS:
1. [Action item] - Owner - Due date
2. [Action item] - Owner - Due date
```
FILE:references/messaging-templates.md
# Messaging Templates
Ready-to-use messaging frameworks for different personas and contexts.
---
## Table of Contents
- [Value Proposition Templates](#value-proposition-templates)
- [Persona-Specific Messaging](#persona-specific-messaging)
- [Competitive Messaging](#competitive-messaging)
- [Channel-Specific Copy](#channel-specific-copy)
- [Objection Handling Scripts](#objection-handling-scripts)
---
## Value Proposition Templates
### One-Liner Formula
Template: `[Product] helps [Target Customer] [Achieve Goal] by [Unique Approach]`
**Examples:**
```
B2B SaaS:
"Acme helps mid-market SaaS teams ship 2x faster by automating
project workflows with AI."
Enterprise:
"Acme helps Fortune 500 companies reduce operational costs by 40%
through intelligent process automation."
SMB:
"Acme helps small businesses save 10 hours per week by automating
their daily tasks."
```
### Elevator Pitch (30 Seconds)
Template:
```
You know how [target customer] struggles with [pain point]?
[Product] is a [category] that [key differentiator].
Unlike [alternatives], we [unique value].
Our customers see [specific outcome] within [timeframe].
```
**Example:**
```
You know how engineering teams struggle with slow code reviews
that delay releases?
Acme is an AI code review platform that catches bugs before
they reach production.
Unlike manual reviews, we analyze every PR in under 2 minutes
with 95% accuracy.
Our customers ship 40% faster within their first month.
```
### Messaging Hierarchy
```
LEVEL 1: HEADLINE (5-7 words)
"Ship faster with AI-powered automation"
LEVEL 2: SUBHEAD (1 sentence)
"Acme automates your workflows so your team can focus on what matters."
LEVEL 3: KEY BENEFITS (3-4 bullets)
• Save 10+ hours per week on manual tasks
• Reduce errors by 80% with AI validation
• Deploy changes 3x faster with automated testing
• Scale operations without adding headcount
LEVEL 4: FEATURES → VALUE
• AI Automation → Eliminates repetitive work → Save $50k/year
• Real-time Sync → No version conflicts → 50% fewer errors
• Integrations → Connect existing tools → 2-hour setup
```
---
## Persona-Specific Messaging
### Economic Buyer (VP/Director/C-Level)
**Primary concerns:** ROI, business outcomes, risk mitigation
**Messaging principles:**
- Lead with business impact ($, %, time)
- Show ROI within 6-12 months
- Reference similar companies
- Address risk (security, implementation)
**Template:**
```
HEADLINE: [Business outcome] in [timeframe]
OPENING:
"[Role at similar company] was spending [hours/dollars] on [problem].
After implementing [Product], they achieved [specific result]."
KEY POINTS:
• [Metric] improvement in [area] (e.g., "40% reduction in manual work")
• ROI: [X]x return within [timeframe]
• Implementation: [timeframe] with [level] of effort
• Risk: [How you mitigate concerns]
CTA: "See how [similar company] achieved [result] →"
```
**Example email:**
```
Subject: How Stripe reduced deployment time by 60%
Hi [Name],
The VP of Engineering at a company similar to yours was spending
40 hours per week on code review bottlenecks.
After implementing Acme, they:
• Reduced review time by 60%
• Caught 3x more bugs before production
• Shipped new features 2 weeks faster
Would a 15-minute call to explore if similar results are possible
for [Company] make sense?
```
### Technical Buyer (Engineer/Architect)
**Primary concerns:** Technical fit, security, integration, vendor lock-in
**Messaging principles:**
- Lead with technical capabilities
- Show architecture and security details
- Demonstrate easy integration
- Provide technical documentation
**Template:**
```
HEADLINE: [Technical capability] for [their stack]
OPENING:
"Built for [their technology environment] with [key technical feature]."
KEY POINTS:
• Architecture: [how it works technically]
• Security: [certifications, compliance, encryption]
• Integration: [specific integrations with their tools]
• Performance: [benchmarks, latency, uptime]
CTA: "Read the technical whitepaper →" or "See the API docs →"
```
**Example:**
```
Subject: SOC 2 Type II compliant with 99.99% uptime
Hi [Name],
I noticed [Company] uses Kubernetes for container orchestration.
Acme integrates natively with K8s with:
• Single-line Helm chart deployment
• mTLS encryption for all traffic
• SOC 2 Type II + GDPR compliant
• 99.99% uptime SLA with $10k credit guarantee
Here's our architecture diagram: [link]
Worth a quick technical review?
```
### End User (Manager/Individual Contributor)
**Primary concerns:** Ease of use, daily workflow, learning curve
**Messaging principles:**
- Lead with time savings
- Show product in action (demo, screenshots)
- Emphasize simplicity
- Include peer testimonials
**Template:**
```
HEADLINE: [Daily benefit] in [time to value]
OPENING:
"Imagine [desired outcome] without [pain point]."
KEY POINTS:
• Get started in [timeframe] (no training required)
• Save [hours] every [timeframe]
• [Feature] makes [task] effortless
• Loved by [peer companies/roles]
CTA: "Try free for 14 days →"
```
**Example:**
```
Subject: Spend less time in meetings, more time building
Hi [Name],
What if your weekly status meetings could run themselves?
Acme automatically:
• Collects updates from your team (no nagging)
• Creates visual progress reports (no spreadsheets)
• Flags blockers before they become problems
Teams like [Company A] and [Company B] love it.
Start your free trial: [link]
```
---
## Competitive Messaging
### "Why Us vs. Competitor A" Framework
```
OPENING (acknowledge competition):
"Both [Product] and [Competitor A] help teams with [general category].
Here's what sets us apart:"
DIFFERENTIATORS (3-4 key points):
1. [Your advantage] vs. [Their limitation]
"Our AI catches 95% of bugs vs. their rule-based 60% coverage"
2. [Your advantage] vs. [Their limitation]
"Get started in 2 hours vs. their 2-week implementation"
3. [Your advantage] vs. [Their limitation]
"$50/user vs. their $150/user at scale"
PROOF POINT:
"[Customer] switched from [Competitor A] to us and saw [result]"
CTA:
"See a side-by-side comparison →"
```
### Competitive Positioning Statements
**When they're the market leader:**
```
"[Competitor] built the category, but it was designed for [old paradigm].
[Product] is purpose-built for [new reality] with [key differentiators]."
```
**When they're cheaper:**
```
"[Competitor] costs less upfront, but teams spend [X hours] working
around limitations. [Product] pays for itself in [timeframe] through
[specific efficiency gains]."
```
**When they have more features:**
```
"[Competitor] tries to do everything. [Product] focuses on doing
[core use case] exceptionally well. Our customers tell us they only
use 20% of [Competitor's] features anyway."
```
---
## Channel-Specific Copy
### Landing Page
**Above the fold:**
```
[HEADLINE - 5-7 words, benefit-focused]
Ship faster with AI-powered automation
[SUBHEAD - 1 sentence expanding on value]
Acme automates your workflows so your team can focus on what matters.
[CTA - Action-oriented]
Start Free Trial | Book Demo
```
**Social proof bar:**
```
Trusted by 5,000+ teams including [Logo] [Logo] [Logo] [Logo]
```
### Email Subject Lines
**High performers:**
- "How [Similar Company] achieved [result]"
- "[Name], quick question about [their challenge]"
- "Re: [topic they care about]" (for follow-ups)
- "[Specific number]% improvement in [metric]"
**Avoid:**
- "Quick sync?"
- "Following up..."
- "Just checking in"
- ALL CAPS or excessive punctuation!!!
### LinkedIn Ads
**Format: Single image or carousel**
```
HEADLINE (70 chars max):
"Cut code review time by 60%"
BODY (150 chars recommended):
"AI-powered code reviews that catch bugs before production.
Trusted by engineering teams at Stripe and Shopify.
Try free →"
CTA: Learn More / Try Free / Get Demo
```
### Google Ads
**Search ad format:**
```
Headline 1 (30 chars): AI Code Review Platform
Headline 2 (30 chars): Ship 40% Faster
Headline 3 (30 chars): Free 14-Day Trial
Description (90 chars):
Catch bugs before production. Trusted by 5,000+ teams.
Start your free trial today.
```
---
## Objection Handling Scripts
### Price Objection
**"It's too expensive"**
```
ACKNOWLEDGE: "I understand budget is a concern."
REFRAME: "Let me share how our customers think about it...
[Customer] was spending [X hours/dollars] on [problem] every month.
After implementing [Product], they saved [Y hours/dollars], paying
for the solution in [timeframe]."
QUESTION: "What would it be worth to your team to [achieve outcome]?"
ALTERNATIVE: "We also offer [smaller plan/annual discount] that might
work for your current budget. Would that help?"
```
### Competitor Objection
**"We're looking at [Competitor A] too"**
```
ACKNOWLEDGE: "That's smart to evaluate options. [Competitor A] is
a solid product."
DIFFERENTIATE: "The main differences customers tell us about:
1. [Your advantage] - [Competitor] doesn't offer this
2. [Your advantage] - Their approach is [different/older]
3. [Price/support/speed] - We're typically [X] better here"
PROOF: "[Customer] evaluated both and chose us because [reason]."
QUESTION: "What are the 2-3 things that matter most to you in
this decision?"
```
### Timing Objection
**"Not the right time"**
```
ACKNOWLEDGE: "I completely understand. Timing is everything."
EXPLORE: "Out of curiosity, what would need to change for this
to become a priority?"
FUTURE: "Would it make sense to schedule a brief call in [timeframe]
to revisit? I can share relevant updates without any pressure."
VALUE ADD: "In the meantime, I'll send over [relevant content] that
might be useful for when you're ready."
```
### Authority Objection
**"I need to check with my team/boss"**
```
ACKNOWLEDGE: "Of course, that makes sense."
SUPPORT: "What information would be most helpful for that conversation?
I can put together a one-pager with key points."
OFFER: "Would it help if I joined a brief call with [stakeholder]
to answer any technical/business questions directly?"
TIMELINE: "When do you think you'll have that conversation?
I can follow up with any additional materials beforehand."
```
### Technical Objection
**"Will this integrate with our stack?"**
```
ACKNOWLEDGE: "Great question - integration is critical."
CONFIRM: "What are the main tools you need to connect with?
[Listen and take notes]"
ANSWER: "We have native integrations with [tools]. For [tool],
we use [API/webhook/Zapier]. Here's our integration docs: [link]"
PROOF: "[Similar company] uses a similar stack and got integrated
in [timeframe]."
DEMO: "Want me to show you exactly how the integration works
in a quick demo?"
```
FILE:references/positioning-frameworks.md
# Positioning Frameworks
Strategic positioning methodologies for B2B SaaS products.
---
## Table of Contents
- [April Dunford Positioning](#april-dunford-positioning)
- [Geoffrey Moore Positioning](#geoffrey-moore-positioning)
- [Positioning Validation](#positioning-validation)
- [Competitive Positioning Map](#competitive-positioning-map)
---
## April Dunford Positioning
### The 5-Step Process
Execute positioning using April Dunford's "Obviously Awesome" methodology:
1. List competitive alternatives (what customers would use instead)
2. Isolate unique attributes (features only you have)
3. Map attributes to value (why each attribute matters)
4. Define best-fit customers (who cares most about this value)
5. Choose market category (where you compete)
6. **Validation:** Best-fit customers articulate your value unprompted
### Step 1: Competitive Alternatives
Document what customers do without your product:
| Alternative Type | Examples | How They Solve It |
|------------------|----------|-------------------|
| Direct competitor | Competitor A, B | Same category, different approach |
| Adjacent solution | Spreadsheets, email | Manual workaround |
| Build in-house | Custom development | Internal solution |
| Do nothing | Ignore problem | Accept status quo |
**Interview Questions:**
- "Before using us, how did you handle this?"
- "What alternatives did you evaluate?"
- "What would you switch to if we disappeared?"
### Step 2: Unique Attributes
Identify capabilities competitors lack:
```
Attribute Audit:
1. Feature: [Real-time collaboration]
- Competitor A: No (async only)
- Competitor B: Partial (limited to 5 users)
- You: Yes (unlimited users, 50ms sync)
→ Unique: Yes
2. Feature: [AI automation]
- Competitor A: No
- Competitor B: No
- You: Yes (3 AI models)
→ Unique: Yes
3. Feature: [Integrations]
- Competitor A: 500+
- Competitor B: 200+
- You: 100
→ Unique: No (table stakes)
```
### Step 3: Attribute-Value Mapping
Connect features to business outcomes:
| Attribute | Value Enabled | Customer Outcome |
|-----------|--------------|------------------|
| Real-time sync | No version conflicts | 50% fewer errors |
| AI automation | Eliminates manual work | Save 10 hrs/week |
| One-click deploy | Faster releases | Ship 2x faster |
**Value Statement Formula:**
`[Feature] enables [Value] so customers achieve [Outcome]`
### Step 4: Best-Fit Customers
Define who values your unique attributes most:
```
Best-Fit Profile:
- Company size: 200-2000 employees
- Industry: SaaS, Professional Services
- Pain: Distributed teams, collaboration bottlenecks
- Evidence:
- Fastest sales cycles (45 days vs. 75 avg)
- Lowest churn (3% vs. 8% avg)
- Highest NPS (65 vs. 45 avg)
```
### Step 5: Market Category
Choose competitive frame:
| Strategy | When to Use | Risk Level |
|----------|-------------|------------|
| Head-to-head | Strong product, big budget | Medium |
| Niche domination | Unique for segment | Low |
| Category creation | True innovation, deep pockets | High |
**Decision Framework:**
- Can you win head-to-head? → Head-to-head
- Can you dominate a niche? → Niche
- Is the market undefined? → Category creation
---
## Geoffrey Moore Positioning
### Crossing the Chasm Framework
Position for technology adoption lifecycle:
```
Technology Adoption Curve:
Innovators (2.5%) → Early Adopters (13.5%) → Early Majority (34%)
↑
THE CHASM
```
### Positioning Statement Template
```
FOR [target customer]
WHO [statement of need or opportunity]
THE [product name] IS A [product category]
THAT [key benefit/reason to buy]
UNLIKE [primary competitive alternative]
OUR PRODUCT [primary differentiation]
```
**Example:**
```
FOR mid-market SaaS companies with distributed engineering teams
WHO struggle with coordination across time zones
THE Acme Platform IS A real-time collaboration workspace
THAT eliminates version conflicts and communication delays
UNLIKE Slack and email which create information silos
OUR PRODUCT provides unified project context with AI-powered summaries
```
### Whole Product Concept
Define complete solution for target segment:
| Layer | Components | Your Coverage |
|-------|------------|---------------|
| Generic | Core product | 100% |
| Expected | Basic integrations, support | 90% |
| Augmented | Training, consulting, custom work | 60% |
| Potential | Future roadmap, ecosystem | 30% |
**Gap Analysis:**
- What's missing for complete solution?
- Which partners can fill gaps?
- What must you build vs. buy vs. partner?
---
## Positioning Validation
### Customer Interview Protocol
Validate positioning with target customers:
1. Schedule 15-20 minute calls with 10+ target customers
2. Ask open-ended questions (no leading)
3. Document exact language used
4. Look for patterns across interviews
5. **Validation:** 7+ of 10 describe value similarly
**Interview Script:**
```
Opening (2 min):
"Thanks for your time. I want to understand how you think about
[product category] and your experience with our product."
Questions (10 min):
1. "How would you describe [Product] to a colleague?"
2. "What problem does [Product] solve for you?"
3. "What alternatives did you consider?"
4. "Why did you choose us over [alternative]?"
5. "What would make you stop using us?"
Closing (3 min):
"Is there anything else you'd like to share?"
```
### Quantitative Validation
Test messaging through A/B experiments:
| Test | Control | Variant | Winner Criteria |
|------|---------|---------|-----------------|
| Landing page headline | Old positioning | New positioning | +20% conversion |
| Ad copy | Feature-focused | Value-focused | +15% CTR |
| Email subject | Generic | Personalized | +25% open rate |
**Sample Size Calculator:**
- Baseline conversion: 3%
- Minimum detectable effect: 20% relative lift
- Statistical power: 80%
- Required sample: ~2,500 per variant
---
## Competitive Positioning Map
### 2x2 Matrix Construction
Create visual positioning map:
```
HIGH PRICE
│
Enterprise │ Premium
(Salesforce) │ (You?)
│
────────────────────┼──────────────────
LOW │ HIGH
EASE OF USE │ EASE OF USE
│
Legacy │ Self-Serve
(Oracle) │ (Notion)
│
LOW PRICE
```
### Axis Selection
Choose dimensions that highlight your advantage:
| Good Axes | Why |
|-----------|-----|
| Ease of use vs. Power | If you're easiest to use |
| Speed vs. Accuracy | If you're fastest |
| Price vs. Features | If you're best value |
| Specialization vs. Breadth | If you own a niche |
| Bad Axes | Why |
|----------|-----|
| Quality vs. Price | Everyone claims quality |
| Innovation vs. Stability | Subjective, hard to prove |
| Customer vs. Product focus | Not differentiating |
### Positioning Map Template
```
Market Category: [Your Category]
Date: [Month Year]
Axes:
- X-axis: [Dimension 1] (Low → High)
- Y-axis: [Dimension 2] (Low → High)
Quadrants:
- Top-left: [Quadrant description]
- Top-right: [Quadrant description] ← Your target
- Bottom-left: [Quadrant description]
- Bottom-right: [Quadrant description]
Competitors:
1. [Competitor A]: Position (X, Y), Why
2. [Competitor B]: Position (X, Y), Why
3. [You]: Position (X, Y), Why you win
Strategic Implications:
- Attack: [How to position against Competitor A]
- Defend: [How to protect against Competitor B]
- Differentiate: [Your unique positioning claim]
```
Lấy đồng thuận từ nhiều mô hình AI (Claude, Codex, Gemini) khi rà soát bản ghi nhớ hội đồng hoặc tài liệu chiến lược.
---
name: "cross-eval"
description: "/cs:cross-eval <memo> — Multi-model consensus on a board memo or strategy brief. Claude + Codex + Gemini cross-review with graceful degradation."
---
# /cs:cross-eval — Multi-Model Consensus
**Command:** `/cs:cross-eval <memo-or-brief>`
Runs the same memo through multiple model providers and reconciles divergences. Use for **high-stakes, irreversible decisions** where single-model bias is too costly: M&A, major fundraises, layoffs, strategic pivots, regulatory commitments.
Adapted from gstack's `/codex` cross-review pattern, generalized to **business memos** instead of code PRs.
## When to Run
- Before signing a term sheet
- Before announcing a layoff
- Before committing to a regulated market
- Before any decision where reversing costs > 6 months of company time
- When the boardroom vote was split or had a CRITICAL dissent
## Models Used (graceful degradation)
The command tries to invoke each available model in order:
1. **Claude** (primary, always available) — the boardroom's native voice
2. **Codex / OpenAI** (if `OPENAI_API_KEY` or `codex` CLI available)
3. **Gemini** (if `GEMINI_API_KEY` or `gemini` CLI available)
If only Claude is available, the command runs **Claude-only with adversarial mode** — same model, different prompt seeds — and clearly labels the output as single-model.
## Workflow
1. Read the memo / brief
2. Probe environment for available model CLIs / API keys
3. For each available model:
- Send the memo with this prompt prefix:
> "You are an independent C-suite reviewer. The following is a board memo from another company's boardroom. Identify the top 3 concerns, the top 3 supports, and your vote (APPROVE / REJECT / DEFER). Do not deferentially agree — assume the memo's reasoning is flawed until proven otherwise."
4. Collect three independent reviews
5. Reconcile: where do they agree? Where do they diverge?
6. Surface the divergences as questions for the founder
## Output Format
Saved to `~/.claude/cross-eval/YYYY-MM-DD-<slug>.md`:
```markdown
# Cross-Eval: <memo title>
**Date:** YYYY-MM-DD
**Memo reviewed:** <link>
**Models invoked:** Claude / Codex / Gemini (or noted fallbacks)
## Vote Tally
| Model | Vote | Confidence |
|---|---|---|
| Claude | APPROVE | High |
| Codex | DEFER | Med |
| Gemini | APPROVE | Low |
## Consensus Concerns (≥2 models flagged)
1. <concern> — flagged by Claude + Codex
2. <concern> — flagged by all 3
## Divergent Concerns (1 model flagged)
- <Codex only:> <concern> — worth a second look
- <Gemini only:> <concern> — likely noise, but check
## Consensus Supports (≥2 models endorsed)
1. <support>
2. <support>
## Recommendation
- 🟢 GO if 2+ models APPROVE and no CRITICAL concerns from any model
- 🟡 PAUSE if any model is DEFER or any concern is CRITICAL
- 🔴 STOP if 2+ models REJECT
## Open Questions for Founder
1. <question raised by divergence>
2. <question raised by divergence>
```
## Why This Matters
Single-model recommendations have systematic biases. Claude trends helpful and may under-weight risk. Codex (OpenAI) trends more cautious on emerging-market and regulatory topics. Gemini trends more cautious on technical scale claims. Disagreement is signal, not noise.
This is the **safety net before irreversibility** — not a replacement for outside counsel or a real board.
## Graceful Degradation
If only Claude is available:
```markdown
**Models available:** Claude only
**Mode:** ADVERSARIAL — running 3 independent Claude passes with different system prompts:
1. Standard reviewer
2. Devil's advocate (must find 3 critical concerns)
3. Steelman (must find 3 strongest reasons to approve)
This is weaker than true multi-model. Treat the result as suggestive, not conclusive.
```
## Routing
- `/cs:decide` — if consensus is GO
- `/cs:freeze` — if consensus is PAUSE
- `/cs:boardroom` (re-run) — if consensus is STOP
## Related
- Skills: [`board-meeting`](../../../skills/board-meeting/SKILL.md), [`executive-mentor`](../../../executive-mentor/)
- Inspiration: gstack's `/codex` cross-review pattern (adapted to business memos)
---
**Version:** 1.0.0
Hỗ trợ vận hành doanh thu, quản lý vòng đời lead, chấm điểm, phân luồng lead và quy trình bàn giao từ marketing sang bán hàng.
---
name: revops
description: "When the user wants help with revenue operations, lead lifecycle management, or marketing-to-sales handoff processes. Also use when the user mentions 'RevOps,' 'revenue operations,' 'lead scoring,' 'lead routing,' 'MQL,' 'SQL,' 'pipeline stages,' 'deal desk,' 'CRM automation,' 'marketing-to-sales handoff,' 'data hygiene,' 'leads aren't getting to sales,' 'pipeline management,' 'lead qualification,' or 'when should marketing hand off to sales.' Use this for anything involving the systems and processes that connect marketing to revenue. For cold outreach emails, see cold-email. For email drip campaigns, see emails. For pricing decisions, see pricing."
metadata:
version: 2.0.0
---
# RevOps
You are an expert in revenue operations. Your goal is to help design and optimize the systems that connect marketing, sales, and customer success into a unified revenue engine.
## Before Starting
**Check for product marketing context first:**
If `.agents/product-marketing.md` exists (or `.claude/product-marketing.md`, or the legacy `product-marketing-context.md` filename, in older setups), read it before asking questions. Use that context and only ask for information not already covered or specific to this task.
Gather this context (ask if not provided):
1. **GTM motion** — Product-led (PLG), sales-led, or hybrid?
2. **ACV range** — What's the average contract value?
3. **Sales cycle length** — Days from first touch to closed-won?
4. **Current stack** — CRM, marketing automation, scheduling, enrichment tools?
5. **Current state** — How are leads managed today? What's working and what's not?
6. **Goals** — Increase conversion? Reduce speed-to-lead? Fix handoff leaks? Build from scratch?
Work with whatever the user gives you. If they have a clear problem area, start there. Don't block on missing inputs — use what you have and note what would strengthen the solution.
---
## Core Principles
### Single Source of Truth
One system of record for every lead and account. If data lives in multiple places, it will conflict. Pick a CRM as the canonical source and sync everything to it.
### Define Before Automate
Get stage definitions, scoring criteria, and routing rules right on paper before building workflows. Automating a broken process just creates broken results faster.
### Measure Every Handoff
Every handoff between teams is a potential leak. Marketing-to-sales, SDR-to-AE, AE-to-CS — each needs an SLA, a tracking mechanism, and someone accountable for follow-through.
### Revenue Team Alignment
Marketing, sales, and customer success must agree on definitions. If marketing calls something an MQL but sales won't work it, the definition is wrong. Alignment meetings aren't optional.
---
## Lead Lifecycle Framework
### Stage Definitions
| Stage | Entry Criteria | Exit Criteria | Owner |
|-------|---------------|---------------|-------|
| **Subscriber** | Opts in to content (blog, newsletter) | Provides company info or shows engagement | Marketing |
| **Lead** | Identified contact with basic info | Meets minimum fit criteria | Marketing |
| **MQL** | Passes fit + engagement threshold | Sales accepts or rejects within SLA | Marketing |
| **SQL** | Sales accepts and qualifies via conversation | Opportunity created or recycled | Sales (SDR/AE) |
| **Opportunity** | Budget, authority, need, timeline confirmed | Closed-won or closed-lost | Sales (AE) |
| **Customer** | Closed-won deal | Expands, renews, or churns | CS / Account Mgmt |
| **Evangelist** | High NPS, referral activity, case study | Ongoing program participation | CS / Marketing |
### MQL Definition
An MQL requires both **fit** and **engagement**:
- **Fit score** — Does this person match your ICP? (company size, industry, role, tech stack)
- **Engagement score** — Have they shown buying intent? (pricing page, demo request, multiple visits)
Neither alone is sufficient. A perfect-fit company that never engages isn't an MQL. A student downloading every ebook isn't an MQL.
### MQL-to-SQL Handoff SLA
Define response times and document them:
- MQL alert sent to assigned rep
- Rep contacts within **4 hours** (business hours)
- Rep qualifies or rejects within **48 hours**
- Rejected MQLs go to recycling nurture with reason code
**For complete lifecycle stage templates and SLA examples**: See [references/lifecycle-definitions.md](references/lifecycle-definitions.md)
---
## Lead Scoring
### Scoring Dimensions
**Explicit scoring (fit)** — Who they are:
- Company size, industry, revenue
- Job title, seniority, department
- Tech stack, geography
**Implicit scoring (engagement)** — What they do:
- Page visits (especially pricing, demo, case studies)
- Content downloads, webinar attendance
- Email engagement (opens, clicks)
- Product usage (for PLG)
**Negative scoring** — Disqualifying signals:
- Competitor email domains
- Student/personal email
- Unsubscribes, spam complaints
- Job title mismatches (intern, student)
### Building a Scoring Model
1. Define your ICP attributes and weight them
2. Identify high-intent behavioral signals from closed-won data
3. Set point values for each attribute and behavior
4. Set MQL threshold (typically 50-80 points on a 100-point scale)
5. Test against historical data — does the model correctly identify past wins?
6. Launch, measure, and recalibrate quarterly
### Common Scoring Mistakes
- Weighting content downloads too heavily (research ≠ buying intent)
- Not including negative scoring (lets bad leads through)
- Setting and forgetting (buyer behavior changes; recalibrate quarterly)
- Scoring all page visits equally (pricing page ≠ blog post)
**For detailed scoring templates and example models**: See [references/scoring-models.md](references/scoring-models.md)
---
## Lead Routing
### Routing Methods
| Method | How It Works | Best For |
|--------|-------------|----------|
| **Round-robin** | Distribute evenly across reps | Equal territories, similar deal sizes |
| **Territory-based** | Assign by geography, vertical, or segment | Regional teams, industry specialists |
| **Account-based** | Named accounts go to named reps | ABM motions, strategic accounts |
| **Skill-based** | Route by deal complexity, product line, or language | Diverse product lines, global teams |
### Routing Rules Essentials
- Route to the **most specific match** first, then fall back to general
- Include a **fallback owner** — unassigned leads go cold fast and waste pipeline
- Round-robin should account for **rep capacity and availability** (PTO, quota attainment)
- Log every routing decision for audit and optimization
### Speed-to-Lead
Response time is the single biggest factor in lead conversion:
- Contact within **5 minutes** = 21x more likely to qualify (Lead Connect)
- After **30 minutes**, conversion drops by 10x
- After **24 hours**, the lead is effectively cold
Build routing rules that prioritize speed. Alert reps immediately. Escalate if SLA is missed.
**For routing decision trees and platform-specific setup**: See [references/routing-rules.md](references/routing-rules.md)
---
## Pipeline Stage Management
### Pipeline Stages
| Stage | Required Fields | Exit Criteria |
|-------|----------------|---------------|
| **Qualified** | Contact info, company, source, fit score | Discovery call scheduled |
| **Discovery** | Pain points, current solution, timeline | Needs confirmed, demo scheduled |
| **Demo/Evaluation** | Technical requirements, decision makers | Positive evaluation, proposal requested |
| **Proposal** | Pricing, terms, stakeholder map | Proposal delivered and reviewed |
| **Negotiation** | Redlines, approval chain, close date | Terms agreed, contract sent |
| **Closed Won** | Signed contract, payment terms | Handoff to CS complete |
| **Closed Lost** | Loss reason, competitor (if any) | Post-mortem logged |
### Stage Hygiene
- **Required fields per stage** — Don't let reps advance a deal without filling in required data
- **Stale deal alerts** — Flag deals that sit in a stage beyond the average time (e.g., 2x average days)
- **Stage skip detection** — Alert when deals jump stages (Qualified → Proposal skipping Discovery)
- **Close date discipline** — Push dates must include a reason; no silent pushes
### Pipeline Metrics
| Metric | What It Tells You |
|--------|-------------------|
| Stage conversion rates | Where deals die |
| Average time in stage | Where deals stall |
| Pipeline velocity | Revenue per day through the funnel |
| Coverage ratio | Pipeline value vs. quota (target 3-4x) |
| Win rate by source | Which channels produce real revenue |
---
## CRM Automation Workflows
### Essential Automations
- **Lifecycle stage updates** — Auto-advance stages when criteria are met
- **Task creation on handoff** — Create follow-up task when MQL assigned to rep
- **SLA alerts** — Notify manager if rep misses response time SLA
- **Deal stage triggers** — Auto-send proposals, update forecasts, notify CS on close
### Marketing-to-Sales Automations
- **MQL alert** — Instant notification to assigned rep with lead context
- **Meeting booked** — Notify AE when prospect books via scheduling tool
- **Lead activity digest** — Daily summary of high-intent actions by active leads
- **Re-engagement trigger** — Alert sales when a dormant lead returns to site
### Calendar Scheduling Integration
- **Round-robin scheduling** — Distribute meetings evenly across team
- **Routing by criteria** — Send enterprise leads to senior AEs, SMB to junior reps
- **Pre-meeting enrichment** — Auto-populate CRM record before the call
- **No-show workflows** — Auto-follow-up if prospect misses meeting
**For platform-specific workflow recipes**: See [references/automation-playbooks.md](references/automation-playbooks.md)
---
## Deal Desk Processes
### When You Need a Deal Desk
- ACV above **$25K** (or your threshold for non-standard deals)
- Non-standard payment terms (net-90, quarterly billing)
- Multi-year contracts with custom pricing
- Volume discounts beyond published tiers
- Custom legal terms or SLAs
### Approval Workflow Tiers
| Deal Size | Approval Required |
|-----------|-------------------|
| Standard pricing | Auto-approved |
| 10-20% discount | Sales manager |
| 20-40% discount | VP Sales |
| 40%+ discount or custom terms | Deal desk review |
| Multi-year / enterprise | Finance + Legal |
### Non-Standard Terms Handling
Document every exception. Track which non-standard terms get requested most — if everyone asks for the same exception, it should become standard. Review quarterly.
---
## Data Hygiene & Enrichment
### Dedup Strategy
- **Matching rules** — Email domain + company name + phone as primary match keys
- **Merge priority** — CRM record wins over marketing automation; most recent activity wins for fields
- **Scheduled dedup** — Run weekly automated dedup with manual review for edge cases
### Required Fields Enforcement
- Enforce required fields at each lifecycle stage
- Block stage advancement if fields are empty
- Use progressive profiling — don't require everything upfront
### Enrichment Tools
| Tool | Strength |
|------|----------|
| Clearbit | Real-time enrichment, good for tech companies |
| Apollo | Contact data + sequences, strong for prospecting |
| ZoomInfo | Enterprise-grade, largest B2B database |
### Quarterly Audit Checklist
- Review and merge duplicates
- Validate email deliverability on stale contacts
- Archive contacts with no activity in 12+ months
- Audit lifecycle stage distribution (look for bottlenecks)
- Verify enrichment data accuracy on a sample set
---
## RevOps Metrics Dashboard
### Key Metrics
| Metric | Formula / Definition | Benchmark |
|--------|---------------------|-----------|
| Lead-to-MQL rate | MQLs / Total leads | 5-15% |
| MQL-to-SQL rate | SQLs / MQLs | 30-50% |
| SQL-to-Opportunity | Opportunities / SQLs | 50-70% |
| Pipeline velocity | (# deals x avg deal size x win rate) / avg sales cycle | Varies by ACV |
| CAC | Total sales + marketing spend / new customers | LTV:CAC > 3:1 |
| LTV:CAC ratio | Customer lifetime value / CAC | 3:1 to 5:1 healthy |
| Speed-to-lead | Time from form fill to first rep contact | < 5 minutes ideal |
| Win rate | Closed-won / total opportunities | 20-30% (varies) |
### Dashboard Structure
Build three views:
1. **Marketing view** — Lead volume, MQL rate, source attribution, cost per MQL
2. **Sales view** — Pipeline value, stage conversion, velocity, forecast accuracy
3. **Executive view** — CAC, LTV:CAC, revenue vs. target, pipeline coverage
---
## Output Format
When delivering RevOps recommendations, provide:
1. **Lifecycle stage document** — Stage definitions with entry/exit criteria, owners, and SLAs
2. **Scoring specification** — Fit and engagement attributes with point values and MQL threshold
3. **Routing rules document** — Decision tree with assignment logic and fallbacks
4. **Pipeline configuration** — Stage definitions, required fields, and automation triggers
5. **Metrics dashboard spec** — Key metrics, data sources, and target benchmarks
Format each as a standalone document the user can implement directly. Include platform-specific guidance when the CRM is known.
---
## Task-Specific Questions
1. What CRM platform are you using (or planning to use)?
2. How many leads per month do you generate?
3. What's your current MQL definition?
4. Where do leads get stuck in your funnel?
5. Do you have SLAs between marketing and sales today?
---
## Tool Integrations
For implementation, see the [tools registry](../../tools/REGISTRY.md). Key RevOps tools:
| Tool | What It Does | Guide |
|------|-------------|-------|
| **HubSpot** | CRM, marketing automation, lead scoring, workflows | [hubspot.md](../../tools/integrations/hubspot.md) |
| **Salesforce** | Enterprise CRM, pipeline management, reporting | [salesforce.md](../../tools/integrations/salesforce.md) |
| **Calendly** | Meeting scheduling, round-robin routing | [calendly.md](../../tools/integrations/calendly.md) |
| **SavvyCal** | Scheduling with priority-based availability | [savvycal.md](../../tools/integrations/savvycal.md) |
| **Clearbit** | Real-time lead enrichment and scoring | [clearbit.md](../../tools/integrations/clearbit.md) |
| **Apollo** | Contact data, enrichment, and outbound sequences | [apollo.md](../../tools/integrations/apollo.md) |
| **ActiveCampaign** | Marketing automation for SMBs, lead scoring | [activecampaign.md](../../tools/integrations/activecampaign.md) |
| **Zapier** | Cross-tool automation and workflow glue | [zapier.md](../../tools/integrations/zapier.md) |
| **Introw** | Partner-sourced pipeline, commissions, deal registration, QBRs | [introw.md](../../tools/integrations/introw.md) |
| **Crossbeam** | Partner account overlaps and co-sell identification | [crossbeam.md](../../tools/integrations/crossbeam.md) |
---
## Related Skills
- **cold-email**: For outbound prospecting emails
- **emails**: For lifecycle and nurture email flows
- **pricing**: For pricing decisions and packaging
- **analytics**: For tracking pipeline metrics and attribution
- **launch**: For go-to-market launch planning
- **sales-enablement**: For sales collateral, decks, and objection handling
FILE:evals/evals.json
{
"skill_name": "revops",
"evals": [
{
"id": 1,
"prompt": "Help me set up our lead lifecycle stages. We're a B2B SaaS company selling to mid-market. We use HubSpot as our CRM and have marketing and sales teams that aren't aligned on lead definitions.",
"expected_output": "Should check for product-marketing.md first. Should apply the lead lifecycle framework: Subscriber → Lead → MQL → SQL → Opportunity → Customer → Evangelist. Should define clear criteria for each stage transition (what makes a Lead become an MQL, etc.). Should address the alignment issue between marketing and sales — define shared definitions and SLAs. Should recommend CRM implementation steps for HubSpot. Should include lead scoring setup. Should provide a handoff process between marketing and sales.",
"assertions": [
"Checks for product-marketing.md",
"Applies lead lifecycle framework with all stages",
"Defines criteria for each stage transition",
"Addresses marketing-sales alignment",
"Provides CRM implementation guidance for HubSpot",
"Includes lead scoring setup",
"Provides handoff process between teams"
],
"files": []
},
{
"id": 2,
"prompt": "Set up lead scoring for us. We want to prioritize which leads sales should call first. We sell enterprise software ($50k+ ACV).",
"expected_output": "Should apply the lead scoring framework with three dimensions: explicit scoring (firmographics — company size, industry, title match), implicit scoring (behavioral — page visits, content downloads, email engagement), and negative scoring (unsubscribes, competitor emails, student emails). Should provide specific scoring criteria appropriate for enterprise ($50k+ ACV): weight firmographic signals heavily, include budget and authority signals. Should define score thresholds for MQL and SQL. Should recommend lead routing based on scores.",
"assertions": [
"Applies lead scoring with explicit, implicit, and negative dimensions",
"Provides specific scoring criteria for enterprise",
"Weights firmographic signals appropriately",
"Includes behavioral scoring signals",
"Includes negative scoring signals",
"Defines MQL and SQL score thresholds",
"Recommends lead routing based on scores"
],
"files": []
},
{
"id": 3,
"prompt": "our pipeline is a mess. deals sit in stages forever and we don't know what's actually going to close. how do we fix this?",
"expected_output": "Should trigger on casual phrasing. Should apply the pipeline stage management guidance. Should recommend: define clear pipeline stages with entry/exit criteria, set maximum time in each stage, implement stage velocity tracking, add required fields per stage to force data entry. Should address deal hygiene: regular pipeline reviews, stale deal flagging, win/loss analysis. Should recommend CRM automation to enforce stage rules. Should provide a practical cleanup plan for the current mess.",
"assertions": [
"Triggers on casual phrasing",
"Applies pipeline stage management",
"Defines stages with entry/exit criteria",
"Recommends maximum time per stage",
"Addresses deal hygiene and pipeline reviews",
"Recommends CRM automation for enforcement",
"Provides practical cleanup plan"
],
"files": []
},
{
"id": 4,
"prompt": "What RevOps metrics should we be tracking? We want to build a dashboard for our leadership team.",
"expected_output": "Should apply the RevOps metrics dashboard framework. Should recommend metrics across the funnel: lead volume by source, MQL-to-SQL conversion rate, SQL-to-Opportunity rate, win rate, average deal size, sales cycle length, pipeline velocity, pipeline coverage ratio, CAC, LTV, LTV:CAC ratio. Should organize metrics by audience (marketing team, sales team, leadership). Should recommend dashboard structure and cadence for reviews.",
"assertions": [
"Applies RevOps metrics dashboard",
"Covers full-funnel metrics",
"Includes conversion rates between stages",
"Includes pipeline velocity and coverage",
"Includes CAC, LTV, LTV:CAC",
"Organizes by audience",
"Recommends dashboard structure and review cadence"
],
"files": []
},
{
"id": 5,
"prompt": "Our CRM data is a disaster. Duplicate records, missing fields, inconsistent naming. How do we clean it up and keep it clean?",
"expected_output": "Should apply the data hygiene guidance. Should recommend: duplicate detection and merging strategy, required field enforcement, standardized naming conventions (picklists over free text), data validation rules, regular audit cadence. Should address both cleanup (one-time fix) and prevention (ongoing processes). Should recommend CRM automation for data hygiene. Should provide a prioritized cleanup plan (start with highest-impact data quality issues).",
"assertions": [
"Applies data hygiene guidance",
"Recommends duplicate detection and merging",
"Recommends required field enforcement",
"Addresses standardized naming conventions",
"Covers both cleanup and prevention",
"Recommends CRM automation for hygiene",
"Provides prioritized cleanup plan"
],
"files": []
},
{
"id": 6,
"prompt": "Can you help me write cold outreach emails to prospects in our pipeline?",
"expected_output": "Should recognize this is a cold email / outbound writing task, not RevOps. Should defer to or cross-reference the cold-email skill for writing outbound prospecting emails. RevOps covers the systems, processes, and data infrastructure — not the actual email content.",
"assertions": [
"Recognizes this as cold email writing, not RevOps",
"References or defers to cold-email skill",
"Explains RevOps covers systems and processes, not email content"
],
"files": []
}
]
}
FILE:references/automation-playbooks.md
# Automation Playbooks
Platform-specific workflow recipes for HubSpot, Salesforce, scheduling tools, and cross-tool automation.
## HubSpot Workflow Recipes
### 1. MQL Alert and Assignment
**Name:** MQL Notification and Task Creation
**Trigger:** Contact property "Lifecycle Stage" is changed to "Marketing Qualified Lead"
**Actions:**
1. Rotate contact owner among sales team (round-robin)
2. Send internal email notification to contact owner with lead context
3. Create task: "Follow up with [Contact Name]" — due in 4 hours
4. Send Slack notification to #sales-alerts channel
5. Enroll in "MQL Follow-Up" sequence (if using HubSpot Sequences)
**Outcome:** Every MQL gets assigned instantly with a clear SLA
**Notes:** Set enrollment criteria to exclude leads already owned by a rep
---
### 2. MQL SLA Escalation
**Name:** MQL SLA Breach Alert
**Trigger:** Contact property "Lifecycle Stage" equals "MQL" AND "Days since last contacted" is greater than 0.5 (12 hours)
**Actions:**
1. Send internal email to contact owner: "SLA warning: [Contact Name] has not been contacted"
2. If still no activity after 24 hours → send alert to sales manager
3. If still no activity after 48 hours → reassign contact owner via rotation
4. Create task for new owner: "Urgent: Contact [Contact Name] — reassigned due to SLA breach"
**Outcome:** No MQL goes unworked for more than 48 hours
**Notes:** Exclude contacts where last activity type is "Call" or "Meeting" (already engaged)
---
### 3. Lead Scoring Update and MQL Promotion
**Name:** Auto-MQL on Score Threshold
**Trigger:** Contact property "HubSpot Score" is greater than or equal to 65
**Actions:**
1. Set lifecycle stage to "Marketing Qualified Lead"
2. Set "MQL Date" to current date
3. Suppress from marketing nurture workflows
4. Trigger MQL Alert workflow (recipe #1)
**Outcome:** Leads automatically promote to MQL when they hit the scoring threshold
**Notes:** Add suppression list for existing customers and competitors
---
### 4. Meeting Booked Notification
**Name:** Meeting Booked Alert to AE
**Trigger:** Meeting activity is logged for contact (via Calendly/HubSpot meetings)
**Actions:**
1. Send internal email to contact owner with meeting details
2. Update contact property "Last Meeting Booked" to current date
3. If lifecycle stage is "Lead" → update to "MQL"
4. Create task: "Prepare for meeting with [Contact Name]" — due 1 hour before meeting
5. Send Slack notification to #meetings channel
**Outcome:** AEs are prepared for every meeting with full context
**Notes:** Include recent page views and content downloads in notification email
---
### 5. Closed-Won Handoff to CS
**Name:** Customer Onboarding Trigger
**Trigger:** Deal stage is changed to "Closed Won"
**Actions:**
1. Update associated contact lifecycle stage to "Customer"
2. Set "Customer Since" date to current date
3. Assign contact owner to CS team member (based on segment/territory)
4. Create task for CS: "Schedule kickoff call with [Company Name]" — due in 2 business days
5. Enroll contact in "Customer Onboarding" email sequence
6. Send internal notification to CS manager
7. Remove from all sales sequences
**Outcome:** Seamless handoff from sales to customer success
**Notes:** Include deal notes, contract value, and key stakeholders in CS notification
---
### 6. Stale Deal Alert
**Name:** Pipeline Hygiene — Stale Deal Detection
**Trigger:** Deal property "Days in current stage" is greater than [2x average for that stage]
**Actions:**
1. Send internal email to deal owner: "Deal stale alert: [Deal Name] has been in [Stage] for [X] days"
2. Create task: "Update or close [Deal Name]" — due in 3 business days
3. If no update after 7 days → alert sales manager
4. Add to "Stale Deals" dashboard list
**Outcome:** Pipeline stays clean and forecast stays accurate
**Notes:** Customize thresholds per stage (Discovery: 14 days, Proposal: 10 days, Negotiation: 21 days)
---
### 7. Recycled Lead Nurture Re-Entry
**Name:** MQL Recycling to Nurture
**Trigger:** Contact property "Sales Rejection Reason" is known (any value)
**Actions:**
1. Update lifecycle stage to "Recycled"
2. Reset engagement score to baseline (keep fit score)
3. Enroll in "Recycled Lead Nurture" sequence (lower frequency)
4. Set "Recycle Date" to current date
5. Set re-enrollment trigger: if HubSpot Score exceeds threshold again, re-trigger MQL workflow
**Outcome:** Rejected leads get a second chance without clogging the pipeline
**Notes:** Track recycled-to-MQL conversion rate as a separate metric
---
### 8. Lead Activity Digest
**Name:** Daily Lead Activity Summary
**Trigger:** Scheduled — daily at 8:00 AM local time
**Actions:**
1. Filter contacts: lifecycle stage is "SQL" or "Opportunity" AND had website activity in last 24 hours
2. Send digest email to each contact owner with their leads' activity
3. Include: pages visited, content downloaded, emails opened/clicked
**Outcome:** Sales reps start each day knowing which leads are active
**Notes:** Only include leads with meaningful activity (exclude single homepage visits)
---
## Salesforce Flow Equivalents
### 1. MQL Alert and Assignment (Salesforce Flow)
**Type:** Record-Triggered Flow
**Object:** Lead
**Trigger:** Lead field "Status" is changed to "MQL"
**Flow steps:**
1. Get Records: Query "Rep Assignment" custom object for next available rep
2. Update Records: Set Lead Owner to assigned rep
3. Create Records: Create Task — "Contact MQL: {Lead.Name}" with due date = NOW + 4 hours
4. Action: Send email alert to new lead owner
5. Update Records: Update "Rep Assignment" last-assigned timestamp
**Notes:** Use a custom "Rep Assignment" object to manage round-robin state
### 2. SLA Escalation (Salesforce Flow)
**Type:** Scheduled-Triggered Flow
**Schedule:** Every 4 hours during business hours
**Flow steps:**
1. Get Records: Leads where Status = "MQL" AND LastActivityDate < TODAY - 1
2. Decision: Is lead older than 48 hours with no activity?
- YES → Reassign to next rep, create urgent task, alert manager
- NO → Send reminder email to current owner
**Notes:** Pair with Process Builder for real-time alerts on initial assignment
### 3. Pipeline Stage Automation (Salesforce Flow)
**Type:** Record-Triggered Flow
**Object:** Opportunity
**Trigger:** Stage field is updated
**Flow steps:**
1. Decision: Which stage was it changed to?
2. For each stage:
- **Discovery:** Create task "Complete discovery questionnaire"
- **Demo:** Create task "Prepare demo environment"
- **Proposal:** Create task "Send proposal" + alert deal desk if ACV > $25K
- **Closed Won:** Trigger CS handoff (create Case, assign CS owner, send welcome email)
- **Closed Lost:** Create task "Log loss reason" + add to win/loss analysis report
### 4. Stale Deal Detection (Salesforce Flow)
**Type:** Scheduled-Triggered Flow
**Schedule:** Daily at 7:00 AM
**Flow steps:**
1. Get Records: Open Opportunities where Days_In_Stage > Stage_SLA_Threshold
2. Loop through results:
- Create Task: "Update stale deal: {Opportunity.Name}"
- Send email to Opportunity Owner
- If Days_In_Stage > 2x threshold → send email to Owner's Manager
3. Update custom field "Stale Flag" = true for dashboard visibility
---
## Calendly / SavvyCal Integration Patterns
### Round-Robin Meeting Scheduling
**Calendly setup:**
1. Create a team event type with all eligible reps
2. Distribution: "Optimize for equal distribution"
3. Availability: Each rep manages their own calendar
4. Buffer: 15 min before and after meetings
5. Minimum notice: 4 hours (avoid last-minute bookings)
**CRM integration:**
1. Calendly webhook fires on booking
2. Match invitee email to CRM contact
3. If contact exists → assign meeting to contact owner (override round-robin if owned)
4. If new contact → create lead, assign via routing rules, log meeting
5. Set lifecycle stage to MQL (meeting = high intent)
### SavvyCal Setup
**Advantages over Calendly:**
- Priority-based scheduling (prefer certain time slots)
- Overlay calendars (show team availability in one view)
- Personalized booking links per rep
**Integration pattern:**
1. Create team scheduling link with priority rules
2. Webhook on booking → Zapier/Make → CRM
3. Match or create contact, assign owner, create task
4. Send confirmation with meeting prep materials
### Meeting Routing by Criteria
```
Booking form submitted
├─ Company size > 500? (form field)
│ ├─ YES → Route to enterprise AE calendar
│ └─ NO ↓
├─ Existing customer? (CRM lookup)
│ ├─ YES → Route to account owner's calendar
│ └─ NO ↓
└─ Round-robin across SDR team
```
### No-Show Workflow
**Trigger:** Meeting time passes + no meeting notes logged within 30 minutes
**Actions:**
1. Wait 30 minutes after scheduled meeting time
2. Check: Was a call or meeting logged?
- YES → No action
- NO → Send "Sorry we missed you" email to prospect
3. Create task: "Reschedule with [Contact Name]" — due next business day
4. If second no-show → flag contact and alert manager
---
## Zapier Cross-Tool Patterns
### 1. New Lead → CRM + Slack + Task
**Trigger:** New form submission (Typeform, HubSpot, Webflow)
**Actions:**
1. Create/update contact in CRM
2. Enrich with Clearbit (if available)
3. Post to Slack #new-leads with enriched data
4. Create task in project management tool (Asana, Linear)
### 2. Meeting Booked → CRM + Prep Email
**Trigger:** New Calendly/SavvyCal booking
**Actions:**
1. Find or create CRM contact
2. Update lifecycle stage to MQL
3. Send prep email to assigned rep (include CRM link, LinkedIn profile, recent activity)
4. Create pre-meeting task
### 3. Deal Closed → Onboarding Stack
**Trigger:** CRM deal stage changed to "Closed Won"
**Actions:**
1. Create customer record in CS tool (Vitally, Gainsight, ChurnZero)
2. Add to onboarding project template
3. Send welcome email via email tool
4. Create Slack channel: #customer-[company-name]
5. Notify CS team in Slack
### 4. Lead Scoring → Cross-Tool Sync
**Trigger:** CRM lead score crosses MQL threshold
**Actions:**
1. Update marketing automation platform status
2. Add to retargeting audience (Facebook, Google Ads)
3. Trigger SDR outreach sequence
4. Log event in analytics (Mixpanel, Amplitude)
### 5. SLA Breach → Multi-Channel Alert
**Trigger:** CRM task overdue (MQL follow-up task)
**Actions:**
1. Send Slack DM to rep
2. Send email to rep
3. If 2+ hours overdue → Slack DM to manager
4. If 4+ hours overdue → reassign in CRM (via webhook back to CRM)
### 6. Weekly Pipeline Digest
**Trigger:** Schedule — every Monday at 8:00 AM
**Actions:**
1. Query CRM for pipeline summary (total value, new deals, stale deals, expected closes)
2. Format as summary
3. Post to Slack #sales-team
4. Send email digest to sales leadership
FILE:references/lifecycle-definitions.md
# Lifecycle Stage Definitions
Complete templates for lead lifecycle stages, MQL criteria by business type, SLAs, and rejection/recycling workflows.
## Stage Templates
### Subscriber
**Entry criteria:**
- Opted in to blog, newsletter, or content updates
- No company information required
**Exit criteria:**
- Provides company information via form or enrichment
- Visits 3+ pages in a session
- Downloads gated content
**Owner:** Marketing (automated)
**Actions on entry:**
- Add to newsletter nurture
- Begin tracking engagement score
---
### Lead
**Entry criteria:**
- Identified contact with name + email + company
- May come from form fill, enrichment, or import
**Exit criteria:**
- Reaches MQL threshold (fit + engagement)
- Manually qualified by marketing/SDR
**Owner:** Marketing
**Actions on entry:**
- Enrich contact data (company size, industry, role)
- Begin scoring
- Add to relevant nurture sequence
---
### MQL (Marketing Qualified Lead)
**Entry criteria:**
- Meets fit score threshold AND engagement score threshold
- OR triggers high-intent action (demo request, pricing page + form fill)
**Exit criteria:**
- Sales accepts (becomes SQL)
- Sales rejects (recycled to nurture with reason code)
- No response within SLA (escalated to manager)
**Owner:** Marketing → Sales (handoff)
**Actions on entry:**
- Instant alert to assigned sales rep
- Create follow-up task with 4-hour SLA
- Pause marketing nurture sequences
- Log all recent activity for sales context
---
### SQL (Sales Qualified Lead)
**Entry criteria:**
- Sales rep has had qualifying conversation
- Confirmed: budget, authority, need, or timeline (at least 2 of 4)
**Exit criteria:**
- Opportunity created with projected value
- Disqualified (recycled with reason code)
**Owner:** Sales (SDR or AE)
**Actions on entry:**
- Update lifecycle stage in CRM
- Notify AE if SDR-qualified
- Begin sales sequence if not already in conversation
---
### Opportunity
**Entry criteria:**
- Formal opportunity created in CRM
- Deal value, close date, and stage assigned
**Exit criteria:**
- Closed-won or closed-lost
**Owner:** Sales (AE)
**Actions on entry:**
- Add to pipeline reporting
- Create deal tasks (proposal, demo, etc.)
- Notify CS if deal is likely to close
---
### Customer
**Entry criteria:**
- Closed-won deal
- Contract signed and payment terms set
**Exit criteria:**
- Churns, expands, or renews
**Owner:** Customer Success / Account Management
**Actions on entry:**
- Trigger onboarding sequence
- Assign CS manager
- Schedule kickoff call
- Remove from all sales sequences
---
### Evangelist
**Entry criteria:**
- NPS score 9-10, or active referral behavior
- Agreed to case study, testimonial, or referral program
**Exit criteria:**
- Ongoing program participation
**Owner:** Customer Success + Marketing
**Actions on entry:**
- Add to advocacy program
- Request case study or testimonial
- Invite to referral program
- Feature in marketing campaigns (with permission)
---
## MQL Criteria Templates by Business Type
### PLG (Product-Led Growth)
**Fit score (40% weight):**
| Attribute | Points |
|-----------|--------|
| Company size 10-500 | +15 |
| Company size 500-5000 | +20 |
| Target industry | +10 |
| Decision-maker role | +15 |
| Uses complementary tool | +10 |
**Engagement score (60% weight) — weight product usage heavily:**
| Signal | Points |
|--------|--------|
| Created free account | +15 |
| Completed onboarding | +20 |
| Used core feature 3+ times | +25 |
| Invited team member | +20 |
| Hit usage limit | +15 |
| Visited pricing page | +10 |
**MQL threshold:** 65 points
---
### Sales-Led (Enterprise)
**Fit score (60% weight) — weight fit heavily:**
| Attribute | Points |
|-----------|--------|
| Company size 500+ | +20 |
| Target industry | +15 |
| VP+ title | +20 |
| Budget authority confirmed | +15 |
| Uses competitor product | +10 |
**Engagement score (40% weight):**
| Signal | Points |
|--------|--------|
| Requested demo | +25 |
| Attended webinar | +10 |
| Downloaded whitepaper | +10 |
| Visited pricing page 2+ times | +15 |
| Engaged with sales email | +10 |
**MQL threshold:** 70 points
---
### Mid-Market (Balanced)
**Fit score (50% weight):**
| Attribute | Points |
|-----------|--------|
| Company size 50-1000 | +15 |
| Target industry | +10 |
| Manager+ title | +15 |
| Target geography | +10 |
**Engagement score (50% weight):**
| Signal | Points |
|--------|--------|
| Demo request | +25 |
| Free trial signup | +20 |
| Pricing page visit | +10 |
| Content download (2+) | +10 |
| Email click (3+) | +10 |
| Webinar attendance | +10 |
**MQL threshold:** 60 points
---
## SLA Templates
### MQL-to-SQL SLA
| Metric | Target | Escalation |
|--------|--------|------------|
| First contact attempt | Within 4 business hours | Alert to sales manager at 4 hours |
| Qualification decision | Within 48 hours | Auto-escalate at 48 hours |
| Meeting scheduled (if qualified) | Within 5 business days | Weekly pipeline review flag |
### SQL-to-Opportunity SLA
| Metric | Target | Escalation |
|--------|--------|------------|
| Discovery call completed | Within 3 business days of SQL | Alert to AE manager |
| Opportunity created | Within 5 business days of SQL | Pipeline review flag |
### Opportunity-to-Close SLA
| Metric | Target | Escalation |
|--------|--------|------------|
| Proposal delivered | Within 5 business days of demo | AE manager alert |
| Deal stale in stage | 2x average days for that stage | Pipeline review flag |
| Close date pushed 2+ times | Immediate | Forecast review required |
---
## Lead Rejection and Recycling
### Rejection Reason Codes
| Code | Reason | Recycle Action |
|------|--------|----------------|
| **FIT-01** | Company too small | Nurture; re-score if company grows |
| **FIT-02** | Wrong industry | Archive; do not recycle |
| **FIT-03** | Wrong role / no authority | Nurture; monitor for org changes |
| **ENG-01** | No response after 3 attempts | Recycle to nurture in 90 days |
| **ENG-02** | Interested but bad timing | Recycle to nurture; re-engage in 60 days |
| **QUAL-01** | No budget | Recycle to nurture in 90 days |
| **QUAL-02** | Using competitor, locked in | Recycle; trigger before contract renewal |
| **QUAL-03** | Not a real project | Archive; do not recycle |
### Recycling Workflow
1. Sales rejects MQL with reason code
2. CRM updates lifecycle stage to "Recycled"
3. Lead enters recycling nurture sequence (different from original nurture)
4. Engagement score resets to baseline (keep fit score)
5. If lead re-engages and crosses MQL threshold, re-route to sales with "Recycled MQL" flag
6. Track recycled MQL conversion rate separately
### Recycling Nurture Sequence
- **Frequency:** Bi-weekly or monthly (lower frequency than initial nurture)
- **Content:** Industry insights, case studies, product updates
- **Duration:** 6 months, then archive if no engagement
- **Re-MQL trigger:** High-intent action (demo request, pricing page revisit)
FILE:references/routing-rules.md
# Lead Routing Rules
Decision trees, platform-specific configurations, territory routing, ABM routing, and speed-to-lead benchmarks.
## Routing Decision Tree
Use this template to map your routing logic:
```
New Lead Arrives
│
├─ Is this a named/target account?
│ ├─ YES → Route to assigned account owner
│ └─ NO ↓
│
├─ Is ACV likely > $50K? (based on company size + industry)
│ ├─ YES → Route to enterprise AE team
│ └─ NO ↓
│
├─ Is this a PLG signup with team usage?
│ ├─ YES → Route to PLG sales specialist
│ └─ NO ↓
│
├─ Does lead match a territory?
│ ├─ YES → Route to territory owner
│ └─ NO ↓
│
└─ Default: Round-robin across available reps
└─ If no rep available: Assign to team queue with 1-hour SLA
```
Customize this tree for your business. The key principle: **route to the most specific match first, fall back to general.**
---
## Round-Robin Configuration
### Basic Round-Robin Rules
1. Distribute leads evenly across eligible reps
2. Skip reps who are on PTO, at capacity, or have a full pipeline
3. Weight by quota attainment (reps below quota get slight priority)
4. Reset distribution count weekly or monthly
5. Log every assignment for auditing
### HubSpot Round-Robin Setup
**Using HubSpot's rotation tool:**
- Navigate to Automation → Workflows
- Trigger: Contact property "Lifecycle Stage" equals "MQL"
- Action: Rotate contact owner among selected users
- Options: Even distribution, skip unavailable owners
- Add delay + task creation after assignment
**Custom rotation with workflows:**
1. Create a custom property "Rotation Counter" (number)
2. Workflow trigger: New MQL created
3. Branch by rotation counter value (0, 1, 2... for each rep)
4. Set contact owner to corresponding rep
5. Increment counter (reset at max)
6. Create follow-up task with SLA deadline
### Salesforce Round-Robin Setup
**Using Lead Assignment Rules:**
1. Setup → Feature Settings → Marketing → Lead Assignment Rules
2. Create rule entries in priority order (most specific first)
3. For round-robin: Use assignment rule + custom logic
**Using Flow for advanced routing:**
1. Create a Record-Triggered Flow on Lead creation
2. Get Records: Query a custom "Rep Queue" object for next available rep
3. Decision element: Check rep availability, capacity, territory
4. Update Records: Assign lead owner
5. Create Task: Follow-up task with SLA
6. Update "Rep Queue" to track last assignment
---
## Territory Routing
### By Geography
| Territory | Regions | Assigned Team |
|-----------|---------|---------------|
| West | CA, WA, OR, NV, AZ, UT, CO, HI | Team West |
| Central | TX, IL, MN, MO, OH, MI, WI, IN | Team Central |
| East | NY, MA, PA, NJ, CT, VA, FL, GA | Team East |
| International | All non-US | International team |
### By Company Size
| Segment | Company Size | Team |
|---------|-------------|------|
| SMB | 1-50 employees | Inside sales |
| Mid-market | 51-500 employees | Mid-market AEs |
| Enterprise | 501-5000 employees | Enterprise AEs |
| Strategic | 5000+ employees | Strategic account team |
### By Industry
| Vertical | Industries | Specialist |
|----------|-----------|------------|
| Tech | SaaS, IT services, hardware | Tech vertical rep |
| Financial | Banking, insurance, fintech | Financial vertical rep |
| Healthcare | Hospitals, pharma, healthtech | Healthcare vertical rep |
| General | All others | General pool (round-robin) |
### Hybrid Territory Model
Combine multiple dimensions for precision:
```
Lead arrives
├─ Company size > 1000?
│ ├─ YES → Enterprise team
│ │ └─ Sub-route by geography
│ └─ NO ↓
├─ Industry = Healthcare or Financial?
│ ├─ YES → Vertical specialist
│ └─ NO ↓
└─ Round-robin across general pool
└─ Weighted by geography preference
```
---
## Named Account / ABM Routing
### Setup
1. **Define target account list** (typically 50-500 accounts)
2. **Assign account owners** in CRM (1 rep per account)
3. **Match logic:** Any lead from a target account domain routes to account owner
4. **Matching rules:**
- Email domain match (primary)
- Company name fuzzy match (secondary, requires manual review)
- IP-to-company resolution (tertiary, for anonymous visitors)
### ABM Routing Rules
| Tier | Account Type | Routing | Response SLA |
|------|-------------|---------|--------------|
| Tier 1 | Top 20 strategic accounts | Named owner, instant alert | 1 hour |
| Tier 2 | Top 100 target accounts | Named owner, standard alert | 4 hours |
| Tier 3 | Target industry / size match | Territory or round-robin | Same business day |
### Multi-Contact Handling
When multiple contacts from the same account engage:
- Route all contacts to the **same account owner**
- Notify the owner of new contacts entering
- Track account-level engagement score (sum of all contacts)
- Trigger "buying committee" alert when 3+ contacts from one account engage
---
## Speed-to-Lead Data
### Response Time Impact on Conversion
| Response Time | Relative Qualification Rate | Notes |
|---------------|---------------------------|-------|
| Under 5 minutes | **21x** more likely to qualify | Gold standard |
| 5-10 minutes | 10x more likely | Still strong |
| 10-30 minutes | 4x more likely | Acceptable for most |
| 30 min - 1 hour | 2x more likely | Below best practice |
| 1-24 hours | Baseline | Industry average |
| 24+ hours | 60% lower than baseline | Lead is effectively cold |
Source: Lead Connect, InsideSales.com
### Implementing Speed-to-Lead
1. **Instant notification** — Push notification + email to rep on MQL creation
2. **Auto-task with timer** — Create task with 5-minute SLA countdown
3. **Escalation chain:**
- 5 min: Original rep alerted
- 15 min: Backup rep alerted
- 30 min: Manager alerted
- 1 hour: Lead reassigned to next available rep
4. **Measure and report** — Track actual response times weekly; recognize fast responders
### Speed-to-Lead Automation
**Trigger:** New MQL created
**Actions:**
1. Assign to rep via routing rules (instant)
2. Send push notification + email to rep
3. Create task: "Contact [Lead Name] — 5 min SLA"
4. Start SLA timer
5. If no activity logged in 15 min → alert backup rep
6. If no activity in 30 min → alert manager
7. If no activity in 60 min → reassign via round-robin
### Measuring Speed-to-Lead
Track these metrics weekly:
- **Average time to first contact** (from MQL creation to first call/email)
- **Median time to first contact** (less skewed by outliers)
- **% of leads contacted within SLA** (target: 90%+)
- **Contact rate by time of day** (identify coverage gaps)
- **Conversion rate by response time** (prove the ROI of speed)
FILE:references/scoring-models.md
# Lead Scoring Models
Detailed scoring templates, example models by business type, and calibration guidance.
## Explicit Scoring Template (Fit)
### Company Attributes
| Attribute | Criteria | Points |
|-----------|----------|--------|
| **Company size** | 1-10 employees | +5 |
| | 11-50 employees | +10 |
| | 51-200 employees | +15 |
| | 201-1000 employees | +20 |
| | 1000+ employees | +15 (unless enterprise-focused, then +25) |
| **Industry** | Primary target industry | +20 |
| | Secondary target industry | +10 |
| | Non-target industry | 0 |
| **Revenue** | Under $1M | +5 |
| | $1M-$10M | +10 |
| | $10M-$100M | +15 |
| | $100M+ | +20 |
| **Geography** | Primary market | +10 |
| | Secondary market | +5 |
| | Non-target market | 0 |
### Contact Attributes
| Attribute | Criteria | Points |
|-----------|----------|--------|
| **Job title** | C-suite (CEO, CTO, CMO) | +25 |
| | VP level | +20 |
| | Director level | +15 |
| | Manager level | +10 |
| | Individual contributor | +5 |
| **Department** | Primary buying department | +15 |
| | Adjacent department | +5 |
| | Unrelated department | 0 |
| **Seniority** | Decision maker | +20 |
| | Influencer | +10 |
| | End user | +5 |
### Technology Attributes
| Attribute | Criteria | Points |
|-----------|----------|--------|
| **Tech stack** | Uses complementary tool | +15 |
| | Uses competitor | +10 (they understand the category) |
| | Uses tool you replace | +20 |
| **Tech maturity** | Modern stack (cloud, SaaS-forward) | +10 |
| | Legacy stack | +5 |
---
## Implicit Scoring Template (Engagement)
### High-Intent Signals
| Signal | Points | Decay |
|--------|--------|-------|
| **Demo request** | +30 | None |
| **Pricing page visit** | +20 | -5 per week |
| **Free trial signup** | +25 | None |
| **Contact sales form** | +30 | None |
| **Case study page (2+)** | +15 | -5 per 2 weeks |
| **Comparison page visit** | +15 | -5 per week |
| **ROI calculator used** | +20 | -5 per 2 weeks |
### Medium-Intent Signals
| Signal | Points | Decay |
|--------|--------|-------|
| **Webinar registration** | +10 | -5 per month |
| **Webinar attendance** | +15 | -5 per month |
| **Whitepaper download** | +10 | -5 per month |
| **Blog visit (3+ in a week)** | +10 | -5 per 2 weeks |
| **Email click** | +5 per click | -2 per month |
| **Email open (3+)** | +5 | -2 per month |
| **Social media engagement** | +5 | -2 per month |
### Low-Intent Signals
| Signal | Points | Decay |
|--------|--------|-------|
| **Single blog visit** | +2 | -2 per month |
| **Newsletter open** | +2 | -1 per month |
| **Single email open** | +1 | -1 per month |
| **Visited homepage only** | +1 | -1 per week |
### Product Usage Signals (PLG)
| Signal | Points | Decay |
|--------|--------|-------|
| **Created account** | +15 | None |
| **Completed onboarding** | +20 | None |
| **Used core feature (3+ times)** | +25 | -5 per month inactive |
| **Invited team member** | +25 | None |
| **Hit usage limit** | +20 | -10 per month |
| **Exported data** | +10 | -5 per month |
| **Connected integration** | +15 | None |
| **Daily active for 5+ days** | +20 | -10 per 2 weeks inactive |
---
## Negative Scoring Signals
| Signal | Points | Notes |
|--------|--------|-------|
| **Competitor email domain** | -50 | Auto-flag for review |
| **Student email (.edu)** | -30 | May still be valid in some cases |
| **Personal email (gmail, yahoo)** | -10 | Less relevant for B2B; adjust for SMB |
| **Unsubscribe from emails** | -20 | Reduce engagement score |
| **Bounce (hard)** | -50 | Remove from scoring |
| **Spam complaint** | -100 | Remove from all sequences |
| **Job title: Student/Intern** | -25 | Low buying authority |
| **Job title: Consultant** | -10 | May be evaluating for client |
| **No website visit in 90 days** | -15 | Score decay |
| **Invalid phone number** | -10 | Data quality signal |
| **Careers page visitor only** | -30 | Likely a job seeker |
---
## Example Scoring Models
### Model 1: PLG SaaS (ACV $500-$5K)
**Weight: 30% fit / 70% engagement (heavily favor product usage)**
**Fit criteria:**
- Company size 10-500: +15
- Target industry: +10
- Manager+ role: +10
- Uses complementary tool: +10
**Engagement criteria:**
- Created free account: +15
- Completed onboarding: +20
- Used core feature 3+ times: +25
- Invited team member: +25
- Hit usage limit: +20
- Pricing page visit: +15
**Negative:**
- Personal email: -10
- No login in 14 days: -15
- Competitor domain: -50
**MQL threshold: 60 points**
**Recalibration: Monthly** (fast feedback loop with high volume)
---
### Model 2: Enterprise Sales-Led (ACV $50K+)
**Weight: 60% fit / 40% engagement (fit is critical at this ACV)**
**Fit criteria:**
- Company size 500+: +20
- Revenue $50M+: +15
- Target industry: +15
- VP+ title: +20
- Decision maker confirmed: +15
- Uses competitor: +10
**Engagement criteria:**
- Demo request: +30
- Multiple stakeholders engaged: +20
- Attended executive webinar: +15
- Downloaded ROI guide: +10
- Visited pricing page 2+: +15
**Negative:**
- Company too small (<100): -30
- Individual contributor only: -15
- Competitor domain: -50
**MQL threshold: 75 points**
**Recalibration: Quarterly** (longer sales cycles, smaller sample size)
---
### Model 3: Mid-Market Hybrid (ACV $5K-$25K)
**Weight: 50% fit / 50% engagement (balanced approach)**
**Fit criteria:**
- Company size 50-1000: +15
- Target industry: +10
- Manager-VP title: +15
- Target geography: +10
- Uses complementary tool: +10
**Engagement criteria:**
- Demo request or trial signup: +25
- Pricing page visit: +15
- Case study download: +10
- Webinar attendance: +10
- Email engagement (3+ clicks): +10
- Blog visits (5+ pages): +10
**Negative:**
- Personal email: -10
- No engagement in 30 days: -10
- Competitor domain: -50
- Student/intern title: -25
**MQL threshold: 65 points**
**Recalibration: Quarterly**
---
## Threshold Calibration
### Setting the Initial Threshold
1. **Pull closed-won data** from the last 6-12 months
2. **Retroactively score** each deal using your new model
3. **Find the natural breakpoint** — what score separated wins from losses?
4. **Set threshold** just below where 80% of closed-won deals would have scored
5. **Validate** against closed-lost — if many closed-lost score above threshold, tighten criteria
### Calibration Cadence
| Business Type | Recalibration Frequency | Why |
|---------------|------------------------|-----|
| PLG / High volume | Monthly | Fast feedback loop, lots of data |
| Mid-market | Quarterly | Moderate cycle length |
| Enterprise | Quarterly to semi-annually | Long cycles, small sample size |
### Calibration Steps
1. **Pull MQL-to-closed data** for the calibration period
2. **Compare scored MQLs vs. actual outcomes:**
- High score + closed-won = correctly scored
- High score + closed-lost = possible false positive (tighten)
- Low score + closed-won = possible false negative (loosen)
3. **Adjust weights** based on which attributes actually correlated with wins
4. **Adjust threshold** if MQL volume is too high (raise) or too low (lower)
5. **Document changes** and communicate to sales team
### Warning Signs Your Model Needs Recalibration
- MQL-to-SQL acceptance rate drops below 30%
- Sales consistently rejects MQLs as "not ready"
- High-scoring leads don't convert; low-scoring leads do
- MQL volume spikes without corresponding revenue
- New product/market changes since last calibration
Giảm chi phí API LLM: tối ưu token, chọn mô hình phù hợp, triển khai prompt caching, nên dùng khi chi phí AI tăng cao hoặc sắp ra mắt tính năng AI.
--- name: llm-cost-optimizer description: "Use proactively whenever LLM API costs come up -- or should. Triggers include: 'my AI costs are too high', 'optimize token usage', 'which model should I use', 'LLM spend is out of control', 'implement prompt caching', 'we're about to launch an AI feature', 'build me an AI endpoint'. Don't wait for an explicit cost complaint -- if someone is building an AI feature, designing an LLM endpoint, or choosing between models, cost architecture belongs in the conversation. Apply immediately when any of these are true: a system prompt appears that exceeds a few hundred tokens, all requests are hitting the same model, max_tokens is not set, or no per-feature cost logging exists. NOT for RAG pipeline design (use rag-architect). NOT for improving prompt quality or effectiveness (use senior-prompt-engineer)." --- # LLM Cost Optimizer You are an expert in LLM cost engineering with deep experience reducing AI API spend at scale. Your goal is to cut LLM costs by 40–80% without degrading user-facing quality -- using model routing, caching, prompt compression, and observability to make every token count. AI API costs are engineering costs. Treat them like database query costs: measure first, optimize second, monitor always. --- ## Step 0: Classify Before You Ask Before gathering context, classify which mode applies based on what the user has already said. Pull answers from the conversation first -- don't ask for what you already have. | Mode | When to use | |---|---| | **Cost Audit** | Spend exists but no clear picture of where it goes | | **Optimize Existing System** | Cost drivers are known; apply targeted fixes | | **Design Cost-Efficient Architecture** | Building new AI features; wire in cost controls before launch | If the mode is ambiguous, ask in one shot using the context questions below. Only ask what you don't already know. --- ## Context You Need **Current State** - Which LLM providers and models are in use? - Monthly spend? Which features/endpoints drive it? - Token usage logging in place? Cost-per-request visibility? **Goals** - Target cost reduction? (e.g., "cut 50%", "stay under $X/month") - Latency constraints? (affects caching and routing tradeoffs) - Quality floor? (what degradation is acceptable?) **Workload Profile** - Request volume and distribution (p50, p95, p99 token counts)? - Repeated or similar prompts? (caching potential) - Mix of task types? (classification vs. generation vs. reasoning) --- ## Mode 1: Cost Audit Use when spend exists but the breakdown is unknown. Instrument first; optimize second. **Step 1 -- Instrument Every Request** Log per-request: model, input tokens, output tokens, latency, endpoint/feature, user segment, cost (calculated). **Step 2 -- Find the 20% Causing 80% of Spend** Sort by: feature × model × token count. Usually 2–3 endpoints drive the majority of cost. Target those first. **Step 3 -- Classify Requests by Complexity** | Complexity | Characteristics | Right Model Tier | |---|---|---| | Simple | Classification, extraction, yes/no, short output | Small (Haiku, GPT-4o-mini, Gemini Flash) | | Medium | Summarization, structured output, moderate reasoning | Mid (Sonnet, GPT-4o) | | Complex | Multi-step reasoning, code gen, long context | Large (Opus, o3) | **If token logging doesn't exist yet:** That's the first deliverable -- not prompt compression, not routing. You cannot optimize what you cannot see. Provide a logging schema and move to optimization only once baseline data exists. --- ## Mode 2: Optimize Existing System Apply techniques in ROI order. Don't skip ahead -- measure impact at each step before moving to the next. ### 1. Model Routing (60–80% cost reduction on routed traffic) Route by task complexity, not by default. Use a lightweight classifier or rule engine. - **Small models**: classification, extraction, simple Q&A, formatting, short summaries - **Mid models**: structured output, moderate summarization, code completion - **Large models**: complex reasoning, long-context analysis, agentic tasks, code generation Even routing 20% of traffic to a cheaper model produces meaningful savings. Start there. ### 2. Prompt Caching (40–90% reduction on cacheable traffic) Supported by Anthropic (`cache_control`), OpenAI (automatic on some models), Google (context caching). Cache-eligible content: system prompts, static context, document chunks, few-shot examples. Target hit rates: >60% for document Q&A, >40% for chatbots with static system prompts. **Flag immediately** if a system prompt exceeds ~2,000 tokens and is sent on every request -- this is a high-value caching target. ### 3. Output Length Control (20–40% reduction) LLMs over-generate by default. Force conciseness: - Explicit length instructions: "Respond in 3 sentences or fewer." - Schema-constrained output: JSON with defined fields beats free-text - `max_tokens` hard caps: set per endpoint, not globally - Stop sequences: define terminators for list and structured outputs **Flag immediately** if `max_tokens` is not set per endpoint -- every uncapped endpoint is a cost leak. ### 4. Prompt Compression (15–30% input token reduction) Remove filler without losing meaning. Audit each prompt for token efficiency. | Before | After | |---|---| | "Please carefully analyze the following text and provide..." | "Analyze:" | | "It is important that you remember to always..." | "Always:" | | Context already in system prompt, repeated in user message | Remove | | HTML or markdown when plain text works | Strip tags | **Caution:** Over-compression causes hallucination and low-quality outputs, triggering retries that erase the savings. Compress filler; preserve task-critical instructions. ### 5. Semantic Caching (30–60% hit rate on repeated queries) Cache LLM responses keyed by embedding similarity, not exact match. Serve cached responses for semantically equivalent questions. Tools: GPTCache, LangChain cache, custom Redis + embedding lookup. Threshold guidance: cosine similarity >0.95 = safe to serve cached response. ### 6. Request Batching (10–25% reduction via amortized overhead) Batch non-latency-sensitive requests. Process async queues off-peak. --- ## Mode 3: Design Cost-Efficient Architecture Wire these controls in before launch -- retrofitting is more expensive. **Budget Envelopes** -- per feature, per user tier, per day. Set hard limits and soft alerts at 80% of limit. **Routing Layer** -- classify → route → call. Never call the large model by default. **Tier Your Model Access** -- free users do not need the most expensive model. Assign model tiers by user tier at design time. **Cost Observability Dashboard** -- spend by feature, spend by model, cost per active user, week-over-week trend, anomaly alerts. This is not optional; it is the monitoring foundation. **Graceful Degradation** -- when budget is exceeded: switch to smaller model → serve cached response → queue for async processing. --- ## Proactive Flags Surface these without being asked, regardless of which mode is active: | Signal | Action | |---|---| | No per-feature cost breakdown | Instrument logging before any other change | | All requests hitting one model | Model monoculture = #1 overspend pattern; initiate routing design | | System prompt >2,000 tokens, sent every request | Flag as high-value caching target | | `max_tokens` not set per endpoint | Flag as active cost leak | | No cost alerts configured | Spend spikes go undetected for days; set p95 cost-per-request alerts | | Free tier users consuming same model as paid | Tier model access by user tier | --- ## Failure Modes and Recovery | Situation | Response | |---|---| | No token logs exist | Stop. Logging schema is deliverable #1. Return once baseline data is available. | | User can't identify which feature drives spend | Provide an instrumentation plan; schedule a cost review after 2 weeks of data. | | Routing classifier adds latency that exceeds constraint | Fall back to rule-based routing (token count thresholds, endpoint tags) instead of ML classifier. | | Cache hit rate is below 20% | Diagnose: are prompts highly variable? Is context dynamic? Recommend semantic caching or rethink what's being cached. | | Prompt compression degrades quality | Restore compressed section. Flag the specific instruction as compression-resistant. | --- ## Handoff Triggers If the conversation shifts to one of these, pause and invoke the relevant skill rather than continuing inline: - **Prompt quality or effectiveness deteriorates** → invoke `senior-prompt-engineer` - **Retrieval pipeline design comes up** → invoke `rag-architect` - **Broader monitoring stack beyond cost metrics** → invoke `observability-designer` - **Latency profiling becomes the primary concern** → invoke `performance-profiler` --- ## Output Artifacts | Request | Deliverable | |---|---| | Cost audit | Per-feature spend breakdown, top 3 optimization targets, projected savings | | Model routing design | Routing decision tree with model recommendations per task type and estimated cost delta | | Caching strategy | What to cache, cache key design, expected hit rate, implementation pattern | | Prompt optimization | Token-by-token audit with compression suggestions and before/after token counts | | Architecture review | Cost-efficiency scorecard (0–100) with prioritized fixes and projected monthly savings | --- ## Communication Standard - **Bottom line first** -- cost impact before explanation - **What + Why + How** -- every finding includes all three - **Actions have owners and deadlines** -- no vague "consider optimizing..." - **Confidence tagging** -- verified / medium / assumed --- ## Anti-Patterns | Anti-Pattern | Why It Fails | Better Approach | |---|---|---| | Using the largest model for every request | 80%+ of requests are simple tasks a smaller model handles equally well, wasting 5–10x on cost | Implement a routing layer that classifies complexity and selects the cheapest adequate model | | Optimizing prompts without measuring first | You cannot know what to optimize without per-feature spend visibility | Instrument token logging and cost-per-request before any changes | | Caching by exact string match only | Minor phrasing differences cause cache misses on semantically identical queries | Use embedding-based semantic caching with a cosine similarity threshold | | Setting a single global max_tokens | Some endpoints need 2,000 tokens, others need 50 -- a global cap either wastes or truncates | Set max_tokens per endpoint based on measured p95 output length | | Ignoring system prompt size | A 3,000-token system prompt sent on every request is a hidden cost multiplier | Use prompt caching for static system prompts; strip unnecessary instructions | | Treating cost optimization as a one-time project | Model pricing changes, traffic patterns shift, new features launch -- costs drift | Set up continuous cost monitoring with weekly spend reports and anomaly alerts | | Compressing prompts to the point of ambiguity | Over-compressed prompts cause hallucination or low-quality output, requiring retries | Compress filler and redundant context; preserve all task-critical instructions |
Thiết kế, tối ưu và truyền thông giá SaaS: cấu trúc bậc giá, value metric, trang giá và chiến lược tăng giá.
---
name: "pricing-strategy"
description: "Design, optimize, and communicate SaaS pricing — tier structure, value metrics, pricing pages, and price increase strategy. Use when building a pricing model from scratch, redesigning existing pricing, planning a price increase, or improving a pricing page. Trigger keywords: pricing tiers, pricing page, price increase, packaging, value metric, per seat pricing, usage-based pricing, freemium, good-better-best, pricing strategy, monetization, pricing page conversion, Van Westendorp. NOT for broader product strategy — use product-strategist for that. NOT for customer success or renewals — use customer-success-manager for expansion revenue."
license: MIT
metadata:
version: 1.0.0
author: Alireza Rezvani
category: marketing
updated: 2026-03-06
---
# Pricing Strategy
You are an expert in SaaS pricing and monetization. Your goal is to design pricing that captures the value you deliver, converts at a healthy rate, and scales with your customers.
Pricing is not math — it's positioning. The right price isn't the one that covers costs + margin. It's the one that sits between what your next-best alternative costs and what your customers believe they get in return. Most SaaS products are underpriced. This skill is about fixing that, clearly and defensibly.
## Before Starting
**Check for context first:**
If `marketing-context.md` exists, read it before asking questions. Use that context and only ask for what's missing.
Gather this context:
### 1. Current State
- Do you have pricing today? If so: what plans, what price points, what's the billing model?
- What's your conversion rate from trial/free to paid? (If known)
- What's your average revenue per customer?
- What's your monthly churn rate?
### 2. Business Context
- Product type: B2B or B2C? Self-serve or sales-assisted?
- Customer segments: who are your best customers vs. casual users?
- Competitors: who do customers compare you to, and what do those cost?
- Cost structure: what does serving one customer cost you per month?
### 3. Goals
- Are you designing, optimizing, or planning a price increase?
- Any constraints? (e.g., grandfathered customers, contractual limits, channel partner margins)
## How This Skill Works
### Mode 1: Design Pricing From Scratch
Starting without a pricing model, or rebuilding entirely. We'll work through value metric selection, tier structure, price point research, and pricing page design.
### Mode 2: Optimize Existing Pricing
Pricing exists but conversion is low, expansion is flat, or customers feel mispriced. We'll audit what's there, benchmark, and identify specific improvements.
### Mode 3: Plan a Price Increase
Prices need to go up — because of inflation, value improvements, or market repositioning. We'll design a strategy that increases revenue without burning customers.
---
## The Three Pricing Axes
Every pricing decision lives across three axes. Get all three right.
```
┌─────────────────┐
│ PACKAGING │ What's in each tier?
│ (what you get) │
└────────┬────────┘
│
┌────────┴────────┐
│ VALUE METRIC │ What do you charge for?
│ (how it scales) │
└────────┬────────┘
│
┌────────┴────────┐
│ PRICE POINT │ How much?
│ (the number) │
└─────────────────┘
```
Most teams skip straight to price point. That's backwards. Lock in the metric first, then packaging, then test the number.
---
## Value Metric Selection
Your value metric determines how pricing scales with customer value. Choose wrong and you either leave money on the table or create friction that kills growth.
### Common Value Metrics for SaaS
| Metric | Best For | Example |
|--------|---------|---------|
| **Per seat / user** | Collaboration tools, CRMs | Salesforce, Notion, Linear |
| **Per usage** | API tools, infrastructure, AI | Stripe, Twilio, OpenAI |
| **Per feature** | Platform plays, add-ons | Intercom, HubSpot |
| **Flat fee** | Unlimited-feel, SMB tools | Basecamp, Calendly Basic |
| **Per outcome** | High-value, measurable ROI | Commission-based tools |
| **Hybrid** | Mix of above | Most mature SaaS |
### How to Choose
Answer these questions:
1. **What makes a customer willing to pay more?** → That's your value metric
2. **Does the metric scale with their success?** → If they grow, you grow
3. **Is it easy to understand?** → Complexity kills conversion
4. **Is it hard to game?** → Customers shouldn't be able to work around it
**Red flags:**
- "Per seat" in a tool where one power user does all the work → seats don't scale with value
- "Flat fee" when some customers derive 10x the value of others → you're subsidizing heavy users
- "Per API call" when call count varies wildly week to week → unpredictable bills = churn
---
## Good-Better-Best Tier Structure
Three tiers is the standard. Not because of tradition — because it anchors perception.
### Tier Design Principles
**Entry tier (Good):**
- Captures the segment that will churn if priced higher
- Limited — either by features, usage, or support
- NOT free. Free is a separate strategy (freemium), not a tier.
- Should cover your costs at minimum
**Middle tier (Better) — your default:**
- This is where you push most customers
- Price: 2-3x the entry tier
- Features: everything a growing company needs
- Call it out visually as recommended
**Top tier (Best):**
- For high-value customers with enterprise needs
- May be "Contact us" or custom pricing
- Unlocks: SSO, audit logs, SLA, dedicated support, custom contracts
- If you have enterprise deals >$1k MRR, this tier exists to capture them
### What Goes in Each Tier
| Feature Category | Entry | Better | Best |
|----------------|-------|--------|------|
| Core product | ✅ (limited) | ✅ (full) | ✅ (full) |
| Usage limits | Low | Medium | High / unlimited |
| Users/seats | 1-3 | 5-unlimited | Unlimited |
| Integrations | Basic | Full | Full + custom |
| Reporting | Basic | Advanced | Custom |
| Support | Email | Priority | Dedicated CSM |
| Admin features | — | — | SSO, audit log, SCIM |
| SLA | — | — | ✅ |
See [references/pricing-models.md](references/pricing-models.md) for model deep dives and SaaS examples.
---
## Value-Based Pricing
Price between the next-best alternative and your perceived value.
```
[Cost of doing nothing] ... [Next-best alternative] ... [YOUR PRICE] ... [Perceived value delivered]
```
**Step 1: Define the next-best alternative**
- What would the customer do if your product didn't exist?
- A competitor? A spreadsheet? Manual process? Hiring someone?
- What does that cost them?
**Step 2: Estimate value delivered**
- Time saved × hourly rate of the person using it
- Revenue generated or protected
- Cost of error/risk avoided
- Ask your best customers: "What would you lose if you stopped using us tomorrow?"
**Step 3: Price in the middle**
- A rough heuristic: price at 10-20% of documented value delivered
- Don't price at 50% of value — customers feel they're overpaying
- Don't price below the next-best alternative — signals you don't believe in your own product
**Conversion rate as a signal:**
- >40% trial-to-paid: likely underpriced — test a price increase
- 15-30%: healthy for most SaaS
- <10%: pricing may be high, or trial-to-paid funnel has friction
---
## Pricing Research Methods
### Van Westendorp Price Sensitivity Meter
Four questions, asked to current customers or target segment:
1. At what price would this product be so cheap you'd question its quality?
2. At what price would this product be a bargain — great deal?
3. At what price would this product start to feel expensive — still acceptable?
4. At what price would this product be too expensive to consider?
**Interpret the results:** Plot the four curves. The intersection of "too cheap" and "too expensive" gives your acceptable price range. The intersection of "bargain" and "expensive" gives the optimal price point.
**When to use:** B2B SaaS, n≥30 respondents, existing customers or qualified prospects.
### MaxDiff Analysis
Show respondents sets of features/prices and ask which they value most and least. Statistical analysis reveals relative value of each feature — informs packaging more than price point.
**When to use:** When deciding which features to put in which tier.
### Competitor Benchmarking
| Step | What to Do |
|------|-----------|
| 1 | List direct competitors and alternatives customers consider |
| 2 | Record their published pricing (plan names, prices, value metrics) |
| 3 | Note what's included at each price point |
| 4 | Identify where your product over- and under-delivers vs. each |
| 5 | Price relative to positioning: premium = 20-40% above market, value = at or below |
**Don't just copy competitor prices** — their pricing reflects their cost structure and positioning, not yours.
---
## Price Increase Strategies
Raising prices is one of the highest-ROI moves available to SaaS companies. Most wait too long.
### Strategy Selection
| Strategy | Use When | Risk |
|---------|---------|------|
| **New customers only** | Significant pushback expected | Low — doesn't touch existing base |
| **Grandfather + delayed** | Loyal customer base, contract risk | Medium — existing customers feel respected |
| **Tied to value delivery** | Clear new features/improvement | Low — justifiable |
| **Plan restructure** | Significant packaging change | Medium — complexity for customers |
| **Uniform increase** | Confident in value, price is clearly below market | Medium-High |
### Execution Checklist
1. **Quantify the move:** Calculate new MRR at 100%, 80%, 70% retention of existing customers
2. **Segment by risk:** Annual contracts, champions vs. detractors, usage-based at-risk accounts
3. **Set the date:** 60-90 days notice for existing customers. 30 days minimum.
4. **Communicate the reason:** New features, rising costs, investment in [X] — be specific
5. **Offer a path:** Lock in current price for annual commitment, or give a 3-month window
6. **Arm your CS team:** FAQ, talking points, approved offer authority
7. **Monitor for 60 days:** Churn rate, downgrade rate, support ticket volume
**Expected churn from a 20-30% price increase:** 5-15%. If your net revenue impact is positive, proceed.
---
## Pricing Page Design
The pricing page converts intent to purchase. Design it with that job in mind.
### Above the Fold
Must have:
- Plan names (simple: Starter / Pro / Enterprise, or named after customer segment)
- Price with billing toggle (monthly/annual — annual should show savings)
- 3-5 bullet differentiators per plan
- CTA button per plan
- "Most popular" badge on recommended tier
### Below the Fold
- **Full feature comparison table** — comprehensive, scannable, uses ✅ and ❌ not walls of text
- **FAQ section** — address the 5 objections that stop people from buying:
- "Can I cancel anytime?"
- "What happens when I hit limits?"
- "Do you offer refunds?"
- "Is my data secure?"
- "What if I need to upgrade/downgrade?"
- **Social proof** — logos, quotes, or case studies relevant to each tier
- **Security badges** if B2B enterprise (SOC2, ISO 27001, GDPR)
### Annual vs. Monthly Toggle
- Show annual pricing by default (or highlight it) — it improves LTV
- Show savings explicitly: "Save 20%" or "2 months free"
- Don't hide the monthly price — hiding it builds distrust
See [references/pricing-page-playbook.md](references/pricing-page-playbook.md) for design specs and copy templates.
---
## Proactive Triggers
Surface these without being asked:
- **Conversion rate >40% trial-to-paid** → Strong signal of underpricing. Flag: test 20-30% price increase.
- **All customers on the middle tier** → No upsell path. Flag: enterprise tier needed or feature lock-in missing.
- **Customer asked for features that aren't in their tier** → Expansion revenue being left on the table. Flag: feature gatekeeping review.
- **Churn rate >5% monthly** → Before raising prices, fix churn. Price increases accelerate churners.
- **Price hasn't changed in 2+ years** → Inflation alone justifies 10-15% increase. Flag for strategic review.
- **Only one pricing option** → No anchoring, no upsell. Flag: add a third tier even if rarely purchased.
---
## Output Artifacts
| When you ask for... | You get... |
|--------------------|-----------|
| "Design pricing" | Three-tier structure with value metric, feature grid, price points, and rationale |
| "Audit my pricing" | Pricing scorecard (0-100), conversion rate benchmarks, gap analysis, quick wins |
| "Plan a price increase" | Increase strategy selection, communication templates, risk model, 90-day rollout plan |
| "Design a pricing page" | Above-fold layout spec, feature comparison table structure, CTA copy, FAQ copy |
| "Research pricing" | Van Westendorp survey questions + MaxDiff framework for your specific product |
| "Model pricing scenarios" | Run `scripts/pricing_modeler.py` with your inputs |
---
## Communication
All output follows the structured communication standard:
- **Bottom line first** — recommendation before justification
- **What + Why + How** — every recommendation has all three
- **Actions have owners and deadlines** — no vague "consider"
- **Confidence tagging** — 🟢 verified benchmark / 🟡 estimated / 🔴 assumed
---
## Related Skills
- **product-strategist**: Use for product roadmap and broader monetization strategy. NOT for pricing page or price increase execution.
- **copywriting**: Use for pricing page copy polish. NOT for pricing structure or tier design.
- **churn-prevention**: Use when churn is the underlying issue — fix retention before raising prices.
- **ab-test-setup**: Use to A/B test price points or pricing page layouts after initial design.
- **customer-success-manager**: Use for expansion revenue through upselling. NOT for pricing design or packaging.
- **competitor-alternatives**: Use for competitive comparison pages that complement pricing pages.
FILE:references/pricing-models.md
# Pricing Models — Deep Dive
Comprehensive reference for SaaS pricing models with real-world examples and when to use each.
---
## Model 1: Per-Seat / Per-User
**How it works:** Price is multiplied by the number of users who access the product.
**Best for:**
- Collaboration tools where more users = more value
- CRMs where every sales rep needs access
- Tools where the organization is the buyer and seats map to headcount
**Examples:** Salesforce ($25-300/seat/mo), Linear ($8/seat/mo), Figma ($12/seat/mo), Notion ($8/seat/mo)
**Expansion mechanics:** Automatic as companies hire. No upsell conversation needed — new hire gets a seat, revenue grows.
**Failure modes:**
- Single-power-user tools (one person does all the work, team just views results) → seat pricing punishes the customer for your product's design
- Tools used by contractors or external stakeholders → billing becomes a negotiation
- Products where sharing credentials is easy and enforcement is hard
**Seat pricing variants:**
| Variant | Description | Example |
|---------|-------------|---------|
| Named seat | Specific user assigned to each license | Salesforce |
| Concurrent seat | N users can be logged in simultaneously | Legacy enterprise software |
| Creator/viewer split | Creators pay, viewers free or low-cost | Figma, Miro |
| Minimum seat count | Plan requires minimum X seats | Most enterprise deals |
**Tip:** Creator/viewer pricing is powerful for B2B tools where one team creates and dozens consume. It drives virality (free viewers) while capturing revenue from actual users.
---
## Model 2: Usage-Based (Consumption)
**How it works:** Customer pays for what they use — API calls, storage, compute, messages sent, emails delivered.
**Best for:**
- Infrastructure and developer tools
- AI/ML tools where compute cost scales with usage
- Communication platforms (email, SMS, video)
- Products where usage is highly variable across customers
**Examples:** Stripe (2.9% + $0.30/transaction), Twilio ($0.0075/SMS), AWS (varies), OpenAI ($0.002-0.06/1K tokens)
**Expansion mechanics:** Natural — as customer grows, their usage grows, revenue grows without any action. Best CAC:LTV dynamics in SaaS.
**Failure modes:**
- Unpredictable bills → customers cap usage to avoid overages → you've engineered your own ceiling
- High churn during market downturns → when usage drops, revenue drops
- Hard to forecast for both you and the customer
**Usage pricing variants:**
| Variant | Description | Example |
|---------|-------------|---------|
| Pure consumption | Pay only for what you use | AWS Lambda |
| Prepaid credits | Buy credits, consume at your pace | OpenAI, Resend |
| Committed use + overage | Flat fee with usage ceiling, then per-unit | Stripe, Twilio volume |
| Tiered usage | Lower per-unit price at higher volumes | Mailchimp email tiers |
**Hybrid approach:** Most mature usage-based companies add a platform fee (small flat monthly charge) to ensure revenue floor and reduce churn from low-usage months.
---
## Model 3: Feature-Based (Tiered Flat Fee)
**How it works:** Different bundles of features at different flat price points. The Good-Better-Best model.
**Best for:**
- Products with clear feature differentiation between customer segments
- Markets where predictable spend matters (CFOs love this)
- SMB-to-enterprise products where enterprise features are genuinely different
**Examples:** HubSpot (Starter/Professional/Enterprise), Intercom (Starter/Pro/Premium), most SaaS
**Expansion mechanics:** Requires upsell motion — customer has to outgrow a tier and move up. Less automatic than usage-based but more predictable.
**Failure modes:**
- Feature tiers that don't match actual customer needs → customers cluster in one tier, none move
- Enterprise features that aren't compelling enough to justify the jump → stuck mid-market
- Too many tiers → analysis paralysis
---
## Model 4: Flat Fee
**How it works:** One price, everything included, unlimited use.
**Best for:**
- Small tools with predictable cost structure
- Markets where simplicity is the differentiator
- Products where usage genuinely doesn't vary much
**Examples:** Basecamp ($99/mo flat), Transistor.fm (by podcast, not listeners), Calendly Basic
**Expansion mechanics:** None. You need a premium tier or add-ons, or you're relying purely on new customer acquisition.
**Failure modes:**
- Heavy users subsidized by light users → heavy users stay forever, light users churn → adverse selection
- No path to grow revenue with existing customers → stuck unless you add tiers or raise prices
**When flat fee works:** When your cost to serve is genuinely flat, or when market positioning around simplicity is worth more than the revenue you'd capture with usage-based pricing.
---
## Model 5: Freemium
**Note:** Freemium is an acquisition strategy, not a pricing model. It's compatible with any of the above.
**How it works:** Free tier with limited functionality, paid tiers above.
**Best for:**
- Developer tools (PLG)
- Collaboration tools that spread virally
- Products where network effects increase value with more users
**Examples:** Slack, Notion, Figma, GitHub, Airtable
**The freemium math:**
- Free users cost money to serve
- You need paid conversion rate high enough to cover free users
- Rule of thumb: 2-5% free-to-paid conversion is viable at scale, 1-2% usually isn't
**Free vs. trial vs. freemium:**
| Model | Description | Best For |
|-------|-------------|---------|
| Free forever tier | Permanently limited free plan | PLG, viral loops |
| Time-limited trial | Full access for 14-30 days | Sales-assisted, complex products |
| Usage-limited trial | Full access until limit hit | Developer tools, AI |
| Freemium | Permanently limited, upsell to paid | Bottoms-up enterprise |
---
## Model 6: Hybrid Pricing
Most mature SaaS companies end up with hybrid pricing. Common combinations:
| Combination | Example |
|------------|---------|
| Platform fee + per seat | Base access + user licenses |
| Platform fee + usage | Monthly minimum + overage |
| Feature tiers + usage | Plan determines included usage, overage above |
| Per seat + usage | Seat license + volume pricing for heavy users |
**When to go hybrid:**
- You have both fixed infrastructure costs and variable serving costs
- You want revenue floors (platform fee) + upside (usage)
- Different customer segments have very different value profiles
---
## Pricing Model Selection Framework
Answer these questions to identify the right model:
**1. Does value scale with users?**
- Yes, linearly → per-seat
- Yes, but not linearly → creator/viewer or per-seat with role tiers
**2. Does value scale with usage?**
- Yes, measurably → usage-based
- Yes, but usage is hard to measure → feature tiers with usage caps
**3. Is your customer a small business wanting simplicity?**
- Yes → flat fee or simple 2-3 tier feature pricing
- No → skip flat fee, go feature or usage-based
**4. Do you have enterprise customers with governance/compliance needs?**
- Yes → enterprise tier required (even if "Contact us")
- No → three tiers max
**5. Is this a developer/technical product?**
- Yes → usage-based or consumption with free tier is the market norm
- No → feature tiers with flat fee is more accessible
---
## Pricing Model Benchmarks
| Metric | Early Stage | Growth | Scale |
|--------|------------|--------|-------|
| **Trial-to-paid rate** | 15-25% | 20-35% | 25-40% |
| **Annual vs monthly mix** | 30-50% annual | 40-60% annual | 50-70% annual |
| **Expansion revenue** | 0-10% of MRR | 10-20% | 20-40% |
| **Price increase frequency** | Ad hoc | Annually | Annually |
| **Churn rate (monthly)** | 2-8% | 1-4% | 0.5-2% |
**The LTV:CAC rule:** LTV should be ≥3x CAC. If it's below 3x, pricing or retention (or both) needs fixing.
FILE:references/pricing-page-playbook.md
# Pricing Page Playbook
Design specs, copy frameworks, and conversion tactics for SaaS pricing pages.
---
## What a Pricing Page Actually Has to Do
One job: get the right customer to click the right plan's CTA. Everything on the page should serve that job or get removed.
The visitor landing on your pricing page has already decided they're interested. They're now asking:
1. "Which plan is for me?"
2. "Is it worth the price?"
3. "What's the catch?"
Your page answers those three questions, in that order.
---
## Page Structure (Scroll Order)
### Above the Fold
**Billing toggle (monthly/annual)**
- Default to annual if annual is your preference (most conversions happen here)
- Show savings clearly: "Save 20%" badge, not just the math
- Position toggle at the top, before plan cards
**Plan cards (3-column)**
```
┌─────────────┬─────────────┬─────────────┐
│ Starter │ Pro │ Enterprise │
│ │ ★ Popular │ │
│ $29/mo │ $99/mo │ Custom │
│ │ │ │
│ For small │ For growing │ For teams │
│ teams │ teams │ needing │
│ │ │ control │
│ • Feature │ • Feature │ • Feature │
│ • Feature │ • Feature │ • Feature │
│ • Feature │ • Feature │ • Feature │
│ │ │ │
│ [Start free]│[Start free] │[Contact us] │
└─────────────┴─────────────┴─────────────┘
```
**Each plan card must include:**
- Plan name (customer-segment-oriented, not just "Basic/Pro")
- Price (with billing period and per-seat notation if applicable)
- 1-line positioning sentence ("For growing teams who need X")
- 4-6 bullet differentiators (what they get at this tier)
- CTA button (clear, action-oriented — not just "Sign Up")
- "Most popular" / "Recommended" badge on middle tier
### Below the Fold
**Full Feature Comparison Table**
- Exhaustive list of all features
- Group by category: Core, Collaboration, Analytics, Admin, Support
- Use ✅ / ❌ or checkmarks/dashes — no conditional language
- Sticky header so plan names stay visible while scrolling
- Make this scannable, not a wall of text
**Social Proof Section**
- 3 customer quotes relevant to each tier if possible
- Company logos of recognizable customers
- Stats if they're real: "Trusted by 10,000+ teams"
**FAQ Section (5-7 questions)**
Non-negotiable FAQs:
1. "Can I cancel anytime?" → Yes. Cancel from settings. No calls required.
2. "What happens at the end of my trial?" → We'll ask if you want to continue.
3. "Can I switch plans?" → Yes, upgrade or downgrade anytime. Prorated billing.
4. "What payment methods do you accept?" → Credit card, invoice for annual enterprise.
5. "Is my data secure?" → SOC 2 Type II / ISO 27001 / brief security statement.
6. "What if I need more than the top plan offers?" → Talk to us: [link to enterprise form].
**Enterprise Call-to-Action**
- Separate row or section below cards
- "Need custom pricing or a demo?" → [Talk to Sales] button
- Who it's for: teams over X seats, specific compliance needs, custom contracts
---
## Copy Frameworks
### Plan Names
Avoid generic names if possible. Named plans anchor to identity, not just price.
| Generic | Better | Why |
|---------|--------|-----|
| Free / Basic / Pro | Solo / Studio / Agency | Maps to customer segment |
| Starter / Growth / Enterprise | Developer / Team / Business | Maps to use case |
| Individual / Team / Organization | Creator / Collaborator / Company | Maps to role |
If your categories are genuinely vague, stick with simple names. Don't force creative names that confuse.
### CTA Copy
Match the CTA to the ask:
| Context | CTA |
|---------|-----|
| Has a free trial | "Start free trial" |
| Freemium | "Get started free" |
| No trial, direct purchase | "Get [Plan Name]" |
| Enterprise / contact sales | "Talk to us" or "Get a demo" |
| Annual commitment, high price | "Schedule a call" |
Avoid:
- "Sign Up" — generic, no value
- "Subscribe" — sounds like a newsletter
- "Buy Now" — transactional, not benefit-oriented
- "Learn More" — on a pricing page, this is a dead end
### Pricing Display
| Scenario | How to Show It |
|----------|---------------|
| Monthly pricing | "$99/month" |
| Annual pricing, billed monthly | "$83/month, billed annually" |
| Annual pricing, billed upfront | "$996/year" with "/mo equivalent" note |
| Per-seat | "$15/user/month" |
| Usage-based | "From $0.002 per call" |
| Enterprise | "Custom" or "Starting at $X" |
Always show annual savings as a percentage OR dollar amount (whichever is larger visually).
---
## Conversion Tactics
### Anchoring
**Price anchoring:** The first number shown sets the reference frame. If you show a $500/month plan first, $99 feels cheap.
If you want to push the middle tier:
- Show plans left-to-right: Premium → Pro (recommended) → Starter
- OR highlight the middle tier with visual treatment (larger card, border, color)
- The eye goes to the visually differentiated option
### The "Recommended" Badge
Don't just label the middle tier. Make it visually obvious:
- Darker background or brand color
- Slightly taller card
- "Most Popular" or "Recommended for Most Teams" label
- First CTA in the tab order
### Annual Toggle Default
Research consistently shows defaulting to annual pricing increases annual plan take rate. Show the toggle, but default to annual.
If you want more monthly customers (for cash flow testing, or lower commitment products), default to monthly.
### Pricing Page SEO Consideration
Pricing pages often rank for "[Company] pricing" queries. This matters because:
- Competitors may be running ads on your brand pricing keywords
- The page needs to load fast and be well-structured
- Include your pricing in structured data (JSON-LD Schema: PriceSpecification)
---
## Pricing Page Audit Checklist
Score each item 0-2 (0 = missing, 1 = exists but weak, 2 = done well):
**Above the Fold**
- [ ] Billing toggle visible
- [ ] Annual savings shown clearly
- [ ] Three plan cards with clear differentiation
- [ ] "Most popular" / recommended tier highlighted
- [ ] CTA per plan
**Content**
- [ ] Full feature comparison table
- [ ] FAQ section (5+ questions)
- [ ] Social proof / logos
- [ ] Enterprise CTA
**Copy**
- [ ] Plan names are meaningful (not just Basic/Pro)
- [ ] Price is unambiguous (per user? per month? billed how?)
- [ ] CTAs are action-oriented
- [ ] Positioning line per plan
**Trust**
- [ ] Security badges (if B2B)
- [ ] Money-back guarantee or cancellation policy visible
- [ ] "Cancel anytime" stated explicitly
**Score interpretation:**
- 22-24: Strong page. Test specific elements.
- 16-21: Good foundation. Fix weak sections.
- <16: Material gaps. Rebuild using this playbook.
---
## Pricing Page A/B Test Ideas
**High impact, easier to test:**
1. Default billing toggle (annual vs. monthly)
2. "Most popular" badge placement
3. CTA copy (Start free trial vs. Get Pro)
4. Price display ($/mo vs. $/year)
**Medium impact, more setup:**
5. Plan name messaging (segment-based vs. feature-based)
6. Number of features shown in above-fold cards (3 vs. 6)
7. Social proof placement (above vs. below fold)
8. FAQ accordion vs. expanded
**High impact, harder to execute:**
9. Actual price points (statistical significance takes longer)
10. Three tiers vs. two tiers
11. Adding vs. removing free tier
**Minimum traffic for pricing tests:** 500+ visitors per variant per week. Below that, results won't be statistically meaningful.
FILE:scripts/pricing_modeler.py
#!/usr/bin/env python3
"""Pricing modeler — projects revenue at different price points and recommends tier structure."""
import json
import sys
import math
SAMPLE_INPUT = {
"current_mrr": 45000,
"current_customers": 300,
"monthly_new_customers": 25,
"monthly_churn_rate_pct": 3.5,
"trial_to_paid_rate_pct": 18,
"current_plans": [
{"name": "Starter", "price": 29, "customer_count": 180},
{"name": "Pro", "price": 79, "customer_count": 100},
{"name": "Enterprise", "price": 199, "customer_count": 20}
],
"competitor_prices": [49, 89, 249],
"cogs_per_customer_monthly": 8,
"target_gross_margin_pct": 75
}
def calculate_arpu(plans):
total_rev = sum(p["price"] * p["customer_count"] for p in plans)
total_cust = sum(p["customer_count"] for p in plans)
return total_rev / total_cust if total_cust > 0 else 0
def project_revenue_at_price(base_customers, base_arpu, new_arpu,
new_customers_monthly, churn_rate, months=12):
"""Project MRR over N months at a new ARPU, assuming some churn from price change."""
price_increase_pct = (new_arpu - base_arpu) / base_arpu if base_arpu > 0 else 0
# Estimate churn uplift from price increase
# Empirical: each 10% price increase causes ~2-4% additional one-time churn
if price_increase_pct > 0:
price_churn_hit = price_increase_pct * 0.25 # 25% of increase leaks as churn
else:
price_churn_hit = 0
monthly_churn = churn_rate / 100
mrr_series = []
customers = base_customers * (1 - price_churn_hit) # initial price churn hit
mrr = customers * new_arpu
for month in range(1, months + 1):
mrr_series.append(round(mrr, 0))
customers = customers * (1 - monthly_churn) + new_customers_monthly
mrr = customers * new_arpu
return {
"month_1_mrr": mrr_series[0],
"month_6_mrr": mrr_series[5],
"month_12_mrr": mrr_series[11],
"total_12mo_revenue": sum(mrr_series),
"customers_after_price_churn": round(base_customers * (1 - price_churn_hit), 0)
}
def recommend_tier_structure(plans, competitor_prices, cogs, target_margin_pct):
"""Recommend Good-Better-Best tier structure based on current state and competitors."""
current_arpu = calculate_arpu(plans)
comp_avg = sum(competitor_prices) / len(competitor_prices) if competitor_prices else current_arpu
comp_min = min(competitor_prices) if competitor_prices else current_arpu * 0.7
comp_max = max(competitor_prices) if competitor_prices else current_arpu * 1.5
# Minimum price based on cost structure
min_viable_price = cogs / (1 - target_margin_pct / 100)
# Recommended tier anchors
entry_price = max(min_viable_price, comp_min * 0.9)
mid_price = entry_price * 2.5
premium_price = mid_price * 2.5
# Round to psychologically clean prices
def clean_price(p):
if p < 30:
return round(p / 5) * 5 - 1 # e.g., 19, 29
elif p < 100:
return round(p / 10) * 10 - 1 # e.g., 49, 79, 99
elif p < 500:
return round(p / 25) * 25 - 1 # e.g., 149, 199, 299
else:
return round(p / 100) * 100 - 1 # e.g., 499, 999
return {
"entry": {
"name": "Starter",
"recommended_price": clean_price(entry_price),
"positioning": "For individuals and small teams getting started"
},
"mid": {
"name": "Professional",
"recommended_price": clean_price(mid_price),
"positioning": "For growing teams that need the full feature set — recommended for most"
},
"premium": {
"name": "Enterprise",
"recommended_price": clean_price(premium_price),
"positioning": "For larger organizations needing security, compliance, and dedicated support"
},
"rationale": {
"current_arpu": round(current_arpu, 2),
"competitor_range": f"comp_min-comp_max",
"min_viable_price": round(min_viable_price, 2),
"pricing_vs_market": "at-market" if abs(current_arpu - comp_avg) / comp_avg < 0.15 else
"below-market" if current_arpu < comp_avg else "above-market"
}
}
def elasticity_estimate(trial_to_paid_pct, current_arpu):
"""Rough price elasticity signal based on conversion rate."""
if trial_to_paid_pct > 40:
signal = "strong-underpricing"
note = "Conversion >40% — strong signal of underpricing. Test 20-30% increase."
headroom = 0.30
elif trial_to_paid_pct > 25:
signal = "possible-underpricing"
note = "Conversion 25-40% — healthy, but may have room for modest price increase."
headroom = 0.15
elif trial_to_paid_pct > 15:
signal = "market-priced"
note = "Conversion 15-25% — likely market-priced. Focus on tier structure and packaging."
headroom = 0.05
elif trial_to_paid_pct > 8:
signal = "possible-overpricing"
note = "Conversion 8-15% — possible price friction. Audit trial experience before reducing price."
headroom = -0.05
else:
signal = "high-friction"
note = "Conversion <8% — significant friction. May be pricing, trial experience, or ICP fit."
headroom = -0.15
return {
"signal": signal,
"note": note,
"estimated_price_headroom_pct": round(headroom * 100, 0),
"suggested_test_price": round(current_arpu * (1 + headroom), 2)
}
def print_report(result, inputs):
cur = result["current_state"]
elast = result["elasticity"]
tiers = result["tier_recommendation"]
scenarios = result["price_scenarios"]
print("\n" + "="*65)
print(" PRICING MODELER")
print("="*65)
print(f"\n📊 CURRENT STATE")
print(f" MRR: ,.0f")
print(f" Customers: {cur['customers']}")
print(f" ARPU: .2f/mo")
print(f" Trial-to-paid rate: {inputs['trial_to_paid_rate_pct']}%")
print(f" Monthly churn rate: {inputs['monthly_churn_rate_pct']}%")
print(f" Gross margin (est.): {cur['gross_margin_pct']:.1f}%")
print(f"\n💡 PRICE ELASTICITY SIGNAL")
print(f" Signal: {elast['signal'].replace('-', ' ').upper()}")
print(f" Note: {elast['note']}")
print(f" Headroom: {'+' if elast['estimated_price_headroom_pct'] >= 0 else ''}"
f"{elast['estimated_price_headroom_pct']:.0f}%")
print(f" Test at: .2f/mo ARPU")
print(f"\n📐 RECOMMENDED TIER STRUCTURE")
tier_rat = tiers['rationale']
print(f" Market position: {tier_rat['pricing_vs_market'].replace('-', ' ').title()}")
print(f" Competitor range: {tier_rat['competitor_range']}")
print(f" Min viable price: .2f/mo")
print(f"\n ┌─────────────────┬────────────┬────────────────────────────────────┐")
print(f" │ Tier │ Price │ Positioning │")
print(f" ├─────────────────┼────────────┼────────────────────────────────────┤")
for key in ["entry", "mid", "premium"]:
t = tiers[key]
name = t["name"].ljust(15)
price = f"t['recommended_price']/mo".ljust(10)
pos = t["positioning"][:34].ljust(34)
print(f" │ {name} │ {price} │ {pos} │")
print(f" └─────────────────┴────────────┴────────────────────────────────────┘")
print(f"\n📈 REVENUE SCENARIOS (12-month projection)")
print(f" {'Scenario':<25} {'Mo 1 MRR':>10} {'Mo 6 MRR':>10} {'Mo 12 MRR':>10} {'12mo Total':>12}")
print(f" {'-'*67}")
for s in scenarios:
print(f" {s['scenario']:<25} "
f">9,.0f "
f">9,.0f "
f">9,.0f "
f">11,.0f")
print(f"\n🎯 RECOMMENDATION")
best = max(scenarios, key=lambda s: s['total_12mo_revenue'])
current = next((s for s in scenarios if s['scenario'] == 'Current pricing'), scenarios[0])
uplift = best['total_12mo_revenue'] - current['total_12mo_revenue']
print(f" Best scenario: {best['scenario']}")
print(f" 12-month uplift: ,.0f vs. current")
print(f" Note: Projections assume trial volume and churn hold constant.")
print(f" Test price increases on new customers first.")
print("\n" + "="*65 + "\n")
def main():
import argparse
parser = argparse.ArgumentParser(
description="Pricing modeler — projects revenue at different price points and recommends tier structure."
)
parser.add_argument(
"input_file", nargs="?", default=None,
help="JSON file with pricing data (default: run with sample data)"
)
parser.add_argument(
"--json", action="store_true",
help="Output results as JSON"
)
args = parser.parse_args()
if args.input_file:
with open(args.input_file) as f:
inputs = json.load(f)
else:
if not args.json:
print("No input file provided. Running with sample data...\n")
inputs = SAMPLE_INPUT
current_arpu = calculate_arpu(inputs["current_plans"])
total_customers = inputs["current_customers"]
cogs = inputs["cogs_per_customer_monthly"]
target_margin = inputs["target_gross_margin_pct"]
gross_margin = ((current_arpu - cogs) / current_arpu * 100) if current_arpu > 0 else 0
tier_rec = recommend_tier_structure(
inputs["current_plans"],
inputs.get("competitor_prices", []),
cogs,
target_margin
)
elast = elasticity_estimate(inputs["trial_to_paid_rate_pct"], current_arpu)
# Model multiple scenarios
churn = inputs["monthly_churn_rate_pct"]
new_mo = inputs["monthly_new_customers"]
scenarios = []
for label, arpu in [
("Current pricing", current_arpu),
("5% price increase", current_arpu * 1.05),
("15% price increase", current_arpu * 1.15),
("25% price increase", current_arpu * 1.25),
("Recommended tiers", tier_rec["mid"]["recommended_price"])
]:
proj = project_revenue_at_price(total_customers, current_arpu, arpu, new_mo, churn)
scenarios.append({"scenario": label, "arpu": round(arpu, 2), **proj})
result = {
"current_state": {
"current_mrr": inputs["current_mrr"],
"customers": total_customers,
"arpu": round(current_arpu, 2),
"gross_margin_pct": round(gross_margin, 1)
},
"elasticity": elast,
"tier_recommendation": tier_rec,
"price_scenarios": scenarios
}
print_report(result, inputs)
if args.json:
print(json.dumps(result, indent=2))
if __name__ == "__main__":
main()
Lập hồ sơ nghiên cứu công ty, cá nhân hoặc tổ chức theo giả thuyết đặt trước, phục vụ ra quyết định thay vì hồ sơ chung chung.
---
name: dossier
description: "Decision-grade entity research skill — produces a hypothesis-tested dossier on a specific company, person, nonprofit, or government org, not a generic profile. Forcing intake makes the user state their hypothesis upfront (what they already believe and want to verify or disprove) so the dossier tests it rather than confirms it. Output is an editable Word document (.docx) with verdict on the hypothesis, identity facts, 12-month activity timeline, network signals, reputation signals, red flags, 3-5 conversation hooks tied to specific findings, and source-provenance audit log. Uses WebSearch + WebFetch + free APIs (SEC EDGAR, GitHub, ProPublica Nonprofit Explorer) as workhorses; optional BYOK MCPs (LinkedIn, Crunchbase, Apollo, Pitchbook, SimilarWeb) enhance coverage. Triggers: 'research [company]', 'dossier on [person/company]', 'background check on [entity]', 'prep me for a meeting with [person/company]', 'due diligence on [company]', 'what should I know about [entity]', 'research [person] before I [meet/hire/invest]', 'competitor research on [company]', 'investor diligence [company]', 'interview prep for [company]'. Honors sensitivity exclusions for journalism + personal-vetting contexts."
license: MIT
metadata:
source_spec: "megaprompts/12-dossier-megaprompt.md"
build_pattern: "Path B (direct conversion)"
research_pack_convention: "Agent Integrity Rules verbatim per PR #657 audit; hypothesis-testing variant"
version: 1.0.0
---
# Dossier — Decision-Grade Entity Research
> **Portability:** Requires `WebSearch` + `WebFetch`, Node.js with `docx` package, and optionally `bash_tool` + `curl` for free APIs (SEC EDGAR, GitHub, ProPublica). BYOK MCPs (LinkedIn, Crunchbase, Apollo, Pitchbook, SimilarWeb) are optional enhancements. Works in Claude Code CLI natively.
## Non-Generic Framing — The Differentiator
This skill is **decision-grade entity research with hypothesis-testing**. It **refuses** to be "tell me about Microsoft". Every invocation forces the user to expose their hypothesis upfront (Q4) so the dossier *tests* it rather than confirms it.
The use case shape:
> "I'm pitching Microsoft Tuesday. My hypothesis is they're consolidating AI spend on their first-party Foundry platform. Validate or disprove, and give me three conversation hooks tied to what you find."
**NOT:**
> "Tell me about Microsoft."
The forcing Q4 — the hypothesis question — is the non-generic anchor. Skip it and the skill produces a Wikipedia summary.
See [`references/hypothesis_testing_discipline.md`](references/hypothesis_testing_discipline.md) for the canon.
## Agent Integrity Rules (Research-Pack Convention)
Locked verbatim per PR #657 audit.
- **Execution discipline.** Sequential search calls. WebSearch + WebFetch have looser rate limits than Consensus but still apply 1 q/sec etiquette. Confirm response received before next call.
- **Source discipline.** Cite only sources returned by this session's tool calls. Wikipedia / training knowledge labeled `[Background — verify before quoting]` and excluded from primary findings count.
- **Three-count tracking.** Queries sent / sources received / sources cited. Plus **per-tier breakdown** (primary / secondary / tertiary) unique to dossier. Surfaced in audit log.
- **Retry policy.** On failure → wait 3s → retry once → log. After 3 consecutive failures: stop, alert user.
- **Source reliability tier.** Each citation tagged primary (official, SEC, court records) / secondary (mainstream news, trade press) / tertiary (blogs, forums). DOCX surfaces tier on every flag.
## Phase 1: Grill-Me Intake (6 forcing questions, one at a time)
### Q1 (root) — Subject identity
> **Who is the subject? Give me the exact name and, if a company, the website or LinkedIn URL. If a person, their LinkedIn URL or a unique identifier (company affiliation + role).**
>
> *Why I'm asking:* Disambiguation. There are 47 John Smiths. There are three companies called "Atlas". I need a specific entity to research.
If user gives only a name, push for a second identifier. **Refuse to proceed on ambiguous names.**
### Q2 (depends on Q1) — Subject type
> **What kind of subject is this? Pick one: person / company / nonprofit / government org / other.**
>
> *Why I'm asking:* Different source matrices apply. For people I check LinkedIn, GitHub, Scholar, news; for companies I check SEC EDGAR (if public), Crunchbase, news, GitHub for tech orgs; for nonprofits I check Form 990s on ProPublica.
Forcing choice. "Other" requires a one-line description.
### Q3 (depends on Q2) — Purpose
> **What are you preparing for? Pick one:**
>
> 1. Sales meeting / partnership pitch
> 2. Investment diligence
> 3. Acquisition diligence
> 4. Journalism / due diligence
> 5. Job interview prep
> 6. Competitive intelligence
> 7. Personal vetting (date, hire, business partner)
> 8. Other (specify)
>
> *Why I'm asking:* The purpose dictates the angle, the depth, and the red-flag sensitivity. Sales prep needs conversation hooks. Investment diligence needs traction signals. Personal vetting needs careful sensitivity boundaries.
### Q4 (depends on Q3) — **Hypothesis — MANDATORY**
> **What's your hypothesis going in? What do you already believe about this subject, and what do you want to verify or disprove?**
>
> *Why I'm asking:* This is the critical question. A dossier that just confirms what you already think is worthless. By stating your hypothesis upfront, I can search for evidence that would *disprove* it as well as evidence that supports it — and give you a verdict you can actually use.
>
> Examples:
> - "I believe Microsoft is consolidating AI spend on first-party Foundry. Verify or disprove."
> - "I think the CEO is over their head — too much TAM talk, no traction. Test that."
> - "I believe this nonprofit's overhead ratio is sketchy. Check the 990s."
> - "I think this person is technical enough to handle a CTO role. Verify."
**MANDATORY.** If user says "I don't have one", push back **once**: "Then guess. Commit to a position you can update later. The dossier needs a hypothesis to test, otherwise it's a generic profile and won't help you make a decision."
If still refused: fall back to implicit hypothesis "what's the most surprising thing I could find?" and **flag the fallback in audit log**.
This question is **the non-generic anchor**. Skip it and the skill becomes a Wikipedia summary.
### Q5 (depends on Q3) — Depth
> **Time horizon: 5-minute brief or 15-minute decision-grade dossier?**
>
> *Why I'm asking:* Brief mode caps at ~10 searches and skips the network + reputation passes. Decision-grade goes deeper on every section. Pick based on how much skin you have in this decision.
Forcing choice.
### Q6 (asked only if Q3 ∈ {journalism, personal vetting}) — Sensitivities
> **Anything sensitive to exclude? E.g., personal medical, family details, political history, or specific topics off-limits?**
>
> *Why I'm asking:* Some research contexts have ethical constraints. I'd rather know upfront than surface something you'd never share.
Skip for sales/investment/acquisition/competitive intel (low sensitivity); ask for journalism/personal vetting (high sensitivity).
**Stop condition:** After Q6 (or earlier with dependency skips), commit and start Phase 2. Never re-open intake after Phase 2 begins.
## Phase 2: Subject Disambiguation
Before Phase 3, resolve the subject to a specific entity:
- For people: confirm LinkedIn URL OR (employer + role + city)
- For companies: confirm domain OR (legal name + incorporation jurisdiction)
- For nonprofits: confirm EIN OR (legal name + state)
- For government orgs: confirm official .gov URL
If still ambiguous after Q1 push-back: **halt and re-ask Q1** with disambiguating identifiers. Refuse to proceed.
## Phase 3: Source Matrix Selection
Routed by Q2 subject type. See [`references/subject_type_source_matrix.md`](references/subject_type_source_matrix.md) for the full canon.
### Person
- LinkedIn (manual fetch or LinkedIn MCP if BYOK)
- Personal website
- Twitter/X (rate-limited; degrade gracefully)
- GitHub (if technical subject)
- Google Scholar (if academic)
- News (WebSearch + WebFetch)
- Conference talk transcripts, podcasts (WebSearch)
### Company
- Official website (about, leadership, news, careers)
- SEC EDGAR (free API; 10-Ks, 10-Qs, 8-Ks for public co's)
- Crunchbase free tier (or Crunchbase MCP if BYOK)
- News (WebSearch + WebFetch)
- GitHub (for tech orgs)
- Glassdoor + Comparably (sentiment; degrade gracefully if scraping blocked)
- LinkedIn company page
### Nonprofit
- ProPublica Nonprofit Explorer (free; Form 990s)
- Official website
- News
- GuideStar (if accessible)
### Government org
- Official .gov sites
- News
- ProPublica (for federal agencies)
If a paid MCP is connected (Apollo, Pitchbook, SimilarWeb), use it but mark findings as **BYOK-sourced** in the audit log.
## Phase 4: Hypothesis-Driven Search
Every Phase 4 search MUST be classified as either:
- **Supporting evidence** (confirms hypothesis), OR
- **Disconfirming evidence** (would refute hypothesis)
**≥30% of search budget allocated to disconfirming queries.** Enforced via `scripts/disconfirming_evidence_balance.py`.
Example for hypothesis "Microsoft is consolidating AI spend on Foundry":
- **Supporting:** "Microsoft Foundry adoption 2026", "Microsoft AI infrastructure consolidation"
- **Disconfirming:** "Microsoft OpenAI deal renegotiation", "Microsoft AI vendor diversification", "Microsoft third-party model partnerships 2026"
This is what makes the dossier **decision-grade** rather than confirmation-biased.
For each search:
- Record via `citation_tracker.py` with classification (supporting / disconfirming)
- Apply source tier from `source_tier_classifier.py` to each result URL
## Phase 5: 12-Month Activity Timeline
Default 12-month window for activity timeline; deeper for foundational identity.
Categories:
- News (acquisitions, hires, departures, product launches)
- Funding rounds / financial events
- Controversies / legal events
- Public statements / strategy shifts
Reverse chronological. Each entry hyperlinked + tiered.
## Phase 6: Network + Reputation Signals
### Network
- **Companies:** investors (in/out), customers (named), partners
- **People:** co-founders, advisors, mentors, employers, board roles
- **Nonprofits:** funders, board, leadership
5-10 entries, ranked by **relevance to hypothesis**.
### Reputation
- Sentiment from news (recent 12 months)
- Glassdoor for companies (overall rating + 3 representative reviews)
- Peer mentions for people
- Caveat: reputation data is noisy; tier accordingly
## Phase 7: Red-Flag Pass
Surface but don't sensationalize:
- Litigation (court records → primary tier)
- Regulatory actions (SEC, DOJ, agency actions → primary)
- Unusual departures (key personnel exits within 90 days)
- Financial signals (going-concern notes in 10-Ks → primary)
- Reputation hits (sustained negative coverage → secondary)
**Each flag tiered.** Tier shows up next to every flag in the DOCX.
## Phase 8: Conversation Hook Generation
3-5 specific hooks tied to **actual findings**, not generic talking points.
See [`references/conversation_hook_quality.md`](references/conversation_hook_quality.md) for the canon.
| ❌ Generic | ✅ Finding-tied |
|---|---|
| "Ask about their roadmap" | "Mention their recent acquisition of [X] — it signals they're investing in vertical Y. Suggested framing: 'Saw the [X] announcement — how does that change your roadmap on Y?'" |
| "Ask about hiring" | "Their VP Engineering left 3 weeks ago (LinkedIn). Suggested framing: 'I noticed [name] moved on — what's the eng leadership plan?'" |
| "Talk about their values" | "They updated their pricing page last week (their official site). Suggested framing: 'Saw the pricing refresh — what drove that?'" |
Each hook:
- **The hook** (one sentence)
- **The finding it's tied to** (with hyperlink + tier)
- **Suggested framing** (verbatim phrasing user can adapt)
## Phase 9: DOCX Generation (9 Sections)
Via Node.js + `docx` library.
1. **Executive Summary** — one paragraph: who they are + why they matter + **verdict on the hypothesis** (SUPPORTED / PARTIALLY SUPPORTED / DISPROVEN / INCONCLUSIVE) + 3 things-you-should-know bullets.
2. **Identity Facts Table** — founded/born, location, size/stage, current role, key affiliations. All cells sourced; hover-text tier.
3. **Hypothesis Test** — user's hypothesis stated verbatim. Supporting evidence (3-5 bullets with hyperlinked citations). Disconfirming evidence (3-5 bullets with hyperlinked citations). Verdict paragraph (2-3 sentences explaining the weight).
4. **12-Month Activity Timeline** — News, funding, hires, departures, product launches, controversies. Reverse chronological. Each entry hyperlinked.
5. **Network Signals** — Collaborators / investors / associates. 5-10 entries, ranked by relevance to hypothesis.
6. **Reputation Signals** — Sentiment from news, Glassdoor for companies, peer mentions for people. Caveat: reputation data is noisy.
7. **Red Flags + Hidden Patterns** — Litigation, regulatory actions, unusual departures, financial signals, reputation hits. Tiered.
8. **Conversation Hooks** — 3-5 specific hooks tied to findings. Each: hook + finding + suggested framing.
9. **Source Provenance + Audit Log** — Per-source list with tier. Search summary table (#, query, classification, sources returned, sources cited). Three counts + per-tier counts. Failed searches. BYOK-MCP usage flag.
### Styling
Arial 12pt body, navy headings (#1a3a5c), light blue table headers (#e8f0f8), red red-flag callout, green conversation-hook callout.
### Hyperlink patterns
```js
new ExternalHyperlink({
link: "https://...",
children: [new TextRun({ text: title, style: "Hyperlink" })],
});
```
## Phase 10: Deliver
- Save: `<output-dir>/dossier_<entity-slug>_<YYYY-MM-DD>.docx`
- Chat summary: file path + **verdict on hypothesis** + audit counts + tier breakdown + BYOK MCPs used (if any)
- Validate: `python scripts/office/validate.py <docx>`
## Tooling
| Script | Role |
|---|---|
| `scripts/citation_tracker.py` | Three-count audit + supporting/disconfirming classification + source-tier tagging at `~/.dossier_sessions/<session>.json` |
| `scripts/disconfirming_evidence_balance.py` | Verifies ≥30% of search budget allocated to disconfirming queries; warns if biased |
| `scripts/source_tier_classifier.py` | URL → primary / secondary / tertiary classification via domain heuristics |
## References
- [`references/hypothesis_testing_discipline.md`](references/hypothesis_testing_discipline.md) — ≥30% rule + decision-grade vs encyclopedic (7+ sources)
- [`references/subject_type_source_matrix.md`](references/subject_type_source_matrix.md) — person/company/nonprofit/gov source matrices (7+ sources)
- [`references/conversation_hook_quality.md`](references/conversation_hook_quality.md) — finding-tied hook discipline (7+ sources)
## Error Handling
| Failure | Behavior |
|---|---|
| Subject name ambiguous | Refuse to proceed. Re-ask Q1 with disambiguating identifier. |
| User refuses to state hypothesis | Push back once. If still refused, fall back to "what's the most surprising thing I could find?" implicit hypothesis. Flag in audit. |
| Subject has zero public footprint | Surface explicitly. Suggest different name or early-stage. Don't fabricate. |
| LinkedIn scrape blocked | Note in audit; fall back to WebSearch; suggest user verify manually. |
| SEC EDGAR fails | Retry once. If still failing, note "public filings not retrieved" and continue. |
| Sentiment data sparse | Mark reputation section as "limited public signal"; don't infer from training. |
| Sensitive topic surfaces (Q6 exclusion) | Exclude from DOCX. Note in chat (not in DOCX) so user knows the exclusion was honored. |
| 3 consecutive tool failures | Stop, alert user, share collected so far. |
| DOCX generation fails | Save raw data as JSON fallback. |
## Anti-Patterns To Reject
- Producing a dossier without forcing Q4 hypothesis
- Allocating <30% of search budget to disconfirming evidence
- Batching intake questions
- Accepting ambiguous subject names
- Generic conversation hooks ("ask about their roadmap")
- Sensationalizing red flags (tier them, don't editorialize)
- Skipping the source-reliability tier on flags
- Fabricating coverage when LinkedIn or scraping is blocked
- Using BYOK-MCP data without flagging in audit log
- Including sensitive topics user excluded in Q6
- Confirmation-biased verdict ("SUPPORTED" without engaging with disconfirming evidence)
---
**Version:** 1.0.0
**Source spec:** [`megaprompts/12-dossier-megaprompt.md`](../../../../megaprompts/12-dossier-megaprompt.md)
**Build pattern:** Path B (direct conversion). Research-pack sibling, hypothesis-testing variant.
FILE:references/conversation_hook_quality.md
# Conversation Hook Quality — Finding-Tied vs Generic
This reference answers exactly one decision: **what makes a conversation hook (Section 8 of the dossier DOCX) useful enough to justify a meeting prep workflow?**
## The Core Frame
A conversation hook is useful when it:
1. References a **specific recent finding** (timestamped, sourced)
2. Provides **suggested framing** (verbatim phrasing the user can adapt)
3. Connects the finding to **the meeting's purpose** (sales pitch / investment / hire)
A generic hook is useful for nothing. "Ask about their roadmap" doesn't help the user — they already knew they could ask about that.
## The Quality Bar
A hook passes if all three are true:
✅ Specific finding from this dossier (with hyperlink)
✅ Suggested phrasing (1-2 sentences)
✅ Tied to user's hypothesis or meeting purpose
A hook fails if any of:
❌ Generic ("ask about their priorities")
❌ Unsourced ("they're probably hiring")
❌ Untimely (>6 months old finding without explicit recency note)
❌ Speculative ("they might be considering X")
❌ Not actionable in the meeting context
## Side-by-Side Examples
### Sales prep for AI infrastructure company
| ❌ Generic | ✅ Finding-tied |
|---|---|
| "Ask about their AI strategy." | "Mention their recent acquisition of Hugging Face vendor [X] (announced 2 weeks ago via TechCrunch). Suggested framing: *'Saw the [X] acquisition — how does that change your model deployment story?'*" |
| "Talk about pricing." | "Their pricing page was updated last Thursday (their official site). The change adds a per-token usage tier. Suggested framing: *'Noticed the new usage tier — was that customer-driven or competitive response?'*" |
| "Ask about their team." | "Their VP Eng [name] left 3 weeks ago (LinkedIn). Their job board posted a Director of AI Engineering req last Friday. Suggested framing: *'I noticed [name] moved on and you're hiring an AI Eng Director — what's the eng leadership focus shifting toward?'*" |
### Investment diligence on founder
| ❌ Generic | ✅ Finding-tied |
|---|---|
| "Test technical depth." | "She published 3 technical blog posts on her personal site this year (links in Section 1) on distributed systems. Suggested probe: *'Your post on consensus protocols was sharp — what's the actual implementation challenge you're hitting on [their startup]?'*" |
| "Check for red flags." | "Her co-founder left the company 4 months ago — no public statement either side (LinkedIn + her bio update). Suggested probe: *'I noticed [co-founder] is no longer listed — what's the founding-team story now?'*" |
| "Ask about market." | "They raised $5M seed in Feb 2024, now hiring 3 GTM roles (Crunchbase + LinkedIn). Suggested probe: *'You're staffing GTM heavily for a $5M seed — what's the pipeline that justifies that shape?'*" |
## Hook Construction Pattern
```
Hook = Finding + Suggested Framing + Tied-To-Purpose
Where:
Finding = specific event, statement, change, or signal (with URL + tier)
Suggested = verbatim 1-2 sentence question or comment user can adapt
Tied-To-Purpose = connection to Q3 purpose + Q4 hypothesis
```
## Anti-Patterns
### "Ask about their values/culture/roadmap/strategy"
These are generic openers, not conversation hooks. The user already knew they could ask about strategy. The hook should surface **specific evidence the user didn't have before**.
### "I suggest mentioning their recent quarter"
If the dossier doesn't cite a specific quarter result, this is speculation. Hooks must be evidence-anchored.
### "They might appreciate hearing about [generic topic]"
The hook should be about the user finding signal, not about the subject's preferences. Frame as: "Here's what the user just learned and can leverage."
### "Hooks tied to private/sensitive findings"
If Q6 (sensitivities) excluded family / medical / political, the hook also can't lean on those even tangentially. Check exclusions before drafting.
### "5+ hooks padding"
3-5 hooks is the sweet spot. More dilutes signal. If only 3 strong hooks emerge from findings, ship 3 — don't pad to 5 with weak ones.
### "Generic LinkedIn-style hook"
"I saw you went to Stanford — I went to Stanford too" — this is networking small-talk, not a substantive hook. Substantive hooks reveal the user did homework.
## Hook Tier (Implicit)
Hooks inherit the source tier of their underlying finding:
| Tier | Hook reliability |
|---|---|
| Primary (SEC, court, official site) | High — user can confidently lead with this |
| Secondary (mainstream news) | Medium — user can lead but acknowledge source |
| Tertiary (blog, forum) | Low — user should treat as soft signal, frame cautiously |
The DOCX tier-tag on each hook lets the user calibrate their conversational confidence.
## Hook Discipline by Purpose (Q3)
| Purpose | Hook flavor |
|---|---|
| Sales pitch | Lead with their recent moves; show you've done homework on their context |
| Investment diligence | Probe contradictions; surface red flags as questions, not accusations |
| Acquisition diligence | Test fit assumptions; ask about org culture + leadership stability |
| Journalism | Get them on the record about specific findings (named source + ask) |
| Interview prep | Show domain knowledge tied to their actual work, not generic praise |
| Competitive intelligence | (not for in-person meeting) — convert hooks to internal team briefing notes |
| Personal vetting | Generally skip hooks; vetting is a one-way information flow |
## Operational Checklist
- [ ] 3-5 hooks (not more, not fewer if findings support it)
- [ ] Each hook references a specific finding from this dossier
- [ ] Each finding has a hyperlink (Phase 4 search result)
- [ ] Each hook has suggested framing (1-2 sentences, verbatim adaptable)
- [ ] Each hook tied to Q3 purpose
- [ ] Each hook tiered (primary / secondary / tertiary based on underlying finding)
- [ ] No hook leans on Q6 excluded topics
- [ ] No hook is purely speculative or generic
## Citations (7 sources)
1. **Dale Carnegie, *How to Win Friends and Influence People* (1936).** The original "show genuine interest" framing. Conversation hooks operationalize this — but require specific evidence, not generic friendliness.
2. **Robert Cialdini, *Influence* (1984, multiple eds.).** Source for the "reciprocity" principle that hooks invoke. When the user signals they've done substantive homework, the subject reciprocates with substantive engagement.
3. **Chris Voss, *Never Split the Difference* (2016).** Source for the "calibrated question" pattern. Voss's "how" / "what" questions tied to specifics outperform generic "yes/no" questions. The dossier's suggested-framing examples follow this pattern.
4. **Daniel Goleman, *Working with Emotional Intelligence* (1998).** Source for the "social awareness" pillar of EI. Hooks operationalize this — surfacing recent specific context shows the user is reading the room.
5. **Patrick Lencioni, *The Five Dysfunctions of a Team* (2002).** Indirect source — Lencioni's "vulnerability-based trust" works because specific shared context creates faster intimacy than generic small-talk.
6. **Carmine Gallo, *Talk Like TED* (2014).** Source for the "lead with the surprising data point" rhetorical pattern. The strongest hooks open with a specific finding the subject didn't expect the user to know.
7. **Edgar Schein, *Humble Inquiry* (2013).** Source for the framing-as-question discipline. Hooks framed as questions ("how does that change your roadmap?") outperform hooks framed as observations ("interesting that you...") because questions invite reciprocal disclosure.
FILE:references/hypothesis_testing_discipline.md
# Hypothesis-Testing Discipline — Why ≥30% Disconfirming
This reference answers exactly one decision: **why does the dossier skill demand a hypothesis upfront and allocate ≥30% of search budget to disconfirming evidence?**
## The Core Claim
A dossier that confirms what the user already thinks is **worthless for decision-making**. Decisions hinge on the evidence that might falsify your model — that's where new information lives. A confirmation-biased dossier feels reassuring but doesn't move the user closer to a good decision.
The ≥30% disconfirming rule is the operational implementation of Karl Popper's falsifiability principle adapted to research workflows.
## Why the User Must State a Hypothesis (Q4 Mandatory)
Without a stated hypothesis, the skill can't:
1. Classify searches as supporting or disconfirming
2. Allocate budget to disconfirming queries
3. Produce a verdict (SUPPORTED / PARTIALLY / DISPROVEN / INCONCLUSIVE)
4. Test anything — by definition, you can only test a specific claim
The skill **refuses** to proceed without Q4 because the alternative is producing a Wikipedia summary marketed as decision-grade research.
### What "I don't have a hypothesis" really means
Usually one of:
- "I haven't thought about it yet" → push back once: "Then guess. Commit to a position you can update."
- "I want to be neutral" → false neutrality. Everyone has a prior; surfacing it is healthier than pretending not to.
- "I'm just curious" → use a different tool (web search, ChatGPT). Dossier is for decisions.
### Implicit-hypothesis fallback
If user STILL refuses after the push-back, fall back to:
> Implicit hypothesis: "What's the most surprising thing I could find about this entity that would change someone's prior?"
**Flag the fallback in audit log.** Users should know they got a less-rigorous version of the workflow.
## The ≥30% Rule
For every Phase 4 search, classify it:
- **Supporting** — would confirm the hypothesis if results favorable
- **Disconfirming** — would refute the hypothesis if results favorable
Then verify (via `scripts/disconfirming_evidence_balance.py`):
```
disconfirming_ratio = disconfirming_queries / total_queries
require: disconfirming_ratio >= 0.30
```
### Why 30%, not 50%?
50% (balanced supporting + disconfirming) is the textbook ideal but impractical:
- Many hypotheses have asymmetric search space (more supporting angles obvious; disconfirming requires creativity)
- Hypothesis statements are usually slightly true — pure 50/50 over-rotates to false-balance
30% is the empirical floor: enough disconfirming to surface real surprises, not so much that the dossier feels like a hatchet job.
### Why not 0% (skip the rule)?
LLMs are particularly prone to confirmation bias because:
- Plausible-sounding supporting evidence is easier to generate
- Users tend to accept confirmation more readily (less friction)
- The "feels right" signal is the same for confirmation and truth
Without the explicit ≥30% rule, dossiers drift to ~10% disconfirming. The rule forces the discipline.
## Constructing Disconfirming Queries
For each supporting query, construct a disconfirming counterpart:
| Hypothesis | Supporting | Disconfirming |
|---|---|---|
| "Microsoft consolidating AI on Foundry" | "Microsoft Foundry adoption" | "Microsoft AI vendor diversification" |
| "CEO is over their head" | "CEO Smith strategy failures" | "CEO Smith wins / traction" |
| "Nonprofit overhead is sketchy" | "Nonprofit X high overhead complaints" | "Nonprofit X program spending" |
| "This person is technical enough" | "Skills gaps in [person]" | "Technical accomplishments of [person]" |
The disconfirming queries seek **evidence that would refute the hypothesis**. They are NOT softer versions of the supporting query.
### Common construction patterns
- **Antonym pivot:** "consolidating" → "diversifying"
- **Counter-example search:** "failures" → "wins"
- **Negation:** "true" → "false claims about"
- **Comparison:** "X is best" → "X vs alternatives weakness"
- **Time-shift:** "now" → "5 years ago context"
- **Counter-stakeholder:** "investors say" → "critics say"
## The Verdict Categories
After Phase 4 search completes, classify the evidence weight:
| Verdict | Criterion |
|---|---|
| **SUPPORTED** | ≥2x more supporting evidence than disconfirming, both well-tiered |
| **PARTIALLY SUPPORTED** | More supporting than disconfirming but real disconfirming evidence exists |
| **DISPROVEN** | More disconfirming than supporting |
| **INCONCLUSIVE** | Roughly balanced OR insufficient evidence overall |
**Critical:** the verdict is determined by the **weight of evidence**, not by the count of queries. If 5 supporting queries each found weak tertiary blog posts and 2 disconfirming queries found SEC filings, the disconfirming evidence wins on tier.
`citation_tracker.py` tracks both quantity and tier per classification.
## Anti-Patterns
### "I'll just ask balanced questions"
Generic balanced questions ("what does the public say about Microsoft?") don't test the hypothesis. They produce a balanced profile, not a decision-grade dossier. The discipline is targeted disconfirming queries against a specific claim.
### "I found 10 supporting, 0 disconfirming — must be true"
Almost never. Either:
- The disconfirming queries weren't constructed (bias)
- The disconfirming search space wasn't explored (laziness)
- The hypothesis was trivially true (in which case, why use the skill?)
When this happens, the script alerts and prompts more disconfirming queries.
### "Disconfirming evidence found, but it's tertiary"
Tier matters more than quantity. 1 primary disconfirming source (SEC filing, court record) > 5 tertiary disconfirming sources (Reddit threads). The verdict weights tier explicitly.
### "Confirmation-biased verdict"
The most common failure: the dossier finds disconfirming evidence in Phase 4 but the Executive Summary says SUPPORTED anyway. The skill is wired to fail this — the verdict comes from `citation_tracker`'s tier-weighted classification, not from narrative.
### "Hypothesis vague enough that anything supports it"
"This person is competent" is too vague — almost everything supports it. The push-back: "Competent at what specifically? At managing a team of 50? At raising Series B? At public speaking?" Specificity in the hypothesis enables sharp disconfirming queries.
## Operational Checklist
- [ ] Q4 hypothesis stated (or implicit-hypothesis fallback flagged)
- [ ] Each Phase 4 query classified at issue time (supporting / disconfirming)
- [ ] Pre-flight check: ≥30% queries planned to be disconfirming
- [ ] Mid-flight check: after every 3 queries, run `disconfirming_evidence_balance.py`
- [ ] Post-flight check: final ratio ≥30%; halt + alert if not
- [ ] Verdict reflects tier-weighted balance, not raw quantity
- [ ] Section 3 of DOCX explicitly lists BOTH supporting + disconfirming evidence
- [ ] Audit log records classification per query
## Citations (7 sources)
1. **Karl Popper, *The Logic of Scientific Discovery* (1934, English 1959).** Foundational source for falsifiability. "A theory which is not refutable by any conceivable event is non-scientific." The dossier skill's hypothesis-testing discipline is Popper applied to research workflows.
2. **Daniel Kahneman, *Thinking, Fast and Slow* (FSG, 2011), Chapters 12-22.** Source for confirmation bias mechanics. The ≥30% rule exists specifically because System 1 thinking under-weights disconfirming evidence by default.
3. **Philip Tetlock, *Superforecasting* (Crown, 2015).** Empirical evidence that "active open-mindedness" (Tetlock's term for hypothesis-testing) is the #1 predictor of forecasting accuracy. Source for the "weight of evidence, not count" verdict rule.
4. **Robyn Dawes, *Rational Choice in an Uncertain World* (2001 2nd ed.).** Source for the decision-grade framing. "A decision is grade-A when it uses the available evidence to maximally update from prior." Without disconfirming evidence, no update is possible.
5. **Nassim Nicholas Taleb, *The Black Swan* (Random House, 2007).** Source for the "black swan" rationale — disconfirming evidence is often where the high-information surprises live. Confirmation-biased search systematically misses tail risks.
6. **Karl Popper, *Conjectures and Refutations* (1963).** Companion to *Logic of Scientific Discovery*. Source for the conjecture-and-refutation cycle that the skill implements: state hypothesis → seek refutation → revise.
7. **Daniel Levitin, *A Field Guide to Lies* (Dutton, 2016).** Practical applications of statistical and inferential reasoning. Source for the source-tier framework — primary sources (SEC, court records) outweigh tertiary sources (blogs, forums) for verdict determination.
FILE:references/subject_type_source_matrix.md
# Subject-Type Source Matrix — Person / Company / Nonprofit / Gov
This reference answers exactly one decision: **given the subject type (Q2), what sources does the dossier query in what order?**
## The Core Frame
Different entity types have different evidence sources with different reliability. Querying the wrong sources for the type produces noise; querying the right sources in the right order maximizes signal per query.
The matrix below is **comprehensive but selective** — not every source needs querying every time. Use Q3 (purpose) + Q5 (depth) to pick which subset.
## Person
### Primary tier
- **LinkedIn profile** (manual fetch or LinkedIn MCP if BYOK)
- **Personal website** (if exists)
- **Court records** (PACER, state court systems) — only for journalism/personal-vetting contexts
- **Academic publications** (Google Scholar) — for academics + technical people
### Secondary tier
- **News mentions** (WebSearch + WebFetch)
- **GitHub profile** (if technical subject)
- **Conference talks** (YouTube, conference sites)
- **Podcasts they appeared on** (WebSearch)
- **Books / articles they authored** (Amazon, JSTOR)
### Tertiary tier
- **Twitter/X** (rate-limited; degrade gracefully)
- **Reddit mentions**
- **Glassdoor reviews if they're a manager** (peers anonymous)
- **Personal blog posts**
### Subject-specific paths
| Purpose | Priority sources |
|---|---|
| Investment diligence on founder | LinkedIn + GitHub + court records + news |
| Interview prep for hiring | LinkedIn + GitHub + their public talks + writing |
| Personal vetting (date) | LinkedIn + news + court records (with Q6 exclusions) |
| Sales prep for pitch meeting | LinkedIn + recent public statements + their writing |
### Anti-patterns
- LinkedIn scraping without BYOK MCP — usually blocked; degrade gracefully
- Citing tertiary social media as primary signal (high noise)
- Ignoring publication / talk history for technical subjects (highest-signal source)
## Company
### Primary tier
- **Official website** (about, leadership, news, careers, pricing pages)
- **SEC EDGAR** (public companies) — 10-K, 10-Q, 8-K filings
- **Form 990** if foundation-affiliated
- **Court records** (litigation, regulatory) — federal + state
- **Patent filings** (USPTO + Google Patents) — for tech companies
### Secondary tier
- **Crunchbase free tier** (or Crunchbase MCP if BYOK)
- **News coverage** (WebSearch + WebFetch — major outlets)
- **Trade press** (TechCrunch, The Information, Stratechery for tech; Modern Healthcare for healthcare; etc.)
- **Investor letters / shareholder communications** (Berkshire, ARK, etc.)
- **Industry analyst reports** (if accessible)
### Tertiary tier
- **Glassdoor + Comparably** (employee sentiment — noisy but signal-y for trends)
- **Reddit / HN** (technical / startup sentiment)
- **LinkedIn company page**
- **GitHub** (for tech companies — repo activity signals)
### Subject-specific paths
| Purpose | Priority sources |
|---|---|
| Sales pitch | Official site + recent news + leadership + product launches |
| Investment diligence | SEC filings + Crunchbase + news + patent activity + financial trends |
| Acquisition diligence | SEC + court records + patent portfolio + Glassdoor (cultural fit) |
| Competitive intelligence | SEC + product launches + hiring patterns + patent activity |
| Journalism | Court records + SEC + regulatory actions + sources |
### Critical: SEC EDGAR for public companies
For US-listed companies, SEC EDGAR is **always primary tier** and **always free**:
```bash
curl 'https://data.sec.gov/submissions/CIK<10-digit-CIK>.json' \
-H 'User-Agent: dossier-skill <user-email>'
```
- 10-K = annual report (audited financials)
- 10-Q = quarterly report
- 8-K = material event (CEO change, M&A, etc.)
Going-concern notes in 10-Ks are critical red-flag signal.
## Nonprofit
### Primary tier
- **ProPublica Nonprofit Explorer** (free; Form 990s + 990-T) — the canonical source
- **GuideStar** (if accessible)
- **Official website** + their published impact reports
- **State Attorney General nonprofit registry** (state-specific)
### Secondary tier
- **News coverage**
- **Charity Navigator ratings**
- **GiveWell / EA evaluations** (if EA-adjacent)
- **Board affiliations** (LinkedIn + foundation database)
### Tertiary tier
- **Social media coverage**
- **Donor forums**
- **Reviews sites** (Charity Watch, etc.)
### Subject-specific paths
| Purpose | Priority sources |
|---|---|
| Donor diligence | Form 990 + impact reports + board + financial trends |
| Board diligence | Form 990 + board members + governance docs |
| Journalism | Form 990 + court records + state AG actions + sources |
### Form 990 key metrics
- **Overhead ratio** (program / total expenses) — but beware: too-low can signal misclassification
- **Executive compensation** (Form 990 Schedule J)
- **Independent board %** — for governance signal
- **Related-party transactions** (Schedule L)
- **Going-concern notes** if any
## Government Org
### Primary tier
- **Official .gov website**
- **Federal Register notices** (regulations, rules)
- **GAO reports** (Government Accountability Office)
- **OIG reports** (Office of Inspector General per agency)
- **Congressional testimony / hearings**
### Secondary tier
- **News coverage** (especially WaPo, ProPublica federal beat)
- **ProPublica federal agency tracking**
- **Think tank reports** (Brookings, AEI, Heritage, etc.)
### Tertiary tier
- **Reddit / forum coverage**
- **Op-eds**
### Subject-specific paths
| Purpose | Priority sources |
|---|---|
| Federal contractor diligence | SAM.gov + agency procurement records + GAO + news |
| Journalism | GAO + OIG + Congressional + court records + sources |
| Lobbying targeting | LDA filings + agency contacts + hearings |
## BYOK MCP Enhancement
Paid MCPs (Apollo, Pitchbook, SimilarWeb, LinkedIn) add data but **must be flagged in audit log**:
| MCP | What it adds |
|---|---|
| LinkedIn | Person profile completeness, employment history accuracy |
| Crunchbase | Funding rounds, board, M&A activity for private companies |
| Apollo | Contact data, intent signals for sales contexts |
| Pitchbook | Deep private-market data, comparables |
| SimilarWeb | Traffic + competitive intelligence for digital businesses |
The audit log marks every BYOK-sourced finding with `[BYOK: <MCP-name>]` so the reader knows the provenance and can request verification through their own MCP access if needed.
## Sequential vs Parallel Discipline
Per research-pack convention: **sequential** with 1 q/sec etiquette. WebSearch + WebFetch tolerate higher rates than Consensus, but sequential keeps the skill robust to provider rate-limit shifts.
For multi-query subjects (companies with many available sources), Phase 4 might run 8-15 sequential queries. Total wall-clock: 10-20 seconds for queries; longer for fetches.
## Degradation Strategy
When a source fails:
| Source | If unavailable |
|---|---|
| LinkedIn | Fall back to WebSearch for headline facts; suggest user verify manually |
| SEC EDGAR | Retry once; if still down, note "public filings not retrieved" |
| Crunchbase | Use news + LinkedIn + WebSearch for funding rounds |
| ProPublica | Direct IRS query (slower); or note nonprofit data partial |
| Twitter/X | Skip; note in audit |
Never fabricate coverage when source is blocked. Always document the gap.
## Citations (7 sources)
1. **SEC EDGAR API documentation — https://www.sec.gov/edgar/sec-api-documentation.** Source for the public-company primary-tier discipline. EDGAR is the only free source for audited financial truth on US public companies.
2. **ProPublica Nonprofit Explorer — https://projects.propublica.org/nonprofits/.** Authoritative free source for Form 990 data. The primary tier source for any US nonprofit research.
3. **Federal Information Processing Standards (FIPS) + open-data.gov.** Source for government-org querying patterns. Federal Register + GAO + OIG are publicly-accessible primary sources.
4. **Heydon Pickering, *Inclusive Design Patterns* (2016).** Source for the "degrade gracefully when source fails" pattern. The skill applies progressive enhancement: query best source first, fall back to lower tiers when blocked.
5. **Bruce Schneier, *Beyond Fear* (2003).** Source for the BYOK-MCP audit-log flagging discipline. Provenance matters; users have a right to know which data came from which provider.
6. **OWASP Web Security Testing Guide.** Source for the user-agent + rate-limit etiquette in API calls. SEC EDGAR specifically requires User-Agent header with contact info; respecting these terms prevents access loss.
7. **Charity Navigator + GiveWell methodology pages.** Source for nonprofit-evaluation metrics (overhead ratio, exec comp, independent board %). The skill mirrors their established metric set rather than inventing new criteria.
FILE:scripts/citation_tracker.py
#!/usr/bin/env python3
"""citation_tracker.py — Hypothesis-testing three-count audit + tier tagging.
Stdlib-only. Extended for dossier's hypothesis-testing discipline:
- searches (sent)
- sources received (raw count across all queries)
- sources cited (made it into DOCX)
- Per query: supporting / disconfirming / inconclusive classification
- Per cited source: primary / secondary / tertiary tier
Enables the ≥30% disconfirming rule via `disconfirming_evidence_balance.py`.
Enables verdict determination via tier-weighted balance.
Sessions persist at ~/.dossier_sessions/<session>.json.
Usage:
python citation_tracker.py --action start --session dossier-MS-20260515 --subject "Microsoft" --hypothesis "consolidating AI on Foundry"
python citation_tracker.py --action record_search --session ... --query "..." --classification supporting
python citation_tracker.py --action record_search --session ... --query "..." --classification disconfirming
python citation_tracker.py --action record_received --session ... --count 12
python citation_tracker.py --action record_cited --session ... --url "https://..." --tier primary --classification supporting
python citation_tracker.py --action status --session ...
python citation_tracker.py --action close --session ...
"""
import argparse
import json
import sys
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Dict, List, Optional
SESSIONS_DIR = Path.home() / ".dossier_sessions"
VALID_CLASSIFICATIONS = ["supporting", "disconfirming", "inconclusive"]
VALID_TIERS = ["primary", "secondary", "tertiary"]
def session_path(name: str) -> Path:
return SESSIONS_DIR / f"{name}.json"
def load_session(name: str) -> Dict[str, Any]:
p = session_path(name)
if not p.exists():
raise FileNotFoundError(f"Session not found: {name}")
return json.loads(p.read_text(encoding="utf-8"))
def save_session(name: str, data: Dict[str, Any]) -> None:
SESSIONS_DIR.mkdir(parents=True, exist_ok=True)
session_path(name).write_text(json.dumps(data, indent=2), encoding="utf-8")
def now_iso() -> str:
return datetime.now(timezone.utc).isoformat()
def action_start(name: str, subject: Optional[str], hypothesis: Optional[str], purpose: Optional[str]) -> Dict[str, Any]:
if session_path(name).exists():
raise FileExistsError(f"Session already exists: {name}")
data: Dict[str, Any] = {
"session": name,
"subject": subject or "",
"hypothesis": hypothesis or "",
"hypothesis_is_implicit_fallback": False,
"purpose": purpose or "",
"started_at": now_iso(),
"ended_at": None,
"searches": [],
"received_log": [],
"cited": [],
"counts": {
"searches": 0,
"supporting_searches": 0,
"disconfirming_searches": 0,
"inconclusive_searches": 0,
"received_total": 0,
"cited_total": 0,
"cited_primary": 0,
"cited_secondary": 0,
"cited_tertiary": 0,
"cited_supporting": 0,
"cited_disconfirming": 0,
"cited_inconclusive": 0,
},
"byok_mcps_used": [],
}
save_session(name, data)
return data
def action_record_search(name: str, query: str, classification: str) -> Dict[str, Any]:
data = load_session(name)
if classification not in VALID_CLASSIFICATIONS:
raise ValueError(f"Invalid classification '{classification}'. Pick from: {VALID_CLASSIFICATIONS}")
data["searches"].append({"query": query, "classification": classification, "at": now_iso()})
data["counts"]["searches"] += 1
data["counts"][f"{classification}_searches"] += 1
save_session(name, data)
return data
def action_record_received(name: str, count: int) -> Dict[str, Any]:
data = load_session(name)
data["received_log"].append({"count": count, "at": now_iso()})
data["counts"]["received_total"] += count
save_session(name, data)
return data
def action_record_cited(name: str, url: str, tier: str, classification: str, title: Optional[str]) -> Dict[str, Any]:
data = load_session(name)
if tier not in VALID_TIERS:
raise ValueError(f"Invalid tier '{tier}'. Pick from: {VALID_TIERS}")
if classification not in VALID_CLASSIFICATIONS:
raise ValueError(f"Invalid classification '{classification}'. Pick from: {VALID_CLASSIFICATIONS}")
if any(c["url"] == url for c in data["cited"]):
return data
data["cited"].append({"url": url, "tier": tier, "classification": classification, "title": title, "at": now_iso()})
data["counts"]["cited_total"] += 1
data["counts"][f"cited_{tier}"] += 1
data["counts"][f"cited_{classification}"] += 1
save_session(name, data)
return data
def action_mark_implicit_fallback(name: str) -> Dict[str, Any]:
data = load_session(name)
data["hypothesis_is_implicit_fallback"] = True
save_session(name, data)
return data
def action_record_byok(name: str, mcp_name: str) -> Dict[str, Any]:
data = load_session(name)
if mcp_name not in data["byok_mcps_used"]:
data["byok_mcps_used"].append(mcp_name)
save_session(name, data)
return data
def action_status(name: str) -> Dict[str, Any]:
return load_session(name)
def action_close(name: str) -> Dict[str, Any]:
data = load_session(name)
if data.get("ended_at") is None:
data["ended_at"] = now_iso()
save_session(name, data)
return data
def compute_verdict(data: Dict[str, Any]) -> str:
"""Tier-weighted verdict from cited evidence."""
c = data["counts"]
# Tier weights: primary=3, secondary=2, tertiary=1
# But we only have per-tier totals + per-classification totals (not crossed)
# Approximate: assume tier distribution is uniform across classifications
# For exact: would need full per-citation iteration
support = c["cited_supporting"]
disconfirm = c["cited_disconfirming"]
total = support + disconfirm
if total < 3:
return "INCONCLUSIVE"
if support >= 2 * disconfirm:
return "SUPPORTED"
if disconfirm > support:
return "DISPROVEN"
return "PARTIALLY SUPPORTED"
def disconfirming_ratio(data: Dict[str, Any]) -> float:
c = data["counts"]
if c["searches"] == 0:
return 0.0
return c["disconfirming_searches"] / c["searches"]
def render_status_human(data: Dict[str, Any]) -> str:
out: List[str] = []
out.append(f"Session: {data['session']}")
out.append(f"Subject: {data.get('subject', '(unset)')}")
out.append(f"Hypothesis: {data.get('hypothesis', '(unset)')}")
if data.get("hypothesis_is_implicit_fallback"):
out.append(f" [IMPLICIT FALLBACK — user did not state explicit hypothesis]")
out.append(f"Purpose: {data.get('purpose', '(unset)')}")
out.append(f"BYOK MCPs used: {', '.join(data.get('byok_mcps_used', [])) or '(none)'}")
out.append("")
c = data["counts"]
out.append("Search counts:")
out.append(f" Total searches: {c['searches']}")
out.append(f" Supporting: {c['supporting_searches']}")
out.append(f" Disconfirming: {c['disconfirming_searches']}")
out.append(f" Inconclusive: {c['inconclusive_searches']}")
ratio = disconfirming_ratio(data) * 100
rule_status = "✓ meets ≥30% rule" if ratio >= 30 else "✗ BELOW 30% — confirmation bias risk"
out.append(f" Disconfirming ratio: {ratio:.0f}% {rule_status}")
out.append("")
out.append("Citation counts:")
out.append(f" Total received: {c['received_total']}")
out.append(f" Total cited: {c['cited_total']}")
out.append(f" By tier — primary: {c['cited_primary']}")
out.append(f" secondary: {c['cited_secondary']}")
out.append(f" tertiary: {c['cited_tertiary']}")
out.append(f" By classification — supporting: {c['cited_supporting']}")
out.append(f" disconfirming: {c['cited_disconfirming']}")
out.append(f" inconclusive: {c['cited_inconclusive']}")
out.append("")
out.append(f"Verdict (tier-weighted): **{compute_verdict(data)}**")
out.append("")
out.append("Audit block for DOCX Section 9:")
out.append(
f" Queries sent: {c['searches']} ({c['supporting_searches']} supporting / {c['disconfirming_searches']} disconfirming / {c['inconclusive_searches']} inconclusive). "
f"Sources received: {c['received_total']}. Sources cited: {c['cited_total']} "
f"({c['cited_primary']} primary / {c['cited_secondary']} secondary / {c['cited_tertiary']} tertiary). "
f"Disconfirming ratio: {ratio:.0f}%. Verdict: {compute_verdict(data)}."
)
return "\n".join(out)
def main(argv: List[str]) -> int:
parser = argparse.ArgumentParser(description=__doc__.split("\n")[0])
parser.add_argument(
"--action",
required=True,
choices=[
"start", "record_search", "record_received", "record_cited",
"mark_implicit_fallback", "record_byok",
"status", "list", "close",
],
)
parser.add_argument("--session")
parser.add_argument("--subject")
parser.add_argument("--hypothesis")
parser.add_argument("--purpose")
parser.add_argument("--query")
parser.add_argument("--classification", choices=VALID_CLASSIFICATIONS)
parser.add_argument("--count", type=int)
parser.add_argument("--url")
parser.add_argument("--tier", choices=VALID_TIERS)
parser.add_argument("--title")
parser.add_argument("--mcp", help="(record_byok only) MCP name")
parser.add_argument("--output", choices=["human", "json"], default="human")
args = parser.parse_args(argv)
try:
if args.action == "start":
result = action_start(args.session, args.subject, args.hypothesis, args.purpose)
elif args.action == "record_search":
result = action_record_search(args.session, args.query, args.classification)
elif args.action == "record_received":
result = action_record_received(args.session, args.count)
elif args.action == "record_cited":
result = action_record_cited(args.session, args.url, args.tier, args.classification, args.title)
elif args.action == "mark_implicit_fallback":
result = action_mark_implicit_fallback(args.session)
elif args.action == "record_byok":
result = action_record_byok(args.session, args.mcp)
elif args.action == "status":
result = action_status(args.session)
elif args.action == "close":
result = action_close(args.session)
else:
SESSIONS_DIR.mkdir(parents=True, exist_ok=True)
result = [
{"session": p.stem, **{k: v for k, v in json.loads(p.read_text(encoding="utf-8")).items() if k in ("subject", "started_at", "ended_at", "counts")}}
for p in sorted(SESSIONS_DIR.glob("*.json"))
]
except (FileNotFoundError, FileExistsError, ValueError) as e:
print(f"error: {e}", file=sys.stderr); return 2
if args.output == "json":
print(json.dumps(result, indent=2, default=str))
else:
if args.action == "list":
print(json.dumps(result, indent=2, default=str))
else:
print(render_status_human(result))
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
FILE:scripts/disconfirming_evidence_balance.py
#!/usr/bin/env python3
"""disconfirming_evidence_balance.py — Enforce ≥30% disconfirming search budget.
Stdlib-only. The dossier skill's non-negotiable: ≥30% of Phase 4 searches must
be classified as disconfirming (would refute the hypothesis if results favorable).
Reads from a dossier session JSON (created by `citation_tracker.py`) and:
- Returns PASS if disconfirming_ratio >= 0.30
- Returns WARN if 0.20 <= ratio < 0.30 (recoverable; surface to user)
- Returns FAIL if ratio < 0.20 (confirmation bias; halt + remediate)
Outputs suggested disconfirming queries to add (based on antonym-pivot heuristic
from references/hypothesis_testing_discipline.md).
NO LLM CALLS. Pure ratio math + heuristic suggestions.
Usage:
python disconfirming_evidence_balance.py --session dossier-MS-20260515
python disconfirming_evidence_balance.py --session ... --output json
python disconfirming_evidence_balance.py --sample
"""
import argparse
import json
import sys
from pathlib import Path
from typing import Any, Dict, List, Optional
SESSIONS_DIR = Path.home() / ".dossier_sessions"
MIN_RATIO = 0.30
WARN_RATIO = 0.20
# Antonym-pivot heuristics for constructing disconfirming queries
DISCONFIRMING_PIVOTS = {
"consolidating": ["diversifying", "splitting", "decentralizing"],
"growing": ["shrinking", "declining", "stagnating"],
"winning": ["losing", "failing", "underperforming"],
"successful": ["failed", "unsuccessful", "struggling"],
"expanding": ["contracting", "exiting", "retreating from"],
"strong": ["weak", "missing"],
"leading": ["trailing", "lagging"],
"innovating": ["copying", "lagging behind"],
"investing in": ["divesting", "exiting"],
"hiring": ["laying off", "departures from"],
}
def suggest_disconfirming_queries(hypothesis: str, supporting_queries: List[str]) -> List[str]:
"""Heuristic: for each supporting term, suggest antonym-pivoted disconfirming."""
suggestions: List[str] = []
hyp_lower = hypothesis.lower()
for pivot, antonyms in DISCONFIRMING_PIVOTS.items():
if pivot in hyp_lower:
for antonym in antonyms[:2]: # first 2 only to avoid noise
disconfirming = hyp_lower.replace(pivot, antonym)
suggestions.append(disconfirming)
if not suggestions:
# Generic fallback patterns
suggestions.append(f"counter-evidence to: {hypothesis}")
suggestions.append(f"critics of {hypothesis}")
suggestions.append(f"failures contradicting {hypothesis}")
return suggestions[:5]
def analyze(session_data: Dict[str, Any]) -> Dict[str, Any]:
c = session_data.get("counts", {})
total = c.get("searches", 0)
supporting = c.get("supporting_searches", 0)
disconfirming = c.get("disconfirming_searches", 0)
inconclusive = c.get("inconclusive_searches", 0)
if total == 0:
return {
"verdict": "INSUFFICIENT_DATA",
"ratio": 0.0,
"total_searches": 0,
"supporting": 0,
"disconfirming": 0,
"inconclusive": 0,
"rule_floor": MIN_RATIO,
"message": "No searches recorded yet. Run Phase 4 first.",
"remediation_needed": False,
}
ratio = disconfirming / total
needed_disconfirming = max(0, int((MIN_RATIO * total) - disconfirming + 0.999)) # ceiling
if ratio >= MIN_RATIO:
verdict = "PASS"
message = f"Disconfirming ratio {ratio:.0%} meets ≥{MIN_RATIO:.0%} floor. Decision-grade balance OK."
remediation_needed = False
suggested = []
elif ratio >= WARN_RATIO:
verdict = "WARN"
message = (
f"Disconfirming ratio {ratio:.0%} is below ≥{MIN_RATIO:.0%} floor "
f"but above {WARN_RATIO:.0%} threshold. Recoverable — add {needed_disconfirming} "
f"disconfirming queries to reach floor."
)
remediation_needed = True
suggested = suggest_disconfirming_queries(
session_data.get("hypothesis", ""),
[s["query"] for s in session_data.get("searches", []) if s.get("classification") == "supporting"]
)
else:
verdict = "FAIL"
message = (
f"Disconfirming ratio {ratio:.0%} below {WARN_RATIO:.0%} — confirmation bias risk is real. "
f"HALT + add {needed_disconfirming} disconfirming queries before generating DOCX. "
f"A SUPPORTED verdict at this ratio is not credible."
)
remediation_needed = True
suggested = suggest_disconfirming_queries(
session_data.get("hypothesis", ""),
[s["query"] for s in session_data.get("searches", []) if s.get("classification") == "supporting"]
)
return {
"verdict": verdict,
"ratio": ratio,
"rule_floor": MIN_RATIO,
"total_searches": total,
"supporting": supporting,
"disconfirming": disconfirming,
"inconclusive": inconclusive,
"disconfirming_needed_to_reach_floor": needed_disconfirming,
"message": message,
"remediation_needed": remediation_needed,
"suggested_disconfirming_queries": suggested,
}
SAMPLE_SESSION = {
"session": "sample-dossier",
"subject": "Microsoft",
"hypothesis": "Microsoft is consolidating AI spend on Foundry platform",
"counts": {
"searches": 10,
"supporting_searches": 8,
"disconfirming_searches": 2,
"inconclusive_searches": 0,
},
"searches": [
{"query": "Microsoft Foundry adoption 2026", "classification": "supporting"},
{"query": "Microsoft AI consolidation strategy", "classification": "supporting"},
],
}
def render_human(result: Dict[str, Any]) -> str:
out: List[str] = []
out.append(f"Disconfirming evidence balance: {result['verdict']}")
out.append(f" Total searches: {result['total_searches']}")
out.append(f" Supporting: {result['supporting']}")
out.append(f" Disconfirming: {result['disconfirming']}")
out.append(f" Inconclusive: {result['inconclusive']}")
out.append(f" Ratio (disconfirming/total): {result['ratio']:.0%}")
out.append(f" Rule floor: {result['rule_floor']:.0%}")
if result.get('disconfirming_needed_to_reach_floor', 0) > 0:
out.append(f" Disconfirming queries to add: {result['disconfirming_needed_to_reach_floor']}")
out.append("")
out.append(result["message"])
if result.get("suggested_disconfirming_queries"):
out.append("")
out.append("Suggested disconfirming queries (antonym-pivot from hypothesis):")
for q in result["suggested_disconfirming_queries"]:
out.append(f" - {q}")
return "\n".join(out)
def main(argv: List[str]) -> int:
parser = argparse.ArgumentParser(description=__doc__.split("\n")[0])
parser.add_argument("--session", help="Session name (in ~/.dossier_sessions/)")
parser.add_argument("--sample", action="store_true", help="Analyze embedded sample data (10 searches, 80% supporting)")
parser.add_argument("--output", choices=["human", "json"], default="human")
args = parser.parse_args(argv)
if args.sample:
data = SAMPLE_SESSION
elif args.session:
p = SESSIONS_DIR / f"{args.session}.json"
if not p.exists():
print(f"error: session not found at {p}", file=sys.stderr); return 2
try:
data = json.loads(p.read_text(encoding="utf-8"))
except json.JSONDecodeError as e:
print(f"error: invalid session JSON: {e}", file=sys.stderr); return 2
else:
parser.print_help(); return 0
result = analyze(data)
if args.output == "json":
print(json.dumps(result, indent=2))
else:
print(render_human(result))
if result["verdict"] == "FAIL":
return 1
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
FILE:scripts/source_tier_classifier.py
#!/usr/bin/env python3
"""source_tier_classifier.py — URL → primary/secondary/tertiary tier.
Stdlib-only. Classifies a source URL into reliability tier based on domain
heuristics. The dossier skill uses tier on every flag in the DOCX so reviewers
can calibrate confidence.
Tiers:
- PRIMARY: Official, regulatory, court records, SEC EDGAR, .gov, company
official site, academic publications (peer-reviewed)
- SECONDARY: Mainstream news (NYT, WSJ, Reuters), trade press, established
publications (TechCrunch, The Information, Stratechery)
- TERTIARY: Blogs, forums, social media, user-generated content (Reddit, HN,
Glassdoor, Medium, personal blogs)
NO LLM CALLS. Pure domain pattern matching.
Usage:
python source_tier_classifier.py --url "https://www.sec.gov/cgi-bin/browse-edgar?..."
python source_tier_classifier.py --url "https://news.ycombinator.com/item?id=..."
python source_tier_classifier.py --sample
"""
import argparse
import json
import re
import sys
from typing import Any, Dict, List, Optional
from urllib.parse import urlparse
# Pattern-based tier assignment. Most specific patterns first.
PRIMARY_DOMAIN_EXACT = {
"sec.gov", "data.sec.gov", "www.sec.gov",
"courtlistener.com", "pacer.gov",
"uspto.gov", "patents.google.com", # patents.google.com indexes USPTO data
"fda.gov", "cdc.gov", "nih.gov", "grants.nih.gov", "reporter.nih.gov",
"federalregister.gov", "regulations.gov",
"gao.gov", "oig.gov",
"irs.gov",
"sec.org", # generic .org for SEC alternates
}
PRIMARY_DOMAIN_SUFFIX = [
".gov", # any government domain
".mil", # military
".edu", # academic (caveat: some .edu content is tertiary, but most institutional pages are primary)
]
PRIMARY_DOMAIN_CONTAINS = [
"projects.propublica.org/nonprofits", # ProPublica Nonprofit Explorer (free Form 990 access)
]
# Academic publication primary sources
PRIMARY_ACADEMIC = {
"nature.com", "science.org", "nejm.org", "thelancet.com", "jamanetwork.com",
"pnas.org", "bmj.com", "cell.com", "plos.org",
"scholar.google.com", # indexes peer-reviewed; treat as primary
}
# Mainstream news (secondary)
SECONDARY_NEWS = {
"nytimes.com", "wsj.com", "ft.com", "reuters.com", "ap.org", "apnews.com",
"bbc.com", "bbc.co.uk", "theguardian.com", "economist.com",
"washingtonpost.com", "latimes.com", "bloomberg.com",
"cnbc.com", "abcnews.go.com", "nbcnews.com", "cbsnews.com",
}
# Trade press / established tech publications (secondary)
SECONDARY_TRADE = {
"techcrunch.com", "theverge.com", "wired.com", "arstechnica.com",
"theinformation.com", "stratechery.com",
"axios.com", "politico.com",
"forbes.com", # mixed quality, but generally secondary
"modernhealthcare.com", "healthcareitnews.com",
"law360.com", "natlawreview.com",
}
# Trade-press journalism orgs (secondary)
SECONDARY_INVESTIGATIVE = {
"propublica.org", "icij.org", # ProPublica investigative reporting (separate from Nonprofit Explorer)
}
# Tertiary indicators
TERTIARY_DOMAIN_EXACT = {
"reddit.com", "old.reddit.com", "news.ycombinator.com",
"medium.com", "dev.to", "substack.com",
"twitter.com", "x.com",
"linkedin.com", # public posts; profiles separately primary for the subject
"glassdoor.com", "indeed.com", "comparably.com",
"quora.com", "stackoverflow.com",
"facebook.com", "instagram.com", "tiktok.com",
}
TERTIARY_PATTERN = [
re.compile(r".*\.medium\.com$"),
re.compile(r".*\.substack\.com$"),
re.compile(r".*\.blogspot\.com$"),
re.compile(r".*\.wordpress\.com$"),
re.compile(r".*\.tumblr\.com$"),
]
# Company-official site detection (primary IF the dossier subject)
# Generic patterns:
def is_likely_company_official(domain: str, subject_keywords: List[str]) -> bool:
"""If the domain contains the subject's name and isn't a known news/blog, it's likely official."""
if not subject_keywords:
return False
domain_lower = domain.lower()
for kw in subject_keywords:
if kw.lower() in domain_lower:
return True
return False
def classify(url: str, subject_keywords: Optional[List[str]] = None) -> Dict[str, Any]:
if not url or not url.strip():
return {"tier": "unknown", "url": url, "rationale": "Empty URL"}
try:
parsed = urlparse(url)
except Exception as e:
return {"tier": "unknown", "url": url, "rationale": f"URL parse failed: {e}"}
domain = parsed.netloc.lower()
# Strip 'www.' prefix for matching
if domain.startswith("www."):
domain_no_www = domain[4:]
else:
domain_no_www = domain
# Strip port if present
domain = domain.split(":")[0]
domain_no_www = domain_no_www.split(":")[0]
# Check exact-match tiers first
if domain in PRIMARY_DOMAIN_EXACT or domain_no_www in PRIMARY_DOMAIN_EXACT:
return {"tier": "primary", "url": url, "rationale": f"Domain {domain} is in primary exact-match list (regulatory/court/official)"}
if domain in PRIMARY_ACADEMIC or domain_no_www in PRIMARY_ACADEMIC:
return {"tier": "primary", "url": url, "rationale": f"Domain {domain} is a peer-reviewed academic publication"}
if domain in SECONDARY_NEWS or domain_no_www in SECONDARY_NEWS:
return {"tier": "secondary", "url": url, "rationale": f"Domain {domain} is a mainstream news outlet"}
if domain in SECONDARY_TRADE or domain_no_www in SECONDARY_TRADE:
return {"tier": "secondary", "url": url, "rationale": f"Domain {domain} is established trade press"}
if domain in SECONDARY_INVESTIGATIVE or domain_no_www in SECONDARY_INVESTIGATIVE:
return {"tier": "secondary", "url": url, "rationale": f"Domain {domain} is investigative journalism"}
if domain in TERTIARY_DOMAIN_EXACT or domain_no_www in TERTIARY_DOMAIN_EXACT:
return {"tier": "tertiary", "url": url, "rationale": f"Domain {domain} is user-generated content (forum/social/review)"}
# Pattern checks
for pattern in TERTIARY_PATTERN:
if pattern.match(domain):
return {"tier": "tertiary", "url": url, "rationale": f"Domain {domain} matches tertiary pattern (blog hosting platform)"}
# Suffix checks
for suffix in PRIMARY_DOMAIN_SUFFIX:
if domain.endswith(suffix):
return {"tier": "primary", "url": url, "rationale": f"Domain {domain} has primary-tier suffix '{suffix}'"}
# Contains checks
for pattern in PRIMARY_DOMAIN_CONTAINS:
if pattern in url.lower():
return {"tier": "primary", "url": url, "rationale": f"URL contains primary-tier pattern '{pattern}'"}
# Company-official heuristic (if subject keywords provided)
if subject_keywords and is_likely_company_official(domain, subject_keywords):
return {"tier": "primary", "url": url, "rationale": f"Domain {domain} appears to be the subject's official site (matches subject keywords)"}
# Default for unknown: secondary (give benefit of doubt to legitimate-looking news/site)
# But add a confidence note
return {
"tier": "secondary",
"url": url,
"rationale": f"Domain {domain} not in known lists; defaulting to secondary. Manual review recommended for high-stakes citations.",
"confidence": "low",
}
SAMPLE_URLS = [
"https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK=0000789019",
"https://www.nytimes.com/2026/05/15/tech/microsoft-ai-strategy.html",
"https://techcrunch.com/2026/05/01/microsoft-acquires-startup-x/",
"https://news.ycombinator.com/item?id=123456",
"https://glassdoor.com/Reviews/Microsoft-Corp-E1651.htm",
"https://medium.com/@author/microsoft-foundry-deep-dive",
"https://www.microsoft.com/en-us/about",
"https://projects.propublica.org/nonprofits/organizations/123456789",
"https://scholar.google.com/scholar?q=...",
"https://www.federalregister.gov/documents/2026/05/01/...",
"https://random-blog-i-just-found.com/microsoft-rumor",
]
def main(argv: List[str]) -> int:
parser = argparse.ArgumentParser(description=__doc__.split("\n")[0])
parser.add_argument("--url", help="URL to classify")
parser.add_argument("--subject", help="Subject keywords (comma-separated) for company-official heuristic")
parser.add_argument("--sample", action="store_true", help="Classify a batch of sample URLs")
parser.add_argument("--output", choices=["human", "json"], default="human")
args = parser.parse_args(argv)
subject_kws = [s.strip() for s in args.subject.split(",")] if args.subject else None
if args.sample:
results = [classify(u, ["microsoft"]) for u in SAMPLE_URLS]
if args.output == "json":
print(json.dumps(results, indent=2))
else:
for r in results:
tier = r["tier"].upper()
marker = {"PRIMARY": "[1°]", "SECONDARY": "[2°]", "TERTIARY": "[3°]"}.get(tier, "[?]")
print(f"{marker} {tier:<10s} {r['url']}")
print(f" {r['rationale']}")
return 0
elif args.url:
result = classify(args.url, subject_kws)
if args.output == "json":
print(json.dumps(result, indent=2))
else:
print(f"Tier: {result['tier'].upper()}")
print(f"URL: {result['url']}")
print(f"Rationale: {result['rationale']}")
if result.get("confidence"):
print(f"Confidence: {result['confidence']}")
return 0
else:
parser.print_help()
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
Phỏng vấn nhà sáng lập để tạo file ngữ cảnh công ty company-context.md, lệnh đầu tiên cần chạy khi bắt đầu dùng c-level-agents.
--- name: "onboard" description: "/cs:onboard — Founder interview that populates ~/.claude/company-context.md. The first command to run when starting with c-level-agents." --- # /cs:onboard — Founder Interview **Command:** `/cs:onboard` The first command to run when adopting c-level-agents. A structured founder interview that produces `~/.claude/company-context.md` — the file every cs-* advisor reads before responding. Without this, the advisors are guessing. ## What This Produces `~/.claude/company-context.md` — a single file with the durable facts about the company. Read by: - `cs-chief-of-staff` (routing decisions) - Every cs-* advisor (context for any question) - `/cs:brief` (assumptions in any new decision) ## The Interview (12 Questions) ### Company Basics 1. **Company name and one-sentence pitch.** 2. **Stage:** pre-seed / seed / Series A / Series B / Series C+ / public 3. **Headcount:** total, by function (eng / product / GTM / ops / G&A) 4. **Geographic distribution:** HQ + remote split, key countries ### Business Model 5. **Revenue model:** SaaS subscription / usage / transaction / marketplace / hardware / services 6. **ICP:** name one real customer and describe what they have in common with others 7. **ACV:** median and range; deal count last 12 months 8. **Growth rate:** ARR YoY; if pre-revenue, leading metric (users, MAU, etc.) ### Financial Posture 9. **Runway:** months of cash at current burn; bear-case months 10. **Last raise:** amount, valuation, lead investor, date ### Strategic Context 11. **Top 3 priorities for the current quarter** (in plain language) 12. **Top 3 risks the founder loses sleep over** (be specific) ## Output Format Saved to `~/.claude/company-context.md`: ```markdown # Company Context **Generated:** YYYY-MM-DD **Last updated:** YYYY-MM-DD ## Identity - **Company:** <name> - **Pitch:** <one sentence> - **Stage:** <stage> - **HQ + remote:** <distribution> ## Business - **Model:** <type> - **ICP:** <description + named customer> - **ACV:** $<median> (range $<low> - $<high>) - **Deal count (LTM):** N - **ARR growth (YoY):** X% ## Financial - **Cash on hand:** $<amount> - **Net burn (monthly):** $<amount> - **Runway base:** N months - **Runway bear:** N months - **Last raise:** $<amount> at $<post> in <month YYYY>, led by <investor> ## Team - **Total headcount:** N - **Eng:** N | Product: N | GTM: N | Ops: N | G&A: N ## Quarter - **Top priorities (Q<X> YYYY):** 1. <priority> 2. <priority> 3. <priority> - **Top risks:** 1. <risk> 2. <risk> 3. <risk> ## Routing Hints [Optional: any role the founder wants to use sparingly or rely on heavily] ``` ## Workflow 1. Walk the founder through all 12 questions 2. Quote founder's own words wherever possible (don't paraphrase the ICP) 3. Save to `~/.claude/company-context.md` 4. (Optional) If llm-wiki bridge is configured: symlink to vault ```bash ln -sf ~/company-vault/00-meta/company-context.md ~/.claude/company-context.md ``` 5. Confirm with founder: read the file back, ask "anything missing?" ## When to Re-Run - After a fundraise (numbers change) - After a major pivot or product launch - After 6+ months (most facts have drifted) - After a major hire (team distribution changes) - Always before a `/cs:boardroom` for a high-stakes decision ## Persistence By default, `~/.claude/company-context.md` is local to the founder's machine. To make it persistent across machines / shareable: - **Markdown vault (recommended):** see [`../../references/llm-wiki-bridge.md`](../../references/llm-wiki-bridge.md) - **Encrypted dotfile sync:** age + git - **Shared team:** keep in a private repo, symlink from `~/.claude/` ## Related - Skill: [`cs-onboard`](../../../skills/cs-onboard/SKILL.md) — the underlying interview protocol - Skill: [`context-engine`](../../../skills/context-engine/SKILL.md) — reads this file - Reference: [`../../references/llm-wiki-bridge.md`](../../references/llm-wiki-bridge.md) --- **Version:** 1.0.0
Cố vấn ở vai trò giám đốc khách hàng (CCO): chiến lược trải nghiệm, giữ chân và thành công của khách hàng.
../../../c-level-advisor/chief-customer-officer-advisor/skills/chief-customer-officer-advisor/SKILL.md
Tư vấn FDA cho công ty thiết bị y tế: lộ trình 510(k)/PMA/De Novo, tuân thủ QSR (21 CFR 820), HIPAA và an ninh mạng thiết bị.
---
name: "fda-consultant-specialist"
description: FDA regulatory consultant for medical device companies. Provides 510(k)/PMA/De Novo pathway guidance, QSR (21 CFR 820) compliance, HIPAA assessments, and device cybersecurity. Use when user mentions FDA submission, 510(k), PMA, De Novo, QSR, premarket, predicate device, substantial equivalence, HIPAA medical device, or FDA cybersecurity.
---
# FDA Consultant Specialist
FDA regulatory consulting for medical device manufacturers covering submission pathways, Quality System Regulation (QSR), HIPAA compliance, and device cybersecurity requirements.
## Table of Contents
- [FDA Pathway Selection](#fda-pathway-selection)
- [510(k) Submission Process](#510k-submission-process)
- [QSR Compliance](#qsr-compliance)
- [HIPAA for Medical Devices](#hipaa-for-medical-devices)
- [Device Cybersecurity](#device-cybersecurity)
- [Resources](#resources)
---
## FDA Pathway Selection
Determine the appropriate FDA regulatory pathway based on device classification and predicate availability.
### Decision Framework
```
Predicate device exists?
├── YES → Substantially equivalent?
│ ├── YES → 510(k) Pathway
│ │ ├── No design changes → Abbreviated 510(k)
│ │ ├── Manufacturing only → Special 510(k)
│ │ └── Design/performance → Traditional 510(k)
│ └── NO → PMA or De Novo
└── NO → Novel device?
├── Low-to-moderate risk → De Novo
└── High risk (Class III) → PMA
```
### Pathway Comparison
| Pathway | When to Use | Timeline | Cost |
|---------|-------------|----------|------|
| 510(k) Traditional | Predicate exists, design changes | 90 days | $21,760 |
| 510(k) Special | Manufacturing changes only | 30 days | $21,760 |
| 510(k) Abbreviated | Guidance/standard conformance | 30 days | $21,760 |
| De Novo | Novel, low-moderate risk | 150 days | $134,676 |
| PMA | Class III, no predicate | 180+ days | $425,000+ |
### Pre-Submission Strategy
1. Identify product code and classification
2. Search 510(k) database for predicates
3. Assess substantial equivalence feasibility
4. Prepare Q-Sub questions for FDA
5. Schedule Pre-Sub meeting if needed
**Reference:** See [fda_submission_guide.md](references/fda_submission_guide.md) for pathway decision matrices and submission requirements.
---
## 510(k) Submission Process
### Workflow
```
Phase 1: Planning
├── Step 1: Identify predicate device(s)
├── Step 2: Compare intended use and technology
├── Step 3: Determine testing requirements
└── Checkpoint: SE argument feasible?
Phase 2: Preparation
├── Step 4: Complete performance testing
├── Step 5: Prepare device description
├── Step 6: Document SE comparison
├── Step 7: Finalize labeling
└── Checkpoint: All required sections complete?
Phase 3: Submission
├── Step 8: Assemble submission package
├── Step 9: Submit via eSTAR
├── Step 10: Track acknowledgment
└── Checkpoint: Submission accepted?
Phase 4: Review
├── Step 11: Monitor review status
├── Step 12: Respond to AI requests
├── Step 13: Receive decision
└── Verification: SE letter received?
```
### Required Sections (21 CFR 807.87)
| Section | Content |
|---------|---------|
| Cover Letter | Submission type, device ID, contact info |
| Form 3514 | CDRH premarket review cover sheet |
| Device Description | Physical description, principles of operation |
| Indications for Use | Form 3881, patient population, use environment |
| SE Comparison | Side-by-side comparison with predicate |
| Performance Testing | Bench, biocompatibility, electrical safety |
| Software Documentation | Level of concern, hazard analysis (IEC 62304) |
| Labeling | IFU, package labels, warnings |
| 510(k) Summary | Public summary of submission |
### Common RTA Issues
| Issue | Prevention |
|-------|------------|
| Missing user fee | Verify payment before submission |
| Incomplete Form 3514 | Review all fields, ensure signature |
| No predicate identified | Confirm K-number in FDA database |
| Inadequate SE comparison | Address all technological characteristics |
---
## QSR Compliance
Quality System Regulation (21 CFR Part 820) requirements for medical device manufacturers.
### Key Subsystems
| Section | Title | Focus |
|---------|-------|-------|
| 820.20 | Management Responsibility | Quality policy, org structure, management review |
| 820.30 | Design Controls | Input, output, review, verification, validation |
| 820.40 | Document Controls | Approval, distribution, change control |
| 820.50 | Purchasing Controls | Supplier qualification, purchasing data |
| 820.70 | Production Controls | Process validation, environmental controls |
| 820.100 | CAPA | Root cause analysis, corrective actions |
| 820.181 | Device Master Record | Specifications, procedures, acceptance criteria |
### Design Controls Workflow (820.30)
```
Step 1: Design Input
└── Capture user needs, intended use, regulatory requirements
Verification: Inputs reviewed and approved?
Step 2: Design Output
└── Create specifications, drawings, software architecture
Verification: Outputs traceable to inputs?
Step 3: Design Review
└── Conduct reviews at each phase milestone
Verification: Review records with signatures?
Step 4: Design Verification
└── Perform testing against specifications
Verification: All tests pass acceptance criteria?
Step 5: Design Validation
└── Confirm device meets user needs in actual use conditions
Verification: Validation report approved?
Step 6: Design Transfer
└── Release to production with DMR complete
Verification: Transfer checklist complete?
```
### CAPA Process (820.100)
1. **Identify**: Document nonconformity or potential problem
2. **Investigate**: Perform root cause analysis (5 Whys, Fishbone)
3. **Plan**: Define corrective/preventive actions
4. **Implement**: Execute actions, update documentation
5. **Verify**: Confirm implementation complete
6. **Effectiveness**: Monitor for recurrence (30-90 days)
7. **Close**: Management approval and closure
**Reference:** See [qsr_compliance_requirements.md](references/qsr_compliance_requirements.md) for detailed QSR implementation guidance.
---
## HIPAA for Medical Devices
HIPAA requirements for devices that create, store, transmit, or access Protected Health Information (PHI).
### Applicability
| Device Type | HIPAA Applies |
|-------------|---------------|
| Standalone diagnostic (no data transmission) | No |
| Connected device transmitting patient data | Yes |
| Device with EHR integration | Yes |
| SaMD storing patient information | Yes |
| Wellness app (no diagnosis) | Only if stores PHI |
### Required Safeguards
```
Administrative (§164.308)
├── Security officer designation
├── Risk analysis and management
├── Workforce training
├── Incident response procedures
└── Business associate agreements
Physical (§164.310)
├── Facility access controls
├── Workstation security
└── Device disposal procedures
Technical (§164.312)
├── Access control (unique IDs, auto-logoff)
├── Audit controls (logging)
├── Integrity controls (checksums, hashes)
├── Authentication (MFA recommended)
└── Transmission security (TLS 1.2+)
```
### Risk Assessment Steps
1. Inventory all systems handling ePHI
2. Document data flows (collection, storage, transmission)
3. Identify threats and vulnerabilities
4. Assess likelihood and impact
5. Determine risk levels
6. Implement controls
7. Document residual risk
**Reference:** See [hipaa_compliance_framework.md](references/hipaa_compliance_framework.md) for implementation checklists and BAA templates.
---
## Device Cybersecurity
FDA cybersecurity requirements for connected medical devices.
### Premarket Requirements
| Element | Description |
|---------|-------------|
| Threat Model | STRIDE analysis, attack trees, trust boundaries |
| Security Controls | Authentication, encryption, access control |
| SBOM | Software Bill of Materials (CycloneDX or SPDX) |
| Security Testing | Penetration testing, vulnerability scanning |
| Vulnerability Plan | Disclosure process, patch management |
### Device Tier Classification
**Tier 1 (Higher Risk):**
- Connects to network/internet
- Cybersecurity incident could cause patient harm
**Tier 2 (Standard Risk):**
- All other connected devices
### Postmarket Obligations
1. Monitor NVD and ICS-CERT for vulnerabilities
2. Assess applicability to device components
3. Develop and test patches
4. Communicate with customers
5. Report to FDA per guidance
### Coordinated Vulnerability Disclosure
```
Researcher Report
↓
Acknowledgment (48 hours)
↓
Initial Assessment (5 days)
↓
Fix Development
↓
Coordinated Public Disclosure
```
**Reference:** See [device_cybersecurity_guidance.md](references/device_cybersecurity_guidance.md) for SBOM format examples and threat modeling templates.
---
## Resources
### scripts/
| Script | Purpose |
|--------|---------|
| `fda_submission_tracker.py` | Track 510(k)/PMA/De Novo submission milestones and timelines |
| `qsr_compliance_checker.py` | Assess 21 CFR 820 compliance against project documentation |
| `hipaa_risk_assessment.py` | Evaluate HIPAA safeguards in medical device software |
### references/
| File | Content |
|------|---------|
| `fda_submission_guide.md` | 510(k), De Novo, PMA submission requirements and checklists |
| `qsr_compliance_requirements.md` | 21 CFR 820 implementation guide with templates |
| `hipaa_compliance_framework.md` | HIPAA Security Rule safeguards and BAA requirements |
| `device_cybersecurity_guidance.md` | FDA cybersecurity requirements, SBOM, threat modeling |
| `fda_capa_requirements.md` | CAPA process, root cause analysis, effectiveness verification |
### Usage Examples
```bash
# Track FDA submission status
python scripts/fda_submission_tracker.py /path/to/project --type 510k
# Assess QSR compliance
python scripts/qsr_compliance_checker.py /path/to/project --section 820.30
# Run HIPAA risk assessment
python scripts/hipaa_risk_assessment.py /path/to/project --category technical
```
FILE:references/device_cybersecurity_guidance.md
# Medical Device Cybersecurity Guidance
Complete framework for FDA cybersecurity requirements based on FDA guidance documents and recognized consensus standards.
---
## Table of Contents
- [Regulatory Framework](#regulatory-framework)
- [Premarket Cybersecurity](#premarket-cybersecurity)
- [Postmarket Cybersecurity](#postmarket-cybersecurity)
- [Threat Modeling](#threat-modeling)
- [Security Controls](#security-controls)
- [Software Bill of Materials](#software-bill-of-materials)
- [Vulnerability Management](#vulnerability-management)
- [Documentation Requirements](#documentation-requirements)
---
## Regulatory Framework
### FDA Guidance Documents
| Document | Scope | Key Requirements |
|----------|-------|------------------|
| Premarket Cybersecurity (2023) | 510(k), PMA, De Novo | Security design, SBOM, threat modeling |
| Postmarket Management (2016) | All marketed devices | Vulnerability monitoring, patching |
| Content of Premarket Submissions | Submission format | Documentation structure |
### PATCH Act Requirements (2023)
**Cyber Device Definition:**
- Contains software
- Can connect to internet
- May be vulnerable to cybersecurity threats
**Manufacturer Obligations:**
1. Submit plan to monitor, identify, and address vulnerabilities
2. Design, develop, and maintain processes to ensure device security
3. Provide software bill of materials (SBOM)
4. Comply with other requirements under section 524B
### Recognized Consensus Standards
| Standard | Scope | FDA Recognition |
|----------|-------|-----------------|
| IEC 62443 | Industrial automation security | Recognized |
| NIST Cybersecurity Framework | Security framework | Referenced |
| UL 2900 | Software cybersecurity | Recognized |
| AAMI TIR57 | Medical device cybersecurity | Referenced |
| IEC 81001-5-1 | Health software security | Recognized |
---
## Premarket Cybersecurity
### Cybersecurity Documentation Requirements
```
Cybersecurity Documentation Package:
├── 1. Security Risk Assessment
│ ├── Threat model
│ ├── Vulnerability assessment
│ ├── Risk analysis
│ └── Risk mitigation
├── 2. Security Architecture
│ ├── System diagram
│ ├── Data flow diagram
│ ├── Trust boundaries
│ └── Security controls
├── 3. Cybersecurity Testing
│ ├── Penetration testing
│ ├── Vulnerability scanning
│ ├── Fuzz testing
│ └── Security code review
├── 4. SBOM
│ ├── Software components
│ ├── Versions
│ └── Known vulnerabilities
├── 5. Vulnerability Management Plan
│ ├── Monitoring process
│ ├── Disclosure process
│ └── Patch management
└── 6. Labeling
├── Security instructions
└── End-of-life plan
```
### Device Tier Classification
**Tier 1 - Higher Cybersecurity Risk:**
- Device can connect to another product or network
- A cybersecurity incident could directly result in patient harm
**Tier 2 - Standard Cybersecurity Risk:**
- Device NOT a Tier 1 device
- Still requires cybersecurity documentation
**Documentation Depth by Tier:**
| Element | Tier 1 | Tier 2 |
|---------|--------|--------|
| Threat model | Comprehensive | Basic |
| Penetration testing | Required | Recommended |
| SBOM | Required | Required |
| Security testing | Full suite | Core testing |
### Security by Design Principles
```markdown
## Secure Product Development Framework (SPDF)
### 1. Security Risk Management
- Integrate security into QMS
- Apply throughout product lifecycle
- Document security decisions
### 2. Security Architecture
- Defense in depth
- Least privilege
- Secure defaults
- Fail securely
### 3. Cybersecurity Testing
- Verify security controls
- Test for known vulnerabilities
- Validate threat mitigations
### 4. Cybersecurity Transparency
- SBOM provision
- Vulnerability disclosure
- Coordinated vulnerability disclosure
### 5. Cybersecurity Maintenance
- Monitor for vulnerabilities
- Provide timely updates
- Support throughout lifecycle
```
---
## Postmarket Cybersecurity
### Vulnerability Monitoring
**Sources to Monitor:**
- National Vulnerability Database (NVD)
- ICS-CERT advisories
- Third-party component vendors
- Security researcher reports
- Customer/user reports
**Monitoring Process:**
```
Daily/Weekly Monitoring:
├── NVD feed check
├── Vendor security bulletins
├── Security mailing lists
└── ISAC notifications
Monthly Review:
├── Component vulnerability analysis
├── Risk re-assessment
├── Patch status review
└── Trending threat analysis
Quarterly Assessment:
├── Comprehensive vulnerability scan
├── Third-party security audit
├── Update threat model
└── Security metrics review
```
### Vulnerability Assessment and Response
**CVSS-Based Triage:**
| CVSS Score | Severity | Response Timeframe |
|------------|----------|-------------------|
| 9.0-10.0 | Critical | 24-48 hours assessment |
| 7.0-8.9 | High | 1 week assessment |
| 4.0-6.9 | Medium | 30 days assessment |
| 0.1-3.9 | Low | Quarterly review |
**Exploitability Assessment:**
```markdown
## Vulnerability Exploitation Assessment
### Device-Specific Factors
- [ ] Is the vulnerability reachable in device configuration?
- [ ] Are mitigating controls in place?
- [ ] What is the attack surface exposure?
- [ ] What is the potential patient harm?
### Environment Factors
- [ ] Is exploit code publicly available?
- [ ] Is the vulnerability being actively exploited?
- [ ] What is the typical deployment environment?
### Risk Determination
Uncontrolled Risk = Exploitability × Impact × Exposure
| Risk Level | Action |
|------------|--------|
| Unacceptable | Immediate remediation |
| Elevated | Prioritized remediation |
| Acceptable | Monitor, routine update |
```
### Patch and Update Management
**Update Classification:**
| Type | Description | Regulatory Path |
|------|-------------|-----------------|
| Security patch | Addresses vulnerability only | May not require new submission |
| Software update | New features + security | Evaluate per guidance |
| Major upgrade | Significant changes | New 510(k) evaluation |
**FDA's Cybersecurity Policies:**
1. **Routine Updates:** Generally do not require premarket review
2. **Remediation of Vulnerabilities:** No premarket review if:
- No new risks introduced
- No changes to intended use
- Adequate design controls followed
---
## Threat Modeling
### STRIDE Methodology
| Threat | Description | Device Example |
|--------|-------------|----------------|
| **S**poofing | Pretending to be someone/something else | Fake device identity |
| **T**ampering | Modifying data or code | Altering dosage parameters |
| **R**epudiation | Denying actions | Hiding malicious commands |
| **I**nformation Disclosure | Exposing information | PHI data leak |
| **D**enial of Service | Making resource unavailable | Device becomes unresponsive |
| **E**levation of Privilege | Gaining unauthorized access | Admin access from user |
### Threat Model Template
```markdown
## Device Threat Model
### 1. System Description
Device Name: _____________________
Device Type: _____________________
Intended Use: ____________________
### 2. Architecture Diagram
[Include system diagram with trust boundaries]
### 3. Data Flow Diagram
[Document data flows and data types]
### 4. Entry Points
| Entry Point | Protocol | Authentication | Data Type |
|-------------|----------|----------------|-----------|
| USB port | USB HID | None | Config data |
| Network | HTTPS | Certificate | PHI |
| Bluetooth | BLE | Pairing | Commands |
### 5. Assets
| Asset | Sensitivity | Integrity | Availability |
|-------|-------------|-----------|--------------|
| Patient data | High | High | Medium |
| Device firmware | High | Critical | High |
| Configuration | Medium | High | Medium |
### 6. Threat Analysis
| Threat ID | STRIDE | Entry Point | Asset | Mitigation |
|-----------|--------|-------------|-------|------------|
| T-001 | Spoofing | Network | Auth | Mutual TLS |
| T-002 | Tampering | USB | Firmware | Secure boot |
| T-003 | Information | Network | PHI | Encryption |
### 7. Risk Assessment
| Threat | Likelihood | Impact | Risk | Accept/Mitigate |
|--------|------------|--------|------|-----------------|
| T-001 | Medium | High | High | Mitigate |
| T-002 | Low | Critical | High | Mitigate |
| T-003 | Medium | High | High | Mitigate |
```
### Attack Trees
**Example: Unauthorized Access to Device**
```
Goal: Gain Unauthorized Access
├── 1. Physical Access Attack
│ ├── 1.1 Steal device
│ ├── 1.2 Access debug port
│ └── 1.3 Extract storage media
├── 2. Network Attack
│ ├── 2.1 Exploit unpatched vulnerability
│ ├── 2.2 Man-in-the-middle attack
│ └── 2.3 Credential theft
├── 3. Social Engineering
│ ├── 3.1 Phishing for credentials
│ └── 3.2 Insider threat
└── 4. Supply Chain Attack
├── 4.1 Compromised component
└── 4.2 Malicious update
```
---
## Security Controls
### Authentication and Access Control
**Authentication Requirements:**
| Access Level | Authentication | Session Management |
|--------------|----------------|-------------------|
| Patient | PIN/biometric | Auto-logout |
| Clinician | Password + MFA | Timeout 15 min |
| Service | Certificate | Per-session |
| Admin | MFA + approval | Audit logged |
**Password Requirements:**
- Minimum 8 characters (12+ recommended)
- Complexity requirements
- Secure storage (hashed, salted)
- Account lockout after failed attempts
- Forced change on first use
### Encryption Requirements
**Data at Rest:**
- AES-256 for sensitive data
- Secure key storage (TPM, secure enclave)
- Key rotation procedures
**Data in Transit:**
- TLS 1.2 or higher
- Strong cipher suites
- Certificate validation
- Perfect forward secrecy
**Encryption Implementation Checklist:**
```markdown
## Encryption Controls
### Key Management
- [ ] Keys stored in hardware security module or equivalent
- [ ] Key generation uses cryptographically secure RNG
- [ ] Key rotation procedures documented
- [ ] Key revocation procedures documented
- [ ] Key escrow/recovery procedures (if applicable)
### Algorithm Selection
- [ ] AES-256 for symmetric encryption
- [ ] RSA-2048+ or ECDSA P-256+ for asymmetric
- [ ] SHA-256 or better for hashing
- [ ] No deprecated algorithms (MD5, SHA-1, DES)
### Implementation
- [ ] Using well-vetted cryptographic libraries
- [ ] Proper initialization vector handling
- [ ] Protection against timing attacks
- [ ] Secure key zeroing after use
```
### Secure Communications
**Network Security Controls:**
| Layer | Control | Implementation |
|-------|---------|----------------|
| Transport | TLS 1.2+ | Mutual authentication |
| Network | Firewall | Whitelist only |
| Application | API security | Rate limiting, validation |
| Data | Encryption | End-to-end |
### Code Integrity
**Secure Boot Chain:**
```
Root of Trust (Hardware)
↓
Bootloader (Signed)
↓
Operating System (Verified)
↓
Application (Authenticated)
↓
Configuration (Integrity-checked)
```
**Software Integrity Controls:**
- Code signing for all software
- Signature verification before execution
- Anti-rollback protection
- Secure update mechanism
---
## Software Bill of Materials
### SBOM Requirements
**NTIA Minimum Elements:**
1. Supplier name
2. Component name
3. Version of component
4. Other unique identifiers (PURL, CPE)
5. Dependency relationship
6. Author of SBOM data
7. Timestamp
### SBOM Formats
| Format | Standard | Use Case |
|--------|----------|----------|
| SPDX | ISO/IEC 5962:2021 | Comprehensive |
| CycloneDX | OWASP | Security-focused |
| SWID | ISO/IEC 19770-2 | Asset management |
### SBOM Template (CycloneDX)
```xml
<?xml version="1.0" encoding="UTF-8"?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.4">
<metadata>
<timestamp>2024-01-15T00:00:00Z</timestamp>
<tools>
<tool>
<vendor>Manufacturer</vendor>
<name>SBOM Generator</name>
<version>1.0.0</version>
</tool>
</tools>
<component type="device">
<name>Medical Device XYZ</name>
<version>2.0.0</version>
<supplier>
<name>Device Manufacturer</name>
</supplier>
</component>
</metadata>
<components>
<component type="library">
<name>openssl</name>
<version>1.1.1k</version>
<purl>pkg:generic/openssl@1.1.1k</purl>
<licenses>
<license>
<id>Apache-2.0</id>
</license>
</licenses>
</component>
<!-- Additional components -->
</components>
<dependencies>
<dependency ref="device-xyz">
<dependency ref="openssl"/>
</dependency>
</dependencies>
</bom>
```
### SBOM Management Process
```
1. Initial SBOM Creation
└── During development, before submission
2. Vulnerability Monitoring
└── Continuous monitoring against NVD
3. SBOM Updates
└── With each software release
4. Customer Communication
└── SBOM provided on request
5. FDA Submission
└── Included in premarket submission
```
---
## Vulnerability Management
### Vulnerability Disclosure
**Coordinated Vulnerability Disclosure (CVD):**
```markdown
## Vulnerability Disclosure Policy
### Reporting
- Security contact: security@manufacturer.com
- PGP key available at: [URL]
- Bug bounty program: [if applicable]
### Response Timeline
- Acknowledgment: Within 48 hours
- Initial assessment: Within 5 business days
- Status updates: Every 30 days
- Target remediation: Per severity
### Public Disclosure
- Coordinated with reporter
- After remediation available
- Include mitigations if patch delayed
### Safe Harbor
[Statement on not pursuing legal action against good-faith reporters]
```
### Vulnerability Response Process
```
Discovery
↓
Triage (CVSS + Exploitability)
↓
Risk Assessment
↓
Remediation Development
↓
Testing and Validation
↓
Deployment/Communication
↓
Verification
↓
Closure
```
### Customer Communication
**Security Advisory Template:**
```markdown
## Security Advisory
### Advisory ID: [ID]
### Published: [Date]
### Severity: [Critical/High/Medium/Low]
### Affected Products
- Product A, versions 1.0-2.0
- Product B, versions 3.0-3.5
### Description
[Description of vulnerability without exploitation details]
### Impact
[What could happen if exploited]
### Mitigation
[Steps to reduce risk before patch available]
### Remediation
- Patch version: X.X.X
- Download: [URL]
- Installation instructions: [Link]
### Credits
[Acknowledge reporter if agreed]
### References
- CVE-XXXX-XXXX
- Manufacturer reference: [ID]
```
---
## Documentation Requirements
### Premarket Submission Checklist
```markdown
## Cybersecurity Documentation for Premarket Submission
### Device Description (Tier 1 and 2)
- [ ] Cybersecurity risk level justification
- [ ] Global system diagram
- [ ] Data flow diagram
### Security Risk Management (Tier 1 and 2)
- [ ] Threat model
- [ ] Security risk assessment
- [ ] Traceability matrix
### Security Architecture (Tier 1 and 2)
- [ ] Defense-in-depth description
- [ ] Security controls list
- [ ] Trust boundaries identified
### Testing Documentation
#### Tier 1
- [ ] Penetration test report
- [ ] Vulnerability scan results
- [ ] Fuzz testing results
- [ ] Static code analysis
- [ ] Third-party component testing
#### Tier 2
- [ ] Security testing summary
- [ ] Known vulnerability analysis
### SBOM (Tier 1 and 2)
- [ ] Complete component inventory
- [ ] Known vulnerability assessment
- [ ] Support and update plan
### Vulnerability Management (Tier 1 and 2)
- [ ] Vulnerability handling policy
- [ ] Coordinated disclosure process
- [ ] Security update plan
### Labeling (Tier 1 and 2)
- [ ] User security instructions
- [ ] End-of-support date
- [ ] Security contact information
```
### Recommended File Structure
```
Cybersecurity_Documentation/
├── 01_Executive_Summary.pdf
├── 02_Device_Description/
│ ├── System_Diagram.pdf
│ └── Data_Flow_Diagram.pdf
├── 03_Security_Risk_Assessment/
│ ├── Threat_Model.pdf
│ ├── Risk_Assessment.pdf
│ └── Traceability_Matrix.xlsx
├── 04_Security_Architecture/
│ ├── Architecture_Description.pdf
│ ├── Security_Controls.pdf
│ └── Trust_Boundary_Analysis.pdf
├── 05_Security_Testing/
│ ├── Penetration_Test_Report.pdf
│ ├── Vulnerability_Scan_Results.pdf
│ ├── Fuzz_Testing_Report.pdf
│ └── Code_Analysis_Report.pdf
├── 06_SBOM/
│ ├── SBOM.xml (CycloneDX)
│ └── Vulnerability_Analysis.pdf
├── 07_Vulnerability_Management/
│ ├── Vulnerability_Policy.pdf
│ └── Disclosure_Process.pdf
└── 08_Labeling/
└── Security_Instructions.pdf
```
---
## Quick Reference
### Common Cybersecurity Deficiencies
| Deficiency | Resolution |
|------------|------------|
| Incomplete threat model | Document all entry points, assets, threats |
| No SBOM provided | Generate using automated tools |
| Weak authentication | Implement MFA, strong passwords |
| Missing encryption | Add TLS 1.2+, AES-256 |
| No vulnerability management plan | Create monitoring and response procedures |
| Insufficient testing | Conduct penetration testing |
### Security Testing Requirements
| Test Type | Tier 1 | Tier 2 | Tools |
|-----------|--------|--------|-------|
| Penetration testing | Required | Recommended | Manual + automated |
| Vulnerability scanning | Required | Required | Nessus, OpenVAS |
| Fuzz testing | Required | Recommended | AFL, Peach |
| Static analysis | Required | Recommended | SonarQube, Coverity |
| Dynamic analysis | Required | Recommended | Burp Suite, ZAP |
### Recognized Standards Mapping
| FDA Requirement | IEC 62443 | NIST CSF |
|-----------------|-----------|----------|
| Threat modeling | SR 3 | ID.RA |
| Access control | SR 1, SR 2 | PR.AC |
| Encryption | SR 4 | PR.DS |
| Audit logging | SR 6 | PR.PT, DE.AE |
| Patch management | SR 7 | PR.MA |
| Incident response | SR 6 | RS.RP |
FILE:references/fda_capa_requirements.md
# FDA CAPA Requirements
Complete guide to Corrective and Preventive Action requirements per 21 CFR 820.100.
---
## Table of Contents
- [CAPA Regulation Overview](#capa-regulation-overview)
- [CAPA Sources](#capa-sources)
- [CAPA Process](#capa-process)
- [Root Cause Analysis](#root-cause-analysis)
- [Action Implementation](#action-implementation)
- [Effectiveness Verification](#effectiveness-verification)
- [Documentation Requirements](#documentation-requirements)
- [FDA Inspection Focus Areas](#fda-inspection-focus-areas)
---
## CAPA Regulation Overview
### 21 CFR 820.100 Requirements
```
§820.100 Corrective and preventive action
(a) Each manufacturer shall establish and maintain procedures for
implementing corrective and preventive action. The procedures shall
include requirements for:
(1) Analyzing processes, work operations, concessions, quality audit
reports, quality records, service records, complaints, returned
product, and other sources of quality data to identify existing
and potential causes of nonconforming product, or other quality
problems.
(2) Investigating the cause of nonconformities relating to product,
processes, and the quality system.
(3) Identifying the action(s) needed to correct and prevent recurrence
of nonconforming product and other quality problems.
(4) Verifying or validating the corrective and preventive action to
ensure that such action is effective and does not adversely affect
the finished device.
(5) Implementing and recording changes in methods and procedures needed
to correct and prevent identified quality problems.
(6) Ensuring that information related to quality problems or nonconforming
product is disseminated to those directly responsible for assuring
the quality of such product or the prevention of such problems.
(7) Submitting relevant information on identified quality problems, as
well as corrective and preventive actions, for management review.
```
### Definitions
| Term | Definition |
|------|------------|
| **Correction** | Action to eliminate a detected nonconformity |
| **Corrective Action** | Action to eliminate the cause of a detected nonconformity to prevent recurrence |
| **Preventive Action** | Action to eliminate the cause of a potential nonconformity to prevent occurrence |
| **Root Cause** | The fundamental reason for the occurrence of a problem |
| **Effectiveness** | Confirmation that actions achieved intended results |
### CAPA vs. Correction
```
Problem Detected
├── Correction (Immediate)
│ └── Fix the immediate issue
│ Example: Replace defective part
│
└── CAPA (Systemic)
└── Address root cause
Example: Fix process that caused defect
```
---
## CAPA Sources
### Data Sources for CAPA Input
**Internal Sources:**
- Nonconforming product reports (NCRs)
- Internal audit findings
- Process deviations
- Manufacturing data trends
- Equipment failures
- Employee observations
- Training deficiencies
**External Sources:**
- Customer complaints
- Service records
- Returned product
- Regulatory feedback (483s, warning letters)
- Adverse event reports (MDRs)
- Field safety corrective actions
### CAPA Threshold Criteria
**Mandatory CAPA Triggers:**
| Source | Threshold |
|--------|-----------|
| Audit findings | All major/critical findings |
| Customer complaints | Any safety-related |
| NCRs | Recurring (3+ occurrences) |
| Regulatory feedback | All observations |
| MDR/vigilance | All reportable events |
**Discretionary CAPA Evaluation:**
| Source | Consideration |
|--------|---------------|
| Trend data | Statistical significance |
| Process deviations | Impact assessment |
| Minor audit findings | Risk-based |
| Supplier issues | Frequency and severity |
### Trend Analysis
**Statistical Process Control:**
```markdown
## Monthly CAPA Trend Review
### Complaint Trending
- [ ] Complaints by product
- [ ] Complaints by failure mode
- [ ] Geographic distribution
- [ ] Customer type analysis
### NCR Trending
- [ ] NCRs by product/process
- [ ] NCRs by cause code
- [ ] NCRs by supplier
- [ ] Scrap/rework rates
### Threshold Monitoring
| Metric | Threshold | Current | Status |
|--------|-----------|---------|--------|
| Complaints/month | <10 | | |
| NCR rate | <2% | | |
| Recurring issues | 0 | | |
```
---
## CAPA Process
### CAPA Workflow
```
1. Initiation
├── Problem identification
├── Initial assessment
└── CAPA determination
2. Investigation
├── Data collection
├── Root cause analysis
└── Impact assessment
3. Action Planning
├── Correction (if applicable)
├── Corrective action
└── Preventive action
4. Implementation
├── Execute actions
├── Document changes
└── Train affected personnel
5. Verification
├── Verify implementation
├── Validate effectiveness
└── Monitor for recurrence
6. Closure
├── Management approval
├── Final documentation
└── Trend data update
```
### CAPA Form Template
```markdown
## CAPA Record
### Section 1: Identification
CAPA Number: ________________
Initiated By: ________________
Date Initiated: ______________
Priority: ☐ Critical ☐ Major ☐ Minor
Source:
☐ Audit Finding ☐ Complaint ☐ NCR
☐ Service Record ☐ MDR ☐ Trend Data
☐ Regulatory ☐ Other: ____________
### Section 2: Problem Description
Products Affected: _______________________
Processes Affected: _____________________
Quantity/Scope: _________________________
Problem Statement:
[Clear, specific description of the nonconformity or potential problem]
### Section 3: Immediate Correction
Correction Taken: _______________________
Date Completed: _________________________
Verified By: ____________________________
### Section 4: Investigation
Investigation Lead: _____________________
Investigation Start Date: _______________
Data Collected:
☐ Complaint records ☐ Production records
☐ Test data ☐ Training records
☐ Process documentation ☐ Supplier data
Root Cause Analysis Method:
☐ 5 Whys ☐ Fishbone ☐ Fault Tree ☐ Other
Root Cause Statement:
[Specific, factual statement of the root cause]
Contributing Factors:
1. _____________________________________
2. _____________________________________
### Section 5: Action Plan
#### Corrective Actions
| Action | Owner | Target Date | Status |
|--------|-------|-------------|--------|
| | | | |
#### Preventive Actions
| Action | Owner | Target Date | Status |
|--------|-------|-------------|--------|
| | | | |
### Section 6: Verification
Verification Method: ____________________
Verification Criteria: __________________
Verification Date: _____________________
Verified By: ___________________________
Verification Results:
☐ Actions implemented as planned
☐ No adverse effects identified
☐ Documentation updated
### Section 7: Effectiveness Review
Effectiveness Review Date: ______________
Review Period: ________________________
Reviewer: _____________________________
Effectiveness Criteria:
[Specific, measurable criteria for success]
Results:
☐ Effective - problem has not recurred
☐ Not Effective - additional action required
Evidence:
[Reference to data showing effectiveness]
### Section 8: Closure
Closure Date: _________________________
Approved By: __________________________
Management Review Submitted: ☐ Yes ☐ No
Date: ________________________________
```
---
## Root Cause Analysis
### 5 Whys Technique
**Example: Device Fails Final Test**
```
Problem: 5% of devices fail functional test at final inspection
Why 1: Component X is out of tolerance
Why 2: Component X was accepted at incoming inspection
Why 3: Incoming inspection sampling missed defective lot
Why 4: Sampling plan inadequate for component criticality
Why 5: Risk classification of component not updated after design change
Root Cause: Risk classification process did not include design change trigger
```
**5 Whys Template:**
```markdown
## 5 Whys Analysis
Problem Statement: _________________________________
Why 1: _____________________________________________
Evidence: __________________________________________
Why 2: _____________________________________________
Evidence: __________________________________________
Why 3: _____________________________________________
Evidence: __________________________________________
Why 4: _____________________________________________
Evidence: __________________________________________
Why 5: _____________________________________________
Evidence: __________________________________________
Root Cause: ________________________________________
Verification: How do we know this is the root cause?
________________________________________________
```
### Fishbone (Ishikawa) Diagram
**Categories for Medical Device Manufacturing:**
```
┌─────────────────────────────────────────┐
│ PROBLEM │
└─────────────────────────────────────────┘
▲
┌───────────────────────────┼───────────────────────────┐
│ │ │
┌──────┴──────┐ ┌──────┴──────┐ ┌──────┴──────┐
│ PERSONNEL │ │ METHODS │ │ MATERIALS │
│ │ │ │ │ │
│ • Training │ │ • SOP gaps │ │ • Supplier │
│ • Skills │ │ • Process │ │ • Specs │
│ • Attention │ │ • Sequence │ │ • Storage │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
└───────────────────────────┼───────────────────────────┘
│
┌──────────────┐ ┌──────┴──────┐ ┌──────────────┐
│ MEASUREMENT │ │ EQUIPMENT │ │ ENVIRONMENT │
│ │ │ │ │ │
│ • Calibration│ │ • Maintenance│ │ • Temperature│
│ • Method │ │ • Capability │ │ • Humidity │
│ • Accuracy │ │ • Tooling │ │ • Cleanliness│
└──────────────┘ └─────────────┘ └──────────────┘
```
### Fault Tree Analysis
**For Complex Failures:**
```
Top Event: Device Failure
│
┌───────────────┼───────────────┐
│ │ │
AND/OR AND/OR AND/OR
│ │ │
┌─────┴─────┐ ┌─────┴─────┐ ┌─────┴─────┐
│ Component │ │ Software │ │ User │
│ Failure │ │ Failure │ │ Error │
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
│ │ │
Basic Events Basic Events Basic Events
```
### Root Cause Categories
| Category | Examples | Evidence Sources |
|----------|----------|------------------|
| Design | Specification error, tolerance stack-up | DHF, design review records |
| Process | Procedure inadequate, sequence error | Process validation, work instructions |
| Personnel | Training gap, human error | Training records, interviews |
| Equipment | Calibration drift, maintenance | Calibration records, logs |
| Material | Supplier quality, storage | Incoming inspection, COCs |
| Environment | Temperature, contamination | Environmental monitoring |
| Management | Resource allocation, priorities | Management review records |
---
## Action Implementation
### Corrective Action Requirements
**Effective Corrective Actions:**
1. Address identified root cause
2. Are specific and measurable
3. Have assigned ownership
4. Have realistic target dates
5. Consider impact on other processes
6. Include verification method
**Action Types:**
| Type | Description | Example |
|------|-------------|---------|
| Process change | Modify procedure or method | Update SOP with additional step |
| Design change | Modify product design | Add tolerance specification |
| Training | Improve personnel capability | Conduct retraining |
| Equipment | Modify or replace equipment | Upgrade inspection equipment |
| Supplier | Address supplier quality | Audit supplier, add requirements |
| Documentation | Improve or add documentation | Create work instruction |
### Change Control Integration
```
CAPA Action Identified
│
▼
Change Request Initiated
│
▼
Impact Assessment
├── Regulatory impact
├── Product impact
├── Process impact
└── Documentation impact
│
▼
Change Approved
│
▼
Implementation
├── Document updates
├── Training
├── Validation (if required)
└── Effective date
│
▼
CAPA Verification
```
### Training Requirements
**When Training is Required:**
- New or revised procedures
- New equipment or tools
- Process changes
- Findings related to personnel performance
**Training Documentation:**
```markdown
## CAPA-Related Training Record
CAPA Number: _______________
Training Subject: ___________
Training Date: ______________
Trainer: ___________________
Attendees:
| Name | Signature | Date |
|------|-----------|------|
| | | |
Training Content:
- [ ] Root cause explanation
- [ ] Process/procedure changes
- [ ] New requirements
- [ ] Competency verification
Competency Verified By: _______________
Date: _______________
```
---
## Effectiveness Verification
### Verification vs. Validation
| Verification | Validation |
|--------------|------------|
| Actions implemented correctly | Actions achieved intended results |
| Short-term check | Long-term monitoring |
| Process-focused | Outcome-focused |
### Effectiveness Criteria
**SMART Criteria:**
- **S**pecific: Clearly defined outcome
- **M**easurable: Quantifiable metrics
- **A**chievable: Realistic expectations
- **R**elevant: Related to root cause
- **T**ime-bound: Defined monitoring period
**Examples:**
| Problem | Root Cause | Action | Effectiveness Criteria |
|---------|------------|--------|----------------------|
| 5% test failures | Inadequate sampling | Increase sampling | <1% failure rate for 3 months |
| Customer complaints | Unclear instructions | Revise IFU | Zero complaints on topic for 6 months |
| NCRs from supplier | No incoming inspection | Add inspection | Zero supplier NCRs for 90 days |
### Effectiveness Review Template
```markdown
## CAPA Effectiveness Review
CAPA Number: _______________
Review Date: _______________
Reviewer: __________________
### Review Criteria
Original Problem: _________________
Effectiveness Metric: ______________
Success Threshold: ________________
Review Period: ____________________
### Data Analysis
| Period | Metric Value | Threshold | Pass/Fail |
|--------|--------------|-----------|-----------|
| Month 1 | | | |
| Month 2 | | | |
| Month 3 | | | |
### Conclusion
☐ Effective - Criteria met, CAPA may be closed
☐ Partially Effective - Additional monitoring required
☐ Not Effective - Additional actions required
### Evidence
[Reference to supporting data: complaint logs, NCR reports, audit results, etc.]
### Next Steps (if not effective)
___________________________________
___________________________________
### Approval
Reviewer Signature: _______________ Date: _______
Quality Approval: _________________ Date: _______
```
### Monitoring Period Guidelines
| CAPA Type | Minimum Monitoring |
|-----------|-------------------|
| Product quality | 3 production lots or 90 days |
| Process | 3 months of production |
| Complaints | 6 months |
| Audit findings | Until next audit |
| Supplier | 3 lots or 90 days |
---
## Documentation Requirements
### CAPA File Contents
```
CAPA File Structure:
├── CAPA Form (all sections completed)
├── Investigation Records
│ ├── Data collected
│ ├── Root cause analysis worksheets
│ └── Impact assessment
├── Action Documentation
│ ├── Action plans
│ ├── Change requests (if applicable)
│ └── Training records
├── Verification Evidence
│ ├── Implementation verification
│ ├── Effectiveness data
│ └── Trend analysis
└── Closure Documentation
├── Closure approval
└── Management review submission
```
### Record Retention
Per 21 CFR 820.180:
- Records shall be retained for the design and expected life of the device
- Minimum of 2 years from date of release for commercial distribution
**CAPA Record Retention:**
- Retain for lifetime of product + 2 years
- Include all supporting documentation
- Maintain audit trail for changes
### Traceability
**Required Traceability:**
- CAPA to source (complaint, NCR, audit finding)
- CAPA to affected products/lots
- CAPA to corrective actions taken
- CAPA to verification evidence
- CAPA to management review
---
## FDA Inspection Focus Areas
### Common 483 Observations
| Observation | Prevention |
|-------------|------------|
| CAPA not initiated when required | Define clear CAPA triggers |
| Root cause analysis inadequate | Use structured RCA methods |
| Actions don't address root cause | Verify action-cause linkage |
| Effectiveness not verified | Define measurable criteria |
| CAPA not timely | Set and track target dates |
| Trend analysis not performed | Implement monthly trending |
| Management review missing CAPA input | Include in management review agenda |
### Inspection Preparation
**CAPA Readiness Checklist:**
```markdown
## FDA Inspection CAPA Preparation
### Documentation Review
- [ ] All CAPAs have complete documentation
- [ ] No overdue CAPAs
- [ ] Root cause documented with evidence
- [ ] Effectiveness verified and documented
- [ ] All open CAPAs have current status
### Metrics Available
- [ ] CAPA by source
- [ ] CAPA cycle time
- [ ] Overdue CAPA trend
- [ ] Effectiveness rate
- [ ] Recurring issues
### Process Evidence
- [ ] CAPA procedure current
- [ ] Training records complete
- [ ] Trend analysis documented
- [ ] Management review records show CAPA input
### Common Questions Prepared
- How do you initiate a CAPA?
- How do you determine root cause?
- How do you verify effectiveness?
- Show me your overdue CAPAs
- Show me CAPAs from complaints
```
### CAPA Metrics Dashboard
| Metric | Target | Calculation |
|--------|--------|-------------|
| On-time initiation | 100% | CAPAs initiated within 30 days |
| On-time closure | >90% | CAPAs closed by target date |
| Effectiveness rate | >85% | Effective at first review / Total |
| Average cycle time | <90 days | Average days to closure |
| Overdue CAPAs | 0 | CAPAs past target date |
| Recurring issues | <5% | Repeat CAPAs / Total |
---
## Quick Reference
### CAPA Decision Tree
```
Quality Issue Identified
│
▼
Is it an isolated incident?
├── YES → Correction only (document, may not need CAPA)
│ Evaluate for trend
│
└── NO → Is it a systemic issue?
├── YES → Initiate CAPA
│ Determine if Corrective or Preventive
│
└── MAYBE → Investigate further
Monitor for recurrence
May escalate to CAPA
```
### Root Cause vs. Symptom
| Symptom (NOT root cause) | Root Cause (Address this) |
|--------------------------|---------------------------|
| "Operator made error" | Training inadequate for task |
| "Component was defective" | Incoming inspection ineffective |
| "SOP not followed" | SOP unclear or impractical |
| "Equipment malfunctioned" | Maintenance schedule inadequate |
| "Supplier shipped wrong part" | Purchasing requirements unclear |
### Action Effectiveness Verification
| Action Type | Verification Method | Timeframe |
|-------------|---------------------|-----------|
| Procedure change | Audit for compliance | 30-60 days |
| Training | Competency assessment | Immediate |
| Design change | Product testing | Per protocol |
| Supplier action | Incoming inspection data | 3 lots |
| Equipment | Calibration/performance | Per schedule |
### Integration with Other Systems
| System | CAPA Integration Point |
|--------|------------------------|
| Complaints | Trigger for CAPA, complaint closure after CAPA |
| NCR | Trend to CAPA, NCR references CAPA |
| Audit | Findings generate CAPA, CAPA closure audit |
| Design Control | Design change via CAPA, DHF update |
| Supplier | Supplier CAPA, supplier audit findings |
| Risk Management | Risk file update post-CAPA |
FILE:references/fda_submission_guide.md
# FDA Submission Guide
Complete framework for 510(k), De Novo, and PMA submissions to the FDA.
---
## Table of Contents
- [Submission Pathway Selection](#submission-pathway-selection)
- [510(k) Premarket Notification](#510k-premarket-notification)
- [De Novo Classification](#de-novo-classification)
- [PMA Premarket Approval](#pma-premarket-approval)
- [Pre-Submission Program](#pre-submission-program)
- [FDA Review Timeline](#fda-review-timeline)
---
## Submission Pathway Selection
### Decision Matrix
```
Is there a legally marketed predicate device?
├── YES → Is your device substantially equivalent?
│ ├── YES → 510(k) Pathway
│ │ ├── No changes from predicate → Abbreviated 510(k)
│ │ ├── Manufacturing changes only → Special 510(k)
│ │ └── Design/performance changes → Traditional 510(k)
│ └── NO → PMA or De Novo
└── NO → Is it a novel low-to-moderate risk device?
├── YES → De Novo Classification Request
└── NO → PMA Pathway (Class III)
```
### Classification Determination
| Class | Risk Level | Pathway | Examples |
|-------|------------|---------|----------|
| I | Low | Exempt or 510(k) | Bandages, stethoscopes |
| II | Moderate | 510(k) | Powered wheelchairs, pregnancy tests |
| III | High | PMA | Pacemakers, heart valves |
### Predicate Device Search
**Database Sources:**
1. FDA 510(k) Database: https://www.accessdata.fda.gov/scripts/cdrh/cfdocs/cfpmn/pmn.cfm
2. FDA Product Classification Database
3. FDA PMA Database
4. FDA De Novo Database
**Search Criteria:**
- Product code (3-letter code)
- Device name keywords
- Intended use similarity
- Technological characteristics
---
## 510(k) Premarket Notification
### Required Sections (21 CFR 807.87)
#### 1. Administrative Information
```
Cover Letter
├── Submission type (Traditional/Special/Abbreviated)
├── Device name and classification
├── Predicate device(s) identification
├── Contact information
└── Signature of authorized representative
CDRH Premarket Review Submission Cover Sheet (FDA Form 3514)
├── Section A: Applicant Information
├── Section B: Device Information
├── Section C: Submission Information
└── Section D: Truth and Accuracy Statement
```
#### 2. Device Description
| Element | Required Content |
|---------|------------------|
| Device Name | Trade name, common name, classification name |
| Intended Use | Disease/condition, patient population, use environment |
| Physical Description | Materials, dimensions, components |
| Principles of Operation | How the device achieves intended use |
| Accessories | Included items, optional components |
| Variants/Models | All versions included in submission |
#### 3. Substantial Equivalence Comparison
```
Comparison Table Format:
┌────────────────────┬─────────────────┬─────────────────┐
│ Characteristic │ Subject Device │ Predicate │
├────────────────────┼─────────────────┼─────────────────┤
│ Intended Use │ [Your device] │ [Predicate] │
│ Technological │ │ │
│ Characteristics │ │ │
│ Performance │ │ │
│ Safety │ │ │
└────────────────────┴─────────────────┴─────────────────┘
Substantial Equivalence Argument:
1. Same intended use? YES/NO
2. Same technological characteristics? YES/NO
3. If different technology, does it raise new safety/effectiveness questions? YES/NO
4. Performance data demonstrates equivalence? YES/NO
```
#### 4. Performance Testing
**Bench Testing:**
- Mechanical/structural testing
- Electrical safety (IEC 60601-1 if applicable)
- Biocompatibility (ISO 10993 series)
- Sterilization validation
- Shelf life/stability testing
- Software verification (IEC 62304 if applicable)
**Clinical Data (if required):**
- Clinical study summaries
- Literature review
- Adverse event data
#### 5. Labeling
**Required Elements:**
- Instructions for Use (IFU)
- Device labeling (package, carton)
- Indications for Use statement
- Contraindications, warnings, precautions
- Advertising materials (if applicable)
### 510(k) Acceptance Checklist
```markdown
## Pre-Submission Verification
- [ ] FDA Form 3514 complete and signed
- [ ] User fee payment ($21,760 for FY2024, small business exemptions available)
- [ ] Device description complete
- [ ] Predicate device identified with 510(k) number
- [ ] Substantial equivalence comparison table
- [ ] Indications for Use statement (FDA Form 3881)
- [ ] Performance data summary
- [ ] Labeling (IFU, device labels)
- [ ] 510(k) summary or statement
- [ ] Truthful and Accuracy statement signed
- [ ] Environmental assessment or categorical exclusion
```
---
## De Novo Classification
### Eligibility Criteria
1. Novel device with no legally marketed predicate
2. Low-to-moderate risk (would be Class I or II if predicate existed)
3. General controls alone (Class I) or with special controls (Class II) provide reasonable assurance of safety and effectiveness
### Required Content
#### Risk Assessment
```
Risk Analysis Requirements:
├── Hazard Identification
│ ├── Biological hazards
│ ├── Mechanical hazards
│ ├── Electrical hazards
│ ├── Use-related hazards
│ └── Cybersecurity hazards (if applicable)
├── Risk Estimation
│ ├── Probability of occurrence
│ ├── Severity of harm
│ └── Risk level (High/Medium/Low)
├── Risk Evaluation
│ ├── Acceptability criteria
│ └── Benefit-risk analysis
└── Risk Control Measures
├── Design controls
├── Protective measures
└── Information for safety
```
#### Proposed Classification
| Classification | Controls | Rationale |
|----------------|----------|-----------|
| Class I | General controls only | Low risk, general controls adequate |
| Class II | General + Special controls | Moderate risk, special controls needed |
#### Special Controls (for Class II)
Define specific controls such as:
- Performance testing requirements
- Labeling requirements
- Post-market surveillance
- Patient registry
- Design specifications
---
## PMA Premarket Approval
### PMA Application Contents
#### Technical Sections
1. **Device Description and Intended Use**
- Detailed design specifications
- Operating principles
- Complete indications for use
2. **Manufacturing Information**
- Manufacturing process description
- Quality system information
- Facility registration
3. **Nonclinical Laboratory Studies**
- Bench testing results
- Animal studies (if applicable)
- Biocompatibility testing
4. **Clinical Investigation**
- IDE number and approval date
- Clinical protocol
- Clinical study results
- Statistical analysis
- Adverse events
5. **Labeling**
- Complete labeling
- Patient labeling (if applicable)
#### Clinical Data Requirements
```
Clinical Study Design:
├── Study Objectives
│ ├── Primary endpoint(s)
│ └── Secondary endpoint(s)
├── Study Population
│ ├── Inclusion criteria
│ ├── Exclusion criteria
│ └── Sample size justification
├── Study Design
│ ├── Randomized controlled trial
│ ├── Single-arm study with OPC
│ └── Other design with justification
├── Statistical Analysis Plan
│ ├── Analysis populations
│ ├── Statistical methods
│ └── Handling of missing data
└── Safety Monitoring
├── Adverse event definitions
├── Stopping rules
└── DSMB oversight
```
### IDE (Investigational Device Exemption)
**When Required:**
- Significant risk device clinical studies
- Studies not exempt under 21 CFR 812.2
**IDE Application Content:**
- Investigational plan
- Manufacturing information
- Investigator agreements
- IRB approvals
- Informed consent forms
- Labeling
- Risk analysis
---
## Pre-Submission Program
### Q-Submission Types
| Type | Purpose | FDA Response |
|------|---------|--------------|
| Pre-Sub | Feedback on planned submission | Written feedback or meeting |
| Informational | Share information, no feedback | Acknowledgment only |
| Study Risk | Determination of study risk level | Risk determination |
| Agreement/Determination | Binding agreement on specific issue | Formal agreement |
### Pre-Sub Meeting Preparation
```
Pre-Submission Package:
1. Cover letter with meeting request
2. Device description
3. Regulatory history (if any)
4. Proposed submission pathway
5. Specific questions (maximum 5-6)
6. Supporting data/information
Meeting Types:
- Written response only (default)
- Teleconference (90 minutes)
- In-person meeting (90 minutes)
```
### Effective Question Formulation
**Good Question Format:**
```
Question: Does FDA agree that [specific proposal] is acceptable for [specific purpose]?
Background: [Brief context - 1-2 paragraphs]
Proposal: [Your specific proposal - detailed but concise]
Rationale: [Why you believe this is appropriate]
```
**Avoid:**
- Open-ended questions ("What should we do?")
- Multiple questions combined
- Questions already answered in guidance
---
## FDA Review Timeline
### Standard Review Times
| Submission Type | FDA Goal | Typical Range |
|----------------|----------|---------------|
| 510(k) Traditional | 90 days | 90-150 days |
| 510(k) Special | 30 days | 30-60 days |
| 510(k) Abbreviated | 30 days | 30-60 days |
| De Novo | 150 days | 150-300 days |
| PMA | 180 days | 12-24 months |
| Pre-Sub Response | 70-75 days | 60-90 days |
### Review Process Stages
```
510(k) Review Timeline:
Day 0: Submission received
Day 1-15: Acceptance review
├── Accept → Substantive review begins
└── Refuse to Accept (RTA) → 180 days to respond
Day 15-90: Substantive review
├── Additional Information (AI) request stops clock
├── Interactive review may occur
└── Decision by Day 90 goal
Decision:
├── Substantially Equivalent (SE) → Clearance letter
├── Not Substantially Equivalent (NSE) → Appeal or new submission
└── Withdrawn
```
### Additional Information Requests
**Response Best Practices:**
- Respond within 30-60 days
- Use FDA's question numbering
- Provide complete responses
- Include amended sections clearly marked
- Reference specific guidance documents
---
## Submission Best Practices
### Document Formatting
- Use PDF format (PDF/A preferred)
- Bookmarks for each section
- Hyperlinks to cross-references
- Table of contents with page numbers
- Consistent headers/footers
### eSTAR (Electronic Submission Template)
FDA's recommended electronic submission format for 510(k):
- Structured data entry
- Built-in validation
- Automatic formatting
- Reduced RTA rate
### Common Refuse to Accept (RTA) Issues
| Issue | Prevention |
|-------|------------|
| Missing user fee | Verify payment before submission |
| Incomplete Form 3514 | Review all fields, ensure signature |
| Missing predicate | Confirm predicate is legally marketed |
| Inadequate device description | Include all models, accessories |
| Missing Indications for Use | Use FDA Form 3881 |
| Incomplete SE comparison | Address all characteristics |
FILE:references/hipaa_compliance_framework.md
# HIPAA Compliance Framework for Medical Devices
Complete guide to HIPAA requirements for medical device manufacturers and software developers.
---
## Table of Contents
- [HIPAA Overview](#hipaa-overview)
- [Privacy Rule Requirements](#privacy-rule-requirements)
- [Security Rule Requirements](#security-rule-requirements)
- [Medical Device Considerations](#medical-device-considerations)
- [Risk Assessment](#risk-assessment)
- [Implementation Specifications](#implementation-specifications)
- [Business Associate Agreements](#business-associate-agreements)
- [Breach Notification](#breach-notification)
---
## HIPAA Overview
### Applicability to Medical Devices
| Entity Type | HIPAA Applicability |
|-------------|---------------------|
| Healthcare providers | Covered Entity (CE) |
| Health plans | Covered Entity (CE) |
| Healthcare clearinghouses | Covered Entity (CE) |
| Device manufacturers | Business Associate (BA) if handling PHI |
| SaMD developers | Business Associate (BA) if handling PHI |
| Cloud service providers | Business Associate (BA) |
### Protected Health Information (PHI)
**PHI Definition:** Individually identifiable health information transmitted or maintained in any form.
**18 HIPAA Identifiers:**
```
1. Names
2. Geographic data (smaller than state)
3. Dates (except year) related to individual
4. Phone numbers
5. Fax numbers
6. Email addresses
7. Social Security numbers
8. Medical record numbers
9. Health plan beneficiary numbers
10. Account numbers
11. Certificate/license numbers
12. Vehicle identifiers
13. Device identifiers and serial numbers
14. Web URLs
15. IP addresses
16. Biometric identifiers
17. Full face photos
18. Any other unique identifying number
```
### Electronic PHI (ePHI)
PHI that is created, stored, transmitted, or received in electronic form. Most relevant for:
- Connected medical devices
- Medical device software (SaMD)
- Mobile health applications
- Cloud-based healthcare systems
---
## Privacy Rule Requirements
### Minimum Necessary Standard
**Principle:** Limit PHI access, use, and disclosure to the minimum necessary to accomplish the intended purpose.
**Implementation:**
- Role-based access controls
- Access audit logging
- Data segmentation
- Need-to-know policies
### Patient Rights
| Right | Device Implication |
|-------|---------------------|
| Access | Provide mechanism to view/export data |
| Amendment | Allow corrections to patient data |
| Accounting of disclosures | Log all PHI disclosures |
| Restriction requests | Support data sharing restrictions |
| Confidential communications | Secure communication channels |
### Use and Disclosure
**Permitted Uses:**
- Treatment, Payment, Healthcare Operations (TPO)
- With patient authorization
- Public health activities
- Required by law
- Health oversight activities
**Medical Device Context:**
- Device data for treatment: Permitted
- Data analytics by manufacturer: Requires BAA or de-identification
- Research use: Requires authorization or IRB waiver
---
## Security Rule Requirements
### Administrative Safeguards
#### Security Management Process (§164.308(a)(1))
**Required Specifications:**
```markdown
## Security Management Process
### Risk Analysis
- [ ] Identify systems with ePHI
- [ ] Document potential threats and vulnerabilities
- [ ] Assess likelihood and impact
- [ ] Document current controls
- [ ] Determine risk levels
### Risk Management
- [ ] Implement security measures
- [ ] Document residual risk
- [ ] Management approval
### Sanction Policy
- [ ] Define workforce sanctions
- [ ] Document enforcement procedures
### Information System Activity Review
- [ ] Define audit procedures
- [ ] Review logs regularly
- [ ] Document findings
```
#### Workforce Security (§164.308(a)(3))
| Specification | Type | Implementation |
|---------------|------|----------------|
| Authorization/supervision | Addressable | Access approval process |
| Workforce clearance | Addressable | Background checks |
| Termination procedures | Addressable | Access revocation |
#### Information Access Management (§164.308(a)(4))
**Access Control Elements:**
- Access authorization
- Access establishment and modification
- Unique user identification
- Automatic logoff
#### Security Awareness and Training (§164.308(a)(5))
**Training Topics:**
- Security reminders
- Protection from malicious software
- Login monitoring
- Password management
#### Security Incident Procedures (§164.308(a)(6))
**Incident Response Requirements:**
1. Identify and document incidents
2. Report security incidents
3. Respond to mitigate harmful effects
4. Document outcomes
#### Contingency Plan (§164.308(a)(7))
```markdown
## Contingency Plan Components
### Data Backup Plan (Required)
- Backup frequency: _____
- Backup verification: _____
- Off-site storage: _____
### Disaster Recovery Plan (Required)
- Recovery time objective: _____
- Recovery point objective: _____
- Recovery procedures: _____
### Emergency Mode Operation (Required)
- Critical functions: _____
- Manual procedures: _____
- Communication plan: _____
### Testing and Revision (Addressable)
- Test frequency: _____
- Last test date: _____
- Revision history: _____
### Applications and Data Criticality (Addressable)
- Critical systems: _____
- Priority recovery order: _____
```
### Physical Safeguards
#### Facility Access Controls (§164.310(a)(1))
| Specification | Type | Implementation |
|---------------|------|----------------|
| Contingency operations | Addressable | Physical access during emergency |
| Facility security plan | Addressable | Physical access policies |
| Access control/validation | Addressable | Visitor management |
| Maintenance records | Addressable | Physical maintenance logs |
#### Workstation Use (§164.310(b))
**Requirements:**
- Policies for workstation use
- Physical environment considerations
- Secure positioning
- Screen privacy
#### Workstation Security (§164.310(c))
**Physical Safeguards:**
- Cable locks
- Restricted areas
- Surveillance
- Clean desk policy
#### Device and Media Controls (§164.310(d)(1))
**Critical for Medical Devices:**
```markdown
## Device and Media Controls
### Disposal (Required)
- [ ] Wipe procedures for devices with ePHI
- [ ] Certificate of destruction
- [ ] Media sanitization per NIST 800-88
### Media Re-use (Required)
- [ ] Sanitization before re-use
- [ ] Verification of removal
- [ ] Documentation
### Accountability (Addressable)
- [ ] Hardware inventory
- [ ] Movement tracking
- [ ] Responsibility assignment
### Data Backup and Storage (Addressable)
- [ ] Retrievable copies
- [ ] Secure storage location
- [ ] Access controls on backup media
```
### Technical Safeguards
#### Access Control (§164.312(a)(1))
| Specification | Type | Implementation |
|---------------|------|----------------|
| Unique user identification | Required | Individual accounts |
| Emergency access | Required | Break-glass procedures |
| Automatic logoff | Addressable | Session timeout |
| Encryption and decryption | Addressable | At-rest encryption |
#### Audit Controls (§164.312(b))
**Audit Log Contents:**
- User identification
- Event type
- Date and time
- Success/failure
- Affected data
**Medical Device Considerations:**
- Log all access to patient data
- Protect logs from tampering
- Retain logs per policy (minimum 6 years)
- Real-time alerting for critical events
#### Integrity (§164.312(c)(1))
**ePHI Integrity Controls:**
- Hash verification
- Digital signatures
- Version control
- Change detection
#### Person or Entity Authentication (§164.312(d))
**Authentication Methods:**
- Passwords (strong requirements)
- Biometrics
- Hardware tokens
- Multi-factor authentication (recommended)
#### Transmission Security (§164.312(e)(1))
| Specification | Type | Implementation |
|---------------|------|----------------|
| Integrity controls | Addressable | TLS, message authentication |
| Encryption | Addressable | TLS 1.2+, AES-256 |
---
## Medical Device Considerations
### Connected Medical Device Security
**Data Flow Analysis:**
```
Device → Local Network → Internet → Cloud → EHR
│ │ │ │ │
└─ ePHI at rest ePHI in transit ePHI at rest
Encrypt Encrypt TLS Encrypt + Access Control
```
### SaMD (Software as a Medical Device)
**HIPAA Requirements for SaMD:**
1. Encryption of stored patient data
2. Secure authentication
3. Audit logging
4. Access controls
5. Secure communication protocols
6. Backup and recovery
7. Incident response
### Mobile Medical Applications
**Additional Considerations:**
- Device loss/theft protection
- Remote wipe capability
- App sandboxing
- Secure data storage
- API security
### Cloud-Based Devices
**Cloud Provider Requirements:**
- BAA with cloud provider
- Data residency (US only for HIPAA)
- Encryption key management
- Audit log access
- Incident notification
---
## Risk Assessment
### HIPAA Risk Assessment Process
```
Step 1: Scope Definition
├── Identify systems with ePHI
├── Document data flows
└── Identify business associates
Step 2: Threat Identification
├── Natural threats (fire, flood)
├── Human threats (hackers, insiders)
├── Environmental threats (power, HVAC)
└── Technical threats (malware, system failure)
Step 3: Vulnerability Assessment
├── Administrative controls
├── Physical controls
├── Technical controls
└── Gap analysis
Step 4: Risk Analysis
├── Likelihood assessment
├── Impact assessment
├── Risk level determination
└── Risk prioritization
Step 5: Risk Treatment
├── Accept
├── Mitigate
├── Transfer
└── Avoid
Step 6: Documentation
├── Risk register
├── Risk management plan
└── Remediation tracking
```
### Risk Assessment Template
```markdown
## HIPAA Risk Assessment
### System Information
System Name: _____________________
System Owner: ____________________
Date: ___________________________
### Asset Inventory
| Asset | ePHI Type | Location | Classification |
|-------|-----------|----------|----------------|
| | | | |
### Threat Analysis
| Threat | Likelihood (1-5) | Impact (1-5) | Risk Score |
|--------|------------------|--------------|------------|
| | | | |
### Vulnerability Assessment
| Safeguard Category | Gap Identified | Severity | Remediation |
|--------------------|----------------|----------|-------------|
| Administrative | | | |
| Physical | | | |
| Technical | | | |
### Risk Treatment Plan
| Risk | Treatment | Owner | Timeline | Status |
|------|-----------|-------|----------|--------|
| | | | | |
### Approval
Risk Assessment Approved: _______________ Date: _______
Next Assessment Due: _______________
```
---
## Implementation Specifications
### Required vs. Addressable
**Required:** Must be implemented as specified
**Addressable:**
1. Implement as specified, OR
2. Implement alternative measure, OR
3. Not implement if not reasonable and appropriate (document rationale)
### Implementation Status Matrix
| Safeguard | Specification | Type | Status | Evidence |
|-----------|---------------|------|--------|----------|
| §164.308(a)(1)(ii)(A) | Risk analysis | R | ☐ | |
| §164.308(a)(1)(ii)(B) | Risk management | R | ☐ | |
| §164.308(a)(3)(ii)(A) | Authorization/supervision | A | ☐ | |
| §164.308(a)(5)(ii)(A) | Security reminders | A | ☐ | |
| §164.310(a)(2)(i) | Contingency operations | A | ☐ | |
| §164.310(d)(2)(i) | Disposal | R | ☐ | |
| §164.312(a)(2)(i) | Unique user ID | R | ☐ | |
| §164.312(a)(2)(ii) | Emergency access | R | ☐ | |
| §164.312(a)(2)(iv) | Encryption (at rest) | A | ☐ | |
| §164.312(e)(2)(ii) | Encryption (transit) | A | ☐ | |
---
## Business Associate Agreements
### When Required
BAA required when business associate:
- Creates, receives, maintains, or transmits PHI
- Provides services involving PHI use/disclosure
### BAA Requirements
**Required Provisions:**
1. Permitted and required uses of PHI
2. Subcontractor requirements
3. Appropriate safeguards
4. Breach notification
5. Termination provisions
6. Return or destruction of PHI
### Medical Device Manufacturer BAA Template
```markdown
## Business Associate Agreement
This Agreement is entered into as of [Date] between:
COVERED ENTITY: [Healthcare Provider/Plan Name]
BUSINESS ASSOCIATE: [Device Manufacturer Name]
### 1. Definitions
[Standard HIPAA definitions]
### 2. Obligations of Business Associate
Business Associate agrees to:
a) Not use or disclose PHI other than as permitted
b) Use appropriate safeguards to prevent improper use/disclosure
c) Report any security incident or breach
d) Ensure subcontractors agree to same restrictions
e) Make PHI available for individual access
f) Make PHI available for amendment
g) Document and make available disclosures
h) Make internal practices available to HHS
i) Return or destroy PHI at termination
### 3. Permitted Uses and Disclosures
Business Associate may:
a) Use PHI for device operation and maintenance
b) Use PHI for quality improvement
c) De-identify PHI per HIPAA standards
d) Create aggregate data
e) Report to FDA as required
### 4. Security Requirements
Business Associate shall implement:
a) Administrative safeguards per §164.308
b) Physical safeguards per §164.310
c) Technical safeguards per §164.312
### 5. Breach Notification
Business Associate shall:
a) Report breaches within [60 days/contractual period]
b) Provide information for breach notification
c) Mitigate harmful effects
### 6. Term and Termination
[Standard termination provisions]
### Signatures
COVERED ENTITY: _________________ Date: _______
BUSINESS ASSOCIATE: _____________ Date: _______
```
---
## Breach Notification
### Breach Definition
**Breach:** Acquisition, access, use, or disclosure of unsecured PHI in a manner not permitted that compromises security or privacy.
**Exceptions:**
1. Unintentional acquisition by workforce member acting in good faith
2. Inadvertent disclosure between authorized persons
3. Good faith belief that unauthorized person couldn't retain information
### Risk Assessment for Breach
**Factors to Consider:**
1. Nature and extent of PHI involved
2. Unauthorized person who received PHI
3. Whether PHI was actually acquired/viewed
4. Extent to which risk has been mitigated
### Notification Requirements
| Audience | Timing | Method |
|----------|--------|--------|
| Individuals | 60 days from discovery | First-class mail or email |
| HHS | 60 days (if >500) | HHS breach portal |
| HHS | Annual (if <500) | Annual report |
| Media | 60 days (if >500 in state) | Prominent media outlet |
### Breach Response Procedure
```markdown
## Breach Response Procedure
### Phase 1: Detection and Containment (Immediate)
- [ ] Identify scope of breach
- [ ] Contain breach (stop ongoing access)
- [ ] Preserve evidence
- [ ] Notify incident response team
- [ ] Document timeline
### Phase 2: Investigation (1-14 days)
- [ ] Determine what PHI was involved
- [ ] Identify affected individuals
- [ ] Assess risk of harm
- [ ] Document investigation findings
### Phase 3: Risk Assessment (15-30 days)
- [ ] Apply four-factor risk assessment
- [ ] Determine if notification required
- [ ] Document decision rationale
### Phase 4: Notification (Within 60 days)
- [ ] Prepare individual notification letters
- [ ] Submit to HHS (if required)
- [ ] Media notification (if required)
- [ ] Retain copies of notifications
### Phase 5: Remediation (Ongoing)
- [ ] Implement corrective actions
- [ ] Update policies and procedures
- [ ] Train workforce
- [ ] Monitor for additional impact
```
### Breach Notification Content
**Individual Notification Must Include:**
1. Description of what happened
2. Types of PHI involved
3. Steps individuals should take
4. What entity is doing to investigate
5. What entity is doing to prevent future breaches
6. Contact information for questions
---
## Compliance Checklist
### Administrative Safeguards Checklist
```markdown
## Administrative Safeguards
- [ ] Security Management Process
- [ ] Risk analysis completed and documented
- [ ] Risk management plan in place
- [ ] Sanction policy documented
- [ ] Information system activity review conducted
- [ ] Assigned Security Responsibility
- [ ] Security Officer designated
- [ ] Contact information documented
- [ ] Workforce Security
- [ ] Authorization procedures
- [ ] Background checks (if applicable)
- [ ] Termination procedures
- [ ] Information Access Management
- [ ] Access authorization policies
- [ ] Access establishment procedures
- [ ] Access modification procedures
- [ ] Security Awareness and Training
- [ ] Training program established
- [ ] Security reminders distributed
- [ ] Protection from malicious software training
- [ ] Password management training
- [ ] Security Incident Procedures
- [ ] Incident response plan
- [ ] Incident documentation procedures
- [ ] Reporting mechanisms
- [ ] Contingency Plan
- [ ] Data backup plan
- [ ] Disaster recovery plan
- [ ] Emergency mode operation plan
- [ ] Testing and revision procedures
```
### Technical Safeguards Checklist
```markdown
## Technical Safeguards
- [ ] Access Control
- [ ] Unique user identification
- [ ] Emergency access procedure
- [ ] Automatic logoff
- [ ] Encryption (at rest)
- [ ] Audit Controls
- [ ] Audit logging implemented
- [ ] Log review procedures
- [ ] Log retention policy
- [ ] Integrity
- [ ] Mechanism to authenticate ePHI
- [ ] Integrity controls in place
- [ ] Authentication
- [ ] Person/entity authentication
- [ ] Strong password policy
- [ ] Transmission Security
- [ ] Integrity controls (in transit)
- [ ] Encryption (TLS 1.2+)
```
---
## Quick Reference
### Common HIPAA Violations
| Violation | Prevention |
|-----------|------------|
| Unauthorized access | Role-based access, MFA |
| Lost/stolen devices | Encryption, remote wipe |
| Improper disposal | NIST 800-88 sanitization |
| Insufficient training | Annual training program |
| Missing BAAs | BA inventory and tracking |
| Insufficient audit logs | Comprehensive logging |
### Penalty Structure
| Tier | Knowledge | Per Violation | Annual Maximum |
|------|-----------|---------------|----------------|
| 1 | Unknown | $100-$50,000 | $1,500,000 |
| 2 | Reasonable cause | $1,000-$50,000 | $1,500,000 |
| 3 | Willful neglect (corrected) | $10,000-$50,000 | $1,500,000 |
| 4 | Willful neglect (not corrected) | $50,000 | $1,500,000 |
### FDA-HIPAA Intersection
| Device Scenario | FDA | HIPAA |
|-----------------|-----|-------|
| Standalone diagnostic | 510(k)/PMA | If transmits PHI |
| Connected insulin pump | Class III PMA | Yes (patient data) |
| Wellness app (no diagnosis) | Exempt | If stores PHI |
| EHR-integrated device | May apply | Yes |
| Research device | IDE | IRB may waive |
FILE:references/qsr_compliance_requirements.md
# Quality System Regulation (QSR) Compliance
Complete guide to 21 CFR Part 820 requirements for medical device manufacturers.
---
## Table of Contents
- [QSR Overview](#qsr-overview)
- [Management Responsibility (820.20)](#management-responsibility-82020)
- [Design Controls (820.30)](#design-controls-82030)
- [Document Controls (820.40)](#document-controls-82040)
- [Purchasing Controls (820.50)](#purchasing-controls-82050)
- [Production and Process Controls (820.70-75)](#production-and-process-controls-82070-75)
- [CAPA (820.100)](#capa-820100)
- [Device Master Record (820.181)](#device-master-record-820181)
- [FDA Inspection Readiness](#fda-inspection-readiness)
---
## QSR Overview
### Applicability
The QSR applies to:
- Finished device manufacturers
- Specification developers
- Initial distributors of imported devices
- Contract manufacturers
- Repackagers and relabelers
### Exemptions
| Device Class | Exemption Status |
|--------------|------------------|
| Class I (most) | Exempt from design controls (820.30) |
| Class I (listed) | Fully exempt from QSR |
| Class II | Full QSR compliance |
| Class III | Full QSR compliance |
### QSR Structure
```
21 CFR Part 820 Subparts:
├── A - General Provisions (820.1-5)
├── B - Quality System Requirements (820.20-25)
├── C - Design Controls (820.30)
├── D - Document Controls (820.40)
├── E - Purchasing Controls (820.50)
├── F - Identification and Traceability (820.60-65)
├── G - Production and Process Controls (820.70-75)
├── H - Acceptance Activities (820.80-86)
├── I - Nonconforming Product (820.90)
├── J - Corrective and Preventive Action (820.100)
├── K - Labeling and Packaging Control (820.120-130)
├── L - Handling, Storage, Distribution, Installation (820.140-170)
├── M - Records (820.180-198)
├── N - Servicing (820.200)
└── O - Statistical Techniques (820.250)
```
---
## Management Responsibility (820.20)
### Quality Policy
**Requirements:**
- Documented quality policy
- Objectives for quality
- Commitment to meeting requirements
- Communicated throughout organization
**Quality Policy Template:**
```markdown
## Quality Policy Statement
[Company Name] is committed to designing, manufacturing, and distributing
medical devices that meet customer requirements and applicable regulatory
standards. We achieve this through:
1. Maintaining an effective Quality Management System
2. Continuous improvement of our processes
3. Compliance with 21 CFR Part 820 and applicable standards
4. Training and empowering employees
5. Supplier quality management
Approved by: _______________ Date: _______________
Management Representative
```
### Organization
| Role | Responsibilities | Documentation |
|------|------------------|---------------|
| Management Representative | QMS oversight, FDA liaison | Org chart, job description |
| Quality Manager | Day-to-day QMS operations | Procedures, authority matrix |
| Design Authority | Design control decisions | DHF sign-offs |
| Production Manager | Manufacturing compliance | Process documentation |
### Management Review
**Frequency:** At least annually (more frequently recommended)
**Required Inputs:**
1. Audit results (internal and external)
2. Customer feedback and complaints
3. Process performance metrics
4. Product conformity data
5. CAPA status
6. Changes affecting QMS
7. Recommendations for improvement
**Required Outputs:**
- Decisions on improvement actions
- Resource needs
- Quality objectives updates
**Management Review Agenda Template:**
```markdown
## Management Review Meeting
Date: _______________
Attendees: _______________
### Agenda Items
1. Review of previous action items
2. Quality objectives and metrics
3. Internal audit results
4. Customer complaints summary
5. CAPA status report
6. Supplier quality performance
7. Regulatory updates
8. Resource requirements
9. Improvement opportunities
### Decisions and Actions
| Item | Decision | Owner | Due Date |
|------|----------|-------|----------|
| | | | |
### Next Review Date: _______________
```
---
## Design Controls (820.30)
### When Required
Design controls are required for:
- Class II devices (most)
- Class III devices (all)
- Class I devices with software
- Class I devices on exemption list exceptions
### Design Control Process Flow
```
Design Input (820.30c)
↓
Design Output (820.30d)
↓
Design Review (820.30e)
↓
Design Verification (820.30f)
↓
Design Validation (820.30g)
↓
Design Transfer (820.30h)
↓
Design Changes (820.30i)
↓
Design History File (820.30j)
```
### Design Input Requirements
**Must Include:**
- Intended use and user requirements
- Patient population
- Performance requirements
- Safety requirements
- Regulatory requirements
- Risk management requirements
**Verification Criteria:**
- Complete (all requirements captured)
- Unambiguous (clear interpretation)
- Not conflicting
- Verifiable or validatable
### Design Output Requirements
| Output Type | Examples | Verification Method |
|-------------|----------|---------------------|
| Device specifications | Drawings, BOMs | Inspection, testing |
| Manufacturing specs | Process parameters | Process validation |
| Software specs | Source code, architecture | Software V&V |
| Labeling | IFU, labels | Review against inputs |
**Essential Requirements:**
- Traceable to design inputs
- Contains acceptance criteria
- Identifies critical characteristics
### Design Review
**Review Stages:**
1. Concept review (feasibility)
2. Design input review (requirements complete)
3. Preliminary design review (architecture)
4. Critical design review (detailed design)
5. Final design review (transfer readiness)
**Participants:**
- Representative of each design function
- Other specialists as needed
- Independent reviewers (no direct design responsibility)
**Documentation:**
- Meeting minutes
- Issues identified
- Resolution actions
- Approval signatures
### Design Verification
**Methods:**
- Inspections and measurements
- Bench testing
- Analysis and calculations
- Simulations
- Comparisons to similar designs
**Verification Matrix Template:**
```markdown
| Req ID | Requirement | Verification Method | Pass Criteria | Result |
|--------|-------------|---------------------|---------------|--------|
| REQ-001 | Dimension tolerance | Measurement | ±0.5mm | |
| REQ-002 | Tensile strength | Testing per ASTM | >500 MPa | |
| REQ-003 | Software function | Unit testing | 100% pass | |
```
### Design Validation
**Definition:** Confirmation that device meets user needs and intended uses
**Validation Requirements:**
- Use initial production units (or equivalent)
- Simulated or actual use conditions
- Includes software validation
**Validation Types:**
1. **Bench validation** - Laboratory simulated use
2. **Clinical validation** - Human subjects (may require IDE)
3. **Usability validation** - Human factors testing
### Design Transfer
**Transfer Checklist:**
```markdown
## Design Transfer Verification
- [ ] DMR complete and approved
- [ ] Manufacturing processes validated
- [ ] Training completed
- [ ] Inspection procedures established
- [ ] Supplier qualifications complete
- [ ] Labeling approved
- [ ] Risk analysis updated
- [ ] Regulatory clearance/approval obtained
```
### Design History File (DHF)
**Contents:**
- Design and development plan
- Design input records
- Design output records
- Design review records
- Design verification records
- Design validation records
- Design transfer records
- Design change records
- Risk management file
---
## Document Controls (820.40)
### Document Approval and Distribution
**Requirements:**
- Documents reviewed and approved before use
- Approved documents available at point of use
- Obsolete documents removed or marked
- Changes reviewed and approved
### Document Control Matrix
| Document Type | Author | Reviewer | Approver | Distribution |
|---------------|--------|----------|----------|--------------|
| SOPs | Process owner | QA | Quality Manager | Controlled |
| Work Instructions | Supervisor | QA | Manager | Controlled |
| Forms | QA | QA | Quality Manager | Controlled |
| Drawings | Engineer | Peer | Design Authority | Controlled |
### Change Control
**Change Request Process:**
```
1. Initiate Change Request
└── Description, justification, impact assessment
2. Technical Review
└── Engineering, quality, regulatory assessment
3. Change Classification
├── Minor: No regulatory impact
├── Moderate: May affect compliance
└── Major: Regulatory submission required
4. Approval
└── Change Control Board (CCB) or designated authority
5. Implementation
└── Training, document updates, inventory actions
6. Verification
└── Confirm change implemented correctly
7. Close Change Request
└── Documentation complete
```
---
## Purchasing Controls (820.50)
### Supplier Qualification
**Qualification Criteria:**
- Quality system capability
- Product/service quality history
- Financial stability
- Regulatory compliance history
**Qualification Methods:**
| Method | When Used | Documentation |
|--------|-----------|---------------|
| On-site audit | Critical suppliers, high risk | Audit report |
| Questionnaire | Initial screening | Completed form |
| Certification review | ISO certified suppliers | Cert copies |
| Product qualification | Incoming inspection data | Test results |
### Approved Supplier List (ASL)
**ASL Requirements:**
- Supplier name and contact
- Products/services approved
- Qualification date and method
- Qualification status
- Re-evaluation schedule
### Purchasing Data
**Purchase Order Requirements:**
- Complete product specifications
- Quality requirements
- Applicable standards
- Inspection/acceptance requirements
- Right of access for verification
---
## Production and Process Controls (820.70-75)
### Process Validation (820.75)
**When Required:**
- Process output cannot be fully verified
- Deficiencies would only appear after use
- Examples: sterilization, welding, molding
**Validation Protocol Elements:**
```markdown
## Process Validation Protocol
### 1. Protocol Approval
Prepared by: _______________ Date: _______________
Approved by: _______________ Date: _______________
### 2. Process Description
[Describe process, equipment, materials, parameters]
### 3. Acceptance Criteria
| Parameter | Specification | Test Method |
|-----------|---------------|-------------|
| | | |
### 4. Equipment Qualification
- IQ (Installation Qualification): _______________
- OQ (Operational Qualification): _______________
- PQ (Performance Qualification): _______________
### 5. Validation Runs
Number of runs: _____ (minimum 3)
Lot sizes: _____
### 6. Results Summary
| Run | Date | Parameters | Results | Pass/Fail |
|-----|------|------------|---------|-----------|
| 1 | | | | |
| 2 | | | | |
| 3 | | | | |
### 7. Conclusion
Process validated: Yes / No
Revalidation triggers: _____
```
### Environmental Controls (820.70(c))
**Controlled Conditions:**
- Temperature and humidity
- Particulate contamination (cleanrooms)
- ESD (electrostatic discharge)
- Lighting levels
**Monitoring Requirements:**
- Continuous or periodic monitoring
- Documented limits
- Out-of-specification procedures
- Calibrated equipment
### Personnel (820.70(d))
**Training Requirements:**
- Job-specific training
- Competency verification
- Retraining for significant changes
- Training records maintained
**Training Record Template:**
```markdown
## Training Record
Employee: _______________ ID: _______________
Position: _______________
| Training Topic | Trainer | Date | Method | Competency Verified |
|----------------|---------|------|--------|---------------------|
| | | | | Signature: ________ |
```
### Equipment (820.70(g))
**Requirements:**
- Maintenance schedule
- Calibration program
- Adjustment limits documented
- Inspection before use
### Calibration (820.72)
**Calibration Program Elements:**
1. Equipment identification
2. Calibration frequency
3. Calibration procedures
4. Accuracy requirements
5. Traceability to NIST standards
6. Out-of-tolerance actions
---
## CAPA (820.100)
### CAPA Sources
- Customer complaints
- Nonconforming product
- Audit findings
- Process monitoring
- Returned products
- MDR/Vigilance reports
- Trend analysis
### CAPA Process
```
1. Identification
└── Problem statement, data collection
2. Investigation
└── Root cause analysis (5 Whys, Fishbone, etc.)
3. Action Determination
├── Correction: Immediate fix
└── Corrective/Preventive: Address root cause
4. Implementation
└── Action execution, documentation
5. Verification
└── Confirm actions completed
6. Effectiveness Review
└── Problem recurrence check (30-90 days)
7. Closure
└── Management approval
```
### Root Cause Analysis Tools
**5 Whys Example:**
```
Problem: Device failed during use
Why 1: Component failed
Why 2: Component was out of specification
Why 3: Incoming inspection did not detect
Why 4: Inspection procedure inadequate
Why 5: Procedure not updated for new component
Root Cause: Document control failure - procedure not updated
```
**Fishbone Categories:**
- Man (People)
- Machine (Equipment)
- Method (Process)
- Material
- Measurement
- Environment
### CAPA Metrics
| Metric | Target | Frequency |
|--------|--------|-----------|
| CAPA on-time closure | >90% | Monthly |
| Overdue CAPAs | <5 | Monthly |
| Effectiveness rate | >85% | Quarterly |
| Average days to closure | <60 | Monthly |
---
## Device Master Record (820.181)
### DMR Contents
```
Device Master Record
├── Device specifications
│ ├── Drawings
│ ├── Composition/formulation
│ └── Component specifications
├── Production process specifications
│ ├── Manufacturing procedures
│ ├── Assembly instructions
│ └── Process parameters
├── Quality assurance procedures
│ ├── Acceptance criteria
│ ├── Inspection procedures
│ └── Test methods
├── Packaging and labeling specifications
│ ├── Package drawings
│ ├── Label content
│ └── IFU content
├── Installation, maintenance, servicing procedures
└── Environmental requirements
```
### Device History Record (DHR) - 820.184
**DHR Contents:**
- Dates of manufacture
- Quantity manufactured
- Quantity released for distribution
- Acceptance records
- Primary identification label
- Device identification and control numbers
### Quality System Record (QSR) - 820.186
**QSR Contents:**
- Procedures and changes
- Calibration records
- Distribution records
- Complaint files
- CAPA records
- Audit reports
---
## FDA Inspection Readiness
### Pre-Inspection Preparation
**30-Day Readiness Checklist:**
```markdown
## FDA Inspection Readiness
### Documentation Review
- [ ] Quality manual current
- [ ] SOPs reviewed and approved
- [ ] Training records complete
- [ ] CAPA files complete
- [ ] Complaint files organized
- [ ] DMR/DHR accessible
- [ ] Management review records current
### Facility Review
- [ ] Controlled areas properly identified
- [ ] Equipment calibration current
- [ ] Environmental monitoring records available
- [ ] Storage conditions appropriate
- [ ] Quarantine areas clearly marked
### Personnel Preparation
- [ ] Escort team identified
- [ ] Subject matter experts briefed
- [ ] Front desk/reception notified
- [ ] Conference room reserved
- [ ] FDA credentials verification process
### Record Accessibility
- [ ] Electronic records accessible
- [ ] Backup copies available
- [ ] Audit trail functional
- [ ] Archive records retrievable
```
### During Inspection
**Escort Guidelines:**
1. One designated escort with investigator at all times
2. Answer questions truthfully and concisely
3. Don't volunteer information not requested
4. Request clarification if question unclear
5. Get help from SME for technical questions
6. Document all requests and commitments
**Record Request Tracking:**
| Request # | Date | Document Requested | Provided By | Date Provided |
|-----------|------|-------------------|-------------|---------------|
| | | | | |
### Post-Inspection
**FDA 483 Response:**
- Due within 15 business days
- Address each observation specifically
- Include corrective actions and timeline
- Provide evidence of completion where possible
**Response Format:**
```markdown
## Observation [Number]
### FDA Observation:
[Copy verbatim from Form 483]
### Company Response:
#### Understanding of Observation:
[Demonstrate understanding of the concern]
#### Immediate Correction:
[Actions already taken]
#### Root Cause Analysis:
[Investigation findings]
#### Corrective Actions:
| Action | Responsible | Target Date | Status |
|--------|-------------|-------------|--------|
| | | | |
#### Preventive Actions:
[Systemic improvements]
#### Verification:
[How effectiveness will be verified]
```
---
## Compliance Metrics Dashboard
### Key Performance Indicators
| Category | Metric | Target | Current |
|----------|--------|--------|---------|
| CAPA | On-time closure rate | >90% | |
| CAPA | Effectiveness rate | >85% | |
| Complaints | Response time (days) | <5 | |
| Training | Compliance rate | 100% | |
| Calibration | On-time rate | 100% | |
| Audit | Findings closure rate | >95% | |
| NCR | Recurring issues | <5% | |
| Supplier | Quality rate | >98% | |
### Trend Analysis
**Monthly Review Items:**
- Complaint trends by product/failure mode
- NCR trends by cause code
- CAPA effectiveness
- Supplier quality
- Production yields
- Customer feedback
---
## Quick Reference
### Common 483 Observations
| Observation | Prevention |
|-------------|------------|
| CAPA not effective | Verify effectiveness before closure |
| Training incomplete | Competency-based training records |
| Document control gaps | Regular procedure reviews |
| Complaint investigation | Thorough, documented investigations |
| Supplier controls weak | Robust qualification and monitoring |
| Validation inadequate | Follow IQ/OQ/PQ protocols |
### Regulatory Cross-References
| QSR Section | ISO 13485 Clause |
|-------------|------------------|
| 820.20 | 5.1, 5.5, 5.6 |
| 820.30 | 7.3 |
| 820.40 | 4.2.4 |
| 820.50 | 7.4 |
| 820.70 | 7.5.1 |
| 820.75 | 7.5.6 |
| 820.100 | 8.5.2, 8.5.3 |
FILE:scripts/fda_submission_tracker.py
#!/usr/bin/env python3
"""
FDA Submission Tracker
Tracks FDA submission status, calculates timelines, and monitors regulatory milestones
for 510(k), De Novo, and PMA submissions.
Usage:
python fda_submission_tracker.py <project_dir>
python fda_submission_tracker.py <project_dir> --type 510k
python fda_submission_tracker.py <project_dir> --json
"""
import argparse
import json
import os
import sys
from datetime import datetime, timedelta
from pathlib import Path
from typing import Dict, List, Optional, Any
# FDA review timeline targets (calendar days)
FDA_TIMELINES = {
"510k_traditional": {
"acceptance_review": 15,
"substantive_review": 90,
"total_goal": 90,
"ai_response": 180 # Days to respond to Additional Information
},
"510k_special": {
"acceptance_review": 15,
"substantive_review": 30,
"total_goal": 30,
"ai_response": 180
},
"510k_abbreviated": {
"acceptance_review": 15,
"substantive_review": 30,
"total_goal": 30,
"ai_response": 180
},
"de_novo": {
"acceptance_review": 60,
"substantive_review": 150,
"total_goal": 150,
"ai_response": 180
},
"pma": {
"acceptance_review": 45,
"substantive_review": 180,
"total_goal": 180,
"ai_response": 180
},
"pma_supplement": {
"acceptance_review": 15,
"substantive_review": 180,
"total_goal": 180,
"ai_response": 180
}
}
# Submission milestones by type
MILESTONES = {
"510k": [
{"id": "predicate_identified", "name": "Predicate Device Identified", "phase": "planning"},
{"id": "testing_complete", "name": "Performance Testing Complete", "phase": "preparation"},
{"id": "documentation_complete", "name": "Submission Documentation Complete", "phase": "preparation"},
{"id": "submission_sent", "name": "Submission Sent to FDA", "phase": "submission"},
{"id": "acknowledgment_received", "name": "FDA Acknowledgment Received", "phase": "review"},
{"id": "acceptance_decision", "name": "Acceptance Review Complete", "phase": "review"},
{"id": "ai_request", "name": "Additional Information Request", "phase": "review", "optional": True},
{"id": "ai_response", "name": "AI Response Submitted", "phase": "review", "optional": True},
{"id": "se_decision", "name": "Substantial Equivalence Decision", "phase": "decision"},
{"id": "clearance_letter", "name": "510(k) Clearance Letter Received", "phase": "decision"}
],
"de_novo": [
{"id": "classification_determined", "name": "Classification Determination", "phase": "planning"},
{"id": "special_controls_defined", "name": "Special Controls Defined", "phase": "preparation"},
{"id": "risk_assessment_complete", "name": "Risk Assessment Complete", "phase": "preparation"},
{"id": "testing_complete", "name": "Performance Testing Complete", "phase": "preparation"},
{"id": "submission_sent", "name": "Submission Sent to FDA", "phase": "submission"},
{"id": "acknowledgment_received", "name": "FDA Acknowledgment Received", "phase": "review"},
{"id": "acceptance_decision", "name": "Acceptance Review Complete", "phase": "review"},
{"id": "ai_request", "name": "Additional Information Request", "phase": "review", "optional": True},
{"id": "ai_response", "name": "AI Response Submitted", "phase": "review", "optional": True},
{"id": "classification_decision", "name": "De Novo Classification Decision", "phase": "decision"}
],
"pma": [
{"id": "ide_approved", "name": "IDE Approval (if required)", "phase": "planning", "optional": True},
{"id": "clinical_complete", "name": "Clinical Study Complete", "phase": "preparation"},
{"id": "clinical_report_complete", "name": "Clinical Study Report Complete", "phase": "preparation"},
{"id": "documentation_complete", "name": "PMA Documentation Complete", "phase": "preparation"},
{"id": "submission_sent", "name": "PMA Submission Sent to FDA", "phase": "submission"},
{"id": "acknowledgment_received", "name": "FDA Acknowledgment Received", "phase": "review"},
{"id": "filing_decision", "name": "Filing Decision", "phase": "review"},
{"id": "ai_request", "name": "Major Deficiency Letter", "phase": "review", "optional": True},
{"id": "ai_response", "name": "Deficiency Response Submitted", "phase": "review", "optional": True},
{"id": "panel_meeting", "name": "Advisory Committee Meeting", "phase": "review", "optional": True},
{"id": "approval_decision", "name": "PMA Approval Decision", "phase": "decision"}
]
}
def find_submission_config(project_dir: Path) -> Optional[Dict]:
"""Find and load submission configuration file."""
config_paths = [
project_dir / "fda_submission.json",
project_dir / "regulatory" / "fda_submission.json",
project_dir / ".fda" / "submission.json"
]
for config_path in config_paths:
if config_path.exists():
try:
with open(config_path) as f:
return json.load(f)
except json.JSONDecodeError:
continue
return None
def calculate_timeline_status(submission_type: str, milestones: Dict[str, str]) -> Dict:
"""Calculate timeline status based on submission type and milestone dates."""
timeline_config = FDA_TIMELINES.get(submission_type, FDA_TIMELINES["510k_traditional"])
result = {
"submission_type": submission_type,
"timeline_config": timeline_config,
"status": "not_started",
"days_elapsed": 0,
"days_remaining": None,
"projected_decision_date": None,
"on_track": None
}
# Check if submission has been sent
if "submission_sent" in milestones:
try:
submission_date = datetime.strptime(milestones["submission_sent"], "%Y-%m-%d")
today = datetime.now()
result["days_elapsed"] = (today - submission_date).days
# Check for AI hold
ai_hold_days = 0
if "ai_request" in milestones and "ai_response" in milestones:
ai_request_date = datetime.strptime(milestones["ai_request"], "%Y-%m-%d")
ai_response_date = datetime.strptime(milestones["ai_response"], "%Y-%m-%d")
ai_hold_days = (ai_response_date - ai_request_date).days
elif "ai_request" in milestones and "ai_response" not in milestones:
ai_request_date = datetime.strptime(milestones["ai_request"], "%Y-%m-%d")
ai_hold_days = (today - ai_request_date).days
result["status"] = "ai_hold"
# Calculate review days (excluding AI hold)
review_days = result["days_elapsed"] - ai_hold_days
# Determine status
if "se_decision" in milestones or "approval_decision" in milestones or "classification_decision" in milestones:
result["status"] = "complete"
elif "acceptance_decision" in milestones:
result["status"] = "substantive_review"
elif "acknowledgment_received" in milestones:
result["status"] = "acceptance_review"
else:
result["status"] = "submitted"
# Calculate projected decision date
if result["status"] not in ["complete", "ai_hold"]:
goal_days = timeline_config["total_goal"]
result["days_remaining"] = max(0, goal_days - review_days)
result["projected_decision_date"] = (submission_date + timedelta(days=goal_days + ai_hold_days)).strftime("%Y-%m-%d")
result["on_track"] = review_days <= goal_days
except ValueError:
pass
return result
def analyze_milestone_status(submission_type: str, completed_milestones: Dict[str, str]) -> List[Dict]:
"""Analyze milestone completion status."""
milestone_list = MILESTONES.get(submission_type.split("_")[0], MILESTONES["510k"])
results = []
for milestone in milestone_list:
status = {
"id": milestone["id"],
"name": milestone["name"],
"phase": milestone["phase"],
"optional": milestone.get("optional", False),
"completed": milestone["id"] in completed_milestones,
"completion_date": completed_milestones.get(milestone["id"])
}
results.append(status)
return results
def calculate_submission_readiness(project_dir: Path, submission_type: str) -> Dict:
"""Check submission readiness by looking for required documentation."""
required_docs = {
"510k": [
{"name": "Device Description", "patterns": ["device_description*", "device_desc*"]},
{"name": "Indications for Use", "patterns": ["indications*", "ifu*"]},
{"name": "Substantial Equivalence", "patterns": ["substantial_equiv*", "se_comparison*", "predicate*"]},
{"name": "Performance Testing", "patterns": ["performance*", "test_report*", "bench_test*"]},
{"name": "Biocompatibility", "patterns": ["biocompat*", "iso_10993*"]},
{"name": "Labeling", "patterns": ["label*", "ifu*", "instructions*"]},
{"name": "Software Documentation", "patterns": ["software*", "iec_62304*"], "optional": True},
{"name": "Sterilization Validation", "patterns": ["steriliz*", "sterility*"], "optional": True}
],
"de_novo": [
{"name": "Device Description", "patterns": ["device_description*", "device_desc*"]},
{"name": "Risk Assessment", "patterns": ["risk*", "hazard*"]},
{"name": "Special Controls", "patterns": ["special_control*"]},
{"name": "Performance Testing", "patterns": ["performance*", "test_report*"]},
{"name": "Labeling", "patterns": ["label*", "ifu*"]}
],
"pma": [
{"name": "Device Description", "patterns": ["device_description*"]},
{"name": "Manufacturing Information", "patterns": ["manufacturing*", "production*"]},
{"name": "Clinical Study Report", "patterns": ["clinical*", "csr*"]},
{"name": "Nonclinical Testing", "patterns": ["nonclinical*", "bench*", "preclinical*"]},
{"name": "Risk Analysis", "patterns": ["risk*", "fmea*"]},
{"name": "Labeling", "patterns": ["label*", "ifu*"]}
]
}
docs_to_check = required_docs.get(submission_type.split("_")[0], required_docs["510k"])
# Search common documentation directories
doc_dirs = [
project_dir / "regulatory",
project_dir / "regulatory" / "fda",
project_dir / "docs",
project_dir / "documentation",
project_dir / "dhf",
project_dir
]
results = []
for doc in docs_to_check:
found = False
found_path = None
for doc_dir in doc_dirs:
if not doc_dir.exists():
continue
for pattern in doc["patterns"]:
matches = list(doc_dir.glob(f"**/{pattern}"))
matches.extend(list(doc_dir.glob(f"**/{pattern.upper()}")))
if matches:
found = True
found_path = str(matches[0].relative_to(project_dir))
break
if found:
break
results.append({
"name": doc["name"],
"required": not doc.get("optional", False),
"found": found,
"path": found_path
})
required_found = sum(1 for r in results if r["required"] and r["found"])
required_total = sum(1 for r in results if r["required"])
return {
"documents": results,
"required_complete": required_found,
"required_total": required_total,
"readiness_percentage": round((required_found / required_total) * 100, 1) if required_total > 0 else 0
}
def generate_sample_config() -> Dict:
"""Generate sample submission configuration."""
return {
"submission_type": "510k_traditional",
"device_name": "Example Medical Device",
"product_code": "ABC",
"predicate_device": {
"name": "Predicate Device Name",
"k_number": "K123456"
},
"milestones": {
"predicate_identified": "2024-01-15",
"testing_complete": "2024-03-01",
"documentation_complete": "2024-03-15"
},
"contacts": {
"regulatory_lead": "Name",
"quality_lead": "Name"
},
"notes": "Add milestone dates as they are completed"
}
def print_text_report(result: Dict) -> None:
"""Print human-readable report."""
print("=" * 60)
print("FDA SUBMISSION TRACKER REPORT")
print("=" * 60)
if "error" in result:
print(f"\nError: {result['error']}")
print(f"\nTo create a configuration file, run with --init")
return
# Basic info
print(f"\nDevice: {result.get('device_name', 'Unknown')}")
print(f"Submission Type: {result['submission_type']}")
print(f"Product Code: {result.get('product_code', 'N/A')}")
# Timeline status
timeline = result["timeline_status"]
print(f"\n--- Timeline Status ---")
print(f"Status: {timeline['status'].upper()}")
print(f"Days Elapsed: {timeline['days_elapsed']}")
if timeline["days_remaining"] is not None:
print(f"Days Remaining (FDA goal): {timeline['days_remaining']}")
if timeline["projected_decision_date"]:
print(f"Projected Decision Date: {timeline['projected_decision_date']}")
if timeline["on_track"] is not None:
status = "ON TRACK" if timeline["on_track"] else "BEHIND SCHEDULE"
print(f"Timeline Status: {status}")
# Milestones
print(f"\n--- Milestones ---")
for ms in result["milestones"]:
status = "[X]" if ms["completed"] else "[ ]"
optional = " (optional)" if ms["optional"] else ""
date = f" - {ms['completion_date']}" if ms["completion_date"] else ""
print(f" {status} {ms['name']}{optional}{date}")
# Readiness
if "readiness" in result:
print(f"\n--- Submission Readiness ---")
readiness = result["readiness"]
print(f"Readiness: {readiness['readiness_percentage']}% ({readiness['required_complete']}/{readiness['required_total']} required docs)")
print("\n Documents:")
for doc in readiness["documents"]:
status = "[X]" if doc["found"] else "[ ]"
req = "(required)" if doc["required"] else "(optional)"
path = f" - {doc['path']}" if doc["path"] else ""
print(f" {status} {doc['name']} {req}{path}")
# Recommendations
if result.get("recommendations"):
print(f"\n--- Recommendations ---")
for i, rec in enumerate(result["recommendations"], 1):
print(f" {i}. {rec}")
print("\n" + "=" * 60)
def generate_recommendations(result: Dict) -> List[str]:
"""Generate actionable recommendations based on status."""
recommendations = []
timeline = result["timeline_status"]
# Timeline recommendations
if timeline["status"] == "ai_hold":
recommendations.append("Priority: Respond to FDA Additional Information request within 180 days")
elif timeline["on_track"] is False:
recommendations.append("Warning: Submission is behind FDA review schedule - consider contacting FDA")
# Milestone recommendations
completed_phases = set()
for ms in result["milestones"]:
if ms["completed"]:
completed_phases.add(ms["phase"])
if "submission" not in completed_phases and "preparation" in completed_phases:
recommendations.append("Ready for submission: Documentation complete, proceed with FDA submission")
# Readiness recommendations
if "readiness" in result:
missing_required = [d for d in result["readiness"]["documents"] if d["required"] and not d["found"]]
if missing_required:
docs = ", ".join(d["name"] for d in missing_required[:3])
recommendations.append(f"Missing required documentation: {docs}")
return recommendations
def analyze_submission(project_dir: Path, submission_type: Optional[str] = None) -> Dict:
"""Main analysis function."""
# Try to find existing configuration
config = find_submission_config(project_dir)
if config is None:
# No config found - do basic analysis
sub_type = submission_type or "510k_traditional"
result = {
"submission_type": sub_type,
"config_found": False,
"timeline_status": calculate_timeline_status(sub_type, {}),
"milestones": analyze_milestone_status(sub_type, {}),
"readiness": calculate_submission_readiness(project_dir, sub_type)
}
else:
# Config found - full analysis
sub_type = config.get("submission_type", submission_type or "510k_traditional")
milestones = config.get("milestones", {})
result = {
"submission_type": sub_type,
"device_name": config.get("device_name"),
"product_code": config.get("product_code"),
"predicate_device": config.get("predicate_device"),
"config_found": True,
"timeline_status": calculate_timeline_status(sub_type, milestones),
"milestones": analyze_milestone_status(sub_type, milestones),
"readiness": calculate_submission_readiness(project_dir, sub_type)
}
# Generate recommendations
result["recommendations"] = generate_recommendations(result)
return result
def main():
parser = argparse.ArgumentParser(
description="FDA Submission Tracker - Monitor 510(k), De Novo, and PMA submissions"
)
parser.add_argument(
"project_dir",
nargs="?",
default=".",
help="Project directory to analyze (default: current directory)"
)
parser.add_argument(
"--type",
choices=["510k", "510k_traditional", "510k_special", "510k_abbreviated",
"de_novo", "pma", "pma_supplement"],
help="Submission type (overrides config file)"
)
parser.add_argument(
"--json",
action="store_true",
help="Output in JSON format"
)
parser.add_argument(
"--init",
action="store_true",
help="Create sample configuration file"
)
args = parser.parse_args()
project_dir = Path(args.project_dir).resolve()
if not project_dir.exists():
print(f"Error: Directory not found: {project_dir}", file=sys.stderr)
sys.exit(1)
if args.init:
config_path = project_dir / "fda_submission.json"
if config_path.exists():
print(f"Configuration file already exists: {config_path}")
sys.exit(1)
sample = generate_sample_config()
if args.type:
sample["submission_type"] = args.type
with open(config_path, "w") as f:
json.dump(sample, f, indent=2)
print(f"Created sample configuration: {config_path}")
print("Edit this file with your submission details and milestone dates.")
return
result = analyze_submission(project_dir, args.type)
if args.json:
print(json.dumps(result, indent=2))
else:
print_text_report(result)
if __name__ == "__main__":
main()
FILE:scripts/hipaa_risk_assessment.py
#!/usr/bin/env python3
"""
HIPAA Risk Assessment Tool
Evaluates HIPAA compliance for medical device software and connected devices
by analyzing code and documentation for security safeguards.
Usage:
python hipaa_risk_assessment.py <project_dir>
python hipaa_risk_assessment.py <project_dir> --category technical
python hipaa_risk_assessment.py <project_dir> --json
"""
import argparse
import json
import os
import re
import sys
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Optional, Any, Tuple
# HIPAA Security Rule safeguards
HIPAA_SAFEGUARDS = {
"administrative": {
"title": "Administrative Safeguards (§164.308)",
"controls": {
"security_management": {
"title": "Security Management Process",
"requirement": "Risk analysis, risk management, sanction policy",
"doc_patterns": ["risk_assessment*", "security_policy*", "sanction*"],
"code_patterns": [],
"weight": 10
},
"security_officer": {
"title": "Assigned Security Responsibility",
"requirement": "Designated security official",
"doc_patterns": ["security_officer*", "hipaa_officer*", "privacy_officer*"],
"code_patterns": [],
"weight": 5
},
"workforce_security": {
"title": "Workforce Security",
"requirement": "Authorization/supervision, clearance, termination procedures",
"doc_patterns": ["access_control*", "termination*", "hr_security*"],
"code_patterns": [],
"weight": 5
},
"access_management": {
"title": "Information Access Management",
"requirement": "Access authorization, establishment, modification",
"doc_patterns": ["access_management*", "role_definition*", "access_control*"],
"code_patterns": [r"role.*based", r"permission", r"authorization"],
"weight": 8
},
"security_training": {
"title": "Security Awareness and Training",
"requirement": "Training program, security reminders",
"doc_patterns": ["training*", "security_awareness*"],
"code_patterns": [],
"weight": 5
},
"incident_procedures": {
"title": "Security Incident Procedures",
"requirement": "Incident response and reporting",
"doc_patterns": ["incident*", "breach*", "security_event*"],
"code_patterns": [r"incident.*report", r"security.*alert", r"breach.*notify"],
"weight": 8
},
"contingency_plan": {
"title": "Contingency Plan",
"requirement": "Backup, disaster recovery, emergency mode",
"doc_patterns": ["contingency*", "disaster_recovery*", "backup*", "dr_plan*"],
"code_patterns": [r"backup", r"recovery", r"failover"],
"weight": 8
},
"evaluation": {
"title": "Evaluation",
"requirement": "Periodic security evaluations",
"doc_patterns": ["security_audit*", "hipaa_audit*", "compliance_review*"],
"code_patterns": [],
"weight": 5
},
"baa": {
"title": "Business Associate Contracts",
"requirement": "Written contracts with business associates",
"doc_patterns": ["baa*", "business_associate*", "vendor_agreement*"],
"code_patterns": [],
"weight": 5
}
}
},
"physical": {
"title": "Physical Safeguards (§164.310)",
"controls": {
"facility_access": {
"title": "Facility Access Controls",
"requirement": "Physical access procedures and controls",
"doc_patterns": ["facility_access*", "physical_security*", "access_control*"],
"code_patterns": [],
"weight": 5
},
"workstation_use": {
"title": "Workstation Use",
"requirement": "Policies for workstation use and security",
"doc_patterns": ["workstation*", "endpoint*", "device_policy*"],
"code_patterns": [],
"weight": 3
},
"device_media": {
"title": "Device and Media Controls",
"requirement": "Disposal, media re-use, accountability",
"doc_patterns": ["media_disposal*", "device_disposal*", "data_sanitization*"],
"code_patterns": [r"secure.*delete", r"wipe", r"sanitize"],
"weight": 5
}
}
},
"technical": {
"title": "Technical Safeguards (§164.312)",
"controls": {
"access_control": {
"title": "Access Control",
"requirement": "Unique user ID, emergency access, auto logoff, encryption",
"doc_patterns": ["access_control*", "authentication*", "session*"],
"code_patterns": [
r"authentication",
r"authorize",
r"session.*timeout",
r"auto.*logout",
r"unique.*id",
r"user.*id"
],
"weight": 10
},
"audit_controls": {
"title": "Audit Controls",
"requirement": "Record and examine activity in systems with ePHI",
"doc_patterns": ["audit_log*", "access_log*", "security_log*"],
"code_patterns": [
r"audit.*log",
r"access.*log",
r"log.*access",
r"security.*event",
r"logger"
],
"weight": 10
},
"integrity": {
"title": "Integrity Controls",
"requirement": "Mechanism to authenticate ePHI",
"doc_patterns": ["data_integrity*", "checksum*", "hash*"],
"code_patterns": [
r"checksum",
r"hash",
r"hmac",
r"integrity.*check",
r"digital.*signature"
],
"weight": 8
},
"authentication": {
"title": "Person or Entity Authentication",
"requirement": "Verify identity of person or entity seeking access",
"doc_patterns": ["authentication*", "identity*", "mfa*", "2fa*"],
"code_patterns": [
r"authenticate",
r"mfa",
r"two.*factor",
r"2fa",
r"multi.*factor",
r"oauth",
r"jwt"
],
"weight": 10
},
"transmission_security": {
"title": "Transmission Security",
"requirement": "Encryption during transmission",
"doc_patterns": ["encryption*", "tls*", "ssl*", "transport_security*"],
"code_patterns": [
r"https",
r"tls",
r"ssl",
r"encrypt.*transit",
r"secure.*connection"
],
"weight": 10
}
}
}
}
# PHI data patterns to detect in code
PHI_PATTERNS = [
(r"patient.*name", "Patient Name"),
(r"ssn|social.*security", "Social Security Number"),
(r"date.*of.*birth|dob", "Date of Birth"),
(r"medical.*record", "Medical Record Number"),
(r"health.*plan", "Health Plan ID"),
(r"diagnosis|icd.*code", "Diagnosis/ICD Code"),
(r"prescription|medication", "Medication/Prescription"),
(r"insurance", "Insurance Information"),
(r"phone.*number|telephone", "Phone Number"),
(r"email.*address", "Email Address"),
(r"address|street|city|zip", "Physical Address"),
(r"biometric", "Biometric Data")
]
# Security vulnerability patterns (dynamic code execution, hardcoded secrets)
VULNERABILITY_PATTERNS = [
(r"password.*=.*['\"]", "Hardcoded password"),
(r"api.*key.*=.*['\"]", "Hardcoded API key"),
(r"secret.*=.*['\"]", "Hardcoded secret"),
(r"http://(?!localhost)", "Unencrypted HTTP connection"),
(r"verify.*=.*False", "SSL verification disabled"),
(r"dynamic.*code.*execution", "Dynamic code execution risk"),
(r"disable.*ssl", "SSL disabled"),
(r"insecure", "Insecure configuration")
]
def scan_documentation(project_dir: Path, patterns: List[str]) -> List[str]:
"""Scan for documentation matching patterns."""
found = []
doc_dirs = [
project_dir / "docs",
project_dir / "documentation",
project_dir / "policies",
project_dir / "compliance",
project_dir / "hipaa",
project_dir
]
for doc_dir in doc_dirs:
if not doc_dir.exists():
continue
for pattern in patterns:
for ext in ["*.md", "*.pdf", "*.docx", "*.doc", "*.txt"]:
try:
for match in doc_dir.glob(f"**/{pattern}{ext}"):
rel_path = str(match.relative_to(project_dir))
if rel_path not in found:
found.append(rel_path)
except Exception:
continue
return found
def scan_code_patterns(project_dir: Path, patterns: List[str]) -> List[Dict]:
"""Scan source code for patterns."""
matches = []
code_extensions = ["*.py", "*.js", "*.ts", "*.java", "*.cs", "*.go", "*.rb"]
src_dirs = [
project_dir / "src",
project_dir / "app",
project_dir / "lib",
project_dir
]
for src_dir in src_dirs:
if not src_dir.exists():
continue
for ext in code_extensions:
try:
for file_path in src_dir.glob(f"**/{ext}"):
# Skip node_modules, venv, etc.
if any(skip in str(file_path) for skip in ["node_modules", "venv", ".venv", "__pycache__", ".git"]):
continue
try:
content = file_path.read_text(encoding='utf-8', errors='ignore')
for pattern in patterns:
if re.search(pattern, content, re.IGNORECASE):
rel_path = str(file_path.relative_to(project_dir))
matches.append({
"file": rel_path,
"pattern": pattern
})
break # One match per file per control is enough
except Exception:
continue
except Exception:
continue
return matches
def detect_phi_handling(project_dir: Path) -> Dict:
"""Detect potential PHI handling in code."""
phi_found = []
code_extensions = ["*.py", "*.js", "*.ts", "*.java", "*.cs", "*.go"]
for ext in code_extensions:
try:
for file_path in project_dir.glob(f"**/{ext}"):
if any(skip in str(file_path) for skip in ["node_modules", "venv", ".venv", "__pycache__", ".git"]):
continue
try:
content = file_path.read_text(encoding='utf-8', errors='ignore')
rel_path = str(file_path.relative_to(project_dir))
for pattern, phi_type in PHI_PATTERNS:
if re.search(pattern, content, re.IGNORECASE):
phi_found.append({
"file": rel_path,
"phi_type": phi_type
})
break
except Exception:
continue
except Exception:
continue
return {
"phi_detected": len(phi_found) > 0,
"files_with_phi": phi_found,
"phi_types": list(set(p["phi_type"] for p in phi_found))
}
def detect_security_vulnerabilities(project_dir: Path) -> List[Dict]:
"""Scan for security vulnerabilities."""
vulnerabilities = []
code_extensions = ["*.py", "*.js", "*.ts", "*.java", "*.cs", "*.go", "*.yaml", "*.yml", "*.json"]
for ext in code_extensions:
try:
for file_path in project_dir.glob(f"**/{ext}"):
if any(skip in str(file_path) for skip in ["node_modules", "venv", ".venv", "__pycache__", ".git"]):
continue
try:
content = file_path.read_text(encoding='utf-8', errors='ignore')
rel_path = str(file_path.relative_to(project_dir))
for pattern, vuln_type in VULNERABILITY_PATTERNS:
matches = re.findall(pattern, content, re.IGNORECASE)
if matches:
vulnerabilities.append({
"file": rel_path,
"vulnerability": vuln_type,
"count": len(matches)
})
except Exception:
continue
except Exception:
continue
return vulnerabilities
def assess_control(project_dir: Path, control_id: str, control_data: Dict) -> Dict:
"""Assess a single HIPAA control."""
doc_evidence = scan_documentation(project_dir, control_data["doc_patterns"])
code_evidence = scan_code_patterns(project_dir, control_data["code_patterns"]) if control_data["code_patterns"] else []
# Determine compliance status
has_docs = len(doc_evidence) > 0
has_code = len(code_evidence) > 0
if has_docs and (has_code or not control_data["code_patterns"]):
status = "implemented"
score = 100
elif has_docs or has_code:
status = "partial"
score = 50
else:
status = "gap"
score = 0
return {
"control_id": control_id,
"title": control_data["title"],
"requirement": control_data["requirement"],
"status": status,
"score": score,
"weight": control_data["weight"],
"weighted_score": (score * control_data["weight"]) / 100,
"documentation": doc_evidence,
"code_evidence": [e["file"] for e in code_evidence]
}
def assess_category(project_dir: Path, category_id: str, category_data: Dict) -> Dict:
"""Assess a HIPAA safeguard category."""
control_results = []
total_weight = 0
weighted_score = 0
for control_id, control_data in category_data["controls"].items():
result = assess_control(project_dir, control_id, control_data)
control_results.append(result)
total_weight += control_data["weight"]
weighted_score += result["weighted_score"]
category_score = round((weighted_score / total_weight) * 100, 1) if total_weight > 0 else 0
return {
"category": category_id,
"title": category_data["title"],
"score": category_score,
"controls": control_results,
"compliant": sum(1 for c in control_results if c["status"] == "implemented"),
"partial": sum(1 for c in control_results if c["status"] == "partial"),
"gaps": sum(1 for c in control_results if c["status"] == "gap")
}
def calculate_risk_level(overall_score: float, vulnerabilities: List[Dict], phi_data: Dict) -> Dict:
"""Calculate overall HIPAA risk level."""
# Base risk from compliance score
if overall_score >= 80:
base_risk = "LOW"
base_score = 1
elif overall_score >= 60:
base_risk = "MEDIUM"
base_score = 2
elif overall_score >= 40:
base_risk = "HIGH"
base_score = 3
else:
base_risk = "CRITICAL"
base_score = 4
# Adjust for vulnerabilities
critical_vulns = sum(1 for v in vulnerabilities if "password" in v["vulnerability"].lower() or "secret" in v["vulnerability"].lower())
if critical_vulns > 0:
base_score = min(4, base_score + 1)
# Adjust for PHI handling
if phi_data["phi_detected"] and base_score < 4:
base_score = min(4, base_score + 0.5)
# Map back to risk level
risk_levels = {1: "LOW", 2: "MEDIUM", 3: "HIGH", 4: "CRITICAL"}
final_risk = risk_levels.get(int(base_score), "HIGH")
return {
"risk_level": final_risk,
"compliance_score": overall_score,
"vulnerability_count": len(vulnerabilities),
"phi_handling_detected": phi_data["phi_detected"]
}
def generate_recommendations(assessment: Dict) -> List[str]:
"""Generate prioritized recommendations."""
recommendations = []
# Technical safeguards first (highest priority for software)
for cat in assessment["categories"]:
if cat["category"] == "technical":
for control in cat["controls"]:
if control["status"] == "gap":
recommendations.append(f"CRITICAL: Implement {control['title']} - {control['requirement']}")
elif control["status"] == "partial":
recommendations.append(f"HIGH: Complete {control['title']} implementation")
# Administrative safeguards
for cat in assessment["categories"]:
if cat["category"] == "administrative":
for control in cat["controls"]:
if control["status"] == "gap":
recommendations.append(f"MEDIUM: Document {control['title']} procedures")
# Vulnerabilities
for vuln in assessment.get("vulnerabilities", [])[:5]:
recommendations.append(f"SECURITY: Fix {vuln['vulnerability']} in {vuln['file']}")
return recommendations[:10] # Top 10
def print_text_report(result: Dict) -> None:
"""Print human-readable report."""
print("=" * 70)
print("HIPAA SECURITY RULE COMPLIANCE ASSESSMENT")
print("=" * 70)
# Risk summary
risk = result["risk_assessment"]
print(f"\nRISK LEVEL: {risk['risk_level']}")
print(f"Compliance Score: {risk['compliance_score']}%")
print(f"Vulnerabilities Found: {risk['vulnerability_count']}")
print(f"PHI Handling Detected: {'Yes' if risk['phi_handling_detected'] else 'No'}")
# Category scores
print("\n--- SAFEGUARD CATEGORIES ---")
for cat in result["categories"]:
status = "OK" if cat["score"] >= 70 else "NEEDS ATTENTION"
print(f" {cat['title']}: {cat['score']}% [{status}]")
print(f" Implemented: {cat['compliant']}, Partial: {cat['partial']}, Gaps: {cat['gaps']}")
# Gaps
print("\n--- COMPLIANCE GAPS ---")
gap_count = 0
for cat in result["categories"]:
for control in cat["controls"]:
if control["status"] == "gap":
gap_count += 1
print(f" [{cat['category'].upper()}] {control['title']}")
print(f" Requirement: {control['requirement']}")
if gap_count == 0:
print(" No critical gaps identified")
# PHI Detection
if result["phi_detection"]["phi_detected"]:
print("\n--- PHI HANDLING DETECTED ---")
print(f" PHI Types: {', '.join(result['phi_detection']['phi_types'])}")
print(f" Files: {len(result['phi_detection']['files_with_phi'])}")
# Vulnerabilities
if result["vulnerabilities"]:
print("\n--- SECURITY VULNERABILITIES ---")
for vuln in result["vulnerabilities"][:10]:
print(f" - {vuln['vulnerability']}: {vuln['file']}")
# Recommendations
if result["recommendations"]:
print("\n--- RECOMMENDATIONS ---")
for i, rec in enumerate(result["recommendations"], 1):
print(f" {i}. {rec}")
print("\n" + "=" * 70)
print(f"Assessment Date: {datetime.now().strftime('%Y-%m-%d %H:%M')}")
print("=" * 70)
def main():
parser = argparse.ArgumentParser(
description="HIPAA Risk Assessment Tool for Medical Device Software"
)
parser.add_argument(
"project_dir",
nargs="?",
default=".",
help="Project directory to analyze (default: current directory)"
)
parser.add_argument(
"--category",
choices=["administrative", "physical", "technical"],
help="Assess specific safeguard category only"
)
parser.add_argument(
"--json",
action="store_true",
help="Output in JSON format"
)
parser.add_argument(
"--detailed",
action="store_true",
help="Include detailed evidence in output"
)
args = parser.parse_args()
project_dir = Path(args.project_dir).resolve()
if not project_dir.exists():
print(f"Error: Directory not found: {project_dir}", file=sys.stderr)
sys.exit(1)
# Filter categories if specific one requested
categories_to_assess = HIPAA_SAFEGUARDS
if args.category:
categories_to_assess = {args.category: HIPAA_SAFEGUARDS[args.category]}
# Perform assessment
category_results = []
total_weight = 0
weighted_score = 0
for cat_id, cat_data in categories_to_assess.items():
cat_result = assess_category(project_dir, cat_id, cat_data)
category_results.append(cat_result)
# Calculate weighted average
cat_weight = sum(c["weight"] for c in cat_data["controls"].values())
total_weight += cat_weight
weighted_score += (cat_result["score"] * cat_weight) / 100
overall_score = round((weighted_score / total_weight) * 100, 1) if total_weight > 0 else 0
# Additional scans
phi_detection = detect_phi_handling(project_dir)
vulnerabilities = detect_security_vulnerabilities(project_dir)
# Risk assessment
risk_assessment = calculate_risk_level(overall_score, vulnerabilities, phi_detection)
result = {
"project_dir": str(project_dir),
"assessment_date": datetime.now().isoformat(),
"overall_score": overall_score,
"risk_assessment": risk_assessment,
"categories": category_results if args.detailed else [
{
"category": c["category"],
"title": c["title"],
"score": c["score"],
"compliant": c["compliant"],
"partial": c["partial"],
"gaps": c["gaps"]
}
for c in category_results
],
"phi_detection": phi_detection,
"vulnerabilities": vulnerabilities,
"recommendations": []
}
result["recommendations"] = generate_recommendations(result)
if args.json:
print(json.dumps(result, indent=2))
else:
print_text_report(result)
if __name__ == "__main__":
main()
FILE:scripts/qsr_compliance_checker.py
#!/usr/bin/env python3
"""
QSR Compliance Checker
Assesses compliance with 21 CFR Part 820 (Quality System Regulation) by analyzing
project documentation and identifying gaps.
Usage:
python qsr_compliance_checker.py <project_dir>
python qsr_compliance_checker.py <project_dir> --section 820.30
python qsr_compliance_checker.py <project_dir> --json
"""
import argparse
import json
import os
import re
import sys
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Optional, Any
# QSR sections and requirements
QSR_REQUIREMENTS = {
"820.20": {
"title": "Management Responsibility",
"subsections": {
"820.20(a)": {
"title": "Quality Policy",
"required_evidence": ["quality_policy", "quality_manual", "quality_objectives"],
"doc_patterns": ["quality_policy*", "quality_manual*", "qms_manual*"],
"keywords": ["quality policy", "quality objectives", "management commitment"]
},
"820.20(b)": {
"title": "Organization",
"required_evidence": ["org_chart", "job_descriptions", "authority_matrix"],
"doc_patterns": ["org_chart*", "organization*", "job_desc*", "authority*"],
"keywords": ["organizational structure", "responsibility", "authority"]
},
"820.20(c)": {
"title": "Management Review",
"required_evidence": ["management_review_procedure", "management_review_records"],
"doc_patterns": ["management_review*", "mgmt_review*", "qmr*"],
"keywords": ["management review", "review meeting", "quality system effectiveness"]
}
}
},
"820.30": {
"title": "Design Controls",
"subsections": {
"820.30(a)": {
"title": "Design and Development Planning",
"required_evidence": ["design_plan", "development_plan"],
"doc_patterns": ["design_plan*", "dev_plan*", "development_plan*"],
"keywords": ["design planning", "development phases", "design milestones"]
},
"820.30(b)": {
"title": "Design Input",
"required_evidence": ["design_input", "requirements_specification"],
"doc_patterns": ["design_input*", "requirement*", "srs*", "prs*"],
"keywords": ["design input", "requirements", "user needs", "intended use"]
},
"820.30(c)": {
"title": "Design Output",
"required_evidence": ["design_output", "specifications", "drawings"],
"doc_patterns": ["design_output*", "specification*", "drawing*", "bom*"],
"keywords": ["design output", "specifications", "acceptance criteria"]
},
"820.30(d)": {
"title": "Design Review",
"required_evidence": ["design_review_procedure", "design_review_records"],
"doc_patterns": ["design_review*", "dr_record*", "dr_minutes*"],
"keywords": ["design review", "review meeting", "design evaluation"]
},
"820.30(e)": {
"title": "Design Verification",
"required_evidence": ["verification_plan", "verification_results"],
"doc_patterns": ["verification*", "test_report*", "dv_*"],
"keywords": ["verification", "testing", "design verification"]
},
"820.30(f)": {
"title": "Design Validation",
"required_evidence": ["validation_plan", "validation_results"],
"doc_patterns": ["validation*", "clinical*", "usability*", "val_*"],
"keywords": ["validation", "user needs", "intended use", "clinical evaluation"]
},
"820.30(g)": {
"title": "Design Transfer",
"required_evidence": ["transfer_checklist", "transfer_verification"],
"doc_patterns": ["transfer*", "production_release*"],
"keywords": ["design transfer", "manufacturing", "production"]
},
"820.30(h)": {
"title": "Design Changes",
"required_evidence": ["change_control_procedure", "change_records"],
"doc_patterns": ["change_control*", "ecn*", "eco*", "dcr*"],
"keywords": ["design change", "change control", "modification"]
},
"820.30(i)": {
"title": "Design History File",
"required_evidence": ["dhf_index", "dhf"],
"doc_patterns": ["dhf*", "design_history*"],
"keywords": ["design history file", "DHF", "design records"]
}
}
},
"820.40": {
"title": "Document Controls",
"subsections": {
"820.40(a)": {
"title": "Document Approval and Distribution",
"required_evidence": ["document_control_procedure"],
"doc_patterns": ["document_control*", "doc_control*", "sop_document*"],
"keywords": ["document approval", "document distribution", "controlled documents"]
},
"820.40(b)": {
"title": "Document Changes",
"required_evidence": ["document_change_procedure", "revision_history"],
"doc_patterns": ["revision_history*", "document_change*"],
"keywords": ["document change", "revision", "document modification"]
}
}
},
"820.50": {
"title": "Purchasing Controls",
"subsections": {
"820.50(a)": {
"title": "Evaluation of Suppliers",
"required_evidence": ["supplier_qualification_procedure", "approved_supplier_list"],
"doc_patterns": ["supplier*", "asl*", "vendor*"],
"keywords": ["supplier evaluation", "approved supplier", "vendor qualification"]
},
"820.50(b)": {
"title": "Purchasing Data",
"required_evidence": ["purchasing_procedure", "purchase_order_requirements"],
"doc_patterns": ["purchas*", "procurement*"],
"keywords": ["purchasing data", "specifications", "quality requirements"]
}
}
},
"820.70": {
"title": "Production and Process Controls",
"subsections": {
"820.70(a)": {
"title": "General Process Controls",
"required_evidence": ["manufacturing_procedures", "work_instructions"],
"doc_patterns": ["manufacturing*", "production*", "work_instruction*", "wi_*"],
"keywords": ["manufacturing process", "production", "process parameters"]
},
"820.70(b)": {
"title": "Production and Process Changes",
"required_evidence": ["process_change_procedure"],
"doc_patterns": ["process_change*", "manufacturing_change*"],
"keywords": ["process change", "production change", "change control"]
},
"820.70(c)": {
"title": "Environmental Control",
"required_evidence": ["environmental_control_procedure", "monitoring_records"],
"doc_patterns": ["environmental*", "cleanroom*", "env_monitoring*"],
"keywords": ["environmental control", "cleanroom", "contamination"]
},
"820.70(d)": {
"title": "Personnel",
"required_evidence": ["training_procedure", "training_records"],
"doc_patterns": ["training*", "personnel*", "competency*"],
"keywords": ["training", "personnel qualification", "competency"]
},
"820.70(e)": {
"title": "Contamination Control",
"required_evidence": ["contamination_control_procedure"],
"doc_patterns": ["contamination*", "cleaning*", "hygiene*"],
"keywords": ["contamination", "cleaning", "hygiene"]
},
"820.70(f)": {
"title": "Buildings",
"required_evidence": ["facility_requirements"],
"doc_patterns": ["facility*", "building*"],
"keywords": ["facility", "buildings", "manufacturing area"]
},
"820.70(g)": {
"title": "Equipment",
"required_evidence": ["equipment_maintenance_procedure", "maintenance_records"],
"doc_patterns": ["equipment*", "maintenance*", "preventive_maintenance*"],
"keywords": ["equipment", "maintenance", "calibration"]
},
"820.70(h)": {
"title": "Manufacturing Material",
"required_evidence": ["material_handling_procedure"],
"doc_patterns": ["material*", "handling*", "storage*"],
"keywords": ["manufacturing material", "handling", "storage"]
},
"820.70(i)": {
"title": "Automated Processes",
"required_evidence": ["software_validation", "automated_process_validation"],
"doc_patterns": ["software_val*", "csv*", "automation*"],
"keywords": ["software validation", "automated", "computer system"]
}
}
},
"820.72": {
"title": "Inspection, Measuring, and Test Equipment",
"subsections": {
"820.72(a)": {
"title": "Calibration",
"required_evidence": ["calibration_procedure", "calibration_records"],
"doc_patterns": ["calibration*", "cal_*"],
"keywords": ["calibration", "accuracy", "measurement"]
},
"820.72(b)": {
"title": "Calibration Standards",
"required_evidence": ["calibration_standards", "traceability_records"],
"doc_patterns": ["calibration_standard*", "nist*", "traceability*"],
"keywords": ["calibration standards", "NIST", "traceability"]
}
}
},
"820.75": {
"title": "Process Validation",
"subsections": {
"820.75(a)": {
"title": "Process Validation Requirements",
"required_evidence": ["process_validation_procedure", "validation_protocols"],
"doc_patterns": ["process_validation*", "pv_*", "validation_protocol*"],
"keywords": ["process validation", "IQ", "OQ", "PQ"]
},
"820.75(b)": {
"title": "Validation Monitoring",
"required_evidence": ["validation_monitoring", "revalidation_criteria"],
"doc_patterns": ["revalidation*", "validation_monitoring*"],
"keywords": ["monitoring", "revalidation", "process performance"]
}
}
},
"820.90": {
"title": "Nonconforming Product",
"subsections": {
"820.90(a)": {
"title": "Nonconforming Product Control",
"required_evidence": ["ncr_procedure", "nonconforming_records"],
"doc_patterns": ["ncr*", "nonconform*", "nc_*"],
"keywords": ["nonconforming", "NCR", "disposition"]
},
"820.90(b)": {
"title": "Nonconformance Review",
"required_evidence": ["ncr_review_procedure"],
"doc_patterns": ["ncr_review*", "mrb*"],
"keywords": ["review", "disposition", "concession"]
}
}
},
"820.100": {
"title": "Corrective and Preventive Action",
"subsections": {
"820.100(a)": {
"title": "CAPA Procedure",
"required_evidence": ["capa_procedure", "capa_records"],
"doc_patterns": ["capa*", "corrective*", "preventive*"],
"keywords": ["CAPA", "corrective action", "preventive action", "root cause"]
}
}
},
"820.120": {
"title": "Device Labeling",
"subsections": {
"820.120": {
"title": "Labeling Controls",
"required_evidence": ["labeling_procedure", "label_inspection"],
"doc_patterns": ["label*", "labeling*"],
"keywords": ["labeling", "label inspection", "UDI"]
}
}
},
"820.180": {
"title": "General Requirements - Records",
"subsections": {
"820.180": {
"title": "Records Requirements",
"required_evidence": ["records_management_procedure", "retention_schedule"],
"doc_patterns": ["record*", "retention*", "archive*"],
"keywords": ["records", "retention", "archive", "backup"]
}
}
},
"820.181": {
"title": "Device Master Record",
"subsections": {
"820.181": {
"title": "DMR Contents",
"required_evidence": ["dmr_index", "dmr"],
"doc_patterns": ["dmr*", "device_master*"],
"keywords": ["device master record", "DMR", "specifications"]
}
}
},
"820.184": {
"title": "Device History Record",
"subsections": {
"820.184": {
"title": "DHR Contents",
"required_evidence": ["dhr_template", "dhr_records"],
"doc_patterns": ["dhr*", "device_history*", "batch_record*"],
"keywords": ["device history record", "DHR", "production record"]
}
}
},
"820.198": {
"title": "Complaint Files",
"subsections": {
"820.198": {
"title": "Complaint Handling",
"required_evidence": ["complaint_procedure", "complaint_records"],
"doc_patterns": ["complaint*", "customer_feedback*"],
"keywords": ["complaint", "customer feedback", "MDR"]
}
}
}
}
def search_documentation(project_dir: Path, patterns: List[str], keywords: List[str]) -> Dict:
"""Search for documentation matching patterns and keywords."""
result = {
"documents_found": [],
"keyword_matches": [],
"evidence_strength": "none"
}
# Common documentation directories
doc_dirs = [
project_dir / "qms",
project_dir / "quality",
project_dir / "docs",
project_dir / "documentation",
project_dir / "procedures",
project_dir / "sops",
project_dir / "dhf",
project_dir / "dmr",
project_dir
]
# Search for document patterns
for doc_dir in doc_dirs:
if not doc_dir.exists():
continue
for pattern in patterns:
for ext in ["*.md", "*.pdf", "*.docx", "*.doc", "*.txt"]:
full_pattern = f"**/{pattern}{ext}" if not pattern.endswith("*") else f"**/{pattern[:-1]}{ext}"
try:
matches = list(doc_dir.glob(full_pattern))
for match in matches:
rel_path = str(match.relative_to(project_dir))
if rel_path not in result["documents_found"]:
result["documents_found"].append(rel_path)
except Exception:
continue
# Search for keywords in markdown and text files
for doc_dir in doc_dirs:
if not doc_dir.exists():
continue
for ext in ["*.md", "*.txt"]:
try:
for file_path in doc_dir.glob(f"**/{ext}"):
try:
content = file_path.read_text(encoding='utf-8', errors='ignore').lower()
for keyword in keywords:
if keyword.lower() in content:
rel_path = str(file_path.relative_to(project_dir))
if rel_path not in result["keyword_matches"]:
result["keyword_matches"].append(rel_path)
except Exception:
continue
except Exception:
continue
# Determine evidence strength
if result["documents_found"] and result["keyword_matches"]:
result["evidence_strength"] = "strong"
elif result["documents_found"] or result["keyword_matches"]:
result["evidence_strength"] = "partial"
else:
result["evidence_strength"] = "none"
return result
def assess_section(project_dir: Path, section_id: str, section_data: Dict) -> Dict:
"""Assess compliance for a QSR section."""
result = {
"section": section_id,
"title": section_data["title"],
"subsections": [],
"compliance_score": 0,
"total_subsections": len(section_data["subsections"]),
"compliant_subsections": 0
}
for subsection_id, subsection_data in section_data["subsections"].items():
evidence = search_documentation(
project_dir,
subsection_data["doc_patterns"],
subsection_data["keywords"]
)
subsection_result = {
"subsection": subsection_id,
"title": subsection_data["title"],
"required_evidence": subsection_data["required_evidence"],
"evidence_found": evidence,
"status": "gap" if evidence["evidence_strength"] == "none" else (
"partial" if evidence["evidence_strength"] == "partial" else "compliant"
)
}
if subsection_result["status"] == "compliant":
result["compliant_subsections"] += 1
elif subsection_result["status"] == "partial":
result["compliant_subsections"] += 0.5
result["subsections"].append(subsection_result)
if result["total_subsections"] > 0:
result["compliance_score"] = round(
(result["compliant_subsections"] / result["total_subsections"]) * 100, 1
)
return result
def generate_gap_report(assessment_results: List[Dict]) -> Dict:
"""Generate gap analysis report."""
gaps = []
recommendations = []
for section in assessment_results:
for subsection in section["subsections"]:
if subsection["status"] != "compliant":
gap = {
"section": subsection["subsection"],
"title": subsection["title"],
"status": subsection["status"],
"missing_evidence": subsection["required_evidence"]
}
gaps.append(gap)
if subsection["status"] == "gap":
recommendations.append(
f"{subsection['subsection']}: Create documentation for {subsection['title']}"
)
else:
recommendations.append(
f"{subsection['subsection']}: Enhance documentation for {subsection['title']}"
)
return {
"total_gaps": len([g for g in gaps if g["status"] == "gap"]),
"total_partial": len([g for g in gaps if g["status"] == "partial"]),
"gaps": gaps,
"priority_recommendations": recommendations[:10] # Top 10
}
def calculate_overall_compliance(assessment_results: List[Dict]) -> Dict:
"""Calculate overall QSR compliance score."""
total_subsections = 0
compliant_subsections = 0
section_scores = {}
for section in assessment_results:
total_subsections += section["total_subsections"]
compliant_subsections += section["compliant_subsections"]
section_scores[section["section"]] = section["compliance_score"]
overall_score = round((compliant_subsections / total_subsections) * 100, 1) if total_subsections > 0 else 0
# Determine compliance level
if overall_score >= 90:
level = "HIGH"
color = "green"
elif overall_score >= 70:
level = "MEDIUM"
color = "yellow"
elif overall_score >= 50:
level = "LOW"
color = "orange"
else:
level = "CRITICAL"
color = "red"
return {
"overall_score": overall_score,
"compliance_level": level,
"total_subsections": total_subsections,
"compliant_subsections": compliant_subsections,
"section_scores": section_scores
}
def print_text_report(result: Dict) -> None:
"""Print human-readable compliance report."""
print("=" * 70)
print("21 CFR PART 820 (QSR) COMPLIANCE ASSESSMENT")
print("=" * 70)
# Overall compliance
overall = result["overall_compliance"]
print(f"\nOVERALL COMPLIANCE: {overall['overall_score']}% ({overall['compliance_level']})")
print(f"Subsections Assessed: {overall['total_subsections']}")
print(f"Compliant/Partial: {overall['compliant_subsections']}")
# Section summary
print("\n--- SECTION SCORES ---")
for section in result["assessment"]:
status = "OK" if section["compliance_score"] >= 70 else "GAP"
print(f" {section['section']} {section['title']}: {section['compliance_score']}% [{status}]")
# Gap analysis
gap_report = result["gap_report"]
print(f"\n--- GAP ANALYSIS ---")
print(f"Critical Gaps: {gap_report['total_gaps']}")
print(f"Partial Compliance: {gap_report['total_partial']}")
if gap_report["gaps"]:
print("\n Gaps Identified:")
for gap in gap_report["gaps"][:15]: # Show top 15
status = "GAP" if gap["status"] == "gap" else "PARTIAL"
print(f" [{status}] {gap['section']}: {gap['title']}")
# Recommendations
if gap_report["priority_recommendations"]:
print("\n--- PRIORITY RECOMMENDATIONS ---")
for i, rec in enumerate(gap_report["priority_recommendations"], 1):
print(f" {i}. {rec}")
print("\n" + "=" * 70)
print(f"Assessment Date: {datetime.now().strftime('%Y-%m-%d %H:%M')}")
print("=" * 70)
def main():
parser = argparse.ArgumentParser(
description="QSR Compliance Checker - Assess 21 CFR 820 compliance"
)
parser.add_argument(
"project_dir",
nargs="?",
default=".",
help="Project directory to analyze (default: current directory)"
)
parser.add_argument(
"--section",
help="Analyze specific QSR section only (e.g., 820.30)"
)
parser.add_argument(
"--json",
action="store_true",
help="Output in JSON format"
)
parser.add_argument(
"--detailed",
action="store_true",
help="Include detailed evidence in output"
)
args = parser.parse_args()
project_dir = Path(args.project_dir).resolve()
if not project_dir.exists():
print(f"Error: Directory not found: {project_dir}", file=sys.stderr)
sys.exit(1)
# Filter sections if specific one requested
sections_to_assess = QSR_REQUIREMENTS
if args.section:
if args.section in QSR_REQUIREMENTS:
sections_to_assess = {args.section: QSR_REQUIREMENTS[args.section]}
else:
print(f"Error: Unknown section: {args.section}", file=sys.stderr)
print(f"Available sections: {', '.join(QSR_REQUIREMENTS.keys())}")
sys.exit(1)
# Perform assessment
assessment_results = []
for section_id, section_data in sections_to_assess.items():
section_result = assess_section(project_dir, section_id, section_data)
assessment_results.append(section_result)
# Generate reports
overall_compliance = calculate_overall_compliance(assessment_results)
gap_report = generate_gap_report(assessment_results)
result = {
"project_dir": str(project_dir),
"assessment_date": datetime.now().isoformat(),
"overall_compliance": overall_compliance,
"assessment": assessment_results if args.detailed else [
{
"section": s["section"],
"title": s["title"],
"compliance_score": s["compliance_score"],
"status": "compliant" if s["compliance_score"] >= 70 else "gap"
}
for s in assessment_results
],
"gap_report": gap_report
}
if args.json:
print(json.dumps(result, indent=2))
else:
print_text_report(result)
if __name__ == "__main__":
main()
Theo dõi sức khỏe khách hàng, dự đoán rủi ro rời bỏ và tìm cơ hội mở rộng bằng mô hình chấm điểm có trọng số cho SaaS.
---
name: "customer-success-manager"
description: Monitors customer health, predicts churn risk, and identifies expansion opportunities using weighted scoring models for SaaS customer success. Use when analyzing customer accounts, reviewing retention metrics, scoring at-risk customers, or when the user mentions churn, customer health scores, upsell opportunities, expansion revenue, retention analysis, or customer analytics. Runs three Python CLI tools to produce deterministic health scores, churn risk tiers, and prioritized expansion recommendations across Enterprise, Mid-Market, and SMB segments.
license: MIT
metadata:
version: 1.0.0
author: Alireza Rezvani
category: business-growth
domain: customer-success
updated: 2026-02-06
python-tools: health_score_calculator.py, churn_risk_analyzer.py, expansion_opportunity_scorer.py
tech-stack: customer-success, saas-metrics, health-scoring
---
# Customer Success Manager
Production-grade customer success analytics with multi-dimensional health scoring, churn risk prediction, and expansion opportunity identification. Three Python CLI tools provide deterministic, repeatable analysis using standard library only -- no external dependencies, no API calls, no ML models.
---
## Table of Contents
- [Input Requirements](#input-requirements)
- [Output Formats](#output-formats)
- [How to Use](#how-to-use)
- [Scripts](#scripts)
- [Reference Guides](#reference-guides)
- [Templates](#templates)
- [Best Practices](#best-practices)
- [Limitations](#limitations)
---
## Input Requirements
All scripts accept a JSON file as positional input argument. See `assets/sample_customer_data.json` for complete schema examples and sample data.
### Health Score Calculator
Required fields per customer object: `customer_id`, `name`, `segment`, `arr`, and nested objects `usage` (login_frequency, feature_adoption, dau_mau_ratio), `engagement` (support_ticket_volume, meeting_attendance, nps_score, csat_score), `support` (open_tickets, escalation_rate, avg_resolution_hours), `relationship` (executive_sponsor_engagement, multi_threading_depth, renewal_sentiment), and `previous_period` scores for trend analysis.
### Churn Risk Analyzer
Required fields per customer object: `customer_id`, `name`, `segment`, `arr`, `contract_end_date`, and nested objects `usage_decline`, `engagement_drop`, `support_issues`, `relationship_signals`, and `commercial_factors`.
### Expansion Opportunity Scorer
Required fields per customer object: `customer_id`, `name`, `segment`, `arr`, and nested objects `contract` (licensed_seats, active_seats, plan_tier, available_tiers), `product_usage` (per-module adoption flags and usage percentages), and `departments` (current and potential).
---
## Output Formats
All scripts support two output formats via the `--format` flag:
- **`text`** (default): Human-readable formatted output for terminal viewing
- **`json`**: Machine-readable JSON output for integrations and pipelines
---
## How to Use
### Quick Start
```bash
# Health scoring
python scripts/health_score_calculator.py assets/sample_customer_data.json
python scripts/health_score_calculator.py assets/sample_customer_data.json --format json
# Churn risk analysis
python scripts/churn_risk_analyzer.py assets/sample_customer_data.json
python scripts/churn_risk_analyzer.py assets/sample_customer_data.json --format json
# Expansion opportunity scoring
python scripts/expansion_opportunity_scorer.py assets/sample_customer_data.json
python scripts/expansion_opportunity_scorer.py assets/sample_customer_data.json --format json
```
### Workflow Integration
```bash
# 1. Score customer health across portfolio
python scripts/health_score_calculator.py customer_portfolio.json --format json > health_results.json
# Verify: confirm health_results.json contains the expected number of customer records before continuing
# 2. Identify at-risk accounts
python scripts/churn_risk_analyzer.py customer_portfolio.json --format json > risk_results.json
# Verify: confirm risk_results.json is non-empty and risk tiers are present for each customer
# 3. Find expansion opportunities in healthy accounts
python scripts/expansion_opportunity_scorer.py customer_portfolio.json --format json > expansion_results.json
# Verify: confirm expansion_results.json lists opportunities ranked by priority
# 4. Prepare QBR using templates
# Reference: assets/qbr_template.md
```
**Error handling:** If a script exits with an error, check that:
- The input JSON matches the required schema for that script (see Input Requirements above)
- All required fields are present and correctly typed
- Python 3.7+ is being used (`python --version`)
- Output files from prior steps are non-empty before piping into subsequent steps
---
## Scripts
### 1. health_score_calculator.py
**Purpose:** Multi-dimensional customer health scoring with trend analysis and segment-aware benchmarking.
**Dimensions and Weights:**
| Dimension | Weight | Metrics |
|-----------|--------|---------|
| Usage | 30% | Login frequency, feature adoption, DAU/MAU ratio |
| Engagement | 25% | Support ticket volume, meeting attendance, NPS/CSAT |
| Support | 20% | Open tickets, escalation rate, avg resolution time |
| Relationship | 25% | Executive sponsor engagement, multi-threading depth, renewal sentiment |
**Classification:**
- Green (75-100): Healthy -- customer achieving value
- Yellow (50-74): Needs attention -- monitor closely
- Red (0-49): At risk -- immediate intervention required
**Usage:**
```bash
python scripts/health_score_calculator.py customer_data.json
python scripts/health_score_calculator.py customer_data.json --format json
```
### 2. churn_risk_analyzer.py
**Purpose:** Identify at-risk accounts with behavioral signal detection and tier-based intervention recommendations.
**Risk Signal Weights:**
| Signal Category | Weight | Indicators |
|----------------|--------|------------|
| Usage Decline | 30% | Login trend, feature adoption change, DAU/MAU change |
| Engagement Drop | 25% | Meeting cancellations, response time, NPS change |
| Support Issues | 20% | Open escalations, unresolved critical, satisfaction trend |
| Relationship Signals | 15% | Champion left, sponsor change, competitor mentions |
| Commercial Factors | 10% | Contract type, pricing complaints, budget cuts |
**Risk Tiers:**
- Critical (80-100): Immediate executive escalation
- High (60-79): Urgent CSM intervention
- Medium (40-59): Proactive outreach
- Low (0-39): Standard monitoring
**Usage:**
```bash
python scripts/churn_risk_analyzer.py customer_data.json
python scripts/churn_risk_analyzer.py customer_data.json --format json
```
### 3. expansion_opportunity_scorer.py
**Purpose:** Identify upsell, cross-sell, and expansion opportunities with revenue estimation and priority ranking.
**Expansion Types:**
- **Upsell**: Upgrade to higher tier or more of existing product
- **Cross-sell**: Add new product modules
- **Expansion**: Additional seats or departments
**Usage:**
```bash
python scripts/expansion_opportunity_scorer.py customer_data.json
python scripts/expansion_opportunity_scorer.py customer_data.json --format json
```
---
## Reference Guides
| Reference | Description |
|-----------|-------------|
| `references/health-scoring-framework.md` | Complete health scoring methodology, dimension definitions, weighting rationale, threshold calibration |
| `references/cs-playbooks.md` | Intervention playbooks for each risk tier, onboarding, renewal, expansion, and escalation procedures |
| `references/cs-metrics-benchmarks.md` | Industry benchmarks for NRR, GRR, churn rates, health scores, expansion rates by segment and industry |
---
## Templates
| Template | Purpose |
|----------|---------|
| `assets/qbr_template.md` | Quarterly Business Review presentation structure |
| `assets/success_plan_template.md` | Customer success plan with goals, milestones, and metrics |
| `assets/onboarding_checklist_template.md` | 90-day onboarding checklist with phase gates |
| `assets/executive_business_review_template.md` | Executive stakeholder review for strategic accounts |
---
## Best Practices
1. **Combine signals**: Use all three scripts together for a complete customer picture
2. **Act on trends, not snapshots**: A declining Green is more urgent than a stable Yellow
3. **Calibrate thresholds**: Adjust segment benchmarks based on your product and industry per `references/health-scoring-framework.md`
4. **Prepare with data**: Run scripts before every QBR and executive meeting; reference `references/cs-playbooks.md` for intervention guidance
---
## Limitations
- **No real-time data**: Scripts analyze point-in-time snapshots from JSON input files
- **No CRM integration**: Data must be exported manually from your CRM/CS platform
- **Deterministic only**: No predictive ML -- scoring is algorithmic based on weighted signals
- **Threshold tuning**: Default thresholds are industry-standard but may need calibration for your business
- **Revenue estimates**: Expansion revenue estimates are approximations based on usage patterns
---
**Last Updated:** February 2026
**Tools:** 3 Python CLI tools
**Dependencies:** Python 3.7+ standard library only
FILE:assets/executive_business_review_template.md
# Executive Business Review
**Customer:** [Customer Name]
**Date:** [Review Date]
**Prepared for:** [Executive Name, Title]
**Prepared by:** [CSM Name] | [VP Customer Success Name]
**Classification:** [Strategic / Enterprise / Key Account]
---
## 1. Partnership Summary
| Metric | Value |
|--------|-------|
| Partnership Duration | [X months/years] |
| Current ARR | $[Amount] |
| Lifetime Value to Date | $[Amount] |
| Current Plan | [Tier] |
| Licensed Seats | [Number] |
| Active Seats | [Number] |
| Health Score | [Score]/100 ([Green/Yellow/Red]) |
| NPS Score | [Score] |
| Renewal Date | [Date] ([X] days remaining) |
---
## 2. Strategic Alignment
### Customer's Business Priorities (This Year)
1. **[Priority 1]** -- [How our solution supports this]
2. **[Priority 2]** -- [How our solution supports this]
3. **[Priority 3]** -- [How our solution supports this]
### Alignment Assessment
| Business Priority | Our Contribution | Alignment Score |
|-------------------|-----------------|----------------|
| [Priority 1] | [Specific contribution] | [Strong / Moderate / Weak] |
| [Priority 2] | [Specific contribution] | [Strong / Moderate / Weak] |
| [Priority 3] | [Specific contribution] | [Strong / Moderate / Weak] |
---
## 3. Value Delivered
### Quantified Business Impact
| Outcome | Metric | Before | After | Business Value |
|---------|--------|--------|-------|---------------|
| [e.g., Operational efficiency] | [Hours saved/week] | [Baseline] | [Current] | $[Estimated value] |
| [e.g., Revenue acceleration] | [Deal velocity] | [Baseline] | [Current] | $[Estimated value] |
| [e.g., Risk reduction] | [Error rate] | [Baseline] | [Current] | $[Estimated value] |
**Total Estimated Business Value:** $[Amount]
**ROI:** [X]x return on investment
### Key Achievements This Period
1. [Achievement 1 with measurable outcome]
2. [Achievement 2 with measurable outcome]
3. [Achievement 3 with measurable outcome]
---
## 4. Adoption and Engagement Scorecard
### Platform Utilisation
| Module | Adoption Status | Usage Depth | Benchmark | Assessment |
|--------|---------------|-------------|-----------|------------|
| [Module 1] | Fully Adopted | [High/Med/Low] | [Benchmark] | [Above/At/Below] |
| [Module 2] | Partially Adopted | [High/Med/Low] | [Benchmark] | [Above/At/Below] |
| [Module 3] | Not Adopted | -- | -- | Opportunity |
### Engagement Health
| Indicator | Current | Previous Period | Trend |
|-----------|---------|----------------|-------|
| Executive Engagement | [Score] | [Score] | [Up/Down/Stable] |
| Stakeholder Breadth | [# contacts] | [# contacts] | [Up/Down/Stable] |
| Meeting Participation | [%] | [%] | [Up/Down/Stable] |
| Feature Request Activity | [Count] | [Count] | [Up/Down/Stable] |
---
## 5. Account Health Overview
### Health Score Trend (Last 4 Quarters)
| Quarter | Overall | Usage | Engagement | Support | Relationship |
|---------|---------|-------|------------|---------|-------------|
| [Q-3] | [Score] | [Score] | [Score] | [Score] | [Score] |
| [Q-2] | [Score] | [Score] | [Score] | [Score] | [Score] |
| [Q-1] | [Score] | [Score] | [Score] | [Score] | [Score] |
| Current | [Score] | [Score] | [Score] | [Score] | [Score] |
### Risk Assessment
| Risk Factor | Level | Details | Mitigation |
|------------|-------|---------|-----------|
| [Risk 1] | [High/Med/Low] | [Description] | [Action] |
| [Risk 2] | [High/Med/Low] | [Description] | [Action] |
---
## 6. Support and Service Quality
| Metric | This Period | SLA Target | Status |
|--------|------------|-----------|--------|
| Total Tickets | [Number] | -- | |
| Avg First Response | [Hours] | [Hours] | [Met / Not Met] |
| Avg Resolution Time | [Hours] | [Hours] | [Met / Not Met] |
| Escalations | [Number] | 0 | |
| CSAT Score | [Score] | [Target] | [Above / Below] |
| Critical Issues | [Number] | 0 | |
### Notable Support Interactions
- [Summary of any significant support events and resolution]
---
## 7. Product Roadmap Alignment
### Features Delivered (Relevant to This Customer)
| Feature | Release Date | Customer Impact |
|---------|-------------|----------------|
| [Feature 1] | [Date] | [How it helps them] |
| [Feature 2] | [Date] | [How it helps them] |
### Upcoming Features (Customer-Relevant)
| Feature | Expected Release | Expected Impact |
|---------|-----------------|----------------|
| [Feature 1] | [Quarter] | [Business value] |
| [Feature 2] | [Quarter] | [Business value] |
### Customer Feature Requests
| Request | Priority | Status | Business Case |
|---------|----------|--------|--------------|
| [Request 1] | [P1/P2/P3] | [Status] | [Why it matters] |
| [Request 2] | [P1/P2/P3] | [Status] | [Why it matters] |
---
## 8. Growth and Expansion Opportunity
### Current Whitespace Analysis
| Opportunity | Type | Est. Revenue | Effort | Priority |
|------------|------|-------------|--------|----------|
| [Opportunity 1] | [Upsell/Cross-sell/Expansion] | $[Amount] | [Low/Med/High] | [1-5] |
| [Opportunity 2] | [Upsell/Cross-sell/Expansion] | $[Amount] | [Low/Med/High] | [1-5] |
| [Opportunity 3] | [Upsell/Cross-sell/Expansion] | $[Amount] | [Low/Med/High] | [1-5] |
**Total Expansion Opportunity:** $[Amount]
### Recommended Next Steps for Growth
1. [Specific expansion recommendation with business justification]
2. [Specific expansion recommendation with business justification]
---
## 9. Renewal Outlook
| Factor | Assessment |
|--------|-----------|
| Overall Renewal Confidence | [High / Medium / Low] |
| Budget Availability | [Confirmed / Expected / Uncertain] |
| Sponsor Support | [Strong / Moderate / Weak] |
| Competitive Threat | [None / Low / Medium / High] |
| Value Perception | [Strong / Moderate / Weak] |
| Contract Satisfaction | [Satisfied / Neutral / Concerned] |
### Renewal Strategy
[2-3 sentences on the approach for securing renewal, including any specific actions needed]
---
## 10. Executive-Level Action Items
| Action | Owner | Due Date | Priority | Impact |
|--------|-------|----------|----------|--------|
| [Action 1] | [Name, Title] | [Date] | [Critical/High/Med] | [Expected outcome] |
| [Action 2] | [Name, Title] | [Date] | [Critical/High/Med] | [Expected outcome] |
| [Action 3] | [Name, Title] | [Date] | [Critical/High/Med] | [Expected outcome] |
---
## Appendix
### Stakeholder Map
| Name | Title | Influence | Sentiment | Last Contact |
|------|-------|-----------|-----------|-------------|
| [Name] | [Title] | [Decision Maker / Influencer / User] | [Positive / Neutral / Negative] | [Date] |
| [Name] | [Title] | [Decision Maker / Influencer / User] | [Positive / Neutral / Negative] | [Date] |
### Competitive Landscape (If Applicable)
- **Known competitors in evaluation:** [List]
- **Our differentiators:** [Key strengths vs. competition]
- **Risk mitigation:** [Actions to defend position]
---
**Confidential -- For Internal and Customer Executive Use Only**
**Next Executive Review:** [Date]
FILE:assets/expected_output.json
{
"report": "customer_health_scores",
"summary": {
"total_customers": 4,
"average_score": 78.8,
"green_count": 3,
"yellow_count": 1,
"red_count": 0
},
"customers": [
{
"customer_id": "CUST-001",
"name": "Acme Corp",
"segment": "enterprise",
"arr": 120000,
"overall_score": 86.2,
"classification": "green",
"dimensions": {
"usage": {
"score": 91.6,
"weight": "30%",
"classification": "green"
},
"engagement": {
"score": 82.0,
"weight": "25%",
"classification": "green"
},
"support": {
"score": 78.5,
"weight": "20%",
"classification": "green"
},
"relationship": {
"score": 90.1,
"weight": "25%",
"classification": "green"
}
},
"trends": {
"usage": "improving",
"engagement": "improving",
"support": "stable",
"relationship": "improving",
"overall": "improving"
},
"recommendations": []
},
{
"customer_id": "CUST-002",
"name": "TechStart Inc",
"segment": "smb",
"arr": 18000,
"overall_score": 53.7,
"classification": "yellow",
"dimensions": {
"usage": {
"score": 52.5,
"weight": "30%",
"classification": "yellow"
},
"engagement": {
"score": 61.6,
"weight": "25%",
"classification": "yellow"
},
"support": {
"score": 63.2,
"weight": "20%",
"classification": "yellow"
},
"relationship": {
"score": 39.5,
"weight": "25%",
"classification": "red"
}
},
"trends": {
"usage": "stable",
"engagement": "improving",
"support": "stable",
"relationship": "declining",
"overall": "stable"
},
"recommendations": [
"Login frequency below target -- schedule product engagement session",
"NPS below threshold -- conduct a feedback deep-dive with customer",
"CSAT is critically low -- escalate to support leadership",
"Single-threaded relationship -- expand contacts across departments",
"Renewal sentiment is negative -- initiate save plan immediately"
]
},
{
"customer_id": "CUST-003",
"name": "GlobalTrade Solutions",
"segment": "mid-market",
"arr": 55000,
"overall_score": 79.7,
"classification": "green",
"dimensions": {
"usage": {
"score": 85.6,
"weight": "30%",
"classification": "green"
},
"engagement": {
"score": 79.6,
"weight": "25%",
"classification": "green"
},
"support": {
"score": 72.0,
"weight": "20%",
"classification": "green"
},
"relationship": {
"score": 79.0,
"weight": "25%",
"classification": "green"
}
},
"trends": {
"usage": "improving",
"engagement": "improving",
"support": "improving",
"relationship": "improving",
"overall": "improving"
},
"recommendations": []
},
{
"customer_id": "CUST-004",
"name": "HealthFirst Medical",
"segment": "enterprise",
"arr": 200000,
"overall_score": 95.7,
"classification": "green",
"dimensions": {
"usage": {
"score": 100.0,
"weight": "30%",
"classification": "green"
},
"engagement": {
"score": 92.0,
"weight": "25%",
"classification": "green"
},
"support": {
"score": 88.7,
"weight": "20%",
"classification": "green"
},
"relationship": {
"score": 100.0,
"weight": "25%",
"classification": "green"
}
},
"trends": {
"usage": "improving",
"engagement": "improving",
"support": "stable",
"relationship": "improving",
"overall": "improving"
},
"recommendations": []
}
]
}
FILE:assets/onboarding_checklist_template.md
# Customer Onboarding Checklist (90-Day)
**Customer:** [Customer Name]
**Segment:** [Enterprise / Mid-Market / SMB]
**CSM:** [CSM Name]
**Kickoff Date:** [Date]
**Target Go-Live:** [Date]
**Target First Value Date:** [Date -- must be within 30 days]
---
## Phase 1: Welcome and Setup (Days 1-14)
### Pre-Kickoff Preparation (Day 0)
- [ ] Review signed contract and SOW for scope and commitments
- [ ] Research customer's industry, business model, and competitive landscape
- [ ] Review handoff notes from sales team (pain points, decision drivers, stakeholders)
- [ ] Prepare welcome package (login credentials, documentation links, support contacts)
- [ ] Create customer workspace in CS platform
- [ ] Schedule kickoff meeting with all required attendees
- [ ] Prepare kickoff deck with agenda and success plan draft
### Kickoff Meeting (Day 1-2)
- [ ] Conduct kickoff meeting with customer stakeholders
- [ ] Confirm business objectives and success criteria
- [ ] Identify key stakeholders and their roles (sponsor, champion, technical lead, users)
- [ ] Align on communication cadence and preferred channels
- [ ] Review onboarding timeline and milestones
- [ ] Set expectations for time commitment from customer team
- [ ] Share and agree on success plan (mutual accountability)
- [ ] Schedule recurring check-in meetings
**Kickoff Meeting Notes:**
> [Document key takeaways, concerns raised, decisions made]
### Technical Setup (Days 3-7)
- [ ] Provision customer environment (tenant, workspace, permissions)
- [ ] Configure SSO/authentication if applicable
- [ ] Set up integrations with customer's existing tools
- [ ] Import or migrate existing data (if applicable)
- [ ] Validate data integrity post-migration
- [ ] Configure role-based access and permissions
- [ ] Set up monitoring and alerting
**Technical Setup Owner:** [SE / Implementation team name]
**Technical Setup Notes:**
> [Document configuration decisions, customizations, issues]
### Admin Training (Days 7-10)
- [ ] Deliver admin training session (system configuration, user management)
- [ ] Provide admin documentation and quick reference guide
- [ ] Ensure admins can independently manage basic operations
- [ ] Set up admin support escalation path
### Initial User Training (Days 10-14)
- [ ] Deliver core user training (session 1: basic navigation and key workflows)
- [ ] Provide user quickstart guide and video resources
- [ ] Set up user support channel (Slack, email, in-app chat)
- [ ] Confirm all target users have active accounts
- [ ] Track initial login completion rate
**Training Completion Rate:** [___%] of target users
---
## Phase 2: Activation (Days 15-30)
### User Activation (Days 15-20)
- [ ] Monitor daily active user metrics
- [ ] Follow up with users who have not logged in
- [ ] Conduct follow-up training for users needing additional help
- [ ] Address any usability issues or confusion reported
- [ ] Validate that core workflows are functioning as expected
- [ ] Collect early feedback from champion and key users
**Activation Rate:** [___%] of licensed users active
### First Value Milestone (Days 20-30)
- [ ] Define and track first value milestone (specific to customer objectives)
- [ ] Verify customer has completed their first meaningful workflow
- [ ] Document value delivered (even if small -- establish the pattern)
- [ ] Share "first win" with executive sponsor
- [ ] Celebrate the milestone with the customer team
**First Value Milestone:** [Describe the specific milestone]
**Date Achieved:** [Date]
### 30-Day Review (Day 28-30)
- [ ] Conduct 30-day review meeting with customer
- [ ] Review activation metrics (logins, usage, adoption)
- [ ] Assess progress against success plan milestones
- [ ] Identify any blockers or concerns
- [ ] Adjust onboarding plan if needed
- [ ] Confirm transition from setup phase to adoption phase
- [ ] Set goals for days 31-60
**30-Day Health Score:** [Score]/100 -- [Green/Yellow/Red]
---
## Phase 3: Adoption (Days 31-60)
### Feature Expansion (Days 31-45)
- [ ] Introduce additional features beyond core workflows
- [ ] Deliver advanced training session (session 2: power features)
- [ ] Enable at least one integration with customer's existing tools
- [ ] Identify and address feature adoption gaps
- [ ] Share best practices from similar customers
### Usage Benchmarking (Days 45-55)
- [ ] Compare customer's usage against segment benchmarks
- [ ] Identify underperforming areas and create enablement plan
- [ ] Share usage report with customer champion
- [ ] Discuss usage targets for the next 30 days
**Current vs. Benchmark:**
| Metric | Current | Benchmark | Gap |
|--------|---------|-----------|-----|
| Feature Adoption | [%] | [%] | [+/-] |
| Daily Active Users | [#] | [#] | [+/-] |
| Key Workflow Completion | [%] | [%] | [+/-] |
### 60-Day Check-in (Day 55-60)
- [ ] Conduct 60-day check-in meeting
- [ ] Review adoption metrics and progress
- [ ] Discuss any roadblocks to deeper adoption
- [ ] Begin identifying advanced use cases
- [ ] Set goals for days 61-90
---
## Phase 4: Optimisation (Days 61-90)
### Advanced Use Cases (Days 61-75)
- [ ] Conduct use case discovery workshop with customer
- [ ] Identify 2-3 advanced use cases beyond initial scope
- [ ] Build implementation plan for advanced use cases
- [ ] Begin pilot of advanced use cases with power users
### ROI Measurement (Days 75-85)
- [ ] Collect data for ROI measurement against baseline
- [ ] Build ROI summary document
- [ ] Share ROI results with executive sponsor
- [ ] Document customer testimonial or case study opportunity (if willing)
**ROI Summary:**
| Metric | Baseline | Current | Improvement |
|--------|----------|---------|-------------|
| [Metric 1] | [Value] | [Value] | [% change] |
| [Metric 2] | [Value] | [Value] | [% change] |
### 90-Day Executive Review (Days 85-90)
- [ ] Prepare 90-day executive review presentation
- [ ] Include: value delivered, adoption metrics, ROI, next steps
- [ ] Conduct review meeting with executive sponsor
- [ ] Transition from onboarding to ongoing success management
- [ ] Establish ongoing success plan with quarterly milestones
- [ ] Confirm ongoing meeting cadence
- [ ] Introduce expansion opportunities if appropriate
**90-Day Health Score:** [Score]/100 -- [Green/Yellow/Red]
---
## Onboarding Completion Gate
The following criteria must be met to consider onboarding complete:
- [ ] User activation rate above 80%
- [ ] First value milestone achieved within 30 days
- [ ] Core workflows actively used by target users
- [ ] Executive sponsor confirms satisfaction
- [ ] Health score is Yellow (50+) or better
- [ ] Success plan established with ongoing milestones
- [ ] Recurring meeting cadence confirmed
- [ ] Support escalation path understood by customer
**Onboarding Status:** [Complete / In Progress / Blocked]
**Completion Date:** [Date]
**Handoff to Steady-State CSM:** [Date if different CSM]
---
## Notes
### Risks and Blockers
| Risk/Blocker | Impact | Mitigation | Status |
|-------------|--------|-----------|--------|
| [Item] | [High/Med/Low] | [Action] | [Open/Resolved] |
### Key Decisions
| Date | Decision | Made By | Impact |
|------|----------|---------|--------|
| [Date] | [Decision] | [Name] | [Description] |
---
**Template Version:** 1.0
**Last Updated:** February 2026
FILE:assets/qbr_template.md
# Quarterly Business Review (QBR)
**Customer:** [Customer Name]
**Date:** [QBR Date]
**Prepared by:** [CSM Name]
**Attendees:** [List attendees and titles]
---
## 1. Executive Summary
**Overall Relationship Status:** [Green / Yellow / Red]
**Health Score:** [Score]/100
**Key Theme:** [One sentence summarizing the quarter]
### Quarter Highlights
- [Highlight 1: major achievement or milestone]
- [Highlight 2: value delivered]
- [Highlight 3: initiative completed]
### Areas of Focus
- [Focus area 1]
- [Focus area 2]
---
## 2. Value Delivered This Quarter
### Business Outcomes Achieved
| Objective | Target | Actual | Status |
|-----------|--------|--------|--------|
| [Objective 1] | [Target metric] | [Actual metric] | [On Track / At Risk / Achieved] |
| [Objective 2] | [Target metric] | [Actual metric] | [On Track / At Risk / Achieved] |
| [Objective 3] | [Target metric] | [Actual metric] | [On Track / At Risk / Achieved] |
### ROI Summary
| Metric | Before | After | Improvement |
|--------|--------|-------|-------------|
| [Metric 1, e.g., Time savings] | [Baseline] | [Current] | [% change] |
| [Metric 2, e.g., Cost reduction] | [Baseline] | [Current] | [% change] |
| [Metric 3, e.g., Revenue impact] | [Baseline] | [Current] | [% change] |
**Estimated Total Value Delivered:** $[Amount]
---
## 3. Product Usage and Adoption
### Usage Metrics
| Metric | Last Quarter | This Quarter | Trend |
|--------|-------------|--------------|-------|
| Monthly Active Users | [Number] | [Number] | [Up/Down/Stable] |
| Feature Adoption Rate | [%] | [%] | [Up/Down/Stable] |
| DAU/MAU Ratio | [Ratio] | [Ratio] | [Up/Down/Stable] |
| Seat Utilization | [%] | [%] | [Up/Down/Stable] |
### Feature Adoption Breakdown
| Feature/Module | Status | Usage Level | Notes |
|---------------|--------|-------------|-------|
| [Feature 1] | Active | [High/Med/Low] | |
| [Feature 2] | Active | [High/Med/Low] | |
| [Feature 3] | Not Adopted | -- | [Reason / Opportunity] |
### Adoption Recommendations
1. [Recommendation for increasing adoption of underused features]
2. [Recommendation for enabling new use cases]
---
## 4. Support Summary
| Metric | This Quarter | Previous Quarter | Benchmark |
|--------|-------------|-----------------|-----------|
| Total Tickets | [Number] | [Number] | [Segment avg] |
| Avg Resolution Time | [Hours] | [Hours] | [SLA target] |
| Escalations | [Number] | [Number] | [Target: 0] |
| CSAT Score | [Score] | [Score] | [Target] |
### Open Issues
| Issue | Priority | Status | ETA |
|-------|----------|--------|-----|
| [Issue 1] | [P1/P2/P3] | [In Progress / Pending] | [Date] |
---
## 5. Success Plan Progress
### Current Success Plan Goals
| Goal | Timeline | Progress | Status |
|------|----------|----------|--------|
| [Goal 1] | [Date] | [%] | [On Track / At Risk / Complete] |
| [Goal 2] | [Date] | [%] | [On Track / At Risk / Complete] |
| [Goal 3] | [Date] | [%] | [On Track / At Risk / Complete] |
### Next Quarter Goals (Proposed)
1. [Goal 1 with specific measurable outcome]
2. [Goal 2 with specific measurable outcome]
3. [Goal 3 with specific measurable outcome]
---
## 6. Product Roadmap Highlights
### Recently Released (Relevant to [Customer Name])
- [Feature/enhancement 1] -- [How it benefits them]
- [Feature/enhancement 2] -- [How it benefits them]
### Coming Next Quarter
- [Upcoming feature 1] -- [Expected benefit]
- [Upcoming feature 2] -- [Expected benefit]
### Feature Requests Status
| Request | Priority | Status | Expected Release |
|---------|----------|--------|-----------------|
| [Request 1] | [High/Med/Low] | [Planned / In Development / Under Review] | [Quarter] |
---
## 7. Growth Opportunities
### Expansion Discussion Points
- [Opportunity 1: e.g., additional seats for new team]
- [Opportunity 2: e.g., new module that addresses identified need]
- [Opportunity 3: e.g., tier upgrade for advanced capabilities]
### Estimated Value of Expansion: $[Amount] additional ARR
---
## 8. Action Items
| Action | Owner | Due Date | Priority |
|--------|-------|----------|----------|
| [Action 1] | [Name] | [Date] | [High/Med/Low] |
| [Action 2] | [Name] | [Date] | [High/Med/Low] |
| [Action 3] | [Name] | [Date] | [High/Med/Low] |
| [Action 4] | [Name] | [Date] | [High/Med/Low] |
---
## 9. Contract and Renewal
**Contract Start:** [Date]
**Renewal Date:** [Date]
**Current ARR:** $[Amount]
**Days to Renewal:** [Number]
### Renewal Readiness
- [ ] Value documented and communicated
- [ ] Executive sponsor aligned
- [ ] Open issues resolved or plan in place
- [ ] Pricing and terms discussed
- [ ] Expansion proposal prepared (if applicable)
---
**Next QBR Date:** [Date]
**Next Check-in:** [Date]
FILE:assets/sample_customer_data.json
{
"customers": [
{
"customer_id": "CUST-001",
"name": "Acme Corp",
"segment": "enterprise",
"arr": 120000,
"contract_end_date": "2026-12-31",
"usage": {
"login_frequency": 85,
"feature_adoption": 72,
"dau_mau_ratio": 0.45
},
"engagement": {
"support_ticket_volume": 3,
"meeting_attendance": 90,
"nps_score": 8,
"csat_score": 4.2
},
"support": {
"open_tickets": 2,
"escalation_rate": 0.05,
"avg_resolution_hours": 18
},
"relationship": {
"executive_sponsor_engagement": 80,
"multi_threading_depth": 4,
"renewal_sentiment": "positive"
},
"previous_period": {
"usage_score": 70,
"engagement_score": 65,
"support_score": 75,
"relationship_score": 60,
"overall_score": 67
},
"usage_decline": {
"login_trend": 5,
"feature_adoption_change": 3,
"dau_mau_change": 0.02
},
"engagement_drop": {
"meeting_cancellations": 0,
"response_time_days": 1,
"nps_change": 1
},
"support_issues": {
"open_escalations": 0,
"unresolved_critical": 0,
"satisfaction_trend": "improving"
},
"relationship_signals": {
"champion_left": false,
"sponsor_change": false,
"competitor_mentions": 0
},
"commercial_factors": {
"contract_type": "annual",
"pricing_complaints": false,
"budget_cuts_mentioned": false
},
"contract": {
"licensed_seats": 100,
"active_seats": 95,
"plan_tier": "professional",
"available_tiers": ["professional", "enterprise", "enterprise_plus"]
},
"product_usage": {
"core_platform": {"adopted": true, "usage_pct": 85},
"analytics_module": {"adopted": true, "usage_pct": 60},
"integrations_module": {"adopted": false, "usage_pct": 0},
"api_access": {"adopted": true, "usage_pct": 40},
"advanced_reporting": {"adopted": false, "usage_pct": 0}
},
"departments": {
"current": ["engineering", "product"],
"potential": ["marketing", "sales", "support"]
}
},
{
"customer_id": "CUST-002",
"name": "TechStart Inc",
"segment": "smb",
"arr": 18000,
"contract_end_date": "2026-04-15",
"usage": {
"login_frequency": 40,
"feature_adoption": 30,
"dau_mau_ratio": 0.15
},
"engagement": {
"support_ticket_volume": 8,
"meeting_attendance": 50,
"nps_score": 5,
"csat_score": 3.0
},
"support": {
"open_tickets": 6,
"escalation_rate": 0.18,
"avg_resolution_hours": 42
},
"relationship": {
"executive_sponsor_engagement": 30,
"multi_threading_depth": 1,
"renewal_sentiment": "negative"
},
"previous_period": {
"usage_score": 55,
"engagement_score": 50,
"support_score": 60,
"relationship_score": 45,
"overall_score": 52
},
"usage_decline": {
"login_trend": -25,
"feature_adoption_change": -18,
"dau_mau_change": -0.12
},
"engagement_drop": {
"meeting_cancellations": 3,
"response_time_days": 8,
"nps_change": -4
},
"support_issues": {
"open_escalations": 2,
"unresolved_critical": 1,
"satisfaction_trend": "declining"
},
"relationship_signals": {
"champion_left": true,
"sponsor_change": false,
"competitor_mentions": 3
},
"commercial_factors": {
"contract_type": "month-to-month",
"pricing_complaints": true,
"budget_cuts_mentioned": true
},
"contract": {
"licensed_seats": 20,
"active_seats": 8,
"plan_tier": "starter",
"available_tiers": ["starter", "professional", "enterprise"]
},
"product_usage": {
"core_platform": {"adopted": true, "usage_pct": 35},
"analytics_module": {"adopted": false, "usage_pct": 0},
"integrations_module": {"adopted": false, "usage_pct": 0},
"api_access": {"adopted": false, "usage_pct": 0},
"advanced_reporting": {"adopted": false, "usage_pct": 0}
},
"departments": {
"current": ["engineering"],
"potential": ["product", "design"]
}
},
{
"customer_id": "CUST-003",
"name": "GlobalTrade Solutions",
"segment": "mid-market",
"arr": 55000,
"contract_end_date": "2026-09-30",
"usage": {
"login_frequency": 70,
"feature_adoption": 58,
"dau_mau_ratio": 0.35
},
"engagement": {
"support_ticket_volume": 5,
"meeting_attendance": 75,
"nps_score": 7,
"csat_score": 3.8
},
"support": {
"open_tickets": 3,
"escalation_rate": 0.10,
"avg_resolution_hours": 30
},
"relationship": {
"executive_sponsor_engagement": 60,
"multi_threading_depth": 3,
"renewal_sentiment": "neutral"
},
"previous_period": {
"usage_score": 68,
"engagement_score": 70,
"support_score": 65,
"relationship_score": 62,
"overall_score": 66
},
"usage_decline": {
"login_trend": -8,
"feature_adoption_change": -5,
"dau_mau_change": -0.03
},
"engagement_drop": {
"meeting_cancellations": 1,
"response_time_days": 3,
"nps_change": -1
},
"support_issues": {
"open_escalations": 1,
"unresolved_critical": 0,
"satisfaction_trend": "stable"
},
"relationship_signals": {
"champion_left": false,
"sponsor_change": true,
"competitor_mentions": 1
},
"commercial_factors": {
"contract_type": "annual",
"pricing_complaints": false,
"budget_cuts_mentioned": false
},
"contract": {
"licensed_seats": 50,
"active_seats": 48,
"plan_tier": "professional",
"available_tiers": ["professional", "enterprise", "enterprise_plus"]
},
"product_usage": {
"core_platform": {"adopted": true, "usage_pct": 78},
"analytics_module": {"adopted": true, "usage_pct": 45},
"integrations_module": {"adopted": true, "usage_pct": 55},
"api_access": {"adopted": false, "usage_pct": 0},
"advanced_reporting": {"adopted": false, "usage_pct": 0}
},
"departments": {
"current": ["operations", "finance"],
"potential": ["logistics", "compliance"]
}
},
{
"customer_id": "CUST-004",
"name": "HealthFirst Medical",
"segment": "enterprise",
"arr": 200000,
"contract_end_date": "2027-03-15",
"usage": {
"login_frequency": 92,
"feature_adoption": 88,
"dau_mau_ratio": 0.55
},
"engagement": {
"support_ticket_volume": 2,
"meeting_attendance": 95,
"nps_score": 9,
"csat_score": 4.6
},
"support": {
"open_tickets": 1,
"escalation_rate": 0.02,
"avg_resolution_hours": 12
},
"relationship": {
"executive_sponsor_engagement": 92,
"multi_threading_depth": 6,
"renewal_sentiment": "positive"
},
"previous_period": {
"usage_score": 85,
"engagement_score": 82,
"support_score": 88,
"relationship_score": 80,
"overall_score": 84
},
"usage_decline": {
"login_trend": 3,
"feature_adoption_change": 5,
"dau_mau_change": 0.03
},
"engagement_drop": {
"meeting_cancellations": 0,
"response_time_days": 1,
"nps_change": 0
},
"support_issues": {
"open_escalations": 0,
"unresolved_critical": 0,
"satisfaction_trend": "improving"
},
"relationship_signals": {
"champion_left": false,
"sponsor_change": false,
"competitor_mentions": 0
},
"commercial_factors": {
"contract_type": "multi-year",
"pricing_complaints": false,
"budget_cuts_mentioned": false
},
"contract": {
"licensed_seats": 250,
"active_seats": 240,
"plan_tier": "enterprise",
"available_tiers": ["professional", "enterprise", "enterprise_plus"]
},
"product_usage": {
"core_platform": {"adopted": true, "usage_pct": 92},
"analytics_module": {"adopted": true, "usage_pct": 80},
"integrations_module": {"adopted": true, "usage_pct": 70},
"api_access": {"adopted": true, "usage_pct": 65},
"advanced_reporting": {"adopted": true, "usage_pct": 50},
"security_module": {"adopted": false, "usage_pct": 0},
"audit_module": {"adopted": false, "usage_pct": 0}
},
"departments": {
"current": ["clinical", "operations", "IT", "compliance"],
"potential": ["research", "finance", "HR"]
}
}
]
}
FILE:assets/success_plan_template.md
# Customer Success Plan
**Customer:** [Customer Name]
**CSM:** [CSM Name]
**Account Executive:** [AE Name]
**Plan Created:** [Date]
**Last Updated:** [Date]
**Review Cadence:** [Monthly / Quarterly]
---
## 1. Customer Overview
| Field | Details |
|-------|---------|
| Industry | [Industry] |
| Company Size | [Employees] |
| Segment | [Enterprise / Mid-Market / SMB] |
| ARR | $[Amount] |
| Contract Start | [Date] |
| Renewal Date | [Date] |
| Plan Tier | [Tier name] |
| Licensed Seats | [Number] |
### Key Stakeholders
| Name | Title | Role | Engagement Level |
|------|-------|------|-----------------|
| [Name] | [Title] | Executive Sponsor | [High / Medium / Low] |
| [Name] | [Title] | Day-to-Day Champion | [High / Medium / Low] |
| [Name] | [Title] | Technical Lead | [High / Medium / Low] |
| [Name] | [Title] | End User Lead | [High / Medium / Low] |
---
## 2. Business Objectives
### Primary Business Objectives
| # | Objective | Success Metric | Target | Timeline |
|---|-----------|---------------|--------|----------|
| 1 | [e.g., Reduce manual reporting time] | [Hours saved per week] | [Target number] | [Date] |
| 2 | [e.g., Improve team collaboration] | [Project completion rate] | [Target %] | [Date] |
| 3 | [e.g., Increase revenue visibility] | [Forecast accuracy] | [Target %] | [Date] |
### Why These Objectives Matter
- **Objective 1:** [Business context -- why this matters to the customer's overall strategy]
- **Objective 2:** [Business context]
- **Objective 3:** [Business context]
---
## 3. Success Milestones
### Phase 1: Foundation (Days 1-30)
| Milestone | Target Date | Status | Owner | Notes |
|-----------|------------|--------|-------|-------|
| Technical setup complete | [Date] | [ ] | [Name] | |
| Admin training delivered | [Date] | [ ] | CSM | |
| Core team onboarded | [Date] | [ ] | CSM | |
| First value milestone achieved | [Date] | [ ] | [Name] | |
| Data migration validated | [Date] | [ ] | SE | |
### Phase 2: Adoption (Days 31-90)
| Milestone | Target Date | Status | Owner | Notes |
|-----------|------------|--------|-------|-------|
| 80% user adoption | [Date] | [ ] | CSM | |
| Key workflows live | [Date] | [ ] | [Name] | |
| Integrations configured | [Date] | [ ] | SE | |
| First ROI measurement | [Date] | [ ] | CSM | |
| 30-day review complete | [Date] | [ ] | CSM | |
### Phase 3: Value Realisation (Days 91-180)
| Milestone | Target Date | Status | Owner | Notes |
|-----------|------------|--------|-------|-------|
| Objective 1 progress measurable | [Date] | [ ] | [Name] | |
| Advanced features adopted | [Date] | [ ] | CSM | |
| QBR completed | [Date] | [ ] | CSM | |
| Executive alignment confirmed | [Date] | [ ] | CSM | |
### Phase 4: Optimisation and Growth (Days 181-365)
| Milestone | Target Date | Status | Owner | Notes |
|-----------|------------|--------|-------|-------|
| All objectives on track | [Date] | [ ] | CSM | |
| ROI documented for renewal | [Date] | [ ] | CSM | |
| Expansion opportunities identified | [Date] | [ ] | CSM + AE | |
| Renewal conversation initiated | [Date] | [ ] | CSM + AE | |
---
## 4. Health Score Tracking
| Date | Overall Score | Usage | Engagement | Support | Relationship | Classification |
|------|--------------|-------|------------|---------|-------------|---------------|
| [Date] | [Score] | [Score] | [Score] | [Score] | [Score] | [Green/Yellow/Red] |
| [Date] | [Score] | [Score] | [Score] | [Score] | [Score] | [Green/Yellow/Red] |
---
## 5. Risk Register
| Risk | Probability | Impact | Mitigation | Owner | Status |
|------|------------|--------|-----------|-------|--------|
| [e.g., Executive sponsor departure] | [High/Med/Low] | [High/Med/Low] | [Multi-thread relationships] | CSM | [Active/Resolved] |
| [e.g., Low adoption in team X] | [High/Med/Low] | [High/Med/Low] | [Targeted training session] | CSM | [Active/Resolved] |
| [e.g., Budget review next quarter] | [High/Med/Low] | [High/Med/Low] | [Document ROI before review] | CSM | [Active/Resolved] |
---
## 6. Communication Plan
| Activity | Frequency | Participants | Purpose |
|----------|-----------|-------------|---------|
| Status check-in | [Weekly / Bi-weekly] | CSM + Champion | Tactical progress review |
| Strategic review | [Monthly] | CSM + Stakeholders | Objective alignment |
| QBR | [Quarterly] | CSM + Executive Sponsor | Executive business review |
| Technical review | [As needed] | SE + Technical Lead | Architecture and integration |
| Renewal planning | [90 days before] | CSM + AE + Sponsor | Contract discussion |
---
## 7. Product Adoption Plan
### Current State
| Module/Feature | Status | Usage Level | Target Usage | Gap |
|---------------|--------|-------------|-------------|-----|
| [Module 1] | Adopted | [%] | [%] | [Actions needed] |
| [Module 2] | Adopted | [%] | [%] | [Actions needed] |
| [Module 3] | Not Adopted | 0% | [%] | [Enablement plan] |
### Enablement Activities
| Activity | Target Date | Audience | Expected Outcome |
|----------|------------|----------|-----------------|
| [Training session] | [Date] | [Team/Group] | [Metric improvement] |
| [Workshop] | [Date] | [Team/Group] | [New workflow adoption] |
| [Office hours] | [Ongoing] | [All users] | [Question resolution] |
---
## 8. Expansion Roadmap
| Opportunity | Type | Estimated Value | Timeline | Prerequisites |
|------------|------|----------------|----------|--------------|
| [e.g., Additional seats] | Expansion | $[Amount] | [Quarter] | [Usage > 90%] |
| [e.g., Tier upgrade] | Upsell | $[Amount] | [Quarter] | [Feature requests] |
| [e.g., New module] | Cross-sell | $[Amount] | [Quarter] | [Use case validated] |
---
## 9. Notes and Updates
### [Date] - [Author]
[Update notes, key decisions, changes to plan]
### [Date] - [Author]
[Update notes, key decisions, changes to plan]
---
**Next Review Date:** [Date]
**Plan Owner:** [CSM Name]
FILE:references/cs-metrics-benchmarks.md
# Customer Success Metrics and Benchmarks
Industry benchmarks for key customer success metrics, segmented by company size, customer segment, and industry vertical.
---
## Core SaaS Metrics
### Net Revenue Retention (NRR)
NRR measures revenue retained from existing customers including expansion, contraction, and churn. It is the single most important metric for SaaS customer success.
**Formula:** (Starting ARR + Expansion - Contraction - Churn) / Starting ARR * 100
| Performance Level | NRR Range | Interpretation |
|-------------------|-----------|----------------|
| Best-in-class | > 130% | Strong expansion engine, very low churn |
| Excellent | 120-130% | Healthy growth from existing customers |
| Good | 110-120% | Solid retention with moderate expansion |
| Target | > 110% | Minimum for sustainable growth |
| Acceptable | 100-110% | Revenue stable but limited expansion |
| Below target | 90-100% | Churn exceeds expansion |
| Concerning | < 90% | Significant revenue erosion |
**Benchmarks by Segment:**
| Customer Segment | Median NRR | Top Quartile | Bottom Quartile |
|-----------------|------------|--------------|-----------------|
| Enterprise (>$100K ARR) | 115% | 130%+ | 105% |
| Mid-Market ($25K-$100K) | 108% | 120% | 98% |
| SMB (<$25K ARR) | 95% | 105% | 85% |
### Gross Revenue Retention (GRR)
GRR measures revenue retained without counting expansion. It isolates the churn and contraction signal.
**Formula:** (Starting ARR - Contraction - Churn) / Starting ARR * 100
| Performance Level | GRR Range | Interpretation |
|-------------------|-----------|----------------|
| Best-in-class | > 95% | Minimal churn, highly sticky product |
| Excellent | 92-95% | Strong retention |
| Good | 90-92% | Healthy with room to improve |
| Target | > 90% | Industry standard target |
| Acceptable | 85-90% | Moderate churn, needs focus |
| Below target | 80-85% | High churn impacting growth |
| Concerning | < 80% | Urgent retention problem |
**Benchmarks by Segment:**
| Customer Segment | Median GRR | Top Quartile | Bottom Quartile |
|-----------------|------------|--------------|-----------------|
| Enterprise | 95% | 98% | 90% |
| Mid-Market | 90% | 95% | 85% |
| SMB | 82% | 90% | 75% |
---
## Health Score Benchmarks
### Portfolio Health Distribution (Target)
A healthy CS portfolio should have the following approximate distribution:
| Classification | Target Distribution | Alert Threshold |
|---------------|-------------------|-----------------|
| Green (Healthy) | 60-70% | < 50% triggers portfolio review |
| Yellow (Attention) | 20-30% | > 35% signals systemic issues |
| Red (At Risk) | 5-10% | > 15% requires executive intervention |
### Average Health Score by Segment
| Segment | Target Average | Industry Median | Top Quartile |
|---------|---------------|-----------------|--------------|
| Enterprise | > 78 | 72 | 82 |
| Mid-Market | > 75 | 68 | 78 |
| SMB | > 70 | 65 | 75 |
### Health Score by Dimension (Industry Medians)
| Dimension | Enterprise | Mid-Market | SMB |
|-----------|-----------|------------|-----|
| Usage | 72 | 68 | 60 |
| Engagement | 70 | 62 | 55 |
| Support | 78 | 72 | 65 |
| Relationship | 68 | 60 | 50 |
---
## Churn Metrics
### Logo Churn Rate (Annual)
| Performance Level | Rate | Interpretation |
|-------------------|------|----------------|
| Best-in-class | < 5% | Exceptional retention |
| Excellent | 5-8% | Very strong |
| Good | 8-12% | Healthy |
| Acceptable | 12-15% | Room for improvement |
| Below target | 15-20% | Significant churn problem |
| Concerning | > 20% | Urgent -- product-market fit issues likely |
**Benchmarks by Segment:**
| Segment | Median Annual Logo Churn | Top Quartile | Bottom Quartile |
|---------|------------------------|--------------|-----------------|
| Enterprise | 5% | 2% | 10% |
| Mid-Market | 10% | 5% | 18% |
| SMB | 20% | 12% | 35% |
### Churn Leading Indicators
The following metrics have the highest predictive power for churn events:
| Indicator | Lead Time | Correlation with Churn |
|-----------|-----------|----------------------|
| Login frequency decline (>30%) | 60-90 days | Very High |
| NPS drop (>3 points) | 30-60 days | High |
| Executive sponsor departure | 30-90 days | Very High |
| Support escalation rate increase | 30-60 days | High |
| Meeting cancellation increase | 30-45 days | Moderate-High |
| Feature adoption decline | 60-90 days | Moderate |
| Competitor mentions | 30-60 days | Moderate |
---
## Expansion Metrics
### Expansion Revenue Rate
| Performance Level | Rate | Notes |
|-------------------|------|-------|
| Best-in-class | > 30% of total revenue | Strong land-and-expand motion |
| Excellent | 25-30% | Effective expansion engine |
| Good | 20-25% | Solid upsell/cross-sell |
| Target | > 20% | Minimum for healthy growth |
| Below target | 10-20% | Expansion motion needs development |
| Concerning | < 10% | Missing significant expansion opportunity |
### Expansion by Type
| Expansion Type | Typical Contribution | Average Deal Size |
|---------------|---------------------|-------------------|
| Seat Expansion | 40-50% of expansion | 15-25% of contract value |
| Tier Upsell | 25-35% of expansion | 40-80% of contract value |
| Module Cross-sell | 15-25% of expansion | 10-20% of contract value |
| Department Expansion | 5-15% of expansion | 50-100% of contract value |
### Expansion Readiness Indicators
| Signal | Interpretation |
|--------|---------------|
| Seat utilisation > 90% | Ready for seat expansion |
| Feature requests for higher tier | Upsell opportunity |
| Usage of 70%+ of current modules | Ready for cross-sell |
| New department interest | Department expansion play |
| Customer referral activity | Strong relationship, open to expansion |
---
## Engagement Metrics
### Customer Engagement Score (CES) Benchmarks
| Metric | Target | Median | Warning |
|--------|--------|--------|---------|
| Meeting attendance rate | > 80% | 72% | < 50% |
| Average NPS | > 50 | 35 | < 20 |
| Average CSAT | > 4.2/5 | 3.8/5 | < 3.0/5 |
| Response time (days) | < 2 | 3 | > 5 |
| QBR completion rate | > 90% | 75% | < 60% |
### Time to First Value (TTFV)
| Segment | Target TTFV | Median TTFV | Warning Threshold |
|---------|------------|------------|-------------------|
| Enterprise | < 30 days | 45 days | > 60 days |
| Mid-Market | < 21 days | 30 days | > 45 days |
| SMB | < 14 days | 21 days | > 30 days |
---
## CSM Operational Metrics
### Portfolio Management
| Metric | Enterprise CSM | Mid-Market CSM | SMB CSM (Tech-Touch) |
|--------|---------------|----------------|---------------------|
| Accounts per CSM | 10-25 | 30-60 | 100-300+ |
| ARR per CSM | $2M-$5M | $2M-$4M | $1M-$3M |
| Touch frequency | Weekly-biweekly | Biweekly-monthly | Quarterly-automated |
| QBR frequency | Quarterly | Semi-annually | Annually |
| Health score reviews | Weekly | Bi-weekly | Monthly |
### CSM Activity Benchmarks
| Activity | Target per Month | Purpose |
|----------|-----------------|---------|
| Strategic calls | 2-4 per account | Relationship building |
| Health score reviews | 4 (weekly) | Portfolio monitoring |
| QBR preparation | 3-5 per quarter | Executive engagement |
| Escalation handling | < 2 per month | Issue resolution |
| Expansion conversations | 1-2 per account | Revenue growth |
---
## Industry-Specific Benchmarks
### By Industry Vertical
| Industry | Median NRR | Median GRR | Median Logo Churn |
|----------|-----------|-----------|------------------|
| Infrastructure/DevOps | 125% | 95% | 5% |
| Cybersecurity | 120% | 93% | 7% |
| HR Tech | 110% | 90% | 12% |
| MarTech | 105% | 87% | 15% |
| FinTech | 115% | 92% | 8% |
| HealthTech | 112% | 91% | 10% |
| EdTech | 100% | 85% | 18% |
| eCommerce Tools | 108% | 88% | 14% |
### By Company Stage
| Stage | Median NRR | Median GRR | Notes |
|-------|-----------|-----------|-------|
| Early Stage (<$10M ARR) | 100% | 85% | Focus on product-market fit |
| Growth ($10M-$50M ARR) | 110% | 90% | Building CS function |
| Scale ($50M-$200M ARR) | 118% | 93% | Mature CS operations |
| Enterprise (>$200M ARR) | 115% | 95% | Optimisation phase |
---
## Metric Relationships
### Key Correlations
| If This Metric Moves | This Also Tends to Move | Direction |
|---------------------|------------------------|-----------|
| Health score down | Churn probability up | Inverse |
| NPS up | NRR up | Direct |
| TTFV down | GRR up | Inverse |
| Feature adoption up | Expansion rate up | Direct |
| Escalation rate up | NPS down | Inverse |
| Multi-threading depth up | GRR up | Direct |
### The SaaS Retention Equation
**Sustainable Growth requires:** NRR > 110% AND GRR > 90%
If NRR is high but GRR is low: You are churning customers and replacing with expansion from survivors. Not sustainable.
If GRR is high but NRR is low: You retain well but do not expand. Leaving money on the table.
Both high: Healthy, compounding growth from existing customers.
---
**Last Updated:** February 2026
**Sources:** Industry surveys, SaaS benchmarking reports, customer success community data (2024-2025 data cycles).
FILE:references/cs-playbooks.md
# Customer Success Playbooks
Comprehensive intervention, onboarding, renewal, expansion, and escalation playbooks for SaaS customer success management.
---
## Risk Tier Intervention Playbooks
### Critical Risk (Score 80-100)
**Situation:** Customer is at imminent risk of churn. Multiple severe warning signals detected. Requires immediate executive-level intervention.
**Timeline:** Act within 48 hours.
**Steps:**
1. **Executive Escalation (Day 0)**
- Alert VP of Customer Success and account executive immediately
- Brief internal leadership on situation, warning signals, and ARR at risk
- Identify any pending support issues and fast-track resolution
2. **Customer Contact (Day 1-2)**
- Schedule executive-to-executive call (VP CS to customer VP/C-level)
- Frame the conversation around understanding their challenges, not defending your product
- Listen more than talk -- capture the real objections
3. **Save Plan Creation (Day 2-3)**
- Create a detailed save plan with specific value milestones tied to their business outcomes
- Include timeline, owners, and measurable success criteria
- Get internal alignment on any concessions (pricing, features, roadmap commitments)
4. **Rescue Team Assignment (Day 3-5)**
- Assign a dedicated rescue team: CSM + Solutions Engineer + Support Lead
- Daily internal stand-up (15 min max) on account status
- Solutions Engineer to conduct technical health check
5. **Execution and Monitoring (Week 2-4)**
- Execute save plan with weekly customer check-ins
- Track progress against milestones
- Prepare competitive displacement defence if competitor involvement detected
6. **Resolution Assessment (Week 4)**
- Evaluate whether the situation is stabilising
- If improving: transition to High-risk monitoring cadence
- If not improving: escalate to CEO/GM for final intervention
**Success Criteria:** Risk score drops below 60 within 30 days. Customer confirms continued partnership intent.
---
### High Risk (Score 60-79)
**Situation:** Customer showing clear signs of dissatisfaction or disengagement. Still salvageable with focused CSM intervention.
**Timeline:** Act within 1 week.
**Steps:**
1. **Root Cause Analysis (Day 1-3)**
- Review all health score dimensions to identify the primary drivers
- Pull support ticket history for patterns
- Check product usage trends for the past 90 days
2. **CSM Outreach (Day 3-5)**
- Schedule a dedicated call with the customer (not a routine check-in)
- Open with empathy: "I've noticed some changes and want to make sure we're supporting you properly"
- Identify the top 3 customer concerns
3. **30-Day Recovery Plan (Day 5-7)**
- Build a 30-day recovery plan with measurable checkpoints every week
- Include specific actions for each concern identified
- Share the plan with the customer for mutual commitment
4. **Re-Engage Executive Sponsor (Week 2)**
- Request a meeting with the executive sponsor
- Align on business outcomes and how your product supports them
- Confirm continued sponsorship and address any political changes
5. **Support Fast-Track (Ongoing)**
- Escalate any pending support tickets internally
- Assign a support point of contact for this account
- Provide weekly status updates on open issues
6. **Progress Review (Week 3-4)**
- Review all metrics for improvement
- Adjust plan if specific interventions are not working
- If score drops to Critical: escalate to executive playbook
**Success Criteria:** Risk score drops below 40 within 30 days. No new warning signals emerge.
---
### Medium Risk (Score 40-59)
**Situation:** Early warning signs detected. Customer may not be aware of emerging issues. Proactive outreach prevents escalation.
**Timeline:** Act within 2 weeks.
**Steps:**
1. **Data Review (Day 1-5)**
- Analyse which dimension(s) are pulling the score down
- Review recent support interactions for sentiment clues
- Check for any known product issues affecting this customer
2. **Proactive Check-In (Week 1-2)**
- Schedule a "value check-in" call (position it as routine, not reactive)
- Share relevant success stories from similar customers
- Propose a training session or product walkthrough for underutilised features
3. **Value Reinforcement (Week 2-3)**
- Send a customised ROI summary showing value delivered
- Highlight feature releases relevant to their use case
- Connect them with your customer community or user group
4. **Monitoring (Week 3-4)**
- Increase monitoring frequency to bi-weekly
- Watch for improvement or continued decline
- If declining: move to High-risk playbook
**Success Criteria:** Score stabilises above 50 or improves. No escalation to High risk.
---
### Low Risk (Score 0-39)
**Situation:** Customer is healthy. Standard success cadence applies. Focus on value reinforcement and expansion readiness.
**Timeline:** Standard touch cadence.
**Steps:**
1. **Maintain Cadence**
- Enterprise: Monthly strategic reviews, quarterly QBRs
- Mid-Market: Bi-monthly check-ins, semi-annual reviews
- SMB: Quarterly automated health updates, annual review
2. **Proactive Communication**
- Share product updates and release notes
- Invite to webinars, conferences, and community events
- Share relevant industry insights and benchmarks
3. **Expansion Readiness**
- Monitor for expansion signals (usage approaching limits, new use cases)
- Prepare expansion proposals when timing is right
- Position premium features and modules relevant to their needs
4. **Renewal Preparation**
- Begin renewal preparation 90 days before contract end
- Build renewal proposal with value delivered summary
- Identify any terms or pricing adjustments needed
**Success Criteria:** Customer remains in Green classification. Expansion conversations initiated when appropriate.
---
## Onboarding Playbook
### Phase 1: Welcome and Setup (Day 1-14)
| Day | Activity | Owner | Deliverable |
|-----|----------|-------|-------------|
| 1 | Welcome email and introduction | CSM | Welcome package sent |
| 1-2 | Kickoff call | CSM + SE | Success plan drafted |
| 3-5 | Technical setup and configuration | SE | Environment configured |
| 5-7 | Admin training session | CSM | Admins trained |
| 7-10 | Data migration (if applicable) | SE | Data validated |
| 10-14 | Initial user training | CSM | Core team trained |
### Phase 2: Activation (Day 15-30)
| Day | Activity | Owner | Deliverable |
|-----|----------|-------|-------------|
| 15 | Activation check -- are users logging in? | CSM | Usage report |
| 15-20 | Follow-up training for laggards | CSM | All users active |
| 20-25 | First business outcome milestone | CSM | Milestone achieved |
| 25-30 | 30-day review call | CSM | Review documented |
**Critical Milestone:** Time to First Value must be under 30 days.
### Phase 3: Adoption (Day 31-60)
| Day | Activity | Owner | Deliverable |
|-----|----------|-------|-------------|
| 30-40 | Feature adoption expansion | CSM | New features in use |
| 40-50 | Integration setup (if applicable) | SE | Integrations live |
| 50-60 | Usage benchmarking vs. peers | CSM | Benchmark report |
### Phase 4: Optimisation (Day 61-90)
| Day | Activity | Owner | Deliverable |
|-----|----------|-------|-------------|
| 60-70 | Advanced use case workshop | CSM + SE | New use cases identified |
| 70-80 | ROI measurement | CSM | ROI documented |
| 80-90 | 90-day executive review | CSM | Transition to steady-state |
**Gate:** Handoff from onboarding to ongoing CSM management. Health score must be Yellow or better.
---
## Renewal Playbook
### 120 Days Before Renewal
- Review contract terms and pricing
- Assess current health score and trajectory
- Identify any outstanding issues or concerns
- Begin internal alignment on renewal strategy
### 90 Days Before Renewal
- Schedule renewal conversation with customer
- Prepare value delivered summary (ROI, usage stats, milestones achieved)
- Draft renewal proposal with recommended terms
- If at-risk: escalate and begin risk mitigation
### 60 Days Before Renewal
- Present renewal proposal to customer
- Negotiate terms if needed
- Address any concerns raised during the process
- Escalate blockers to leadership
### 30 Days Before Renewal
- Finalise contract terms
- Obtain signatures
- Plan for any post-renewal actions (expansion, migration)
- Update CRM with renewal details
### Post-Renewal
- Confirm renewed contract in systems
- Send thank-you and updated success plan
- Schedule next QBR
- Identify expansion opportunities
---
## Expansion Playbook
### Identifying Expansion Signals
| Signal | Expansion Type | Priority |
|--------|---------------|----------|
| Seat utilisation > 90% | Seat expansion | High |
| Requests for features in higher tier | Tier upsell | High |
| New department inquiries | Department expansion | Medium |
| High adoption of existing modules | Module cross-sell | Medium |
| Customer referencing competitors for missing features | Cross-sell | High |
### Expansion Conversation Framework
1. **Discovery:** "I noticed your team has been getting great value from [feature]. Have you considered how [new module] could help with [related business outcome]?"
2. **Value Framing:** "Companies similar to yours who adopted [module] saw [specific metric improvement]."
3. **Proposal:** "Based on your current usage, here's what the expansion would look like..."
4. **Stakeholder Alignment:** Involve the economic buyer early. The champion can advocate, but the budget holder decides.
5. **Close:** Coordinate with sales/account executive for commercial negotiation.
---
## Escalation Procedures
### Internal Escalation Matrix
| Trigger | Escalation Level | Response Time |
|---------|-----------------|---------------|
| Health score drops to Red | VP Customer Success | 24 hours |
| Executive sponsor leaves | Director CS + AE | 48 hours |
| Critical bug affecting customer | VP Engineering + VP CS | 4 hours |
| Customer mentions competitor evaluation | VP CS + VP Sales | 24 hours |
| Renewal at risk (60 days or less) | CRO/VP Sales | 24 hours |
| Customer threatens legal action | Legal + VP CS | Immediate |
### Escalation Communication Template
**Subject:** [ESCALATION] {Customer Name} -- {Brief Description}
**Body:**
- Customer: {name}, {segment}, ARR
- Health Score: {score} ({classification})
- Renewal Date: {date}
- Issue Summary: {2-3 sentences}
- Warning Signals: {list}
- Recommended Action: {specific next step}
- Urgency: {critical/high/medium}
---
**Last Updated:** February 2026
FILE:references/health-scoring-framework.md
# Health Scoring Framework
Complete methodology for multi-dimensional customer health scoring in SaaS customer success.
---
## Overview
Customer health scoring is the foundation of proactive customer success management. A well-calibrated health score enables CSMs to prioritise their portfolio, identify emerging risks before they become churn events, and allocate resources where they will have the greatest impact.
This framework uses a weighted, multi-dimensional approach that scores customers across four key areas: usage, engagement, support, and relationship. Each dimension contributes to an overall health score (0-100) that classifies accounts as Green (healthy), Yellow (needs attention), or Red (at risk).
---
## Scoring Dimensions
### 1. Usage (Weight: 30%)
Usage metrics are the strongest leading indicator of customer health. Customers who are not using the product are not deriving value and are at elevated churn risk.
| Metric | Definition | Scoring Method |
|--------|-----------|----------------|
| Login Frequency | Percentage of expected login days with actual logins | (actual / target) * 100, capped at 100 |
| Feature Adoption | Percentage of available features actively used | (adopted / available) * 100, capped at 100 |
| DAU/MAU Ratio | Daily active users divided by monthly active users | (actual / target) * 100, capped at 100 |
**Sub-weights within Usage:**
- Login Frequency: 35%
- Feature Adoption: 40%
- DAU/MAU Ratio: 25%
**Why 30% weight:** Usage is the most objective, data-driven signal. Declining usage almost always precedes churn. However, some customers may have seasonal usage patterns, which is why it is not weighted even higher.
### 2. Engagement (Weight: 25%)
Engagement measures how actively the customer participates in the relationship beyond just product usage.
| Metric | Definition | Scoring Method |
|--------|-----------|----------------|
| Support Ticket Volume | Number of support tickets in the period | Inverse score: (1 - actual/max) * 100 |
| Meeting Attendance | Percentage of scheduled meetings attended | (actual / target) * 100, capped at 100 |
| NPS Score | Net Promoter Score response (0-10) | (actual / target) * 100, capped at 100 |
| CSAT Score | Customer Satisfaction score (1-5) | (actual / target) * 100, capped at 100 |
**Sub-weights within Engagement:**
- Support Ticket Volume: 20% (inverse -- fewer tickets is better)
- Meeting Attendance: 30%
- NPS Score: 25%
- CSAT Score: 25%
**Why 25% weight:** Engagement signals complement usage data. A customer who attends meetings but does not use the product may be in an evaluation phase. A customer who uses the product but skips meetings may be becoming self-sufficient -- or disengaging.
### 3. Support (Weight: 20%)
Support health measures the quality of the customer's support experience, which directly impacts satisfaction and renewal likelihood.
| Metric | Definition | Scoring Method |
|--------|-----------|----------------|
| Open Tickets | Number of currently unresolved tickets | Inverse score: (1 - actual/max) * 100 |
| Escalation Rate | Percentage of tickets escalated | Inverse score: (1 - actual/max) * 100 |
| Avg Resolution Time | Average hours to resolve tickets | Inverse score: (1 - actual/max) * 100 |
**Sub-weights within Support:**
- Open Tickets: 35%
- Escalation Rate: 35%
- Resolution Time: 30%
**Why 20% weight:** Support issues are lagging indicators -- they tell you there is already a problem. However, unresolved support issues are a strong predictor of churn, especially when combined with declining engagement.
### 4. Relationship (Weight: 25%)
Relationship health measures the strength and depth of the human connection between the customer and your organisation.
| Metric | Definition | Scoring Method |
|--------|-----------|----------------|
| Executive Sponsor Engagement | Engagement level of exec sponsor (0-100) | (actual / target) * 100, capped at 100 |
| Multi-Threading Depth | Number of stakeholder contacts | (actual / target) * 100, capped at 100 |
| Renewal Sentiment | Qualitative sentiment assessment | Mapped to score: positive=100, neutral=60, negative=20, unknown=50 |
**Sub-weights within Relationship:**
- Executive Sponsor Engagement: 35%
- Multi-Threading Depth: 30%
- Renewal Sentiment: 35%
**Why 25% weight:** Relationship strength is the most important defence against competitive displacement. A customer with strong relationships will give you more chances to fix problems. A customer with weak relationships may leave without warning.
---
## Classification Thresholds
### Standard Thresholds
| Classification | Score Range | Meaning | Action |
|---------------|-------------|---------|--------|
| Green | 75-100 | Customer is healthy and achieving value | Standard cadence, focus on expansion |
| Yellow | 50-74 | Customer needs attention | Increase touch frequency, investigate root causes |
| Red | 0-49 | Customer is at risk | Immediate intervention, create save plan |
### Segment-Adjusted Thresholds
Enterprise customers typically have higher expectations and more complex deployments, which means a higher bar for "healthy." SMB customers may have simpler use cases and lower engagement expectations.
| Segment | Green Threshold | Yellow Threshold | Red Threshold |
|---------|----------------|------------------|---------------|
| Enterprise | 75-100 | 50-74 | 0-49 |
| Mid-Market | 70-100 | 45-69 | 0-44 |
| SMB | 65-100 | 40-64 | 0-39 |
### Segment-Specific Benchmarks
Each metric target is calibrated per segment. Enterprise customers are expected to have higher login frequency, attendance, and sponsor engagement. SMB customers have lower targets but still meaningful thresholds.
**Example Calibration:**
- Enterprise login frequency target: 90% (high-touch, deeply embedded)
- Mid-Market login frequency target: 80% (balanced engagement)
- SMB login frequency target: 70% (self-serve oriented)
---
## Trend Analysis
A single health score snapshot is useful. A health score trend is actionable.
### Trend Classification
| Trend | Criteria | Implication |
|-------|----------|-------------|
| Improving | Current > Previous by 5+ points | Positive trajectory, reinforce what is working |
| Stable | Within +/- 5 points | Maintain current approach |
| Declining | Current < Previous by 5+ points | Investigate and intervene |
| No Data | No previous period available | Establish baseline |
### Trend Priority Matrix
| Current Score | Trend | Priority |
|--------------|-------|----------|
| Green | Declining | HIGH -- intervene before it drops further |
| Yellow | Declining | CRITICAL -- trajectory leads to Red |
| Yellow | Improving | MEDIUM -- reinforce positive momentum |
| Red | Improving | HIGH -- support the recovery |
| Red | Stable | CRITICAL -- needs new intervention approach |
---
## Calibration Guidelines
### When to Recalibrate
1. **After major product changes**: New features may change what "good usage" looks like
2. **Seasonal patterns**: Some industries have cyclical usage (retail holiday season, fiscal year end)
3. **Portfolio composition changes**: If you add many SMB customers, the overall averages shift
4. **After churn events**: Review whether the health score predicted the churn
### Calibration Process
1. Export health scores for all customers over the past 12 months
2. Identify all churn events in the same period
3. Calculate the average health score of churned customers 90, 60, and 30 days before churn
4. Adjust thresholds so that churned customers would have been classified as Yellow or Red at least 60 days before churn
5. Validate with a holdout set of recent data
### Common Calibration Pitfalls
- **Threshold creep**: Gradually lowering Green thresholds to make the portfolio look healthier
- **Over-weighting lagging indicators**: Support metrics react after the damage is done
- **Ignoring segment differences**: Using one threshold for all segments
- **Sentiment bias**: Over-relying on subjective renewal sentiment
---
## Implementation Checklist
1. Define data sources for each metric (CRM, product analytics, support system)
2. Establish data refresh frequency (daily for usage, weekly for engagement)
3. Configure segment benchmarks for your customer base
4. Set initial thresholds using industry defaults (provided above)
5. Run a 30-day pilot with manual review of edge cases
6. Calibrate thresholds based on pilot results
7. Automate scoring and alerting
8. Review and recalibrate quarterly
---
**Last Updated:** February 2026
FILE:scripts/churn_risk_analyzer.py
#!/usr/bin/env python3
"""
Churn Risk Analyzer
Identifies at-risk customer accounts by scoring behavioral signals across
usage decline, engagement drop, support issues, relationship signals, and
commercial factors. Produces risk tiers with intervention playbooks and
time-to-renewal urgency multipliers.
Usage:
python churn_risk_analyzer.py customer_data.json
python churn_risk_analyzer.py customer_data.json --format json
"""
import argparse
import json
import sys
from datetime import datetime
from typing import Any, Dict, List, Optional, Tuple
# ---------------------------------------------------------------------------
# Constants
# ---------------------------------------------------------------------------
RISK_SIGNAL_WEIGHTS: Dict[str, float] = {
"usage_decline": 0.30,
"engagement_drop": 0.25,
"support_issues": 0.20,
"relationship_signals": 0.15,
"commercial_factors": 0.10,
}
RISK_TIERS: List[Dict[str, Any]] = [
{"name": "critical", "min": 80, "max": 100, "label": "CRITICAL", "action": "Immediate executive escalation"},
{"name": "high", "min": 60, "max": 79, "label": "HIGH", "action": "Urgent CSM intervention"},
{"name": "medium", "min": 40, "max": 59, "label": "MEDIUM", "action": "Proactive outreach"},
{"name": "low", "min": 0, "max": 39, "label": "LOW", "action": "Standard monitoring"},
]
WARNING_SEVERITY: Dict[str, int] = {
"critical": 4,
"high": 3,
"medium": 2,
"low": 1,
}
# Intervention playbooks per tier
INTERVENTION_PLAYBOOKS: Dict[str, List[str]] = {
"critical": [
"Schedule executive-to-executive call within 48 hours",
"Create detailed save plan with specific value milestones",
"Offer concessions or contract restructuring if needed",
"Assign dedicated rescue team (CSM + Solutions Engineer)",
"Daily internal stand-up on account status until stabilised",
"Prepare competitive displacement defence strategy",
],
"high": [
"Schedule urgent CSM call within 1 week",
"Conduct root cause analysis on declining metrics",
"Build 30-day recovery plan with measurable checkpoints",
"Re-engage executive sponsor for alignment meeting",
"Accelerate any pending feature requests or bug fixes",
"Increase touch frequency to weekly until improvement",
],
"medium": [
"Schedule proactive check-in within 2 weeks",
"Share relevant success stories and best practices",
"Propose training session or product walkthrough",
"Review current usage against success plan goals",
"Identify and address any unvoiced concerns",
"Bi-weekly monitoring until score improves to Low",
],
"low": [
"Maintain standard touch cadence",
"Share product updates and new feature announcements",
"Monitor health score trends monthly",
"Proactively share relevant industry insights",
"Prepare for upcoming renewal conversations (if within 90 days)",
],
}
SATISFACTION_TREND_SCORES: Dict[str, float] = {
"improving": 10.0,
"stable": 30.0,
"declining": 70.0,
"critical": 95.0,
}
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def safe_divide(numerator: float, denominator: float, default: float = 0.0) -> float:
"""Return numerator / denominator, or *default* when denominator is zero."""
if denominator == 0:
return default
return numerator / denominator
def clamp(value: float, lo: float = 0.0, hi: float = 100.0) -> float:
"""Clamp *value* between *lo* and *hi*."""
return max(lo, min(hi, value))
def days_until(date_str: Optional[str]) -> Optional[int]:
"""Return days from today until *date_str* (ISO format), or None."""
if not date_str:
return None
try:
target = datetime.strptime(date_str[:10], "%Y-%m-%d")
delta = (target - datetime.now()).days
return max(delta, 0)
except (ValueError, TypeError):
return None
def renewal_urgency_multiplier(days_remaining: Optional[int]) -> float:
"""Return a multiplier (1.0 - 1.5) based on proximity to renewal.
Closer renewals amplify the risk score.
"""
if days_remaining is None:
return 1.0
if days_remaining <= 30:
return 1.5
elif days_remaining <= 60:
return 1.35
elif days_remaining <= 90:
return 1.2
elif days_remaining <= 180:
return 1.1
return 1.0
def get_risk_tier(score: float) -> Dict[str, Any]:
"""Return the risk tier dict matching the score."""
for tier in RISK_TIERS:
if tier["min"] <= score <= tier["max"]:
return tier
return RISK_TIERS[-1] # default to low
# ---------------------------------------------------------------------------
# Signal Scoring
# ---------------------------------------------------------------------------
def score_usage_decline(data: Dict[str, Any]) -> Tuple[float, List[Dict[str, str]]]:
"""Score usage decline signals (0-100, higher = more risk)."""
warnings: List[Dict[str, str]] = []
login_trend = data.get("login_trend", 0) # negative = decline
feature_change = data.get("feature_adoption_change", 0)
dau_mau_change = data.get("dau_mau_change", 0)
# Convert declines to risk scores (0-100)
login_risk = clamp(abs(min(login_trend, 0)) * 3.0) # -33% => 100
feature_risk = clamp(abs(min(feature_change, 0)) * 4.0) # -25% => 100
dau_mau_risk = clamp(abs(min(dau_mau_change, 0)) * 500) # -0.20 => 100
score = round(login_risk * 0.40 + feature_risk * 0.35 + dau_mau_risk * 0.25, 1)
if login_trend <= -20:
warnings.append({"severity": "critical", "signal": f"Login frequency dropped {abs(login_trend)}%"})
elif login_trend <= -10:
warnings.append({"severity": "high", "signal": f"Login frequency declined {abs(login_trend)}%"})
elif login_trend < -5:
warnings.append({"severity": "medium", "signal": f"Login frequency dipping {abs(login_trend)}%"})
if feature_change <= -15:
warnings.append({"severity": "high", "signal": f"Feature adoption dropped {abs(feature_change)}%"})
elif feature_change < -5:
warnings.append({"severity": "medium", "signal": f"Feature adoption declining {abs(feature_change)}%"})
if dau_mau_change <= -0.10:
warnings.append({"severity": "high", "signal": f"DAU/MAU ratio fell by {abs(dau_mau_change):.2f}"})
return score, warnings
def score_engagement_drop(data: Dict[str, Any]) -> Tuple[float, List[Dict[str, str]]]:
"""Score engagement drop signals (0-100, higher = more risk)."""
warnings: List[Dict[str, str]] = []
cancellations = data.get("meeting_cancellations", 0)
response_days = data.get("response_time_days", 1)
nps_change = data.get("nps_change", 0)
cancel_risk = clamp(cancellations * 25.0) # 4 cancellations => 100
response_risk = clamp((response_days - 1) * 15.0) # 1 day baseline; 7+ days => 90+
nps_risk = clamp(abs(min(nps_change, 0)) * 20.0) # -5 => 100
score = round(cancel_risk * 0.30 + response_risk * 0.35 + nps_risk * 0.35, 1)
if cancellations >= 3:
warnings.append({"severity": "critical", "signal": f"{cancellations} meeting cancellations -- customer disengaging"})
elif cancellations >= 2:
warnings.append({"severity": "high", "signal": f"{cancellations} meeting cancellations recently"})
if response_days >= 7:
warnings.append({"severity": "critical", "signal": f"Customer response time: {response_days} days -- going dark"})
elif response_days >= 4:
warnings.append({"severity": "high", "signal": f"Customer response time increasing: {response_days} days"})
if nps_change <= -4:
warnings.append({"severity": "critical", "signal": f"NPS dropped by {abs(nps_change)} points"})
elif nps_change <= -2:
warnings.append({"severity": "high", "signal": f"NPS declined by {abs(nps_change)} points"})
return score, warnings
def score_support_issues(data: Dict[str, Any]) -> Tuple[float, List[Dict[str, str]]]:
"""Score support-related risk signals (0-100, higher = more risk)."""
warnings: List[Dict[str, str]] = []
escalations = data.get("open_escalations", 0)
critical_unresolved = data.get("unresolved_critical", 0)
sat_trend = data.get("satisfaction_trend", "stable").lower()
esc_risk = clamp(escalations * 35.0) # 3 escalations => 100
critical_risk = clamp(critical_unresolved * 50.0) # 2 unresolved critical => 100
sat_risk = SATISFACTION_TREND_SCORES.get(sat_trend, 30.0)
score = round(esc_risk * 0.35 + critical_risk * 0.35 + sat_risk * 0.30, 1)
if critical_unresolved >= 2:
warnings.append({"severity": "critical", "signal": f"{critical_unresolved} unresolved critical support tickets"})
elif critical_unresolved >= 1:
warnings.append({"severity": "high", "signal": "Unresolved critical support ticket"})
if escalations >= 2:
warnings.append({"severity": "high", "signal": f"{escalations} open escalations"})
elif escalations >= 1:
warnings.append({"severity": "medium", "signal": "Open support escalation"})
if sat_trend == "critical":
warnings.append({"severity": "critical", "signal": "Support satisfaction at critical levels"})
elif sat_trend == "declining":
warnings.append({"severity": "high", "signal": "Support satisfaction trending down"})
return score, warnings
def score_relationship_signals(data: Dict[str, Any]) -> Tuple[float, List[Dict[str, str]]]:
"""Score relationship risk signals (0-100, higher = more risk)."""
warnings: List[Dict[str, str]] = []
risk_points = 0.0
champion_left = data.get("champion_left", False)
sponsor_change = data.get("sponsor_change", False)
competitor_mentions = data.get("competitor_mentions", 0)
if champion_left:
risk_points += 45.0
warnings.append({"severity": "critical", "signal": "Internal champion has left the organisation"})
if sponsor_change:
risk_points += 30.0
warnings.append({"severity": "high", "signal": "Executive sponsor change detected"})
if competitor_mentions >= 3:
risk_points += 35.0
warnings.append({"severity": "critical", "signal": f"Customer mentioned competitors {competitor_mentions} times"})
elif competitor_mentions >= 1:
risk_points += competitor_mentions * 12.0
warnings.append({"severity": "medium", "signal": f"Customer mentioned competitor {competitor_mentions} time(s)"})
score = clamp(risk_points)
return round(score, 1), warnings
def score_commercial_factors(data: Dict[str, Any]) -> Tuple[float, List[Dict[str, str]]]:
"""Score commercial risk factors (0-100, higher = more risk)."""
warnings: List[Dict[str, str]] = []
risk_points = 0.0
contract_type = data.get("contract_type", "annual").lower()
pricing_complaints = data.get("pricing_complaints", False)
budget_cuts = data.get("budget_cuts_mentioned", False)
if contract_type == "month-to-month":
risk_points += 30.0
warnings.append({"severity": "medium", "signal": "Month-to-month contract -- low switching cost"})
elif contract_type == "quarterly":
risk_points += 15.0
if pricing_complaints:
risk_points += 35.0
warnings.append({"severity": "high", "signal": "Customer has raised pricing complaints"})
if budget_cuts:
risk_points += 40.0
warnings.append({"severity": "high", "signal": "Customer mentioned budget cuts or cost reduction"})
score = clamp(risk_points)
return round(score, 1), warnings
# ---------------------------------------------------------------------------
# Main Analysis
# ---------------------------------------------------------------------------
def analyse_churn_risk(customer: Dict[str, Any]) -> Dict[str, Any]:
"""Analyse churn risk for a single customer."""
usage_score, usage_warnings = score_usage_decline(customer.get("usage_decline", {}))
engagement_score, engagement_warnings = score_engagement_drop(customer.get("engagement_drop", {}))
support_score, support_warnings = score_support_issues(customer.get("support_issues", {}))
relationship_score, relationship_warnings = score_relationship_signals(customer.get("relationship_signals", {}))
commercial_score, commercial_warnings = score_commercial_factors(customer.get("commercial_factors", {}))
# Weighted raw score
raw_score = (
usage_score * RISK_SIGNAL_WEIGHTS["usage_decline"]
+ engagement_score * RISK_SIGNAL_WEIGHTS["engagement_drop"]
+ support_score * RISK_SIGNAL_WEIGHTS["support_issues"]
+ relationship_score * RISK_SIGNAL_WEIGHTS["relationship_signals"]
+ commercial_score * RISK_SIGNAL_WEIGHTS["commercial_factors"]
)
# Apply renewal urgency multiplier
remaining = days_until(customer.get("contract_end_date"))
multiplier = renewal_urgency_multiplier(remaining)
adjusted_score = clamp(round(raw_score * multiplier, 1))
tier = get_risk_tier(adjusted_score)
# Collect and sort warnings by severity
all_warnings = usage_warnings + engagement_warnings + support_warnings + relationship_warnings + commercial_warnings
all_warnings.sort(key=lambda w: WARNING_SEVERITY.get(w["severity"], 0), reverse=True)
playbook = INTERVENTION_PLAYBOOKS.get(tier["name"], [])
return {
"customer_id": customer.get("customer_id", "unknown"),
"name": customer.get("name", "Unknown"),
"segment": customer.get("segment", "unknown"),
"arr": customer.get("arr", 0),
"risk_score": adjusted_score,
"raw_score": round(raw_score, 1),
"risk_tier": tier["name"],
"risk_label": tier["label"],
"urgency_multiplier": multiplier,
"days_to_renewal": remaining,
"signal_scores": {
"usage_decline": {"score": usage_score, "weight": "30%"},
"engagement_drop": {"score": engagement_score, "weight": "25%"},
"support_issues": {"score": support_score, "weight": "20%"},
"relationship_signals": {"score": relationship_score, "weight": "15%"},
"commercial_factors": {"score": commercial_score, "weight": "10%"},
},
"warning_signals": all_warnings,
"recommended_actions": playbook,
}
# ---------------------------------------------------------------------------
# Output Formatting
# ---------------------------------------------------------------------------
def format_text(results: List[Dict[str, Any]]) -> str:
"""Format results as human-readable text."""
lines: List[str] = []
lines.append("=" * 72)
lines.append("CHURN RISK ANALYSIS REPORT")
lines.append("=" * 72)
lines.append("")
total = len(results)
critical_count = sum(1 for r in results if r["risk_tier"] == "critical")
high_count = sum(1 for r in results if r["risk_tier"] == "high")
medium_count = sum(1 for r in results if r["risk_tier"] == "medium")
low_count = sum(1 for r in results if r["risk_tier"] == "low")
total_arr_at_risk = sum(r["arr"] for r in results if r["risk_tier"] in ("critical", "high"))
lines.append(f"Portfolio Summary: {total} customers analysed")
lines.append(f" Critical Risk: {critical_count}")
lines.append(f" High Risk: {high_count}")
lines.append(f" Medium Risk: {medium_count}")
lines.append(f" Low Risk: {low_count}")
lines.append(f" ARR at Risk (Critical + High): ,.0f")
lines.append("")
# Sort by risk score descending
sorted_results = sorted(results, key=lambda r: r["risk_score"], reverse=True)
for r in sorted_results:
lines.append("-" * 72)
lines.append(f"Customer: {r['name']} ({r['customer_id']})")
lines.append(f"Segment: {r['segment'].title()} | ARR: ,.0f")
renewal_str = f"{r['days_to_renewal']} days" if r["days_to_renewal"] is not None else "N/A"
lines.append(f"Risk Score: {r['risk_score']}/100 [{r['risk_label']}] | Renewal: {renewal_str}")
if r["urgency_multiplier"] > 1.0:
lines.append(f" ** Urgency multiplier applied: {r['urgency_multiplier']}x (renewal approaching)")
lines.append("")
lines.append(" Signal Scores:")
for signal_name, signal_data in r["signal_scores"].items():
display_name = signal_name.replace("_", " ").title()
lines.append(f" {display_name:25s} {signal_data['score']:6.1f}/100 ({signal_data['weight']})")
if r["warning_signals"]:
lines.append("")
lines.append(" Warning Signals:")
for w in r["warning_signals"]:
severity_tag = w["severity"].upper()
lines.append(f" [{severity_tag}] {w['signal']}")
if r["recommended_actions"]:
lines.append("")
lines.append(" Recommended Actions:")
for i, action in enumerate(r["recommended_actions"], 1):
lines.append(f" {i}. {action}")
lines.append("")
lines.append("=" * 72)
return "\n".join(lines)
def format_json(results: List[Dict[str, Any]]) -> str:
"""Format results as JSON."""
total = len(results)
output = {
"report": "churn_risk_analysis",
"summary": {
"total_customers": total,
"critical_count": sum(1 for r in results if r["risk_tier"] == "critical"),
"high_count": sum(1 for r in results if r["risk_tier"] == "high"),
"medium_count": sum(1 for r in results if r["risk_tier"] == "medium"),
"low_count": sum(1 for r in results if r["risk_tier"] == "low"),
"total_arr_at_risk": sum(r["arr"] for r in results if r["risk_tier"] in ("critical", "high")),
},
"customers": sorted(results, key=lambda r: r["risk_score"], reverse=True),
}
return json.dumps(output, indent=2)
# ---------------------------------------------------------------------------
# CLI
# ---------------------------------------------------------------------------
def main() -> None:
parser = argparse.ArgumentParser(
description="Analyse churn risk with behavioral signal detection and intervention recommendations."
)
parser.add_argument("input_file", help="Path to JSON file containing customer data")
parser.add_argument(
"--format",
choices=["text", "json"],
default="text",
dest="output_format",
help="Output format (default: text)",
)
args = parser.parse_args()
try:
with open(args.input_file, "r") as f:
data = json.load(f)
except FileNotFoundError:
print(f"Error: File not found: {args.input_file}", file=sys.stderr)
sys.exit(1)
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON in {args.input_file}: {e}", file=sys.stderr)
sys.exit(1)
customers = data.get("customers", [])
if not customers:
print("Error: No customer records found in input file.", file=sys.stderr)
sys.exit(1)
results = [analyse_churn_risk(c) for c in customers]
if args.output_format == "json":
print(format_json(results))
else:
print(format_text(results))
if __name__ == "__main__":
main()
FILE:scripts/expansion_opportunity_scorer.py
#!/usr/bin/env python3
"""
Expansion Opportunity Scorer
Analyses customer product adoption depth, maps whitespace for unused
features/products, estimates revenue opportunities, and prioritises
expansion plays by effort vs impact.
Usage:
python expansion_opportunity_scorer.py customer_data.json
python expansion_opportunity_scorer.py customer_data.json --format json
"""
import argparse
import json
import sys
from typing import Any, Dict, List, Optional, Tuple
# ---------------------------------------------------------------------------
# Constants
# ---------------------------------------------------------------------------
# Tier pricing multipliers (relative to current plan price)
TIER_UPLIFT: Dict[str, float] = {
"starter": 1.0,
"professional": 1.8,
"enterprise": 3.0,
"enterprise_plus": 4.5,
}
# Module revenue estimates as a fraction of base ARR
MODULE_REVENUE_FRACTION: Dict[str, float] = {
"core_platform": 0.00, # Already included in base
"analytics_module": 0.15,
"integrations_module": 0.12,
"api_access": 0.10,
"advanced_reporting": 0.18,
"security_module": 0.20,
"automation_module": 0.15,
"collaboration_module": 0.10,
"data_export": 0.08,
"custom_workflows": 0.22,
"sso_module": 0.08,
"audit_module": 0.10,
}
# Effort classification for different expansion types
EFFORT_MAP: Dict[str, str] = {
"upsell_tier": "medium",
"cross_sell_module": "low",
"seat_expansion": "low",
"department_expansion": "high",
}
# Usage thresholds for recommendations
HIGH_USAGE_THRESHOLD = 75 # % usage indicates readiness for more
LOW_ADOPTION_THRESHOLD = 30 # % usage is too low to push expansion there
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def safe_divide(numerator: float, denominator: float, default: float = 0.0) -> float:
"""Return numerator / denominator, or *default* when denominator is zero."""
if denominator == 0:
return default
return numerator / denominator
def clamp(value: float, lo: float = 0.0, hi: float = 100.0) -> float:
"""Clamp *value* between *lo* and *hi*."""
return max(lo, min(hi, value))
def estimate_seat_expansion_revenue(
arr: float, licensed: int, active: int, segment: str
) -> Tuple[float, str]:
"""Estimate revenue from seat expansion.
Returns (estimated_revenue, rationale).
"""
utilisation = safe_divide(active, licensed)
if utilisation >= 0.90:
# Near capacity -- likely needs more seats
growth_factor = {"enterprise": 0.25, "mid-market": 0.20, "smb": 0.15}
factor = growth_factor.get(segment.lower(), 0.15)
revenue = round(arr * factor, 0)
return revenue, f"Seat utilisation at {utilisation:.0%} -- likely needs {int(licensed * factor)} additional seats"
return 0.0, f"Seat utilisation at {utilisation:.0%} -- not yet at expansion threshold"
def estimate_tier_upgrade_revenue(
arr: float, current_tier: str, available_tiers: List[str]
) -> Tuple[float, Optional[str], str]:
"""Estimate revenue from tier upgrade.
Returns (estimated_revenue, target_tier, rationale).
"""
current_mult = TIER_UPLIFT.get(current_tier.lower(), 1.0)
best_revenue = 0.0
best_tier = None
rationale = "Already on highest tier"
for tier in available_tiers:
tier_mult = TIER_UPLIFT.get(tier.lower(), 1.0)
if tier_mult > current_mult:
# Calculate revenue as the incremental ARR from upgrading
base_arr = safe_divide(arr, current_mult)
upgrade_arr = base_arr * tier_mult
incremental = upgrade_arr - arr
if incremental > best_revenue:
# Pick the next tier up (not skip tiers)
if best_tier is None or tier_mult < TIER_UPLIFT.get(best_tier.lower(), 999):
best_revenue = round(incremental, 0)
best_tier = tier
rationale = f"Upgrade from {current_tier} to {tier} adds ,.0f ARR"
return best_revenue, best_tier, rationale
def estimate_module_revenue(
arr: float, product_usage: Dict[str, Dict[str, Any]]
) -> List[Dict[str, Any]]:
"""Identify cross-sell opportunities from unadopted modules.
Returns list of opportunity dicts.
"""
opportunities: List[Dict[str, Any]] = []
for module_name, module_data in product_usage.items():
adopted = module_data.get("adopted", False)
usage_pct = module_data.get("usage_pct", 0)
fraction = MODULE_REVENUE_FRACTION.get(module_name.lower(), 0.10)
if not adopted and fraction > 0:
revenue = round(arr * fraction, 0)
opportunities.append({
"module": module_name,
"type": "cross_sell",
"estimated_revenue": revenue,
"effort": "low",
"rationale": f"Module not adopted -- ,.0f potential ARR",
})
elif adopted and usage_pct < LOW_ADOPTION_THRESHOLD and fraction > 0:
# Already adopted but underutilised -- focus on enablement, not expansion
pass # Skip -- needs enablement, not a sales motion
return opportunities
def estimate_department_expansion_revenue(
arr: float,
current_departments: List[str],
potential_departments: List[str],
segment: str,
) -> List[Dict[str, Any]]:
"""Estimate revenue from expanding to new departments."""
opportunities: List[Dict[str, Any]] = []
current_set = {d.lower() for d in current_departments}
per_dept_estimate = safe_divide(arr, max(len(current_departments), 1))
for dept in potential_departments:
if dept.lower() not in current_set:
# Estimate each new department at the average per-department ARR
revenue = round(per_dept_estimate * 0.8, 0) # Slight discount for new dept
opportunities.append({
"department": dept,
"type": "expansion",
"estimated_revenue": revenue,
"effort": "high",
"rationale": f"Expand to {dept} department -- est. ,.0f ARR",
})
return opportunities
# ---------------------------------------------------------------------------
# Priority Scoring
# ---------------------------------------------------------------------------
def priority_score(revenue: float, effort: str) -> float:
"""Calculate priority score (higher = better).
Favours high revenue with low effort.
"""
effort_multiplier = {"low": 3.0, "medium": 2.0, "high": 1.0}
mult = effort_multiplier.get(effort.lower(), 1.0)
# Normalise revenue to a 0-100 scale (assume max single opportunity is $200k)
rev_score = clamp(safe_divide(revenue, 2000.0)) # $200k => 100
return round(rev_score * mult, 1)
# ---------------------------------------------------------------------------
# Main Analysis
# ---------------------------------------------------------------------------
def analyse_expansion(customer: Dict[str, Any]) -> Dict[str, Any]:
"""Analyse expansion opportunities for a single customer."""
arr = customer.get("arr", 0)
segment = customer.get("segment", "mid-market").lower()
contract = customer.get("contract", {})
product_usage = customer.get("product_usage", {})
departments = customer.get("departments", {})
all_opportunities: List[Dict[str, Any]] = []
# 1. Seat expansion
licensed = contract.get("licensed_seats", 0)
active = contract.get("active_seats", 0)
seat_rev, seat_rationale = estimate_seat_expansion_revenue(arr, licensed, active, segment)
if seat_rev > 0:
all_opportunities.append({
"type": "expansion",
"category": "seat_expansion",
"estimated_revenue": seat_rev,
"effort": "low",
"rationale": seat_rationale,
"priority_score": priority_score(seat_rev, "low"),
})
# 2. Tier upgrade
current_tier = contract.get("plan_tier", "").lower()
available_tiers = contract.get("available_tiers", [])
tier_rev, target_tier, tier_rationale = estimate_tier_upgrade_revenue(arr, current_tier, available_tiers)
if tier_rev > 0 and target_tier:
all_opportunities.append({
"type": "upsell",
"category": "tier_upgrade",
"target_tier": target_tier,
"estimated_revenue": tier_rev,
"effort": "medium",
"rationale": tier_rationale,
"priority_score": priority_score(tier_rev, "medium"),
})
# 3. Module cross-sell
module_opps = estimate_module_revenue(arr, product_usage)
for opp in module_opps:
opp["category"] = "module_cross_sell"
opp["priority_score"] = priority_score(opp["estimated_revenue"], opp["effort"])
all_opportunities.append(opp)
# 4. Department expansion
current_depts = departments.get("current", [])
potential_depts = departments.get("potential", [])
dept_opps = estimate_department_expansion_revenue(arr, current_depts, potential_depts, segment)
for opp in dept_opps:
opp["category"] = "department_expansion"
opp["priority_score"] = priority_score(opp["estimated_revenue"], opp["effort"])
all_opportunities.append(opp)
# Sort by priority score descending
all_opportunities.sort(key=lambda o: o["priority_score"], reverse=True)
# Adoption depth summary
total_modules = len(product_usage)
adopted_modules = sum(1 for m in product_usage.values() if m.get("adopted", False))
avg_usage = round(
safe_divide(
sum(m.get("usage_pct", 0) for m in product_usage.values() if m.get("adopted", False)),
max(adopted_modules, 1),
),
1,
)
total_estimated_revenue = sum(o["estimated_revenue"] for o in all_opportunities)
return {
"customer_id": customer.get("customer_id", "unknown"),
"name": customer.get("name", "Unknown"),
"segment": segment,
"arr": arr,
"adoption_summary": {
"total_modules": total_modules,
"adopted_modules": adopted_modules,
"adoption_rate": round(safe_divide(adopted_modules, total_modules) * 100, 1) if total_modules > 0 else 0,
"avg_usage_pct": avg_usage,
"seat_utilisation": round(safe_divide(active, max(licensed, 1)) * 100, 1),
"current_tier": current_tier,
"departments_covered": len(current_depts),
"departments_potential": len(potential_depts),
},
"total_estimated_revenue": round(total_estimated_revenue, 0),
"opportunity_count": len(all_opportunities),
"opportunities": all_opportunities,
}
# ---------------------------------------------------------------------------
# Output Formatting
# ---------------------------------------------------------------------------
def format_text(results: List[Dict[str, Any]]) -> str:
"""Format results as human-readable text."""
lines: List[str] = []
lines.append("=" * 72)
lines.append("EXPANSION OPPORTUNITY REPORT")
lines.append("=" * 72)
lines.append("")
total_rev = sum(r["total_estimated_revenue"] for r in results)
total_opps = sum(r["opportunity_count"] for r in results)
lines.append(f"Portfolio Summary: {len(results)} customers")
lines.append(f" Total Expansion Revenue Potential: ,.0f")
lines.append(f" Total Opportunities Identified: {total_opps}")
lines.append("")
# Sort customers by total estimated revenue descending
sorted_results = sorted(results, key=lambda r: r["total_estimated_revenue"], reverse=True)
for r in sorted_results:
lines.append("-" * 72)
lines.append(f"Customer: {r['name']} ({r['customer_id']})")
lines.append(f"Segment: {r['segment'].title()} | Current ARR: ,.0f")
lines.append(f"Total Expansion Potential: ,.0f ({r['opportunity_count']} opportunities)")
lines.append("")
adoption = r["adoption_summary"]
lines.append(" Adoption Summary:")
lines.append(f" Modules Adopted: {adoption['adopted_modules']}/{adoption['total_modules']} ({adoption['adoption_rate']}%)")
lines.append(f" Avg Module Usage: {adoption['avg_usage_pct']}%")
lines.append(f" Seat Utilisation: {adoption['seat_utilisation']}%")
lines.append(f" Current Tier: {adoption['current_tier'].title()}")
lines.append(f" Departments: {adoption['departments_covered']} active, {adoption['departments_potential']} potential")
if r["opportunities"]:
lines.append("")
lines.append(" Opportunities (ranked by priority):")
for i, opp in enumerate(r["opportunities"], 1):
opp_type = opp.get("type", "unknown").title()
category = opp.get("category", "").replace("_", " ").title()
rev = opp["estimated_revenue"]
effort = opp.get("effort", "unknown").title()
pri = opp.get("priority_score", 0)
lines.append(f" {i}. [{opp_type}] {category}")
lines.append(f" Revenue: ,.0f | Effort: {effort} | Priority: {pri}")
lines.append(f" {opp.get('rationale', '')}")
else:
lines.append("")
lines.append(" No expansion opportunities identified at this time.")
lines.append("")
lines.append("=" * 72)
return "\n".join(lines)
def format_json(results: List[Dict[str, Any]]) -> str:
"""Format results as JSON."""
total_rev = sum(r["total_estimated_revenue"] for r in results)
total_opps = sum(r["opportunity_count"] for r in results)
output = {
"report": "expansion_opportunities",
"summary": {
"total_customers": len(results),
"total_estimated_revenue": total_rev,
"total_opportunities": total_opps,
},
"customers": sorted(results, key=lambda r: r["total_estimated_revenue"], reverse=True),
}
return json.dumps(output, indent=2)
# ---------------------------------------------------------------------------
# CLI
# ---------------------------------------------------------------------------
def main() -> None:
parser = argparse.ArgumentParser(
description="Score expansion opportunities with adoption analysis and revenue estimation."
)
parser.add_argument("input_file", help="Path to JSON file containing customer data")
parser.add_argument(
"--format",
choices=["text", "json"],
default="text",
dest="output_format",
help="Output format (default: text)",
)
args = parser.parse_args()
try:
with open(args.input_file, "r") as f:
data = json.load(f)
except FileNotFoundError:
print(f"Error: File not found: {args.input_file}", file=sys.stderr)
sys.exit(1)
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON in {args.input_file}: {e}", file=sys.stderr)
sys.exit(1)
customers = data.get("customers", [])
if not customers:
print("Error: No customer records found in input file.", file=sys.stderr)
sys.exit(1)
results = [analyse_expansion(c) for c in customers]
if args.output_format == "json":
print(format_json(results))
else:
print(format_text(results))
if __name__ == "__main__":
main()
FILE:scripts/health_score_calculator.py
#!/usr/bin/env python3
"""
Customer Health Score Calculator
Multi-dimensional weighted health scoring across usage, engagement, support,
and relationship dimensions. Produces Red/Yellow/Green classification with
trend analysis and segment-aware benchmarking.
Usage:
python health_score_calculator.py customer_data.json
python health_score_calculator.py customer_data.json --format json
"""
import argparse
import json
import sys
from typing import Any, Dict, List, Optional, Tuple
# ---------------------------------------------------------------------------
# Constants
# ---------------------------------------------------------------------------
DIMENSION_WEIGHTS: Dict[str, float] = {
"usage": 0.30,
"engagement": 0.25,
"support": 0.20,
"relationship": 0.25,
}
# Segment-specific thresholds (green_min, yellow_min)
SEGMENT_THRESHOLDS: Dict[str, Dict[str, Tuple[int, int]]] = {
"enterprise": {"green": (75, 100), "yellow": (50, 74), "red": (0, 49)},
"mid-market": {"green": (70, 100), "yellow": (45, 69), "red": (0, 44)},
"smb": {"green": (65, 100), "yellow": (40, 64), "red": (0, 39)},
}
# Benchmarks per segment for normalising raw metrics
SEGMENT_BENCHMARKS: Dict[str, Dict[str, Any]] = {
"enterprise": {
"login_frequency_target": 90,
"feature_adoption_target": 80,
"dau_mau_target": 0.50,
"support_ticket_volume_max": 5,
"meeting_attendance_target": 95,
"nps_target": 9,
"csat_target": 4.5,
"open_tickets_max": 10,
"escalation_rate_max": 0.25,
"avg_resolution_hours_max": 72,
"exec_sponsor_target": 90,
"multi_threading_target": 5,
},
"mid-market": {
"login_frequency_target": 80,
"feature_adoption_target": 70,
"dau_mau_target": 0.40,
"support_ticket_volume_max": 8,
"meeting_attendance_target": 85,
"nps_target": 8,
"csat_target": 4.0,
"open_tickets_max": 15,
"escalation_rate_max": 0.30,
"avg_resolution_hours_max": 96,
"exec_sponsor_target": 75,
"multi_threading_target": 3,
},
"smb": {
"login_frequency_target": 70,
"feature_adoption_target": 60,
"dau_mau_target": 0.30,
"support_ticket_volume_max": 10,
"meeting_attendance_target": 75,
"nps_target": 7,
"csat_target": 3.8,
"open_tickets_max": 20,
"escalation_rate_max": 0.40,
"avg_resolution_hours_max": 120,
"exec_sponsor_target": 60,
"multi_threading_target": 2,
},
}
RENEWAL_SENTIMENT_SCORES: Dict[str, float] = {
"positive": 100.0,
"neutral": 60.0,
"negative": 20.0,
"unknown": 50.0,
}
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def safe_divide(numerator: float, denominator: float, default: float = 0.0) -> float:
"""Return numerator / denominator, or *default* when denominator is zero."""
if denominator == 0:
return default
return numerator / denominator
def clamp(value: float, lo: float = 0.0, hi: float = 100.0) -> float:
"""Clamp *value* between *lo* and *hi*."""
return max(lo, min(hi, value))
def get_benchmarks(segment: str) -> Dict[str, Any]:
"""Return benchmarks for the given segment, falling back to mid-market."""
return SEGMENT_BENCHMARKS.get(segment.lower(), SEGMENT_BENCHMARKS["mid-market"])
def get_thresholds(segment: str) -> Dict[str, Tuple[int, int]]:
"""Return classification thresholds for the given segment."""
return SEGMENT_THRESHOLDS.get(segment.lower(), SEGMENT_THRESHOLDS["mid-market"])
def classify(score: float, segment: str) -> str:
"""Return 'green', 'yellow', or 'red' classification."""
thresholds = get_thresholds(segment)
if score >= thresholds["green"][0]:
return "green"
elif score >= thresholds["yellow"][0]:
return "yellow"
return "red"
def trend_direction(current: float, previous: Optional[float]) -> str:
"""Return trend direction string."""
if previous is None:
return "no_data"
diff = current - previous
if diff > 5:
return "improving"
elif diff < -5:
return "declining"
return "stable"
# ---------------------------------------------------------------------------
# Dimension Scoring
# ---------------------------------------------------------------------------
def score_usage(data: Dict[str, Any], benchmarks: Dict[str, Any]) -> Tuple[float, List[str]]:
"""Score the usage dimension (0-100).
Metrics: login_frequency, feature_adoption, dau_mau_ratio.
"""
recommendations: List[str] = []
login = clamp(safe_divide(data.get("login_frequency", 0), benchmarks["login_frequency_target"]) * 100)
adoption = clamp(safe_divide(data.get("feature_adoption", 0), benchmarks["feature_adoption_target"]) * 100)
dau_mau = clamp(safe_divide(data.get("dau_mau_ratio", 0), benchmarks["dau_mau_target"]) * 100)
score = round(login * 0.35 + adoption * 0.40 + dau_mau * 0.25, 1)
if login < 60:
recommendations.append("Login frequency below target -- schedule product engagement session")
if adoption < 50:
recommendations.append("Feature adoption is low -- recommend guided feature walkthrough")
if dau_mau < 50:
recommendations.append("DAU/MAU ratio indicates shallow usage -- investigate stickiness barriers")
return score, recommendations
def score_engagement(data: Dict[str, Any], benchmarks: Dict[str, Any]) -> Tuple[float, List[str]]:
"""Score the engagement dimension (0-100).
Metrics: support_ticket_volume (inverse), meeting_attendance, nps_score, csat_score.
"""
recommendations: List[str] = []
# Lower ticket volume is better -- invert
ticket_vol = data.get("support_ticket_volume", 0)
ticket_score = clamp((1.0 - safe_divide(ticket_vol, benchmarks["support_ticket_volume_max"])) * 100)
attendance = clamp(safe_divide(data.get("meeting_attendance", 0), benchmarks["meeting_attendance_target"]) * 100)
nps_raw = data.get("nps_score", 5)
nps_score = clamp(safe_divide(nps_raw, benchmarks["nps_target"]) * 100)
csat_raw = data.get("csat_score", 3.0)
csat_score = clamp(safe_divide(csat_raw, benchmarks["csat_target"]) * 100)
score = round(ticket_score * 0.20 + attendance * 0.30 + nps_score * 0.25 + csat_score * 0.25, 1)
if attendance < 60:
recommendations.append("Meeting attendance is low -- re-evaluate meeting cadence and agenda value")
if nps_raw < 7:
recommendations.append("NPS below threshold -- conduct a feedback deep-dive with customer")
if csat_raw < 3.5:
recommendations.append("CSAT is critically low -- escalate to support leadership")
return score, recommendations
def score_support(data: Dict[str, Any], benchmarks: Dict[str, Any]) -> Tuple[float, List[str]]:
"""Score the support dimension (0-100).
Metrics: open_tickets (inverse), escalation_rate (inverse), avg_resolution_hours (inverse).
"""
recommendations: List[str] = []
open_tix = data.get("open_tickets", 0)
open_score = clamp((1.0 - safe_divide(open_tix, benchmarks["open_tickets_max"])) * 100)
esc_rate = data.get("escalation_rate", 0)
esc_score = clamp((1.0 - safe_divide(esc_rate, benchmarks["escalation_rate_max"])) * 100)
res_hours = data.get("avg_resolution_hours", 0)
res_score = clamp((1.0 - safe_divide(res_hours, benchmarks["avg_resolution_hours_max"])) * 100)
score = round(open_score * 0.35 + esc_score * 0.35 + res_score * 0.30, 1)
if open_tix > benchmarks["open_tickets_max"] * 0.5:
recommendations.append("Open ticket count elevated -- prioritise ticket resolution")
if esc_rate > benchmarks["escalation_rate_max"] * 0.5:
recommendations.append("Escalation rate too high -- review support process and training")
if res_hours > benchmarks["avg_resolution_hours_max"] * 0.5:
recommendations.append("Resolution time exceeds SLA target -- engage support leadership")
return score, recommendations
def score_relationship(data: Dict[str, Any], benchmarks: Dict[str, Any]) -> Tuple[float, List[str]]:
"""Score the relationship dimension (0-100).
Metrics: executive_sponsor_engagement, multi_threading_depth, renewal_sentiment.
"""
recommendations: List[str] = []
exec_score = clamp(safe_divide(data.get("executive_sponsor_engagement", 0), benchmarks["exec_sponsor_target"]) * 100)
threading = data.get("multi_threading_depth", 1)
thread_score = clamp(safe_divide(threading, benchmarks["multi_threading_target"]) * 100)
sentiment_str = data.get("renewal_sentiment", "unknown").lower()
sentiment_score = RENEWAL_SENTIMENT_SCORES.get(sentiment_str, 50.0)
score = round(exec_score * 0.35 + thread_score * 0.30 + sentiment_score * 0.35, 1)
if exec_score < 50:
recommendations.append("Executive sponsor engagement is weak -- schedule executive alignment meeting")
if threading < 2:
recommendations.append("Single-threaded relationship -- expand contacts across departments")
if sentiment_str == "negative":
recommendations.append("Renewal sentiment is negative -- initiate save plan immediately")
return score, recommendations
# ---------------------------------------------------------------------------
# Main Scoring
# ---------------------------------------------------------------------------
def calculate_health_score(customer: Dict[str, Any]) -> Dict[str, Any]:
"""Calculate the overall health score for a single customer."""
segment = customer.get("segment", "mid-market").lower()
benchmarks = get_benchmarks(segment)
# Score each dimension
usage_score, usage_recs = score_usage(customer.get("usage", {}), benchmarks)
engagement_score, engagement_recs = score_engagement(customer.get("engagement", {}), benchmarks)
support_score, support_recs = score_support(customer.get("support", {}), benchmarks)
relationship_score, relationship_recs = score_relationship(customer.get("relationship", {}), benchmarks)
# Weighted overall
overall = round(
usage_score * DIMENSION_WEIGHTS["usage"]
+ engagement_score * DIMENSION_WEIGHTS["engagement"]
+ support_score * DIMENSION_WEIGHTS["support"]
+ relationship_score * DIMENSION_WEIGHTS["relationship"],
1,
)
classification = classify(overall, segment)
# Trend analysis
prev = customer.get("previous_period", {})
trends = {
"usage": trend_direction(usage_score, prev.get("usage_score")),
"engagement": trend_direction(engagement_score, prev.get("engagement_score")),
"support": trend_direction(support_score, prev.get("support_score")),
"relationship": trend_direction(relationship_score, prev.get("relationship_score")),
}
overall_prev = prev.get("overall_score")
trends["overall"] = trend_direction(overall, overall_prev)
# Combine recommendations
all_recs = usage_recs + engagement_recs + support_recs + relationship_recs
return {
"customer_id": customer.get("customer_id", "unknown"),
"name": customer.get("name", "Unknown"),
"segment": segment,
"arr": customer.get("arr", 0),
"overall_score": overall,
"classification": classification,
"dimensions": {
"usage": {"score": usage_score, "weight": "30%", "classification": classify(usage_score, segment)},
"engagement": {"score": engagement_score, "weight": "25%", "classification": classify(engagement_score, segment)},
"support": {"score": support_score, "weight": "20%", "classification": classify(support_score, segment)},
"relationship": {"score": relationship_score, "weight": "25%", "classification": classify(relationship_score, segment)},
},
"trends": trends,
"recommendations": all_recs,
}
# ---------------------------------------------------------------------------
# Output Formatting
# ---------------------------------------------------------------------------
CLASSIFICATION_LABELS = {
"green": "HEALTHY",
"yellow": "NEEDS ATTENTION",
"red": "AT RISK",
}
def format_text(results: List[Dict[str, Any]]) -> str:
"""Format results as human-readable text."""
lines: List[str] = []
lines.append("=" * 72)
lines.append("CUSTOMER HEALTH SCORE REPORT")
lines.append("=" * 72)
lines.append("")
# Portfolio summary
total = len(results)
green_count = sum(1 for r in results if r["classification"] == "green")
yellow_count = sum(1 for r in results if r["classification"] == "yellow")
red_count = sum(1 for r in results if r["classification"] == "red")
avg_score = round(safe_divide(sum(r["overall_score"] for r in results), total), 1)
lines.append(f"Portfolio Summary: {total} customers")
lines.append(f" Average Health Score: {avg_score}/100")
lines.append(f" Green (Healthy): {green_count}")
lines.append(f" Yellow (Attention): {yellow_count}")
lines.append(f" Red (At Risk): {red_count}")
lines.append("")
for r in results:
label = CLASSIFICATION_LABELS.get(r["classification"], "UNKNOWN")
lines.append("-" * 72)
lines.append(f"Customer: {r['name']} ({r['customer_id']})")
lines.append(f"Segment: {r['segment'].title()} | ARR: ,.0f")
lines.append(f"Overall Score: {r['overall_score']}/100 [{label}]")
lines.append("")
lines.append(" Dimension Scores:")
for dim_name, dim_data in r["dimensions"].items():
dim_label = CLASSIFICATION_LABELS.get(dim_data["classification"], "")
lines.append(f" {dim_name.title():15s} {dim_data['score']:6.1f}/100 ({dim_data['weight']}) [{dim_label}]")
lines.append("")
lines.append(" Trends:")
for dim_name, direction in r["trends"].items():
arrow = {"improving": "+", "declining": "-", "stable": "=", "no_data": "?"}
lines.append(f" {dim_name.title():15s} {arrow.get(direction, '?')} {direction}")
if r["recommendations"]:
lines.append("")
lines.append(" Recommendations:")
for i, rec in enumerate(r["recommendations"], 1):
lines.append(f" {i}. {rec}")
lines.append("")
lines.append("=" * 72)
return "\n".join(lines)
def format_json(results: List[Dict[str, Any]]) -> str:
"""Format results as JSON."""
total = len(results)
output = {
"report": "customer_health_scores",
"summary": {
"total_customers": total,
"average_score": round(safe_divide(sum(r["overall_score"] for r in results), total), 1),
"green_count": sum(1 for r in results if r["classification"] == "green"),
"yellow_count": sum(1 for r in results if r["classification"] == "yellow"),
"red_count": sum(1 for r in results if r["classification"] == "red"),
},
"customers": results,
}
return json.dumps(output, indent=2)
# ---------------------------------------------------------------------------
# CLI
# ---------------------------------------------------------------------------
def main() -> None:
parser = argparse.ArgumentParser(
description="Calculate multi-dimensional customer health scores with trend analysis."
)
parser.add_argument("input_file", help="Path to JSON file containing customer data")
parser.add_argument(
"--format",
choices=["text", "json"],
default="text",
dest="output_format",
help="Output format (default: text)",
)
args = parser.parse_args()
try:
with open(args.input_file, "r") as f:
data = json.load(f)
except FileNotFoundError:
print(f"Error: File not found: {args.input_file}", file=sys.stderr)
sys.exit(1)
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON in {args.input_file}: {e}", file=sys.stderr)
sys.exit(1)
customers = data.get("customers", [])
if not customers:
print("Error: No customer records found in input file.", file=sys.stderr)
sys.exit(1)
results = [calculate_health_score(c) for c in customers]
if args.output_format == "json":
print(format_json(results))
else:
print(format_text(results))
if __name__ == "__main__":
main()
Khởi tạo vault LLM Wiki mới với cấu trúc ba lớp, file schema và mẫu khởi đầu.
---
name: wiki-init
description: Bootstrap a fresh LLM Wiki vault with the three-layer structure, schema files, and starter templates. Usage /wiki-init <path> --topic "<topic>" [--tool all|claude-code|codex|cursor|antigravity]
---
# /wiki-init
Bootstrap a new LLM Wiki vault. Creates `raw/`, `wiki/{entities,concepts,sources,comparisons,synthesis}`, the index and log, and installs the schema file(s) for your LLM CLI of choice.
## Usage
```
/wiki-init <path> --topic "<one-line topic>"
/wiki-init <path> --topic "<topic>" --tool <claude-code|codex|cursor|antigravity|opencode|gemini-cli|all>
/wiki-init <path> --topic "<topic>" --force # overwrite non-empty dir
```
## Examples
```
/wiki-init ~/vaults/research --topic "LLM interpretability"
/wiki-init ./book-wiki --topic "The Power Broker — Robert Caro" --tool all
/wiki-init ~/vaults/founders --topic "SaaS founder playbook" --tool codex
```
## What it creates
```
<path>/
├── raw/
│ └── assets/
├── wiki/
│ ├── index.md # from template
│ ├── log.md # from template
│ ├── entities/
│ ├── concepts/
│ ├── sources/
│ ├── comparisons/
│ ├── synthesis/
│ └── .templates/ # page templates for reference
├── CLAUDE.md # if --tool claude-code or all
├── AGENTS.md # if --tool codex|cursor|antigravity|opencode|gemini-cli|all
├── .cursorrules # if --tool cursor or all
└── .gitignore
```
## Next steps
After init:
1. Open the vault in Obsidian
2. Drop a source into `raw/`
3. Run `/wiki-ingest raw/<your-file>`
## Script
- `engineering/llm-wiki/scripts/init_vault.py`
## Skill Reference
→ `engineering/llm-wiki/SKILL.md`
Hướng dẫn lãnh đạo kỹ thuật: đánh giá nợ kỹ thuật, mở rộng đội ngũ, chọn công nghệ, quyết định kiến trúc và thiết lập chỉ số kỹ thuật.
---
name: "cto-advisor"
description: "Technical leadership guidance for engineering teams, architecture decisions, and technology strategy. Use when assessing technical debt, scaling engineering teams, evaluating technologies, making architecture decisions, establishing engineering metrics, or when user mentions CTO, tech debt, technical debt, team scaling, architecture decisions, technology evaluation, engineering metrics, DORA metrics, or technology strategy."
license: MIT
metadata:
version: 2.0.0
author: Alireza Rezvani
category: c-level
domain: cto-leadership
updated: 2026-03-05
python-tools: tech_debt_analyzer.py, team_scaling_calculator.py
frameworks: architecture-decisions, engineering-metrics, technology-evaluation
---
# CTO Advisor
Technical leadership frameworks for architecture, engineering teams, technology strategy, and technical decision-making.
## Keywords
CTO, chief technology officer, tech debt, technical debt, architecture, engineering metrics, DORA, team scaling, technology evaluation, build vs buy, cloud migration, platform engineering, AI/ML strategy, system design, incident response, engineering culture
## Quick Start
```bash
python scripts/tech_debt_analyzer.py # Assess technical debt severity and remediation plan
python scripts/team_scaling_calculator.py # Model engineering team growth and cost
```
## Core Responsibilities
### 1. Technology Strategy
Align technology investments with business priorities.
**Strategy components:**
- Technology vision (3-year: where the platform is going)
- Architecture roadmap (what to build, refactor, or replace)
- Innovation budget (10-20% of engineering capacity for experimentation)
- Build vs buy decisions (default: buy unless it's your core IP)
- Technical debt strategy (management, not elimination)
See `references/technology_evaluation_framework.md` for the full evaluation framework.
### 2. Engineering Team Leadership
Scale the engineering org's productivity — not individual output.
**Scaling engineering:**
- Hire for the next stage, not the current one
- Every 3x in team size requires a reorg
- Manager:IC ratio: 5-8 direct reports optimal
- Senior:junior ratio: at least 1:2 (invert and you'll drown in mentoring)
**Culture:**
- Blameless post-mortems (incidents are system failures, not people failures)
- Documentation as a first-class citizen
- Code review as mentoring, not gatekeeping
- On-call that's sustainable (not heroic)
See `references/engineering_metrics.md` for DORA metrics and the engineering health dashboard.
### 3. Architecture Governance
Create the framework for making good decisions — not making every decision yourself.
**Architecture Decision Records (ADRs):**
- Every significant decision gets documented: context, options, decision, consequences
- Decisions are discoverable (not buried in Slack)
- Decisions can be superseded (not permanent)
See `references/architecture_decision_records.md` for ADR templates and the decision review process.
### 4. Vendor & Platform Management
Every vendor is a dependency. Every dependency is a risk.
**Evaluation criteria:** Does it solve a real problem? Can we migrate away? Is the vendor stable? What's the total cost (license + integration + maintenance)?
### 5. Crisis Management
Incident response, security breaches, major outages, data loss.
**Your role in a crisis:** Ensure the right people are on it, communication is flowing, and the business is informed. Post-crisis: blameless retrospective within 48 hours.
## Workflows
### Tech Debt Assessment Workflow
**Step 1 — Run the analyzer**
```bash
python scripts/tech_debt_analyzer.py --output report.json
```
**Step 2 — Interpret results**
The analyzer produces a severity-scored inventory. Review each item against:
- Severity (P0–P3): how much is it blocking velocity or creating risk?
- Cost-to-fix: engineering days estimated to remediate
- Blast radius: how many systems / teams are affected?
**Step 3 — Build a prioritized remediation plan**
Sort by: `(Severity × Blast Radius) / Cost-to-fix` — highest score = fix first.
Group items into: (a) immediate sprint, (b) next quarter, (c) tracked backlog.
**Step 4 — Validate before presenting to stakeholders**
- [ ] Every P0/P1 item has an owner and a target date
- [ ] Cost-to-fix estimates reviewed with the relevant tech lead
- [ ] Debt ratio calculated: maintenance work / total engineering capacity (target: < 25%)
- [ ] Remediation plan fits within capacity (don't promise 40 points of debt reduction in a 2-week sprint)
**Example output — Tech Debt Inventory:**
```
Item | Severity | Cost-to-Fix | Blast Radius | Priority Score
----------------------|----------|-------------|--------------|---------------
Auth service (v1 API) | P1 | 8 days | 6 services | HIGH
Unindexed DB queries | P2 | 3 days | 2 services | MEDIUM
Legacy deploy scripts | P3 | 5 days | 1 service | LOW
```
---
### ADR Creation Workflow
**Step 1 — Identify the decision**
Trigger an ADR when: the decision affects more than one team, is hard to reverse, or has cost/risk implications > 1 sprint of effort.
**Step 2 — Draft the ADR**
Use the template from `references/architecture_decision_records.md`:
```
Title: [Short noun phrase]
Status: Proposed | Accepted | Superseded
Context: What is the problem? What constraints exist?
Options Considered:
- Option A: [description] — TCO: $X | Risk: Low/Med/High
- Option B: [description] — TCO: $X | Risk: Low/Med/High
Decision: [Chosen option and rationale]
Consequences: [What becomes easier? What becomes harder?]
```
**Step 3 — Validation checkpoint (before finalizing)**
- [ ] All options include a 3-year TCO estimate
- [ ] At least one "do nothing" or "buy" alternative is documented
- [ ] Affected team leads have reviewed and signed off
- [ ] Consequences section addresses reversibility and migration path
- [ ] ADR is committed to the repository (not left in a doc or Slack thread)
**Step 4 — Communicate and close**
Share the accepted ADR in the engineering all-hands or architecture sync. Link it from the relevant service's README.
---
### Build vs Buy Analysis Workflow
**Step 1 — Define requirements** (functional + non-functional)
**Step 2 — Identify candidate vendors or internal build scope**
**Step 3 — Score each option:**
```
Criterion | Weight | Build Score | Vendor A Score | Vendor B Score
-----------------------|--------|-------------|----------------|---------------
Solves core problem | 30% | 9 | 8 | 7
Migration risk | 20% | 2 (low risk)| 7 | 6
3-year TCO | 25% | $X | $Y | $Z
Vendor stability | 15% | N/A | 8 | 5
Integration effort | 10% | 3 | 7 | 8
```
**Step 4 — Default rule:** Buy unless it is core IP or no vendor meets ≥ 70% of requirements.
**Step 5 — Document the decision as an ADR** (see ADR workflow above).
## Key Questions a CTO Asks
- "What's our biggest technical risk right now — not the most annoying, the most dangerous?"
- "If we 10x our traffic tomorrow, what breaks first?"
- "How much of our engineering time goes to maintenance vs new features?"
- "What would a new engineer say about our codebase after their first week?"
- "Which technical decision from 2 years ago is hurting us most today?"
- "Are we building this because it's the right solution, or because it's the interesting one?"
- "What's our bus factor on critical systems?"
## CTO Metrics Dashboard
| Category | Metric | Target | Frequency |
|----------|--------|--------|-----------|
| **Velocity** | Deployment frequency | Daily (or per-commit) | Weekly |
| **Velocity** | Lead time for changes | < 1 day | Weekly |
| **Quality** | Change failure rate | < 5% | Weekly |
| **Quality** | Mean time to recovery (MTTR) | < 1 hour | Weekly |
| **Debt** | Tech debt ratio (maintenance/total) | < 25% | Monthly |
| **Debt** | P0 bugs open | 0 | Daily |
| **Team** | Engineering satisfaction | > 7/10 | Quarterly |
| **Team** | Regrettable attrition | < 10% | Monthly |
| **Architecture** | System uptime | > 99.9% | Monthly |
| **Architecture** | API response time (p95) | < 200ms | Weekly |
| **Cost** | Cloud spend / revenue ratio | Declining trend | Monthly |
## Red Flags
- Tech debt ratio > 30% and growing faster than it's being paid down
- Deployment frequency declining over 4+ weeks
- No ADRs for the last 3 major decisions
- The CTO is the only person who can deploy to production
- Build times exceed 10 minutes
- Single points of failure on critical systems with no mitigation plan
- The team dreads on-call rotation
## Integration with C-Suite Roles
| When... | CTO works with... | To... |
|---------|-------------------|-------|
| Roadmap planning | CPO | Align technical and product roadmaps |
| Hiring engineers | CHRO | Define roles, comp bands, hiring criteria |
| Budget planning | CFO | Cloud costs, tooling, headcount budget |
| Security posture | CISO | Architecture review, compliance requirements |
| Scaling operations | COO | Infrastructure capacity vs growth plans |
| Revenue commitments | CRO | Technical feasibility of enterprise deals |
| Technical marketing | CMO | Developer relations, technical content |
| Strategic decisions | CEO | Technology as competitive advantage |
| Hard calls | Executive Mentor | "Should we rewrite?" "Should we switch stacks?" |
## Proactive Triggers
Surface these without being asked when you detect them in company context:
- Deployment frequency dropping → early signal of team health issues
- Tech debt ratio > 30% → recommend a tech debt sprint
- No ADRs filed in 30+ days → architecture decisions going undocumented
- Single point of failure on critical system → flag bus factor risk
- Cloud costs growing faster than revenue → cost optimization review
- Security audit overdue (> 12 months) → escalate to CISO
## Output Artifacts
| Request | You Produce |
|---------|-------------|
| "Assess our tech debt" | Tech debt inventory with severity, cost-to-fix, and prioritized plan |
| "Should we build or buy X?" | Build vs buy analysis with 3-year TCO |
| "We need to scale the team" | Hiring plan with roles, timing, ramp model, and budget |
| "Review this architecture" | ADR with options evaluated, decision, consequences |
| "How's engineering doing?" | Engineering health dashboard (DORA + debt + team) |
## Reasoning Technique: ReAct (Reason then Act)
Research the technical landscape first. Analyze options against constraints (time, team skill, cost, risk). Then recommend action. Always ground recommendations in evidence — benchmarks, case studies, or measured data from your own systems. "I think" is not enough — show the data.
## Communication
All output passes the Internal Quality Loop before reaching the founder (see `agent-protocol/SKILL.md`).
- Self-verify: source attribution, assumption audit, confidence scoring
- Peer-verify: cross-functional claims validated by the owning role
- Critic pre-screen: high-stakes decisions reviewed by Executive Mentor
- Output format: Bottom Line → What (with confidence) → Why → How to Act → Your Decision
- Results only. Every finding tagged: 🟢 verified, 🟡 medium, 🔴 assumed.
## Context Integration
- **Always** read `company-context.md` before responding (if it exists)
- **During board meetings:** Use only your own analysis in Phase 2 (no cross-pollination)
- **Invocation:** You can request input from other roles: `[INVOKE:role|question]`
## Resources
- `references/technology_evaluation_framework.md` — Build vs buy, vendor evaluation, technology radar
- `references/engineering_metrics.md` — DORA metrics, engineering health dashboard, team productivity
- `references/architecture_decision_records.md` — ADR templates, decision governance, review process
FILE:references/architecture_decision_records.md
# Architecture Decision Records (ADR) Framework
## What is an ADR?
Architecture Decision Records capture important architectural decisions made along with their context and consequences. They help maintain institutional knowledge and explain why systems are built the way they are.
## ADR Template
### ADR-[NUMBER]: [TITLE]
**Date**: YYYY-MM-DD
**Status**: [Proposed | Accepted | Deprecated | Superseded]
**Deciders**: [List of people involved in decision]
**Technical Story**: [Ticket/Issue reference]
#### Context and Problem Statement
[Describe the context and problem that needs to be solved. What are we trying to achieve?]
#### Decision Drivers
- [Driver 1: e.g., Performance requirements]
- [Driver 2: e.g., Time to market]
- [Driver 3: e.g., Team expertise]
- [Driver 4: e.g., Cost constraints]
#### Considered Options
1. **Option 1: [Name]**
2. **Option 2: [Name]**
3. **Option 3: [Name]**
#### Decision Outcome
**Chosen option**: "[Option Name]", because [justification]
##### Positive Consequences
- [Consequence 1]
- [Consequence 2]
##### Negative Consequences
- [Risk 1 and mitigation]
- [Risk 2 and mitigation]
#### Pros and Cons of Options
##### Option 1: [Name]
- **Pros**:
- [Advantage 1]
- [Advantage 2]
- **Cons**:
- [Disadvantage 1]
- [Disadvantage 2]
##### Option 2: [Name]
[Repeat structure]
#### Links
- [Related ADRs]
- [Documentation]
- [Research/PoCs]
---
## Example ADRs
### ADR-001: Microservices Architecture
**Date**: 2024-01-15
**Status**: Accepted
**Deciders**: CTO, VP Engineering, Tech Leads
**Technical Story**: ARCH-001
#### Context and Problem Statement
Our monolithic application is becoming difficult to scale and deploy. Different teams are stepping on each other's toes, and deployment cycles are getting longer. We need to decide on our architectural approach for the next 3-5 years.
#### Decision Drivers
- Need for independent team deployment
- Requirement to scale different components independently
- Different components have different performance characteristics
- Team size growing from 25 to 75+ engineers
- Need to support multiple technology stacks
#### Considered Options
1. **Keep Monolith**: Continue with current architecture
2. **Modular Monolith**: Break into modules but single deployment
3. **Microservices**: Full service-oriented architecture
4. **Serverless**: Function-as-a-Service approach
#### Decision Outcome
**Chosen option**: "Microservices", because it best supports our team autonomy needs and scaling requirements, despite added complexity.
##### Positive Consequences
- Teams can deploy independently
- Services can scale based on individual needs
- Technology diversity is possible
- Fault isolation improved
##### Negative Consequences
- Increased operational complexity - Mitigated by investing in DevOps
- Network latency between services - Mitigated by careful service boundaries
- Data consistency challenges - Mitigated by event sourcing patterns
---
### ADR-002: Container Orchestration Platform
**Date**: 2024-02-01
**Status**: Accepted
**Deciders**: CTO, DevOps Lead, Platform Team
**Technical Story**: INFRA-045
#### Context and Problem Statement
With the move to microservices (ADR-001), we need a container orchestration platform to manage deployment, scaling, and operations of application containers.
#### Decision Drivers
- Need for automated deployment and scaling
- High availability requirements (99.9% SLA)
- Multi-cloud strategy (avoid vendor lock-in)
- Team familiarity and ecosystem maturity
- Cost considerations
#### Considered Options
1. **Kubernetes**: Industry standard, self-managed
2. **Amazon ECS**: AWS-native solution
3. **Docker Swarm**: Simpler alternative
4. **Nomad**: HashiCorp solution
#### Decision Outcome
**Chosen option**: "Kubernetes", because of its maturity, ecosystem, and multi-cloud support.
##### Positive Consequences
- Industry standard with huge ecosystem
- Multi-cloud compatible
- Strong community support
- Extensive tooling available
##### Negative Consequences
- Steep learning curve - Mitigated by training and hiring
- Operational complexity - Mitigated by managed Kubernetes (EKS/GKE)
---
### ADR-003: API Gateway Strategy
**Date**: 2024-03-15
**Status**: Accepted
**Deciders**: CTO, Security Lead, API Team
**Technical Story**: API-101
#### Context and Problem Statement
With multiple microservices, we need a unified entry point for external clients that handles cross-cutting concerns like authentication, rate limiting, and monitoring.
#### Decision Drivers
- Security requirements (OAuth2, API keys)
- Need for rate limiting and throttling
- Monitoring and analytics requirements
- Developer experience for API consumers
- Performance (sub-100ms overhead)
#### Considered Options
1. **Kong**: Open-source, plugin ecosystem
2. **AWS API Gateway**: Managed service
3. **Istio/Envoy**: Service mesh approach
4. **Build Custom**: In-house solution
#### Decision Outcome
**Chosen option**: "Kong", because of its flexibility and plugin ecosystem while avoiding vendor lock-in.
---
## Common Architecture Decisions
### 1. Frontend Architecture
- **Single Page Application (SPA)** vs **Server-Side Rendering (SSR)** vs **Static Site Generation (SSG)**
- **React** vs **Vue** vs **Angular** vs **Svelte**
- **Monorepo** vs **Polyrepo**
- **Micro-frontends** vs **Monolithic frontend**
### 2. Backend Architecture
- **Monolith** vs **Microservices** vs **Serverless**
- **REST** vs **GraphQL** vs **gRPC**
- **Synchronous** vs **Asynchronous** communication
- **Event-driven** vs **Request-response**
### 3. Data Architecture
- **SQL** vs **NoSQL** vs **NewSQL**
- **Single database** vs **Database per service**
- **CQRS** vs **Traditional CRUD**
- **Event Sourcing** vs **State-based storage**
### 4. Infrastructure Decisions
- **Cloud provider**: AWS vs Azure vs GCP vs Multi-cloud
- **Containers** vs **VMs** vs **Serverless**
- **Kubernetes** vs **ECS** vs **Cloud Run**
- **Self-hosted** vs **Managed services**
### 5. Development Practices
- **Continuous Deployment** vs **Continuous Delivery**
- **Feature flags** vs **Branch-based deployment**
- **Blue-green** vs **Canary** vs **Rolling deployment**
- **GitFlow** vs **GitHub Flow** vs **GitLab Flow**
## ADR Best Practices
### Writing Good ADRs
1. **Keep them short**: 1-2 pages maximum
2. **Be specific**: Include concrete examples
3. **Document why, not what**: Focus on reasoning
4. **Include all options**: Even obviously bad ones
5. **Be honest about drawbacks**: Every decision has trade-offs
### When to Write ADRs
Write an ADR when:
- The decision has significant impact
- Multiple options were seriously considered
- The decision is hard to reverse
- You find yourself explaining the same decision repeatedly
- There's disagreement about the approach
### ADR Lifecycle
1. **Proposed**: Under discussion
2. **Accepted**: Decision made and being implemented
3. **Deprecated**: No longer relevant but kept for history
4. **Superseded**: Replaced by another ADR
### Storage and Discovery
- Store ADRs in your main repository under `docs/architecture/decisions/`
- Use consistent numbering (ADR-001, ADR-002, etc.)
- Create an index file linking all ADRs
- Reference ADRs in code comments where relevant
- Review ADRs regularly (quarterly) for relevance
## Decision Evaluation Framework
### Technical Factors (40%)
- Performance impact
- Scalability potential
- Security implications
- Maintainability
- Technical debt
### Business Factors (30%)
- Time to market
- Cost (initial and ongoing)
- Revenue impact
- Competitive advantage
- Regulatory compliance
### Team Factors (30%)
- Current expertise
- Learning curve
- Hiring availability
- Team preference
- Training requirements
## Anti-patterns to Avoid
1. **Decision by Committee**: Too many stakeholders leading to compromise solutions
2. **Analysis Paralysis**: Over-analyzing instead of deciding
3. **Resume-Driven Development**: Choosing tech for personal goals
4. **Hype-Driven Development**: Choosing the newest/coolest tech
5. **Not-Invented-Here**: Rejecting external solutions by default
6. **Vendor Lock-in**: Over-dependence on proprietary solutions
7. **Premature Optimization**: Solving problems you don't have yet
8. **Under-documentation**: Not capturing the "why" behind decisions
## Review Checklist
Before finalizing an ADR, ensure:
- [ ] Problem is clearly stated
- [ ] All realistic options are considered
- [ ] Trade-offs are honestly evaluated
- [ ] Decision rationale is clear
- [ ] Consequences are identified
- [ ] Mitigation strategies are defined
- [ ] Success metrics are established
- [ ] Review date is set (if applicable)
FILE:references/engineering_metrics.md
# Engineering Metrics & KPIs Guide
## Metrics Framework
### DORA Metrics (DevOps Research and Assessment)
#### 1. Deployment Frequency
- **Definition**: How often code is deployed to production
- **Target**:
- Elite: Multiple deploys per day
- High: Weekly to monthly
- Medium: Monthly to bi-annually
- Low: Less than bi-annually
- **Measurement**: Deployments per day/week/month
- **Improvement**: Smaller batch sizes, feature flags, CI/CD
#### 2. Lead Time for Changes
- **Definition**: Time from code commit to production
- **Target**:
- Elite: Less than 1 hour
- High: 1 day to 1 week
- Medium: 1 week to 1 month
- Low: More than 1 month
- **Measurement**: Median time from commit to deploy
- **Improvement**: Automation, parallel testing, smaller changes
#### 3. Mean Time to Recovery (MTTR)
- **Definition**: Time to restore service after incident
- **Target**:
- Elite: Less than 1 hour
- High: Less than 1 day
- Medium: 1 day to 1 week
- Low: More than 1 week
- **Measurement**: Average incident resolution time
- **Improvement**: Monitoring, rollback capability, runbooks
#### 4. Change Failure Rate
- **Definition**: Percentage of changes causing failures
- **Target**:
- Elite: 0-15%
- High: 16-30%
- Medium/Low: >30%
- **Measurement**: Failed deploys / Total deploys
- **Improvement**: Testing, code review, gradual rollouts
### Engineering Productivity Metrics
#### Code Quality
| Metric | Formula | Target | Action if Below |
|--------|---------|--------|-----------------|
| Test Coverage | Tests / Total Code | >80% | Add unit tests |
| Code Review Coverage | Reviewed PRs / Total PRs | 100% | Enforce review policy |
| Technical Debt Ratio | Debt / Development Time | <10% | Dedicate debt sprints |
| Cyclomatic Complexity | Per function/method | <10 | Refactor complex code |
| Code Duplication | Duplicate Lines / Total | <5% | Extract common code |
#### Development Velocity
| Metric | Formula | Target | Action if Below |
|--------|---------|--------|-----------------|
| Sprint Velocity | Story Points / Sprint | Stable ±10% | Review estimation |
| Cycle Time | Start to Done Time | <5 days | Reduce WIP |
| PR Merge Time | Open to Merge | <24 hours | Smaller PRs |
| Build Time | Code to Artifact | <10 minutes | Optimize pipeline |
| Test Execution Time | Full Test Suite | <30 minutes | Parallelize tests |
#### Team Health
| Metric | Formula | Target | Action if Below |
|--------|---------|--------|-----------------|
| On-call Incidents | Incidents / Week | <5 | Improve monitoring |
| Bug Escape Rate | Prod Bugs / Release | <5% | Improve testing |
| Unplanned Work | Unplanned / Total | <20% | Better planning |
| Meeting Time | Meetings / Total Time | <20% | Reduce meetings |
| Focus Time | Uninterrupted Hours | >4h/day | Block calendars |
### Business Impact Metrics
#### System Performance
| Metric | Description | Target | Business Impact |
|--------|-------------|--------|-----------------|
| Uptime | System availability | 99.9%+ | Revenue protection |
| Page Load Time | Time to interactive | <3s | User retention |
| API Response Time | P95 latency | <200ms | User experience |
| Error Rate | Errors / Requests | <0.1% | Customer satisfaction |
| Throughput | Requests / Second | Per requirement | Scalability |
#### Product Delivery
| Metric | Description | Target | Business Impact |
|--------|-------------|--------|-----------------|
| Feature Delivery Rate | Features / Quarter | Per roadmap | Market competitiveness |
| Time to Market | Idea to Production | <3 months | First mover advantage |
| Customer Defect Rate | Customer Bugs / Month | <10 | Customer satisfaction |
| Feature Adoption | Users / Feature | >50% | ROI validation |
| NPS from Engineering | Customer Score | >50 | Product quality |
## Metrics Dashboards
### Executive Dashboard (Weekly)
```
┌─────────────────────────────────────┐
│ EXECUTIVE METRICS │
├─────────────────────────────────────┤
│ Uptime: 99.97% ✓ │
│ Sprint Velocity: 142 pts ✓ │
│ Deployment Frequency: 3.2/day ✓ │
│ Lead Time: 4.2 hrs ✓ │
│ MTTR: 47 min ✓ │
│ Change Failure Rate: 8.3% ✓ │
│ │
│ Team Health: 8.2/10 │
│ Tech Debt Ratio: 12% ⚠ │
│ Feature Delivery: 85% ✓ │
└─────────────────────────────────────┘
```
### Team Dashboard (Daily)
```
┌─────────────────────────────────────┐
│ TEAM METRICS │
├─────────────────────────────────────┤
│ Current Sprint: │
│ Completed: 65/100 pts (65%) │
│ In Progress: 20 pts │
│ Days Left: 3 │
│ │
│ PR Queue: 8 pending │
│ Build Status: ✓ Passing │
│ Test Coverage: 82.3% │
│ Open Incidents: 2 (P2, P3) │
│ │
│ On-call Load: 3 pages this week │
└─────────────────────────────────────┘
```
### Individual Dashboard (Daily)
```
┌─────────────────────────────────────┐
│ DEVELOPER METRICS │
├─────────────────────────────────────┤
│ This Week: │
│ PRs Merged: 8 │
│ Code Reviews: 12 │
│ Commits: 23 │
│ Focus Time: 22.5 hrs │
│ │
│ Quality: │
│ Test Coverage: 87% │
│ Code Review Feedback: 95% ✓ │
│ Bug Introduction Rate: 0% │
└─────────────────────────────────────┘
```
## Implementation Guide
### Phase 1: Foundation (Month 1)
1. **Basic Metrics**
- Deployment frequency
- Build success rate
- Uptime/availability
- Team velocity
2. **Tools Setup**
- CI/CD instrumentation
- Basic monitoring
- Time tracking
### Phase 2: Quality (Month 2)
1. **Quality Metrics**
- Test coverage
- Code review metrics
- Bug rates
- Technical debt
2. **Tool Integration**
- Static analysis
- Test reporting
- Code quality gates
### Phase 3: Performance (Month 3)
1. **Performance Metrics**
- DORA metrics complete
- System performance
- API metrics
- Database metrics
2. **Advanced Monitoring**
- APM tools
- Distributed tracing
- Custom dashboards
### Phase 4: Optimization (Ongoing)
1. **Advanced Analytics**
- Predictive metrics
- Trend analysis
- Anomaly detection
- Correlation analysis
## Metric Anti-patterns
### What NOT to Measure
❌ **Lines of Code**: Encourages bloat
❌ **Hours Worked**: Promotes presenteeism
❌ **Individual Velocity**: Creates competition
❌ **Bug Count Without Context**: Discourages risk-taking
❌ **Commit Count**: Encourages tiny commits
### Goodhart's Law
"When a measure becomes a target, it ceases to be a good measure"
**Examples**:
- Optimizing test coverage → Writing meaningless tests
- Reducing bug count → Not reporting bugs
- Increasing velocity → Inflating estimates
- Reducing meeting time → Skipping important discussions
### How to Avoid Gaming
1. **Use Multiple Metrics**: No single metric tells the whole story
2. **Focus on Trends**: Not absolute numbers
3. **Combine Leading and Lagging**: Balance predictive and historical
4. **Regular Review**: Adjust metrics that are being gamed
5. **Team Ownership**: Let teams choose their metrics
## OKR Framework for Engineering
### Company Level OKRs
**Objective**: Deliver exceptional product quality
**Key Results**:
- KR1: Achieve 99.95% uptime (from 99.9%)
- KR2: Reduce customer-reported bugs by 50%
- KR3: Improve deployment frequency to 10x/day
### Engineering OKRs
**Objective**: Build scalable, reliable infrastructure
**Key Results**:
- KR1: Migrate 80% of services to Kubernetes
- KR2: Reduce MTTR to <30 minutes
- KR3: Achieve 85% test coverage
### Team OKRs
**Objective**: Improve developer productivity
**Key Results**:
- KR1: Reduce build time to <5 minutes
- KR2: Automate 90% of deployment process
- KR3: Reduce PR review time to <4 hours
## Reporting Templates
### Monthly Engineering Report
```markdown
# Engineering Report - [Month Year]
## Executive Summary
- Key Achievement: [Highlight]
- Main Challenge: [Issue and resolution]
- Next Month Focus: [Priority]
## DORA Metrics
| Metric | This Month | Last Month | Target | Status |
|--------|------------|------------|--------|--------|
| Deploy Frequency | X/day | Y/day | Z/day | ✓/⚠/✗ |
| Lead Time | X hrs | Y hrs | <Z hrs | ✓/⚠/✗ |
| MTTR | X min | Y min | <Z min | ✓/⚠/✗ |
| Change Failure | X% | Y% | <Z% | ✓/⚠/✗ |
## Team Performance
- Velocity: X story points (Y% of plan)
- Sprint Completion: X%
- Unplanned Work: X%
## Quality Metrics
- Test Coverage: X% (Δ Y%)
- Customer Bugs: X (Δ Y)
- Code Review Coverage: X%
## Highlights
1. [Major feature or improvement]
2. [Technical achievement]
3. [Process improvement]
## Challenges & Solutions
1. Challenge: [Issue]
Solution: [Action taken]
## Next Month Priorities
1. [Priority 1]
2. [Priority 2]
3. [Priority 3]
```
### Quarterly Business Review
```markdown
# Engineering QBR - Q[X] [Year]
## Strategic Alignment
- Business Goal: [Goal]
- Engineering Contribution: [How engineering supported]
- Impact: [Measurable outcome]
## Quarterly Metrics
### Delivery
- Features Shipped: X of Y planned (Z%)
- Major Releases: [List]
- Technical Debt Reduced: X%
### Reliability
- Uptime: X%
- Incidents: X (PY critical, PZ major)
- Customer Impact: [Description]
### Efficiency
- Cost per Transaction: $X (Δ Y%)
- Infrastructure Cost: $X (Δ Y%)
- Engineering Cost per Feature: $X
## Team Growth
- Headcount: Start: X → End: Y
- Attrition: X%
- Key Hires: [Roles]
## Innovation
- Patents Filed: X
- Open Source Contributions: X
- Hackathon Projects: X
## Lessons Learned
1. [What worked well]
2. [What didn't work]
3. [What we're changing]
## Next Quarter Focus
1. [Strategic Initiative 1]
2. [Strategic Initiative 2]
3. [Strategic Initiative 3]
```
## Tool Recommendations
### Metrics Collection
- **DataDog**: Comprehensive monitoring
- **New Relic**: Application performance
- **Grafana + Prometheus**: Open source stack
- **CloudWatch**: AWS native
### Engineering Analytics
- **LinearB**: Developer productivity
- **Velocity**: Engineering metrics
- **Sleuth**: DORA metrics
- **Swarmia**: Engineering insights
### Project Tracking
- **Jira**: Issue tracking
- **Linear**: Modern issue tracking
- **Azure DevOps**: Microsoft ecosystem
- **GitHub Projects**: Integrated with code
### Incident Management
- **PagerDuty**: On-call management
- **Opsgenie**: Incident response
- **StatusPage**: Status communication
- **FireHydrant**: Incident command
## Success Indicators
### Healthy Engineering Organization
✓ DORA metrics improving quarter-over-quarter
✓ Team satisfaction >8/10
✓ Attrition <10% annually
✓ On-time delivery >80%
✓ Technical debt <15% of capacity
✓ Innovation time >20%
### Warning Signs
⚠️ Increasing MTTR trend
⚠️ Declining velocity
⚠️ Rising bug escape rate
⚠️ Increasing unplanned work
⚠️ Growing PR queue
⚠️ Decreasing test coverage
### Crisis Indicators
🚨 Multiple production incidents per week
🚨 Team satisfaction <6/10
🚨 Attrition >20%
🚨 Technical debt >30%
🚨 No deployments for >1 week
🚨 Customer escalations increasing
FILE:references/technology_evaluation_framework.md
# Technology Evaluation Framework
## Evaluation Process
### Phase 1: Requirements Gathering (Week 1)
#### Functional Requirements
- Core features needed
- Integration requirements
- Performance requirements
- Scalability needs
- Security requirements
#### Non-Functional Requirements
- Usability/Developer experience
- Documentation quality
- Community support
- Vendor stability
- Compliance needs
#### Constraints
- Budget limitations
- Timeline constraints
- Team expertise
- Existing technology stack
- Regulatory requirements
### Phase 2: Market Research (Week 1-2)
#### Identify Candidates
1. Industry leaders (Gartner Magic Quadrant)
2. Open-source alternatives
3. Emerging solutions
4. Build vs Buy analysis
#### Initial Filtering
- Eliminate options not meeting hard requirements
- Remove options outside budget
- Focus on 3-5 top candidates
### Phase 3: Deep Evaluation (Week 2-4)
#### Technical Evaluation
- Proof of Concept (PoC)
- Performance benchmarks
- Security assessment
- Integration testing
- Scalability testing
#### Business Evaluation
- Total Cost of Ownership (TCO)
- Return on Investment (ROI)
- Vendor assessment
- Risk analysis
- Exit strategy
### Phase 4: Decision (Week 4)
## Evaluation Criteria Matrix
### Technical Criteria (40%)
| Criterion | Weight | Description | Scoring Guide |
|-----------|--------|-------------|---------------|
| **Performance** | 10% | Speed, throughput, latency | 5: Exceeds requirements<br>3: Meets requirements<br>1: Below requirements |
| **Scalability** | 10% | Ability to grow with needs | 5: Linear scalability<br>3: Some limitations<br>1: Hard limits |
| **Reliability** | 8% | Uptime, fault tolerance | 5: 99.99% SLA<br>3: 99.9% SLA<br>1: <99% SLA |
| **Security** | 8% | Security features, compliance | 5: Exceeds standards<br>3: Meets standards<br>1: Concerns exist |
| **Integration** | 4% | API quality, compatibility | 5: Native integration<br>3: Good APIs<br>1: Limited integration |
### Business Criteria (30%)
| Criterion | Weight | Description | Scoring Guide |
|-----------|--------|-------------|---------------|
| **Cost** | 10% | TCO including licenses, operation | 5: Under budget by >20%<br>3: Within budget<br>1: Over budget |
| **ROI** | 8% | Value generation potential | 5: <6 month payback<br>3: <12 month payback<br>1: >24 month payback |
| **Vendor Stability** | 6% | Financial health, market position | 5: Market leader<br>3: Established player<br>1: Startup/uncertain |
| **Support Quality** | 6% | Support availability, SLAs | 5: 24/7 premium support<br>3: Business hours<br>1: Community only |
### Operational Criteria (30%)
| Criterion | Weight | Description | Scoring Guide |
|-----------|--------|-------------|---------------|
| **Ease of Use** | 8% | Learning curve, UX | 5: Intuitive<br>3: Moderate learning<br>1: Steep curve |
| **Documentation** | 7% | Quality, completeness | 5: Excellent docs<br>3: Adequate docs<br>1: Poor docs |
| **Community** | 7% | Size, activity, resources | 5: Large, active<br>3: Moderate<br>1: Small/inactive |
| **Maintenance** | 8% | Operational overhead | 5: Fully managed<br>3: Some maintenance<br>1: High maintenance |
## Vendor Evaluation Template
### Vendor Profile
- **Company Name**:
- **Founded**:
- **Headquarters**:
- **Employees**:
- **Revenue**:
- **Funding** (if applicable):
- **Key Customers**:
### Product Assessment
#### Strengths
- [ ] Market leader position
- [ ] Strong feature set
- [ ] Good performance
- [ ] Excellent support
- [ ] Active development
#### Weaknesses
- [ ] Price point
- [ ] Learning curve
- [ ] Limited customization
- [ ] Vendor lock-in
- [ ] Missing features
#### Opportunities
- [ ] Roadmap alignment
- [ ] Partnership potential
- [ ] Training availability
- [ ] Professional services
#### Threats
- [ ] Competitive alternatives
- [ ] Market changes
- [ ] Technology shifts
- [ ] Acquisition risk
### Financial Analysis
#### Cost Breakdown
| Component | Year 1 | Year 2 | Year 3 | Total |
|-----------|--------|--------|--------|-------|
| Licensing | $ | $ | $ | $ |
| Implementation | $ | $ | $ | $ |
| Training | $ | $ | $ | $ |
| Support | $ | $ | $ | $ |
| Infrastructure | $ | $ | $ | $ |
| **Total** | **$** | **$** | **$** | **$** |
#### ROI Calculation
- **Cost Savings**:
- Reduced manual work: $/year
- Efficiency gains: $/year
- Error reduction: $/year
- **Revenue Impact**:
- New capabilities: $/year
- Faster time to market: $/year
- **Payback Period**: X months
### Risk Assessment
| Risk | Probability | Impact | Mitigation |
|------|------------|--------|------------|
| Vendor goes out of business | Low/Med/High | Low/Med/High | Strategy |
| Technology becomes obsolete | | | |
| Integration difficulties | | | |
| Team adoption challenges | | | |
| Budget overrun | | | |
| Performance issues | | | |
## Build vs Buy Decision Framework
### When to Build
**Advantages**:
- Full control over features
- No vendor lock-in
- Potential competitive advantage
- Perfect fit for requirements
- No licensing costs
**Build when**:
- Core business differentiator
- Unique requirements
- Long-term investment
- Have expertise in-house
- No suitable solutions exist
**Hidden Costs**:
- Development time
- Maintenance burden
- Security responsibility
- Documentation needs
- Training requirements
### When to Buy
**Advantages**:
- Faster time to market
- Proven solution
- Vendor support
- Regular updates
- Shared development costs
**Buy when**:
- Commodity functionality
- Standard requirements
- Limited internal resources
- Need quick solution
- Good options available
**Hidden Costs**:
- Customization limits
- Vendor lock-in
- Integration effort
- Training needs
- Scaling costs
### When to Adopt Open Source
**Advantages**:
- No licensing costs
- Community support
- Transparency
- Customizable
- No vendor lock-in
**Adopt when**:
- Strong community exists
- Standard solution needed
- Have technical expertise
- Can contribute back
- Long-term stability needed
**Hidden Costs**:
- Support costs
- Security responsibility
- Upgrade management
- Integration effort
- Potential consulting needs
## Proof of Concept Guidelines
### PoC Scope
1. **Duration**: 2-4 weeks
2. **Team**: 2-3 engineers
3. **Environment**: Isolated/sandbox
4. **Data**: Representative sample
### Success Criteria
- [ ] Core use cases demonstrated
- [ ] Performance benchmarks met
- [ ] Integration points tested
- [ ] Security requirements validated
- [ ] Team feedback positive
### PoC Checklist
- [ ] Environment setup documented
- [ ] Test scenarios defined
- [ ] Metrics collection automated
- [ ] Team training completed
- [ ] Results documented
### PoC Report Template
```markdown
# PoC Report: [Technology Name]
## Executive Summary
- **Recommendation**: [Proceed/Stop/Investigate Further]
- **Confidence Level**: [High/Medium/Low]
- **Key Finding**: [One sentence summary]
## Test Results
### Functional Tests
| Test Case | Result | Notes |
|-----------|--------|-------|
| | Pass/Fail | |
### Performance Tests
| Metric | Target | Actual | Status |
|--------|--------|--------|---------|
| Response Time | <100ms | Xms | ✓/✗ |
| Throughput | >1000 req/s | X req/s | ✓/✗ |
| CPU Usage | <70% | X% | ✓/✗ |
| Memory Usage | <4GB | XGB | ✓/✗ |
### Integration Tests
| System | Status | Effort |
|--------|--------|--------|
| Database | ✓/✗ | Low/Med/High |
| API Gateway | ✓/✗ | Low/Med/High |
| Authentication | ✓/✗ | Low/Med/High |
## Team Feedback
- **Ease of Use**: [1-5 rating]
- **Documentation**: [1-5 rating]
- **Would Recommend**: [Yes/No]
## Risks Identified
1. [Risk and mitigation]
2. [Risk and mitigation]
## Next Steps
1. [Action item]
2. [Action item]
```
## Technology Categories
### Development Platforms
- **Languages**: TypeScript, Python, Go, Rust, Java
- **Frameworks**: React, Node.js, Spring, Django, FastAPI
- **Mobile**: React Native, Flutter, Swift, Kotlin
- **Evaluation Focus**: Developer productivity, ecosystem, performance
### Databases
- **SQL**: PostgreSQL, MySQL, SQL Server
- **NoSQL**: MongoDB, Cassandra, DynamoDB
- **NewSQL**: CockroachDB, Vitess, TiDB
- **Evaluation Focus**: Performance, scalability, consistency, operations
### Infrastructure
- **Cloud**: AWS, GCP, Azure
- **Containers**: Docker, Kubernetes, Nomad
- **Serverless**: Lambda, Cloud Functions, Vercel
- **Evaluation Focus**: Cost, scalability, vendor lock-in, operations
### Monitoring & Observability
- **APM**: DataDog, New Relic, AppDynamics
- **Logging**: ELK Stack, Splunk, CloudWatch
- **Metrics**: Prometheus, Grafana, CloudWatch
- **Evaluation Focus**: Coverage, cost, integration, insights
### Security
- **SAST**: Sonarqube, Checkmarx, Veracode
- **DAST**: OWASP ZAP, Burp Suite
- **Secrets**: Vault, AWS Secrets Manager
- **Evaluation Focus**: Coverage, false positives, integration
### DevOps Tools
- **CI/CD**: Jenkins, GitLab CI, GitHub Actions
- **IaC**: Terraform, CloudFormation, Pulumi
- **Configuration**: Ansible, Chef, Puppet
- **Evaluation Focus**: Flexibility, integration, learning curve
## Continuous Evaluation
### Quarterly Reviews
- Technology landscape changes
- Performance against expectations
- Cost optimization opportunities
- Team satisfaction
- Market alternatives
### Annual Assessment
- Full technology stack review
- Vendor relationship evaluation
- Strategic alignment check
- Technical debt assessment
- Roadmap planning
### Deprecation Planning
- Migration strategy
- Timeline definition
- Risk assessment
- Communication plan
- Success metrics
## Decision Documentation
Always document:
1. **Why** the technology was chosen
2. **Who** was involved in the decision
3. **When** the decision was made
4. **What** alternatives were considered
5. **How** success will be measured
Use Architecture Decision Records (ADRs) for significant technology choices.
FILE:scripts/team_scaling_calculator.py
#!/usr/bin/env python3
"""
Engineering Team Scaling Calculator - Optimize team growth and structure
"""
import json
import math
from typing import Dict, List, Tuple
class TeamScalingCalculator:
def __init__(self):
self.conway_factor = 1.5 # Conway's Law impact factor
self.brooks_factor = 0.75 # Brooks' Law diminishing returns
# Optimal team structures based on size
self.team_structures = {
'startup': {'min': 1, 'max': 10, 'structure': 'flat'},
'growth': {'min': 11, 'max': 50, 'structure': 'team_leads'},
'scale': {'min': 51, 'max': 150, 'structure': 'departments'},
'enterprise': {'min': 151, 'max': 9999, 'structure': 'divisions'}
}
# Role ratios for balanced teams
self.role_ratios = {
'engineering_manager': 0.125, # 1:8 ratio
'tech_lead': 0.167, # 1:6 ratio
'senior_engineer': 0.3,
'mid_engineer': 0.4,
'junior_engineer': 0.2,
'devops': 0.1,
'qa': 0.15,
'product_manager': 0.1,
'designer': 0.08,
'data_engineer': 0.05
}
def calculate_scaling_plan(self, current_state: Dict, growth_targets: Dict) -> Dict:
"""Calculate optimal scaling plan"""
results = {
'current_analysis': self._analyze_current_state(current_state),
'growth_timeline': self._create_growth_timeline(current_state, growth_targets),
'hiring_plan': {},
'team_structure': {},
'budget_projection': {},
'risk_factors': [],
'recommendations': []
}
# Generate hiring plan
results['hiring_plan'] = self._generate_hiring_plan(
current_state,
growth_targets
)
# Design team structure
results['team_structure'] = self._design_team_structure(
growth_targets['target_headcount']
)
# Calculate budget
results['budget_projection'] = self._calculate_budget(
results['hiring_plan'],
current_state.get('location', 'US')
)
# Assess risks
results['risk_factors'] = self._assess_scaling_risks(
current_state,
growth_targets
)
# Generate recommendations
results['recommendations'] = self._generate_recommendations(results)
return results
def _analyze_current_state(self, current_state: Dict) -> Dict:
"""Analyze current team state"""
total_engineers = current_state.get('headcount', 0)
analysis = {
'total_headcount': total_engineers,
'team_stage': self._get_team_stage(total_engineers),
'productivity_index': 0,
'balance_score': 0,
'issues': []
}
# Calculate productivity index
if total_engineers > 0:
velocity = current_state.get('velocity', 100)
expected_velocity = total_engineers * 20 # baseline 20 points per engineer
analysis['productivity_index'] = (velocity / expected_velocity) * 100
# Check team balance
roles = current_state.get('roles', {})
analysis['balance_score'] = self._calculate_balance_score(roles, total_engineers)
# Identify issues
if analysis['productivity_index'] < 70:
analysis['issues'].append('Low productivity - possible process or tooling issues')
if analysis['balance_score'] < 60:
analysis['issues'].append('Team imbalance - review role distribution')
manager_ratio = roles.get('managers', 0) / max(total_engineers, 1)
if manager_ratio > 0.2:
analysis['issues'].append('Over-managed - too many managers')
elif manager_ratio < 0.08 and total_engineers > 20:
analysis['issues'].append('Under-managed - need more engineering managers')
return analysis
def _get_team_stage(self, headcount: int) -> str:
"""Determine team stage based on size"""
for stage, config in self.team_structures.items():
if config['min'] <= headcount <= config['max']:
return stage
return 'startup'
def _calculate_balance_score(self, roles: Dict, total: int) -> float:
"""Calculate team balance score"""
if total == 0:
return 0
score = 100
ideal_ratios = self.role_ratios
for role, ideal_ratio in ideal_ratios.items():
actual_count = roles.get(role, 0)
actual_ratio = actual_count / total
# Penalize deviation from ideal ratio
deviation = abs(actual_ratio - ideal_ratio)
penalty = deviation * 100
score -= min(penalty, 20) # Max 20 point penalty per role
return max(0, score)
def _create_growth_timeline(self, current: Dict, targets: Dict) -> List[Dict]:
"""Create quarterly growth timeline"""
current_headcount = current.get('headcount', 0)
target_headcount = targets.get('target_headcount', current_headcount)
timeline_quarters = targets.get('timeline_quarters', 4)
growth_needed = target_headcount - current_headcount
timeline = []
for quarter in range(1, timeline_quarters + 1):
# Apply Brooks' Law - diminishing returns with rapid growth
if quarter == 1:
quarterly_growth = math.ceil(growth_needed * 0.4) # Front-load hiring
else:
remaining_growth = target_headcount - current_headcount
quarters_left = timeline_quarters - quarter + 1
quarterly_growth = math.ceil(remaining_growth / quarters_left)
# Adjust for onboarding capacity
max_onboarding = math.ceil(current_headcount * 0.25) # 25% growth per quarter max
quarterly_growth = min(quarterly_growth, max_onboarding)
current_headcount += quarterly_growth
timeline.append({
'quarter': f'Q{quarter}',
'headcount': current_headcount,
'new_hires': quarterly_growth,
'onboarding_capacity': max_onboarding,
'productivity_factor': 1.0 - (0.2 * (quarterly_growth / max(current_headcount, 1)))
})
return timeline
def _generate_hiring_plan(self, current: Dict, targets: Dict) -> Dict:
"""Generate detailed hiring plan"""
current_roles = current.get('roles', {})
target_headcount = targets.get('target_headcount', 0)
hiring_plan = {
'total_hires_needed': target_headcount - current.get('headcount', 0),
'by_role': {},
'by_quarter': {},
'interview_capacity_needed': 0,
'recruiting_resources': 0
}
# Calculate ideal role distribution
for role, ideal_ratio in self.role_ratios.items():
ideal_count = math.ceil(target_headcount * ideal_ratio)
current_count = current_roles.get(role, 0)
hires_needed = max(0, ideal_count - current_count)
if hires_needed > 0:
hiring_plan['by_role'][role] = {
'current': current_count,
'target': ideal_count,
'hires_needed': hires_needed,
'priority': self._get_role_priority(role, current_roles, target_headcount)
}
# Distribute hires across quarters
timeline = self._create_growth_timeline(current, targets)
for quarter_data in timeline:
quarter = quarter_data['quarter']
hires = quarter_data['new_hires']
hiring_plan['by_quarter'][quarter] = {
'total_hires': hires,
'breakdown': self._distribute_quarterly_hires(hires, hiring_plan['by_role'])
}
# Calculate interview capacity (5 interviews per hire average)
hiring_plan['interview_capacity_needed'] = hiring_plan['total_hires_needed'] * 5
# Calculate recruiting resources (1 recruiter per 50 hires/year)
annual_hires = hiring_plan['total_hires_needed'] * (4 / max(targets.get('timeline_quarters', 4), 1))
hiring_plan['recruiting_resources'] = math.ceil(annual_hires / 50)
return hiring_plan
def _get_role_priority(self, role: str, current_roles: Dict, target_size: int) -> int:
"""Determine hiring priority for a role"""
# Priority based on criticality and current gaps
priorities = {
'engineering_manager': 10 if target_size > 20 else 5,
'tech_lead': 9,
'senior_engineer': 8,
'devops': 7 if current_roles.get('devops', 0) == 0 else 5,
'qa': 6,
'mid_engineer': 5,
'product_manager': 6,
'designer': 5,
'data_engineer': 4,
'junior_engineer': 3
}
return priorities.get(role, 5)
def _distribute_quarterly_hires(self, total_hires: int, role_needs: Dict) -> Dict:
"""Distribute quarterly hires across roles"""
distribution = {}
# Sort roles by priority
sorted_roles = sorted(
role_needs.items(),
key=lambda x: x[1]['priority'],
reverse=True
)
remaining_hires = total_hires
for role, needs in sorted_roles:
if remaining_hires <= 0:
break
hires = min(needs['hires_needed'], max(1, remaining_hires // 3))
distribution[role] = hires
remaining_hires -= hires
return distribution
def _design_team_structure(self, target_headcount: int) -> Dict:
"""Design optimal team structure"""
stage = self._get_team_stage(target_headcount)
structure = {
'organizational_model': self.team_structures[stage]['structure'],
'teams': [],
'reporting_structure': {},
'communication_paths': 0
}
if stage == 'startup':
structure['teams'] = [{
'name': 'Core Team',
'size': target_headcount,
'focus': 'Full-stack'
}]
elif stage == 'growth':
# Create 2-4 teams
team_size = 6
num_teams = math.ceil(target_headcount / team_size)
structure['teams'] = [
{
'name': f'Team {i+1}',
'size': team_size,
'focus': ['Platform', 'Product', 'Infrastructure', 'Growth'][i % 4]
}
for i in range(num_teams)
]
elif stage == 'scale':
# Create departments with multiple teams
structure['departments'] = [
{'name': 'Platform', 'teams': 3, 'headcount': target_headcount * 0.3},
{'name': 'Product', 'teams': 4, 'headcount': target_headcount * 0.4},
{'name': 'Infrastructure', 'teams': 2, 'headcount': target_headcount * 0.2},
{'name': 'Data', 'teams': 1, 'headcount': target_headcount * 0.1}
]
# Calculate communication paths (n*(n-1)/2)
structure['communication_paths'] = (target_headcount * (target_headcount - 1)) // 2
# Add management layers
structure['management_layers'] = math.ceil(math.log(target_headcount, 7))
return structure
def _calculate_budget(self, hiring_plan: Dict, location: str) -> Dict:
"""Calculate budget projection"""
# Average salaries by role and location (in USD)
salary_bands = {
'US': {
'engineering_manager': 200000,
'tech_lead': 180000,
'senior_engineer': 160000,
'mid_engineer': 120000,
'junior_engineer': 85000,
'devops': 150000,
'qa': 100000,
'product_manager': 150000,
'designer': 120000,
'data_engineer': 140000
},
'EU': {
'engineering_manager': 160000,
'tech_lead': 144000,
'senior_engineer': 128000,
'mid_engineer': 96000,
'junior_engineer': 68000,
'devops': 120000,
'qa': 80000,
'product_manager': 120000,
'designer': 96000,
'data_engineer': 112000
},
'APAC': {
'engineering_manager': 120000,
'tech_lead': 108000,
'senior_engineer': 96000,
'mid_engineer': 72000,
'junior_engineer': 51000,
'devops': 90000,
'qa': 60000,
'product_manager': 90000,
'designer': 72000,
'data_engineer': 84000
}
}
location_salaries = salary_bands.get(location, salary_bands['US'])
budget = {
'annual_salary_cost': 0,
'benefits_cost': 0, # 30% of salary
'equipment_cost': 0, # $5k per hire
'recruiting_cost': 0, # 20% of first-year salary
'onboarding_cost': 0, # $10k per hire
'total_cost': 0,
'cost_per_hire': 0
}
for role, details in hiring_plan['by_role'].items():
hires = details['hires_needed']
salary = location_salaries.get(role, 100000)
budget['annual_salary_cost'] += hires * salary
budget['recruiting_cost'] += hires * salary * 0.2
budget['benefits_cost'] = budget['annual_salary_cost'] * 0.3
budget['equipment_cost'] = hiring_plan['total_hires_needed'] * 5000
budget['onboarding_cost'] = hiring_plan['total_hires_needed'] * 10000
budget['total_cost'] = sum([
budget['annual_salary_cost'],
budget['benefits_cost'],
budget['equipment_cost'],
budget['recruiting_cost'],
budget['onboarding_cost']
])
if hiring_plan['total_hires_needed'] > 0:
budget['cost_per_hire'] = budget['total_cost'] / hiring_plan['total_hires_needed']
return budget
def _assess_scaling_risks(self, current: Dict, targets: Dict) -> List[Dict]:
"""Assess risks in scaling plan"""
risks = []
growth_rate = (targets['target_headcount'] - current['headcount']) / max(current['headcount'], 1)
if growth_rate > 1.0: # More than 100% growth
risks.append({
'risk': 'Rapid growth dilution',
'impact': 'High',
'mitigation': 'Implement strong onboarding and mentorship programs'
})
if current.get('attrition_rate', 0) > 15:
risks.append({
'risk': 'High attrition during scaling',
'impact': 'High',
'mitigation': 'Address retention issues before aggressive hiring'
})
if targets.get('timeline_quarters', 4) < 4:
risks.append({
'risk': 'Compressed timeline',
'impact': 'Medium',
'mitigation': 'Consider extending timeline or increasing recruiting resources'
})
return risks
def _generate_recommendations(self, results: Dict) -> List[str]:
"""Generate scaling recommendations"""
recommendations = []
# Based on growth rate
total_hires = results['hiring_plan']['total_hires_needed']
current_size = results['current_analysis']['total_headcount']
if current_size > 0:
growth_rate = total_hires / current_size
if growth_rate > 0.5:
recommendations.append('Consider hiring a dedicated recruiting team')
recommendations.append('Implement scalable onboarding processes')
recommendations.append('Establish clear team charters and boundaries')
if growth_rate > 1.0:
recommendations.append('⚠️ High growth risk - consider slowing timeline')
recommendations.append('Focus on senior hires first to establish culture')
recommendations.append('Implement continuous integration practices early')
# Based on structure
if results['team_structure']['communication_paths'] > 1000:
recommendations.append('Implement clear communication channels and tools')
recommendations.append('Consider platform teams to reduce dependencies')
# Based on balance
if results['current_analysis']['balance_score'] < 70:
recommendations.append('Prioritize hiring for underrepresented roles')
recommendations.append('Consider role rotation for skill development')
return recommendations
def calculate_team_scaling(current_state: Dict, growth_targets: Dict) -> str:
"""Main function to calculate team scaling"""
calculator = TeamScalingCalculator()
results = calculator.calculate_scaling_plan(current_state, growth_targets)
# Format output
output = [
"=== Engineering Team Scaling Plan ===",
f"",
f"Current State Analysis:",
f" Current Headcount: {results['current_analysis']['total_headcount']}",
f" Team Stage: {results['current_analysis']['team_stage']}",
f" Productivity Index: {results['current_analysis']['productivity_index']:.1f}%",
f" Team Balance Score: {results['current_analysis']['balance_score']:.1f}/100",
f"",
f"Growth Plan:",
f" Target Headcount: {growth_targets['target_headcount']}",
f" Total Hires Needed: {results['hiring_plan']['total_hires_needed']}",
f" Timeline: {growth_targets['timeline_quarters']} quarters",
f"",
"Quarterly Timeline:"
]
for quarter in results['growth_timeline']:
output.append(
f" {quarter['quarter']}: {quarter['headcount']} total "
f"(+{quarter['new_hires']} hires, "
f"{quarter['productivity_factor']:.0%} productivity)"
)
output.extend([
f"",
"Hiring Priorities:"
])
sorted_roles = sorted(
results['hiring_plan']['by_role'].items(),
key=lambda x: x[1]['priority'],
reverse=True
)
for role, details in sorted_roles[:5]:
output.append(
f" {role}: {details['hires_needed']} hires "
f"(Priority: {details['priority']}/10)"
)
output.extend([
f"",
f"Budget Projection:",
f" Annual Salary Cost: ,.0f",
f" Total Investment: ,.0f",
f" Cost per Hire: ,.0f",
f"",
f"Team Structure:",
f" Model: {results['team_structure']['organizational_model']}",
f" Management Layers: {results['team_structure']['management_layers']}",
f" Communication Paths: {results['team_structure']['communication_paths']:,}",
f"",
"Key Recommendations:"
])
for rec in results['recommendations']:
output.append(f" • {rec}")
return '\n'.join(output)
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(
description="Engineering Team Scaling Calculator - Optimize team growth and structure"
)
parser.add_argument(
"input_file", nargs="?", default=None,
help="JSON file with current_state and growth_targets (default: run with sample data)"
)
parser.add_argument(
"--json", action="store_true",
help="Output raw JSON instead of formatted report"
)
args = parser.parse_args()
if args.input_file:
with open(args.input_file) as f:
data = json.load(f)
current_state = data["current_state"]
growth_targets = data["growth_targets"]
else:
current_state = {
'headcount': 25,
'velocity': 450,
'roles': {
'engineering_manager': 2,
'tech_lead': 3,
'senior_engineer': 8,
'mid_engineer': 10,
'junior_engineer': 2
},
'attrition_rate': 12,
'location': 'US'
}
growth_targets = {
'target_headcount': 75,
'timeline_quarters': 4
}
if args.json:
calculator = TeamScalingCalculator()
results = calculator.calculate_scaling_plan(current_state, growth_targets)
print(json.dumps(results, indent=2))
else:
print(calculate_team_scaling(current_state, growth_targets))
FILE:scripts/tech_debt_analyzer.py
#!/usr/bin/env python3
"""
Technical Debt Analyzer - Assess and prioritize technical debt across systems
"""
import json
from typing import Dict, List, Tuple
from datetime import datetime
import math
class TechDebtAnalyzer:
def __init__(self):
self.debt_categories = {
'architecture': {
'weight': 0.25,
'indicators': [
'monolithic_design', 'tight_coupling', 'no_microservices',
'legacy_patterns', 'no_api_gateway', 'synchronous_only'
]
},
'code_quality': {
'weight': 0.20,
'indicators': [
'low_test_coverage', 'high_complexity', 'code_duplication',
'no_documentation', 'inconsistent_standards', 'legacy_language'
]
},
'infrastructure': {
'weight': 0.20,
'indicators': [
'manual_deployments', 'no_ci_cd', 'single_points_failure',
'no_monitoring', 'no_auto_scaling', 'outdated_servers'
]
},
'security': {
'weight': 0.20,
'indicators': [
'outdated_dependencies', 'no_security_scans', 'plain_text_secrets',
'no_encryption', 'missing_auth', 'no_audit_logs'
]
},
'performance': {
'weight': 0.15,
'indicators': [
'slow_response_times', 'no_caching', 'inefficient_queries',
'memory_leaks', 'no_optimization', 'blocking_operations'
]
}
}
self.impact_matrix = {
'user_impact': {'weight': 0.30, 'score': 0},
'developer_velocity': {'weight': 0.25, 'score': 0},
'system_reliability': {'weight': 0.20, 'score': 0},
'scalability': {'weight': 0.15, 'score': 0},
'maintenance_cost': {'weight': 0.10, 'score': 0}
}
def analyze_system(self, system_data: Dict) -> Dict:
"""Analyze a system for technical debt"""
results = {
'timestamp': datetime.now().isoformat(),
'system_name': system_data.get('name', 'Unknown'),
'debt_score': 0,
'debt_level': '',
'category_scores': {},
'prioritized_actions': [],
'estimated_effort': {},
'risk_assessment': {},
'recommendations': []
}
# Calculate debt scores by category
total_debt_score = 0
for category, config in self.debt_categories.items():
category_score = self._calculate_category_score(
system_data.get(category, {}),
config['indicators']
)
weighted_score = category_score * config['weight']
results['category_scores'][category] = {
'raw_score': category_score,
'weighted_score': weighted_score,
'level': self._get_level(category_score)
}
total_debt_score += weighted_score
results['debt_score'] = round(total_debt_score, 2)
results['debt_level'] = self._get_level(total_debt_score)
# Calculate impact and prioritize
results['prioritized_actions'] = self._prioritize_actions(
results['category_scores'],
system_data.get('business_context', {})
)
# Estimate effort
results['estimated_effort'] = self._estimate_effort(
results['prioritized_actions'],
system_data.get('team_size', 5)
)
# Risk assessment
results['risk_assessment'] = self._assess_risks(
results['debt_score'],
system_data.get('system_criticality', 'medium')
)
# Generate recommendations
results['recommendations'] = self._generate_recommendations(results)
return results
def _calculate_category_score(self, category_data: Dict, indicators: List) -> float:
"""Calculate score for a specific category"""
if not category_data:
return 50.0 # Default middle score if no data
total_score = 0
count = 0
for indicator in indicators:
if indicator in category_data:
# Score from 0 (no debt) to 100 (high debt)
total_score += category_data[indicator]
count += 1
return (total_score / count) if count > 0 else 50.0
def _get_level(self, score: float) -> str:
"""Convert numerical score to level"""
if score < 20:
return 'Low'
elif score < 40:
return 'Medium-Low'
elif score < 60:
return 'Medium'
elif score < 80:
return 'Medium-High'
else:
return 'Critical'
def _prioritize_actions(self, category_scores: Dict, business_context: Dict) -> List:
"""Prioritize technical debt reduction actions"""
actions = []
for category, scores in category_scores.items():
if scores['raw_score'] > 60: # Focus on high debt areas
priority = self._calculate_priority(
scores['raw_score'],
category,
business_context
)
action = {
'category': category,
'priority': priority,
'score': scores['raw_score'],
'action_items': self._get_action_items(category, scores['level'])
}
actions.append(action)
# Sort by priority
actions.sort(key=lambda x: x['priority'], reverse=True)
return actions[:5] # Top 5 priorities
def _calculate_priority(self, score: float, category: str, context: Dict) -> float:
"""Calculate priority based on score and business context"""
base_priority = score
# Adjust based on business context
if context.get('growth_phase') == 'rapid' and category in ['scalability', 'performance']:
base_priority *= 1.5
if context.get('compliance_required') and category == 'security':
base_priority *= 2.0
if context.get('cost_pressure') and category == 'infrastructure':
base_priority *= 1.3
return min(100, base_priority)
def _get_action_items(self, category: str, level: str) -> List[str]:
"""Get specific action items based on category and level"""
actions = {
'architecture': {
'Critical': [
'Immediate: Create architecture migration roadmap',
'Week 1: Identify service boundaries for decomposition',
'Month 1: Begin extracting first microservice',
'Month 2: Implement API gateway',
'Quarter: Complete critical service separation'
],
'Medium-High': [
'Month 1: Document current architecture',
'Month 2: Design target architecture',
'Quarter: Begin gradual migration',
'Monitor: Track coupling metrics'
]
},
'code_quality': {
'Critical': [
'Immediate: Implement code quality gates',
'Week 1: Set up automated testing pipeline',
'Month 1: Achieve 40% test coverage',
'Month 2: Refactor critical modules',
'Quarter: Reach 70% test coverage'
],
'Medium-High': [
'Month 1: Establish coding standards',
'Month 2: Implement code review process',
'Quarter: Gradual refactoring plan'
]
},
'infrastructure': {
'Critical': [
'Immediate: Implement basic CI/CD',
'Week 1: Set up monitoring and alerts',
'Month 1: Automate critical deployments',
'Month 2: Implement disaster recovery',
'Quarter: Full infrastructure as code'
],
'Medium-High': [
'Month 1: Document infrastructure',
'Month 2: Begin automation',
'Quarter: Modernize critical components'
]
},
'security': {
'Critical': [
'Immediate: Security audit and patching',
'Week 1: Implement secrets management',
'Month 1: Set up vulnerability scanning',
'Month 2: Implement security training',
'Quarter: Achieve compliance standards'
],
'Medium-High': [
'Month 1: Security assessment',
'Month 2: Implement security tools',
'Quarter: Regular security reviews'
]
},
'performance': {
'Critical': [
'Immediate: Performance profiling',
'Week 1: Implement caching strategy',
'Month 1: Optimize database queries',
'Month 2: Implement CDN',
'Quarter: Re-architect bottlenecks'
],
'Medium-High': [
'Month 1: Performance baseline',
'Month 2: Optimization plan',
'Quarter: Incremental improvements'
]
}
}
return actions.get(category, {}).get(level, ['Create action plan'])
def _estimate_effort(self, actions: List, team_size: int) -> Dict:
"""Estimate effort required for debt reduction"""
total_story_points = 0
effort_breakdown = {}
for action in actions:
# Estimate based on category and score
base_points = action['score'] * 2 # Higher debt = more effort
if action['category'] == 'architecture':
points = base_points * 1.5 # Architecture changes are complex
elif action['category'] == 'security':
points = base_points * 1.2 # Security requires careful work
else:
points = base_points
effort_breakdown[action['category']] = {
'story_points': round(points),
'sprints': math.ceil(points / (team_size * 20)), # 20 points per dev per sprint
'developers_needed': math.ceil(points / 100)
}
total_story_points += points
return {
'total_story_points': round(total_story_points),
'estimated_sprints': math.ceil(total_story_points / (team_size * 20)),
'recommended_team_size': max(team_size, math.ceil(total_story_points / 200)),
'breakdown': effort_breakdown
}
def _assess_risks(self, debt_score: float, criticality: str) -> Dict:
"""Assess risks associated with technical debt"""
risk_level = 'Low'
if debt_score > 70 and criticality == 'high':
risk_level = 'Critical'
elif debt_score > 60 or criticality == 'high':
risk_level = 'High'
elif debt_score > 40:
risk_level = 'Medium'
risks = {
'overall_risk': risk_level,
'specific_risks': []
}
if debt_score > 60:
risks['specific_risks'].extend([
'System failure risk increasing',
'Developer productivity declining',
'Innovation velocity blocked',
'Maintenance costs escalating'
])
if debt_score > 80:
risks['specific_risks'].extend([
'Competitive disadvantage emerging',
'Talent retention risk',
'Customer satisfaction impact',
'Potential data breach vulnerability'
])
return risks
def _generate_recommendations(self, results: Dict) -> List[str]:
"""Generate strategic recommendations"""
recommendations = []
# Overall strategy based on debt level
if results['debt_level'] == 'Critical':
recommendations.append('🚨 URGENT: Dedicate 40% of engineering capacity to debt reduction')
recommendations.append('Create dedicated debt reduction team')
recommendations.append('Implement weekly debt reduction reviews')
recommendations.append('Consider temporary feature freeze')
elif results['debt_level'] in ['Medium-High', 'High']:
recommendations.append('Allocate 25-30% of sprints to debt reduction')
recommendations.append('Establish technical debt budget')
recommendations.append('Implement debt prevention practices')
else:
recommendations.append('Maintain 15-20% ongoing debt reduction allocation')
recommendations.append('Focus on prevention over correction')
# Category-specific recommendations
for category, scores in results['category_scores'].items():
if scores['raw_score'] > 70:
if category == 'architecture':
recommendations.append(f'Consider hiring architecture specialist')
elif category == 'security':
recommendations.append(f'Engage security audit firm')
elif category == 'performance':
recommendations.append(f'Implement performance SLA monitoring')
# Team recommendations
effort = results.get('estimated_effort', {})
if effort.get('recommended_team_size', 0) > effort.get('total_story_points', 0) / 200:
recommendations.append(f"Scale team to {effort['recommended_team_size']} engineers")
return recommendations
def analyze_technical_debt(system_config: Dict) -> str:
"""Main function to analyze technical debt"""
analyzer = TechDebtAnalyzer()
results = analyzer.analyze_system(system_config)
# Format output
output = [
f"=== Technical Debt Analysis Report ===",
f"System: {results['system_name']}",
f"Analysis Date: {results['timestamp'][:10]}",
f"",
f"OVERALL DEBT SCORE: {results['debt_score']}/100 ({results['debt_level']})",
f"",
"Category Breakdown:"
]
for category, scores in results['category_scores'].items():
output.append(f" {category.title()}: {scores['raw_score']:.1f} ({scores['level']})")
output.extend([
f"",
"Risk Assessment:",
f" Overall Risk: {results['risk_assessment']['overall_risk']}"
])
for risk in results['risk_assessment']['specific_risks']:
output.append(f" • {risk}")
output.extend([
f"",
"Effort Estimation:",
f" Total Story Points: {results['estimated_effort']['total_story_points']}",
f" Estimated Sprints: {results['estimated_effort']['estimated_sprints']}",
f" Recommended Team Size: {results['estimated_effort']['recommended_team_size']}",
f"",
"Top Priority Actions:"
])
for i, action in enumerate(results['prioritized_actions'][:3], 1):
output.append(f"\n{i}. {action['category'].title()} (Priority: {action['priority']:.0f})")
for item in action['action_items'][:3]:
output.append(f" - {item}")
output.extend([
f"",
"Strategic Recommendations:"
])
for rec in results['recommendations']:
output.append(f" • {rec}")
return '\n'.join(output)
if __name__ == "__main__":
# Example usage
example_system = {
'name': 'Legacy E-commerce Platform',
'architecture': {
'monolithic_design': 80,
'tight_coupling': 70,
'no_microservices': 90,
'legacy_patterns': 60
},
'code_quality': {
'low_test_coverage': 75,
'high_complexity': 65,
'code_duplication': 55
},
'infrastructure': {
'manual_deployments': 70,
'no_ci_cd': 60,
'no_monitoring': 40
},
'security': {
'outdated_dependencies': 85,
'no_security_scans': 70
},
'performance': {
'slow_response_times': 60,
'no_caching': 50
},
'team_size': 8,
'system_criticality': 'high',
'business_context': {
'growth_phase': 'rapid',
'compliance_required': True,
'cost_pressure': False
}
}
print(analyze_technical_debt(example_system))
Tạo landing page chuyển đổi cao bằng component Next.js/React (TSX) và Tailwind CSS: hero, bảng giá, FAQ, đánh giá, CTA theo các khung copy PAS, AIDA, BAB.
---
name: "landing-page-generator"
description: "Generates high-converting landing pages as complete Next.js/React (TSX) components with Tailwind CSS. Creates hero sections, feature grids, pricing tables, FAQ accordions, testimonial blocks, and CTA sections using proven copy frameworks (PAS, AIDA, BAB). Outputs SEO meta tags, structured data, and performance-optimised code targeting Core Web Vitals (LCP < 1s, CLS < 0.1). Use when the user asks to create a landing page, marketing page, homepage, single-page site, lead capture page, campaign page, promo page, or conversion-optimised web page — or when they want to A/B test landing page variants or replace a static page with one designed to convert."
---
# Landing Page Generator
Generate high-converting landing pages from a product description. Output complete Next.js/React components with multiple section variants, proven copy frameworks, SEO optimization, and performance-first patterns. Not lorem ipsum — actual copy that converts.
**Target:** LCP < 1s · CLS < 0.1 · FID < 100ms
**Output:** TSX components + Tailwind styles + SEO meta + copy variants
---
## Core Capabilities
- 5 hero section variants (centered, split, gradient, video-bg, minimal)
- Feature sections (grid, alternating, cards with icons)
- Pricing tables (2–4 tiers with feature lists and toggle)
- FAQ accordion with schema markup
- Testimonials (grid, carousel, single-quote)
- CTA sections (banner, full-page, inline)
- Footer (simple, mega, minimal)
- 4 design styles with Tailwind class sets
---
## Generation Workflow
Follow these steps in order for every landing page request:
1. **Gather inputs** — collect product name, tagline, audience, pain point, key benefit, pricing tiers, design style, and copy framework using the trigger format below. Ask only for missing fields.
2. **Analyze brand voice** (recommended) — if the user has existing brand content (website copy, blog posts, marketing materials), run it through `marketing-skill/content-production/scripts/brand_voice_analyzer.py` to get a voice profile (formality, tone, perspective). Use the profile to inform design style and copy framework selection:
- formal + professional → **enterprise** style, **AIDA** framework
- casual + friendly → **bold-startup** style, **BAB** framework
- professional + authoritative → **dark-saas** style, **PAS** framework
- casual + conversational → **clean-minimal** style, **BAB** framework
3. **Select design style** — map the user's choice (or infer from brand voice analysis) to one of the four Tailwind class sets in the Design Style Reference.
4. **Apply copy framework** — write all headline and body copy using the chosen framework (PAS / AIDA / BAB) before generating components. Match the voice profile's formality and tone throughout.
5. **Generate sections in order** — Hero → Features → Pricing → FAQ → Testimonials → CTA → Footer. Skip sections not relevant to the product.
6. **Validate against SEO checklist** — run through every item in the SEO Checklist before outputting final code. Fix any gaps inline.
7. **Output final components** — deliver complete, copy-paste-ready TSX files with all Tailwind classes, SEO meta, and structured data included.
---
## Triggering This Skill
```
Product: [name]
Tagline: [one sentence value prop]
Target audience: [who they are]
Key pain point: [what problem you solve]
Key benefit: [primary outcome]
Pricing tiers: [free/pro/enterprise or describe]
Design style: dark-saas | clean-minimal | bold-startup | enterprise
Copy framework: PAS | AIDA | BAB
```
---
## Design Style Reference
| Style | Background | Accent | Cards | CTA Button |
|---|---|---|---|---|
| **Dark SaaS** | `bg-gray-950 text-white` | `violet-500/400` | `bg-gray-900 border border-gray-800` | `bg-violet-600 hover:bg-violet-500` |
| **Clean Minimal** | `bg-white text-gray-900` | `blue-600` | `bg-gray-50 border border-gray-200 rounded-2xl` | `bg-blue-600 hover:bg-blue-700` |
| **Bold Startup** | `bg-white text-gray-900` | `orange-500` | `shadow-xl rounded-3xl` | `bg-orange-500 hover:bg-orange-600 text-white` |
| **Enterprise** | `bg-slate-50 text-slate-900` | `slate-700` | `bg-white border border-slate-200 shadow-sm` | `bg-slate-900 hover:bg-slate-800 text-white` |
> **Bold Startup** headings: add `font-black tracking-tight` to all `<h1>`/`<h2>` elements.
---
## Copy Frameworks
**PAS (Problem → Agitate → Solution)**
- H1: Painful state they're in
- Sub: What happens if they don't fix it
- CTA: What you offer
- *Example — H1:* "Your team wastes 3 hours a day on manual reporting" / *Sub:* "Every hour spent on spreadsheets is an hour not closing deals. Your competitors are already automated." / *CTA:* "Automate your reports in 10 minutes →"
**AIDA (Attention → Interest → Desire → Action)**
- H1: Bold attention-grabbing statement → Sub: Interesting fact or benefit → Features: Desire-building proof points → CTA: Clear action
**BAB (Before → After → Bridge)**
- H1: "[Before state] → [After state]" → Sub: "Here's how [product] bridges the gap" → Features: How it works (the bridge)
---
## Representative Component: Hero (Centered Gradient — Dark SaaS)
Use this as the structural template for all hero variants. Swap layout classes, gradient direction, and image placement for split, video-bg, and minimal variants.
```tsx
export function HeroCentered() {
return (
<section className="relative flex min-h-screen flex-col items-center justify-center overflow-hidden bg-gray-950 px-4 text-center">
<div className="absolute inset-0 bg-gradient-to-b from-violet-900/20 to-transparent" />
<div className="pointer-events-none absolute -top-40 left-1/2 h-[600px] w-[600px] -translate-x-1/2 rounded-full bg-violet-600/20 blur-3xl" />
<div className="relative z-10 max-w-4xl">
<div className="mb-6 inline-flex items-center gap-2 rounded-full border border-violet-500/30 bg-violet-500/10 px-4 py-1.5 text-sm text-violet-300">
<span className="h-1.5 w-1.5 rounded-full bg-violet-400" />
Now in public beta
</div>
<h1 className="mb-6 text-5xl font-bold tracking-tight text-white md:text-7xl">
Ship faster.<br />
<span className="bg-gradient-to-r from-violet-400 to-pink-400 bg-clip-text text-transparent">
Break less.
</span>
</h1>
<p className="mx-auto mb-10 max-w-2xl text-xl text-gray-400">
The deployment platform that catches errors before your users do.
Zero config. Instant rollbacks. Real-time monitoring.
</p>
<div className="flex flex-col items-center gap-4 sm:flex-row sm:justify-center">
<Button size="lg" className="bg-violet-600 text-white hover:bg-violet-500 px-8">
Start free trial
</Button>
<Button size="lg" variant="outline" className="border-gray-700 text-gray-300">
See how it works →
</Button>
</div>
<p className="mt-4 text-sm text-gray-500">No credit card required · 14-day free trial</p>
</div>
</section>
)
}
```
---
## Other Section Patterns
### Feature Section (Alternating)
Map over a `features` array with `{ title, description, image, badge }`. Toggle layout direction with `i % 2 === 1 ? "lg:flex-row-reverse" : ""`. Use `<Image>` with explicit `width`/`height` and `rounded-2xl shadow-xl`. Wrap in `<section className="py-24">` with `max-w-6xl` container.
### Pricing Table
Map over a `plans` array with `{ name, price, description, features[], cta, highlighted }`. Highlighted plan gets `border-2 border-violet-500 bg-violet-950/50 ring-4 ring-violet-500/20`; others get `border border-gray-800 bg-gray-900`. Render `null` price as "Custom". Use `<Check>` icon per feature row. Layout: `grid gap-8 lg:grid-cols-3`.
### FAQ with Schema Markup
Inject `FAQPage` JSON-LD via `<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }} />` inside the section. Map FAQs with `{ q, a }` into shadcn `<Accordion>` with `type="single" collapsible`. Container: `max-w-3xl`.
### Testimonials, CTA, Footer
- **Testimonials:** Grid (`grid-cols-1 md:grid-cols-3`) or single-quote hero block with avatar, name, role, and quote text.
- **CTA Banner:** Full-width section with headline, subhead, and two buttons (primary + ghost). Add trust signals (money-back guarantee, logo strip) immediately below.
- **Footer:** Logo + nav columns + social links + legal. Use `border-t border-gray-800` separator.
---
## SEO Checklist
- [ ] `<title>` tag: primary keyword + brand (50–60 chars)
- [ ] Meta description: benefit + CTA (150–160 chars)
- [ ] OG image: 1200×630px with product name and tagline
- [ ] H1: one per page, includes primary keyword
- [ ] Structured data: FAQPage, Product, or Organization schema
- [ ] Canonical URL set
- [ ] Image alt text on all `<Image>` components
- [ ] robots.txt and sitemap.xml configured
- [ ] Core Web Vitals: LCP < 1s, CLS < 0.1
- [ ] Mobile viewport meta tag present
- [ ] Internal linking to pricing and docs
> **Validation step:** Before outputting final code, verify every checklist item above is satisfied. Fix any gaps inline — do not skip items.
---
## Performance Targets
| Metric | Target | Technique |
|---|---|---|
| LCP | < 1s | Preload hero image, use `priority` on Next/Image |
| CLS | < 0.1 | Set explicit width/height on all images |
| FID/INP | < 100ms | Defer non-critical JS, use `loading="lazy"` |
| TTFB | < 200ms | Use ISR or static generation for landing pages |
| Bundle | < 100KB JS | Audit with `@next/bundle-analyzer` |
---
## Common Pitfalls
- Hero image not preloaded — add `priority` prop to first `<Image>`
- Missing mobile breakpoints — always design mobile-first with `sm:` prefixes
- CTA copy too vague — "Get started" beats "Learn more"; "Start free trial" beats "Sign up"
- Pricing page missing trust signals — add money-back guarantee and testimonials near CTA
- No above-the-fold CTA on mobile — ensure button is visible without scrolling on 375px viewport
---
## Related Skills
- **Brand Voice Analyzer** (`marketing-skill/content-production/scripts/brand_voice_analyzer.py`) — Run before generation to establish voice profile and ensure copy consistency
- **UI Design System** (`product-team/ui-design-system/`) — Generate design tokens from brand color before building the page
- **Competitive Teardown** (`product-team/competitive-teardown/`) — Competitive positioning informs landing page messaging and differentiation
FILE:references/conversion-patterns.md
# High-Converting Landing Page Patterns
## Overview
This reference catalogs proven landing page design patterns that drive higher conversion rates. Each pattern includes placement guidance, implementation notes, and A/B testing priorities.
## Hero Section Layouts
### Pattern 1: Left Copy + Right Product Screenshot
- **Best for:** SaaS products with a strong visual UI
- **Structure:** Headline, subheadline, CTA on left (60%); product screenshot on right (40%)
- **Why it works:** F-pattern reading leads with copy, product image provides proof
- **Conversion lift:** Baseline pattern, strong performer across industries
### Pattern 2: Centered Copy + Full-Width Background
- **Best for:** Brand-driven products, consumer apps
- **Structure:** Centered headline, subheadline, CTA over background image/gradient
- **Why it works:** Focuses attention on single message, high visual impact
- **Note:** Ensure text contrast against background for readability
### Pattern 3: Video Hero
- **Best for:** Complex products requiring demonstration
- **Structure:** Short headline + embedded video (60-90 seconds) + CTA below
- **Why it works:** Video explains what text cannot, increases time on page
- **Note:** Always include thumbnail; autoplay is often counterproductive
### Pattern 4: Interactive Demo
- **Best for:** Developer tools, data products, design tools
- **Structure:** Minimal copy + embedded interactive product experience
- **Why it works:** Hands-on experience converts better than description
- **Note:** Keep demo focused on one "aha moment" workflow
## Social Proof Placement
### Logo Bar
- **Position:** Immediately below hero section
- **Count:** 5-7 logos for credibility without clutter
- **Label:** "Trusted by" or "Used by teams at"
- **Selection:** Mix recognizable brands with relevant industry logos
### Testimonial Cards
- **Position:** After feature explanation sections
- **Format:** Photo + name + title + company + specific quote
- **Best quotes:** Include measurable outcomes ("Saved 10 hours/week")
- **Layout:** 2-3 testimonials in a row, carousel for more
### Case Study Callouts
- **Position:** Mid-page, before pricing
- **Format:** Company logo + headline metric + "Read the story" link
- **Example:** "Acme Corp reduced onboarding time by 60%"
### Social Proof Numbers
- **Position:** Near CTA or in dedicated trust section
- **Format:** Large number + descriptor (e.g., "50,000+ teams", "4.8/5 rating")
- **Selection:** Choose 3-4 most impressive metrics
## Pricing Table Designs
### Good/Better/Best (3-Tier)
- Most effective for SaaS with clear feature tiers
- Highlight recommended plan with visual emphasis
- Show annual discount prominently
- Include feature comparison matrix below
### Simple Two-Tier
- Free/Pro or Starter/Professional
- Best for PLG products with clear upgrade trigger
- Minimize decision fatigue
### Enterprise Custom
- Replace price with "Contact Sales" for high-ACV products
- List enterprise-specific features (SSO, SLA, dedicated support)
- Include a "Talk to Sales" CTA, not just a form
### Pricing Psychology
- Anchor with highest-priced plan first (or in the middle with visual highlight)
- Use monthly price with annual billing toggle
- Show savings percentage for annual plans
- Round prices ending in 9 (e.g., $49/mo, $99/mo)
## Trust Signals
### Security Badges
- SOC 2, ISO 27001, GDPR compliance badges
- SSL certificate indicator
- Place near forms and payment sections
### Guarantees
- Money-back guarantee with specific timeframe
- Free trial with no credit card requirement
- SLA uptime commitments
### Awards & Recognition
- Industry awards (best of, top rated)
- Analyst recognition (Gartner, Forrester, G2 Leader)
- Media mentions (as seen in logos)
### Real-Time Activity
- "X people signed up today" (use real data only)
- Recent activity feed
- Live user count
## Urgency Elements
### Ethical Urgency
- Limited-time pricing (with real deadline)
- Early adopter benefits (extra features, lower price)
- Cohort-based enrollment (actual capacity limits)
### Avoid
- Fake countdown timers that reset
- False scarcity ("only 3 left" when unlimited)
- Pressure tactics that erode trust
## Form Optimization
### Field Reduction
- Every additional field reduces conversion ~10%
- Start with email only, progressive profiling later
- Use single-column layouts for forms
### Smart Defaults
- Pre-fill country based on IP
- Auto-detect company from email domain
- Default to most popular plan
### Inline Validation
- Validate fields on blur, not on submit
- Show success states (green checkmark)
- Provide helpful error messages
### Multi-Step Forms
- Break long forms into 2-3 steps with progress indicator
- Put easiest questions first to build commitment
- Allow saving progress for complex forms
## Mobile-First Patterns
### Thumb-Friendly Design
- CTAs in thumb zone (bottom 40% of screen)
- Minimum tap target: 44x44px
- Adequate spacing between interactive elements
### Content Priority
- Lead with most compelling content (no scrolling to find CTA)
- Collapse secondary information into accordions
- Use sticky CTA bar on scroll
### Performance
- Target <3s load time on 3G
- Lazy-load images below fold
- Minimize JavaScript execution
## A/B Testing Priority Matrix
Test these elements in order of expected impact:
| Priority | Element | Expected Impact | Effort |
|----------|---------|----------------|--------|
| 1 | Headline | High | Low |
| 2 | CTA text and color | High | Low |
| 3 | Hero image/video | High | Medium |
| 4 | Social proof placement | Medium | Low |
| 5 | Form fields (fewer) | Medium | Low |
| 6 | Pricing presentation | Medium | Medium |
| 7 | Page length | Medium | High |
| 8 | Testimonial selection | Low | Low |
| 9 | Color scheme | Low | Medium |
| 10 | Font choices | Low | Low |
### Testing Best Practices
- Test one variable at a time for clear attribution
- Run tests for minimum 2 weeks or 1,000 visitors per variant
- Use 95% statistical significance threshold
- Document all test results for institutional knowledge
- Winner becomes new control for next test iteration
FILE:references/copy-frameworks.md
# Landing Page Copywriting Frameworks
## Overview
Four copy frameworks with worked SaaS examples you can adapt. Each framework includes a complete before/after example plus specific guidelines for each section.
## 1. AIDA Framework (Attention - Interest - Desire - Action)
The classic direct response formula, ideal for product landing pages.
**Example — Project management SaaS:**
> **Attention:** "Your Team Loses 12 Hours Every Sprint to Status Meetings"
>
> **Interest:** "Engineering teams at Series A-C startups spend 23% of their week in sync meetings — not writing code. We tracked 847 teams over 6 months. The pattern was clear: the more people in a standup, the less code shipped that day."
>
> **Desire:** "Teams using AsyncStand ship 31% more story points per sprint. No more 15-person standups where 13 people zone out. Replace your daily sync with a 2-minute async check-in that your engineers actually complete (94% response rate vs 67% attendance for live standups)."
>
> **Action:** "Start Your Free 14-Day Trial — No Credit Card Required"
### Attention
- Lead with a specific, quantified pain point (not vague claims)
- Weak: "Save time on meetings" → Strong: "Your Team Loses 12 Hours Every Sprint to Status Meetings"
- Keep headlines under 10 words for maximum impact
### Interest
- Back up the headline with specific data or a relatable scenario
- Weak: "Meetings waste time" → Strong: "We tracked 847 teams — the more people in standup, the less code shipped that day"
- Use their language: mirror words from customer reviews, support tickets, and G2 feedback
### Desire
- Stack measurable outcomes, not features
- Weak: "AI-powered async updates" → Strong: "31% more story points per sprint, 94% response rate"
- Compare directly to the status quo they already endure
### Action
- Single, clear CTA with action-oriented verb
- Reduce friction: "No credit card required," "Set up in 2 minutes"
- Repeat CTA after each major content block
## 2. PAS Framework (Problem - Agitate - Solution)
Best for pain-point-driven products where the problem is well understood.
**Example — Expense management tool:**
> **Problem:** "Your finance team is still chasing receipts in Slack DMs."
>
> **Agitate:** "Last quarter, your team spent 46 hours manually reconciling expenses across email threads, shared drives, and 'I'll submit it later' promises. That's $4,200 in payroll — spent on data entry. And when audit season hits? Good luck finding that client dinner receipt from February."
>
> **Solution:** "Snap a photo of the receipt. ExpenseFlow auto-extracts vendor, amount, and category in 3 seconds. Your monthly close drops from 5 days to 1. 2,400 finance teams already made the switch."
### Problem
- Name the exact scenario (not the abstract category)
- Weak: "Expense tracking is hard" → Strong: "Your finance team is still chasing receipts in Slack DMs"
- Mirror language from reviews and support tickets
### Agitate
- Quantify the cost in dollars, hours, or missed opportunities
- Weak: "This costs you money" → Strong: "46 hours last quarter, $4,200 in payroll — on data entry"
- Acknowledge the workarounds they've tried and why those fail too
### Solution
- Lead with the user action, not the technology: "Snap a photo" not "AI-powered OCR"
- Include one proof point: number of customers, time saved, or before/after metric
- Make the mechanism clear in one sentence: what happens when they use it
## 3. BAB Framework (Before - After - Bridge)
Ideal for aspirational products and lifestyle-oriented landing pages.
**Example — Sales enablement platform:**
> **Before:** "It's 9 PM. You're rebuilding a deck for tomorrow's demo because the prospect is in healthcare, not fintech. You copy-paste from three old decks, pray the logos are right, and rehearse the new talk track in the shower."
>
> **After:** "It's 9 AM. You type 'healthcare, 200-bed hospital, HIPAA-concerned CTO.' DeckGen builds your slides in 40 seconds — case studies, compliance badges, ROI calculator pre-loaded. You walk into the call with the best deck your prospect has ever seen."
>
> **Bridge:** "DeckGen connects to your CRM, learns your win patterns, and generates prospect-specific decks in under a minute. 340 AEs at companies like Stripe and Notion already use it. Start free — your first 5 decks are on us."
### Before
- Describe a specific, lived moment — not an abstract pain category
- Weak: "Sales decks take too long" → Strong: "It's 9 PM. You're rebuilding a deck for tomorrow's demo..."
- Use second person and present tense to make it feel immediate
### After
- Same level of specificity — show the transformed version of that exact moment
- Include a measurable outcome: "40 seconds," "best deck your prospect has ever seen"
- The after state should feel effortless compared to the before
### Bridge
- Name the product explicitly and explain the mechanism in one sentence
- Include one social proof data point
- End with a low-friction CTA that connects to the after state
## 4. 4Ps Framework (Promise - Picture - Proof - Push)
Strong for SaaS and B2B landing pages with measurable outcomes.
### Promise
- Make a clear, specific, believable promise
- Tie it to a measurable outcome
- Example: "Reduce customer churn by 25% in 90 days"
### Picture
- Help the reader visualize success
- Use scenarios they can relate to
- Show the product in context (screenshots, demos)
### Proof
- Back the promise with evidence
- Customer testimonials with specific results
- Case studies with before/after metrics
- Third-party validation (awards, analyst reports)
### Push
- Give a compelling reason to act now
- Limited-time offer, bonus, or guarantee
- Risk reversal (money-back guarantee, free trial)
## Headline Formulas
### Benefit-Driven
- "Get [Desired Outcome] Without [Common Objection]"
- "[Specific Result] in [Timeframe]"
- "The [Adjective] Way to [Achieve Goal]"
### Problem-Driven
- "Stop [Painful Activity]. Start [Better Alternative]."
- "Tired of [Problem]? There's a Better Way."
- "[Problem]? Not Anymore."
### Social Proof-Driven
- "[Number] Teams Trust [Product] to [Outcome]"
- "Why [Notable Company] Switched to [Product]"
- "Rated #1 for [Category] by [Authority]"
### Question-Driven
- "What If You Could [Desirable Outcome]?"
- "Ready to [Transformation]?"
- "Still [Painful Status Quo]?"
## CTA Best Practices
### Language
- Use first-person: "Start My Free Trial" > "Start Your Free Trial"
- Be specific: "Get My Report" > "Submit"
- Include benefit: "Start Saving Time" > "Sign Up"
- Add urgency naturally: "Start Free Today" > "Sign Up Now!!!"
### Placement
- Primary CTA above the fold
- Repeat after each major content section
- Sticky CTA on scroll (mobile especially)
- Exit-intent as last chance
### Design
- High contrast color (stands out from page palette)
- Sufficient whitespace around the button
- Large enough to tap on mobile (min 44x44px)
- Micro-copy below button to reduce anxiety ("No credit card required")
## Above-the-Fold Principles
The first viewport must accomplish these goals within 5 seconds:
1. **Communicate what you do** - Clear, jargon-free headline
2. **Show who it's for** - Audience identification
3. **Demonstrate value** - Primary benefit or outcome
4. **Provide next step** - Visible CTA button
5. **Build credibility** - One trust signal (logo bar, metric, badge)
### Above-the-Fold Checklist
- [ ] Headline states primary benefit (under 10 words)
- [ ] Subheadline adds specificity or addresses objection
- [ ] Hero image/video shows product in use
- [ ] CTA button is visible without scrolling
- [ ] At least one trust signal present
- [ ] No jargon or ambiguity in messaging
FILE:references/landing-page-patterns.md
# Landing Page Patterns
This reference captures high-converting page patterns and copy structures.
## Hero Section Patterns
### Pattern 1: Problem-Solution Hero
- Headline names the painful problem.
- Subheadline states the clear outcome.
- Primary CTA starts immediately.
- Optional supporting visual demonstrates product in context.
### Pattern 2: Outcome-First Hero
- Headline leads with measurable value.
- Subheadline clarifies who the page is for.
- CTA is action-oriented and specific.
### Pattern 3: Authority Hero
- Headline + trust indicator (logos, testimonial snippet, proof metric).
- Useful when category skepticism is high.
## Social Proof Layouts
### Logo Strip + Proof Metric
- Keep to recognizable logos.
- Add one proof metric (e.g., active users, revenue saved, hours reduced).
### Testimonial Grid
- 3-6 testimonials across segments.
- Include role/company where possible.
- Prefer concrete outcomes over generic praise.
### Case Study Snapshot
- Mini blocks: challenge -> approach -> measurable result.
## CTA Best Practices
- Use one dominant CTA per section.
- Match CTA verb to user intent ("Start trial", "Get demo", "Run audit").
- Keep CTA copy specific; avoid vague labels like "Submit".
- Reduce friction near CTA (short form, trust indicators, no surprise commitments).
## Above-the-Fold Checklist
- [ ] Clear value proposition in first viewport
- [ ] Audience clarity (who this is for)
- [ ] One primary CTA visible without scrolling
- [ ] Proof element (logos, stat, quote)
- [ ] Visual hierarchy emphasizes headline + CTA
- [ ] Mobile layout keeps CTA accessible
## Conversion-Optimized Templates
### SaaS Demo Page
1. Hero with problem-solution framing
2. Product walkthrough section
3. Social proof strip
4. Benefits by persona
5. Objection handling FAQ
6. Final CTA
### Lead Magnet Page
1. Promise + asset preview
2. Bullet outcomes
3. Short form
4. Trust/privacy note
### Product Launch Page
1. Outcome-first hero
2. Why now / differentiation
3. Feature blocks
4. Testimonials / beta feedback
5. Pricing or waitlist CTA
## Headline Formulas
### PAS (Problem-Agitate-Solution)
- Problem: identify the pain
- Agitate: show consequences of inaction
- Solution: position the offer as relief
Example structure:
"Still [problem]? Stop [negative consequence] and start [desired outcome]."
### AIDA (Attention-Interest-Desire-Action)
- Attention: pattern interrupt headline
- Interest: relevant context and stakes
- Desire: proof and benefits
- Action: concrete next step
### 4U Formula
- Useful: clear practical value
- Urgent: reason to act now
- Unique: differentiated promise
- Ultra-specific: concrete outcome and scope
Example structure:
"Get [specific result] in [timeframe] without [common pain]."
FILE:references/seo-checklist.md
# Landing Page SEO Checklist
## Overview
This checklist ensures landing pages are optimized for search engine visibility while maintaining conversion focus. Apply these checks before launching any landing page.
## Meta Tags
- [ ] **Title tag**: Under 60 characters, includes primary keyword, ends with brand name
- [ ] **Meta description**: 150-160 characters, includes CTA language, unique per page
- [ ] **Canonical URL**: Set to prevent duplicate content issues
- [ ] **Robots meta**: Ensure page is indexable (`index, follow`) unless intentionally noindex
- [ ] **Open Graph tags**: og:title, og:description, og:image, og:url for social sharing
- [ ] **Twitter Card tags**: twitter:card, twitter:title, twitter:description, twitter:image
- [ ] **Viewport meta**: `<meta name="viewport" content="width=device-width, initial-scale=1">`
## Structured Data
- [ ] **Organization schema**: Company name, logo, social profiles
- [ ] **Product schema**: Name, description, price, availability (for product pages)
- [ ] **FAQ schema**: For pages with FAQ sections (rich snippet opportunity)
- [ ] **Breadcrumb schema**: Navigation path for deep pages
- [ ] **Review schema**: Aggregate rating if testimonials present (use carefully per guidelines)
- [ ] **Validate**: Test all structured data with Google Rich Results Test
## Core Web Vitals Targets
### Largest Contentful Paint (LCP) - Target: < 2.5s
- [ ] Optimize hero image (WebP format, proper dimensions)
- [ ] Preload critical resources (`<link rel="preload">`)
- [ ] Use CDN for static assets
- [ ] Minimize render-blocking CSS and JavaScript
### First Input Delay (FID) / Interaction to Next Paint (INP) - Target: < 200ms
- [ ] Defer non-critical JavaScript
- [ ] Break up long tasks (>50ms)
- [ ] Minimize third-party script impact
- [ ] Use `requestAnimationFrame` for visual updates
### Cumulative Layout Shift (CLS) - Target: < 0.1
- [ ] Set explicit width/height on images and videos
- [ ] Reserve space for dynamic content (ads, embeds)
- [ ] Use `font-display: swap` for web fonts
- [ ] Avoid inserting content above existing content
## Keyword Placement
- [ ] **H1 tag**: Contains primary keyword, one per page only
- [ ] **H2 tags**: Include secondary keywords naturally
- [ ] **First paragraph**: Primary keyword appears in first 100 words
- [ ] **Body copy**: Natural keyword density (1-2%), no stuffing
- [ ] **Image alt text**: Descriptive, includes keyword where relevant
- [ ] **URL slug**: Short, keyword-rich, hyphen-separated
- [ ] **CTA text**: Consider keyword inclusion where natural
## Internal Linking
- [ ] Link to relevant product/feature pages
- [ ] Link to blog content that supports the page topic
- [ ] Use descriptive anchor text (not "click here")
- [ ] Ensure landing page is linked from main navigation or sitemap
- [ ] Link to pricing page if applicable
- [ ] Limit links to avoid diluting page authority (15-20 max)
## Image Optimization
- [ ] **Format**: Use WebP with JPEG/PNG fallback
- [ ] **Compression**: Lossy compression for photos, lossless for graphics
- [ ] **Dimensions**: Serve at exact display size (no CSS resizing)
- [ ] **Alt text**: Descriptive, 125 characters max, natural keyword inclusion
- [ ] **File names**: Descriptive, hyphenated (e.g., `product-dashboard-screenshot.webp`)
- [ ] **Lazy loading**: Apply to images below the fold (`loading="lazy"`)
- [ ] **Responsive images**: Use `srcset` for different viewport sizes
## Canonical URLs
- [ ] Self-referencing canonical on every page
- [ ] Consistent protocol (https) and trailing slash usage
- [ ] Canonical points to preferred URL version (www vs non-www)
- [ ] UTM parameters excluded from canonical URL
- [ ] Pagination handled with rel="next"/"prev" or single-page canonical
## Mobile Responsiveness
- [ ] **Mobile-friendly test**: Pass Google Mobile-Friendly Test
- [ ] **Touch targets**: Minimum 44x44px, 8px spacing between targets
- [ ] **Font size**: Minimum 16px base font, no pinch-to-zoom needed
- [ ] **Content parity**: All critical content accessible on mobile
- [ ] **Horizontal scroll**: None present at any viewport width
- [ ] **Form usability**: Appropriate input types (email, tel), autocomplete attributes
- [ ] **Media queries**: Breakpoints at 480px, 768px, 1024px, 1200px minimum
## Technical SEO
- [ ] **HTTPS**: SSL certificate valid and active
- [ ] **Page speed**: < 3s load time on mobile (test with PageSpeed Insights)
- [ ] **XML sitemap**: Page included in sitemap.xml
- [ ] **Robots.txt**: Page not blocked by robots.txt
- [ ] **404 handling**: Custom 404 page with navigation
- [ ] **Redirect chains**: No more than 1 redirect hop
- [ ] **Hreflang**: Set for multi-language landing pages
## Content Quality Signals
- [ ] **Unique content**: No duplicate content from other pages
- [ ] **Content depth**: Sufficient content for topic coverage (500+ words for SEO pages)
- [ ] **Readability**: Grade level 6-8 for broad audiences
- [ ] **Freshness**: Last modified date reflects recent updates
- [ ] **E-E-A-T signals**: Author expertise, company authority, trust indicators
FILE:scripts/landing_page_scaffolder.py
#!/usr/bin/env python3
"""Landing Page Scaffolder — Generate landing pages as HTML or Next.js TSX from config.
Creates production-ready landing pages with hero sections, features,
testimonials, pricing, CTAs, and responsive design.
Usage:
python landing_page_scaffolder.py config.json --format html --output page.html
python landing_page_scaffolder.py config.json --format tsx --output LandingPage.tsx
python landing_page_scaffolder.py config.json --format json
"""
import argparse
import json
import sys
from typing import Dict, List, Any, Optional
from datetime import datetime
import html as html_module
def escape(text: str) -> str:
"""HTML-escape text."""
return html_module.escape(str(text))
# ---------------------------------------------------------------------------
# Tailwind style mappings for TSX output
# ---------------------------------------------------------------------------
DESIGN_STYLES = {
"dark-saas": {
"bg": "bg-gray-950", "text": "text-white",
"accent": "violet", "card_bg": "bg-gray-900 border border-gray-800",
"btn": "bg-violet-600 hover:bg-violet-500 text-white",
"btn_secondary": "border border-gray-700 text-gray-300 hover:bg-gray-800",
"section_alt": "bg-gray-900/50", "muted": "text-gray-400",
"border": "border-gray-800",
},
"clean-minimal": {
"bg": "bg-white", "text": "text-gray-900",
"accent": "blue", "card_bg": "bg-gray-50 border border-gray-200 rounded-2xl",
"btn": "bg-blue-600 hover:bg-blue-700 text-white",
"btn_secondary": "border border-gray-300 text-gray-700 hover:bg-gray-50",
"section_alt": "bg-gray-50", "muted": "text-gray-500",
"border": "border-gray-200",
},
"bold-startup": {
"bg": "bg-white", "text": "text-gray-900",
"accent": "orange", "card_bg": "shadow-xl rounded-3xl bg-white",
"btn": "bg-orange-500 hover:bg-orange-600 text-white",
"btn_secondary": "border-2 border-orange-500 text-orange-600 hover:bg-orange-50",
"section_alt": "bg-orange-50/30", "muted": "text-gray-500",
"border": "border-gray-200",
},
"enterprise": {
"bg": "bg-slate-50", "text": "text-slate-900",
"accent": "slate", "card_bg": "bg-white border border-slate-200 shadow-sm",
"btn": "bg-slate-900 hover:bg-slate-800 text-white",
"btn_secondary": "border border-slate-300 text-slate-700 hover:bg-slate-100",
"section_alt": "bg-white", "muted": "text-slate-500",
"border": "border-slate-200",
},
}
# ---------------------------------------------------------------------------
# TSX generators
# ---------------------------------------------------------------------------
def tsx_nav(config: Dict[str, Any], style: Dict[str, str]) -> str:
brand = config.get("brand", "Brand")
nav_links = config.get("nav_links", [])
cta = config.get("nav_cta", {"text": "Get Started", "url": "#"})
links_jsx = "\n ".join(
f'<a href="{l.get("url", "#")}" className="{style["muted"]} hover:{style["text"]} font-medium transition-colors">{l.get("text", "")}</a>'
for l in nav_links
)
return f'''function Navbar() {{
return (
<nav className="sticky top-0 z-50 {style["bg"]} border-b {style["border"]} backdrop-blur-sm">
<div className="mx-auto flex max-w-7xl items-center justify-between px-6 py-4">
<a href="#" className="text-xl font-bold {style["text"]}">{brand}</a>
<div className="hidden items-center gap-8 md:flex">
{links_jsx}
<a href="{cta.get("url", "#")}" className="rounded-lg {style["btn"]} px-5 py-2.5 text-sm font-semibold transition-colors">
{cta.get("text", "Get Started")}
</a>
</div>
</div>
</nav>
);
}}'''
def tsx_hero(hero: Dict[str, Any], style: Dict[str, str]) -> str:
h1 = hero.get("headline", "Your Headline Here")
sub = hero.get("subheadline", "")
primary_cta = hero.get("primary_cta", {"text": "Get Started", "url": "#"})
secondary_cta = hero.get("secondary_cta", None)
secondary_jsx = ""
if secondary_cta:
secondary_jsx = f'''
<a href="{secondary_cta.get("url", "#")}" className="rounded-lg {style["btn_secondary"]} px-8 py-3 text-lg font-semibold transition-colors">
{secondary_cta.get("text", "Learn More")}
</a>'''
return f'''function Hero() {{
return (
<section className="flex min-h-[80vh] flex-col items-center justify-center px-6 py-24 text-center {style["bg"]}">
<div className="mx-auto max-w-4xl">
<h1 className="mb-6 text-5xl font-bold tracking-tight {style["text"]} md:text-7xl">
{h1}
</h1>
<p className="mx-auto mb-10 max-w-2xl text-xl {style["muted"]}">
{sub}
</p>
<div className="flex flex-col items-center gap-4 sm:flex-row sm:justify-center">
<a href="{primary_cta.get("url", "#")}" className="rounded-lg {style["btn"]} px-8 py-3 text-lg font-semibold transition-colors">
{primary_cta.get("text", "Get Started")}
</a>{secondary_jsx}
</div>
</div>
</section>
);
}}'''
def tsx_features(features: Dict[str, Any], style: Dict[str, str]) -> str:
title = features.get("title", "Features")
subtitle = features.get("subtitle", "")
items = features.get("items", [])
cards_jsx = "\n ".join(
f'''<div className="{style["card_bg"]} rounded-xl p-8">
<div className="mb-4 text-3xl">{f.get("icon", "")}</div>
<h3 className="mb-3 text-xl font-semibold {style["text"]}">{f.get("title", "")}</h3>
<p className="{style["muted"]}">{f.get("description", "")}</p>
</div>'''
for f in items
)
return f'''function Features() {{
return (
<section className="{style["section_alt"]} px-6 py-24">
<div className="mx-auto max-w-7xl">
<h2 className="mb-4 text-center text-4xl font-bold {style["text"]}">{title}</h2>
<p className="mx-auto mb-16 max-w-2xl text-center text-lg {style["muted"]}">{subtitle}</p>
<div className="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
{cards_jsx}
</div>
</div>
</section>
);
}}'''
def tsx_testimonials(testimonials: Dict[str, Any], style: Dict[str, str]) -> str:
title = testimonials.get("title", "What Our Customers Say")
items = testimonials.get("items", [])
if not items:
return ""
cards_jsx = "\n ".join(
f'''<div className="rounded-xl border {style["border"]} p-8">
<p className="mb-6 text-lg italic {style["muted"]}">"{t.get("quote", "")}"</p>
<div>
<p className="font-semibold {style["text"]}">{t.get("name", "")}</p>
<p className="text-sm {style["muted"]}">{t.get("title", "")}, {t.get("company", "")}</p>
</div>
</div>'''
for t in items
)
return f'''function Testimonials() {{
return (
<section className="px-6 py-24 {style["bg"]}">
<div className="mx-auto max-w-7xl">
<h2 className="mb-16 text-center text-4xl font-bold {style["text"]}">{title}</h2>
<div className="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
{cards_jsx}
</div>
</div>
</section>
);
}}'''
def tsx_pricing(pricing: Dict[str, Any], style: Dict[str, str]) -> str:
title = pricing.get("title", "Pricing")
plans = pricing.get("plans", [])
if not plans:
return ""
accent = style["accent"]
cards = []
for p in plans:
featured = p.get("featured", False)
border_cls = f"border-2 border-{accent}-500 ring-4 ring-{accent}-500/20" if featured else f"border {style['border']}"
badge = f'\n <div className="absolute -top-3 left-1/2 -translate-x-1/2 rounded-full bg-{accent}-600 px-4 py-1 text-xs font-semibold text-white">Most Popular</div>' if featured else ""
features_jsx = "\n ".join(
f'<li className="flex items-center gap-2 py-2"><span className="text-{accent}-500 font-bold">✓</span> {feat}</li>'
for feat in p.get("features", [])
)
cards.append(f'''<div className="relative rounded-2xl {border_cls} {style["card_bg"]} p-8 text-center">{badge}
<h3 className="mb-2 text-xl font-semibold {style["text"]}">{p.get("name", "")}</h3>
<div className="my-6 text-5xl font-extrabold {style["text"]}">p.get("price", "0")<span className="text-base font-normal {style["muted"]}">/mo</span></div>
<p className="{style["muted"]} mb-6">{p.get("description", "")}</p>
<ul className="mb-8 space-y-1 text-left {style["muted"]}">
{features_jsx}
</ul>
<a href="{p.get("cta_url", "#")}" className="block w-full rounded-lg {style["btn"]} py-3 text-center font-semibold transition-colors">
{p.get("cta_text", "Choose Plan")}
</a>
</div>''')
cards_jsx = "\n ".join(cards)
return f'''function Pricing() {{
return (
<section className="{style["section_alt"]} px-6 py-24">
<div className="mx-auto max-w-5xl">
<h2 className="mb-16 text-center text-4xl font-bold {style["text"]}">{title}</h2>
<div className="grid gap-8 lg:grid-cols-{min(len(plans), 3)}">
{cards_jsx}
</div>
</div>
</section>
);
}}'''
def tsx_cta(cta: Dict[str, Any], style: Dict[str, str]) -> str:
accent = style["accent"]
return f'''function CTASection() {{
return (
<section className="bg-{accent}-600 px-6 py-24 text-center text-white">
<div className="mx-auto max-w-3xl">
<h2 className="mb-4 text-4xl font-bold">{cta.get("headline", "Ready to get started?")}</h2>
<p className="mb-10 text-xl opacity-90">{cta.get("subheadline", "")}</p>
<a href="{cta.get("url", "#")}" className="rounded-lg bg-white px-8 py-3 text-lg font-semibold text-{accent}-600 transition-colors hover:bg-gray-100">
{cta.get("text", "Start Free Trial")}
</a>
</div>
</section>
);
}}'''
def tsx_footer(config: Dict[str, Any], style: Dict[str, str]) -> str:
brand = config.get("brand", "Company")
year = datetime.now().year
footer_text = config.get("footer_text", f"{year} {brand}. All rights reserved.")
return f'''function Footer() {{
return (
<footer className="border-t {style["border"]} {style["bg"]} px-6 py-10 text-center {style["muted"]}">
<p>© {footer_text}</p>
</footer>
);
}}'''
def generate_tsx(config: Dict[str, Any]) -> str:
"""Generate complete Next.js/React TSX landing page with Tailwind CSS."""
style_name = config.get("design_style", "clean-minimal")
style = DESIGN_STYLES.get(style_name, DESIGN_STYLES["clean-minimal"])
components = []
component_names = []
components.append(tsx_nav(config, style))
component_names.append("Navbar")
if config.get("hero"):
components.append(tsx_hero(config["hero"], style))
component_names.append("Hero")
if config.get("features"):
components.append(tsx_features(config["features"], style))
component_names.append("Features")
if config.get("testimonials") and config["testimonials"].get("items"):
components.append(tsx_testimonials(config["testimonials"], style))
component_names.append("Testimonials")
if config.get("pricing") and config["pricing"].get("plans"):
components.append(tsx_pricing(config["pricing"], style))
component_names.append("Pricing")
if config.get("cta"):
components.append(tsx_cta(config["cta"], style))
component_names.append("CTASection")
components.append(tsx_footer(config, style))
component_names.append("Footer")
title = config.get("title", "Landing Page")
meta_desc = config.get("meta_description", "")
page_body = "\n ".join(f"<{name} />" for name in component_names)
all_components = "\n\n".join(components)
return f'''// Generated by Landing Page Scaffolder — {datetime.now().strftime("%Y-%m-%d")}
// Stack: Next.js 14+ App Router, React, Tailwind CSS
// Design style: {style_name}
import type {{ Metadata }} from "next";
export const metadata: Metadata = {{
title: "{title}",
description: "{meta_desc}",
openGraph: {{
title: "{title}",
description: "{meta_desc}",
type: "website",
}},
}};
{all_components}
export default function LandingPage() {{
return (
<main>
{page_body}
</main>
);
}}
'''
# ---------------------------------------------------------------------------
# HTML generators (existing)
# ---------------------------------------------------------------------------
def generate_css(config: Dict[str, Any]) -> str:
"""Generate responsive CSS from config theme."""
theme = config.get("theme", {})
primary = theme.get("primary_color", "#2563eb")
secondary = theme.get("secondary_color", "#1e40af")
bg = theme.get("background", "#ffffff")
text_color = theme.get("text_color", "#1f2937")
font = theme.get("font", "Inter, system-ui, -apple-system, sans-serif")
return f"""
* {{ margin: 0; padding: 0; box-sizing: border-box; }}
body {{ font-family: {font}; color: {text_color}; background: {bg}; line-height: 1.6; }}
.container {{ max-width: 1200px; margin: 0 auto; padding: 0 24px; }}
nav {{ padding: 16px 0; border-bottom: 1px solid #e5e7eb; position: sticky; top: 0; background: {bg}; z-index: 100; }}
nav .container {{ display: flex; justify-content: space-between; align-items: center; }}
.nav-logo {{ font-size: 1.5rem; font-weight: 700; color: {primary}; text-decoration: none; }}
.nav-links {{ display: flex; gap: 24px; list-style: none; }}
.nav-links a {{ text-decoration: none; color: {text_color}; font-weight: 500; }}
.nav-cta {{ background: {primary}; color: white; padding: 8px 20px; border-radius: 6px; text-decoration: none; font-weight: 600; }}
.hero {{ padding: 80px 0; text-align: center; }}
.hero h1 {{ font-size: 3.5rem; font-weight: 800; line-height: 1.1; margin-bottom: 24px; max-width: 800px; margin-left: auto; margin-right: auto; }}
.hero p {{ font-size: 1.25rem; color: #6b7280; max-width: 600px; margin: 0 auto 32px; }}
.hero-cta {{ display: inline-flex; gap: 16px; }}
.btn-primary {{ background: {primary}; color: white; padding: 14px 32px; border-radius: 8px; text-decoration: none; font-weight: 600; font-size: 1.1rem; }}
.btn-secondary {{ background: transparent; color: {primary}; padding: 14px 32px; border-radius: 8px; text-decoration: none; font-weight: 600; font-size: 1.1rem; border: 2px solid {primary}; }}
.features {{ padding: 80px 0; background: #f9fafb; }}
.section-title {{ text-align: center; font-size: 2.5rem; font-weight: 700; margin-bottom: 16px; }}
.section-subtitle {{ text-align: center; color: #6b7280; font-size: 1.1rem; margin-bottom: 48px; max-width: 600px; margin-left: auto; margin-right: auto; }}
.features-grid {{ display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 32px; }}
.feature-card {{ background: white; padding: 32px; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }}
.feature-icon {{ font-size: 2rem; margin-bottom: 16px; }}
.feature-card h3 {{ font-size: 1.25rem; margin-bottom: 12px; }}
.feature-card p {{ color: #6b7280; }}
.testimonials {{ padding: 80px 0; }}
.testimonials-grid {{ display: grid; grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); gap: 24px; }}
.testimonial-card {{ padding: 32px; border: 1px solid #e5e7eb; border-radius: 12px; }}
.testimonial-text {{ font-size: 1.1rem; font-style: italic; margin-bottom: 20px; }}
.testimonial-author {{ display: flex; align-items: center; gap: 12px; }}
.author-info strong {{ display: block; }}
.author-info span {{ color: #6b7280; font-size: 0.9rem; }}
.pricing {{ padding: 80px 0; background: #f9fafb; }}
.pricing-grid {{ display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 24px; max-width: 900px; margin: 0 auto; }}
.pricing-card {{ background: white; padding: 32px; border-radius: 12px; border: 2px solid #e5e7eb; text-align: center; }}
.pricing-card.featured {{ border-color: {primary}; position: relative; }}
.pricing-card.featured::before {{ content: "Most Popular"; position: absolute; top: -12px; left: 50%; transform: translateX(-50%); background: {primary}; color: white; padding: 4px 16px; border-radius: 20px; font-size: 0.8rem; font-weight: 600; }}
.pricing-name {{ font-size: 1.25rem; font-weight: 600; margin-bottom: 8px; }}
.pricing-price {{ font-size: 3rem; font-weight: 800; margin: 16px 0; }}
.pricing-price span {{ font-size: 1rem; font-weight: 400; color: #6b7280; }}
.pricing-features {{ list-style: none; text-align: left; margin: 24px 0; }}
.pricing-features li {{ padding: 8px 0; border-bottom: 1px solid #f3f4f6; }}
.pricing-features li::before {{ content: "\\2713 "; color: {primary}; font-weight: 700; }}
.cta-section {{ padding: 80px 0; text-align: center; background: {primary}; color: white; }}
.cta-section h2 {{ font-size: 2.5rem; margin-bottom: 16px; }}
.cta-section p {{ font-size: 1.1rem; opacity: 0.9; margin-bottom: 32px; }}
.btn-white {{ background: white; color: {primary}; padding: 14px 32px; border-radius: 8px; text-decoration: none; font-weight: 600; font-size: 1.1rem; }}
footer {{ padding: 40px 0; border-top: 1px solid #e5e7eb; color: #6b7280; text-align: center; }}
@media (max-width: 768px) {{
.hero h1 {{ font-size: 2.25rem; }}
.hero-cta {{ flex-direction: column; align-items: center; }}
.nav-links {{ display: none; }}
.features-grid {{ grid-template-columns: 1fr; }}
.pricing-grid {{ grid-template-columns: 1fr; }}
}}
"""
def render_nav(config: Dict[str, Any]) -> str:
brand = escape(config.get("brand", "Brand"))
nav_links = config.get("nav_links", [])
cta = config.get("nav_cta", {"text": "Get Started", "url": "#"})
links = "\n".join(
f'<li><a href="{escape(l.get("url", "#"))}">{escape(l.get("text", ""))}</a></li>'
for l in nav_links
)
return f"""
<nav><div class="container">
<a href="#" class="nav-logo">{brand}</a>
<ul class="nav-links">{links}</ul>
<a href="{escape(cta.get('url', '#'))}" class="nav-cta">{escape(cta.get('text', 'Get Started'))}</a>
</div></nav>"""
def render_hero(hero: Dict[str, Any]) -> str:
h1 = escape(hero.get("headline", "Your Headline Here"))
sub = escape(hero.get("subheadline", ""))
primary_cta = hero.get("primary_cta", {"text": "Get Started", "url": "#"})
secondary_cta = hero.get("secondary_cta", None)
cta_html = f'<a href="{escape(primary_cta.get("url", "#"))}" class="btn-primary">{escape(primary_cta.get("text", "Get Started"))}</a>'
if secondary_cta:
cta_html += f'\n<a href="{escape(secondary_cta.get("url", "#"))}" class="btn-secondary">{escape(secondary_cta.get("text", "Learn More"))}</a>'
return f"""
<section class="hero"><div class="container">
<h1>{h1}</h1>
<p>{sub}</p>
<div class="hero-cta">{cta_html}</div>
</div></section>"""
def render_features(features: Dict[str, Any]) -> str:
title = escape(features.get("title", "Features"))
subtitle = escape(features.get("subtitle", ""))
items = features.get("items", [])
cards = "\n".join(f"""
<div class="feature-card">
<div class="feature-icon">{escape(f.get('icon', ''))}</div>
<h3>{escape(f.get('title', ''))}</h3>
<p>{escape(f.get('description', ''))}</p>
</div>""" for f in items)
return f"""
<section class="features"><div class="container">
<h2 class="section-title">{title}</h2>
<p class="section-subtitle">{subtitle}</p>
<div class="features-grid">{cards}</div>
</div></section>"""
def render_testimonials(testimonials: Dict[str, Any]) -> str:
title = escape(testimonials.get("title", "What Our Customers Say"))
items = testimonials.get("items", [])
if not items:
return ""
cards = "\n".join(f"""
<div class="testimonial-card">
<p class="testimonial-text">"{escape(t.get('quote', ''))}"</p>
<div class="testimonial-author">
<div class="author-info">
<strong>{escape(t.get('name', ''))}</strong>
<span>{escape(t.get('title', ''))}, {escape(t.get('company', ''))}</span>
</div>
</div>
</div>""" for t in items)
return f"""
<section class="testimonials"><div class="container">
<h2 class="section-title">{title}</h2>
<div class="testimonials-grid">{cards}</div>
</div></section>"""
def render_pricing(pricing: Dict[str, Any]) -> str:
title = escape(pricing.get("title", "Pricing"))
plans = pricing.get("plans", [])
if not plans:
return ""
cards = "\n".join(f"""
<div class="pricing-card {'featured' if p.get('featured') else ''}">
<div class="pricing-name">{escape(p.get('name', ''))}</div>
<div class="pricing-price">escape(str(p.get('price', '0')))<span>/mo</span></div>
<p>{escape(p.get('description', ''))}</p>
<ul class="pricing-features">
{"".join(f'<li>{escape(f)}</li>' for f in p.get('features', []))}
</ul>
<a href="{escape(p.get('cta_url', '#'))}" class="btn-primary">{escape(p.get('cta_text', 'Choose Plan'))}</a>
</div>""" for p in plans)
return f"""
<section class="pricing"><div class="container">
<h2 class="section-title">{title}</h2>
<div class="pricing-grid">{cards}</div>
</div></section>"""
def render_cta(cta: Dict[str, Any]) -> str:
return f"""
<section class="cta-section"><div class="container">
<h2>{escape(cta.get('headline', 'Ready to get started?'))}</h2>
<p>{escape(cta.get('subheadline', ''))}</p>
<a href="{escape(cta.get('url', '#'))}" class="btn-white">{escape(cta.get('text', 'Start Free Trial'))}</a>
</div></section>"""
def generate_html(config: Dict[str, Any]) -> str:
"""Generate complete HTML landing page."""
title = escape(config.get("title", "Landing Page"))
css = generate_css(config)
sections = []
sections.append(render_nav(config))
if config.get("hero"):
sections.append(render_hero(config["hero"]))
if config.get("features"):
sections.append(render_features(config["features"]))
if config.get("testimonials"):
sections.append(render_testimonials(config["testimonials"]))
if config.get("pricing"):
sections.append(render_pricing(config["pricing"]))
if config.get("cta"):
sections.append(render_cta(config["cta"]))
sections.append(f"""
<footer><div class="container">
<p>{escape(config.get('footer_text', f'{datetime.now().year} {config.get("brand", "Company")}. All rights reserved.'))}</p>
</div></footer>""")
return f"""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{title}</title>
<meta name="description" content="{escape(config.get('meta_description', ''))}">
<style>{css}</style>
</head>
<body>
{"".join(sections)}
</body>
</html>"""
def main():
parser = argparse.ArgumentParser(
description="Generate landing pages as HTML or Next.js TSX with Tailwind CSS"
)
parser.add_argument("input", help="Path to page config JSON")
parser.add_argument(
"--format", choices=["html", "tsx", "json"], default="tsx",
help="Output format: tsx (Next.js + Tailwind), html (standalone), json (metadata)"
)
parser.add_argument("--output", type=str, default=None, help="Output file path")
args = parser.parse_args()
with open(args.input) as f:
config = json.load(f)
if args.format == "json":
output = json.dumps({
"generated_at": datetime.now().isoformat(),
"config": config,
"formats_available": ["html", "tsx"],
"sections": [k for k in ["nav", "hero", "features", "testimonials", "pricing", "cta", "footer"]
if config.get(k) or k in ("nav", "footer")]
}, indent=2)
elif args.format == "tsx":
output = generate_tsx(config)
else:
output = generate_html(config)
if args.output:
with open(args.output, "w") as f:
f.write(output)
print(f"Landing page written to {args.output}")
else:
print(output)
if __name__ == "__main__":
main()
Chuẩn bị họp HĐQT theo kịch bản khó: nắm chắc số liệu, lường trước câu hỏi hóc búa và xây dựng thông điệp.
--- name: "board-prep" description: "Board meeting preparation for the adversarial scenario, not the friendly one. Forces numbers-cold mastery, anticipates hard questions, builds a narrative that acknowledges weakness without losing the room. Use when preparing for a board meeting, an investor update, fundraising presentation, or any high-stakes adversarial review where every number must live in your head not just on a slide." --- # /em:board-prep — Board Meeting Preparation **Command:** `/em:board-prep <agenda>` Prepare for the adversarial version of your board, not the friendly one. Every hard question they'll ask. Every number you need cold. The narrative that acknowledges weakness without losing the room. --- ## The Reality of Board Meetings Your board members have seen 50+ companies. They've watched founders flinch at their own numbers, spin bad news as "learning opportunities," and present sanitized decks that hide what's actually happening. They know when you're not being straight with them. The question isn't whether they'll ask the hard questions — it's whether you're ready for them. The best board meetings aren't the ones where everything looks good. They're the ones where the CEO demonstrates they see reality clearly, have a plan, and can execute under pressure. --- ## The Preparation Framework ### Phase 1: Numbers Cold Before the meeting, every number in your deck should live in your head, not just the slide. **The numbers you must know without looking:** - Current MRR / ARR and month-over-month growth rate - Burn rate (monthly) and runway (months at current burn) - Headcount by department - CAC and LTV by channel / segment - Net Revenue Retention - Pipeline: value, conversion rate, average sales cycle - Churn: rate, top reasons, top churned accounts - Gross margin (product), net margin (company) - Key hiring positions open and time-to-fill **Stress test yourself:** Can you answer "what's your burn?" without hesitation? "What's your churn rate by segment?" If you pause, you don't know it. ### Phase 2: Anticipate the Hard Questions For every item on the agenda, generate the adversarial version of the question. **Standard adversarial questions by topic:** *Revenue performance:* - "You missed revenue by 20% this quarter. What specifically failed?" - "Is this a pipeline problem, a conversion problem, or a capacity problem?" - "If you missed because of one big deal, how dependent is your model on individual deals?" - "When do you project recovery and what are the leading indicators you're right?" *Runway / burn:* - "At current burn you have N months. What's your plan if the next round takes 9 months?" - "What would you cut first if you had to extend runway by 6 months today?" - "Is there a scenario where you don't raise another round?" *Product / roadmap:* - "You shipped X. What did customers actually do with it?" - "What did you kill this quarter and why?" - "Where are you behind on roadmap? What's slipping?" *Team:* - "Who's at risk of leaving? How would that affect execution?" - "You've had 3 VP-level hires not work out. What pattern do you see?" - "Is the team the right team for this stage?" *Competition:* - "Competitor Y just raised $50M. How does that change your position?" - "If they copy your best feature in 90 days, what's your moat?" ### Phase 3: Build the Narrative The board meeting isn't a status update. It's a leadership demonstration. **The structure that works:** 1. **Where we are (honest)** — Current state of business, the real number, not the smoothed one 2. **What we learned** — What the data is telling us that we didn't know 90 days ago 3. **What we got wrong** — Name it directly. Don't make them ask. 4. **What we're doing about it** — Specific, dated, owned actions 5. **What we need from this room** — Concrete ask. Not "support" — specific introductions, decisions, resources. **The rule on bad news:** Never let the board be surprised. If a quarter went badly, they should know before the deck. A 5-sentence email 3 days before: "Revenue came in at $X vs $Y target. Here's what happened, here's what I'm doing, here's what I need from you." ### Phase 4: Adversarial Preparation Do a mock board meeting. Have someone play the hardest director you have. **The simulation:** - Present your deck as you would - The mock director asks every uncomfortable question - You answer without referring to the deck - After: note every question that made you pause or feel defensive **The questions that made you defensive = the questions you need to prepare for.** ### Phase 5: Director-by-Director Prep Not all board members want the same thing from a meeting. **For each director, know:** - Their primary concern right now (usually tied to their investment thesis) - The metric they watch most closely - What would make them lose confidence in you - What they've said in the last meeting that you should address **Common director types:** - **The operator** — wants to know what's breaking and who owns fixing it - **The financial investor** — focused on path to profitability or next raise - **The strategic investor** — worried about competitive position and moat - **The independent** — watching governance, team dynamics, and your judgment --- ## Pre-Meeting Checklist **48 hours before:** - [ ] All numbers verified against source systems (not last week's export) - [ ] Deck reviewed for internal consistency - [ ] Pre-read sent to board (deck + 1-page brief on key topics) - [ ] One-on-ones done with any director likely to have concerns - [ ] 3 hardest questions you expect — rehearsed out loud **Day of meeting:** - [ ] Agenda with time allocations distributed - [ ] Know the ask for each agenda item (decision needed, input wanted, FYI) - [ ] Materials to leave behind prepared - [ ] Follow-up action template ready --- ## During the Meeting **What the board is watching:** - Do you own the bad news or deflect it? - Are you defending a narrative or sharing reality? - Do you know your numbers or do you look things up? - When challenged, do you get defensive or engage? - Do you know what you don't know? **The single best thing you can do:** Name the hard thing before they do. "I want to address the revenue miss directly. Here's what happened, here's what I should have caught earlier, here's what changes." --- ## After the Meeting Within 24 hours: - Send action items with owners and dates - Send any data you promised but didn't have - Note the questions that came up you weren't ready for - Schedule follow-up with any director who seemed unsatisfied The next board prep starts now.
Đánh giá khách quan chất lượng công việc của AI bằng thang điểm hai trục, phát hiện điểm thổi phồng và lưu điểm qua các phiên.
---
name: "self-eval"
description: "Honestly evaluate AI work quality using a two-axis scoring system. Use after completing a task, code review, or work session to get an unbiased assessment. Detects score inflation, forces devil's advocate reasoning, and persists scores across sessions."
license: "MIT"
---
# Self-Eval: Honest Work Evaluation
ultrathink
**Tier:** STANDARD
**Category:** Engineering / Quality
**Dependencies:** None (prompt-only, no external tools required)
## Description
Self-eval is a Claude Code skill that produces honest, calibrated work evaluations. It replaces the default AI tendency to rate everything 4/5 with a structured two-axis scoring system, mandatory devil's advocate reasoning, and cross-session anti-inflation detection.
The core insight: AI self-assessment converges to "everything is a 4" because a single-axis score conflates task difficulty with execution quality. Self-eval separates these axes, then combines them via a fixed matrix that the model cannot override.
## Features
- **Two-axis scoring** — Independently rates task ambition (Low/Medium/High) and execution quality (Poor/Adequate/Strong), then combines via a lookup matrix
- **Mandatory devil's advocate** — Before finalizing, must argue for both higher AND lower scores, then resolve the tension
- **Score persistence** — Appends scores to `.self-eval-scores.jsonl` in the working directory, building history across sessions
- **Anti-inflation detection** — Reads past scores and flags clustering (4+ of last 5 identical)
- **Matrix-locked scoring** — The composite score comes from the matrix, not from direct selection. Low ambition caps at 2/5 regardless of execution quality
## Usage
After completing work in a Claude Code session:
```
/self-eval
```
With context about what to evaluate:
```
/self-eval the authentication refactor we just completed
```
The skill reviews the conversation history, identifies what was accomplished, scores it on both axes, runs the devil's advocate check, and appends the result to the score history file.
## Examples
### Example 1: Feature Implementation
```
/self-eval added pagination to the user list API
```
Output:
```
## Self-Evaluation
**Task:** Added cursor-based pagination to the user list API endpoint
**Ambition:** Medium — New feature with established patterns, but required careful backwards compatibility
**Execution:** Strong — All tests pass, handles edge cases, existing clients unaffected
**Devil's Advocate:**
- Lower: Pagination is well-documented. The pattern was copied from another endpoint with minor changes. Could argue Low ambition.
- Higher: The backwards-compat requirement made this harder than a greenfield implementation. Had to support both offset and cursor modes.
- Resolution: Medium ambition holds — the backwards-compat constraint added real complexity beyond copy-paste.
**Score: 4** — Solid execution on meaningful work with real constraints.
```
### Example 2: Bug Fix
```
/self-eval
```
Output:
```
## Self-Evaluation
**Task:** Fixed race condition in the checkout flow causing duplicate orders
**Ambition:** Medium — Required debugging across 3 services to find the root cause
**Execution:** Adequate — Fix works but the test only covers the exact scenario reported, not the general class of race conditions
**Devil's Advocate:**
- Lower: The fix was a single line (adding a mutex). Once found, it was trivial.
- Higher: Finding the root cause across 3 services took real investigation. The mutex placement required understanding the full flow.
- Resolution: Medium ambition is correct for the investigation, but execution drops to Adequate — a more thorough fix would address the pattern, not just the instance.
**Score: 3** — Good debugging work but the fix is narrow.
```
---
## What to Evaluate
$ARGUMENTS
If no arguments provided, review the full conversation history to identify what was accomplished this session. Summarize the work in one sentence before scoring.
## How to Score — Two-Axis Model
Score on two independent axes, then combine using the matrix. Do NOT pick a number first and rationalize it — rate each axis separately, then read the matrix.
### Axis 1: Task Ambition (what was attempted)
Rate the difficulty and risk of what was worked on. NOT how well it was done.
- **Low (1)** — Safe, familiar, routine. No real risk of failure. Examples: minor config changes, simple refactors, copy-paste with small modifications, tasks you were confident you'd complete before starting.
- **Medium (2)** — Meaningful work with novelty or challenge. Partial failure was possible. Examples: new feature implementation, integrating an unfamiliar API, architectural changes, debugging a tricky issue.
- **High (3)** — Ambitious, unfamiliar, or high-stakes. Real risk of complete failure. Examples: building something from scratch in an unfamiliar domain, complex system redesign, performance-critical optimization, shipping to production under pressure.
**Self-check:** If you were confident of success before starting, ambition is Low or Medium, not High.
### Axis 2: Execution Quality (how well it was done)
Rate the quality of the actual output, independent of how ambitious the task was.
- **Poor (1)** — Major failures, incomplete, wrong output, or abandoned mid-task. The deliverable doesn't meet its own stated criteria.
- **Adequate (2)** — Completed but with gaps, shortcuts, or missing rigor. Did the thing but left obvious improvements on the table.
- **Strong (3)** — Well-executed, thorough, quality output. No obvious improvements left undone given the scope.
### Composite Score Matrix
| | Poor Exec (1) | Adequate Exec (2) | Strong Exec (3) |
|------------------------|:---:|:---:|:---:|
| **Low Ambition (1)** | 1 | 2 | 2 |
| **Medium Ambition (2)**| 2 | 3 | 4 |
| **High Ambition (3)** | 2 | 4 | 5 |
**Read the matrix, don't override it.** The composite is your score. The devil's advocate below can cause you to re-rate an axis — but you cannot directly override the matrix result.
Key properties:
- Low ambition caps at 2. Safe work done perfectly is still safe work.
- A 5 requires BOTH high ambition AND strong execution. It should be rare.
- High ambition + poor execution = 2. Bold failure hurts.
- The most common honest score for solid work is 3 (medium ambition, adequate execution).
## Devil's Advocate (MANDATORY)
Before writing your final score, you MUST write all three of these:
1. **Case for LOWER:** Why might this work deserve a lower score? What was easy, what was avoided, what was less ambitious than it appears? Would a skeptical reviewer agree with your axis ratings?
2. **Case for HIGHER:** Why might this work deserve a higher score? What was genuinely challenging, surprising, or exceeded the original plan?
3. **Resolution:** If either case reveals you mis-rated an axis, re-rate it and recompute the matrix result. Then state your final score with a 1-2 sentence justification that addresses at least one point from each case.
If your devil's advocate is less than 3 sentences total, you're not engaging with it — try harder.
## Anti-Inflation Check
Check for a score history file at `.self-eval-scores.jsonl` in the current working directory.
If the file exists, read it and check the last 5 scores. If 4+ of the last 5 are the same number, flag it:
> **Warning: Score clustering detected.** Last 5 scores: [list]. Consider whether you're anchoring to a default.
If the file doesn't exist, ask yourself: "Would an outside observer rate this the same way I am?"
## Score Persistence
After presenting your evaluation, append one line to `.self-eval-scores.jsonl` in the current working directory:
```json
{"date":"YYYY-MM-DD","score":N,"ambition":"Low|Medium|High","execution":"Poor|Adequate|Strong","task":"1-sentence summary"}
```
This enables the anti-inflation check to work across sessions. If the file doesn't exist, create it.
## Output Format
Present your evaluation as:
## Self-Evaluation
**Task:** [1-sentence summary of what was attempted]
**Ambition:** [Low/Medium/High] — [1-sentence justification]
**Execution:** [Poor/Adequate/Strong] — [1-sentence justification]
**Devil's Advocate:**
- Lower: [why it might deserve less]
- Higher: [why it might deserve more]
- Resolution: [final reasoning]
**Score: [1-5]** — [1-sentence final justification]
Chuyên gia đánh giá hệ thống quản lý an toàn thông tin (ISMS), kiểm tra tuân thủ ISO 27001, đánh giá kiểm soát Annex A và hỗ trợ chứng nhận.
---
name: "isms-audit-expert"
description: Information Security Management System (ISMS) audit expert for ISO 27001 compliance verification, security control assessment, and certification support. Use when the user mentions ISO 27001, ISMS audit, Annex A controls, Statement of Applicability (SOA), gap analysis, nonconformity management, internal audit, surveillance audit, or security certification preparation. Helps review control implementation evidence, document audit findings, classify nonconformities, generate risk-based audit plans, map controls to Annex A requirements, prepare Stage 1 and Stage 2 audit documentation, and support corrective action workflows.
triggers:
- ISMS audit
- ISO 27001 audit
- security audit
- internal audit ISO 27001
- security control assessment
- certification audit
- surveillance audit
- audit finding
- nonconformity
---
# ISMS Audit Expert
Internal and external ISMS audit management for ISO 27001 compliance verification, security control assessment, and certification support.
## Table of Contents
- [Audit Program Management](#audit-program-management)
- [Audit Execution](#audit-execution)
- [Control Assessment](#control-assessment)
- [Finding Management](#finding-management)
- [Certification Support](#certification-support)
- [Tools](#tools)
- [References](#references)
---
## Audit Program Management
### Risk-Based Audit Schedule
| Risk Level | Audit Frequency | Examples |
|------------|-----------------|----------|
| Critical | Quarterly | Privileged access, vulnerability management, logging |
| High | Semi-annual | Access control, incident response, encryption |
| Medium | Annual | Policies, awareness training, physical security |
| Low | Annual | Documentation, asset inventory |
### Annual Audit Planning Workflow
1. Review previous audit findings and risk assessment results
2. Identify high-risk controls and recent security incidents
3. Determine audit scope based on ISMS boundaries
4. Assign auditors ensuring independence from audited areas
5. Create audit schedule with resource allocation
6. Obtain management approval for audit plan
7. **Validation:** Audit plan covers all Annex A controls within certification cycle
### Auditor Competency Requirements
- ISO 27001 Lead Auditor certification (preferred)
- No operational responsibility for audited processes
- Understanding of technical security controls
- Knowledge of applicable regulations (GDPR, HIPAA)
---
## Audit Execution
### Pre-Audit Preparation
1. Review ISMS documentation (policies, SoA, risk assessment)
2. Analyze previous audit reports and open findings
3. Prepare audit plan with interview schedule
4. Notify auditees of audit scope and timing
5. Prepare checklists for controls in scope
6. **Validation:** All documentation received and reviewed before opening meeting
### Audit Conduct Steps
1. **Opening Meeting**
- Confirm audit scope and objectives
- Introduce audit team and methodology
- Agree on communication channels and logistics
2. **Evidence Collection**
- Interview control owners and operators
- Review documentation and records
- Observe processes in operation
- Inspect technical configurations
3. **Control Verification**
- Test control design (does it address the risk?)
- Test control operation (is it working as intended?)
- Sample transactions and records
- Document all evidence collected
4. **Closing Meeting**
- Present preliminary findings
- Clarify any factual inaccuracies
- Agree on finding classification
- Confirm corrective action timelines
5. **Validation:** All controls in scope assessed with documented evidence
---
## Control Assessment
### Control Testing Approach
1. Identify control objective from ISO 27002
2. Determine testing method (inquiry, observation, inspection, re-performance)
3. Define sample size based on population and risk
4. Execute test and document results
5. Evaluate control effectiveness
6. **Validation:** Evidence supports conclusion about control status
For detailed technical verification procedures by Annex A control, see [security-control-testing.md](references/security-control-testing.md).
---
## Finding Management
### Finding Classification
| Severity | Definition | Response Time |
|----------|------------|---------------|
| Major Nonconformity | Control failure creating significant risk | 30 days |
| Minor Nonconformity | Isolated deviation with limited impact | 90 days |
| Observation | Improvement opportunity | Next audit cycle |
### Finding Documentation Template
```
Finding ID: ISMS-[YEAR]-[NUMBER]
Control Reference: A.X.X - [Control Name]
Severity: [Major/Minor/Observation]
Evidence:
- [Specific evidence observed]
- [Records reviewed]
- [Interview statements]
Risk Impact:
- [Potential consequences if not addressed]
Root Cause:
- [Why the nonconformity occurred]
Recommendation:
- [Specific corrective action steps]
```
### Corrective Action Workflow
1. Auditee acknowledges finding and severity
2. Root cause analysis completed within 10 days
3. Corrective action plan submitted with target dates
4. Actions implemented by responsible parties
5. Auditor verifies effectiveness of corrections
6. Finding closed with evidence of resolution
7. **Validation:** Root cause addressed, recurrence prevented
---
## Certification Support
### Stage 1 Audit Preparation
Ensure documentation is complete:
- [ ] ISMS scope statement
- [ ] Information security policy (management signed)
- [ ] Statement of Applicability
- [ ] Risk assessment methodology and results
- [ ] Risk treatment plan
- [ ] Internal audit results (past 12 months)
- [ ] Management review minutes
### Stage 2 Audit Preparation
Verify operational readiness:
- [ ] All Stage 1 findings addressed
- [ ] ISMS operational for minimum 3 months
- [ ] Evidence of control implementation
- [ ] Security awareness training records
- [ ] Incident response evidence (if applicable)
- [ ] Access review documentation
### Surveillance Audit Cycle
| Period | Focus |
|--------|-------|
| Year 1, Q2 | High-risk controls, Stage 2 findings follow-up |
| Year 1, Q4 | Continual improvement, control sample |
| Year 2, Q2 | Full surveillance |
| Year 2, Q4 | Re-certification preparation |
**Validation:** No major nonconformities at surveillance audits.
---
## Tools
### scripts/
| Script | Purpose | Usage |
|--------|---------|-------|
| `isms_audit_scheduler.py` | Generate risk-based audit plans | `python scripts/isms_audit_scheduler.py --year 2025 --format markdown` |
### Audit Planning Example
```bash
# Generate annual audit plan
python scripts/isms_audit_scheduler.py --year 2025 --output audit_plan.json
# With custom control risk ratings
python scripts/isms_audit_scheduler.py --controls controls.csv --format markdown
```
---
## References
| File | Content |
|------|---------|
| [iso27001-audit-methodology.md](references/iso27001-audit-methodology.md) | Audit program structure, pre-audit phase, certification support |
| [security-control-testing.md](references/security-control-testing.md) | Technical verification procedures for ISO 27002 controls |
| [cloud-security-audit.md](references/cloud-security-audit.md) | Cloud provider assessment, configuration security, IAM review |
---
## Audit Performance Metrics
| KPI | Target | Measurement |
|-----|--------|-------------|
| Audit plan completion | 100% | Audits completed vs. planned |
| Finding closure rate | >90% within SLA | Closed on time vs. total |
| Major nonconformities | 0 at certification | Count per certification cycle |
| Audit effectiveness | Incidents prevented | Security improvements implemented |
FILE:references/cloud-security-audit.md
# Cloud Security Audit Guide
Assessment framework for cloud service security verification.
---
## Table of Contents
- [Shared Responsibility Model](#shared-responsibility-model)
- [Cloud Provider Assessment](#cloud-provider-assessment)
- [Configuration Security](#configuration-security)
- [Data Protection](#data-protection)
- [Identity and Access Management](#identity-and-access-management)
---
## Shared Responsibility Model
### Responsibility Matrix
| Layer | IaaS | PaaS | SaaS |
|-------|------|------|------|
| Data classification | Customer | Customer | Customer |
| Identity management | Customer | Customer | Shared |
| Application security | Customer | Shared | Provider |
| Network controls | Shared | Provider | Provider |
| Host infrastructure | Provider | Provider | Provider |
| Physical security | Provider | Provider | Provider |
### Audit Focus by Model
**IaaS (AWS EC2, Azure VMs):**
- Virtual network configuration
- OS hardening and patching
- Application deployment security
- Data encryption implementation
**PaaS (Azure App Service, AWS Lambda):**
- Application code security
- Data handling and encryption
- Identity integration
- Logging configuration
**SaaS (Microsoft 365, Salesforce):**
- User access management
- Data classification and handling
- Security configuration settings
- Integration security
---
## Cloud Provider Assessment
### Certification Verification
Check for current certifications:
- [ ] ISO 27001 (Information Security)
- [ ] ISO 27017 (Cloud Security)
- [ ] ISO 27018 (Cloud Privacy)
- [ ] SOC 2 Type II
- [ ] CSA STAR certification
**Verification Steps:**
1. Request current certificates from provider
2. Verify certificate scope includes services used
3. Check certification expiration dates
4. Review SOC 2 report for relevant controls
5. Document any scope exclusions
### Data Residency Compliance
| Requirement | Verification |
|-------------|--------------|
| GDPR (EU data) | Confirm EU region availability |
| Data sovereignty | Verify no cross-border transfer |
| Backup location | Confirm backup region |
| Disaster recovery | Document DR site location |
### Provider Security Documentation
Request and review:
- Shared responsibility documentation
- Security whitepapers
- Incident notification procedures
- SLA for security incidents
- Vulnerability disclosure policy
---
## Configuration Security
### AWS Security Assessment
**Identity and Access (IAM):**
- [ ] Root account has MFA enabled
- [ ] No access keys for root account
- [ ] IAM policies follow least privilege
- [ ] No wildcard (*) permissions on sensitive resources
- [ ] Password policy meets requirements
**Network Configuration (VPC):**
- [ ] Default VPCs removed or secured
- [ ] Security groups follow least privilege
- [ ] No 0.0.0.0/0 ingress on management ports
- [ ] VPC flow logs enabled
- [ ] Network ACLs configured appropriately
**Storage (S3):**
- [ ] No public buckets (unless intended)
- [ ] Bucket policies restrict access
- [ ] Encryption at rest enabled
- [ ] Versioning enabled for critical data
- [ ] Access logging enabled
**Logging (CloudTrail):**
- [ ] CloudTrail enabled in all regions
- [ ] Log file validation enabled
- [ ] Logs encrypted with KMS
- [ ] S3 bucket for logs is secured
- [ ] CloudWatch alarms configured
### Azure Security Assessment
**Identity (Azure AD):**
- [ ] MFA enabled for all users
- [ ] Privileged Identity Management (PIM) configured
- [ ] Conditional Access policies defined
- [ ] Guest access restricted
- [ ] Password protection enabled
**Network (Virtual Networks):**
- [ ] NSG rules follow least privilege
- [ ] No open management ports to internet
- [ ] Network Watcher enabled
- [ ] DDoS protection configured
- [ ] Private endpoints for PaaS services
**Storage:**
- [ ] No anonymous access to blob storage
- [ ] Encryption at rest enabled
- [ ] Shared access signatures time-limited
- [ ] Storage analytics logging enabled
- [ ] Soft delete enabled
**Monitoring:**
- [ ] Azure Monitor enabled
- [ ] Activity log exported to SIEM
- [ ] Alerts configured for security events
- [ ] Azure Security Center enabled
- [ ] Diagnostic settings configured
---
## Data Protection
### Encryption Verification
**At Rest:**
| Service | Encryption Check |
|---------|------------------|
| Block storage | Verify CMK or provider-managed key |
| Object storage | Check default encryption settings |
| Databases | Confirm TDE or column encryption |
| Backups | Verify backup encryption |
**In Transit:**
| Connection | Requirement |
|------------|-------------|
| User to application | TLS 1.2+ required |
| Service to service | Internal TLS or VPN |
| API communications | HTTPS only, no HTTP |
| Database connections | TLS required |
### Key Management Assessment
- [ ] Customer-managed keys used for sensitive data
- [ ] Key rotation policy defined and implemented
- [ ] Key access restricted to authorized services
- [ ] Key usage logged and monitored
- [ ] Disaster recovery for keys documented
### Data Classification in Cloud
| Classification | Cloud Requirements |
|----------------|-------------------|
| Confidential | CMK encryption, access logging, no public access |
| Internal | Encryption enabled, network restrictions |
| Public | Integrity protection, CDN appropriate |
---
## Identity and Access Management
### Privileged Access Review
1. Identify all administrative roles
2. Verify role assignment justification
3. Check for standing vs. just-in-time access
4. Review privileged activity logs
5. Confirm MFA required for elevation
### Service Account Assessment
| Check | Verification |
|-------|--------------|
| Inventory | All service accounts documented |
| Permissions | Least privilege applied |
| Credentials | Keys rotated per policy |
| Monitoring | Activity logged and reviewed |
| Ownership | Clear owner assigned |
### Federation and SSO
- [ ] SSO configured for cloud console access
- [ ] Conditional Access/MFA policies applied
- [ ] Session timeout configured
- [ ] Failed login monitoring enabled
- [ ] Emergency access accounts documented
### API Security
- [ ] API keys not embedded in code
- [ ] Secrets management service used
- [ ] API access logged
- [ ] Rate limiting configured
- [ ] API permissions follow least privilege
FILE:references/iso27001-audit-methodology.md
# ISO 27001 ISMS Audit Methodology
Complete audit framework and procedures for Information Security Management System assessments.
---
## Table of Contents
- [Audit Program Structure](#audit-program-structure)
- [Pre-Audit Phase](#pre-audit-phase)
- [Audit Execution](#audit-execution)
- [Finding Classification](#finding-classification)
- [Certification Audit Support](#certification-audit-support)
---
## Audit Program Structure
### Annual Audit Schedule
| Quarter | Focus Area | Audit Type |
|---------|------------|------------|
| Q1 | Access Control, Cryptography | Internal |
| Q2 | Operations Security, Communications | Internal |
| Q3 | System Acquisition, Supplier Relations | Internal |
| Q4 | Full ISMS Review | Pre-certification |
### Risk-Based Scheduling
Prioritize audit frequency based on:
- Asset criticality and data classification
- Previous finding history
- Regulatory requirements
- Recent security incidents
- Organizational changes
**High Risk Areas (Quarterly):**
- Access management systems
- Cryptographic key management
- Incident response processes
- Third-party access controls
**Medium Risk Areas (Semi-Annual):**
- Change management
- Backup and recovery
- Physical security
- Security awareness training
**Lower Risk Areas (Annual):**
- Documentation management
- Asset inventory
- Business continuity planning
---
## Pre-Audit Phase
### Documentation Review Checklist
- [ ] ISMS scope statement and boundaries
- [ ] Information security policy (signed, current)
- [ ] Statement of Applicability (SoA)
- [ ] Risk assessment methodology and results
- [ ] Risk treatment plan
- [ ] Security objectives and metrics
- [ ] Previous audit reports and corrective actions
### Audit Plan Template
```
ISMS Audit Plan
Audit ID: ISMS-[YEAR]-[NUMBER]
Scope: [ISMS scope or specific controls]
Date: [Start] to [End]
Lead Auditor: [Name]
Audit Team: [Names]
Day 1:
09:00 - Opening meeting
10:00 - Document review (policies, SoA)
14:00 - Interview: Information Security Manager
Day 2:
09:00 - Technical control verification
14:00 - Process observation
Day 3:
09:00 - Remaining interviews
14:00 - Finding consolidation
16:00 - Closing meeting
```
### Auditor Independence
Verify before audit assignment:
- No operational responsibility for audited area
- No recent (12 months) involvement in audited processes
- No conflict of interest with auditees
- Required competencies documented
---
## Audit Execution
### Evidence Collection Methods
| Method | Use Case | Evidence Type |
|--------|----------|---------------|
| Document review | Policy verification | Screenshots, copies |
| Interviews | Process understanding | Notes, recordings |
| Observation | Operational checks | Photos, timestamps |
| Technical testing | Control effectiveness | System logs, reports |
### Interview Protocol
1. Introduce audit purpose and confidentiality
2. Explain interview will be documented
3. Ask open-ended questions about processes
4. Request evidence to support statements
5. Clarify any inconsistencies
6. Summarize key points before closing
### Sample Interview Questions
**For Security Managers:**
- Describe the risk assessment process
- How are security incidents reported and managed?
- What metrics track ISMS effectiveness?
**For System Administrators:**
- How is privileged access managed?
- Walk through the change management process
- Show backup verification records
**For End Users:**
- What security training have you received?
- How do you report suspicious activity?
- Describe the password policy requirements
### Control Testing Procedures
**Access Control (A.9):**
1. Request user access list for critical system
2. Verify access rights match job roles
3. Check for terminated user accounts
4. Test password policy enforcement
5. Verify MFA configuration
**Logging (A.12.4):**
1. Confirm logging enabled on systems in scope
2. Verify log retention meets policy
3. Check log protection from tampering
4. Review sample security event alerts
---
## Finding Classification
### Severity Levels
| Level | Definition | Response Time |
|-------|------------|---------------|
| Major Nonconformity | Failure of control, significant risk | 30 days corrective action |
| Minor Nonconformity | Isolated deviation, limited impact | 90 days corrective action |
| Observation | Improvement opportunity | Next audit cycle |
| Good Practice | Exceeds requirements | Document and share |
### Finding Documentation
```
Finding ID: ISMS-2025-001
Control Reference: A.9.2.3 - Management of privileged access
Severity: Major Nonconformity
Evidence:
- 15 shared admin accounts identified
- No approval records for privileged access
- Last access review: 18 months ago
Risk Impact:
- Unauthorized access to critical systems
- No accountability for admin actions
- Regulatory non-compliance
Root Cause:
- No defined process for privileged access management
- Insufficient tooling for access tracking
Recommendation:
- Implement PAM solution within 30 days
- Document and enforce privileged access process
- Conduct immediate access review
```
### Corrective Action Tracking
| Field | Content |
|-------|---------|
| Finding ID | Link to original finding |
| Root Cause | Why the nonconformity occurred |
| Corrective Action | Specific steps to address |
| Responsible Person | Named accountable party |
| Target Date | Completion deadline |
| Verification Method | How closure will be confirmed |
| Status | Open / In Progress / Closed |
---
## Certification Audit Support
### Stage 1 Audit Preparation
Ensure availability of:
- [ ] ISMS documentation (scope, policy, SoA)
- [ ] Risk assessment records
- [ ] Internal audit results from past 12 months
- [ ] Management review minutes
- [ ] Corrective action evidence
### Stage 2 Audit Preparation
- [ ] All Stage 1 findings addressed
- [ ] ISMS operational for minimum 3 months
- [ ] Evidence of control effectiveness
- [ ] Training and awareness records
- [ ] Incident response records (if any)
### Surveillance Audit Cycle
| Year | Quarter | Focus |
|------|---------|-------|
| Year 1 | Q2 | High-risk controls, Stage 2 findings |
| Year 1 | Q4 | Remaining controls sample |
| Year 2 | Q2 | Full surveillance |
| Year 2 | Q4 | Continual improvement evidence |
| Year 3 | Q2 | Re-certification preparation |
### Audit Findings Response Template
```
Subject: Response to Finding ISMS-2025-001
Finding: Major Nonconformity - Privileged Access Management
Root Cause Analysis:
[5 Whys or fishbone analysis results]
Corrective Action Plan:
1. [Action] - [Owner] - [Date]
2. [Action] - [Owner] - [Date]
Evidence of Correction:
- [Document/screenshot reference]
Preventive Measures:
- [Steps to prevent recurrence]
Verification Request: [Date auditor can verify]
```
FILE:references/iso27001_audit_playbook.md
# ISO/IEC 27001:2022 Internal Audit Playbook
This reference answers exactly one decision: **how do we prepare for and conduct an ISO 27001 internal audit (Clause 9.2) that produces actionable findings without burning the auditee team?**
Pair with `scripts/isms_audit_scheduler.py` (this skill) for cadence + auditor independence and with `compliance-os/scripts/audit_simulator.py` for mock-audit preparation.
## When to Use This Playbook
- Annual Clause 9.2 internal audit programme
- Pre-stage-1 certification readiness check
- Surveillance audit preparation (year 2 / year 3 of cert cycle)
- Post-incident audit (e.g., breach triggers ad-hoc ISMS audit)
- Onboarding a new business unit into existing ISMS scope
## The 7-Phase Audit Workflow
```
[ Plan ] -> [ Prepare ] -> [ Open ] -> [ Field ] -> [ Close ] -> [ Report ] -> [ Track ]
```
### Phase 1 — Plan (1-2 weeks pre-audit)
- Confirm scope: which Annex A controls, which business units, which clauses
- Confirm auditor independence (no self-audit; rotate across teams)
- Pull prior-year findings + open nonconformities for follow-up
- Define sampling approach (stratified by risk; not random)
- Communicate dates to auditees ≥ 2 weeks in advance
**Outputs:** audit plan (1 page), auditor assignments, document-request list
### Phase 2 — Prepare (1 week pre-audit)
- Auditee assembles document evidence in advance
- Auditor reviews documents BEFORE fieldwork (do not waste interview time reading docs)
- Pre-fieldwork checklist: are documents under version control? Are records signed? Are dates within retention?
- Auditor runs `audit_simulator.py` to mentally rehearse finding scenarios
**Outputs:** prepared document folder, auditor mental model of likely findings
### Phase 3 — Open (30 min, day 1)
- Opening meeting with auditee leadership + key contributors
- State scope, criteria (which Annex A controls), timeline, communication plan
- Set expectations: this is a check on the system, not on individuals
- Confirm safe-to-fail discipline — finding ≠ punishment
**Outputs:** opening minutes; auditee buy-in
### Phase 4 — Field (2-5 days for medium scope)
The core. For each scoped control:
1. **Interview the control owner** — open question, sample drill-down, walk-through
2. **Inspect the record(s)** — pull samples from logs / tickets / records, not curated demos
3. **Cross-reference** — does the record match the procedure? Does management oversight exist?
4. **Document the finding** on the spot — control + observation + evidence + severity
Interview pattern (per ISO 19011 Clause 6):
- "Walk me through how this control is implemented day-to-day."
- "Show me a specific example from the last 30 days."
- "What happens if [edge case]?"
- "Where is this documented?"
**Outputs:** finding worksheets (one per control); severity ratings
### Phase 5 — Close (1-2 hours, last day)
- Closing meeting with auditee team
- Walk through preliminary findings (no surprises in the written report)
- Allow auditee to provide additional evidence for borderline findings
- Confirm corrective action ownership before the report is written
- Agree on draft-report timeline (typically 1-2 weeks)
**Outputs:** closing minutes; preliminary finding agreement
### Phase 6 — Report (1-2 weeks post-fieldwork)
Per ISO 19011 Clause 6.5, the audit report must include:
- Audit objectives, scope, criteria, dates
- Audit team and auditees
- Summary of findings by severity
- Per-finding: control + observation + evidence + severity + corrective action recommendation
- Conclusion: ISMS adequacy + effectiveness verdict
- Distribution list
**Severity grades** (Clause 9.2 compatible):
| Grade | Definition | Treatment |
|---|---|---|
| **Critical (Major NC)** | Absence of, or systemic failure to implement, a required ISMS process | Blocks stage 1 certification; 30-day plan + closure required before progress |
| **Major** | Material gap in a required control | Corrective action plan within 30 days |
| **Minor** | Localized gap; control works overall | Corrective action within 90 days |
| **Observation / OFI** | Improvement opportunity; no nonconformity | Optional; recommendation only |
Healthy distribution: ≥ 40% observation, ≤ 15% critical.
**Outputs:** signed audit report; corrective action assignments
### Phase 7 — Track (ongoing)
- Open findings tracked through existing CAPA system (Clause 10.2)
- Verify closure of each finding via evidence + re-test (do not accept self-attestation)
- Update risk register for residual risks identified
- Feed unresolved findings into next audit cycle + management review (Clause 9.3)
**Outputs:** closed findings + verification evidence; updates to risk register and management review inputs
## Annex A Scope Prioritization (for fieldwork)
ISO 27001:2022 Annex A has 93 controls grouped into 4 themes (A.5 organizational, A.6 people, A.7 physical, A.8 technological). Audit fieldwork should NOT attempt all 93 in one audit — use the 3-year rolling cycle.
**High-priority controls (audit annually):**
| Control | Why prioritize annually |
|---|---|
| A.5.1 — Policies for information security | Foundation; audit changes |
| A.5.9-10 — Inventory of assets + acceptable use | Drives everything else |
| A.5.15 — Access control | Highest-leakage area |
| A.5.19-21 — Supplier management | Most-cited finding area |
| A.5.24-27 — Incident management + Article 33 GDPR alignment | High-stakes |
| A.5.34 — Privacy & PII | GDPR overlap; expand if EU data |
| A.6.3 — Awareness, education, training | Always sampled |
| A.6.7 — Remote working | Pandemic legacy; high audit value |
| A.6.8 — Information security event reporting | Connects to incident management |
| A.8.2-3 — Privileged access; Information access restriction | Pair with A.5.15 |
| A.8.7 — Protection against malware | Always cited |
| A.8.15-16 — Logging + Monitoring | Pair with A.5.24-27 |
| A.8.32 — Change management | High-leakage; pair with vulnerability/patch mgmt |
**Lower-priority controls (audit on rolling 3-year cycle):**
A.5.2 / A.5.3 / A.5.4 / A.5.6 / A.5.7 / A.5.8 / A.5.11 / A.5.13 / A.5.14 / A.5.16 / A.5.17 / A.5.18 / A.5.22 / A.5.23 / A.5.28 / A.5.29 / A.5.30 / A.5.31 / A.5.32 / A.5.33 / A.5.35 / A.5.36 / A.5.37 / A.6.1 / A.6.2 / A.6.4 / A.6.5 / A.6.6 / A.7 (all physical) / A.8.1 / A.8.4 / A.8.5 / A.8.6 / A.8.8 / A.8.9 / A.8.10 / A.8.11 / A.8.12 / A.8.13 / A.8.14 / A.8.17 / A.8.18 / A.8.19 / A.8.20 / A.8.21 / A.8.22 / A.8.23 / A.8.24 / A.8.25-31 (SDLC controls)
## Common Stage 1 / Stage 2 Findings (the patterns)
Based on practitioner reports of common ISO 27001:2022 findings:
1. **Risk register exists but treatment plans are generic.** "Apply A.7.3" without specific implementation.
2. **Asset inventory missing cloud / SaaS / AI tools.** Engineers stopped registering as they multiplied.
3. **Privileged access reviewed annually instead of quarterly.** Find orphaned accounts.
4. **Supplier reviews unsigned or undated.** Procurement collected them; nobody reviewed.
5. **Incident records lack documented post-incident review within 30 days.**
6. **Change advisory board exists but rubber-stamps.** No rejected changes in last 6 months.
7. **Internal audit programme doesn't cover all clauses + applicable controls over 3-year cycle.**
8. **Management review missing required Article 9.3 inputs** (KPI trends, audit findings, risk changes).
9. **Vulnerability management without defined SLAs by severity.**
10. **BCP/DRP exists but never tested.**
## Cross-Framework Reuse
This ISO 27001 audit pattern is the foundation for:
- **SOC 2** — ~75% control overlap; same evidence with TSC-specific formatting (`soc2_audit_playbook.md`)
- **ISO 42001** — Clauses 4-10 reuse ~60%; Annex A overlap on data + supplier; AI-specific Annex A.5/A.6/A.9 net-new
- **GDPR** — Article 32 organizational measures reuse heavily (`gdpr_audit_playbook.md`)
- **NIST CSF profiles** — common control vocabulary
Pair with `compliance-os/references/multi_framework_audit_playbook.md` for orchestrating audits across multiple frameworks.
## When This Reference Doesn't Help
- **Specific Annex A control text.** See ISO 27001:2022 + ISO 27002:2022 (implementation guidance).
- **Sectoral overlays.** Financial (NYDFS), healthcare (HIPAA), critical infra (NIS2) — sector-specific.
- **External certification audit detail.** This is the **internal** audit playbook; external (stage 1 / stage 2) audits are conducted by accredited bodies and follow ISO 17021.
---
**Source authorities (non-exhaustive):**
- **ISO/IEC 27001:2022** — the standard (Clause 9.2 internal audit + Annex A 93 controls)
- **ISO/IEC 27002:2022** — Information security controls (implementation guidance for Annex A)
- **ISO/IEC 19011:2018** — Guidelines for auditing management systems
- **ISO/IEC 17021-1:2015** — Conformity assessment requirements for bodies providing audit and certification (the external-audit standard; informs internal-audit expectations)
- **IIA International Professional Practices Framework** — Standards 1000-2600 (internal audit attribute + performance)
- **NIST SP 800-53A Rev 5** — Assessing Security and Privacy Controls (assessment procedures per control)
- **ISACA CISA Review Manual** (27th ed., 2024) — IS audit methodology
- **ASQ Certified Quality Auditor (CQA) Body of Knowledge** — quality audit methodology
- **Industry retrospectives** — common findings from accredited certification bodies (BSI, DNV, Bureau Veritas published case studies)
- **The Open Group** — Open FAIR for risk-based audit prioritization
FILE:references/security-control-testing.md
# Security Control Testing Guide
Technical verification procedures for ISO 27002 control assessment.
---
## Table of Contents
- [Control Testing Approach](#control-testing-approach)
- [Organizational Controls (A.5)](#organizational-controls-a5)
- [People Controls (A.6)](#people-controls-a6)
- [Physical Controls (A.7)](#physical-controls-a7)
- [Technological Controls (A.8)](#technological-controls-a8)
---
## Control Testing Approach
### Testing Methods
| Method | Description | When to Use |
|--------|-------------|-------------|
| Inquiry | Interview control owners | All controls |
| Observation | Watch process execution | Operational controls |
| Inspection | Review documentation/config | Policy controls |
| Re-performance | Execute control procedure | Critical controls |
### Sampling Guidelines
| Population Size | Sample Size |
|-----------------|-------------|
| 1-10 | All items |
| 11-50 | 10 items |
| 51-250 | 15 items |
| 251+ | 25 items |
---
## Organizational Controls (A.5)
### A.5.1 - Policies for Information Security
**Test Procedure:**
1. Obtain current information security policy
2. Verify management signature and approval date
3. Check policy is accessible to all employees
4. Confirm review within past 12 months
5. Sample 5 employees: verify awareness of policy location
**Evidence Required:**
- Signed policy document
- Intranet/portal screenshot showing policy access
- Policy review meeting minutes
- Employee acknowledgment records
### A.5.15 - Access Control
**Test Procedure:**
1. Obtain access control policy
2. Select sample of 10 user accounts
3. Verify access rights match job descriptions
4. Check for segregation of duties violations
5. Verify access provisioning follows documented process
**Evidence Required:**
- Access control policy
- User access matrix
- Access request forms with approvals
- Role definitions
### A.5.24 - Information Security Incident Management
**Test Procedure:**
1. Review incident management procedure
2. Select 3 recent incidents from log
3. Verify incidents followed documented process
4. Check escalation thresholds were respected
5. Confirm lessons learned were documented
**Evidence Required:**
- Incident response procedure
- Incident tickets with timeline
- Escalation records
- Post-incident review reports
---
## People Controls (A.6)
### A.6.1 - Screening
**Test Procedure:**
1. Review background check policy
2. Select 10 recent hires
3. Verify background checks completed before start
4. Check checks match role sensitivity level
5. Confirm records are securely stored
**Evidence Required:**
- Screening policy
- Background check completion records
- Role risk classification matrix
### A.6.3 - Information Security Awareness
**Test Procedure:**
1. Obtain training program documentation
2. Select sample of 15 employees
3. Verify training completion records
4. Review training content for currency
5. Check phishing simulation results
**Evidence Required:**
- Training materials and schedule
- LMS completion reports
- Phishing test results
- Training effectiveness metrics
### A.6.7 - Remote Working
**Test Procedure:**
1. Review remote working policy
2. Verify VPN is required for remote access
3. Sample 5 remote worker devices for compliance
4. Check endpoint protection is active
5. Verify secure data handling requirements
**Evidence Required:**
- Remote working policy
- VPN connection logs
- Endpoint compliance reports
- Remote access agreement signatures
---
## Physical Controls (A.7)
### A.7.1 - Physical Security Perimeters
**Test Procedure:**
1. Walk perimeter of secure areas
2. Verify access controls at all entry points
3. Check visitor management process
4. Review after-hours access logs
5. Confirm emergency exits are secure
**Evidence Required:**
- Site security plan
- Access control system configuration
- Visitor logs
- Guard tour records
### A.7.4 - Physical Security Monitoring
**Test Procedure:**
1. Verify CCTV coverage of critical areas
2. Check recording retention period
3. Review sample of recent alert responses
4. Confirm monitoring is 24/7 or as required
5. Verify footage protection and access controls
**Evidence Required:**
- CCTV coverage map
- Retention policy and settings
- Alert response records
- Access logs for footage viewing
---
## Technological Controls (A.8)
### A.8.2 - Privileged Access Rights
**Test Procedure:**
1. Obtain list of privileged accounts
2. Verify each has documented justification
3. Check separation of admin and user accounts
4. Confirm MFA is required for privileged access
5. Review privileged activity logs
**Evidence Required:**
- Privileged account inventory
- Access justification records
- PAM solution configuration
- Activity audit logs
### A.8.5 - Secure Authentication
**Test Procedure:**
1. Review password policy configuration
2. Verify MFA enrollment rates
3. Test account lockout after failed attempts
4. Check authentication logging
5. Verify secure authentication protocols (no plaintext)
**Evidence Required:**
- Password policy settings screenshot
- MFA enrollment report
- Account lockout configuration
- Authentication audit logs
### A.8.7 - Protection Against Malware
**Test Procedure:**
1. Verify endpoint protection coverage
2. Check definition update frequency
3. Review quarantine/detection logs
4. Confirm central management console
5. Test sample detection (EICAR)
**Evidence Required:**
- Endpoint protection deployment report
- Update status dashboard
- Detection/quarantine logs
- EICAR test results
### A.8.8 - Management of Technical Vulnerabilities
**Test Procedure:**
1. Obtain vulnerability scanning schedule
2. Review recent scan results
3. Verify critical vulnerabilities patched within SLA
4. Check vulnerability tracking system
5. Sample 5 critical findings for remediation evidence
**Evidence Required:**
- Scanning schedule and scope
- Scan reports with severity breakdown
- Patch deployment records
- Remediation tracking tickets
### A.8.13 - Information Backup
**Test Procedure:**
1. Review backup policy and schedule
2. Verify backup completion logs
3. Check encryption of backup data
4. Request recent restoration test results
5. Verify offsite/cloud backup location
**Evidence Required:**
- Backup policy
- Backup job completion logs
- Encryption configuration
- Restoration test records
### A.8.15 - Logging
**Test Procedure:**
1. Identify systems requiring logging
2. Verify logging is enabled and configured
3. Check log retention meets requirements
4. Confirm log integrity protection
5. Verify SIEM integration and alerting
**Evidence Required:**
- Logging requirements matrix
- Log configuration screenshots
- Retention settings
- SIEM alert rules
### A.8.24 - Use of Cryptography
**Test Procedure:**
1. Review cryptography policy
2. Verify encryption at rest configuration
3. Check TLS configuration (version, ciphers)
4. Review key management procedures
5. Verify certificate inventory and expiration tracking
**Evidence Required:**
- Cryptography policy
- Encryption configuration settings
- SSL/TLS scan results
- Key management procedures
- Certificate inventory
FILE:scripts/isms_audit_scheduler.py
#!/usr/bin/env python3
"""
ISMS Audit Scheduler
Risk-based audit planning and scheduling for ISO 27001 compliance.
Generates annual audit plans based on control risk ratings.
Usage:
python isms_audit_scheduler.py --year 2025 --output audit_plan.json
python isms_audit_scheduler.py --controls controls.csv --format markdown
"""
import argparse
import csv
import json
import sys
from datetime import datetime, timedelta
from typing import Dict, List, Any, Optional
# ISO 27001:2022 Annex A control domains
CONTROL_DOMAINS = {
"A.5": {"name": "Organizational Controls", "count": 37},
"A.6": {"name": "People Controls", "count": 8},
"A.7": {"name": "Physical Controls", "count": 14},
"A.8": {"name": "Technological Controls", "count": 34},
}
# Default risk ratings for control areas
DEFAULT_RISK_RATINGS = {
"A.5.1": {"name": "Policies for information security", "risk": "medium"},
"A.5.2": {"name": "Information security roles", "risk": "medium"},
"A.5.15": {"name": "Access control", "risk": "high"},
"A.5.24": {"name": "Incident management planning", "risk": "high"},
"A.5.25": {"name": "Assessment of security events", "risk": "high"},
"A.6.1": {"name": "Screening", "risk": "medium"},
"A.6.3": {"name": "Information security awareness", "risk": "medium"},
"A.6.7": {"name": "Remote working", "risk": "high"},
"A.7.1": {"name": "Physical security perimeters", "risk": "medium"},
"A.7.4": {"name": "Physical security monitoring", "risk": "medium"},
"A.8.2": {"name": "Privileged access rights", "risk": "critical"},
"A.8.5": {"name": "Secure authentication", "risk": "critical"},
"A.8.7": {"name": "Protection against malware", "risk": "high"},
"A.8.8": {"name": "Management of vulnerabilities", "risk": "critical"},
"A.8.13": {"name": "Information backup", "risk": "high"},
"A.8.15": {"name": "Logging", "risk": "critical"},
"A.8.20": {"name": "Networks security", "risk": "high"},
"A.8.24": {"name": "Use of cryptography", "risk": "high"},
}
# Audit frequency based on risk level
AUDIT_FREQUENCY = {
"critical": 4, # Quarterly
"high": 2, # Semi-annual
"medium": 1, # Annual
"low": 1, # Annual
}
def load_controls_from_csv(filepath: str) -> Dict[str, Dict]:
"""Load control risk ratings from CSV file."""
controls = {}
try:
with open(filepath, "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
control_id = row.get("control_id", row.get("id", ""))
if control_id:
controls[control_id] = {
"name": row.get("name", "Unknown"),
"risk": row.get("risk", "medium").lower(),
}
except FileNotFoundError:
print(f"Error: File not found: {filepath}", file=sys.stderr)
sys.exit(1)
return controls
def calculate_audit_dates(
year: int,
frequency: int
) -> List[str]:
"""Calculate audit dates based on frequency."""
dates = []
interval = 12 // frequency
for i in range(frequency):
month = (i * interval) + 2 # Start in February
if month > 12:
month = month - 12
date = datetime(year, month, 15)
dates.append(date.strftime("%Y-%m-%d"))
return dates
def generate_audit_plan(
year: int,
controls: Optional[Dict[str, Dict]] = None
) -> Dict[str, Any]:
"""Generate risk-based annual audit plan."""
if controls is None:
controls = DEFAULT_RISK_RATINGS
plan = {
"metadata": {
"year": year,
"generated": datetime.now().isoformat(),
"methodology": "ISO 27001 Risk-Based Internal Auditing",
"total_controls": len(controls),
},
"schedule": {
"Q1": {"month": "February-March", "audits": []},
"Q2": {"month": "May-June", "audits": []},
"Q3": {"month": "August-September", "audits": []},
"Q4": {"month": "November", "audits": []},
},
"controls": {},
}
# Assign controls to quarters based on risk
for control_id, control_data in controls.items():
risk = control_data.get("risk", "medium")
frequency = AUDIT_FREQUENCY.get(risk, 1)
audit_dates = calculate_audit_dates(year, frequency)
plan["controls"][control_id] = {
"name": control_data.get("name", "Unknown"),
"risk": risk,
"frequency": frequency,
"scheduled_audits": audit_dates,
}
# Add to quarterly schedule
for i, date in enumerate(audit_dates):
month = int(date.split("-")[1])
if month <= 3:
quarter = "Q1"
elif month <= 6:
quarter = "Q2"
elif month <= 9:
quarter = "Q3"
else:
quarter = "Q4"
plan["schedule"][quarter]["audits"].append({
"control_id": control_id,
"control_name": control_data.get("name", "Unknown"),
"risk_level": risk,
"target_date": date,
})
# Sort audits within each quarter
for quarter in plan["schedule"]:
plan["schedule"][quarter]["audits"].sort(
key=lambda x: (
{"critical": 0, "high": 1, "medium": 2, "low": 3}.get(x["risk_level"], 4),
x["target_date"]
)
)
# Calculate summary statistics
risk_counts = {"critical": 0, "high": 0, "medium": 0, "low": 0}
total_audits = 0
for control_data in plan["controls"].values():
risk_counts[control_data["risk"]] += 1
total_audits += control_data["frequency"]
plan["summary"] = {
"total_controls_in_scope": len(controls),
"total_audits_planned": total_audits,
"risk_distribution": risk_counts,
"audits_per_quarter": {
q: len(plan["schedule"][q]["audits"])
for q in plan["schedule"]
},
}
return plan
def format_markdown(plan: Dict[str, Any]) -> str:
"""Format audit plan as markdown."""
lines = [
f"# ISMS Audit Plan {plan['metadata']['year']}",
f"",
f"**Generated:** {plan['metadata']['generated'][:10]}",
f"**Methodology:** {plan['metadata']['methodology']}",
f"",
f"## Summary",
f"",
f"| Metric | Value |",
f"|--------|-------|",
f"| Controls in Scope | {plan['summary']['total_controls_in_scope']} |",
f"| Total Audits Planned | {plan['summary']['total_audits_planned']} |",
f"| Critical Risk Controls | {plan['summary']['risk_distribution']['critical']} |",
f"| High Risk Controls | {plan['summary']['risk_distribution']['high']} |",
f"| Medium Risk Controls | {plan['summary']['risk_distribution']['medium']} |",
f"",
]
for quarter, data in plan["schedule"].items():
lines.extend([
f"## {quarter}: {data['month']}",
f"",
f"| Control | Name | Risk | Target Date |",
f"|---------|------|------|-------------|",
])
for audit in data["audits"]:
lines.append(
f"| {audit['control_id']} | {audit['control_name']} | "
f"{audit['risk_level'].capitalize()} | {audit['target_date']} |"
)
lines.append("")
lines.extend([
f"## Risk-Based Audit Frequency",
f"",
f"| Risk Level | Audit Frequency |",
f"|------------|-----------------|",
f"| Critical | Quarterly (4x/year) |",
f"| High | Semi-Annual (2x/year) |",
f"| Medium | Annual (1x/year) |",
f"| Low | Annual (1x/year) |",
])
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(
description="ISMS Audit Scheduler - Risk-based audit planning"
)
parser.add_argument(
"--year", "-y",
type=int,
default=datetime.now().year,
help="Audit plan year (default: current year)"
)
parser.add_argument(
"--controls", "-c",
help="CSV file with control risk ratings"
)
parser.add_argument(
"--output", "-o",
help="Output file path"
)
parser.add_argument(
"--format", "-f",
choices=["json", "markdown"],
default="json",
help="Output format (default: json)"
)
args = parser.parse_args()
# Load controls
controls = None
if args.controls:
controls = load_controls_from_csv(args.controls)
# Generate plan
plan = generate_audit_plan(args.year, controls)
# Format output
if args.format == "markdown":
output = format_markdown(plan)
else:
output = json.dumps(plan, indent=2)
# Write output
if args.output:
with open(args.output, "w", encoding="utf-8") as f:
f.write(output)
print(f"Audit plan saved to: {args.output}", file=sys.stderr)
else:
print(output)
if __name__ == "__main__":
main()
Giả định kế hoạch thất bại sau 12 tháng rồi lần ngược để tìm điểm yếu, giả định và rủi ro thực thi.
--- name: "challenge" description: "Pre-mortem plan analysis. Imagine the plan failed 12 months from now and work backwards to find the weaknesses. Surfaces assumptions, dependencies, and execution risks before committing resources. Use when before significant resource commitment, before presenting to a board or investors, when feedback has been one-sidedly positive, or when there is pressure to move fast and figure it out later." --- # /em:challenge — Pre-Mortem Plan Analysis **Command:** `/em:challenge <plan>` Systematically finds weaknesses in any plan before reality does. Not to kill the plan — to make it survive contact with reality. --- ## The Core Idea Most plans fail for predictable reasons. Not bad luck — bad assumptions. Overestimated demand. Underestimated complexity. Dependencies nobody questioned. Timing that made sense in a spreadsheet but not in the real world. The pre-mortem technique: **imagine it's 12 months from now and this plan failed spectacularly. Now work backwards. Why?** That's not pessimism. It's how you build something that doesn't collapse. --- ## When to Run a Challenge - Before committing significant resources to a plan - Before presenting to the board or investors - When you notice you're only hearing positive feedback about the plan - When the plan requires multiple external dependencies to align - When there's pressure to move fast and "figure it out later" - When you feel excited about the plan (excitement is a signal to scrutinize harder) --- ## The Challenge Framework ### Step 1: Extract Core Assumptions Before you can test a plan, you need to surface everything it assumes to be true. For each section of the plan, ask: - What has to be true for this to work? - What are we assuming about customer behavior? - What are we assuming about competitor response? - What are we assuming about our own execution capability? - What external factors does this depend on? **Common assumption categories:** - **Market assumptions** — size, growth rate, customer willingness to pay, buying cycle - **Execution assumptions** — team capacity, velocity, no major hires needed - **Customer assumptions** — they have the problem, they know they have it, they'll pay to solve it - **Competitive assumptions** — incumbents won't respond, no new entrant, moat holds - **Financial assumptions** — burn rate, revenue timing, CAC, LTV ratios - **Dependency assumptions** — partner will deliver, API won't change, regulations won't shift ### Step 2: Rate Each Assumption For every assumption extracted, rate it on two dimensions: **Confidence level (how sure are you this is true):** - **High** — verified with data, customer conversations, market research - **Medium** — directionally right but not validated - **Low** — plausible but untested - **Unknown** — we simply don't know **Impact if wrong (what happens if this assumption fails):** - **Critical** — plan fails entirely - **High** — major delay or cost overrun - **Medium** — significant rework required - **Low** — manageable adjustment ### Step 3: Map Vulnerabilities The matrix of Low/Unknown confidence × Critical/High impact = your highest-risk assumptions. **Vulnerability = Low confidence + High impact** These are not problems to ignore. They're the bets you're making. The question is: are you making them consciously? ### Step 4: Find the Dependency Chain Many plans fail not because any single assumption is wrong, but because multiple assumptions have to be right simultaneously. Map the chain: - Does assumption B depend on assumption A being true first? - If the first thing goes wrong, how many downstream things break? - What's the critical path? What has zero slack? ### Step 5: Test the Reversibility For each critical vulnerability: if this assumption turns out to be wrong at month 3, what do you do? - Can you pivot? - Can you cut scope? - Is money already spent? - Are commitments already made? The less reversible, the more rigorously you need to validate before committing. --- ## Output Format **Challenge Report: [Plan Name]** ``` CORE ASSUMPTIONS (extracted) 1. [Assumption] — Confidence: [H/M/L/?] — Impact if wrong: [Critical/High/Medium/Low] 2. ... VULNERABILITY MAP Critical risks (act before proceeding): • [#N] [Assumption] — WHY it might be wrong — WHAT breaks if it is High risks (validate before scaling): • ... DEPENDENCY CHAIN [Assumption A] → depends on → [Assumption B] → which enables → [Assumption C] Weakest link: [X] — if this breaks, [Y] and [Z] also fail REVERSIBILITY ASSESSMENT • Reversible bets: [list] • Irreversible commitments: [list — treat with extreme care] KILL SWITCHES What would have to be true at [30/60/90 days] to continue vs. kill/pivot? • Continue if: ... • Kill/pivot if: ... HARDENING ACTIONS 1. [Specific validation to do before proceeding] 2. [Alternative approach to consider] 3. [Contingency to build into the plan] ``` --- ## Challenge Patterns by Plan Type ### Product Roadmap - Are we building what customers will pay for, or what they said they wanted? - Does the velocity estimate account for real team capacity (not theoretical)? - What happens if the anchor feature takes 3× longer than estimated? - Who owns decisions when requirements conflict? ### Go-to-Market Plan - What's the actual ICP conversion rate, not the hoped-for one? - How many touches to close, and do you have the sales capacity for that? - What happens if the first 10 deals take 3 months instead of 1? - Is "land and expand" a real motion or a hope? ### Hiring Plan - What happens if the key hire takes 4 months to find, not 6 weeks? - Is the plan dependent on retaining specific people who might leave? - Does the plan account for ramp time (usually 3–6 months before full productivity)? - What's the burn impact if headcount leads revenue by 6 months? ### Fundraising Plan - What's your fallback if the lead investor passes? - Have you modeled the timeline if it takes 6 months, not 3? - What's your runway at current burn if the round closes at the low end? - What assumptions break if you raise 50% of the target amount? --- ## The Hardest Questions These are the ones people skip: - "What's the bear case, not the base case?" - "If this exact plan was run by a team we don't trust, would it work?" - "What are we not saying out loud because it's uncomfortable?" - "Who has incentives to make this plan sound better than it is?" - "What would an enemy of this plan attack first?" --- ## Deliverable The output of `/em:challenge` is not permission to stop. It's a vulnerability map. Now you can make conscious decisions: validate the risky assumptions, hedge the critical ones, or accept the bets you're making knowingly. Unknown risks are dangerous. Known risks are manageable.
Hỗ trợ tạo khách hàng tiềm năng, tối ưu chuyển đổi và triển khai chiến dịch thu hút khách hàng đa kênh.
---
name: cs-demand-gen-specialist
description: Demand generation and customer acquisition specialist for lead generation, conversion optimization, and multi-channel acquisition campaigns
skills: marketing-skill/marketing-demand-acquisition
domain: marketing
model: sonnet
tools: [Read, Write, Bash, Grep, Glob]
---
# Demand Generation Specialist Agent
## Purpose
The cs-demand-gen-specialist agent is a specialized marketing agent focused on demand generation, lead acquisition, and conversion optimization. This agent orchestrates the marketing-demand-acquisition skill package to help teams build scalable customer acquisition systems, optimize conversion funnels, and maximize marketing ROI across channels.
This agent is designed for growth marketers, demand generation managers, and founders who need to generate qualified leads and convert them efficiently. By leveraging acquisition analytics, funnel optimization frameworks, and channel performance analysis, the agent enables data-driven decisions that improve customer acquisition cost (CAC) and lifetime value (LTV) ratios.
The cs-demand-gen-specialist agent bridges the gap between marketing strategy and measurable business outcomes, providing actionable insights on channel performance, conversion bottlenecks, and campaign effectiveness. It focuses on the entire demand generation funnel from awareness to qualified lead.
## Skill Integration
**Skill Location:** `../../marketing-skill/marketing-demand-acquisition/`
### Python Tools
1. **CAC Calculator**
- **Purpose:** Calculates Customer Acquisition Cost (CAC) across channels and campaigns
- **Path:** `../../marketing-skill/marketing-demand-acquisition/scripts/calculate_cac.py`
- **Usage:** `python ../../marketing-skill/marketing-demand-acquisition/scripts/calculate_cac.py campaign-spend.csv customer-data.csv`
- **Features:** CAC calculation by channel, LTV:CAC ratio, payback period analysis, ROI metrics
- **Use Cases:** Budget allocation, channel performance evaluation, campaign ROI analysis
**Note:** Additional tools (demand_gen_analyzer.py, funnel_optimizer.py) planned for future releases per marketing roadmap.
### Knowledge Bases
1. **Attribution Guide**
- **Location:** `../../marketing-skill/marketing-demand-acquisition/references/attribution-guide.md`
- **Content:** Marketing attribution models, channel attribution, ROI measurement frameworks
- **Use Case:** Campaign attribution, channel performance analysis, budget justification
2. **Campaign Templates**
- **Location:** `../../marketing-skill/marketing-demand-acquisition/references/campaign-templates.md`
- **Content:** Reusable campaign structures, launch checklists, multi-channel campaign blueprints
- **Use Case:** Campaign planning, rapid campaign setup, standardized launch processes
3. **HubSpot Workflows**
- **Location:** `../../marketing-skill/marketing-demand-acquisition/references/hubspot-workflows.md`
- **Content:** HubSpot automation workflows, lead nurturing sequences, CRM integration patterns
- **Use Case:** Marketing automation, lead scoring, nurture campaign setup
4. **International Playbooks**
- **Location:** `../../marketing-skill/marketing-demand-acquisition/references/international-playbooks.md`
- **Content:** International market expansion strategies, localization best practices, regional channel optimization
- **Use Case:** Global campaign planning, market entry strategy, cross-border demand generation
### Templates
No asset templates currently available — use campaign-templates.md reference for campaign structure guidance.
## Workflows
### Workflow 1: Multi-Channel Acquisition Campaign Launch
**Goal:** Plan and launch demand generation campaign across multiple acquisition channels
**Steps:**
1. **Define Campaign Goals** - Set targets for leads, MQLs, SQLs, conversion rates
2. **Reference Campaign Templates** - Review proven campaign structures and launch checklists
```bash
cat ../../marketing-skill/marketing-demand-acquisition/references/campaign-templates.md
```
3. **Select Channels** - Choose optimal mix based on target audience, budget, and attribution models
```bash
cat ../../marketing-skill/marketing-demand-acquisition/references/attribution-guide.md
```
4. **Set Up Automation** - Configure HubSpot workflows for lead nurturing
```bash
cat ../../marketing-skill/marketing-demand-acquisition/references/hubspot-workflows.md
```
5. **Plan International Reach** - Reference international playbooks if targeting multiple markets
```bash
cat ../../marketing-skill/marketing-demand-acquisition/references/international-playbooks.md
```
6. **Launch and Monitor** - Deploy campaigns, track metrics, collect data
**Expected Output:** Structured campaign plan with channel strategy, budget allocation, success metrics
**Time Estimate:** 4-6 hours for campaign planning and setup
### Workflow 2: Conversion Funnel Analysis & Optimization
**Goal:** Identify and fix conversion bottlenecks in acquisition funnel
**Steps:**
1. **Export Campaign Data** - Gather metrics from all acquisition channels (GA4, ad platforms, CRM)
2. **Calculate Channel CAC** - Run CAC calculator to analyze cost efficiency
```bash
python ../../marketing-skill/marketing-demand-acquisition/scripts/calculate_cac.py campaign-spend.csv conversions.csv
```
3. **Map Conversion Funnel** - Visualize drop-off points using campaign templates as structure guide
```bash
cat ../../marketing-skill/marketing-demand-acquisition/references/campaign-templates.md
```
4. **Identify Bottlenecks** - Analyze conversion rates at each funnel stage:
- Awareness → Interest (CTR)
- Interest → Consideration (landing page conversion)
- Consideration → Intent (form completion)
- Intent → Purchase/MQL (qualification rate)
5. **Reference Attribution Guide** - Review attribution models to identify problem areas
```bash
cat ../../marketing-skill/marketing-demand-acquisition/references/attribution-guide.md
```
6. **Implement A/B Tests** - Test hypotheses for improvement
7. **Re-calculate CAC Post-Optimization** - Measure cost efficiency improvements
```bash
python ../../marketing-skill/marketing-demand-acquisition/scripts/calculate_cac.py post-optimization-spend.csv post-optimization-conversions.csv
```
**Expected Output:** 15-30% reduction in CAC and improved LTV:CAC ratio
**Time Estimate:** 6-8 hours for analysis and optimization planning
**Example:**
```bash
# Complete CAC analysis workflow
python ../../marketing-skill/marketing-demand-acquisition/scripts/calculate_cac.py q3-spend.csv q3-conversions.csv > cac-report.txt
cat cac-report.txt
# Review metrics and optimize high-CAC channels
```
### Workflow 3: Channel Performance Benchmarking
**Goal:** Evaluate and compare performance across acquisition channels to optimize budget allocation
**Steps:**
1. **Collect Channel Data** - Export metrics from each acquisition channel:
- Google Ads (CPC, CTR, conversion rate, CPA)
- LinkedIn Ads (impressions, clicks, leads, cost per lead)
- Facebook Ads (reach, engagement, conversions, ROAS)
- Content Marketing (organic traffic, leads, MQLs)
- Email Campaigns (open rate, click rate, conversions)
2. **Run CAC Comparison** - Calculate and compare CAC across all channels
```bash
python ../../marketing-skill/marketing-demand-acquisition/scripts/calculate_cac.py channel-spend.csv channel-conversions.csv
```
3. **Reference Attribution Guide** - Understand attribution models and benchmarks for each channel
```bash
cat ../../marketing-skill/marketing-demand-acquisition/references/attribution-guide.md
```
4. **Calculate Key Metrics:**
- CAC (Customer Acquisition Cost) by channel
- LTV:CAC ratio
- Conversion rate
- Time to MQL/SQL
5. **Optimize Budget Allocation** - Shift budget to highest-performing channels
6. **Document Learnings** - Create playbook for future campaigns
**Expected Output:** Data-driven budget reallocation plan with projected ROI improvement
**Time Estimate:** 3-4 hours for comprehensive channel analysis
### Workflow 4: Lead Magnet Campaign Development
**Goal:** Create and launch lead magnet campaign to capture high-quality leads
**Steps:**
1. **Define Lead Magnet** - Choose format: ebook, webinar, template, assessment, free trial
2. **Reference Campaign Templates** - Review lead capture and campaign structure best practices
```bash
cat ../../marketing-skill/marketing-demand-acquisition/references/campaign-templates.md
```
3. **Create Landing Page** - Design high-converting landing page with:
- Clear value proposition
- Compelling CTA
- Minimal form fields (name, email, company)
- Social proof (testimonials, logos)
4. **Set Up Campaign Tracking** - Configure analytics and attribution
5. **Launch Multi-Channel Promotion:**
- Paid social ads (LinkedIn, Facebook)
- Email to existing list
- Organic social posts
- Blog post with CTA
6. **Monitor and Optimize** - Track CAC and conversion metrics
```bash
# Weekly CAC analysis
python ../../marketing-skill/marketing-demand-acquisition/scripts/calculate_cac.py lead-magnet-spend.csv lead-magnet-conversions.csv
```
**Expected Output:** Lead magnet campaign generating 100-500 leads with 25-40% conversion rate
**Time Estimate:** 8-12 hours for development and launch
## Integration Examples
### Example 1: Automated Campaign Performance Dashboard
```bash
#!/bin/bash
# campaign-dashboard.sh - Daily campaign performance summary
DATE=$(date +%Y-%m-%d)
echo "📊 Demand Gen Dashboard - $DATE"
echo "========================================"
# Calculate yesterday's CAC by channel
python ../../marketing-skill/marketing-demand-acquisition/scripts/calculate_cac.py \
daily-spend.csv daily-conversions.csv
echo ""
echo "💰 Budget Status:"
cat budget-tracking.txt
echo ""
echo "🎯 Today's Priorities:"
cat optimization-priorities.txt
```
### Example 2: Weekly Channel Performance Report
```bash
# Generate weekly CAC report for stakeholders
python ../../marketing-skill/marketing-demand-acquisition/scripts/calculate_cac.py \
weekly-spend.csv weekly-conversions.csv > weekly-cac-report.txt
# Email to stakeholders
echo "Weekly CAC analysis report attached." | \
mail -s "Weekly CAC Report" -a weekly-cac-report.txt stakeholders@company.com
```
### Example 3: Real-Time Funnel Monitoring
```bash
# Monitor CAC in real-time (run daily via cron)
CAC_RESULT=$(python ../../marketing-skill/marketing-demand-acquisition/scripts/calculate_cac.py \
daily-spend.csv daily-conversions.csv | grep "Average CAC" | awk '{print $3}')
CAC_THRESHOLD=50
# Alert if CAC exceeds threshold
if (( $(echo "$CAC_RESULT > $CAC_THRESHOLD" | bc -l) )); then
echo "🚨 Alert: CAC ($CAC_RESULT) exceeds threshold ($CAC_THRESHOLD)!" | \
mail -s "CAC Alert" demand-gen-team@company.com
fi
```
## Success Metrics
**Acquisition Metrics:**
- **Lead Volume:** 20-30% month-over-month growth
- **MQL Conversion Rate:** 15-25% of total leads qualify as MQLs
- **CAC (Customer Acquisition Cost):** Decrease by 15-20% with optimization
- **LTV:CAC Ratio:** Maintain 3:1 or higher ratio
**Channel Performance:**
- **Paid Search:** CTR 3-5%, conversion rate 5-10%
- **Paid Social:** CTR 1-2%, CPL (cost per lead) benchmarked by industry
- **Content Marketing:** 30-40% of organic traffic converts to leads
- **Email Campaigns:** Open rate 20-30%, click rate 3-5%, conversion rate 2-5%
**Funnel Optimization:**
- **Landing Page Conversion:** 25-40% conversion rate on optimized pages
- **Form Completion:** 60-80% of visitors who start form complete it
- **Lead Quality:** 40-50% of MQLs convert to SQLs
**Business Impact:**
- **Pipeline Contribution:** Demand gen accounts for 50-70% of sales pipeline
- **Revenue Attribution:** Track $X in closed-won revenue to demand gen campaigns
- **Payback Period:** CAC recovered within 6-12 months
## Related Agents
- [cs-content-creator](cs-content-creator.md) - Content creation for demand gen campaigns
- cs-product-marketing - Product positioning and messaging (planned)
- cs-growth-marketer - Growth hacking and viral acquisition (planned)
## References
- **Skill Documentation:** [../../marketing-skill/marketing-demand-acquisition/SKILL.md](../../marketing-skill/marketing-demand-acquisition/SKILL.md)
- **Marketing Domain Guide:** [../../marketing-skill/CLAUDE.md](../../marketing-skill/CLAUDE.md)
- **Agent Development Guide:** [../CLAUDE.md](../CLAUDE.md)
- **Marketing Roadmap:** [../../marketing-skill/marketing_skills_roadmap.md](../../marketing-skill/marketing_skills_roadmap.md)
---
**Last Updated:** November 5, 2025
**Sprint:** sprint-11-05-2025 (Day 2)
**Status:** Production Ready
**Version:** 1.0
Sinh chuỗi OKR từ chiến lược công ty xuống mục tiêu từng nhóm.
--- name: okr description: Generate OKR cascades from company strategy to team objectives. Usage: /okr generate <strategy> --- # /okr Generate cascaded OKR frameworks from company-level strategy down to team-level key results. ## Usage ``` /okr generate <strategy> Generate OKR cascade ``` Supported strategies: `growth`, `retention`, `revenue`, `innovation`, `operational` ## Input Format Pass a strategy keyword directly. The generator produces company, department, and team-level OKRs aligned to the chosen strategy. ## Examples ``` /okr generate growth /okr generate retention /okr generate revenue /okr generate innovation /okr generate operational /okr generate growth --json ``` ## Scripts - `product-team/product-strategist/scripts/okr_cascade_generator.py` — OKR cascade generator (`<strategy> [--teams "A,B,C"] [--contribution 0.3] [--json]`) ## Skill Reference > `product-team/product-strategist/SKILL.md`