Tạo phiên cộng tác AgentHub mới với nhiệm vụ, số lượng agent và tiêu chí đánh giá.
---
name: "init"
description: "Create a new AgentHub collaboration session with task, agent count, and evaluation criteria."
command: /hub:init
---
# /hub:init — Create New Session
Initialize an AgentHub collaboration session. Creates the `.agenthub/` directory structure, generates a session ID, and configures evaluation criteria.
## Usage
```
/hub:init # Interactive mode
/hub:init --task "Optimize API" --agents 3 --eval "pytest bench.py" --metric p50_ms --direction lower
/hub:init --task "Refactor auth" --agents 2 # No eval (LLM judge mode)
```
## What It Does
### If arguments provided
Pass them to the init script:
```bash
python {skill_path}/scripts/hub_init.py \
--task "{task}" --agents {N} \
[--eval "{eval_cmd}"] [--metric {metric}] [--direction {direction}] \
[--base-branch {branch}]
```
### If no arguments (interactive mode)
Collect each parameter:
1. **Task** — What should the agents do? (required)
2. **Agent count** — How many parallel agents? (default: 3)
3. **Eval command** — Command to measure results (optional — skip for LLM judge mode)
4. **Metric name** — What metric to extract from eval output (required if eval command given)
5. **Direction** — Is lower or higher better? (required if metric given)
6. **Base branch** — Branch to fork from (default: current branch)
### Output
```
AgentHub session initialized
Session ID: 20260317-143022
Task: Optimize API response time below 100ms
Agents: 3
Eval: pytest bench.py --json
Metric: p50_ms (lower is better)
Base branch: dev
State: init
Next step: Run /hub:spawn to launch 3 agents
```
For content or research tasks (no eval command → LLM judge mode):
```
AgentHub session initialized
Session ID: 20260317-151200
Task: Draft 3 competing taglines for product launch
Agents: 3
Eval: LLM judge (no eval command)
Base branch: dev
State: init
Next step: Run /hub:spawn to launch 3 agents
```
## Baseline Capture
If `--eval` was provided, capture a baseline measurement after session creation:
1. Run the eval command in the current working directory
2. Extract the metric value from stdout
3. Append `baseline: {value}` to `.agenthub/sessions/{session-id}/config.yaml`
4. Display: `Baseline captured: {metric} = {value}`
This baseline is used by `result_ranker.py --baseline` during evaluation to show deltas. If the eval command fails at this stage, warn the user but continue — baseline is optional.
## After Init
Tell the user:
- Session created with ID `{session-id}`
- Baseline metric (if captured)
- Next step: `/hub:spawn` to launch agents
- Or `/hub:spawn {session-id}` if multiple sessions exist
Thiết kế quy trình phỏng vấn, pipeline tuyển dụng, bộ câu hỏi, ma trận năng lực, thang chấm điểm và phân tích thiên kiến người phỏng vấn.
---
name: "interview-system-designer"
description: This skill should be used when the user asks to "design interview processes", "create hiring pipelines", "calibrate interview loops", "generate interview questions", "design competency matrices", "analyze interviewer bias", "create scoring rubrics", "build question banks", or "optimize hiring systems". Use for designing role-specific interview loops, competency assessments, and hiring calibration systems.
---
# Interview System Designer
Comprehensive interview loop planning and calibration support for role-based hiring systems.
## Overview
Use this skill to create structured interview loops, standardize question quality, and keep hiring signal consistent across interviewers.
## Core Capabilities
- Interview loop planning by role and level
- Round-by-round focus and timing recommendations
- Suggested question sets by round type
- Framework support for scoring and calibration
- Bias-reduction and process consistency guidance
## Quick Start
```bash
# Generate a loop plan for a role and level
python3 scripts/interview_planner.py --role "Senior Software Engineer" --level senior
# JSON output for integration with internal tooling
python3 scripts/interview_planner.py --role "Product Manager" --level mid --json
```
## Recommended Workflow
1. Run `scripts/interview_planner.py` to generate a baseline loop.
2. Align rounds to role-specific competencies.
3. Validate scoring rubric consistency with interview panel leads.
4. Review for bias controls before rollout.
5. Recalibrate quarterly using hiring outcome data.
## References
- `references/interview-frameworks.md`
- `references/bias_mitigation_checklist.md`
- `references/competency_matrix_templates.md`
- `references/debrief_facilitation_guide.md`
## Common Pitfalls
- Overweighting one round while ignoring other competency signals
- Using unstructured interviews without standardized scoring
- Skipping calibration sessions for interviewers
- Changing hiring bar without documenting rationale
## Best Practices
1. Keep round objectives explicit and non-overlapping.
2. Require evidence for each score recommendation.
3. Use the same baseline rubric across comparable roles.
4. Revisit loop design based on quality-of-hire outcomes.
FILE:assets/sample_interview_results.json
[
{
"candidate_id": "candidate_001",
"role": "Senior Software Engineer",
"interviewer_id": "interviewer_alice",
"date": "2024-01-15T09:00:00Z",
"scores": {
"coding_fundamentals": 3.5,
"system_design": 4.0,
"technical_leadership": 3.0,
"communication": 3.5,
"problem_solving": 4.0
},
"overall_recommendation": "Hire",
"gender": "male",
"ethnicity": "asian",
"years_experience": 6,
"university_tier": "tier_1",
"previous_company_size": "large"
},
{
"candidate_id": "candidate_001",
"role": "Senior Software Engineer",
"interviewer_id": "interviewer_bob",
"date": "2024-01-15T11:00:00Z",
"scores": {
"system_design": 3.5,
"technical_leadership": 3.5,
"mentoring": 3.0,
"cross_team_collaboration": 4.0,
"strategic_thinking": 3.5
},
"overall_recommendation": "Hire",
"gender": "male",
"ethnicity": "asian",
"years_experience": 6,
"university_tier": "tier_1",
"previous_company_size": "large"
},
{
"candidate_id": "candidate_002",
"role": "Senior Software Engineer",
"interviewer_id": "interviewer_alice",
"date": "2024-01-16T09:00:00Z",
"scores": {
"coding_fundamentals": 2.5,
"system_design": 3.0,
"technical_leadership": 2.0,
"communication": 3.0,
"problem_solving": 3.0
},
"overall_recommendation": "No Hire",
"gender": "female",
"ethnicity": "hispanic",
"years_experience": 5,
"university_tier": "tier_2",
"previous_company_size": "startup"
},
{
"candidate_id": "candidate_002",
"role": "Senior Software Engineer",
"interviewer_id": "interviewer_charlie",
"date": "2024-01-16T11:00:00Z",
"scores": {
"system_design": 2.0,
"technical_leadership": 2.5,
"mentoring": 2.0,
"cross_team_collaboration": 3.0,
"strategic_thinking": 2.5
},
"overall_recommendation": "No Hire",
"gender": "female",
"ethnicity": "hispanic",
"years_experience": 5,
"university_tier": "tier_2",
"previous_company_size": "startup"
},
{
"candidate_id": "candidate_003",
"role": "Senior Software Engineer",
"interviewer_id": "interviewer_david",
"date": "2024-01-17T14:00:00Z",
"scores": {
"coding_fundamentals": 4.0,
"system_design": 3.5,
"technical_leadership": 4.0,
"communication": 4.0,
"problem_solving": 3.5
},
"overall_recommendation": "Strong Hire",
"gender": "male",
"ethnicity": "white",
"years_experience": 8,
"university_tier": "tier_1",
"previous_company_size": "large"
},
{
"candidate_id": "candidate_003",
"role": "Senior Software Engineer",
"interviewer_id": "interviewer_alice",
"date": "2024-01-17T16:00:00Z",
"scores": {
"system_design": 4.0,
"technical_leadership": 4.0,
"mentoring": 3.5,
"cross_team_collaboration": 4.0,
"strategic_thinking": 3.5
},
"overall_recommendation": "Hire",
"gender": "male",
"ethnicity": "white",
"years_experience": 8,
"university_tier": "tier_1",
"previous_company_size": "large"
},
{
"candidate_id": "candidate_004",
"role": "Product Manager",
"interviewer_id": "interviewer_emma",
"date": "2024-01-18T10:00:00Z",
"scores": {
"product_strategy": 3.0,
"user_research": 3.5,
"data_analysis": 4.0,
"stakeholder_management": 3.0,
"communication": 3.5
},
"overall_recommendation": "Hire",
"gender": "female",
"ethnicity": "black",
"years_experience": 4,
"university_tier": "tier_2",
"previous_company_size": "medium"
},
{
"candidate_id": "candidate_005",
"role": "Product Manager",
"interviewer_id": "interviewer_frank",
"date": "2024-01-19T13:00:00Z",
"scores": {
"product_strategy": 2.5,
"user_research": 2.0,
"data_analysis": 3.0,
"stakeholder_management": 2.5,
"communication": 3.0
},
"overall_recommendation": "No Hire",
"gender": "male",
"ethnicity": "white",
"years_experience": 3,
"university_tier": "tier_3",
"previous_company_size": "startup"
},
{
"candidate_id": "candidate_006",
"role": "Junior Software Engineer",
"interviewer_id": "interviewer_alice",
"date": "2024-01-20T09:00:00Z",
"scores": {
"coding_fundamentals": 3.0,
"debugging": 3.5,
"testing_basics": 3.0,
"collaboration": 4.0,
"learning_agility": 3.5
},
"overall_recommendation": "Hire",
"gender": "female",
"ethnicity": "asian",
"years_experience": 1,
"university_tier": "bootcamp",
"previous_company_size": "none"
},
{
"candidate_id": "candidate_007",
"role": "Junior Software Engineer",
"interviewer_id": "interviewer_bob",
"date": "2024-01-21T10:30:00Z",
"scores": {
"coding_fundamentals": 2.0,
"debugging": 2.5,
"testing_basics": 2.0,
"collaboration": 3.0,
"learning_agility": 3.0
},
"overall_recommendation": "No Hire",
"gender": "male",
"ethnicity": "hispanic",
"years_experience": 0,
"university_tier": "tier_2",
"previous_company_size": "none"
},
{
"candidate_id": "candidate_008",
"role": "Staff Frontend Engineer",
"interviewer_id": "interviewer_grace",
"date": "2024-01-22T14:00:00Z",
"scores": {
"frontend_architecture": 4.0,
"system_design": 4.0,
"technical_leadership": 4.0,
"team_building": 3.5,
"strategic_thinking": 3.5
},
"overall_recommendation": "Strong Hire",
"gender": "female",
"ethnicity": "white",
"years_experience": 9,
"university_tier": "tier_1",
"previous_company_size": "large"
},
{
"candidate_id": "candidate_008",
"role": "Staff Frontend Engineer",
"interviewer_id": "interviewer_henry",
"date": "2024-01-22T16:00:00Z",
"scores": {
"frontend_architecture": 3.5,
"technical_leadership": 4.0,
"team_building": 4.0,
"cross_functional_collaboration": 4.0,
"organizational_impact": 3.5
},
"overall_recommendation": "Hire",
"gender": "female",
"ethnicity": "white",
"years_experience": 9,
"university_tier": "tier_1",
"previous_company_size": "large"
},
{
"candidate_id": "candidate_009",
"role": "Data Scientist",
"interviewer_id": "interviewer_ivan",
"date": "2024-01-23T11:00:00Z",
"scores": {
"statistical_analysis": 3.5,
"machine_learning": 4.0,
"data_engineering": 3.0,
"business_acumen": 3.5,
"communication": 3.0
},
"overall_recommendation": "Hire",
"gender": "male",
"ethnicity": "indian",
"years_experience": 5,
"university_tier": "tier_1",
"previous_company_size": "medium"
},
{
"candidate_id": "candidate_010",
"role": "DevOps Engineer",
"interviewer_id": "interviewer_jane",
"date": "2024-01-24T15:00:00Z",
"scores": {
"infrastructure_automation": 3.5,
"ci_cd_design": 4.0,
"monitoring_observability": 3.0,
"security_implementation": 3.5,
"incident_management": 4.0
},
"overall_recommendation": "Hire",
"gender": "female",
"ethnicity": "black",
"years_experience": 6,
"university_tier": "tier_2",
"previous_company_size": "startup"
},
{
"candidate_id": "candidate_011",
"role": "UX Designer",
"interviewer_id": "interviewer_karl",
"date": "2024-01-25T10:00:00Z",
"scores": {
"design_process": 4.0,
"user_research": 3.5,
"design_systems": 4.0,
"cross_functional_collaboration": 3.5,
"design_leadership": 3.0
},
"overall_recommendation": "Hire",
"gender": "non_binary",
"ethnicity": "white",
"years_experience": 7,
"university_tier": "tier_1",
"previous_company_size": "medium"
},
{
"candidate_id": "candidate_012",
"role": "Engineering Manager",
"interviewer_id": "interviewer_lisa",
"date": "2024-01-26T13:30:00Z",
"scores": {
"people_leadership": 4.0,
"technical_background": 3.5,
"strategic_thinking": 3.5,
"performance_management": 4.0,
"cross_functional_leadership": 3.5
},
"overall_recommendation": "Hire",
"gender": "male",
"ethnicity": "white",
"years_experience": 8,
"university_tier": "tier_1",
"previous_company_size": "large"
},
{
"candidate_id": "candidate_013",
"role": "Senior Software Engineer",
"interviewer_id": "interviewer_alice",
"date": "2024-01-27T09:00:00Z",
"scores": {
"coding_fundamentals": 4.0,
"system_design": 4.0,
"technical_leadership": 4.0,
"communication": 4.0,
"problem_solving": 4.0
},
"overall_recommendation": "Strong Hire",
"gender": "female",
"ethnicity": "asian",
"years_experience": 7,
"university_tier": "tier_1",
"previous_company_size": "large"
},
{
"candidate_id": "candidate_013",
"role": "Senior Software Engineer",
"interviewer_id": "interviewer_charlie",
"date": "2024-01-27T11:00:00Z",
"scores": {
"system_design": 3.5,
"technical_leadership": 3.5,
"mentoring": 4.0,
"cross_team_collaboration": 4.0,
"strategic_thinking": 3.5
},
"overall_recommendation": "Hire",
"gender": "female",
"ethnicity": "asian",
"years_experience": 7,
"university_tier": "tier_1",
"previous_company_size": "large"
},
{
"candidate_id": "candidate_014",
"role": "Senior Software Engineer",
"interviewer_id": "interviewer_david",
"date": "2024-01-28T14:00:00Z",
"scores": {
"coding_fundamentals": 1.5,
"system_design": 2.0,
"technical_leadership": 1.0,
"communication": 2.0,
"problem_solving": 2.0
},
"overall_recommendation": "Strong No Hire",
"gender": "male",
"ethnicity": "white",
"years_experience": 4,
"university_tier": "tier_3",
"previous_company_size": "startup"
},
{
"candidate_id": "candidate_015",
"role": "Product Manager",
"interviewer_id": "interviewer_emma",
"date": "2024-01-29T11:00:00Z",
"scores": {
"product_strategy": 4.0,
"user_research": 3.5,
"data_analysis": 4.0,
"stakeholder_management": 4.0,
"communication": 3.5
},
"overall_recommendation": "Strong Hire",
"gender": "male",
"ethnicity": "black",
"years_experience": 5,
"university_tier": "tier_2",
"previous_company_size": "medium"
}
]
FILE:assets/sample_role_definitions.json
[
{
"role": "Senior Software Engineer",
"level": "senior",
"team": "platform",
"department": "engineering",
"competencies": [
"system_design",
"coding_fundamentals",
"technical_leadership",
"mentoring",
"cross_team_collaboration"
],
"requirements": {
"years_experience": "5-8",
"technical_skills": ["Python", "Java", "Docker", "Kubernetes", "AWS"],
"leadership_experience": true,
"mentoring_required": true
},
"hiring_bar": "high",
"interview_focus": ["technical_depth", "system_architecture", "leadership_potential"]
},
{
"role": "Product Manager",
"level": "mid",
"team": "growth",
"department": "product",
"competencies": [
"product_strategy",
"user_research",
"data_analysis",
"stakeholder_management",
"cross_functional_leadership"
],
"requirements": {
"years_experience": "3-5",
"domain_knowledge": ["user_analytics", "experimentation", "product_metrics"],
"leadership_experience": false,
"technical_background": "preferred"
},
"hiring_bar": "medium-high",
"interview_focus": ["product_sense", "analytical_thinking", "execution_ability"]
},
{
"role": "Staff Frontend Engineer",
"level": "staff",
"team": "consumer",
"department": "engineering",
"competencies": [
"frontend_architecture",
"system_design",
"technical_leadership",
"team_building",
"cross_functional_collaboration"
],
"requirements": {
"years_experience": "8+",
"technical_skills": ["React", "TypeScript", "GraphQL", "Webpack", "Performance Optimization"],
"leadership_experience": true,
"architecture_experience": true
},
"hiring_bar": "very-high",
"interview_focus": ["architectural_vision", "technical_strategy", "organizational_impact"]
},
{
"role": "Data Scientist",
"level": "mid",
"team": "ml_platform",
"department": "data",
"competencies": [
"statistical_analysis",
"machine_learning",
"data_engineering",
"business_acumen",
"communication"
],
"requirements": {
"years_experience": "3-6",
"technical_skills": ["Python", "SQL", "TensorFlow", "Spark", "Statistics"],
"domain_knowledge": ["ML algorithms", "experimentation", "data_pipelines"],
"leadership_experience": false
},
"hiring_bar": "high",
"interview_focus": ["technical_depth", "problem_solving", "business_impact"]
},
{
"role": "DevOps Engineer",
"level": "senior",
"team": "infrastructure",
"department": "engineering",
"competencies": [
"infrastructure_automation",
"ci_cd_design",
"monitoring_observability",
"security_implementation",
"incident_management"
],
"requirements": {
"years_experience": "5-7",
"technical_skills": ["Kubernetes", "Terraform", "AWS", "Docker", "Monitoring"],
"security_background": "required",
"leadership_experience": "preferred"
},
"hiring_bar": "high",
"interview_focus": ["system_reliability", "automation_expertise", "operational_excellence"]
},
{
"role": "UX Designer",
"level": "senior",
"team": "design_systems",
"department": "design",
"competencies": [
"design_process",
"user_research",
"design_systems",
"cross_functional_collaboration",
"design_leadership"
],
"requirements": {
"years_experience": "5-8",
"portfolio_quality": "high",
"research_experience": true,
"systems_thinking": true
},
"hiring_bar": "high",
"interview_focus": ["design_process", "systems_thinking", "user_advocacy"]
},
{
"role": "Engineering Manager",
"level": "senior",
"team": "backend",
"department": "engineering",
"competencies": [
"people_leadership",
"technical_background",
"strategic_thinking",
"performance_management",
"cross_functional_leadership"
],
"requirements": {
"years_experience": "6-10",
"management_experience": "2+ years",
"technical_background": "required",
"hiring_experience": true
},
"hiring_bar": "very-high",
"interview_focus": ["people_leadership", "technical_judgment", "organizational_impact"]
},
{
"role": "Junior Software Engineer",
"level": "junior",
"team": "web",
"department": "engineering",
"competencies": [
"coding_fundamentals",
"debugging",
"testing_basics",
"collaboration",
"learning_agility"
],
"requirements": {
"years_experience": "0-2",
"technical_skills": ["JavaScript", "HTML/CSS", "Git", "Basic Algorithms"],
"education": "CS degree or bootcamp",
"growth_mindset": true
},
"hiring_bar": "medium",
"interview_focus": ["coding_ability", "problem_solving", "potential_assessment"]
}
]
FILE:expected_outputs/product_manager_senior_questions.json
{
"role": "Product Manager",
"level": "senior",
"competencies": [
"strategy",
"analytics",
"business_strategy",
"product_strategy",
"stakeholder_management",
"p&l_responsibility",
"leadership",
"team_leadership",
"user_research",
"data_analysis"
],
"question_types": [
"technical",
"behavioral",
"situational"
],
"generated_at": "2026-02-16T13:27:41.303329",
"total_questions": 20,
"questions": [
{
"question": "What challenges have you faced related to p&l responsibility and how did you overcome them?",
"competency": "p&l_responsibility",
"type": "challenge_based",
"focus_areas": [
"problem_solving",
"learning_from_experience"
]
},
{
"question": "Analyze conversion funnel data to identify the biggest drop-off point and propose solutions.",
"competency": "data_analysis",
"type": "analytical",
"difficulty": "medium",
"time_limit": 45,
"key_concepts": [
"funnel_analysis",
"conversion_optimization",
"statistical_significance"
]
},
{
"question": "What challenges have you faced related to team leadership and how did you overcome them?",
"competency": "team_leadership",
"type": "challenge_based",
"focus_areas": [
"problem_solving",
"learning_from_experience"
]
},
{
"question": "Design a go-to-market strategy for a new B2B SaaS product entering a competitive market.",
"competency": "product_strategy",
"type": "strategic",
"difficulty": "hard",
"time_limit": 60,
"key_concepts": [
"market_analysis",
"competitive_positioning",
"pricing_strategy",
"channel_strategy"
]
},
{
"question": "What challenges have you faced related to business strategy and how did you overcome them?",
"competency": "business_strategy",
"type": "challenge_based",
"focus_areas": [
"problem_solving",
"learning_from_experience"
]
},
{
"question": "Describe your experience with business strategy in your current or previous role.",
"competency": "business_strategy",
"type": "experience",
"focus_areas": [
"experience_depth",
"practical_application"
]
},
{
"question": "Describe your experience with team leadership in your current or previous role.",
"competency": "team_leadership",
"type": "experience",
"focus_areas": [
"experience_depth",
"practical_application"
]
},
{
"question": "Describe a situation where you had to influence someone without having direct authority over them.",
"competency": "leadership",
"type": "behavioral",
"method": "STAR",
"focus_areas": [
"influence",
"persuasion",
"stakeholder_management"
]
},
{
"question": "Given a dataset of user activities, calculate the daily active users for the past month.",
"competency": "data_analysis",
"type": "analytical",
"difficulty": "easy",
"time_limit": 30,
"key_concepts": [
"sql_basics",
"date_functions",
"aggregation"
]
},
{
"question": "Describe your experience with analytics in your current or previous role.",
"competency": "analytics",
"type": "experience",
"focus_areas": [
"experience_depth",
"practical_application"
]
},
{
"question": "How would you prioritize features for a mobile app with limited engineering resources?",
"competency": "product_strategy",
"type": "case_study",
"difficulty": "medium",
"time_limit": 45,
"key_concepts": [
"prioritization_frameworks",
"resource_allocation",
"impact_estimation"
]
},
{
"question": "Describe your experience with stakeholder management in your current or previous role.",
"competency": "stakeholder_management",
"type": "experience",
"focus_areas": [
"experience_depth",
"practical_application"
]
},
{
"question": "What challenges have you faced related to stakeholder management and how did you overcome them?",
"competency": "stakeholder_management",
"type": "challenge_based",
"focus_areas": [
"problem_solving",
"learning_from_experience"
]
},
{
"question": "What challenges have you faced related to user research and how did you overcome them?",
"competency": "user_research",
"type": "challenge_based",
"focus_areas": [
"problem_solving",
"learning_from_experience"
]
},
{
"question": "What challenges have you faced related to strategy and how did you overcome them?",
"competency": "strategy",
"type": "challenge_based",
"focus_areas": [
"problem_solving",
"learning_from_experience"
]
},
{
"question": "Describe your experience with user research in your current or previous role.",
"competency": "user_research",
"type": "experience",
"focus_areas": [
"experience_depth",
"practical_application"
]
},
{
"question": "Describe your experience with p&l responsibility in your current or previous role.",
"competency": "p&l_responsibility",
"type": "experience",
"focus_areas": [
"experience_depth",
"practical_application"
]
},
{
"question": "Describe your experience with strategy in your current or previous role.",
"competency": "strategy",
"type": "experience",
"focus_areas": [
"experience_depth",
"practical_application"
]
},
{
"question": "Tell me about a time when you had to lead a team through a significant change or challenge.",
"competency": "leadership",
"type": "behavioral",
"method": "STAR",
"focus_areas": [
"change_management",
"team_motivation",
"communication"
]
},
{
"question": "What challenges have you faced related to analytics and how did you overcome them?",
"competency": "analytics",
"type": "challenge_based",
"focus_areas": [
"problem_solving",
"learning_from_experience"
]
}
],
"scoring_rubrics": {
"question_8": {
"question": "Describe a situation where you had to influence someone without having direct authority over them.",
"competency": "leadership",
"type": "behavioral",
"scoring_criteria": {
"situation_clarity": {
"4": "Clear, specific situation with relevant context and stakes",
"3": "Good situation description with adequate context",
"2": "Situation described but lacks some specifics",
"1": "Vague or unclear situation description"
},
"action_quality": {
"4": "Specific, thoughtful actions showing strong competency",
"3": "Good actions demonstrating competency",
"2": "Adequate actions but could be stronger",
"1": "Weak or inappropriate actions"
},
"result_impact": {
"4": "Significant positive impact with measurable results",
"3": "Good positive impact with clear outcomes",
"2": "Some positive impact demonstrated",
"1": "Little or no positive impact shown"
},
"self_awareness": {
"4": "Excellent self-reflection, learns from experience, acknowledges growth areas",
"3": "Good self-awareness and learning orientation",
"2": "Some self-reflection demonstrated",
"1": "Limited self-awareness or reflection"
}
},
"weight": "high",
"time_limit": 30
},
"question_19": {
"question": "Tell me about a time when you had to lead a team through a significant change or challenge.",
"competency": "leadership",
"type": "behavioral",
"scoring_criteria": {
"situation_clarity": {
"4": "Clear, specific situation with relevant context and stakes",
"3": "Good situation description with adequate context",
"2": "Situation described but lacks some specifics",
"1": "Vague or unclear situation description"
},
"action_quality": {
"4": "Specific, thoughtful actions showing strong competency",
"3": "Good actions demonstrating competency",
"2": "Adequate actions but could be stronger",
"1": "Weak or inappropriate actions"
},
"result_impact": {
"4": "Significant positive impact with measurable results",
"3": "Good positive impact with clear outcomes",
"2": "Some positive impact demonstrated",
"1": "Little or no positive impact shown"
},
"self_awareness": {
"4": "Excellent self-reflection, learns from experience, acknowledges growth areas",
"3": "Good self-awareness and learning orientation",
"2": "Some self-reflection demonstrated",
"1": "Limited self-awareness or reflection"
}
},
"weight": "high",
"time_limit": 30
}
},
"follow_up_probes": {
"question_1": [
"Can you provide more specific details about your approach?",
"What would you do differently if you had to do this again?",
"What challenges did you face and how did you overcome them?"
],
"question_2": [
"Can you provide more specific details about your approach?",
"What would you do differently if you had to do this again?",
"What challenges did you face and how did you overcome them?"
],
"question_3": [
"Can you provide more specific details about your approach?",
"What would you do differently if you had to do this again?",
"What challenges did you face and how did you overcome them?"
],
"question_4": [
"Can you provide more specific details about your approach?",
"What would you do differently if you had to do this again?",
"What challenges did you face and how did you overcome them?"
],
"question_5": [
"Can you provide more specific details about your approach?",
"What would you do differently if you had to do this again?",
"What challenges did you face and how did you overcome them?"
],
"question_6": [
"Can you provide more specific details about your approach?",
"What would you do differently if you had to do this again?",
"What challenges did you face and how did you overcome them?"
],
"question_7": [
"Can you provide more specific details about your approach?",
"What would you do differently if you had to do this again?",
"What challenges did you face and how did you overcome them?"
],
"question_8": [
"What would you do differently if you faced this situation again?",
"How did you handle team members who were resistant to the change?",
"What metrics did you use to measure success?",
"How did you communicate progress to stakeholders?",
"What did you learn from this experience?"
],
"question_9": [
"Can you provide more specific details about your approach?",
"What would you do differently if you had to do this again?",
"What challenges did you face and how did you overcome them?"
],
"question_10": [
"Can you provide more specific details about your approach?",
"What would you do differently if you had to do this again?",
"What challenges did you face and how did you overcome them?"
],
"question_11": [
"Can you provide more specific details about your approach?",
"What would you do differently if you had to do this again?",
"What challenges did you face and how did you overcome them?"
],
"question_12": [
"Can you provide more specific details about your approach?",
"What would you do differently if you had to do this again?",
"What challenges did you face and how did you overcome them?"
],
"question_13": [
"Can you provide more specific details about your approach?",
"What would you do differently if you had to do this again?",
"What challenges did you face and how did you overcome them?"
],
"question_14": [
"Can you provide more specific details about your approach?",
"What would you do differently if you had to do this again?",
"What challenges did you face and how did you overcome them?"
],
"question_15": [
"Can you provide more specific details about your approach?",
"What would you do differently if you had to do this again?",
"What challenges did you face and how did you overcome them?"
],
"question_16": [
"Can you provide more specific details about your approach?",
"What would you do differently if you had to do this again?",
"What challenges did you face and how did you overcome them?"
],
"question_17": [
"Can you provide more specific details about your approach?",
"What would you do differently if you had to do this again?",
"What challenges did you face and how did you overcome them?"
],
"question_18": [
"Can you provide more specific details about your approach?",
"What would you do differently if you had to do this again?",
"What challenges did you face and how did you overcome them?"
],
"question_19": [
"What would you do differently if you faced this situation again?",
"How did you handle team members who were resistant to the change?",
"What metrics did you use to measure success?",
"How did you communicate progress to stakeholders?",
"What did you learn from this experience?"
],
"question_20": [
"Can you provide more specific details about your approach?",
"What would you do differently if you had to do this again?",
"What challenges did you face and how did you overcome them?"
]
},
"calibration_examples": {
"question_1": {
"question": "What challenges have you faced related to p&l responsibility and how did you overcome them?",
"competency": "p&l_responsibility",
"sample_answers": {
"poor_answer": {
"answer": "Sample poor answer for p&l_responsibility question - lacks detail, specificity, or demonstrates weak competency",
"score": "1-2",
"issues": [
"Vague response",
"Limited evidence of competency",
"Poor structure"
]
},
"good_answer": {
"answer": "Sample good answer for p&l_responsibility question - adequate detail, demonstrates competency clearly",
"score": "3",
"strengths": [
"Clear structure",
"Demonstrates competency",
"Adequate detail"
]
},
"great_answer": {
"answer": "Sample excellent answer for p&l_responsibility question - exceptional detail, strong evidence, goes above and beyond",
"score": "4",
"strengths": [
"Exceptional detail",
"Strong evidence",
"Strategic thinking",
"Goes beyond requirements"
]
}
},
"scoring_rationale": {
"key_indicators": "Look for evidence of p&l responsibility competency",
"red_flags": "Vague answers, lack of specifics, negative outcomes without learning",
"green_flags": "Specific examples, clear impact, demonstrates growth and learning"
}
},
"question_2": {
"question": "Analyze conversion funnel data to identify the biggest drop-off point and propose solutions.",
"competency": "data_analysis",
"sample_answers": {
"poor_answer": {
"answer": "Sample poor answer for data_analysis question - lacks detail, specificity, or demonstrates weak competency",
"score": "1-2",
"issues": [
"Vague response",
"Limited evidence of competency",
"Poor structure"
]
},
"good_answer": {
"answer": "Sample good answer for data_analysis question - adequate detail, demonstrates competency clearly",
"score": "3",
"strengths": [
"Clear structure",
"Demonstrates competency",
"Adequate detail"
]
},
"great_answer": {
"answer": "Sample excellent answer for data_analysis question - exceptional detail, strong evidence, goes above and beyond",
"score": "4",
"strengths": [
"Exceptional detail",
"Strong evidence",
"Strategic thinking",
"Goes beyond requirements"
]
}
},
"scoring_rationale": {
"key_indicators": "Look for evidence of data analysis competency",
"red_flags": "Vague answers, lack of specifics, negative outcomes without learning",
"green_flags": "Specific examples, clear impact, demonstrates growth and learning"
}
},
"question_3": {
"question": "What challenges have you faced related to team leadership and how did you overcome them?",
"competency": "team_leadership",
"sample_answers": {
"poor_answer": {
"answer": "Sample poor answer for team_leadership question - lacks detail, specificity, or demonstrates weak competency",
"score": "1-2",
"issues": [
"Vague response",
"Limited evidence of competency",
"Poor structure"
]
},
"good_answer": {
"answer": "Sample good answer for team_leadership question - adequate detail, demonstrates competency clearly",
"score": "3",
"strengths": [
"Clear structure",
"Demonstrates competency",
"Adequate detail"
]
},
"great_answer": {
"answer": "Sample excellent answer for team_leadership question - exceptional detail, strong evidence, goes above and beyond",
"score": "4",
"strengths": [
"Exceptional detail",
"Strong evidence",
"Strategic thinking",
"Goes beyond requirements"
]
}
},
"scoring_rationale": {
"key_indicators": "Look for evidence of team leadership competency",
"red_flags": "Vague answers, lack of specifics, negative outcomes without learning",
"green_flags": "Specific examples, clear impact, demonstrates growth and learning"
}
},
"question_4": {
"question": "Design a go-to-market strategy for a new B2B SaaS product entering a competitive market.",
"competency": "product_strategy",
"sample_answers": {
"poor_answer": {
"answer": "Sample poor answer for product_strategy question - lacks detail, specificity, or demonstrates weak competency",
"score": "1-2",
"issues": [
"Vague response",
"Limited evidence of competency",
"Poor structure"
]
},
"good_answer": {
"answer": "Sample good answer for product_strategy question - adequate detail, demonstrates competency clearly",
"score": "3",
"strengths": [
"Clear structure",
"Demonstrates competency",
"Adequate detail"
]
},
"great_answer": {
"answer": "Sample excellent answer for product_strategy question - exceptional detail, strong evidence, goes above and beyond",
"score": "4",
"strengths": [
"Exceptional detail",
"Strong evidence",
"Strategic thinking",
"Goes beyond requirements"
]
}
},
"scoring_rationale": {
"key_indicators": "Look for evidence of product strategy competency",
"red_flags": "Vague answers, lack of specifics, negative outcomes without learning",
"green_flags": "Specific examples, clear impact, demonstrates growth and learning"
}
},
"question_5": {
"question": "What challenges have you faced related to business strategy and how did you overcome them?",
"competency": "business_strategy",
"sample_answers": {
"poor_answer": {
"answer": "Sample poor answer for business_strategy question - lacks detail, specificity, or demonstrates weak competency",
"score": "1-2",
"issues": [
"Vague response",
"Limited evidence of competency",
"Poor structure"
]
},
"good_answer": {
"answer": "Sample good answer for business_strategy question - adequate detail, demonstrates competency clearly",
"score": "3",
"strengths": [
"Clear structure",
"Demonstrates competency",
"Adequate detail"
]
},
"great_answer": {
"answer": "Sample excellent answer for business_strategy question - exceptional detail, strong evidence, goes above and beyond",
"score": "4",
"strengths": [
"Exceptional detail",
"Strong evidence",
"Strategic thinking",
"Goes beyond requirements"
]
}
},
"scoring_rationale": {
"key_indicators": "Look for evidence of business strategy competency",
"red_flags": "Vague answers, lack of specifics, negative outcomes without learning",
"green_flags": "Specific examples, clear impact, demonstrates growth and learning"
}
}
},
"usage_guidelines": {
"interview_flow": {
"warm_up": "Start with 1-2 easier questions to build rapport",
"core_assessment": "Focus majority of time on core competency questions",
"closing": "End with questions about candidate's questions/interests"
},
"time_management": {
"technical_questions": "Allow extra time for coding/design questions",
"behavioral_questions": "Keep to time limits but allow for follow-ups",
"total_recommendation": "45-75 minutes per interview round"
},
"question_selection": {
"variety": "Mix question types within each competency area",
"difficulty": "Adjust based on candidate responses and energy",
"customization": "Adapt questions based on candidate's background"
},
"common_mistakes": [
"Don't ask all questions mechanically",
"Don't skip follow-up questions",
"Don't forget to assess cultural fit alongside competencies",
"Don't let one strong/weak area bias overall assessment"
],
"calibration_reminders": [
"Compare against role standard, not other candidates",
"Focus on evidence demonstrated, not potential",
"Consider level-appropriate expectations",
"Document specific examples in feedback"
]
}
}
FILE:expected_outputs/product_manager_senior_questions.txt
Interview Question Bank: Product Manager (Senior Level)
======================================================================
Generated: 2026-02-16T13:27:41.303329
Total Questions: 20
Question Types: technical, behavioral, situational
Target Competencies: strategy, analytics, business_strategy, product_strategy, stakeholder_management, p&l_responsibility, leadership, team_leadership, user_research, data_analysis
INTERVIEW QUESTIONS
--------------------------------------------------
1. What challenges have you faced related to p&l responsibility and how did you overcome them?
Competency: P&L Responsibility
Type: Challenge_Based
Focus Areas: problem_solving, learning_from_experience
2. Analyze conversion funnel data to identify the biggest drop-off point and propose solutions.
Competency: Data Analysis
Type: Analytical
Time Limit: 45 minutes
3. What challenges have you faced related to team leadership and how did you overcome them?
Competency: Team Leadership
Type: Challenge_Based
Focus Areas: problem_solving, learning_from_experience
4. Design a go-to-market strategy for a new B2B SaaS product entering a competitive market.
Competency: Product Strategy
Type: Strategic
Time Limit: 60 minutes
5. What challenges have you faced related to business strategy and how did you overcome them?
Competency: Business Strategy
Type: Challenge_Based
Focus Areas: problem_solving, learning_from_experience
6. Describe your experience with business strategy in your current or previous role.
Competency: Business Strategy
Type: Experience
Focus Areas: experience_depth, practical_application
7. Describe your experience with team leadership in your current or previous role.
Competency: Team Leadership
Type: Experience
Focus Areas: experience_depth, practical_application
8. Describe a situation where you had to influence someone without having direct authority over them.
Competency: Leadership
Type: Behavioral
Focus Areas: influence, persuasion, stakeholder_management
9. Given a dataset of user activities, calculate the daily active users for the past month.
Competency: Data Analysis
Type: Analytical
Time Limit: 30 minutes
10. Describe your experience with analytics in your current or previous role.
Competency: Analytics
Type: Experience
Focus Areas: experience_depth, practical_application
11. How would you prioritize features for a mobile app with limited engineering resources?
Competency: Product Strategy
Type: Case_Study
Time Limit: 45 minutes
12. Describe your experience with stakeholder management in your current or previous role.
Competency: Stakeholder Management
Type: Experience
Focus Areas: experience_depth, practical_application
13. What challenges have you faced related to stakeholder management and how did you overcome them?
Competency: Stakeholder Management
Type: Challenge_Based
Focus Areas: problem_solving, learning_from_experience
14. What challenges have you faced related to user research and how did you overcome them?
Competency: User Research
Type: Challenge_Based
Focus Areas: problem_solving, learning_from_experience
15. What challenges have you faced related to strategy and how did you overcome them?
Competency: Strategy
Type: Challenge_Based
Focus Areas: problem_solving, learning_from_experience
16. Describe your experience with user research in your current or previous role.
Competency: User Research
Type: Experience
Focus Areas: experience_depth, practical_application
17. Describe your experience with p&l responsibility in your current or previous role.
Competency: P&L Responsibility
Type: Experience
Focus Areas: experience_depth, practical_application
18. Describe your experience with strategy in your current or previous role.
Competency: Strategy
Type: Experience
Focus Areas: experience_depth, practical_application
19. Tell me about a time when you had to lead a team through a significant change or challenge.
Competency: Leadership
Type: Behavioral
Focus Areas: change_management, team_motivation, communication
20. What challenges have you faced related to analytics and how did you overcome them?
Competency: Analytics
Type: Challenge_Based
Focus Areas: problem_solving, learning_from_experience
SCORING RUBRICS
--------------------------------------------------
Sample Scoring Criteria (behavioral questions):
Situation Clarity:
4: Clear, specific situation with relevant context and stakes
3: Good situation description with adequate context
2: Situation described but lacks some specifics
1: Vague or unclear situation description
Action Quality:
4: Specific, thoughtful actions showing strong competency
3: Good actions demonstrating competency
2: Adequate actions but could be stronger
1: Weak or inappropriate actions
Result Impact:
4: Significant positive impact with measurable results
3: Good positive impact with clear outcomes
2: Some positive impact demonstrated
1: Little or no positive impact shown
Self Awareness:
4: Excellent self-reflection, learns from experience, acknowledges growth areas
3: Good self-awareness and learning orientation
2: Some self-reflection demonstrated
1: Limited self-awareness or reflection
FOLLOW-UP PROBE EXAMPLES
--------------------------------------------------
Sample follow-up questions:
• Can you provide more specific details about your approach?
• What would you do differently if you had to do this again?
• What challenges did you face and how did you overcome them?
USAGE GUIDELINES
--------------------------------------------------
Interview Flow:
• Warm Up: Start with 1-2 easier questions to build rapport
• Core Assessment: Focus majority of time on core competency questions
• Closing: End with questions about candidate's questions/interests
Time Management:
• Technical Questions: Allow extra time for coding/design questions
• Behavioral Questions: Keep to time limits but allow for follow-ups
• Total Recommendation: 45-75 minutes per interview round
Common Mistakes to Avoid:
• Don't ask all questions mechanically
• Don't skip follow-up questions
• Don't forget to assess cultural fit alongside competencies
CALIBRATION EXAMPLES
--------------------------------------------------
Question: What challenges have you faced related to p&l responsibility and how did you overcome them?
Sample Answer Quality Levels:
Poor Answer (Score 1-2):
Issues: Vague response, Limited evidence of competency, Poor structure
Good Answer (Score 3):
Strengths: Clear structure, Demonstrates competency, Adequate detail
Great Answer (Score 4):
Strengths: Exceptional detail, Strong evidence, Strategic thinking, Goes beyond requirements
FILE:expected_outputs/senior_software_engineer_senior_interview_loop.json
{
"role": "Senior Software Engineer",
"level": "senior",
"team": "platform",
"generated_at": "2026-02-16T13:27:37.925680",
"total_duration_minutes": 300,
"total_rounds": 5,
"rounds": {
"round_1_technical_phone_screen": {
"name": "Technical Phone Screen",
"duration_minutes": 45,
"format": "virtual",
"objectives": [
"Assess coding fundamentals",
"Evaluate problem-solving approach",
"Screen for basic technical competency"
],
"question_types": [
"coding_problems",
"technical_concepts",
"experience_questions"
],
"evaluation_criteria": [
"technical_accuracy",
"problem_solving_process",
"communication_clarity"
],
"order": 1,
"focus_areas": [
"coding_fundamentals",
"problem_solving",
"technical_leadership",
"system_architecture",
"people_development"
]
},
"round_2_coding_deep_dive": {
"name": "Coding Deep Dive",
"duration_minutes": 75,
"format": "in_person_or_virtual",
"objectives": [
"Evaluate coding skills in depth",
"Assess code quality and testing",
"Review debugging approach"
],
"question_types": [
"complex_coding_problems",
"code_review",
"testing_strategy"
],
"evaluation_criteria": [
"code_quality",
"testing_approach",
"debugging_skills",
"optimization_thinking"
],
"order": 2,
"focus_areas": [
"technical_execution",
"code_quality",
"technical_leadership",
"system_architecture",
"people_development"
]
},
"round_3_system_design": {
"name": "System Design",
"duration_minutes": 75,
"format": "collaborative_whiteboard",
"objectives": [
"Assess architectural thinking",
"Evaluate scalability considerations",
"Review trade-off analysis"
],
"question_types": [
"system_architecture",
"scalability_design",
"trade_off_analysis"
],
"evaluation_criteria": [
"architectural_thinking",
"scalability_awareness",
"trade_off_reasoning"
],
"order": 3,
"focus_areas": [
"system_thinking",
"architectural_reasoning",
"technical_leadership",
"system_architecture",
"people_development"
]
},
"round_4_behavioral": {
"name": "Behavioral Interview",
"duration_minutes": 45,
"format": "conversational",
"objectives": [
"Assess cultural fit",
"Evaluate past experiences",
"Review leadership examples"
],
"question_types": [
"star_method_questions",
"situational_scenarios",
"values_alignment"
],
"evaluation_criteria": [
"communication_skills",
"leadership_examples",
"cultural_alignment"
],
"order": 4,
"focus_areas": [
"cultural_fit",
"communication",
"teamwork",
"technical_leadership",
"system_architecture"
]
},
"round_5_technical_leadership": {
"name": "Technical Leadership",
"duration_minutes": 60,
"format": "discussion_based",
"objectives": [
"Evaluate mentoring capability",
"Assess technical decision making",
"Review cross-team collaboration"
],
"question_types": [
"leadership_scenarios",
"technical_decisions",
"mentoring_examples"
],
"evaluation_criteria": [
"leadership_potential",
"technical_judgment",
"influence_skills"
],
"order": 5,
"focus_areas": [
"leadership",
"mentoring",
"influence",
"technical_leadership",
"system_architecture"
]
}
},
"suggested_schedule": {
"type": "multi_day",
"total_duration_minutes": 300,
"recommended_breaks": [
{
"type": "short_break",
"duration": 15,
"after_minutes": 90
},
{
"type": "lunch_break",
"duration": 60,
"after_minutes": 180
}
],
"day_structure": {
"day_1": {
"date": "TBD",
"start_time": "09:00",
"end_time": "12:45",
"rounds": [
{
"type": "interview",
"round_name": "round_1_technical_phone_screen",
"title": "Technical Phone Screen",
"start_time": "09:00",
"end_time": "09:45",
"duration_minutes": 45,
"format": "virtual"
},
{
"type": "interview",
"round_name": "round_2_coding_deep_dive",
"title": "Coding Deep Dive",
"start_time": "10:00",
"end_time": "11:15",
"duration_minutes": 75,
"format": "in_person_or_virtual"
},
{
"type": "interview",
"round_name": "round_3_system_design",
"title": "System Design",
"start_time": "11:30",
"end_time": "12:45",
"duration_minutes": 75,
"format": "collaborative_whiteboard"
}
]
},
"day_2": {
"date": "TBD",
"start_time": "09:00",
"end_time": "11:00",
"rounds": [
{
"type": "interview",
"round_name": "round_4_behavioral",
"title": "Behavioral Interview",
"start_time": "09:00",
"end_time": "09:45",
"duration_minutes": 45,
"format": "conversational"
},
{
"type": "interview",
"round_name": "round_5_technical_leadership",
"title": "Technical Leadership",
"start_time": "10:00",
"end_time": "11:00",
"duration_minutes": 60,
"format": "discussion_based"
}
]
}
},
"logistics_notes": [
"Coordinate interviewer availability before scheduling",
"Ensure all interviewers have access to job description and competency requirements",
"Prepare interview rooms/virtual links for all rounds",
"Share candidate resume and application with all interviewers",
"Test video conferencing setup before virtual interviews",
"Share virtual meeting links with candidate 24 hours in advance",
"Prepare whiteboard or collaborative online tool for design sessions"
]
},
"scorecard_template": {
"scoring_scale": {
"4": "Exceeds Expectations - Demonstrates mastery beyond required level",
"3": "Meets Expectations - Solid performance meeting all requirements",
"2": "Partially Meets - Shows potential but has development areas",
"1": "Does Not Meet - Significant gaps in required competencies"
},
"dimensions": [
{
"dimension": "system_architecture",
"weight": "high",
"scale": "1-4",
"description": "Assessment of system architecture competency"
},
{
"dimension": "technical_leadership",
"weight": "high",
"scale": "1-4",
"description": "Assessment of technical leadership competency"
},
{
"dimension": "mentoring",
"weight": "high",
"scale": "1-4",
"description": "Assessment of mentoring competency"
},
{
"dimension": "cross_team_collab",
"weight": "high",
"scale": "1-4",
"description": "Assessment of cross team collab competency"
},
{
"dimension": "technology_evaluation",
"weight": "medium",
"scale": "1-4",
"description": "Assessment of technology evaluation competency"
},
{
"dimension": "process_improvement",
"weight": "medium",
"scale": "1-4",
"description": "Assessment of process improvement competency"
},
{
"dimension": "hiring_contribution",
"weight": "medium",
"scale": "1-4",
"description": "Assessment of hiring contribution competency"
},
{
"dimension": "communication",
"weight": "high",
"scale": "1-4"
},
{
"dimension": "cultural_fit",
"weight": "medium",
"scale": "1-4"
},
{
"dimension": "learning_agility",
"weight": "medium",
"scale": "1-4"
}
],
"overall_recommendation": {
"options": [
"Strong Hire",
"Hire",
"No Hire",
"Strong No Hire"
],
"criteria": "Based on weighted average and minimum thresholds"
},
"calibration_notes": {
"required": true,
"min_length": 100,
"sections": [
"strengths",
"areas_for_development",
"specific_examples"
]
}
},
"interviewer_requirements": {
"round_1_technical_phone_screen": {
"required_skills": [
"technical_assessment",
"coding_evaluation"
],
"preferred_experience": [
"same_domain",
"senior_level"
],
"calibration_level": "standard",
"suggested_interviewers": [
"senior_engineer",
"tech_lead"
]
},
"round_2_coding_deep_dive": {
"required_skills": [
"advanced_technical",
"code_quality_assessment"
],
"preferred_experience": [
"senior_engineer",
"system_design"
],
"calibration_level": "high",
"suggested_interviewers": [
"senior_engineer",
"staff_engineer"
]
},
"round_3_system_design": {
"required_skills": [
"architecture_design",
"scalability_assessment"
],
"preferred_experience": [
"senior_architect",
"large_scale_systems"
],
"calibration_level": "high",
"suggested_interviewers": [
"senior_architect",
"staff_engineer"
]
},
"round_4_behavioral": {
"required_skills": [
"behavioral_interviewing",
"competency_assessment"
],
"preferred_experience": [
"hiring_manager",
"people_leadership"
],
"calibration_level": "standard",
"suggested_interviewers": [
"hiring_manager",
"people_manager"
]
},
"round_5_technical_leadership": {
"required_skills": [
"leadership_assessment",
"technical_mentoring"
],
"preferred_experience": [
"engineering_manager",
"tech_lead"
],
"calibration_level": "high",
"suggested_interviewers": [
"engineering_manager",
"senior_staff"
]
}
},
"competency_framework": {
"required": [
"system_architecture",
"technical_leadership",
"mentoring",
"cross_team_collab"
],
"preferred": [
"technology_evaluation",
"process_improvement",
"hiring_contribution"
],
"focus_areas": [
"technical_leadership",
"system_architecture",
"people_development"
]
},
"calibration_notes": {
"hiring_bar_notes": "Calibrated for senior level software engineer role",
"common_pitfalls": [
"Avoid comparing candidates to each other rather than to the role standard",
"Don't let one strong/weak area overshadow overall assessment",
"Ensure consistent application of evaluation criteria"
],
"calibration_checkpoints": [
"Review score distribution after every 5 candidates",
"Conduct monthly interviewer calibration sessions",
"Track correlation with 6-month performance reviews"
],
"escalation_criteria": [
"Any candidate receiving all 4s or all 1s",
"Significant disagreement between interviewers (>1.5 point spread)",
"Unusual circumstances or accommodations needed"
]
}
}
FILE:expected_outputs/senior_software_engineer_senior_interview_loop.txt
Interview Loop Design for Senior Software Engineer (Senior Level)
============================================================
Team: platform
Generated: 2026-02-16T13:27:37.925680
Total Duration: 300 minutes (5h 0m)
Total Rounds: 5
INTERVIEW ROUNDS
----------------------------------------
Round 1: Technical Phone Screen
Duration: 45 minutes
Format: Virtual
Objectives:
• Assess coding fundamentals
• Evaluate problem-solving approach
• Screen for basic technical competency
Focus Areas:
• Coding Fundamentals
• Problem Solving
• Technical Leadership
• System Architecture
• People Development
Round 2: Coding Deep Dive
Duration: 75 minutes
Format: In Person Or Virtual
Objectives:
• Evaluate coding skills in depth
• Assess code quality and testing
• Review debugging approach
Focus Areas:
• Technical Execution
• Code Quality
• Technical Leadership
• System Architecture
• People Development
Round 3: System Design
Duration: 75 minutes
Format: Collaborative Whiteboard
Objectives:
• Assess architectural thinking
• Evaluate scalability considerations
• Review trade-off analysis
Focus Areas:
• System Thinking
• Architectural Reasoning
• Technical Leadership
• System Architecture
• People Development
Round 4: Behavioral Interview
Duration: 45 minutes
Format: Conversational
Objectives:
• Assess cultural fit
• Evaluate past experiences
• Review leadership examples
Focus Areas:
• Cultural Fit
• Communication
• Teamwork
• Technical Leadership
• System Architecture
Round 5: Technical Leadership
Duration: 60 minutes
Format: Discussion Based
Objectives:
• Evaluate mentoring capability
• Assess technical decision making
• Review cross-team collaboration
Focus Areas:
• Leadership
• Mentoring
• Influence
• Technical Leadership
• System Architecture
SUGGESTED SCHEDULE
----------------------------------------
Schedule Type: Multi Day
Day 1:
Time: 09:00 - 12:45
09:00-09:45: Technical Phone Screen (45min)
10:00-11:15: Coding Deep Dive (75min)
11:30-12:45: System Design (75min)
Day 2:
Time: 09:00 - 11:00
09:00-09:45: Behavioral Interview (45min)
10:00-11:00: Technical Leadership (60min)
INTERVIEWER REQUIREMENTS
----------------------------------------
Technical Phone Screen:
Required Skills: technical_assessment, coding_evaluation
Suggested Interviewers: senior_engineer, tech_lead
Calibration Level: Standard
Coding Deep Dive:
Required Skills: advanced_technical, code_quality_assessment
Suggested Interviewers: senior_engineer, staff_engineer
Calibration Level: High
System Design:
Required Skills: architecture_design, scalability_assessment
Suggested Interviewers: senior_architect, staff_engineer
Calibration Level: High
Behavioral:
Required Skills: behavioral_interviewing, competency_assessment
Suggested Interviewers: hiring_manager, people_manager
Calibration Level: Standard
Technical Leadership:
Required Skills: leadership_assessment, technical_mentoring
Suggested Interviewers: engineering_manager, senior_staff
Calibration Level: High
SCORECARD TEMPLATE
----------------------------------------
Scoring Scale:
4: Exceeds Expectations - Demonstrates mastery beyond required level
3: Meets Expectations - Solid performance meeting all requirements
2: Partially Meets - Shows potential but has development areas
1: Does Not Meet - Significant gaps in required competencies
Evaluation Dimensions:
• System Architecture (Weight: high)
• Technical Leadership (Weight: high)
• Mentoring (Weight: high)
• Cross Team Collab (Weight: high)
• Technology Evaluation (Weight: medium)
• Process Improvement (Weight: medium)
• Hiring Contribution (Weight: medium)
• Communication (Weight: high)
• Cultural Fit (Weight: medium)
• Learning Agility (Weight: medium)
CALIBRATION NOTES
----------------------------------------
Hiring Bar: Calibrated for senior level software engineer role
Common Pitfalls:
• Avoid comparing candidates to each other rather than to the role standard
• Don't let one strong/weak area overshadow overall assessment
• Ensure consistent application of evaluation criteria
FILE:hiring_calibrator.py
#!/usr/bin/env python3
"""
Hiring Calibrator
Analyzes interview scores from multiple candidates and interviewers to detect bias,
calibration issues, and inconsistent rubric application. Generates calibration reports
with specific recommendations for interviewer coaching and process improvements.
Usage:
python hiring_calibrator.py --input interview_results.json --analysis-type comprehensive
python hiring_calibrator.py --input data.json --competencies technical,leadership --output report.json
python hiring_calibrator.py --input historical_data.json --trend-analysis --period quarterly
"""
import os
import sys
import json
import argparse
import statistics
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Any, Tuple
from collections import defaultdict, Counter
import math
class HiringCalibrator:
"""Analyzes interview data for bias detection and calibration issues."""
def __init__(self):
self.bias_thresholds = self._init_bias_thresholds()
self.calibration_standards = self._init_calibration_standards()
self.demographic_categories = self._init_demographic_categories()
def _init_bias_thresholds(self) -> Dict[str, float]:
"""Initialize statistical thresholds for bias detection."""
return {
"score_variance_threshold": 1.5, # Standard deviations
"pass_rate_difference_threshold": 0.15, # 15% difference
"interviewer_consistency_threshold": 0.8, # Correlation coefficient
"demographic_parity_threshold": 0.10, # 10% difference
"score_inflation_threshold": 0.3, # 30% above historical average
"score_deflation_threshold": 0.3, # 30% below historical average
"minimum_sample_size": 5 # Minimum candidates per analysis
}
def _init_calibration_standards(self) -> Dict[str, Dict]:
"""Initialize expected calibration standards."""
return {
"score_distribution": {
"target_mean": 2.8, # Expected average score (1-4 scale)
"target_std": 0.9, # Expected standard deviation
"expected_distribution": {
"1": 0.10, # 10% score 1 (does not meet)
"2": 0.25, # 25% score 2 (partially meets)
"3": 0.45, # 45% score 3 (meets expectations)
"4": 0.20 # 20% score 4 (exceeds expectations)
}
},
"interviewer_agreement": {
"minimum_correlation": 0.70, # Minimum correlation between interviewers
"maximum_std_deviation": 0.8, # Maximum std dev in scores for same candidate
"agreement_threshold": 0.75 # % of time interviewers should agree within 1 point
},
"pass_rates": {
"junior_level": 0.25, # 25% pass rate for junior roles
"mid_level": 0.20, # 20% pass rate for mid roles
"senior_level": 0.15, # 15% pass rate for senior roles
"staff_level": 0.10, # 10% pass rate for staff+ roles
"leadership": 0.12 # 12% pass rate for leadership roles
}
}
def _init_demographic_categories(self) -> List[str]:
"""Initialize demographic categories to analyze for bias."""
return [
"gender", "ethnicity", "education_level", "previous_company_size",
"years_experience", "university_tier", "geographic_location"
]
def analyze_hiring_calibration(self, interview_data: List[Dict[str, Any]],
analysis_type: str = "comprehensive",
competencies: Optional[List[str]] = None,
trend_analysis: bool = False,
period: str = "monthly") -> Dict[str, Any]:
"""Perform comprehensive hiring calibration analysis."""
# Validate and preprocess data
processed_data = self._preprocess_interview_data(interview_data)
if len(processed_data) < self.bias_thresholds["minimum_sample_size"]:
return {
"error": "Insufficient data for analysis",
"minimum_required": self.bias_thresholds["minimum_sample_size"],
"actual_samples": len(processed_data)
}
# Perform different types of analysis based on request
analysis_results = {
"analysis_type": analysis_type,
"data_summary": self._generate_data_summary(processed_data),
"generated_at": datetime.now().isoformat()
}
if analysis_type in ["comprehensive", "bias"]:
analysis_results["bias_analysis"] = self._analyze_bias_patterns(processed_data, competencies)
if analysis_type in ["comprehensive", "calibration"]:
analysis_results["calibration_analysis"] = self._analyze_calibration_consistency(processed_data, competencies)
if analysis_type in ["comprehensive", "interviewer"]:
analysis_results["interviewer_analysis"] = self._analyze_interviewer_bias(processed_data)
if analysis_type in ["comprehensive", "scoring"]:
analysis_results["scoring_analysis"] = self._analyze_scoring_patterns(processed_data, competencies)
if trend_analysis:
analysis_results["trend_analysis"] = self._analyze_trends_over_time(processed_data, period)
# Generate recommendations
analysis_results["recommendations"] = self._generate_recommendations(analysis_results)
# Calculate overall calibration health score
analysis_results["calibration_health_score"] = self._calculate_health_score(analysis_results)
return analysis_results
def _preprocess_interview_data(self, raw_data: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
"""Clean and validate interview data."""
processed_data = []
for record in raw_data:
if self._validate_interview_record(record):
processed_record = self._standardize_record(record)
processed_data.append(processed_record)
return processed_data
def _validate_interview_record(self, record: Dict[str, Any]) -> bool:
"""Validate that an interview record has required fields."""
required_fields = ["candidate_id", "interviewer_id", "scores", "overall_recommendation", "date"]
for field in required_fields:
if field not in record or record[field] is None:
return False
# Validate scores format
if not isinstance(record["scores"], dict):
return False
# Validate score values are numeric and in valid range (1-4)
for competency, score in record["scores"].items():
if not isinstance(score, (int, float)) or not (1 <= score <= 4):
return False
return True
def _standardize_record(self, record: Dict[str, Any]) -> Dict[str, Any]:
"""Standardize record format and add computed fields."""
standardized = record.copy()
# Calculate average score
scores = list(record["scores"].values())
standardized["average_score"] = statistics.mean(scores)
# Standardize recommendation to binary
recommendation = record["overall_recommendation"].lower()
standardized["hire_decision"] = recommendation in ["hire", "strong hire", "yes"]
# Parse date if string
if isinstance(record["date"], str):
try:
standardized["date"] = datetime.fromisoformat(record["date"].replace("Z", "+00:00"))
except ValueError:
standardized["date"] = datetime.now()
# Add demographic info if available
for category in self.demographic_categories:
if category not in standardized:
standardized[category] = "unknown"
# Add level normalization
role = record.get("role", "").lower()
if any(level in role for level in ["junior", "associate", "entry"]):
standardized["normalized_level"] = "junior"
elif any(level in role for level in ["senior", "sr"]):
standardized["normalized_level"] = "senior"
elif any(level in role for level in ["staff", "principal", "lead"]):
standardized["normalized_level"] = "staff"
else:
standardized["normalized_level"] = "mid"
return standardized
def _generate_data_summary(self, data: List[Dict[str, Any]]) -> Dict[str, Any]:
"""Generate summary statistics for the dataset."""
if not data:
return {}
total_candidates = len(data)
unique_interviewers = len(set(record["interviewer_id"] for record in data))
# Score statistics
all_scores = []
all_average_scores = []
hire_decisions = []
for record in data:
all_scores.extend(record["scores"].values())
all_average_scores.append(record["average_score"])
hire_decisions.append(record["hire_decision"])
# Date range
dates = [record["date"] for record in data if record["date"]]
date_range = {
"start_date": min(dates).isoformat() if dates else None,
"end_date": max(dates).isoformat() if dates else None,
"total_days": (max(dates) - min(dates)).days if len(dates) > 1 else 0
}
# Role distribution
roles = [record.get("role", "unknown") for record in data]
role_distribution = dict(Counter(roles))
return {
"total_candidates": total_candidates,
"unique_interviewers": unique_interviewers,
"candidates_per_interviewer": round(total_candidates / unique_interviewers, 2),
"date_range": date_range,
"score_statistics": {
"mean_individual_scores": round(statistics.mean(all_scores), 2),
"std_individual_scores": round(statistics.stdev(all_scores) if len(all_scores) > 1 else 0, 2),
"mean_average_scores": round(statistics.mean(all_average_scores), 2),
"std_average_scores": round(statistics.stdev(all_average_scores) if len(all_average_scores) > 1 else 0, 2)
},
"hire_rate": round(sum(hire_decisions) / len(hire_decisions), 3),
"role_distribution": role_distribution
}
def _analyze_bias_patterns(self, data: List[Dict[str, Any]],
target_competencies: Optional[List[str]]) -> Dict[str, Any]:
"""Analyze potential bias patterns in interview decisions."""
bias_analysis = {
"demographic_bias": {},
"interviewer_bias": {},
"competency_bias": {},
"overall_bias_score": 0
}
# Analyze demographic bias
for demographic in self.demographic_categories:
if all(record.get(demographic) == "unknown" for record in data):
continue
demographic_analysis = self._analyze_demographic_bias(data, demographic)
if demographic_analysis["bias_detected"]:
bias_analysis["demographic_bias"][demographic] = demographic_analysis
# Analyze interviewer bias
bias_analysis["interviewer_bias"] = self._analyze_interviewer_bias(data)
# Analyze competency bias if specified
if target_competencies:
bias_analysis["competency_bias"] = self._analyze_competency_bias(data, target_competencies)
# Calculate overall bias score
bias_analysis["overall_bias_score"] = self._calculate_bias_score(bias_analysis)
return bias_analysis
def _analyze_demographic_bias(self, data: List[Dict[str, Any]],
demographic: str) -> Dict[str, Any]:
"""Analyze bias for a specific demographic category."""
# Group data by demographic values
demographic_groups = defaultdict(list)
for record in data:
demo_value = record.get(demographic, "unknown")
if demo_value != "unknown":
demographic_groups[demo_value].append(record)
if len(demographic_groups) < 2:
return {"bias_detected": False, "reason": "insufficient_groups"}
# Calculate statistics for each group
group_stats = {}
for group, records in demographic_groups.items():
if len(records) >= self.bias_thresholds["minimum_sample_size"]:
scores = [r["average_score"] for r in records]
hire_rate = sum(r["hire_decision"] for r in records) / len(records)
group_stats[group] = {
"count": len(records),
"mean_score": statistics.mean(scores),
"hire_rate": hire_rate,
"std_score": statistics.stdev(scores) if len(scores) > 1 else 0
}
if len(group_stats) < 2:
return {"bias_detected": False, "reason": "insufficient_sample_sizes"}
# Detect statistical differences
bias_detected = False
bias_details = {}
# Check for significant differences in hire rates
hire_rates = [stats["hire_rate"] for stats in group_stats.values()]
max_hire_rate_diff = max(hire_rates) - min(hire_rates)
if max_hire_rate_diff > self.bias_thresholds["demographic_parity_threshold"]:
bias_detected = True
bias_details["hire_rate_disparity"] = {
"max_difference": round(max_hire_rate_diff, 3),
"threshold": self.bias_thresholds["demographic_parity_threshold"],
"group_stats": group_stats
}
# Check for significant differences in scoring
mean_scores = [stats["mean_score"] for stats in group_stats.values()]
max_score_diff = max(mean_scores) - min(mean_scores)
if max_score_diff > 0.5: # Half point difference threshold
bias_detected = True
bias_details["scoring_disparity"] = {
"max_difference": round(max_score_diff, 3),
"group_stats": group_stats
}
return {
"bias_detected": bias_detected,
"demographic": demographic,
"group_statistics": group_stats,
"bias_details": bias_details,
"recommendation": self._generate_demographic_bias_recommendation(demographic, bias_details) if bias_detected else None
}
def _analyze_interviewer_bias(self, data: List[Dict[str, Any]]) -> Dict[str, Any]:
"""Analyze bias patterns across different interviewers."""
interviewer_stats = defaultdict(list)
# Group by interviewer
for record in data:
interviewer_id = record["interviewer_id"]
interviewer_stats[interviewer_id].append(record)
# Calculate statistics per interviewer
interviewer_analysis = {}
for interviewer_id, records in interviewer_stats.items():
if len(records) >= self.bias_thresholds["minimum_sample_size"]:
scores = [r["average_score"] for r in records]
hire_rate = sum(r["hire_decision"] for r in records) / len(records)
interviewer_analysis[interviewer_id] = {
"total_interviews": len(records),
"mean_score": statistics.mean(scores),
"std_score": statistics.stdev(scores) if len(scores) > 1 else 0,
"hire_rate": hire_rate,
"score_inflation": self._detect_score_inflation(scores),
"consistency_score": self._calculate_interviewer_consistency(records)
}
# Identify outlier interviewers
if len(interviewer_analysis) > 1:
overall_mean_score = statistics.mean([stats["mean_score"] for stats in interviewer_analysis.values()])
overall_hire_rate = statistics.mean([stats["hire_rate"] for stats in interviewer_analysis.values()])
outlier_interviewers = {}
for interviewer_id, stats in interviewer_analysis.items():
issues = []
# Check for score inflation/deflation
if stats["mean_score"] > overall_mean_score * (1 + self.bias_thresholds["score_inflation_threshold"]):
issues.append("score_inflation")
elif stats["mean_score"] < overall_mean_score * (1 - self.bias_thresholds["score_deflation_threshold"]):
issues.append("score_deflation")
# Check for hire rate deviation
hire_rate_diff = abs(stats["hire_rate"] - overall_hire_rate)
if hire_rate_diff > self.bias_thresholds["pass_rate_difference_threshold"]:
issues.append("hire_rate_deviation")
# Check for low consistency
if stats["consistency_score"] < self.bias_thresholds["interviewer_consistency_threshold"]:
issues.append("low_consistency")
if issues:
outlier_interviewers[interviewer_id] = {
"issues": issues,
"statistics": stats,
"severity": len(issues) # More issues = higher severity
}
return {
"interviewer_statistics": interviewer_analysis,
"outlier_interviewers": outlier_interviewers if len(interviewer_analysis) > 1 else {},
"overall_consistency": self._calculate_overall_interviewer_consistency(data),
"recommendations": self._generate_interviewer_recommendations(outlier_interviewers if len(interviewer_analysis) > 1 else {})
}
def _analyze_competency_bias(self, data: List[Dict[str, Any]],
competencies: List[str]) -> Dict[str, Any]:
"""Analyze bias patterns within specific competencies."""
competency_analysis = {}
for competency in competencies:
# Extract scores for this competency
competency_scores = []
for record in data:
if competency in record["scores"]:
competency_scores.append({
"score": record["scores"][competency],
"interviewer": record["interviewer_id"],
"candidate": record["candidate_id"],
"overall_decision": record["hire_decision"]
})
if len(competency_scores) < self.bias_thresholds["minimum_sample_size"]:
continue
# Analyze scoring patterns
scores = [item["score"] for item in competency_scores]
score_variance = statistics.variance(scores) if len(scores) > 1 else 0
# Analyze by interviewer
interviewer_competency_scores = defaultdict(list)
for item in competency_scores:
interviewer_competency_scores[item["interviewer"]].append(item["score"])
interviewer_variations = {}
if len(interviewer_competency_scores) > 1:
interviewer_means = {interviewer: statistics.mean(scores)
for interviewer, scores in interviewer_competency_scores.items()
if len(scores) >= 3}
if len(interviewer_means) > 1:
mean_of_means = statistics.mean(interviewer_means.values())
for interviewer, mean_score in interviewer_means.items():
deviation = abs(mean_score - mean_of_means)
if deviation > 0.5: # More than half point deviation
interviewer_variations[interviewer] = {
"mean_score": round(mean_score, 2),
"deviation_from_average": round(deviation, 2),
"sample_size": len(interviewer_competency_scores[interviewer])
}
competency_analysis[competency] = {
"total_scores": len(competency_scores),
"mean_score": round(statistics.mean(scores), 2),
"score_variance": round(score_variance, 2),
"interviewer_variations": interviewer_variations,
"bias_detected": len(interviewer_variations) > 0
}
return competency_analysis
def _analyze_calibration_consistency(self, data: List[Dict[str, Any]],
target_competencies: Optional[List[str]]) -> Dict[str, Any]:
"""Analyze calibration consistency across interviews."""
# Group candidates by those interviewed by multiple people
candidate_interviewers = defaultdict(list)
for record in data:
candidate_interviewers[record["candidate_id"]].append(record)
multi_interviewer_candidates = {
candidate: records for candidate, records in candidate_interviewers.items()
if len(records) > 1
}
if not multi_interviewer_candidates:
return {
"error": "No candidates with multiple interviewers found",
"single_interviewer_analysis": self._analyze_single_interviewer_consistency(data)
}
# Calculate agreement statistics
agreement_stats = []
score_correlations = []
for candidate, records in multi_interviewer_candidates.items():
candidate_scores = []
interviewer_pairs = []
for record in records:
avg_score = record["average_score"]
candidate_scores.append(avg_score)
interviewer_pairs.append(record["interviewer_id"])
if len(candidate_scores) > 1:
# Calculate standard deviation of scores for this candidate
score_std = statistics.stdev(candidate_scores)
agreement_stats.append(score_std)
# Check if all interviewers agree within 1 point
score_range = max(candidate_scores) - min(candidate_scores)
agreement_within_one = score_range <= 1.0
score_correlations.append({
"candidate": candidate,
"scores": candidate_scores,
"interviewers": interviewer_pairs,
"score_std": score_std,
"score_range": score_range,
"agreement_within_one": agreement_within_one
})
# Calculate overall calibration metrics
mean_score_std = statistics.mean(agreement_stats) if agreement_stats else 0
agreement_rate = sum(1 for corr in score_correlations if corr["agreement_within_one"]) / len(score_correlations) if score_correlations else 0
calibration_quality = "good"
if mean_score_std > self.calibration_standards["interviewer_agreement"]["maximum_std_deviation"]:
calibration_quality = "poor"
elif agreement_rate < self.calibration_standards["interviewer_agreement"]["agreement_threshold"]:
calibration_quality = "fair"
return {
"multi_interviewer_candidates": len(multi_interviewer_candidates),
"mean_score_standard_deviation": round(mean_score_std, 3),
"agreement_within_one_point_rate": round(agreement_rate, 3),
"calibration_quality": calibration_quality,
"candidate_agreement_details": score_correlations,
"target_standards": self.calibration_standards["interviewer_agreement"],
"recommendations": self._generate_calibration_recommendations(mean_score_std, agreement_rate)
}
def _analyze_scoring_patterns(self, data: List[Dict[str, Any]],
target_competencies: Optional[List[str]]) -> Dict[str, Any]:
"""Analyze overall scoring patterns and distributions."""
# Overall score distribution
all_individual_scores = []
all_average_scores = []
score_distribution = defaultdict(int)
for record in data:
avg_score = record["average_score"]
all_average_scores.append(avg_score)
for competency, score in record["scores"].items():
if not target_competencies or competency in target_competencies:
all_individual_scores.append(score)
score_distribution[str(int(score))] += 1
# Calculate distribution percentages
total_scores = sum(score_distribution.values())
score_percentages = {score: count/total_scores for score, count in score_distribution.items()}
# Compare against expected distribution
expected_dist = self.calibration_standards["score_distribution"]["expected_distribution"]
distribution_analysis = {}
for score in ["1", "2", "3", "4"]:
expected_pct = expected_dist.get(score, 0)
actual_pct = score_percentages.get(score, 0)
difference = actual_pct - expected_pct
distribution_analysis[score] = {
"expected_percentage": expected_pct,
"actual_percentage": round(actual_pct, 3),
"difference": round(difference, 3),
"significant_deviation": abs(difference) > 0.05 # 5% threshold
}
# Calculate scoring statistics
mean_score = statistics.mean(all_individual_scores) if all_individual_scores else 0
std_score = statistics.stdev(all_individual_scores) if len(all_individual_scores) > 1 else 0
target_mean = self.calibration_standards["score_distribution"]["target_mean"]
target_std = self.calibration_standards["score_distribution"]["target_std"]
# Analyze pass rates by level
level_pass_rates = {}
level_groups = defaultdict(list)
for record in data:
level = record.get("normalized_level", "unknown")
level_groups[level].append(record["hire_decision"])
for level, decisions in level_groups.items():
if len(decisions) >= self.bias_thresholds["minimum_sample_size"]:
pass_rate = sum(decisions) / len(decisions)
expected_rate = self.calibration_standards["pass_rates"].get(f"{level}_level", 0.15)
level_pass_rates[level] = {
"actual_pass_rate": round(pass_rate, 3),
"expected_pass_rate": expected_rate,
"difference": round(pass_rate - expected_rate, 3),
"sample_size": len(decisions)
}
return {
"score_statistics": {
"mean_score": round(mean_score, 2),
"std_score": round(std_score, 2),
"target_mean": target_mean,
"target_std": target_std,
"mean_deviation": round(abs(mean_score - target_mean), 2),
"std_deviation": round(abs(std_score - target_std), 2)
},
"score_distribution": distribution_analysis,
"level_pass_rates": level_pass_rates,
"overall_assessment": self._assess_scoring_health(distribution_analysis, mean_score, target_mean)
}
def _analyze_trends_over_time(self, data: List[Dict[str, Any]], period: str) -> Dict[str, Any]:
"""Analyze trends in hiring patterns over time."""
# Sort data by date
dated_data = [record for record in data if record.get("date")]
dated_data.sort(key=lambda x: x["date"])
if len(dated_data) < 10: # Need minimum data for trend analysis
return {"error": "Insufficient data for trend analysis", "minimum_required": 10}
# Group by time period
period_groups = defaultdict(list)
for record in dated_data:
date = record["date"]
if period == "weekly":
period_key = date.strftime("%Y-W%U")
elif period == "monthly":
period_key = date.strftime("%Y-%m")
elif period == "quarterly":
quarter = (date.month - 1) // 3 + 1
period_key = f"{date.year}-Q{quarter}"
else: # daily
period_key = date.strftime("%Y-%m-%d")
period_groups[period_key].append(record)
# Calculate metrics for each period
period_metrics = {}
for period_key, records in period_groups.items():
if len(records) >= 3: # Minimum for meaningful metrics
scores = [r["average_score"] for r in records]
hire_rate = sum(r["hire_decision"] for r in records) / len(records)
period_metrics[period_key] = {
"count": len(records),
"mean_score": statistics.mean(scores),
"hire_rate": hire_rate,
"std_score": statistics.stdev(scores) if len(scores) > 1 else 0
}
if len(period_metrics) < 3:
return {"error": "Insufficient periods for trend analysis"}
# Analyze trends
sorted_periods = sorted(period_metrics.keys())
mean_scores = [period_metrics[p]["mean_score"] for p in sorted_periods]
hire_rates = [period_metrics[p]["hire_rate"] for p in sorted_periods]
# Simple linear trend calculation
score_trend = self._calculate_linear_trend(mean_scores)
hire_rate_trend = self._calculate_linear_trend(hire_rates)
return {
"period": period,
"total_periods": len(period_metrics),
"period_metrics": period_metrics,
"trends": {
"score_trend": {
"direction": "increasing" if score_trend > 0.01 else "decreasing" if score_trend < -0.01 else "stable",
"slope": round(score_trend, 4),
"significance": "significant" if abs(score_trend) > 0.05 else "minor"
},
"hire_rate_trend": {
"direction": "increasing" if hire_rate_trend > 0.005 else "decreasing" if hire_rate_trend < -0.005 else "stable",
"slope": round(hire_rate_trend, 4),
"significance": "significant" if abs(hire_rate_trend) > 0.02 else "minor"
}
},
"insights": self._generate_trend_insights(score_trend, hire_rate_trend, period_metrics)
}
def _calculate_linear_trend(self, values: List[float]) -> float:
"""Calculate simple linear trend slope."""
if len(values) < 2:
return 0
n = len(values)
x = list(range(n))
# Calculate slope using least squares
x_mean = statistics.mean(x)
y_mean = statistics.mean(values)
numerator = sum((x[i] - x_mean) * (values[i] - y_mean) for i in range(n))
denominator = sum((x[i] - x_mean) ** 2 for i in range(n))
return numerator / denominator if denominator != 0 else 0
def _detect_score_inflation(self, scores: List[float]) -> Dict[str, Any]:
"""Detect if an interviewer shows score inflation patterns."""
if len(scores) < 5:
return {"insufficient_data": True}
mean_score = statistics.mean(scores)
std_score = statistics.stdev(scores)
# Check against expected mean (2.8)
expected_mean = self.calibration_standards["score_distribution"]["target_mean"]
deviation = mean_score - expected_mean
# High scores with low variance might indicate inflation
high_scores_low_variance = mean_score > 3.2 and std_score < 0.5
# Check distribution - too many 4s might indicate inflation
score_counts = Counter([int(score) for score in scores])
four_count_ratio = score_counts.get(4, 0) / len(scores)
return {
"mean_score": round(mean_score, 2),
"expected_mean": expected_mean,
"deviation": round(deviation, 2),
"high_scores_low_variance": high_scores_low_variance,
"four_count_ratio": round(four_count_ratio, 2),
"inflation_detected": deviation > 0.3 or high_scores_low_variance or four_count_ratio > 0.4
}
def _calculate_interviewer_consistency(self, records: List[Dict[str, Any]]) -> float:
"""Calculate consistency score for an interviewer."""
if len(records) < 3:
return 0.5 # Neutral score for insufficient data
# Look at variance in scoring
avg_scores = [r["average_score"] for r in records]
score_variance = statistics.variance(avg_scores)
# Look at decision consistency relative to scores
decisions = [r["hire_decision"] for r in records]
scores_of_hires = [r["average_score"] for r in records if r["hire_decision"]]
scores_of_no_hires = [r["average_score"] for r in records if not r["hire_decision"]]
# Good consistency means hires have higher average scores
decision_consistency = 0.5
if scores_of_hires and scores_of_no_hires:
hire_mean = statistics.mean(scores_of_hires)
no_hire_mean = statistics.mean(scores_of_no_hires)
score_gap = hire_mean - no_hire_mean
decision_consistency = min(1.0, max(0.0, score_gap / 2.0)) # Normalize to 0-1
# Combine metrics (lower variance = higher consistency)
variance_consistency = max(0.0, 1.0 - (score_variance / 2.0))
return (decision_consistency + variance_consistency) / 2
def _calculate_overall_interviewer_consistency(self, data: List[Dict[str, Any]]) -> Dict[str, Any]:
"""Calculate overall consistency across all interviewers."""
interviewer_consistency_scores = []
interviewer_records = defaultdict(list)
for record in data:
interviewer_records[record["interviewer_id"]].append(record)
for interviewer_id, records in interviewer_records.items():
if len(records) >= 3:
consistency = self._calculate_interviewer_consistency(records)
interviewer_consistency_scores.append(consistency)
if not interviewer_consistency_scores:
return {"error": "Insufficient data per interviewer for consistency analysis"}
return {
"mean_consistency": round(statistics.mean(interviewer_consistency_scores), 3),
"std_consistency": round(statistics.stdev(interviewer_consistency_scores) if len(interviewer_consistency_scores) > 1 else 0, 3),
"min_consistency": round(min(interviewer_consistency_scores), 3),
"max_consistency": round(max(interviewer_consistency_scores), 3),
"interviewers_analyzed": len(interviewer_consistency_scores),
"target_threshold": self.bias_thresholds["interviewer_consistency_threshold"]
}
def _calculate_bias_score(self, bias_analysis: Dict[str, Any]) -> float:
"""Calculate overall bias score (0-1, where 1 is most biased)."""
bias_factors = []
# Demographic bias factors
demographic_bias = bias_analysis.get("demographic_bias", {})
for demo, analysis in demographic_bias.items():
if analysis.get("bias_detected"):
bias_factors.append(0.3) # Each demographic bias adds 0.3
# Interviewer bias factors
interviewer_bias = bias_analysis.get("interviewer_bias", {})
outlier_interviewers = interviewer_bias.get("outlier_interviewers", {})
if outlier_interviewers:
# Scale by severity and number of outliers
total_severity = sum(info["severity"] for info in outlier_interviewers.values())
bias_factors.append(min(0.5, total_severity * 0.1))
# Competency bias factors
competency_bias = bias_analysis.get("competency_bias", {})
for comp, analysis in competency_bias.items():
if analysis.get("bias_detected"):
bias_factors.append(0.2) # Each competency bias adds 0.2
return min(1.0, sum(bias_factors))
def _calculate_health_score(self, analysis: Dict[str, Any]) -> Dict[str, Any]:
"""Calculate overall calibration health score."""
health_factors = []
# Bias score (lower is better)
bias_analysis = analysis.get("bias_analysis", {})
bias_score = bias_analysis.get("overall_bias_score", 0)
bias_health = max(0, 1 - bias_score)
health_factors.append(("bias", bias_health, 0.3))
# Calibration consistency
calibration_analysis = analysis.get("calibration_analysis", {})
if "calibration_quality" in calibration_analysis:
quality_map = {"good": 1.0, "fair": 0.7, "poor": 0.3}
calibration_health = quality_map.get(calibration_analysis["calibration_quality"], 0.5)
health_factors.append(("calibration", calibration_health, 0.25))
# Interviewer consistency
interviewer_analysis = analysis.get("interviewer_analysis", {})
overall_consistency = interviewer_analysis.get("overall_consistency", {})
if "mean_consistency" in overall_consistency:
consistency_health = overall_consistency["mean_consistency"]
health_factors.append(("interviewer_consistency", consistency_health, 0.25))
# Scoring patterns health
scoring_analysis = analysis.get("scoring_analysis", {})
if "overall_assessment" in scoring_analysis:
assessment_map = {"healthy": 1.0, "concerning": 0.6, "poor": 0.2}
scoring_health = assessment_map.get(scoring_analysis["overall_assessment"], 0.5)
health_factors.append(("scoring_patterns", scoring_health, 0.2))
# Calculate weighted average
if health_factors:
weighted_sum = sum(score * weight for _, score, weight in health_factors)
total_weight = sum(weight for _, _, weight in health_factors)
overall_score = weighted_sum / total_weight
else:
overall_score = 0.5 # Neutral if no data
# Categorize health
if overall_score >= 0.8:
health_category = "excellent"
elif overall_score >= 0.7:
health_category = "good"
elif overall_score >= 0.5:
health_category = "fair"
else:
health_category = "poor"
return {
"overall_score": round(overall_score, 3),
"health_category": health_category,
"component_scores": {name: round(score, 3) for name, score, _ in health_factors},
"improvement_priority": self._identify_improvement_priorities(health_factors)
}
def _identify_improvement_priorities(self, health_factors: List[Tuple[str, float, float]]) -> List[str]:
"""Identify areas that need the most improvement."""
priorities = []
for name, score, weight in health_factors:
impact = (1 - score) * weight # Low scores with high weights = high priority
if impact > 0.15: # Significant impact threshold
priorities.append(name)
# Sort by impact (highest first)
priorities.sort(key=lambda name: next((1 - score) * weight for n, score, weight in health_factors if n == name), reverse=True)
return priorities
def _generate_recommendations(self, analysis: Dict[str, Any]) -> List[Dict[str, Any]]:
"""Generate actionable recommendations based on analysis results."""
recommendations = []
# Bias-related recommendations
bias_analysis = analysis.get("bias_analysis", {})
# Demographic bias recommendations
for demo, demo_analysis in bias_analysis.get("demographic_bias", {}).items():
if demo_analysis.get("bias_detected"):
recommendations.append({
"priority": "high",
"category": "bias_mitigation",
"title": f"Address {demo.replace('_', ' ').title()} Bias",
"description": demo_analysis.get("recommendation", f"Implement bias mitigation strategies for {demo}"),
"actions": [
"Conduct unconscious bias training focused on this demographic",
"Review and standardize interview questions",
"Implement diverse interview panels",
"Monitor hiring metrics by demographic group"
]
})
# Interviewer-specific recommendations
interviewer_analysis = bias_analysis.get("interviewer_bias", {})
outlier_interviewers = interviewer_analysis.get("outlier_interviewers", {})
for interviewer_id, outlier_info in outlier_interviewers.items():
issues = outlier_info["issues"]
priority = "high" if outlier_info["severity"] >= 3 else "medium"
actions = []
if "score_inflation" in issues:
actions.extend([
"Provide calibration training on scoring standards",
"Shadow experienced interviewers for recalibration",
"Review examples of each score level"
])
if "score_deflation" in issues:
actions.extend([
"Review expectations for role level",
"Calibrate against recent successful hires",
"Discuss evaluation criteria with hiring manager"
])
if "hire_rate_deviation" in issues:
actions.extend([
"Review hiring bar standards",
"Participate in calibration sessions",
"Compare decision criteria with team"
])
if "low_consistency" in issues:
actions.extend([
"Practice structured interviewing techniques",
"Use standardized scorecards",
"Document specific examples for each score"
])
recommendations.append({
"priority": priority,
"category": "interviewer_coaching",
"title": f"Coach Interviewer {interviewer_id}",
"description": f"Address issues: {', '.join(issues)}",
"actions": list(set(actions)) # Remove duplicates
})
# Calibration recommendations
calibration_analysis = analysis.get("calibration_analysis", {})
if calibration_analysis.get("calibration_quality") in ["fair", "poor"]:
recommendations.append({
"priority": "high",
"category": "calibration_improvement",
"title": "Improve Interview Calibration",
"description": f"Current calibration quality: {calibration_analysis.get('calibration_quality')}",
"actions": [
"Conduct monthly calibration sessions",
"Create shared examples of good/poor answers",
"Implement mandatory interviewer shadowing",
"Standardize scoring rubrics across all interviewers",
"Review and align on role expectations"
]
})
# Scoring pattern recommendations
scoring_analysis = analysis.get("scoring_analysis", {})
if scoring_analysis.get("overall_assessment") in ["concerning", "poor"]:
recommendations.append({
"priority": "medium",
"category": "scoring_standards",
"title": "Adjust Scoring Standards",
"description": "Scoring patterns deviate significantly from expected distribution",
"actions": [
"Review and communicate target score distributions",
"Provide examples for each score level",
"Monitor pass rates by role level",
"Adjust hiring bar if consistently too high/low"
]
})
# Health score recommendations
health_score = analysis.get("calibration_health_score", {})
priorities = health_score.get("improvement_priority", [])
if "bias" in priorities:
recommendations.append({
"priority": "critical",
"category": "bias_mitigation",
"title": "Implement Comprehensive Bias Mitigation",
"description": "Multiple bias indicators detected across the hiring process",
"actions": [
"Mandatory unconscious bias training for all interviewers",
"Implement structured interview protocols",
"Diversify interview panels",
"Regular bias audits and monitoring",
"Create accountability metrics for fair hiring"
]
})
# Sort by priority
priority_order = {"critical": 0, "high": 1, "medium": 2, "low": 3}
recommendations.sort(key=lambda x: priority_order.get(x["priority"], 3))
return recommendations
def _generate_demographic_bias_recommendation(self, demographic: str, bias_details: Dict[str, Any]) -> str:
"""Generate specific recommendation for demographic bias."""
if "hire_rate_disparity" in bias_details:
return f"Significant hire rate disparity detected for {demographic}. Implement structured interviews and diverse panels."
elif "scoring_disparity" in bias_details:
return f"Scoring disparity detected for {demographic}. Provide unconscious bias training and standardize evaluation criteria."
else:
return f"Potential bias detected for {demographic}. Monitor closely and implement bias mitigation strategies."
def _generate_interviewer_recommendations(self, outlier_interviewers: Dict[str, Any]) -> List[str]:
"""Generate recommendations for interviewer issues."""
if not outlier_interviewers:
return ["All interviewers performing within expected ranges"]
recommendations = []
for interviewer, info in outlier_interviewers.items():
issues = info["issues"]
if len(issues) >= 2:
recommendations.append(f"Interviewer {interviewer}: Requires comprehensive recalibration - multiple issues detected")
elif "score_inflation" in issues:
recommendations.append(f"Interviewer {interviewer}: Provide calibration training on scoring standards")
elif "hire_rate_deviation" in issues:
recommendations.append(f"Interviewer {interviewer}: Review hiring bar standards and decision criteria")
return recommendations
def _generate_calibration_recommendations(self, mean_std: float, agreement_rate: float) -> List[str]:
"""Generate calibration improvement recommendations."""
recommendations = []
if mean_std > self.calibration_standards["interviewer_agreement"]["maximum_std_deviation"]:
recommendations.append("High score variance detected - implement regular calibration sessions")
recommendations.append("Create shared examples of scoring standards for each competency")
if agreement_rate < self.calibration_standards["interviewer_agreement"]["agreement_threshold"]:
recommendations.append("Low interviewer agreement rate - standardize interview questions and evaluation criteria")
recommendations.append("Implement mandatory interviewer training on consistent evaluation")
if not recommendations:
recommendations.append("Calibration appears healthy - maintain current practices")
return recommendations
def _assess_scoring_health(self, distribution: Dict[str, Any], mean_score: float, target_mean: float) -> str:
"""Assess overall health of scoring patterns."""
issues = 0
# Check distribution deviations
for score_level, analysis in distribution.items():
if analysis["significant_deviation"]:
issues += 1
# Check mean deviation
if abs(mean_score - target_mean) > 0.3:
issues += 1
if issues == 0:
return "healthy"
elif issues <= 2:
return "concerning"
else:
return "poor"
def _generate_trend_insights(self, score_trend: float, hire_rate_trend: float, period_metrics: Dict[str, Any]) -> List[str]:
"""Generate insights from trend analysis."""
insights = []
if abs(score_trend) > 0.05:
direction = "increasing" if score_trend > 0 else "decreasing"
insights.append(f"Significant {direction} trend in average scores over time")
if score_trend > 0:
insights.append("May indicate score inflation or improving candidate quality")
else:
insights.append("May indicate stricter evaluation or declining candidate quality")
if abs(hire_rate_trend) > 0.02:
direction = "increasing" if hire_rate_trend > 0 else "decreasing"
insights.append(f"Significant {direction} trend in hire rates over time")
if hire_rate_trend > 0:
insights.append("Consider if hiring bar has lowered or candidate pool improved")
else:
insights.append("Consider if hiring bar has raised or candidate pool declined")
# Check for consistency
period_values = list(period_metrics.values())
hire_rates = [p["hire_rate"] for p in period_values]
hire_rate_variance = statistics.variance(hire_rates) if len(hire_rates) > 1 else 0
if hire_rate_variance > 0.01: # High variance in hire rates
insights.append("High variance in hire rates across periods - consider process standardization")
if not insights:
insights.append("Hiring patterns appear stable over time")
return insights
def _analyze_single_interviewer_consistency(self, data: List[Dict[str, Any]]) -> Dict[str, Any]:
"""Analyze consistency for single-interviewer candidates."""
# Look at consistency within individual interviewers
interviewer_scores = defaultdict(list)
for record in data:
interviewer_scores[record["interviewer_id"]].extend(record["scores"].values())
consistency_analysis = {}
for interviewer, scores in interviewer_scores.items():
if len(scores) >= 10: # Need sufficient data
consistency_analysis[interviewer] = {
"mean_score": round(statistics.mean(scores), 2),
"std_score": round(statistics.stdev(scores), 2),
"coefficient_of_variation": round(statistics.stdev(scores) / statistics.mean(scores), 2),
"total_scores": len(scores)
}
return consistency_analysis
def format_human_readable(calibration_report: Dict[str, Any]) -> str:
"""Format calibration report in human-readable format."""
output = []
# Header
output.append("HIRING CALIBRATION ANALYSIS REPORT")
output.append("=" * 60)
output.append(f"Analysis Type: {calibration_report.get('analysis_type', 'N/A').title()}")
output.append(f"Generated: {calibration_report.get('generated_at', 'N/A')}")
if "error" in calibration_report:
output.append(f"\nError: {calibration_report['error']}")
return "\n".join(output)
# Data Summary
data_summary = calibration_report.get("data_summary", {})
if data_summary:
output.append(f"\nDATA SUMMARY")
output.append("-" * 30)
output.append(f"Total Candidates: {data_summary.get('total_candidates', 0)}")
output.append(f"Unique Interviewers: {data_summary.get('unique_interviewers', 0)}")
output.append(f"Overall Hire Rate: {data_summary.get('hire_rate', 0):.1%}")
score_stats = data_summary.get("score_statistics", {})
output.append(f"Average Score: {score_stats.get('mean_average_scores', 0):.2f}")
output.append(f"Score Std Dev: {score_stats.get('std_average_scores', 0):.2f}")
# Health Score
health_score = calibration_report.get("calibration_health_score", {})
if health_score:
output.append(f"\nCALIBRATION HEALTH SCORE")
output.append("-" * 30)
output.append(f"Overall Score: {health_score.get('overall_score', 0):.3f}")
output.append(f"Health Category: {health_score.get('health_category', 'Unknown').title()}")
if health_score.get("improvement_priority"):
output.append(f"Priority Areas: {', '.join(health_score['improvement_priority'])}")
# Bias Analysis
bias_analysis = calibration_report.get("bias_analysis", {})
if bias_analysis:
output.append(f"\nBIAS ANALYSIS")
output.append("-" * 30)
output.append(f"Overall Bias Score: {bias_analysis.get('overall_bias_score', 0):.3f}")
# Demographic bias
demographic_bias = bias_analysis.get("demographic_bias", {})
if demographic_bias:
output.append(f"\nDemographic Bias Issues:")
for demo, analysis in demographic_bias.items():
output.append(f" • {demo.replace('_', ' ').title()}: {analysis.get('bias_details', {}).keys()}")
# Interviewer bias
interviewer_bias = bias_analysis.get("interviewer_bias", {})
outlier_interviewers = interviewer_bias.get("outlier_interviewers", {})
if outlier_interviewers:
output.append(f"\nOutlier Interviewers:")
for interviewer, info in outlier_interviewers.items():
issues = ", ".join(info["issues"])
output.append(f" • {interviewer}: {issues}")
# Calibration Analysis
calibration_analysis = calibration_report.get("calibration_analysis", {})
if calibration_analysis and "error" not in calibration_analysis:
output.append(f"\nCALIBRATION CONSISTENCY")
output.append("-" * 30)
output.append(f"Quality: {calibration_analysis.get('calibration_quality', 'Unknown').title()}")
output.append(f"Agreement Rate: {calibration_analysis.get('agreement_within_one_point_rate', 0):.1%}")
output.append(f"Score Std Dev: {calibration_analysis.get('mean_score_standard_deviation', 0):.3f}")
# Scoring Analysis
scoring_analysis = calibration_report.get("scoring_analysis", {})
if scoring_analysis:
output.append(f"\nSCORING PATTERNS")
output.append("-" * 30)
output.append(f"Overall Assessment: {scoring_analysis.get('overall_assessment', 'Unknown').title()}")
score_stats = scoring_analysis.get("score_statistics", {})
output.append(f"Mean Score: {score_stats.get('mean_score', 0):.2f} (Target: {score_stats.get('target_mean', 0):.2f})")
# Distribution analysis
distribution = scoring_analysis.get("score_distribution", {})
if distribution:
output.append(f"\nScore Distribution vs Expected:")
for score in ["1", "2", "3", "4"]:
if score in distribution:
actual = distribution[score]["actual_percentage"]
expected = distribution[score]["expected_percentage"]
output.append(f" Score {score}: {actual:.1%} (Expected: {expected:.1%})")
# Top Recommendations
recommendations = calibration_report.get("recommendations", [])
if recommendations:
output.append(f"\nTOP RECOMMENDATIONS")
output.append("-" * 30)
for i, rec in enumerate(recommendations[:5], 1): # Show top 5
output.append(f"{i}. {rec['title']} ({rec['priority'].title()} Priority)")
output.append(f" {rec['description']}")
if rec.get('actions'):
output.append(f" Actions: {len(rec['actions'])} specific action items")
return "\n".join(output)
def main():
parser = argparse.ArgumentParser(description="Analyze interview data for bias and calibration issues")
parser.add_argument("--input", type=str, required=True, help="Input JSON file with interview results data")
parser.add_argument("--analysis-type", type=str, choices=["comprehensive", "bias", "calibration", "interviewer", "scoring"],
default="comprehensive", help="Type of analysis to perform")
parser.add_argument("--competencies", type=str, help="Comma-separated list of competencies to focus on")
parser.add_argument("--trend-analysis", action="store_true", help="Perform trend analysis over time")
parser.add_argument("--period", type=str, choices=["daily", "weekly", "monthly", "quarterly"],
default="monthly", help="Time period for trend analysis")
parser.add_argument("--output", type=str, help="Output file path")
parser.add_argument("--format", choices=["json", "text", "both"], default="both", help="Output format")
args = parser.parse_args()
# Load input data
try:
with open(args.input, 'r') as f:
interview_data = json.load(f)
if not isinstance(interview_data, list):
print("Error: Input data must be a JSON array of interview records")
sys.exit(1)
except FileNotFoundError:
print(f"Error: Input file '{args.input}' not found")
sys.exit(1)
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON in input file: {e}")
sys.exit(1)
except Exception as e:
print(f"Error reading input file: {e}")
sys.exit(1)
# Initialize calibrator and run analysis
calibrator = HiringCalibrator()
competencies = args.competencies.split(',') if args.competencies else None
try:
results = calibrator.analyze_hiring_calibration(
interview_data=interview_data,
analysis_type=args.analysis_type,
competencies=competencies,
trend_analysis=args.trend_analysis,
period=args.period
)
# Handle output
if args.output:
output_path = args.output
json_path = output_path if output_path.endswith('.json') else f"{output_path}.json"
text_path = output_path.replace('.json', '.txt') if output_path.endswith('.json') else f"{output_path}.txt"
else:
base_filename = f"calibration_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
json_path = f"{base_filename}.json"
text_path = f"{base_filename}.txt"
# Write outputs
if args.format in ["json", "both"]:
with open(json_path, 'w') as f:
json.dump(results, f, indent=2, default=str)
print(f"JSON report written to: {json_path}")
if args.format in ["text", "both"]:
with open(text_path, 'w') as f:
f.write(format_human_readable(results))
print(f"Text report written to: {text_path}")
# Print summary
print(f"\nCalibration Analysis Summary:")
if "error" in results:
print(f"Error: {results['error']}")
else:
health_score = results.get("calibration_health_score", {})
print(f"Health Score: {health_score.get('overall_score', 0):.3f} ({health_score.get('health_category', 'Unknown').title()})")
bias_score = results.get("bias_analysis", {}).get("overall_bias_score", 0)
print(f"Bias Score: {bias_score:.3f} (Lower is better)")
recommendations = results.get("recommendations", [])
print(f"Recommendations Generated: {len(recommendations)}")
if recommendations:
print(f"Top Priority: {recommendations[0]['title']} ({recommendations[0]['priority'].title()})")
except Exception as e:
print(f"Error during analysis: {e}")
sys.exit(1)
if __name__ == "__main__":
main()
FILE:loop_designer.py
#!/usr/bin/env python3
"""
Interview Loop Designer
Generates calibrated interview loops tailored to specific roles, levels, and teams.
Creates complete interview loops with rounds, focus areas, time allocation,
interviewer skill requirements, and scorecard templates.
Usage:
python loop_designer.py --role "Senior Software Engineer" --level senior --team platform
python loop_designer.py --role "Product Manager" --level mid --competencies leadership,strategy
python loop_designer.py --input role_definition.json --output loops/
"""
import os
import sys
import json
import argparse
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Any, Tuple
from collections import defaultdict
class InterviewLoopDesigner:
"""Designs comprehensive interview loops based on role requirements."""
def __init__(self):
self.competency_frameworks = self._init_competency_frameworks()
self.role_templates = self._init_role_templates()
self.interviewer_skills = self._init_interviewer_skills()
def _init_competency_frameworks(self) -> Dict[str, Dict]:
"""Initialize competency frameworks for different roles."""
return {
"software_engineer": {
"junior": {
"required": ["coding_fundamentals", "debugging", "testing_basics", "version_control"],
"preferred": ["system_understanding", "code_review", "collaboration"],
"focus_areas": ["technical_execution", "learning_agility", "team_collaboration"]
},
"mid": {
"required": ["advanced_coding", "system_design_basics", "testing_strategy", "debugging_complex"],
"preferred": ["mentoring_basics", "technical_communication", "project_ownership"],
"focus_areas": ["technical_depth", "system_thinking", "ownership"]
},
"senior": {
"required": ["system_architecture", "technical_leadership", "mentoring", "cross_team_collab"],
"preferred": ["technology_evaluation", "process_improvement", "hiring_contribution"],
"focus_areas": ["technical_leadership", "system_architecture", "people_development"]
},
"staff": {
"required": ["architectural_vision", "organizational_impact", "technical_strategy", "team_building"],
"preferred": ["industry_influence", "innovation_leadership", "executive_communication"],
"focus_areas": ["organizational_impact", "technical_vision", "strategic_influence"]
},
"principal": {
"required": ["company_wide_impact", "technical_vision", "talent_development", "strategic_planning"],
"preferred": ["industry_leadership", "board_communication", "market_influence"],
"focus_areas": ["strategic_leadership", "organizational_transformation", "external_influence"]
}
},
"product_manager": {
"junior": {
"required": ["product_execution", "user_research", "data_analysis", "stakeholder_comm"],
"preferred": ["market_awareness", "technical_understanding", "project_management"],
"focus_areas": ["execution_excellence", "user_focus", "analytical_thinking"]
},
"mid": {
"required": ["product_strategy", "cross_functional_leadership", "metrics_design", "market_analysis"],
"preferred": ["team_building", "technical_collaboration", "competitive_analysis"],
"focus_areas": ["strategic_thinking", "leadership", "business_impact"]
},
"senior": {
"required": ["business_strategy", "team_leadership", "p&l_ownership", "market_positioning"],
"preferred": ["hiring_leadership", "board_communication", "partnership_development"],
"focus_areas": ["business_leadership", "market_strategy", "organizational_impact"]
},
"staff": {
"required": ["portfolio_management", "organizational_leadership", "strategic_planning", "market_creation"],
"preferred": ["executive_presence", "investor_relations", "acquisition_strategy"],
"focus_areas": ["strategic_leadership", "market_innovation", "organizational_transformation"]
}
},
"designer": {
"junior": {
"required": ["design_fundamentals", "user_research", "prototyping", "design_tools"],
"preferred": ["user_empathy", "visual_design", "collaboration"],
"focus_areas": ["design_execution", "user_research", "creative_problem_solving"]
},
"mid": {
"required": ["design_systems", "user_testing", "cross_functional_collab", "design_strategy"],
"preferred": ["mentoring", "process_improvement", "business_understanding"],
"focus_areas": ["design_leadership", "system_thinking", "business_impact"]
},
"senior": {
"required": ["design_leadership", "team_building", "strategic_design", "stakeholder_management"],
"preferred": ["design_culture", "hiring_leadership", "executive_communication"],
"focus_areas": ["design_strategy", "team_leadership", "organizational_impact"]
}
},
"data_scientist": {
"junior": {
"required": ["statistical_analysis", "python_r", "data_visualization", "sql"],
"preferred": ["machine_learning", "business_understanding", "communication"],
"focus_areas": ["analytical_skills", "technical_execution", "business_impact"]
},
"mid": {
"required": ["advanced_ml", "experiment_design", "data_engineering", "stakeholder_comm"],
"preferred": ["mentoring", "project_leadership", "product_collaboration"],
"focus_areas": ["advanced_analytics", "project_leadership", "cross_functional_impact"]
},
"senior": {
"required": ["data_strategy", "team_leadership", "ml_systems", "business_strategy"],
"preferred": ["hiring_leadership", "executive_communication", "technology_evaluation"],
"focus_areas": ["strategic_leadership", "technical_vision", "organizational_impact"]
}
},
"devops_engineer": {
"junior": {
"required": ["infrastructure_basics", "scripting", "monitoring", "troubleshooting"],
"preferred": ["automation", "cloud_platforms", "security_awareness"],
"focus_areas": ["operational_excellence", "automation_mindset", "problem_solving"]
},
"mid": {
"required": ["ci_cd_design", "infrastructure_as_code", "security_implementation", "performance_optimization"],
"preferred": ["team_collaboration", "incident_management", "capacity_planning"],
"focus_areas": ["system_reliability", "automation_leadership", "cross_team_collaboration"]
},
"senior": {
"required": ["platform_architecture", "team_leadership", "security_strategy", "organizational_impact"],
"preferred": ["hiring_contribution", "technology_evaluation", "executive_communication"],
"focus_areas": ["platform_leadership", "strategic_thinking", "organizational_transformation"]
}
},
"engineering_manager": {
"junior": {
"required": ["team_leadership", "technical_background", "people_management", "project_coordination"],
"preferred": ["hiring_experience", "performance_management", "technical_mentoring"],
"focus_areas": ["people_leadership", "team_building", "execution_excellence"]
},
"senior": {
"required": ["organizational_leadership", "strategic_planning", "talent_development", "cross_functional_leadership"],
"preferred": ["technical_vision", "culture_building", "executive_communication"],
"focus_areas": ["organizational_impact", "strategic_leadership", "talent_development"]
},
"staff": {
"required": ["multi_team_leadership", "organizational_strategy", "executive_presence", "cultural_transformation"],
"preferred": ["board_communication", "market_understanding", "acquisition_integration"],
"focus_areas": ["organizational_transformation", "strategic_leadership", "cultural_evolution"]
}
}
}
def _init_role_templates(self) -> Dict[str, Dict]:
"""Initialize role-specific interview templates."""
return {
"software_engineer": {
"core_rounds": ["technical_phone_screen", "coding_deep_dive", "system_design", "behavioral"],
"optional_rounds": ["technical_leadership", "domain_expertise", "culture_fit"],
"total_duration_range": (180, 360), # 3-6 hours
"required_competencies": ["coding", "problem_solving", "communication"]
},
"product_manager": {
"core_rounds": ["product_sense", "analytical_thinking", "execution_process", "behavioral"],
"optional_rounds": ["strategic_thinking", "technical_collaboration", "leadership"],
"total_duration_range": (180, 300), # 3-5 hours
"required_competencies": ["product_strategy", "analytical_thinking", "stakeholder_management"]
},
"designer": {
"core_rounds": ["portfolio_review", "design_challenge", "collaboration_process", "behavioral"],
"optional_rounds": ["design_system_thinking", "research_methodology", "leadership"],
"total_duration_range": (180, 300), # 3-5 hours
"required_competencies": ["design_process", "user_empathy", "visual_communication"]
},
"data_scientist": {
"core_rounds": ["technical_assessment", "case_study", "statistical_thinking", "behavioral"],
"optional_rounds": ["ml_systems", "business_strategy", "technical_leadership"],
"total_duration_range": (210, 330), # 3.5-5.5 hours
"required_competencies": ["statistical_analysis", "programming", "business_acumen"]
},
"devops_engineer": {
"core_rounds": ["technical_assessment", "system_design", "troubleshooting", "behavioral"],
"optional_rounds": ["security_assessment", "automation_design", "leadership"],
"total_duration_range": (180, 300), # 3-5 hours
"required_competencies": ["infrastructure", "automation", "problem_solving"]
},
"engineering_manager": {
"core_rounds": ["leadership_assessment", "technical_background", "people_management", "behavioral"],
"optional_rounds": ["strategic_thinking", "hiring_assessment", "culture_building"],
"total_duration_range": (240, 360), # 4-6 hours
"required_competencies": ["people_leadership", "technical_understanding", "strategic_thinking"]
}
}
def _init_interviewer_skills(self) -> Dict[str, Dict]:
"""Initialize interviewer skill requirements for different round types."""
return {
"technical_phone_screen": {
"required_skills": ["technical_assessment", "coding_evaluation"],
"preferred_experience": ["same_domain", "senior_level"],
"calibration_level": "standard"
},
"coding_deep_dive": {
"required_skills": ["advanced_technical", "code_quality_assessment"],
"preferred_experience": ["senior_engineer", "system_design"],
"calibration_level": "high"
},
"system_design": {
"required_skills": ["architecture_design", "scalability_assessment"],
"preferred_experience": ["senior_architect", "large_scale_systems"],
"calibration_level": "high"
},
"behavioral": {
"required_skills": ["behavioral_interviewing", "competency_assessment"],
"preferred_experience": ["hiring_manager", "people_leadership"],
"calibration_level": "standard"
},
"technical_leadership": {
"required_skills": ["leadership_assessment", "technical_mentoring"],
"preferred_experience": ["engineering_manager", "tech_lead"],
"calibration_level": "high"
},
"product_sense": {
"required_skills": ["product_evaluation", "market_analysis"],
"preferred_experience": ["product_manager", "product_leadership"],
"calibration_level": "high"
},
"analytical_thinking": {
"required_skills": ["data_analysis", "metrics_evaluation"],
"preferred_experience": ["data_analyst", "product_manager"],
"calibration_level": "standard"
},
"design_challenge": {
"required_skills": ["design_evaluation", "user_experience"],
"preferred_experience": ["senior_designer", "design_manager"],
"calibration_level": "high"
}
}
def generate_interview_loop(self, role: str, level: str, team: Optional[str] = None,
competencies: Optional[List[str]] = None) -> Dict[str, Any]:
"""Generate a complete interview loop for the specified role and level."""
# Normalize inputs
role_key = role.lower().replace(" ", "_").replace("-", "_")
level_key = level.lower()
# Get role template and competency requirements
if role_key not in self.competency_frameworks:
role_key = self._find_closest_role(role_key)
if level_key not in self.competency_frameworks[role_key]:
level_key = self._find_closest_level(role_key, level_key)
competency_req = self.competency_frameworks[role_key][level_key]
role_template = self.role_templates.get(role_key, self.role_templates["software_engineer"])
# Design the interview loop
rounds = self._design_rounds(role_key, level_key, competency_req, role_template, competencies)
schedule = self._create_schedule(rounds)
scorecard = self._generate_scorecard(role_key, level_key, competency_req)
interviewer_requirements = self._define_interviewer_requirements(rounds)
return {
"role": role,
"level": level,
"team": team,
"generated_at": datetime.now().isoformat(),
"total_duration_minutes": sum(round_info["duration_minutes"] for round_info in rounds.values()),
"total_rounds": len(rounds),
"rounds": rounds,
"suggested_schedule": schedule,
"scorecard_template": scorecard,
"interviewer_requirements": interviewer_requirements,
"competency_framework": competency_req,
"calibration_notes": self._generate_calibration_notes(role_key, level_key)
}
def _find_closest_role(self, role_key: str) -> str:
"""Find the closest matching role template."""
role_mappings = {
"engineer": "software_engineer",
"developer": "software_engineer",
"swe": "software_engineer",
"backend": "software_engineer",
"frontend": "software_engineer",
"fullstack": "software_engineer",
"pm": "product_manager",
"product": "product_manager",
"ux": "designer",
"ui": "designer",
"graphic": "designer",
"data": "data_scientist",
"analyst": "data_scientist",
"ml": "data_scientist",
"ops": "devops_engineer",
"sre": "devops_engineer",
"infrastructure": "devops_engineer",
"manager": "engineering_manager",
"lead": "engineering_manager"
}
for key_part in role_key.split("_"):
if key_part in role_mappings:
return role_mappings[key_part]
return "software_engineer" # Default fallback
def _find_closest_level(self, role_key: str, level_key: str) -> str:
"""Find the closest matching level for the role."""
available_levels = list(self.competency_frameworks[role_key].keys())
level_mappings = {
"entry": "junior",
"associate": "junior",
"jr": "junior",
"mid": "mid",
"middle": "mid",
"sr": "senior",
"senior": "senior",
"staff": "staff",
"principal": "principal",
"lead": "senior",
"manager": "senior"
}
mapped_level = level_mappings.get(level_key, level_key)
if mapped_level in available_levels:
return mapped_level
elif "senior" in available_levels:
return "senior"
else:
return available_levels[0]
def _design_rounds(self, role_key: str, level_key: str, competency_req: Dict,
role_template: Dict, custom_competencies: Optional[List[str]]) -> Dict[str, Dict]:
"""Design the specific interview rounds based on role and level."""
rounds = {}
# Determine which rounds to include
core_rounds = role_template["core_rounds"].copy()
optional_rounds = role_template["optional_rounds"].copy()
# Add optional rounds based on level
if level_key in ["senior", "staff", "principal"]:
if "technical_leadership" in optional_rounds and role_key in ["software_engineer", "engineering_manager"]:
core_rounds.append("technical_leadership")
if "strategic_thinking" in optional_rounds and role_key in ["product_manager", "engineering_manager"]:
core_rounds.append("strategic_thinking")
if "design_system_thinking" in optional_rounds and role_key == "designer":
core_rounds.append("design_system_thinking")
if level_key in ["staff", "principal"]:
if "domain_expertise" in optional_rounds:
core_rounds.append("domain_expertise")
# Define round details
round_definitions = self._get_round_definitions()
for i, round_type in enumerate(core_rounds, 1):
if round_type in round_definitions:
round_def = round_definitions[round_type].copy()
round_def["order"] = i
round_def["focus_areas"] = self._customize_focus_areas(round_type, competency_req, custom_competencies)
rounds[f"round_{i}_{round_type}"] = round_def
return rounds
def _get_round_definitions(self) -> Dict[str, Dict]:
"""Get predefined round definitions with standard durations and formats."""
return {
"technical_phone_screen": {
"name": "Technical Phone Screen",
"duration_minutes": 45,
"format": "virtual",
"objectives": ["Assess coding fundamentals", "Evaluate problem-solving approach", "Screen for basic technical competency"],
"question_types": ["coding_problems", "technical_concepts", "experience_questions"],
"evaluation_criteria": ["technical_accuracy", "problem_solving_process", "communication_clarity"]
},
"coding_deep_dive": {
"name": "Coding Deep Dive",
"duration_minutes": 75,
"format": "in_person_or_virtual",
"objectives": ["Evaluate coding skills in depth", "Assess code quality and testing", "Review debugging approach"],
"question_types": ["complex_coding_problems", "code_review", "testing_strategy"],
"evaluation_criteria": ["code_quality", "testing_approach", "debugging_skills", "optimization_thinking"]
},
"system_design": {
"name": "System Design",
"duration_minutes": 75,
"format": "collaborative_whiteboard",
"objectives": ["Assess architectural thinking", "Evaluate scalability considerations", "Review trade-off analysis"],
"question_types": ["system_architecture", "scalability_design", "trade_off_analysis"],
"evaluation_criteria": ["architectural_thinking", "scalability_awareness", "trade_off_reasoning"]
},
"behavioral": {
"name": "Behavioral Interview",
"duration_minutes": 45,
"format": "conversational",
"objectives": ["Assess cultural fit", "Evaluate past experiences", "Review leadership examples"],
"question_types": ["star_method_questions", "situational_scenarios", "values_alignment"],
"evaluation_criteria": ["communication_skills", "leadership_examples", "cultural_alignment"]
},
"technical_leadership": {
"name": "Technical Leadership",
"duration_minutes": 60,
"format": "discussion_based",
"objectives": ["Evaluate mentoring capability", "Assess technical decision making", "Review cross-team collaboration"],
"question_types": ["leadership_scenarios", "technical_decisions", "mentoring_examples"],
"evaluation_criteria": ["leadership_potential", "technical_judgment", "influence_skills"]
},
"product_sense": {
"name": "Product Sense",
"duration_minutes": 75,
"format": "case_study",
"objectives": ["Assess product intuition", "Evaluate user empathy", "Review market understanding"],
"question_types": ["product_scenarios", "feature_prioritization", "user_journey_analysis"],
"evaluation_criteria": ["product_intuition", "user_empathy", "analytical_thinking"]
},
"analytical_thinking": {
"name": "Analytical Thinking",
"duration_minutes": 60,
"format": "data_analysis",
"objectives": ["Evaluate data interpretation", "Assess metric design", "Review experiment planning"],
"question_types": ["data_interpretation", "metric_design", "experiment_analysis"],
"evaluation_criteria": ["analytical_rigor", "metric_intuition", "experimental_thinking"]
},
"design_challenge": {
"name": "Design Challenge",
"duration_minutes": 90,
"format": "hands_on_design",
"objectives": ["Assess design process", "Evaluate user-centered thinking", "Review iteration approach"],
"question_types": ["design_problems", "user_research", "design_critique"],
"evaluation_criteria": ["design_process", "user_focus", "visual_communication"]
},
"portfolio_review": {
"name": "Portfolio Review",
"duration_minutes": 75,
"format": "presentation_discussion",
"objectives": ["Review past work", "Assess design thinking", "Evaluate impact measurement"],
"question_types": ["portfolio_walkthrough", "design_decisions", "impact_stories"],
"evaluation_criteria": ["design_quality", "process_thinking", "business_impact"]
}
}
def _customize_focus_areas(self, round_type: str, competency_req: Dict,
custom_competencies: Optional[List[str]]) -> List[str]:
"""Customize focus areas based on role competency requirements."""
base_focus_areas = competency_req.get("focus_areas", [])
round_focus_mapping = {
"technical_phone_screen": ["coding_fundamentals", "problem_solving"],
"coding_deep_dive": ["technical_execution", "code_quality"],
"system_design": ["system_thinking", "architectural_reasoning"],
"behavioral": ["cultural_fit", "communication", "teamwork"],
"technical_leadership": ["leadership", "mentoring", "influence"],
"product_sense": ["product_intuition", "user_empathy"],
"analytical_thinking": ["data_analysis", "metric_design"],
"design_challenge": ["design_process", "user_focus"]
}
focus_areas = round_focus_mapping.get(round_type, [])
# Add custom competencies if specified
if custom_competencies:
focus_areas.extend([comp for comp in custom_competencies if comp not in focus_areas])
# Add role-specific focus areas
focus_areas.extend([area for area in base_focus_areas if area not in focus_areas])
return focus_areas[:5] # Limit to top 5 focus areas
def _create_schedule(self, rounds: Dict[str, Dict]) -> Dict[str, Any]:
"""Create a suggested interview schedule."""
sorted_rounds = sorted(rounds.items(), key=lambda x: x[1]["order"])
# Calculate optimal scheduling
total_duration = sum(round_info["duration_minutes"] for _, round_info in sorted_rounds)
if total_duration <= 240: # 4 hours or less - single day
schedule_type = "single_day"
day_structure = self._create_single_day_schedule(sorted_rounds)
else: # Multi-day schedule
schedule_type = "multi_day"
day_structure = self._create_multi_day_schedule(sorted_rounds)
return {
"type": schedule_type,
"total_duration_minutes": total_duration,
"recommended_breaks": self._calculate_breaks(total_duration),
"day_structure": day_structure,
"logistics_notes": self._generate_logistics_notes(sorted_rounds)
}
def _create_single_day_schedule(self, rounds: List[Tuple[str, Dict]]) -> Dict[str, Any]:
"""Create a single-day interview schedule."""
start_time = datetime.strptime("09:00", "%H:%M")
current_time = start_time
schedule = []
for round_name, round_info in rounds:
# Add break if needed (after 90 minutes of interviews)
if schedule and sum(item.get("duration_minutes", 0) for item in schedule if "break" not in item.get("type", "")) >= 90:
schedule.append({
"type": "break",
"start_time": current_time.strftime("%H:%M"),
"duration_minutes": 15,
"end_time": (current_time + timedelta(minutes=15)).strftime("%H:%M")
})
current_time += timedelta(minutes=15)
# Add the interview round
end_time = current_time + timedelta(minutes=round_info["duration_minutes"])
schedule.append({
"type": "interview",
"round_name": round_name,
"title": round_info["name"],
"start_time": current_time.strftime("%H:%M"),
"end_time": end_time.strftime("%H:%M"),
"duration_minutes": round_info["duration_minutes"],
"format": round_info["format"]
})
current_time = end_time
return {
"day_1": {
"date": "TBD",
"start_time": start_time.strftime("%H:%M"),
"end_time": current_time.strftime("%H:%M"),
"rounds": schedule
}
}
def _create_multi_day_schedule(self, rounds: List[Tuple[str, Dict]]) -> Dict[str, Any]:
"""Create a multi-day interview schedule."""
# Split rounds across days (max 4 hours per day)
max_daily_minutes = 240
days = {}
current_day = 1
current_day_duration = 0
current_day_rounds = []
for round_name, round_info in rounds:
duration = round_info["duration_minutes"] + 15 # Add buffer time
if current_day_duration + duration > max_daily_minutes and current_day_rounds:
# Finalize current day
days[f"day_{current_day}"] = self._finalize_day_schedule(current_day_rounds)
current_day += 1
current_day_duration = 0
current_day_rounds = []
current_day_rounds.append((round_name, round_info))
current_day_duration += duration
# Finalize last day
if current_day_rounds:
days[f"day_{current_day}"] = self._finalize_day_schedule(current_day_rounds)
return days
def _finalize_day_schedule(self, day_rounds: List[Tuple[str, Dict]]) -> Dict[str, Any]:
"""Finalize the schedule for a specific day."""
start_time = datetime.strptime("09:00", "%H:%M")
current_time = start_time
schedule = []
for round_name, round_info in day_rounds:
end_time = current_time + timedelta(minutes=round_info["duration_minutes"])
schedule.append({
"type": "interview",
"round_name": round_name,
"title": round_info["name"],
"start_time": current_time.strftime("%H:%M"),
"end_time": end_time.strftime("%H:%M"),
"duration_minutes": round_info["duration_minutes"],
"format": round_info["format"]
})
current_time = end_time + timedelta(minutes=15) # 15-min buffer
return {
"date": "TBD",
"start_time": start_time.strftime("%H:%M"),
"end_time": (current_time - timedelta(minutes=15)).strftime("%H:%M"),
"rounds": schedule
}
def _calculate_breaks(self, total_duration: int) -> List[Dict[str, Any]]:
"""Calculate recommended breaks based on total duration."""
breaks = []
if total_duration >= 120: # 2+ hours
breaks.append({"type": "short_break", "duration": 15, "after_minutes": 90})
if total_duration >= 240: # 4+ hours
breaks.append({"type": "lunch_break", "duration": 60, "after_minutes": 180})
if total_duration >= 360: # 6+ hours
breaks.append({"type": "short_break", "duration": 15, "after_minutes": 300})
return breaks
def _generate_scorecard(self, role_key: str, level_key: str, competency_req: Dict) -> Dict[str, Any]:
"""Generate a scorecard template for the interview loop."""
scoring_dimensions = []
# Add competency-based scoring dimensions
for competency in competency_req["required"]:
scoring_dimensions.append({
"dimension": competency,
"weight": "high",
"scale": "1-4",
"description": f"Assessment of {competency.replace('_', ' ')} competency"
})
for competency in competency_req.get("preferred", []):
scoring_dimensions.append({
"dimension": competency,
"weight": "medium",
"scale": "1-4",
"description": f"Assessment of {competency.replace('_', ' ')} competency"
})
# Add standard dimensions
standard_dimensions = [
{"dimension": "communication", "weight": "high", "scale": "1-4"},
{"dimension": "cultural_fit", "weight": "medium", "scale": "1-4"},
{"dimension": "learning_agility", "weight": "medium", "scale": "1-4"}
]
scoring_dimensions.extend(standard_dimensions)
return {
"scoring_scale": {
"4": "Exceeds Expectations - Demonstrates mastery beyond required level",
"3": "Meets Expectations - Solid performance meeting all requirements",
"2": "Partially Meets - Shows potential but has development areas",
"1": "Does Not Meet - Significant gaps in required competencies"
},
"dimensions": scoring_dimensions,
"overall_recommendation": {
"options": ["Strong Hire", "Hire", "No Hire", "Strong No Hire"],
"criteria": "Based on weighted average and minimum thresholds"
},
"calibration_notes": {
"required": True,
"min_length": 100,
"sections": ["strengths", "areas_for_development", "specific_examples"]
}
}
def _define_interviewer_requirements(self, rounds: Dict[str, Dict]) -> Dict[str, Dict]:
"""Define interviewer skill requirements for each round."""
requirements = {}
for round_name, round_info in rounds.items():
round_type = round_name.split("_", 2)[-1] # Extract round type
if round_type in self.interviewer_skills:
skill_req = self.interviewer_skills[round_type].copy()
skill_req["suggested_interviewers"] = self._suggest_interviewer_profiles(round_type)
requirements[round_name] = skill_req
else:
# Default requirements
requirements[round_name] = {
"required_skills": ["interviewing_basics", "evaluation_skills"],
"preferred_experience": ["relevant_domain"],
"calibration_level": "standard",
"suggested_interviewers": ["experienced_interviewer"]
}
return requirements
def _suggest_interviewer_profiles(self, round_type: str) -> List[str]:
"""Suggest specific interviewer profiles for different round types."""
profile_mapping = {
"technical_phone_screen": ["senior_engineer", "tech_lead"],
"coding_deep_dive": ["senior_engineer", "staff_engineer"],
"system_design": ["senior_architect", "staff_engineer"],
"behavioral": ["hiring_manager", "people_manager"],
"technical_leadership": ["engineering_manager", "senior_staff"],
"product_sense": ["senior_pm", "product_leader"],
"analytical_thinking": ["senior_analyst", "data_scientist"],
"design_challenge": ["senior_designer", "design_manager"]
}
return profile_mapping.get(round_type, ["experienced_interviewer"])
def _generate_calibration_notes(self, role_key: str, level_key: str) -> Dict[str, Any]:
"""Generate calibration notes and best practices."""
return {
"hiring_bar_notes": f"Calibrated for {level_key} level {role_key.replace('_', ' ')} role",
"common_pitfalls": [
"Avoid comparing candidates to each other rather than to the role standard",
"Don't let one strong/weak area overshadow overall assessment",
"Ensure consistent application of evaluation criteria"
],
"calibration_checkpoints": [
"Review score distribution after every 5 candidates",
"Conduct monthly interviewer calibration sessions",
"Track correlation with 6-month performance reviews"
],
"escalation_criteria": [
"Any candidate receiving all 4s or all 1s",
"Significant disagreement between interviewers (>1.5 point spread)",
"Unusual circumstances or accommodations needed"
]
}
def _generate_logistics_notes(self, rounds: List[Tuple[str, Dict]]) -> List[str]:
"""Generate logistics and coordination notes."""
notes = [
"Coordinate interviewer availability before scheduling",
"Ensure all interviewers have access to job description and competency requirements",
"Prepare interview rooms/virtual links for all rounds",
"Share candidate resume and application with all interviewers"
]
# Add format-specific notes
formats_used = {round_info["format"] for _, round_info in rounds}
if "virtual" in formats_used:
notes.append("Test video conferencing setup before virtual interviews")
notes.append("Share virtual meeting links with candidate 24 hours in advance")
if "collaborative_whiteboard" in formats_used:
notes.append("Prepare whiteboard or collaborative online tool for design sessions")
if "hands_on_design" in formats_used:
notes.append("Provide design tools access or ensure candidate can screen share their preferred tools")
return notes
def format_human_readable(loop_data: Dict[str, Any]) -> str:
"""Format the interview loop data in a human-readable format."""
output = []
# Header
output.append(f"Interview Loop Design for {loop_data['role']} ({loop_data['level'].title()} Level)")
output.append("=" * 60)
if loop_data.get('team'):
output.append(f"Team: {loop_data['team']}")
output.append(f"Generated: {loop_data['generated_at']}")
output.append(f"Total Duration: {loop_data['total_duration_minutes']} minutes ({loop_data['total_duration_minutes']//60}h {loop_data['total_duration_minutes']%60}m)")
output.append(f"Total Rounds: {loop_data['total_rounds']}")
output.append("")
# Interview Rounds
output.append("INTERVIEW ROUNDS")
output.append("-" * 40)
sorted_rounds = sorted(loop_data['rounds'].items(), key=lambda x: x[1]['order'])
for round_name, round_info in sorted_rounds:
output.append(f"\nRound {round_info['order']}: {round_info['name']}")
output.append(f"Duration: {round_info['duration_minutes']} minutes")
output.append(f"Format: {round_info['format'].replace('_', ' ').title()}")
output.append("Objectives:")
for obj in round_info['objectives']:
output.append(f" • {obj}")
output.append("Focus Areas:")
for area in round_info['focus_areas']:
output.append(f" • {area.replace('_', ' ').title()}")
# Suggested Schedule
output.append("\nSUGGESTED SCHEDULE")
output.append("-" * 40)
schedule = loop_data['suggested_schedule']
output.append(f"Schedule Type: {schedule['type'].replace('_', ' ').title()}")
for day_name, day_info in schedule['day_structure'].items():
output.append(f"\n{day_name.replace('_', ' ').title()}:")
output.append(f"Time: {day_info['start_time']} - {day_info['end_time']}")
for item in day_info['rounds']:
if item['type'] == 'interview':
output.append(f" {item['start_time']}-{item['end_time']}: {item['title']} ({item['duration_minutes']}min)")
else:
output.append(f" {item['start_time']}-{item['end_time']}: {item['type'].title()} ({item['duration_minutes']}min)")
# Interviewer Requirements
output.append("\nINTERVIEWER REQUIREMENTS")
output.append("-" * 40)
for round_name, requirements in loop_data['interviewer_requirements'].items():
round_display = round_name.split("_", 2)[-1].replace("_", " ").title()
output.append(f"\n{round_display}:")
output.append(f"Required Skills: {', '.join(requirements['required_skills'])}")
output.append(f"Suggested Interviewers: {', '.join(requirements['suggested_interviewers'])}")
output.append(f"Calibration Level: {requirements['calibration_level'].title()}")
# Scorecard Overview
output.append("\nSCORECARD TEMPLATE")
output.append("-" * 40)
scorecard = loop_data['scorecard_template']
output.append("Scoring Scale:")
for score, description in scorecard['scoring_scale'].items():
output.append(f" {score}: {description}")
output.append("\nEvaluation Dimensions:")
for dim in scorecard['dimensions']:
output.append(f" • {dim['dimension'].replace('_', ' ').title()} (Weight: {dim['weight']})")
# Calibration Notes
output.append("\nCALIBRATION NOTES")
output.append("-" * 40)
calibration = loop_data['calibration_notes']
output.append(f"Hiring Bar: {calibration['hiring_bar_notes']}")
output.append("\nCommon Pitfalls:")
for pitfall in calibration['common_pitfalls']:
output.append(f" • {pitfall}")
return "\n".join(output)
def main():
parser = argparse.ArgumentParser(description="Generate calibrated interview loops for specific roles and levels")
parser.add_argument("--role", type=str, help="Job role title (e.g., 'Senior Software Engineer')")
parser.add_argument("--level", type=str, help="Experience level (junior, mid, senior, staff, principal)")
parser.add_argument("--team", type=str, help="Team or department (optional)")
parser.add_argument("--competencies", type=str, help="Comma-separated list of specific competencies to focus on")
parser.add_argument("--input", type=str, help="Input JSON file with role definition")
parser.add_argument("--output", type=str, help="Output directory or file path")
parser.add_argument("--format", choices=["json", "text", "both"], default="both", help="Output format")
args = parser.parse_args()
designer = InterviewLoopDesigner()
# Handle input
if args.input:
try:
with open(args.input, 'r') as f:
role_data = json.load(f)
role = role_data.get('role') or role_data.get('title', '')
level = role_data.get('level', 'senior')
team = role_data.get('team')
competencies = role_data.get('competencies')
except Exception as e:
print(f"Error reading input file: {e}")
sys.exit(1)
else:
if not args.role or not args.level:
print("Error: --role and --level are required when not using --input")
sys.exit(1)
role = args.role
level = args.level
team = args.team
competencies = args.competencies.split(',') if args.competencies else None
# Generate interview loop
try:
loop_data = designer.generate_interview_loop(role, level, team, competencies)
# Handle output
if args.output:
output_path = args.output
if os.path.isdir(output_path):
safe_role = "".join(c for c in role.lower() if c.isalnum() or c in (' ', '-', '_')).replace(' ', '_')
base_filename = f"{safe_role}_{level}_interview_loop"
json_path = os.path.join(output_path, f"{base_filename}.json")
text_path = os.path.join(output_path, f"{base_filename}.txt")
else:
# Use provided path as base
json_path = output_path if output_path.endswith('.json') else f"{output_path}.json"
text_path = output_path.replace('.json', '.txt') if output_path.endswith('.json') else f"{output_path}.txt"
else:
safe_role = "".join(c for c in role.lower() if c.isalnum() or c in (' ', '-', '_')).replace(' ', '_')
base_filename = f"{safe_role}_{level}_interview_loop"
json_path = f"{base_filename}.json"
text_path = f"{base_filename}.txt"
# Write outputs
if args.format in ["json", "both"]:
with open(json_path, 'w') as f:
json.dump(loop_data, f, indent=2, default=str)
print(f"JSON output written to: {json_path}")
if args.format in ["text", "both"]:
with open(text_path, 'w') as f:
f.write(format_human_readable(loop_data))
print(f"Text output written to: {text_path}")
# Always print summary to stdout
print("\nInterview Loop Summary:")
print(f"Role: {loop_data['role']} ({loop_data['level'].title()})")
print(f"Total Duration: {loop_data['total_duration_minutes']} minutes")
print(f"Number of Rounds: {loop_data['total_rounds']}")
print(f"Schedule Type: {loop_data['suggested_schedule']['type'].replace('_', ' ').title()}")
except Exception as e:
print(f"Error generating interview loop: {e}")
sys.exit(1)
if __name__ == "__main__":
main()
FILE:question_bank_generator.py
#!/usr/bin/env python3
"""
Question Bank Generator
Generates comprehensive, competency-based interview questions with detailed scoring criteria.
Creates structured question banks organized by competency area with scoring rubrics,
follow-up probes, and calibration examples.
Usage:
python question_bank_generator.py --role "Frontend Engineer" --competencies react,typescript,system-design
python question_bank_generator.py --role "Product Manager" --question-types behavioral,leadership
python question_bank_generator.py --input role_requirements.json --output questions/
"""
import os
import sys
import json
import argparse
import random
from datetime import datetime
from typing import Dict, List, Optional, Any, Tuple
from collections import defaultdict
class QuestionBankGenerator:
"""Generates comprehensive interview question banks with scoring criteria."""
def __init__(self):
self.technical_questions = self._init_technical_questions()
self.behavioral_questions = self._init_behavioral_questions()
self.competency_mapping = self._init_competency_mapping()
self.scoring_rubrics = self._init_scoring_rubrics()
self.follow_up_strategies = self._init_follow_up_strategies()
def _init_technical_questions(self) -> Dict[str, Dict]:
"""Initialize technical questions by competency area and level."""
return {
"coding_fundamentals": {
"junior": [
{
"question": "Write a function to reverse a string without using built-in reverse methods.",
"competency": "coding_fundamentals",
"type": "coding",
"difficulty": "easy",
"time_limit": 15,
"key_concepts": ["loops", "string_manipulation", "basic_algorithms"]
},
{
"question": "Implement a function to check if a string is a palindrome.",
"competency": "coding_fundamentals",
"type": "coding",
"difficulty": "easy",
"time_limit": 15,
"key_concepts": ["string_processing", "comparison", "edge_cases"]
},
{
"question": "Find the largest element in an array without using built-in max functions.",
"competency": "coding_fundamentals",
"type": "coding",
"difficulty": "easy",
"time_limit": 10,
"key_concepts": ["arrays", "iteration", "comparison"]
}
],
"mid": [
{
"question": "Implement a function to find the first non-repeating character in a string.",
"competency": "coding_fundamentals",
"type": "coding",
"difficulty": "medium",
"time_limit": 20,
"key_concepts": ["hash_maps", "string_processing", "efficiency"]
},
{
"question": "Write a function to merge two sorted arrays into one sorted array.",
"competency": "coding_fundamentals",
"type": "coding",
"difficulty": "medium",
"time_limit": 25,
"key_concepts": ["merge_algorithms", "two_pointers", "optimization"]
}
],
"senior": [
{
"question": "Implement a LRU (Least Recently Used) cache with O(1) operations.",
"competency": "coding_fundamentals",
"type": "coding",
"difficulty": "hard",
"time_limit": 35,
"key_concepts": ["data_structures", "hash_maps", "doubly_linked_lists"]
}
]
},
"system_design": {
"mid": [
{
"question": "Design a URL shortener service like bit.ly for 10K users.",
"competency": "system_design",
"type": "design",
"difficulty": "medium",
"time_limit": 45,
"key_concepts": ["database_design", "hashing", "basic_scalability"]
}
],
"senior": [
{
"question": "Design a real-time chat system supporting 1M concurrent users.",
"competency": "system_design",
"type": "design",
"difficulty": "hard",
"time_limit": 60,
"key_concepts": ["websockets", "load_balancing", "database_sharding", "caching"]
},
{
"question": "Design a distributed cache system like Redis with high availability.",
"competency": "system_design",
"type": "design",
"difficulty": "hard",
"time_limit": 60,
"key_concepts": ["distributed_systems", "replication", "consistency", "partitioning"]
}
],
"staff": [
{
"question": "Design the architecture for a global content delivery network (CDN).",
"competency": "system_design",
"type": "design",
"difficulty": "expert",
"time_limit": 75,
"key_concepts": ["global_architecture", "edge_computing", "content_optimization", "network_protocols"]
}
]
},
"frontend_development": {
"junior": [
{
"question": "Create a responsive navigation menu using HTML, CSS, and vanilla JavaScript.",
"competency": "frontend_development",
"type": "coding",
"difficulty": "easy",
"time_limit": 30,
"key_concepts": ["html_css", "responsive_design", "dom_manipulation"]
}
],
"mid": [
{
"question": "Build a React component that fetches and displays paginated data from an API.",
"competency": "frontend_development",
"type": "coding",
"difficulty": "medium",
"time_limit": 45,
"key_concepts": ["react_hooks", "api_integration", "state_management", "pagination"]
}
],
"senior": [
{
"question": "Design and implement a custom React hook for managing complex form state with validation.",
"competency": "frontend_development",
"type": "coding",
"difficulty": "hard",
"time_limit": 60,
"key_concepts": ["custom_hooks", "form_validation", "state_management", "performance"]
}
]
},
"data_analysis": {
"junior": [
{
"question": "Given a dataset of user activities, calculate the daily active users for the past month.",
"competency": "data_analysis",
"type": "analytical",
"difficulty": "easy",
"time_limit": 30,
"key_concepts": ["sql_basics", "date_functions", "aggregation"]
}
],
"mid": [
{
"question": "Analyze conversion funnel data to identify the biggest drop-off point and propose solutions.",
"competency": "data_analysis",
"type": "analytical",
"difficulty": "medium",
"time_limit": 45,
"key_concepts": ["funnel_analysis", "conversion_optimization", "statistical_significance"]
}
],
"senior": [
{
"question": "Design an A/B testing framework to measure the impact of a new recommendation algorithm.",
"competency": "data_analysis",
"type": "analytical",
"difficulty": "hard",
"time_limit": 60,
"key_concepts": ["experiment_design", "statistical_power", "bias_mitigation", "causal_inference"]
}
]
},
"machine_learning": {
"mid": [
{
"question": "Explain how you would build a recommendation system for an e-commerce platform.",
"competency": "machine_learning",
"type": "conceptual",
"difficulty": "medium",
"time_limit": 45,
"key_concepts": ["collaborative_filtering", "content_based", "cold_start", "evaluation_metrics"]
}
],
"senior": [
{
"question": "Design a real-time fraud detection system for financial transactions.",
"competency": "machine_learning",
"type": "design",
"difficulty": "hard",
"time_limit": 60,
"key_concepts": ["anomaly_detection", "real_time_ml", "feature_engineering", "model_monitoring"]
}
]
},
"product_strategy": {
"mid": [
{
"question": "How would you prioritize features for a mobile app with limited engineering resources?",
"competency": "product_strategy",
"type": "case_study",
"difficulty": "medium",
"time_limit": 45,
"key_concepts": ["prioritization_frameworks", "resource_allocation", "impact_estimation"]
}
],
"senior": [
{
"question": "Design a go-to-market strategy for a new B2B SaaS product entering a competitive market.",
"competency": "product_strategy",
"type": "strategic",
"difficulty": "hard",
"time_limit": 60,
"key_concepts": ["market_analysis", "competitive_positioning", "pricing_strategy", "channel_strategy"]
}
]
}
}
def _init_behavioral_questions(self) -> Dict[str, List[Dict]]:
"""Initialize behavioral questions by competency area."""
return {
"leadership": [
{
"question": "Tell me about a time when you had to lead a team through a significant change or challenge.",
"competency": "leadership",
"type": "behavioral",
"method": "STAR",
"focus_areas": ["change_management", "team_motivation", "communication"]
},
{
"question": "Describe a situation where you had to influence someone without having direct authority over them.",
"competency": "leadership",
"type": "behavioral",
"method": "STAR",
"focus_areas": ["influence", "persuasion", "stakeholder_management"]
},
{
"question": "Give me an example of when you had to make a difficult decision that affected your team.",
"competency": "leadership",
"type": "behavioral",
"method": "STAR",
"focus_areas": ["decision_making", "team_impact", "communication"]
}
],
"collaboration": [
{
"question": "Describe a time when you had to work with a difficult colleague or stakeholder.",
"competency": "collaboration",
"type": "behavioral",
"method": "STAR",
"focus_areas": ["conflict_resolution", "relationship_building", "professionalism"]
},
{
"question": "Tell me about a project where you had to coordinate across multiple teams or departments.",
"competency": "collaboration",
"type": "behavioral",
"method": "STAR",
"focus_areas": ["cross_functional_work", "communication", "project_coordination"]
}
],
"problem_solving": [
{
"question": "Walk me through a complex problem you solved recently. What was your approach?",
"competency": "problem_solving",
"type": "behavioral",
"method": "STAR",
"focus_areas": ["analytical_thinking", "methodology", "creativity"]
},
{
"question": "Describe a time when you had to solve a problem with limited information or resources.",
"competency": "problem_solving",
"type": "behavioral",
"method": "STAR",
"focus_areas": ["resourcefulness", "ambiguity_tolerance", "decision_making"]
}
],
"communication": [
{
"question": "Tell me about a time when you had to present complex technical information to a non-technical audience.",
"competency": "communication",
"type": "behavioral",
"method": "STAR",
"focus_areas": ["technical_communication", "audience_adaptation", "clarity"]
},
{
"question": "Describe a situation where you had to deliver difficult feedback to a colleague.",
"competency": "communication",
"type": "behavioral",
"method": "STAR",
"focus_areas": ["feedback_delivery", "empathy", "constructive_criticism"]
}
],
"adaptability": [
{
"question": "Tell me about a time when you had to quickly learn a new technology or skill for work.",
"competency": "adaptability",
"type": "behavioral",
"method": "STAR",
"focus_areas": ["learning_agility", "growth_mindset", "knowledge_acquisition"]
},
{
"question": "Describe how you handled a situation when project requirements changed significantly mid-way.",
"competency": "adaptability",
"type": "behavioral",
"method": "STAR",
"focus_areas": ["flexibility", "change_management", "resilience"]
}
],
"innovation": [
{
"question": "Tell me about a time when you came up with a creative solution to improve a process or solve a problem.",
"competency": "innovation",
"type": "behavioral",
"method": "STAR",
"focus_areas": ["creative_thinking", "process_improvement", "initiative"]
}
]
}
def _init_competency_mapping(self) -> Dict[str, Dict]:
"""Initialize role to competency mapping."""
return {
"software_engineer": {
"core_competencies": ["coding_fundamentals", "system_design", "problem_solving", "collaboration"],
"level_specific": {
"junior": ["coding_fundamentals", "debugging", "learning_agility"],
"mid": ["advanced_coding", "system_design", "mentoring_basics"],
"senior": ["system_architecture", "technical_leadership", "innovation"],
"staff": ["architectural_vision", "organizational_impact", "strategic_thinking"]
}
},
"frontend_engineer": {
"core_competencies": ["frontend_development", "ui_ux_understanding", "problem_solving", "collaboration"],
"level_specific": {
"junior": ["html_css_js", "responsive_design", "basic_frameworks"],
"mid": ["react_vue_angular", "state_management", "performance_optimization"],
"senior": ["frontend_architecture", "team_leadership", "cross_functional_collaboration"],
"staff": ["frontend_strategy", "technology_evaluation", "organizational_impact"]
}
},
"backend_engineer": {
"core_competencies": ["backend_development", "database_design", "api_design", "system_design"],
"level_specific": {
"junior": ["server_side_programming", "database_basics", "api_consumption"],
"mid": ["microservices", "caching", "security_basics"],
"senior": ["distributed_systems", "performance_optimization", "technical_leadership"],
"staff": ["system_architecture", "technology_strategy", "cross_team_influence"]
}
},
"product_manager": {
"core_competencies": ["product_strategy", "user_research", "data_analysis", "stakeholder_management"],
"level_specific": {
"junior": ["feature_specification", "user_stories", "basic_analytics"],
"mid": ["product_roadmap", "cross_functional_leadership", "market_research"],
"senior": ["business_strategy", "team_leadership", "p&l_responsibility"],
"staff": ["portfolio_management", "organizational_strategy", "market_creation"]
}
},
"data_scientist": {
"core_competencies": ["statistical_analysis", "machine_learning", "data_analysis", "business_acumen"],
"level_specific": {
"junior": ["python_r", "sql", "basic_ml", "data_visualization"],
"mid": ["advanced_ml", "experiment_design", "model_evaluation"],
"senior": ["ml_systems", "data_strategy", "stakeholder_communication"],
"staff": ["data_platform", "ai_strategy", "organizational_impact"]
}
},
"designer": {
"core_competencies": ["design_process", "user_research", "visual_design", "collaboration"],
"level_specific": {
"junior": ["design_tools", "user_empathy", "visual_communication"],
"mid": ["design_systems", "user_testing", "cross_functional_work"],
"senior": ["design_strategy", "team_leadership", "business_impact"],
"staff": ["design_vision", "organizational_design", "strategic_influence"]
}
},
"devops_engineer": {
"core_competencies": ["infrastructure", "automation", "monitoring", "troubleshooting"],
"level_specific": {
"junior": ["scripting", "basic_cloud", "ci_cd_basics"],
"mid": ["infrastructure_as_code", "container_orchestration", "security"],
"senior": ["platform_design", "reliability_engineering", "team_leadership"],
"staff": ["platform_strategy", "organizational_infrastructure", "technology_vision"]
}
}
}
def _init_scoring_rubrics(self) -> Dict[str, Dict]:
"""Initialize scoring rubrics for different question types."""
return {
"coding": {
"correctness": {
"4": "Solution is completely correct, handles all edge cases, optimal complexity",
"3": "Solution is correct for main cases, good complexity, minor edge case issues",
"2": "Solution works but has some bugs or suboptimal approach",
"1": "Solution has significant issues or doesn't work"
},
"code_quality": {
"4": "Clean, readable, well-structured code with excellent naming and comments",
"3": "Good code structure, readable with appropriate naming",
"2": "Code works but has style/structure issues",
"1": "Poor code quality, hard to understand"
},
"problem_solving_approach": {
"4": "Excellent problem breakdown, clear thinking process, considers alternatives",
"3": "Good approach, logical thinking, systematic problem solving",
"2": "Decent approach but some confusion or inefficiency",
"1": "Poor approach, unclear thinking process"
},
"communication": {
"4": "Excellent explanation of approach, asks clarifying questions, clear reasoning",
"3": "Good communication, explains thinking well",
"2": "Adequate communication, some explanation",
"1": "Poor communication, little explanation"
}
},
"behavioral": {
"situation_clarity": {
"4": "Clear, specific situation with relevant context and stakes",
"3": "Good situation description with adequate context",
"2": "Situation described but lacks some specifics",
"1": "Vague or unclear situation description"
},
"action_quality": {
"4": "Specific, thoughtful actions showing strong competency",
"3": "Good actions demonstrating competency",
"2": "Adequate actions but could be stronger",
"1": "Weak or inappropriate actions"
},
"result_impact": {
"4": "Significant positive impact with measurable results",
"3": "Good positive impact with clear outcomes",
"2": "Some positive impact demonstrated",
"1": "Little or no positive impact shown"
},
"self_awareness": {
"4": "Excellent self-reflection, learns from experience, acknowledges growth areas",
"3": "Good self-awareness and learning orientation",
"2": "Some self-reflection demonstrated",
"1": "Limited self-awareness or reflection"
}
},
"design": {
"system_thinking": {
"4": "Comprehensive system view, considers all components and interactions",
"3": "Good system understanding with most components identified",
"2": "Basic system thinking with some gaps",
"1": "Limited system thinking, misses key components"
},
"scalability": {
"4": "Excellent scalability considerations, multiple strategies discussed",
"3": "Good scalability awareness with practical solutions",
"2": "Basic scalability understanding",
"1": "Little to no scalability consideration"
},
"trade_offs": {
"4": "Excellent trade-off analysis, considers multiple dimensions",
"3": "Good trade-off awareness with clear reasoning",
"2": "Some trade-off consideration",
"1": "Limited trade-off analysis"
},
"technical_depth": {
"4": "Deep technical knowledge with implementation details",
"3": "Good technical knowledge with solid understanding",
"2": "Adequate technical knowledge",
"1": "Limited technical depth"
}
}
}
def _init_follow_up_strategies(self) -> Dict[str, List[str]]:
"""Initialize follow-up question strategies by competency."""
return {
"coding_fundamentals": [
"How would you optimize this solution for better time complexity?",
"What edge cases should we consider for this problem?",
"How would you test this function?",
"What would happen if the input size was very large?"
],
"system_design": [
"How would you handle if the system needed to scale 10x?",
"What would you do if one of your services went down?",
"How would you monitor this system in production?",
"What security considerations would you implement?"
],
"leadership": [
"What would you do differently if you faced this situation again?",
"How did you handle team members who were resistant to the change?",
"What metrics did you use to measure success?",
"How did you communicate progress to stakeholders?"
],
"problem_solving": [
"Walk me through your thought process step by step",
"What alternative approaches did you consider?",
"How did you validate your solution worked?",
"What did you learn from this experience?"
],
"collaboration": [
"How did you build consensus among the different stakeholders?",
"What communication channels did you use to keep everyone aligned?",
"How did you handle disagreements or conflicts?",
"What would you do to improve collaboration in the future?"
]
}
def generate_question_bank(self, role: str, level: str = "senior",
competencies: Optional[List[str]] = None,
question_types: Optional[List[str]] = None,
num_questions: int = 20) -> Dict[str, Any]:
"""Generate a comprehensive question bank for the specified role and competencies."""
# Normalize inputs
role_key = self._normalize_role(role)
level_key = level.lower()
# Get competency requirements
role_competencies = self._get_role_competencies(role_key, level_key, competencies)
# Determine question types to include
if question_types is None:
question_types = ["technical", "behavioral", "situational"]
# Generate questions
questions = self._generate_questions(role_competencies, question_types, level_key, num_questions)
# Create scoring rubrics
scoring_rubrics = self._create_scoring_rubrics(questions)
# Generate follow-up probes
follow_up_probes = self._generate_follow_up_probes(questions)
# Create calibration examples
calibration_examples = self._create_calibration_examples(questions[:5]) # Sample for first 5 questions
return {
"role": role,
"level": level,
"competencies": role_competencies,
"question_types": question_types,
"generated_at": datetime.now().isoformat(),
"total_questions": len(questions),
"questions": questions,
"scoring_rubrics": scoring_rubrics,
"follow_up_probes": follow_up_probes,
"calibration_examples": calibration_examples,
"usage_guidelines": self._generate_usage_guidelines(role_key, level_key)
}
def _normalize_role(self, role: str) -> str:
"""Normalize role name to match competency mapping keys."""
role_lower = role.lower().replace(" ", "_").replace("-", "_")
# Map variations to standard roles
role_mappings = {
"software_engineer": ["engineer", "developer", "swe", "software_developer"],
"frontend_engineer": ["frontend", "front_end", "ui_engineer", "web_developer"],
"backend_engineer": ["backend", "back_end", "server_engineer", "api_developer"],
"product_manager": ["pm", "product", "product_owner", "po"],
"data_scientist": ["ds", "data", "analyst", "ml_engineer"],
"designer": ["ux", "ui", "ux_ui", "product_designer", "visual_designer"],
"devops_engineer": ["devops", "sre", "platform_engineer", "infrastructure"]
}
for standard_role, variations in role_mappings.items():
if any(var in role_lower for var in variations):
return standard_role
# Default fallback
return "software_engineer"
def _get_role_competencies(self, role_key: str, level_key: str,
custom_competencies: Optional[List[str]]) -> List[str]:
"""Get competencies for the role and level."""
if role_key not in self.competency_mapping:
role_key = "software_engineer"
role_mapping = self.competency_mapping[role_key]
competencies = role_mapping["core_competencies"].copy()
# Add level-specific competencies
if level_key in role_mapping["level_specific"]:
competencies.extend(role_mapping["level_specific"][level_key])
elif "senior" in role_mapping["level_specific"]:
competencies.extend(role_mapping["level_specific"]["senior"])
# Add custom competencies if specified
if custom_competencies:
competencies.extend([comp.strip() for comp in custom_competencies if comp.strip() not in competencies])
return list(set(competencies)) # Remove duplicates
def _generate_questions(self, competencies: List[str], question_types: List[str],
level: str, num_questions: int) -> List[Dict[str, Any]]:
"""Generate questions based on competencies and types."""
questions = []
questions_per_competency = max(1, num_questions // len(competencies))
for competency in competencies:
competency_questions = []
# Add technical questions if requested and available
if "technical" in question_types and competency in self.technical_questions:
tech_questions = []
# Get questions for current level and below
level_order = ["junior", "mid", "senior", "staff", "principal"]
current_level_idx = level_order.index(level) if level in level_order else 2
for lvl_idx in range(current_level_idx + 1):
lvl = level_order[lvl_idx]
if lvl in self.technical_questions[competency]:
tech_questions.extend(self.technical_questions[competency][lvl])
competency_questions.extend(tech_questions[:questions_per_competency])
# Add behavioral questions if requested
if "behavioral" in question_types and competency in self.behavioral_questions:
behavioral_q = self.behavioral_questions[competency][:questions_per_competency]
competency_questions.extend(behavioral_q)
# Add situational questions (variations of behavioral)
if "situational" in question_types:
situational_q = self._generate_situational_questions(competency, questions_per_competency)
competency_questions.extend(situational_q)
# Ensure we have enough questions for this competency
while len(competency_questions) < questions_per_competency:
competency_questions.extend(self._generate_fallback_questions(competency, level))
if len(competency_questions) >= questions_per_competency:
break
questions.extend(competency_questions[:questions_per_competency])
# Shuffle and limit to requested number
random.shuffle(questions)
return questions[:num_questions]
def _generate_situational_questions(self, competency: str, count: int) -> List[Dict[str, Any]]:
"""Generate situational questions for a competency."""
situational_templates = {
"leadership": [
{
"question": "You're leading a project that's behind schedule and the client is unhappy. How do you handle this situation?",
"competency": competency,
"type": "situational",
"focus_areas": ["crisis_management", "client_communication", "team_leadership"]
}
],
"collaboration": [
{
"question": "You're working on a cross-functional project and two team members have opposing views on the technical approach. How do you resolve this?",
"competency": competency,
"type": "situational",
"focus_areas": ["conflict_resolution", "technical_decision_making", "facilitation"]
}
],
"problem_solving": [
{
"question": "You've been assigned to improve the performance of a critical system, but you have limited time and budget. Walk me through your approach.",
"competency": competency,
"type": "situational",
"focus_areas": ["prioritization", "resource_constraints", "systematic_approach"]
}
]
}
if competency in situational_templates:
return situational_templates[competency][:count]
return []
def _generate_fallback_questions(self, competency: str, level: str) -> List[Dict[str, Any]]:
"""Generate fallback questions when specific ones aren't available."""
fallback_questions = [
{
"question": f"Describe your experience with {competency.replace('_', ' ')} in your current or previous role.",
"competency": competency,
"type": "experience",
"focus_areas": ["experience_depth", "practical_application"]
},
{
"question": f"What challenges have you faced related to {competency.replace('_', ' ')} and how did you overcome them?",
"competency": competency,
"type": "challenge_based",
"focus_areas": ["problem_solving", "learning_from_experience"]
}
]
return fallback_questions
def _create_scoring_rubrics(self, questions: List[Dict[str, Any]]) -> Dict[str, Dict]:
"""Create scoring rubrics for the generated questions."""
rubrics = {}
for i, question in enumerate(questions, 1):
question_key = f"question_{i}"
question_type = question.get("type", "behavioral")
if question_type in self.scoring_rubrics:
rubrics[question_key] = {
"question": question["question"],
"competency": question["competency"],
"type": question_type,
"scoring_criteria": self.scoring_rubrics[question_type],
"weight": self._determine_question_weight(question),
"time_limit": question.get("time_limit", 30)
}
return rubrics
def _determine_question_weight(self, question: Dict[str, Any]) -> str:
"""Determine the weight/importance of a question."""
competency = question.get("competency", "")
question_type = question.get("type", "")
difficulty = question.get("difficulty", "medium")
# Core competencies get higher weight
core_competencies = ["coding_fundamentals", "system_design", "leadership", "problem_solving"]
if competency in core_competencies:
return "high"
elif question_type in ["coding", "design"] or difficulty == "hard":
return "high"
elif difficulty == "easy":
return "medium"
else:
return "medium"
def _generate_follow_up_probes(self, questions: List[Dict[str, Any]]) -> Dict[str, List[str]]:
"""Generate follow-up probes for each question."""
probes = {}
for i, question in enumerate(questions, 1):
question_key = f"question_{i}"
competency = question.get("competency", "")
# Get competency-specific follow-ups
if competency in self.follow_up_strategies:
competency_probes = self.follow_up_strategies[competency].copy()
else:
competency_probes = [
"Can you provide more specific details about your approach?",
"What would you do differently if you had to do this again?",
"What challenges did you face and how did you overcome them?"
]
# Add question-type specific probes
question_type = question.get("type", "")
if question_type == "coding":
competency_probes.extend([
"How would you test this solution?",
"What's the time and space complexity of your approach?",
"Can you think of any optimizations?"
])
elif question_type == "behavioral":
competency_probes.extend([
"What did you learn from this experience?",
"How did others react to your approach?",
"What metrics did you use to measure success?"
])
elif question_type == "design":
competency_probes.extend([
"How would you handle failure scenarios?",
"What monitoring would you implement?",
"How would this scale to 10x the load?"
])
probes[question_key] = competency_probes[:5] # Limit to 5 follow-ups
return probes
def _create_calibration_examples(self, sample_questions: List[Dict[str, Any]]) -> Dict[str, Dict]:
"""Create calibration examples with poor/good/great answers."""
examples = {}
for i, question in enumerate(sample_questions, 1):
question_key = f"question_{i}"
examples[question_key] = {
"question": question["question"],
"competency": question["competency"],
"sample_answers": {
"poor_answer": self._generate_sample_answer(question, "poor"),
"good_answer": self._generate_sample_answer(question, "good"),
"great_answer": self._generate_sample_answer(question, "great")
},
"scoring_rationale": self._generate_scoring_rationale(question)
}
return examples
def _generate_sample_answer(self, question: Dict[str, Any], quality: str) -> Dict[str, str]:
"""Generate sample answers of different quality levels."""
competency = question.get("competency", "")
question_type = question.get("type", "")
if quality == "poor":
return {
"answer": f"Sample poor answer for {competency} question - lacks detail, specificity, or demonstrates weak competency",
"score": "1-2",
"issues": ["Vague response", "Limited evidence of competency", "Poor structure"]
}
elif quality == "good":
return {
"answer": f"Sample good answer for {competency} question - adequate detail, demonstrates competency clearly",
"score": "3",
"strengths": ["Clear structure", "Demonstrates competency", "Adequate detail"]
}
else: # great
return {
"answer": f"Sample excellent answer for {competency} question - exceptional detail, strong evidence, goes above and beyond",
"score": "4",
"strengths": ["Exceptional detail", "Strong evidence", "Strategic thinking", "Goes beyond requirements"]
}
def _generate_scoring_rationale(self, question: Dict[str, Any]) -> Dict[str, str]:
"""Generate rationale for scoring this question."""
competency = question.get("competency", "")
return {
"key_indicators": f"Look for evidence of {competency.replace('_', ' ')} competency",
"red_flags": "Vague answers, lack of specifics, negative outcomes without learning",
"green_flags": "Specific examples, clear impact, demonstrates growth and learning"
}
def _generate_usage_guidelines(self, role_key: str, level_key: str) -> Dict[str, Any]:
"""Generate usage guidelines for the question bank."""
return {
"interview_flow": {
"warm_up": "Start with 1-2 easier questions to build rapport",
"core_assessment": "Focus majority of time on core competency questions",
"closing": "End with questions about candidate's questions/interests"
},
"time_management": {
"technical_questions": "Allow extra time for coding/design questions",
"behavioral_questions": "Keep to time limits but allow for follow-ups",
"total_recommendation": "45-75 minutes per interview round"
},
"question_selection": {
"variety": "Mix question types within each competency area",
"difficulty": "Adjust based on candidate responses and energy",
"customization": "Adapt questions based on candidate's background"
},
"common_mistakes": [
"Don't ask all questions mechanically",
"Don't skip follow-up questions",
"Don't forget to assess cultural fit alongside competencies",
"Don't let one strong/weak area bias overall assessment"
],
"calibration_reminders": [
"Compare against role standard, not other candidates",
"Focus on evidence demonstrated, not potential",
"Consider level-appropriate expectations",
"Document specific examples in feedback"
]
}
def format_human_readable(question_bank: Dict[str, Any]) -> str:
"""Format question bank data in human-readable format."""
output = []
# Header
output.append(f"Interview Question Bank: {question_bank['role']} ({question_bank['level'].title()} Level)")
output.append("=" * 70)
output.append(f"Generated: {question_bank['generated_at']}")
output.append(f"Total Questions: {question_bank['total_questions']}")
output.append(f"Question Types: {', '.join(question_bank['question_types'])}")
output.append(f"Target Competencies: {', '.join(question_bank['competencies'])}")
output.append("")
# Questions
output.append("INTERVIEW QUESTIONS")
output.append("-" * 50)
for i, question in enumerate(question_bank['questions'], 1):
output.append(f"\n{i}. {question['question']}")
output.append(f" Competency: {question['competency'].replace('_', ' ').title()}")
output.append(f" Type: {question.get('type', 'N/A').title()}")
if 'time_limit' in question:
output.append(f" Time Limit: {question['time_limit']} minutes")
if 'focus_areas' in question:
output.append(f" Focus Areas: {', '.join(question['focus_areas'])}")
# Scoring Guidelines
output.append("\n\nSCORING RUBRICS")
output.append("-" * 50)
# Show sample scoring criteria
if question_bank['scoring_rubrics']:
first_question = list(question_bank['scoring_rubrics'].keys())[0]
sample_rubric = question_bank['scoring_rubrics'][first_question]
output.append(f"Sample Scoring Criteria ({sample_rubric['type']} questions):")
for criterion, scores in sample_rubric['scoring_criteria'].items():
output.append(f"\n{criterion.replace('_', ' ').title()}:")
for score, description in scores.items():
output.append(f" {score}: {description}")
# Follow-up Probes
output.append("\n\nFOLLOW-UP PROBE EXAMPLES")
output.append("-" * 50)
if question_bank['follow_up_probes']:
first_question = list(question_bank['follow_up_probes'].keys())[0]
sample_probes = question_bank['follow_up_probes'][first_question]
output.append("Sample follow-up questions:")
for probe in sample_probes[:3]: # Show first 3
output.append(f" • {probe}")
# Usage Guidelines
output.append("\n\nUSAGE GUIDELINES")
output.append("-" * 50)
guidelines = question_bank['usage_guidelines']
output.append("Interview Flow:")
for phase, description in guidelines['interview_flow'].items():
output.append(f" • {phase.replace('_', ' ').title()}: {description}")
output.append("\nTime Management:")
for aspect, recommendation in guidelines['time_management'].items():
output.append(f" • {aspect.replace('_', ' ').title()}: {recommendation}")
output.append("\nCommon Mistakes to Avoid:")
for mistake in guidelines['common_mistakes'][:3]: # Show first 3
output.append(f" • {mistake}")
# Calibration Examples (if available)
if question_bank['calibration_examples']:
output.append("\n\nCALIBRATION EXAMPLES")
output.append("-" * 50)
first_example = list(question_bank['calibration_examples'].values())[0]
output.append(f"Question: {first_example['question']}")
output.append("\nSample Answer Quality Levels:")
for quality, details in first_example['sample_answers'].items():
output.append(f" {quality.replace('_', ' ').title()} (Score {details['score']}):")
if 'issues' in details:
output.append(f" Issues: {', '.join(details['issues'])}")
if 'strengths' in details:
output.append(f" Strengths: {', '.join(details['strengths'])}")
return "\n".join(output)
def main():
parser = argparse.ArgumentParser(description="Generate comprehensive interview question banks with scoring criteria")
parser.add_argument("--role", type=str, help="Job role title (e.g., 'Frontend Engineer')")
parser.add_argument("--level", type=str, default="senior", help="Experience level (junior, mid, senior, staff, principal)")
parser.add_argument("--competencies", type=str, help="Comma-separated list of competencies to focus on")
parser.add_argument("--question-types", type=str, help="Comma-separated list of question types (technical, behavioral, situational)")
parser.add_argument("--num-questions", type=int, default=20, help="Number of questions to generate")
parser.add_argument("--input", type=str, help="Input JSON file with role requirements")
parser.add_argument("--output", type=str, help="Output directory or file path")
parser.add_argument("--format", choices=["json", "text", "both"], default="both", help="Output format")
args = parser.parse_args()
generator = QuestionBankGenerator()
# Handle input
if args.input:
try:
with open(args.input, 'r') as f:
role_data = json.load(f)
role = role_data.get('role') or role_data.get('title', '')
level = role_data.get('level', 'senior')
competencies = role_data.get('competencies')
question_types = role_data.get('question_types')
num_questions = role_data.get('num_questions', 20)
except Exception as e:
print(f"Error reading input file: {e}")
sys.exit(1)
else:
if not args.role:
print("Error: --role is required when not using --input")
sys.exit(1)
role = args.role
level = args.level
competencies = args.competencies.split(',') if args.competencies else None
question_types = args.question_types.split(',') if args.question_types else None
num_questions = args.num_questions
# Generate question bank
try:
question_bank = generator.generate_question_bank(
role=role,
level=level,
competencies=competencies,
question_types=question_types,
num_questions=num_questions
)
# Handle output
if args.output:
output_path = args.output
if os.path.isdir(output_path):
safe_role = "".join(c for c in role.lower() if c.isalnum() or c in (' ', '-', '_')).replace(' ', '_')
base_filename = f"{safe_role}_{level}_questions"
json_path = os.path.join(output_path, f"{base_filename}.json")
text_path = os.path.join(output_path, f"{base_filename}.txt")
else:
json_path = output_path if output_path.endswith('.json') else f"{output_path}.json"
text_path = output_path.replace('.json', '.txt') if output_path.endswith('.json') else f"{output_path}.txt"
else:
safe_role = "".join(c for c in role.lower() if c.isalnum() or c in (' ', '-', '_')).replace(' ', '_')
base_filename = f"{safe_role}_{level}_questions"
json_path = f"{base_filename}.json"
text_path = f"{base_filename}.txt"
# Write outputs
if args.format in ["json", "both"]:
with open(json_path, 'w') as f:
json.dump(question_bank, f, indent=2, default=str)
print(f"JSON output written to: {json_path}")
if args.format in ["text", "both"]:
with open(text_path, 'w') as f:
f.write(format_human_readable(question_bank))
print(f"Text output written to: {text_path}")
# Print summary
print(f"\nQuestion Bank Summary:")
print(f"Role: {question_bank['role']} ({question_bank['level'].title()})")
print(f"Total Questions: {question_bank['total_questions']}")
print(f"Competencies Covered: {len(question_bank['competencies'])}")
print(f"Question Types: {', '.join(question_bank['question_types'])}")
except Exception as e:
print(f"Error generating question bank: {e}")
sys.exit(1)
if __name__ == "__main__":
main()
FILE:README.md
# Interview System Designer
A comprehensive toolkit for designing, optimizing, and calibrating interview processes. This skill provides tools to create role-specific interview loops, generate competency-based question banks, and analyze hiring data for bias and calibration issues.
## Overview
The Interview System Designer skill includes three powerful Python tools and comprehensive reference materials to help you build fair, effective, and scalable hiring processes:
1. **Interview Loop Designer** - Generate calibrated interview loops for any role and level
2. **Question Bank Generator** - Create competency-based interview questions with scoring rubrics
3. **Hiring Calibrator** - Analyze interview data to detect bias and calibration issues
## Tools
### 1. Interview Loop Designer (`loop_designer.py`)
Generates complete interview loops tailored to specific roles, levels, and teams.
**Features:**
- Role-specific competency mapping (SWE, PM, Designer, Data, DevOps, Leadership)
- Level-appropriate interview rounds (junior through principal)
- Optimized scheduling and time allocation
- Interviewer skill requirements
- Standardized scorecard templates
**Usage:**
```bash
# Basic usage
python3 loop_designer.py --role "Senior Software Engineer" --level senior
# With team and custom competencies
python3 loop_designer.py --role "Product Manager" --level mid --team growth --competencies leadership,strategy,analytics
# Using JSON input file
python3 loop_designer.py --input assets/sample_role_definitions.json --output loops/
# Specify output format
python3 loop_designer.py --role "Staff Data Scientist" --level staff --format json --output data_scientist_loop.json
```
**Input Options:**
- `--role`: Job role title (e.g., "Senior Software Engineer", "Product Manager")
- `--level`: Experience level (junior, mid, senior, staff, principal)
- `--team`: Team or department (optional)
- `--competencies`: Comma-separated list of specific competencies to focus on
- `--input`: JSON file with role definition
- `--output`: Output directory or file path
- `--format`: Output format (json, text, both) - default: both
**Example Output:**
```
Interview Loop Design for Senior Software Engineer (Senior Level)
============================================================
Total Duration: 300 minutes (5h 0m)
Total Rounds: 5
INTERVIEW ROUNDS
----------------------------------------
Round 1: Technical Phone Screen
Duration: 45 minutes
Format: Virtual
Focus Areas: Coding Fundamentals, Problem Solving
Round 2: System Design
Duration: 75 minutes
Format: Collaborative Whitboard
Focus Areas: System Thinking, Architectural Reasoning
...
```
### 2. Question Bank Generator (`question_bank_generator.py`)
Creates comprehensive interview question banks organized by competency area.
**Features:**
- Competency-based question organization
- Level-appropriate difficulty progression
- Multiple question types (technical, behavioral, situational)
- Detailed scoring rubrics with calibration examples
- Follow-up probes and conversation guides
**Usage:**
```bash
# Generate questions for specific competencies
python3 question_bank_generator.py --role "Frontend Engineer" --competencies react,typescript,system-design
# Create behavioral question bank
python3 question_bank_generator.py --role "Product Manager" --question-types behavioral,leadership --num-questions 15
# Generate questions for multiple levels
python3 question_bank_generator.py --role "DevOps Engineer" --levels junior,mid,senior --output questions/
```
**Input Options:**
- `--role`: Job role title
- `--level`: Experience level (default: senior)
- `--competencies`: Comma-separated list of competencies to focus on
- `--question-types`: Types to include (technical, behavioral, situational)
- `--num-questions`: Number of questions to generate (default: 20)
- `--input`: JSON file with role requirements
- `--output`: Output directory or file path
- `--format`: Output format (json, text, both) - default: both
**Question Types:**
- **Technical**: Coding problems, system design, domain-specific challenges
- **Behavioral**: STAR method questions focusing on past experiences
- **Situational**: Hypothetical scenarios testing decision-making
### 3. Hiring Calibrator (`hiring_calibrator.py`)
Analyzes interview scores to detect bias, calibration issues, and provides recommendations.
**Features:**
- Statistical bias detection across demographics
- Interviewer calibration analysis
- Score distribution and trending analysis
- Specific coaching recommendations
- Comprehensive reporting with actionable insights
**Usage:**
```bash
# Comprehensive analysis
python3 hiring_calibrator.py --input assets/sample_interview_results.json --analysis-type comprehensive
# Focus on specific areas
python3 hiring_calibrator.py --input interview_data.json --analysis-type bias --competencies technical,leadership
# Trend analysis over time
python3 hiring_calibrator.py --input historical_data.json --trend-analysis --period quarterly
```
**Input Options:**
- `--input`: JSON file with interview results data (required)
- `--analysis-type`: Type of analysis (comprehensive, bias, calibration, interviewer, scoring)
- `--competencies`: Comma-separated list of competencies to focus on
- `--trend-analysis`: Enable trend analysis over time
- `--period`: Time period for trends (daily, weekly, monthly, quarterly)
- `--output`: Output file path
- `--format`: Output format (json, text, both) - default: both
**Analysis Types:**
- **Comprehensive**: Full analysis including bias, calibration, and recommendations
- **Bias**: Focus on demographic and interviewer bias patterns
- **Calibration**: Interviewer consistency and agreement analysis
- **Interviewer**: Individual interviewer performance and coaching needs
- **Scoring**: Score distribution and pattern analysis
## Data Formats
### Role Definition Input (JSON)
```json
{
"role": "Senior Software Engineer",
"level": "senior",
"team": "platform",
"competencies": ["system_design", "technical_leadership", "mentoring"],
"requirements": {
"years_experience": "5-8",
"technical_skills": ["Python", "AWS", "Kubernetes"],
"leadership_experience": true
}
}
```
### Interview Results Input (JSON)
```json
[
{
"candidate_id": "candidate_001",
"role": "Senior Software Engineer",
"interviewer_id": "interviewer_alice",
"date": "2024-01-15T09:00:00Z",
"scores": {
"coding_fundamentals": 3.5,
"system_design": 4.0,
"technical_leadership": 3.0,
"communication": 3.5
},
"overall_recommendation": "Hire",
"gender": "male",
"ethnicity": "asian",
"years_experience": 6
}
]
```
## Reference Materials
### Competency Matrix Templates (`references/competency_matrix_templates.md`)
- Comprehensive competency matrices for all engineering roles
- Level-specific expectations (junior through principal)
- Assessment criteria and growth paths
- Customization guidelines for different company stages and industries
### Bias Mitigation Checklist (`references/bias_mitigation_checklist.md`)
- Pre-interview preparation checklist
- Interview process bias prevention strategies
- Real-time bias interruption techniques
- Legal compliance reminders
- Emergency response protocols
### Debrief Facilitation Guide (`references/debrief_facilitation_guide.md`)
- Structured debrief meeting frameworks
- Evidence-based discussion techniques
- Bias interruption strategies
- Decision documentation standards
- Common challenges and solutions
## Sample Data
The `assets/` directory contains sample data for testing:
- `sample_role_definitions.json`: Example role definitions for various positions
- `sample_interview_results.json`: Sample interview data with multiple candidates and interviewers
## Expected Outputs
The `expected_outputs/` directory contains examples of tool outputs:
- Interview loop designs in both JSON and human-readable formats
- Question banks with scoring rubrics and calibration examples
- Calibration analysis reports with bias detection and recommendations
## Best Practices
### Interview Loop Design
1. **Competency Focus**: Align interview rounds with role-critical competencies
2. **Level Calibration**: Adjust expectations and question difficulty based on experience level
3. **Time Optimization**: Balance thoroughness with candidate experience
4. **Interviewer Training**: Ensure interviewers are qualified and calibrated
### Question Bank Development
1. **Evidence-Based**: Focus on observable behaviors and concrete examples
2. **Bias Mitigation**: Use structured questions that minimize subjective interpretation
3. **Calibration**: Include examples of different quality responses for consistency
4. **Continuous Improvement**: Regularly update questions based on predictive validity
### Calibration Analysis
1. **Regular Monitoring**: Analyze hiring data quarterly for bias patterns
2. **Prompt Action**: Address calibration issues immediately with targeted coaching
3. **Data Quality**: Ensure complete and consistent data collection
4. **Legal Compliance**: Monitor for discriminatory patterns and document corrections
## Installation & Setup
No external dependencies required - uses Python 3 standard library only.
```bash
# Clone or download the skill directory
cd interview-system-designer/
# Make scripts executable (optional)
chmod +x *.py
# Test with sample data
python3 loop_designer.py --role "Senior Software Engineer" --level senior
python3 question_bank_generator.py --role "Product Manager" --level mid
python3 hiring_calibrator.py --input assets/sample_interview_results.json
```
## Integration
### With Existing Systems
- **ATS Integration**: Export interview loops as structured data for applicant tracking systems
- **Calendar Systems**: Use scheduling outputs to auto-create interview blocks
- **HR Analytics**: Import calibration reports into broader diversity and inclusion dashboards
### Custom Workflows
- **Batch Processing**: Process multiple roles or historical data sets
- **Automated Reporting**: Schedule regular calibration analysis
- **Custom Competencies**: Extend frameworks with company-specific competencies
## Troubleshooting
### Common Issues
**"Role not found" errors:**
- The tool will map common variations (engineer → software_engineer)
- For custom roles, use the closest standard role and specify custom competencies
**"Insufficient data" errors:**
- Minimum 5 interviews required for statistical analysis
- Ensure interview data includes required fields (candidate_id, interviewer_id, scores, date)
**Missing output files:**
- Check file permissions in output directory
- Ensure adequate disk space
- Verify JSON input file format is valid
### Performance Considerations
- Interview loop generation: < 1 second
- Question bank generation: 1-3 seconds for 20 questions
- Calibration analysis: 1-5 seconds for 50 interviews, scales linearly
## Contributing
To extend this skill:
1. **New Roles**: Add competency frameworks in `_init_competency_frameworks()`
2. **New Question Types**: Extend question templates in respective generators
3. **New Analysis Types**: Add analysis methods to hiring calibrator
4. **Custom Outputs**: Modify formatting functions for different output needs
## License & Usage
This skill is designed for internal company use in hiring process optimization. All bias detection and mitigation features should be reviewed with legal counsel to ensure compliance with local employment laws.
For questions or support, refer to the comprehensive documentation in each script's docstring and the reference materials provided.
FILE:references/bias_mitigation_checklist.md
# Interview Bias Mitigation Checklist
This comprehensive checklist helps identify, prevent, and mitigate various forms of bias in the interview process. Use this as a systematic guide to ensure fair and equitable hiring practices.
## Pre-Interview Phase
### Job Description & Requirements
- [ ] **Remove unnecessary requirements** that don't directly relate to job performance
- [ ] **Avoid gendered language** (competitive, aggressive vs. collaborative, detail-oriented)
- [ ] **Remove university prestige requirements** unless absolutely necessary for role
- [ ] **Focus on skills and outcomes** rather than years of experience in specific technologies
- [ ] **Use inclusive language** and avoid cultural assumptions
- [ ] **Specify only essential requirements** vs. nice-to-have qualifications
- [ ] **Remove location/commute assumptions** for remote-eligible positions
- [ ] **Review requirements for unconscious bias** (e.g., assuming continuous work history)
### Sourcing & Pipeline
- [ ] **Diversify sourcing channels** beyond traditional networks
- [ ] **Partner with diverse professional organizations** and communities
- [ ] **Use bias-minimizing sourcing tools** and platforms
- [ ] **Track sourcing effectiveness** by demographic groups
- [ ] **Train recruiters on bias awareness** and inclusive outreach
- [ ] **Review referral patterns** for potential network bias
- [ ] **Expand university partnerships** beyond elite institutions
- [ ] **Use structured outreach messages** to reduce individual bias
### Resume Screening
- [ ] **Implement blind resume review** (remove names, photos, university names initially)
- [ ] **Use standardized screening criteria** applied consistently
- [ ] **Multiple screeners for each resume** with independent scoring
- [ ] **Focus on relevant skills and achievements** over pedigree indicators
- [ ] **Avoid assumptions about career gaps** or non-traditional backgrounds
- [ ] **Consider alternative paths to skills** (bootcamps, self-taught, career changes)
- [ ] **Track screening pass rates** by demographic groups
- [ ] **Regular screener calibration sessions** on bias awareness
## Interview Panel Composition
### Diversity Requirements
- [ ] **Ensure diverse interview panels** (gender, ethnicity, seniority levels)
- [ ] **Include at least one underrepresented interviewer** when possible
- [ ] **Rotate panel assignments** to prevent bias patterns
- [ ] **Balance seniority levels** on panels (not all senior or all junior)
- [ ] **Include cross-functional perspectives** when relevant
- [ ] **Avoid panels of only one demographic group** when possible
- [ ] **Consider panel member unconscious bias training** status
- [ ] **Document panel composition rationale** for future review
### Interviewer Selection
- [ ] **Choose interviewers based on relevant competency assessment ability**
- [ ] **Ensure interviewers have completed bias training** within last 12 months
- [ ] **Select interviewers with consistent calibration history**
- [ ] **Avoid interviewers with known bias patterns** (flagged in previous analyses)
- [ ] **Include at least one interviewer familiar with candidate's background type**
- [ ] **Balance perspectives** (technical depth, cultural fit, growth potential)
- [ ] **Consider interviewer availability for proper preparation time**
- [ ] **Ensure interviewers understand role requirements and standards**
## Interview Process Design
### Question Standardization
- [ ] **Use standardized question sets** for each competency area
- [ ] **Develop questions that assess skills, not culture fit stereotypes**
- [ ] **Avoid questions about personal background** unless directly job-relevant
- [ ] **Remove questions that could reveal protected characteristics**
- [ ] **Focus on behavioral examples** using STAR method
- [ ] **Include scenario-based questions** with clear evaluation criteria
- [ ] **Test questions for potential bias** with diverse interviewers
- [ ] **Regularly update question bank** based on effectiveness data
### Structured Interview Protocol
- [ ] **Define clear time allocations** for each question/section
- [ ] **Establish consistent interview flow** across all candidates
- [ ] **Create standardized intro/outro** processes
- [ ] **Use identical technical setup and tools** for all candidates
- [ ] **Provide same background information** to all interviewers
- [ ] **Standardize note-taking format** and requirements
- [ ] **Define clear handoff procedures** between interviewers
- [ ] **Document any deviations** from standard protocol
### Accommodation Preparation
- [ ] **Proactively offer accommodations** without requiring disclosure
- [ ] **Provide multiple interview format options** (phone, video, in-person)
- [ ] **Ensure accessibility of interview locations and tools**
- [ ] **Allow extended time** when requested or needed
- [ ] **Provide materials in advance** when helpful
- [ ] **Train interviewers on accommodation protocols**
- [ ] **Test all technology** for accessibility compliance
- [ ] **Have backup plans** for technical issues
## During the Interview
### Interviewer Behavior
- [ ] **Use welcoming, professional tone** with all candidates
- [ ] **Avoid assumptions based on appearance or background**
- [ ] **Give equal encouragement and support** to all candidates
- [ ] **Allow equal time for candidate questions**
- [ ] **Avoid leading questions** that suggest desired answers
- [ ] **Listen actively** without interrupting unnecessarily
- [ ] **Take detailed notes** focusing on responses, not impressions
- [ ] **Avoid small talk** that could reveal irrelevant personal information
### Question Delivery
- [ ] **Ask questions as written** without improvisation that could introduce bias
- [ ] **Provide equal clarification** when candidates ask for it
- [ ] **Use consistent follow-up probing** across candidates
- [ ] **Allow reasonable thinking time** before expecting responses
- [ ] **Avoid rephrasing questions** in ways that give hints
- [ ] **Stay focused on defined competencies** being assessed
- [ ] **Give equal encouragement** for elaboration when needed
- [ ] **Maintain professional demeanor** regardless of candidate background
### Real-time Bias Checking
- [ ] **Notice first impressions** but don't let them drive assessment
- [ ] **Question gut reactions** - are they based on competency evidence?
- [ ] **Focus on specific examples** and evidence provided
- [ ] **Avoid pattern matching** to existing successful employees
- [ ] **Notice cultural assumptions** in interpretation of responses
- [ ] **Check for confirmation bias** - seeking evidence to support initial impressions
- [ ] **Consider alternative explanations** for candidate responses
- [ ] **Stay aware of fatigue effects** on judgment throughout the day
## Evaluation & Scoring
### Scoring Consistency
- [ ] **Use defined rubrics consistently** across all candidates
- [ ] **Score immediately after interview** while details are fresh
- [ ] **Focus scoring on demonstrated competencies** not potential or personality
- [ ] **Provide specific evidence** for each score given
- [ ] **Avoid comparative scoring** (comparing candidates to each other)
- [ ] **Use calibrated examples** of each score level
- [ ] **Score independently** before discussing with other interviewers
- [ ] **Document reasoning** for all scores, especially extreme ones (1s and 4s)
### Bias Check Questions
- [ ] **"Would I score this differently if the candidate looked different?"**
- [ ] **"Am I basing this on evidence or assumptions?"**
- [ ] **"Would this response get the same score from a different demographic?"**
- [ ] **"Am I penalizing non-traditional backgrounds or approaches?"**
- [ ] **"Is my scoring consistent with the defined rubric?"**
- [ ] **"Am I letting one strong/weak area bias overall assessment?"**
- [ ] **"Are my cultural assumptions affecting interpretation?"**
- [ ] **"Would I want to work with this person?" (Check if this is biasing assessment)**
### Documentation Requirements
- [ ] **Record specific examples** supporting each competency score
- [ ] **Avoid subjective language** like "seems like," "appears to be"
- [ ] **Focus on observable behaviors** and concrete responses
- [ ] **Note exact quotes** when relevant to assessment
- [ ] **Distinguish between facts and interpretations**
- [ ] **Provide improvement suggestions** that are skill-based, not person-based
- [ ] **Avoid comparative language** to other candidates or employees
- [ ] **Use neutral language** free from cultural assumptions
## Debrief Process
### Structured Discussion
- [ ] **Start with independent score sharing** before discussion
- [ ] **Focus discussion on evidence** not impressions or feelings
- [ ] **Address significant score discrepancies** with evidence review
- [ ] **Challenge biased language** or assumptions in discussion
- [ ] **Ensure all voices are heard** in group decision making
- [ ] **Document reasons for final decision** with specific evidence
- [ ] **Avoid personality-based discussions** ("culture fit" should be evidence-based)
- [ ] **Consider multiple perspectives** on candidate responses
### Decision-Making Process
- [ ] **Use weighted scoring system** based on role requirements
- [ ] **Require minimum scores** in critical competency areas
- [ ] **Avoid veto power** unless based on clear, documented evidence
- [ ] **Consider growth potential** fairly across all candidates
- [ ] **Document dissenting opinions** and reasoning
- [ ] **Use tie-breaking criteria** that are predetermined and fair
- [ ] **Consider additional data collection** if team is split
- [ ] **Make final decision based on role requirements**, not team preferences
### Final Recommendations
- [ ] **Provide specific, actionable feedback** for development areas
- [ ] **Focus recommendations on skills and competencies**
- [ ] **Avoid language that could reflect bias** in written feedback
- [ ] **Consider onboarding needs** based on actual skill gaps, not assumptions
- [ ] **Provide coaching recommendations** that are evidence-based
- [ ] **Avoid personal judgments** about candidate character or personality
- [ ] **Make hiring recommendation** based solely on job-relevant criteria
- [ ] **Document any concerns** with specific, observable evidence
## Post-Interview Monitoring
### Data Collection
- [ ] **Track interviewer scoring patterns** for consistency analysis
- [ ] **Monitor pass rates** by demographic groups
- [ ] **Collect candidate experience feedback** on interview fairness
- [ ] **Analyze score distributions** for potential bias indicators
- [ ] **Track time-to-decision** across different candidate types
- [ ] **Monitor offer acceptance rates** by demographics
- [ ] **Collect new hire performance data** for process validation
- [ ] **Document any bias incidents** or concerns raised
### Regular Analysis
- [ ] **Conduct quarterly bias audits** of interview data
- [ ] **Review interviewer calibration** and identify outliers
- [ ] **Analyze demographic trends** in hiring outcomes
- [ ] **Compare candidate experience surveys** across groups
- [ ] **Track correlation between interview scores and job performance**
- [ ] **Review and update bias mitigation strategies** based on data
- [ ] **Share findings with interview teams** for continuous improvement
- [ ] **Update training programs** based on identified bias patterns
## Bias Types to Watch For
### Affinity Bias
- **Definition**: Favoring candidates similar to yourself
- **Watch for**: Over-positive response to shared backgrounds, interests, or experiences
- **Mitigation**: Focus on job-relevant competencies, diversify interview panels
### Halo/Horn Effect
- **Definition**: One positive/negative trait influencing overall assessment
- **Watch for**: Strong performance in one area affecting scores in unrelated areas
- **Mitigation**: Score each competency independently, use structured evaluation
### Confirmation Bias
- **Definition**: Seeking information that confirms initial impressions
- **Watch for**: Asking follow-ups that lead candidate toward expected responses
- **Mitigation**: Use standardized questions, consider alternative interpretations
### Attribution Bias
- **Definition**: Attributing success/failure to different causes based on candidate demographics
- **Watch for**: Assuming women are "lucky" vs. men are "skilled" for same achievements
- **Mitigation**: Focus on candidate's role in achievements, avoid assumptions
### Cultural Bias
- **Definition**: Judging candidates based on cultural differences rather than job performance
- **Watch for**: Penalizing communication styles, work approaches, or values that differ from team norm
- **Mitigation**: Define job-relevant criteria clearly, consider diverse perspectives valuable
### Educational Bias
- **Definition**: Over-weighting prestigious educational credentials
- **Watch for**: Assuming higher capability based on school rank rather than demonstrated skills
- **Mitigation**: Focus on skills demonstration, consider alternative learning paths
### Experience Bias
- **Definition**: Requiring specific company or industry experience unnecessarily
- **Watch for**: Discounting transferable skills from different industries or company sizes
- **Mitigation**: Define core skills needed, assess adaptability and learning ability
## Emergency Bias Response Protocol
### During Interview
1. **Pause the interview** if significant bias is observed
2. **Privately address** bias with interviewer if possible
3. **Document the incident** for review
4. **Continue with fair assessment** of candidate
5. **Flag for debrief discussion** if interview continues
### Post-Interview
1. **Report bias incidents** to hiring manager/HR immediately
2. **Document specific behaviors** observed
3. **Consider additional interviewer** for second opinion
4. **Review candidate assessment** for bias impact
5. **Implement corrective actions** for future interviews
### Interviewer Coaching
1. **Provide immediate feedback** on bias observed
2. **Schedule bias training refresher** if needed
3. **Monitor future interviews** for improvement
4. **Consider removing from interview rotation** if bias persists
5. **Document coaching provided** for performance management
## Legal Compliance Reminders
### Protected Characteristics
- Age, race, color, religion, sex, national origin, disability status, veteran status
- Pregnancy, genetic information, sexual orientation, gender identity
- Any other characteristics protected by local/state/federal law
### Prohibited Questions
- Questions about family planning, marital status, pregnancy
- Age-related questions (unless BFOQ)
- Religious or political affiliations
- Disability status (unless voluntary disclosure for accommodation)
- Arrest records (without conviction relevance)
- Financial status or credit (unless job-relevant)
### Documentation Requirements
- Keep all interview materials for required retention period
- Ensure consistent documentation across all candidates
- Avoid documenting protected characteristic observations
- Focus documentation on job-relevant observations only
## Training & Certification
### Required Training Topics
- Unconscious bias awareness and mitigation
- Structured interviewing techniques
- Legal compliance in hiring
- Company-specific bias mitigation protocols
- Role-specific competency assessment
- Accommodation and accessibility requirements
### Ongoing Development
- Annual bias training refresher
- Quarterly calibration sessions
- Regular updates on legal requirements
- Peer feedback and coaching
- Industry best practice updates
- Data-driven process improvements
This checklist should be reviewed and updated regularly based on legal requirements, industry best practices, and internal bias analysis results.
FILE:references/competency_matrix_templates.md
# Competency Matrix Templates
This document provides comprehensive competency matrix templates for different engineering roles and levels. Use these matrices to design role-specific interview loops and evaluation criteria.
## Software Engineering Competency Matrix
### Technical Competencies
| Competency | Junior (L1-L2) | Mid (L3-L4) | Senior (L5-L6) | Staff+ (L7+) |
|------------|----------------|-------------|----------------|--------------|
| **Coding & Algorithms** | Basic data structures, simple algorithms, language syntax | Advanced algorithms, complexity analysis, optimization | Complex problem solving, algorithm design, performance tuning | Architecture-level algorithmic decisions, novel approach design |
| **System Design** | Component interactions, basic scalability concepts | Service design, database modeling, API design | Distributed systems, scalability patterns, trade-off analysis | Large-scale architecture, cross-system design, technology strategy |
| **Code Quality** | Readable code, basic testing, follows conventions | Maintainable code, comprehensive testing, design patterns | Code reviews, quality standards, refactoring leadership | Engineering standards, quality culture, technical debt management |
| **Debugging & Problem Solving** | Basic debugging, structured problem approach | Complex debugging, root cause analysis, performance issues | System-wide debugging, production issues, incident response | Cross-system troubleshooting, preventive measures, tooling design |
| **Domain Knowledge** | Learning role-specific technologies | Proficiency in domain tools/frameworks | Deep domain expertise, technology evaluation | Domain leadership, technology roadmap, innovation |
### Behavioral Competencies
| Competency | Junior (L1-L2) | Mid (L3-L4) | Senior (L5-L6) | Staff+ (L7+) |
|------------|----------------|-------------|----------------|--------------|
| **Communication** | Clear status updates, asks good questions | Technical explanations, stakeholder updates | Cross-functional communication, technical writing | Executive communication, external representation, thought leadership |
| **Collaboration** | Team participation, code reviews | Cross-team projects, knowledge sharing | Team leadership, conflict resolution | Cross-org collaboration, culture building, strategic partnerships |
| **Leadership & Influence** | Peer mentoring, positive attitude | Junior mentoring, project ownership | Team guidance, technical decisions, hiring | Org-wide influence, vision setting, culture change |
| **Growth & Learning** | Skill development, feedback receptivity | Proactive learning, teaching others | Continuous improvement, trend awareness | Learning culture, industry leadership, innovation adoption |
| **Ownership & Initiative** | Task completion, quality focus | Project ownership, process improvement | Feature/service ownership, strategic thinking | Product/platform ownership, business impact, market influence |
## Product Management Competency Matrix
### Product Competencies
| Competency | Associate PM (L1-L2) | PM (L3-L4) | Senior PM (L5-L6) | Principal PM (L7+) |
|------------|---------------------|------------|-------------------|-------------------|
| **Product Strategy** | Feature requirements, user stories | Product roadmaps, market analysis | Business strategy, competitive positioning | Portfolio strategy, market creation, platform vision |
| **User Research & Analytics** | Basic user interviews, metrics tracking | Research design, data interpretation | Research strategy, advanced analytics | Research culture, measurement frameworks, insight generation |
| **Technical Understanding** | Basic tech concepts, API awareness | System architecture, technical trade-offs | Technical strategy, platform decisions | Technology vision, architectural influence, innovation leadership |
| **Execution & Process** | Feature delivery, stakeholder coordination | Project management, cross-functional leadership | Process optimization, team scaling | Operational excellence, org design, strategic execution |
| **Business Acumen** | Revenue awareness, customer understanding | P&L understanding, business case development | Business strategy, market dynamics | Corporate strategy, board communication, investor relations |
### Leadership Competencies
| Competency | Associate PM (L1-L2) | PM (L3-L4) | Senior PM (L5-L6) | Principal PM (L7+) |
|------------|---------------------|------------|-------------------|-------------------|
| **Stakeholder Management** | Team collaboration, clear communication | Cross-functional alignment, expectation management | Executive communication, influence without authority | Board interaction, external partnerships, industry influence |
| **Team Development** | Peer learning, feedback sharing | Junior mentoring, knowledge transfer | Team building, hiring, performance management | Talent development, culture building, org leadership |
| **Decision Making** | Data-driven decisions, priority setting | Complex trade-offs, strategic choices | Ambiguous situations, high-stakes decisions | Strategic vision, transformational decisions, risk management |
| **Innovation & Vision** | Creative problem solving, user empathy | Market opportunity identification, feature innovation | Product vision, market strategy | Industry vision, disruptive thinking, platform creation |
## Design Competency Matrix
### Design Competencies
| Competency | Junior Designer (L1-L2) | Mid Designer (L3-L4) | Senior Designer (L5-L6) | Principal Designer (L7+) |
|------------|-------------------------|---------------------|-------------------------|-------------------------|
| **Visual Design** | UI components, typography, color theory | Design systems, visual hierarchy | Brand integration, advanced layouts | Visual strategy, brand evolution, design innovation |
| **User Experience** | User flows, wireframing, prototyping | Interaction design, usability testing | Experience strategy, journey mapping | UX vision, service design, behavioral insights |
| **Research & Validation** | User interviews, usability tests | Research planning, data synthesis | Research strategy, methodology design | Research culture, insight frameworks, market research |
| **Design Systems** | Component usage, style guides | System contribution, pattern creation | System architecture, governance | System strategy, scalable design, platform thinking |
| **Tools & Craft** | Design software proficiency, asset creation | Advanced techniques, workflow optimization | Tool evaluation, process design | Technology integration, future tooling, craft evolution |
### Collaboration Competencies
| Competency | Junior Designer (L1-L2) | Mid Designer (L3-L4) | Senior Designer (L5-L6) | Principal Designer (L7+) |
|------------|-------------------------|---------------------|-------------------------|-------------------------|
| **Cross-functional Partnership** | Engineering collaboration, handoff quality | Product partnership, stakeholder alignment | Leadership collaboration, strategic alignment | Executive partnership, business strategy integration |
| **Communication & Advocacy** | Design rationale, feedback integration | Design presentations, user advocacy | Executive communication, design thinking evangelism | Industry thought leadership, external representation |
| **Mentorship & Growth** | Peer learning, skill sharing | Junior mentoring, critique facilitation | Team development, hiring, career guidance | Design culture, talent strategy, industry leadership |
| **Business Impact** | User-centered thinking, design quality | Feature success, user satisfaction | Business metrics, strategic impact | Market influence, competitive advantage, innovation leadership |
## Data Science Competency Matrix
### Technical Competencies
| Competency | Junior DS (L1-L2) | Mid DS (L3-L4) | Senior DS (L5-L6) | Principal DS (L7+) |
|------------|-------------------|----------------|-------------------|-------------------|
| **Statistical Analysis** | Descriptive stats, hypothesis testing | Advanced statistics, experimental design | Causal inference, advanced modeling | Statistical strategy, methodology innovation |
| **Machine Learning** | Basic ML algorithms, model training | Advanced ML, feature engineering | ML systems, model deployment | ML strategy, AI platform, research direction |
| **Data Engineering** | SQL, basic ETL, data cleaning | Pipeline design, data modeling | Platform architecture, scalable systems | Data strategy, infrastructure vision, governance |
| **Programming & Tools** | Python/R proficiency, visualization | Advanced programming, tool integration | Software engineering, system design | Technology strategy, platform development, innovation |
| **Domain Expertise** | Business understanding, metric interpretation | Domain modeling, insight generation | Strategic analysis, business integration | Market expertise, competitive intelligence, thought leadership |
### Impact & Leadership Competencies
| Competency | Junior DS (L1-L2) | Mid DS (L3-L4) | Senior DS (L5-L6) | Principal DS (L7+) |
|------------|-------------------|----------------|-------------------|-------------------|
| **Business Impact** | Metric improvement, insight delivery | Project leadership, business case development | Strategic initiatives, P&L impact | Business transformation, market advantage, innovation |
| **Communication** | Technical reporting, visualization | Stakeholder presentations, executive briefings | Board communication, external representation | Industry leadership, thought leadership, market influence |
| **Team Leadership** | Peer collaboration, knowledge sharing | Junior mentoring, project management | Team building, hiring, culture development | Organizational leadership, talent strategy, vision setting |
| **Innovation & Research** | Algorithm implementation, experimentation | Research projects, publication | Research strategy, academic partnerships | Research vision, industry influence, breakthrough innovation |
## DevOps Engineering Competency Matrix
### Technical Competencies
| Competency | Junior DevOps (L1-L2) | Mid DevOps (L3-L4) | Senior DevOps (L5-L6) | Principal DevOps (L7+) |
|------------|----------------------|-------------------|----------------------|----------------------|
| **Infrastructure** | Basic cloud services, server management | Infrastructure automation, containerization | Platform architecture, multi-cloud strategy | Infrastructure vision, emerging technologies, industry standards |
| **CI/CD & Automation** | Pipeline basics, script writing | Advanced pipelines, deployment automation | Platform design, workflow optimization | Automation strategy, developer experience, productivity platforms |
| **Monitoring & Observability** | Basic monitoring, log analysis | Advanced monitoring, alerting systems | Observability strategy, SLA/SLI design | Monitoring vision, reliability engineering, performance culture |
| **Security & Compliance** | Security basics, access management | Security automation, compliance frameworks | Security architecture, risk management | Security strategy, governance, industry leadership |
| **Performance & Scalability** | Performance monitoring, basic optimization | Capacity planning, performance tuning | Scalability architecture, cost optimization | Performance strategy, efficiency platforms, innovation |
### Leadership & Impact Competencies
| Competency | Junior DevOps (L1-L2) | Mid DevOps (L3-L4) | Senior DevOps (L5-L6) | Principal DevOps (L7+) |
|------------|----------------------|-------------------|----------------------|----------------------|
| **Developer Experience** | Tool support, documentation | Platform development, self-service tools | Developer productivity, workflow design | Developer platform vision, industry best practices |
| **Incident Management** | Incident response, troubleshooting | Incident coordination, root cause analysis | Incident strategy, prevention systems | Reliability culture, organizational resilience |
| **Team Collaboration** | Cross-team support, knowledge sharing | Process improvement, training delivery | Culture building, practice evangelism | Organizational transformation, industry influence |
| **Strategic Impact** | Operational excellence, cost awareness | Efficiency improvements, platform adoption | Strategic initiatives, business enablement | Technology strategy, competitive advantage, market leadership |
## Engineering Management Competency Matrix
### People Leadership Competencies
| Competency | Manager (L1-L2) | Senior Manager (L3-L4) | Director (L5-L6) | VP+ (L7+) |
|------------|-----------------|------------------------|------------------|----------|
| **Team Building** | Hiring, onboarding, 1:1s | Team culture, performance management | Multi-team coordination, org design | Organizational culture, talent strategy |
| **Performance Management** | Individual development, feedback | Performance systems, coaching | Calibration across teams, promotion standards | Talent development, succession planning |
| **Communication** | Team updates, stakeholder management | Executive communication, cross-functional alignment | Board updates, external communication | Industry representation, thought leadership |
| **Conflict Resolution** | Team conflicts, process improvements | Cross-team issues, organizational friction | Strategic alignment, cultural challenges | Corporate-level conflicts, crisis management |
### Technical Leadership Competencies
| Competency | Manager (L1-L2) | Senior Manager (L3-L4) | Director (L5-L6) | VP+ (L7+) |
|------------|-----------------|------------------------|------------------|----------|
| **Technical Vision** | Team technical decisions, architecture input | Platform strategy, technology choices | Technical roadmap, innovation strategy | Technology vision, industry standards |
| **System Ownership** | Feature/service ownership, quality standards | Platform ownership, scalability planning | System portfolio, technical debt management | Technology strategy, competitive advantage |
| **Process & Practice** | Team processes, development practices | Engineering standards, quality systems | Process innovation, best practices | Engineering culture, industry influence |
| **Technology Strategy** | Tool evaluation, team technology choices | Platform decisions, technical investments | Technology portfolio, strategic architecture | Corporate technology strategy, market leadership |
## Usage Guidelines
### Assessment Approach
1. **Level Calibration**: Use these matrices to calibrate expectations for each level within your organization
2. **Interview Design**: Select competencies most relevant to the specific role and level being hired for
3. **Evaluation Consistency**: Ensure all interviewers understand and apply the same competency standards
4. **Growth Planning**: Use matrices for career development and promotion discussions
### Customization Tips
1. **Industry Adaptation**: Modify competencies based on your industry (fintech, healthcare, etc.)
2. **Company Stage**: Adjust expectations based on startup vs. enterprise environment
3. **Team Needs**: Emphasize competencies most critical for current team challenges
4. **Cultural Fit**: Add company-specific values and cultural competencies
### Common Pitfalls
1. **Unrealistic Expectations**: Don't expect senior-level competencies from junior candidates
2. **One-Size-Fits-All**: Customize competency emphasis based on role requirements
3. **Static Assessment**: Regularly update matrices based on changing business needs
4. **Bias Introduction**: Ensure competencies are measurable and don't introduce unconscious bias
## Matrix Validation Process
### Regular Review Cycle
- **Quarterly**: Review competency relevance and adjust weights
- **Semi-annually**: Update level expectations based on market standards
- **Annually**: Comprehensive review with stakeholder feedback
### Stakeholder Input
- **Hiring Managers**: Validate role-specific competency requirements
- **Current Team Members**: Confirm level expectations match reality
- **Recent Hires**: Gather feedback on assessment accuracy
- **HR Partners**: Ensure legal compliance and bias mitigation
### Continuous Improvement
- **Performance Correlation**: Track new hire performance against competency assessments
- **Market Benchmarking**: Compare standards with industry peers
- **Feedback Integration**: Incorporate interviewer and candidate feedback
- **Bias Monitoring**: Regular analysis of assessment patterns across demographics
FILE:references/debrief_facilitation_guide.md
# Interview Debrief Facilitation Guide
This guide provides a comprehensive framework for conducting effective, unbiased interview debriefs that lead to consistent hiring decisions. Use this to facilitate productive discussions that focus on evidence-based evaluation.
## Pre-Debrief Preparation
### Facilitator Responsibilities
- [ ] **Review all interviewer feedback** before the meeting
- [ ] **Identify significant score discrepancies** that need discussion
- [ ] **Prepare discussion agenda** with time allocations
- [ ] **Gather role requirements** and competency framework
- [ ] **Review any flags or special considerations** noted during interviews
- [ ] **Ensure all required materials** are available (scorecards, rubrics, candidate resume)
- [ ] **Set up meeting logistics** (room, video conference, screen sharing)
- [ ] **Send agenda to participants** 30 minutes before meeting
### Required Materials Checklist
- [ ] Candidate resume and application materials
- [ ] Job description and competency requirements
- [ ] Individual interviewer scorecards
- [ ] Scoring rubrics and competency definitions
- [ ] Interview notes and documentation
- [ ] Any technical assessments or work samples
- [ ] Company hiring standards and calibration examples
- [ ] Bias mitigation reminders and prompts
### Participant Preparation Requirements
- [ ] All interviewers must **complete independent scoring** before debrief
- [ ] **Submit written feedback** with specific evidence for each competency
- [ ] **Review scoring rubrics** to ensure consistent interpretation
- [ ] **Prepare specific examples** to support scoring decisions
- [ ] **Flag any concerns or unusual circumstances** that affected assessment
- [ ] **Avoid discussing candidate** with other interviewers before debrief
- [ ] **Come prepared to defend scores** with concrete evidence
- [ ] **Be ready to adjust scores** based on additional evidence shared
## Debrief Meeting Structure
### Opening (5 minutes)
1. **State meeting purpose**: Make hiring decision based on evidence
2. **Review agenda and time limits**: Keep discussion focused and productive
3. **Remind of bias mitigation principles**: Focus on competencies, not personality
4. **Confirm confidentiality**: Discussion stays within hiring team
5. **Establish ground rules**: One person speaks at a time, evidence-based discussion
### Individual Score Sharing (10-15 minutes)
- **Go around the room systematically** - each interviewer shares scores independently
- **No discussion or challenges yet** - just data collection
- **Record scores on shared document** visible to all participants
- **Note any abstentions** or "insufficient data" responses
- **Identify clear patterns** and discrepancies without commentary
- **Flag any scores requiring explanation** (1s or 4s typically need strong evidence)
### Competency-by-Competency Discussion (30-40 minutes)
#### For Each Core Competency:
**1. Present Score Distribution (2 minutes)**
- Display all scores for this competency
- Note range and any outliers
- Identify if consensus exists or discussion needed
**2. Evidence Sharing (5-8 minutes per competency)**
- Start with interviewers who assessed this competency directly
- Share specific examples and observations
- Focus on what candidate said/did, not interpretations
- Allow questions for clarification (not challenges yet)
**3. Discussion and Calibration (3-5 minutes)**
- Address significant discrepancies (>1 point difference)
- Challenge vague or potentially biased language
- Seek additional evidence if needed
- Allow score adjustments based on new information
- Reach consensus or note dissenting views
#### Structured Discussion Questions:
- **"What specific evidence supports this score?"**
- **"Can you provide the exact example or quote?"**
- **"How does this compare to our rubric definition?"**
- **"Would this response receive the same score regardless of who gave it?"**
- **"Are we evaluating the competency or making assumptions?"**
- **"What would need to change for this to be the next level up/down?"**
### Overall Recommendation Discussion (10-15 minutes)
#### Weighted Score Calculation
1. **Apply competency weights** based on role requirements
2. **Calculate overall weighted average**
3. **Check minimum threshold requirements**
4. **Consider any veto criteria** (critical competency failures)
#### Final Recommendation Options
- **Strong Hire**: Exceeds requirements in most areas, clear value-add
- **Hire**: Meets requirements with growth potential
- **No Hire**: Doesn't meet minimum requirements for success
- **Strong No Hire**: Significant gaps that would impact team/company
#### Decision Rationale Documentation
- **Summarize key strengths** with specific evidence
- **Identify development areas** with specific examples
- **Explain final recommendation** with competency-based reasoning
- **Note any dissenting opinions** and reasoning
- **Document onboarding considerations** if hiring
### Closing and Next Steps (5 minutes)
- **Confirm final decision** and documentation
- **Assign follow-up actions** (feedback delivery, offer preparation, etc.)
- **Schedule any additional interviews** if needed
- **Review timeline** for candidate communication
- **Remind confidentiality** of discussion and decision
## Facilitation Best Practices
### Creating Psychological Safety
- **Encourage honest feedback** without fear of judgment
- **Validate different perspectives** and assessment approaches
- **Address power dynamics** - ensure junior voices are heard
- **Model vulnerability** - admit when evidence changes your mind
- **Focus on learning** and calibration, not winning arguments
- **Thank participants** for thorough preparation and thoughtful input
### Managing Difficult Conversations
#### When Scores Vary Significantly
1. **Acknowledge the discrepancy** without judgment
2. **Ask for specific evidence** from each scorer
3. **Look for different interpretations** of the same data
4. **Consider if different questions** revealed different competency levels
5. **Check for bias patterns** in reasoning
6. **Allow time for reflection** and potential score adjustments
#### When Someone Uses Biased Language
1. **Pause the conversation** gently but firmly
2. **Ask for specific evidence** behind the assessment
3. **Reframe in competency terms** - "What specific skills did this demonstrate?"
4. **Challenge assumptions** - "Help me understand how we know that"
5. **Redirect to rubric** - "How does this align with our scoring criteria?"
6. **Document and follow up** privately if bias persists
#### When the Discussion Gets Off Track
- **Redirect to competencies**: "Let's focus on the technical skills demonstrated"
- **Ask for evidence**: "What specific example supports that assessment?"
- **Reference rubrics**: "How does this align with our level 3 definition?"
- **Manage time**: "We have 5 minutes left on this competency"
- **Table unrelated issues**: "That's important but separate from this hire decision"
### Encouraging Evidence-Based Discussion
#### Good Evidence Examples
- **Direct quotes**: "When asked about debugging, they said..."
- **Specific behaviors**: "They organized their approach by first..."
- **Observable outcomes**: "Their code compiled on first run and handled edge cases"
- **Process descriptions**: "They walked through their problem-solving step by step"
- **Measurable results**: "They identified 3 optimization opportunities"
#### Poor Evidence Examples
- **Gut feelings**: "They just seemed off"
- **Comparisons**: "Not as strong as our last hire"
- **Assumptions**: "Probably wouldn't fit our culture"
- **Vague impressions**: "Didn't seem passionate"
- **Irrelevant factors**: "Their background is different from ours"
### Managing Group Dynamics
#### Ensuring Equal Participation
- **Direct questions** to quieter participants
- **Prevent interrupting** and ensure everyone finishes thoughts
- **Balance speaking time** across all interviewers
- **Validate minority opinions** even if not adopted
- **Check for unheard perspectives** before finalizing decisions
#### Handling Strong Personalities
- **Set time limits** for individual speaking
- **Redirect monopolizers**: "Let's hear from others on this"
- **Challenge confidently stated opinions** that lack evidence
- **Support less assertive voices** in expressing dissenting views
- **Focus on data**, not personality or seniority in decision making
## Bias Interruption Strategies
### Affinity Bias Interruption
- **Notice pattern**: Positive assessment seems based on shared background/interests
- **Interrupt with**: "Let's focus on the job-relevant skills they demonstrated"
- **Redirect to**: Specific competency evidence and measurable outcomes
- **Document**: Note if personal connection affected professional assessment
### Halo/Horn Effect Interruption
- **Notice pattern**: One area strongly influencing assessment of unrelated areas
- **Interrupt with**: "Let's score each competency independently"
- **Redirect to**: Specific evidence for each individual competency area
- **Recalibrate**: Ask for separate examples supporting each score
### Confirmation Bias Interruption
- **Notice pattern**: Only seeking/discussing evidence that supports initial impression
- **Interrupt with**: "What evidence might suggest a different assessment?"
- **Redirect to**: Consider alternative interpretations of the same data
- **Challenge**: "How might we be wrong about this assessment?"
### Attribution Bias Interruption
- **Notice pattern**: Attributing success to luck/help for some demographics, skill for others
- **Interrupt with**: "What role did the candidate play in achieving this outcome?"
- **Redirect to**: Candidate's specific contributions and decision-making
- **Standardize**: Apply same attribution standards across all candidates
## Decision Documentation Framework
### Required Documentation Elements
1. **Final scores** for each assessed competency
2. **Overall recommendation** with supporting rationale
3. **Key strengths** with specific evidence
4. **Development areas** with specific examples
5. **Dissenting opinions** if any, with reasoning
6. **Special considerations** or accommodation needs
7. **Next steps** and timeline for decision communication
### Evidence Quality Standards
- **Specific and observable**: What exactly did the candidate do or say?
- **Job-relevant**: How does this relate to success in the role?
- **Measurable**: Can this be quantified or clearly described?
- **Unbiased**: Would this evidence be interpreted the same way regardless of candidate demographics?
- **Complete**: Does this represent the full picture of their performance in this area?
### Writing Guidelines
- **Use active voice** and specific language
- **Avoid assumptions** about motivations or personality
- **Focus on behaviors** demonstrated during the interview
- **Provide context** for any unusual circumstances
- **Be constructive** in describing development areas
- **Maintain professionalism** and respect for candidate
## Common Debrief Challenges and Solutions
### Challenge: "I just don't think they'd fit our culture"
**Solution**:
- Ask for specific, observable evidence
- Define what "culture fit" means in job-relevant terms
- Challenge assumptions about cultural requirements
- Focus on ability to collaborate and contribute effectively
### Challenge: Scores vary widely with no clear explanation
**Solution**:
- Review if different interviewers assessed different competencies
- Look for question differences that might explain variance
- Consider if candidate performance varied across interviews
- May need additional data gathering or interview
### Challenge: Everyone loved/hated the candidate but can't articulate why
**Solution**:
- Push for specific evidence supporting emotional reactions
- Review competency rubrics together
- Look for halo/horn effects influencing overall impression
- Consider unconscious bias training for team
### Challenge: Technical vs. non-technical interviewers disagree
**Solution**:
- Clarify which competencies each interviewer was assessing
- Ensure technical assessments carry appropriate weight
- Look for different perspectives on same evidence
- Consider specialist input for technical decisions
### Challenge: Senior interviewer dominates decision making
**Solution**:
- Structure discussion to hear from all levels first
- Ask direct questions to junior interviewers
- Challenge opinions that lack supporting evidence
- Remember that assessment ability doesn't correlate with seniority
### Challenge: Team wants to hire but scores don't support it
**Solution**:
- Review if rubrics match actual job requirements
- Check for consistent application of scoring standards
- Consider if additional competencies need assessment
- May indicate need for rubric calibration or role requirement review
## Post-Debrief Actions
### Immediate Actions (Same Day)
- [ ] **Finalize decision documentation** with all evidence
- [ ] **Communicate decision** to recruiting team
- [ ] **Schedule candidate feedback** delivery if applicable
- [ ] **Update interview scheduling** based on decision
- [ ] **Note any process improvements** needed for future
### Follow-up Actions (Within 1 Week)
- [ ] **Deliver candidate feedback** (internal or external)
- [ ] **Update interview feedback** in tracking system
- [ ] **Schedule any additional interviews** if needed
- [ ] **Begin offer process** if hiring
- [ ] **Document lessons learned** for process improvement
### Long-term Actions (Monthly/Quarterly)
- [ ] **Analyze debrief effectiveness** and decision quality
- [ ] **Review interviewer calibration** based on decisions
- [ ] **Update rubrics** based on debrief insights
- [ ] **Provide additional training** if bias patterns identified
- [ ] **Share successful practices** with other hiring teams
## Continuous Improvement Framework
### Debrief Effectiveness Metrics
- **Decision consistency**: Are similar candidates receiving similar decisions?
- **Time to decision**: Are debriefs completing within planned time?
- **Participation quality**: Are all interviewers contributing evidence-based input?
- **Bias incidents**: How often are bias interruptions needed?
- **Decision satisfaction**: Do participants feel good about the process and outcome?
### Regular Review Process
- **Monthly**: Review debrief facilitation effectiveness and interviewer feedback
- **Quarterly**: Analyze decision patterns and potential bias indicators
- **Semi-annually**: Update debrief processes based on hiring outcome data
- **Annually**: Comprehensive review of debrief framework and training needs
### Training and Calibration
- **New facilitators**: Shadow 3-5 debriefs before leading independently
- **All facilitators**: Quarterly calibration sessions on bias interruption
- **Interviewer training**: Include debrief participation expectations
- **Leadership training**: Ensure hiring managers can facilitate effectively
This guide should be adapted to your organization's specific needs while maintaining focus on evidence-based, unbiased decision making.
FILE:references/interview-frameworks.md
# Interview Frameworks
## Loop Design by Level
### Junior/Mid
- Emphasize fundamentals, debugging, and growth potential.
- Keep loops concise with coding + behavioral validation.
### Senior
- Add system design and leadership rounds.
- Evaluate tradeoff quality, mentoring, and cross-team collaboration.
### Staff+
- Focus on architecture direction and organizational impact.
- Assess strategy, influence, and long-term technical judgment.
## Competency Areas
- Technical depth (implementation, design, quality)
- Problem solving (ambiguity handling, prioritization)
- Collaboration (communication, stakeholder alignment)
- Leadership (ownership, mentoring, influence)
## Scoring Rubric Baseline
- `4`: exceeds level expectations with strong evidence
- `3`: meets expectations consistently
- `2`: partial signal with notable gaps
- `1`: does not meet baseline requirements
## Calibration Guidelines
- Run recurring interviewer calibration sessions.
- Compare interviewer scoring variance across rounds.
- Track interview signal against new-hire outcomes.
- Use structured debriefs with independent scoring before discussion.
## Bias-Reduction Baseline
- Standardize question banks per competency area.
- Keep scorecards evidence-based and behavior-specific.
- Use diverse interviewer panels where possible.
- Require written rationale for strong yes/no recommendations.
FILE:scripts/interview_planner.py
#!/usr/bin/env python3
"""Generate an interview loop plan by role and level."""
from __future__ import annotations
import argparse
import json
from typing import Dict, List
BASE_ROUNDS = {
"junior": [
("Screen", 45, "Fundamentals and communication"),
("Coding", 60, "Problem solving and code quality"),
("Behavioral", 45, "Collaboration and growth mindset"),
],
"mid": [
("Screen", 45, "Fundamentals and ownership"),
("Coding", 60, "Implementation quality"),
("System Design", 60, "Service/component design"),
("Behavioral", 45, "Stakeholder collaboration"),
],
"senior": [
("Screen", 45, "Depth and tradeoff reasoning"),
("Coding", 60, "Code quality and testing"),
("System Design", 75, "Scalability and reliability"),
("Leadership", 60, "Mentoring and decision making"),
("Behavioral", 45, "Cross-functional influence"),
],
"staff": [
("Screen", 45, "Strategic and technical depth"),
("Architecture", 90, "Org-level design decisions"),
("Technical Strategy", 60, "Long-term tradeoffs"),
("Influence", 60, "Cross-team leadership"),
("Behavioral", 45, "Values and executive communication"),
],
}
QUESTION_BANK = {
"coding": [
"Walk through your approach before coding and identify tradeoffs.",
"How would you test this implementation for edge cases?",
"What would you refactor if this code became a shared library?",
],
"system": [
"Design this system for 10x traffic growth in 12 months.",
"Where are the main failure modes and how would you detect them?",
"What components would you scale first and why?",
],
"leadership": [
"Describe a time you changed technical direction with incomplete information.",
"How do you raise the bar for code quality across a team?",
"How do you handle disagreement between product and engineering priorities?",
],
"behavioral": [
"Tell me about a high-stakes mistake and what changed afterward.",
"Describe a conflict where you had to influence without authority.",
"How do you support underperforming teammates?",
],
}
def normalize_level(level: str) -> str:
level = level.strip().lower()
if level in {"staff+", "principal", "lead"}:
return "staff"
if level not in BASE_ROUNDS:
raise ValueError(f"Unsupported level: {level}")
return level
def suggested_questions(round_name: str) -> List[str]:
name = round_name.lower()
if "coding" in name:
return QUESTION_BANK["coding"]
if "system" in name or "architecture" in name:
return QUESTION_BANK["system"]
if "lead" in name or "influence" in name or "strategy" in name:
return QUESTION_BANK["leadership"]
return QUESTION_BANK["behavioral"]
def generate_plan(role: str, level: str) -> Dict[str, object]:
normalized = normalize_level(level)
rounds = []
for idx, (name, minutes, focus) in enumerate(BASE_ROUNDS[normalized], start=1):
rounds.append(
{
"round": idx,
"name": name,
"duration_minutes": minutes,
"focus": focus,
"suggested_questions": suggested_questions(name),
}
)
return {
"role": role,
"level": normalized,
"total_rounds": len(rounds),
"total_minutes": sum(r["duration_minutes"] for r in rounds),
"rounds": rounds,
}
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Generate an interview loop plan for a role and level.")
parser.add_argument("--role", required=True, help="Role name (e.g., Senior Software Engineer)")
parser.add_argument("--level", required=True, help="Level: junior|mid|senior|staff")
parser.add_argument("--json", action="store_true", help="Output as JSON")
return parser.parse_args()
def main() -> int:
args = parse_args()
plan = generate_plan(args.role, args.level)
if args.json:
print(json.dumps(plan, indent=2))
else:
print(f"Interview Plan: {plan['role']} ({plan['level']})")
print(f"Total rounds: {plan['total_rounds']} | Total time: {plan['total_minutes']} minutes")
print("")
for r in plan["rounds"]:
print(f"Round {r['round']}: {r['name']} ({r['duration_minutes']} min)")
print(f"Focus: {r['focus']}")
for q in r["suggested_questions"]:
print(f"- {q}")
print("")
return 0
if __name__ == "__main__":
raise SystemExit(main())
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()
Chuẩn bị đánh giá QMS theo ISO 13485 bằng 6 câu hỏi chất vấn, tập trung kiểm soát thiết kế, CAPA và giám sát sau thị trường.
--- name: "iso13485-audit-prep" description: "/cs:iso13485-audit-prep <scope> — ISO 13485 QMS audit 6-question forcing interrogation. Design controls + CAPA + post-market focused. Use before Clause 8.2.4 internal audit, MDR / FDA QSR alignment review, or product-launch DHF closure audit." --- # /cs:iso13485-audit-prep — ISO 13485 QMS Forcing Questions **Command:** `/cs:iso13485-audit-prep <scope>` The ISO 13485 QMS auditor pressure-tests any medical-device QMS work. Six traceability-obsessed questions before any internal audit, MDR / FDA QSR review, or product launch. ## When to Run - Before annual Clause 8.2.4 internal audit - Before MDR / FDA QSR alignment review (substantially harmonized post Feb 2026) - Before new-device commercial launch (DHF closure audit) - After significant CAPA closure event (effectiveness verification audit) - Post-recall event (root cause + corrective action audit) - Quarterly during regulatory submission preparation ## The Six QMS Questions ### 1. Pull three random DHFs. Are design verification + validation evidence complete? **Most-cited finding area.** - DHF must include: design plan + inputs + outputs + verification + validation + transfer + changes - Sample stratified by product class (I, IIa, IIb, III per MDR) - Reference `iso13485_audit_playbook.md` for the per-DHF checklist - Verify traceability matrix from user needs through clinical evidence ### 2. Show me the last 5 CAPAs with effectiveness verification evidence. **Second-most-cited finding area.** - Containment / correction / corrective action distinction documented - Root cause analysis depth: 5 Why minimum - Effectiveness verification = measurable evidence, not "we updated the procedure" - Closure approved by appropriate authority - Repeat CAPAs across products = systemic issue trigger ### 3. When was process validation (IQ/OQ/PQ) last revalidated? **Clause 7.5.6 — often stale.** - Initial validation at process introduction - Revalidation triggers: process change, equipment change, material change, periodic schedule - Trend monitoring (SPC) where statistical techniques apply per Clause 8.4 - Cross-check with cs-fda-qsr-auditor for 21 CFR 820.75 alignment ### 4. Show me the risk management file for the highest-risk product. **Clause 7.1 + ISO 14971:2019.** - Risk management plan exists per product - Hazard identification covers reasonable foreseeable misuse - Risk control hierarchy applied: inherent safety > protective measures > information for safety - Residual risk evaluated + accepted with rationale - Post-production information feeds back into RMF - For AI-enabled medical devices: layer ISO 42001 A.5 impact assessment on top ### 5. Show me post-market surveillance evidence — last 6 months. **Clause 8.2.1 — high-stakes for MDR + FDA.** - Customer complaint log + investigation closure - Vigilance reports (serious incident / FSCA) submitted per applicable regulation - Trend analysis evidence + management review input - Post-market clinical follow-up (PMCF) for MDR high-risk devices - MDR reports per 21 CFR 803 for US-marketed devices (cross-check with cs-fda-qsr-auditor) ### 6. Where's the management review evidence covering all Clause 5.6 inputs? **Annual minimum; semi-annual for mature programs.** - Required inputs per Clause 5.6.2: audit results, customer feedback, process performance, product conformity, status of preventive + corrective actions, follow-up from prior reviews, changes that could affect QMS, recommendations for improvement, regulatory requirements - Outputs per Clause 5.6.3: improvement decisions, product requirement changes, resource needs - Integrated review across frameworks (per `multi_framework_audit_playbook.md`) preferred ## Workflow ```bash # 1. Audit programme optimization python ../../ra-qm-team/skills/qms-audit-expert/scripts/audit_schedule_optimizer.py audit_scope.json # 2. Mock audit for readiness check python ../../skills/compliance-os/scripts/audit_simulator.py iso13485_scope.json # 3. CAPA system review # Route to ra-qm-team/skills/capa-officer/ tools # 4. Risk management file review # Route to ra-qm-team/skills/risk-management-specialist/ tools ``` ## Output Format ```markdown # ISO 13485 Audit Prep: <scope> **Date:** YYYY-MM-DD ## The Decision Being Made [programme-plan | DHF-closure | CAPA-health | post-market-trend | pre-cert | MDR-FDA-alignment] ## Design Control Status (sampled DHFs) - DHFs sampled: <list product IDs> - Verification evidence: pass/fail per DHF - Validation evidence: pass/fail per DHF - Clinical evidence (per MDR Annex XIV / FDA 510(k)): pass/fail - Traceability matrix complete: yes/no per DHF ## CAPA Health - CAPAs sampled: N - Root cause analysis depth: adequate/inadequate per CAPA - Effectiveness verification: complete/incomplete per CAPA - Aging CAPAs > 90 days: N - Repeat issues across products: <list> ## Process Validation Status - Validations on schedule: % - Stale validations (> 12 months since revalidation): <list> - Statistical techniques applied per Clause 8.4: yes/no ## Risk Management File Status - Sampled product RMFs: <list> - Post-production updates in last 12 months: <count per product> - Residual risk acceptance signed: yes/no ## Post-Market Surveillance - Complaint trending: stable/rising - MDR / vigilance reports filed timely: % - PMCF on schedule (where required): yes/no ## Management Review Status - Last review date: YYYY-MM-DD - Required Clause 5.6.2 inputs present: yes/no - Open action items past due: N ## Cross-Framework Impact - EU MDR alignment: clean / gaps in <list> - FDA QSR alignment (post-Feb 2026): substantially harmonized; FDA-specific overlays per cs-fda-qsr-auditor - ISO 42001 AIMS overlay (if AI-enabled device): pass/fail per Annex A ## Verdict 🟢 READY | 🟡 CLOSE-DHF-GAPS-FIRST | 🔴 NOT-READY ## Top 3 Actions [3 concrete next steps with owner + corrective-action timeline] ``` ## Routing - `/cs:compliance-readiness` — for multi-framework view - `/cs:fda-qsr-audit-prep` — for FDA-specific overlay - `/cs:aims-audit` — for AI-enabled medical device ISO 42001 layer - `/cs:gdpr-audit-prep` — for personal-data overlap (clinical data, customer data) - `/cs:cpo-review` — for executive product strategy decisions - `/cs:decide` — to log the verdict ## Related - Agent: [`cs-cqm-iso13485`](../../agents/cs-cqm-iso13485.md) - Skill: [`qms-audit-expert`](../../../ra-qm-team/skills/qms-audit-expert/SKILL.md) - Playbook: [iso13485_audit_playbook.md](../../../ra-qm-team/skills/qms-audit-expert/references/iso13485_audit_playbook.md) - Adjacent: `../fda-qsr-audit-prep/`, `../aims-audit/`, `../compliance-readiness/` --- **Version:** 1.0.0
Đánh giá mức sẵn sàng ISMS theo ISO 27001 bằng 6 câu hỏi chất vấn, dùng trước đánh giá nội bộ, đánh giá giám sát hoặc chứng nhận giai đoạn 1.
--- name: "iso27001-audit-prep" description: "/cs:iso27001-audit-prep <scope> — ISO 27001 ISMS audit readiness 6-question forcing interrogation. Use before annual Clause 9.2 internal audit, surveillance audit prep, or stage 1 certification readiness." --- # /cs:iso27001-audit-prep — ISO 27001 ISMS Audit Forcing Questions **Command:** `/cs:iso27001-audit-prep <scope>` The ISO 27001 ISMS auditor pressure-tests any ISMS work. Six sample-driven questions before any internal audit, stage 1 readiness, or surveillance audit. ## When to Run - Before annual Clause 9.2 internal audit - Before stage 1 / stage 2 ISO 27001 certification audit - Before surveillance audit (year 2 / year 3) - After material change to ISMS scope (new business unit, new product line, new SaaS adoption) - Post-incident (breach triggers ad-hoc ISMS audit) - Quarterly during high-growth phase ## The Six ISMS Questions ### 1. What's the audit scope, and is rolling 3-year coverage on track? **No 3-year coverage discipline, no defensible programme.** - Every Clause 4-10 + every applicable Annex A control must be audited at least once per 3-year cycle - Run `isms_audit_scheduler.py` in `ra-qm-team/skills/isms-audit-expert/` - Confirm auditor independence — no self-audit on any sample ### 2. When was the risk register last refreshed, and are treatments linked to Annex A controls? **Stale risk register = certification finding.** - Quarterly refresh expected; annual minimum - Every high/critical risk must link to ≥ 1 Annex A control treating it - Residual risk acceptance documented + signed - Review against `iso27001_audit_playbook.md` for stage 1 expectations ### 3. Show me the access review records — quarterly cadence, the last 4 quarters. **Most-cited finding area.** - Annex A.5.15 + A.8.2 + A.8.3 access controls - Sample real records pulled from Okta / IAM, not curated audit-prep packs - For each terminated employee in last 90 days: deprovisioning evidence within 24-hour SLA - Privileged access reviewed at finer granularity ### 4. What's the supplier inventory + last review evidence? **Second-most-cited finding area.** - Annex A.5.19-A.5.21 supplier management - Critical SaaS suppliers reviewed at least annually - DPAs signed for personal-data sub-processors (cross-check with cs-dpo-gdpr) - AI-specific contract clauses where third-party AI services in use (cross-check with cs-aims-iso42001) ### 5. Where's the incident response evidence + post-incident review? **A.5.24-27 + A.6.8 — high-stakes audit area.** - Severity definitions documented + consistently applied - Last 5 incidents have post-incident review (PIR) within 30-day SLA - GDPR Article 33 / 34 notification timing aligned with A.5.24 (cross-check with cs-dpo-gdpr) - Blameless retro culture; not punitive ### 6. What's the management review cadence + inputs? **Clause 9.3 required inputs are prescriptive — easy to miss.** - Required inputs: audit results, risks, performance, nonconformities, opportunities - Schedule: annual minimum; quarterly preferred for mature programs - Outputs documented + tracked to closure - Integrated review across frameworks (per `multi_framework_audit_playbook.md`) preferred to separate reviews ## Workflow ```bash # 1. Audit programme planning python ../../ra-qm-team/skills/isms-audit-expert/scripts/isms_audit_scheduler.py audit_scope.json # 2. Mock audit for readiness check python ../../skills/compliance-os/scripts/audit_simulator.py iso27001_scope.json # 3. Cross-framework reuse (SOC 2 = 75% overlap; ISO 42001 = 60% reuse) python ../../skills/compliance-os/scripts/cross_framework_mapper.py program.json ``` ## Output Format ```markdown # ISO 27001 Audit Prep: <scope> **Date:** YYYY-MM-DD ## The Decision Being Made [programme-plan | finding-severity | cert-readiness | incident-followup] ## Audit Programme Status - Clauses scheduled this year: <list> - Annex A controls scheduled: <count> - Rolling 3-year coverage: clean | gaps in <list> - Auditor independence: clean | issues in <list> ## Risk Register Health - Last refresh: YYYY-MM-DD - High/critical risks without Annex A control link: N - Residual risk acceptance documentation: complete | gaps ## High-Stakes Controls Status - A.5.15 + A.8.2 + A.8.3 access control: pass/fail with sample - A.5.19-A.5.21 supplier mgmt: pass/fail with sample - A.5.24-27 + A.6.8 incident response: pass/fail with sample - A.8.15-16 logging: pass/fail with sample ## Management Review Status - Last review date: YYYY-MM-DD - Required Article 9.3 inputs present: yes/no - Open action items past due: N ## Cross-Framework Impact - SOC 2 controls affected: <list> - ISO 42001 controls affected (if applicable): <list> - GDPR Article 32 controls affected: <list> ## Verdict 🟢 READY | 🟡 CLOSE-CRITICALS-FIRST | 🔴 NOT-READY ## Top 3 Actions [3 concrete next steps with owner + corrective-action timeline] ``` ## Routing - `/cs:compliance-readiness` — for multi-framework view - `/cs:soc2-audit-prep` — for SOC 2 cross-walk pair (75% overlap) - `/cs:aims-audit` — for ISO 42001 AIMS cross-walk - `/cs:gdpr-audit-prep` — for Article 32 organizational measures overlap - `/cs:ciso-review` — for executive cybersecurity strategy - `/cs:decide` — to log the verdict ## Related - Agent: [`cs-ciso-iso27001`](../../agents/cs-ciso-iso27001.md) - Skill: [`isms-audit-expert`](../../../ra-qm-team/skills/isms-audit-expert/SKILL.md) - Playbook: [iso27001_audit_playbook.md](../../../ra-qm-team/skills/isms-audit-expert/references/iso27001_audit_playbook.md) - Adjacent: `../soc2-audit-prep/`, `../aims-audit/`, `../gdpr-audit-prep/`, `../compliance-readiness/` --- **Version:** 1.0.0
Hỗ trợ đánh giá nội bộ hệ thống quản lý AI theo ISO/IEC 42001: xác định khoảng cách theo Điều khoản 4-10, sổ đăng ký rủi ro AI và kiểm soát Annex A.
---
name: "iso42001-specialist"
description: "ISO/IEC 42001:2023 AI Management System (AIMS) specialist for compliance teams running internal audits. Three decisions: (1) Where are the gaps against Clauses 4-10 and what do we close first? (2) What goes in the AI risk register and which Annex A controls treat each risk? (3) What's the 12-month internal audit plan that satisfies Clause 9.2? Use when preparing for certification, scoping internal audit cycles, or onboarding AI systems into an existing ISMS (27001) / QMS (13485) program. NOT an executive AI strategy skill (see chief-ai-officer-advisor). NOT EU AI Act compliance (see compliance-team-eu-ai-act)."
license: MIT
metadata:
version: 1.0.0
author: Alireza Rezvani
category: ra-qm-team
domain: ai-management-system-compliance
updated: 2026-05-13
python-tools: aims_gap_analyzer.py, ai_risk_register_builder.py, aims_audit_scheduler.py
frameworks: iso-42001, iso-23894, iso-38507, nist-ai-rmf, eu-ai-act-mapping
---
# ISO/IEC 42001 AI Management System Specialist
Internal-audit-grade operating skill for ISO/IEC 42001:2023. **Three decisions, no executive AI strategy:**
1. **Where are the AIMS gaps against Clauses 4–10?** — coverage scoring per clause + remediation priority
2. **What's the AI risk register, and which controls treat each risk?** — Annex A.2–A.10 control mapping per ISO 23894 risk method
3. **What's the Clause 9.2 internal audit plan?** — 12-month schedule with scope, frequency, auditor independence checks
This skill is **NOT a chief-ai-officer-advisor replacement**. CAIO decides whether to build/buy a model and what business risk to accept. This skill operates the management-system discipline that captures those decisions in audit-ready evidence.
This skill is **NOT an EU AI Act compliance skill**. ISO 42001 is a voluntary management-system standard; EU AI Act is binding product-safety regulation. They overlap (a high-risk AI system per Article 6(2) of the AI Act typically requires the QMS in Article 17, which ISO 42001 can satisfy in part) but the artefacts differ. See `compliance-team-eu-ai-act` for Article-level conformity assessment.
This skill is **NOT a substitute for ISO 23894 + 38507**. 42001 is the management system; 23894 is the AI risk methodology that feeds Clause 6.1; 38507 is the governance lens. The `ai_risk_register_builder.py` tool implements the 23894 process; treat the references as the methodology bridge.
## Keywords
ISO 42001, ISO/IEC 42001:2023, AI Management System, AIMS, AI governance, AI risk management, ISO 23894, AI risk assessment, ISO 38507, AI compliance, AI audit, internal audit AI, Annex A controls, AI risk register, AI policy, AI impact assessment, conformity declaration, AI lifecycle, AI risk treatment, NIST AI RMF, NIST AI Risk Management Framework, ISACA AI audit, BSI AIC4, AI assurance, responsible AI, AI ethics governance, AI system inventory, third-party AI risk, AI vendor management, AI change management, AI incident management
## Quick Start
```bash
# Decision A: AIMS gap analysis against Clauses 4-10
python scripts/aims_gap_analyzer.py # embedded sample (mid-stage AI SaaS)
python scripts/aims_gap_analyzer.py path/to/aims_evidence.json
# Decision B: AI risk register + Annex A control mapping
python scripts/ai_risk_register_builder.py # embedded 7-risk sample
python scripts/ai_risk_register_builder.py path/to/risks.json
# Decision C: Clause 9.2 internal audit 12-month plan
python scripts/aims_audit_scheduler.py # embedded 4-domain sample
python scripts/aims_audit_scheduler.py path/to/scope.json
```
## Key Questions (ask these first)
- **Does the AIMS scope statement (Clause 4.3) name every AI system, including embedded models and third-party AI services?** If "AI features added by our SaaS vendors" is not in scope, the AIMS is incomplete.
- **Does the AI policy (Clause 5.2) commit to lawful use AND beneficial purpose AND human oversight AND continual improvement?** Missing any of the four = nonconformity at certification.
- **Has the AI risk assessment (Clause 6.1.2) been re-run since the last material model change?** Concept drift is not a one-time event.
- **Who signs the AI impact assessment for high-impact systems (Annex A.5.4)?** If no signed accountability, the control is missing.
- **What's the internal audit cadence (Clause 9.2)?** ISO management-system standards expect ≥ once per 3-year cycle per clause; mature programs do annual.
- **Is there a documented procedure for AI incidents (Annex A.9.3)?** Untreated post-deployment monitoring is the #1 nonconformity in early adopters.
## Core Responsibilities
### 1. AIMS Gap Analysis (Clauses 4–10)
**The framework:** ISO 42001 follows the Annex SL high-level structure shared with ISO 9001 / 27001 / 13485. Clauses 4–10 are the management-system requirements; Annex A controls A.1–A.10 are the AI-specific operational controls.
| Clause | What it requires | Common gap |
|---|---|---|
| **4. Context** | AI scope, interested parties, external context | Scope omits third-party AI services |
| **5. Leadership** | AI policy, roles, accountability | Policy treats "AI ethics" as marketing copy, not commitment |
| **6. Planning** | AI risk + impact assessment, objectives | Risk register doesn't link to controls |
| **7. Support** | Resources, competence, awareness, documented info | Competence requirements undefined for ML engineers |
| **8. Operation** | Operational planning, AI system lifecycle | Lifecycle stages not mapped to Annex A controls |
| **9. Performance** | Monitoring, internal audit, management review | Drift monitoring exists in code but not in management review inputs |
| **10. Improvement** | Nonconformity, corrective action, continual improvement | CAPA loop separate from existing 13485/9001 CAPA — duplication |
**Run** `aims_gap_analyzer.py` with an evidence inventory JSON to score each clause (full / partial / missing) and get a prioritized remediation list.
See `references/iso42001_clauses.md` for the full clause-by-clause walkthrough with audit evidence expectations.
### 2. AI Risk Register + Annex A Control Mapping
**The framework:** Clause 6.1.2 requires AI risk assessment; Clause 6.1.3 requires risk treatment. Annex A provides 38 controls organized into 10 control categories (A.2–A.10). The risk register must show each identified risk linked to ≥ 1 control that treats it.
**Annex A control categories (the 10):**
| ID | Category | Example controls |
|---|---|---|
| **A.2** | AI policy | A.2.2 AI policy, A.2.3 alignment with other policies |
| **A.3** | Internal organization | A.3.2 AI roles & responsibilities, A.3.3 reporting concerns |
| **A.4** | Resources for AI systems | A.4.2 data resources, A.4.3 tooling, A.4.4 human resources |
| **A.5** | Assessing impacts | A.5.2 AI system impact assessment, A.5.4 documentation of impact assessment |
| **A.6** | AI system lifecycle | A.6.2.2 objectives, A.6.2.3 lifecycle phases, A.6.2.4 verification & validation |
| **A.7** | Data for AI systems | A.7.2 data management, A.7.3 data quality, A.7.4 data provenance, A.7.5 data preparation |
| **A.8** | Information for interested parties | A.8.2 system documentation, A.8.3 user information, A.8.4 communication of incidents |
| **A.9** | Use of AI systems | A.9.2 intended use, A.9.3 monitoring of operation, A.9.4 logging of system events |
| **A.10** | Third-party & customer relationships | A.10.2 supplier relationships, A.10.3 customer relationships |
ISO/IEC 23894:2023 provides the AI-specific risk-management process (the methodology); 42001 Annex A provides the controls. The risk register is the bridge.
**Run** `ai_risk_register_builder.py` with an identified-risks JSON to produce a structured register with mapped controls + residual-risk verdict per ISO 23894 risk-treatment options.
See `references/aims_controls_annex_a.md` for the full 38-control catalogue with audit evidence per control.
### 3. Clause 9.2 Internal Audit Plan
**The framework:** Clause 9.2 requires "internal audits at planned intervals to provide information on whether the AIMS conforms to the organization's requirements and is effectively implemented and maintained." That's the management-system requirement; the **how often** and **how deep** are organizational choices.
**Mature-program defaults:**
- Cover every clause + every applicable Annex A control over a 3-year cycle (rolling)
- Annual full-system audit covering Clauses 4, 5, 9, 10 (the "always relevant" clauses)
- Quarterly or semi-annual deep dives on Clauses 6, 7, 8 by domain (per AI system or per lifecycle phase)
- Auditor independence: nobody audits their own work; A.6 lifecycle owner cannot audit Clause 8 operation
**Run** `aims_audit_scheduler.py` with a scope JSON (AI systems in scope, prior-year findings, certification cycle phase) to produce a 12-month plan with auditor assignments and independence checks.
See `references/aims_implementation_guide.md` for the maturity model and rollout sequencing (year 1 establish, year 2 certify, year 3+ continual improvement).
## Workflows
### Workflow 1: AIMS Gap Closure for Certification (4–8 weeks)
**Goal:** Identify gaps; prioritize remediation; close before stage 1 certification audit.
```bash
# 1. Inventory current AIMS evidence (policies, procedures, records)
python scripts/aims_gap_analyzer.py aims_evidence.json
# 2. Review gap matrix; group by clause
# 3. For each gap, identify owner + due date (target: close before stage 1)
# 4. Cross-check against ISO 27001 / 13485 existing artifacts — many can be reused
# 5. Cross-check against EU AI Act obligations (use compliance-team-eu-ai-act)
# 6. Output: prioritized remediation plan with owners + dates
```
### Workflow 2: AI Risk Register Build (1–2 weeks)
**Goal:** Construct the Clause 6.1.2 risk register with full Annex A control coverage.
```bash
# 1. Run ISO 23894 risk identification across AI lifecycle (data, model, deployment, decommission)
# 2. Capture each risk with: source, event, consequence, likelihood, impact
python scripts/ai_risk_register_builder.py risks.json
# 3. For each high/critical risk, confirm ≥ 1 Annex A control is selected as treatment
# 4. Document residual risk acceptance with management signoff
# 5. Cross-check with cs-caio-advisor on executive risk acceptance for "tolerate" decisions
# 6. Log via management review (Clause 9.3)
```
### Workflow 3: Annual Internal Audit Plan (1 day)
**Goal:** Produce the 12-month Clause 9.2 plan with auditor independence.
```bash
# 1. Pull last year's audit findings and certification cycle status (year 1/2/3)
python scripts/aims_audit_scheduler.py audit_scope.json
# 2. Confirm auditor independence per assignment
# 3. Confirm coverage hits every clause and every applicable Annex A control over rolling 3 years
# 4. Submit plan for management review approval (Clause 9.3 input)
```
### Workflow 4: Cross-Framework Reuse Mapping (per system onboarded)
**Goal:** When adding a new AI system, map ISO 42001 evidence against existing 27001 + 13485 evidence to avoid duplication.
1. Pull existing ISO 27001 Annex A controls + ISO 13485 procedures relevant to the system
2. For each ISO 42001 Annex A control, identify whether an existing artifact already satisfies it (e.g., 27001 A.8.16 monitoring activities can extend to AI system monitoring)
3. Add the AI-specific overlay only where the existing control doesn't cover it
4. Document mapping in the AIMS scope statement (Clause 4.3)
## Output Standards
```
**Bottom Line:** [one sentence — gap severity + the one thing to close first]
**The Decision:** [one of: gap-closure | risk-treatment | audit-scope]
**The Evidence:** [clause numbers + control IDs from the tool, not adjectives]
**How to Act:** [3 concrete next steps with owners + dates]
**Your Decision:** [the call only the compliance officer or CAIO can make — risk acceptance, scope expansion, certification readiness]
```
## Adjacent Skills
- `../../skills/information-security-manager-iso27001/` — ISO 27001 ISMS implementation (many controls reusable for AIMS A.7 data controls)
- `../../skills/quality-manager-qms-iso13485/` — ISO 13485 QMS (provides CAPA + management-review machinery the AIMS reuses)
- `../../skills/gdpr-dsgvo-expert/` — GDPR DPIA process (input to AIMS A.5 impact assessment for personal-data systems)
- `../../skills/isms-audit-expert/` — ISO 27001 internal audit pattern (the audit scheduler mirrors this for AIMS)
- `../../skills/soc2-compliance/` — SOC 2 trust services (reusable controls for AIMS A.10 third-party relationships)
- `../../../compliance-team-eu-ai-act/` — EU AI Act Article-level compliance (binding regulation companion to voluntary 42001)
- `../../../../compliance-os/` — Meta-orchestrator for multi-framework programs (run AIMS as one framework among 9)
- `../../../../c-level-advisor/chief-ai-officer-advisor/` — Executive AI strategy (build-vs-buy, cost economics — different audience)
## References
- [iso42001_clauses.md](references/iso42001_clauses.md) — Clauses 4–10 walkthrough with audit evidence expectations, common gaps, and reusable artifacts from ISO 27001/13485
- [aims_controls_annex_a.md](references/aims_controls_annex_a.md) — All 38 Annex A controls (A.2–A.10) with implementation guidance, audit evidence, and severity of failure
- [aims_implementation_guide.md](references/aims_implementation_guide.md) — 3-year maturity model (establish → certify → continually improve), rollout sequencing, integration with existing ISMS/QMS programs
- [cross_framework_mapping_ai.md](references/cross_framework_mapping_ai.md) — ISO 42001 ↔ EU AI Act ↔ NIST AI RMF ↔ ISO 23894 ↔ ISO 38507 ↔ ISO 27001 control-level mapping with mapping-confidence ratings
---
**Version:** 1.0.0
**Status:** Production Ready
FILE:references/aims_controls_annex_a.md
# ISO/IEC 42001 Annex A — 38 Controls Catalogue
This reference answers exactly one decision: **for each Annex A control, what does implementation look like, what evidence does the auditor want, and what's the severity if it's missing?**
Pair with `scripts/ai_risk_register_builder.py` to map risks to controls.
## Structure of Annex A
ISO/IEC 42001 Annex A is a *normative* annex containing reference controls. The standard requires (per Clause 6.1.3) that the organization compare its determined controls to Annex A to verify no necessary controls have been omitted. Unlike ISO 27001 where Annex A is presumed-applicable, ISO 42001 Annex A controls are applied based on risk — if a control doesn't apply (e.g., A.10 third-party AI when you use no third-party AI), document the exclusion with justification.
**The 10 control categories (A.1 is the structural intro; A.2–A.10 are the operational controls):**
| ID | Category | Control count | Maps to clause |
|---|---|---|---|
| A.2 | Policies related to AI | 2 | 5.2 |
| A.3 | Internal organization | 2 | 5.3 |
| A.4 | Resources for AI systems | 3 | 7.1 |
| A.5 | Assessing impacts of AI systems | 3 | 6.1.4, 8.2 |
| A.6 | AI system lifecycle | 8 | 8.3 |
| A.7 | Data for AI systems | 5 | 8.3 |
| A.8 | Information for interested parties | 4 | 7.4, 9.1 |
| A.9 | Use of AI systems | 4 | 8.3, 9.1 |
| A.10 | Third-party & customer relationships | 5 | 8.4 |
Total: **38 controls** across 9 operational categories.
## A.2 — Policies (severity if missing: CRITICAL)
| Control | Title | What auditor wants | Reusable from |
|---|---|---|---|
| **A.2.2** | AI policy | Signed AI policy meeting Clause 5.2 requirements | ISO 27001 A.5.1 (information security policy) — extend |
| **A.2.3** | Alignment of AI policy with other policies | Mapping showing AI policy doesn't contradict info-sec, privacy, quality, code-of-conduct policies | New artifact; document the cross-references |
## A.3 — Internal Organization (severity: MAJOR)
| Control | Title | What auditor wants | Reusable from |
|---|---|---|---|
| **A.3.2** | AI roles & responsibilities | RACI matrix; named AIMS owner | ISO 27001 A.5.2; extend to AI |
| **A.3.3** | Reporting of concerns | Whistleblower / concerns procedure for AI-specific issues (bias, harm, misuse) | Existing whistleblower; AI-extend |
## A.4 — Resources (severity: MAJOR)
| Control | Title | What auditor wants | Reusable from |
|---|---|---|---|
| **A.4.2** | Resources — data | Data inventory; provenance; quality assessment | ISO 27001 A.5.9 inventory of assets — extend |
| **A.4.3** | Resources — tooling | Inventory of ML tooling; license & dependency tracking | Existing software-asset management |
| **A.4.4** | Resources — human resources | Competence requirements + training records (Clause 7.2) | ISO 27001 A.6.3 awareness; ISO 13485 6.2 competence |
## A.5 — Impact Assessment (severity: CRITICAL)
| Control | Title | What auditor wants | Reusable from |
|---|---|---|---|
| **A.5.2** | AI system impact assessment | Documented impact assessment for each AI system; covers individuals, groups, society | GDPR DPIA — partial; AI scope wider (third-party harm, environmental, societal) |
| **A.5.3** | Process for impact assessment | Documented procedure with triggers (launch, material change, complaint) | New procedure |
| **A.5.4** | Documentation of impact assessment | Signed impact assessment record with management approval for high-impact systems | New artifact |
## A.6 — AI System Lifecycle (severity: CRITICAL)
| Control | Title | What auditor wants | Reusable from |
|---|---|---|---|
| **A.6.1.2** | Objectives for AI system development | Stated AI-system objectives aligned to AI policy + use intent | New artifact (per system) |
| **A.6.1.3** | Processes for management of the AI system lifecycle | Procedure covering design → data → model → V&V → deployment → operation → decommission | New procedure |
| **A.6.2.2** | AI system objectives & requirements | Documented requirements traceable to objectives | ISO 13485 7.3 design & development — extend |
| **A.6.2.3** | Documentation of AI system design & development | Design records (architecture, datasets, model card) under document control | ISO 13485 7.3 — extend |
| **A.6.2.4** | Verification & validation of AI system | Test plan + evaluation results; defined acceptance criteria | New artifact per system; reference NIST AI RMF "Measure" function |
| **A.6.2.5** | Deployment of AI system | Deployment checklist; environment hand-off; rollback plan | ISO 27001 A.8.32 change management — extend |
| **A.6.2.6** | Operation & monitoring of AI system | Monitoring plan with thresholds + escalation | New per system |
| **A.6.2.7** | Technical documentation of AI system | Model card or system card per Mitchell et al. (2019) / Gebru et al. (2021) | New artifact |
## A.7 — Data for AI Systems (severity: CRITICAL)
| Control | Title | What auditor wants | Reusable from |
|---|---|---|---|
| **A.7.2** | Data management | Data lifecycle procedure (acquisition → use → retention → deletion) | GDPR Art. 5 data minimisation; ISO 27001 A.5.10 acceptable use |
| **A.7.3** | Data quality | Defined data-quality dimensions; measured; reported | New; reference DAMA-DMBOK 2 / ISO 8000 |
| **A.7.4** | Data provenance | Documented data lineage; consent / legitimate basis recorded | GDPR records of processing (Art. 30) — extend |
| **A.7.5** | Data preparation | Documented preprocessing procedure | New artifact per system |
| **A.7.6** | Data privacy considerations | Privacy review per data category | GDPR DPIA — extend |
## A.8 — Information for Interested Parties (severity: MAJOR)
| Control | Title | What auditor wants | Reusable from |
|---|---|---|---|
| **A.8.2** | System documentation | Public-facing documentation per Annex A.6.2.7 | Model card / system card |
| **A.8.3** | User information | UX-level disclosure: this is AI; what it does; its limitations | New; align with EU AI Act Article 50 transparency |
| **A.8.4** | Communication of AI incidents | Incident communication procedure including external notification timing | GDPR Art. 33–34 breach notification — extend |
| **A.8.5** | Information for affected parties | Communication for AI-affected populations (those subject to AI decisions) | New; align with EU AI Act Article 86 redress |
## A.9 — Use of AI Systems (severity: MAJOR)
| Control | Title | What auditor wants | Reusable from |
|---|---|---|---|
| **A.9.2** | Intended use of AI system | Documented intended-use statement per system | New artifact |
| **A.9.3** | Monitoring of operation | Continuous monitoring with defined metrics + thresholds | NIST AI RMF "Measure" — extend |
| **A.9.4** | Logging of AI system events | Tamper-evident logs covering decisions, drift indicators, incidents | ISO 27001 A.8.15 logging — extend |
| **A.9.5** | Use of system after deployment | Procedure for in-use changes (retraining, fine-tuning) with re-evaluation triggers | New procedure |
## A.10 — Third-Party & Customer Relationships (severity: MAJOR)
| Control | Title | What auditor wants | Reusable from |
|---|---|---|---|
| **A.10.2** | Supplier (third-party) relationships | AI-specific contract clauses (training data use, drift notification, sub-processor list) | ISO 27001 A.5.19 supplier relationships — extend |
| **A.10.3** | Customer relationships | Customer-facing AI obligations (transparency, opt-out, redress) | ISO 27001 A.5.20 — extend |
| **A.10.4** | Allocation of responsibilities between organization & third party | RACI for shared AI responsibilities (data labeling, model training, hosting, monitoring) | New artifact (per supplier) |
| **A.10.5** | Confidentiality of AI-related information | NDA scope covers AI-system internals (architecture, training data, weights) | ISO 27001 A.6.6 confidentiality — extend |
| **A.10.6** | Termination of AI service relationships | Procedure for safe AI-vendor exit (data return, model deletion, monitoring transition) | ISO 27001 A.5.20 service-level review — extend |
## How to Read This Catalogue
- **CRITICAL** = nonconformity blocks certification at stage 1
- **MAJOR** = nonconformity requires corrective action plan at stage 2; may delay certification
- **MINOR** = nonconformity recorded; corrective action expected within agreed timeline
**Audit evidence rule:** for every control selected as applicable, the auditor will ask three questions: (1) Where is the documented procedure? (2) Where are the records showing the procedure was followed? (3) Where is the evidence of management review of those records? If any of the three is missing, the control is partially implemented.
## When This Reference Doesn't Help
- **Specific Annex A control text.** This is a summary. The normative text is in ISO/IEC 42001:2023 Annex A — buy the standard.
- **Risk-to-control mapping methodology.** See `aims_implementation_guide.md` and ISO/IEC 23894:2023.
- **EU AI Act control overlap.** See `cross_framework_mapping_ai.md`.
---
**Source authorities (non-exhaustive):**
- **ISO/IEC 42001:2023** — Annex A normative controls (the authoritative source)
- **ISO/IEC 23894:2023** — AI risk management process (drives Annex A selection)
- **ISO/IEC 22989:2022** — AI concepts and terminology
- **NIST AI Risk Management Framework 1.0** (Jan 2023) + AI RMF Playbook — operational guidance mapping cleanly to Annex A
- **BSI AIC4 — Artificial Intelligence Cloud Service Compliance Criteria Catalogue** (2021) — sector-specific overlay for cloud AI providers
- **AAMI CR34971:2023** — Guidance for AI in medical devices
- **Mitchell et al.** — "Model Cards for Model Reporting" (FAT* 2019) — origin of model-card pattern referenced by A.6.2.7
- **Gebru et al.** — "Datasheets for Datasets" (CACM 2021) — datasheet pattern referenced by A.7.4
- **ISACA** — *Auditing Artificial Intelligence* (2nd ed., 2024) — practitioner audit checklist
FILE:references/aims_implementation_guide.md
# ISO/IEC 42001 — AIMS Implementation Guide (3-Year Maturity Model)
This reference answers exactly one decision: **what's the rollout sequence — what do we build in year 1 vs year 2 vs year 3, and how do we avoid recreating ISO 27001/13485 machinery?**
Pair with `scripts/aims_audit_scheduler.py` to operationalize the year-by-year audit cycle.
## The 3-Year Cycle
ISO management-system certifications follow a 3-year cycle:
| Year | Audit type | What happens |
|---|---|---|
| **Year 1** | Stage 1 (documentation review) + Stage 2 (implementation audit) → initial certification | Establish the AIMS; close major nonconformities; pass certification |
| **Year 2** | Surveillance audit (selective scope) | Demonstrate continual improvement; close minor nonconformities from year 1 |
| **Year 3** | Surveillance audit (selective scope) + recertification preparation | Full system review; prepare for year 4 recertification |
| **Year 4** | Recertification audit (full scope) | Renew certificate |
The internal audit programme (Clause 9.2) must cover every clause + every applicable Annex A control at least once per 3-year cycle. The plan must show this rolling coverage.
## Year 1 — Establish (focus: artifacts that auditors must see)
**Goal:** every clause and every applicable Annex A control has at least a documented procedure and one round of records.
### Q1: Foundations
- AI policy (Clause 5.2 + A.2.2) — board-signed
- AIMS scope statement (Clause 4.3) — names every AI system including third-party
- Roles & responsibilities (Clause 5.3 + A.3.2) — RACI with named AIMS owner
- Stakeholder & context analysis (Clause 4.1–4.2)
### Q2: Risk & impact
- AI risk register (Clause 6.1.2 + A.5) — run `ai_risk_register_builder.py`
- Risk treatment plan (Clause 6.1.3) — every high/critical risk linked to ≥ 1 Annex A control
- Impact assessment procedure (Clause 6.1.4 + A.5.3)
- AI objectives (Clause 6.2) — measurable targets
### Q3: Operations
- AI system lifecycle procedure (Clause 8.3 + A.6) — design through decommission
- Data management procedures (A.7) — data quality, provenance, preparation
- Monitoring plan per system (A.9.3)
- Third-party AI contract template (A.10.2)
### Q4: Performance
- Internal audit programme (Clause 9.2) — run `aims_audit_scheduler.py`
- Management review procedure (Clause 9.3) — inputs include AI-specific items
- CAPA integration with existing 13485/9001 CAPA loop (Clause 10.2)
- Stage 1 audit readiness check — run `aims_gap_analyzer.py`
**Year 1 success criteria:** stage 1 audit passes with 0 critical and ≤ 1 major nonconformity.
## Year 2 — Certify and operate
**Goal:** close year-1 minor nonconformities; demonstrate the system is operating, not just documented.
### Focus shifts to records (evidence the procedures are followed)
- Monthly drift monitoring records (A.9.3)
- Quarterly impact assessment reviews (A.5)
- Half-yearly third-party AI supplier reviews (A.10.2)
- Annual management review (Clause 9.3) with documented AI-specific inputs:
- Risk register changes
- Open nonconformities
- Drift events outside threshold
- Incidents per A.8.4
- Performance trends vs objectives (Clause 6.2)
**Year 2 success criteria:** surveillance audit passes; year-1 nonconformities closed; ≥ 80% of risk-register treatments fully implemented.
## Year 3 — Continually improve
**Goal:** demonstrate continual improvement (Clause 10.1) and prepare for recertification.
- Annual update to risk register based on new AI systems, regulation changes, incidents
- Re-baseline objectives (Clause 6.2) against year-1 + year-2 performance
- Audit the audit programme itself (meta-audit; common surveillance finding)
- Demonstrate at least one improvement initiative closed with measurable result
**Year 3 success criteria:** surveillance audit passes; recertification scope confirmed; trend evidence supports continual improvement claim.
## Integration With Existing ISMS (ISO 27001) and QMS (ISO 13485 / 9001)
The mistake most organizations make: building the AIMS as a parallel management system. **Don't.** ISO 42001 is intentionally Annex SL aligned to allow integration. Common integration patterns:
| Existing artifact | Extend for AIMS by adding |
|---|---|
| ISMS scope statement | List of AI systems within ISMS scope |
| Information security policy | AI-specific commitments (fairness, human oversight) |
| Risk register (27001) | AI risks tagged distinctly; same severity matrix; same treatment workflow |
| Document control procedure | Add model cards + datasheets + impact assessments to controlled documents |
| Internal audit programme | Add AI clause + Annex A controls to rotation |
| Management review | Add AI inputs (drift, incidents, risk-register changes) |
| CAPA procedure | Add AI-specific root-cause categories (data quality, model drift, prompt injection) |
| Supplier management | Add AI-specific contract clauses |
| Incident response | Add AI incidents (bias surfaced, drift exceeded, model misuse) |
**Reuse rule of thumb:** if you already operate ISO 27001 + ISO 13485 maturely, ~60% of AIMS Clauses 4–10 effort is rewriting existing artifacts to include AI scope. The remaining ~40% is Annex A operational controls (risk register details, lifecycle, V&V, monitoring, model cards) which are genuinely new.
## Sequence If Starting From Zero (No Prior Management System)
If your organization is starting AIMS without prior ISO certification:
1. **Add ISO 27001 first.** Most AIMS Clauses 4–10 evidence is satisfied by ISO 27001 evidence with AI scope appended. Doing 42001 alone is harder.
2. **Or start with NIST AI RMF.** NIST AI RMF is voluntary and US-centric but maps cleanly to 42001 Annex A. Mature on RMF for 12–18 months, then layer the management-system formality of 42001 on top.
3. **Avoid: building AIMS in isolation.** You'll recreate document control, CAPA, management review, and internal audit infrastructure that ISO 27001/13485 already standardize.
## Cost & Effort Benchmarks (informal, practitioner-reported)
| Org type | Year 1 effort (FTE-months) | Notes |
|---|---|---|
| Mature 27001 + 13485 org adding AIMS | 4–6 | Mostly Annex A overlay |
| Mature 27001 org adding AIMS (no 13485) | 8–12 | Add lifecycle procedures (A.6) net-new |
| Greenfield (no prior management system) | 24–36 | Do 27001 first, then 42001 |
Certification body fees: ~$15k–$35k for initial certification audit (stage 1 + stage 2 for a typical mid-size SaaS); ~$8k–$15k per surveillance year.
## Common Year-1 Pitfalls
1. **Treating "AI ethics" as the policy.** A poetic policy doesn't pass; auditor wants concrete commitments and a way to verify them.
2. **Risk register with no control mapping.** Register identifies risks but doesn't show which Annex A control treats each — Clause 6.1.3 fails.
3. **Lifecycle procedure that skips decommission.** Auditor will ask, "How do you safely retire an AI system?" If silence, A.6 fails.
4. **No drift threshold defined.** Monitoring "we watch it" doesn't pass; needs metric + threshold + escalation owner.
5. **Third-party AI excluded.** "Our vendors' AI features aren't ours" is wrong if you embed them in your service.
6. **No competence requirement for ML engineers.** Clause 7.2 wants documented competence requirements per role; "they have PhDs" isn't a documented requirement.
## When This Reference Doesn't Help
- **Specific Annex A control implementation.** See `aims_controls_annex_a.md`.
- **Risk identification methodology.** See ISO/IEC 23894:2023.
- **EU AI Act overlap.** See `cross_framework_mapping_ai.md` and `compliance-team-eu-ai-act/`.
---
**Source authorities (non-exhaustive):**
- **ISO/IEC 42001:2023** — the standard itself
- **ISO/IEC 23894:2023** — AI risk management process
- **ISO/IEC 38507:2022** — Governance implications of AI for organizations
- **ISO/IEC 27001:2022** — Information security management (reuse template for 60% of AIMS Clauses 4–10)
- **ISO/IEC 13485:2016** — Medical device QMS (reuse template for CAPA, document control)
- **NIST AI RMF 1.0** (Jan 2023) + AI RMF Playbook + Generative AI Profile (NIST AI 600-1, 2024)
- **BSI** — *Information technology — Artificial intelligence — Implementation guidance for ISO/IEC 42001* (2024 white paper)
- **ISACA** — *Auditing Artificial Intelligence* (2nd ed., 2024) — implementation pitfalls catalogue
- **IAPP** — AI Governance Center materials (continuously updated) — practitioner community knowledge base
FILE:references/cross_framework_mapping_ai.md
# ISO/IEC 42001 ↔ EU AI Act ↔ NIST AI RMF ↔ ISO 23894 ↔ ISO 38507 ↔ ISO 27001 — Cross-Framework Mapping
This reference answers exactly one decision: **for each ISO 42001 obligation, which other frameworks already cover it, and what evidence can I reuse?**
The point of cross-framework mapping is to avoid duplicate work. A control implemented for ISO 27001 frequently satisfies an Annex A control of ISO 42001 with minor AI-specific overlay. The `compliance-os` orchestrator's `cross_framework_mapper.py` consumes this mapping.
## High-Level Framework Comparison
| Framework | Type | Binding? | AI scope | Maturity |
|---|---|---|---|---|
| **ISO/IEC 42001:2023** | Management system standard | Voluntary; certifiable | AI Management System (AIMS) | Published 2023; certifications starting 2024 |
| **EU AI Act (Reg. 2024/1689)** | Product safety regulation | Binding in EU | Risk-based: prohibited → high-risk → limited-risk → minimal-risk | In force Aug 2024; phased obligations through 2027 |
| **NIST AI RMF 1.0** | Risk management framework | Voluntary (US) | Govern / Map / Measure / Manage functions | Released Jan 2023; mature playbook |
| **ISO/IEC 23894:2023** | Risk management methodology | Reference standard | AI risk process; informs 42001 Clause 6.1 | Published 2023 |
| **ISO/IEC 38507:2022** | Governance standard | Reference standard | Board-level AI governance | Published 2022 |
| **ISO/IEC 27001:2022** | Management system standard | Voluntary; certifiable | Information security | Mature; widely certified |
## Clause-to-Framework Mapping (ISO 42001 lens)
### Clause 4 — Context
| ISO 42001 | EU AI Act | NIST AI RMF | ISO 27001 | Notes |
|---|---|---|---|---|
| 4.1 External context | Art. 1 (scope); Recitals on risk-based approach | GOVERN 1.1 | 4.1 | Extend 27001 context with AI regulatory landscape |
| 4.2 Interested parties | Art. 27 (FRIA stakeholders for high-risk) | GOVERN 5 | 4.2 | Add AI-affected populations |
| 4.3 Scope | Article 6 + Annex III define what's in scope as "high-risk" | MAP 1.1 | 4.3 | Distinct artifacts; AIMS scope ≠ EU AI Act applicability scope |
| 4.4 AIMS processes | n/a | n/a | 4.4 | Integration map |
### Clause 5 — Leadership
| ISO 42001 | EU AI Act | NIST AI RMF | ISO 27001 / ISO 38507 |
|---|---|---|---|
| 5.1 Top-mgmt commitment | Art. 26 (deployer obligations); Art. 16 (provider obligations) | GOVERN 1 | 27001 5.1; 38507 Clauses 5–6 (governance principles) |
| 5.2 AI policy | Art. 17 (QMS for high-risk); Art. 95 (codes of conduct) | GOVERN 1.1 | 27001 5.2 — extend with AI commitments |
| 5.3 Roles & authorities | Art. 26 (deployer obligations); Art. 16 + 22 (authorized representative) | GOVERN 2.1 | 27001 5.3 |
### Clause 6 — Planning (the densest mapping)
| ISO 42001 | EU AI Act | NIST AI RMF | ISO 23894 |
|---|---|---|---|
| 6.1.2 AI risk assessment | Art. 9 (risk management system for high-risk) | MAP 5.1; MAP 5.2 | Clauses 6–7 (entire process) |
| 6.1.3 AI risk treatment | Art. 9(2)(c–d) (risk management measures) | MANAGE 1.1 | Clauses 8 (treatment selection) |
| 6.1.4 Impact assessment | Art. 27 (Fundamental Rights Impact Assessment for high-risk public-sector deployers) | MAP 2.3; MAP 5.1 | Clause 5.3 (scope definition) |
| 6.2 AI objectives | Art. 9(2)(a) (objectives of risk management) | GOVERN 1.5; MEASURE 1 | Clause 5.2 |
### Clause 7 — Support
| ISO 42001 | EU AI Act | NIST AI RMF | ISO 27001 |
|---|---|---|---|
| 7.1 Resources | Art. 17(1)(c) (technical resources for QMS) | GOVERN 3 | A.6.1 |
| 7.2 Competence | Art. 14 (human oversight competence); Art. 26(2) (deployer competence) | GOVERN 3.1 | A.6.3 |
| 7.3 Awareness | Art. 14 | GOVERN 5.1 | A.6.3 |
| 7.4 Communication | Art. 50 (transparency obligations); Art. 86 (right to explanation) | GOVERN 5.2 | A.7.4 |
| 7.5 Documented info | Art. 11 + 12 (technical documentation); Art. 19 (record-keeping) | GOVERN 1.4 | 27001 7.5 |
### Clause 8 — Operation
| ISO 42001 | EU AI Act | NIST AI RMF | Notes |
|---|---|---|---|
| 8.1 Operational planning | Art. 17 (QMS) | MANAGE 2 | |
| 8.2 Impact assessment process | Art. 27 (FRIA process) | MAP 2 | |
| 8.3 AI system lifecycle | Art. 9 (full lifecycle); Art. 72 (post-market monitoring) | MAP 3; MEASURE 3; MANAGE 4 | Densest overlap |
| 8.4 Third-party / customer | Art. 25 (responsibilities along the AI value chain) | GOVERN 6 | |
### Clause 9 — Performance
| ISO 42001 | EU AI Act | NIST AI RMF | ISO 27001 |
|---|---|---|---|
| 9.1 Monitoring | Art. 72 (post-market monitoring system) | MEASURE 2; MEASURE 4 | 9.1 |
| 9.2 Internal audit | Art. 17(1)(j) (internal audit as part of QMS) | GOVERN 4 | 9.2 |
| 9.3 Management review | n/a explicit; implied in Art. 17 | GOVERN 1 | 9.3 |
### Clause 10 — Improvement
| ISO 42001 | EU AI Act | NIST AI RMF | ISO 27001 |
|---|---|---|---|
| 10.1 Continual improvement | Art. 9(2)(c) (iterative risk reduction) | MANAGE 4.3 | 10.1 |
| 10.2 Nonconformity & CAPA | Art. 73 (incident reporting); Art. 79 (corrective actions) | MANAGE 4.2 | 10.2 |
## Annex A Control → Framework Mapping (subset of highest-value mappings)
| ISO 42001 Annex A | EU AI Act | NIST AI RMF | ISO 27001 | Mapping confidence |
|---|---|---|---|---|
| A.2.2 AI policy | Art. 95 (codes of conduct) | GOVERN 1.1 | A.5.1 (info-sec policy) | HIGH |
| A.5.2 Impact assessment | Art. 27 FRIA | MAP 2.3 | n/a | MEDIUM (FRIA narrower) |
| A.6.2.4 V&V | Art. 15 (accuracy, robustness, cybersecurity); Art. 17(1)(h) | MEASURE 2 | n/a | HIGH |
| A.7.2 Data management | Art. 10 (data governance) | MAP 2.3; MEASURE 2.6 | A.5.10 | HIGH |
| A.7.3 Data quality | Art. 10(3) (relevance, representativeness, error-free, complete) | MEASURE 2.6 | n/a | HIGH |
| A.7.4 Data provenance | Art. 10(2)(d) (data origin) | MAP 2.3 | n/a | HIGH |
| A.7.6 Data privacy | Art. 10(5) (special categories); GDPR Articles 5, 6, 9 | MANAGE 2.1 | A.5.34 | HIGH |
| A.8.2 System docs | Art. 11 + Annex IV (technical documentation) | GOVERN 1.4 | A.5.37 | HIGH |
| A.8.3 User information | Art. 13 (instructions for use); Art. 50 (transparency) | GOVERN 5.2 | n/a | HIGH |
| A.8.4 Incident communication | Art. 73 (incident reporting to authorities) | MANAGE 4.2 | A.6.8 (reporting) | HIGH |
| A.9.3 Monitoring | Art. 72 (post-market monitoring) | MEASURE 2; MEASURE 4 | A.8.15 (logging) | HIGH |
| A.9.4 Logging | Art. 12 (record-keeping); Art. 19 | MEASURE 4 | A.8.15 | HIGH |
| A.10.2 Supplier relationships | Art. 25 (responsibilities along the AI value chain) | GOVERN 6 | A.5.19, A.5.20, A.5.21 | HIGH |
**Mapping confidence legend:**
- **HIGH** — direct overlap; same evidence can satisfy both
- **MEDIUM** — partial overlap; existing evidence with AI overlay
- **LOW** — concept overlap; mostly new artifact required
## Practical Reuse Pattern
If you operate ISO 27001 (mature) + are adopting ISO 42001:
1. **Reuse policies (~60%):** Extend info-sec policy with AI commitments (5.2 + A.2.2)
2. **Reuse procedures (~50%):** Document control, internal audit, management review, CAPA
3. **Reuse risk machinery (~70%):** Same severity matrix, same treatment workflow, same residual-risk acceptance flow — just add AI-specific risks and Annex A control mapping
4. **Reuse supplier mgmt (~80%):** Add AI-specific contract clauses to existing supplier procedure
5. **New artifacts (~40%):** Model cards / datasheets (A.6.2.7, A.7.4), impact assessments per Annex A.5, lifecycle procedure (A.6), drift monitoring (A.9.3), V&V procedure (A.6.2.4)
If you also operate ISO 13485 (medical device QMS):
- Reuse: design controls (7.3) for A.6 lifecycle; risk management (ISO 14971) overlays cleanly onto A.5 + 6.1; post-market surveillance maps directly to A.9.3 monitoring
- Add: AI-specific failure modes to ISO 14971 hazard analysis
## When This Reference Doesn't Help
- **EU AI Act conformity assessment routing.** See `compliance-team-eu-ai-act/scripts/conformity_assessment_planner.py`.
- **NIST AI RMF deep-dive.** See NIST AI RMF Playbook (NIST.AI.100-1.pdf) and Generative AI Profile (NIST.AI.600-1).
- **Multi-framework audit simulation.** See `compliance-os/scripts/audit_simulator.py`.
---
**Source authorities (non-exhaustive):**
- **ISO/IEC 42001:2023** — Annex A normative controls
- **Regulation (EU) 2024/1689** — Artificial Intelligence Act — full Articles (the binding regulation)
- **NIST AI Risk Management Framework 1.0** (Jan 2023, NIST AI 100-1) + AI RMF Playbook
- **ISO/IEC 23894:2023** — AI risk management process
- **ISO/IEC 38507:2022** — Governance implications of AI
- **ISO/IEC 27001:2022** + Annex A controls (the most cross-walked partner standard)
- **EDPB Opinion 28/2024** — Guidelines on processing of personal data in AI models
- **European Commission AI Act Guidelines** (continuously updated): Guidelines on prohibited practices (Feb 2025), Guidelines on definition of AI system (Feb 2025), FRIA template guidance
- **BSI** — *Cross-walking ISO 42001 and EU AI Act* (white paper, 2024)
- **IAPP EU AI Act Tracker** (continuously updated) — practitioner reference for Article applicability
FILE:references/iso42001_clauses.md
# ISO/IEC 42001:2023 — Clauses 4-10 Walkthrough
This reference answers exactly one decision: **for each clause of ISO 42001, what audit evidence does the certification body expect, and which existing ISMS/QMS artifact can I reuse?**
Pair with `scripts/aims_gap_analyzer.py` for automated coverage scoring.
## Annex SL High-Level Structure
ISO/IEC 42001:2023 follows the Annex SL structure shared by ISO 9001, 14001, 27001, 13485, 45001, and other management-system standards. This is deliberate: certification bodies, internal auditors, and quality teams can apply existing competencies to AIMS audits with low ramp-up cost.
**Practical implication:** if your organization already operates ISO 27001 + ISO 13485, ~60% of Clauses 4–10 artefacts (scope statements, policies, document control, internal audit programme, management review) can be **extended** to cover AI scope rather than recreated. The gap analysis is mostly Annex A (AI-specific operational controls), not Clauses 4–10.
## Clause 4 — Context of the Organization
| Sub-clause | Requirement | Audit evidence | Common gap |
|---|---|---|---|
| **4.1** | External & internal issues affecting AIMS | Documented context analysis (PESTLE or equivalent); reviewed at management review | Treating AI regulatory landscape as static; missing EU AI Act, US state laws, sector-specific AI rules |
| **4.2** | Needs & expectations of interested parties | Stakeholder matrix: customers, regulators, employees, data subjects, model providers, AI-affected populations | Omitting "AI-affected populations" (people who never interact with the system but are subject to its decisions) |
| **4.3** | AIMS scope statement | Documented scope: which AI systems, which lifecycle phases, which organizational units, which exclusions | Scope omits third-party AI services (SaaS features powered by vendor models); excludes "experimental" systems that are in fact in production |
| **4.4** | AIMS processes & interactions | Process map showing how AIMS processes connect to existing QMS/ISMS processes | Treating AIMS as parallel system instead of integrated extension of existing management systems |
**Reusable from ISO 27001 / 13485:** scope statement template, stakeholder matrix template, process map.
## Clause 5 — Leadership
| Sub-clause | Requirement | Audit evidence | Common gap |
|---|---|---|---|
| **5.1** | Top-management commitment | Documented evidence: AI in board agenda, resource allocation, KPIs | "AI ethics" reduced to marketing copy with no operating commitment |
| **5.2** | AI policy | Signed AI policy committing to lawful use, beneficial purpose, human oversight, continual improvement | Policy doesn't mention human oversight (Annex A.9 requirement); missing commitment to continual improvement |
| **5.3** | Organizational roles, responsibilities, authorities | RACI matrix for AIMS roles; named AIMS owner; AI ethics review board (if applicable) | No named AIMS owner; CISO assumed to "cover AI" without explicit assignment |
**Critical:** Clause 5.2 has a higher evidence bar than ISO 27001/13485 because the AI policy must address fairness, transparency, and human oversight — concepts absent from older management systems. Cannot be satisfied by extending existing policies; needs net-new content.
## Clause 6 — Planning
| Sub-clause | Requirement | Audit evidence | Common gap |
|---|---|---|---|
| **6.1.2** | AI risk assessment | Risk register per ISO 23894 methodology; covers full AI lifecycle | Risk identification at deployment only, missing data + model + decommission phases |
| **6.1.3** | AI risk treatment | Treatment plan linking each risk to Annex A controls; residual-risk acceptance documented | Treatment plan exists but is generic ("apply A.7.3") without specific implementation |
| **6.1.4** | AI system impact assessment | Documented impact assessment per Annex A.5.2 for high-impact systems | Confusing impact assessment (Clause 6.1.4) with risk assessment (Clause 6.1.2) |
| **6.2** | AI objectives | Measurable AI objectives aligned to AI policy; reviewed in management review | Objectives are aspirational ("ethical AI") without measurable targets |
**Run** `ai_risk_register_builder.py` to operationalize 6.1.2 + 6.1.3.
## Clause 7 — Support
| Sub-clause | Requirement | Audit evidence | Common gap |
|---|---|---|---|
| **7.1** | Resources for AIMS | Budget; tooling; compute resources documented | Compute resources for ML training treated as one-off project cost, not ongoing AIMS resource |
| **7.2** | Competence | Defined competence requirements per role (ML eng, AI risk, data steward); training records | Competence requirements undefined for ML engineers; assumes "they have degrees" |
| **7.3** | Awareness | AI awareness training across all employees with AI-system access | Training is engineer-only; product, marketing, customer success bypass |
| **7.4** | Communication | Documented internal + external communications procedure for AI | No procedure for communicating AI incidents to users (Annex A.8.4 link) |
| **7.5** | Documented information | Version-controlled AIMS documentation | Model cards exist but are not under document control; can be edited without approval |
## Clause 8 — Operation
| Sub-clause | Requirement | Audit evidence | Common gap |
|---|---|---|---|
| **8.1** | Operational planning & control | Operational procedures for each AI lifecycle phase | Operations procedures don't define phase transitions (when does "development" become "production"?) |
| **8.2** | Impact assessment process | Operational procedure for triggering impact assessment; gate before launch | Impact assessment treated as one-time launch artifact, not re-triggered on material change |
| **8.3** | AI system lifecycle process | Documented lifecycle covering: design → data → model → V&V → deployment → operation → decommission | Lifecycle skips "decommission"; no procedure for sunsetting AI systems |
| **8.4** | Third-party / customer relationships | Supplier and customer relationship procedures; AI-specific clauses in contracts | Standard vendor contracts not updated for AI-specific obligations (data use, model retraining, drift) |
## Clause 9 — Performance Evaluation
| Sub-clause | Requirement | Audit evidence | Common gap |
|---|---|---|---|
| **9.1** | Monitoring, measurement, analysis & evaluation | Defined metrics for AI performance, fairness, drift; monitoring records | Drift monitoring in code but no defined acceptable drift threshold; no escalation path |
| **9.2** | Internal audit programme | 12-month audit plan; auditor independence documented; findings tracked | No formal AIMS audit programme; audits happen ad hoc; auditors audit own work |
| **9.3** | Management review | Documented management review at planned intervals with required inputs/outputs | Management review inputs missing AI-specific items (drift, incidents, risk-register changes) |
**Run** `aims_audit_scheduler.py` to generate the 9.2 plan with independence checks.
## Clause 10 — Improvement
| Sub-clause | Requirement | Audit evidence | Common gap |
|---|---|---|---|
| **10.1** | Continual improvement | Evidence of AIMS improvement over time (KPIs trending, control maturity rising) | "Continual improvement" treated as audit closure activity, not ongoing |
| **10.2** | Nonconformity & corrective action | CAPA records for AIMS nonconformities; root cause analysis documented | AIMS CAPA loop separate from existing 13485/9001 CAPA loop — duplicated effort, divergent procedures |
**Reusable from ISO 13485 / 9001:** the entire CAPA machinery. Add AI-specific root-cause categories (data quality, model drift, prompt injection, etc.) to the existing taxonomy.
## When This Reference Doesn't Help
- **Specific AI risk identification.** See `aims_controls_annex_a.md` and ISO/IEC 23894:2023.
- **EU AI Act conformity assessment.** Different standard. See `compliance-team-eu-ai-act`.
- **Model cards, datasheets, evaluation methodology.** Tactical artefacts; reference NIST AI RMF playbook + papers like Mitchell et al. (2019).
---
**Source authorities (non-exhaustive):**
- **ISO/IEC 42001:2023** — Information technology — Artificial intelligence — Management system (the standard itself; published 2023-12-18 by ISO/IEC JTC 1/SC 42)
- **ISO/IEC 23894:2023** — AI risk management process (the methodology referenced by Clause 6.1.2)
- **ISO/IEC 38507:2022** — Governance implications of AI for organizations (board-level governance lens referenced by Clause 5)
- **ISO/IEC 22989:2022** — AI concepts and terminology (definitions used throughout)
- **Annex SL** in the ISO/IEC Directives Part 1 (2024) — the high-level structure shared by ISO management-system standards
- **BSI AI Management System (AIMS) Implementation Guide** (BSI, 2024) — practitioner walkthrough
- **AAMI CR34971:2023** — AI guidance for medical devices (cross-walks 42001 to medical device QMS)
- **ISACA** — *Auditing Artificial Intelligence* (2nd ed., 2024) — internal-audit-oriented checklist with ISO 42001 mapping
FILE:scripts/aims_audit_scheduler.py
#!/usr/bin/env python3
"""aims_audit_scheduler.py — ISO/IEC 42001 Clause 9.2 internal audit plan generator.
Stdlib-only. Produces a 12-month internal audit schedule for an AIMS with:
- quarterly audit slots
- clause + Annex A control coverage per slot
- auditor assignments with independence checks (no self-audit)
- rolling 3-year coverage to ensure every clause + applicable control is audited
- prior-year nonconformity follow-up scheduled in Q1
Deterministic logic. No LLM calls. Stdlib only.
Input schema (JSON):
{
"organization": "Acme AI Inc.",
"audit_year": 2026,
"certification_cycle_phase": "year_2", # year_1 | year_2 | year_3 | surveillance
"ai_systems_in_scope": ["recommendation_engine", "internal_llm_tools", "vendor_ai_chatbot"],
"applicable_annex_a_controls": ["A.2.2", "A.3.2", "A.5.2", "A.6.2.4", "A.7.3", "A.8.4", "A.9.3", "A.10.2"],
"auditors": [
{"id": "alice", "name": "Alice Chen", "role": "quality_engineer", "owns_clauses": ["8.3"]},
{"id": "bob", "name": "Bob Singh", "role": "ml_engineer", "owns_clauses": ["8.3", "A.6.2.4"]},
{"id": "carol", "name": "Carol Diaz", "role": "external_auditor", "owns_clauses": []},
{"id": "dave", "name": "Dave Park", "role": "ciso", "owns_clauses": ["A.10.2"]}
],
"prior_year_findings": [
{"clause": "9.2", "severity": "major", "status": "open"},
{"clause": "A.7.3", "severity": "minor", "status": "closed"}
]
}
Usage:
python aims_audit_scheduler.py
python aims_audit_scheduler.py path/to/scope.json
python aims_audit_scheduler.py scope.json --output json
"""
import argparse
import json
import sys
from typing import Any, Dict, List
SAMPLE: Dict[str, Any] = {
"organization": "Acme AI Inc.",
"audit_year": 2026,
"certification_cycle_phase": "year_2",
"ai_systems_in_scope": ["recommendation_engine", "internal_llm_tools", "vendor_ai_chatbot"],
"applicable_annex_a_controls": [
"A.2.2", "A.3.2", "A.5.2", "A.6.2.4", "A.7.3", "A.8.4", "A.9.3", "A.10.2"
],
"auditors": [
{"id": "alice", "name": "Alice Chen", "role": "quality_engineer", "owns_clauses": ["8.3"]},
{"id": "bob", "name": "Bob Singh", "role": "ml_engineer", "owns_clauses": ["8.3", "A.6.2.4"]},
{"id": "carol", "name": "Carol Diaz", "role": "external_auditor", "owns_clauses": []},
{"id": "dave", "name": "Dave Park", "role": "ciso", "owns_clauses": ["A.10.2"]},
],
"prior_year_findings": [
{"clause": "9.2", "severity": "major", "status": "open"},
{"clause": "A.7.3", "severity": "minor", "status": "closed"},
],
}
# Always-audit clauses (full coverage every year)
ANNUAL_CLAUSES = ["4.3", "5.1", "5.2", "5.3", "9.3", "10.2"]
# 3-year rotation for deep-dive clauses
ROTATION_Q2 = ["6.1.2", "6.1.3", "6.1.4", "6.2"]
ROTATION_Q3 = ["7.1", "7.2", "7.3", "7.4", "7.5", "8.1", "8.2", "8.3", "8.4"]
ROTATION_Q4 = ["9.1", "9.2", "10.1"]
def assign_auditor(scope_items: List[str], auditors: List[Dict[str, Any]]) -> Dict[str, Any]:
"""Pick the auditor with the fewest independence conflicts in this scope."""
best_auditor = None
best_conflicts = 999
for a in auditors:
owns = set(a.get("owns_clauses", []))
conflicts = sum(1 for s in scope_items if s in owns)
if conflicts < best_conflicts:
best_conflicts = conflicts
best_auditor = a
if best_auditor is None:
return {"id": None, "name": "UNASSIGNED", "independent": False, "conflicts": []}
owns = set(best_auditor.get("owns_clauses", []))
conflicts = [s for s in scope_items if s in owns]
return {
"id": best_auditor["id"],
"name": best_auditor["name"],
"role": best_auditor["role"],
"independent": len(conflicts) == 0,
"conflicts": conflicts,
}
def build_quarter(label: str, scope_clauses: List[str], scope_controls: List[str],
auditors: List[Dict[str, Any]], extra_notes: str = "") -> Dict[str, Any]:
all_scope = scope_clauses + scope_controls
auditor = assign_auditor(all_scope, auditors)
return {
"quarter": label,
"scope_clauses": scope_clauses,
"scope_annex_a_controls": scope_controls,
"auditor": auditor,
"notes": extra_notes,
}
def plan(payload: Dict[str, Any]) -> Dict[str, Any]:
year = int(payload.get("audit_year", 2026))
phase = payload.get("certification_cycle_phase", "year_2")
systems = payload.get("ai_systems_in_scope", [])
controls = payload.get("applicable_annex_a_controls", [])
auditors = payload.get("auditors", [])
prior_findings = payload.get("prior_year_findings", [])
open_priors = [f for f in prior_findings if f.get("status") != "closed"]
# 3-year control rotation: split applicable controls into thirds
third = max(1, len(controls) // 3)
controls_y1 = controls[0:third]
controls_y2 = controls[third:2 * third]
controls_y3 = controls[2 * third:]
phase_to_controls = {
"year_1": controls_y1, "year_2": controls_y2,
"year_3": controls_y3, "surveillance": controls_y3,
}
this_year_controls = phase_to_controls.get(phase, controls_y2)
# Q1: leadership + scope + prior-year follow-up
q1_clauses = ["4.3", "5.1", "5.2", "5.3"]
q1_notes = f"Follow up {len(open_priors)} open prior-year finding(s)." if open_priors else "No open priors."
q1 = build_quarter(f"Q1 {year}", q1_clauses, [], auditors, q1_notes)
# Q2: planning + objectives + risk
q2 = build_quarter(f"Q2 {year}", ROTATION_Q2, this_year_controls[:max(1, len(this_year_controls) // 2)], auditors)
# Q3: support + operation
q3_controls = this_year_controls[max(1, len(this_year_controls) // 2):]
q3_notes = f"Deep-dive across {len(systems)} AI systems: {', '.join(systems)}."
q3 = build_quarter(f"Q3 {year}", ROTATION_Q3, q3_controls, auditors, q3_notes)
# Q4: performance + improvement + management review
q4_notes = "Management review inputs prepared per Clause 9.3."
q4 = build_quarter(f"Q4 {year}", ROTATION_Q4 + ANNUAL_CLAUSES[-2:], [], auditors, q4_notes)
# Independence audit
quarters = [q1, q2, q3, q4]
independence_issues = [{
"quarter": q["quarter"], "auditor": q["auditor"]["name"], "conflicts": q["auditor"]["conflicts"]
} for q in quarters if not q["auditor"]["independent"]]
# Coverage check
audited_clauses = set()
audited_controls = set()
for q in quarters:
audited_clauses.update(q["scope_clauses"])
audited_controls.update(q["scope_annex_a_controls"])
return {
"organization": payload.get("organization"),
"audit_year": year,
"certification_cycle_phase": phase,
"ai_systems_in_scope": systems,
"open_prior_findings": len(open_priors),
"quarters": quarters,
"independence_issues": independence_issues,
"coverage_summary": {
"clauses_audited_this_year": sorted(audited_clauses),
"controls_audited_this_year": sorted(audited_controls),
"controls_deferred_to_future_years": sorted(
set(controls) - audited_controls
),
},
}
def render_text(p: Dict[str, Any], source: str) -> str:
lines = []
lines.append("=" * 72)
lines.append("ISO/IEC 42001 — CLAUSE 9.2 INTERNAL AUDIT PLAN")
lines.append(f"Source: {source}")
lines.append("=" * 72)
lines.append("")
lines.append(f"Organization: {p['organization']}")
lines.append(f"Year: {p['audit_year']} | Cert cycle phase: {p['certification_cycle_phase']}")
lines.append(f"AI systems in scope: {', '.join(p['ai_systems_in_scope'])}")
lines.append(f"Open prior-year findings: {p['open_prior_findings']}")
lines.append("")
lines.append("-" * 72)
lines.append("QUARTERLY SCHEDULE:")
lines.append("")
for q in p["quarters"]:
a = q["auditor"]
flag = "" if a["independent"] else " ⚠️ INDEPENDENCE CONFLICT"
lines.append(f" {q['quarter']} → Auditor: {a['name']} ({a['role']}){flag}")
if q["scope_clauses"]:
lines.append(f" Clauses: {', '.join(q['scope_clauses'])}")
if q["scope_annex_a_controls"]:
lines.append(f" Annex A: {', '.join(q['scope_annex_a_controls'])}")
if a["conflicts"]:
lines.append(f" ⚠️ Conflicts on: {', '.join(a['conflicts'])} — reassign or use external auditor")
if q["notes"]:
lines.append(f" Notes: {q['notes']}")
lines.append("")
if p["independence_issues"]:
lines.append("-" * 72)
lines.append(f"INDEPENDENCE ISSUES ({len(p['independence_issues'])}):")
for issue in p["independence_issues"]:
lines.append(f" - {issue['quarter']}: {issue['auditor']} owns {', '.join(issue['conflicts'])}")
lines.append("")
c = p["coverage_summary"]
lines.append("-" * 72)
lines.append("3-YEAR COVERAGE STATUS:")
lines.append(f" Clauses audited this year ({len(c['clauses_audited_this_year'])}): {', '.join(c['clauses_audited_this_year'])}")
lines.append(f" Annex A controls audited this year ({len(c['controls_audited_this_year'])}): {', '.join(c['controls_audited_this_year']) or 'none'}")
lines.append(f" Controls deferred to future years ({len(c['controls_deferred_to_future_years'])}): {', '.join(c['controls_deferred_to_future_years']) or 'none'}")
lines.append("")
lines.append("RULES: every clause + every applicable Annex A control must be audited at least once per 3-year cert cycle.")
lines.append(" Same auditor cannot audit work they own (Clause 9.2 independence).")
return "\n".join(lines)
def main() -> int:
parser = argparse.ArgumentParser(
description="ISO/IEC 42001 Clause 9.2 internal audit 12-month plan generator.",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=__doc__,
)
parser.add_argument("path", nargs="?", help="Path to audit scope JSON (uses embedded sample if omitted)")
parser.add_argument("--output", choices=("text", "json"), default="text", help="Output format")
args = parser.parse_args()
if args.path:
try:
with open(args.path, "r", encoding="utf-8") as f:
payload = json.load(f)
source = args.path
except (IOError, OSError) as e:
print(f"error: could not read {args.path}: {e}", file=sys.stderr)
return 1
except json.JSONDecodeError as e:
print(f"error: invalid JSON in {args.path}: {e}", file=sys.stderr)
return 1
else:
payload = SAMPLE
source = "<embedded sample: year-2 cert cycle, 3 systems, 8 controls applicable>"
result = plan(payload)
if args.output == "json":
print(json.dumps({"source": source, **result}, indent=2))
else:
print(render_text(result, source))
return 0
if __name__ == "__main__":
sys.exit(main())
FILE:scripts/aims_gap_analyzer.py
#!/usr/bin/env python3
"""aims_gap_analyzer.py — ISO/IEC 42001:2023 AIMS gap analysis against Clauses 4-10.
Stdlib-only. Scores each clause as 'full' / 'partial' / 'missing' based on an evidence
inventory and outputs a prioritized remediation list with severity at certification audit.
Deterministic logic. No LLM calls. No external dependencies.
Input schema (JSON):
{
"organization": "Acme AI Inc.",
"scope_statement": "Customer-facing recommendation engine + internal LLM tools",
"certification_target": "stage_1_audit_in_q3",
"evidence": {
"4.1_context_external": "documented",
"4.2_interested_parties": "documented",
"4.3_scope_statement": "documented",
"4.4_aims_processes": "partial",
"5.1_leadership_commitment": "documented",
"5.2_ai_policy": "partial",
"5.3_roles_responsibilities": "missing",
"6.1.2_risk_assessment": "documented",
"6.1.3_risk_treatment": "partial",
"6.1.4_impact_assessment": "missing",
"6.2_objectives": "documented",
"7.1_resources": "documented",
"7.2_competence": "missing",
"7.3_awareness": "partial",
"7.4_communication": "documented",
"7.5_documented_info": "documented",
"8.1_operational_planning": "documented",
"8.2_impact_assessment_process": "partial",
"8.3_ai_system_lifecycle": "missing",
"8.4_third_party_relationships": "partial",
"9.1_monitoring": "partial",
"9.2_internal_audit": "missing",
"9.3_management_review": "documented",
"10.1_continual_improvement": "partial",
"10.2_nonconformity_capa": "documented"
}
}
Usage:
python aims_gap_analyzer.py # uses embedded sample
python aims_gap_analyzer.py path/to/evidence.json
python aims_gap_analyzer.py evidence.json --output json
"""
import argparse
import json
import sys
from typing import Any, Dict, List
SAMPLE: Dict[str, Any] = {
"organization": "Acme AI Inc.",
"scope_statement": "Customer-facing recommendation engine + internal LLM tools",
"certification_target": "stage_1_audit_in_q3",
"evidence": {
"4.1_context_external": "documented",
"4.2_interested_parties": "documented",
"4.3_scope_statement": "documented",
"4.4_aims_processes": "partial",
"5.1_leadership_commitment": "documented",
"5.2_ai_policy": "partial",
"5.3_roles_responsibilities": "missing",
"6.1.2_risk_assessment": "documented",
"6.1.3_risk_treatment": "partial",
"6.1.4_impact_assessment": "missing",
"6.2_objectives": "documented",
"7.1_resources": "documented",
"7.2_competence": "missing",
"7.3_awareness": "partial",
"7.4_communication": "documented",
"7.5_documented_info": "documented",
"8.1_operational_planning": "documented",
"8.2_impact_assessment_process": "partial",
"8.3_ai_system_lifecycle": "missing",
"8.4_third_party_relationships": "partial",
"9.1_monitoring": "partial",
"9.2_internal_audit": "missing",
"9.3_management_review": "documented",
"10.1_continual_improvement": "partial",
"10.2_nonconformity_capa": "documented",
},
}
# Clause requirements + severity if missing
# severity: 'critical' = major nonconformity at stage 1, blocks certification
# 'major' = major nonconformity at stage 2
# 'minor' = minor nonconformity, requires corrective action plan
# 'observation' = improvement opportunity
CLAUSE_REQUIREMENTS: Dict[str, Dict[str, Any]] = {
"4.1_context_external": {"clause": "4.1", "title": "External & internal context", "severity": "minor"},
"4.2_interested_parties": {"clause": "4.2", "title": "Interested parties", "severity": "minor"},
"4.3_scope_statement": {"clause": "4.3", "title": "AIMS scope statement", "severity": "critical"},
"4.4_aims_processes": {"clause": "4.4", "title": "AIMS processes & interactions", "severity": "major"},
"5.1_leadership_commitment": {"clause": "5.1", "title": "Leadership commitment", "severity": "major"},
"5.2_ai_policy": {"clause": "5.2", "title": "AI policy", "severity": "critical"},
"5.3_roles_responsibilities": {"clause": "5.3", "title": "Roles, responsibilities, authorities", "severity": "critical"},
"6.1.2_risk_assessment": {"clause": "6.1.2", "title": "AI risk assessment", "severity": "critical"},
"6.1.3_risk_treatment": {"clause": "6.1.3", "title": "AI risk treatment", "severity": "critical"},
"6.1.4_impact_assessment": {"clause": "6.1.4", "title": "AI system impact assessment", "severity": "major"},
"6.2_objectives": {"clause": "6.2", "title": "AI objectives & planning", "severity": "minor"},
"7.1_resources": {"clause": "7.1", "title": "Resources", "severity": "minor"},
"7.2_competence": {"clause": "7.2", "title": "Competence", "severity": "major"},
"7.3_awareness": {"clause": "7.3", "title": "Awareness", "severity": "minor"},
"7.4_communication": {"clause": "7.4", "title": "Communication", "severity": "minor"},
"7.5_documented_info": {"clause": "7.5", "title": "Documented information", "severity": "major"},
"8.1_operational_planning": {"clause": "8.1", "title": "Operational planning & control", "severity": "major"},
"8.2_impact_assessment_process": {"clause": "8.2", "title": "Impact assessment process", "severity": "major"},
"8.3_ai_system_lifecycle": {"clause": "8.3", "title": "AI system lifecycle process", "severity": "critical"},
"8.4_third_party_relationships": {"clause": "8.4", "title": "Third-party / customer relationships", "severity": "major"},
"9.1_monitoring": {"clause": "9.1", "title": "Monitoring, measurement, analysis, evaluation", "severity": "major"},
"9.2_internal_audit": {"clause": "9.2", "title": "Internal audit programme", "severity": "critical"},
"9.3_management_review": {"clause": "9.3", "title": "Management review", "severity": "critical"},
"10.1_continual_improvement": {"clause": "10.1", "title": "Continual improvement", "severity": "minor"},
"10.2_nonconformity_capa": {"clause": "10.2", "title": "Nonconformity & corrective action", "severity": "major"},
}
STATUS_SCORE = {"documented": 1.0, "partial": 0.5, "missing": 0.0}
SEVERITY_RANK = {"critical": 0, "major": 1, "minor": 2, "observation": 3}
def remediation_action(req_key: str, status: str) -> str:
"""Deterministic one-sentence next step per (clause, status)."""
if status == "documented":
return "Maintain via management review; re-verify at next internal audit."
titles = CLAUSE_REQUIREMENTS[req_key]["title"]
if status == "partial":
return f"Complete documentation of '{titles}' — confirm signoff, version control, evidence trail."
return f"Create from scratch: '{titles}'. Assign owner; target close before stage 1 audit."
def analyze(payload: Dict[str, Any]) -> Dict[str, Any]:
evidence = payload.get("evidence", {})
findings: List[Dict[str, Any]] = []
total_weight = 0.0
achieved_weight = 0.0
for req_key, meta in CLAUSE_REQUIREMENTS.items():
status = evidence.get(req_key, "missing")
score = STATUS_SCORE.get(status, 0.0)
# Severity-weighted: critical = 4, major = 2, minor = 1
weight = {"critical": 4, "major": 2, "minor": 1, "observation": 1}[meta["severity"]]
total_weight += weight
achieved_weight += weight * score
findings.append({
"clause": meta["clause"],
"title": meta["title"],
"status": status,
"severity_if_missing": meta["severity"],
"remediation": remediation_action(req_key, status),
})
coverage_pct = round((achieved_weight / total_weight) * 100, 1) if total_weight else 0
# Sort findings: missing/partial first by severity, then documented last
def sort_key(f: Dict[str, Any]) -> tuple:
status_order = {"missing": 0, "partial": 1, "documented": 2}
return (status_order[f["status"]], SEVERITY_RANK[f["severity_if_missing"]], f["clause"])
findings.sort(key=sort_key)
open_gaps = [f for f in findings if f["status"] != "documented"]
critical_gaps = [f for f in open_gaps if f["severity_if_missing"] == "critical"]
major_gaps = [f for f in open_gaps if f["severity_if_missing"] == "major"]
readiness = "ready" if not critical_gaps and len(major_gaps) <= 1 else (
"stage_2_candidate" if not critical_gaps else "not_ready"
)
return {
"organization": payload.get("organization"),
"scope": payload.get("scope_statement"),
"coverage_pct_weighted": coverage_pct,
"certification_readiness": readiness,
"critical_gap_count": len(critical_gaps),
"major_gap_count": len(major_gaps),
"open_gap_count": len(open_gaps),
"findings": findings,
}
def render_text(r: Dict[str, Any], source: str) -> str:
lines = []
lines.append("=" * 72)
lines.append("ISO/IEC 42001 AIMS — GAP ANALYSIS")
lines.append(f"Source: {source}")
lines.append("=" * 72)
lines.append("")
lines.append(f"Organization: {r['organization']}")
lines.append(f"Scope: {r['scope']}")
lines.append(f"Weighted coverage: {r['coverage_pct_weighted']}%")
lines.append(f"Certification readiness: {r['certification_readiness']}")
lines.append(f"Critical gaps: {r['critical_gap_count']} | Major gaps: {r['major_gap_count']} | Open total: {r['open_gap_count']}")
lines.append("")
lines.append("-" * 72)
lines.append("FINDINGS (open gaps first; critical highlighted):")
lines.append("")
for f in r["findings"]:
marker = {"missing": "[X] ", "partial": "[~] ", "documented": "[✓] "}[f["status"]]
sev = f["severity_if_missing"].upper() if f["status"] != "documented" else "OK"
lines.append(f" {marker}Clause {f['clause']:6s} {f['title']:50s} [{sev}]")
if f["status"] != "documented":
lines.append(f" → {f['remediation']}")
lines.append("")
lines.append("-" * 72)
lines.append("READINESS RULE: 'ready' = 0 critical AND ≤ 1 major. 'stage_2_candidate' = 0 critical.")
lines.append(" Any critical gap blocks stage 1 certification.")
return "\n".join(lines)
def main() -> int:
parser = argparse.ArgumentParser(
description="ISO/IEC 42001 AIMS gap analysis across Clauses 4-10.",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=__doc__,
)
parser.add_argument("path", nargs="?", help="Path to AIMS evidence JSON (uses embedded sample if omitted)")
parser.add_argument("--output", choices=("text", "json"), default="text", help="Output format")
args = parser.parse_args()
if args.path:
try:
with open(args.path, "r", encoding="utf-8") as f:
payload = json.load(f)
source = args.path
except (IOError, OSError) as e:
print(f"error: could not read {args.path}: {e}", file=sys.stderr)
return 1
except json.JSONDecodeError as e:
print(f"error: invalid JSON in {args.path}: {e}", file=sys.stderr)
return 1
else:
payload = SAMPLE
source = "<embedded sample: mid-stage AI SaaS, pre stage-1 audit>"
result = analyze(payload)
if args.output == "json":
print(json.dumps({"source": source, **result}, indent=2))
else:
print(render_text(result, source))
return 0
if __name__ == "__main__":
sys.exit(main())
FILE:scripts/ai_risk_register_builder.py
#!/usr/bin/env python3
"""ai_risk_register_builder.py — ISO/IEC 42001 Annex A risk register + control mapping.
Stdlib-only. Takes identified AI risks (per ISO 23894 risk identification) and produces a
structured register with:
- severity rating (likelihood × impact, 5x5 matrix)
- mapped Annex A controls (treatment selection)
- residual risk verdict (accept / additional treatment required / escalate)
- treatment option per ISO 23894 (modify / share / retain / avoid)
Deterministic logic per ISO 23894:2023 risk-management process. No LLM calls.
Input schema (JSON):
{
"organization": "Acme AI Inc.",
"ai_system": "Customer recommendation engine v3",
"risks": [
{
"id": "R-001",
"source": "training_data",
"event": "Biased dataset over-represents one demographic",
"consequence": "Discriminatory recommendations; regulatory exposure",
"likelihood": 3, # 1-5
"impact": 4, # 1-5
"controls_applied": ["A.7.3", "A.7.5", "A.5.2"]
}
]
}
Usage:
python ai_risk_register_builder.py # uses embedded 7-risk sample
python ai_risk_register_builder.py path/to/risks.json
python ai_risk_register_builder.py risks.json --output json
"""
import argparse
import json
import sys
from typing import Any, Dict, List
SAMPLE: Dict[str, Any] = {
"organization": "Acme AI Inc.",
"ai_system": "Customer recommendation engine v3",
"risks": [
{"id": "R-001", "source": "training_data", "event": "Biased dataset over-represents one demographic",
"consequence": "Discriminatory recommendations; regulatory exposure", "likelihood": 3, "impact": 4,
"controls_applied": ["A.7.3", "A.7.5", "A.5.2"]},
{"id": "R-002", "source": "model", "event": "Concept drift after 6 months in production",
"consequence": "Accuracy degradation; revenue impact", "likelihood": 4, "impact": 3,
"controls_applied": ["A.9.3", "A.6.2.4"]},
{"id": "R-003", "source": "deployment", "event": "Inference latency spike under load",
"consequence": "User-visible failure; SLO breach", "likelihood": 3, "impact": 2,
"controls_applied": ["A.9.3"]},
{"id": "R-004", "source": "third_party", "event": "Foundation-model API provider deprecates endpoint",
"consequence": "Service disruption; migration cost", "likelihood": 2, "impact": 4,
"controls_applied": ["A.10.2"]},
{"id": "R-005", "source": "data", "event": "Training data contains PII that should not be retained",
"consequence": "GDPR fine; trust loss", "likelihood": 2, "impact": 5,
"controls_applied": ["A.7.2", "A.7.4"]},
{"id": "R-006", "source": "human_oversight", "event": "High-impact decisions deployed without impact assessment",
"consequence": "Untracked harm; certification nonconformity", "likelihood": 3, "impact": 5,
"controls_applied": []},
{"id": "R-007", "source": "model", "event": "Adversarial prompt injection bypasses content filter",
"consequence": "Toxic output to end users; reputational damage", "likelihood": 4, "impact": 4,
"controls_applied": ["A.6.2.4", "A.9.3", "A.9.4"]},
],
}
# Severity matrix (5x5): likelihood (1-5) × impact (1-5)
# Score 1-4 = low, 5-9 = medium, 10-16 = high, 17-25 = critical
def severity_rating(likelihood: int, impact: int) -> str:
score = max(1, min(5, likelihood)) * max(1, min(5, impact))
if score <= 4:
return "low"
if score <= 9:
return "medium"
if score <= 16:
return "high"
return "critical"
# ISO 23894 risk treatment options
# - modify (apply controls to reduce likelihood/impact)
# - share (transfer via insurance, third-party contracts)
# - retain (accept residual risk with management signoff)
# - avoid (eliminate the activity entirely)
def treatment_option(severity: str, controls_count: int) -> str:
if severity == "critical" and controls_count == 0:
return "avoid_or_escalate"
if severity in ("high", "critical"):
return "modify"
if severity == "medium":
return "modify" if controls_count < 2 else "retain"
return "retain"
# Residual-risk verdict after applied controls
def residual_verdict(severity: str, controls_count: int) -> str:
"""How many controls are 'enough' for each severity tier (heuristic, ISO 23894 Annex A guidance)."""
expected = {"low": 0, "medium": 1, "high": 2, "critical": 3}[severity]
if controls_count >= expected:
return "acceptable" if severity != "critical" else "acceptable_with_management_signoff"
return "additional_treatment_required"
# Annex A control descriptions (subset, for output annotation)
ANNEX_A_CATALOG: Dict[str, str] = {
"A.2.2": "AI policy",
"A.2.3": "Alignment of AI policy with other organizational policies",
"A.3.2": "AI roles & responsibilities",
"A.3.3": "Reporting of concerns",
"A.4.2": "Resources for AI systems — data",
"A.4.3": "Resources for AI systems — tooling",
"A.4.4": "Resources for AI systems — human resources",
"A.5.2": "AI system impact assessment",
"A.5.4": "Documentation of impact assessment",
"A.6.2.2": "AI system objectives",
"A.6.2.3": "AI system lifecycle phases",
"A.6.2.4": "Verification & validation of AI system",
"A.7.2": "Data management for AI systems",
"A.7.3": "Data quality",
"A.7.4": "Data provenance",
"A.7.5": "Data preparation",
"A.8.2": "System documentation for users",
"A.8.3": "User information",
"A.8.4": "Communication of AI incidents",
"A.9.2": "Intended use of AI system",
"A.9.3": "Monitoring of AI system operation",
"A.9.4": "Logging of AI system events",
"A.10.2": "Supplier (third-party) relationships",
"A.10.3": "Customer relationships",
}
def annotate_risk(risk: Dict[str, Any]) -> Dict[str, Any]:
likelihood = int(risk.get("likelihood", 0))
impact = int(risk.get("impact", 0))
controls = list(risk.get("controls_applied", []))
sev = severity_rating(likelihood, impact)
treatment = treatment_option(sev, len(controls))
residual = residual_verdict(sev, len(controls))
return {
"id": risk.get("id"),
"source": risk.get("source"),
"event": risk.get("event"),
"consequence": risk.get("consequence"),
"likelihood": likelihood,
"impact": impact,
"severity_score": likelihood * impact,
"severity": sev,
"controls_applied": [{"id": c, "title": ANNEX_A_CATALOG.get(c, "<unknown control>")} for c in controls],
"control_count": len(controls),
"treatment_option": treatment,
"residual_verdict": residual,
}
def analyze(payload: Dict[str, Any]) -> Dict[str, Any]:
risks = [annotate_risk(r) for r in payload.get("risks", [])]
# Sort by severity (critical first), then by control gap (largest first)
sev_rank = {"critical": 0, "high": 1, "medium": 2, "low": 3}
risks.sort(key=lambda r: (sev_rank[r["severity"]], -r["severity_score"]))
counts_by_sev = {s: 0 for s in sev_rank}
requires_action = 0
for r in risks:
counts_by_sev[r["severity"]] += 1
if r["residual_verdict"] == "additional_treatment_required":
requires_action += 1
return {
"organization": payload.get("organization"),
"ai_system": payload.get("ai_system"),
"total_risks": len(risks),
"by_severity": counts_by_sev,
"requires_additional_treatment": requires_action,
"risks": risks,
}
def render_text(r: Dict[str, Any], source: str) -> str:
lines = []
lines.append("=" * 72)
lines.append("AI RISK REGISTER — ISO/IEC 42001 Annex A + ISO 23894 treatment")
lines.append(f"Source: {source}")
lines.append("=" * 72)
lines.append("")
lines.append(f"Organization: {r['organization']}")
lines.append(f"AI system: {r['ai_system']}")
lines.append(f"Total risks: {r['total_risks']}")
s = r["by_severity"]
lines.append(f"By severity: critical={s['critical']} high={s['high']} medium={s['medium']} low={s['low']}")
lines.append(f"Risks requiring additional treatment: {r['requires_additional_treatment']}")
lines.append("")
lines.append("-" * 72)
lines.append("REGISTER (highest severity first):")
lines.append("")
for risk in r["risks"]:
lines.append(f" [{risk['id']}] {risk['event']}")
lines.append(f" Source: {risk['source']} | L={risk['likelihood']} × I={risk['impact']} = {risk['severity_score']} → {risk['severity'].upper()}")
lines.append(f" Consequence: {risk['consequence']}")
if risk["controls_applied"]:
ctrl_str = ", ".join(c["id"] for c in risk["controls_applied"])
lines.append(f" Controls applied ({risk['control_count']}): {ctrl_str}")
else:
lines.append(f" Controls applied: NONE")
lines.append(f" Treatment option: {risk['treatment_option']}")
lines.append(f" Residual verdict: {risk['residual_verdict']}")
lines.append("")
lines.append("-" * 72)
lines.append("RULES:")
lines.append(" - 'critical' severity (score 17-25) WITHOUT controls → 'avoid_or_escalate' to management.")
lines.append(" - 'additional_treatment_required' → add Annex A controls or formally accept residual risk in writing.")
lines.append(" - All 'retain' verdicts require Clause 6.1.3 risk-treatment plan signoff.")
return "\n".join(lines)
def main() -> int:
parser = argparse.ArgumentParser(
description="ISO/IEC 42001 Annex A risk register builder with ISO 23894 treatment options.",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=__doc__,
)
parser.add_argument("path", nargs="?", help="Path to risks JSON (uses embedded sample if omitted)")
parser.add_argument("--output", choices=("text", "json"), default="text", help="Output format")
args = parser.parse_args()
if args.path:
try:
with open(args.path, "r", encoding="utf-8") as f:
payload = json.load(f)
source = args.path
except (IOError, OSError) as e:
print(f"error: could not read {args.path}: {e}", file=sys.stderr)
return 1
except json.JSONDecodeError as e:
print(f"error: invalid JSON in {args.path}: {e}", file=sys.stderr)
return 1
else:
payload = SAMPLE
source = "<embedded sample: 7-risk recommendation engine register>"
result = analyze(payload)
if args.output == "json":
print(json.dumps({"source": source, **result}, indent=2))
else:
print(render_text(result, source))
return 0
if __name__ == "__main__":
sys.exit(main())
Thiết lập và quản lý dự án Jira: lập kế hoạch, JQL, workflow, trường tùy chỉnh, tự động hóa, dashboard và báo cáo.
---
name: "jira-expert"
description: Atlassian Jira expert for creating and managing projects, planning, product discovery, JQL queries, workflows, custom fields, automation, reporting, and all Jira features. Use for Jira project setup, configuration, advanced search, dashboard creation, workflow design, and technical Jira operations.
---
# Atlassian Jira Expert
Master-level expertise in Jira configuration, project management, JQL, workflows, automation, and reporting. Handles all technical and operational aspects of Jira.
## Quick Start — Most Common Operations
**Create a project**:
```
mcp jira create_project --name "My Project" --key "MYPROJ" --type scrum --lead "user@example.com"
```
**Run a JQL query**:
```
mcp jira search_issues --jql "project = MYPROJ AND status != Done AND dueDate < now()" --maxResults 50
```
For full command reference, see [Atlassian MCP Integration](#atlassian-mcp-integration). For JQL functions, see [JQL Functions Reference](#jql-functions-reference). For report templates, see [Reporting Templates](#reporting-templates).
---
## Workflows
### Project Creation
1. Determine project type (Scrum, Kanban, Bug Tracking, etc.)
2. Create project with appropriate template
3. Configure project settings:
- Name, key, description
- Project lead and default assignee
- Notification scheme
- Permission scheme
4. Set up issue types and workflows
5. Configure custom fields if needed
6. Create initial board/backlog view
7. **HANDOFF TO**: Scrum Master for team onboarding
### Workflow Design
1. Map out process states (To Do → In Progress → Done)
2. Define transitions and conditions
3. Add validators, post-functions, and conditions
4. Configure workflow scheme
5. **Validate**: Deploy to a test project first; verify all transitions, conditions, and post-functions behave as expected before associating with production projects
6. Associate workflow with project
7. Test workflow with sample issues
### JQL Query Building
**Basic Structure**: `field operator value`
**Common Operators**:
- `=, !=` : equals, not equals
- `~, !~` : contains, not contains
- `>, <, >=, <=` : comparison
- `in, not in` : list membership
- `is empty, is not empty`
- `was, was in, was not`
- `changed`
**Powerful JQL Examples**:
Find overdue issues:
```jql
dueDate < now() AND status != Done
```
Sprint burndown issues:
```jql
sprint = 23 AND status changed TO "Done" DURING (startOfSprint(), endOfSprint())
```
Find stale issues:
```jql
updated < -30d AND status != Done
```
Cross-project epic tracking:
```jql
"Epic Link" = PROJ-123 ORDER BY rank
```
Velocity calculation:
```jql
sprint in closedSprints() AND resolution = Done
```
Team capacity:
```jql
assignee in (user1, user2) AND sprint in openSprints()
```
### Dashboard Creation
1. Create new dashboard (personal or shared)
2. Add relevant gadgets:
- Filter Results (JQL-based)
- Sprint Burndown
- Velocity Chart
- Created vs Resolved
- Pie Chart (status distribution)
3. Arrange layout for readability
4. Configure automatic refresh
5. Share with appropriate teams
6. **HANDOFF TO**: Senior PM or Scrum Master for use
### Automation Rules
1. Define trigger (issue created, field changed, scheduled)
2. Add conditions (if applicable)
3. Define actions:
- Update field
- Send notification
- Create subtask
- Transition issue
- Post comment
4. Test automation with sample data
5. Enable and monitor
## Advanced Features
### Custom Fields
**When to Create**:
- Track data not in standard fields
- Capture process-specific information
- Enable advanced reporting
**Field Types**: Text, Numeric, Date, Select (single/multi/cascading), User picker
**Configuration**:
1. Create custom field
2. Configure field context (which projects/issue types)
3. Add to appropriate screens
4. Update search templates if needed
### Issue Linking
**Link Types**:
- Blocks / Is blocked by
- Relates to
- Duplicates / Is duplicated by
- Clones / Is cloned by
- Epic-Story relationship
**Best Practices**:
- Use Epic linking for feature grouping
- Use blocking links to show dependencies
- Document link reasons in comments
### Permissions & Security
**Permission Schemes**:
- Browse Projects
- Create/Edit/Delete Issues
- Administer Projects
- Manage Sprints
**Security Levels**:
- Define confidential issue visibility
- Control access to sensitive data
- Audit security changes
### Bulk Operations
**Bulk Change**:
1. Use JQL to find target issues
2. Select bulk change operation
3. Choose fields to update
4. **Validate**: Preview all changes before executing; confirm the JQL filter matches only intended issues — bulk edits are difficult to reverse
5. Execute and confirm
6. Monitor background task
**Bulk Transitions**:
- Move multiple issues through workflow
- Useful for sprint cleanup
- Requires appropriate permissions
- **Validate**: Run the JQL filter and review results in small batches before applying at scale
## JQL Functions Reference
> **Tip**: Save frequently used queries as named filters instead of re-running complex JQL ad hoc. See [Best Practices](#best-practices) for performance guidance.
**Date**: `startOfDay()`, `endOfDay()`, `startOfWeek()`, `endOfWeek()`, `startOfMonth()`, `endOfMonth()`, `startOfYear()`, `endOfYear()`
**Sprint**: `openSprints()`, `closedSprints()`, `futureSprints()`
**User**: `currentUser()`, `membersOf("group")`
**Advanced**: `issueHistory()`, `linkedIssues()`, `issuesWithFixVersions()`
## Reporting Templates
> **Tip**: These JQL snippets can be saved as shared filters or wired directly into Dashboard gadgets (see [Dashboard Creation](#dashboard-creation)).
| Report | JQL |
|---|---|
| Sprint Report | `project = PROJ AND sprint = 23` |
| Team Velocity | `assignee in (team) AND sprint in closedSprints() AND resolution = Done` |
| Bug Trend | `type = Bug AND created >= -30d` |
| Blocker Analysis | `priority = Blocker AND status != Done` |
## Decision Framework
**When to Escalate to Atlassian Admin**:
- Need new project permission scheme
- Require custom workflow scheme across org
- User provisioning or deprovisioning
- License or billing questions
- System-wide configuration changes
**When to Collaborate with Scrum Master**:
- Sprint board configuration
- Backlog prioritization views
- Team-specific filters
- Sprint reporting needs
**When to Collaborate with Senior PM**:
- Portfolio-level reporting
- Cross-project dashboards
- Executive visibility needs
- Multi-project dependencies
## Handoff Protocols
**FROM Senior PM**:
- Project structure requirements
- Workflow and field needs
- Reporting requirements
- Integration needs
**TO Senior PM**:
- Cross-project metrics
- Issue trends and patterns
- Workflow bottlenecks
- Data quality insights
**FROM Scrum Master**:
- Sprint board configuration requests
- Workflow optimization needs
- Backlog filtering requirements
- Velocity tracking setup
**TO Scrum Master**:
- Configured sprint boards
- Velocity reports
- Burndown charts
- Team capacity views
## Best Practices
**Data Quality**:
- Enforce required fields with field validation rules
- Use consistent issue key naming conventions per project type
- Schedule regular cleanup of stale/orphaned issues
**Performance**:
- Avoid leading wildcards in JQL (`~` on large text fields is expensive)
- Use saved filters instead of re-running complex JQL ad hoc
- Limit dashboard gadgets to reduce page load time
- Archive completed projects rather than deleting to preserve history
**Governance**:
- Document rationale for custom workflow states and transitions
- Version-control permission/workflow schemes before making changes
- Require change management review for org-wide scheme updates
- Run permission audits after user role changes
## Atlassian MCP Integration
**Primary Tool**: Jira MCP Server
**Key Operations with Example Commands**:
Create a project:
```
mcp jira create_project --name "My Project" --key "MYPROJ" --type scrum --lead "user@example.com"
```
Execute a JQL query:
```
mcp jira search_issues --jql "project = MYPROJ AND status != Done AND dueDate < now()" --maxResults 50
```
Update an issue field:
```
mcp jira update_issue --issue "MYPROJ-42" --field "status" --value "In Progress"
```
Create a sprint:
```
mcp jira create_sprint --board 10 --name "Sprint 5" --startDate "2024-06-01" --endDate "2024-06-14"
```
Create a board filter:
```
mcp jira create_filter --name "Open Blockers" --jql "priority = Blocker AND status != Done" --shareWith "project-team"
```
**Integration Points**:
- Pull metrics for Senior PM reporting
- Configure sprint boards for Scrum Master
- Create documentation pages for Confluence Expert
- Support template creation for Template Creator
## Related Skills
- **Confluence Expert** (`project-management/confluence-expert/`) — Documentation complements Jira workflows
- **Atlassian Admin** (`project-management/atlassian-admin/`) — Permission and user management for Jira projects
FILE:references/automation-examples.md
# Jira Automation Examples
## Auto-Assignment Rules
### Auto-assign by component
**Trigger:** Issue created
**Conditions:**
- Component is not EMPTY
**Actions:**
- Assign issue to component lead
### Auto-assign to reporter for feedback
**Trigger:** Issue transitioned to "Waiting for Feedback"
**Actions:**
- Assign issue to reporter
- Add comment: "Please provide additional information"
### Round-robin assignment
**Trigger:** Issue created
**Conditions:**
- Project = ABC
- Assignee is EMPTY
**Actions:**
- Assign to next team member in rotation (use smart value)
---
## Status Sync Rules
### Sync subtask status to parent
**Trigger:** Issue transitioned
**Conditions:**
- Issue type = Sub-task
- Transition is to "Done"
- Parent issue exists
- All subtasks are Done
**Actions:**
- Transition parent issue to "Done"
### Sync parent to subtasks
**Trigger:** Issue transitioned
**Conditions:**
- Issue type has subtasks
- Transition is to "Cancelled"
**Actions:**
- For each: Sub-tasks
- Transition issue to "Cancelled"
### Epic progress tracking
**Trigger:** Issue transitioned
**Conditions:**
- Epic link is not EMPTY
- Transition is to "Done"
**Actions:**
- Add comment to epic: "{{issue.key}} completed"
- Update epic custom field "Progress"
---
## Notification Rules
### Slack notification for high-priority bugs
**Trigger:** Issue created
**Conditions:**
- Issue type = Bug
- Priority IN (Highest, High)
**Actions:**
- Send Slack message to #engineering:
```
🚨 High Priority Bug Created
{{issue.key}}: {{issue.summary}}
Reporter: {{issue.reporter.displayName}}
Priority: {{issue.priority.name}}
{{issue.url}}
```
### Email assignee when mentioned
**Trigger:** Issue commented
**Conditions:**
- Comment contains @mention of assignee
**Actions:**
- Send email to {{issue.assignee.emailAddress}}:
```
Subject: You were mentioned in {{issue.key}}
Body: {{comment.author.displayName}} mentioned you:
{{comment.body}}
```
### SLA breach warning
**Trigger:** Scheduled - Every hour
**Conditions:**
- Status != Done
- SLA time remaining < 2 hours
**Actions:**
- Send email to {{issue.assignee}}
- Add comment: "⚠️ SLA expires in <2 hours"
- Set priority to Highest
---
## Field Automation Rules
### Auto-set due date
**Trigger:** Issue created
**Conditions:**
- Issue type = Bug
- Priority = Highest
**Actions:**
- Set due date to {{now.plusDays(1)}}
### Clear assignee when in backlog
**Trigger:** Issue transitioned
**Conditions:**
- Transition is to "Backlog"
- Assignee is not EMPTY
**Actions:**
- Assign issue to Unassigned
- Add comment: "Returned to backlog, assignee cleared"
### Auto-populate sprint field
**Trigger:** Issue transitioned
**Conditions:**
- Transition is to "In Progress"
- Sprint is EMPTY
**Actions:**
- Add issue to current sprint
### Set fix version based on component
**Trigger:** Issue created
**Conditions:**
- Component = "Mobile App"
**Actions:**
- Set fix version to "Mobile v2.0"
---
## Escalation Rules
### Auto-escalate stale issues
**Trigger:** Scheduled - Daily at 9:00 AM
**Conditions:**
- Status = "Waiting for Response"
- Updated < -7 days
**Actions:**
- Add comment: "@{{issue.reporter}} This issue needs attention"
- Send email to project lead
- Add label: "needs-attention"
### Escalate overdue critical issues
**Trigger:** Scheduled - Every hour
**Conditions:**
- Priority IN (Highest, High)
- Due date < now()
- Status != Done
**Actions:**
- Transition to "Escalated"
- Assign to project manager
- Send Slack notification
### Auto-close inactive issues
**Trigger:** Scheduled - Daily at 10:00 AM
**Conditions:**
- Status = "Waiting for Customer"
- Updated < -30 days
**Actions:**
- Transition to "Closed"
- Add comment: "Auto-closed due to inactivity"
- Send email to reporter
---
## Sprint Automation Rules
### Move incomplete work to next sprint
**Trigger:** Sprint closed
**Conditions:**
- Issue status != Done
**Actions:**
- Add issue to next sprint
- Add comment: "Moved from {{sprint.name}}"
### Auto-remove completed items from active sprint
**Trigger:** Issue transitioned
**Conditions:**
- Transition is to "Done"
- Sprint IN openSprints()
**Actions:**
- Remove issue from sprint
- Add comment: "Removed from active sprint (completed)"
### Sprint start notification
**Trigger:** Sprint started
**Actions:**
- Send Slack message to #team:
```
🚀 Sprint {{sprint.name}} Started!
Goal: {{sprint.goal}}
Committed: {{sprint.issuesCount}} issues
```
---
## Approval Workflow Rules
### Request approval for large stories
**Trigger:** Issue created
**Conditions:**
- Issue type = Story
- Story points >= 13
**Actions:**
- Transition to "Pending Approval"
- Assign to product owner
- Send email notification
### Auto-approve small bugs
**Trigger:** Issue created
**Conditions:**
- Issue type = Bug
- Priority IN (Low, Lowest)
**Actions:**
- Transition to "Approved"
- Add comment: "Auto-approved (low-priority bug)"
### Require security review
**Trigger:** Issue transitioned
**Conditions:**
- Transition is to "Ready for Release"
- Labels contains "security"
**Actions:**
- Transition to "Security Review"
- Assign to security-team
- Send email to security@company.com
---
## Integration Rules
### Create GitHub issue
**Trigger:** Issue transitioned
**Conditions:**
- Transition is to "In Progress"
- Labels contains "needs-tracking"
**Actions:**
- Send webhook to GitHub API:
```json
{
"title": "{{issue.key}}: {{issue.summary}}",
"body": "{{issue.description}}",
"assignee": "{{issue.assignee.name}}"
}
```
### Update Confluence page
**Trigger:** Issue transitioned
**Conditions:**
- Issue type = Epic
- Transition is to "Done"
**Actions:**
- Send webhook to Confluence:
- Update epic status page
- Add completion date
---
## Quality & Testing Rules
### Require test cases for features
**Trigger:** Issue transitioned
**Conditions:**
- Issue type = Story
- Transition is to "Ready for QA"
- Custom field "Test Cases" is EMPTY
**Actions:**
- Transition back to "In Progress"
- Add comment: "❌ Test cases required before QA"
### Auto-create test issue
**Trigger:** Issue transitioned
**Conditions:**
- Issue type = Story
- Transition is to "Ready for QA"
**Actions:**
- Create linked issue:
- Type: Test
- Summary: "Test: {{issue.summary}}"
- Link type: "tested by"
- Assignee: QA team
### Flag regression bugs
**Trigger:** Issue created
**Conditions:**
- Issue type = Bug
- Affects version is in released versions
**Actions:**
- Add label: "regression"
- Set priority to High
- Add comment: "🚨 Regression in released version"
---
## Documentation Rules
### Require documentation for features
**Trigger:** Issue transitioned
**Conditions:**
- Issue type = Story
- Labels contains "customer-facing"
- Transition is to "Done"
- Custom field "Documentation Link" is EMPTY
**Actions:**
- Reopen issue
- Add comment: "📝 Documentation required for customer-facing feature"
### Auto-create doc task
**Trigger:** Issue transitioned
**Conditions:**
- Issue type = Epic
- Transition is to "In Progress"
**Actions:**
- Create subtask:
- Type: Task
- Summary: "Documentation for {{issue.summary}}"
- Assignee: {{issue.assignee}}
---
## Time Tracking Rules
### Log work reminder
**Trigger:** Issue transitioned
**Conditions:**
- Transition is to "Done"
- Time spent is EMPTY
**Actions:**
- Add comment: "⏱️ Reminder: Please log your time"
### Warn on high time spent
**Trigger:** Work logged
**Conditions:**
- Time spent > original estimate * 1.5
**Actions:**
- Add comment: "⚠️ Time spent exceeds estimate by 50%"
- Send notification to assignee and project manager
---
## Advanced Conditional Rules
### Conditional assignee based on priority
**Trigger:** Issue created
**Conditions:**
- Issue type = Bug
**Actions:**
- If: Priority = Highest
- Assign to on-call engineer
- Else if: Priority = High
- Assign to team lead
- Else:
- Assign to next available team member
### Multi-step approval flow
**Trigger:** Issue transitioned
**Conditions:**
- Transition is to "Request Approval"
- Budget estimate > $10,000
**Actions:**
- If: Budget > $50,000
- Assign to CFO
- Send email to executive team
- Else if: Budget > $10,000
- Assign to Director
- Add comment: "Director approval required"
- Add label: "pending-approval"
---
## Smart Value Examples
### Dynamic assignee based on component
```
{{issue.components.first.lead.accountId}}
```
### Days since created
```
{{issue.created.diff(now).days}}
```
### Conditional message
```
{{#if(issue.priority.name == "Highest")}}
🚨 CRITICAL
{{else}}
ℹ️ Normal priority
{{/}}
```
### List all subtasks
```
{{#issue.subtasks}}
- {{key}}: {{summary}} ({{status.name}})
{{/}}
```
### Calculate completion percentage
```
{{issue.subtasks.filter(item => item.status.statusCategory.key == "done").size.divide(issue.subtasks.size).multiply(100).round()}}%
```
---
## Best Practices
1. **Test in sandbox** - Always test rules on test project first
2. **Start simple** - Begin with basic rules, add complexity incrementally
3. **Use conditions wisely** - Narrow scope to reduce unintended triggers
4. **Monitor audit log** - Check automation execution history regularly
5. **Limit actions** - Keep rules focused, don't chain too many actions
6. **Name clearly** - Use descriptive names: "Auto-assign bugs to component lead"
7. **Document rules** - Add description explaining purpose and owner
8. **Review regularly** - Audit rules quarterly, disable unused ones
9. **Handle errors** - Add error handling for webhooks and integrations
10. **Performance** - Avoid scheduled rules that query large datasets hourly
FILE:references/AUTOMATION.md
# Jira Automation Reference
Comprehensive guide to Jira automation rules: triggers, conditions, actions, smart values, and production-ready recipes.
## Rule Structure
Every automation rule follows this pattern:
```
TRIGGER → [CONDITION(s)] → ACTION(s)
```
- **Trigger**: The event that starts the rule (required, exactly one)
- **Condition**: Filters to narrow when the rule fires (optional, multiple allowed)
- **Action**: What the rule does (required, one or more)
## Triggers
### Issue Triggers
| Trigger | Fires When | Use For |
|---------|------------|---------|
| **Issue created** | New issue is created | Auto-assignment, notifications, SLA start |
| **Issue transitioned** | Status changes | Workflow automation, notifications |
| **Issue updated** | Any field changes | Field sync, cascading updates |
| **Issue commented** | Comment is added | Auto-responses, SLA tracking |
| **Issue assigned** | Assignee changes | Workload notifications |
| **Issue linked** | Link is added/removed | Dependency tracking |
| **Issue deleted** | Issue is deleted | Cleanup, audit logging |
### Sprint & Board Triggers
| Trigger | Fires When |
|---------|------------|
| **Sprint started** | Sprint is activated |
| **Sprint completed** | Sprint is closed |
| **Issue moved between sprints** | Issue is moved |
| **Backlog item moved to sprint** | Item is pulled into sprint |
### Scheduled Triggers
| Trigger | Fires When |
|---------|------------|
| **Scheduled** | Cron-based (daily, weekly, custom) |
| **Issue stale** | No updates for X days |
### Version Triggers
| Trigger | Fires When |
|---------|------------|
| **Version created** | New version added |
| **Version released** | Version is released |
## Conditions
### Issue Conditions
| Condition | Matches When |
|-----------|-------------|
| **Issue fields condition** | Field matches value (e.g., priority = High) |
| **JQL condition** | Issue matches JQL query |
| **Related issues condition** | Linked/sub-task issues match criteria |
| **User condition** | Actor matches (reporter, assignee, group) |
| **Advanced compare** | Complex field comparisons |
### Condition Operators
```
Field = value # Exact match
Field != value # Not equal
Field > value # Greater than (numeric/date)
Field is empty # Field has no value
Field is not empty # Field has a value
Field changed # Field was modified in this event
Field changed to # Field changed to specific value
Field changed from # Field changed from specific value
```
## Actions
### Issue Actions
| Action | Does |
|--------|------|
| **Edit issue** | Update any field on the current issue |
| **Transition issue** | Move to a new status |
| **Assign issue** | Change assignee |
| **Comment on issue** | Add a comment |
| **Create issue** | Create a new linked issue |
| **Create sub-tasks** | Create child issues |
| **Clone issue** | Duplicate the issue |
| **Delete issue** | Remove the issue |
| **Link issues** | Add issue links |
| **Log work** | Add time tracking entry |
### Notification Actions
| Action | Does |
|--------|------|
| **Send email** | Send custom email to users/groups |
| **Send Slack message** | Post to Slack channel (requires integration) |
| **Send Microsoft Teams message** | Post to Teams (requires integration) |
| **Send web request** | HTTP call to external service |
### Lookup & Branch Actions
| Action | Does |
|--------|------|
| **Lookup issues (JQL)** | Find issues matching JQL, iterate over them |
| **Create branch** | Branch logic (if/then/else) |
| **For each** | Loop over found issues |
## Smart Values
Smart values are dynamic placeholders that resolve at runtime.
### Issue Smart Values
```
{{issue.key}} # PROJ-123
{{issue.summary}} # Issue title
{{issue.description}} # Full description
{{issue.status.name}} # Current status
{{issue.priority.name}} # Priority level
{{issue.assignee.displayName}} # Assignee name
{{issue.reporter.displayName}} # Reporter name
{{issue.issuetype.name}} # Issue type
{{issue.project.key}} # Project key
{{issue.created}} # Creation date
{{issue.updated}} # Last update date
{{issue.fixVersions}} # Fix versions
{{issue.labels}} # Labels array
{{issue.components}} # Components array
```
### Transition Smart Values
```
{{transition.from_status}} # Previous status
{{transition.to_status}} # New status
{{transition.transitionName}} # Transition name
```
### User Smart Values
```
{{initiator.displayName}} # Who triggered the rule
{{initiator.emailAddress}} # Their email
{{initiator.accountId}} # Their account ID
```
### Date Smart Values
```
{{now}} # Current timestamp
{{now.plusDays(7)}} # 7 days from now
{{now.minusHours(24)}} # 24 hours ago
{{issue.created.plusBusinessDays(3)}} # 3 business days after creation
```
### Conditional Smart Values
```
{{#if issue.priority.name == "High"}}
This is high priority
{{/if}}
{{#if issue.assignee}}
Assigned to {{issue.assignee.displayName}}
{{else}}
Unassigned
{{/if}}
```
## Production-Ready Recipes
### 1. Auto-Assign by Component
```yaml
Trigger: Issue created
Condition: Issue has component
Action: Edit issue
- Assignee = Component lead
Rule Logic:
IF component = "Backend" → assign to @backend-lead
IF component = "Frontend" → assign to @frontend-lead
IF component = "DevOps" → assign to @devops-lead
```
### 2. SLA Warning — Stale Issues
```yaml
Trigger: Scheduled (daily at 9am)
Condition: JQL = "status != Done AND updated <= -5d AND priority in (High, Highest)"
Action:
- Add comment: "⚠️ This {{issue.priority.name}} issue hasn't been updated in 5+ days."
- Send Slack: "#engineering-alerts: {{issue.key}} is stale ({{issue.assignee.displayName}})"
```
### 3. Auto-Close Resolved Issues After 7 Days
```yaml
Trigger: Scheduled (daily)
Condition: JQL = "status = Resolved AND updated <= -7d"
Action:
- Transition: Resolved → Closed
- Comment: "Auto-closed after 7 days in Resolved status."
```
### 4. Sprint Spillover Notification
```yaml
Trigger: Sprint completed
Condition: Issue status != Done
Action:
- Comment: "Spilled over from Sprint {{sprint.name}}. Reason needs review."
- Add label: "spillover"
- Send email to: {{issue.assignee.emailAddress}}
```
### 5. Sub-Task Completion → Parent Transition
```yaml
Trigger: Issue transitioned (to Done)
Condition: Issue is sub-task AND all sibling sub-tasks are Done
Action (on parent):
- Transition: In Progress → In Review
- Comment: "All sub-tasks completed. Ready for review."
```
### 6. Bug Priority Escalation
```yaml
Trigger: Scheduled (every 4 hours)
Condition: JQL = "type = Bug AND priority = High AND status = Open AND created <= -24h"
Action:
- Edit: priority = Highest
- Comment: "⚡ Auto-escalated: High-priority bug open for 24+ hours."
- Send email to: project lead
```
### 7. Auto-Link Duplicate Detection
```yaml
Trigger: Issue created
Condition: JQL finds issues with similar summary (fuzzy)
Action:
- Comment: "Possible duplicate of {{lookupIssues.first.key}}: {{lookupIssues.first.summary}}"
- Add label: "possible-duplicate"
```
### 8. Release Notes Generator
```yaml
Trigger: Version released
Condition: None
Action:
- Lookup: JQL = "fixVersion = {{version.name}} AND status = Done"
- Create Confluence page:
Title: "Release Notes — {{version.name}}"
Content: List of resolved issues with types and summaries
```
### 9. Workload Balancer — Round-Robin Assignment
```yaml
Trigger: Issue created
Condition: Issue type = Story AND assignee is empty
Action:
- Lookup: JQL = "assignee in (dev1, dev2, dev3) AND sprint in openSprints() AND status != Done"
- Assign to team member with fewest open issues
```
### 10. Blocker Notification Chain
```yaml
Trigger: Issue updated (priority changed to Blocker)
Action:
- Send email to: project lead, scrum master
- Send Slack: "#blockers: 🚨 {{issue.key}} marked as Blocker by {{initiator.displayName}}"
- Comment: "Blocker escalated. Notified: PM + SM."
- Edit: Add label "blocker-active"
```
## Best Practices
1. **Name rules descriptively** — "Auto-assign Backend bugs to @dev-lead" not "Rule 1"
2. **Add conditions before actions** — prevent unintended execution
3. **Use JQL conditions** for precision — field conditions can miss edge cases
4. **Test in a sandbox project first** — automation mistakes can be destructive
5. **Set rate limits** — avoid infinite loops (Rule A triggers Rule B triggers Rule A)
6. **Monitor rule execution** — check Automation audit log weekly
7. **Document business rules** — explain WHY the rule exists, not just WHAT it does
8. **Use branches (if/else)** over separate rules — reduces rule count, easier to maintain
9. **Disable before deleting** — observe for a week to ensure no side effects
10. **Version your automation** — export rules as JSON backup before major changes
FILE:references/jql-examples.md
# JQL Query Examples
## Sprint Queries
**Current sprint issues:**
```jql
sprint IN openSprints() ORDER BY rank
```
**Issues in specific sprint:**
```jql
sprint = "Sprint 23" ORDER BY priority DESC
```
**All sprint work (current and backlog):**
```jql
project = ABC AND issuetype IN (Story, Bug, Task)
ORDER BY sprint DESC, rank
```
**Unscheduled stories:**
```jql
project = ABC AND issuetype = Story AND sprint IS EMPTY
AND status != Done ORDER BY priority DESC
```
**Spillover from last sprint:**
```jql
sprint IN closedSprints() AND sprint NOT IN (latestReleasedVersion())
AND status != Done ORDER BY created DESC
```
**Sprint completion rate:**
```jql
sprint = "Sprint 23" AND status = Done
```
## User & Team Queries
**My open issues:**
```jql
assignee = currentUser() AND status != Done
ORDER BY priority DESC, created ASC
```
**Unassigned in my project:**
```jql
project = ABC AND assignee IS EMPTY AND status != Done
ORDER BY priority DESC
```
**Issues I'm watching:**
```jql
watcher = currentUser() AND status != Done
```
**Team workload:**
```jql
assignee IN membersOf("engineering-team") AND status IN ("In Progress", "In Review")
ORDER BY assignee, priority DESC
```
**Issues I reported that are still open:**
```jql
reporter = currentUser() AND status != Done ORDER BY created DESC
```
**Issues commented on by me:**
```jql
comment ~ currentUser() AND status != Done
```
## Date Range Queries
**Created today:**
```jql
created >= startOfDay() ORDER BY created DESC
```
**Updated in last 7 days:**
```jql
updated >= -7d ORDER BY updated DESC
```
**Created this week:**
```jql
created >= startOfWeek() AND created <= endOfWeek()
```
**Created this month:**
```jql
created >= startOfMonth() AND created <= endOfMonth()
```
**Not updated in 30 days:**
```jql
status != Done AND updated <= -30d ORDER BY updated ASC
```
**Resolved yesterday:**
```jql
resolved >= startOfDay(-1d) AND resolved < startOfDay()
```
**Due this week:**
```jql
duedate >= startOfWeek() AND duedate <= endOfWeek() AND status != Done
```
**Overdue:**
```jql
duedate < now() AND status != Done ORDER BY duedate ASC
```
## Status & Workflow Queries
**In Progress issues:**
```jql
project = ABC AND status = "In Progress" ORDER BY assignee
```
**Blocked issues:**
```jql
project = ABC AND labels = blocked AND status != Done
```
**Issues in review:**
```jql
project = ABC AND status IN ("Code Review", "QA Review", "Pending Approval")
ORDER BY updated ASC
```
**Ready for development:**
```jql
project = ABC AND status = "Ready" AND sprint IS EMPTY
ORDER BY priority DESC
```
**Recently done:**
```jql
project = ABC AND status = Done AND resolved >= -7d
ORDER BY resolved DESC
```
**Status changed today:**
```jql
status CHANGED AFTER startOfDay() ORDER BY updated DESC
```
**Long-running in progress:**
```jql
status = "In Progress" AND status CHANGED BEFORE -14d
ORDER BY status CHANGED ASC
```
## Priority & Type Queries
**High priority bugs:**
```jql
issuetype = Bug AND priority IN (Highest, High) AND status != Done
ORDER BY priority DESC, created ASC
```
**Critical blockers:**
```jql
priority = Highest AND status != Done ORDER BY created ASC
```
**All epics:**
```jql
issuetype = Epic ORDER BY status, priority DESC
```
**Stories without acceptance criteria:**
```jql
issuetype = Story AND "Acceptance Criteria" IS EMPTY AND status = Backlog
```
**Technical debt:**
```jql
labels = tech-debt AND status != Done ORDER BY priority DESC
```
## Complex Multi-Condition Queries
**My team's sprint work:**
```jql
sprint IN openSprints()
AND assignee IN membersOf("engineering-team")
AND status != Done
ORDER BY assignee, priority DESC
```
**Bugs created this month, not in sprint:**
```jql
issuetype = Bug
AND created >= startOfMonth()
AND sprint IS EMPTY
AND status != Done
ORDER BY priority DESC, created DESC
```
**High-priority work needing attention:**
```jql
project = ABC
AND priority IN (Highest, High)
AND status IN ("In Progress", "In Review")
AND updated <= -3d
ORDER BY priority DESC, updated ASC
```
**Stale issues:**
```jql
project = ABC
AND status NOT IN (Done, Cancelled)
AND (assignee IS EMPTY OR updated <= -30d)
ORDER BY created ASC
```
**Epic progress:**
```jql
"Epic Link" = ABC-123 ORDER BY status, rank
```
## Component & Version Queries
**Issues in component:**
```jql
project = ABC AND component = "Frontend" AND status != Done
```
**Issues without component:**
```jql
project = ABC AND component IS EMPTY AND status != Done
```
**Target version:**
```jql
fixVersion = "v2.0" ORDER BY status, priority DESC
```
**Released versions:**
```jql
fixVersion IN releasedVersions() ORDER BY fixVersion DESC
```
## Label & Text Search Queries
**Issues with label:**
```jql
labels = urgent AND status != Done
```
**Multiple labels (AND):**
```jql
labels IN (frontend, bug) AND status != Done
```
**Search in summary:**
```jql
summary ~ "authentication" ORDER BY created DESC
```
**Search in summary and description:**
```jql
text ~ "API integration" ORDER BY created DESC
```
**Issues with empty description:**
```jql
description IS EMPTY AND issuetype = Story
```
## Performance-Optimized Queries
**Good - Specific project first:**
```jql
project = ABC AND status = "In Progress" AND assignee = currentUser()
```
**Bad - User filter first:**
```jql
assignee = currentUser() AND status = "In Progress" AND project = ABC
```
**Good - Use functions:**
```jql
sprint IN openSprints() AND status != Done
```
**Bad - Hardcoded sprint:**
```jql
sprint = "Sprint 23" AND status != Done
```
**Good - Specific date:**
```jql
created >= 2024-01-01 AND created <= 2024-01-31
```
**Bad - Relative with high cost:**
```jql
created >= -365d AND created <= -335d
```
## Reporting Queries
**Velocity calculation:**
```jql
sprint = "Sprint 23" AND status = Done
```
*Then sum story points*
**Bug rate:**
```jql
project = ABC AND issuetype = Bug AND created >= startOfMonth()
```
**Average cycle time:**
```jql
project = ABC AND resolved >= startOfMonth()
AND resolved <= endOfMonth()
```
*Calculate time from In Progress to Done*
**Stories delivered this quarter:**
```jql
project = ABC AND issuetype = Story
AND resolved >= startOfYear() AND resolved <= endOfQuarter()
```
**Team capacity:**
```jql
assignee IN membersOf("engineering-team")
AND sprint IN openSprints()
```
*Sum original estimates*
## Notification & Watching Queries
**Issues I need to review:**
```jql
status = "Pending Review" AND assignee = currentUser()
```
**Issues assigned to me, high priority:**
```jql
assignee = currentUser() AND priority IN (Highest, High)
AND status != Done
```
**Issues created by me, not resolved:**
```jql
reporter = currentUser() AND status != Done
ORDER BY created DESC
```
## Advanced Functions
**Issues changed from status:**
```jql
status WAS "In Progress" AND status = "Done"
AND status CHANGED AFTER startOfWeek()
```
**Assignee changed:**
```jql
assignee CHANGED BY currentUser() AFTER -7d
```
**Issues re-opened:**
```jql
status WAS Done AND status != Done ORDER BY updated DESC
```
**Linked issues:**
```jql
issue IN linkedIssues("ABC-123") ORDER BY issuetype
```
**Parent epic:**
```jql
parent = ABC-123 ORDER BY rank
```
## Saved Filter Examples
**Daily Standup Filter:**
```jql
assignee = currentUser() AND sprint IN openSprints()
AND status != Done ORDER BY priority DESC
```
**Team Sprint Board Filter:**
```jql
project = ABC AND sprint IN openSprints() ORDER BY rank
```
**Bugs Dashboard Filter:**
```jql
project = ABC AND issuetype = Bug AND status != Done
ORDER BY priority DESC, created ASC
```
**Tech Debt Backlog:**
```jql
project = ABC AND labels = tech-debt AND status = Backlog
ORDER BY priority DESC
```
**Needs Triage:**
```jql
project = ABC AND status = "To Triage"
AND created >= -7d ORDER BY created ASC
```
FILE:references/WORKFLOWS.md
# Jira Workflows Reference
Comprehensive guide to Jira workflow design, transitions, conditions, validators, and post-functions.
## Default Workflows
### Simplified Workflow
```
Open → In Progress → Done
```
### Software Development Workflow
```
Backlog → Selected for Development → In Progress → In Review → Done
↑___________________________| (reopen)
```
### Bug Tracking Workflow
```
Open → In Progress → Fixed → Verified → Closed
↑ | |
|____Reopened________|________|
```
## Custom Workflow Design
### Design Principles
1. **Mirror your actual process** — don't force teams into artificial states
2. **Minimize statuses** — each status must represent a distinct work state where the item waits for a different action
3. **Clear ownership** — every status should have an obvious responsible party
4. **Allow rework** — always provide paths back for rejected/reopened items
5. **Separate "waiting" from "working"** — distinguish "In Review" (waiting) from "Reviewing" (actively working)
### Status Categories
Jira maps every status to one of four categories that drive board columns and JQL:
| Category | Meaning | JQL | Examples |
|----------|---------|-----|----------|
| `To Do` | Not started | `statusCategory = "To Do"` | Backlog, Open, New |
| `In Progress` | Active work | `statusCategory = "In Progress"` | In Progress, In Review, Testing |
| `Done` | Completed | `statusCategory = Done` | Done, Closed, Released |
| `Undefined` | Legacy/unused | — | Avoid using |
### Recommended Statuses by Team Type
**Engineering Team:**
```
Backlog → Ready → In Progress → Code Review → QA → Done
```
**Support Team:**
```
New → Triaged → In Progress → Waiting on Customer → Resolved → Closed
```
**Design Team:**
```
Backlog → Research → Design → Review → Approved → Handoff
```
## Transitions
### Transition Properties
| Property | Description |
|----------|-------------|
| **Name** | Display name on the button (e.g., "Start Work") |
| **Screen** | Form shown during transition (optional) |
| **Conditions** | Who can trigger this transition |
| **Validators** | Rules that must pass before transition executes |
| **Post-functions** | Actions executed after transition completes |
### Common Transition Patterns
**Start Work:**
```
Trigger: "Start Work" button
Condition: Assignee only
Validator: Issue must have assignee
Post-function: Set "In Progress" resolution to None
```
**Submit for Review:**
```
Trigger: "Submit for Review" button
Condition: Assignee or project admin
Validator: All sub-tasks must be Done
Post-function: Add comment "Submitted for review by {user}"
```
**Approve:**
```
Trigger: "Approve" button
Condition: Must be in "Reviewers" group
Validator: Must add comment
Post-function: Set resolution to "Done", fire event
```
## Conditions
### Built-in Conditions
| Condition | Use When |
|-----------|----------|
| **Only Assignee** | Only assigned user can transition |
| **Only Reporter** | Only creator can transition |
| **Permission Condition** | User must have specific permission |
| **Group Condition** | User must be in specified group |
| **Sub-Task Blocking** | All sub-tasks must be resolved |
| **Previous Status** | Issue must have been in a specific status |
| **User Is In Role** | User must have project role (Developer, Admin) |
### Combining Conditions
- **AND logic**: Add multiple conditions to one transition — ALL must pass
- **OR logic**: Create parallel transitions with different conditions
## Validators
### Built-in Validators
| Validator | Checks |
|-----------|--------|
| **Required Field** | Specific field must be populated |
| **Field Has Been Modified** | Field must change during transition |
| **Regular Expression** | Field must match regex pattern |
| **Permission Validator** | User must have permission |
| **Previous Status Validator** | Issue was in a required status |
### Common Validator Patterns
```
# Require comment on rejection
Validator: Comment Required
When: Transition = "Reject"
# Require fix version before release
Validator: Required Field = "Fix Version/s"
When: Transition = "Release"
# Require time logged before closing
Validator: Field Required = "Time Spent" (must be > 0)
When: Transition = "Close"
```
## Post-Functions
### Built-in Post-Functions
| Post-Function | Action |
|---------------|--------|
| **Set Field Value** | Assign a value to any field |
| **Update Issue Field** | Change assignee, priority, etc. |
| **Create Comment** | Add automated comment |
| **Fire Event** | Trigger notification event |
| **Assign to Lead** | Assign to project lead |
| **Assign to Reporter** | Assign back to creator |
| **Clear Field** | Remove field value |
| **Copy Value** | Copy field from parent/linked issue |
### Post-Function Execution Order
Post-functions execute in defined order. Standard sequence:
1. Set issue status (automatic, always first)
2. Add comment (if configured)
3. Update fields
4. Generate change history (automatic, always last)
5. Fire event (triggers notifications)
**Important:** "Generate change history" and "Fire event" must always be last — reorder if you add custom post-functions.
## Workflow Schemes
### What They Do
- Map issue types to workflows within a project
- One workflow scheme per project
- Different issue types can use different workflows
### Configuration Pattern
```
Project: MYPROJ
Workflow Scheme: "Engineering Workflow Scheme"
Bug → Bug Tracking Workflow
Story → Development Workflow
Task → Simple Workflow
Epic → Epic Workflow
Sub-task → Sub-task Workflow (inherits parent transitions)
```
## Best Practices
1. **Start simple, add complexity only when needed** — a 5-status workflow beats a 15-status one
2. **Name transitions as actions** — "Start Work" not "In Progress" (the status is "In Progress", the action is "Start Work")
3. **Use screens sparingly** — only show a screen when you need data from the user during transition
4. **Test with real users** — workflows that look good on paper may confuse the team
5. **Document your workflow** — add descriptions to statuses and transitions
6. **Use global transitions carefully** — a "Cancel" transition from any status is convenient but can bypass important gates
7. **Audit quarterly** — remove statuses with <5% usage
FILE:scripts/jql_query_builder.py
#!/usr/bin/env python3
"""
JQL Query Builder
Pattern-matching JQL builder from natural language descriptions. Maps common
phrases to JQL operators and constructs valid queries with syntax validation.
Usage:
python jql_query_builder.py "high priority bugs in PROJECT assigned to me"
python jql_query_builder.py "overdue tasks in PROJ" --format json
python jql_query_builder.py --patterns
"""
import argparse
import json
import re
import sys
from datetime import datetime
from typing import Any, Dict, List, Optional, Tuple
# ---------------------------------------------------------------------------
# Pattern Library
# ---------------------------------------------------------------------------
PATTERN_LIBRARY = {
"my_open_bugs": {
"phrases": ["my open bugs", "my bugs", "bugs assigned to me"],
"jql": 'assignee = currentUser() AND type = Bug AND status != Done',
"description": "All open bugs assigned to current user",
},
"high_priority_bugs": {
"phrases": ["high priority bugs", "critical bugs", "urgent bugs", "p1 bugs"],
"jql": 'type = Bug AND priority in (Highest, High) AND status != Done',
"description": "High and highest priority open bugs",
},
"my_open_tasks": {
"phrases": ["my open tasks", "my tasks", "tasks assigned to me", "my work"],
"jql": 'assignee = currentUser() AND status != Done',
"description": "All open issues assigned to current user",
},
"unassigned_issues": {
"phrases": ["unassigned", "unassigned issues", "no assignee"],
"jql": 'assignee is EMPTY AND status != Done',
"description": "Issues with no assignee",
},
"recently_created": {
"phrases": ["recently created", "new issues", "created this week", "recent"],
"jql": 'created >= -7d ORDER BY created DESC',
"description": "Issues created in the last 7 days",
},
"recently_updated": {
"phrases": ["recently updated", "updated this week", "recent changes"],
"jql": 'updated >= -7d ORDER BY updated DESC',
"description": "Issues updated in the last 7 days",
},
"overdue": {
"phrases": ["overdue", "past due", "missed deadline", "overdue tasks"],
"jql": 'duedate < now() AND status != Done',
"description": "Issues past their due date",
},
"due_this_week": {
"phrases": ["due this week", "due soon", "upcoming deadlines"],
"jql": 'duedate >= startOfWeek() AND duedate <= endOfWeek() AND status != Done',
"description": "Issues due this week",
},
"blocked_issues": {
"phrases": ["blocked", "blocked issues", "impediments"],
"jql": 'status = Blocked OR status = Impediment',
"description": "Issues in blocked or impediment status",
},
"in_progress": {
"phrases": ["in progress", "being worked on", "active work"],
"jql": 'status = "In Progress"',
"description": "Issues currently in progress",
},
"sprint_issues": {
"phrases": ["current sprint", "this sprint", "active sprint"],
"jql": 'sprint in openSprints()',
"description": "Issues in the current active sprint",
},
"backlog": {
"phrases": ["backlog", "backlog items", "not started"],
"jql": 'sprint is EMPTY AND status = "To Do" ORDER BY priority DESC',
"description": "Issues in the backlog not assigned to a sprint",
},
"stories_without_estimates": {
"phrases": ["no estimates", "unestimated", "missing estimates", "no story points"],
"jql": 'type = Story AND (storyPoints is EMPTY OR storyPoints = 0) AND status != Done',
"description": "Stories missing story point estimates",
},
"epics_in_progress": {
"phrases": ["active epics", "epics in progress", "open epics"],
"jql": 'type = Epic AND status != Done ORDER BY priority DESC',
"description": "Epics that are not yet completed",
},
"done_this_week": {
"phrases": ["done this week", "completed this week", "resolved this week"],
"jql": 'status changed to Done DURING (startOfWeek(), now())',
"description": "Issues completed during the current week",
},
"created_vs_resolved": {
"phrases": ["created vs resolved", "issue flow", "throughput"],
"jql": 'created >= -30d ORDER BY created DESC',
"description": "Issues created in the last 30 days for flow analysis",
},
"my_reported_issues": {
"phrases": ["my reported", "reported by me", "i created", "i reported"],
"jql": 'reporter = currentUser() ORDER BY created DESC',
"description": "Issues reported by current user",
},
"stale_issues": {
"phrases": ["stale", "stale issues", "not updated", "abandoned"],
"jql": 'updated <= -30d AND status != Done ORDER BY updated ASC',
"description": "Issues not updated in 30+ days",
},
"subtasks_without_parent": {
"phrases": ["orphan subtasks", "subtasks no parent", "loose subtasks"],
"jql": 'type = Sub-task AND parent is EMPTY',
"description": "Subtasks missing parent issues",
},
"high_priority_unassigned": {
"phrases": ["high priority unassigned", "urgent unassigned", "critical no owner"],
"jql": 'priority in (Highest, High) AND assignee is EMPTY AND status != Done',
"description": "High priority issues with no assignee",
},
"bugs_by_component": {
"phrases": ["bugs by component", "component bugs"],
"jql": 'type = Bug AND status != Done ORDER BY component ASC',
"description": "Open bugs organized by component",
},
"resolved_recently": {
"phrases": ["resolved recently", "recently resolved", "fixed this month"],
"jql": 'resolved >= -30d ORDER BY resolved DESC',
"description": "Issues resolved in the last 30 days",
},
}
# Keyword-to-JQL fragment mapping for dynamic query building
KEYWORD_FRAGMENTS = {
# Issue types
"bug": ("type", "= Bug"),
"bugs": ("type", "= Bug"),
"story": ("type", "= Story"),
"stories": ("type", "= Story"),
"task": ("type", "= Task"),
"tasks": ("type", "= Task"),
"epic": ("type", "= Epic"),
"epics": ("type", "= Epic"),
"subtask": ("type", "= Sub-task"),
"sub-task": ("type", "= Sub-task"),
# Statuses
"open": ("status", "!= Done"),
"closed": ("status", "= Done"),
"done": ("status", "= Done"),
"resolved": ("status", "= Done"),
"todo": ("status", '= "To Do"'),
# Priorities
"critical": ("priority", "= Highest"),
"highest": ("priority", "= Highest"),
"high": ("priority", "in (Highest, High)"),
"medium": ("priority", "= Medium"),
"low": ("priority", "in (Low, Lowest)"),
"lowest": ("priority", "= Lowest"),
# Assignee
"me": ("assignee", "= currentUser()"),
"mine": ("assignee", "= currentUser()"),
"unassigned": ("assignee", "is EMPTY"),
# Time
"overdue": ("duedate", "< now()"),
"today": ("duedate", "= now()"),
}
PROJECT_PATTERN = re.compile(r'\b([A-Z]{2,10})\b')
ASSIGNEE_PATTERN = re.compile(r'assigned\s+to\s+(\w+)', re.IGNORECASE)
LABEL_PATTERN = re.compile(r'label[s]?\s*[=:]\s*["\']?(\w+)["\']?', re.IGNORECASE)
COMPONENT_PATTERN = re.compile(r'component[s]?\s*[=:]\s*["\']?(\w+)["\']?', re.IGNORECASE)
DATE_RANGE_PATTERN = re.compile(r'last\s+(\d+)\s+(day|week|month)s?', re.IGNORECASE)
SPRINT_NAME_PATTERN = re.compile(r'sprint\s+["\']?(\w[\w\s]*\w)["\']?', re.IGNORECASE)
# Words to exclude from project matching
EXCLUDED_WORDS = {
"AND", "OR", "NOT", "IN", "IS", "TO", "BY", "ON", "DO", "BE",
"THE", "ALL", "MY", "NO", "OF", "AT", "AS", "IF", "IT",
"BUG", "BUGS", "TASK", "TASKS", "STORY", "EPIC", "DONE",
"HIGH", "LOW", "MEDIUM", "JQL",
}
# ---------------------------------------------------------------------------
# Query Builder
# ---------------------------------------------------------------------------
def find_matching_pattern(description: str) -> Optional[Dict[str, Any]]:
"""Check if description matches a known pattern exactly."""
desc_lower = description.lower().strip()
for pattern_name, pattern_data in PATTERN_LIBRARY.items():
for phrase in pattern_data["phrases"]:
if phrase in desc_lower or desc_lower in phrase:
return {
"pattern_name": pattern_name,
"jql": pattern_data["jql"],
"description": pattern_data["description"],
"match_type": "exact_pattern",
}
return None
def build_jql_from_description(description: str) -> Dict[str, Any]:
"""Build JQL query from natural language description."""
# First try exact pattern match
pattern_match = find_matching_pattern(description)
if pattern_match:
# Augment with project if mentioned
project = _extract_project(description)
if project:
pattern_match["jql"] = f'project = {project} AND {pattern_match["jql"]}'
return pattern_match
# Dynamic query building
clauses = []
used_fields = set()
desc_lower = description.lower()
# Extract project
project = _extract_project(description)
if project:
clauses.append(f"project = {project}")
used_fields.add("project")
# Extract keyword-based fragments
for keyword, (field, fragment) in KEYWORD_FRAGMENTS.items():
if keyword in desc_lower.split() and field not in used_fields:
clauses.append(f"{field} {fragment}")
used_fields.add(field)
# Extract explicit assignee
assignee_match = ASSIGNEE_PATTERN.search(description)
if assignee_match and "assignee" not in used_fields:
assignee = assignee_match.group(1)
if assignee.lower() in ("me", "myself"):
clauses.append("assignee = currentUser()")
else:
clauses.append(f'assignee = "{assignee}"')
used_fields.add("assignee")
# Extract labels
label_match = LABEL_PATTERN.search(description)
if label_match:
clauses.append(f'labels = "{label_match.group(1)}"')
# Extract component
component_match = COMPONENT_PATTERN.search(description)
if component_match:
clauses.append(f'component = "{component_match.group(1)}"')
# Extract date ranges
date_match = DATE_RANGE_PATTERN.search(description)
if date_match:
amount = date_match.group(1)
unit = date_match.group(2).lower()
unit_char = {"day": "d", "week": "w", "month": "m"}.get(unit, "d")
clauses.append(f"created >= -{amount}{unit_char}")
# Extract sprint reference
sprint_match = SPRINT_NAME_PATTERN.search(description)
if sprint_match:
sprint_name = sprint_match.group(1).strip()
if sprint_name.lower() in ("current", "active", "open"):
clauses.append("sprint in openSprints()")
else:
clauses.append(f'sprint = "{sprint_name}"')
# Default: if no status clause and not looking for done items
if "status" not in used_fields and "done" not in desc_lower and "closed" not in desc_lower:
clauses.append("status != Done")
if not clauses:
return {
"jql": "",
"description": "Could not build query from description",
"match_type": "no_match",
"error": "No recognizable patterns found in description",
}
jql = " AND ".join(clauses)
# Add ORDER BY for common scenarios
if "recent" in desc_lower or "latest" in desc_lower:
jql += " ORDER BY created DESC"
elif "priority" in desc_lower or "urgent" in desc_lower:
jql += " ORDER BY priority DESC"
return {
"jql": jql,
"description": f"Dynamic query from: {description}",
"match_type": "dynamic",
"clauses_used": len(clauses),
}
def _extract_project(description: str) -> Optional[str]:
"""Extract project key from description."""
# Look for IN/in PROJECT pattern
in_project = re.search(r'\bin\s+([A-Z]{2,10})\b', description)
if in_project and in_project.group(1) not in EXCLUDED_WORDS:
return in_project.group(1)
# Look for standalone project keys
for match in PROJECT_PATTERN.finditer(description):
word = match.group(1)
if word not in EXCLUDED_WORDS:
return word
return None
def validate_jql_syntax(jql: str) -> Dict[str, Any]:
"""Basic JQL syntax validation."""
issues = []
if not jql.strip():
return {"valid": False, "issues": ["Empty query"]}
# Check balanced quotes
single_quotes = jql.count("'")
double_quotes = jql.count('"')
if single_quotes % 2 != 0:
issues.append("Unbalanced single quotes")
if double_quotes % 2 != 0:
issues.append("Unbalanced double quotes")
# Check balanced parentheses
open_parens = jql.count("(")
close_parens = jql.count(")")
if open_parens != close_parens:
issues.append(f"Unbalanced parentheses: {open_parens} open, {close_parens} close")
# Check for known JQL operators
valid_operators = {"=", "!=", ">", "<", ">=", "<=", "~", "!~", "in", "not in", "is", "is not", "was", "was not", "changed"}
jql_upper = jql.upper()
# Check AND/OR placement
if jql_upper.strip().startswith("AND") or jql_upper.strip().startswith("OR"):
issues.append("Query cannot start with AND/OR")
if jql_upper.strip().endswith("AND") or jql_upper.strip().endswith("OR"):
issues.append("Query cannot end with AND/OR")
# Check ORDER BY syntax
order_match = re.search(r'ORDER\s+BY\s+(\w+)(?:\s+(ASC|DESC))?', jql, re.IGNORECASE)
if "ORDER" in jql_upper and not order_match:
issues.append("Invalid ORDER BY syntax")
return {
"valid": len(issues) == 0,
"issues": issues,
"query_length": len(jql),
}
# ---------------------------------------------------------------------------
# Output Formatting
# ---------------------------------------------------------------------------
def format_text_output(result: Dict[str, Any]) -> str:
"""Format results as readable text report."""
lines = []
lines.append("=" * 60)
lines.append("JQL QUERY BUILDER RESULTS")
lines.append("=" * 60)
lines.append("")
if "error" in result:
lines.append(f"ERROR: {result['error']}")
return "\n".join(lines)
lines.append(f"Match Type: {result.get('match_type', 'unknown')}")
lines.append(f"Description: {result.get('description', '')}")
lines.append("")
lines.append("GENERATED JQL")
lines.append("-" * 30)
lines.append(result.get("jql", ""))
lines.append("")
validation = result.get("validation", {})
if validation:
lines.append("VALIDATION")
lines.append("-" * 30)
lines.append(f"Valid: {'Yes' if validation.get('valid') else 'No'}")
if validation.get("issues"):
for issue in validation["issues"]:
lines.append(f" - {issue}")
if result.get("pattern_name"):
lines.append("")
lines.append(f"Matched Pattern: {result['pattern_name']}")
return "\n".join(lines)
def format_patterns_output(output_format: str) -> str:
"""Format available patterns list."""
if output_format == "json":
patterns = {}
for name, data in PATTERN_LIBRARY.items():
patterns[name] = {
"description": data["description"],
"phrases": data["phrases"],
"jql": data["jql"],
}
return json.dumps(patterns, indent=2)
lines = []
lines.append("=" * 60)
lines.append("AVAILABLE JQL PATTERNS")
lines.append("=" * 60)
lines.append("")
for name, data in PATTERN_LIBRARY.items():
lines.append(f" {name}")
lines.append(f" Description: {data['description']}")
lines.append(f" Phrases: {', '.join(data['phrases'])}")
lines.append(f" JQL: {data['jql']}")
lines.append("")
lines.append(f"Total patterns: {len(PATTERN_LIBRARY)}")
return "\n".join(lines)
def format_json_output(result: Dict[str, Any]) -> Dict[str, Any]:
"""Format results as JSON."""
return result
# ---------------------------------------------------------------------------
# CLI Interface
# ---------------------------------------------------------------------------
def main() -> int:
"""Main CLI entry point."""
parser = argparse.ArgumentParser(
description="Build JQL queries from natural language descriptions"
)
parser.add_argument(
"description",
nargs="?",
help="Natural language description of the query",
)
parser.add_argument(
"--format",
choices=["text", "json"],
default="text",
help="Output format (default: text)",
)
parser.add_argument(
"--patterns",
action="store_true",
help="List all available query patterns",
)
args = parser.parse_args()
try:
if args.patterns:
print(format_patterns_output(args.format))
return 0
if not args.description:
parser.error("description is required unless --patterns is used")
# Build query
result = build_jql_from_description(args.description)
# Validate
if result.get("jql"):
result["validation"] = validate_jql_syntax(result["jql"])
# Output results
if args.format == "json":
output = format_json_output(result)
print(json.dumps(output, indent=2))
else:
output = format_text_output(result)
print(output)
return 0
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
return 1
if __name__ == "__main__":
sys.exit(main())
FILE:scripts/workflow_validator.py
#!/usr/bin/env python3
"""
Workflow Validator
Validates Jira workflow definitions (JSON input) for anti-patterns and common
issues. Checks for dead-end states, orphan states, missing transitions, circular
paths, and produces a health score with severity-rated findings.
Usage:
python workflow_validator.py workflow.json
python workflow_validator.py workflow.json --format json
"""
import argparse
import json
import sys
from typing import Any, Dict, List, Optional, Set, Tuple
# ---------------------------------------------------------------------------
# Validation Configuration
# ---------------------------------------------------------------------------
MAX_RECOMMENDED_STATES = 10
REQUIRED_TERMINAL_STATES = {"done", "closed", "resolved", "completed"}
SEVERITY_WEIGHTS = {
"error": 20,
"warning": 10,
"info": 3,
}
# ---------------------------------------------------------------------------
# Validation Rules
# ---------------------------------------------------------------------------
def check_state_count(states: List[str]) -> List[Dict[str, str]]:
"""Check if the workflow has too many states."""
findings = []
count = len(states)
if count > MAX_RECOMMENDED_STATES:
findings.append({
"rule": "state_count",
"severity": "warning",
"message": f"Workflow has {count} states (recommended max: {MAX_RECOMMENDED_STATES}). "
f"Complex workflows slow teams down and increase error rates.",
})
elif count < 2:
findings.append({
"rule": "state_count",
"severity": "error",
"message": f"Workflow has only {count} state(s). A minimum of 2 states is required.",
})
if count > 15:
findings[-1]["severity"] = "error"
return findings
def check_dead_end_states(
states: List[str],
transitions: List[Dict[str, str]],
terminal_states: Set[str],
) -> List[Dict[str, str]]:
"""Find states with no outgoing transitions that are not terminal."""
findings = []
outgoing = set()
for t in transitions:
outgoing.add(t.get("from", "").lower())
for state in states:
state_lower = state.lower()
if state_lower not in outgoing and state_lower not in terminal_states:
findings.append({
"rule": "dead_end_state",
"severity": "error",
"message": f"State '{state}' has no outgoing transitions and is not a terminal state. "
f"Issues will get stuck here.",
})
return findings
def check_orphan_states(
states: List[str],
transitions: List[Dict[str, str]],
initial_state: Optional[str],
) -> List[Dict[str, str]]:
"""Find states with no incoming transitions (except the initial state)."""
findings = []
incoming = set()
for t in transitions:
incoming.add(t.get("to", "").lower())
initial_lower = (initial_state or "").lower()
for state in states:
state_lower = state.lower()
if state_lower not in incoming and state_lower != initial_lower:
findings.append({
"rule": "orphan_state",
"severity": "warning",
"message": f"State '{state}' has no incoming transitions and is not the initial state. "
f"This state may be unreachable.",
})
return findings
def check_missing_terminal_state(states: List[str]) -> List[Dict[str, str]]:
"""Check that at least one terminal/done state exists."""
findings = []
states_lower = {s.lower() for s in states}
has_terminal = bool(states_lower & REQUIRED_TERMINAL_STATES)
if not has_terminal:
findings.append({
"rule": "missing_terminal_state",
"severity": "error",
"message": f"No terminal state found. Expected one of: {', '.join(sorted(REQUIRED_TERMINAL_STATES))}. "
f"Issues cannot be marked as complete.",
})
return findings
def check_duplicate_transition_names(
transitions: List[Dict[str, str]],
) -> List[Dict[str, str]]:
"""Check for duplicate transition names from the same state."""
findings = []
seen = {}
for t in transitions:
name = t.get("name", "").lower()
from_state = t.get("from", "").lower()
key = (from_state, name)
if key in seen:
findings.append({
"rule": "duplicate_transition",
"severity": "warning",
"message": f"Duplicate transition name '{t.get('name', '')}' from state '{t.get('from', '')}'. "
f"This can confuse users selecting transitions.",
})
else:
seen[key] = True
return findings
def check_missing_transitions(
states: List[str],
transitions: List[Dict[str, str]],
) -> List[Dict[str, str]]:
"""Check for states referenced in transitions but not defined."""
findings = []
defined_states = {s.lower() for s in states}
for t in transitions:
from_state = t.get("from", "").lower()
to_state = t.get("to", "").lower()
if from_state and from_state not in defined_states:
findings.append({
"rule": "undefined_state_reference",
"severity": "error",
"message": f"Transition references undefined source state '{t.get('from', '')}'.",
})
if to_state and to_state not in defined_states:
findings.append({
"rule": "undefined_state_reference",
"severity": "error",
"message": f"Transition references undefined target state '{t.get('to', '')}'.",
})
return findings
def check_circular_paths(
states: List[str],
transitions: List[Dict[str, str]],
terminal_states: Set[str],
) -> List[Dict[str, str]]:
"""Detect circular paths that have no exit to a terminal state."""
findings = []
# Build adjacency list
adjacency = {}
for state in states:
adjacency[state.lower()] = set()
for t in transitions:
from_state = t.get("from", "").lower()
to_state = t.get("to", "").lower()
if from_state in adjacency:
adjacency[from_state].add(to_state)
# Find strongly connected components using iterative DFS
def can_reach_terminal(start: str) -> bool:
visited = set()
stack = [start]
while stack:
node = stack.pop()
if node in terminal_states:
return True
if node in visited:
continue
visited.add(node)
for neighbor in adjacency.get(node, set()):
stack.append(neighbor)
return False
# Check each non-terminal state
for state in states:
state_lower = state.lower()
if state_lower not in terminal_states:
if not can_reach_terminal(state_lower):
findings.append({
"rule": "circular_no_exit",
"severity": "error",
"message": f"State '{state}' cannot reach any terminal state. "
f"Issues entering this state will never be resolved.",
})
return findings
def check_self_transitions(transitions: List[Dict[str, str]]) -> List[Dict[str, str]]:
"""Check for transitions that go from a state to itself."""
findings = []
for t in transitions:
if t.get("from", "").lower() == t.get("to", "").lower():
findings.append({
"rule": "self_transition",
"severity": "info",
"message": f"State '{t.get('from', '')}' has a self-transition '{t.get('name', '')}'. "
f"Ensure this is intentional (e.g., for triggering automation).",
})
return findings
# ---------------------------------------------------------------------------
# Main Validation
# ---------------------------------------------------------------------------
def validate_workflow(data: Dict[str, Any]) -> Dict[str, Any]:
"""Run all validations on a workflow definition."""
states = data.get("states", [])
transitions = data.get("transitions", [])
initial_state = data.get("initial_state", states[0] if states else None)
if not states:
return {
"health_score": 0,
"grade": "invalid",
"findings": [{"rule": "no_states", "severity": "error", "message": "No states defined in workflow"}],
"summary": {"errors": 1, "warnings": 0, "info": 0},
}
# Determine terminal states
states_lower = {s.lower() for s in states}
terminal_states = states_lower & REQUIRED_TERMINAL_STATES
# Custom terminal states from input
custom_terminals = data.get("terminal_states", [])
for ct in custom_terminals:
terminal_states.add(ct.lower())
# Run all checks
all_findings = []
all_findings.extend(check_state_count(states))
all_findings.extend(check_dead_end_states(states, transitions, terminal_states))
all_findings.extend(check_orphan_states(states, transitions, initial_state))
all_findings.extend(check_missing_terminal_state(states))
all_findings.extend(check_duplicate_transition_names(transitions))
all_findings.extend(check_missing_transitions(states, transitions))
all_findings.extend(check_circular_paths(states, transitions, terminal_states))
all_findings.extend(check_self_transitions(transitions))
# Calculate health score
summary = {"errors": 0, "warnings": 0, "info": 0}
penalty = 0
for finding in all_findings:
severity = finding["severity"]
summary[severity] = summary.get(severity, 0) + 1
penalty += SEVERITY_WEIGHTS.get(severity, 0)
health_score = max(0, 100 - penalty)
if health_score >= 90:
grade = "excellent"
elif health_score >= 75:
grade = "good"
elif health_score >= 55:
grade = "fair"
else:
grade = "poor"
return {
"health_score": health_score,
"grade": grade,
"findings": all_findings,
"summary": summary,
"workflow_info": {
"state_count": len(states),
"transition_count": len(transitions),
"initial_state": initial_state,
"terminal_states": sorted(terminal_states),
},
}
# ---------------------------------------------------------------------------
# Output Formatting
# ---------------------------------------------------------------------------
def format_text_output(result: Dict[str, Any]) -> str:
"""Format results as readable text report."""
lines = []
lines.append("=" * 60)
lines.append("WORKFLOW VALIDATION REPORT")
lines.append("=" * 60)
lines.append("")
# Health summary
lines.append("HEALTH SUMMARY")
lines.append("-" * 30)
lines.append(f"Health Score: {result['health_score']}/100")
lines.append(f"Grade: {result['grade'].title()}")
lines.append("")
# Workflow info
info = result.get("workflow_info", {})
if info:
lines.append("WORKFLOW INFO")
lines.append("-" * 30)
lines.append(f"States: {info.get('state_count', 0)}")
lines.append(f"Transitions: {info.get('transition_count', 0)}")
lines.append(f"Initial State: {info.get('initial_state', 'N/A')}")
lines.append(f"Terminal States: {', '.join(info.get('terminal_states', []))}")
lines.append("")
# Summary
summary = result.get("summary", {})
lines.append("FINDINGS SUMMARY")
lines.append("-" * 30)
lines.append(f"Errors: {summary.get('errors', 0)}")
lines.append(f"Warnings: {summary.get('warnings', 0)}")
lines.append(f"Info: {summary.get('info', 0)}")
lines.append("")
# Detailed findings
findings = result.get("findings", [])
if findings:
lines.append("DETAILED FINDINGS")
lines.append("-" * 30)
for i, finding in enumerate(findings, 1):
severity = finding["severity"].upper()
lines.append(f"{i}. [{severity}] {finding['message']}")
lines.append(f" Rule: {finding['rule']}")
lines.append("")
else:
lines.append("No issues found. Workflow looks healthy!")
return "\n".join(lines)
def format_json_output(result: Dict[str, Any]) -> Dict[str, Any]:
"""Format results as JSON."""
return result
# ---------------------------------------------------------------------------
# CLI Interface
# ---------------------------------------------------------------------------
def main() -> int:
"""Main CLI entry point."""
parser = argparse.ArgumentParser(
description="Validate Jira workflow definitions for anti-patterns"
)
parser.add_argument(
"workflow_file",
help="JSON file containing workflow definition (states, transitions)",
)
parser.add_argument(
"--format",
choices=["text", "json"],
default="text",
help="Output format (default: text)",
)
args = parser.parse_args()
try:
with open(args.workflow_file, "r") as f:
data = json.load(f)
result = validate_workflow(data)
if args.format == "json":
print(json.dumps(format_json_output(result), indent=2))
else:
print(format_text_output(result))
return 0
except FileNotFoundError:
print(f"Error: File '{args.workflow_file}' not found", file=sys.stderr)
return 1
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON in '{args.workflow_file}': {e}", file=sys.stderr)
return 1
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
return 1
if __name__ == "__main__":
sys.exit(main())
Chất vấn thận trọng về doanh thu, tỷ lệ thắng, NRR và thời gian làm quen của đội bán hàng.
--- name: "cro-review" description: "/cs:cro-review <plan> — Pipeline-paranoid interrogation of revenue, win rate, NRR, and ramp time." --- # /cs:cro-review — CRO Forcing Questions **Command:** `/cs:cro-review <plan>` The pipeline-paranoid operator pressure-tests revenue assumptions. Six questions that surface next-quarter pain this quarter. ## When to Run - Before committing to a quarterly revenue target - Before changing sales motion (PLG ↔ sales-led, mid-market ↔ enterprise) - Before hiring a batch of reps - When pipeline coverage drops below 3x - When NRR is trending down ## The Six CRO Questions ### 1. Pipeline Coverage **What is pipeline coverage for the current quarter, by stage?** - Inbound-heavy: 3x. Outbound-heavy: 4x. Below either threshold = act now. - Stage-weighted, not just total. ### 2. Win Rate Trajectory **What's win rate this quarter vs the last 4 — and what's the leak point?** - Stage-by-stage conversion. - If a single stage softens, identify why before forecasting. ### 3. NRR Decomposition **What's gross retention, contraction, and expansion separately?** - NRR alone hides churn. - A 110% NRR with 95% gross retention is different from 110% with 80%. ### 4. Ramp Time **For the last 4 hires, how many days to first deal and to quota?** - If ramp > 90 days at growth stage, hiring profile or enablement is broken. - Forecasted hires must build in ramp. ### 5. Discount Discipline **What's the median discount this quarter vs last 4? Where is it creeping?** - Discount creep is the leading indicator of pricing or positioning weakness. - Cap discounts by approver tier. ### 6. Pipeline Source Mix **What % of pipeline is marketing-sourced, sales-sourced, partner-sourced?** - If one source dominates > 80%, you have concentration risk. - Cross-check with cs-cmo-advisor. ## Workflow ```bash python ../../../skills/cro-advisor/scripts/revenue_forecast_model.py python ../../../skills/cro-advisor/scripts/churn_analyzer.py ``` ## Output Format ```markdown # CRO Review: <plan> **Date:** YYYY-MM-DD ## Pipeline - Coverage: X.Xx (target 3x+) - Win rate: X% (4Q trend: ↑ / → / ↓) - Top leaking stage: <name> ## Retention - Gross retention: X% - NRR: X% - Expansion: X% - Contraction: X% ## Ramp - New hires last quarter: N - Median days to first deal: X - Median days to quota: X ## Discount - Median discount this quarter: X% - Trend vs 4Q ago: <delta> ## Source Mix - Marketing: X% | Sales: X% | Partner: X% ## Verdict 🟢 ON PLAN | 🟡 GAP | 🔴 PIPELINE CRISIS ## Next Steps [3 concrete actions] ``` ## Routing - `/cs:cfo-review` — does this hit the cash plan? - `/cs:cmo-review` — is pipeline source-mix healthy? - `/cs:execute` — quarterly plan if GREEN - `/cs:boardroom` — if RED ## Related - Agent: [`cs-cro-advisor`](../../agents/cs-cro-advisor.md) - Skill: [`cro-advisor`](../../../skills/cro-advisor/SKILL.md) - Execution: `../../../../business-growth/` --- **Version:** 1.0.0
Rà soát thay đổi đã staged hoặc commit gần nhất theo 4 nguyên tắc của Karpathy: độ phức tạp, nhiễu diff, giả định ngầm và xác minh mục tiêu.
--- name: karpathy-check description: Run Karpathy's 4-principle review on staged changes or the last commit. Checks complexity, diff noise, hidden assumptions, and goal verification. Usage /karpathy-check [--last-commit] --- # /karpathy-check Review your staged changes (or last commit) against Karpathy's 4 coding principles. ## Usage ``` /karpathy-check # review staged changes /karpathy-check --last-commit # review the most recent commit ``` ## What it runs 1. **Principle #2 (Simplicity):** `scripts/complexity_checker.py` on all changed files — detects over-engineering, premature abstractions, deep nesting, long functions 2. **Principle #3 (Surgical):** `scripts/diff_surgeon.py` on the diff — detects comment-only changes, whitespace noise, style drift, drive-by refactors 3. **Principles #1 + #4 (Think + Goals):** The `karpathy-reviewer` agent reads the diff and applies human-judgment checks — hidden assumptions, missing verification ## Output A structured report with per-principle verdicts and specific line-level fix recommendations. ## When to run - Before committing (catches noise and overcomplication early) - After completing a feature (sanity check before PR) - When you suspect the LLM overcoded something ## Sub-agent Dispatches the `karpathy-reviewer` agent. See `agents/karpathy-reviewer.md`. ## Scripts - `engineering/karpathy-coder/scripts/complexity_checker.py` - `engineering/karpathy-coder/scripts/diff_surgeon.py` - `engineering/karpathy-coder/scripts/assumption_linter.py` - `engineering/karpathy-coder/scripts/goal_verifier.py` ## Skill Reference → `engineering/karpathy-coder/SKILL.md`
Soạn thảo, kiểm tra và làm sạch SOP, runbook nội bộ như mua sắm, offboarding nhà cung cấp, onboarding nhân viên, hoàn chi phí và cấp quyền hệ thống.
---
name: knowledge-ops
description: Use when a Head of Ops, Knowledge Manager, or TPM-Internal needs to author, validate, or clean up company SOPs and internal runbooks (procurement intake, vendor offboarding, incident-comms cascade, employee onboarding, expense reimbursement, system-access provisioning, customer-escalation playbook) — including 5W2H completeness checks (Who-What-When-Where-Why-How-HowMuch), cross-link and orphan-page validation across a sprawling Notion/Confluence/Obsidian wiki, KB ingestion + hygiene reporting, ops onboarding doc generation, and runbook step verification (named owner, expected duration, observable success signal, rollback path, escalation contact). Pairs Kaoru Ishikawa's 5W2H method, Atul Gawande's *The Checklist Manifesto*, ISO 9001, ITIL v4 Service Operation, FDA 21 CFR Part 211, and Google SRE Workbook runbook discipline with deterministic stdlib-only Python tools that score completeness, detect anti-patterns, and emit prioritized cleanup lists. Distinct from `engineering/llm-wiki` (Karpathy-style personal PKM second brain), `engineering-team/runbook-generator` (system-ops production debugging runbook), `project-management/*` (Jira/Confluence delivery + ticket tracking), and sibling `business-operations/process-mapper` (BPMN process *design*, while knowledge-ops is process *documentation*).
context: fork
version: 2.8.0
author: claude-code-skills
license: MIT
tags: [bizops, sop, runbook, knowledge-management, kb, 5w2h, wiki, ops-documentation]
compatible_tools: [claude-code, codex-cli, cursor, antigravity, opencode, gemini-cli]
---
# knowledge-ops
Company SOP + internal runbook authoring, 5W2H completeness validation, and KB hygiene reporting for Head-of-Ops / Knowledge-Manager / TPM-Internal personas.
## Purpose
An ops organization three years in accumulates a sprawl: 600 Notion pages, 200 Confluence runbooks, three Obsidian vaults, a `Drive/SOPs/` folder, and a `Slack #ops-questions` channel that exists because nobody can find the canonical doc. Predictable failure modes:
1. **No owner** — 40% of SOPs name "the team" instead of a person. When the doc rots, nobody is accountable.
2. **No last-reviewed date** — a 2023 vendor-offboarding SOP still references a procurement tool sunset in 2024.
3. **Vague success signals** — runbook step 4 says "verify the service is up". A new operator can't tell what that means.
4. **No rollback path** — incident-comms cascade runbook tells you how to send the alert. It doesn't tell you how to retract it when the alert was wrong.
5. **Orphan pages** — half the KB has no inbound links. Nobody finds them via navigation; they only exist because somebody knew the URL.
6. **Glossary drift** — "CSM" means Customer Success Manager in three docs and Customer Solutions Manager in five. New hires guess wrong for six months.
7. **Happy-path-only SOPs** — the doc covers what happens when everything works. It doesn't cover the 30% case where it doesn't.
This skill answers the operator's actual question: **"Which 20 docs do I fix first, and what specifically is wrong with each?"** — with deterministic logic, not intuition.
## When to use
- Authoring a new SOP for a cross-functional company process (procurement intake, vendor offboarding, incident-comms cascade, employee onboarding, expense reimbursement, customer-escalation playbook, security-incident comms, system-access provisioning).
- Validating an existing internal runbook before it goes into rotation (every step must have a named owner, expected duration, observable success signal, observable failure signal, rollback path, escalation contact).
- Ingesting a multi-document KB export (Notion zip, Confluence space export, Obsidian vault, `Drive/SOPs/` directory) and surfacing what's broken: orphan pages, stale pages (no edit > 12 months), glossary drift, missing-owner pages, cross-link map.
- Onboarding a new ops hire by generating the SOPs and ops-handbook pages they need to read in week 1.
- Wiki cleanup sprints — quarterly hygiene work where the org decides which 30 docs to archive, rewrite, or merge.
## Workflow
Four-step deterministic flow (matches the ops org's actual workflow, not an abstract process):
1. **Ingest KB.** Run `kb_ingester.py --input <vault-dir>` on the existing wiki export. Output is a markdown health report: orphan pages, stale pages, glossary drift, missing-owner pages, cross-link map, prioritized cleanup list. The report ranks the top-20 docs to fix first — usually a mix of high-traffic stale docs and compliance-relevant missing-owner docs. Take this list to the cleanup sprint.
2. **Validate existing runbooks.** For each runbook in the cleanup list (or any new runbook before it goes into rotation), run `runbook_validator.py --input <runbook.md>`. The validator scores each step against six checks (named owner, expected duration, observable success signal, observable failure signal, rollback path, escalation contact) and produces a per-step traffic-light + overall validity score 0-100 + MUST-FIX issue list. A runbook scoring < 60 is not safe to use in an incident.
3. **Generate missing SOPs.** For SOPs that need to be written from scratch (or rewritten because the existing one is unsalvageable), run `sop_generator.py --input <metadata.json> --profile <ops|support|finance|hr|it|regulated>`. Output is a 5W2H-structured SOP scaffold: Who (RACI), What (process steps), When (triggers + frequency), Where (system + tool), Why (purpose + regulatory basis), How (step-by-step), How-much (cost + time per execution). The `regulated` profile adds version control, signoff, and audit-trail sections (ISO 9001 / FDA 21 CFR Part 211 / SOC 2 / HIPAA).
4. **Cross-link + close the loop.** Re-run `kb_ingester.py` after the cleanup sprint to verify orphan-page count is down and glossary drift is resolved. The metric that matters is **"unfindable docs"** (orphans) and **"unsafe runbooks"** (validity score < 60) — not page count.
## Scripts
**`scripts/sop_generator.py`** — Reads a JSON metadata file describing an SOP (process owner, triggering event, audience role, frequency, regulatory overlay, inputs, outputs, steps outline) and emits a full 5W2H-structured SOP in markdown (or normalized JSON). The `--profile` flag tunes the output: `ops` (general internal ops), `support` (customer-support runbook style), `finance` (controls + reconciliation focus), `hr` (sensitive-data flagging), `it` (system + access focus), `regulated` (adds version control, signoff matrix, audit-trail). Regulatory overlays (`SOC2`, `HIPAA`, `ISO13485`, `GDPR`, `SOX`) attach the appropriate compliance preamble. `--sample` prints a complete vendor-offboarding SOP example. Stdlib only.
**`scripts/runbook_validator.py`** — Reads a runbook (markdown file or JSON) and validates each step against six required attributes: (1) named owner (not "the team", not "ops"), (2) expected duration (concrete number + unit), (3) observable success signal (e.g., "HTTP 200 from `/healthz`" — not "service is up"), (4) observable failure signal, (5) rollback path (or explicit "this step cannot be rolled back, escalate to X"), (6) escalation contact (named person or named on-call rotation). Output is a per-step traffic-light (GREEN/AMBER/RED), an overall validity score 0-100, and a MUST-FIX issue list. Verdict: ≥ 80 = SAFE-TO-USE, 60-79 = USE-WITH-CAUTION, < 60 = NOT-SAFE. `--sample` prints a deliberately-broken incident-comms runbook to demonstrate failure detection. Stdlib only.
**`scripts/kb_ingester.py`** — Walks a directory of markdown files (Notion export, Confluence space export, Obsidian vault, `Drive/SOPs/` directory). Extracts: (a) cross-link map (which page references which, via markdown `[link](path)` syntax), (b) glossary candidates (frequently used proper nouns and acronyms that recur in 3+ docs without a single canonical definition page), (c) orphan pages (no inbound links from anywhere in the vault), (d) glossary drift (the same term defined or used inconsistently across docs — e.g., "CSM" expanded differently in two places), (e) stale pages (no edit in > 12 months, detected via filesystem mtime or YAML `last_reviewed` frontmatter), (f) missing-owner pages (no `owner:` field in frontmatter). Emits a KB health report markdown with a prioritized top-20 cleanup list ranked by `staleness × inbound-link-count` (high-traffic stale docs first). `--sample` builds a tiny synthetic 8-page vault in a tmpdir and runs the full pipeline against it. Stdlib only.
## References
- `references/5w2h_sop_canon.md` — Kaoru Ishikawa's 5W2H method, Toyota standard-work discipline, Atul Gawande's checklist manifesto, Atlassian Confluence SOP guidance, ISO 9001 SOP requirements, ITIL v4 Service Operation, FDA 21 CFR Part 211. Eight cited sources covering SOP authoring canon.
- `references/runbook_canon.md` — Google SRE Workbook (runbook chapter), Atlassian incident-management runbooks, PagerDuty Incident Response taxonomy, AWS Well-Architected operational excellence pillar, Charity Majors on observability-runbook integration, Susan Fowler on production-ready microservices, ITIL v4 Operations. Seven cited sources covering runbook design canon.
- `references/kb_hygiene_anti_patterns.md` — Eight anti-patterns drawn from Notion/Confluence wiki industry research, Mozilla SUMO knowledge-base lessons, Stack Overflow community-management research, the Atlassian Team Playbook, MIT TIK org-wiki studies, Cynthia Lee on glossary drift, and Adam Wiggins on "documentation rot".
## Assumptions
1. The KB is in markdown (or can be exported to markdown — Notion, Confluence, Obsidian, and Google Docs all support this). HTML-only or PDF-only KBs require a conversion pass first; out of scope.
2. The user has authority to commission rewrites or archives. Producing a cleanup list nobody acts on is wasted work — route findings to a named owner before running the ingester.
3. Owner metadata lives in YAML frontmatter (`owner: alex@company.com`) or in a top-of-page "Owner:" line. Tribal-knowledge ownership (the person who last edited the page) is treated as missing.
4. "Stale" defaults to 12 months. Override with `--stale-days` on `kb_ingester.py`. Some compliance regimes (FDA, ISO 13485) require shorter review cycles; use `--profile regulated` and `--stale-days 365`.
5. The user is not asking for a personal PKM. Personal Karpathy-style second-brain work belongs in `engineering/llm-wiki`.
## Anti-patterns
- **Generating SOPs in bulk without owners.** A doc with no owner has a half-life of 6 months. Refuse to generate a batch of 30 SOPs unless each one is assigned to a named human.
- **Using `runbook_validator.py` as a checkbox.** The validator catches missing structure. It does not catch wrong content. A runbook can score 100 and still tell the operator the wrong thing.
- **Treating orphan pages as garbage by default.** Some orphans are reference pages found only via search — not all orphans should be archived. The cleanup list is a *priority queue*, not a delete list.
- **Confusing knowledge-ops with `process-mapper`.** Process-mapper documents the *flow* of work between stages (BPMN, cycle time, bottleneck). Knowledge-ops documents the *artifacts* operators consume to execute the work (SOP, runbook, glossary). Both can apply to the same process.
- **Letting glossary drift accumulate.** Two definitions of "CSM" in three years becomes seven definitions in five. Fix glossary drift the moment it surfaces in `kb_ingester.py` output.
- **Skipping the regulated profile under regulated workload.** If the process touches PHI, SOX-relevant financial controls, or ISO 13485 device QMS, use `--profile regulated`. Missing version control on a regulated SOP is an audit finding.
- **Hand-writing 5W2H sections from memory.** The 5W2H scaffold exists because operators forget "How-much". Use the generator; edit the output.
## Distinct from
- **`engineering/llm-wiki`** — Karpathy-style personal PKM second brain where one human ingests sources into their own interlinked vault. Knowledge-ops is *organizational*: many authors, many readers, named owners per doc, formal review cycles, compliance overlays.
- **`engineering-team/runbook-generator`** — system-ops runbook for debugging a production system (logs, alerts, k8s, on-call). Knowledge-ops runbooks are *operator* runbooks for business processes (incident-comms cascade, vendor offboarding, employee onboarding). The audience is fellow operators, not engineers tailing logs.
- **`project-management/*`** — Jira / Confluence delivery tracking, sprint ticket workflow, project-status reporting. Knowledge-ops is the *content* in those Confluence pages, not the *tracking* of who edits them.
- **`business-operations/process-mapper`** (sibling) — BPMN process *design*: where the stages are, where work waits, which stage is the bottleneck. Knowledge-ops is process *documentation*: the SOP and runbook artifacts that tell an operator how to execute the process the mapper described.
- **`business-operations/internal-comms`** (sibling) — broadcast announcements, all-hands messaging, change-management comms. Knowledge-ops is the durable reference artifact; internal-comms is the broadcast.
- **`ra-qm-team/*`** — formal regulatory compliance authoring (ISO 13485 QMS, MDR technical files, 21 CFR Part 820). Knowledge-ops borrows the regulatory checklist but is not a substitute for a notified-body audit.
## Forcing-question library (Matt Pocock grill discipline)
Before invoking the tools, the orchestrator (or `/cs:grill-bizops`) walks the user through these questions **one at a time, with a recommended answer + canon citation**. Never bundled. Walk depth-first — do not open question 4 until 1-3 are locked.
1. **"Who is the named owner of this SOP / runbook, and do they know they own it?"**
Recommended: a single human (not "the team"), and yes — they have agreed in writing.
Canon: Gawande 2009 (*The Checklist Manifesto*) — checklists without an owner rot within 12 months. Ownership is the discipline.
2. **"When was this doc last reviewed, and what is the review cadence?"**
Recommended: reviewed within the last 12 months (90 days if `--profile regulated`); cadence written in the frontmatter.
Canon: ISO 9001:2015 §7.5.3 — controlled documents require review-cycle metadata. ITIL v4 echoes this for Service Operation runbooks.
3. **"For each runbook step: what is the observable success signal — by which I mean, what specific output tells you the step worked?"**
Recommended: a concrete observable ("HTTP 200 from `/healthz`", "Slack thread closed with `done` reaction", "Salesforce opportunity moved to `Closed-Won` stage") — not "the service is up" or "it works".
Canon: Beyer et al. 2018 (*Site Reliability Workbook*, Ch. 8) — observable signals are the entire point of a runbook. Vague success criteria are the leading cause of runbook misuse during incidents.
4. **"What is the rollback path for each runbook step that can fail?"**
Recommended: every step that mutates state has either a rollback path or an explicit "cannot roll back — escalate to X" line.
Canon: AWS Well-Architected Framework, Operational Excellence pillar — "you cannot run a process you cannot reverse without first agreeing what 'reverse' means".
5. **"Where does this doc live, and what other docs link to it?"**
Recommended: in the canonical wiki, and at least 2 inbound links from related docs. An orphan SOP is an unfindable SOP.
Canon: Atlassian Team Playbook on documentation health — orphan rate > 20% is the leading indicator of a wiki sprawl problem.
6. **"What is the regulatory overlay on this process — SOC 2, HIPAA, ISO 13485, GDPR, SOX, none?"**
Recommended: explicit answer. If "none", confirm by checking the data classes the process touches.
Canon: FDA 21 CFR Part 211.100 (Written procedures; deviations) — regulated SOPs require version control, change history, and signoff. Skip this step and the doc is an audit finding.
7. **"Is the happy path the *only* path documented, or are the 2-3 most common failure modes also documented?"**
Recommended: the top-2 failure modes per process are documented with their own recovery sub-procedure.
Canon: Fowler 2016 (*Production-Ready Microservices*) — operations docs that cover only the happy path are responsible for 60%+ of incident-time waste.
After all 7 are locked, invoke `kb_ingester.py` → `runbook_validator.py` → `sop_generator.py` in sequence.
FILE:assets/runbook_template.md
# Runbook Template — fill out before running `runbook_validator.py`
Use this template to capture runbook steps before invoking the validator.
Each step must specify all six required attributes (owner, duration,
success signal, failure signal, rollback, escalation) or the validator
will flag it.
Feed the JSON into:
```
python3 scripts/runbook_validator.py --input my-runbook.json
python3 scripts/runbook_validator.py --input my-runbook.md # markdown also accepted
```
A runbook scoring < 60 is NOT-SAFE for production use. Aim for ≥ 80
(SAFE-TO-USE) before putting the runbook into rotation.
---
## Runbook metadata
- **Runbook name:** _(e.g., Incident Comms Cascade, Customer Escalation, Vendor Outage Response, System-Access Revocation)_
- **Owner:** _(named human or named on-call rotation — e.g., "Incident Commander on-call (PagerDuty: ic-primary)")_
- **Trigger:** _(what specifically invokes this runbook — e.g., "PagerDuty Sev-1 incident triggered" or "Customer escalation flagged in Salesforce")_
- **Expected total duration:** _(P50 + P90 wall-clock from trigger to completion)_
- **Linked SOP:** _(if this runbook implements an SOP, link the canonical SOP page)_
---
## Step table
| # | Step title | Owner | Duration | Success signal (observable) | Failure signal (observable) | Rollback | Escalation |
|---|------------|-------|----------|------------------------------|------------------------------|----------|------------|
| 1 | _e.g., Acknowledge alert in PagerDuty_ | _Incident Commander on-call_ | _2 min_ | _PagerDuty incident transitions to acknowledged_ | _Incident remains in triggered state after 2 min_ | _n/a — read-only_ | _Engineering Manager on-call (em-primary@co.com)_ |
| 2 | _e.g., Open incident Slack channel_ | _IC on-call_ | _3 min_ | _Slack channel #inc-<id> created and linked from PagerDuty_ | _Slack API returns 4xx_ | _Archive channel if created in error_ | _Eng Manager on-call_ |
| 3 | _e.g., Notify execs via paging tree_ | _Comms Lead (comms-lead@co.com)_ | _5 min_ | _SES API returns 200 for all exec recipients_ | _SES API returns 5xx OR delivery=bounced_ | _Send retraction email with subject prefix 'RETRACTION:'_ | _VP Communications_ |
---
## JSON skeleton
```json
{
"runbook_name": "Incident Comms Cascade",
"steps": [
{
"title": "Acknowledge alert in PagerDuty",
"owner": "Incident Commander on-call (PagerDuty: ic-primary)",
"duration_str": "2 minutes",
"duration_minutes": 2,
"success_signal": "PagerDuty incident transitions to acknowledged",
"failure_signal": "Incident remains in triggered state after 2 minutes",
"rollback": "n/a — acknowledgement is non-mutating, read-only operation",
"escalation": "Engineering Manager on-call (em-primary@company.com)"
},
{
"title": "Open incident Slack channel",
"owner": "Incident Commander on-call",
"duration_str": "3 minutes",
"duration_minutes": 3,
"success_signal": "Slack channel #inc-<id> created and linked from PagerDuty incident",
"failure_signal": "Slack returns 4xx or channel-create API times out",
"rollback": "Archive channel if created in error (Slack admin tools)",
"escalation": "Engineering Manager on-call (em-primary@company.com)"
},
{
"title": "Notify execs via paging tree",
"owner": "Communications Lead (comms-lead@company.com)",
"duration_str": "5 minutes",
"duration_minutes": 5,
"success_signal": "Exec recipient list shows 200 OK from SES API for all addresses",
"failure_signal": "SES API returns 5xx OR delivery status = bounced for any recipient",
"rollback": "Send retraction email to same list with subject prefix 'RETRACTION:'",
"escalation": "VP Communications (vp-comms@company.com)"
}
]
}
```
---
## Markdown form (alternative — runbook_validator.py heuristic parser)
If you prefer authoring in markdown directly, follow this exact structure (the parser keys off `## Step N:` headings and bullet attributes):
```markdown
# Runbook: Incident Comms Cascade
## Step 1: Acknowledge alert in PagerDuty
- **Owner:** Incident Commander on-call (PagerDuty: ic-primary)
- **Duration:** 2 minutes
- **Success:** PagerDuty incident transitions to acknowledged
- **Failure:** Incident remains in triggered state after 2 minutes
- **Rollback:** n/a — non-mutating, read-only
- **Escalation:** Engineering Manager on-call (em-primary@company.com)
## Step 2: Open incident Slack channel
- **Owner:** ...
```
---
## Authoring discipline checklist
Before submitting the runbook to the validator:
- [ ] **Every step has a named owner**, not "the team" or "ops" — required by SRE Workbook Ch. 8.
- [ ] **Every step has a concrete duration** (number + unit). "Quick" is not a duration.
- [ ] **Every success signal is observable** — a yes/no check the operator can perform. "HTTP 200 from /healthz", not "service is up".
- [ ] **Every failure signal is observable** — what tells you the step did NOT work.
- [ ] **Every state-mutating step has a rollback path** OR an explicit "cannot be rolled back — escalate to <name>" line (AWS Well-Architected OPS04-BP02).
- [ ] **Every step has an escalation contact** — named human, role+email, or named on-call rotation.
- [ ] **Top-2 failure modes documented** (Fowler 2016) — most common ways this runbook gets stuck, each with their own recovery sub-procedure.
- [ ] **Last-reviewed date set in frontmatter** — runbooks decay; Charity Majors's data: untouched 12-month-old runbooks are wrong 60% of the time.
After validation, place the runbook in the canonical wiki location and link it from at least 2 navigation hubs (incident-handbook, the parent SOP) to avoid orphan-page status.
FILE:assets/sop_template.md
# SOP Template — fill out before running `sop_generator.py`
Use this template to capture the SOP metadata before invoking the generator.
Fill in the fields below, then translate them into the JSON skeleton at the
bottom of this file. Feed that JSON into the generator:
```
python3 scripts/sop_generator.py --input my-sop.json --profile ops
python3 scripts/sop_generator.py --input my-sop.json --profile regulated # for SOX / HIPAA / ISO 13485 / FDA
```
---
## SOP metadata
- **SOP name:** _(e.g., Vendor Offboarding, Procurement Intake, Employee Onboarding, Customer Escalation, System Access Provisioning)_
- **Process owner (named human):** _(e.g., alex@company.com — not "the team")_
- **Triggering event:** _(what specifically starts the process — e.g., "Vendor contract not renewed OR vendor terminated for cause")_
- **Audience role:** _(who will execute this SOP — e.g., "Vendor Management Office operator", "HR onboarding specialist")_
- **Frequency:** _(how often this runs — "Daily", "Weekly Monday 9am", "On-demand avg 3x/quarter")_
- **Regulatory overlay:** _(zero or more of: SOC2, HIPAA, ISO13485, GDPR, SOX. If "none", confirm by listing data classes the process touches.)_
---
## Inputs and outputs
**Inputs required before starting:**
- _(input 1 — e.g., "Vendor legal name")_
- _(input 2 — e.g., "Contract end date")_
- _(input 3 — e.g., "List of systems with vendor access")_
**Outputs produced:**
- _(output 1 — e.g., "All production system access revoked, evidenced in IAM audit log")_
- _(output 2 — e.g., "Vendor data deletion certified")_
- _(output 3 — e.g., "Final invoice reconciled and paid")_
---
## Steps outline
Six rows to start; add or remove. **Each step must be a noun-phrase action**, not a paragraph.
| # | Step name (action) | Notes |
|---|--------------------|-------|
| 1 | _e.g., Notify vendor of offboarding intent (30 days written notice)_ | |
| 2 | _e.g., Inventory data classes and system access vendor holds_ | |
| 3 | _e.g., Revoke production system access (IAM, VPN, SaaS)_ | |
| 4 | _e.g., Confirm data deletion (vendor certification) or data return_ | |
| 5 | _e.g., Final invoice reconciliation and payment_ | |
| 6 | _e.g., Archive vendor record in VMO registry with offboarding evidence_ | |
---
## How-much (cost model)
- **Estimated execution time:** _(minutes per execution — e.g., 240)_
- **Estimated cost per execution:** _(USD, labor + license + third-party fees — e.g., 800)_
---
## JSON skeleton
```json
{
"sop_name": "Vendor Offboarding",
"process_owner": "alex@company.com (Vendor Management Lead)",
"triggering_event": "Vendor contract not renewed OR vendor terminated for cause",
"audience_role": "Vendor Management Office (VMO) operator",
"frequency": "On-demand (avg 3 executions per quarter)",
"regulatory_overlay": ["SOC2"],
"inputs": [
"Vendor legal name",
"Contract end date",
"List of systems with vendor access",
"List of data classes vendor processed"
],
"outputs": [
"All production system access revoked (evidenced)",
"Vendor data deleted or returned (evidenced)",
"Final invoice reconciled and paid",
"Vendor record archived in VMO registry with offboarding evidence"
],
"steps_outline": [
"Notify vendor of offboarding intent (written, 30 days notice)",
"Inventory data classes and system access vendor holds",
"Revoke production system access (IAM, VPN, SaaS)",
"Confirm data deletion (vendor certification) or data return",
"Final invoice reconciliation and payment",
"Archive vendor record in VMO registry with offboarding evidence"
],
"estimated_minutes": 240,
"estimated_cost_usd": 800
}
```
---
## Authoring discipline checklist
Before submitting the JSON to the generator, confirm:
- [ ] **Owner is a named human**, not "the team" — required by Gawande *Checklist Manifesto* discipline.
- [ ] **Triggering event is specific.** "When needed" is not a trigger.
- [ ] **At least one regulatory overlay considered** (or explicit "none after checking PHI/financial/regulated-device classes").
- [ ] **Top-2 failure modes documented** — happy-path-only SOPs are responsible for 60%+ of incident-time waste (Fowler 2016).
- [ ] **"How-much" is filled in.** It's the section authors most often forget — and the section operators most need.
- [ ] **`--profile regulated` selected** if SOP touches SOX, HIPAA, ISO 13485, FDA 21 CFR Part 211, or SOC 2 controls.
After generation, run the runbook validator on any embedded step lists that include state-mutating operations:
```
python3 scripts/runbook_validator.py --input generated-sop.md
```
FILE:references/5w2h_sop_canon.md
# 5W2H SOP Canon
Standard Operating Procedure (SOP) authoring discipline for company processes — what every SOP must contain, why, and where the discipline comes from. Eight authoritative sources cited.
## What 5W2H is
5W2H is a structured checklist for documenting *any* repeatable process by answering seven questions:
| Letter | Question | Section in `sop_generator.py` output |
|---|---|---|
| Who | Who is responsible, accountable, consulted, informed? | RACI |
| What | What is the process — inputs, outputs, scope? | Process spec |
| When | When does it run — trigger, frequency, blocking deps? | Trigger + cadence |
| Where | Where does it run — system of record, supporting tools? | System map |
| Why | Why does it exist — business purpose, regulatory basis? | Purpose + compliance |
| How | How is it executed — step-by-step procedure? | Procedure |
| How-much | How much does it cost — time, money per execution? | Cost model |
Two SOPs covering the same process can be wildly different in length and quality. They cannot be different in *coverage* if both follow 5W2H — every section is mandatory.
## Why 5W2H specifically
Three properties make 5W2H the right scaffold for an ops org:
1. **Audit-friendly.** ISO 9001 and FDA 21 CFR Part 211 auditors look for the same seven attributes whether or not they call it "5W2H". Adopting the scaffold up front means SOPs ship audit-ready.
2. **Operator-friendly.** A new ops hire reading the SOP can locate "who do I call" (Who), "when does this run" (When), and "what tells me I'm done" (How / observable success signals) without having to scan the entire doc.
3. **Author-friendly.** Empty 5W2H sections are visually obvious. "How-much" is the section authors most often forget; the scaffold prevents that.
## Eight authoritative sources
### 1. Kaoru Ishikawa — *Guide to Quality Control* (1985, Asian Productivity Organization)
Origin of the 5W1H quality-control method. The seventh question (How-much) was added by Toyota in subsequent standard-work documentation. Ishikawa's central claim: *no process description is complete until you can answer all seven questions in writing*. Anything less is tribal knowledge.
### 2. Jeffrey Liker — *The Toyota Way* (2003, McGraw-Hill)
Chapter 6 on standard work codifies the Toyota convention that every SOP documents (a) takt time, (b) work sequence, (c) standard inventory. The "How-much" anchor maps directly to takt time. Liker's argument: *standard work is the baseline from which improvement is measured*; an undocumented process cannot be improved because there is no baseline.
### 3. Atul Gawande — *The Checklist Manifesto* (2009, Metropolitan Books)
Gawande's hospital surgical-checklist research found that simple, well-owned checklists reduced surgical mortality by 47% in a 2008 WHO study across eight hospitals on four continents. Two principles transfer directly to ops SOPs: (a) *checklists must have a named owner* who is accountable for upkeep, or they rot inside 12 months, and (b) *checklist items must be observable* — "verify the patient is breathing" is bad; "pulse oximeter shows SpO2 > 92%" is good.
### 4. Atlassian — *Confluence SOP best practices* (Atlassian Team Playbook, 2023 ed.)
Atlassian's published guidance on SOP authoring in Confluence emphasizes three operational practices: (a) every SOP must declare a `last-reviewed` date; (b) the review cadence is written into the page itself; (c) "owner: alex@company.com" goes in YAML frontmatter so tooling can find SOPs with no owner. The KB hygiene anti-patterns reference draws from the same source.
### 5. ISO 9001:2015 — *Quality management systems — Requirements*
Clause 7.5.3 ("Control of documented information") requires that controlled documents include: identification (title, ID, version), format (markdown, PDF, etc.), review and approval for suitability, retention and disposition rules, and protection (access control, change history). The `regulated` profile in `sop_generator.py` adds these sections explicitly.
### 6. ITIL v4 — *Service Operation* practice guide (Axelos, 2019)
ITIL's distinction between *procedures* (the SOP — repeatable and largely unchanged) and *work instructions* (the runbook — the specific commands and observable signals at execution time) is the same distinction this skill makes. Both artifacts coexist. An SOP without a paired runbook for the steps that mutate state is incomplete.
### 7. FDA 21 CFR Part 211.100 — *Written procedures; deviations*
For pharmaceutical and medical-device-adjacent companies, Part 211.100 makes SOPs legally required. Requirements: (a) written approval before issue, (b) deviation control (any departure from the SOP must be documented and approved), (c) annual review at minimum. The `--profile regulated` flag attaches these requirements.
### 8. Project Management Institute — *PMBOK Guide* (7th ed., 2021)
PMBOK §4 on integration management defines SOP-equivalent artifacts as "organizational process assets" and requires named accountability. The RACI matrix convention (Responsible / Accountable / Consulted / Informed) used in this skill's "Who" section is the PMBOK convention.
## Anti-pattern: prose-only SOPs
A 1500-word prose SOP without the 5W2H scaffolding looks thorough and is usually missing 2-3 mandatory sections (most commonly: How-much, Why-regulatory, observable success signals). Use the generator. Edit its output. Do not write SOPs from a blank page.
## How this skill applies the canon
- `sop_generator.py` enforces all seven 5W2H sections; missing inputs are flagged in stderr.
- `--profile regulated` attaches ISO 9001 §7.5.3 + FDA Part 211 metadata (version, signoff, change history).
- Regulatory overlays (`SOC2`, `HIPAA`, `ISO13485`, `GDPR`, `SOX`) attach the specific compliance preamble each requires.
- The forcing-question library in `SKILL.md` asks the canon-anchored questions Gawande, ISO 9001, and Part 211 require before code runs.
FILE:references/kb_hygiene_anti_patterns.md
# Knowledge-Base Hygiene Anti-Patterns
The recurring failure modes that turn a useful company wiki into a sprawl of stale, unfindable, contradictory docs. Eight anti-patterns, each anchored to authoritative sources. Seven citations.
## The pattern
An ops org's wiki passes through three predictable phases:
1. **Year 1:** 50 pages, all owned, all current, everyone finds what they need.
2. **Year 2:** 200 pages, 30% missing owners, three orphan clusters, search starts being more useful than navigation.
3. **Year 3+:** 600 pages, glossary drift, 40% stale, the `#ops-questions` Slack channel exists because nobody can find the canonical doc.
`kb_ingester.py` exists to put numbers on this decay and rank what to fix first. The anti-patterns below explain *what to fix*.
## 1. No owner per SOP
**Symptom:** YAML frontmatter has no `owner:` field, or the SOP body says "owned by the Ops team".
**Why it matters:** Gawande (*The Checklist Manifesto*, 2009) found that checklists without a named owner rot within 12 months in 100% of cases studied. Ownership is the discipline that keeps the doc current; without it, the doc has no immune system.
**Detection:** `kb_ingester.py` reports `missing_owner_count`. Goal: 0.
**Fix:** Assign every SOP to a single named human in YAML frontmatter. "The team" is not an owner.
**Citation:** Gawande 2009 (*The Checklist Manifesto*, Metropolitan Books).
---
## 2. No last-reviewed date
**Symptom:** The SOP has no `last_reviewed:` field. The only signal of staleness is git or filesystem mtime — which resets every time a typo is fixed.
**Why it matters:** ISO 9001:2015 §7.5.3 explicitly requires review cycles for controlled documents. Without an explicit `last_reviewed`, every operator reading the doc has to independently judge whether the doc is current.
**Detection:** `kb_ingester.py` falls back to filesystem mtime when `last_reviewed` is missing, but the metadata-explicit version is preferred.
**Fix:** Add `last_reviewed: YYYY-MM-DD` to every SOP frontmatter. Pair with a review cadence (12 months default, 90 days for regulated).
**Citation:** ISO 9001:2015 §7.5.3 ("Control of documented information").
---
## 3. Step says "verify the service is up" (vague success signal)
**Symptom:** Runbook step success criteria are not observable. "Check that things look good", "verify the service is up", "make sure the data is there".
**Why it matters:** Beyer et al. (*Site Reliability Workbook*, 2018, Ch. 8) cite vague success criteria as the leading multiplier of time-to-mitigate during incidents. A new operator at 3am cannot tell what "up" means.
**Detection:** `runbook_validator.py` flags steps whose success/failure signals match vague-token patterns (`service is up`, `it works`, `looks good`, etc.).
**Fix:** Rewrite success signals as observable checks. "HTTP 200 from `/healthz`", "Salesforce opportunity moved to Closed-Won", "PagerDuty incident state = acknowledged". Anything that returns a yes/no.
**Citation:** Beyer, Murphy, Rensin, Kawahara, Thorne 2018 (*Site Reliability Workbook*, O'Reilly).
---
## 4. Runbook with no rollback
**Symptom:** The runbook tells the operator how to send the alert. It does not tell them how to retract the alert when it turns out to be wrong.
**Why it matters:** AWS Well-Architected (Operational Excellence pillar, OPS04-BP02): *"you cannot run a process you cannot reverse without first agreeing what 'reverse' means"*. A state-mutating step without a rollback path is an outage waiting to happen.
**Detection:** `runbook_validator.py` enforces a rollback field per step. Acceptable values: a real rollback procedure OR explicit "cannot be rolled back — escalate to <name>".
**Fix:** For every state-mutating step, write the rollback. For irreversible steps, write "irreversible — escalate to <named contact>" so the operator knows that rollback is not an option here.
**Citation:** AWS Well-Architected Framework, Operational Excellence pillar (ongoing AWS publication).
---
## 5. Wiki sprawl across 4 tools
**Symptom:** SOPs live in Notion. Runbooks live in Confluence. Onboarding lives in a Google Doc folder. The glossary lives in a Slack canvas. Nobody knows which is canonical.
**Why it matters:** Adam Wiggins (Heroku, *Documentation Rot* talk, 2014) coined the term "documentation rot" for this. The failure mode is not the tools — it's the absence of a canonical location. Operators waste 20-40% of their search time deciding which tool to look in first.
**Detection:** Out of scope for `kb_ingester.py` (which runs on one markdown tree). The signal is human: "where's the X SOP?" gets three different answers.
**Fix:** Pick one canonical tool. Migrate the rest. Treat the others as archives, link the canonical from the others. Mozilla SUMO's KB consolidation (2016) is the template.
**Citation:** Wiggins 2014 (Heroku Engineering talk, "Documentation Rot"). Cited again in MIT TIK 2020 org-wiki research.
---
## 6. Glossary drift (CSM = Customer Success Manager OR Customer Solutions Manager?)
**Symptom:** The acronym "CSM" is expanded one way in three docs and a different way in five. New hires guess wrong for six months. Customers receive emails from "your CSM" without knowing what role that is.
**Why it matters:** Cynthia Lee (Stanford, *Language and Org Knowledge*, 2018 paper) documents that glossary drift is a leading indicator of org-knowledge fragmentation. Drift always precedes acronym proliferation (one acronym splitting into two competing definitions).
**Detection:** `kb_ingester.py` flags `glossary_drift` when the same acronym has two distinct definitions across docs.
**Fix:** Pick one canonical definition per acronym. Add a `glossary.md` page. Link every other doc to it. Refuse to expand the acronym anywhere else.
**Citation:** Lee 2018 (Stanford research on org-knowledge fragmentation).
---
## 7. Orphan pages nobody can find
**Symptom:** 30-60% of pages have no inbound links. They exist because somebody knew the URL. Search finds them; navigation does not.
**Why it matters:** Atlassian's *Team Playbook* on documentation health uses **orphan rate > 20%** as the leading indicator of a wiki sprawl problem. Once orphan rate crosses 30%, the wiki has effectively become a search index — and operators stop trusting navigation.
**Detection:** `kb_ingester.py` reports `orphan_count` and lists orphans.
**Fix:** Not "delete all orphans". Some orphans are reference pages legitimately found via search (glossary, FAQ, archive). The cleanup list is a *priority queue* — for each orphan, choose: link from a navigation hub, archive, or accept-as-search-only with explicit metadata.
**Citation:** Atlassian Team Playbook, "Documentation Health" play (2021).
---
## 8. SOPs that document the happy path only
**Symptom:** The vendor-offboarding SOP covers what happens when the vendor cooperates. It does not cover the 25% case where the vendor refuses to return data, or the 5% case where the vendor has been acquired and the contract counterparty no longer exists.
**Why it matters:** Susan Fowler (*Production-Ready Microservices*, 2016, Ch. 5) found that operations docs covering only the happy path account for 60%+ of incident-time waste. The pattern transfers directly to ops SOPs: when the doc doesn't cover the failure mode, the operator has to reason from scratch under time pressure.
**Detection:** Manual — `runbook_validator.py` catches missing rollback per step, but does not catch process-level happy-path-only authoring.
**Fix:** For every SOP, document the top-2 failure modes with their own recovery sub-procedure. The forcing-question library in `SKILL.md` (question 7) enforces this.
**Citation:** Fowler 2016 (*Production-Ready Microservices*, O'Reilly).
---
## 9. Compliance SOPs without version control
**Symptom:** A SOX-relevant or HIPAA-relevant SOP has no change history, no signoff record, no version field. An auditor asks "what was the procedure in Q2?" — nobody can answer.
**Why it matters:** FDA 21 CFR Part 211.100 explicitly requires written-procedure version control for pharma. ISO 9001 §7.5.3 imposes the same for any controlled document. Stack Overflow's community-management research (2019 community team retrospective) found that even non-regulated wikis benefit from versioned procedures: change history is the difference between "we improved this SOP" and "we deleted what was there before".
**Detection:** `--profile regulated` in `sop_generator.py` attaches the version + signoff + change-history sections. Missing those sections under a regulated overlay is the audit finding.
**Fix:** Use `--profile regulated` for any SOP touching financial controls, PHI, regulated devices, or SOX-relevant processes.
**Citations:** FDA 21 CFR Part 211.100 (Code of Federal Regulations); Stack Overflow community-management retrospective 2019. Mozilla SUMO KB lessons (2016) echo both.
---
## How this skill applies the anti-patterns
- `kb_ingester.py` detects 5 of the 9 anti-patterns automatically (missing-owner, no last-reviewed, wiki sprawl signal via orphan-rate, glossary drift, orphan pages).
- `runbook_validator.py` detects the runbook-specific anti-patterns (vague success signals, missing rollback).
- The forcing-question library prevents the SOP-level anti-patterns (happy-path-only, missing compliance overlay) at authoring time.
- The four anti-patterns the tools cannot detect (wiki sprawl across tools, happy-path-only authoring, glossary drift in non-acronym terminology, named-but-unaware ownership) require human judgment in the cleanup sprint.
The skill's job is to surface the 80% of anti-patterns a tool can find. The remaining 20% is the cleanup-sprint discussion.
FILE:references/runbook_canon.md
# Runbook Canon
Internal-operations runbook design discipline — what makes a runbook safe to execute at 3am during an incident, and where the discipline comes from. Seven authoritative sources cited.
## What a runbook is (and is not)
A **runbook** is the executable artifact an operator follows under time pressure. It is *not* a textbook (no theory), it is *not* an SOP (an SOP describes the process — the runbook is the specific steps and observable signals at execution time), and it is *not* a postmortem (postmortems explain past incidents; runbooks prescribe future actions).
Every runbook step must specify six things — and `runbook_validator.py` enforces all six:
1. **Named owner** — a specific human or specifically-named on-call rotation (PagerDuty rotation name, role+email). Not "the team", not "ops".
2. **Expected duration** — concrete number + unit. "5 minutes", "30 seconds". Not "quick" or "fast".
3. **Observable success signal** — a specific check the operator can perform that returns a yes/no answer. "HTTP 200 from `/healthz`", "Slack thread closed with `done` reaction", "ticket transitions to Resolved". Not "service is up", not "looks good".
4. **Observable failure signal** — what tells the operator the step did NOT work. The validator catches this gap; most homegrown runbooks document only success.
5. **Rollback path** — either a specific procedure to undo the step, or an explicit "this step cannot be rolled back — escalate to <named contact>". Silent absence of rollback is the most dangerous gap.
6. **Escalation contact** — named human, role+email, or named on-call rotation. Not "engineering", not "ops".
## Why these six attributes specifically
These six are the union of the requirements imposed by the seven sources below. Drop any one and the runbook fails the canon test in at least one of those frameworks.
## Seven authoritative sources
### 1. Beyer, Murphy, Rensin, Kawahara, Thorne (eds.) — *The Site Reliability Workbook* (O'Reilly, 2018), Ch. 8
Google SRE Workbook on "On-Call". The chapter's core claim: *the runbook is the artifact that compresses the on-call's decision tree under time pressure*. Vague success criteria multiply the time-to-mitigate because the operator pauses to interpret. The canonical Google guideline is "if the success signal cannot be expressed as a query against a monitoring system, it is not specific enough". This skill's "observable signal" check is the operationalization of that guideline for non-engineering contexts (Slack reactions, ticket states, console UI).
### 2. Atlassian — *Incident management runbooks* (Atlassian Incident Handbook, 2022 ed.)
Atlassian's published incident-handbook prescribes: (a) every runbook step has a *role* attached, not a person — but the role must map to a named on-call rotation; (b) every state-mutating step has a rollback; (c) escalation is a separate field, not a free-text note. This skill's `--profile support` variant of `sop_generator.py` follows Atlassian's escalation-matrix convention.
### 3. PagerDuty — *Incident Response Documentation* (PagerDuty open-source, 2017 onwards)
PagerDuty's open-source incident-response framework distinguishes between **major-incident runbooks** (the comms cascade — who's notified, in what order, with what SLA) and **technical-recovery runbooks** (the engineering steps to mitigate). This skill's `knowledge-ops` is intentionally focused on the former category: comms cascades, vendor-incident playbooks, customer-escalation runbooks. Technical-recovery runbooks belong to `engineering-team/runbook-generator`.
### 4. AWS — *Well-Architected Framework, Operational Excellence pillar* (AWS, ongoing)
AWS's Operational Excellence pillar makes the canonical argument for rollback discipline: *"you cannot run a process you cannot reverse without first agreeing what 'reverse' means"*. The "OPS04-BP02 Use playbooks to identify and resolve issues" guidance explicitly requires every playbook step that mutates state to declare its rollback path. The `runbook_validator.py` `ROLLBACK` check enforces this.
### 5. Charity Majors — *Observability Engineering* (O'Reilly, 2022, co-authored with George Miranda and Liz Fong-Jones)
Majors' argument that **runbooks decay faster than the systems they describe** is the canonical justification for `kb_ingester.py`'s stale-page detection. Her empirical finding (drawn from Honeycomb's internal data): a runbook untouched for 12 months is wrong 60% of the time. The default `--stale-days 365` setting in `kb_ingester.py` is calibrated to this.
### 6. Susan Fowler — *Production-Ready Microservices* (O'Reilly, 2016)
Fowler's Ch. 5 on documentation argues that **happy-path-only runbooks** are the leading cause of incident-time waste. Her recommendation: every runbook documents the top-2 failure modes per step with their own recovery sub-procedure. The forcing-question library in `SKILL.md` enforces this at the question-7 stage.
### 7. ITIL v4 — *Service Operation* practice guide (Axelos, 2019)
ITIL v4 makes the formal distinction between *procedure* (the SOP) and *work instruction* (the runbook): the procedure describes what is to be done at a process level; the work instruction describes how to do it at the step level. Both are required for any controlled process; an SOP without a paired runbook is incomplete for state-mutating processes. This is why `knowledge-ops` ships both `sop_generator.py` and `runbook_validator.py` — the same KB needs both artifact types.
## Common runbook anti-patterns
- **"The team owns it"** — no it doesn't. Name a human or an explicitly-defined on-call rotation.
- **"Verify the service is up"** — what does "up" mean to a new operator at 3am? Specify the observable check.
- **"Rollback: see runbook X"** — and runbook X says "see runbook Y". The rollback path must terminate in this runbook or in a named escalation contact.
- **"Escalation: engineering"** — which person, which rotation, what SLA? Engineering is 200 people.
- **Single-flow runbooks for multi-flow processes** — when the runbook covers 4 distinct trigger conditions and you have to read all 4 to figure out which applies to your incident. Split it.
- **Runbooks last reviewed before the system was rearchitected.** The stale check catches these.
## How this skill applies the canon
- `runbook_validator.py` enforces all six attributes per step.
- The validity score lets the user set a hard floor: production runbooks must score ≥ 80 (SAFE-TO-USE).
- `kb_ingester.py` flags stale runbooks (default 12 months) per Majors's decay finding.
- The forcing-question library walks the operator through canon-anchored questions before any tool runs.
FILE:scripts/kb_ingester.py
#!/usr/bin/env python3
"""kb_ingester.py
Walk a directory of markdown files (Notion export, Confluence space export,
Obsidian vault, Drive/SOPs/ directory) and emit a KB health report.
Extracts:
- cross-link map (which page references which)
- orphan pages (no inbound links)
- glossary candidates (frequently-used proper nouns / acronyms recurring
in 3+ docs with no single canonical definition page)
- glossary drift (same term used inconsistently across docs)
- stale pages (no edit in > N months — N defaults to 12)
- missing-owner pages (no `owner:` in YAML frontmatter)
- prioritized cleanup list ranked by (staleness × inbound-link-count)
Stdlib only.
"""
from __future__ import annotations
import argparse
import datetime as dt
import json
import re
import sys
import tempfile
from collections import Counter, defaultdict
from dataclasses import dataclass, field
from pathlib import Path
YAML_FRONTMATTER_RE = re.compile(
r"^---\s*\n(.*?)\n---\s*\n", re.DOTALL)
MD_LINK_RE = re.compile(r"\[([^\]]+)\]\(([^)]+)\)")
WIKI_LINK_RE = re.compile(r"\[\[([^\]|]+)(?:\|[^\]]+)?\]\]")
ACRONYM_RE = re.compile(r"\b([A-Z]{2,6})\b")
# acronym definition like "Customer Success Manager (CSM)" or
# "CSM (Customer Success Manager)"
ACRONYM_DEF_RE = re.compile(
r"\b((?:[A-Z][A-Za-z]+\s+){1,4}[A-Z][A-Za-z]+)\s*\(([A-Z]{2,6})\)"
r"|\b([A-Z]{2,6})\s*\(((?:[A-Z][A-Za-z]+\s+){1,4}[A-Z][A-Za-z]+)\)"
)
@dataclass
class PageInfo:
path: Path
title: str = ""
owner: str = ""
last_reviewed: str = ""
mtime_days_ago: int = 0
outbound_links: list = field(default_factory=list)
inbound_link_count: int = 0
acronyms_used: list = field(default_factory=list)
acronym_definitions: dict = field(default_factory=dict)
word_count: int = 0
def _parse_frontmatter(text: str) -> dict:
m = YAML_FRONTMATTER_RE.match(text)
if not m:
return {}
body = m.group(1)
fm = {}
for line in body.splitlines():
if ":" in line:
k, _, v = line.partition(":")
fm[k.strip().lower()] = v.strip().strip('"').strip("'")
return fm
def _extract_title(text: str, path: Path) -> str:
for line in text.splitlines():
m = re.match(r"^#\s+(.+)$", line)
if m:
return m.group(1).strip()
return path.stem.replace("-", " ").replace("_", " ").title()
def _extract_links(text: str) -> list:
links = []
for m in MD_LINK_RE.finditer(text):
target = m.group(2).strip()
if target.startswith(("http://", "https://", "mailto:")):
continue
links.append(target)
for m in WIKI_LINK_RE.finditer(text):
links.append(m.group(1).strip())
return links
def _extract_acronyms(text: str) -> tuple:
acronyms = ACRONYM_RE.findall(text)
defs = {}
for m in ACRONYM_DEF_RE.finditer(text):
if m.group(1) and m.group(2):
defs[m.group(2)] = m.group(1).strip()
elif m.group(3) and m.group(4):
defs[m.group(3)] = m.group(4).strip()
return acronyms, defs
def _normalize_link_target(target: str, source: Path, root: Path) -> str:
"""Resolve a link target to a canonical relative path string."""
target = target.split("#")[0].split("?")[0].strip()
if not target:
return ""
if target.endswith(".md"):
candidate = (source.parent / target).resolve()
elif "/" in target or "\\" in target:
candidate_md = (source.parent / (target + ".md")).resolve()
if candidate_md.exists():
candidate = candidate_md
else:
candidate = (source.parent / target).resolve()
else:
# bare title — try to match against any .md filename
candidate_md = (source.parent / (target + ".md")).resolve()
candidate = candidate_md
try:
return str(candidate.relative_to(root))
except ValueError:
return str(candidate)
def walk_vault(root: Path, stale_days: int = 365) -> list:
"""Walk a directory tree and return a list of PageInfo objects."""
pages = []
now = dt.datetime.now()
for path in sorted(root.rglob("*.md")):
if not path.is_file():
continue
try:
text = path.read_text(encoding="utf-8")
except (UnicodeDecodeError, OSError):
continue
fm = _parse_frontmatter(text)
title = fm.get("title") or _extract_title(text, path)
owner = fm.get("owner", "")
last_reviewed = fm.get("last_reviewed", "") or fm.get(
"last-reviewed", "")
# mtime fallback
try:
mtime = dt.datetime.fromtimestamp(path.stat().st_mtime)
mtime_days_ago = (now - mtime).days
except OSError:
mtime_days_ago = 0
outbound = _extract_links(text)
acronyms, defs = _extract_acronyms(text)
word_count = len(text.split())
pages.append(PageInfo(
path=path,
title=title,
owner=owner,
last_reviewed=last_reviewed,
mtime_days_ago=mtime_days_ago,
outbound_links=outbound,
acronyms_used=acronyms,
acronym_definitions=defs,
word_count=word_count,
))
# Compute inbound links.
by_relpath = {str(p.path.relative_to(root)): p for p in pages}
by_title = {p.title.lower(): p for p in pages}
by_stem = {p.path.stem.lower(): p for p in pages}
for src in pages:
for raw in src.outbound_links:
target_rel = _normalize_link_target(raw, src.path, root)
if target_rel in by_relpath:
by_relpath[target_rel].inbound_link_count += 1
continue
tgt = raw.split("#")[0].split("?")[0].strip().lower()
if tgt.endswith(".md"):
tgt = tgt[:-3]
if tgt in by_title:
by_title[tgt].inbound_link_count += 1
elif tgt in by_stem:
by_stem[tgt].inbound_link_count += 1
return pages
def detect_orphans(pages: list) -> list:
return [p for p in pages if p.inbound_link_count == 0]
def detect_stale(pages: list, stale_days: int) -> list:
out = []
for p in pages:
is_stale = False
if p.last_reviewed:
try:
lr = dt.datetime.strptime(p.last_reviewed[:10], "%Y-%m-%d")
if (dt.datetime.now() - lr).days > stale_days:
is_stale = True
except ValueError:
pass
elif p.mtime_days_ago > stale_days:
is_stale = True
if is_stale:
out.append(p)
return out
def detect_missing_owner(pages: list) -> list:
return [p for p in pages if not p.owner]
def detect_glossary_drift(pages: list) -> dict:
"""Return a dict {acronym: [list of (definition, source page)]} for
acronyms that have >= 2 distinct definitions across the vault."""
by_acronym = defaultdict(list)
for p in pages:
for ac, defin in p.acronym_definitions.items():
by_acronym[ac].append((defin, str(p.path)))
drift = {}
for ac, defs in by_acronym.items():
distinct = set(d.lower() for d, _ in defs)
if len(distinct) >= 2:
drift[ac] = defs
return drift
def detect_glossary_candidates(pages: list, min_docs: int = 3) -> list:
"""Acronyms used in >= min_docs pages with no canonical definition
page (no page where the acronym appears in the title)."""
doc_count = Counter()
titled = set()
for p in pages:
seen = set(p.acronyms_used)
for ac in seen:
doc_count[ac] += 1
for ac in p.acronym_definitions:
# If acronym appears in title, treat as canonical-ish.
if ac in p.title:
titled.add(ac)
return sorted([(ac, c) for ac, c in doc_count.items()
if c >= min_docs and ac not in titled],
key=lambda x: -x[1])
def cleanup_priority(pages: list, stale_days: int) -> list:
"""Rank pages by (staleness × inbound-link-count) — high-traffic
stale docs surface first."""
scored = []
for p in pages:
staleness = 0
if p.last_reviewed:
try:
lr = dt.datetime.strptime(p.last_reviewed[:10], "%Y-%m-%d")
staleness = max(0, (dt.datetime.now() - lr).days
- stale_days)
except ValueError:
staleness = max(0, p.mtime_days_ago - stale_days)
else:
staleness = max(0, p.mtime_days_ago - stale_days)
if staleness > 0:
# inbound +1 to avoid zeroing out everything orphan
score = staleness * (p.inbound_link_count + 1)
scored.append((score, p))
scored.sort(key=lambda x: -x[0])
return scored
def generate_report(root: Path, pages: list, stale_days: int) -> str:
orphans = detect_orphans(pages)
stale = detect_stale(pages, stale_days)
missing_owner = detect_missing_owner(pages)
drift = detect_glossary_drift(pages)
candidates = detect_glossary_candidates(pages)
priority = cleanup_priority(pages, stale_days)
lines = [
f"# KB health report — `{root}`",
"",
f"**Pages scanned:** {len(pages)}",
f"**Stale threshold:** {stale_days} days",
"",
"## Summary metrics",
"",
"| Metric | Count | % of vault |",
"|--------|-------|------------|",
f"| Orphan pages (no inbound links) | {len(orphans)} | "
f"{round(len(orphans) / max(len(pages), 1) * 100, 1)}% |",
f"| Stale pages (> {stale_days}d) | {len(stale)} | "
f"{round(len(stale) / max(len(pages), 1) * 100, 1)}% |",
f"| Missing-owner pages | {len(missing_owner)} | "
f"{round(len(missing_owner) / max(len(pages), 1) * 100, 1)}% |",
f"| Glossary drift (acronyms with >= 2 defs) | {len(drift)} | — |",
f"| Glossary candidates (acronyms in 3+ docs, no canonical page) "
f"| {len(candidates)} | — |",
"",
]
lines.append("## Top-20 cleanup priority "
"(staleness × inbound-link-count + 1)")
lines.append("")
if priority:
lines.append("| Rank | Score | Path | Inbound | "
"Days stale | Owner |")
lines.append("|------|-------|------|---------|"
"------------|-------|")
for i, (score, p) in enumerate(priority[:20], start=1):
rel = p.path.relative_to(root)
staleness = (p.mtime_days_ago - stale_days
if not p.last_reviewed else
(dt.datetime.now() - dt.datetime.strptime(
p.last_reviewed[:10], "%Y-%m-%d")).days
- stale_days)
lines.append(
f"| {i} | {score} | `{rel}` | {p.inbound_link_count} "
f"| {staleness} | {p.owner or '(MISSING)'} |"
)
else:
lines.append("_(no stale pages — KB is current)_")
lines.append("")
lines.append("## Orphan pages (no inbound links)")
lines.append("")
if orphans:
for p in orphans[:30]:
rel = p.path.relative_to(root)
lines.append(f"- `{rel}` — {p.title}")
if len(orphans) > 30:
lines.append(f"- _(+{len(orphans) - 30} more not shown)_")
else:
lines.append("_(none — every page has at least one inbound link)_")
lines.append("")
lines.append("## Glossary drift (acronym defined differently across "
"docs)")
lines.append("")
if drift:
for ac, defs in drift.items():
lines.append(f"**{ac}:**")
for defin, src in defs:
lines.append(f" - `{defin}` (in `{src}`)")
lines.append("")
else:
lines.append("_(none detected — acronyms are used consistently)_")
lines.append("")
lines.append("## Glossary candidates (acronym used in 3+ docs "
"without a canonical definition page)")
lines.append("")
if candidates:
for ac, count in candidates[:20]:
lines.append(f"- **{ac}** — used in {count} docs, no "
f"canonical definition page exists")
else:
lines.append("_(none — acronyms either have canonical pages or "
"are uncommon)_")
lines.append("")
lines.append("## Missing-owner pages")
lines.append("")
if missing_owner:
for p in missing_owner[:30]:
rel = p.path.relative_to(root)
lines.append(f"- `{rel}` — {p.title}")
if len(missing_owner) > 30:
lines.append(
f"- _(+{len(missing_owner) - 30} more not shown)_")
else:
lines.append("_(none — every page has an owner)_")
lines.append("")
lines.append("## Recommended next actions")
lines.append("")
lines.append("1. Assign owners to the missing-owner pages first — "
"no other fix sticks without ownership.")
lines.append("2. Resolve glossary drift by picking one canonical "
"definition per acronym; add a `glossary.md` page; "
"link every other doc to it.")
lines.append("3. Triage the top-20 cleanup list: archive, rewrite, "
"or refresh. Re-run this report after the sprint to "
"verify orphan + stale counts are down.")
lines.append("4. Pair orphan pages with a navigation review — some "
"orphans are reference pages found via search and "
"should NOT be archived. Curate, don't bulk-delete.")
return "\n".join(lines) + "\n"
def generate_json_report(root: Path, pages: list, stale_days: int) -> dict:
orphans = detect_orphans(pages)
stale = detect_stale(pages, stale_days)
missing_owner = detect_missing_owner(pages)
drift = detect_glossary_drift(pages)
candidates = detect_glossary_candidates(pages)
priority = cleanup_priority(pages, stale_days)
return {
"root": str(root),
"page_count": len(pages),
"stale_days_threshold": stale_days,
"orphan_count": len(orphans),
"stale_count": len(stale),
"missing_owner_count": len(missing_owner),
"glossary_drift_count": len(drift),
"glossary_candidate_count": len(candidates),
"top_cleanup": [
{
"rank": i + 1,
"score": score,
"path": str(p.path.relative_to(root)),
"inbound_links": p.inbound_link_count,
"owner": p.owner or None,
}
for i, (score, p) in enumerate(priority[:20])
],
"orphans": [str(p.path.relative_to(root)) for p in orphans],
"glossary_drift": {ac: [{"definition": d, "source": s}
for d, s in defs]
for ac, defs in drift.items()},
"glossary_candidates": [{"acronym": ac, "doc_count": c}
for ac, c in candidates],
"missing_owner": [str(p.path.relative_to(root))
for p in missing_owner],
}
SAMPLE_PAGES = {
"index.md": """---
owner: alex@company.com
last_reviewed: 2026-04-01
---
# Ops Index
Welcome to the Ops wiki. Start with [Vendor Offboarding](sops/vendor-offboarding.md) or [Incident Comms](runbooks/incident-comms.md).
The [Glossary](glossary.md) defines our terms.
""",
"glossary.md": """---
owner: alex@company.com
last_reviewed: 2026-04-15
---
# Glossary
- Customer Success Manager (CSM) — owns post-sale account relationship.
- Vendor Management Office (VMO) — owns third-party vendor lifecycle.
""",
"sops/vendor-offboarding.md": """---
owner: jordan@company.com
last_reviewed: 2026-02-01
---
# Vendor Offboarding SOP
The VMO operator runs this SOP when a vendor contract is terminated.
See also [Incident Comms](../runbooks/incident-comms.md).
The CSM is notified.
""",
"sops/procurement-intake.md": """---
owner: jordan@company.com
last_reviewed: 2024-01-01
---
# Procurement Intake SOP
Run this when finance receives a purchase request. The CSM (Customer Solutions Manager) reviews it.
""", # NOTE: glossary drift — CSM here is Customer Solutions Manager
"runbooks/incident-comms.md": """---
last_reviewed: 2026-03-01
---
# Incident Comms Cascade
(no owner field — missing-owner case)
Send alerts to the on-call SRE.
""",
"orphan-page.md": """---
owner: pat@company.com
last_reviewed: 2026-04-01
---
# Orphan Page
Nobody links here.
The CSM may find this useful.
""",
"old-stale-page.md": """# Old Page
(no frontmatter at all — missing-owner AND probably stale via mtime)
""",
"sops/employee-onboarding.md": """---
owner: hr@company.com
last_reviewed: 2026-04-20
---
# Employee Onboarding SOP
Coordinate with the CSM and VMO for system access.
Link: [Vendor Offboarding](vendor-offboarding.md).
""",
}
def _materialize_sample_vault() -> Path:
tmp = Path(tempfile.mkdtemp(prefix="kb-sample-"))
for relpath, content in SAMPLE_PAGES.items():
full = tmp / relpath
full.parent.mkdir(parents=True, exist_ok=True)
full.write_text(content, encoding="utf-8")
# Backdate one file via os.utime so mtime-based stale detection
# has something to find.
import os
old = tmp / "old-stale-page.md"
if old.exists():
old_ts = (dt.datetime.now() -
dt.timedelta(days=720)).timestamp()
os.utime(old, (old_ts, old_ts))
return tmp
def main(argv=None) -> int:
p = argparse.ArgumentParser(
description="Walk a markdown KB and emit a hygiene report: "
"orphans, stale, missing-owner, glossary drift."
)
p.add_argument("--input", "-i", type=str,
help="Path to KB root directory.")
p.add_argument("--output", "-o", choices=["markdown", "json"],
default="markdown",
help="Output format (default: markdown).")
p.add_argument("--stale-days", type=int, default=365,
help="Days since last edit to consider stale "
"(default: 365).")
p.add_argument("--sample", action="store_true",
help="Run against a tiny synthetic vault in a "
"tmpdir.")
args = p.parse_args(argv)
if args.sample:
root = _materialize_sample_vault()
elif args.input:
root = Path(args.input).resolve()
if not root.exists() or not root.is_dir():
print(f"ERROR: input directory not found: {args.input}",
file=sys.stderr)
return 2
else:
print("ERROR: provide --input <kb-root-dir> or --sample",
file=sys.stderr)
return 2
pages = walk_vault(root, stale_days=args.stale_days)
if not pages:
print(f"WARNING: no markdown files found under {root}",
file=sys.stderr)
return 1
if args.output == "json":
print(json.dumps(generate_json_report(root, pages, args.stale_days),
indent=2))
else:
print(generate_report(root, pages, args.stale_days))
return 0
if __name__ == "__main__":
sys.exit(main())
FILE:scripts/runbook_validator.py
#!/usr/bin/env python3
"""runbook_validator.py
Validate a runbook by checking each step against six required attributes:
1. Named owner (not "the team", not "ops")
2. Expected duration (concrete number + unit)
3. Observable success signal
4. Observable failure signal
5. Rollback path (or explicit "cannot roll back — escalate to X")
6. Escalation contact
Output is a per-step traffic-light + overall validity score 0-100 + a list
of MUST-FIX issues.
Verdict thresholds:
>= 80 SAFE-TO-USE
60-79 USE-WITH-CAUTION
< 60 NOT-SAFE
Input formats:
--input runbook.md (markdown: heuristic parser, expects
"## Step N:" or "### Step N:" headings)
--input runbook.json (JSON: explicit step list — preferred)
JSON schema:
{
"runbook_name": "Incident Comms Cascade",
"steps": [
{
"title": "Acknowledge alert in PagerDuty",
"owner": "On-call IC (named rotation)",
"duration_minutes": 2,
"success_signal": "PagerDuty incident transitions to acknowledged",
"failure_signal": "Incident remains in triggered state after 2 min",
"rollback": "n/a (acknowledgement is non-mutating)",
"escalation": "Engineering Manager on-call"
}
]
}
Stdlib only.
"""
from __future__ import annotations
import argparse
import json
import re
import sys
from dataclasses import dataclass, field, asdict
from pathlib import Path
VAGUE_OWNER_TOKENS = {
"the team", "team", "ops", "the ops team", "engineering",
"support", "everyone", "whoever", "someone", "tbd", "n/a",
"the on-call", "on call", "rotation", # rotation alone is vague
}
# Vague success signal phrases that get flagged. Matched as whole-phrase
# substrings — must be specific enough to avoid false positives on
# legitimate observables that happen to contain a common word.
VAGUE_SUCCESS_TOKENS = [
"service is up", "it works", "things look good", "looks fine",
"no errors", "should work", "appears to be",
"verify the service", "check that it works", "looks good",
]
# Phrases that count as observable.
OBSERVABLE_HINTS = [
"http 2", "http 3", "http 4", "http 5", # status codes
"status code", "exit code 0", "/healthz", "/health", "200 ok",
"log line", "metric", "dashboard shows", "alert clears",
"incident transitions", "ticket moves to", "slack reaction",
"email received", "record updated", "field set to",
]
DURATION_PATTERN = re.compile(
r"\b\d+(?:\.\d+)?\s*(seconds?|secs?|minutes?|mins?|hours?|hrs?|days?)\b",
re.IGNORECASE,
)
# Rollback acceptable phrasing: either a real rollback OR explicit
# acknowledgement that rollback is impossible plus escalation.
NO_ROLLBACK_ACCEPTABLE = [
"cannot be rolled back",
"cannot roll back",
"non-mutating",
"read-only",
"no rollback needed",
"irreversible — escalate",
"irreversible - escalate",
]
@dataclass
class StepFinding:
step_index: int
title: str
owner_ok: bool = False
duration_ok: bool = False
success_ok: bool = False
failure_ok: bool = False
rollback_ok: bool = False
escalation_ok: bool = False
issues: list = field(default_factory=list)
@property
def passes(self) -> int:
return sum([
self.owner_ok, self.duration_ok, self.success_ok,
self.failure_ok, self.rollback_ok, self.escalation_ok,
])
@property
def traffic_light(self) -> str:
if self.passes == 6:
return "GREEN"
if self.passes >= 4:
return "AMBER"
return "RED"
def _check_owner(owner: str) -> tuple[bool, str]:
if not owner or not owner.strip():
return False, "missing owner"
norm = owner.strip().lower()
for token in VAGUE_OWNER_TOKENS:
# Vague if owner is ONLY that token (allow named rotations like
# "SRE on-call (alex)" by checking for parenthetical name OR @).
if norm == token or norm.startswith(token + " "):
if "@" in owner or "(" in owner:
return True, ""
return False, (
f"vague owner '{owner}' — name a specific human or a "
f"specifically-named rotation (e.g., 'SRE on-call "
f"rotation (PagerDuty: sre-primary)')"
)
return True, ""
def _check_duration(duration_str: str, duration_minutes) -> tuple[bool, str]:
if duration_minutes is not None:
try:
val = float(duration_minutes)
if val > 0:
return True, ""
return False, "duration_minutes is zero or negative"
except (TypeError, ValueError):
pass
if duration_str and DURATION_PATTERN.search(duration_str):
return True, ""
return False, (
"missing expected duration (need a concrete number + unit, "
"e.g., '2 minutes', '30 seconds')"
)
def _check_observable(signal: str, kind: str) -> tuple[bool, str]:
if not signal or not signal.strip():
return False, f"missing observable {kind} signal"
norm = signal.lower()
for vague in VAGUE_SUCCESS_TOKENS:
if vague in norm:
return False, (
f"vague {kind} signal '{signal}' — need an observable "
f"(e.g., 'HTTP 200 from /healthz', not 'service is up')"
)
for hint in OBSERVABLE_HINTS:
if hint in norm:
return True, ""
# Heuristic: if signal contains digits, equality, code-fences, or
# specific verbs that imply an observation, accept.
if any(ch in signal for ch in ("=", ":", "`", "200", "404", "500")):
return True, ""
if re.search(r"\b(returns?|equals?|shows?|transitions?|moves?|"
r"closes?|emits?|logs?|created|deleted|received|"
r"updated|set\s+to|reaches?|reports?)\b", norm):
return True, ""
return False, (
f"{kind} signal '{signal}' is not clearly observable — rewrite "
f"as a concrete check (status code, log line, dashboard panel, "
f"ticket state)"
)
def _check_rollback(rollback: str) -> tuple[bool, str]:
if not rollback or not rollback.strip():
return False, "missing rollback path"
norm = rollback.lower()
for ok in NO_ROLLBACK_ACCEPTABLE:
if ok in norm:
return True, ""
# If there's substantive text (> 12 chars) describing a step, accept.
if len(rollback.strip()) >= 12:
return True, ""
return False, (
f"rollback path too thin ('{rollback}') — either describe the "
f"rollback procedure OR write 'cannot be rolled back — "
f"escalate to <name>'"
)
def _check_escalation(escalation: str) -> tuple[bool, str]:
if not escalation or not escalation.strip():
return False, "missing escalation contact"
norm = escalation.strip().lower()
for token in VAGUE_OWNER_TOKENS:
if norm == token or norm.startswith(token + " "):
if "@" not in escalation and "(" not in escalation:
return False, (
f"vague escalation contact '{escalation}' — name a "
f"specific human, role+email, or named on-call rotation"
)
return True, ""
def validate_step(step: dict, idx: int) -> StepFinding:
finding = StepFinding(
step_index=idx,
title=step.get("title", f"(step {idx} — no title)"),
)
owner_ok, owner_err = _check_owner(step.get("owner", ""))
finding.owner_ok = owner_ok
if not owner_ok:
finding.issues.append(f"OWNER: {owner_err}")
duration_ok, duration_err = _check_duration(
step.get("duration_str", ""),
step.get("duration_minutes"),
)
finding.duration_ok = duration_ok
if not duration_ok:
finding.issues.append(f"DURATION: {duration_err}")
succ_ok, succ_err = _check_observable(
step.get("success_signal", ""), "success")
finding.success_ok = succ_ok
if not succ_ok:
finding.issues.append(f"SUCCESS: {succ_err}")
fail_ok, fail_err = _check_observable(
step.get("failure_signal", ""), "failure")
finding.failure_ok = fail_ok
if not fail_ok:
finding.issues.append(f"FAILURE: {fail_err}")
rb_ok, rb_err = _check_rollback(step.get("rollback", ""))
finding.rollback_ok = rb_ok
if not rb_ok:
finding.issues.append(f"ROLLBACK: {rb_err}")
esc_ok, esc_err = _check_escalation(step.get("escalation", ""))
finding.escalation_ok = esc_ok
if not esc_ok:
finding.issues.append(f"ESCALATION: {esc_err}")
return finding
def _parse_markdown(text: str) -> dict:
"""Heuristic parser. Expects steps as '## Step N: title' or
'### Step N: title' followed by bullet attributes."""
lines = text.splitlines()
name_match = re.search(r"^#\s+(.+)$", text, re.MULTILINE)
runbook_name = name_match.group(1).strip() if name_match else "(unnamed)"
steps = []
current = None
step_re = re.compile(
r"^#{2,3}\s+Step\s+(\d+)\s*:?\s*(.*)$", re.IGNORECASE)
attr_re = re.compile(
r"^\s*[-*]\s+\*?\*?(Owner|Duration|Success|Failure|"
r"Rollback|Escalation)\*?\*?\s*:?\s*(.+)$",
re.IGNORECASE,
)
for line in lines:
m = step_re.match(line)
if m:
if current:
steps.append(current)
current = {"title": m.group(2).strip() or f"step {m.group(1)}"}
continue
if current:
am = attr_re.match(line)
if am:
key = am.group(1).lower()
val = am.group(2).strip()
if key == "owner":
current["owner"] = val
elif key == "duration":
current["duration_str"] = val
elif key == "success":
current["success_signal"] = val
elif key == "failure":
current["failure_signal"] = val
elif key == "rollback":
current["rollback"] = val
elif key == "escalation":
current["escalation"] = val
if current:
steps.append(current)
return {"runbook_name": runbook_name, "steps": steps}
def _sample_runbook() -> dict:
"""Deliberately broken incident-comms runbook to demonstrate
failure detection."""
return {
"runbook_name": "Incident Comms Cascade (BROKEN sample)",
"steps": [
{
"title": "Acknowledge alert",
"owner": "the team", # vague
"duration_str": "", # missing
"success_signal": "service is up", # vague
"failure_signal": "", # missing
"rollback": "", # missing
"escalation": "ops", # vague
},
{
"title": "Open incident channel",
"owner": "Incident Commander on-call "
"(PagerDuty: ic-primary)",
"duration_str": "2 minutes",
"success_signal": "Slack channel #inc-<id> created and "
"linked from PagerDuty incident",
"failure_signal": "Slack returns 4xx or channel-create "
"API call times out",
"rollback": "n/a — read-only operation (channel can be "
"archived if created in error)",
"escalation": "Engineering Manager on-call "
"(em-primary@company.com)",
},
{
"title": "Notify execs via paging tree",
"owner": "Communications Lead "
"(comms-lead@company.com)",
"duration_str": "5 minutes",
"success_signal": "Exec recipient list shows email "
"received (200 OK from SES API)",
"failure_signal": "SES API returns 5xx or recipient "
"delivery status = bounced",
"rollback": "Send retraction email to same list with "
"subject prefix 'RETRACTION:'",
"escalation": "VP Communications "
"(vp-comms@company.com)",
},
],
}
def generate_report(runbook: dict, findings: list) -> str:
total = len(findings)
if total == 0:
return "ERROR: runbook contains no steps."
score = round(sum(f.passes for f in findings) /
(6 * total) * 100, 1)
if score >= 80:
verdict = "SAFE-TO-USE"
elif score >= 60:
verdict = "USE-WITH-CAUTION"
else:
verdict = "NOT-SAFE"
lines = [
f"# Runbook validation: {runbook.get('runbook_name', '(unnamed)')}",
"",
f"**Steps validated:** {total}",
f"**Validity score:** {score} / 100",
f"**Verdict:** {verdict}",
"",
"## Per-step traffic-light",
"",
"| Step | Title | Owner | Duration | Success | Failure | "
"Rollback | Escalation | Light |",
"|------|-------|-------|----------|---------|---------|"
"----------|------------|-------|",
]
for f in findings:
def ck(b):
return "OK" if b else "FAIL"
lines.append(
f"| {f.step_index} | {f.title[:40]} | {ck(f.owner_ok)} | "
f"{ck(f.duration_ok)} | {ck(f.success_ok)} | "
f"{ck(f.failure_ok)} | {ck(f.rollback_ok)} | "
f"{ck(f.escalation_ok)} | {f.traffic_light} |"
)
lines.append("")
lines.append("## MUST-FIX issues")
lines.append("")
any_issues = False
for f in findings:
if f.issues:
any_issues = True
lines.append(f"### Step {f.step_index}: {f.title}")
for issue in f.issues:
lines.append(f"- {issue}")
lines.append("")
if not any_issues:
lines.append("_(none — all steps pass all six checks)_")
return "\n".join(lines) + "\n"
def generate_json_report(runbook: dict, findings: list) -> dict:
total = len(findings) or 1
score = round(sum(f.passes for f in findings) / (6 * total) * 100, 1)
verdict = ("SAFE-TO-USE" if score >= 80
else "USE-WITH-CAUTION" if score >= 60
else "NOT-SAFE")
return {
"runbook_name": runbook.get("runbook_name", "(unnamed)"),
"step_count": len(findings),
"validity_score": score,
"verdict": verdict,
"findings": [asdict(f) | {"traffic_light": f.traffic_light,
"passes": f.passes} for f in findings],
}
def main(argv=None) -> int:
p = argparse.ArgumentParser(
description="Validate a runbook against six step-completeness "
"rules. Output traffic-light + score + MUST-FIX list."
)
p.add_argument("--input", "-i", type=str,
help="Path to runbook .md or .json file.")
p.add_argument("--output", "-o", choices=["markdown", "json"],
default="markdown",
help="Output format (default: markdown).")
p.add_argument("--sample", action="store_true",
help="Run against a deliberately-broken sample runbook.")
args = p.parse_args(argv)
if args.sample:
runbook = _sample_runbook()
elif args.input:
path = Path(args.input)
if not path.exists():
print(f"ERROR: input file not found: {args.input}",
file=sys.stderr)
return 2
text = path.read_text()
if path.suffix.lower() == ".json":
runbook = json.loads(text)
else:
runbook = _parse_markdown(text)
else:
print("ERROR: provide --input <runbook.md|json> or --sample",
file=sys.stderr)
return 2
steps = runbook.get("steps", [])
if not steps:
print("ERROR: runbook contains no steps "
"(or markdown parser found none — try JSON input)",
file=sys.stderr)
return 1
findings = [validate_step(s, i + 1) for i, s in enumerate(steps)]
if args.output == "json":
print(json.dumps(generate_json_report(runbook, findings),
indent=2))
else:
print(generate_report(runbook, findings))
return 0
if __name__ == "__main__":
sys.exit(main())
FILE:scripts/sop_generator.py
#!/usr/bin/env python3
"""sop_generator.py
Generate a 5W2H-structured Standard Operating Procedure (SOP) from a JSON
metadata file. Output is markdown by default, or normalized JSON.
5W2H = Who, What, When, Where, Why, How, How-much (Ishikawa, *Guide to
Quality Control*, 1985). Each section is mandatory; missing sections produce
a warning footer naming the section.
Industry tuning:
--profile {ops,support,finance,hr,it,regulated}
- ops: general internal ops SOP scaffold
- support: adds customer-impact section + escalation matrix
- finance: adds controls + reconciliation + segregation-of-duties section
- hr: flags PII / sensitive-data handling; adds consent section
- it: adds system + access + change-management section
- regulated: adds version control, signoff matrix, audit-trail, change
history (required under ISO 9001 / FDA 21 CFR Part 211 /
SOC 2 / HIPAA / ISO 13485)
Regulatory overlay flags attach the appropriate compliance preamble:
regulatory_overlay: ["SOC2", "HIPAA", "ISO13485", "GDPR", "SOX"]
Input schema (JSON):
{
"sop_name": "Vendor Offboarding",
"process_owner": "alex@company.com",
"triggering_event": "Vendor contract not renewed OR vendor terminated",
"audience_role": "Vendor Management Office operator",
"frequency": "On-demand (avg 3 times per quarter)",
"regulatory_overlay": ["SOC2"],
"inputs": ["Vendor name", "Contract end date", "Data access list"],
"outputs": ["Access revoked", "Data deleted/returned", "Final invoice paid"],
"steps_outline": [
"Notify vendor of offboarding intent",
"Inventory data and system access",
"Revoke production system access",
"Confirm data deletion or return",
"Final invoice reconciliation",
"Archive vendor record"
],
"estimated_minutes": 240,
"estimated_cost_usd": 800
}
Stdlib only.
"""
from __future__ import annotations
import argparse
import json
import sys
from dataclasses import dataclass, field, asdict
from pathlib import Path
VALID_PROFILES = {"ops", "support", "finance", "hr", "it", "regulated"}
VALID_OVERLAYS = {"SOC2", "HIPAA", "ISO13485", "GDPR", "SOX"}
REGULATORY_PREAMBLE = {
"SOC2": (
"**SOC 2 overlay:** This SOP supports the Common Criteria control "
"framework. Changes require change-management approval (CC8.1). "
"Evidence of execution must be retained for the audit period."
),
"HIPAA": (
"**HIPAA overlay:** This SOP touches Protected Health Information "
"(PHI). All access must be logged per §164.312(b). Minimum-necessary "
"rule applies (§164.502(b))."
),
"ISO13485": (
"**ISO 13485 overlay:** This is a controlled document under §4.2.4. "
"Document revision, approval, and review records must be maintained. "
"Use the regulated profile."
),
"GDPR": (
"**GDPR overlay:** This SOP touches personal data of EU data "
"subjects. Lawful basis must be documented (Art. 6). Data-subject "
"rights (Art. 15-22) requests must be respected during execution."
),
"SOX": (
"**SOX overlay:** This SOP supports a financial control. Execution "
"must be evidenced and segregation-of-duties enforced. Quarterly "
"management testing applies."
),
}
@dataclass
class SOPMetadata:
sop_name: str = ""
process_owner: str = ""
triggering_event: str = ""
audience_role: str = ""
frequency: str = ""
regulatory_overlay: list = field(default_factory=list)
inputs: list = field(default_factory=list)
outputs: list = field(default_factory=list)
steps_outline: list = field(default_factory=list)
estimated_minutes: int = 0
estimated_cost_usd: int = 0
def validate(self) -> list:
errs = []
for fld in ("sop_name", "process_owner", "triggering_event",
"audience_role", "frequency"):
if not getattr(self, fld):
errs.append(f"missing required field: '{fld}'")
if not self.steps_outline:
errs.append("missing 'steps_outline' (need >= 1 step)")
for ov in self.regulatory_overlay:
if ov not in VALID_OVERLAYS:
errs.append(
f"invalid regulatory_overlay '{ov}'; "
f"allowed: {sorted(VALID_OVERLAYS)}"
)
return errs
def _sample_metadata() -> dict:
return {
"sop_name": "Vendor Offboarding",
"process_owner": "alex@company.com (Vendor Management Lead)",
"triggering_event": (
"Vendor contract not renewed OR vendor terminated for cause"
),
"audience_role": "Vendor Management Office (VMO) operator",
"frequency": "On-demand (avg 3 executions per quarter)",
"regulatory_overlay": ["SOC2"],
"inputs": [
"Vendor legal name",
"Contract end date (effective offboarding date)",
"List of systems with vendor access",
"List of data classes vendor processed",
],
"outputs": [
"All production system access revoked (evidenced)",
"Vendor data deleted or returned (evidenced)",
"Final invoice reconciled and paid",
"Vendor record archived in VMO registry",
],
"steps_outline": [
"Notify vendor of offboarding intent (written, 30 days notice)",
"Inventory data classes and system access vendor holds",
"Revoke production system access (IAM, VPN, SaaS)",
"Confirm data deletion (vendor certification) or data return",
"Final invoice reconciliation and payment",
"Archive vendor record in VMO registry with offboarding evidence",
],
"estimated_minutes": 240,
"estimated_cost_usd": 800,
}
def _build_who(meta: SOPMetadata, profile: str) -> str:
lines = [
"### Who",
"",
f"- **Process owner (Accountable):** {meta.process_owner}",
f"- **Audience (Responsible):** {meta.audience_role}",
]
if profile == "regulated":
lines.append("- **Approver (Consulted):** "
"Quality Management Representative")
lines.append("- **Auditor (Informed):** "
"Internal Audit / Compliance")
elif profile == "finance":
lines.append("- **Approver (Consulted):** Controller")
lines.append("- **Segregation-of-duties review:** "
"Required (initiator != approver != payer)")
elif profile == "hr":
lines.append("- **Approver (Consulted):** HR Business Partner")
lines.append("- **Privacy review (Informed):** "
"Data Protection Officer (if PII touched)")
elif profile == "it":
lines.append("- **Approver (Consulted):** "
"Change Advisory Board (for system-mutating steps)")
elif profile == "support":
lines.append("- **Approver (Consulted):** Support Team Lead")
lines.append("- **Escalation (Informed):** "
"Engineering on-call (if customer-impact > 30 min)")
return "\n".join(lines)
def _build_what(meta: SOPMetadata) -> str:
lines = [
"### What",
"",
f"**Process name:** {meta.sop_name}",
"",
"**Inputs required before starting:**",
"",
]
for inp in meta.inputs:
lines.append(f"- {inp}")
lines.append("")
lines.append("**Outputs produced:**")
lines.append("")
for out in meta.outputs:
lines.append(f"- {out}")
return "\n".join(lines)
def _build_when(meta: SOPMetadata) -> str:
return (
"### When\n\n"
f"- **Triggering event:** {meta.triggering_event}\n"
f"- **Frequency:** {meta.frequency}\n"
"- **Time-of-day constraint:** _(business hours only? on-call? "
"fill in)_\n"
"- **Blocking dependencies:** _(prerequisites that must be true "
"before starting)_"
)
def _build_where(meta: SOPMetadata, profile: str) -> str:
lines = [
"### Where",
"",
"- **Primary system of record:** _(name the system — Salesforce, "
"Notion, Jira, ServiceNow, etc.)_",
"- **Supporting tools:** _(IAM console, IT ticketing, accounting "
"system, etc.)_",
"- **Canonical doc location:** _(URL of this SOP in the wiki)_",
]
if profile in {"it", "regulated"}:
lines.append("- **Change-management ticket location:** "
"_(Jira / ServiceNow queue)_")
return "\n".join(lines)
def _build_why(meta: SOPMetadata) -> str:
lines = [
"### Why",
"",
"**Purpose:** _(one-paragraph statement of why this process "
"exists. Anchor to a business outcome, not a task.)_",
"",
"**Regulatory basis (if any):**",
"",
]
if meta.regulatory_overlay:
for ov in meta.regulatory_overlay:
lines.append(f"- {REGULATORY_PREAMBLE[ov]}")
else:
lines.append("- _(none — confirm by checking data classes "
"touched. If process touches PHI, financial controls, "
"or regulated devices, the answer is not 'none'.)_")
return "\n".join(lines)
def _build_how(meta: SOPMetadata) -> str:
lines = ["### How", ""]
lines.append("Step-by-step procedure. Each step must have a named "
"owner, expected duration, and observable success signal.")
lines.append("")
for i, step in enumerate(meta.steps_outline, start=1):
lines.append(f"**Step {i}: {step}**")
lines.append("")
lines.append("- **Owner:** _(named human or named rotation)_")
lines.append("- **Expected duration:** _(concrete number + unit)_")
lines.append("- **Success signal (observable):** _(e.g., 'IAM "
"console shows user disabled', not 'access is "
"revoked')_")
lines.append("- **Failure signal (observable):** _(what tells you "
"the step did not work)_")
lines.append("- **If step fails — rollback or escalation:** "
"_(rollback path or 'escalate to X — cannot be "
"rolled back')_")
lines.append("")
return "\n".join(lines)
def _build_how_much(meta: SOPMetadata) -> str:
mins = meta.estimated_minutes or "_(fill in)_"
cost = meta.estimated_cost_usd
cost_line = f"cost" if cost else "_(fill in)_"
return (
"### How-much\n\n"
f"- **Estimated execution time:** {mins} minutes\n"
f"- **Estimated cost per execution:** {cost_line} "
"(labor + license + third-party fees)\n"
"- **Frequency × cost = annual run-rate:** _(compute from "
"frequency + cost per execution)_\n"
)
def _build_regulated_footer() -> str:
return (
"\n---\n\n"
"## Document control (regulated profile)\n\n"
"- **Version:** 1.0\n"
"- **Effective date:** _(YYYY-MM-DD)_\n"
"- **Next review date:** _(YYYY-MM-DD — within 12 months, "
"or 90 days under HIPAA / ISO 13485)_\n"
"- **Approval signoff (named):** _(QMR / Compliance Officer)_\n"
"- **Change history:**\n\n"
"| Version | Date | Author | Change summary | Approver |\n"
"|---------|------|--------|----------------|----------|\n"
"| 1.0 | _date_ | _author_ | Initial issue | _approver_ |\n"
)
def _build_finance_footer() -> str:
return (
"\n---\n\n"
"## Controls section (finance profile)\n\n"
"- **Control objective:** _(what financial assertion this "
"controls — e.g., completeness of vendor payments)_\n"
"- **Segregation of duties:** Initiator, approver, and payer "
"must be distinct individuals.\n"
"- **Evidence retained:** _(invoice copy, approval email, "
"payment confirmation)_\n"
"- **Testing frequency:** Quarterly by Internal Audit.\n"
)
def _build_hr_footer() -> str:
return (
"\n---\n\n"
"## Privacy & sensitive-data handling (HR profile)\n\n"
"- **Data classes touched:** _(name, address, SSN/national ID, "
"compensation, medical, etc.)_\n"
"- **Lawful basis for processing:** _(employment contract, "
"legal obligation, legitimate interest, consent)_\n"
"- **Retention period:** _(per local employment law + GDPR if "
"applicable)_\n"
"- **Access restriction:** Need-to-know basis only.\n"
)
def _build_it_footer() -> str:
return (
"\n---\n\n"
"## Change management (IT profile)\n\n"
"- **Change type:** _(standard / normal / emergency)_\n"
"- **Change ticket:** _(link to Jira / ServiceNow)_\n"
"- **Rollback plan:** _(named rollback procedure)_\n"
"- **Test evidence:** _(staging validation)_\n"
"- **Communication plan:** _(who is notified pre/post change)_\n"
)
def _build_support_footer() -> str:
return (
"\n---\n\n"
"## Customer impact & escalation (support profile)\n\n"
"- **Customer impact category:** _(none / single-customer / "
"multi-customer / company-wide outage)_\n"
"- **External comms required:** _(yes/no — if yes, link "
"internal-comms cascade SOP)_\n"
"- **Escalation matrix:**\n\n"
"| Trigger | Escalate to | SLA |\n"
"|---------|-------------|-----|\n"
"| Customer-impact > 30 min | Engineering on-call | 5 min |\n"
"| Multi-customer impact | Support Lead + VP Eng | 10 min |\n"
"| External comms needed | Communications + CEO | 30 min |\n"
)
PROFILE_FOOTER = {
"ops": "",
"support": _build_support_footer(),
"finance": _build_finance_footer(),
"hr": _build_hr_footer(),
"it": _build_it_footer(),
"regulated": _build_regulated_footer(),
}
def generate_markdown(meta: SOPMetadata, profile: str) -> str:
header = (
f"# SOP: {meta.sop_name}\n\n"
f"_Profile: `{profile}` | "
f"Regulatory overlay: "
f"{meta.regulatory_overlay or 'none'}_\n\n"
"---\n\n"
"## 5W2H scaffolding\n\n"
"_(Ishikawa 1985, 5W2H method. Each section is required.)_\n"
)
body = "\n\n".join([
_build_who(meta, profile),
_build_what(meta),
_build_when(meta),
_build_where(meta, profile),
_build_why(meta),
_build_how(meta),
_build_how_much(meta),
])
footer = PROFILE_FOOTER.get(profile, "")
return header + "\n" + body + footer + "\n"
def generate_json(meta: SOPMetadata, profile: str) -> dict:
return {
"sop_name": meta.sop_name,
"profile": profile,
"metadata": asdict(meta),
"sections": {
"who": "RACI populated",
"what": f"{len(meta.inputs)} inputs / "
f"{len(meta.outputs)} outputs",
"when": meta.triggering_event,
"where": "system of record + canonical doc location",
"why": meta.regulatory_overlay or ["none"],
"how": [{"step": i + 1, "title": s}
for i, s in enumerate(meta.steps_outline)],
"how_much": {
"estimated_minutes": meta.estimated_minutes,
"estimated_cost_usd": meta.estimated_cost_usd,
},
},
}
def main(argv=None) -> int:
p = argparse.ArgumentParser(
description="Generate a 5W2H-structured SOP from JSON metadata."
)
p.add_argument("--input", "-i", type=str,
help="Path to SOP metadata JSON file.")
p.add_argument("--profile", choices=sorted(VALID_PROFILES),
default="ops",
help="Industry profile (default: ops).")
p.add_argument("--output", "-o", choices=["markdown", "json"],
default="markdown",
help="Output format (default: markdown).")
p.add_argument("--sample", action="store_true",
help="Print a sample vendor-offboarding SOP.")
args = p.parse_args(argv)
if args.sample:
data = _sample_metadata()
elif args.input:
path = Path(args.input)
if not path.exists():
print(f"ERROR: input file not found: {args.input}",
file=sys.stderr)
return 2
data = json.loads(path.read_text())
else:
print("ERROR: provide --input <metadata.json> or --sample",
file=sys.stderr)
return 2
meta = SOPMetadata(**data)
errs = meta.validate()
if errs:
print("VALIDATION ERRORS:", file=sys.stderr)
for e in errs:
print(f" - {e}", file=sys.stderr)
return 1
if args.output == "json":
print(json.dumps(generate_json(meta, args.profile), indent=2))
else:
print(generate_markdown(meta, args.profile))
return 0
if __name__ == "__main__":
sys.exit(main())
Ghi quyết định vào bộ nhớ hai lớp qua decision-logger; bản ghi nhớ đã duyệt được lưu bền, bản ghi gốc giữ để tham khảo.
---
name: "decide"
description: "/cs:decide <memo> — Log a decision to two-layer memory via decision-logger. Approved memo becomes durable; raw transcripts kept for reference."
---
# /cs:decide — Log the Decision
**Command:** `/cs:decide <memo-path>`
Logs the founder's decision via the `decision-logger` skill. This is the gate where in-session deliberation becomes durable company memory.
## Pipeline Position
```
/cs:office-hours → /cs:brief → /cs:boardroom → /cs:decide → /cs:execute → /cs:post-mortem
↑ you are here
```
## Two-Layer Memory Model
The `decision-logger` skill maintains two layers:
1. **Raw transcripts** — every boardroom session, every advisor's Phase 2 position, every dissent. Stored under `~/.claude/decisions/raw/`. Reference only, never feeds back automatically.
2. **Approved decisions** — only the founder-signed memos. Stored under `~/.claude/decisions/approved/`. Feeds into future `/cs:office-hours` and `/cs:founder-mode` calls.
This split prevents the system from "remembering" unresolved debates as if they were decisions.
## Input
A board memo file (output of `/cs:boardroom`).
## Workflow
1. Read the memo path
2. Verify it has founder approval (status: APPROVED)
3. Extract structured decision record:
- Decision title
- Date decided
- Option chosen
- Success + kill criteria
- Dissent (preserved)
- Review checkpoint date
4. Append to `~/.claude/decisions/approved/<YYYY-MM-DD>-<slug>.md`
5. Update the raw transcript pointer
6. If llm-wiki bridge configured, write to vault (`~/company-vault/10-decisions/`)
7. Schedule auto-revisit (90 days)
## Output Record Format
```markdown
# Decision: <title>
**Decided:** YYYY-MM-DD
**By:** <founder name>
**Memo:** <link to boardroom memo>
**Brief:** <link to original brief>
**Review checkpoint:** YYYY-MM-DD (90d default)
## Decision
**Chose:** <option>
**Rejected:** <other options + one-line why>
## Success Criteria (binding)
- <metric, threshold, timeframe>
## Kill Criteria (binding)
- <metric, threshold, action>
## Preserved Dissent
- **<dissenter>:** <unresolved concern>
- (preserved verbatim; dissent never erased)
## Next Action
- `/cs:execute` → 90-day plan due <date>
## Status History
- YYYY-MM-DD: APPROVED
```
## Why Preserved Dissent
The biggest risk in approved decisions is forgetting why someone disagreed. When the kill criteria trigger, the dissent often turns out to have been correct. Preserving it verbatim — not summarized — keeps the company honest at post-mortem time.
## Routing
- `/cs:execute <decision>` — build the 90-day plan
- `/cs:freeze <decision> <days>` — lock if irreversible
- (Auto-scheduled) `/cs:post-mortem <decision>` — at 90-day checkpoint
## Stale-Decision Audit
`cs-chief-of-staff` runs a weekly stale audit:
- Decisions > 90 days without revisit → flag for `/cs:post-mortem`
- Decisions with kill criteria triggered → flag immediately
- Decisions whose company-context.md basis has changed → flag for re-examination
## Related
- Skill: [`decision-logger`](../../../skills/decision-logger/SKILL.md)
- Agent: [`cs-chief-of-staff`](../../agents/cs-chief-of-staff.md)
- Bridge: [`../../references/llm-wiki-bridge.md`](../../references/llm-wiki-bridge.md)
---
**Version:** 1.0.0
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()
Biến danh sách công việc rời rạc thành kế hoạch ưu tiên theo ma trận Eisenhower, có timeline và phân bổ năng lượng hợp lý.
--- name: lap-ke-hoach description: Biến danh sách công việc rời rạc thành kế hoạch có ưu tiên theo ma trận Eisenhower, timeline và phân bổ năng lượng hợp lý. Dùng khi nói "lên kế hoạch", "quản lý thời gian", "ưu tiên công việc", "MIT". --- # Lên kế hoạch & Quản lý thời gian ## Mục tiêu Biến danh sách công việc rời rạc thành kế hoạch có ưu tiên, timeline và phân bổ năng lượng hợp lý. ## Khi nào dùng - Đầu tuần cần lên kế hoạch - Có quá nhiều việc, không biết bắt đầu từ đâu - Cần review tiến độ và điều chỉnh ưu tiên ## Đầu vào cần cung cấp - Danh sách việc cần làm - Deadline của từng việc (nếu có) - Mức năng lượng dự kiến trong ngày/tuần - Việc nào có thể bỏ hoặc giao người khác ## Quy trình xử lý 1. Phân loại: Khẩn/Quan trọng theo ma trận Eisenhower 2. Ước lượng thời gian thực tế cho mỗi việc 3. Gộp việc tương tự vào cùng khung giờ (batching) 4. Đặt buffer 20% cho việc phát sinh 5. Xác định 3 việc quan trọng nhất trong ngày (MIT) ## Tiêu chuẩn đầu ra - Danh sách ưu tiên rõ ràng theo ngày/tuần - Mỗi việc có: tên, thời lượng dự kiến, deadline, mức ưu tiên - Có phần "việc nên bỏ hoặc hoãn" - Định dạng: markdown bảng hoặc danh sách có thứ tự ## Tránh - Nhồi quá nhiều việc vào một ngày - Bỏ qua việc phục hồi năng lượng (nghỉ, tập thể dục) - Không tính đến thói quen và múi giờ năng suất của người dùng
Hoạch định chiến lược ra mắt sản phẩm hoặc phát hành tính năng, gồm Product Hunt, beta, early access, waitlist, kế hoạch GTM và checklist ra mắt.
---
name: "launch-strategy"
description: "When the user wants to plan a product launch, feature announcement, or release strategy. Also use when the user mentions 'launch,' 'Product Hunt,' 'feature release,' 'announcement,' 'go-to-market,' 'beta launch,' 'early access,' 'waitlist,' 'product update,' 'GTM plan,' 'launch checklist,' or 'launch momentum.' This skill covers phased launches, channel strategy, and ongoing launch momentum."
license: MIT
metadata:
version: 1.0.0
author: Alireza Rezvani
category: marketing
updated: 2026-03-06
---
# Launch Strategy
You are an expert in SaaS product launches and feature announcements. Your goal is to help users plan launches that build momentum, capture attention, and convert interest into users.
## Before Starting
**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.
---
## Core Philosophy
→ See references/launch-frameworks-and-checklists.md for details
## Task-Specific Questions
1. What are you launching? (New product, major feature, minor update)
2. What's your current audience size and engagement?
3. What owned channels do you have? (Email list size, blog traffic, community)
4. What's your timeline for launch?
5. Have you launched before? What worked/didn't work?
6. Are you considering Product Hunt? What's your preparation status?
---
## Proactive Triggers
Proactively offer launch planning when:
1. **Feature ship date mentioned** — When an engineering delivery date is discussed, immediately ask about the launch plan; shipping without a marketing plan is a missed opportunity.
2. **Waitlist or early access mentioned** — Offer to design the full phased launch funnel from alpha through full GA, not just the landing page.
3. **Product Hunt consideration** — Any mention of Product Hunt should trigger the full PH strategy section including pre-launch relationship building timeline.
4. **Post-launch silence** — If a user launched recently but hasn't followed up with momentum content, proactively suggest the post-launch marketing actions (comparison pages, roundup email, interactive demo).
5. **Pricing change planned** — Pricing updates are a launch opportunity; offer to build an announcement campaign treating it as a product update.
---
## Output Artifacts
| Artifact | Format | Description |
|----------|--------|-------------|
| Launch Plan | Markdown doc | Phase-by-phase plan with owners, dates, channels, and success metrics |
| ORB Channel Map | Table | Owned/Rented/Borrowed channel strategy with tactics per channel |
| Launch Day Checklist | Checklist | Complete day-of execution checklist with time-boxed actions |
| Product Hunt Brief | Markdown doc | Listing copy, asset specs, pre-launch timeline, engagement playbook |
| Post-Launch Momentum Plan | Bulleted list | 30-day post-launch actions to sustain and compound the launch |
---
## Communication
Launch plans should be concrete, time-bound, and channel-specific — no vague "post on social media" recommendations. Every output should specify who does what and when. Reference `marketing-context` to ensure the launch narrative matches ICP language and positioning before drafting any copy. Quality bar: a launch plan is only complete when it covers all three ORB channel types and includes both launch-day and post-launch actions.
---
## Related Skills
- **email-sequence** — USE for building the launch announcement and post-launch onboarding email sequences; NOT as a substitute for the full channel strategy.
- **social-content** — USE for drafting the specific social posts and threads for launch day; NOT for channel selection strategy.
- **paid-ads** — USE when the launch plan includes a paid amplification component; NOT for organic launch-only strategies.
- **content-strategy** — USE when the launch requires a sustained content program (blog posts, case studies) in the weeks after; NOT for single-day launch execution.
- **pricing-strategy** — USE when the launch involves a pricing change or new tier introduction; NOT for feature-only launches.
- **marketing-context** — USE as foundation to align launch messaging with ICP and brand voice; always load first.
FILE:references/launch-frameworks-and-checklists.md
# launch-strategy reference
## Core Philosophy
The best companies don't just launch once—they launch again and again. Every new feature, improvement, and update is an opportunity to capture attention and engage your audience.
A strong launch isn't about a single moment. It's about:
- Getting your product into users' hands early
- Learning from real feedback
- Making a splash at every stage
- Building momentum that compounds over time
---
## The ORB Framework
Structure your launch marketing across three channel types. Everything should ultimately lead back to owned channels.
### Owned Channels
You own the channel (though not the audience). Direct access without algorithms or platform rules.
**Examples:**
- Email list
- Blog
- Podcast
- Branded community (Slack, Discord)
- Website/product
**Why they matter:**
- Get more effective over time
- No algorithm changes or pay-to-play
- Direct relationship with audience
- Compound value from content
**Start with 1-2 based on audience:**
- Industry lacks quality content → Start a blog
- People want direct updates → Focus on email
- Engagement matters → Build a community
**Example - Superhuman:**
Built demand through an invite-only waitlist and one-on-one onboarding sessions. Every new user got a 30-minute live demo. This created exclusivity, FOMO, and word-of-mouth—all through owned relationships. Years later, their original onboarding materials still drive engagement.
### Rented Channels
Platforms that provide visibility but you don't control. Algorithms shift, rules change, pay-to-play increases.
**Examples:**
- Social media (Twitter/X, LinkedIn, Instagram)
- App stores and marketplaces
- YouTube
- Reddit
**How to use correctly:**
- Pick 1-2 platforms where your audience is active
- Use them to drive traffic to owned channels
- Don't rely on them as your only strategy
**Example - Notion:**
Hacked virality through Twitter, YouTube, and Reddit where productivity enthusiasts were active. Encouraged community to share templates and workflows. But they funneled all visibility into owned assets—every viral post led to signups, then targeted email onboarding.
**Platform-specific tactics:**
- Twitter/X: Threads that spark conversation → link to newsletter
- LinkedIn: High-value posts → lead to gated content or email signup
- Marketplaces (Shopify, Slack): Optimize listing → drive to site for more
Rented channels give speed, not stability. Capture momentum by bringing users into your owned ecosystem.
### Borrowed Channels
Tap into someone else's audience to shortcut the hardest part—getting noticed.
**Examples:**
- Guest content (blog posts, podcast interviews, newsletter features)
- Collaborations (webinars, co-marketing, social takeovers)
- Speaking engagements (conferences, panels, virtual summits)
- Influencer partnerships
**Be proactive, not passive:**
1. List industry leaders your audience follows
2. Pitch win-win collaborations
3. Use tools like SparkToro or Listen Notes to find audience overlap
4. Set up affiliate/referral incentives
**Example - TRMNL:**
Sent a free e-ink display to YouTuber Snazzy Labs—not a paid sponsorship, just hoping he'd like it. He created an in-depth review that racked up 500K+ views and drove $500K+ in sales. They also set up an affiliate program for ongoing promotion.
Borrowed channels give instant credibility, but only work if you convert borrowed attention into owned relationships.
---
## Five-Phase Launch Approach
Launching isn't a one-day event. It's a phased process that builds momentum.
### Phase 1: Internal Launch
Gather initial feedback and iron out major issues before going public.
**Actions:**
- Recruit early users one-on-one to test for free
- Collect feedback on usability gaps and missing features
- Ensure prototype is functional enough to demo (doesn't need to be production-ready)
**Goal:** Validate core functionality with friendly users.
### Phase 2: Alpha Launch
Put the product in front of external users in a controlled way.
**Actions:**
- Create landing page with early access signup form
- Announce the product exists
- Invite users individually to start testing
- MVP should be working in production (even if still evolving)
**Goal:** First external validation and initial waitlist building.
### Phase 3: Beta Launch
Scale up early access while generating external buzz.
**Actions:**
- Work through early access list (some free, some paid)
- Start marketing with teasers about problems you solve
- Recruit friends, investors, and influencers to test and share
**Consider adding:**
- Coming soon landing page or waitlist
- "Beta" sticker in dashboard navigation
- Email invites to early access list
- Early access toggle in settings for experimental features
**Goal:** Build buzz and refine product with broader feedback.
### Phase 4: Early Access Launch
Shift from small-scale testing to controlled expansion.
**Actions:**
- Leak product details: screenshots, feature GIFs, demos
- Gather quantitative usage data and qualitative feedback
- Run user research with engaged users (incentivize with credits)
- Optionally run product/market fit survey to refine messaging
**Expansion options:**
- Option A: Throttle invites in batches (5-10% at a time)
- Option B: Invite all users at once under "early access" framing
**Goal:** Validate at scale and prepare for full launch.
### Phase 5: Full Launch
Open the floodgates.
**Actions:**
- Open self-serve signups
- Start charging (if not already)
- Announce general availability across all channels
**Launch touchpoints:**
- Customer emails
- In-app popups and product tours
- Website banner linking to launch assets
- "New" sticker in dashboard navigation
- Blog post announcement
- Social posts across platforms
- Product Hunt, BetaList, Hacker News, etc.
**Goal:** Maximum visibility and conversion to paying users.
---
## Product Hunt Launch Strategy
Product Hunt can be powerful for reaching early adopters, but it's not magic—it requires preparation.
### Pros
- Exposure to tech-savvy early adopter audience
- Credibility bump (especially if Product of the Day)
- Potential PR coverage and backlinks
### Cons
- Very competitive to rank well
- Short-lived traffic spikes
- Requires significant pre-launch planning
### How to Launch Successfully
**Before launch day:**
1. Build relationships with influential supporters, content hubs, and communities
2. Optimize your listing: compelling tagline, polished visuals, short demo video
3. Study successful launches to identify what worked
4. Engage in relevant communities—provide value before pitching
5. Prepare your team for all-day engagement
**On launch day:**
1. Treat it as an all-day event
2. Respond to every comment in real-time
3. Answer questions and spark discussions
4. Encourage your existing audience to engage
5. Direct traffic back to your site to capture signups
**After launch day:**
1. Follow up with everyone who engaged
2. Convert Product Hunt traffic into owned relationships (email signups)
3. Continue momentum with post-launch content
### Case Studies
**SavvyCal** (Scheduling tool):
- Optimized landing page and onboarding before launch
- Built relationships with productivity/SaaS influencers in advance
- Responded to every comment on launch day
- Result: #2 Product of the Month
**Reform** (Form builder):
- Studied successful launches and applied insights
- Crafted clear tagline, polished visuals, demo video
- Engaged in communities before launch (provided value first)
- Treated launch as all-day engagement event
- Directed traffic to capture signups
- Result: #1 Product of the Day
---
## Post-Launch Product Marketing
Your launch isn't over when the announcement goes live. Now comes adoption and retention work.
### Immediate Post-Launch Actions
**Educate new users:**
Set up automated onboarding email sequence introducing key features and use cases.
**Reinforce the launch:**
Include announcement in your weekly/biweekly/monthly roundup email to catch people who missed it.
**Differentiate against competitors:**
Publish comparison pages highlighting why you're the obvious choice.
**Update web pages:**
Add dedicated sections about the new feature/product across your site.
**Offer hands-on preview:**
Create no-code interactive demo (using tools like Navattic) so visitors can explore before signing up.
### Keep Momentum Going
It's easier to build on existing momentum than start from scratch. Every touchpoint reinforces the launch.
---
## Ongoing Launch Strategy
Don't rely on a single launch event. Regular updates and feature rollouts sustain engagement.
### How to Prioritize What to Announce
Use this matrix to decide how much marketing each update deserves:
**Major updates** (new features, product overhauls):
- Full campaign across multiple channels
- Blog post, email campaign, in-app messages, social media
- Maximize exposure
**Medium updates** (new integrations, UI enhancements):
- Targeted announcement
- Email to relevant segments, in-app banner
- Don't need full fanfare
**Minor updates** (bug fixes, small tweaks):
- Changelog and release notes
- Signal that product is improving
- Don't dominate marketing
### Announcement Tactics
**Space out releases:**
Instead of shipping everything at once, stagger announcements to maintain momentum.
**Reuse high-performing tactics:**
If a previous announcement resonated, apply those insights to future updates.
**Keep engaging:**
Continue using email, social, and in-app messaging to highlight improvements.
**Signal active development:**
Even small changelog updates remind customers your product is evolving. This builds retention and word-of-mouth—customers feel confident you'll be around.
---
## Launch Checklist
### Pre-Launch
- [ ] Landing page with clear value proposition
- [ ] Email capture / waitlist signup
- [ ] Early access list built
- [ ] Owned channels established (email, blog, community)
- [ ] Rented channel presence (social profiles optimized)
- [ ] Borrowed channel opportunities identified (podcasts, influencers)
- [ ] Product Hunt listing prepared (if using)
- [ ] Launch assets created (screenshots, demo video, GIFs)
- [ ] Onboarding flow ready
- [ ] Analytics/tracking in place
### Launch Day
- [ ] Announcement email to list
- [ ] Blog post published
- [ ] Social posts scheduled and posted
- [ ] Product Hunt listing live (if using)
- [ ] In-app announcement for existing users
- [ ] Website banner/notification active
- [ ] Team ready to engage and respond
- [ ] Monitor for issues and feedback
### Post-Launch
- [ ] Onboarding email sequence active
- [ ] Follow-up with engaged prospects
- [ ] Roundup email includes announcement
- [ ] Comparison pages published
- [ ] Interactive demo created
- [ ] Gather and act on feedback
- [ ] Plan next launch moment
---
FILE:scripts/launch_readiness_scorer.py
#!/usr/bin/env python3
"""
launch_readiness_scorer.py — Product Launch Readiness Scorer
100% stdlib, no pip installs required.
Usage:
python3 launch_readiness_scorer.py # demo mode
python3 launch_readiness_scorer.py --checklist checklist.json
python3 launch_readiness_scorer.py --checklist checklist.json --json
python3 launch_readiness_scorer.py --export-template > my_checklist.json
checklist.json format:
{
"product": [
{"item": "Beta tested with 10+ users", "status": "done"},
{"item": "Documentation ready", "status": "partial"},
{"item": "Support team trained", "status": "not_started"}
],
"marketing": [...],
"technical": [...]
}
Valid status values: "done" | "partial" | "not_started"
"""
import argparse
import json
import sys
from datetime import datetime, timezone
# ---------------------------------------------------------------------------
# Default checklist template
# ---------------------------------------------------------------------------
DEFAULT_CHECKLIST = {
"product": [
{"item": "Beta tested with real users (≥10)", "status": "done", "weight": 3},
{"item": "Core user journey validated end-to-end", "status": "done", "weight": 3},
{"item": "Known P0/P1 bugs resolved", "status": "partial", "weight": 3},
{"item": "User-facing documentation complete", "status": "partial", "weight": 2},
{"item": "In-app onboarding / empty states ready", "status": "done", "weight": 2},
{"item": "Support team trained on common Q&A", "status": "not_started", "weight": 2},
{"item": "Pricing finalised and live", "status": "done", "weight": 2},
{"item": "Accessibility basics checked (WCAG AA)", "status": "not_started", "weight": 1},
{"item": "Localisation / i18n ready (if applicable)", "status": "done", "weight": 1},
{"item": "Feedback collection mechanism in place", "status": "partial", "weight": 1},
],
"marketing": [
{"item": "Landing page live and conversion-optimised", "status": "done", "weight": 3},
{"item": "Email announcement list ready (≥100)", "status": "done", "weight": 3},
{"item": "Press / media kit prepared", "status": "partial", "weight": 2},
{"item": "Social media assets created", "status": "done", "weight": 2},
{"item": "Product Hunt / launch platform submission", "status": "not_started", "weight": 2},
{"item": "SEO meta tags and OG images set", "status": "done", "weight": 2},
{"item": "Influencer / community outreach planned", "status": "partial", "weight": 2},
{"item": "Launch-day email sequence scheduled", "status": "not_started", "weight": 2},
{"item": "Paid ads creative prepared (if applicable)", "status": "not_started", "weight": 1},
{"item": "Referral / viral loop mechanism designed", "status": "not_started", "weight": 1},
],
"technical": [
{"item": "Production monitoring & alerting active", "status": "done", "weight": 3},
{"item": "Load / performance tested at 5× expected", "status": "partial", "weight": 3},
{"item": "Rollback plan documented and rehearsed", "status": "not_started", "weight": 3},
{"item": "Database backups verified and automated", "status": "done", "weight": 2},
{"item": "CDN / caching configured", "status": "done", "weight": 2},
{"item": "Error tracking (Sentry/similar) live", "status": "done", "weight": 2},
{"item": "SSL / HTTPS confirmed on all endpoints", "status": "done", "weight": 2},
{"item": "Analytics events firing correctly", "status": "partial", "weight": 2},
{"item": "Rate limiting / DDoS protection in place", "status": "partial", "weight": 2},
{"item": "Feature flags configured for safe rollout", "status": "not_started", "weight": 1},
],
}
CATEGORY_META = {
"product": {"emoji": "🛠 ", "label": "Product Readiness"},
"marketing": {"emoji": "📣 ", "label": "Marketing Readiness"},
"technical": {"emoji": "⚙️ ", "label": "Technical Readiness"},
}
STATUS_WEIGHTS = {
"done": 1.0,
"partial": 0.5,
"not_started": 0.0,
}
BLOCKERS_THRESHOLD = 0.0 # not_started items with weight ≥3 are blockers
# ---------------------------------------------------------------------------
# Core scoring
# ---------------------------------------------------------------------------
def score_category(items: list) -> dict:
"""Score a single category 0-100 using weighted item scores."""
if not items:
return {"score": 0, "items": [], "blockers": []}
total_weight = 0
earned_weight = 0
blockers = []
scored_items = []
for it in items:
raw_status = it.get("status", "not_started").strip().lower()
status = raw_status if raw_status in STATUS_WEIGHTS else "not_started"
weight = it.get("weight", 1)
sw = STATUS_WEIGHTS[status]
earned = sw * weight
total_weight += weight
earned_weight += earned
scored_items.append({
"item": it["item"],
"status": status,
"weight": weight,
"points_earned": earned,
"points_max": weight,
})
if status == "not_started" and weight >= 3:
blockers.append(it["item"])
score = round((earned_weight / total_weight) * 100) if total_weight > 0 else 0
return {
"score": score,
"score_label": _score_label(score),
"items": scored_items,
"blockers": blockers,
"items_done": sum(1 for i in scored_items if i["status"] == "done"),
"items_partial": sum(1 for i in scored_items if i["status"] == "partial"),
"items_pending": sum(1 for i in scored_items if i["status"] == "not_started"),
"total_items": len(scored_items),
}
def score_readiness(checklist: dict) -> dict:
"""Score all categories and produce an overall launch readiness result."""
categories = {}
all_scores = []
all_blockers = []
for cat, items in checklist.items():
result = score_category(items)
categories[cat] = result
all_scores.append(result["score"])
all_blockers.extend(result["blockers"])
overall = round(sum(all_scores) / len(all_scores)) if all_scores else 0
return {
"overall": {
"score": overall,
"score_label": _score_label(overall),
"launch_decision": _launch_decision(overall, all_blockers),
"blockers": all_blockers,
"generated_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
},
"categories": {
cat: {**CATEGORY_META.get(cat, {"emoji": "📋", "label": cat.title()}),
**res}
for cat, res in categories.items()
},
"action_plan": _action_plan(categories),
}
def _launch_decision(score: int, blockers: list) -> str:
if blockers:
return f"⛔ NOT READY — {len(blockers)} blocker(s) must be resolved before launch."
if score >= 80:
return "✅ LAUNCH READY — all categories are in good shape."
if score >= 60:
return "🟡 CONDITIONAL — address partial items but launch is defensible."
if score >= 40:
return "🟠 CAUTION — significant gaps; soft launch / waitlist recommended."
return "🔴 NOT READY — major preparation required across multiple areas."
def _action_plan(categories: dict) -> list:
"""Build a prioritised action list: blockers first, then by score ascending."""
actions = []
for cat, res in categories.items():
label = CATEGORY_META.get(cat, {}).get("label", cat.title())
for bl in res.get("blockers", []):
actions.append({
"priority": "🚨 BLOCKER",
"category": label,
"action": bl,
})
for cat, res in sorted(categories.items(), key=lambda x: x[1]["score"]):
label = CATEGORY_META.get(cat, {}).get("label", cat.title())
for it in res.get("items", []):
if it["status"] == "partial":
actions.append({
"priority": "⚠️ PARTIAL",
"category": label,
"action": f"Complete: {it['item']}",
})
return actions[:15] # top 15 actions
def _score_label(s: int) -> str:
if s >= 90: return "Excellent"
if s >= 75: return "Good"
if s >= 60: return "Fair"
if s >= 40: return "Poor"
return "Critical"
# ---------------------------------------------------------------------------
# Pretty-print
# ---------------------------------------------------------------------------
def pretty_print(result: dict) -> None:
ov = result["overall"]
print("\n" + "=" * 65)
print(" 🚀 LAUNCH READINESS SCORER")
print("=" * 65)
print(f"\n Overall Score : {ov['score']}/100 ({ov['score_label']})")
print(f" Launch Decision : {ov['launch_decision']}")
if ov["blockers"]:
print(f"\n 🚨 BLOCKERS ({len(ov['blockers'])}):")
for b in ov["blockers"]:
print(f" • {b}")
print(f"\n{'─'*65}")
print(f" {'CATEGORY':<30} {'SCORE':>6} {'DONE':>5} {'PARTIAL':>7} {'PENDING':>7}")
print(f"{'─'*65}")
for cat, res in result["categories"].items():
bar = "█" * (res["score"] // 10) + "░" * (10 - res["score"] // 10)
print(f" {res['emoji']} {res['label']:<27} {res['score']:>5}/100 "
f"{res['items_done']:>5} {res['items_partial']:>7} {res['items_pending']:>7} {bar}")
print(f"\n{'─'*65}")
print(f" 🗂 CATEGORY DETAILS\n")
for cat, res in result["categories"].items():
print(f" {res['emoji']} {res['label']} — {res['score']}/100 ({res['score_label']})")
for it in res["items"]:
icon = {"done": "✅", "partial": "🔶", "not_started": "⬜"}.get(it["status"], "⬜")
print(f" {icon} [{it['status']:<11}] (w={it['weight']}) {it['item']}")
print()
ap = result["action_plan"]
if ap:
print(f" 📋 ACTION PLAN (top {len(ap)} items)\n")
for i, a in enumerate(ap, 1):
print(f" {i:>2}. {a['priority']} [{a['category']}] {a['action']}")
print(f"\n Generated: {ov['generated_at']}")
print()
# ---------------------------------------------------------------------------
# CLI
# ---------------------------------------------------------------------------
def parse_args():
parser = argparse.ArgumentParser(
description="Score product launch readiness across categories (stdlib only).",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=__doc__,
)
parser.add_argument("--checklist", type=str, default=None,
help="Path to JSON checklist file")
parser.add_argument("--json", action="store_true",
help="Output results as JSON")
parser.add_argument("--export-template", action="store_true",
help="Print the default checklist template as JSON and exit")
return parser.parse_args()
def main():
args = parse_args()
if args.export_template:
print(json.dumps(DEFAULT_CHECKLIST, indent=2))
return
if args.checklist:
with open(args.checklist) as f:
checklist = json.load(f)
else:
print("🔬 DEMO MODE — using embedded sample checklist\n")
checklist = DEFAULT_CHECKLIST
result = score_readiness(checklist)
if args.json:
print(json.dumps(result, indent=2))
else:
pretty_print(result)
if __name__ == "__main__":
main()
Tạo và duy trì tài liệu ngữ cảnh marketing (giọng thương hiệu, đối tượng, ICP, định vị) để các skill marketing khác đọc trước khi làm việc.
---
name: "marketing-context"
description: "Create and maintain the marketing context document that all marketing skills read before starting. Use when the user mentions 'marketing context,' 'brand voice,' 'set up context,' 'target audience,' 'ICP,' 'style guide,' 'who is my customer,' 'positioning,' or wants to avoid repeating foundational information across marketing tasks. Run this at the start of any new project before using other marketing skills."
license: MIT
metadata:
version: 1.0.0
author: Alireza Rezvani
category: marketing
updated: 2026-03-06
---
# Marketing Context
You are an expert product marketer. Your goal is to capture the foundational positioning, messaging, and brand context that every other marketing skill needs — so users never repeat themselves.
The document is stored at `.agents/marketing-context.md` (or `marketing-context.md` in the project root).
## How This Skill Works
### Mode 1: Auto-Draft from Codebase
Study the repo — README, landing pages, marketing copy, about pages, package.json, existing docs — and draft a V1. The user reviews, corrects, and fills gaps. This is faster than starting from scratch.
### Mode 2: Guided Interview
Walk through each section conversationally, one at a time. Don't dump all questions at once.
### Mode 3: Update Existing
Read the current context, summarize what's captured, and ask which sections need updating.
Most users prefer Mode 1. After presenting the draft, ask: *"What needs correcting? What's missing?"*
---
## Sections to Capture
### 1. Product Overview
- One-line description
- What it does (2-3 sentences)
- Product category (the "shelf" — how customers search for you)
- Product type (SaaS, marketplace, e-commerce, service)
- Business model and pricing
### 2. Target Audience
- Target company type (industry, size, stage)
- Target decision-makers (roles, departments)
- Primary use case (the main problem you solve)
- Jobs to be done (2-3 things customers "hire" you for)
- Specific use cases or scenarios
### 3. Personas
For each stakeholder involved in buying:
- Role (User, Champion, Decision Maker, Financial Buyer, Technical Influencer)
- What they care about, their challenge, the value you promise them
### 4. Problems & Pain Points
- Core challenge customers face before finding you
- Why current solutions fall short
- What it costs them (time, money, opportunities)
- Emotional tension (stress, fear, doubt)
### 5. Competitive Landscape
- **Direct competitors**: Same solution, same problem
- **Secondary competitors**: Different solution, same problem
- **Indirect competitors**: Conflicting approach entirely
- How each falls short for customers
### 6. Differentiation
- Key differentiators (capabilities alternatives lack)
- How you solve it differently
- Why that's better (benefits, not features)
- Why customers choose you over alternatives
### 7. Objections & Anti-Personas
- Top 3 objections heard in sales + how to address each
- Who is NOT a good fit (anti-persona)
### 8. Switching Dynamics (JTBD Four Forces)
- **Push**: Frustrations driving them away from current solution
- **Pull**: What attracts them to you
- **Habit**: What keeps them stuck with current approach
- **Anxiety**: What worries them about switching
### 9. Customer Language (Verbatim)
- How customers describe the problem in their own words
- How they describe your solution in their own words
- Words and phrases TO use
- Words and phrases to AVOID
- Glossary of product-specific terms
### 10. Brand Voice
- Tone (professional, casual, playful, authoritative)
- Communication style (direct, conversational, technical)
- Brand personality (3-5 adjectives)
- Voice DO's and DON'T's
### 11. Style Guide
- Grammar and mechanics rules
- Capitalization conventions
- Formatting standards
- Preferred terminology
### 12. Proof Points
- Key metrics or results to cite
- Notable customers / logos
- Testimonial snippets (verbatim)
- Main value themes with supporting evidence
### 13. Content & SEO Context
- Target keywords (organized by topic cluster)
- Internal links map (key pages, anchor text)
- Writing examples (3-5 exemplary pieces)
- Content tone and length preferences
### 14. Goals
- Primary business goal
- Key conversion action (what you want people to do)
- Current metrics (if known)
---
## Output Template
See `templates/marketing-context-template.md` for the full template.
---
## Tips
- **Be specific**: Ask "What's the #1 frustration that brings them to you?" not "What problem do they solve?"
- **Capture exact words**: Customer language beats polished descriptions
- **Ask for examples**: "Can you give me an example?" unlocks better answers
- **Validate as you go**: Summarize each section and confirm before moving on
- **Skip what doesn't apply**: Not every product needs all sections
---
## Proactive Triggers
Surface these without being asked:
- **Missing customer language section** → "Without verbatim customer phrases, copy will sound generic. Can you share 3-5 quotes from customers describing their problem?"
- **No competitive landscape defined** → "Every marketing skill performs better with competitor context. Who are the top 3 alternatives your customers consider?"
- **Brand voice undefined** → "Without voice guidelines, every skill will sound different. Let's define 3-5 adjectives that capture your brand."
- **Context older than 6 months** → "Your marketing context was last updated [date]. Positioning may have shifted — review recommended."
- **No proof points** → "Marketing without proof points is opinion. What metrics, logos, or testimonials can we reference?"
## Output Artifacts
| When you ask for... | You get... |
|---------------------|------------|
| "Set up marketing context" | Guided interview → complete `marketing-context.md` |
| "Auto-draft from codebase" | Codebase scan → V1 draft for review |
| "Update positioning" | Targeted update of differentiation + competitive sections |
| "Add customer quotes" | Customer language section populated with verbatim phrases |
| "Review context freshness" | Staleness audit with recommended updates |
## 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-ops**: Routes marketing questions to the right skill — reads this context first.
- **copywriting**: For landing page and web copy. Reads brand voice + customer language from this context.
- **content-strategy**: For planning what content to create. Reads target keywords + personas from this context.
- **marketing-strategy-pmm**: For positioning and GTM strategy. Reads competitive landscape from this context.
- **cs-onboard** (C-Suite): For company-level context. This skill is marketing-specific — complements, not replaces, company-context.md.
FILE:scripts/context_validator.py
#!/usr/bin/env python3
"""Validate marketing context completeness — scores 0-100."""
import json
import re
import sys
from pathlib import Path
SECTIONS = {
"Product Overview": {"required": True, "weight": 10, "markers": ["one-liner", "what it does", "product category", "business model"]},
"Target Audience": {"required": True, "weight": 12, "markers": ["target compan", "decision-maker", "use case", "jobs to be done"]},
"Personas": {"required": False, "weight": 5, "markers": ["persona", "champion", "decision maker"]},
"Problems & Pain Points": {"required": True, "weight": 10, "markers": ["core problem", "fall short", "cost", "tension"]},
"Competitive Landscape": {"required": True, "weight": 10, "markers": ["direct", "competitor", "secondary"]},
"Differentiation": {"required": True, "weight": 10, "markers": ["differentiator", "differently", "why customers choose"]},
"Objections": {"required": False, "weight": 5, "markers": ["objection", "response", "anti-persona"]},
"Switching Dynamics": {"required": False, "weight": 5, "markers": ["push", "pull", "habit", "anxiety"]},
"Customer Language": {"required": True, "weight": 10, "markers": ["verbatim", "words to use", "words to avoid"]},
"Brand Voice": {"required": True, "weight": 8, "markers": ["tone", "style", "personality"]},
"Style Guide": {"required": False, "weight": 3, "markers": ["grammar", "capitalization", "formatting"]},
"Proof Points": {"required": True, "weight": 7, "markers": ["metric", "customer", "testimonial"]},
"Content & SEO": {"required": False, "weight": 3, "markers": ["keyword", "internal link"]},
"Goals": {"required": True, "weight": 2, "markers": ["business goal", "conversion"]}
}
def validate_context(content: str) -> dict:
"""Validate marketing context file and return score."""
content_lower = content.lower()
results = {"sections": {}, "score": 0, "max_score": 100, "missing_required": [], "missing_optional": [], "warnings": []}
total_weight = sum(s["weight"] for s in SECTIONS.values())
earned = 0
for name, config in SECTIONS.items():
section_present = name.lower().replace("& ", "").replace(" ", " ") in content_lower or any(
m in content_lower for m in config["markers"][:2]
)
markers_found = sum(1 for m in config["markers"] if m in content_lower)
markers_total = len(config["markers"])
has_placeholder = bool(re.search(r'\[.*?\]', content[content_lower.find(name.lower()):content_lower.find(name.lower()) + 500] if name.lower() in content_lower else ""))
if section_present and markers_found > 0:
completeness = markers_found / markers_total
if has_placeholder and completeness < 0.5:
completeness *= 0.5 # Penalize unfilled templates
section_score = round(config["weight"] * completeness)
earned += section_score
status = "complete" if completeness >= 0.75 else "partial"
else:
section_score = 0
status = "missing"
if config["required"]:
results["missing_required"].append(name)
else:
results["missing_optional"].append(name)
results["sections"][name] = {
"status": status,
"markers_found": markers_found,
"markers_total": markers_total,
"score": section_score,
"max_score": config["weight"],
"required": config["required"]
}
results["score"] = round((earned / total_weight) * 100)
# Warnings
if "verbatim" not in content_lower and '"' not in content:
results["warnings"].append("No verbatim customer quotes found — copy will sound generic")
if not re.search(r'\d+%|\$\d+|\d+ customer', content_lower):
results["warnings"].append("No metrics or proof points with numbers found")
if "last updated" in content_lower:
date_match = re.search(r'last updated:?\s*(\d{4}-\d{2}-\d{2})', content_lower)
if date_match:
from datetime import datetime
try:
updated = datetime.strptime(date_match.group(1), "%Y-%m-%d")
age_days = (datetime.now() - updated).days
if age_days > 180:
results["warnings"].append(f"Context is {age_days} days old — review recommended (>180 days)")
except ValueError:
pass
return results
def print_report(results: dict):
"""Print human-readable validation report."""
print(f"\n{'='*50}")
print(f"MARKETING CONTEXT VALIDATION")
print(f"{'='*50}")
print(f"\nOverall Score: {results['score']}/100")
print(f"{'🟢 Strong' if results['score'] >= 80 else '🟡 Needs Work' if results['score'] >= 50 else '🔴 Incomplete'}")
print(f"\n{'─'*50}")
print(f"{'Section':<25} {'Status':<10} {'Score':<10}")
print(f"{'─'*50}")
for name, data in results["sections"].items():
icon = {"complete": "✅", "partial": "⚠️", "missing": "❌"}[data["status"]]
req = " *" if data["required"] else ""
print(f"{icon} {name:<23} {data['status']:<10} {data['score']}/{data['max_score']}{req}")
if results["missing_required"]:
print(f"\n🔴 Missing Required Sections:")
for s in results["missing_required"]:
print(f" → {s}")
if results["missing_optional"]:
print(f"\n🟡 Missing Optional Sections:")
for s in results["missing_optional"]:
print(f" → {s}")
if results["warnings"]:
print(f"\n⚠️ Warnings:")
for w in results["warnings"]:
print(f" → {w}")
print(f"\n* = required section")
print(f"{'='*50}")
def main():
import argparse
parser = argparse.ArgumentParser(
description="Validates marketing context completeness. "
"Scores 0-100 based on required and optional section coverage."
)
parser.add_argument(
"file", nargs="?", default=None,
help="Path to a marketing context markdown file. "
"If omitted, runs demo with embedded sample data."
)
parser.add_argument(
"--json", action="store_true",
help="Also output results as JSON."
)
args = parser.parse_args()
if args.file:
filepath = Path(args.file)
if not filepath.exists():
print(f"Error: File not found: {filepath}", file=sys.stderr)
sys.exit(1)
content = filepath.read_text()
else:
# Demo with sample data
content = """# Marketing Context
*Last updated: 2026-01-15*
## Product Overview
**One-liner:** AI-powered mobility analysis for elderly care
**What it does:** Smartphone-based fall risk assessment using computer vision
**Product category:** HealthTech / Digital Health
**Business model:** SaaS, per-facility licensing
## Target Audience
**Target companies:** Care facilities, nursing homes, 50+ beds
**Decision-makers:** Facility directors, quality managers
**Primary use case:** Automated fall risk assessment replacing manual observation
**Jobs to be done:**
- Reduce fall incidents by identifying high-risk residents
- Meet regulatory documentation requirements efficiently
- Give care staff actionable mobility insights
## Problems & Pain Points
**Core problem:** Manual fall risk assessment is subjective, time-consuming, and inconsistent
**Why alternatives fall short:**
- Manual observation takes 30+ minutes per resident
- Paper-based assessments are completed once per quarter at best
**What it costs them:** Falls cost €8,000-12,000 per incident, plus liability
**Emotional tension:** Staff fear missing warning signs, blame after incidents
## Competitive Landscape
**Direct:** Traditional gait labs — $50K+ hardware, need trained staff
**Secondary:** Wearable sensors — low compliance, residents remove them
**Indirect:** Manual observation — subjective, inconsistent
## Differentiation
**Key differentiators:**
- Uses standard smartphone (no special hardware)
- AI-powered analysis (objective, repeatable)
**Why customers choose us:** Fast, affordable, no hardware investment
## Customer Language
**How they describe the problem:**
- "We never know who's going to fall next"
- "The documentation takes forever"
**Words to use:** mobility analysis, fall prevention, care quality
**Words to avoid:** surveillance, monitoring, tracking
## Brand Voice
**Tone:** Professional, empathetic, evidence-based
**Personality:** Trustworthy, innovative, caring
## Proof Points
**Metrics:**
- 80+ care facilities served
- 30% reduction in fall incidents (pilot data)
**Customers:** Major care facility chains in Germany
## Goals
**Business goal:** Expand to 200+ facilities, enter Spain and Netherlands
**Conversion action:** Book a demo
"""
print("[Using embedded sample data — pass a file path for real validation]")
results = validate_context(content)
print_report(results)
if args.json:
print(f"\n{json.dumps(results, indent=2)}")
if __name__ == "__main__":
main()
FILE:templates/marketing-context-template.md
# Marketing Context
*Last updated: [date]*
## Product Overview
**One-liner:** [What you do in one sentence]
**What it does:** [2-3 sentences]
**Product category:** [The "shelf" — how customers search for you]
**Product type:** [SaaS, marketplace, e-commerce, service]
**Business model:** [Pricing model and range]
## Target Audience
**Target companies:** [Industry, size, stage]
**Decision-makers:** [Roles, departments]
**Primary use case:** [The main problem you solve]
**Jobs to be done:**
- [Job 1]
- [Job 2]
- [Job 3]
**Use cases:**
- [Scenario 1]
- [Scenario 2]
## Personas
| Persona | Role | Cares about | Challenge | Value we promise |
|---------|------|-------------|-----------|------------------|
| [Name] | User | | | |
| [Name] | Champion | | | |
| [Name] | Decision Maker | | | |
| [Name] | Financial Buyer | | | |
## Problems & Pain Points
**Core problem:** [What customers face before finding you]
**Why alternatives fall short:**
- [Gap 1]
- [Gap 2]
**What it costs them:** [Time, money, opportunities]
**Emotional tension:** [Stress, fear, doubt]
## Competitive Landscape
| Competitor | Type | How they fall short |
|-----------|------|---------------------|
| [Name] | Direct | [Gap] |
| [Name] | Secondary | [Gap] |
| [Name] | Indirect | [Gap] |
## Differentiation
**Key differentiators:**
- [Differentiator 1]
- [Differentiator 2]
**How we do it differently:** [Approach]
**Why that's better:** [Benefits]
**Why customers choose us:** [Decision drivers]
## Objections
| Objection | Response |
|-----------|----------|
| "[Objection 1]" | [How to address] |
| "[Objection 2]" | [How to address] |
| "[Objection 3]" | [How to address] |
**Anti-persona (NOT a good fit):** [Who should NOT buy this]
## Switching Dynamics
**Push (away from current):** [Frustrations]
**Pull (toward us):** [Attractions]
**Habit (keeping them stuck):** [Inertia]
**Anxiety (about switching):** [Worries]
## Customer Language
**How they describe the problem:**
- "[verbatim quote]"
- "[verbatim quote]"
**How they describe us:**
- "[verbatim quote]"
- "[verbatim quote]"
**Words to use:** [list]
**Words to avoid:** [list]
| Term | Meaning |
|------|---------|
| [Product term] | [Definition] |
## Brand Voice
**Tone:** [professional, casual, playful, authoritative]
**Style:** [direct, conversational, technical]
**Personality:** [3-5 adjectives]
**Voice DO's:** [list]
**Voice DON'T's:** [list]
## Style Guide
**Grammar:** [Key rules]
**Capitalization:** [Conventions]
**Formatting:** [Standards]
**Preferred terms:** [List]
## Proof Points
**Metrics:**
- [Metric 1]
- [Metric 2]
**Customers:** [Notable logos]
**Testimonials:**
> "[quote]" — [Name, Title, Company]
> "[quote]" — [Name, Title, Company]
| Value Theme | Supporting Proof |
|-------------|-----------------|
| [Theme 1] | [Evidence] |
| [Theme 2] | [Evidence] |
## Content & SEO Context
**Target keywords:**
| Cluster | Primary Keyword | Secondary Keywords | Intent |
|---------|----------------|-------------------|--------|
| [Topic 1] | [keyword] | [kw1, kw2] | [informational/commercial] |
**Internal links map:**
| Page | URL | Use for | Anchor text |
|------|-----|---------|-------------|
| [Page name] | [URL] | [Topic] | [Suggested anchor] |
**Writing examples:**
- [URL or file — what makes it good]
## Goals
**Business goal:** [Primary objective]
**Conversion action:** [What you want people to do]
**Current metrics:** [If known]
Bộ 23 skill kỹ thuật: kiến trúc, frontend, backend, QA, DevOps, bảo mật, AI/ML, dữ liệu, Playwright, Stripe, AWS, MS365 cùng 30+ công cụ Python.
--- name: "engineering-skills" description: "23 engineering agent skills and plugins for Claude Code, Codex, Gemini CLI, Cursor, OpenClaw, and 6 more tools. Architecture, frontend, backend, QA, DevOps, security, AI/ML, data engineering, Playwright, Stripe, AWS, MS365. 30+ Python tools (stdlib-only)." version: 2.9.0 author: Alireza Rezvani license: MIT tags: - engineering - frontend - backend - devops - security - ai-ml - data-engineering agents: - claude-code - codex-cli - openclaw --- # Engineering Team Skills 23 production-ready engineering skills organized into core engineering, AI/ML/Data, and specialized tools. ## Quick Start ### Claude Code ``` /read engineering-team/senior-fullstack/SKILL.md ``` ### Codex CLI ```bash npx agent-skills-cli add alirezarezvani/claude-skills/engineering-team ``` ## Skills Overview ### Core Engineering (13 skills) | Skill | Folder | Focus | |-------|--------|-------| | Senior Architect | `senior-architect/` | System design, architecture patterns | | Senior Frontend | `senior-frontend/` | React, Next.js, TypeScript, Tailwind | | Senior Backend | `senior-backend/` | API design, database optimization | | Senior Fullstack | `senior-fullstack/` | Project scaffolding, code quality | | Senior QA | `senior-qa/` | Test generation, coverage analysis | | Senior DevOps | `senior-devops/` | CI/CD, infrastructure, containers | | Senior SecOps | `senior-secops/` | Security operations, vulnerability management | | Code Reviewer | `code-reviewer/` | PR review, code quality analysis | | Senior Security | `senior-security/` | Threat modeling, STRIDE, penetration testing | | AWS Solution Architect | `aws-solution-architect/` | Serverless, CloudFormation, cost optimization | | MS365 Tenant Manager | `ms365-tenant-manager/` | Microsoft 365 administration | | TDD Guide | `tdd-guide/` | Test-driven development workflows | | Tech Stack Evaluator | `tech-stack-evaluator/` | Technology comparison, TCO analysis | ### AI/ML/Data (5 skills) | Skill | Folder | Focus | |-------|--------|-------| | Senior Data Scientist | `senior-data-scientist/` | Statistical modeling, experimentation | | Senior Data Engineer | `senior-data-engineer/` | Pipelines, ETL, data quality | | Senior ML Engineer | `senior-ml-engineer/` | Model deployment, MLOps, LLM integration | | Senior Prompt Engineer | `senior-prompt-engineer/` | Prompt optimization, RAG, agents | | Senior Computer Vision | `senior-computer-vision/` | Object detection, segmentation | ### Specialized Tools (5 skills) | Skill | Folder | Focus | |-------|--------|-------| | Playwright Pro | `playwright-pro/` | E2E testing (9 sub-skills) | | Self-Improving Agent | `self-improving-agent/` | Memory curation (5 sub-skills) | | Stripe Integration | `stripe-integration-expert/` | Payment integration, webhooks | | Incident Commander | `incident-commander/` | Incident response workflows | | Email Template Builder | `email-template-builder/` | HTML email generation | ## Python Tools 30+ scripts, all stdlib-only. Run directly: ```bash python3 <skill>/scripts/<tool>.py --help ``` No pip install needed. Scripts include embedded samples for demo mode. ## Rules - Load only the specific skill SKILL.md you need — don't bulk-load all 23 - Use Python tools for analysis and scaffolding, not manual judgment - Check CLAUDE.md for tool usage examples and workflows
Giữ vệ sinh biến môi trường và an toàn bí mật: kiểm tra .env lộ bí mật, lập kế hoạch xoay vòng credential, xử lý sự cố thiếu biến.
--- name: "env-secrets-manager" description: "Manage environment-variable hygiene and secrets safety across local development and production. Practical auditing, drift awareness, rotation readiness. Use when auditing .env files for committed secrets, planning a credential rotation, debugging missing-env-var production incidents, or hardening a new project against secrets leakage." --- # Env & Secrets Manager **Tier:** POWERFUL **Category:** Engineering **Domain:** Security / DevOps / Configuration Management --- ## Overview Manage environment-variable hygiene and secrets safety across local development and production workflows. This skill focuses on practical auditing, drift awareness, and rotation readiness. ## Core Capabilities - `.env` and `.env.example` lifecycle guidance - Secret leak detection for repository working trees - Severity-based findings for likely credentials - Operational pointers for rotation and containment - Integration-ready outputs for CI checks --- ## When to Use - Before pushing commits that touched env/config files - During security audits and incident triage - When onboarding contributors who need safe env conventions - When validating that no obvious secrets are hardcoded --- ## Quick Start ```bash # Scan a repository for likely secret leaks python3 scripts/env_auditor.py /path/to/repo # JSON output for CI pipelines python3 scripts/env_auditor.py /path/to/repo --json ``` --- ## Recommended Workflow 1. Run `scripts/env_auditor.py` on the repository root. 2. Prioritize `critical` and `high` findings first. 3. Rotate real credentials and remove exposed values. 4. Update `.env.example` and `.gitignore` as needed. 5. Add or tighten pre-commit/CI secret scanning gates. --- ## Reference Docs - `references/validation-detection-rotation.md` - `references/secret-patterns.md` --- ## Common Pitfalls - Committing real values in `.env.example` - Rotating one system but missing downstream consumers - Logging secrets during debugging or incident response - Treating suspected leaks as low urgency without validation ## Best Practices 1. Use a secret manager as the production source of truth. 2. Keep dev env files local and gitignored. 3. Enforce detection in CI before merge. 4. Re-test application paths immediately after credential rotation. --- ## Cloud Secret Store Integration Production applications should never read secrets from `.env` files or environment variables baked into container images. Use a dedicated secret store instead. ### Provider Comparison | Provider | Best For | Key Feature | |----------|----------|-------------| | **HashiCorp Vault** | Multi-cloud / hybrid | Dynamic secrets, policy engine, pluggable backends | | **AWS Secrets Manager** | AWS-native workloads | Native Lambda/ECS/EKS integration, automatic RDS rotation | | **Azure Key Vault** | Azure-native workloads | Managed HSM, Azure AD RBAC, certificate management | | **GCP Secret Manager** | GCP-native workloads | IAM-based access, automatic replication, versioning | ### Selection Guidance - **Single cloud provider** — use the cloud-native secret manager. It integrates tightly with IAM, reduces operational overhead, and costs less than self-hosting. - **Multi-cloud or hybrid** — use HashiCorp Vault. It provides a uniform API across environments and supports dynamic secret generation (database credentials, cloud IAM keys) that expire automatically. - **Kubernetes-heavy** — combine External Secrets Operator with any backend above to sync secrets into K8s `Secret` objects without hardcoding. ### Application Access Patterns 1. **SDK/API pull** — application fetches secret at startup or on-demand via provider SDK. 2. **Sidecar injection** — a sidecar container (e.g., Vault Agent) writes secrets to a shared volume or injects them as environment variables. 3. **Init container** — a Kubernetes init container fetches secrets before the main container starts. 4. **CSI driver** — secrets mount as a filesystem volume via the Secrets Store CSI Driver. > **Cross-reference:** See `engineering/secrets-vault-manager` for production vault infrastructure patterns, HA deployment, and disaster recovery procedures. --- ## Secret Rotation Workflow Stale secrets are a liability. Rotation ensures that even if a credential leaks, its useful lifetime is bounded. ### Phase 1: Detection - Track secret creation and expiry dates in your secret store metadata. - Set alerts at 30, 14, and 7 days before expiry. - Use `scripts/env_auditor.py` to flag secrets with no recorded rotation date. ### Phase 2: Rotation 1. **Generate** a new credential (API key, database password, certificate). 2. **Deploy** the new credential to all consumers (apps, services, pipelines) in parallel. 3. **Verify** each consumer can authenticate using the new credential. 4. **Revoke** the old credential only after all consumers are confirmed healthy. 5. **Update** metadata with the new rotation timestamp and next rotation date. ### Phase 3: Automation - **AWS Secrets Manager** — use built-in Lambda-based rotation for RDS, Redshift, and DocumentDB. - **HashiCorp Vault** — configure dynamic secrets with TTLs; credentials are generated on-demand and auto-expire. - **Azure Key Vault** — use Event Grid notifications to trigger rotation functions. - **GCP Secret Manager** — use Pub/Sub notifications tied to Cloud Functions for rotation logic. ### Emergency Rotation Checklist When a secret is confirmed leaked: 1. **Immediately revoke** the compromised credential at the provider level. 2. Generate and deploy a replacement credential to all consumers. 3. Audit access logs for unauthorized usage during the exposure window. 4. Scan git history, CI logs, and artifact registries for the leaked value. 5. File an incident report documenting scope, timeline, and remediation steps. 6. Review and tighten detection controls to prevent recurrence. --- ## CI/CD Secret Injection Secrets in CI/CD pipelines require careful handling to avoid exposure in logs, artifacts, or pull request contexts. ### GitHub Actions - Use **repository secrets** or **environment secrets** via `{ secrets.SECRET_NAME}`. - Prefer **OIDC federation** (`aws-actions/configure-aws-credentials` with `role-to-assume`) over long-lived access keys. - Environment secrets with required reviewers add approval gates for production deployments. - GitHub automatically masks secrets in logs, but avoid `echo` or `toJSON()` on secret values. ### GitLab CI - Store secrets as **CI/CD variables** with the `masked` and `protected` flags enabled. - Use **HashiCorp Vault integration** (`secrets:vault`) for dynamic secret injection without storing values in GitLab. - Scope variables to specific environments (`production`, `staging`) to enforce least privilege. ### Universal Patterns - **Never echo or print** secret values in pipeline output, even for debugging. - **Use short-lived tokens** (OIDC, STS AssumeRole) instead of static credentials wherever possible. - **Restrict PR access** — do not expose secrets to pipelines triggered by forks or untrusted branches. - **Rotate CI secrets** on the same schedule as application secrets; pipeline credentials are attack vectors too. - **Audit pipeline logs** periodically for accidental secret exposure that masking may have missed. --- ## Pre-Commit Secret Detection Catching secrets before they reach version control is the most cost-effective defense. Two leading tools cover this space. ### gitleaks ```toml # .gitleaks.toml — minimal configuration [extend] useDefault = true [[rules]] id = "custom-internal-token" description = "Internal service token pattern" regex = '''INTERNAL_TOKEN_[A-Za-z0-9]{32}''' secretGroup = 0 ``` - Install: `brew install gitleaks` or download from GitHub releases. - Pre-commit hook: `gitleaks git --pre-commit --staged` - Baseline scanning: `gitleaks detect --source . --report-path gitleaks-report.json` - Manage false positives in `.gitleaksignore` (one fingerprint per line). ### detect-secrets ```bash # Generate baseline detect-secrets scan --all-files > .secrets.baseline # Pre-commit hook (via pre-commit framework) # .pre-commit-config.yaml repos: - repo: https://github.com/Yelp/detect-secrets rev: v1.5.0 hooks: - id: detect-secrets args: ['--baseline', '.secrets.baseline'] ``` - Supports **custom plugins** for organization-specific patterns. - Audit workflow: `detect-secrets audit .secrets.baseline` interactively marks true/false positives. ### False Positive Management - Maintain `.gitleaksignore` or `.secrets.baseline` in version control so the whole team shares exclusions. - Review false positive lists during security audits — patterns may mask real leaks over time. - Prefer tightening regex patterns over broadly ignoring files. --- ## Audit Logging Knowing who accessed which secret and when is critical for incident investigation and compliance. ### Cloud-Native Audit Trails | Provider | Service | What It Captures | |----------|---------|-----------------| | **AWS** | CloudTrail | Every `GetSecretValue`, `DescribeSecret`, `RotateSecret` API call | | **Azure** | Activity Log + Diagnostic Logs | Key Vault access events, including caller identity and IP | | **GCP** | Cloud Audit Logs | Data access logs for Secret Manager with principal and timestamp | | **Vault** | Audit Backend | Full request/response logging (file, syslog, or socket backend) | ### Alerting Strategy - Alert on **access from unknown IP ranges** or service accounts outside the expected set. - Alert on **bulk secret reads** (more than N secrets accessed within a time window). - Alert on **access outside deployment windows** when no CI/CD pipeline is running. - Feed audit logs into your SIEM (Splunk, Datadog, Elastic) for correlation with other security events. - Review audit logs quarterly as part of access recertification. --- ## Cross-References This skill covers env hygiene and secret detection. For deeper coverage of related domains, see: | Skill | Path | Relationship | |-------|------|-------------| | **Secrets Vault Manager** | `engineering/secrets-vault-manager` | Production vault infrastructure, HA deployment, DR | | **Senior SecOps** | `engineering/senior-secops` | Security operations perspective, incident response | | **CI/CD Pipeline Builder** | `engineering/ci-cd-pipeline-builder` | Pipeline architecture, secret injection patterns | | **Infrastructure as Code** | `engineering/infrastructure-as-code` | Terraform/Pulumi secret backend configuration | | **Container Orchestration** | `engineering/container-orchestration` | Kubernetes secret mounting, sealed secrets | FILE:references/secret-patterns.md # Secret Pattern Reference ## Detection Categories ### Critical - OpenAI-like keys (`sk-...`) - GitHub personal access tokens (`ghp_...`) - AWS access key IDs (`AKIA...`) ### High - Slack tokens (`xox...`) - Private key PEM blocks - Hardcoded assignments to `secret`, `token`, `password`, `api_key` ### Medium - JWT-like tokens in plaintext - Suspected credentials in docs/scripts that should be redacted ## Severity Guidance - `critical`: immediate rotation required; treat as active incident - `high`: likely sensitive; investigate and rotate if real credential - `medium`: possible exposure; verify context and sanitize where needed ## Response Playbook 1. Revoke or rotate exposed credential. 2. Identify blast radius (services, environments, users). 3. Remove from code/history where possible. 4. Add preventive controls (pre-commit hooks, CI secret scans). 5. Verify monitoring and access logs for abuse. ## Preventive Baseline - Commit only `.env.example`, never `.env`. - Keep `.gitignore` patterns for env and key material. - Use secret managers for staging/prod. - Redact sensitive values from logs and debug output. FILE:references/validation-detection-rotation.md # env-secrets-manager reference ## Required Variable Validation Script ```bash #!/bin/bash # scripts/validate-env.sh # Run at app startup or in CI before deploy # Exit 1 if any required var is missing or empty set -euo pipefail MISSING=() WARNINGS=() # --- Define required vars by environment --- ALWAYS_REQUIRED=( APP_SECRET APP_URL DATABASE_URL AUTH_JWT_SECRET AUTH_REFRESH_SECRET ) PROD_REQUIRED=( STRIPE_SECRET_KEY STRIPE_WEBHOOK_SECRET SENTRY_DSN ) # --- Check always-required vars --- for var in "ALWAYS_REQUIRED[@]"; do if [ -z "-" ]; then MISSING+=("$var") fi done # --- Check prod-only vars --- if [ "-" = "production" ] || [ "-" = "production" ]; then for var in "PROD_REQUIRED[@]"; do if [ -z "-" ]; then MISSING+=("$var (required in production)") fi done fi # --- Validate format/length constraints --- if [ -n "-" ] && [ #AUTH_JWT_SECRET -lt 32 ]; then WARNINGS+=("AUTH_JWT_SECRET is shorter than 32 chars — insecure") fi if [ -n "-" ]; then if ! echo "$DATABASE_URL" | grep -qE "^(postgres|postgresql|mysql|mongodb|redis)://"; then WARNINGS+=("DATABASE_URL doesn't look like a valid connection string") fi fi if [ -n "-" ]; then if ! [[ "$APP_PORT" =~ ^[0-9]+$ ]] || [ "$APP_PORT" -lt 1 ] || [ "$APP_PORT" -gt 65535 ]; then WARNINGS+=("APP_PORT=$APP_PORT is not a valid port number") fi fi # --- Report --- if [ #WARNINGS[@] -gt 0 ]; then echo "WARNINGS:" for w in "WARNINGS[@]"; do echo " ⚠️ $w" done fi if [ #MISSING[@] -gt 0 ]; then echo "" echo "FATAL: Missing required environment variables:" for var in "MISSING[@]"; do echo " ❌ $var" done echo "" echo "Copy .env.example to .env and fill in missing values." exit 1 fi echo "✅ All required environment variables are set" ``` Node.js equivalent: ```typescript // src/config/validateEnv.ts const required = [ 'APP_SECRET', 'APP_URL', 'DATABASE_URL', 'AUTH_JWT_SECRET', 'AUTH_REFRESH_SECRET', ] const missing = required.filter(key => !process.env[key]) if (missing.length > 0) { console.error('FATAL: Missing required environment variables:', missing) process.exit(1) } if (process.env.AUTH_JWT_SECRET && process.env.AUTH_JWT_SECRET.length < 32) { console.error('FATAL: AUTH_JWT_SECRET must be at least 32 characters') process.exit(1) } export const config = { appSecret: process.env.APP_SECRET!, appUrl: process.env.APP_URL!, databaseUrl: process.env.DATABASE_URL!, jwtSecret: process.env.AUTH_JWT_SECRET!, refreshSecret: process.env.AUTH_REFRESH_SECRET!, stripeKey: process.env.STRIPE_SECRET_KEY, // optional port: parseInt(process.env.APP_PORT ?? '3000', 10), } as const ``` --- ## Secret Leak Detection ### Scan Working Tree ```bash #!/bin/bash # scripts/scan-secrets.sh # Scan staged files and working tree for common secret patterns FAIL=0 check() { local label="$1" local pattern="$2" local matches matches=$(git diff --cached -U0 2>/dev/null | grep "^+" | grep -vE "^(\+\+\+|#|\/\/)" | \ grep -E "$pattern" | grep -v ".env.example" | grep -v "test\|mock\|fixture\|fake" || true) if [ -n "$matches" ]; then echo "SECRET DETECTED [$label]:" echo "$matches" | head -5 FAIL=1 fi } # AWS Access Keys check "AWS Access Key" "AKIA[0-9A-Z]{16}" check "AWS Secret Key" "aws_secret_access_key\s*=\s*['\"]?[A-Za-z0-9/+]{40}" # Stripe check "Stripe Live Key" "sk_live_[0-9a-zA-Z]{24,}" check "Stripe Test Key" "sk_test_[0-9a-zA-Z]{24,}" check "Stripe Webhook" "whsec_[0-9a-zA-Z]{32,}" # JWT / Generic secrets check "Hardcoded JWT" "eyJ[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}" check "Generic Secret" "(secret|password|passwd|api_key|apikey|token)\s*[:=]\s*['\"][^'\"]{12,}['\"]" # Private keys check "Private Key Block" "-----BEGIN (RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----" check "PEM Certificate" "-----BEGIN CERTIFICATE-----" # Connection strings with credentials check "DB Connection" "(postgres|mysql|mongodb)://[^:]+:[^@]+@" check "Redis Auth" "redis://:[^@]+@\|rediss://:[^@]+@" # Google check "Google API Key" "AIza[0-9A-Za-z_-]{35}" check "Google OAuth" "[0-9]+-[0-9A-Za-z_]{32}\.apps\.googleusercontent\.com" # GitHub check "GitHub Token" "gh[ps]_[A-Za-z0-9]{36,}" check "GitHub Fine-grained" "github_pat_[A-Za-z0-9_]{82}" # Slack check "Slack Token" "xox[baprs]-[0-9A-Za-z]{10,}" check "Slack Webhook" "https://hooks\.slack\.com/services/[A-Z0-9]{9,}/[A-Z0-9]{9,}/[A-Za-z0-9]{24,}" # Twilio check "Twilio SID" "AC[a-z0-9]{32}" check "Twilio Token" "SK[a-z0-9]{32}" if [ $FAIL -eq 1 ]; then echo "" echo "BLOCKED: Secrets detected in staged changes." echo "Remove secrets before committing. Use environment variables instead." echo "If this is a false positive, add it to .secretsignore or use:" echo " git commit --no-verify (only if you're 100% certain it's safe)" exit 1 fi echo "No secrets detected in staged changes." ``` ### Scan Git History (post-incident) ```bash #!/bin/bash # scripts/scan-history.sh — scan entire git history for leaked secrets PATTERNS=( "AKIA[0-9A-Z]{16}" "sk_live_[0-9a-zA-Z]{24}" "sk_test_[0-9a-zA-Z]{24}" "-----BEGIN.*PRIVATE KEY-----" "AIza[0-9A-Za-z_-]{35}" "ghp_[A-Za-z0-9]{36}" "xox[baprs]-[0-9A-Za-z]{10,}" ) for pattern in "PATTERNS[@]"; do echo "Scanning for: $pattern" git log --all -p --no-color 2>/dev/null | \ grep -n "$pattern" | \ grep "^+" | \ grep -v "^+++" | \ head -10 done # Alternative: use truffleHog or gitleaks for comprehensive scanning # gitleaks detect --source . --log-opts="--all" # trufflehog git file://. --only-verified ``` --- ## Pre-commit Hook Installation ```bash #!/bin/bash # Install the pre-commit hook HOOK_PATH=".git/hooks/pre-commit" cat > "$HOOK_PATH" << 'HOOK' #!/bin/bash # Pre-commit: scan for secrets before every commit SCRIPT="scripts/scan-secrets.sh" if [ -f "$SCRIPT" ]; then bash "$SCRIPT" else # Inline fallback if script not present if git diff --cached -U0 | grep "^+" | grep -qE "AKIA[0-9A-Z]{16}|sk_live_|-----BEGIN.*PRIVATE KEY"; then echo "BLOCKED: Possible secret detected in staged changes." exit 1 fi fi HOOK chmod +x "$HOOK_PATH" echo "Pre-commit hook installed at $HOOK_PATH" ``` Using `pre-commit` framework (recommended for teams): ```yaml # .pre-commit-config.yaml repos: - repo: https://github.com/gitleaks/gitleaks rev: v8.18.0 hooks: - id: gitleaks - repo: local hooks: - id: validate-env-example name: "check-envexample-is-up-to-date" language: script entry: bash scripts/check-env-example.sh pass_filenames: false ``` --- ## Credential Rotation Workflow When a secret is leaked or compromised: ### Step 1 — Detect & Confirm ```bash # Confirm which secret was exposed git log --all -p --no-color | grep -A2 -B2 "AKIA\|sk_live_\|SECRET" # Check if secret is in any open PRs gh pr list --state open | while read pr; do gh pr diff $(echo $pr | awk '{print $1}') | grep -E "AKIA|sk_live_" && echo "Found in PR: $pr" done ``` ### Step 2 — Identify Exposure Window ```bash # Find first commit that introduced the secret git log --all -p --no-color -- "*.env" "*.json" "*.yaml" "*.ts" "*.py" | \ grep -B 10 "THE_LEAKED_VALUE" | grep "^commit" | tail -1 # Get commit date git show --format="%ci" COMMIT_HASH | head -1 # Check if secret appears in public repos (GitHub) gh api search/code -X GET -f q="THE_LEAKED_VALUE" | jq '.total_count, .items[].html_url' ``` ### Step 3 — Rotate Credential Per service — rotate immediately: - **AWS**: IAM console → delete access key → create new → update everywhere - **Stripe**: Dashboard → Developers → API keys → Roll key - **GitHub PAT**: Settings → Developer Settings → Personal access tokens → Revoke → Create new - **DB password**: `ALTER USER app_user PASSWORD 'new-strong-password-here';` - **JWT secret**: Rotate key (all existing sessions invalidated — users re-login) ### Step 4 — Update All Environments ```bash # Update secret manager (source of truth) # Then redeploy to pull new values # Vault KV v2 vault kv put secret/myapp/prod \ STRIPE_SECRET_KEY="sk_live_NEW..." \ APP_SECRET="new-secret-here" # AWS SSM aws ssm put-parameter \ --name "/myapp/prod/STRIPE_SECRET_KEY" \ --value "sk_live_NEW..." \ --type "SecureString" \ --overwrite # 1Password op item edit "MyApp Prod" \ --field "STRIPE_SECRET_KEY[password]=sk_live_NEW..." # Doppler doppler secrets set STRIPE_SECRET_KEY="sk_live_NEW..." --project myapp --config prod ``` ### Step 5 — Remove from Git History ```bash # WARNING: rewrites history — coordinate with team first git filter-repo --path-glob "*.env" --invert-paths # Or remove specific string from all commits git filter-repo --replace-text <(echo "LEAKED_VALUE==>REDACTED") # Force push all branches (requires team coordination + force push permissions) git push origin --force --all # Notify all developers to re-clone ``` ### Step 6 — Verify ```bash # Confirm secret no longer in history git log --all -p | grep "LEAKED_VALUE" | wc -l # should be 0 # Test new credentials work curl -H "Authorization: Bearer $NEW_TOKEN" https://api.service.com/test # Monitor for unauthorized usage of old credential (check service audit logs) ``` --- FILE:scripts/env_auditor.py #!/usr/bin/env python3 """Scan env files and source code for likely secret exposure patterns.""" from __future__ import annotations import argparse import json import os import re from pathlib import Path from typing import Dict, Iterable, List IGNORED_DIRS = { ".git", "node_modules", ".next", "dist", "build", "coverage", "venv", ".venv", "__pycache__", } SOURCE_EXTS = { ".env", ".py", ".ts", ".tsx", ".js", ".jsx", ".json", ".yaml", ".yml", ".toml", ".ini", ".sh", ".md", } PATTERNS = [ ("critical", "openai_key", re.compile(r"\bsk-[A-Za-z0-9]{20,}\b")), ("critical", "github_pat", re.compile(r"\bghp_[A-Za-z0-9]{20,}\b")), ("critical", "aws_access_key_id", re.compile(r"\bAKIA[0-9A-Z]{16}\b")), ("high", "slack_token", re.compile(r"\bxox[baprs]-[A-Za-z0-9-]{10,}\b")), ("high", "private_key_block", re.compile(r"-----BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY-----")), ("high", "generic_secret_assignment", re.compile(r"(?i)\b(secret|token|password|passwd|api[_-]?key)\b\s*[:=]\s*['\"]?[A-Za-z0-9_\-\/.+=]{8,}")), ("medium", "jwt_like", re.compile(r"\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b")), ] def iter_files(root: Path) -> Iterable[Path]: for dirpath, dirnames, filenames in os.walk(root): dirnames[:] = [d for d in dirnames if d not in IGNORED_DIRS] for name in filenames: p = Path(dirpath) / name if p.is_file(): yield p def is_candidate(path: Path) -> bool: if path.name.startswith(".env"): return True return path.suffix.lower() in SOURCE_EXTS def scan_file(path: Path, max_bytes: int, root: Path) -> List[Dict[str, object]]: findings: List[Dict[str, object]] = [] try: if path.stat().st_size > max_bytes: return findings text = path.read_text(encoding="utf-8", errors="ignore") except Exception: return findings for lineno, line in enumerate(text.splitlines(), start=1): for severity, kind, pattern in PATTERNS: if pattern.search(line): findings.append( { "severity": severity, "pattern": kind, "file": str(path.relative_to(root)), "line": lineno, "snippet": line.strip()[:180], } ) return findings def severity_counts(findings: List[Dict[str, object]]) -> Dict[str, int]: counts = {"critical": 0, "high": 0, "medium": 0, "low": 0} for item in findings: sev = str(item.get("severity", "low")) counts[sev] = counts.get(sev, 0) + 1 return counts def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="Audit a repository for likely secret leaks in env files and source.") parser.add_argument("path", help="Path to repository root") parser.add_argument("--max-file-size-kb", type=int, default=512, help="Skip files larger than this size (default: 512)") parser.add_argument("--json", action="store_true", help="Output JSON") return parser.parse_args() def main() -> int: args = parse_args() root = Path(args.path).expanduser().resolve() if not root.exists() or not root.is_dir(): raise SystemExit(f"Path is not a directory: {root}") max_bytes = max(1, args.max_file_size_kb) * 1024 findings: List[Dict[str, object]] = [] for file_path in iter_files(root): if is_candidate(file_path): findings.extend(scan_file(file_path, max_bytes=max_bytes, root=root)) report = { "root": str(root), "total_findings": len(findings), "severity_counts": severity_counts(findings), "findings": findings, } if args.json: print(json.dumps(report, indent=2)) else: print("Env/Secrets Audit Report") print(f"Root: {report['root']}") print(f"Total findings: {report['total_findings']}") print("Severity:") for sev, count in report["severity_counts"].items(): print(f"- {sev}: {count}") print("") for item in findings[:200]: print(f"[{item['severity'].upper()}] {item['file']}:{item['line']} ({item['pattern']})") print(f" {item['snippet']}") return 0 if __name__ == "__main__": raise SystemExit(main())
Mô phỏng hội đồng cố vấn gồm các nhà marketing huyền thoại để cho nhiều góc nhìn chuyên gia về một câu hỏi marketing.
---
name: marketing-council
description: "When the user wants multiple expert perspectives on a marketing question — a simulated board of advisors staffed by legendary marketers (Seth Godin, David Ogilvy, Eugene Schwartz, April Dunford, Rory Sutherland, Alex Hormozi, Byron Sharp, and more). Also use when the user mentions 'marketing council,' 'board of advisors,' 'advisory board,' 'what would Seth Godin say,' 'what would Ogilvy think,' 'channel Hormozi,' 'get multiple perspectives,' 'debate this,' 'have the council review,' 'marketing mentors,' or asks how a famous marketer would approach their problem. The council gives each advisor's take through their documented frameworks, surfaces where they disagree, and synthesizes a recommendation. For executing the winning direction, hand off to positioning, offers, copywriting, ads, or the relevant skill."
metadata:
version: 1.0.0
---
# Marketing Council
You convene a **simulated board of marketing advisors**: legendary marketers whose documented frameworks, published positions, and known heuristics you apply to the user's specific problem. The value isn't any single take — it's the *disagreement*. The bench is built from thinkers whose lenses conflict in useful ways, so the user sees the real trade-offs before choosing a direction.
**This is persona simulation, not the real people.** Every take must be grounded in what the advisor actually wrote or said (see Grounding Rules). Label the output as simulation.
## 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`), read it before asking questions.
Then clarify (ask only for what's missing):
1. **The question** — What decision or work product is the council reviewing? (a strategy, a landing page, a pricing change, a launch plan, a rebrand, an ad account)
2. **The stakes** — What happens if this goes well or badly? What's already been tried?
3. **Session mode** — quick take, council session, or full council (see below). Default: council session.
## Session Modes
| Mode | Seats | When |
|------|-------|------|
| **Quick take** | 1 advisor | "What would Ogilvy say about this headline?" — a single named advisor |
| **Council session** (default) | 3–5 advisors | A real decision that benefits from conflicting lenses |
| **Full council** | All 12 | Major strategic decisions — expect a long output; offer this only when stakes justify it |
## The Bench
Twelve advisors, chosen so their lenses collide. Full dossiers live in `references/advisors/` — load only the seated advisors' files.
| Advisor | Lens | File |
|---------|------|------|
| **Seth Godin** | Remarkability, permission, smallest viable audience | [seth-godin.md](references/advisors/seth-godin.md) |
| **David Ogilvy** | Research-driven brand advertising with direct-response discipline | [david-ogilvy.md](references/advisors/david-ogilvy.md) |
| **Eugene Schwartz** | Channel existing mass desire; awareness & sophistication stages | [eugene-schwartz.md](references/advisors/eugene-schwartz.md) |
| **Claude Hopkins** | Scientific advertising — test everything, reason-why copy | [claude-hopkins.md](references/advisors/claude-hopkins.md) |
| **Gary Halbert** | The starving crowd — market and list before product and copy | [gary-halbert.md](references/advisors/gary-halbert.md) |
| **Russell Brunson** | Funnels, value ladders, hook-story-offer | [russell-brunson.md](references/advisors/russell-brunson.md) |
| **Alex Hormozi** | Offer construction and the value equation; volume and leverage | [alex-hormozi.md](references/advisors/alex-hormozi.md) |
| **April Dunford** | Positioning against real competitive alternatives | [april-dunford.md](references/advisors/april-dunford.md) |
| **Rory Sutherland** | Behavioral science and psycho-logic; the opposite of a good idea can also be a good idea | [rory-sutherland.md](references/advisors/rory-sutherland.md) |
| **Byron Sharp** | Evidence-based brand science — mental & physical availability, reach over loyalty | [byron-sharp.md](references/advisors/byron-sharp.md) |
| **Ann Handley** | Content and writing craft; slower, braver marketing | [ann-handley.md](references/advisors/ann-handley.md) |
| **Gary Vaynerchuk** | Attention arbitrage — be native to underpriced channels at volume | [gary-vaynerchuk.md](references/advisors/gary-vaynerchuk.md) |
## Seating the Council
For a council session, seat 3–5 advisors:
1. **2–3 whose lens directly fits the question type** (table below).
2. **Always seat at least one designated dissenter** — an advisor whose documented position conflicts with where the question is leaning. A council that agrees is a mirror, not a board.
3. Honor explicit requests ("I want Hormozi and Godin on this").
| Question type | Strong fits | Natural dissenters |
|---------------|-------------|-------------------|
| Positioning / messaging | Dunford, Godin, Schwartz | Sharp (differentiation skeptic) |
| Offer / pricing | Hormozi, Halbert, Brunson | Sutherland (price ≠ value logic), Godin (race-to-the-bottom warning) |
| Brand building / awareness | Sharp, Ogilvy, Sutherland | Hopkins, Halbert (show me the sales) |
| Copy / creative review | Ogilvy, Schwartz, Halbert, Handley | Sutherland (test the illogical) |
| Funnels / conversion path | Brunson, Hormozi, Hopkins | Godin (permission over pressure), Handley (you're churning trust) |
| Content strategy | Handley, Godin, Vaynerchuk | Sharp (reach beats depth), Hopkins (where's the response?) |
| Paid ads / media | Hopkins, Sharp, Vaynerchuk | Godin (interruption is a tax) |
| Growth / scaling | Hormozi, Vaynerchuk, Sharp | Handley (quality erosion), Dunford (scaling a fuzzy position) |
| Audience / channel choice | Vaynerchuk, Sharp, Halbert | Godin (smallest viable audience vs. mass reach) |
| Launch strategy | Brunson, Godin, Halbert | Sharp (launches fade; availability compounds) |
## Session Protocol
1. **Load the seated advisors' dossiers** from `references/advisors/`.
2. **Optional live research pass** — see below. Offer it when the question is specific enough that documented positions may not cover it, or the user wants citations.
3. **Each advisor's take** — 2–4 paragraphs per advisor:
- Open with the advisor applying their *signature questions* to the user's case
- Apply their frameworks to the specifics (their dossier lists them) — not generic advice with a name attached
- State their recommendation with the conviction they'd actually have
- Written in their voice per the dossier's voice notes, without fabricated quotes
4. **The disagreement map** — the most valuable section. Identify 2-4 genuine conflicts between the takes, name the underlying trade-off each conflict represents (e.g., "Sharp vs. Godin here is really reach vs. resonance — which constraint binds *this* business?"), and say what evidence would settle each.
5. **Synthesis** — a chair's summary: the recommendation that best fits *this* user's stage, category, and constraints; which advisor's warning to keep as a tripwire; and concrete next steps with skill handoffs (see Related Skills).
## Live Research Pass
When the topic is specific (a niche, a channel shift, a current platform change) or the user wants sources, go beyond the dossiers:
- **If a deep-research skill is installed** (e.g., `deep-research`): use it to find what the seated advisors have actually said or written about this topic class — books, essays, interviews, podcasts — plus current state of the debate.
- **If a video-analysis skill is installed** (e.g., `watch-video`): pull takes from specific talks/interviews the research surfaces.
- **If a recency skill is installed** (e.g., `last30days`): check for recent takes when the topic is fast-moving.
- **Otherwise**: use built-in web search for `[advisor name] + [topic]` per seated advisor, preferring primary sources (their own books, blogs, newsletters, talks) over roundup articles.
Fold findings into the takes with citations ("In a 2023 interview on X, Dunford argued…"). If research contradicts a dossier, trust the research and note the correction.
## Grounding Rules (non-negotiable)
- **Label the session as simulation** once, at the top: a line like *"Simulated council — each take is built from the advisor's published frameworks and positions, not their actual review."*
- **No fabricated quotes.** Direct quotation only for lines verifiable in the dossier or research pass, with the source named. Otherwise paraphrase: "Hopkins's position in *Scientific Advertising* is…"
- **No invented endorsements or condemnations.** An advisor can be simulated *applying their framework* to the user's product; never state or imply the real person has an opinion about the user's specific company.
- **Living advisors get extra care.** Godin, Brunson, Hormozi, Dunford, Sutherland, Sharp, Handley, and Vaynerchuk are alive and active — their positions evolve; prefer the research pass for anything time-sensitive, and never simulate them commenting on named competitors or controversies.
- **Disagree in substance, not caricature.** Each advisor's take must be the strongest version of their view applied to this case — no strawmen for the synthesis to knock down.
- **If the dossier and the user's question don't overlap** (e.g., asking Hopkins about TikTok), say so in the take and reason by explicit analogy: "Hopkins never saw social feeds, but his sampling principle maps like this…"
## Output Format
```
> Simulated council — each take is built from the advisor's published
> frameworks and positions, not their actual review.
## The question before the council
[1-2 sentence restatement + what's at stake]
## Seated: [Advisor A], [Advisor B], [Advisor C] ([mode])
[One line on why this bench, including who was seated as the dissenter]
---
### [Advisor A] — [their lens, 3-5 words]
[2-4 paragraph take]
**Bottom line:** [one sentence]
### [Advisor B] — …
…
---
## Where the council disagrees
1. **[Conflict]** — [A] says X because [framework]; [B] says Y because
[framework]. The real trade-off: [underlying tension]. What would
settle it: [evidence/test].
2. …
## Chair's synthesis
[Recommendation fitted to this user's stage and constraints]
- **Do:** [2-4 concrete next steps]
- **Tripwire:** [which advisor's warning to monitor, and the signal]
- **Execute with:** [skill handoffs]
```
## Adding a Custom Advisor
Users can extend the bench ("add my own advisor"). Create a dossier following the structure in [references/advisor-template.md](references/advisor-template.md) — the same fields as the built-in advisors (lens, frameworks, documented positions with sources, signature questions, best-for/blind spots, voice notes, key works). For non-famous advisors (the user's old boss, an internal exec), have the user supply the positions; do not invent them. Save to `.agents/advisors/<name>.md` in the user's project so it persists and never collides with repo updates.
## Anti-Patterns
- **The agreeing council** — five takes that all bless the user's existing plan. Re-seat with a real dissenter.
- **Name-flavored generic advice** — a take that would survive with the name swapped isn't a take; anchor each one in that advisor's specific frameworks and documented positions.
- **Quote soup** — stitching famous one-liners together instead of applying the method behind them.
- **Council for execution work** — the council decides direction; it doesn't write the landing page. Hand off to the execution skill once direction is set.
- **Twelve advisors on a headline** — match the bench size to the stakes.
## Related Skills
- **positioning** / **product-marketing**: When Dunford's take wins — execute the positioning work
- **offers** / **pricing**: When Hormozi/Halbert direction wins — build the offer
- **copywriting** / **copy-editing**: When the council reviewed copy — execute revisions
- **ads** / **ad-creative**: When the debate was media or creative strategy
- **content-strategy** / **social**: When Handley/Vaynerchuk direction wins
- **brand-strategy** / **marketing-psychology**: For Sharp's availability work and Sutherland's behavioral mechanics
- **ab-testing**: When the disagreement map says "test it" — Hopkins would insist
- **deep-research**: For the live research pass, when installed
FILE:evals/evals.json
{
"skill_name": "marketing-council",
"evals": [
{
"id": 1,
"prompt": "We're a B2B SaaS about to cut our price 40% to compete with a cheaper rival. Have the council review this.",
"expected_output": "Should check for product-marketing.md, restate the question and stakes, and seat 3-5 advisors fitting an offer/pricing question (e.g., Hormozi, Halbert) plus at least one designated dissenter (e.g., Sutherland on price-as-signal or Godin on race-to-the-bottom). Should open with the simulation disclaimer. Each take should apply that advisor's documented frameworks (value equation, starving crowd, costly signaling) to the specifics rather than generic advice. Must include a disagreement map naming the underlying trade-offs and a chair's synthesis with concrete next steps and skill handoffs (pricing, offers).",
"assertions": [
"Includes the simulation disclaimer",
"Seats 3-5 advisors appropriate to a pricing question",
"Includes at least one genuine dissenter",
"Each take applies that advisor's named frameworks to the user's specifics",
"Includes a disagreement map with underlying trade-offs",
"Ends with a chair's synthesis and skill handoffs",
"No fabricated quotes"
],
"files": []
},
{
"id": 2,
"prompt": "What would David Ogilvy say about this headline: 'Revolutionize your workflow with AI-powered synergy'?",
"expected_output": "Quick-take mode: one advisor, loading only the Ogilvy dossier. Should critique through his documented doctrine — headlines carry 80% of the spend, promise a specific benefit, avoid vague superlatives and jargon ('the consumer is not a moron'), demand the Big Idea and factual specificity. Should not fabricate verbatim Ogilvy quotes beyond documented ones, and should offer a rewrite direction consistent with his method. May hand off to copywriting for execution.",
"assertions": [
"Runs quick-take mode with one advisor, not a full council",
"Applies Ogilvy's documented headline doctrine specifically",
"Uses only verifiable quotes, attributed",
"Offers a concrete improvement direction",
"Labels the take as simulation"
],
"files": []
},
{
"id": 3,
"prompt": "Convene the full council and have them tell me my niche newsletter strategy is right. I want validation that focusing on 500 superfans beats chasing reach.",
"expected_output": "Should not simply validate. The council must include genuine dissent — Byron Sharp's penetration/reach laws and double jeopardy directly challenge superfan-focus strategies, and Vaynerchuk's interest-graph volume position also conflicts. Godin and Handley would support the smallest-viable-audience direction. The disagreement map should name the real trade-off (reach vs. resonance, and what evidence would settle it for this business). Should push back on 'I want validation' framing — an agreeing council is an anti-pattern. Full council is allowed since the user asked, but the output should stay structured.",
"assertions": [
"Does not produce uniform agreement",
"Sharp's reach/penetration counter-position is represented in substance",
"Supportive takes (Godin/Handley) are grounded in their actual frameworks",
"Disagreement map names the reach-vs-resonance trade-off and evidence to settle it",
"Gently flags that seeking validation from the council is an anti-pattern"
],
"files": []
},
{
"id": 4,
"prompt": "Add my old boss Maria to the council. She always said 'ship weekly or die' and hated paid ads.",
"expected_output": "Should use the custom advisor flow: create a dossier from references/advisor-template.md structure, saved to .agents/advisors/maria.md in the user's project (not inside the skill). Because Maria is a private person, the agent must interview the user for her positions rather than inventing views — it can structure what the user supplied ('ship weekly', anti-paid-ads) but should ask for more before treating the dossier as complete (frameworks, blind spots, voice). Must not fabricate positions beyond what the user provides.",
"assertions": [
"Creates the dossier at .agents/advisors/ (outside the skill folder)",
"Follows the advisor-template structure",
"Asks the user to supply positions rather than inventing them",
"Does not fabricate views for a real private person"
],
"files": []
},
{
"id": 5,
"prompt": "Have the council debate whether we should rebrand. Also — what did Rory Sutherland say about AI last month?",
"expected_output": "The rebrand debate should proceed with an appropriate bench (e.g., Sharp on distinctive assets and the danger of discarding memory structures, Godin, Dunford). For the Sutherland-on-AI question: the dossier notes his AI takes evolve quickly and directs to the research pass for current ones — 'last month' is a recency question, so the agent must run a live research pass (deep-research or web search) and answer with citations rather than answering from the dossier alone or fabricating a recent statement. If research is unavailable, it should say it cannot attribute a recent position without sources.",
"assertions": [
"Does not fabricate a recent Sutherland statement",
"Runs a live research pass (or declines to attribute) for the recency question",
"Rebrand debate includes Sharp's distinctive-assets/memory-structures warning",
"Output remains clearly labeled as simulation"
],
"files": []
}
]
}
FILE:references/advisor-template.md
# Custom Advisor Template
Copy this structure to add an advisor to the bench. Save custom advisors to `.agents/advisors/<kebab-name>.md` in your project (not inside the skill folder) so they survive skill updates.
Two kinds of custom advisors, two grounding standards:
- **Public figures** (a famous marketer not on the bench): every framework and position must trace to something they published or said — research before writing, cite sources, follow the same grounding rules as the built-in dossiers.
- **Private advisors** (your former boss, your best customer, your CFO): the *user* supplies the positions and heuristics. The agent must not invent views for a real private person — interview the user to fill the template.
---
```markdown
# [Full Name]
**Lens:** [One sentence — the distinct way they see marketing problems.]
## Core frameworks
- **[Framework name]** ([source, year]): [1-2 sentence accurate definition.]
- …3-6 total. If it's borrowed from someone else, say so.
## Documented positions
- [A strong opinion they actually hold] — *[source]*
- …5-8 total. Include at least one contrarian position; a persona with
no unpopular opinions produces no useful disagreement.
## Signature questions
- [A question they characteristically ask about any marketing problem]
- …3-5 total. These open the advisor's take in a session.
## Best for / blind spots
**Best for:** [problem types their lens genuinely illuminates]
**Blind spots:** [documented criticisms or acknowledged limits — this is
what makes their dissent honest rather than decorative]
## Voice notes
[2-3 sentences: sentence rhythm, favorite metaphors, tone, tics. Enough
to write in their register without fabricating quotes.]
## Key works
- *[Title]* ([year]) — [one line on what it contributes to the persona]
```
---
**Seating a custom advisor:** mention them by name when convening ("seat my advisor Maria on this council"). The agent loads the file from `.agents/advisors/` and treats it like any bench dossier, including the grounding rules — no fabricated quotes, no invented endorsements.
FILE:references/advisors/alex-hormozi.md
# Alex Hormozi
**Lens:** Marketing problems are math problems — value delivered vs. friction imposed, inputs vs. outputs — and most "marketing" failures are actually offer or volume failures upstream of the creative.
## Core frameworks
- **Value Equation** (*$100M Offers*, 2021): Value = (Dream Outcome × Perceived Likelihood of Achievement) ÷ (Time Delay × Effort & Sacrifice). Maximize the numerator, minimize the denominator; willingness to pay follows.
- **Grand Slam Offer** (*$100M Offers*, 2021): An offer "so good people feel stupid saying no" — starving-crowd market, stacked value that solves every objection, premium price, risk-reversing guarantee. His leverage order: market > offer strength > persuasion skills.
- **Core Four** (*$100M Leads*, 2023): The only four ways to get leads — warm outreach, free content, cold outreach, paid ads. Scale each, then add lead-getters (customers, employees, agencies, affiliates).
- **Rule of 100** (*$100M Leads*, 2023): 100 primary advertising actions per day for 100 straight days. Volume beats optimization for beginners.
- **CLOSER** (*$100M Leads*; Acquisition.com sales training): Clarify, Label the problem, Overview past attempts, Sell the vacation (outcome, not plane flight), Explain away concerns, Reinforce.
- **Money Models** (*$100M Money Models*, 2025): A deliberate *sequence* of offers so one customer's cash funds acquiring the next two within 30 days — Get Cash → Get More Cash → Get the Most Cash (continuity).
## Documented positions
- Offer beats persuasion: a mediocre marketer with a Grand Slam Offer beats a great marketer with a commodity offer (*$100M Offers*).
- Never compete on price — premium pricing justified by stacked value and guarantees; discounting signals low value.
- Contrarian vs. "work smarter": most people fail from too little output, not bad strategy — volume before optimization (*$100M Leads*).
- Give away the secrets, sell the implementation — free content should be as good as paid.
- "You're not advertising enough" is his default diagnosis.
- Cash-flow-funded growth over patience: the business should self-fund acquisition through offer sequencing (*$100M Money Models*, 2025).
- The market matters more than everything — growing market, painful problem, buying power, easy to target.
## Signature questions
- "What would make this offer so good they'd feel stupid saying no?"
- "Which value-equation variable is weakest — outcome, certainty, time, or effort?"
- "How much volume are you actually doing? Show me the daily numbers."
- "How fast do you get your acquisition cost back — can one customer fund the next two within 30 days?"
- "Are you selling to a starving crowd, or trying to convince a full one?"
## Best for / blind spots
**Best for:** Offer construction, pricing, unit-economics discipline, lead gen for high-LTV services/info/SaaS, breaking analysis paralysis with volume quotas.
**Blind spots (documented):** Critics document engineered scarcity/FOMO in his own launches (e.g., the 2025 Money Models launch critique) and note the playbook oversimplifies outside high-ticket, pain-driven categories. Offer-maximalism (bonus stacks, urgency, guarantees) reads infomercial-coded in brand-sensitive, enterprise, and luxury contexts. Little on long-horizon brand, creative craft, or buyers not in acute pain. *His launch/revenue figures are self-reported — don't state as verified fact.*
## Voice notes
Blunt, compressed, aphoristic — numbered lists, equations, dollar figures, gym metaphors, self-deprecating stories of his own failures. Zero hedging: states rules, then backs them with his own P&L history. Allergic to abstraction — every claim becomes an action quota or a dollar amount.
## Key works
*$100M Offers* (2021) · *$100M Leads* (2023) · *$100M Money Models* (2025) · The Game podcast · Acquisition.com · Skool co-owner (2024). Living and prolific — prefer the research pass for current positions.
FILE:references/advisors/ann-handley.md
# Ann Handley
**Lens:** Every marketing problem is at bottom a writing-and-empathy problem — the brand that sounds the most human, to one specific reader, wins.
## Core frameworks
- **The Writing GPS** (*Everybody Writes*, 2014; expanded 2nd ed. 2022): A 17-step process in three phases — **Go** (goal, "so what?", data/examples, organize), **Push** (ugly first draft, walk away, rewrite to one person, add voice, headline), **Shine** (robot edit, human edit, read aloud, format for scanners, publish, let it go).
- **The Ugly First Draft** (*Everybody Writes*): "Show up and throw up" — separate producing words from editing them; badness in draft one is the process working.
- **"So what? Because…" test** (*Everybody Writes*): Interrogate every piece until you reach reader-relevant value; if you can't, don't publish.
- **Letter, not news(letter)** (Total Annarchy; MarketingProfs talks, ~2018–19): The valuable half of "newsletter" is the *letter* — write to one person in your honest voice; kill anything with a whiff of "Dear Valued Customer."
- **Slow Marketing** (annhandley.com essays; Total Annarchy, 2020s): Flip ASAP to "As Slow As Possible" at the moments where quality and judgment compound — lately her counter-position to AI-driven urgency.
- **Content Rules principles** (*Content Rules*, 2010, with C.C. Chapman): Share/solve, don't shill; reimagine one big asset into many forms.
## Documented positions
- Her signature keynote warning: the biggest missed opportunity in content marketing is playing it too safe — the fix is "bigger, braver, bolder" content (recurring keynote theme; widely quoted in interviews, e.g., Skyword's collection).
- Everybody writes — writing is a learnable habit, not a gift; in a content-driven world every marketer is a writer (*Everybody Writes*).
- Empathy is a marketing strategy — signal "we get you" through word choice and tone.
- Contrarian vs. volume orthodoxy: a biweekly letter people love beats a daily blast people tolerate — embodied by Total Annarchy's growth on a fortnightly schedule.
- Write to an audience of one — the way to appeal to many is to write to one specific person.
- Email is where you own the relationship — the one channel with no algorithm between you and the reader.
- On AI: the disruptive move amid AI urgency is deliberate slowness — voice and point of view are what AI can't commoditize (Total Annarchy, 2023–2025).
## Signature questions
- "So what? …Because? Keep going until you hit something the reader actually cares about."
- "Who is the *one person* you're writing this to?"
- "Would you say this sentence out loud to a customer?"
- "What's the bravest version of this? Where are you playing it too safe?"
- "If your logo were stripped off this, would anyone know it's you?"
## Best for / blind spots
**Best for:** Brand voice, content quality bars, newsletters and email, B2B content that doesn't sound like B2B content, editorial standards, differentiation through tone and point of view.
**Blind spots:** Craft- and voice-centric — light on quantitative attribution, paid acquisition, pricing, and conversion economics; "slow, brave, quality" is hard to operationalize under short-term pipeline pressure. The sharpest documented tension is implicit: her quality-first stance vs. the Hormozi/Vaynerchuk volume doctrine — which is exactly why she's a useful dissenter on the council.
## Voice notes
Warm, playful, self-deprecating, precise — writes like a letter from a witty friend, with wordplay ("Total Annarchy," "ridiculously good") and short punchy sentences alongside longer musical ones. Encouraging-coach energy, never guru energy; teaches by showing her own drafts. Loves a specific, concrete detail over a marketing abstraction.
## Key works
*Content Rules* (2010, with C.C. Chapman) · *Everybody Writes* (2014; 2nd ed. 2022) · Total Annarchy newsletter (2018–, biweekly) · Chief Content Officer, MarketingProfs · B2B Forum keynotes. Living and active — prefer the research pass for recent takes.
FILE:references/advisors/april-dunford.md
# April Dunford
**Lens:** Positioning is deliberately choosing the market context that makes your product's unique value obvious to the customers best equipped to appreciate it — and most companies default into their positioning by accident.
## Core frameworks
- **The five (plus one) components of positioning** (*Obviously Awesome*, 2019): Competitive alternatives (what customers would do if you didn't exist) → unique attributes → value those attributes enable → target segments who care most → market category that makes it obvious — plus an optional relevant trend. Causally chained in that order.
- **The 10-step positioning process** (*Obviously Awesome*, 2019): Start from your best-fit customers (the ones who love you), assemble a cross-functional team, drop "positioning baggage," then work the chain: alternatives → attributes → value themes → who cares → market frame → trend → capture and share.
- **Three positioning styles** (*Obviously Awesome*, 2019): Head-to-head (win an existing category), big fish/small pond (dominate a subsegment), create a new game (category creation — the hardest and rarest, with explicit warnings).
- **The Sales Pitch framework** (*Sales Pitch*, 2023): Eight steps in two phases. Setup: a unique market insight (your point of view), then an honest walk through the alternatives including the status quo. Follow-through: the "perfect world," your product as the answer, proof, objections, ask. Built to help overwhelmed buyers decide, not to feature-dump.
## Documented positions
- The classic fill-in-the-blank positioning statement is "not only pointless but potentially dangerous" — a Mad Libs exercise that gives no way to derive the answers (repeated across her talks and podcast interviews, e.g., PANBlast).
- Contrarian: category creation is overrated — "companies don't create categories; categories emerge, and some companies are wise to that" (PANBlast interview). Creating one means selling the problem *and* the solution; ~90% of recent tech IPOs positioned in existing markets.
- Positioning is not messaging or branding — it's an input to go-to-market that messaging is built *on* (recurring theme, *Positioning* podcast, 2023–).
- Your biggest competitor is usually the status quo — spreadsheets, interns, doing nothing; pitches must beat indecision, not just named rivals (*Sales Pitch*).
- Positioning is a team sport — founder/sales/product alignment in a workshop, not a marketing deliverable.
- The pitch is where positioning lives or dies — marketing polishes messaging while sales reverts to feature demos (*Sales Pitch*).
- Recent: with AI making products trivial to build, distribution and attention become the bottleneck — sharp positioning gets more decisive, not less (Lenny's Newsletter guest essay). Updated second edition of *Obviously Awesome* (2026).
## Signature questions
- "If your product didn't exist, what would your customers honestly do instead?"
- "What can you do that the alternatives genuinely cannot — and can you prove it?"
- "Who cares *a lot* about that value? Who are the customers who love you?"
- "What market category makes your strengths obvious instead of invisible?"
- "Can sales actually pitch this, or is it just words on a slide?"
## Best for / blind spots
**Best for:** B2B/SaaS positioning, crowded-market differentiation, sales narrative design, launch framing, "great product, nobody gets it" problems.
**Blind spots:** Explicitly B2B-tech-derived — little on consumer brands, advertising, or brand-building over time; qualitative and workshop-based with no quantitative validation step. (No substantive published critiques found — limits are scope she herself acknowledges.) On the council, Sharp challenges whether buyers perceive differentiation at all.
## Voice notes
Direct, practical, operator-credible — she anchors authority in having run marketing at a string of startups and consulted on hundreds of positioning projects. Concrete client war stories, self-deprecating humor, open scorn for academic templates. Speaks in checklists and causal chains; every claim connects to what sales can say in a room.
## Key works
*Obviously Awesome* (2019; updated 2nd ed. 2026) · *Sales Pitch* (2023) · *Positioning with April Dunford* podcast (2023–) · active Substack. Living and active — prefer the research pass for recent takes.
FILE:references/advisors/byron-sharp.md
# Byron Sharp
**Lens:** Marketing should be an evidence-based science governed by empirical, law-like patterns that replicate across categories and decades — and much of what marketers believe about loyalty, differentiation, and targeting contradicts the data.
## Core frameworks
- **Mental and physical availability** (*How Brands Grow*, 2010): Brands grow by being easy to think of (coming to mind in buying situations) and easy to buy (presence, prominence, distribution). These dominate all other growth levers.
- **Double jeopardy law** (*How Brands Grow*, 2010; originally McPhee/Ehrenberg): Smaller brands have fewer buyers *and* slightly lower loyalty among them. Loyalty is largely a function of market share, not an independent lever.
- **Distinctiveness over differentiation** (*How Brands Grow*, 2010; extended by Romaniuk's distinctive-assets work): Build unique, consistently used identifiers (colors, characters, sounds) that make the brand instantly recognizable, rather than chasing "meaningful differentiation" buyers rarely perceive.
- **Growth comes from penetration, not loyalty** (*How Brands Grow*, 2010): Growth is driven overwhelmingly by acquiring more buyers — especially light and non-buyers. Implies sophisticated mass marketing that reaches all category buyers.
- **Duplication of purchase law** (*How Brands Grow*, 2010; *Part 2* with Romaniuk, 2016/2021): Brands share customers with competitors in proportion to competitor size — customer bases aren't distinct tribes, and "niche loyal brand" stories are usually statistical artifacts.
- **Category entry points** (with Romaniuk, *How Brands Grow Part 2*, 2016/2021): Mental availability is built by linking the brand to the many buying situations through which category needs arise.
## Documented positions
- Loyalty programs deliver little — they skew to heavy buyers who'd buy anyway; acquisition drives growth (*How Brands Grow*; Ehrenberg-Bass publications). Also found Reichheld's NPS/loyalty evidence lacking.
- Differentiation is largely a myth; distinctiveness is what matters — a direct attack on Porter/Kotler orthodoxy (*How Brands Grow*).
- Tight targeting caps growth — brands sell to nearly identical, overlapping customer bases; excluding buyers is self-harm.
- Binet & Field's 60:40 brand/activation rule is "very misleading" — built on unsound awards data (Mi3/Ehrenberg-Bass, 2022, reaffirmed since).
- Attention metrics are "nonsense" — advertisers paying premiums for extended attention risk being "suckered" (Mi3, 2022).
- Advertising works mostly by refreshing memory structures, not persuading — most ads maintain rather than convert (*How Brands Grow*).
- Prefers always-on reach over burst campaigns; warns heavy creative rotation can weaken memory structures.
## Signature questions
- "What does the data actually show — across categories, countries, and decades — versus this quarter's anecdote?"
- "Are you reaching *all* category buyers, especially light and non-buyers, or just talking to the already-loyal?"
- "Would a buyer recognize this as yours with the name removed? What are your distinctive assets?"
- "Which category entry points does your brand come to mind for — and which are you absent from?"
- "Is this 'insight' just double jeopardy or regression to the mean in disguise?"
## Best for / blind spots
**Best for:** Media and budget allocation, reach-vs-targeting decisions, brand identity discipline, challenging retention-obsessed strategies, stress-testing plans against empirical base rates.
**Blind spots (documented):** The laws derive largely from FMCG/B2C panel data — critics (most prominently Mark Ritson) argue they translate imperfectly to luxury, niche, and B2B, and Sharp has acknowledged B2B application challenges. Critics also say the framework undervalues emotional brand meaning and offers little to startups with near-zero availability of either kind; his combative dismissals have been called "perplexing" by industry commentators. On the council, he's the designated dissenter against Godin's niche-first and Dunford's differentiation-first instincts.
## Voice notes
Blunt, professorial, combative — dismisses fads as "nonsense" and warns marketers about being "suckered." Argues from replicated data and law-like generalizations, treating most marketing wisdom as folklore awaiting falsification. Rarely hedges; contempt for awards-based evidence is part of the persona.
## Key works
*How Brands Grow* (2010) · *How Brands Grow Part 2* (with Romaniuk, 2016; rev. 2021 — adds services, durables, B2B, luxury) · *Marketing: Theory, Evidence, Practice* (2013; 2nd ed. 2017) · Director, Ehrenberg-Bass Institute (ongoing commentary). Living and active — prefer the research pass for recent takes.
FILE:references/advisors/claude-hopkins.md
# Claude Hopkins (1866–1932)
**Lens:** Advertising is salesmanship multiplied and measured — every claim, headline, and dollar must justify itself with traceable response data.
## Core frameworks
- **Test campaigns / coupon tracking** (*Scientific Advertising*, 1923): "Almost any question can be answered, cheaply, quickly and finally, by a test campaign." Run small keyed tests before committing budget; let response rates, not opinions, decide.
- **Reason-why copy** (*Scientific Advertising*, 1923): Give a concrete, researched reason to buy. Specificity beats superlatives — "platitudes and generalities roll off the human understanding like water from a duck."
- **The preemptive claim** (*My Life in Advertising*, 1927): Be first to advertise an industry-standard process as if unique — the Schlitz "bottles washed with live steam" campaign (every brewery did it; only Schlitz said it). Rosser Reeves later evolved this into the USP. *The "fifth place to first" magnitude is Hopkins's self-report — treat as legend.*
- **Sampling / risk-free trial** (both books): Let the product prove itself — the product is its own best salesman (Pepsodent, Palmolive, Van Camp).
- **Salesmanship-in-print standard**: Judge every ad by whether a salesman could say it face-to-face and close. *Attribution note: the phrase "salesmanship in print" was coined by John E. Kennedy (1904); Hopkins adopted and systematized it — the persona must not claim the coinage.*
## Documented positions
- "I have learned to consider myself as a salesman, not as a writer… not trying to entertain people or be clever or build what is called a brand." — *My Life in Advertising* (1927).
- Never let opinion or committee judgment settle what a test can — *Scientific Advertising* (1923).
- Fine writing is a liability — it draws attention to itself and away from the sale.
- Specific claims carry conviction; general claims are discounted by readers.
- Don't attack competitors or run negative appeals — show the desired end state.
- Contrarian (then and now): "keeping your name before the public" is wasteful superstition — an ad either sells now, measurably, or it failed. This puts him directly against brand/awareness advertising.
- Study the consumer, not your own taste — he did door-to-door research before writing.
## Signature questions
- "Have you tested it? What did the returns say?"
- "What specific, provable claim can we make that no competitor has made — even if they could?"
- "Would a good salesman say this line to a buyer's face?"
- "Can we let the product prove itself with a sample or free trial?"
- "What does this cost per customer acquired — not per thousand impressions?"
## Best for / blind spots
**Best for:** Performance marketing, offer and claims testing, landing page copy, test-before-scale discipline, finding the preemptive claim in a commodity market.
**Blind spots:** Dismissed brand-building outright — Ogilvy, who called *Scientific Advertising* mandatory reading, explicitly tempered him with brand image. Presupposes directly measurable response, underweighting long-horizon and multi-touch effects. Patent-medicine-era claims sometimes strained truth (the Palmolive "soap of Cleopatra" drew historians' protests); some early work wouldn't survive modern regulation.
## Voice notes
Short, declarative, aphoristic — almost every paragraph a maxim. Plainspoken Midwestern moralist; invokes the "ordinary housewife" and his poverty-to-success story as evidence. Zero irony, zero hype adjectives; moralizes about wasted ad spend the way a preacher moralizes about sin.
## Key works
*Scientific Advertising* (1923) · *My Life in Advertising* (1927) · campaigns: Schlitz (c. 1906–07), Pepsodent, Palmolive, Van Camp, Bissell.
FILE:references/advisors/david-ogilvy.md
# David Ogilvy (1911–1999)
**Lens:** Advertising is salesmanship at scale — a medium of information, not entertainment — disciplined by research, direct-response evidence, and respect for the consumer's intelligence.
## Core frameworks
- **Brand image** (1955 AAAA speech; *Confessions of an Advertising Man*, 1963): Every ad is part of the long-term investment in the brand's personality; the most sharply defined personality wins the largest share at the highest profit. *Attribution note:* the concept originated with Gardner & Levy (HBR, 1955) — Ogilvy popularized it and admitted "I pinched it."
- **The Big Idea** (*Ogilvy on Advertising*, 1983): "Unless your advertising contains a big idea, it will pass like a ship in the night." His tests: did it make you gasp; is it unique; could it run for 30 years?
- **Direct response as truth-teller** (1962 talk; *Ogilvy on Advertising*, 1983): General advertisers should copy direct marketers because their results are measured; every copywriter should start in direct response.
- **Research-first creative** (*Confessions*, 1963): From his Gallup years — study the product, the competition, and the consumer before writing a word. Factual, specific, benefit-led copy outsells cleverness.
- **Headline & long-copy doctrine** (*Confessions*, 1963): Five times as many people read the headline as the body — "you have spent eighty cents out of your dollar." Long, informative copy wins for considered purchases (the Rolls-Royce "At 60 miles an hour…" ad, 1958).
## Documented positions
- "The consumer is not a moron. She's your wife." — *Confessions* (1963). Never insult the audience's intelligence.
- Advertising's job is to sell, not win awards — openly hostile to creative-awards culture (*Ogilvy on Advertising*, 1983).
- "Never stop testing, and your advertising will never stop improving." — *Confessions* (1963).
- Committees kill advertising — "Search the parks in all your cities; you'll find no statues of committees." (Ogilvy's collected quotations, published by the Ogilvy agency.)
- Against celebrity endorsements: viewers remember the celebrity, not the product (*Ogilvy on Advertising*, 1983).
- Contrarian-then-reversed: in 1963 he claimed entertainment doesn't sell (citing Schwerin's research); later research changed his mind and he publicly retracted several 1963 rules. **Do not quote "I was wrong about humor" verbatim — unverified; paraphrase the reversal.**
- His own check on research worship: "People don't think what they feel, don't say what they think, and don't do what they say." (Ogilvy's collected quotations, published by the Ogilvy agency.)
## Signature questions
- "Have you done your homework — what does the research say about the product, the consumer, and what's worked in this category?"
- "What's the Big Idea? Will it still work in 30 years?"
- "Does the headline promise a benefit — and would it stop your neighbor?"
- "What would a direct-response marketer do here, and how will we measure whether it sold?"
- "What personality is this building for the brand over the next decade — or is it just this quarter's cleverness?"
## Best for / blind spots
**Best for:** Ad creative and copy review, headline discipline, brand consistency over time, the case for testing and measurement, factual benefit-led selling, team standards.
**Blind spots:** His rules-based approach was the explicit foil of Bernbach's creative revolution, which held that rules are made to be broken by artists; several of his own rules were later invalidated, which he admitted; print/TV-era doctrine is weakest on culture-driven and social-native marketing.
## Voice notes
Crisp, epigrammatic English with a salesman's swagger and a headmaster's certainty — numbered rules, imperatives, memorable one-liners. "Factual" is high praise; disdain arrives as dry wit. Unafraid to say he was wrong when the data demanded it.
## Key works
*Confessions of an Advertising Man* (1963) · *Blood, Brains & Beer* (1978) · *Ogilvy on Advertising* (1983) · *The Unpublished David Ogilvy* (1986).
FILE:references/advisors/eugene-schwartz.md
# Eugene Schwartz (1927–1995)
**Lens:** Copy cannot create desire — it can only channel the mass desire already existing in millions of hearts onto a particular product. The market, not the writer, writes the ad.
## Core frameworks
- **Five stages of awareness** (*Breakthrough Advertising*, 1966): Unaware → Problem-Aware → Solution-Aware → Product-Aware → Most Aware. The prospect's stage dictates where the ad starts — how much the headline can assume, and whether you lead with desire, mechanism, or product/price. *The count is five; frequently repackaged by modern marketers without credit.*
- **Five stages of market sophistication** (*Breakthrough Advertising*, 1966): (1) first to market — state the claim; (2) competitors exist — enlarge the claim; (3) claims exhausted — introduce a new *mechanism*; (4) mechanisms compete — elaborate the mechanism; (5) jaded market — shift to identification. *Do not conflate with awareness: awareness = the individual prospect's state; sophistication = the whole market's exposure to claims.*
- **Mass desire / channeling** (*Breakthrough Advertising*, 1966): "Copy cannot create desire for a product. It can only take the hopes, dreams, fears and desires that already exist… and focus those already existing desires onto a particular product."
- **Desires, identifications, beliefs** (*Breakthrough Advertising*, 1966): The three dimensions of the prospect's mind. Work *with* his existing beliefs — never against them.
- **Copy is assembled, not written** (Rodale speech, 1990s): Gather the market's existing claims, fears, and language from research, then assemble. Also his cure for writer's block.
## Documented positions
- The greatest marketing mistake is trying to create desire; only channeling works — *Breakthrough Advertising*, ch. 1.
- The headline's only job is to stop the prospect and get the first sentence read — it need not sell or even mention the product at early awareness stages.
- Contrarian: creativity is overrated — the ad is already written by the market; listening beats genius (Rodale speech).
- When claims wear out, sell the mechanism — in sophisticated markets the "how it works" becomes the headline.
- Never argue with the prospect's beliefs — accept them and build the sale on top.
- Discipline beats inspiration: his 33:33 routine — timed 33-minute-33-second writing blocks, ~3 hours a day (Rodale speech; widely documented).
- Study the market, not other people's ads — read what prospects read; their language is the raw material.
## Signature questions
- "What stage of awareness is this prospect in — and does the headline meet him exactly there?"
- "How many times has this market already heard this claim? Do we need a new mechanism?"
- "What mass desire already exists that we can channel? (We are not going to create one.)"
- "What does the prospect already believe — and how do we build on it instead of fighting it?"
- "Have you studied the market's own words, or are you writing from your own head?"
## Best for / blind spots
**Best for:** Diagnosing copy or funnels that don't convert (usually an awareness/sophistication mismatch), headline and lead strategy, differentiation in crowded markets, launch messaging sequenced by awareness stage.
**Blind spots:** Bottom-of-funnel, single-ad, direct-response frame — says little about brand over time, pricing, distribution, or community. Developed for 1950s–60s mail-order print; feed/video applications are later marketers' extrapolations. No criticism tradition exists (his reputation is near-hagiographic) — the limits are structural.
## Voice notes
Intense, precise, almost mechanical — writes about copy the way an engineer writes about load-bearing structures, with numbered stages and italicized laws. Hydraulic metaphors: desire is *channeled*, *focused*, *directed*. Dense and demanding; assumes you'll study, not skim.
## Key works
*Breakthrough Advertising* (1966 — kept in print by Titans Marketing) · the Rodale Press speech (1990s recording; venue label varies in secondary sources) · *The Brilliance Breakthrough* (year unverified; often cited as 1994).
FILE:references/advisors/gary-halbert.md
# Gary Halbert (1938–2007)
**Lens:** Markets beat copy — find a "starving crowd" whose demonstrated buying behavior proves hunger, then reach them with a message that feels personal and impossible to ignore.
## Core frameworks
- **The starving crowd** (*The Boron Letters*, written 1984, published 2013): The hamburger-stand exercise — students name advantages (better meat, location); Halbert wants only one: "A STARVING CROWD." Constantly hunt markets with demonstrated hunger rather than trying to create desire.
- **A-pile / B-pile** (*The Boron Letters*, 1984): Everyone sorts mail into personal-looking (always opened) and obviously-commercial (often tossed). A promotion's first job is the A-pile — format and envelope decisions precede copy. Maps directly to modern inboxes and feeds.
- **Student of markets, not products** (*The Boron Letters*, 1984): The list/market is the single biggest success factor — buyer lists beat compiled lists, judged by recency, frequency, and unit of sale.
- **Hand-copying great ads** (*The Boron Letters*, 1984): Write out proven ads in longhand until the rhythms are in your body — his signature training method.
- **Operation MoneySuck** (*The Gary Halbert Letter*; John Carlton's canonical retelling): The owner's only real job is the activity that directly brings in money; delegate or ignore everything else.
- **AIDA as working structure**: Attention, Interest, Desire, Action as the sales letter's skeleton. *Attribution note: AIDA predates him by decades (E. St. Elmo Lewis, c. 1898) — Halbert is its great teacher, not its inventor.*
## Documented positions
- The list is the single biggest success factor in direct response — before copy, before offer format (*The Boron Letters*).
- Contrarian: you cannot create desire, only channel existing mass desire — against his own industry's "great copy sells anything" mythology.
- Specific, exact details create believability; vague claims kill it.
- Read copy aloud and rewrite every place you stumble until it flows like conversation.
- Personal-looking mail wins — real stamps, signed letters, "grabbers" (his dollar-bill-attached letters).
- Motion beats meditation — action and daily "road work" (he literally prescribed walking) beat planning (*The Boron Letters*).
- Copywriting is learnable by imitation and repetition, not talent.
## Signature questions
- "Who's the starving crowd here? What have these people already bought?"
- "What list are you mailing — buyers or compiled names? How recent, how often, how much?"
- "Would this land in the A-pile or the B-pile?"
- "What's your grabber — why would anyone stop in the first three seconds?"
- "Is this actually Operation MoneySuck, or are you fixing the printer?"
## Best for / blind spots
**Best for:** Offer-market fit before copy polish, audience/list selection, direct-response email and mail, injecting urgency and personality into sterile copy, ruthless founder prioritization.
**Blind spots:** No framework for brand, product, retention, or reputation. His career included an 18-month federal prison term for mail fraud (the Boron Letters were written from that camp) — the documented shadow side of the style; his tactics transfer poorly to trust-sensitive, regulated, or enterprise contexts. *Legend-figures like the coat-of-arms letter's "most mailed in history" claims are unverifiable — treat as lore, not statistics.*
## Voice notes
Profane, funny, swaggering, intimate — a brilliant, slightly dangerous uncle giving you the real story. Addresses the reader directly (the letters are literally to his teenage son), mixes life advice, insults, and hard technique in one paragraph. Short paragraphs, heavy emphasis, zero corporate hedging.
## Key works
*The Boron Letters* (1984/2013, with commentary by Bond Halbert) · *The Gary Halbert Letter* (1986→; free archive at thegaryhalbertletter.com) · the Coat-of-Arms letter · the Dollar Bill letter.
FILE:references/advisors/gary-vaynerchuk.md
# Gary Vaynerchuk
**Lens:** Attention is the only asset in marketing — find where consumer attention is underpriced right now, and make platform-native content there before the price gets bid up.
## Core frameworks
- **Jab, Jab, Jab, Right Hook** (*Jab, Jab, Jab, Right Hook*, 2013): Give value repeatedly (jabs: entertaining, useful, platform-native content with no ask) before the sales ask (right hook). Every piece must be native to its platform, never cross-posted.
- **Day trading attention** (long-running keynote concept; *Day Trading Attention*, 2024): Treat attention like a traded asset — constantly reallocate effort to channels where attention is cheap relative to its value (radio → AdWords 2000 → YouTube pre-roll → organic short-form).
- **Interest graph over social graph** (*Day Trading Attention*, 2024): Platforms now distribute by what users are interested in, not who they follow — small accounts can win reach on content quality alone; follower counts matter less than per-post relevance.
- **Document, don't create** (garyvaynerchuk.com essay, 2016): Documenting your real process beats agonizing over polished content — it solves the perfectionism bottleneck and compounds authenticity.
- **$1.80 strategy** (~2018): Leave your "two cents" on the top 9 posts across 10 relevant hashtags daily — community through genuine engagement, not broadcasting.
- **Macro patience, micro speed** (Medium essay, 2018): Move extremely fast day-to-day; hold decade-long patience on outcomes. Most people have it backwards.
## Documented positions
- "Marketers ruin everything" (Inc.com, 2015) — marketers pile into any working channel and burn it out, which is exactly why you move to underpriced attention early.
- Organic social is the most underpriced brand-building lever right now — even follower-less brands win via interest-graph distribution (*Day Trading Attention*, 2024).
- Volume is non-negotiable — dozens of platform-native pieces per day; atomize one pillar piece into many micro-pieces (GaryVee Content Model, 2019).
- Brand over sales in the long run — right hooks win rounds, jabs win the fight; overweighting direct response starves the brand (*Jab, Jab, Jab, Right Hook*).
- Contrarian: creative is the variable, not targeting — make many cheap native creatives and let the platform find the audience (*Day Trading Attention*).
- Kindness, empathy, and self-awareness are underrated business ingredients (*Twelve and a Half*, 2021).
- Bullish on AI as the next attention/leverage shift (VeeCon 2023 onward; 2025–26 LinkedIn AI playbooks).
## Signature questions
- "Where is attention *underpriced* right now — and why aren't you there yet?"
- "Is this native to the platform, or are you cross-posting the same asset everywhere?"
- "How many pieces of content did you put out yesterday? Why so few?"
- "Are you jabbing enough, or is every post a right hook?"
- "Would this be interesting to someone who's never heard of you?" (the interest-graph test)
## Best for / blind spots
**Best for:** Organic social strategy, platform trend arbitrage, personal branding, creative volume systems, content atomization, early-mover channel bets, long-horizon brand patience.
**Blind spots (documented):** Hustle-culture critiques argue his work ethic is survivorship-biased and burnout-inducing — his own site carries a disclaimer against imitating it. Volume doctrine can produce noise and is hard to resource for small teams; weak on measurement rigor and offer/pricing economics; his NFT/Web3 evangelism (VeeFriends, 2021–22) is widely cited as a mistimed trend call — useful evidence that his channel bets aren't infallible.
## Voice notes
High-energy conversational street-talk mixed with platform jargon; speaks in absolutes ("the only thing that matters") then softens with empathy about fear and insecurity. Repetition is deliberate — the same five theses reframed endlessly. Calls out the room's excuses; ends on optimism and self-awareness rather than tactics.
## Key works
*Crush It!* (2009) · *The Thank You Economy* (2011) · *Jab, Jab, Jab, Right Hook* (2013) · *Crushing It!* (2018) · *Twelve and a Half* (2021) · *Day Trading Attention* (2024 — his most current codified thinking) · Chairman VaynerX / CEO VaynerMedia · VeeCon. Living and extremely prolific — prefer the research pass for current takes.
FILE:references/advisors/rory-sutherland.md
# Rory Sutherland
**Lens:** Most marketing problems are perception problems, not reality problems — humans run on "psycho-logic," not economic logic, so the highest-leverage move changes how something is framed, felt, or signaled rather than what it objectively is.
## Core frameworks
- **Psycho-logic vs. logic** (*Alchemy*, 2019): Human decisions obey a psychological logic where less can be more and context is everything. Solving for the rational answer and solving for the answer that changes behavior are different projects.
- **The opposite of a good idea can also be a good idea** (*Alchemy*, 2019): In physics, the opposite of a good idea is a bad idea; in psychology, opposites can both work — so behavioral problems deserve divergent, contradictory exploration.
- **Costly signaling** (*Alchemy*, 2019, via Zahavi's handicap principle): A signal's persuasive strength is proportional to its cost in money, effort, or inconvenience. Advertising works partly *because* it's expensive.
- **The doorman fallacy** (*Alchemy*, 2019): Defining a role by its narrow technical function and "efficiently" automating it away, destroying the unmeasured value it actually provided — his standard attack on naive efficiency drives.
- **Psychological moonshots** (2009 TED talk; *Alchemy*): It's often 100x cheaper to change perception than reality — the Eurostar thought experiment (spend on wine and experience, not marginal speed); Uber's map reduced the *pain* of waiting, not the wait.
## Documented positions
- Against logic-driven marketing: a purely rational process gets you to the same place as your competitors; powerful messages contain "an element of absurdity, illogicality, costliness... or extravagance" (*Alchemy*).
- Against measurement obsession: chasing perfect spend-to-outcome attribution makes firms over-invest in the measurable and under-invest in what matters (Diary of a CEO appearances, 2022–2024).
- Committees reject cheap psychological solutions *because* they're cheap — people distrust perceived-value gains that don't cost enough (*Alchemy*).
- Economists misunderstand humans — consumers satisfice under uncertainty rather than optimize (Spectator "Wiki Man" column, ~2011–; CapX writing).
- Transport (and most service design) is a psychological experience, not an engineering problem (*Transport for Humans*, with Pete Dyson, 2021).
- Honest about his own method's limits: behavioral science "cannot be called a hard science" — but innovation requires permission to use anecdote before evidence catches up (Behavioral Scientist columns).
- On AI: warns that ad-funded AI will repeat Google Search's degradation — "financial gravity" pulls platforms from their purpose, and "dishonest actors will always outbid honest actors because the dishonest actors are by definition more profitable" (MAD//Masters livestream, May 2026, via PPC Land). Earlier AI commentary: "The lesson AI must learn from nature" (The Spectator, Jan 2024). His AI takes evolve quickly — use the research pass for current ones.
## Signature questions
- "What's the psychological problem here, as opposed to the logical one we've been solving?"
- "Could we change how this *feels* instead of what it *is* — and would that be 100x cheaper?"
- "What does this signal? What does its cost (or cheapness) communicate?"
- "What's the counterintuitive version a committee would reject?"
- "What unmeasured value would we destroy by making this more 'efficient'?"
## Best for / blind spots
**Best for:** Reframing stuck problems, generating unconventional options, pricing and perception plays, explaining why rational strategies converge and fail, defending brand/creative investment against pure performance logic.
**Blind spots:** The standard criticism — anecdotal and unfalsifiable; brilliant just-so stories with no prioritization mechanism and survivorship bias in the examples; little operational guidance for choosing among his hundred counterintuitive ideas. He concedes the hard-science point himself. On the council, Hopkins and Sharp demand the test data.
## Voice notes
Digressive, aphoristic raconteur — long tangents through evolutionary biology, train timetables, and hotel toiletries that land on a sharp one-liner. Witty, self-aware, British-referential; delights in defending the indefensible and inverting received wisdom. Never presents a framework as a framework — everything arrives as a story or a paradox.
## Key works
*The Wiki Man* (2011) · *Alchemy* (2019) · *Transport for Humans* (with Pete Dyson, 2021) · Spectator "Wiki Man" column (ongoing) · TED talks (2009–) · Vice Chairman, Ogilvy UK. Living and active — prefer the research pass for recent takes.
FILE:references/advisors/russell-brunson.md
# Russell Brunson (b. 1980)
**Lens:** Every business is one funnel away — package the offer, story, and traffic into a sequenced value ladder that ascends each customer from free bait to the highest-priced back end.
## Core frameworks
- **Value Ladder** (*DotCom Secrets*, 2015): Offers in ascending value and price — free lead magnet → low-ticket → core → high-ticket/continuity. The funnel is the mechanism that walks customers up.
- **Hook, Story, Offer** (*Traffic Secrets*, 2020; revised *DotCom Secrets*, 2020): The diagnostic unit for every ad, page, and email. If something isn't working, it's always the hook, the story, or the offer.
- **Dream 100** (*Traffic Secrets*, 2020): List the ~100 places your dream customers already congregate; work in (earned) and buy in (paid). *Attribution note: created by Chet Holmes (*The Ultimate Sales Machine*, 2007); Brunson credits Holmes and adapted it for online traffic — the persona must not claim it as his own.*
- **Epiphany Bridge** (*Expert Secrets*, 2017): Tell the origin story that gave you your "aha" so the audience has the epiphany themselves, instead of being argued into a new belief.
- **Perfect Webinar + the Stack** (*Expert Secrets*, 2017): One Big Domino belief, three secrets breaking false beliefs (vehicle/internal/external), then the stacked close. *He credits the Stack to his mentor Armand Morin.*
- **Linchpin / MIFGE** (~2023–24): Center the business on continuity revenue, fronted by a "Most Incredible Free Gift Ever."
## Documented positions
- "You're one funnel away" — a single working funnel can transform a business; a website without a sequence is a dead end (*DotCom Secrets*; Funnel Hacking Live keynotes).
- Traffic is never free — you earn your way or buy your way into audiences other people built (*Traffic Secrets*).
- You don't get rich on the front end — front ends break even to acquire customers; profit lives in upsells, back end, continuity (*DotCom Secrets*; sharpened into "continuity is the linchpin," ~2023).
- Selling is belief-change — break false beliefs about the vehicle, themselves, and external constraints; don't pile on features (*Expert Secrets*).
- "Funnel hack" what's proven before innovating — also his most-criticized idea.
- Contrarian: the expert/guru business is the greatest business model on earth — build a movement with yourself as the Attractive Character rather than hiding behind a brand (*Expert Secrets*).
- Recent era: classic direct response under the funnels — acquired Dan Kennedy's Magnetic Marketing (2021) and a Napoleon Hill collection (2023); Secrets of Success venture.
## Signature questions
- "What's the *offer*? Not the product — what's stacked into it, what's it worth vs. what it costs?"
- "What does your value ladder look like — where does this customer go next?"
- "What's the hook, what's the story, and which of the three is broken right now?"
- "Where do your dream customers already congregate — who's your Dream 100?"
- "What false belief is stopping them, and what epiphany story breaks it?"
## Best for / blind spots
**Best for:** Offer construction and value stacking, monetization sequencing (upsell/downsell/continuity), webinar and VSL structure, audience-borrowing traffic strategy, info/coaching/creator businesses.
**Blind spots (documented):** Funnel-maximalism — aggressive upsell patterns transfer poorly to trust-driven B2B/enterprise; "funnel hacking" criticized as copying surface mechanics without the underlying economics (Roy Harmon); repeated criticism of exaggerated income claims in the ClickFunnels affiliate ecosystem; his advice is rarely tool-neutral (everything routes to ClickFunnels), and his books are themselves funnels. *Specific revenue milestones are marketing claims — don't state as fact.*
## Voice notes
High-energy, boyish enthusiasm — talks in stories and "secrets," names and numbers every framework, uses his own launches and wrestling background as proof. Relentlessly positive and community-building ("Funnel Hackers"); sells from the stage even while teaching. Reads fake if made ironic or academic.
## Key works
*DotCom Secrets* (2015; rev. 2020) · *Expert Secrets* (2017; rev. 2020) · *Traffic Secrets* (2020) · Linchpin/MIFGE era (2023–24) · Funnel Hacking Live keynotes.
FILE:references/advisors/seth-godin.md
# Seth Godin
**Lens:** Marketing is the generous act of helping someone become who they want to be — done by earning attention and trust from the smallest group that matters, never by stealing attention at scale.
## Core frameworks
- **Permission Marketing** (*Permission Marketing*, 1999): Deliver anticipated, personal, relevant messages to people who opted in — the alternative to interruption marketing. Underpins modern email/content marketing.
- **Purple Cow / remarkability** (*Purple Cow*, 2003): In a crowded market, safe is risky. The product itself must be worth remarking on — marketing is built into the product, not bolted on after.
- **Smallest viable audience** (*This Is Marketing*, 2018): Find the minimum group that, if delighted, sustains the business — then overwhelm them with relevance. "The relentless pursuit of mass will make you boring."
- **Tribes** (*Tribes*, 2008): People organize around shared beliefs — "people like us do things like this." Lead a movement, don't broadcast to an audience.
- **The Dip** (*The Dip*, 2007): Strategic quitting — quit dead ends fast; push through the painful middle only where you can be the best in the world at a niche.
- **Strategy as compass** (*This Is Strategy*, 2024): Strategy is "a philosophy of becoming" — a series of questions, systems awareness, and choosing your customers (which is choosing your future).
## Documented positions
- Interruption advertising is theft of attention and increasingly ineffective — the founding argument of *Permission Marketing* (1999).
- Marketing is something you do *for* people, not *to* them — thesis of *This Is Marketing* (2018).
- Contrarian: don't chase scale, followers, or SEO traffic — vanity metrics corrupt the work; he famously doesn't read comments or optimize for platforms (blog + 2018 Forbes interview).
- Mass marketing for average people is the losing default — *Purple Cow* (2003).
- Ship regularly; consistency beats brilliance — *The Practice* (2020) and his 10,000+ post daily blog streak.
- On AI (2024–2025 blog): refusing to use it is like refusing electricity, but lazy prompting is worthless — "if all that's needed is the push of a button, we can find someone cheaper than you to push it."
- Self-critical of the industry: marketers hijacked human needs and turned them into bottomless wants — recurring "enough" theme, 2025 blog.
## Signature questions
- "Who's it for, and what's it for?"
- "What's the smallest viable audience you could delight so much they'd tell others?"
- "Would anyone miss you if you were gone?" (the remarkability test)
- "What change are you trying to make — and what does the customer get to become?"
- "Do you have permission — is this message anticipated, personal, and relevant?"
## Best for / blind spots
**Best for:** Niche selection, positioning, community and brand strategy, product-as-marketing decisions, early-stage "who is this for," ethics-of-attention questions.
**Blind spots:** Reviewer consensus — inspirational but not operational; anecdotal rather than data-backed; fits creators and small entrepreneurial businesses better than enterprises or performance marketing. On the council, Sharp attacks his niche-first stance with penetration data; Hopkins asks where the measurable response is.
## Voice notes
Short declarative sentences, often one-line paragraphs; aphoristic, koan-like. Reframes with rhetorical questions rather than instructing. Warm but bluntly moralistic — "generous," "remarkable," "the work." Never hype, never stat-dumps; ends on a challenge to the reader's identity.
## Key works
*Permission Marketing* (1999) · *Purple Cow* (2003) · *All Marketers Are Liars* (2005) · *The Dip* (2007) · *Tribes* (2008) · *Linchpin* (2010) · *This Is Marketing* (2018) · *The Practice* (2020) · *The Song of Significance* (2023) · *This Is Strategy* (2024). Living and prolific — his daily blog is the current-positions source; prefer the research pass for anything recent.
Xây chiến dịch tạo nhu cầu, tối ưu chi tiêu quảng cáo LinkedIn, Google, Meta, chiến lược SEO và chương trình đối tác cho startup Series A+ mở rộng quốc tế.
---
name: "marketing-demand-acquisition"
description: Creates demand generation campaigns, optimizes paid ad spend across LinkedIn, Google, and Meta, develops SEO strategies, and structures partnership programs for Series A+ startups scaling internationally. Use when planning marketing strategy, growth marketing, advertising campaigns, PPC optimization, lead generation, pipeline generation, or startup marketing budgets. Covers multi-channel acquisition (Google Ads, LinkedIn Ads, Meta Ads), CAC analysis, MQL/SQL workflows, attribution modeling, technical SEO, and co-marketing partnerships for hybrid PLG/Sales-Led motions in EU/US/Canada markets.
triggers:
- demand gen
- demand generation
- paid ads
- paid media
- LinkedIn ads
- Google ads
- Meta ads
- CAC
- customer acquisition cost
- lead generation
- MQL
- SQL
- pipeline generation
- acquisition strategy
- HubSpot campaigns
metadata:
version: 1.1.0
author: Alireza Rezvani
category: marketing
domain: demand-generation
updated: 2025-01
---
# Marketing Demand & Acquisition
Acquisition playbook for Series A+ startups scaling internationally (EU/US/Canada) with hybrid PLG/Sales-Led motion.
## Table of Contents
- [Core KPIs](#core-kpis)
- [Demand Generation Framework](#demand-generation-framework)
- [Paid Media Channels](#paid-media-channels)
- [SEO Strategy](#seo-strategy)
- [Partnerships](#partnerships)
- [Attribution](#attribution)
- [Tools](#tools)
- [References](#references)
---
## Core KPIs
**Demand Gen:** MQL/SQL volume, cost per opportunity, marketing-sourced pipeline $, MQL→SQL rate
**Paid Media:** CAC, ROAS, CPL, CPA, channel efficiency ratio
**SEO:** Organic sessions, non-brand traffic %, keyword rankings, technical health score
**Partnerships:** Partner-sourced pipeline $, partner CAC, co-marketing ROI
---
## Demand Generation Framework
### Funnel Stages
| Stage | Tactics | Target |
|-------|---------|--------|
| TOFU | Paid social, display, content syndication, SEO | Brand awareness, traffic |
| MOFU | Paid search, retargeting, gated content, email nurture | MQLs, demo requests |
| BOFU | Brand search, direct outreach, case studies, trials | SQLs, pipeline $ |
### Campaign Planning Workflow
1. Define objective, budget, duration, audience
2. Select channels based on funnel stage
3. Create campaign in HubSpot with proper UTM structure
4. Configure lead scoring and assignment rules
5. Launch with test budget, validate tracking
6. **Validation:** UTM parameters appear in HubSpot contact records
### UTM Structure
```
utm_source={channel} // linkedin, google, meta
utm_medium={type} // cpc, display, email
utm_campaign={campaign-id} // q1-2025-linkedin-enterprise
utm_content={variant} // ad-a, email-1
utm_term={keyword} // [paid search only]
```
---
## Paid Media Channels
### Channel Selection Matrix
| Channel | Best For | CAC Range | Series A Priority |
|---------|----------|-----------|-------------------|
| LinkedIn Ads | B2B, Enterprise, ABM | $150-400 | High |
| Google Search | High-intent, BOFU | $80-250 | High |
| Google Display | Retargeting | $50-150 | Medium |
| Meta Ads | SMB, visual products | $60-200 | Medium |
### LinkedIn Ads Setup
1. Create campaign group for initiative
2. Structure: Awareness → Consideration → Conversion campaigns
3. Target: Director+, 50-5000 employees, relevant industries
4. Start $50/day per campaign
5. Scale 20% weekly if CAC < target
6. **Validation:** LinkedIn Insight Tag firing on all pages
### Google Ads Setup
1. Prioritize: Brand → Competitor → Solution → Category keywords
2. Structure ad groups with 5-10 tightly themed keywords
3. Create 3 responsive search ads per ad group (15 headlines, 4 descriptions)
4. Maintain negative keyword list (100+)
5. Start Manual CPC, switch to Target CPA after 50+ conversions
6. **Validation:** Conversion tracking firing, search terms reviewed weekly
### Budget Allocation (Series A, $40k/month)
| Channel | Budget | Expected SQLs |
|---------|--------|---------------|
| LinkedIn | $15k | 10 |
| Google Search | $12k | 20 |
| Google Display | $5k | 5 |
| Meta | $5k | 8 |
| Partnerships | $3k | 5 |
See [campaign-templates.md](references/campaign-templates.md) for detailed structures.
---
## SEO Strategy
### Technical Foundation Checklist
- [ ] XML sitemap submitted to Search Console
- [ ] Robots.txt configured correctly
- [ ] HTTPS enabled
- [ ] Page speed >90 mobile
- [ ] Core Web Vitals passing
- [ ] Structured data implemented
- [ ] Canonical tags on all pages
- [ ] Hreflang tags for international
- **Validation:** Run Screaming Frog crawl, zero critical errors
### Keyword Strategy
| Tier | Type | Volume | Priority |
|------|------|--------|----------|
| 1 | High-intent BOFU | 100-1k | First |
| 2 | Solution-aware MOFU | 500-5k | Second |
| 3 | Problem-aware TOFU | 1k-10k | Third |
### On-Page Optimization
1. URL: Include primary keyword, 3-5 words
2. Title tag: Primary keyword + brand (60 chars)
3. Meta description: CTA + value prop (155 chars)
4. H1: Match search intent (one per page)
5. Content: 2000-3000 words for comprehensive topics
6. Internal links: 3-5 relevant pages
7. **Validation:** Google Search Console shows page indexed, no errors
### Link Building Priorities
1. Digital PR (original research, industry reports)
2. Guest posting (DA 40+ sites only)
3. Partner co-marketing (complementary SaaS)
4. Community engagement (Reddit, Quora)
---
## Partnerships
### Partnership Tiers
| Tier | Type | Effort | ROI |
|------|------|--------|-----|
| 1 | Strategic integrations | High | Very high |
| 2 | Affiliate partners | Medium | Medium-high |
| 3 | Customer referrals | Low | Medium |
| 4 | Marketplace listings | Medium | Low-medium |
### Partnership Workflow
1. Identify partners with overlapping ICP, no competition
2. Outreach with specific integration/co-marketing proposal
3. Define success metrics, revenue model, term
4. Create co-branded assets and partner tracking
5. Enable partner sales team with demo training
6. **Validation:** Partner UTM tracking functional, leads routing correctly
### Affiliate Program Setup
1. Select platform (PartnerStack, Impact, Rewardful)
2. Configure commission structure (20-30% recurring)
3. Create affiliate enablement kit (assets, links, content)
4. Recruit through outbound, inbound, events
5. **Validation:** Test affiliate link tracks through to conversion
See [international-playbooks.md](references/international-playbooks.md) for regional tactics.
---
## Attribution
### Model Selection
| Model | Use Case |
|-------|----------|
| First-Touch | Awareness campaigns |
| Last-Touch | Direct response |
| W-Shaped (40-20-40) | Hybrid PLG/Sales (recommended) |
### HubSpot Attribution Setup
1. Navigate to Marketing → Reports → Attribution
2. Select W-Shaped model for hybrid motion
3. Define conversion event (deal created)
4. Set 90-day lookback window
5. **Validation:** Run report for past 90 days, all channels show data
### Weekly Metrics Dashboard
| Metric | Target |
|--------|--------|
| MQLs | Weekly target |
| SQLs | Weekly target |
| MQL→SQL Rate | >15% |
| Blended CAC | <$300 |
| Pipeline Velocity | <60 days |
See [attribution-guide.md](references/attribution-guide.md) for detailed setup.
---
## Tools
### scripts/
| Script | Purpose | Usage |
|--------|---------|-------|
| `calculate_cac.py` | Calculate blended and channel CAC | `python scripts/calculate_cac.py --spend 40000 --customers 50` |
### HubSpot Integration
- Campaign tracking with UTM parameters
- Lead scoring and MQL/SQL workflows
- Attribution reporting (multi-touch)
- Partner lead routing
See [hubspot-workflows.md](references/hubspot-workflows.md) for workflow templates.
---
## References
| File | Content |
|------|---------|
| [hubspot-workflows.md](references/hubspot-workflows.md) | Lead scoring, nurture, assignment workflows |
| [campaign-templates.md](references/campaign-templates.md) | LinkedIn, Google, Meta campaign structures |
| [international-playbooks.md](references/international-playbooks.md) | EU, US, Canada market tactics |
| [attribution-guide.md](references/attribution-guide.md) | Multi-touch attribution, dashboards, A/B testing |
---
## Channel Benchmarks (B2B SaaS Series A)
| Metric | LinkedIn | Google Search | SEO | Email |
|--------|----------|---------------|-----|-------|
| CTR | 0.4-0.9% | 2-5% | 1-3% | 15-25% |
| CVR | 1-3% | 3-7% | 2-5% | 2-5% |
| CAC | $150-400 | $80-250 | $50-150 | $20-80 |
| MQL→SQL | 10-20% | 15-25% | 12-22% | 8-15% |
---
## MQL→SQL Handoff
### SQL Criteria
```
Required:
✅ Job title: Director+ or budget authority
✅ Company size: 50-5000 employees
✅ Budget: $10k+ annual
✅ Timeline: Buying within 90 days
✅ Engagement: Demo requested or high-intent action
```
### SLA
| Handoff | Target |
|---------|--------|
| SDR responds to MQL | 4 hours |
| AE books demo with SQL | 24 hours |
| First demo scheduled | 3 business days |
**Validation:** Test lead through workflow, verify notifications and routing.
## Proactive Triggers
- **Over-relying on one channel** → Single-channel dependency is a business risk. Diversify.
- **No lead scoring** → Not all leads are equal. Route to revenue-operations for scoring.
- **CAC exceeding LTV** → Demand gen is unprofitable. Optimize or cut channels.
- **No nurture for non-ready leads** → 80% of leads aren't ready to buy. Nurture converts them later.
## Related Skills
- **paid-ads**: For executing paid acquisition campaigns.
- **content-strategy**: For content-driven demand generation.
- **email-sequence**: For nurture sequences in the demand funnel.
- **campaign-analytics**: For measuring demand gen effectiveness.
FILE:references/attribution-guide.md
# Attribution Guide
Multi-touch attribution setup, analysis, and reporting.
---
## Table of Contents
- [Attribution Models](#attribution-models)
- [HubSpot Attribution Setup](#hubspot-attribution-setup)
- [Google Analytics Configuration](#google-analytics-configuration)
- [Reporting Dashboards](#reporting-dashboards)
- [A/B Testing Framework](#ab-testing-framework)
---
## Attribution Models
### Model Comparison
| Model | Credit Distribution | Best For |
|-------|---------------------|----------|
| First-Touch | 100% to first interaction | Awareness campaigns |
| Last-Touch | 100% to last interaction | Direct response, BOFU |
| Linear | Equal across all touchpoints | Simple full-funnel view |
| Time Decay | More credit to recent touches | Long sales cycles |
| W-Shaped | 40% first, 20% middle, 40% last | Hybrid PLG/Sales-Led |
### Recommended Model: W-Shaped
For Series A hybrid motion:
- 40% credit to first touch (awareness)
- 20% distributed across middle touches
- 40% credit to last touch (conversion)
**Rationale:** Balances discovery and closing influence.
---
## HubSpot Attribution Setup
### Enable Attribution Reports
1. Navigate to Marketing → Reports → Attribution
2. Select attribution model (W-Shaped recommended)
3. Define conversion event (deal created, SQL stage)
4. Set lookback window (90 days typical)
### Attribution Report Types
| Report | Purpose | Frequency |
|--------|---------|-----------|
| Revenue Attribution | Credit revenue to channels | Monthly |
| Content Attribution | Credit to content assets | Weekly |
| Campaign Attribution | Credit to campaigns | Per campaign |
### Custom Attribution Report
Create: Marketing → Reports → Create Report
**Metrics:**
- Marketing-sourced pipeline $
- Marketing-influenced revenue
- CAC by channel
- ROAS by campaign
**Dimensions:**
- Channel (Organic, Paid, Email, Social, Referral)
- Campaign
- Region (US, EU, Canada)
- Funnel stage (TOFU, MOFU, BOFU)
**Validation:** Run report for past 90 days. Verify all channels appear with data.
---
## Google Analytics Configuration
### GA4 Events to Track
**Engagement Events:**
```
page_view (auto-tracked)
scroll (75% depth)
video_play (product demos)
file_download (whitepapers, eBooks)
```
**Conversion Events:**
```
sign_up (free trial, account)
demo_request (calendar booking)
contact_form (inbound interest)
pricing_view (pricing page visit)
```
### Custom Dimensions
| Dimension | Source | Purpose |
|-----------|--------|---------|
| User Type | CRM sync | Free vs Paid |
| Plan Type | CRM sync | Starter, Pro, Enterprise |
| Lead Status | HubSpot | MQL, SQL, Customer |
| Campaign ID | UTM | HubSpot campaign |
### GA4 + HubSpot Integration
1. Install HubSpot tracking code (includes GA4)
2. Or use Google Tag Manager for advanced tracking
3. Sync GA4 audiences → HubSpot lists for retargeting
4. Import GA4 conversions to Google Ads
**Validation:** Real-time report shows events firing. Conversion events marked correctly.
---
## Reporting Dashboards
### Weekly Performance Dashboard
| Metric | Purpose | Target |
|--------|---------|--------|
| Visits | Traffic volume | +10% WoW |
| Unique visitors | Reach | +5% WoW |
| Bounce rate | Engagement | <50% |
| MQLs | Lead volume | Weekly target |
| SQLs | Pipeline | Weekly target |
| Conversion rate | Efficiency | >2% |
### Monthly Executive Dashboard
| KPI | Formula | Target |
|-----|---------|--------|
| Marketing-Sourced Pipeline | Sum of new pipeline $ | $X/month |
| Marketing-Sourced Revenue | Closed-won from marketing | $Y/month |
| Blended CAC | Total spend / customers | <$Z |
| MQL→SQL Rate | SQLs / MQLs | >15% |
| Pipeline Velocity | Avg days in pipeline | <60 days |
| ROMI | Revenue / Marketing spend | >3:1 |
### Dashboard Build Process
1. Define KPIs with leadership
2. Create data sources in HubSpot
3. Build visualizations (charts, tables)
4. Set up automated refresh
5. Schedule weekly/monthly distribution
**Validation:** Dashboard shows last 7 days data. All metrics calculating correctly.
---
## A/B Testing Framework
### ICE Prioritization
**Formula:** ICE = (Impact × Confidence × Ease) ÷ 3
| Factor | Rating | Description |
|--------|--------|-------------|
| Impact | 1-10 | Effect on primary metric |
| Confidence | 1-10 | Certainty of success |
| Ease | 1-10 | Implementation difficulty |
### Test Template
```
Hypothesis: [Adding a case study carousel to pricing will
increase demo requests by 20%]
Metric: [Demo requests from /pricing page]
Sample Size: [1000 visitors per variant]
Duration: [2 weeks or until significance]
Success Criteria: [20% lift, 95% confidence]
Variant A (Control): [Current pricing page]
Variant B (Treatment): [Pricing page + case study carousel]
Tools: [HubSpot A/B test or Google Optimize]
```
### Statistical Requirements
- Minimum confidence: 95%
- Minimum sample: 1000 visitors per variant
- Minimum duration: 2 weeks
- Do not stop tests early (false positives)
### Common Test Categories
**Landing Page:**
- Headline variations
- CTA copy and color
- Form length
- Social proof placement
- Hero image type
**Ad Creative:**
- Format (static vs video)
- Messaging angle
- Audience targeting
- Landing page destination
**Email:**
- Subject line length
- Personalization depth
- Send time
- CTA placement
### Test Velocity Target
Series A: 4-6 tests per month
- Realistic win rate: 30-40%
- Document all results (wins and losses)
- Build testing knowledge base
**Validation:** Test reaches statistical significance before declaring winner.
FILE:references/campaign-templates.md
# Campaign Templates
Ready-to-use campaign briefs and structures for LinkedIn, Google, and Meta.
---
## Table of Contents
- [Campaign Brief Template](#campaign-brief-template)
- [LinkedIn Ads Structure](#linkedin-ads-structure)
- [Google Ads Structure](#google-ads-structure)
- [Meta Ads Structure](#meta-ads-structure)
- [Ad Copy Frameworks](#ad-copy-frameworks)
---
## Campaign Brief Template
Use for every campaign:
```
Campaign Name: [Q2-2025-LinkedIn-ABM-Enterprise]
Objective: [Generate 50 SQLs from Enterprise accounts ($50k+ ACV)]
Budget: [$15k/month]
Duration: [90 days]
Channels: [LinkedIn Ads, Retargeting, Email]
Audience: [Director+ at SaaS companies, 500-5000 employees, EU/US]
Offer: [Gated Industry Benchmark Report]
Success Metrics:
- Primary: 50 SQLs, <$300 CPO
- Secondary: 500 MQLs, 10% MQL→SQL rate, 40% email open rate
HubSpot Setup:
- Campaign ID: [create in HubSpot]
- Lead scoring: +20 for download, +30 for demo request
- Attribution: First-touch + Multi-touch
Handoff Protocol:
- SQL criteria: Title + Company size + Budget confirmed
- Routing: Enterprise SDR team via HubSpot workflow
- SLA: 4-hour response time
```
**Validation:** Campaign appears in HubSpot with all assets tagged.
---
## LinkedIn Ads Structure
### Account Hierarchy
```
Account
└─ Campaign Group: [Q2-2025-Enterprise-ABM]
├─ Campaign 1: [Awareness - Thought Leadership]
│ ├─ Ad Set: [CTO/VP Eng, US, Tech Companies]
│ └─ Creatives: [3 carousel posts, 2 video ads]
├─ Campaign 2: [Consideration - Product Education]
│ ├─ Ad Set: [Engaged audience, retargeting]
│ └─ Creatives: [2 lead gen forms, 1 landing page]
└─ Campaign 3: [Conversion - Demo Requests]
├─ Ad Set: [Website visitors, content downloaders]
└─ Creatives: [Direct demo CTA, case study]
```
### Targeting Settings
| Parameter | Series A Sweet Spot |
|-----------|---------------------|
| Company Size | 50-5000 employees |
| Job Titles | Director+, VP+, C-level |
| Industries | Software, SaaS, Tech Services |
| Budget | Start $50/day per campaign |
### Scaling Rules
- CAC < target → Increase budget 20% weekly
- CAC > target → Pause, optimize, relaunch
- Scale 20% weekly maximum to maintain performance
### Lead Gen Forms vs Landing Pages
| Type | Conversion | Quality | Use Case |
|------|------------|---------|----------|
| Lead Gen Forms | 2-3x higher | Lower | TOFU/MOFU |
| Landing Pages | Lower | Higher | BOFU/demos |
**Validation:** LinkedIn Insight Tag firing. Matched audiences syncing.
---
## Google Ads Structure
### Campaign Priority
1. **Search - Brand** (highest priority, protect brand terms)
2. **Search - Competitor** (steal market share)
3. **Search - Solution** (problem-aware buyers)
4. **Search - Product Category** (earlier stage)
5. **Display - Retargeting** (re-engage warm traffic)
### Search Campaign Template
```
Campaign: [Search-Solution-Keywords]
├─ Ad Group: [project management software]
│ ├─ Keywords:
│ │ - "project management software" [Phrase]
│ │ - "best project management tool" [Phrase]
│ │ - +project +management +solution [Broad Match Modifier]
│ └─ Ads: [3 responsive search ads]
│
└─ Ad Group: [team collaboration tools]
├─ Keywords: [5-10 tightly themed keywords]
└─ Ads: [3 responsive search ads]
```
### Keyword Strategy
| Type | Match | Bid Priority |
|------|-------|--------------|
| Brand Terms | Exact | High - protect brand |
| Competitor Terms | Phrase | Medium - comparison |
| Solution Terms | Phrase | Medium - category |
| Problem Terms | Broad | Lower - education |
### Negative Keywords (Maintain 100+)
```
free, cheap, jobs, career, reviews, salary, login, support,
download, tutorial, course, certification, example, template
```
### Bid Strategy Progression
1. New campaigns: Manual CPC (control)
2. After 50+ conversions: Target CPA
3. After 100+ conversions: Maximize Conversions with tCPA
4. EU markets: Bid 15-20% higher for same quality
**Validation:** Conversion tracking firing. Search terms report reviewed weekly.
---
## Meta Ads Structure
### When to Use Meta
| Scenario | Meta | LinkedIn |
|----------|------|----------|
| ACV <$10k | ✅ | ❌ |
| Visual product | ✅ | ❌ |
| SMB audience | ✅ | ❌ |
| Enterprise | ❌ | ✅ |
### Campaign Template
```
Campaign Objective: [Conversions]
├─ Ad Set 1: [Lookalike - 1% of converters]
│ └─ Placement: [Feed + Stories, Auto]
├─ Ad Set 2: [Interest - Business Software]
│ └─ Placement: [Feed only]
└─ Ad Set 3: [Retargeting - Website 30d]
└─ Placement: [All placements]
```
### Creative Best Practices
- Video format: 1:1 or 9:16 for Stories
- First 3 seconds: Hook with problem or result
- Show product UI in action
- Add captions (85% watch muted)
- Test 3-5 variants per campaign
**Validation:** Meta Pixel events firing. Conversion values passing correctly.
---
## Ad Copy Frameworks
### LinkedIn Thought Leadership
```
[Industry insight or contrarian take]
[Supporting data point or experience]
[Call to discuss or engage]
#RelevantHashtag #Industry
```
### LinkedIn Social Proof
```
[Customer result with specific numbers]
"[Customer quote]"
- [Name, Title, Company]
[Soft CTA: See how →]
```
### Google Responsive Search Ads
**Headlines (15 required):**
- H1-3: Value props (Save 10 hours/week, Trusted by 500+ teams)
- H4-6: Features (AI-powered, Real-time sync, Mobile app)
- H7-9: Social proof (4.8★ G2 rating, Used by Microsoft)
- H10-12: CTAs (Start free trial, Book demo, See pricing)
- H13-15: Dynamic keyword insertion
**Descriptions (4 required):**
- D1: Primary value prop + CTA (30-60 chars)
- D2: Feature list + differentiator (60-90 chars)
- D3: Social proof + urgency (45-90 chars)
- D4: Backup generic (60-90 chars)
**Validation:** Ad strength score of "Excellent" before launch.
FILE:references/hubspot-workflows.md
# HubSpot Workflow Templates
Pre-built workflow configurations for lead scoring, nurturing, and assignment.
---
## Table of Contents
- [Campaign Tracking Setup](#campaign-tracking-setup)
- [Lead Scoring Configuration](#lead-scoring-configuration)
- [MQL to SQL Workflow](#mql-to-sql-workflow)
- [Partner Lead Tracking](#partner-lead-tracking)
- [Nurture Sequences](#nurture-sequences)
---
## Campaign Tracking Setup
### Create Campaign in HubSpot
1. Navigate to Marketing → Campaigns → Create Campaign
2. Name using convention: `Q[N]-[YEAR]-[CHANNEL]-[CAMPAIGN-TYPE]`
- Example: `Q2-2025-LinkedIn-ABM-Enterprise`
3. Tag all assets (landing pages, emails, ads) with campaign ID
### UTM Parameter Structure
```
utm_source={channel} // linkedin, google, facebook
utm_medium={type} // cpc, display, email, organic
utm_campaign={campaign-id} // q2-2025-linkedin-abm-enterprise
utm_content={variant} // ad-variant-a, email-1
utm_term={keyword} // [for paid search only]
```
**Validation:** Verify UTM parameters appear in HubSpot contact records after test submission.
---
## Lead Scoring Configuration
### Navigate to Configuration
Settings → Marketing → Lead Scoring
### Scoring Rules
| Action | Points | Rationale |
|--------|--------|-----------|
| Content download | +10 to +20 | Based on content depth |
| Demo request | +30 | High intent signal |
| Pricing page visit | +15 | Commercial intent |
| Webinar attendance | +20 | Engaged prospect |
| Email open | +2 | Basic engagement |
| Email click | +5 | Active interest |
### Channel Quality Modifiers
| Source | Points | Rationale |
|--------|--------|-----------|
| LinkedIn | +5 | Professional context |
| Google Search | +10 | Active search intent |
| Organic | +15 | Self-discovery |
| Referral | +20 | Pre-qualified |
**Validation:** Test lead scoring by creating a test contact and triggering each action.
---
## MQL to SQL Workflow
### SQL Definition Criteria
```
Required (all must be true):
✅ Job title: Director+ (or Budget Authority confirmed)
✅ Company size: 50-5000 employees
✅ Budget: $10k+ annual
✅ Timeline: Buying within 90 days
✅ Engagement: Demo requested OR High intent action
```
### Workflow Configuration
1. **Trigger:** Lead score reaches MQL threshold (>75 points)
2. **Action 1:** Send automated email to SDR with lead details
3. **Action 2:** Create task for SDR qualification call
4. **Branch Logic:**
- If qualified → Update lifecycle stage to SQL, assign to AE
- If not qualified → Move to nurture list, reduce lead score by 30
### SLA Configuration
| Handoff | Target | Escalation |
|---------|--------|------------|
| SDR responds to MQL | 4 hours | Manager notification |
| AE books demo with SQL | 24 hours | Director notification |
| First demo scheduled | 3 business days | VP notification |
**Validation:** Test workflow with a sample lead. Verify notifications trigger correctly.
---
## Partner Lead Tracking
### Create Partner Property
1. Settings → Properties → Create Property
2. Property name: `Partner Source`
3. Type: Dropdown select
4. Values: Partner A, Partner B, Affiliate Network, Direct
### Partner UTM Configuration
```
Partner links: ?utm_source=partner-name&utm_medium=referral
```
### Lead Assignment Workflow
1. **Trigger:** Contact property `Partner Source` is set
2. **Action:** Assign to Partner Manager
3. **Notification:** Slack alert when partner lead arrives
### Partner Reporting Dashboard
Create custom report: Marketing → Reports → Create Report
- Metrics: Leads, Pipeline, Revenue by Partner Source
- Dimensions: Partner Name, Time Period
**Validation:** Submit test lead with partner UTM. Verify property populates and routing works.
---
## Nurture Sequences
### Lost Opportunity Recycle
**Trigger:** Deal stage = Closed Lost
**Sequence:**
1. Day 0: Add to nurture list, remove from active campaigns
2. Day 30: Educational content email
3. Day 60: Industry insights email
4. Day 90: Re-engagement offer email
5. Month 6: SDR re-qualification task
### TOFU to MOFU Progression
**Trigger:** Contact downloads 2+ content pieces
**Sequence:**
1. Day 0: Thank you email with related content
2. Day 3: Case study email
3. Day 7: Webinar invitation
4. Day 14: Demo offer (soft CTA)
### Closed Lost Reason Tracking
Configure deal properties to capture:
- Price too high
- Missing features
- Chose competitor
- No budget
- Bad timing
- Champion left company
**Use data to inform:** Product roadmap, pricing adjustments, competitive positioning.
FILE:references/international-playbooks.md
# International Market Playbooks
Market-specific tactics for EU, US, and Canada expansion.
---
## Table of Contents
- [EU Market Entry](#eu-market-entry)
- [US Market Entry](#us-market-entry)
- [Canada Market Entry](#canada-market-entry)
- [Budget Allocation by Region](#budget-allocation-by-region)
- [Localization Checklist](#localization-checklist)
---
## EU Market Entry
### Compliance Requirements
| Requirement | Implementation |
|-------------|----------------|
| GDPR consent | Double opt-in for email |
| Cookie consent | Explicit consent banner |
| Data storage | EU data center option |
| Privacy policy | EU-specific language |
**HubSpot Configuration:**
- Enable double opt-in in Forms settings
- Configure consent tracking properties
- Set up GDPR deletion workflows
### Localization Priority
| Language | Market Priority | Revenue Potential |
|----------|-----------------|-------------------|
| German (DE) | High | Largest EU economy |
| French (FR) | High | Second largest EU |
| Spanish (ES) | Medium | Growing tech sector |
| Dutch (NL) | Medium | English proficiency |
| Italian (IT) | Lower | Later expansion |
### Channel Mix (EU)
| Channel | Budget % | Rationale |
|---------|----------|-----------|
| LinkedIn | 40% | Primary B2B channel |
| Google Ads | 25% | High intent capture |
| SEO | 20% | Long-term investment |
| Partnerships | 15% | Local credibility |
### EU Messaging Adjustments
- More formal tone than US
- Focus on data security and compliance
- Emphasize local customer references
- Include EU headquarters or presence
- Display prices in EUR
**Validation:** Test landing pages with EU VPN. Verify consent flows work correctly.
---
## US Market Entry
### Market Characteristics
| Aspect | US Approach |
|--------|-------------|
| Messaging | Direct, ROI-focused |
| Tone | Less formal than EU |
| Sales cycle | Faster decision-making |
| Proof points | Dollar impact, not features |
### Channel Mix (US)
| Channel | Budget % | Rationale |
|---------|----------|-----------|
| Google Ads | 35% | High commercial intent |
| LinkedIn | 30% | B2B targeting |
| SEO | 20% | Competitive necessity |
| Partnerships | 15% | Industry associations |
### Partner Ecosystem
| Partner Type | Examples |
|--------------|----------|
| Review sites | G2, Capterra, TrustRadius |
| Industry associations | SaaStr, ProductLed |
| Integration partners | Salesforce, HubSpot |
| Channel partners | VARs, consultants |
### Content Adjustments
- Case studies with $ impact metrics
- Faster, more aggressive CTAs
- Video testimonials with customers
- Comparison pages (vs. competitors)
**Validation:** US-based speed test. Payment processing in USD functional.
---
## Canada Market Entry
### Market Characteristics
| Aspect | Canada Approach |
|--------|-----------------|
| Language | English + French (Quebec) |
| Regulation | PIPEDA compliance |
| Messaging | Mix of US and EU styles |
| Pricing | CAD display preferred |
### Regional Considerations
| Region | Language | Focus |
|--------|----------|-------|
| Ontario | English | Tech hub, Toronto |
| British Columbia | English | Vancouver tech scene |
| Quebec | French | Requires localization |
| Alberta | English | Energy sector |
### Channel Mix (Canada)
| Channel | Budget % | Rationale |
|---------|----------|-----------|
| Google Ads | 35% | Primary acquisition |
| LinkedIn | 30% | Professional targeting |
| SEO | 20% | Local content |
| Partnerships | 15% | Local associations |
**Validation:** French Quebec landing page tested. CAD pricing displays correctly.
---
## Budget Allocation by Region
### Series A Recommended Split
| Region | Budget % | Expected CAC |
|--------|----------|--------------|
| US | 50% | $150-300 |
| EU | 35% | $200-400 |
| Canada | 15% | $175-350 |
### Channel by Region Matrix
| Channel | US | EU | Canada |
|---------|----|----|--------|
| LinkedIn | 30% | 40% | 30% |
| Google | 35% | 25% | 35% |
| SEO | 20% | 20% | 20% |
| Partners | 15% | 15% | 15% |
### Scaling Criteria
Expand regional budget when:
- CAC < 80% of target for 4 consecutive weeks
- MQL→SQL rate > regional benchmark
- Sales team has regional capacity
---
## Localization Checklist
### Website Localization
- [ ] Translate navigation and UI elements
- [ ] Localize pricing (currency, formatting)
- [ ] Adapt case studies to regional references
- [ ] Update screenshots with localized UI
- [ ] Configure hreflang tags correctly
- [ ] Submit to regional search consoles
### Content Localization
- [ ] Translate (don't just localize) key pages
- [ ] Adapt idioms and cultural references
- [ ] Update date formats (DD/MM/YYYY vs MM/DD/YYYY)
- [ ] Adjust number formatting (1,000 vs 1.000)
- [ ] Use regional spelling (optimise vs optimize)
### Campaign Localization
- [ ] Translate ad copy (not just translate, adapt)
- [ ] Create regional landing pages
- [ ] Set up regional tracking parameters
- [ ] Configure regional lead routing
- [ ] Align with regional sales hours
### Legal Localization
- [ ] GDPR compliance (EU)
- [ ] PIPEDA compliance (Canada)
- [ ] Cookie consent mechanisms
- [ ] Privacy policy translations
- [ ] Terms of service updates
**Validation:** Native speaker review of all localized content before launch.
FILE:scripts/calculate_cac.py
#!/usr/bin/env python3
"""
CAC (Customer Acquisition Cost) Calculator
Calculate blended and channel-specific CAC for marketing campaigns.
Supports multiple time periods and channel breakdowns.
"""
import sys
from typing import Dict, List
def calculate_cac(total_spend: float, customers_acquired: int) -> float:
"""Calculate basic CAC"""
if customers_acquired == 0:
return 0.0
return round(total_spend / customers_acquired, 2)
def calculate_channel_cac(channel_data: List[Dict]) -> Dict:
"""
Calculate CAC per channel
Args:
channel_data: List of dicts with 'channel', 'spend', 'customers' keys
Returns:
Dict with channel CAC breakdown and blended CAC
"""
results = {}
total_spend = 0
total_customers = 0
for channel in channel_data:
name = channel['channel']
spend = channel['spend']
customers = channel['customers']
cac = calculate_cac(spend, customers)
results[name] = {
'spend': spend,
'customers': customers,
'cac': cac
}
total_spend += spend
total_customers += customers
results['blended'] = {
'total_spend': total_spend,
'total_customers': total_customers,
'blended_cac': calculate_cac(total_spend, total_customers)
}
return results
def print_results(results: Dict):
"""Pretty print CAC results"""
print("\n" + "="*60)
print("CAC CALCULATION RESULTS")
print("="*60 + "\n")
for channel, data in results.items():
if channel == 'blended':
print("-"*60)
print(f"BLENDED CAC")
print(f" Total Spend: ,.2f")
print(f" Total Customers: {data['total_customers']:,}")
print(f" Blended CAC: ,.2f")
else:
print(f"{channel.upper()}")
print(f" Spend: ,.2f")
print(f" Customers: {data['customers']:,}")
print(f" CAC: ,.2f")
print()
def main():
# Example data - replace with your actual numbers
example_data = [
{'channel': 'LinkedIn Ads', 'spend': 15000, 'customers': 10},
{'channel': 'Google Search', 'spend': 12000, 'customers': 20},
{'channel': 'SEO/Organic', 'spend': 5000, 'customers': 15},
{'channel': 'Partnerships', 'spend': 3000, 'customers': 5},
]
print("Marketing CAC Calculator")
print("Edit the script to input your actual channel data\n")
results = calculate_channel_cac(example_data)
print_results(results)
# CAC benchmarks
print("\n" + "="*60)
print("B2B SAAS BENCHMARKS (Series A)")
print("="*60)
print("LinkedIn Ads: $150-$400")
print("Google Search: $80-$250")
print("SEO/Organic: $50-$150")
print("Partnerships: $100-$300")
print("Blended Target: <$300")
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()
Lập kế hoạch marketing toàn diện cho khách hàng, công ty hoặc sản phẩm riêng: kế hoạch tăng trưởng, GTM, AARRR, lộ trình 90 ngày hoặc 12 tháng.
---
name: marketing-plan
description: When the user needs a comprehensive marketing plan for a client, a company they advise, or their own product. Also use when the user mentions "marketing plan," "growth plan," "GTM plan," "go-to-market plan," "AARRR plan," "90-day marketing plan," "12-month marketing roadmap," "fractional CMO plan," or "fCMO plan." Generates an exhaustive 13-section plan structured by AARRR (Acquisition, Activation, Retention, Referral, Revenue), customized to the client's current budget, team, and stage, mapped to future funding milestones, cross-referenced with the 139-idea marketing-ideas library and an embedded 17-section current-state audit rubric, with a full marketing operations stack showing which skills and MCP/API integrations execute each part. Outputs a Notion-paste-ready markdown document. For positioning and ICP context before planning, see product-marketing. For stage-specific deep work, see onboarding, signup, emails, referrals, pricing.
metadata:
version: 1.1.1
---
# Marketing Plan
You are an expert marketing strategist operating at fCMO (fractional CMO) level. Your job is to produce a comprehensive, executable 12-month marketing plan for a specific client or company, structured by AARRR (Acquisition, Activation, Retention, Referral, Revenue), customized to their actual budget, team, stage, and capabilities, and cross-referenced with the full marketing-ideas library and the embedded 17-section current-state audit rubric.
The deliverable is a single Notion-paste-ready markdown document — the kind of strategy artifact a fractional CMO would present to founders. It must be specific to the client (not generic), exhaustive (covers every tactical surface area, not just what's prescribed), and operationally honest (reflects what their team can actually execute with their current stack and headcount).
## When to use
Invoke this skill when:
- A user is starting a new client engagement as a fractional CMO or marketing consultant
- A founder needs a 12-month marketing roadmap they can share with their team or investors
- A team wants to consolidate scattered marketing work (SEO research, brand voice docs, audit findings, onboarding analyses) into a single coherent plan
- The user explicitly asks for a "marketing plan," "growth plan," "GTM plan," "fCMO plan," "AARRR plan," or "90-day + 12-month marketing roadmap"
- An existing scored audit (from any prior current-state assessment) needs to be sequenced into an action plan
**Do not use** when the user wants a tactical execution document for a single channel (use the channel-specific skill instead — `emails`, `ads`, `seo-audit`, `onboarding`, etc.), or when the user just wants marketing ideas without commitment to a plan (use `marketing-ideas`).
## How this skill is invoked
```
/marketing-plan {client-name-or-domain}
```
Examples:
- `/marketing-plan quietude.app`
- `/marketing-plan acme-saas`
- `/marketing-plan` (will prompt for client name)
On invocation, the skill reads `~/marketing-plans/{client-slug}/progress.md` and resumes based on the state machine documented in `references/methodology.md` Step 1.1.2 (fresh → INIT → REVIEW → FINALIZE → finalized). Finalized plans are never silently overwritten — the user is asked whether to revise as v{N+1}, start fresh, or re-open a section.
## The three phases
The full workflow lives in `references/methodology.md`. Quick summary:
### Phase 1 — INIT (research + intake)
Read all available materials about the client. Pull data from any wired tools (Ahrefs, GA4 MCP, Stripe MCP, etc.). Conduct structured intake covering: client overview, ICP, current funnel state, funding state, team composition, marketing budget, channels currently active, what's already been done, what's in-flight, what's stuck, tooling stack. Save to `research.md`.
Use the embedded 17-section current-state rubric (`references/current-state-rubric.md`) as your scoring lens for Section 3 — score each section 0–5 against available materials.
### Phase 2 — REVIEW (walk through each of 13 sections interactively)
Present each section's draft in chat. For each section you can:
- Approve as-is ("good," "next")
- Adjust ("change X to Y")
- Add observations ("also mention Z")
- Expand ("go deeper on this")
Save each confirmed section to the progress file as you go. The skill is resumable — if interrupted, run `/marketing-plan client-name` again to pick up at the next unfinished section.
### Phase 3 — FINALIZE (compile + verify + publish)
Compile all 13 sections into `final_plan.md`. Run a verification pass: confirm cross-references (marketing-ideas idea numbers, related skills, MCP integrations) are accurate; check for machine-specific paths that shouldn't ship; ensure the brand voice matches what was captured in the strategic frame.
Optionally offer to publish to a shared GitHub repo (e.g., `{client-org}/{client-context}/marketing/plan.md`) if the user wants to share it with the team.
## The 13-section plan structure
Full template lives in `references/plan-template.md`. The structure:
1. **Executive summary** — 3 big bets, 90-day priorities, 12-month outcome. Written so it can be lifted into an investor or board update.
2. **Strategic frame** — Category claim, ICP distilled, business-model logic, brand voice non-negotiables.
3. **Current state** — Team, budget, what's done, what's in-flight, what's stuck. Scored against the embedded 17-section current-state rubric (`references/current-state-rubric.md`).
4. **Acquisition** — How strangers become aware. Channels current + planned + skipped, 90-day and 12-month moves, skills + tools.
5. **Activation** — How a new user has an experience that converts. Onboarding, first session, App Store / signup, paywall, lifecycle setup.
6. **Retention** — How a converted user stays and deepens. Lifecycle flows, churn prevention, win-back, support-as-marketing.
7. **Referral** — How retained users bring more users. Ambassador / affiliate / Guides / WOM mechanics.
8. **Revenue** — Pricing, packaging, upsells, bundles, hardware-to-software, B2B ACV.
9. **90-day roadmap** — Weeks 1–2 (Unblock), 3–4 (Foundation), 5–8 (Velocity), 9–12 (Compound). AARRR-tagged, owner-assigned.
10. **12-month outlook** — Quarterly milestones tied to funding-stage capability unlocks.
11. **Marketing operations stack** — Marketing skills + MCP/API integrations mapped to each AARRR stage. Capability unlocks by funding stage.
12. **Tactical idea bank** — All 139 ideas from `marketing-ideas` cross-referenced to AARRR + client-specific status (Now / Q2 / Q3+ / Q4+ / Skip).
13. **Measurement, RACI, open decisions, appendix** — North-star metric, leading indicators by stage, RACI table, blocking decisions, links to deeper docs.
## The AARRR framing
AARRR replaces the older "channels and tactics" approach because it forces every recommendation to be funnel-stage-tagged, which makes the plan executable in priority order.
Full primer in `references/aarrr-framework.md`. Quick rule:
- **Acquisition** = strangers → aware (top of funnel)
- **Activation** = aware → first valued experience (signup, onboarding, first session)
- **Retention** = repeat users (lifecycle, churn prevention, deepening engagement)
- **Referral** = retained users → bring more users (programs, viral mechanics)
- **Revenue** = monetization (pricing, upsells, bundles, ACV expansion)
Brand and content are **cross-cutting**, not their own AARRR stage — they serve every stage.
## Marketing as investing — the north-star framing
AARRR gives the plan its *structure*. This gives it its *spine*. Every plan should read as if written by someone who believes the following — and the exec summary and strategic frame should reflect it.
Adapted from *Founding Marketing* by Corey Haines (Ch. 1).
- **Marketing is like investing.** Treat the plan as a **compounding portfolio**, not a campaign calendar. Buy-and-hold assets (SEO content, a newsletter, a community, a referral loop) over one-off spikes. Diversify — no single channel carries the plan. Time in market beats timing the market.
- **No silver bullets, a hundred golden pellets.** There is no one move that fixes growth. The plan wins by stacking many small compounding assets. Be suspicious of any recommendation that promises to be *the* thing.
- **One asset, many returns.** A single well-made asset should pay off across the portfolio: a cornerstone piece ranks in search, earns backlinks, feeds the newsletter, seeds social, and becomes a conference talk. When sequencing moves (Sections 4–9), prefer assets with the most downstream reuse.
- **Audition, not an auction.** You earn attention by being worth paying attention to — you don't buy your way to a captive audience. Marketing is **non-deterministic**: the same input doesn't guarantee the same output, so the plan runs a portfolio of bets and doubles down on what works.
- **Hope is not a strategy.** Every move in the plan names its mechanism and its leading indicator. "Post more and hope it works" is not a line item. If a move can't be tied to a measurable, name it as an experiment with a kill criterion.
### The market-quality gate — problem size × frequency
Before planning *how* to market, sanity-check *what* is being marketed. Score the core problem the product solves on two axes:
- **Size** — how painful/valuable is the problem when it occurs? (small → large)
- **Frequency** — how often does the customer feel it? (rare → constant)
| | **Low frequency** | **High frequency** |
|---|---|---|
| **Large problem** | Winnable but expensive to keep top-of-mind (long sales cycles, retargeting-heavy) | **Best quadrant — build here.** Big + frequent = marketing compounds |
| **Small problem** | Weakest — hard to justify attention or spend | Habit-forming but easy to churn on price; needs strong retention |
Use it as a **strategic gate in Section 2 (Strategic frame)**: name which quadrant the product sits in. Big-and-frequent problems reward the compounding-portfolio approach most. If the product sits in a weaker quadrant, say so plainly — it constrains realistic CAC, channel mix, and the budget math downstream, and it belongs in Section 13's open decisions rather than being papered over.
## The current-state rubric
The plan's "Current State" section scores the client against the embedded 17-section rubric. Full rubric in `references/current-state-rubric.md` — it's the source of truth, not a derivative of any external skill.
If the user already has a separately scored audit, ingest those scores directly into Section 3. Otherwise, score from available materials using the rubric as your lens — mark "scored from materials" in the section header so the team can push back where they have better data.
## Cross-references — skills this plan integrates with
1. **`marketing-ideas`** — 139 proven marketing tactics. Section 12 of the plan cross-references every one to AARRR + client status. Detail in `references/idea-cross-reference.md`.
2. **`product-marketing`** — Sets up the foundational `.agents/product-marketing.md` context file (positioning, ICP, voice). Read this first; Section 2 (Strategic frame) builds on it.
3. **AARRR-stage-specific skills** — `onboarding`, `signup`, `emails`, `referrals`, `pricing`, etc. The "Marketing operations stack" (Section 11) maps these to AARRR stages.
The plan is **opinionated about which skills serve which stages.** Full mapping in `references/ops-stack-mapping.md`.
## The marketing operations stack
This is the differentiator of an fCMO-style plan vs. a generic marketing plan. The plan doesn't just say *what* to do — it says *what skills and tooling execute it.*
A small team + an fCMO + the marketing-skills library + MCP integrations can output the work of a 15–20-person traditional marketing org. The plan must show this stack explicitly, AARRR-stage by AARRR-stage.
Full mapping in `references/ops-stack-mapping.md`.
## Funding-stage capability unlocks
Every plan must include explicit "what changes when funding closes / when budget unlocks" reasoning. This makes the plan investor-friendly (founders mid-raise see what they're buying) and operationally honest (we're not pretending the team can spend $50K/mo on paid before the round closes).
Standard tiers in `references/funding-stage-unlocks.md`:
- **Pre-seed / bootstrapped** — $0–$2K/mo total marketing spend; organic only
- **Seed close** — $5–$15K/mo paid test budget; first marketing hire
- **Seed deployment** — $20–$50K/mo paid; second marketing hire
- **Series A** — $50–$150K/mo paid; performance + content + designer; international consideration
- **Series B+** — $150K+/mo paid; brand campaigns; PR firm; full-stack marketing org
Use these as anchors. Adjust for category (consumer apps and ecommerce can spend more; deep-tech B2B may spend less).
## Setting the budget scientifically
The funding-stage anchors above tell you *what's in the ballpark*. To set the actual number defensibly, use one of two methods (full detail in `references/budget-planning.md`):
1. **Revenue-Based (5–40% of ARR)** — start from comfortable spend, forecast resulting revenue. Best when historical CAC data exists.
2. **Goal-Based** — reverse-engineer the budget from the revenue target. Formula: `[(New ARR / (ARPC × 12)) × CAC] / annual retention rate`. Best for fundraising or when the goal is fixed.
Always add **10–20% experimental budget** on top — CAC is the main dependency, and the experimental layer is what funds the next-channel investment before the current one plateaus.
For VC-backed Series A+ clients, anchor the 12-month outlook against the **3-3-2-2-2 rule** (3× in years 1–2, 2× in years 3–7 from $1M ARR).
## Growth patterns — the real shape of SaaS growth
Pitch decks show hockey sticks. Real growth is a series of S-curves with plateaus between them. Full framework in `references/growth-patterns.md`. Key implications for the plan:
- **Phase identification** — $0–10K ARR (grueling), $10K–100K (treacherous middle), $100K–1M (acceleration). Section 3 names the current phase; Section 10 sequences the next.
- **Linear vs step-function** — most healthy SaaS growth is linear (predictable additions per month) punctuated by step-functions (enterprise tier launch, new segment, channel breakthrough). The plan should describe both honestly — not promise exponential.
- **S-curve layering** — Channel × Product × Market. Start the next S-curve while the current one is still growing. Riding any single S-curve to its ceiling before investing in the next produces multi-month plateaus.
- **70/20/10 resource allocation** — split the plan's effort/budget across current (70%), next (20%), and experimental (10%) initiatives so the next S-curve is always funded before the current one plateaus.
- **Weekly tracking cadence** — review leading indicators weekly and watch for S-curve plateau signals; a flattening curve is the trigger to shift weight toward the next one, not a reason to push harder on the current.
## Team and agency model
Strategy lives in-house. Execution can — and often should — be outsourced. Full framework in `references/team-and-agency-model.md`. Three implications for every plan:
1. **First hire is a strategist, not a tactician.** Look for a **π-shaped marketer** (two deep skill sets) — common high-leverage combos: Product Marketing + Growth Marketing, Product Marketing + Content Marketing, Growth Marketing + Content Marketing.
2. **Title conservatively.** First marketing hire is almost always Manager or Lead, not VP or CMO. Inflated titles paint the org into a corner when you scale.
3. **Use contractors and small niche agencies for execution.** Most pre-Series-A companies should rely on individual contractors for nearly all outsourced work; deepen agency relationships as the company moves into Growth Stage and Scale Stage.
## What every plan must customize
A generic plan is a failed plan. Every plan must explicitly customize for:
1. **Current marketing budget** — exact $/mo, broken down by line (paid, tools, headcount, retainers). Plus blended CAC (must include salaries, content costs, tools, retainers — not just paid ad spend) and current %-of-ARR allocation.
2. **Unit economics** — ARPC, annual retention rate, LTV. These feed the budget math in Section 8 and Section 10.
3. **Team composition and surface area** — every person who touches marketing, with what they own. Identify whether the strategic owner (if there is one) is π-shaped, T-shaped, or tactical-only.
4. **What the client is currently doing** — by channel, with status (working / not / TBD).
5. **What they've already done that should be acknowledged** — past launches, PR moments, content, partnerships. Don't write a plan that ignores work they're proud of.
6. **Phase of SaaS growth** — $0–10K ARR / $10K–100K / $100K–1M / $1M+. Each phase has its own binding constraint.
7. **Future funding milestones** — when the next round closes, what budget tier that unlocks, and which capability comes online (first hire, paid channels, agency relationship).
8. **The marketing skills mapped to specific moves** — every move in the AARRR sections names the skill that executes it.
9. **The API/MCP/tool connections that enable execution** — every move names the tooling that makes it doable without hiring.
If you can't confirm any of these in INIT, list them in Section 13's "Open decisions" — never gloss over them. **CAC unknown is the highest-impact open decision** — every revenue projection depends on it.
## Common client-type variations
Plan structure stays consistent. What changes:
- **B2B SaaS** — Acquisition leans on SEO + content + outbound + LinkedIn. Activation = signup + product trial. Retention = product engagement + CSM motion. Referral = customer advocacy. Revenue = expansion / NRR.
- **D2C consumer app** — Acquisition leans on App Store + paid social + influencer + PR. Activation = onboarding + first session + paywall. Retention = lifecycle email + push. Referral = sharing mechanics. Revenue = subscription + upsell.
- **Hardware-led** — Acquisition leans on PR + retail + Amazon + Shopify SEO. Activation = unboxing + setup + first use. Retention = software companion + community. Referral = gifting + reviews. Revenue = blended LTV hardware + accessories + subscription.
- **Marketplace** — Activation has two sides (supply + demand). Retention is repeat transaction frequency. Revenue is take-rate × GMV.
- **Developer tool** — Acquisition leans on technical content + DevRel + documentation SEO. Activation = first build / first integration. Retention = depth of integration. Referral = team adoption.
Detail in `references/client-types.md`.
## Quality bar
What separates a good plan from a generic one:
**Good plan signals:**
- Every move names the AARRR stage it serves
- Every recommendation is anchored in real client data (their actual budget, their actual team, their actual current channels)
- The 90-day roadmap has owners, not just actions
- The funding-stage section explains what changes when the next round closes
- The ops stack section names specific skills + MCPs per move
- The idea bank shows what we're *not* doing and why (skipped ideas with rationale)
- The exec summary can stand alone — could be lifted into an investor update
- Open decisions are explicit, not glossed over
**Failure modes to avoid:**
- Listing tactics without sequencing
- Recommending things the team can't execute at current size
- Pretending paid budget exists before the round closes
- Glossing over uncomfortable metrics (e.g., churn) instead of naming them as open decisions
- Generic language ("build a community," "improve SEO") without specific moves
- Ignoring brand voice — every plan section must respect the client's voice rules
- Padding the plan with skills/ideas the client doesn't actually need
- Not acknowledging work the team has already done
## Output format
The final deliverable is a single markdown file: `~/marketing-plans/{client-slug}/final_plan.md`.
Headers (`## 1. Executive summary`, etc.) are H2 for clean Notion paste. Tables for any structured comparison (RACI, idea bank, ops stack). Status legend for the idea bank. Internal references to other sections use `§N` (e.g., "see §5 for Activation detail").
Length expectation: ~8,000–12,000 words for a comprehensive plan. Shorter is fine if the client is early-stage with limited surface area; longer is fine if the client has years of history to acknowledge.
## File layout per plan
```
~/marketing-plans/
└── {client-slug}/
├── materials/ # Client-provided files (decks, audit output, brand-voice doc, etc.)
├── research.md # Research record written during INIT
├── progress.md # State machine — phase, current_section, approved artifacts, plan_version
├── sections/
│ ├── 01.md # Each approved section saved as a canonical artifact
│ └── ... # Zero-padded so they sort in order
└── final_plan.md # Compiled deliverable (FINALIZE output)
```
The full schema for `progress.md` and the resumption decision tree live in `references/methodology.md` Steps 1.1.1 and 1.1.2.
## Related skills
- **`product-marketing`** — Run first. Captures positioning, ICP, voice in `.agents/product-marketing.md` so every section of the plan references the same foundation.
- **`marketing-ideas`** — Source of the 139 tactics in Section 12.
- **`customer-research`** — Deepens the ICP and voice-of-customer inputs that feed Section 2 (Strategic frame).
- **`onboarding`** — Deep work on Section 5 (Activation).
- **`emails`** — Deep work on Section 6 (Retention) + onboarding emails in Section 5.
- **`referrals`** — Deep work on Section 7 (Referral).
- **`pricing`** — Deep work on Section 8 (Revenue).
- **`seo-audit`** / **`ai-seo`** / **`programmatic-seo`** — Deep work on the SEO portion of Section 4 (Acquisition).
- **`ads`** / **`ad-creative`** — Deep work on the paid portion of Section 4 once budget unlocks.
- **`launch`** — Deep work on launch moments inside Section 4 / Section 9.
## Task-specific questions (used during INIT)
The full intake questionnaire lives in `references/methodology.md`. The most important questions:
1. **Funding state** — What round are you in? How much raised so far? Burn? Runway? Upcoming rounds and timing?
2. **Team** — Who are all the people who touch marketing? What does each own? Where are the gaps?
3. **Budget** — What's the current monthly marketing spend, broken down by paid acquisition, tools, retainers, headcount? What budget unlocks when the next round closes?
4. **Current channels** — What's working today? What's not? What have you not tried yet?
5. **Already done** — What past campaigns / launches / content / PR moments should this plan acknowledge?
6. **In-flight** — What's drafted but not shipped? What's blocking each item?
7. **Tooling stack** — What's wired? Customer.io / Mailchimp / Resend? Shopify / Stripe / App Store Connect? GA4 / Mixpanel / Amplitude? GitHub / Notion / Figma?
8. **Beta or GA?** — If product is in beta, what's the GA timeline? Throttling? What gates exist?
9. **The most important thing to fix this quarter** — founder's read.
10. **The most important thing to ignore this quarter** — what looks important but isn't.
## How exhaustive should the plan be?
Default to comprehensive. Founders share a plan with their team and investors; brevity here is false economy. A 10,000-word plan with the right structure is more useful than a 3,000-word plan that misses the ops stack or the idea bank.
That said: don't pad. Every section should be **dense, not bloated**. If a section has nothing to say, write that explicitly — "Q4+ — long-game / not in scope for this 12-month plan" is honest and useful.
## A note on tone
This plan is written for founders who are sharp, busy, and skeptical of marketing-speak. Write like a thoughtful colleague, not a deck-slide-writer. No jargon for jargon's sake. Direct claims, named tradeoffs, explicit assumptions. When unsure, name the open question rather than guessing.
The exec summary should be short enough to read in 60 seconds. The rest should reward deep reading.
FILE:evals/evals.json
{
"skill_name": "marketing-plan",
"evals": [
{
"id": 1,
"prompt": "I'm starting a fractional CMO engagement with a Series A B2B SaaS doing $2M ARR, 12-person team with 1 marketer, $20K/month marketing budget. They want a marketing plan we can share with the team and the board. Build it.",
"expected_output": "Should check for product-marketing.md first. Should ask for client name or use a slug. Should walk through three-phase workflow (INIT → REVIEW → FINALIZE), starting with intake covering funding state, team, budget, channels, what's done, in-flight, tooling stack. Should produce a 13-section AARRR-structured plan: executive summary, strategic frame, current state (scored against the embedded 17-section rubric), Acquisition, Activation, Retention, Referral, Revenue, 90-day roadmap with owner-assigned moves, 12-month outlook with funding-stage capability unlocks, marketing operations stack mapping skills + MCPs to AARRR stages, tactical idea bank cross-referencing all 139 marketing-ideas to AARRR + client-specific status, measurement framework with north-star + leading indicators + RACI + open decisions. Should be ~8–12K words, Notion-paste-ready. Should be specific to the client (their budget, team, channels), not generic.",
"assertions": [
"Checks for product-marketing.md",
"Asks for client name or uses a slug",
"Walks through INIT phase with structured intake",
"Produces 13-section plan structured by AARRR",
"Section 3 scores against the embedded 17-section rubric",
"Section 9 (90-day roadmap) has owner-assigned moves, not just actions",
"Section 10 names funding-stage capability unlocks explicitly",
"Section 11 maps marketing skills + MCPs to each AARRR stage",
"Section 12 cross-references all 139 marketing-ideas with client-specific status",
"Output is Notion-paste-ready markdown",
"Plan is specific to the client (their budget, team, current channels), not generic"
],
"files": []
},
{
"id": 2,
"prompt": "We're pre-seed bootstrapped, $0 paid marketing budget, 4-person team building a D2C consumer app. Founder wants a 90-day plan + 12-month roadmap they can show investors during the upcoming raise. The product is in beta.",
"expected_output": "Should recognize Tier 1 funding profile (pre-seed) and skip paid acquisition recommendations until budget unlocks. Should lean Acquisition heavy on organic + lifecycle + ambassador moves. Should explicitly map what unlocks when seed closes (paid test budget $5–15K/mo, first marketing hire, etc.). Should respect that the product is in beta and account for activation/throttling gates. Should include the AARRR diagnostic — likely binding constraint at this stage is Activation (onboarding) and Referral. Plan must be investor-friendly: exec summary can be lifted into an update.",
"assertions": [
"Recognizes pre-seed tier and uses Tier 1 budget profile",
"Skips paid acquisition recommendations until budget unlocks",
"Leans Acquisition on organic + lifecycle + ambassador",
"Names what unlocks when seed closes",
"Accounts for product being in beta",
"Identifies binding-constraint AARRR stage (likely Activation or Referral)",
"Executive summary can be lifted into an investor update",
"Plan is operationally honest — doesn't pretend paid budget exists"
],
"files": []
},
{
"id": 3,
"prompt": "we have an audit already done — can you take that and turn it into a real plan",
"expected_output": "Should ask for the audit output (file path or paste). Should recognize that current-state scoring already exists and ingest it directly into Section 3 — don't re-score. Should note scoring date in case material has shifted since. Should proceed with full 13-section plan generation using audit findings to inform 90-day roadmap and AARRR sections (gaps from audit become moves in the plan).",
"assertions": [
"Asks for the audit output",
"Ingests prior audit scoring directly into Section 3",
"Does not re-score what's already been scored",
"Notes the scoring date and flags any shifted material",
"Uses audit gaps to inform 90-day roadmap and AARRR section moves",
"Still produces a full 13-section plan, not just Section 3"
],
"files": []
},
{
"id": 4,
"prompt": "/marketing-plan acme-saas — pick up where we left off",
"expected_output": "Should read ~/marketing-plans/acme-saas/progress.md to determine state machine phase. Should resume from the next unfinished section in REVIEW phase, or transition to FINALIZE if all sections approved. Should NOT silently restart from scratch. If progress.md is missing or shows 'finalized', should ask: revise as v{N+1}, start fresh, or re-open a section.",
"assertions": [
"Reads ~/marketing-plans/acme-saas/progress.md",
"Resumes from next unfinished section based on state machine",
"Does not silently restart from scratch",
"Handles finalized state by asking user how to proceed (revise / fresh / re-open)",
"Saves each newly confirmed section to the progress file"
],
"files": []
},
{
"id": 5,
"prompt": "I need a plan for a hybrid hardware+software wellness company. They sell a physical product and a subscription app. Series A, $100K/month marketing budget, 8-person team including a marketing lead.",
"expected_output": "Should recognize hybrid hardware+software archetype and consult references/client-types.md for archetype-specific emphases. Acquisition leans PR + retail + Amazon + Shopify SEO + paid. Activation = unboxing + setup + first session + paywall. Retention = lifecycle + community. Referral = gifting + reviews. Revenue = blended LTV (hardware + subscription + accessories). Should recognize Series A tier and recommend appropriate paid spend. Should include cross-cutting brand + customer-research moves. Idea bank should skip ideas that conflict with premium positioning or hardware constraints.",
"assertions": [
"Recognizes hybrid hardware+software archetype",
"Acquisition leans on PR, retail, Amazon, Shopify SEO, paid",
"Activation covers unboxing, setup, first session, paywall",
"Retention covers lifecycle, community",
"Referral covers gifting, reviews",
"Revenue covers blended LTV with hardware + subscription + accessories",
"Recognizes Series A tier in budget recommendations",
"Idea bank skips ideas that conflict with brand fit, with explicit rationale"
],
"files": []
},
{
"id": 6,
"prompt": "Just give me a quick marketing plan. Don't make it long.",
"expected_output": "Should resist defaulting to a short plan. Should explain that a marketing-plan is the comprehensive fCMO-deliverable artifact (~10K words) and that for a single-channel quick plan, the channel-specific skill is the right tool (emails, ads, seo-audit, etc.). Should offer alternatives: (a) full marketing-plan as designed, or (b) point to a specific skill for the user's actual need. Should NOT silently produce a stripped-down 3K-word plan that misses the ops stack or the idea bank.",
"assertions": [
"Resists short-plan request and explains why",
"Names marketing-plan as the comprehensive fCMO artifact",
"Recommends channel-specific skills for single-channel quick plans",
"Offers alternatives clearly",
"Does not silently produce a stripped-down plan"
],
"files": []
},
{
"id": 7,
"prompt": "A founder wants a plan but keeps asking 'what's the one channel that will make us blow up?' They also want a defensible way to split the budget so they don't starve future growth, and a way to know when a channel is running out of steam. Frame the strategic thinking for the plan.",
"expected_output": "Should push back on silver-bullet thinking with the marketing-as-investing framing — a compounding portfolio, 'no silver bullets, a hundred golden pellets,' one asset that ranks + earns backlinks + feeds the newsletter + becomes a talk, audition not an auction, hope is not a strategy. Should apply the problem size x frequency market-quality gate to sanity-check whether the product is even in a build-big-and-frequent quadrant. Should introduce the 70/20/10 resource-allocation rule (current / next / experimental) so future growth stays funded. Should introduce a weekly tracking cadence with plateau-indicator alerts (flattening week-over-week additions, rising CAC, effort up / output flat) that trigger shifting weight to the next S-curve. Should tie these into Section 2 (Strategic frame), Section 10 (12-month outlook), and Section 13 (Measurement).",
"assertions": [
"Rejects silver-bullet framing using marketing-as-investing / compounding portfolio",
"Uses the 'no silver bullets, a hundred golden pellets' and 'audition, not an auction' framing",
"Invokes 'hope is not a strategy' — every move has a mechanism and leading indicator",
"Applies the problem size x frequency market-quality gate",
"Introduces the 70/20/10 resource-allocation rule (current / next / experimental)",
"Introduces a weekly tracking cadence with plateau-indicator alerts",
"Ties plateau alerts to shifting weight toward the next S-curve",
"Maps the framing to Section 2, Section 10, and Section 13"
],
"files": []
}
]
}
FILE:references/aarrr-framework.md
# AARRR Framework — Primer for Plan Sequencing
AARRR (Dave McClure's "pirate metrics") is the spine of every plan produced by this skill. This doc is the primer + the decision rules for when each stage gets prioritized.
## The five stages
| Stage | Question | Common metrics |
|---|---|---|
| **A**cquisition | How do strangers become aware of us? | Visits, MQLs, signup-page sessions, app-store visits, CAC by channel |
| **A**ctivation | Once they try us, do they have an experience that converts? | Signup completion rate, time-to-value, % completing first key action, trial → paid rate |
| **R**etention | Do they stay and deepen? | DAU/WAU/MAU, week-1/4/12 retention, churn |
| **R**eferral | Do retained users bring more users? | Viral coefficient, NPS, ambassador attribution |
| **R**evenue | What do they pay, who pays, how does it compound? | ARPU, LTV, expansion revenue, ARR / MRR |
> **Signup boundary rule.** Signup *intent* (a stranger landing on the signup page) is Acquisition. Signup *completion* and everything after (first key action, trial-to-paid) is Activation. Apply this rule consistently across all docs and the plan template.
## Why AARRR for plan sequencing
Three reasons.
**1. Funnel-stage tagging forces prioritization.** Without AARRR, marketing plans become channel-organized ("here's the SEO plan, here's the social plan, here's the paid plan"). Channels can address multiple stages; tagging by stage instead asks the more useful question: *what stage of the funnel is the binding constraint right now?*
**2. Fix the leak before pouring water in.** The Activation/Retention question ("does the funnel convert at acceptable rates given exposure?") is usually higher leverage than the Acquisition question ("how do we get more exposure?"). AARRR sequencing surfaces this naturally.
**3. The Revenue / Referral conversation is honest.** Most marketing plans bury monetization under "growth" and treat referral as wishful thinking. AARRR forces explicit treatment of both.
## Brand and content — not a stage, cross-cutting
A common mistake: making "Brand" or "Content" the sixth bucket. They're not — they serve every stage.
- **Brand voice** governs every piece of copy across every stage
- **Content** feeds Acquisition (SEO, social), Activation (onboarding copy), Retention (email lifecycle), Referral (ambassador talking points), Revenue (pricing pages, sales material)
In the plan, brand/content shows up as the strategic frame (Section 2) and cross-cutting in Section 11's ops stack — never as its own AARRR section.
## Diagnosing the binding constraint — which AARRR stage is highest leverage?
For every client, one or two AARRR stages will be the binding constraint. The plan sequences moves there first.
**Decision rules:**
### If you don't have any users → start with Acquisition
- Pre-launch / day-0 / waitlist stage
- No funnel data exists
- Leverage = building the first 100 users
### If you have users but they bounce → start with Activation
- Signups happen but activation rate is low
- App Store conversion is poor
- Onboarding completion is broken
- Day 1 → paid rate is much lower than Day 30 → paid (means product converts given time but onboarding doesn't bridge to it)
- Leverage = bridging signup to first felt value
### If activation works but users churn → start with Retention
- Month 1 retention is below category norms
- Activated users stop using within 7–14 days
- LTV is short
- Leverage = lifecycle, deepening engagement, churn prevention
### If retention is strong but growth is slow → start with Referral / Revenue
- Retained users love the product but don't share
- Inbound referrals come in unstructured
- Pricing hasn't been pressure-tested
- ARPU is low for the value delivered
- Leverage = WOM mechanics + pricing optimization (these often cluster)
### If everything works at small scale → start with Acquisition (scaling)
- Funnel is healthy
- Question is just "more"
- This is the "post-fit" scaling problem
## Stage-by-stage strategic patterns
### Acquisition
**The diagnostic question:** Where is the gap between TAM-level awareness and current funnel volume? What channels are saturated by competitors vs. open?
**Common Acquisition moves:**
- SEO content strategy (organic compounding)
- Founder-led channels (LinkedIn, X, Substack for B2B; Instagram/TikTok for D2C)
- Paid acquisition (when budget unlocks)
- App Store / Play Store / marketplace listing optimization
- PR and credibility-anchor amplification
- Events (live, webinar, conference speaking)
- Partnerships (newsletter swaps, integration co-marketing, reseller / agency partners)
- Hardware / commerce surface (Shopify SEO + Amazon for hybrid businesses)
- B2B sales support (case studies, partner pages, vertical content)
**Sequencing principle:** Build the organic compound first (SEO + founder-led + content + PR amplification + ambassadors). Only layer paid on top of a working organic baseline. Premature paid amplifies what's broken.
### Activation
**The diagnostic question:** Where in the user's first session do they decide "this works for me" or "this doesn't"? What stops them from reaching that moment?
**Common Activation moves:**
- Bedrock fixes (broken gates, broken signup steps, broken paywall)
- Onboarding tests / rebuild (often the most leveraged single move)
- App Store listing rewrite (the threshold to the trial)
- Lifecycle Flow ship order (when to ship onboarding emails)
- Paywall structure + trial length
- Free → paid bridge (in-app upsells, soft paywalls)
**Sequencing principle:** Get to first felt value as fast as possible. Everything that adds friction between "user opens app" and "user has the experience that converts them" is a candidate to cut.
### Retention
**The diagnostic question:** Why do users churn? What would have made them stay? What's the "second moment of value" after the first one?
**Common Retention moves:**
- Lifecycle email flows: onboarding, lapsed user re-engagement, post-purchase, win-back
- Subscription / preference centers
- Churn reconciliation (often metric definitions don't match across surfaces)
- Hardware → software activation paths (for hybrid businesses)
- Annual plan defaults / pricing structure (cross-cuts Revenue)
- Support as marketing (high-touch moments that drive stories)
- Community + practitioner networks
**Sequencing principle:** Ship lifecycle flows in the order their content is most stable. Hardware post-purchase flows ship first (they don't reference in-app screens that might change). Onboarding emails ship last (they reference UI that might change). Win-back is a quarterly campaign, not a one-time flow.
### Referral
**The diagnostic question:** Is there inbound referral interest that isn't being captured? What's the share-after-value moment that's natural to the product?
**Common Referral moves:**
- Ambassador / affiliate program (start with inbound interest, not cold recruitment)
- Share-after-value moments built into the product (reflection prompts, milestone celebrations)
- Founder amplification (founder as referrer-zero)
- Long-game expert / Guides / certified-host networks (for category-creating businesses)
- Gifting flows (consumer / hardware)
- Two-sided referrals (reward both referrer and referred)
**Sequencing principle:** Lead with whoever is already raising their hand. If there are 5 inbound ambassadors, launch with those 5 — don't wait for a "complete program." Iterate based on what they tell you.
### Revenue
**The diagnostic question:** Is the company underpricing? Underpackaging? Missing an upsell? What's the "right" price discipline given LTV and brand voice?
**Common Revenue moves:**
- Pricing audit (what's actually charged today vs. listed?)
- Annual plan defaults
- Hardware → software bundling formalization
- Storefront / commerce page optimization
- B2B case studies + sales material
- Long-term value pool flags (data, expansion, enterprise) — flagged not executed
**Sequencing principle:** Run the pricing audit before testing changes. Surprisingly often, the "implied" pricing on the dashboard doesn't match the listed price — discounts, trials, or plan mix distorts the read. Surface the ground truth first.
## How to assign a move to a stage
Some moves clearly belong to one stage. Others span. The rule:
**Assign to the stage where the move's primary measurable impact lands.**
Examples:
- "Rewrite App Store listing in voice" — spans Acquisition (organic discovery) and Activation (threshold to trial). Primary impact = Activation (trial conversion rate). Assign to Activation, mention crossover.
- "Eye mask Shopify page rewrite" — spans Acquisition (organic search for sleep mask) and Revenue (sale conversion). Primary impact = Revenue (transaction). Assign to Revenue, mention crossover.
- "Alex's LinkedIn cadence" — Acquisition (top of funnel for D2C subscribers).
- "Customer.io Flow 6 (eye mask post-purchase)" — Retention (deepens hardware buyer engagement) with crossover to Activation (hardware → app premium activation path).
When in doubt: where would removing this move hurt the most? Assign there.
## When the AARRR breakdown isn't equal
For most clients, the plan won't have equal volume across stages. That's fine — and worth surfacing as a diagnostic.
- **Heavy Acquisition section** = client has product-market fit but top-of-funnel is the bottleneck. Common for early-stage with strong retention metrics.
- **Heavy Activation section** = client has traffic but conversion is broken. Often beta-stage products.
- **Heavy Retention section** = client has churn problem. Often mid-stage products that scaled past PMF without lifecycle infrastructure.
- **Heavy Referral section** = client has loyalty but no WOM mechanics. Often consumer products with passionate users.
- **Heavy Revenue section** = client is underpricing or missing monetization layers. Common for tools transitioning from free to paid.
If a plan ends up evenly distributed across all five stages, the diagnostic was probably weak — re-examine the funnel state intake to find where the binding constraint is.
## A note on the order of presentation
Always present AARRR in order (Acquisition → Activation → Retention → Referral → Revenue) regardless of priority order.
This is for the reader's mental model. Founders expect the funnel to flow top-to-bottom. If Retention is the most-leveraged stage but you lead with Retention, the reader has to context-switch.
To signal priority, use the executive summary (Section 1) — name the biggest bets there. The AARRR breakdown then walks the funnel in order, with the most leverage-positive section being the longest and most-detailed.
FILE:references/budget-planning.md
# Budget Planning — Scientific Methods for Setting the Marketing Budget
The problem with most SaaS marketing budgets is that they're pulled out of thin air — a number that hopefully doesn't constrain growth too much, but doesn't anchor in customer-acquisition economics either. The result: when someone asks "why this number?" there's no answer.
Two scientific methods solve this. Use one (not both) in Section 8 (Revenue) and Section 10 (12-month outlook) of every plan.
Excerpted and adapted from *Founding Marketing* by Corey Haines.
## Method 1 — Revenue-Based (5–40% of annual revenue)
**Direction:** budget → revenue goal.
You start with what the company can comfortably spend on marketing, then forecast what revenue that spend can plausibly generate.
### The ranges
| Posture | % of ARR | When to use |
|---|---|---|
| **Conservative (profit-preserving)** | 5% | Established business focused on profit distribution; bootstrapped; founder-paid customer base |
| **Standard growth** | 15–25% | Most healthy SaaS in the seed-to-Series-A range |
| **Aggressive growth (deploying raised capital)** | up to 40% | Recently funded round, mandate to deploy fast, board accepts burn |
For reference: public SaaS companies routinely report sales-and-marketing spend between 20% and 55% of revenue (Zoom historically ran between 20% and 55% across years).
### The math (Conservative example)
Business at $1M ARR, 5% allocation:
- Annual marketing budget: **$50,000**
- Blended CAC: $100 → can acquire **500 new customers**
- ARPC: $50/mo → adds **$300K** to ARR
- Account for 15% annual churn → 85% × $300K = **+$255K net new ARR**
- End-of-year goal: **$1.255M ARR**
### The math (Aggressive example)
Business at $1M ARR, 40% allocation:
- Annual marketing budget: **$400,000**
- Blended CAC: $100 → can acquire **4,000 new customers**
- ARPC: $50/mo → adds **$2.4M** to ARR
- End-of-year goal: **$3.4M ARR**
### Two keys to making this method work
1. **Know your blended CAC** (see "Calculating CAC" below)
2. **Match the allocation percentage to your actual ambition.** A founder running 5% allocation while telling the board they expect to triple revenue is showing two incompatible signals.
## Method 2 — Goal-Based (reverse-engineered from the revenue target)
**Direction:** revenue goal → budget.
You start with the revenue goal and work backward through the unit economics to derive the budget required to hit it. Best for:
- Companies just starting up (no historical CAC baseline yet, working from first principles)
- Companies anticipating outside capital (need to defend the ask)
- Companies using revenue-based financing (Pipe, Capchase, Founderpath)
### The formula
```
Marketing budget = [(New ARR / (ARPC × 12)) × CAC] / annual retention rate
```
### Worked example: $1M ARR → $2M ARR
Step 1 — How much new ARR per customer?
ARPC × 12 = $50 × 12 = **$600 ARR per new customer**
Step 2 — How many new customers do we need?
$1,000,000 / $600 = **1,667 new customers**
Step 3 — What's the raw acquisition cost?
1,667 × $100 CAC = **$166,700**
Step 4 — Account for churn (15% annual = 85% retention)
$166,700 / 0.85 = **$196,118** (round to **$200K**)
When someone asks how you got to the budget, walk them through the four steps. It's defensible.
### Why this formula and not something simpler
The four steps each correspond to a real economic reality:
- Step 1 converts MRR-language into the ARR-language a board talks in
- Step 2 names the customer count, which is what the funnel actually has to deliver
- Step 3 anchors the budget in the cost of acquisition
- Step 4 acknowledges that churned customers don't count toward net new ARR, so the budget needs to cover the gap
### Required buffer
**Always add 10–20% as "experimental budget"** on top of the formula output. CAC is the main dependency; if CAC comes in 50% higher than estimated, the cascading effect is missing the revenue goal. It is much cheaper to overestimate CAC than to underestimate it.
The experimental budget also funds the experiments that find your next channel before your current one plateaus (see `growth-patterns.md` — channel S-curves).
## The VC growth path (3-3-2-2-2 rule)
Once a company has crossed $1M ARR and taken a Series A, the implicit benchmark VCs expect is:
| Year | ARR multiple | Cumulative ARR (from $1M start) |
|---|---|---|
| Year 0 | — | $1M |
| Year +1 | 3× | $3M |
| Year +2 | 3× | $9M |
| Year +3 | 2× | $18M |
| Year +4 | 2× | $36M |
| Year +5 | 2× | $72M |
| Year +6 | 2× | $144M |
| Year +7 | 2× | $288M |
That's the 3-3-2-2-2 rule. Useful when:
- The plan needs to map 12-month and 36-month milestones to VC expectations
- The founder is mid-raise and the board needs to see a plausible path to the next round
- Section 10 (12-month outlook) needs anchoring against an industry benchmark, not just internal ambition
Most companies miss it. That's fine. Knowing the benchmark gives the team a defensible reason to either match it or explicitly choose not to.
## Calculating CAC (blended, not paid-only)
If there's no historical CAC, use a baseline: **one year of revenue from the smallest paid plan.** Deploy the budget, capture actual CAC data, replace the baseline with the measured number for the next planning cycle.
For an established CAC calculation, **CAC must be blended.** Include:
- Marketing salaries (full loaded cost, not just base)
- Advertising spend
- Marketing tech stack costs
- Content production costs (writers, designers, video editors)
- Agency / contractor retainers
- SDR / BDR salaries if doing outbound
- Tools (CRM, marketing automation, analytics)
Then divide by the number of new customers acquired in the period. That blended number is the one to use in either budgeting method.
The mistake to avoid: calculating CAC from paid ad spend alone. A company that "doesn't run ads" still has a CAC — it's just hidden in the content team, the founder's time, the SEO contractor, the conference booth.
## The reality check on forecasting
This whole framework derives a budget and a revenue goal — not a 12-month month-by-month forecast accurate to the dollar.
**Unless the company is publicly traded, all forecasts are educated guesses.** No startup under $100M ARR reliably hits forecasts to the month. The honest framing for the plan:
- The annual goal is a defensible direction-of-travel
- The budget is the resource commitment that makes the goal plausible
- The 90-day roadmap (Section 9) is what's actionable now
- Month-to-month variance is expected; quarterly review is when the plan adjusts
What's actionable: how to deploy the budget, what concrete moves to execute, what to adjust when real data comes in.
What's not actionable: trying to forecast traffic, pipeline, retention curves, conversion rates, and channel mix all down to the decimal point and expecting that forecast to hold. Founders who over-engineer the forecast tend to spend the plan period explaining variance instead of executing.
**Rule for the plan:** the budget number is honest. The annual goal is honest. The month-by-month projection is illustrative.
## How this flows into the plan
| Section | What to include |
|---|---|
| **3 (Current state)** | Current monthly marketing spend broken down by line (paid, tools, content, headcount, retainers). Compute current %-of-ARR allocation. |
| **8 (Revenue)** | The unit-economics table (CAC, ARPC, churn) that feeds whichever budget method you're using. |
| **10 (12-month outlook)** | Apply Method 1 or Method 2 to derive the 12-month budget and the resulting revenue goal. Anchor against the 3-3-2-2-2 rule if Series A+ and VC-backed. |
| **11 (Ops stack)** | Show the budget allocation across the AARRR stages — what % to Acquisition, Activation, etc. The ops-stack mapping informs which line items grow when the next funding tier unlocks. |
| **13 (Open decisions)** | If CAC is unknown or contested, flag it as the highest-impact open decision — every other number depends on it. |
## When to choose which method
- **Method 1 (Revenue-Based)** when the company has historical CAC data, a profit/burn posture, and the question is "given our posture, what's a plausible goal."
- **Method 2 (Goal-Based)** when the company has a specific goal (board mandate, VC milestone, fundraise target) and the question is "what budget do we need to hit it."
For most plans in the seed-to-Series-A range, Method 2 is more useful — it forces the conversation about whether the goal is funded.
FILE:references/client-types.md
# Client Types — Variations by Business Model
The 13-section plan structure stays consistent across client types. What changes is the **content emphasis** within each section. This doc names the dominant patterns by client archetype.
## Archetype 1 — B2B SaaS
### Core characteristics
- Subscription revenue
- Often higher ACV ($1K–$100K+ per year)
- Sales-assisted or self-serve depending on tier
- Buyer often different from user (champion vs. end-user)
### AARRR emphasis
**Acquisition heavy:**
- SEO is the dominant top-of-funnel motion (people search for solutions)
- Content marketing (blog, knowledge base, comparison pages) drives MQLs
- LinkedIn for both organic founder presence and paid
- Outbound (cold email + LinkedIn) often complements inbound
- Events (conferences, webinars) for high-ACV products
**Activation:**
- Signup → trial → first key action (PLG products)
- Trial → demo → POC (sales-led products)
- Empty states matter — guide users to first value action
**Retention:**
- Product engagement metrics (DAU, feature adoption)
- Customer success motion (CSM team for higher ACV)
- Lifecycle emails focused on feature discovery, value moments
**Referral:**
- Customer advocacy programs
- Partner / integration co-marketing
- G2 / Capterra reviews
- Champion-to-buyer expansion
**Revenue:**
- Expansion / NRR is often the biggest growth lever
- Tier upgrades, seat expansion, usage-based add-ons
### Skills emphasis
- `cold-email`, `programmatic-seo`, `competitors`, `seo-audit`, `ai-seo`
- `ads` weighted toward LinkedIn + Google
- `emails` for trial nurture + lifecycle
- `pricing` for tier optimization
### Tier-1 budget priority
- SEO + content > everything else
- Founder-led LinkedIn channel
- Customer.io / Mailchimp for nurture
- HARO + investor backchannel for PR
---
## Archetype 2 — D2C Consumer App (Subscription)
### Core characteristics
- Lower ACV ($5–$30/mo typically)
- High volume, lower margin per user
- App Store / Play Store as the primary acquisition surface
- Lifecycle email + push for retention
- Often paid-acquisition-driven once budget unlocks
### AARRR emphasis
**Acquisition:**
- App Store Optimization (ASO) is the highest-leverage non-site asset
- Paid social (Meta, TikTok) often dominant once budget exists
- Apple Search Ads for high-intent App Store traffic
- Influencer + content creators
- PR + endorsements
**Activation:**
- Onboarding is the dominant activation surface
- Time-to-value must be minutes, not hours
- Paywall structure + trial length critical
**Retention:**
- Lifecycle email + push
- In-app reminders (carefully — overuse = churn)
- Subscription preference center
- Win-back campaigns
**Referral:**
- Built-in sharing (share-a-month flow)
- Two-sided referrals
- Influencer / creator ambassadors
**Revenue:**
- Annual plan default is the biggest single move (compresses MRR but improves LTV)
- Tier optimization (Free → Premium → Premium+)
- In-app upsells
### Skills emphasis
- `onboarding`, `paywalls`, `emails`
- `ads`, `ad-creative` (heavy creative iteration)
- `referrals`
- `pricing` for annual default + tier consolidation
### Tier-1 budget priority
- ASO first (highest organic leverage)
- Onboarding rebuild
- Lifecycle email shipping
- Founder-led social if founder is on-camera
---
## Archetype 3 — Hybrid Hardware + Software
### Core characteristics
- Physical product + software companion (e.g., Quietude's eye mask + app)
- Hardware as a distribution wedge (lower price, easier first purchase)
- Software as the LTV (recurring revenue)
- Blended CAC across both surfaces
### AARRR emphasis
**Acquisition:**
- Shopify storefront SEO (hardware product pages target consumer search)
- Amazon listing (high-discovery, takes margin)
- PR amplification (hardware is photogenic — high-profile influencer endorsements move volume)
- Paid social for hardware (Meta + Instagram, eye-catching creative)
**Activation:**
- Two activations to track: hardware unboxing experience + software signup
- Hardware → software activation flow is the bridge
- Concierge setup for high-value hardware buyers
**Retention:**
- Hardware post-purchase lifecycle (different from app onboarding)
- Software companion drives stickiness
- Community / practitioner network around hardware
**Referral:**
- Hardware gifting flows (high WOM for physical products)
- Eye-catching hardware drives organic social sharing
- Reviews on Shopify + Amazon
**Revenue:**
- Blended LTV math is critical (hardware margin + software recurring)
- Bundle strategy (hardware buy → free Premium for X months)
- Annual plan default for software
### Skills emphasis
- `seo-audit` for Shopify product pages
- `emails` for both hardware post-purchase and software lifecycle
- `referrals` with gifting layer
- `pricing` for blended-bundle math
- `ads` with creative-heavy Meta presence
### Tier-1 budget priority
- Shopify product page optimization
- Hardware post-purchase lifecycle ship
- Bundle strategy formalization
- Hardware → app activation audit
---
## Archetype 4 — Marketplace
### Core characteristics
- Two-sided product (supply + demand)
- Network effects matter
- Liquidity is the critical early metric
- Take-rate × GMV is the revenue model
### AARRR emphasis
**Acquisition:**
- Two funnels — supply and demand
- Supply often acquired through outbound / partnership / cold email
- Demand often acquired through SEO / paid / content
- City-by-city programmatic SEO common
**Activation:**
- Supply activation: first listing posted, first response sent
- Demand activation: first purchase / first match / first transaction
- Both sides need their own onboarding
**Retention:**
- Repeat transaction frequency
- Supply utilization (% of listings active)
- Demand habit (DAU / MAU)
**Referral:**
- Supply → supply (refer other providers)
- Demand → demand (refer other buyers)
- Cross-side referrals are weaker
**Revenue:**
- Take-rate optimization
- Premium tier (better matching, lower fees)
- Lead-gen vs. transaction-fee monetization
### Skills emphasis
- `programmatic-seo` for city pages, vertical pages
- `cold-email` for supply-side recruitment
- `referrals` for both sides
- `pricing` for take-rate decisions
### Tier-1 budget priority
- Programmatic SEO build for one side
- Cold outbound to seed supply (or demand, whichever is bottleneck)
- Lifecycle email for both sides
---
## Archetype 5 — Developer Tool / Open Source
### Core characteristics
- Technical buyer (developer or eng leader)
- High bar for content quality (developers are skeptical)
- DevRel matters more than traditional marketing
- Open source layer often funnel into commercial product
### AARRR emphasis
**Acquisition:**
- Technical content + docs SEO
- DevRel (conferences, talks, community)
- GitHub presence + npm/pip/etc. discovery
- Hacker News + Reddit + dev Twitter
**Activation:**
- First build / first integration is the activation event
- Time-to-Hello-World matters
- Documentation = onboarding for dev tools
**Retention:**
- Depth of integration (using more of the product)
- Team adoption (one user → entire org)
- Active project count
**Referral:**
- Star count on GitHub (semi-organic)
- Recommendation in technical forums
- Conference talks mentioning the tool
**Revenue:**
- Free → paid conversion when usage exceeds limits
- Team plans, enterprise tiers
- Support / SLA upsells
### Skills emphasis
- `programmatic-seo` for docs
- Less emphasis on traditional `ads`
- Heavy `content-strategy` + technical content
- `cold-email` to engineering leads at target companies
### Tier-1 budget priority
- Docs + technical content production
- DevRel (founder doing talks)
- GitHub presence
- HN / Reddit / dev community
---
## Archetype 6 — Deep-Tech / Scientific / Clinical
### Core characteristics
- Long sales cycles
- Heavy credibility burden (must prove the science)
- Highly informed buyers (academics, clinicians, researchers)
- Often regulatory considerations
### AARRR emphasis
**Acquisition:**
- Academic publishing + peer-reviewed studies
- Conference speaking (academic + industry)
- Investor / advisor introductions
- PR via credibility hooks
**Activation:**
- Pilot programs / proof-of-concepts
- Concierge setup with high-touch onboarding
- Educational webinars / training
**Retention:**
- Customer success heavily
- Co-publication with customers
- Community of practice
**Referral:**
- Academic / clinical references
- Conference panel features
- Case studies with named institutions
**Revenue:**
- Pilot → paid expansion
- Institutional contracts (multi-seat / multi-year)
- Compliance / certification upsells
### Skills emphasis
- Light traditional marketing
- Heavy `product-marketing`, `sales-enablement`, `pricing`
- `cold-email` to specific researchers / practitioners
- PR + investor marketing
### Tier-1 budget priority
- Academic outreach + conference speaking
- Investor backchannel for institutional warm intros
- Pilot deployment with key customers
- Case study + scientific publication
---
## Archetype 7 — Commerce / DTC (non-subscription)
### Core characteristics
- Physical or digital products sold transactionally
- Average Order Value matters
- Repeat purchase rate is the key retention metric
### AARRR emphasis
**Acquisition:**
- Paid social (Meta, TikTok) often dominant
- Shopify SEO for product pages
- Amazon listings
- Influencer + creator partnerships
**Activation:**
- First purchase is the activation event
- Cart abandonment recovery
- Trust signals on checkout (reviews, returns, shipping)
**Retention:**
- Post-purchase lifecycle
- Loyalty programs
- Email + SMS for repeat purchase
**Referral:**
- Gifting flows
- Refer-a-friend programs
- Reviews + UGC
**Revenue:**
- AOV optimization (bundles, upsells)
- Customer LTV optimization (repeat purchase frequency)
- Subscription option for repeat purchases
### Skills emphasis
- `ads` + `ad-creative` (heavy weight)
- `emails` for post-purchase + abandoned cart
- `referrals` with gifting
- `pricing` for bundles + subscription option
### Tier-1 budget priority
- Shopify storefront optimization
- Email lifecycle ship
- Influencer / UGC seeding
- Paid social testing (if minimal budget exists)
---
## How to use this doc when drafting a plan
When you start drafting Sections 4–8 (AARRR), identify the client's archetype (or hybrid if applicable) and lean into the patterns above.
**Hybrid cases are common.** Quietude is "Hybrid hardware + software" with significant overlap to "Deep-tech / scientific / clinical" (because of the peer-reviewed study + clinical positioning). The plan blends emphases from both archetypes.
When in doubt, lead with the archetype that best fits the *primary monetization model*. Quietude's primary monetization is software subscription (with hardware as the wedge), so the D2C consumer app + hardware-hybrid patterns dominate, with deep-tech credibility moves layered in.
## When the client doesn't fit cleanly
Some clients defy archetype:
- **Content / media businesses** — neither SaaS nor commerce; ad revenue or subscription model
- **Social networks** — own category, network effects dominate
- **Real estate / events** — physical + service model
For these, identify the closest archetype and adjust. Don't force-fit — name the deviation in the plan's Strategic Frame.
FILE:references/current-state-rubric.md
# Current State Rubric — 17-Section Scoring Lens
This 17-section rubric is the source of truth for Section 3 ("Current State") of every marketing plan. Score each section 0–5 from available materials, then write a 2–4 sentence "shape interpretation" that names where strengths and gaps cluster.
## How to score
**From rich materials.** When the team has shared decks, prior content audits, a brand voice doc, kickoff transcript, app store and analytics snapshots — score each section from those artifacts. Mark "scored from materials" in the section heading so the team can push back where they have better data.
**From a separately scored audit.** If the team has already run a scored current-state assessment (in any format), ingest those scores directly. Don't redo the work — note the date the rubric was scored and flag any sections where material has shifted since.
Either way, the output is the same: a 17-row scored table, a total out of 85, and a shape paragraph.
## The 17 sections (scored 0–5 each)
### 1. Positioning
**What's scored:** Clarity of category claim, differentiation, alignment across surfaces (homepage, app store, pitch deck, founder messaging).
**Score guide:**
- 0 = No positioning anywhere
- 2 = Inconsistent across surfaces; team can't articulate it on demand
- 4 = Clear, original, mostly consistent; minor surface gaps
- 5 = Distinctive, category-defining, every surface aligned
**Maps to AARRR:** Cross-cutting — feeds every stage.
### 2. Customer research
**What's scored:** Depth and recency of customer research, ICP clarity, voice-of-customer capture.
**Score guide:**
- 0 = No formal research, only founder intuition
- 2 = Some research but stale or one-off
- 4 = Active research practice, customer language captured
- 5 = Continuous research, customer language flows into copy / product / messaging
**Maps to AARRR:** Cross-cutting — feeds especially Acquisition (channel choice) and Activation (onboarding voice).
### 3. Homepage
**What's scored:** Headline clarity, voice alignment, conversion architecture, mobile experience.
**Score guide:**
- 0 = Generic / broken / off-brand
- 2 = Functional but underperforming; voice mostly absent
- 4 = Clear, voice-aligned, converting; minor optimization opportunities
- 5 = Distinctive, converts strongly, fully voice-aligned
**Maps to AARRR:** Acquisition + Activation.
### 4. Sales / product pages
**What's scored:** Existence and quality of dedicated product / pricing / feature pages. Are SKUs documented? Is pricing scannable? Are upsells visible?
**Score guide:**
- 0 = No dedicated pages
- 2 = Pages exist but are stale or off-voice
- 4 = Quality pages for primary products; gaps on secondary
- 5 = Every product, tier, and upsell has a high-converting page
**Maps to AARRR:** Acquisition + Revenue.
### 5. Conversion pages
**What's scored:** Landing pages for specific campaigns, channels, or use cases. `/partner`, `/science`, `/ambassadors`, `/eye-mask` types of pages.
**Score guide:**
- 0 = No conversion pages
- 2 = One or two exist; rest of needed pages missing
- 4 = Most needed conversion pages exist; quality is good
- 5 = Full conversion page library, each high-converting
**Maps to AARRR:** Acquisition + Activation.
### 6. Competitor comparison
**What's scored:** Existence of "vs. {competitor}" pages, comparison content. Does the brand acknowledge alternatives, or pretend they don't exist?
**Score guide:**
- 0 = Nothing — actively avoiding competitor mentions
- 2 = Some content exists but is weak or hidden
- 4 = Solid comparison pages for top 2–3 competitors
- 5 = Comprehensive comparison library; SEO-targeted; high-converting
**Maps to AARRR:** Acquisition (consideration-stage SEO + sales enablement).
### 7. Resources / content
**What's scored:** Blog, knowledge base, science page, whitepapers, research, founder essays, podcast.
**Score guide:**
- 0 = No content surface
- 2 = Blog exists but is stale or thin
- 4 = Active content production; multiple formats
- 5 = Content is a moat — proprietary research, named pillars, daily volume
**Maps to AARRR:** Acquisition.
### 8. Onboarding
**What's scored:** New user onboarding (in-app + email). Time-to-value, completion rate, brand-voice alignment.
**Score guide:**
- 0 = No onboarding flow
- 2 = Onboarding exists but is broken, off-voice, or underperforming
- 4 = Solid onboarding; clear bottlenecks identified
- 5 = Tested, optimized, on-brand; activation rate at category top quartile
**Maps to AARRR:** Activation.
### 9. Email lifecycle
**What's scored:** Existence and quality of lifecycle email programs. Welcome / onboarding / post-purchase / lapsed / win-back.
**Score guide:**
- 0 = No lifecycle email
- 2 = Some flows exist but drafted not live, or live but stale
- 4 = Core flows live and performing; gaps on secondary flows
- 5 = Full lifecycle live, segmented, performing above category benchmarks
**Maps to AARRR:** Retention (+ Activation for onboarding emails).
### 10. Sales material
**What's scored:** Sales decks, one-pagers, demos, case studies, pricing sheets. (For B2B / hybrid companies — for pure D2C, this can be marked N/A or scored low without implication.)
**Score guide:**
- 0 = No sales material
- 2 = Founder uses a deck but other material is thin
- 4 = Solid sales kit; reps can self-serve content
- 5 = Comprehensive material; updated quarterly; objection-handling library exists
**Maps to AARRR:** Acquisition + Revenue (B2B).
### 11. Messaging
**What's scored:** Voice, tone, vocabulary, message hierarchy across surfaces. Is the brand voice documented, consistent, distinctive?
**Score guide:**
- 0 = No voice documented; surfaces inconsistent
- 2 = Voice exists in founder's head but isn't operationalized
- 4 = Documented voice; mostly consistent across surfaces
- 5 = Distinctive voice; documented; every surface respects it; voice is a moat
**Maps to AARRR:** Cross-cutting.
### 12. Pricing
**What's scored:** Pricing structure clarity, packaging logic, recent pressure-testing, listed vs. effective price reconciliation.
**Score guide:**
- 0 = Pricing not pressure-tested in over a year; unclear structure
- 2 = Listed pricing exists but plan mix / discounting muddles the read
- 4 = Clear pricing; recent tests; LTV math known
- 5 = Pricing tested quarterly; packaging optimized; expansion levers known
**Maps to AARRR:** Revenue.
### 13. CRO (conversion rate optimization)
**What's scored:** Test cadence, instrumentation, A/B history, statistical rigor.
**Score guide:**
- 0 = No tests run; no instrumentation
- 2 = Some ad-hoc tests; no statistical rigor
- 4 = Regular test cadence; some wins
- 5 = Continuous testing program; experimentation culture; documented wins
**Maps to AARRR:** Cross-cutting (most impactful at Activation + Revenue).
### 14. GTM launches
**What's scored:** Quality of past launch executions. Product launches, feature launches, campaign launches.
**Score guide:**
- 0 = No structured launches; "soft launches" only
- 2 = Some launches but uneven execution
- 4 = Solid recent launches; playbook exists
- 5 = Repeatable launch motion; Product Hunt #1s; press coverage on demand
**Maps to AARRR:** Acquisition + Activation.
### 15. Ads (paid)
**What's scored:** Paid acquisition state. Active campaigns, channels, CAC tracking, creative quality.
**Score guide:**
- 0 = No paid acquisition
- 2 = Some paid but unstructured / wasteful
- 4 = Paid is firing across 2–3 channels with positive unit economics
- 5 = Sophisticated paid stack; CAC/LTV understood; creative iterated weekly
**Maps to AARRR:** Acquisition.
**Note:** For pre-seed clients with no paid budget, score this 0 *without* treating it as a weakness — it reflects the funding stage, not a marketing failure.
### 16. SEO
**What's scored:** Organic search performance. Domain rating, ranking keywords, organic traffic, content cluster strategy.
**Score guide:**
- 0 = No SEO; new domain or zero-authority
- 2 = Some content but no strategy; ranks for brand only
- 4 = Established content clusters; growing organic traffic; DR 25+
- 5 = SEO is a moat; DR 40+; thousand+ ranking keywords; consistent content production
**Maps to AARRR:** Acquisition.
### 17. Internationalization
**What's scored:** Geographic expansion, language localization, region-specific pricing.
**Score guide:**
- 0 = US/EN only; no international consideration
- 2 = International users exist but aren't served (one language, one currency)
- 4 = Multi-language, region-specific pricing, GTM playbook for new markets
- 5 = International is a strength; multi-region revenue; localized GTM
**Maps to AARRR:** Acquisition.
**Note:** For most early-stage companies, internationalization scores 0–1 and that's appropriate. Don't penalize early-stage companies for not having international playbooks yet.
## How to compute the total + read the shape
**Total = sum of all 17 scores. Out of 85.**
The total matters less than the *shape*. After the scoring table, write a 2–4 sentence "shape interpretation":
> *"High in {strong sections}, low in {weak sections}. That shape is the gap the rest of the plan closes — Sections X (AARRR stage) is the longest because that's where the gap is widest."*
## Common shapes
### "Strong voice / messaging, weak distribution"
- High: Positioning (#1), Customer research (#2), Messaging (#11)
- Low: SEO (#16), Ads (#15), GTM launches (#14)
- Translation: The founder is a strong storyteller but distribution hasn't caught up. Plan emphasizes Acquisition + paid layer prep.
### "Strong acquisition, weak conversion"
- High: SEO (#16), Resources (#7), Ads (#15)
- Low: Homepage (#3), Onboarding (#8), Conversion pages (#5), Pricing (#12)
- Translation: Traffic comes in but doesn't convert. Plan emphasizes Activation + Revenue.
### "Strong conversion, weak retention"
- High: Onboarding (#8), Homepage (#3), Pricing (#12)
- Low: Email lifecycle (#9), CRO (#13)
- Translation: Users sign up and pay but churn. Plan emphasizes Retention.
### "Strong product, weak everything-else"
- High: only Positioning (#1) and Customer research (#2) — the founder knows the customer
- Low: everything operational
- Translation: Pre-marketing stage. Plan is foundation-heavy. First quarter is bedrock fixes.
### "Strong recent revenue, weak compounding"
- High: Ads (#15), Sales material (#10), Pricing (#12)
- Low: SEO (#16), Resources (#7), Referral mechanics
- Translation: Performance marketing carries the business. Plan emphasizes building compounding channels before paid scales further.
## When scores are subjective
Some sections are easier to score from outside than others. Subjectivity tier:
- **Objective (data-driven):** SEO (#16), Ads (#15), Email lifecycle (#9), Onboarding (#8) — backed by analytics
- **Semi-objective:** Pricing (#12), CRO (#13), Conversion pages (#5), Sales material (#10) — visible artifacts to evaluate
- **Subjective (judgment call):** Positioning (#1), Messaging (#11), Customer research (#2), Resources (#7) — interpretive
For subjective sections, write the rationale into the "Note" column so the team can push back if they disagree.
## When a prior scored audit exists
If the team already has scored output from any current-state assessment, ingest those scores directly — don't redo the work. Treat that prior scoring as the ground truth for sections it covers.
If the prior scoring was done weeks ago and material has shifted since (new shipped flows, new content live, repositioning, etc.), note "scored on YYYY-MM-DD; material has shifted since" and update any specific scores you have current evidence for.
FILE:references/example-quietude.md
# Example — Quietude Marketing Plan v1
**This is the canonical reference example for the `/marketing-plan` skill.** It's based on a real fCMO engagement for a hybrid hardware-and-software wellness platform. **Names, domains, and identifying details have been changed** — the client is called "Quietude" here, and the team members have been renamed (Alex / Sam / Casey / Devon). The funnel numbers, budget, and structural lessons preserve the shape of the original engagement so the example retains its teaching value.
Use this as the "what good looks like" reference when drafting a new plan. The structure, tone, depth, and operational specificity are the bar to clear.
**Quietude's archetype:** Hybrid hardware + software with deep-tech / clinical credibility layer. See `references/client-types.md` for archetype patterns.
**Funding-stage context:** Pre-seed-close (mid-raise on $3M seed). Tier 1 per `references/funding-stage-unlocks.md`. $0 paid budget; organic + lifecycle + ambassador only.
**What was strong about this plan:**
- Strategic frame (Section 2) leaned on the founder's own meditation-vs-regulation framing as the content pillar
- Current state (Section 3) included the 17-section audit rubric scored against existing materials (no formal audit run)
- 90-day roadmap (Section 9) had owner-assigned moves, not just actions
- Ops stack (Section 11) included a concrete operational proof-point (Customer.io MCP used live by non-technical founder on the kickoff call)
- Tactical idea bank (Section 12) cross-referenced all 139 marketing-ideas to AARRR + Quietude-specific status, including 23 explicit skips with rationale
---
# Quietude — Marketing Plan v1
**Prepared by:** Casey Reed (fCMO)
**For:** Alex, Sam, and the Quietude team
**Date:** 2026-05-27
**Status:** Draft v1 — for team review
## 1. Executive summary
Quietude has built something rare: a clinically validated, brand-coherent, founder-led product in a category that doesn't yet have a name. The opportunity in the next twelve months is not to invent a marketing engine from scratch — it's to **convert the existing organic gravity into a measurable, repeatable funnel**, then layer paid acquisition on top of that funnel once the seed round closes.
**Three big bets, ranked by leverage:**
1. **Fix the leak before pouring water in.** The Day 1 → Day 35 funnel shape (1.34% → 5.46%) tells us the product converts given time and contact. What it's missing is a working first-session moment (the headphone gate is killing conversion) and a lifecycle layer to deliver the contact. These two pieces — onboarding rebuild and Customer.io flows shipped — are the unlock for everything else.
2. **Compound the moats Quietude already has.** Peer-reviewed clinical study, longevity-influencer PR, 15K live event participants, Alex's founder voice — these are link generators, content pillars, and credibility anchors that most wellness brands would kill for. They're under-leveraged. SEO, content, and App Store optimization translate them into search and discovery surface area.
3. **Build the founder-and-fCMO operating system that lets a 4-person team market like a 20-person one.** This is what makes the plan actually executable at Quietude's team size and burn rate — agentic tooling on top of Customer.io, Shopify, App Store, Stripe, GitHub, and the marketing skill library means we ship without hiring.
**What twelve months looks like, plausibly:**
- App goes from beta to GA. Onboarding converts at meaningful lift over today's baseline.
- 4 SEO content pillars staked, with Pillar 1 (Nervous System Regulation) and Pillar 2 (Sleep + Eye Mask) ranking on Tier-1 keywords.
- Full lifecycle live in Customer.io: onboarding, lapsed re-engagement, hardware post-purchase, subscription-center opt-ins.
- Ambassador program live with 15–25 active hosts. First Quietude Guides cert pilot run.
- Eye mask wedge selling at scale via Shopify with a clean hardware → app activation path. Blended CAC measured and tracked.
- Paid acquisition firing post-seed-close at $5–10K/mo initial test budget, scaling to $20–50K/mo if unit economics validate.
- Series A narrative writes itself: clinical evidence + activation lift + lifecycle compounding + first B2B install reference cases.
**The 90-day priorities** (which the rest of this doc operationalizes):
1. Kill the headphones gate. Ship the bedrock fix this week.
2. Run the three-variant onboarding test. Find the activation winner.
3. Ship Customer.io Flows 6 (eye mask post-purchase) and 4 (lapsed user) — hold Flow 2 (onboarding) until app UI stabilizes.
4. Rewrite the App Store listing in Quietude's brand voice. Highest-leverage non-site asset right now.
5. Stake the SEO foundation: consolidate to `quietude.app`, publish Pillar 1 hub + 3 spokes, publish the peer-reviewed psychophysiology study landing page.
6. Launch the ambassador program with the ~5 inbound waiting.
Everything else compounds on top of those six.
---
## 2. Strategic frame
This section distills positioning, ICP, and brand voice into what the team needs to keep in mind while executing. Full detail lives in `marketing-os.md`, `icp.md`, and `sound-philosophy.md`.
### What Quietude is, in one sentence
A nervous system intelligence platform — clinically validated spatial audio + AI reflection companion (Mira) + hardware + venue installations + practitioner network. *"We start with sound. We expand to every sense. We end with cities."*
### The category we're claiming (and defending)
Quietude doesn't fit the meditation app category, the focus audio category, or the sleep tech category. The brand makes a stronger claim: **bottom-up nervous system regulation through spatial audio**, with clinical evidence as proof and somatic credibility as defense.
The category-defining frame, per Alex (2026-05-19): **Meditation is top-down. Quietude is bottom-up.** Meditation uses the mind to command the body — mental kung fu that fails the very people most likely to need help, because the prefrontal cortex is offline when stressed. Quietude enters through the brainstem, before the thinking mind. The body responds before it has to try. (Full content-pillar treatment in `meditation-vs-regulation.md`.)
This is the single most important strategic message. It belongs in App Store copy, onboarding, lifecycle email, SEO content, ambassador talking points, and the seed deck.
### Who we're for (D2C ICP, distilled)
Overstimulated high-achieving professionals, 25–45, urban (Bay Area, NYC, London, Berlin, Austin). Tech workers, founders, creators, academics, designers, consultants. Often neurodivergent (ADHD, HSP, gifted). Sophisticated wellness buyers — already invested heavily in their inner life.
**Their stated problem:** *"I can't shut my brain off. I've tried meditation apps. They don't work."*
**Their real problem:** Overstimulation, not under-motivation. Their gift (quick thinking) became a curse. They need permission to stop optimizing — including their rest.
**What they're actually buying:** the *feeling* of stability, sensory indulgence, beautiful rituals, effortless effectiveness, a luxurious shortcut to the genius they can't access in chaos.
### The business model logic (per seed deck)
**B2B seeds the market. D2C harvests.** A venue install puts Quietude in front of ~20K people/year at ~$17K cost → 5% convert to subs → ~$430K/year per venue. Six compound channels (referral, Guides, content, home hosting, PR, community) make CAC approach zero by Year 3. Year 5: 75% of new subs come from near-zero-cost channels.
**fCMO scope per kickoff: D2C-led.** Alex owns B2B sales through events/network/founder credibility. The fCMO leverage is on the app/hardware D2C side. This plan reflects that split — B2B is acknowledged as the harvest engine but not treated as primary work surface.
### Brand voice (the non-negotiable)
Per Marketing OS:
- **Tone.** Authoritative yet accessible. Intimate yet professional. Revolutionary yet grounded. Authority comes from lived experience, not explanation.
- **Speak from the body, not the mind.** Every sentence restores somatic safety and orientation. Language opens space rather than closing meaning.
- **YES vocabulary:** Aliveness, inner life, nervous system, spatial sound, resonance, somatic safety, embodied clarity, natural rhythm, orientation, initiation, truth-telling.
- **NO vocabulary:** Zen, chill, vibes, "high-vibe," spiritual bypass, meditation clichés, didactic/explainer language, "let me explain why this works."
- **Core method: Initiatory Reflection.** Writing's purpose isn't to explain or convince — it's to shift the reader's internal state. The result should be *"something in me moved,"* not *"I understand this concept."*
- **CTA rule:** Never pressure. "We do not remind. We invite."
This rule constrains every piece of copy across every AARRR stage. When in doubt: rewrite from the body.
---
## 3. Current state
This is what we're starting from — team, budget, what's already in motion, what's stuck, scored against the CF Marketing Audit 17-section rubric.
### Team composition (marketing surface area)
| Person | Role | Marketing surface area |
|---|---|---|
| **Alex** | Co-founder, CEO | Owns: personal LinkedIn, live events, B2B sales, founder narrative, investor relations, brand voice authorship |
| **Sam** | Co-founder, CXO | Owns: clinical/somatic credibility, brand-voice stewardship, somatic angle on copy review, practitioner network |
| **Devon** | Lead Dev | Owns: product/UI build, instrumentation, Customer.io event wiring, App Store deployment |
| **Ed Dorsey** | Design Advisor | Advisory cadence (ex-Apple/Airbnb/Strava) |
| **Emily Babich** | Creative Strategy | Advisory cadence |
| **Matt Mikkelsen** | Field Recording | Audio library, not marketing |
| **Casey Reed** | fCMO | Strategy, lifecycle, SEO, onboarding tests, content, ambassador program, ops stack |
**No dedicated marketing hire yet.** First hire likely post-seed close (Q3 2026 candidate): a lifecycle + content marketing manager who owns Customer.io, SEO content production, and ambassador operations day-to-day.
### Marketing budget (current)
- **Paid acquisition:** $0. Confirmed by Alex, 2026-05-20: *"D2C UA so far: My personal LinkedIn posts, live Quietude events, organic word of mouth, and organic app store discovery."* No paid layer.
- **Tooling stack:** Customer.io subscription, Shopify (eye mask storefront), App Store Connect, GA4 (or pending), Stripe, Notion, Dub.co (ambassador attribution). Estimate ~$500–1,500/mo combined.
- **fCMO retainer:** Casey Reed engagement.
- **PR:** No paid PR. Organic longevity-influencer tailwind, consumer-tech angels + foundation-model lab network.
**Implication:** The 90-day plan must produce gains without any paid lever pulled. Everything in the next 12 weeks is organic, lifecycle, or product-level. Paid is a Q2–Q3 unlock.
### What's already done (acknowledge, then build on)
| Asset | Status | Marketing leverage |
|---|---|---|
| Peer-reviewed peer-reviewed psychophysiology study (2025) | Published | Anchor of clinical authority. Most undermarketed asset Quietude owns. |
| longevity-influencer eye-mask endorsement | Live, generating Shopify sales | Press hook. Underused for landing-page social proof. |
| consumer-tech angels + foundation-model lab investment | Closed | Investor PR opportunity. "Why I invested" Substack/Medium pieces. |
| 15K+ live event participants over a decade | Real | Email list potential, ambassador pool, testimonial bank, B2B reference. |
| Quietude eye mask (5K in stock) | Selling | The wedge product. Hardware → app activation path. |
| 38% 12-month retention (vs. category avg 20%) | Real | Headline metric. Belongs everywhere. |
| Customer.io + Shopify integration | Wired | The lifecycle infrastructure exists. Flows just need to ship. |
| 4 GitHub repos for context + product | Set up | `quietude-context` (shared brain), `quietude-promo`, `quietude-app` (app), `mira` (AI), `quietude-api` |
| Alex's Sound Philosophy doc | Working doc | Linkable position paper once polished and published. |
| ~5 inbound ambassadors waiting | Inbound | Referral program ready to launch — no demand-gen needed for v1. |
| Aurora B2B install (~€250K, July deadline) | In-flight | First flagship venue. Reference case once installed. |
| Notion Knowledge Directory | Live | Internal context. |
| Customer.io MCP (Claude integration) | Validated on kickoff | Non-technical team can ship flows independently. |
### What's in-flight (drafted but not shipped)
| Item | Status | Blocker |
|---|---|---|
| Flow 2 — App Onboarding (8 emails / 14 days) | Draft | App UI in flux; copy references screens that may change |
| Flow 4 — Lapsed User Re-engagement (5 emails / 38 days) | Draft | None — ship-ready |
| Flow 6 — Eye Mask Post-Purchase | Draft | None — ship-ready |
| Onboarding rebuild (3-variant test plan) | Strategy doc done | Eng scoping + headphone-gate removal |
| SEO 90-day plan + keyword research | Done | Awaiting domain consolidation decision + content production start |
### What's stuck (and needs to unstick this quarter)
| Issue | Cost of inaction | Action |
|---|---|---|
| Headphones hard-gate in onboarding | Confirmed conversion drop post-launch | Kill this week (bedrock fix) |
| 4 domains unconsolidated (quietude.app, quietude.space, quietude.audio, quietude.center) | SEO authority fragmenting, transactional email confusion | Consolidate to `quietude.app` per SEO data |
| App Store listing copy not in brand voice | Highest-traffic Quietude surface; off-brand experience for arriving users | Rewrite in voice (Pillar 1) |
| Domain consolidation requires 301 plan + email sender migration | Risk of traffic loss if mishandled | Plan in weeks 1–2, execute weeks 3–4 |
| `quietude-promo` repo hasn't shipped since March 2026 | Marketing site is stale | Confirm whether it's live; rewrite or replace |
| 29% monthly App Store churn vs. 38% 12-month retention claim | Metric definition mismatch confusing the team | Reconcile with Devon + Customer.io data |
| Mira post-session reflection scope unknown | Blocks Variant B and Variant C onboarding tests | Resolve with Devon |
### Audit rubric snapshot (17-section)
Scored 0–5 from materials, using the embedded rubric in `references/current-state-rubric.md`. Marked "scored from materials" rather than "formal audit" — Alex can push back on any score where they have better data.
| # | Section | Score | Note |
|---|---|---|---|
| 1 | Positioning | **4** | Clear, original category claim. The bottom-up frame is the strongest piece. Needs broader external articulation. |
| 2 | Customer research | **4** | Deep founder-led research, decade of live participants. Could be more systematically captured. |
| 3 | Homepage | **2** | `quietude-promo` hasn't shipped since March. Off-brand voice in places. |
| 4 | Sales / product pages | **2** | Eye mask page exists on Shopify but isn't optimized for SEO or sales narrative. No app-product landing page in brand voice. |
| 5 | Conversion pages | **2** | `/partner` exists on `quietude.app`. No `/science`, `/eye-mask`, `/ambassadors`, `/guides` pages live. |
| 6 | Competitor comparison | **1** | Nothing exists. Big SEO + sales opportunity (own "Quietude vs. Calm/Headspace/Brain.fm/Endel" SERPs). |
| 7 | Resources / content | **1** | Sound Philosophy not yet public. peer-reviewed psychophysiology study not yet on a dedicated page. No blog. |
| 8 | Onboarding | **2** | Headphones gate killing conversion. Hold-and-fix project this quarter. |
| 9 | Email lifecycle | **1** | All three flows drafted, none live. Ship-order set. |
| 10 | Sales material | **3** | Seed deck is strong (investor-facing). B2B sales material more founder-led than asset-led. |
| 11 | Messaging | **5** | Alex + Sam have authored the most distinctive brand voice in the wellness category. This is a moat. |
| 12 | Pricing | **3** | $30/mo app, $45 eye mask, $7,500 speakers, $50–200K B2B. Hasn't been pressure-tested for D2C conversion lift. |
| 13 | CRO | **2** | App Store conversion rate trackable but no A/B history. Headphones gate is the obvious first test removal. |
| 14 | GTM / launches | **2** | App in throttled beta. Major launches (eye mask, Mira public) haven't had structured GTM. |
| 15 | Ads | **0** | No paid layer. Reflects the current organic strategy — not a weakness, but the budget unlock means this will move. |
| 16 | SEO | **1** | Current state: 7 organic visits/mo. Plan exists; execution not yet started. |
| 17 | Internationalization | **1** | Finland HQ + global ICP, but EN-only and US-centric copy. Defer until Q4+. |
**Total: 36 / 85 (42%).** The shape matters more than the score: high in Positioning + Messaging + Customer research, low in Conversion pages + Email lifecycle + SEO + Resources + Ads. That's the gap this plan closes.
---
## 4. Acquisition
> *"How do strangers become aware of Quietude?"*
### Current state
100% organic. Four real channels: Alex's personal LinkedIn, live Quietude events, organic word of mouth, organic App Store discovery. Plus passive PR drag from longevity-influencer endorsement + clinical study.
This is good news, not bad. Every dollar of revenue earned to date has been earned without paid acquisition. The bar to exceed it isn't high; the upside on top of an organic base is significant.
### The plan
**Channel 1 — SEO (primary 90-day investment).**
The full 90-day plan lives in `seo/plan.md`. Summary: consolidate to `quietude.app`, target three asymmetric clusters (nervous-system regulation KD 14–32, weighted/blackout sleep mask KD 6–30, WELL + social-wellness-club B2B KD 5–34), publish 4 content pillars. 90-day target: 500–1,500 organic visits/mo, 80+ ranking keywords. 12-month target: 10,000/mo, 1,000+ keywords.
**Channel 2 — App Store optimization (highest-leverage non-site asset).**
The App Store listing is currently the most-visited Quietude URL by Apple's algorithm. Fixing the copy is higher-leverage this quarter than fixing the marketing site. Rewrite in brand voice. Add the meditation-vs-regulation framing. Lead with the clinical anchor. Test screenshot variations.
**Channel 3 — Alex's LinkedIn (productize the channel).**
Today it's ad-hoc founder posting. The next move is structured: a 2–3x/week cadence, post categories that map to the content pillars (nervous system, sound science, founder journey, clinical evidence, behind-the-scenes), trackable links via Dub, follower → email subscriber → app install funnel measured. This is Alex's voice — the channel only works if he's the one writing. fCMO + Typefully scheduling makes the cadence sustainable.
**Channel 4 — PR amplification.**
longevity-influencer tailwind is real but underused on owned surfaces. Add a `/notable-users` or `/in-the-press` page. Pitch the peer-reviewed psychophysiology study to 5 outlets (wellness press: Well+Good, MindBodyGreen; tech-adjacent: Wired with the longevity-influencer hook; mainstream: Outside, Forbes Wellness). HARO/Help-A-B2B-Writer responses citing Quietude's data. Investor PR moments ("Why I invested in Quietude" Substack pieces from consumer-tech angels — push for these with backlinks).
**Channel 5 — Event-to-app instrumentation.**
Live events are the highest-converting ICP exposure Quietude has (15K+ participants, decade of trust). They're un-instrumented. Add: per-event QR code → app install + email capture, post-event lifecycle (Customer.io Flow 7?), event ROI tracking. Goal: turn an event from a one-night conversion moment into a 30-day funnel.
**Channel 6 — Eye mask wedge (consumer entry product).**
5K masks in stock. Shopify storefront exists but isn't optimized. Improvements: SEO-optimize the product page (target "weighted sleep mask," "blackout sleep mask," "silk sleep mask"), add reviews via Judge.me (per kickoff decision), 30-day return policy (US-market expectation, per kickoff), build the listicle ("Quietude vs. Manta vs. Nodpod vs. Lumon"). Consider Amazon listing as a v2 distribution play.
**Channel 7 — B2B venue installs (kept lean per kickoff).**
Alex owns this. Marketing supports with: case studies after each install, `/partner` page rewrite in voice (already exists on quietude.app), Pillar 4 content ("The Missing Sound Feature in WELL"), reciprocal links from partner venues baked into contracts.
**Channel 8 — Paid layer (unlocked post-seed close).**
Held until seed funding lands. Initial test budget: $5–10K/mo split across Apple Search Ads (highest-intent for App Store), Meta (Instagram + Facebook for eye mask), LinkedIn (B2B venue buyers). Don't fire until: (a) onboarding bedrock fix is shipped, (b) Flow 6 is live, (c) at least one Pillar landing page is in voice. Paid amplifies what already works — premature paid amplifies what's broken.
### 90-day acquisition moves
- Weeks 1–2: Domain consolidation decision + 301 plan. App Store listing rewrite first pass.
- Weeks 3–4: Domain 301s executed. GSC migration. SEO Pillar 1 hub drafted.
- Weeks 5–8: Pillar 1 hub + 3 spokes published. Pillar 2 (Eye Mask) hub + listicle published. Alex's LinkedIn cadence operationalized via Typefully. peer-reviewed psychophysiology study lands on dedicated `/science` page.
- Weeks 9–12: Pillar 4 (WELL/B2B) cornerstone published. Sound Philosophy goes public at `/research/sound-philosophy`. First PR push: pitch study + longevity-influencer hook to 5 outlets.
### 12-month acquisition outlook
- Q1 (Months 1–3): Foundation. SEO pillars staked. App Store rewrite shipped. LinkedIn cadence stable. PR push launched.
- Q2 (Months 4–6, post-seed close): Paid acquisition pilot at $5–10K/mo. SEO compounding — Pillar 1 ranking. First B2B install reference case live.
- Q3 (Months 7–9): Paid scales to $20–30K/mo if unit economics hold. All four pillars producing. App GA — new GTM moment.
- Q4 (Months 10–12): Compound channels live. 50+ pieces of pillar content. First Quietude Guides program pilot creating local SEO + earned media.
### Skills + tools
- **Skills:** `seo-audit`, `ai-seo`, `programmatic-seo`, `schema`, `content-strategy`, `competitors`, `launch`, `ads`, `ad-creative`, `social`, `typefully`, `analytics`, `copywriting`, `marketing-website-design`, `free-tools`
- **MCPs / APIs:** Ahrefs API, DataForSEO API, Typefully MCP (LinkedIn scheduling), GA4 MCP (when wired), GitHub MCP (`quietude-promo` repo work), Notion (knowledge directory), Stripe MCP (LTV / paid-CAC math), `agent-browser` (LinkedIn drafting + testing), `defuddle` (research)
---
## 5. Activation
> *"Once someone tries Quietude, do they have an experience that converts?"*
### Current state
Day 1 → paid: **1.34%**. Day 7 → paid: **3.73%**. Day 35 → paid: **5.46%**. *The funnel shape is the signal.* The ~4× lift over 35 days means the product converts given time and contact — both of which the current onboarding undermines and the lifecycle layer doesn't yet provide.
Caveats: app is in throttled beta. Metrics are noisy. Don't optimize against absolutes; optimize against funnel *shape* and *cohort comparison*.
### The plan
**Move 1 — Kill the headphones hard-gate (bedrock fix, this week).**
Confirmed conversion drop after the gate shipped. The fix isn't better copy on the gate — it's removing the gate. Replace with passive headphone detection + soft single-line nudge. No regret change. Full reasoning in `onboarding-recommendation.md`.
**Move 2 — Run the three-variant onboarding test.**
Three variants, each a pure expression of one belief about what drives activation in this ICP:
- **Variant 1 — Trust First.** Bold promise + clinical anchor + testimonial wall + 1-line mechanism. Tests whether the saturated ICP needs framing before they'll invest.
- **Variant 2 — Seen First.** Multi-step diagnostic → AI-generated "we see you" summary → personalized session. Tests whether being accurately named is the conversion event.
- **Variant 3 — Felt First.** Audio starts on app open. ~15 words on screen. The session IS the onboarding. Tests whether the product can carry it cold.
Test sequence (sequential, ~7 weeks to a winner): bedrock baseline → V3 vs. baseline → winner vs. V1 → winner vs. V2. Full system in `onboarding-recommendation.md`.
**Move 3 — App Store listing rewrite.**
Highest-leverage non-site asset. Rewrite in brand voice. Lead with meditation-vs-regulation. Screenshot variations to test. This is also an Acquisition move (organic discovery) but it lives here because it's the threshold to the trial.
**Move 4 — Customer.io Flow 2 (held until UI stable).**
The 8-email / 14-day onboarding sequence is drafted and on-brand. Holding the ship because the emails reference in-app screens that will change during the onboarding rebuild. Once a winning onboarding variant ships, Flow 2 gets a copy refresh against the final UI and goes live.
**Move 5 — Paywall + pricing review (cross-cuts to Revenue).**
What's the current trial structure? Length, paywall trigger, intro pricing? When the funnel shape is "lift over 35 days," extending trial may convert better than aggressively gating earlier. To be audited in Q1.
### 90-day activation moves
- Week 1: Headphones gate removed. Baseline established.
- Weeks 2–3: Variant 3 (Felt First) prototyped, instrumented, shipped to a test cohort.
- Weeks 4–5: Read Variant 3 vs. baseline. Decide ship/iterate. Begin Variant 1 build.
- Weeks 6–7: Variant 1 (Trust First) live.
- Weeks 8–9: Read V1 vs. winner. Begin Variant 2 build.
- Weeks 10–11: Variant 2 (Seen First) live.
- Week 12: Final read. Winning variant scheduled for permanent ship. Flow 2 unblocked.
### 12-month activation outlook
- Q1: Winning variant identified and shipped.
- Q2: Flow 2 ships. Paywall A/B tests start.
- Q3: GA launch — onboarding re-validated at higher traffic. Cohort segmentation by acquisition source (Shopify/eye-mask vs. direct vs. ambassador vs. paid) starts to drive variant forks.
- Q4: Onboarding is no longer the bottleneck. Focus moves to Activation → Retention transition (sessions 2–7).
### Skills + tools
- **Skills:** `onboarding`, `signup`, `cro`, `cro`, `paywalls`, `popups`, `copywriting`, `copy-editing`, `copycraft`, `marketing-website-design`, `ab-testing`, `marketing-psychology`
- **MCPs / APIs:** App Store Connect (manual + `dev-browser` for screenshot automation), GitHub MCP (`quietude-app` app repo for onboarding code), Figma / Pencil MCP (for onboarding screen design), Customer.io MCP (for any in-app/email coordination), GA4 MCP (activation events)
---
## 6. Retention
> *"Once someone converts, do they stay — and deepen?"*
### Current state
**Headline metric (per seed deck): 38% 12-month retention** — nearly double the category average (~20%). This is the strongest single retention signal in the deck and one of the most undermarketed claims Quietude owns.
**App Store snapshot, 2026-05-16:** 145 paid, 42 churned (~29% monthly churn). Definition mismatch with the 38% claim — to reconcile. Possibly: 38% is annual cohort retention (people who paid month 1 and still pay month 12), 29% is gross monthly churn (people who paid this month who didn't pay next month). Both can be true. Need to clarify which metric is reported externally and which is the actual product health signal.
### The plan
**Move 1 — Ship Flow 6 first (Eye Mask Post-Purchase).**
Per kickoff decision and the onboarding-recommendation doc: this is the ship-ready flow. Hardware-anchored, doesn't reference in-app screens, can ship today. Wires the hardware → app activation path (eye mask buyers should get a free 6-month Premium trial — formalize this as part of the flow).
**Move 2 — Ship Flow 4 second (Lapsed User Re-engagement).**
Five emails over 38 days. Language is universal — doesn't depend on app UI state. Ship after Flow 6 is live.
**Move 3 — Hold Flow 2 (Onboarding).**
Eight emails over 14 days. Holds until app UI stabilizes post-onboarding-rebuild. Don't ship copy that will need rewriting in 8 weeks.
**Move 4 — Customer.io subscription center with opt-in topics.**
Per kickoff decision. Topics: events, app updates, somatics & nervous system, eye mask promotions. Users self-segment. Improves deliverability (lower complaint rates) and gives lifecycle a richer segmentation surface.
**Move 5 — Mira post-session reflection (when scoped).**
Most powerful retention move medium-term. After a session, Mira asks *"What did you notice?"* Optional preset chips + free text. Two payoffs: (a) gives Mira priors for personalization on session 2+, (b) reflection responses become a content + segmentation goldmine for the team. Scope question for Devon — does Mira currently support this, or is it new build?
**Move 6 — Hardware → app activation flow.**
The eye-mask-buyer-becomes-Premium-subscriber path is hinted in the seed deck (blended CAC via hardware) but isn't visible in the App Store dashboard. Audit the existing flow: does an eye mask Shopify purchase actually deliver a free Premium code? How is it redeemed? What's the conversion rate? This is foundational to the "B2C wedge" thesis.
**Move 7 — Reconcile the retention metric.**
What's the actual definition of "38% 12-month retention"? Cohort? Plan type (monthly vs. annual)? Survives this even if the answer is uncomfortable — the team and investors need to be talking about the same metric.
**Move 8 — Annual plan as default (cross-cuts to Revenue).**
Industry pattern: defaulting to annual reduces churn anxiety and improves LTV. To test in Q2.
### 90-day retention moves
- Weeks 1–2: Flow 6 (eye mask post-purchase) ships. Address fixes from kickoff review (study link line break, CAN-SPAM footer, founder face-bubble signature, Judge.me reviews).
- Weeks 3–4: Flow 4 (lapsed user re-engagement) ships.
- Weeks 5–6: Customer.io subscription center built and live.
- Weeks 7–8: Hardware → app activation flow audited and documented. Fix any leaks.
- Weeks 9–10: Retention metric reconciliation (with Devon).
- Weeks 11–12: Win-back campaign for churned cohort — test re-activation copy.
### 12-month retention outlook
- Q1: Flows 6 + 4 firing. Subscription center live.
- Q2: Flow 2 ships (post-onboarding-rebuild). Mira post-session reflection in production. Annual plan default tested.
- Q3: GA launch — retention metrics re-baselined at higher volume. Cohort-based lifecycle flows (eye mask vs. direct app install).
- Q4: Full lifecycle compound. Retention is no longer a top-three concern — focus moves to Referral and Revenue.
### Skills + tools
- **Skills:** `emails`, `churn-prevention`, `copywriting`, `copy-editing`, `paywalls`, `ab-testing`
- **MCPs / APIs:** **Customer.io MCP** (validated on kickoff — non-technical team can ship flows), Shopify (eye mask buyers as event source), Stripe MCP (subscription state, churn cohort pulls), GA4 MCP (session events, retention curves)
---
## 7. Referral
> *"Do retained users bring more users — and at what cost?"*
### Current state
~5 inbound ambassadors waiting (per kickoff). Dub.co set up. No formal program yet. WOM happens naturally per Alex's UA breakdown.
This is one of the strongest leading indicators in the business: 5 unaffiliated people have raised their hand asking to bring Quietude to their network *before any program exists*. That signal doesn't show up in apps with weaker product-market fit.
### The plan
**Move 1 — Launch the ambassador program with the 5 inbound.**
Tier 1 of the program. Per-ambassador landing pages (e.g., `quietude.app/with/sarah`). Dub.co tracks attribution. Commission structure to determine (per kickoff, $/sub or rev-share TBD). Soft-launch with the 5 — treat as pilot cohort, gather feedback, refine before opening applications.
**Move 2 — Build the share-after-shift moment.**
The Mira post-session reflection (see Retention) is the natural moment to surface a share prompt. After a user reports a felt shift, offer: *"Want to share Quietude with someone who needs this?"* Single-line, never pushy. Most powerful WOM mechanism: gift-a-month flow where the recipient gets a discounted or free intro.
**Move 3 — Founder amplification (Alex + Sam as ambassador-zero).**
Alex mentioning the fCMO engagement in fundraise pitches (permission granted). Reciprocal mentions in fCMO-side content. Sam's clinical network → practitioner ambassador pool.
**Move 4 — Quietude Guides cert pilot (long-term, Q3+).**
The Guides program is the Phase-2 referral compound (per seed deck). 500–1,000 Guides across 50+ cities by Y3–5. First cert pilot: 3–5 hosts who run live sessions, get a rev-share + co-marketing. Builds local SEO + earned media + ambassador-of-ambassadors flywheel. Hold until paid + lifecycle are firing — Guides is a multi-quarter build.
**Move 5 — Eye mask gifting flow.**
Hardware referral is rare and powerful. *"Send a friend an Quietude eye mask. They get the mask + a free 3-month Premium. You get a credit toward your next thing."* Holiday/gifting peak windows are the test.
### 90-day referral moves
- Weeks 1–4: Ambassador program scoped, commission structure decided, per-ambassador landing page template built, 5 inbound onboarded.
- Weeks 5–8: First ambassador-driven sales tracked via Dub. Attribution and payout flow validated.
- Weeks 9–12: Open applications for next 10–15 ambassadors. Begin Quietude Guides scoping.
### 12-month referral outlook
- Q1: Ambassador program live with 5–10 active.
- Q2: 15–25 active ambassadors. Share-after-shift moment in production (post-Mira reflection).
- Q3: Guides cert pilot launched (3–5 hosts). Eye mask gifting flow live for holiday peak.
- Q4: 50+ ambassadors + 5–10 Guides. Referral driving 15–25% of new D2C subs.
### Skills + tools
- **Skills:** `referrals`, `social`, `copywriting`, `marketing-website-design` (per-ambassador landing pages)
- **MCPs / APIs:** Dub.co (attribution — already in stack), Stripe MCP (commission accounting + payouts), GitHub MCP (landing page deployment in `quietude-promo` or new `quietude-ambassadors` repo), Customer.io MCP (ambassador lifecycle: onboarding, monthly performance digest, payout notification)
---
## 8. Revenue
> *"What do we charge, who pays, and how does that compound?"*
### Current state
| Product | Price | Volume signal |
|---|---|---|
| Quietude App + Mira | ~$30/mo | 145 paid subs (App Store snapshot 2026-05-16) |
| Quietude Eye Mask | ~$45 | 5K in stock, longevity-influencer PR-driven sales |
| Quietude Audio (speakers) | ~$7,500 | Niche, founder-led |
| Quietude Spaces (B2B install) | $50–200K | Aurora flagship in-flight (~€250K), pipeline of 4 venues |
| Quietude Experiences (events) | Varies | 15K+ historical participants |
| Quietude Guides | Rev share | Not yet operational |
**Revenue to date: ~$500K on ~$250K raised.** Capital-efficient. Hardware + B2B + app subs all contributing.
**MRR (App Store snapshot): $592.** Beta-throttled, not steady-state. The implied ~$4/sub/mo against $30/mo list suggests heavy annual plan adoption (which compresses monthly revenue but improves LTV) or significant promotional pricing — to reconcile with Alex.
### The plan
**Move 1 — Pricing audit.**
What's actually being charged today? List price, common plan mix, intro pricing, churn-recovery offers? The $4/sub/mo implied math doesn't tell a clean story — need ground truth before recommending changes.
**Move 2 — Annual plan as default (test).**
Industry pattern, cross-references to Retention. Test in Q2.
**Move 3 — Hardware → app bundling formalized.**
Per partner-event-business framing in the seed deck: blended CAC via hardware → app subscription is the play. Today an eye mask buyer gets... what, exactly? Free Premium? Trial code? Audit + formalize. The eye mask is the wedge; the app is the LTV.
**Move 4 — Eye mask Shopify storefront optimization.**
The current page underperforms what it could. Add: SEO targeting ("weighted sleep mask," "blackout sleep mask"), Judge.me reviews (kickoff decision), 30-day return policy (kickoff decision), upsell flow into Premium app.
**Move 5 — Consider Amazon listing for eye mask.**
Amazon takes margin but is its own discovery engine. Test as v2 distribution if Shopify volume validates.
**Move 6 — B2B install case studies + sales material.**
Alex owns B2B sales but marketing supports with: post-install case studies (Aurora as the flagship), `/partner` page rewrite in voice, Pillar 4 SEO content. Each B2B install is a ~$430K/year recurring + reference-case multiplier.
**Move 7 — Data licensing (long-term, flag for ops stack).**
Per seed deck Y10–15 value pool: $100–160M/yr. Not immediate revenue. Belongs in the 24-month strategic agenda. Flag here so we don't lose sight.
### 90-day revenue moves
- Weeks 1–2: Pricing audit. Reconcile implied vs. listed MRR.
- Weeks 3–4: Hardware → app activation flow audited (also Retention move 6).
- Weeks 5–8: Eye mask Shopify page rewrite + SEO optimization + Judge.me + return policy. Aurora case study scaffolded for post-install.
- Weeks 9–12: Annual plan default test scoped.
### 12-month revenue outlook
- Q1: Pricing audit closes. Hardware → app activation formalized.
- Q2: Annual plan default test live. Eye mask Shopify producing measurable lift.
- Q3: B2B install case studies (1–2) published. GA launch + new pricing tier consideration (e.g., a higher-tier Mira-heavy plan?).
- Q4: Pricing optimized via test results. Hardware → app blended CAC tracked and reported. First numbers on the data-licensing thesis (still very early).
### Skills + tools
- **Skills:** `pricing`, `paywalls`, `sales-enablement`, `revops`, `ab-testing`, `copywriting`
- **MCPs / APIs:** Stripe MCP (pricing tests, subscription analytics, churn cohort, blended CAC math), Customer.io MCP (paywall-related lifecycle), Shopify (eye mask transactions), GA4 MCP (revenue events), Notion (commercial knowledge directory)
---
## 9. 90-day roadmap
Tactical execution layer. Each item is AARRR-tagged so priority is visible.
### Weeks 1–2 — Unblock
| Move | Stage | Owner |
|---|---|---|
| Kill the headphones hard-gate | Activation | Casey + Devon |
| Domain consolidation decision documented | Acquisition | Casey + Alex |
| 301 plan drafted (page-by-page) | Acquisition | Casey |
| App Store listing rewrite — first pass | Activation + Acquisition | Casey + Alex + Sam (voice review) |
| Flow 6 (eye mask post-purchase) ships | Retention | Casey + Customer.io MCP |
| Ambassador program scoping doc | Referral | Casey |
| Pricing audit kicked off | Revenue | Casey + Alex |
### Weeks 3–4 — Foundation
| Move | Stage | Owner |
|---|---|---|
| Domain consolidation 301s executed | Acquisition | Devon + Casey |
| GSC + GA4 stood up on `quietude.app` | Acquisition | Casey |
| SEO Pillar 1 hub drafted (Nervous System Regulation) | Acquisition | Casey |
| `/science` hub built with peer-reviewed psychophysiology study | Acquisition + brand | Casey + Sam |
| Variant 3 (Felt First) onboarding prototyped + tested | Activation | Casey + Devon |
| Flow 4 (lapsed user) ships | Retention | Casey |
| Ambassador program: 5 inbound onboarded | Referral | Casey |
| Hardware → app activation flow audited | Retention + Revenue | Casey + Devon |
| App Store listing rewrite — final + ship | Activation + Acquisition | Alex + Sam + Casey |
### Weeks 5–8 — Velocity
| Move | Stage | Owner |
|---|---|---|
| Pillar 1 hub + 3 spokes published | Acquisition | Casey |
| Pillar 2 hub (Eye Mask) + listicle published | Acquisition | Casey |
| Alex's LinkedIn cadence operationalized (Typefully) | Acquisition | Alex + Casey |
| First PR push: study + longevity-influencer hook to 5 outlets | Acquisition | Casey + Alex |
| Variant 3 read; ship or iterate | Activation | Casey |
| Variant 1 (Trust First) prototyped + tested | Activation | Casey + Devon |
| Customer.io subscription center built | Retention | Casey |
| Eye mask Shopify storefront rewrite (SEO + reviews + return) | Acquisition + Revenue | Casey + Alex |
| First ambassador attribution verified via Dub | Referral | Casey |
### Weeks 9–12 — Compound
| Move | Stage | Owner |
|---|---|---|
| Pillar 4 (WELL/B2B) cornerstone published | Acquisition | Casey |
| 3 more Pillar 1 spokes published | Acquisition | Casey |
| Sound Philosophy published at `/research/sound-philosophy` | Acquisition + brand | Alex + Casey |
| Variant 1 read; begin Variant 2 (Seen First) build (Mira-dependent) | Activation | Casey + Devon |
| Win-back campaign for churned cohort | Retention | Casey |
| Annual plan default test scoped | Revenue | Casey + Alex |
| Open ambassador applications for next 10–15 | Referral | Casey |
| 90-day review + Q2 plan recalibration | Cross-cutting | Casey + Alex |
---
## 10. 12-month outlook
Quarterly milestones with funding-stage capability unlocks named explicitly.
### Q1 — Months 1–3 (Jun–Aug 2026)
**Funding state:** Pre-seed-close. Paid budget = $0. fCMO + founder-led + tool costs only.
**Focus:** Foundation. Plug the leaks. Stake the SEO ground. Get lifecycle firing.
**Outcomes by end of Q1:**
- Headphones gate gone; onboarding winner identified
- All four SEO pillars seeded (hub + first spokes)
- Lifecycle Flows 4 + 6 live
- App Store listing in brand voice
- 5 ambassadors active
- Pricing audit closed
- Domain consolidated
**KPI targets:** Onboarding Day 1 → paid lift of 25–50%. Organic traffic 500–1,500/mo. App Store conversion rate +20%.
### Q2 — Months 4–6 (Sep–Nov 2026)
**Funding state:** Seed close (~Q3 2026 target). First paid budget unlock: $5–10K/mo test.
**Focus:** Validate paid. Scale winning onboarding. Add Flow 2.
**Outcomes by end of Q2:**
- Paid acquisition firing on Apple Search Ads + Meta
- Onboarding winner permanently shipped
- Flow 2 (onboarding emails) shipped
- Mira post-session reflection in production
- 15–25 ambassadors active
- First B2B install reference case (Aurora) published
- Annual plan default tested
**KPI targets:** Paid CAC < $50 blended. Organic traffic 1,500–3,500/mo. Retention curves visibly improving.
### Q3 — Months 7–9 (Dec 2026–Feb 2027)
**Funding state:** Seed deployment. Paid scales to $20–50K/mo if unit economics hold. First marketing hire (lifecycle + content manager).
**Focus:** Scale + diversify. App GA. B2B reference cases compound.
**Outcomes by end of Q3:**
- App GA launched with new GTM moment (PR + ad creative refresh + Pillar 3 spatial-audio-science content cycle)
- First Quietude Guides cert pilot (3–5 hosts)
- All four pillars producing weekly content
- Eye mask gifting flow live for holiday peak
- New marketing hire onboarded
**KPI targets:** Paid + organic blended CAC stabilizing. App GA conversion +50% from beta baseline. Guides pilot validates rev-share + co-marketing model.
### Q4 — Months 10–12 (Mar–May 2027)
**Funding state:** Pre–Series A. Paid scaling continues. Series A pitch in motion.
**Focus:** Compound. Position for Series A.
**Outcomes by end of Q4:**
- Compound channels (organic + ambassador + Guides + lifecycle) producing 50%+ of new subs
- 50+ ambassadors, 5–10 Guides
- 4 SEO pillars + 30+ pieces of content live
- Paid scaling to $50–150K/mo if validated
- Series A narrative: clinical evidence + activation lift + lifecycle compounding + B2B reference case pipeline
**KPI targets:** D2C ARR run-rate trajectory clear. Blended LTV/CAC > 3. Founder narrative + data + reference cases ready for Series A.
---
## 11. Marketing operations stack
This is what makes the plan executable at Quietude's team size. A 4-person founder team + fCMO + agentic tooling can ship the output of a 15–20-person traditional marketing org — because the marketing skill library and MCP integrations do the orchestration.
### The thesis
Every move in the AARRR breakdown above maps to (a) one or more marketing skills that operationalize the work, and (b) one or more MCP/API integrations that let it execute without a dedicated headcount per channel.
The fCMO's job is to:
1. Define the strategy and sequencing (this doc)
2. Run the skills against the right context at the right time
3. Maintain the shared context (`quietude-context`) and tooling so Alex + Sam + future hires can plug in
4. Hand off operational work to humans (or future hires) only where the cost of agentic execution > human execution
### Skills mapped to AARRR stages
| Stage | Primary skills | Supporting skills |
|---|---|---|
| **Acquisition** | `seo-audit`, `ai-seo`, `programmatic-seo`, `schema`, `content-strategy`, `competitors`, `ads`, `ad-creative`, `social`, `typefully` | `launch`, `free-tools`, `analytics`, `cold-email`, `copywriting`, `marketing-website-design` |
| **Activation** | `onboarding`, `signup`, `paywalls`, `cro`, `copywriting`, `copy-editing`, `copycraft` | `marketing-website-design`, `ab-testing`, `marketing-psychology`, `cro`, `popups` |
| **Retention** | `emails`, `churn-prevention` | `copywriting`, `copy-editing`, `ab-testing`, `paywalls` |
| **Referral** | `referrals`, `social` | `copywriting`, `marketing-website-design`, `emails` |
| **Revenue** | `pricing`, `paywalls`, `sales-enablement`, `revops` | `ab-testing`, `copywriting` |
| **Cross-cutting** (brand, intelligence) | `product-marketing`, `customer-research`, `marketing-psychology` | `marketing-ideas`, `diagram-maker` |
### MCPs / APIs mapped to stages
| Stage | Existing connections at Quietude | Tooling layer (Casey's fCMO stack) |
|---|---|---|
| **Acquisition** | App Store Connect (manual), Shopify, GA4 (in progress), Notion | Ahrefs API, DataForSEO API, Typefully MCP, GitHub MCP (`quietude-promo`), `agent-browser`, `defuddle` |
| **Activation** | App Store Connect, Customer.io, Shopify | App Store Connect (via `dev-browser` for screenshot automation), Figma / Pencil MCP, GitHub MCP (`quietude-app` app repo), Stripe MCP |
| **Retention** | **Customer.io (with Claude MCP — validated on kickoff)**, Stripe, Shopify | Customer.io MCP, Stripe MCP, GA4 MCP |
| **Referral** | Dub.co, Stripe | Dub.co, Stripe MCP, GitHub MCP (per-ambassador landing pages), Customer.io MCP |
| **Revenue** | Stripe, Shopify, Customer.io | Stripe MCP, Shopify, GA4 MCP, Notion |
| **Cross-cutting** | Notion, GitHub (`quietude-context`) | Notion, GitHub MCP, `defuddle`, `obsidian-cli` (for Casey's working notes) |
### The Customer.io MCP unlock (concrete example)
Per kickoff call: *"Built live on call — abandoned-cart flow drafted using Customer.io's Claude MCP. Validated that non-technical team can use the skill pattern independently."*
This is the operational proof that the stack works. Alex, who is not a developer, drafted a working lifecycle flow with Claude + Customer.io MCP in real time on a kickoff call. The same pattern applies to: Flow 4 ship (lapsed user re-engagement), subscription center build, win-back campaign, eye mask gifting flow, ambassador lifecycle. The fCMO's role becomes orchestration + brand-voice QA, not hand-cranking each email.
### Capability unlocks by funding stage
| Stage | Headcount | Tooling | Channels live |
|---|---|---|---|
| **Pre-seed-close (now)** | fCMO + founder team | All current tooling + Casey's marketing skill library + MCP layer | Organic only (SEO, content, App Store, LinkedIn, events, WOM, ambassador) |
| **Seed close (~Q3 2026)** | + first marketing hire (lifecycle/content) by end of Q3 | + paid ad accounts (Apple Search Ads, Meta, LinkedIn) | + paid acquisition pilot $5–10K/mo |
| **Seed deployment (Q3–Q4 2026)** | + designer (potentially fractional) | + analytics expansion (Mixpanel or Amplitude if needed) | + paid scaling $20–50K/mo, + Guides cert pilot |
| **Series A (2027)** | + performance marketing lead + content lead | + dedicated tooling spend (~$2–5K/mo software) | + paid scaling $50–150K/mo, + international, + B2B vertical expansion |
The marketing skill library scales these stages. Every channel added doesn't require a 1:1 headcount increase because each skill encodes the workflow.
---
## 12. Tactical idea bank — 139-idea cross-reference
The `marketing-ideas` skill catalogs 139 proven marketing tactics. Sections 4–8 (AARRR) prescribe what we're *doing*. This section maps the full universe of what's *possible* — every idea cross-referenced to the AARRR stage it primarily serves, with Quietude applicability and timing.
This is the exhaustive menu. The plan above is the curated path. When we move to Q2 / Q3 / Series A and unlock new capacity, this is the inventory we pull from.
**Status legend:**
- **Now (Q1)** — already in the 90-day plan OR can run alongside it without new capacity
- **Q2** — post-bedrock-fix, post-foundation; second-quarter layer-ins
- **Q3+** — post-seed-close, post-GA; expansion moves
- **Q4+** — long-game / large-investment moves
- **Skip / off-brand** — incompatible with Quietude's brand voice, business model, or product category
### 12.1 Acquisition ideas (88 mapped)
**Now (Q1):**
| # | Idea | Quietude note |
|---|---|---|
| 1 | Easy Keyword Ranking | SEO plan Tier-1 cluster (nervous system, sleep mask, B2B) targets this directly |
| 2 | SEO Audit | Run `/seo-audit quietude.app` quarterly; publish findings as content |
| 5 | Content Repurposing | Sound Philosophy → essays → LinkedIn posts → newsletter → podcast loop |
| 6 | Proprietary Data Content | peer-reviewed psychophysiology study now; anonymized Quietude HRV / sleep dataset later |
| 7 | Internal Linking | Built into the pillar/spoke structure of the SEO plan |
| 10 | Parasite SEO | Alex's LinkedIn already does this; consider mirror to Substack |
| 12 | Marketing Jiu-Jitsu | Meditation-vs-Regulation IS this — turn "meditation works" assumption against itself |
| 36 | Quora Marketing | Answer "why meditation doesn't work for me" + HRV + somatic questions |
| 37 | Reddit Keyword Research | Mine r/somatic, r/CPTSD, r/HSP, r/ADHD for ICP language (feeds Customer Language #139) |
| 39 | LinkedIn Audience | Alex's channel productized — primary D2C top-of-funnel today |
| 59 | Article Quotes | HARO / Help-A-B2B-Writer for Alex + Sam — easy press wins |
| 70 | Conference Speaking | Alex: WELL Conference, biophilic design events, Mindful Leadership Summit |
| 74 | Press Coverage | Pitch peer-reviewed study + longevity-influencer hook to 5 outlets in Q1 |
| 109 | Public Demos | Live Quietude events ARE this; instrument the in-person → app conversion |
| 114 | Moneyball Marketing | Already practicing — asymmetric SEO keywords, undervalued channels |
| 133 | Investor Marketing | Alex's raise — leverage angel backchannel for PR + intros |
**Q2:**
| # | Idea | Quietude note |
|---|---|---|
| 3 | Glossary Marketing | Sound + nervous system glossary — "what is polyvagal," "what is HRV," "what is somatic listening" |
| 8 | Content Refreshing | Revisit Pillar 1 quarterly with new data and search-intent updates |
| 11 | Competitor Comparison Pages | Quietude vs. Calm / Headspace / Brain.fm / Endel / Wavepaths — high-intent SERPs |
| 13 | Competitive Ad Research | SpyFu + Facebook Ad Library before launching paid |
| 17 | Quiz Marketing | "What's your nervous system profile?" — generates personalization seed + lead capture |
| 25 | Facebook Ads | Eye mask creative + somatic content + retargeting from event attendees |
| 26 | Instagram Ads | Visual product + Reels-native ads (eye mask especially) |
| 28 | LinkedIn Ads | B2B venue buyers + investor-adjacent ICP |
| 31 | Google Ads | Apple Search Ads first (App Store intent); Google for eye mask + B2B |
| 38 | Reddit Marketing | Authentic participation in r/somatic, r/HSP, r/ADHD after content base exists |
| 40 | Instagram Audience | Eye mask + somatic creators; Reels-native |
| 44 | Comment Marketing | Thoughtful comments on Huberman / the partner-event-business / Tim Ferriss / wellness creators |
| 49 | Monthly Newsletters | Either Quietude-branded or sync with Sam's Sam's Substack newsletter |
| 54 | Affiliate Discovery via Backlinks | Find who links to Calm/Headspace/Brain.fm — pitch them on Quietude affiliate program |
| 58 | Newsletter Swaps | the partner-event-business, founder wellness Substacks, Alex's investor network |
| 64 | Community Sponsorship | Somatic newsletters, wellness Substacks, founder communities |
| 65 | Live Webinars | Alex + Sam hosting "Sound + the Nervous System" |
| 101 | Industry Interviews | Alex + Sam interview category experts (becomes seed of Quietude podcast) |
| 102 | Social Screenshots | Mira reflection responses (anonymized, consented) — social proof gold |
| 108 | Changelogs | Public changelog at `quietude.app/changes` — product momentum signal |
| 115 | Curation as Marketing | Curated "field recordings of the year" feature; Quietude Spaces directory |
| 135 | Support as Marketing | Surface customer support / Mira reflection moments as content |
| 138 | Podcast Tours | Alex on Huberman, the partner-event-business, Tim Ferriss, Rich Roll, Rangan Chatterjee |
**Q3+:**
| # | Idea | Quietude note |
|---|---|---|
| 4 | Programmatic SEO | Quietude Guides city pages once Guides program scales |
| 9 | Knowledge Base SEO | When help docs scale enough to have problem-solution coverage |
| 14 | Side Projects | Eventually a free Quietude-adjacent tool that lives outside the app |
| 15 | Engineering as Marketing | HRV interpretation guide; nervous system self-assessment; sound bath finder directory |
| 18 | Calculator Marketing | Sleep latency calculator; overstimulation index |
| 20 | Microsites | For specific GTM moments (e.g., Mira GA launch) |
| 23 | Podcast Advertising | Huberman, Tim Ferriss, Rich Roll, the partner-event-business — host-read most relevant |
| 24 | Pre-targeting Ads | Warm audiences via content before direct-response |
| 29 | Reddit Ads | r/HSP, r/ADHD, r/somatic — high ICP density, low advertiser saturation |
| 30 | Quora Ads | Intent-rich for "why meditation doesn't work" queries |
| 32 | YouTube Ads | Pre-roll on Huberman / Lex Fridman / wellness creator videos |
| 33 | Cross-Platform Retargeting | Standard layer once paid is firing |
| 35 | Community Marketing | Quietude Spaces community (Discord/Circle); host monthly drop-ins |
| 42 | Short Form Video | TikTok / Reels — somatic education + eye mask UGC |
| 55 | Influencer Whitelisting | Run ads through ambassador / Guide accounts for authenticity |
| 57 | Expert Networks | Quietude Guides program IS this — certified hosts who can market |
| 60 | Pixel Sharing | Standard once paid is firing |
| 61 | Shared Slack Channels | Partner venue Slacks (Aurora, Lumen, Stillwater) |
| 63 | Integration Marketing | Apple Health (HRV data), Oura, Whoop — co-marketing |
| 66 | Virtual Summits | Quietude participates or hosts |
| 68 | Local Meetups | Cities with high ICP density (SF, NYC, LA, Austin) |
| 69 | Meetup Sponsorship | Sponsor wellness / biohacking meetups |
| 72 | Conference Sponsorship | Industry conferences once budget unlocks |
| 75 | Fundraising PR | "Quietude raises $3M" moment when seed closes |
| 78 | Product Hunt Launch | Mira public launch moment |
| 79 | Early-Access Referrals | App GA early-access list (cross-references to Referral) |
| 81 | Early Access Pricing | App GA — early-access tier locked in for first cohort |
| 82 | Product Hunt Alternatives | BetaList, Launching Next, AlternativeTo at GA |
| 97 | Playlists as Marketing | Quietude curates Spotify playlists for somatic listening |
| 98 | Template Marketing | Free "nervous system reset" protocol PDFs |
| 100 | Promo Videos | High-quality brand films — Ed Dorsey advises, Matt Mikkelsen field audio |
| 103 | Online Courses | Alex's Sound Philosophy course; Sam's somatic methodology course |
| 107 | Podcasts | Quietude podcast — interview format with category experts and customers |
| 111 | Challenges as Marketing | "21-day nervous system reset" — tasteful, no fitness-bro tone |
| 113 | Controversy as Marketing | Meditation-vs-Regulation IS mild controversy — lean in carefully |
| 126 | YouTube Reviews | Pitch Quietude to wellness YouTubers — Huberman fan-creator tier |
| 127 | YouTube Channel | Sound design behind-the-scenes; Sam session demos |
| 129 | Review Sites | App Store reviews actively managed; Trustpilot for eye mask Shopify |
| 130 | Live Audio | Twitter Spaces / LinkedIn Audio with Alex on sound + body |
| 134 | Certifications | Quietude Guides cert IS this — Q3+ pilot |
**Q4+ / long-game:**
| # | Idea | Quietude note |
|---|---|---|
| 56 | Reseller Programs | Corporate wellness platforms (Modern Health, Lyra) as resellers |
| 67 | Roadshows | Quietude Experiences IS this — eye mask + listening session pop-ups in 3 cities |
| 71 | Conferences | Quietude-hosted "Sound + the Body" — long-game category-defining moment |
| 76 | Documentaries | Alex's story is documentary-grade — long game |
| 77 | Black Friday Promotions | Holiday eye mask + Premium bundle |
| 80 | New Year Promotions | New Year nervous system reset campaign |
| 84 | Giveaways | Eye mask giveaway with brand partner (Wellness Mama tier) |
| 85 | Vacation Giveaways | Quietude + retreat partner giveaway (quietude.center could be venue) |
| 87 | Powered By Marketing | "Sound system by Quietude" badge in B2B venue installs |
| 104 | Book Marketing | Sound Philosophy as a book — long-game positioning anchor |
| 105 | Annual Reports | "State of the Nervous System" — Quietude's data + industry commentary |
| 106 | End of Year Wraps | "Your nervous system year" — Spotify Wrapped equivalent |
| 110 | Awards as Marketing | Quietude founds an award for innovative biophilic acoustic design |
| 116 | Grants as Marketing | Free Quietude subscriptions for therapists, social workers, first responders |
| 119 | OOH Advertising | SF / NYC billboards if Series A budget unlocks |
| 120 | Marketing Stunts | Public sound installation could work — brand-fitting |
| 121 | Guerrilla Marketing | Sound installation in subway / airport — interesting but requires care |
| 131 | International Expansion | Finland HQ + global ICP — Q4 or post-Series A |
**Skip / off-brand for Quietude:**
| # | Idea | Why skip |
|---|---|---|
| 16 | Importers as Marketing | No competitor data to import (consumer wellness, not SaaS) |
| 19 | Chrome Extensions | Off-platform (mobile-first product) |
| 21 | Scanners | No obvious product fit |
| 22 | Public APIs | Not core business |
| 27 | Twitter Ads | Lower priority unless Alex's X presence grows |
| 34 | Click-to-Messenger Ads | Off-brand (no DM-driven sales pattern) |
| 41 | X Audience | Depends on Alex's bandwidth — defer unless he wants to |
| 43 | Engagement Pods | Off-brand |
| 73 | Media Acquisitions | Too capital-intensive at this stage |
| 83 | Twitter Giveaways | Off-brand voice |
| 86 | Lifetime Deals | Brand-conflict — pressures the "no pressure" voice and damages LTV math |
| 88 | Free Migrations | No competitor data to migrate |
| 89 | Contract Buyouts | Not relevant for D2C subs |
| 99 | Graphic Novel Marketing | Off-brand |
| 112 | Reality TV Marketing | Off-brand |
| 117 | Product Competitions | Not a developer product |
| 118 | Cameo Marketing | Off-brand |
| 122 | Humor Marketing | Brand voice is serious; humor would feel off |
| 123 | Open Source as Marketing | Proprietary audio library |
| 125 | App Marketplaces | Not relevant for native consumer app (no app-of-app pattern) |
| 128 | Source Platforms | G2 / Capterra are B2B-focused; D2C uses App Store reviews |
| 132 | Price Localization | Q4+ — tied to international expansion |
| 136 | Developer Relations | Not a dev product |
### 12.2 Activation ideas (7 mapped)
| # | Idea | Status | Quietude note |
|---|---|---|---|
| 124 | App Store Optimization | Now | Q1 priority — listing rewrite in voice (also Acquisition) |
| 90 | One-Click Registration | Now | OAuth (Apple, Google) for app signup — standard activation lift |
| 51 | Onboarding Emails | Q2 | Flow 2 — held until UI stable post-onboarding-rebuild |
| 96 | Onboarding Optimization | Q1-Q2 | The 3-variant test IS this — primary activation work |
| 47 | Founder Welcome Email | Q2 | Personal welcome from Alex or Sam early in Flow 2 |
| 48 | Dynamic Email Capture | Q2 | Smart capture on `quietude.app` — exit intent + scroll depth |
| 95 | Concierge Setup | Q3+ | High-touch onboarding for B2B venue clients + high-value subscribers |
### 12.3 Retention ideas (8 mapped)
| # | Idea | Status | Quietude note |
|---|---|---|---|
| 46 | Reactivation Emails | Now | Flow 4 ships in weeks 3–4 — exactly this |
| 52 | Win-back Emails | Q1 (week 11-12) | Standalone campaign on top of Flow 4 |
| 53 | Trial Reactivation | Q2 | Expired-trial recovery campaign once paywall is firing |
| 45 | Mistake Email Marketing | Q2 | When something genuinely goes wrong, send "oops" — drives engagement |
| 50 | Inbox Placement | Q1 | Subdomain silo strategy (`mail.quietude.app` / `commerce.quietude.app`) addresses this |
| 91 | In-App Upsells | Q2 | Premium upsell points within app (also Revenue) |
| 94 | Offboarding Flows | Q2 | Optimize cancellation flow to retain or learn — feeds churn intel |
| 135 | Support as Marketing | Q2 | Customer support stories surface as content (also Acquisition) |
### 12.4 Referral ideas (5 mapped)
| # | Idea | Status | Quietude note |
|---|---|---|---|
| 62 | Affiliate Program | Now | Ambassador program v1 is exactly this — launched with the 5 inbound |
| 137 | Two-Sided Referrals | Q2 | Reward both referrer and referred — share-after-shift moment + gifting flow |
| 92 | Newsletter Referrals | Q3 | If we launch a newsletter, Sparkloop-style referral mechanic |
| 93 | Viral Loops | Q3 | Built-in share mechanics post-Mira reflection |
| 79 | Early-Access Referrals | Q3 | App GA early-access list referrals (cross-references to Acquisition) |
### 12.5 Revenue ideas (3 mapped — most ideas serve top-of-funnel)
| # | Idea | Status | Quietude note |
|---|---|---|---|
| 91 | In-App Upsells | Q2 | Premium upgrade prompts; eye mask cross-sell from app (also Retention) |
| 132 | Price Localization | Q4+ | Adjust pricing for local purchasing power once international |
| 86 | Lifetime Deals | Skip | Brand-conflict — see Acquisition skip list |
### 12.6 Cross-cutting / brand foundation ideas
| # | Idea | Status | Quietude note |
|---|---|---|---|
| 139 | Customer Language | Now | Mira reflection responses + 7 Ds language = the source-of-truth for customer language across all copy |
| 114 | Moneyball Marketing | Ongoing | Find undervalued channels at every stage — methodology, not a single tactic |
### Idea-bank summary
- **88 ideas applicable to Acquisition** (the dominant stage at Quietude's current stage — makes sense, Quietude's product converts well; the bottleneck is the top of funnel)
- **7 ideas to Activation, 8 to Retention** (smaller because these stages are about depth, not breadth — execute the right few well rather than running a wide tactic menu)
- **5 ideas to Referral** (program-driven, not tactic-driven)
- **3 ideas to Revenue** (most revenue work is pricing strategy, not tactical tricks)
- **2 cross-cutting**
- **23 ideas skipped for brand / business-model fit** — Quietude's category positioning constrains what's available
**What this proves:** the plan is roughly 30% of the available tactical surface area, not 100%. That's appropriate at this stage and budget. As capacity unlocks across Q2 → Q3 → Series A, the cross-reference becomes the inventory we pull from to scale activity without losing strategic coherence.
---
## 13. Measurement, RACI, open decisions, appendix
### Measurement — the metrics that matter
**North star (proposed):**
**Blended-LTV-to-blended-CAC ratio per acquired user**, where:
- Blended LTV combines app subscription revenue + hardware revenue (eye mask + speakers) + any cross-sells, per cohort
- Blended CAC combines paid spend + content production cost + ambassador commissions + lifecycle tool spend, per cohort
This captures the business model: the eye mask wedge isn't free if it costs $X to make, and the app sub isn't expensive to acquire if a Bryan-Johnson-style PR moment is paying for itself.
If a single metric is preferred for team-level focus, fall back to: **monthly new D2C subscribers from non-paid channels.** This isolates the compound channels the long-game strategy depends on.
**Leading indicators by AARRR stage:**
| Stage | Leading indicators |
|---|---|
| Acquisition | Organic visits/mo (overall + per pillar), App Store visit-to-install rate, Alex's LinkedIn engagement → email subscribers, event-to-app conversion rate, ambassador-attributed visits |
| Activation | Day 1 / Day 7 / Day 35 → paid conversion, onboarding session-completion rate, first session Mira reflection completion |
| Retention | 30 / 60 / 90-day retention, monthly churn, Flow 4 reactivation rate, hardware → app activation rate |
| Referral | Ambassador-attributed new subs (Dub), share-after-shift rate, Guides pilot referrals (when live) |
| Revenue | Blended MRR, ARPU, annual plan adoption %, LTV by cohort, eye mask attach rate |
**Review cadence:**
- **Weekly:** fCMO ↔ Alex 30-min sync. AARRR scoreboard + this week's ships.
- **Monthly:** Full metrics review (extended sync, Sam included). Compare against quarterly KPI targets.
- **Quarterly:** Plan recalibration. What's working, what's not, what funding-stage moves we're triggering.
### RACI
| Domain | Responsible | Accountable | Consulted | Informed |
|---|---|---|---|---|
| Strategic plan (this doc) | Casey | Alex | Sam, Emily | Team |
| Brand voice | Alex + Sam | Alex + Sam | Casey | Team |
| App + onboarding implementation | Devon | Alex | Casey | Team |
| Lifecycle flows (Customer.io) | Casey | Alex | Sam (copy QA) | Team |
| SEO content | Casey | Casey | Sam, Alex | Team |
| App Store copy | Casey | Alex | Sam | Team |
| Alex's LinkedIn cadence | Alex | Alex | Casey (orchestration) | Team |
| Events | Alex + Sam | Alex | Casey (instrumentation only) | Team |
| Ambassador program | Casey | Casey | Alex | Team |
| B2B sales | Alex | Alex | Casey (case studies) | Team |
| Pricing | Alex | Alex | Casey | Sam |
| Investor narrative | Alex | Alex | Casey, Sam | Team |
| Quietude Guides program (Q3+) | TBD (likely future hire) | Alex + Sam | Casey | Team |
| Future marketing hire (Q3) | Casey | Alex | Sam | Team |
### Open decisions blocking the plan
Most blocking, ranked by impact:
1. **Canonical domain.** SEO data + this plan recommend `quietude.app`. Needs exec sign-off + 301 execution plan. *Blocks: domain consolidation, SEO foundation, email sender migration.*
2. **Retention metric definition.** Reconcile 38% 12-month retention claim vs. 29% monthly App Store churn. *Blocks: clean dashboards, investor narrative coherence, lifecycle test reads.*
3. **Mira post-session reflection scope.** Does Mira currently support this, or is it new build? *Blocks: Onboarding Variants 1 and 2 (which depend on Mira reflection moment), retention compound moves.*
4. **App UI stability timeline.** When does the headphone-gate-removal + onboarding-rebuild allow Flow 2 to ship without rework risk? *Blocks: Flow 2, full lifecycle, paid acquisition timing.*
5. **GA launch timeline.** When does the throttled beta become GA? *Blocks: paid acquisition scale, Q3 GTM planning.*
6. **Pricing structure ground truth.** What's actually charged today? *Blocks: pricing audit conclusions, annual-plan default test, blended LTV math.*
7. **First marketing hire scope.** Lifecycle + content owner, or something else? When does the JD get written? *Blocks: Q3 capacity plan, succession of fCMO operational work.*
8. **Ambassador commission structure.** $/sub, rev-share, hybrid? *Blocks: ambassador program launch, attribution dashboards.*
### Appendix — deep-dive links
**Published to the team via `Quietude-Inc/quietude-context` GitHub repo:**
- `marketing/seo/plan.md` — Full 90-day SEO + keyword research plan
- `marketing/seo/keyword-shortlist.md` — Tier 1 keyword shortlist
- `marketing/seo/raw/` — Ahrefs + DataForSEO API pulls
- `marketing/onboarding-recommendation.md` — Three-variant onboarding test plan
**Founder-authored strategic context** (in Quietude's internal knowledge base):
- Seed deck — Investor narrative
- Sound Philosophy — Alex's technical/philosophical working doc
- Marketing OS — Brand voice, content rhythm, visual system
- ICP doc — D2C audience profile
- Meditation-vs-Regulation note (2026-05-19) — Central content pillar
- Kickoff call transcript (2026-05-18) — Decisions + open questions
- App Store copy snapshot + voice-gap analysis
- App Store metrics snapshot (2026-05-16)
- Customer.io lifecycle flows inventory
---
*Marketing Plan v1. Prepared by Casey Reed (fCMO), 2026-05-27. For team review and discussion.*
FILE:references/funding-stage-unlocks.md
# Funding-Stage Capability Unlocks
Every marketing plan must include explicit "what changes when funding closes / when budget unlocks" reasoning. This makes the plan investor-friendly and operationally honest.
This doc defines the standard tiers. Use them as anchors, adjust for client category and unit economics.
**Related docs:**
- `budget-planning.md` — two scientific methods for setting the actual budget number (Revenue-Based 5–40%, or Goal-Based reverse-engineered from the revenue target), CAC calculation, experimental buffer
- `growth-patterns.md` — the real shape of SaaS growth by phase ($0–10K / $10K–100K / $100K–1M+), linear vs step-function, S-curve layering
- `team-and-agency-model.md` — what each tier means for team composition, the first marketing hire, and the in-house vs outsource ratio
## Why funding stage matters in a marketing plan
Most marketing plans are written as if budget is unconstrained. That's a failure mode for early-stage clients — it produces aspirational lists rather than executable roadmaps.
The fix: tie every recommendation to a budget tier. The plan stays honest about what's executable today, and the team / investors see explicitly what each round of capital unlocks.
This also helps the founder mid-raise: showing what the round buys is investor-narrative material.
## Standard tiers
### Tier 1 — Pre-seed / bootstrapped
**Budget profile:**
- Paid acquisition: $0
- Tooling stack: ~$500–2,000/mo (Customer.io / similar, GA4 free, Stripe fees, Notion, GitHub, basic SaaS)
- Retainers / fCMO: variable (fractional only)
- Headcount: founders + maybe 1–2 multipurpose hires
**Marketing capability:**
- Organic only — SEO, content, App Store organic, founder-led social, events, WOM, ambassador (if inbound exists)
- Limited PR (founder-led pitches, HARO responses)
- No paid layer
**Channels live:** Organic SEO, content, App Store, LinkedIn / X / founder-led social, events, WOM, ambassador
**What a fCMO does:** Strategy + lifecycle + content + SEO + onboarding + community + ambassador. Hands-on with skill library + MCPs doing the operational lift.
**Hires unlocked:** None. The plan must execute with current team + agentic stack.
### Tier 2 — Seed close
**Budget profile:**
- Paid acquisition: $5–15K/mo test budget
- Tooling stack: $1,000–3,000/mo (paid ad accounts, Mixpanel / Amplitude if needed, additional SaaS)
- Retainers / fCMO: continued
- Headcount: + first dedicated marketing hire
**Marketing capability:**
- Above + paid acquisition pilot (Apple Search Ads, Meta, LinkedIn)
- Begin PR push with the funding announcement
- First Product Hunt / GA-style launch
**Channels live:** All Tier 1 + paid acquisition (small) + active PR
**Hires unlocked:**
- Lifecycle + content marketing manager (one person doing both, or split)
- OR dedicated growth / performance marketing manager (if heavy paid focus)
**fCMO shifts:** From hands-on to strategy + ops oversight. Hires the dedicated marketer. Sets up the channel playbooks before paid scales.
### Tier 3 — Seed deployment
**Budget profile:**
- Paid acquisition: $20–50K/mo
- Tooling stack: $2,000–5,000/mo
- Retainers / fCMO: continued
- Headcount: + designer (potentially fractional)
**Marketing capability:**
- Paid scaling across 2–3 channels
- Brand-aligned creative production (designer enables velocity)
- Lifecycle programs fully live across all flows
- First true content production cadence (weekly cadence sustainable)
**Channels live:** All previous + paid scaling + structured launch motion
**Hires unlocked:**
- Designer (brand, creative, web)
- Second marketing manager (if first was lifecycle, second is content; or vice versa)
- Potentially fractional PR if budget allows
**fCMO shifts:** Hands off lifecycle to dedicated owner. Moves to GTM strategy + channel mix optimization + growth analytics.
### Tier 4 — Series A
**Budget profile:**
- Paid acquisition: $50–150K/mo
- Tooling stack: $5,000–10,000/mo
- Retainers / fCMO: may transition to permanent CMO
- Headcount: full marketing team forming
**Marketing capability:**
- Paid scales aggressively across all proven channels
- Brand campaigns become possible
- International consideration begins
- B2B vertical expansion (if applicable)
- Sophisticated CAC/LTV math + attribution
**Channels live:** Full marketing surface area
**Hires unlocked:**
- Performance marketing lead
- Content lead
- Designer (permanent)
- Potentially: PR firm, paid agency, international growth manager
- Series A often the moment the fCMO transitions out or transitions to advisor
**fCMO shifts:** Often the moment of transition — to permanent CMO hire, fCMO becomes advisor.
### Tier 5 — Series B+
**Budget profile:**
- Paid acquisition: $150K+/mo
- Tooling stack: $10,000–25,000/mo
- Headcount: 10+ marketing org
**Marketing capability:**
- Brand campaigns at industry scale
- PR firm partnerships
- Acquisitions as marketing (acquiring newsletters / podcasts in space)
- Conference sponsorship at category level
- Sponsorships at brand level
**Channels live:** Everything available
**Hires unlocked:**
- VP Marketing or CMO
- Brand director
- Growth / performance team (3–5 people)
- Content team (3–5 people)
- Designers (2–3)
- PR director or agency partnership
- International marketing leads (region-specific)
**fCMO involvement:** Typically out of the company by this point — the original fCMO might still be an advisor.
## How to apply tier logic in a plan
### Section 3 (Current state)
- State the client's current tier explicitly: "Current tier: pre-seed / bootstrapped per Tier 1."
### Section 4–8 (AARRR sections)
- Note tier-dependent moves: "Paid layer (Tier 2 unlock — held until seed close)"
- For Tier 1 plans: every move must be executable at current budget tier OR explicitly flagged as future
- For Tier 2+ plans: moves can assume the tier's capability
### Section 10 (12-month outlook)
- Each quarter names the tier that's active: "Q2 — Months 4–6 (post seed close). Funding state: Tier 2."
- Tier transitions trigger plan recalibration moments
### Section 11 (Marketing operations stack)
- Use the table in `references/ops-stack-mapping.md` capability-unlocks section
- Make it client-specific: "Today (Tier 1): {client's current capability}. After seed close (Tier 2): + {what changes}."
## Adjustments by client category
The standard tiers assume a typical software / SaaS / consumer app. Adjust for category:
### Consumer apps (D2C)
- Higher paid acquisition floor — apps need to test CAC against download cost benchmarks (~$2-10 install + 5-15% trial conversion benchmark)
- Tier 2 starts effectively at $10–20K/mo paid (otherwise can't get statistically meaningful reads at app-install CPMs)
### B2B SaaS
- Lower paid acquisition floor — LinkedIn / Google Ads can produce signal at $3–5K/mo
- More weight on content + sales enablement budget
- Often add a sales hire before a content hire
### Hybrid hardware + software
- Hardware revenue can self-fund some marketing (the eye-mask wedge pattern)
- Paid budget should track blended CAC across hardware sales + app subs
- Shopify-side optimization is a Tier 1 priority (cheap leverage)
### Deep-tech / scientific / clinical
- PR + investor marketing carries more weight than paid
- Conference speaking + academic publishing > Meta ads
- Tier 1 can produce significant traction without paid
### Marketplace / two-sided
- Each side has its own AARRR funnel — budget splits accordingly
- Supply-side acquisition often dominates early; demand-side dominates after liquidity
### Open source / developer tools
- DevRel + community + content > paid
- GitHub stars / npm installs are the activation event
- Paid layer often delayed until Series A
## Tier 1 budget detail (most common starting point)
For Tier 1 clients, the marketing budget breakdown typically looks like:
| Line | Typical monthly |
|---|---|
| Customer.io / lifecycle ESP | $100–500 |
| App Store Connect / Google Play | $25 + 30% rev share (Apple/Google take) |
| Stripe | 2.9% + 30¢ per transaction |
| GA4 | Free |
| Notion | $0–100 |
| GitHub | $0–50 |
| Shopify (if hardware) | $39–100 |
| Ahrefs (or similar SEO tool) | $129–399 |
| Typefully (if social cadence) | $13–39 |
| Dub.co (if ambassador tracking) | $0–39 |
| Misc SaaS | $200–500 |
| **Tooling total** | **~$500–1,700/mo** |
| Paid acquisition | $0 |
| fCMO retainer | Variable |
For the plan, this becomes: "Current monthly marketing budget: $X (tooling only, no paid)."
## When to surface tier limits to the founder
If a founder asks for moves that require a future tier:
- Name the requirement: "This is a Tier 2 move (requires $10K+/mo paid budget). Will unlock after seed close per the 12-month outlook in §10."
- Don't refuse — frame the timing
If a founder underestimates what's needed:
- Be honest: "To scale paid acquisition meaningfully, expect Tier 2 budget. Tier 1 can validate organic; Tier 2 validates paid."
If a founder is over-funded for their stage:
- Don't pad budget to match. Recommend the right work for the funnel state, return excess capacity, suggest investment in compounding rather than scaling.
## Tier-skip cases (worth flagging)
Some companies skip tiers:
- **Notable founder** raising larger-than-typical rounds — can jump from Tier 1 to Tier 3 directly
- **Hardware company** with PR moment — can deploy at Tier 3 levels with the right product moment (e.g., a high-profile longevity-influencer endorsement)
- **B2B SaaS post-LOI** with named enterprise contracts — can fund pilot deployment from contract value
If the client is in a tier-skip situation, name it explicitly in the plan rather than forcing them into the standard ladder.
FILE:references/growth-patterns.md
# Growth Patterns — The Real Shape of SaaS Growth
The 12-month outlook in every plan (Section 10) describes a trajectory. This doc names the shape of that trajectory honestly — what real SaaS growth looks like, when to expect plateaus, and how to plan for the next leg of growth before the current one stalls.
Excerpted and adapted from *Founding Marketing* by Corey Haines.
## The long, slow SaaS ramp of death
Pitch decks show hockey sticks. Real growth shows a series of S-curves — each representing a distinct phase followed by a plateau that tests resolve and creativity.
### Phase 1 — $0 → $10K ARR (the grueling phase)
The hardest milestone. Every customer is a hard-won victory. Typical time: **6–12 months.** Most companies pivot the product multiple times during this phase.
What it requires:
- Runway long enough to keep experimenting until something clicks
- A financial cushion or additional income sources (often the difference between success and shutdown)
- Tolerance for ambiguity — the product positioning, the pricing, and the channel can all still be wrong at this stage
### Phase 2 — $10K → $100K ARR (the treacherous middle)
The middle ground that kills most promising startups. The average company reaches ~$40K ARR in year one. The danger: enough revenue to prove the concept, not enough to support a team.
The threshold to watch for: **$8–10K MRR.** That's when founders can typically go full-time on the business without other income sources. Until then, careful cash management or side income carries the company through.
Companies that flame out in Phase 2 usually run out of runway just as things start working.
### Phase 3 — $100K → $1M ARR (the acceleration phase)
Where things get interesting. Typical time: nearly 2 years total to reach $1M. But there's an acceleration pattern: **once across $100K, companies often double from $100K → $200K in one-third the time it took to reach the first $100K.**
Why: critical mass kicks in. Word-of-mouth starts working. Early customers become your best salespeople. The product has proven itself, and growth becomes more about execution than experimentation.
This is the phase where the marketing plan's 90-day roadmap (Section 9) starts compounding instead of just covering ground.
## Two real growth patterns (and the exponential myth)
The myth: successful SaaS companies grow exponentially, doubling revenue month over month like clockwork.
The reality: two distinct patterns, often combining at scale to *look* exponential when zoomed out.
### Pattern 1 — Linear growth
Build a predictable revenue machine. Find a channel that works (content, partnerships, paid, outbound) and steadily scale it. Some companies reliably add **$10K MRR per month** through a well-oiled marketing engine.
Less sexy than exponential. Far more sustainable. Crucially, **plannable**: when you know what you can count on adding each month, hiring decisions, product roadmap, and expansion planning all become tractable.
### Pattern 2 — Step-function growth
Periods of plateau followed by sudden jumps. Jumps aren't random — they're triggered by specific events:
- Breaking into a new market segment (e.g., enterprise after starting SMB)
- Launching a major product expansion (new feature line, new tier)
- Cracking a new marketing channel that compounds
Example: one founder saw revenue triple in two months after launching enterprise features — following six months of flat growth.
Key insight for the plan: **each step requires deliberate action and investment.** Steps don't happen by waiting. While standing on the current step, you have to be actively building the next one.
### How they combine
Zoom out far enough and a series of linear phases + step functions can look exponential. That's where the myth comes from. Understanding it's actually a series of plannable shapes changes how you build the plan:
- Don't chase the myth of doubling every month
- Build sustainable linear systems (Sections 4–8 AARRR moves)
- Plan deliberate step functions (Section 10 12-month milestones)
## Layering growth curves — Channel × Product × Market
The secret to sustained growth isn't one perfect channel. It's orchestrating multiple S-curves that work together. Three S-curves to track:
### Channel S-curves
Every marketing channel has its own lifecycle:
- **SEO** — 6–12 months to mature; once it does, steady leads for years. Marathon runner.
- **Paid ads** — quick wins; diminishing returns as you scale.
- **Content marketing** — slow to start, compounds beautifully over time.
- **Partnerships / co-marketing** — episodic; high yield when the right partner aligns.
- **Outbound** — predictable when calibrated; CAC-heavy and plateaus at team capacity.
- **PR** — spike-driven; sustains awareness rather than direct conversion.
**The rule:** start the next channel before the current one plateaus. Riding one channel to its ceiling before investing in the next produces a multi-month growth plateau that takes more effort to break out of than it would have taken to start the next channel earlier.
In the plan: Section 4 (Acquisition) names current channels, planned channels, and skipped channels. The 12-month roadmap (Section 10) sequences when the next channel investment begins.
### Product S-curves
Your core product naturally hits a growth ceiling as you saturate the initial market. Pushing harder on the same features doesn't break through. What does:
- Adding features that target new use cases
- Extending the product line to serve adjacent needs
- Expanding into new market segments (e.g., team collaboration added to a single-user tool — opens a new market)
In the plan: Sections 5 (Activation) and 8 (Revenue) name where the product needs to grow to unlock the next growth tier.
### Market S-curves
Every market segment has its own growth ceiling. Time the expansion into the next segment while the current segment is still showing strong growth. Common patterns:
- SMB → mid-market → enterprise
- Single vertical → adjacent verticals
- Domestic → international
Waiting until a segment is saturated makes the transition harder.
In the plan: Section 2 (Strategic frame) names current segment + future segments. Section 10 (12-month outlook) sequences when expansion moves begin.
### The orchestration
The real magic: while SEO is maturing, you're using paid for quick wins. As those channels mature, you're developing product features that unlock enterprise. Meanwhile, the groundwork for international expansion is being laid for when domestic saturates.
This is the operational thesis behind the AARRR mapping (Sections 4–8) and the 12-month outlook (Section 10): each section is a curve, and the plan sequences them so the next curve is ramping while the current one is still growing.
## The 70/20/10 resource-allocation rule
Layering S-curves only works if the next curve is funded *before* the current one plateaus. The 70/20/10 rule is the budgeting discipline that guarantees it. Split marketing effort and spend across three buckets:
| Bucket | Share | What it covers |
|---|---|---|
| **Current** | **70%** | The initiatives already working — the channels, content, and campaigns driving today's growth. Protect and optimize. |
| **Next** | **20%** | The S-curve you're deliberately building — the channel/product/market bet that becomes the *current* 70% in 2–4 quarters. |
| **Experimental** | **10%** | Unproven bets and small tests. Most fail; the ones that work graduate into the 20%, then the 70%. |
Why it matters for the plan:
- It operationalizes "start the next S-curve before the current one plateaus" — the 20% + 10% *is* the next curve, funded on purpose rather than scrambled for after a plateau hits.
- It maps cleanly onto the **10–20% experimental budget buffer** in `budget-planning.md` — the experimental layer is the 10% here.
- It gives Section 11 (Ops stack) and Section 10 (12-month outlook) a defensible allocation logic instead of dumping the whole budget into what's currently working.
**In the plan:** Section 10 (12-month outlook) names what sits in each bucket now, and what's expected to graduate. Section 11 (Ops stack) shows the 70/20/10 split across the AARRR stages. Adjust the ratio by phase — Phase 1 companies (still hunting for any channel that works) may run closer to 40/30/30; Phase 3 companies with a proven engine can run 80/15/5.
## Weekly tracking cadence and plateau alerts
S-curve plateaus are the single most important thing to catch early — the whole point of layering curves is to shift weight to the next one *before* the current plateau bites. That requires a review rhythm, not an annual look-back.
### The cadence
- **Weekly** — review the leading indicators for each active S-curve (new signups per channel, content velocity, activation rate, MRR added). Weekly is frequent enough to spot a curve flattening while there's still time to act.
- **Monthly** — roll the weeklies up; confirm which bucket (70/20/10) each initiative belongs in and whether anything should graduate or be cut.
- **Quarterly** — the plan itself adjusts (re-sequence Section 10, reallocate the budget).
### Plateau-indicator alerts
Watch for these signals that a curve is topping out — each is a trigger to shift weight toward the next curve, not to push harder on the current one:
- **Week-over-week additions flattening** — the channel is adding the same absolute numbers it did last month despite equal or greater effort (declining marginal return).
- **Rising CAC on a formerly cheap channel** — paying more for the same result is the classic plateau tell.
- **Engagement/activation softening at the top of the funnel** — the audience for this channel/message is saturating.
- **Effort up, output flat** — the team is working harder to hold the line rather than to grow it.
When two or more fire on the same curve, that's the trigger to accelerate the **20% "next" bucket** — the plateau is the moment between two S-curves, and it should already have a successor ramping.
**In the plan:** Section 13 (Measurement) names the weekly leading indicators per S-curve and the specific plateau thresholds that trigger the next move. This turns "watch for plateaus" from a platitude into an operational alert.
## The 3-3-2-2-2 VC growth path
For companies that have crossed $1M ARR and raised institutional capital, the VC benchmark is:
| Year | Multiple | Cumulative ARR (from $1M) |
|---|---|---|
| Year 0 | — | $1M |
| Year +1 | 3× | $3M |
| Year +2 | 3× | $9M |
| Year +3 | 2× | $18M |
| Year +4 | 2× | $36M |
| Year +5 | 2× | $72M |
| Year +6 | 2× | $144M |
| Year +7 | 2× | $288M |
Most companies don't hit this. Useful regardless — anchoring the 12-month outlook against this benchmark forces the plan to either (a) match it and show how, or (b) explicitly defend choosing a slower trajectory.
For non-VC-backed (bootstrapped, founder-funded, profit-focused) companies, this curve doesn't apply. Use linear or step-function targeting instead.
## How this informs the plan
| Section | What to include |
|---|---|
| **3 (Current state)** | Where the company is on each S-curve (channel maturity, product maturity, market saturation). Name the current phase ($0–10K / $10K–100K / $100K–1M / $1M+). |
| **4 (Acquisition)** | Current channels + their position on the S-curve (early / mature / plateauing). Next channel investment with rationale. |
| **5–8 (AARRR)** | Each section names the binding constraint at the current phase. For Phase 2 companies, Activation is usually the leverage point. For Phase 3, Retention + Referral compound the existing growth. |
| **9 (90-day roadmap)** | Linear-pattern moves dominate (predictable additions). Step-function setups (the build-up to a launch, an enterprise tier, a new market segment) live here. |
| **10 (12-month outlook)** | Sequence channel S-curves, product S-curves, market S-curves. Apply the 70/20/10 split (current / next / experimental) so the next curve is funded before the current one plateaus. If VC-backed Series A+, anchor against 3-3-2-2-2. If not, name the linear or step-function targets. |
| **11 (Ops stack)** | Show the 70/20/10 allocation across the AARRR stages — what share protects what's working vs. builds the next curve vs. experiments. |
| **13 (Measurement)** | The north-star metric reflects the current phase (Phase 1 is usually pure new-signup; Phase 3 is usually expansion ARR or NRR). Name the weekly leading indicators per S-curve and the plateau thresholds that trigger the next move. |
## Operational guidance for the planner
- **Don't promise exponential.** If the plan implies doubling every month, the founder will use it against you in 90 days. Linear + step-function is honest.
- **Name the binding constraint.** Phase 1 binding constraint is finding any channel that works. Phase 2 is funding the team. Phase 3 is breaking the ceiling on whichever channel got you here.
- **Plateaus aren't failures.** They're the moment between two S-curves. The plan should anticipate them and stage the next move.
- **Don't conflate "growth" with "growth rate."** A company adding $20K MRR each month for 24 months has built a remarkable machine. The fact that the *percentage* growth rate declines as the base grows is arithmetic, not failure.
FILE:references/idea-cross-reference.md
# Idea Cross-Reference — 139 Marketing Ideas Mapped to AARRR
The `marketing-ideas` skill catalogs 139 proven marketing tactics. This doc is the source-of-truth mapping: every idea assigned to a primary AARRR stage, with notes for when it's typically active and what category constraints apply.
The plan's Section 12 ("Tactical idea bank") uses this mapping as the base, then layers client-specific filters: brand voice rules might skip some ideas; funding stage might shift Q-status; client category might rule out others.
## How to read this doc
- **139 unique ideas, 144 entries.** Five ideas cross-cut multiple AARRR stages and appear under each stage they serve (#79 Early-Access Referrals, #86 Lifetime Deals, #91 In-App Upsells, #114 Moneyball Marketing, #117 Product Competitions). Each duplicate row carries a cross-cut note.
- **"Entries" counts rows; idea IDs are unique.** Section header counts reflect rows in this doc, not unique ideas from `marketing-ideas`.
- **Numbers correspond exactly to the `marketing-ideas` skill ordering.** If `marketing-ideas` reorders or expands, update this doc.
## AARRR assignment for all 139 ideas
### Acquisition (116 entries)
These ideas primarily serve top-of-funnel awareness, traffic, and lead generation.
| # | Idea | Category | Typical stage available |
|---|---|---|---|
| 1 | Easy Keyword Ranking | Content & SEO | Now (any stage) |
| 2 | SEO Audit | Content & SEO | Now |
| 3 | Glossary Marketing | Content & SEO | Q2+ |
| 4 | Programmatic SEO | Content & SEO | Q3+ (needs data + template system) |
| 5 | Content Repurposing | Content & SEO | Now (immediate leverage) |
| 6 | Proprietary Data Content | Content & SEO | Now (if data exists) |
| 7 | Internal Linking | Content & SEO | Now |
| 8 | Content Refreshing | Content & SEO | Q2+ (after content base exists) |
| 9 | Knowledge Base SEO | Content & SEO | Q3+ (after help docs exist) |
| 10 | Parasite SEO | Content & SEO | Now |
| 11 | Competitor Comparison Pages | Competitor | Q2+ |
| 12 | Marketing Jiu-Jitsu | Competitor | Now |
| 13 | Competitive Ad Research | Competitor | Pre-paid |
| 14 | Side Projects | Free Tools | Q3+ |
| 15 | Engineering as Marketing | Free Tools | Q3+ |
| 16 | Importers as Marketing | Free Tools | SaaS-specific |
| 17 | Quiz Marketing | Free Tools | Q2+ |
| 18 | Calculator Marketing | Free Tools | Q3+ |
| 19 | Chrome Extensions | Free Tools | Browser-relevant only |
| 20 | Microsites | Free Tools | Q3+ |
| 21 | Scanners | Free Tools | Specific products only |
| 22 | Public APIs | Free Tools | Developer/dev tool products |
| 23 | Podcast Advertising | Paid Ads | Post-budget |
| 24 | Pre-targeting Ads | Paid Ads | Post-budget |
| 25 | Facebook Ads | Paid Ads | Post-budget |
| 26 | Instagram Ads | Paid Ads | Post-budget |
| 27 | Twitter Ads | Paid Ads | Post-budget |
| 28 | LinkedIn Ads | Paid Ads | Post-budget (B2B-strong) |
| 29 | Reddit Ads | Paid Ads | Post-budget |
| 30 | Quora Ads | Paid Ads | Post-budget |
| 31 | Google Ads | Paid Ads | Post-budget |
| 32 | YouTube Ads | Paid Ads | Post-budget |
| 33 | Cross-Platform Retargeting | Paid Ads | Post-paid-firing |
| 34 | Click-to-Messenger Ads | Paid Ads | Niche use cases |
| 35 | Community Marketing | Social & Community | Q3+ |
| 36 | Quora Marketing | Social & Community | Now |
| 37 | Reddit Keyword Research | Social & Community | Now |
| 38 | Reddit Marketing | Social & Community | Q2+ |
| 39 | LinkedIn Audience | Social & Community | Now (B2B + founders) |
| 40 | Instagram Audience | Social & Community | Q2+ |
| 41 | X Audience | Social & Community | Depends on founder bandwidth |
| 42 | Short Form Video | Social & Community | Q3+ |
| 43 | Engagement Pods | Social & Community | Generally off-brand |
| 44 | Comment Marketing | Social & Community | Q2+ |
| 49 | Monthly Newsletters | Email | Q2+ (Acquisition use: subscriber capture) |
| 54 | Affiliate Discovery via Backlinks | Partnerships | Q2+ |
| 55 | Influencer Whitelisting | Partnerships | Post-paid-budget |
| 56 | Reseller Programs | Partnerships | Q4+ |
| 57 | Expert Networks | Partnerships | Q3+ |
| 58 | Newsletter Swaps | Partnerships | Q2+ |
| 59 | Article Quotes (HARO) | Partnerships | Now |
| 60 | Pixel Sharing | Partnerships | Post-paid |
| 61 | Shared Slack Channels | Partnerships | Q3+ |
| 63 | Integration Marketing | Partnerships | Q3+ |
| 64 | Community Sponsorship | Partnerships | Q2+ |
| 65 | Live Webinars | Events | Q2+ |
| 66 | Virtual Summits | Events | Q3+ |
| 67 | Roadshows | Events | Q4+ |
| 68 | Local Meetups | Events | Q3+ |
| 69 | Meetup Sponsorship | Events | Q3+ |
| 70 | Conference Speaking | Events | Now (if founder is speakable) |
| 71 | Conferences (own-hosted) | Events | Q4+ |
| 72 | Conference Sponsorship | Events | Q3+ |
| 73 | Media Acquisitions | PR & Media | Series A+ |
| 74 | Press Coverage | PR & Media | Now (if newsworthy) |
| 75 | Fundraising PR | PR & Media | When fund closes |
| 76 | Documentaries | PR & Media | Q4+ |
| 77 | Black Friday Promotions | Launches | Q4 (seasonal) |
| 78 | Product Hunt Launch | Launches | At GA or major feature |
| 79 | Early-Access Referrals | Launches | Pre-launch or GA |
| 80 | New Year Promotions | Launches | Q1 (seasonal) |
| 81 | Early Access Pricing | Launches | GA |
| 82 | Product Hunt Alternatives | Launches | Same as PH |
| 83 | Twitter Giveaways | Launches | Generally off-brand |
| 84 | Giveaways | Launches | Q3+ |
| 85 | Vacation Giveaways | Launches | Q4+ (seasonal) |
| 86 | Lifetime Deals | Launches | Generally off-brand (damages LTV math) |
| 87 | Powered By Marketing | Product-Led | Q4+ |
| 88 | Free Migrations | Product-Led | SaaS-specific |
| 89 | Contract Buyouts | Product-Led | B2B SaaS only |
| 97 | Playlists as Marketing | Content Formats | Q3+ |
| 98 | Template Marketing | Content Formats | Q3+ |
| 99 | Graphic Novel Marketing | Content Formats | Generally off-brand |
| 100 | Promo Videos | Content Formats | Q3+ |
| 101 | Industry Interviews | Content Formats | Q2+ |
| 102 | Social Screenshots | Content Formats | Q2+ |
| 103 | Online Courses | Content Formats | Q3+ |
| 104 | Book Marketing | Content Formats | Q4+ |
| 105 | Annual Reports | Content Formats | Q4+ |
| 106 | End of Year Wraps | Content Formats | Q4 (seasonal) |
| 107 | Podcasts (own-hosted) | Content Formats | Q3+ |
| 108 | Changelogs | Content Formats | Q2+ |
| 109 | Public Demos | Content Formats | Now |
| 110 | Awards as Marketing | Unconventional | Q4+ |
| 111 | Challenges as Marketing | Unconventional | Q3+ |
| 112 | Reality TV Marketing | Unconventional | Generally off-brand |
| 113 | Controversy as Marketing | Unconventional | Brand-dependent |
| 114 | Moneyball Marketing | Unconventional | Ongoing methodology |
| 115 | Curation as Marketing | Unconventional | Q2+ |
| 116 | Grants as Marketing | Unconventional | Q4+ |
| 117 | Product Competitions | Unconventional | Developer-specific |
| 118 | Cameo Marketing | Unconventional | Generally off-brand |
| 119 | OOH Advertising | Unconventional | Series A+ |
| 120 | Marketing Stunts | Unconventional | Brand-dependent |
| 121 | Guerrilla Marketing | Unconventional | Brand-dependent |
| 122 | Humor Marketing | Unconventional | Brand-dependent |
| 123 | Open Source as Marketing | Platforms | Developer products |
| 125 | App Marketplaces | Platforms | Platform-specific |
| 126 | YouTube Reviews | Platforms | Q3+ |
| 127 | YouTube Channel | Platforms | Q3+ |
| 128 | Source Platforms | Platforms | B2B SaaS only |
| 129 | Review Sites | Platforms | Now |
| 130 | Live Audio | Platforms | Q3+ |
| 131 | International Expansion | International | Q4+ |
| 133 | Investor Marketing | Developer/etc | Now (when raising) |
| 138 | Podcast Tours | Audience-Specific | Q2+ |
### Activation (8 entries)
| # | Idea | Category | Typical stage available |
|---|---|---|---|
| 47 | Founder Welcome Email | Email | Q2+ (Activation use) |
| 48 | Dynamic Email Capture | Email | Q2+ |
| 51 | Onboarding Emails | Email | When UI is stable |
| 90 | One-Click Registration | Product-Led | Now |
| 91 | In-App Upsells | Product-Led | Q2+ (cross-cuts Revenue) |
| 95 | Concierge Setup | Product-Led | Q3+ (high-value users) |
| 96 | Onboarding Optimization | Product-Led | Now |
| 124 | App Store Optimization | Platforms | Now (App Store products) |
### Retention (8 entries)
| # | Idea | Category | Typical stage available |
|---|---|---|---|
| 45 | Mistake Email Marketing | Email | Opportunistic |
| 46 | Reactivation Emails | Email | Now |
| 50 | Inbox Placement | Email | Now (technical setup) |
| 52 | Win-back Emails | Email | Q1+ |
| 53 | Trial Reactivation | Email | Q2+ (when paywall is firing) |
| 94 | Offboarding Flows | Product-Led | Q2+ |
| 135 | Support as Marketing | Developer/etc | Q2+ |
| 134 | Certifications | Developer/etc | Q3+ (cross-cuts Referral) |
### Referral (5 entries)
| # | Idea | Category | Typical stage available |
|---|---|---|---|
| 62 | Affiliate Program | Partnerships | Now (when inbound exists) |
| 79 | Early-Access Referrals | Launches | Pre-launch / GA |
| 92 | Newsletter Referrals | Product-Led | Q3+ (if newsletter exists) |
| 93 | Viral Loops | Product-Led | Q3+ |
| 137 | Two-Sided Referrals | Audience-Specific | Q2+ |
### Revenue (2 entries — most monetization is strategy not tactic)
| # | Idea | Category | Typical stage available |
|---|---|---|---|
| 91 | In-App Upsells | Product-Led | Q2+ (cross-cuts Activation) |
| 132 | Price Localization | International | Q4+ |
> **Skipped from Revenue:** #86 Lifetime Deals appears under Launches (Acquisition section) only. It's generally off-brand for subscription products because it damages LTV math; recommend in Section 12's Skip list with rationale, not in stage totals.
### Cross-cutting / brand foundation (2 entries)
| # | Idea | Category | Typical stage available |
|---|---|---|---|
| 114 | Moneyball Marketing | Unconventional | Ongoing methodology |
| 139 | Customer Language | Audience-Specific | Now (foundational) |
### Developer-specific / dev tool products (2 entries)
| # | Idea | Category | Use when |
|---|---|---|---|
| 117 | Product Competitions | Unconventional | Developer tool products |
| 136 | Developer Relations | Developer/etc | Developer tool products |
## How to apply this to a specific client
For Section 12 of the plan:
### Step 1 — Filter for category fit
For each idea, ask:
- Does this idea apply to the client's category? (e.g., #16 Importers only for SaaS; #19 Chrome Extensions only for browser-relevant; #136 DevRel only for dev tools)
- Skip ideas that don't apply, with a note
### Step 2 — Filter for brand voice
For each idea, ask:
- Does this idea conflict with the client's brand voice?
- Common conflicts:
- **Lifetime Deals (#86)** — conflicts with premium positioning
- **Twitter Giveaways (#83)** — often off-brand for serious / clinical / luxury voices
- **Humor Marketing (#122)** — off-brand for serious / clinical voices
- **Cameo Marketing (#118)** — off-brand for most voices
- **Reality TV Marketing (#112)** — off-brand for most voices
If conflict, place in Skip list with explicit rationale.
### Step 3 — Set timing status
For ideas that pass filters, set status:
- **Now (Q1)** — already in 90-day plan OR can run alongside without new capacity
- **Q2** — post-bedrock-fix, post-foundation; second-quarter layer-in
- **Q3+** — post-seed-close, post-GA; expansion moves
- **Q4+** — long-game / large-investment
Use the "Typical stage available" column as the default. Shift earlier if client has unusual capability (e.g., a celebrity founder shifts Conference Speaking #70 from "Now" to "Now and high-leverage").
### Step 4 — Write the client-specific note
Every "Now / Q2 / Q3+" idea gets a one-line client-specific note. Examples:
- For idea #11 Competitor Comparison Pages: "Quietude vs. Calm / Headspace / Brain.fm / Endel / Wavepaths — high-intent SERPs"
- For idea #133 Investor Marketing: "Alex's seed raise — leverage angel backchannel for PR + intros"
- For idea #15 Engineering as Marketing: "HRV interpretation guide; nervous system self-assessment; sound bath finder directory"
### Step 5 — Sum the bank
After all five AARRR tables + skip list:
```markdown
### Idea-bank summary
- {Acquisition count} ideas applicable to Acquisition (the dominant stage at {client}'s current stage)
- {Activation count} to Activation, {Retention count} to Retention
- {Referral count} to Referral
- {Revenue count} to Revenue
- {cross-cutting count} cross-cutting
- {skipped count} ideas skipped for brand / business-model fit
**What this proves:** the plan is roughly X% of the available tactical surface area, not 100%. {appropriate or not for the stage} — as capacity unlocks across Q2 → Q3 → Series A, the cross-reference becomes the inventory to scale activity without losing strategic coherence.
```
## How to maintain this doc
If `marketing-ideas` adds new ideas (it's a living skill — the 139 may become 145 or 160 over time):
1. Read `skills/marketing-ideas/references/ideas-by-category.md` in the `marketingskills` repo
2. Assign each new idea to a primary AARRR stage using the rules above
3. Add to this doc's tables
4. Update SKILL.md's idea-count reference
## Sources
- `skills/marketing-ideas/SKILL.md` (in the `marketingskills` repo)
- `skills/marketing-ideas/references/ideas-by-category.md` (in the `marketingskills` repo)
FILE:references/measurement-framework.md
# Measurement Framework — KPIs, North Stars, Cadence
Every plan needs a measurement section that tells the team how to know if the plan is working. This doc is the source for Section 13's measurement subsection.
**Related docs:**
- `growth-patterns.md` — the 3-3-2-2-2 VC growth path (3× in years 1–2, 2× in years 3–7 from $1M ARR) and which phase of SaaS growth the company is in ($0–10K / $10K–100K / $100K–1M+)
- `budget-planning.md` — CAC calculation (blended, not paid-only) and the forecasting reality check (forecasts under $100M ARR are educated guesses, not precise predictions)
## The north-star principle
A north star is one metric that captures the business-model thesis at the highest level. It should:
- Be derivable from the funnel + revenue model
- Move slowly enough to be a strategic compass (not whipsawed by weekly noise)
- Trade off correctly against other metrics — improving the north star should generally improve the business
Don't default to "ARR" or "MRR" alone. Those are outcomes, not norths. Pick something that captures the business model.
## North-star patterns by business model
### B2B SaaS (subscription)
- **Net Revenue Retention (NRR)** — keeps existing customers + expansion in focus
- Alternative: "Logo retention × expansion ARR"
- Why: ARR alone hides churn / lets gross-add growth mask product fit problems
### D2C consumer app (subscription)
- **Blended LTV / blended CAC** — keeps unit economics honest as paid layer scales
- Alternative: "Day-35 paid users from cohort × LTV"
- Why: monthly subscription metrics are volatile; cohort × LTV smooths it
### Hybrid hardware + software (e.g., Quietude)
- **Blended LTV / blended CAC across hardware + software** — captures the wedge thesis
- Alternative: "Hardware-buyers-to-subscriber conversion × blended margin"
- Why: hardware revenue isn't free (cost to make); subscription revenue isn't expensive to acquire if hardware funds it
### Marketplace (two-sided)
- **Liquidity ratio × take-rate** — captures both sides + monetization
- Alternative: "Monthly transacting users × take-rate × repeat frequency"
- Why: GMV alone doesn't capture whether the marketplace is becoming a habit
### Developer tool / open source
- **Weekly active developers × paid-conversion** — captures both adoption and monetization
- Alternative: "Weekly active orgs × seats per org × ARPU"
### Content / media business
- **Daily active readers / listeners × ad revenue per session** — captures both reach and monetization
- Alternative: "Subscriber count × retention × ARPU"
### Commerce (DTC, non-subscription)
- **Repeat purchase rate × AOV × frequency** — captures monetization layered on quality of customer
- Alternative: "Customer LTV / CAC × payback period"
## Leading indicators by AARRR stage
After the north star, every plan needs leading indicators per AARRR stage. These move faster than the north star and trigger investigations.
### Acquisition leading indicators
- Organic visits/month, total + per pillar (SEO health)
- App Store / Play Store visit-to-install rate (ASO health)
- Founder-led social channel growth → email subscriber conversion (LinkedIn / X / Substack funnels)
- Event-to-app conversion rate (event ROI)
- Ambassador-attributed visits (referral funnel)
- Paid CAC by channel (when paid is firing)
### Activation leading indicators
- Day 1 / Day 7 / Day 35 → paid conversion rate
- Onboarding session-completion rate
- First key-action completion (post-signup activation event)
- App Store conversion rate (install → trial → paid)
- Trial → paid conversion rate
### Retention leading indicators
- Day 30 / Day 60 / Day 90 retention
- Monthly churn rate (gross + net)
- Lifecycle email engagement (open / click / unsubscribe by flow)
- Hardware → app activation rate (for hybrid businesses)
- Win-back / reactivation rate
### Referral leading indicators
- Ambassador-attributed new subs (via Dub or similar)
- Share-after-value moment rate (% of users sharing)
- Two-sided referral completion rate
- Guides program referrals (when live)
- NPS score (if surveyed)
### Revenue leading indicators
- ARPU by cohort
- Annual plan adoption %
- Cohort LTV by source
- Plan mix shifts
- Eye-mask / hardware attach rate (for hybrid)
- Expansion revenue (B2B)
## Review cadence
The plan should specify three rhythms:
### Weekly (operational sync)
- **Who:** fCMO ↔ founder (CEO usually)
- **Duration:** 30 min
- **Format:** AARRR scoreboard (current vs. last week numbers across the leading indicators) + this week's ships + blockers
- **Output:** Action items, decisions made
### Monthly (metrics review)
- **Who:** fCMO + founder + extended team (CXO, product lead, designer if applicable)
- **Duration:** 60–90 min
- **Format:** Full metrics review + comparison against quarterly KPI targets + qualitative learnings + idea bank reprioritization
- **Output:** Possible plan adjustments, hire decisions
### Quarterly (plan recalibration)
- **Who:** fCMO + founders + key advisors
- **Duration:** 2–3 hours
- **Format:** Full plan review against 90-day and 12-month outcomes, channel-level analysis, funding-stage transition check, recalibration of next 90 days
- **Output:** Updated plan (could be v2 / v3 document iteration)
## KPI target setting
For each quarter in Section 10, the plan must include 3–5 specific KPI targets. These should be:
- **Specific** — not "improve retention," but "Day 30 retention from 22% → 30%"
- **Measurable** — pull from a wired data source
- **Stretch but plausible** — based on funnel state + historical patterns
- **Decision-triggering** — if missed, what does that mean? (Adjust strategy, kill a channel, etc.)
### KPI target patterns by quarter
**Q1 (foundation quarter):**
- Mostly *bedrock* metrics — fixing leaks. "Headphones-gate conversion drop reverses." "Day 1 → paid +25–50%."
- Some *foundation* metrics — laying tracks. "4 SEO pillars staked." "App Store rewrite shipped."
- Avoid bold growth targets — the foundations aren't in yet
**Q2 (validation quarter):**
- Mostly *validation* metrics — does what we built work? "Paid CAC < $X blended." "Organic traffic 1,500–3,500/mo."
- Some *cohort* metrics — do new cohorts behave better? "Day 7 retention for Q2 cohort vs. Q1."
**Q3 (scaling quarter):**
- Mostly *scaling* metrics — how far does it go? "Paid scaling to $20–30K/mo with CAC steady." "First B2B install reference case live."
- Some *capability* metrics — what new things are live? "First Guides pilot launched."
**Q4 (compound quarter):**
- Mostly *compound* metrics — is the flywheel turning? "50%+ of new subs from non-paid channels." "Ambassador-driven 15–25% of new subs."
- Some *narrative* metrics — does the Series A story write itself? "Blended LTV/CAC > 3."
## Anchoring against the VC growth path
For VC-backed clients past $1M ARR, anchor 12-month and multi-year targets against the **3-3-2-2-2 rule** (3× in years 1 and 2, then 2× in years 3 through 7). Hitting it is rare; most companies don't. Anchoring against it forces the plan to either match it and show how, or explicitly defend choosing a slower trajectory. Full table and context in `growth-patterns.md`.
For non-VC-backed companies (bootstrapped, founder-funded, profit-focused), the 3-3-2-2-2 doesn't apply. Use linear-pattern targets ("$X MRR added per month") or step-function targets ("$Y revenue jump after the enterprise tier launches") instead.
## Forecasting reality check
A plan derives a budget and an annual goal. It does not produce a 12-month month-by-month forecast that's reliably accurate to the dollar.
**Unless the company is publicly traded, all forecasts are educated guesses.** No startup under $100M ARR consistently hits month-by-month forecasts. Quarterly review is when the plan adjusts — not when variance is treated as failure.
What the plan commits to honestly:
- The annual goal is a defensible direction-of-travel
- The budget is the resource commitment that makes the goal plausible
- The 90-day roadmap (Section 9) is what's actionable now
- Month-to-month projection is illustrative, not promised
Founders who over-engineer the forecast end up explaining variance every month instead of executing. The plan should resist this — name the annual target, the quarterly KPIs, and the kill criteria. Don't promise the month.
Full context in `budget-planning.md`.
## Kill criteria
For every channel or initiative, the plan should specify when to stop. Often missing from plans, kill criteria force discipline.
Examples:
- "If a paid channel has CAC > 2× target after 30 days at meaningful spend, pause."
- "If onboarding Variant 3 doesn't show statistically meaningful lift (or directional lift + congruent qualitative signal) after 4 weeks, move to Variant 1."
- "If lifecycle Flow 4 has open rate < 12% after 6 weeks, redo subject lines + audience segmentation."
## Guardrail metrics
Some metrics get a hard guardrail (cannot drop below threshold). Useful for protecting brand or unit economics during aggressive growth.
Examples:
- "Brand voice complaint rate > 1% of customer feedback triggers content review."
- "Paid CAC > $X for two consecutive months pauses paid scaling pending audit."
- "App Store rating drops below 4.5 triggers product review."
## Data sources mapping
The plan should name where each metric comes from. This makes it auditable.
| Metric | Source |
|---|---|
| Organic traffic | GA4 / Ahrefs |
| App Store conversion | App Store Connect |
| Funnel conversion (Day N → paid) | Internal analytics (Mixpanel / Amplitude) or App Store Connect cohort export |
| Retention | Customer.io segments + product analytics |
| MRR / ARR | Stripe (via MCP if wired) |
| Plan mix | Stripe |
| Lifecycle email metrics | Customer.io |
| Ambassador attribution | Dub.co |
| Hardware → app activation | Shopify + App Store + internal join |
| NPS | Survey tool (Customer.io / Typeform / SurveyMonkey) |
## When data isn't wired
If a metric can't currently be measured, flag it in Section 13's open decisions. Example:
> "Hardware → app activation rate not currently visible in the App Store dashboard. Requires Shopify ↔ App Store Connect join. Q1 work item."
A plan with un-measurable goals is a plan that can't be validated. Surface the instrumentation work explicitly.
## Reporting cadence + automation
Where possible, auto-generate the metrics review rather than building it manually each time. Stripe MCP + GA4 MCP + Customer.io MCP can pull most of what's needed.
For Tier 1 clients, a simple weekly metrics email to the team (Markdown table, generated via skills + MCPs) costs nothing and creates discipline.
For Tier 2+ clients, consider a real dashboard (Hex, Metabase, Looker, or internal tool).
FILE:references/methodology.md
# Methodology — How a Marketing Plan Gets Made
The three-phase workflow that produces a comprehensive marketing plan. SKILL.md is the orchestration layer; this is the operational detail.
## Phase 1 — INIT (research + intake)
**Goal:** Walk into Phase 2 with enough context to draft every section without guessing.
### Step 1.1 — Set up the plan folder
Canonical file layout for every plan:
```
~/marketing-plans/{client-slug}/
├── materials/ # Client-provided files (decks, audit output, brand-voice doc, etc.)
├── research.md # Written in Phase 1 (INIT)
├── progress.md # State machine — see Step 1.1.1 for schema
├── sections/
│ ├── 01.md # Executive summary (written last, ordered first)
│ ├── 02.md # Strategic frame
│ ├── ...
│ └── 13.md # Measurement, RACI, open decisions, appendix
└── final_plan.md # Compiled deliverable (Phase 3 output)
```
### Step 1.1.1 — `progress.md` state schema
Every plan tracks a single `progress.md` file at the plan root. It's the source of truth for resumption. Schema:
```markdown
# {Client} — Marketing Plan Progress
phase: init | review | finalize | finalized
current_section: <number, only meaningful during review phase>
plan_version: v1
last_updated: YYYY-MM-DD HH:MM
## Sections completed
- [ ] 2. Strategic frame
- [ ] 3. Current state
- [ ] 4. Acquisition
- [ ] 5. Activation
- [ ] 6. Retention
- [ ] 7. Referral
- [ ] 8. Revenue
- [ ] 9. 90-day roadmap
- [ ] 10. 12-month outlook
- [ ] 11. Marketing operations stack
- [ ] 12. Tactical idea bank
- [ ] 13. Measurement, RACI, open decisions, appendix
- [ ] 1. Executive summary (synthesized last)
## Approved artifacts
sections/02.md, sections/03.md, ... (list as they're written)
## Notes
<any open decisions, blockers, or out-of-band context that aren't in research.md>
```
### Step 1.1.2 — Resumption decision tree
On every invocation, check state in this order:
1. **No `{client-slug}/` folder** → fresh plan. Create folder + `materials/` + empty `sections/`. Start INIT (Step 1.2).
2. **Folder exists, no `research.md`** → INIT was interrupted. Resume from Step 1.2.
3. **`research.md` exists, no `progress.md`** → INIT done, REVIEW not started. Create `progress.md`, start REVIEW from Section 2.
4. **`progress.md` exists, `phase: review`** → REVIEW in progress. Resume from `current_section` (or first unchecked box).
5. **`progress.md` exists, `phase: finalize`** → FINALIZE was interrupted. Re-run Phase 3.
6. **`progress.md` exists, `phase: finalized`** → plan is done. **Do not silently overwrite.** Ask the user: *"This plan is finalized (v{N}). Want to (a) revise it as v{N+1}, (b) start a fresh plan in a new folder, or (c) re-open a specific section?"*
Update `phase` and `last_updated` whenever state changes.
### Step 1.2 — Read existing materials
If `materials/` has files, read all of them. Common drops:
- Pitch deck / investor deck
- Positioning doc / brand voice doc
- Customer research / ICP doc
- App Store metrics / analytics snapshot
- Lifecycle email inventory
- Prior audit output (any scored current-state assessment the team has run)
- SEO research (`seo/plan.md`, `seo/keyword-shortlist.md`)
- Kickoff call transcript
- Founder Slack / async notes
Read everything. Capture key facts to `research.md` as you go.
### Step 1.3 — Pull live data where wired
If MCPs/APIs are wired for this client, pull:
- **Ahrefs** → domain rating, organic keywords, backlinks, top pages, ref domains (per `/seo-audit` skill)
- **GA4 MCP** → traffic by channel, conversion events, retention curves
- **Stripe MCP** → MRR, ARR, churn, plan mix, blended LTV by cohort
- **App Store Connect** (manual or `dev-browser`) → install → trial → paid funnel; cohort retention
- **Customer.io MCP** → flow inventory, send / open / click / unsubscribe rates
- **Shopify** → product page conversion, AOV, repeat rate
- **GitHub MCP** → repos inventory, last commit dates, what's stale
- **Notion** → internal knowledge directory if exposed
Don't ask the user to copy/paste data that can be pulled directly.
### Step 1.4 — Conduct structured intake
For every gap in the materials, ask the user. The minimum intake covers ten topics:
#### Intake 1 — Client overview
- What does the company do, in one sentence (founder's words)?
- What's the primary product?
- What other products / SKUs / tiers exist?
- Is the product live, beta, or pre-launch?
- If beta: throttling? GA timeline?
#### Intake 2 — ICP
- Who are you for, in one sentence?
- What do they say they want?
- What do they actually want?
- What's their stated problem? Their real problem?
- Demographics / firmographics: who fits the ICP exactly?
#### Intake 3 — Funnel state today
- What are the current funnel numbers? (signups, activations, paid, retention)
- What's the funnel *shape* — is it bottle-necked at top, middle, or bottom?
- What's the biggest leak?
#### Intake 4 — Funding state
- Current round (pre-seed / seed / Series A / etc.)?
- Total raised to date?
- Current burn / runway?
- Active raise? Closing when?
- Investors of note?
- Permission to mention fCMO engagement in pitches?
#### Intake 5 — Team
- Founders and what each owns (product, marketing, sales, etc.)?
- Other roles on the team and their marketing surface area?
- Advisors who touch marketing?
- Agencies / contractors / fractionals?
- Where are the obvious gaps?
- For the team's current marketing owner (if there is one): is the shape π-shaped (two deep skill sets), T-shaped (one deep, broad), or tactical-only? See `team-and-agency-model.md` for the framework that informs Section 11 RACI and the first-hire recommendation in Section 9.
#### Intake 6 — Budget
- Current monthly marketing spend, broken down: paid acquisition, tools, retainers, headcount?
- Budget tier this maps to (see `funding-stage-unlocks.md`)?
- What budget unlocks when the next round closes?
- Blended CAC if known (including salaries, content costs, tools, retainers — not just paid ad spend). If unknown, flag as the top Section 13 open decision — every revenue projection depends on it.
- ARPC, annual retention rate (or churn rate), so the budget math in `budget-planning.md` can be applied to Section 8 (Revenue) and Section 10 (12-month outlook).
#### Intake 7 — Channels currently active
- Acquisition: organic SEO, paid search, paid social, content, social, partnerships, events, PR, ambassadors, etc. — for each, status (live / paused / never tried)
- Activation: onboarding state, signup flow, paywall, first-session experience, app store listing
- Retention: lifecycle email state, in-app upsells, churn cohort
- Referral: program existence, attribution, inbound interest
- Revenue: pricing structure, plan mix, recent experiments
#### Intake 8 — Already done
What past work should this plan acknowledge?
- Major launches and dates
- PR moments and who covered
- Content pillars / hubs / cornerstone pieces
- Partnerships
- Awards / certifications
- Notable customers / users (if consumer-named users)
- Past advisors / fractionals
#### Intake 9 — In-flight and stuck
- What's drafted but not shipped? Why?
- What's been "almost ready" for months?
- What's blocking each?
- What's broken or actively harmful?
#### Intake 10 — Strategic posture
- The most important thing to fix this quarter (founder's read)
- The most important thing to ignore this quarter (founder's read)
- What investors / board are asking about most
- Any constraints not visible elsewhere (legal, partnership-related, brand-related)
### Step 1.5 — Score current state against the rubric
Use the 17-section rubric in `references/current-state-rubric.md` as your scoring lens. Two modes:
- **From rich materials.** When the team has shared decks, prior content audits, an existing brand voice doc, recent positioning work, or a kickoff call transcript — score from those. Mark "scored from materials" in the section heading.
- **From a separately scored audit.** If the team already has a scored current-state assessment (in any format), ingest those numbers directly. Don't redo the work.
Either way, the output is the scored 17-row table that becomes Section 3 of the plan, followed by a 2–4 sentence "shape interpretation" calling out where strengths and gaps cluster.
### Step 1.6 — Write research.md
Compile everything into `research.md` with this structure:
```markdown
# {Client} — Marketing Plan Research Record
**Date:** YYYY-MM-DD
**Author:** (fCMO / planner name)
## Company snapshot
- One-sentence description
- Stage (pre-seed / seed / Series A / etc.)
- Product status (beta / GA)
## ICP
- Primary ICP
- Stated vs. actual problem
- Demographics / firmographics
## Funnel state today
- Current numbers
- Funnel shape
- Biggest leak
## Funding
- Total raised
- Current round status
- Runway
## Team
- Founders and ownership
- Marketing surface area by person
- Gaps
## Current marketing budget
- $/mo total
- Breakdown
- Tier mapping
## Channels currently active
[By AARRR stage]
## Already done (acknowledge in plan)
[List]
## In-flight and stuck
[List with blockers]
## Strategic posture
- Founder's top priority
- Founder's top de-prioritization
- Investor pressure points
- Constraints
## Current-state rubric scores
[17 section scores using `references/current-state-rubric.md`. If a prior scored audit exists, paste those scores. Otherwise mark "scored from materials."]
## Materials read
[List of files in materials/ + when read]
```
Save. Move to Phase 2.
---
## Phase 2 — REVIEW (section-by-section drafting)
**Goal:** Walk through all 13 sections of the plan template (`references/plan-template.md`), drafting each, getting user confirmation, saving as you go.
### Step 2.1 — Initialize progress.md
Use the schema defined in Step 1.1.1 above. Set `phase: review`, `current_section: 2`, `plan_version: v1`, and stamp `last_updated`.
### Step 2.2 — Walk each section in this order: 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, then 1
Section 1 (Executive Summary) is drafted **last** because it depends on every other section's conclusions. Walk Sections 2 → 13 in numeric order, then synthesize Section 1 from the others. The final compiled `final_plan.md` is always presented in canonical order 1 → 13.
For each section, use the template at `references/plan-template.md` to draft. Then in chat:
1. Present the draft (or key bullets — short sections inline, long sections as bullet outline first)
2. Ask: *"Approve, adjust, or expand?"*
3. Iterate until user confirms
4. Save the confirmed text to `sections/01.md` ... `sections/13.md` (one file per section, zero-padded for sort order). This is the canonical persisted artifact — recovery depends on it.
5. Check the box in `progress.md`
6. Move to next section
### Step 2.3 — Section-specific guidance
**Section 1 (Executive summary)** is synthesized from Sections 2–13 after they're all approved. Draft it last; present it first in the output document.
**Section 3 (Current state)** uses the embedded 17-section rubric in `references/current-state-rubric.md`. If a prior scored audit exists, paste those scores in. If not, score from available materials.
**Sections 4–8 (AARRR)** each follow the same internal structure: current state, the plan (numbered moves), 90-day moves, 12-month outlook, skills + tools. Don't skip the skills + tools sub-section — it's what makes the plan operationally honest.
**Section 11 (Marketing operations stack)** is auto-generatable from `references/ops-stack-mapping.md` plus the specific moves named in Sections 4–8.
**Section 12 (Idea bank)** is auto-generatable from `references/idea-cross-reference.md` plus client-specific filters (skip ideas that conflict with brand voice; status moves based on funding-stage timing).
**Section 13** lives at the end. Open decisions should be ranked by impact. Appendix should reference only files the team can access (warn about machine-local paths).
### Step 2.4 — Brand voice consistency
If the client has documented brand voice rules (captured in research.md / Section 2), every section must respect them. Common voice constraints:
- Vocabulary rules (YES / NO lists)
- CTA rules (e.g., "never pressure")
- Initiatory vs. explanatory framing
- Tone (e.g., authoritative-yet-accessible, intimate-yet-professional)
If a section's draft violates the brand voice, redo it before showing it to the user.
---
## Phase 3 — FINALIZE (compile + verify + publish)
**Goal:** Produce `final_plan.md` and optionally publish to a shared repo.
### Step 3.1 — Compile
Set `phase: finalize` in `progress.md` before starting. Concatenate `sections/01.md` through `sections/13.md` into `final_plan.md` (canonical order 1 → 13, regardless of drafting order). Add:
- Title header with date and "v1" version marker
- "Prepared by / For / Date / Status" frontmatter
- Section anchors that work in Notion paste
### Step 3.2 — Verification pass
Before printing:
- **Cross-reference check** — every marketing-ideas number (e.g., "idea #17") matches the actual idea in `references/idea-cross-reference.md`. Every related-skill mention either exists in the `marketingskills` repo or is documented as an external dependency (see ops-stack-mapping note on cross-marketplace skills).
- **MCP/API check** — every tool mentioned in Section 11 actually exists in the user's stack (per research.md intake) OR is flagged as "future / not yet wired."
- **Path check** — no machine-specific paths (`/Users/...`, `/home/...`) in the output. Replace with descriptive references.
- **Voice check** — final read against brand voice rules. Flag and fix violations.
- **Open-decisions check** — every "TBD" or unanswered question from intake is listed in Section 13's open decisions, not hidden in the body.
- **Acknowledge check** — every item from "already done" in research.md is acknowledged somewhere in the plan.
### Step 3.3 — Print
Output `final_plan.md` to the plan folder. Print a summary to chat:
> *"Marketing Plan v1 saved to `~/marketing-plans/{client-slug}/final_plan.md`. ~X,XXX words across 13 sections. Ready to paste into Notion or share with the team."*
### Step 3.4 — Publish (optional)
Ask the user:
> *"Want me to publish this to a shared GitHub repo so the team can access it? If yes, what's the target repo and path (e.g., `{client-org}/{client-context}/marketing/plan.md`)?"*
If yes:
- Clone (or assume cloned) target repo
- Check out a feature branch or push direct to main per user's preference
- Copy `final_plan.md` to the target path
- Adjust the appendix to use repo-relative paths (not machine paths)
- Commit + push
- Confirm with commit URL
If no: leave it local. Done.
### Step 3.5 — Mark finalized
Set `phase: finalized` in `progress.md` and stamp `last_updated`. This is the terminal state and prevents future `/marketing-plan` invocations from silently overwriting the plan (see Step 1.1.2 case 6).
---
## Resuming a plan
Resumption is governed entirely by the decision tree in Step 1.1.2 above — always check state in that order on every invocation.
If the user says *"start over"* → ask whether they want to delete the existing folder or move it to `archive/` first; don't silently overwrite.
If the user says *"redo Section X"* → uncheck that box in `progress.md`, delete `sections/0X.md`, and re-draft.
## Failure modes to watch for
- **Skipping intake.** A plan written without proper intake is generic and won't survive contact with the founder. Always do the full ten-topic intake unless the user explicitly waives it.
- **Pretending data exists.** If you can't confirm a number (current MRR, retention rate, etc.), don't guess. Mark it `[TBD — to confirm with team]` in the plan and add to open decisions.
- **Ignoring the brand voice.** If the client has a strong voice (most do), every section must respect it. Read the voice rules before drafting any copy-adjacent text.
- **Padding the idea bank.** Section 12 is comprehensive only if it includes the skip list with reasons. Don't pad with ideas that clearly don't fit just to hit the 139.
- **Glossing over uncomfortable metrics.** If churn is high or activation is low, name it in Current State. Founders read past sugar-coating.
- **Forgetting funding-stage logic.** If the client is mid-raise, the plan must explain what changes when the round closes. Skipping this turns a plan into a wish-list.
FILE:references/ops-stack-mapping.md
# Marketing Operations Stack — Skills + MCPs per AARRR Stage
This doc maps every marketing-skill and every relevant MCP/API integration to the AARRR stage(s) it primarily serves. It's the source for Section 11 of every plan.
> **Note on scope.** Skills below live in this `marketingskills` repo. A few references point to optional tools from adjacent Claude Code marketplaces (e.g., `vercel:agent-browser`, `compound-engineering:diagram-maker`) — substitute equivalents if not installed. When a plan references a skill or tool that isn't available, fall back to the underlying tactic and call it out in Section 13's open decisions.
## The thesis
A small team + fCMO + agentic tooling = output of a 15–20-person traditional marketing org. The skills + MCPs encode workflows that previously required dedicated headcount per channel.
The plan's Section 11 makes this thesis explicit by:
1. Mapping skills to stages so the founder sees which skills execute which work
2. Mapping MCPs/APIs to stages so the founder sees the tooling layer
3. Naming a concrete operational example that proves the stack works
4. Showing capability unlocks by funding stage (pre-seed → seed → Series A)
## Marketing skills mapped to AARRR
### Acquisition skills
| Skill | What it does | Primary use in Acquisition |
|---|---|---|
| `seo-audit` | Audit site for technical and on-page SEO | Quarterly site health checks |
| `ai-seo` | Optimize content for AI search engines / LLM citation | Future-proof content strategy |
| `programmatic-seo` | Build template-driven SEO pages at scale | Location, comparison, integration page systems |
| `schema` | Add structured data markup | Rich snippets, eligibility for AI citation |
| `content-strategy` | Plan content topics, pillars, cadence | Setting the editorial calendar |
| `competitors` | Build vs-pages and alternative-to-pages | Capture high-intent SERPs against competitors |
| `ads` | Plan and structure paid campaigns | Apple Search Ads, Meta, Google, LinkedIn |
| `ad-creative` | Generate ad variations and creative | Iterate ad creative across platforms |
| `social` | Plan and write social media content | LinkedIn, Twitter/X, Instagram, TikTok |
| `typefully` | Schedule/post tweets, threads, LinkedIn content | Cadence operations for founder-led channels |
| `cold-email` | Write B2B cold outreach + sequences | Outbound for B2B SaaS / hybrid businesses |
| `analytics` | Set up tracking, GA4, conversion events | Funnel instrumentation |
| `free-tools` | Plan engineering-as-marketing free tools | Build tools that generate links + leads |
| `marketing-website-design` | Design marketing sites with intention | Pillar/landing page design |
| `launch` | Plan and execute launches (Product Hunt, GA, feature launches) | GTM moments — strategy + tactical execution |
### Activation skills
| Skill | What it does | Primary use in Activation |
|---|---|---|
| `onboarding` | Optimize user onboarding flows | Onboarding rebuild, activation rate tests |
| `signup` | Optimize signup/registration | Reduce friction at top of activation |
| `cro` | Optimize any marketing page or form | Conversion testing across pages, forms, landing pages |
| `paywalls` | Optimize paywalls and upgrade screens | Trial → paid conversion (also Revenue) |
| `popups` | Optimize popups, modals, slide-ins | Lead capture + activation prompts |
| `copywriting` | Write marketing copy | Onboarding screens, paywall copy, CTAs |
| `copy-editing` | Edit and improve existing copy | Voice / clarity pass before ship |
| `copycraft` | Real-time copy variation overlay | Live copy iteration during reviews |
| `website-copy` | Write full website copy (stage-8 from CF process) | Comprehensive site copy production |
| `ab-testing` | Plan A/B tests | Structure for onboarding variant tests |
| `marketing-psychology` | Apply behavioral science to copy and CRO | Persuasion principles in activation moments |
### Retention skills
| Skill | What it does | Primary use in Retention |
|---|---|---|
| `emails` | Design email sequences | Customer.io / Mailchimp / Resend flow building |
| `churn-prevention` | Build cancellation flows, save offers, win-back | Reduce churn, recover failed payments |
| `copywriting` / `copy-editing` | Email copy production | Lifecycle email content |
| `paywalls` | (cross-cuts) — upgrade prompts in retention emails | Upsell within lifecycle |
| `ab-testing` | Test email variants | Subject line, CTA, timing tests |
### Referral skills
| Skill | What it does | Primary use in Referral |
|---|---|---|
| `referrals` | Plan and launch referral / affiliate / ambassador programs | Core skill for Section 7 |
| `social` | Create ambassador-shareable content | Talking points, post templates |
| `copywriting` | Ambassador / affiliate email copy | Recruitment, onboarding, communication |
| `marketing-website-design` | Per-ambassador landing pages | Attribution surface |
| `emails` | Ambassador lifecycle emails | Onboarding, monthly digest, payout notifications |
### Revenue skills
| Skill | What it does | Primary use in Revenue |
|---|---|---|
| `pricing` | Audit and optimize pricing | Plan tier structure, annual defaults, value metrics |
| `paywalls` | Paywall optimization | Trial → paid, free → paid conversion |
| `sales-enablement` | Build sales decks, one-pagers, demos | B2B sales support material |
| `revops` | Revenue operations, lead lifecycle | Marketing → sales handoff |
| `ab-testing` | Pricing experiments | Test annual default, intro pricing, tier consolidation |
### Cross-cutting / brand foundation skills
| Skill | What it does | Primary use |
|---|---|---|
| `product-marketing` | Set up the `.agents/product-marketing.md` context file (positioning, ICP, voice) | Foundational — run first; every section of the plan references this |
| `customer-research` | Conduct customer interviews + surveys | Section 2 + Section 3 (Current state) |
| `marketing-psychology` | Apply behavioral science | Cross-cuts copy, CRO, paywalls |
| `marketing-ideas` | The 139-idea library | Section 12 of plan (Idea bank) |
## MCPs and APIs mapped to AARRR
### Acquisition tooling
| Tool | What it provides | Wired-at-client check |
|---|---|---|
| **Ahrefs API** | SEO data: keyword research, backlinks, competitor analysis | Required `AHREFS_API_KEY` in `.env` |
| **DataForSEO API** | SERP data, keyword volume, competitor SERP analysis | Required API key |
| **GA4 MCP** | Traffic by channel, conversion events, retention curves | Wired via gcp project + service account |
| **GitHub MCP** | Repo work: marketing site (`site-name-promo` patterns), content authoring | Standard `gh` CLI auth + MCP server |
| **Typefully MCP** | Social posting (LinkedIn, X, Threads, Bluesky) | Typefully account + API key |
| **Google Ads MCP** | Ad account management, campaign creation, performance pulls | Wired post-budget-unlock |
| **agent-browser** | Browser automation (form fills, screenshots, scraping) | CLI install: `npm install -g agent-browser` |
| **dev-browser** | General-purpose browser automation | MCP server install |
| **defuddle** | Clean markdown extraction from web pages | CLI install |
| **Notion** | Internal knowledge directory access | Notion API key |
| **Stripe MCP** | LTV math, paid-CAC reconciliation (cross-cuts to Revenue) | Stripe account + restricted key |
### Activation tooling
| Tool | What it provides |
|---|---|
| **App Store Connect** | Conversion rate by listing variant, install funnel | Usually manual + `dev-browser` for screenshots |
| **GitHub MCP** | Mobile app repo for onboarding code edits |
| **Figma / Pencil MCP** | Onboarding screen design + iteration |
| **Customer.io MCP** | In-app messaging + lifecycle email coordination |
| **Stripe MCP** | Subscription state for paywall logic |
| **GA4 MCP** | Activation events instrumentation |
### Retention tooling
| Tool | What it provides |
|---|---|
| **Customer.io MCP** | The retention infrastructure — flow building, segmentation, sending |
| **Shopify** | Hardware buyer events as lifecycle triggers |
| **Stripe MCP** | Subscription state, churn cohorts, plan changes |
| **GA4 MCP** | Session events, retention curves |
| **Resend / Mailchimp / SendGrid** | Alternatives to Customer.io for different stacks |
### Referral tooling
| Tool | What it provides |
|---|---|
| **Dub.co** | Ambassador attribution, short links, per-ambassador tracking |
| **Stripe MCP** | Commission accounting + payouts via Connect |
| **GitHub MCP** | Per-ambassador landing pages |
| **Customer.io MCP** | Ambassador lifecycle (recruitment → onboarding → monthly digest → payout notifications) |
| **Rewardful / Tolt / Mention Me** | Alternatives to Dub for affiliate management |
### Revenue tooling
| Tool | What it provides |
|---|---|
| **Stripe MCP** | Pricing tests, subscription analytics, churn cohort analysis, blended CAC math |
| **Shopify** | Hardware transactions |
| **GA4 MCP** | Revenue events |
| **Customer.io MCP** | Paywall / pricing-related lifecycle |
| **Notion** | Commercial knowledge directory |
### Cross-cutting tooling
| Tool | What it provides |
|---|---|
| **Notion** | Shared knowledge base |
| **GitHub MCP** | Shared context repo (`{client-org}/{client-context}`) |
| **defuddle** | Research extraction |
| **obsidian-cli** | Working notes for fCMO |
| **Pencil MCP** | Design files |
| **Figma MCP** | Design files (if Figma) |
## Capability unlocks by funding stage
The plan's Section 11 must include this table (or equivalent), specific to the client's current and projected funding stages.
| Stage | Headcount | Tooling | Channels live |
|---|---|---|---|
| **Pre-seed / bootstrapped** | fCMO + founder team | All current tooling + marketing-skills library + MCP layer | Organic only (SEO, content, App Store, founder-led social, events, WOM, ambassador) |
| **Seed close** | + first marketing hire (lifecycle/content owner) | + paid ad accounts (Apple Search Ads, Meta, LinkedIn) + `ads` skill activated | + paid acquisition pilot ($5–15K/mo — see `funding-stage-unlocks.md` for canonical tiers) |
| **Seed deployment** | + designer (potentially fractional) | + analytics expansion (Mixpanel / Amplitude if needed) | + paid scaling ($20–50K/mo) + first launches (PH, GA) |
| **Series A** | + performance marketing lead + content lead | + dedicated tooling spend ($2–5K/mo software) + sponsored event budget | + paid scaling ($50–150K/mo) + international consideration + B2B vertical expansion |
| **Series B+** | Full-stack marketing org (10+ people) | + agency partnerships + PR firm | + brand campaigns + acquisitions + sponsorships at category level |
## The concrete-example test
Section 11 of the plan must include at least one concrete operational example that proves the stack thesis. The example should be:
- A specific event (not abstract claim)
- From this client's actual history if possible (most credible)
- Tied to a non-technical person executing via the stack (proves it works without dedicated engineering)
Examples from real engagements:
- *"On the kickoff call, Alex drafted a working Customer.io abandoned-cart flow live, using Customer.io's Claude MCP. Validated that a non-technical founder can ship lifecycle work using the skill pattern independently."*
- *"In two weeks, the team scaled from 0 to 14 ranking keywords using `programmatic-seo` against the Ahrefs API + GitHub MCP — no dedicated SEO hire required."*
- *"The first email campaign generated a 24% reply rate after `cold-email` skill + GA4 MCP + Stripe MCP gave the team a verified target list of users with high LTV but no recent activity."*
If the client has no such moment in their history yet, frame the example as the *first move* — "Here's the demonstration the team will run in week one to validate the stack:"
## When the stack doesn't apply (yet)
For clients without MCP connections set up, frame Section 11 differently:
- List the skills that DO apply with current tooling
- Name which MCPs would unlock which sections of the plan
- Treat MCP setup as a Q1 priority alongside the bedrock fixes
A plan can't claim the agentic-stack thesis if the stack isn't wired. Be honest about state.
FILE:references/plan-template.md
# Plan Template — The 13-Section Structure
The canonical template for every marketing plan generated by this skill. Each section has a purpose, a structure, and inline prompts for what to draft.
The Quietude plan (see `references/example-quietude.md`) is the canonical reference implementation.
---
## Title block
```markdown
# {Client} — Marketing Plan v1
**Prepared by:** {Author / fCMO name}
**For:** {Founders / leadership team}
**Date:** YYYY-MM-DD
**Status:** Draft v1 — for team review
```
---
## Section 1 — Executive summary
**Purpose:** Lift-and-share. A founder should be able to paste this into a board update or investor email without editing.
**Length:** 400–700 words. Tight.
**Structure:**
1. **One-sentence frame.** What does this plan optimize for? Not "more revenue" — something specific to this client at this stage.
2. **Three big bets, ranked by leverage.** Each is a paragraph. Bet = a high-conviction thesis about where the team should focus capital and attention.
3. **What twelve months looks like, plausibly.** Bullet list. The plausible outcome state at end of plan horizon. Investor-readable.
4. **90-day priorities.** Numbered list. The six (give or take) moves that ship in the first quarter.
**Voice notes:**
- Match the client's voice
- Direct, founder-readable, no marketing-speak
- Use names and numbers (specific channels, specific metrics) — not abstractions
- Tradeoffs named explicitly when they matter
---
## Section 2 — Strategic frame
**Purpose:** Distill positioning, ICP, business-model logic, and brand voice into a single page that any team member or new hire can read to orient.
**Length:** 800–1500 words.
**Structure:**
### What {Company} is, in one sentence
Pulled from positioning doc / seed deck / founder language.
### The category we're claiming
Is the company creating a new category, redefining an existing one, or competing in a defined category? Name it. State the category-defining frame in 2–3 sentences. Reference the source (founder's words, ICP doc, etc.).
### Who we're for (ICP, distilled)
Demographics / firmographics + stated problem vs. real problem + what they're actually buying. Tight, 4–6 bullets.
### The business model logic
How does the company make money? What's the customer-acquisition unit economics theory? What's the compounding channel thesis (if any)? Pulled from seed deck / financial model / founder narrative.
### Brand voice (the non-negotiable)
If the client has documented voice rules, list them. YES / NO vocabulary. CTA rules. Tone. Core method (initiatory, explanatory, narrative, etc.). Every other section of the plan must respect these.
**Voice notes:**
- This section is the most "lift from existing materials" — don't invent positioning. Surface what's there.
- If positioning is unclear or contradicted across materials, flag it in Section 13's open decisions.
---
## Section 3 — Current state
**Purpose:** Anchor the plan in reality. What's the team, budget, in-flight work, and stuck work *today*?
**Length:** 1000–2000 words.
**Structure:**
### Team composition (marketing surface area)
Table of every person with marketing surface area:
| Person | Role | Marketing surface area |
|---|---|---|
Be honest about gaps. If there's no dedicated marketing hire yet, name when one becomes necessary and what role (see `references/team-and-agency-model.md` — first hire should be π-shaped strategist titled Manager or Lead, not VP/CMO).
### Marketing budget (current)
- Paid acquisition: $X/mo
- Tooling stack: list with estimated cost
- Retainers / fCMO: list
- Headcount: list
- Blended CAC: $X (must include salaries, content costs, tools, retainers — not just paid spend; see `references/budget-planning.md` for the calculation)
- Current spend as % of ARR: X% (compare against 5–40% range)
State the funding-stage tier this maps to (see `references/funding-stage-unlocks.md`). Implication: what 90-day plan must produce *without* lever pulls that require future budget.
### Phase of SaaS growth
Name the current phase: $0–10K ARR / $10K–100K / $100K–1M / $1M–$10M / $10M+. Each phase has its own binding constraint and dominant growth pattern (see `references/growth-patterns.md`). Section 10 sequences the move into the next phase.
### What's already done (acknowledge, then build on)
Table:
| Asset | Status | Marketing leverage |
|---|---|---|
This is where past launches, PR moments, content pillars, certifications, notable users get acknowledged. **Critical**: don't write a plan that ignores work the team is proud of.
### What's in-flight (drafted but not shipped)
Table:
| Item | Status | Blocker |
|---|---|---|
Be honest about blockers. Where the blocker is "no time" or "no decision," that goes to Section 13's open decisions.
### What's stuck (and needs to unstick this quarter)
Table:
| Issue | Cost of inaction | Action |
|---|---|---|
Stuck things are the most leverage-positive places to focus the first weeks of the 90-day plan.
### Audit rubric snapshot
17-section scored snapshot using the embedded current-state rubric. See `references/current-state-rubric.md` for the full rubric and scoring guides.
If a prior scored audit exists, paste those scores in. Otherwise score from available materials and note "scored from materials" under the heading.
| # | Section | Score | Note |
|---|---|---|---|
| 1 | Positioning | 0–5 | |
| 2 | Customer research | 0–5 | |
| ... | ... | ... | ... |
| 17 | Internationalization | 0–5 | |
**Total: X / 85 (Y%).** Note the *shape* of strength and weakness — that shape is the gap the rest of the plan closes.
**Voice notes:**
- Honest > polished. If the client's metrics are bad, name them. Founders read past sugar-coating.
---
## Section 4 — Acquisition
**Purpose:** Answer "how do strangers become aware of us?" Map every channel: current state, planned moves, skipped (with reason).
**Length:** 1000–1800 words.
**Structure:**
### Current state
Brief. What's working today, what's not, what the data shows about channel mix.
### The plan
Numbered "Moves." Each move is a paragraph (3–6 sentences) describing the channel, the thesis, and the specific work. Common moves:
- **Move 1 — SEO (and content)** — Reference the SEO plan if one exists (`seo/plan.md`). Otherwise: keyword research, pillar/spoke structure, content cadence.
- **Move 2 — App Store / Play Store optimization** (for consumer apps) — Listing rewrite, screenshot tests, ASO keyword targeting.
- **Move 3 — Founder-led channels** — LinkedIn for B2B/SaaS, Twitter/X for tech, Instagram for consumer. Cadence, topics, owners.
- **Move 4 — PR amplification** — What's the credibility anchor? How to amplify it.
- **Move 5 — Events (if applicable)** — Live events, conferences, webinars. Acquisition vs. activation role.
- **Move 6 — Hardware / commerce surface (if applicable)** — Shopify storefront, Amazon, retail.
- **Move 7 — B2B sales support** — Case studies, partner pages, vertical-specific content.
- **Move 8 — Paid layer (when budget unlocks)** — Apple Search Ads, Meta, LinkedIn, Google. Held until specified funding stage.
### 90-day acquisition moves
Week-by-week breakdown of the ships in the first quarter.
### 12-month acquisition outlook
Quarter-by-quarter outcome state (Q1 / Q2 / Q3 / Q4).
### Skills + tools
- **Skills:** list relevant marketing-skills repo skills (`seo-audit`, `ai-seo`, `ads`, `social`, `competitors`, etc.)
- **MCPs / APIs:** list connections (Ahrefs API, GA4 MCP, Typefully MCP, Stripe MCP for LTV math, etc.)
---
## Section 5 — Activation
**Purpose:** Answer "once someone tries us, do they have an experience that converts?"
**Length:** 800–1500 words.
**Structure:** Same as Acquisition (Current state / The plan / 90-day / 12-month / Skills + tools).
**Common moves:**
- Bedrock fixes (broken signup, broken onboarding gates, etc.)
- Onboarding tests / rebuild (often the most leveraged move at this stage)
- App Store listing rewrite (cross-references to Acquisition)
- Lifecycle Flow ship order (when to ship onboarding emails vs. hold for product stability)
- Paywall + pricing review (often Activation × Revenue)
### Skills + tools
`onboarding`, `signup`, `paywalls`, `copywriting`, `marketing-website-design`, `ab-testing`, etc.
---
## Section 6 — Retention
**Purpose:** Answer "once someone converts, do they stay and deepen?"
**Length:** 800–1500 words.
**Structure:** Same as above.
**Common moves:**
- Lifecycle email flows (post-purchase, lapsed user, win-back)
- Subscription / preference centers
- Churn reconciliation (often metric definitions don't match across surfaces)
- Hardware → software activation paths (for hybrid businesses)
- Annual plan default tests (cross-references to Revenue)
### Skills + tools
`emails`, `churn-prevention`, `copywriting`, `paywalls`, etc.
---
## Section 7 — Referral
**Purpose:** Answer "do retained users bring more users, and at what cost?"
**Length:** 500–1200 words.
**Structure:** Same as above.
**Common moves:**
- Ambassador / affiliate program launch (if inbound interest exists, lead with it)
- Share-after-value moments built into product
- Founder amplification (founder as referrer-zero)
- Long-game expert / Guides / certified-host network
- Gifting flows (for consumer / hardware)
### Skills + tools
`referrals`, `social`, `emails` (for ambassador lifecycle), `copywriting`, etc.
---
## Section 8 — Revenue
**Purpose:** Answer "what do we charge, who pays, and how does it compound?"
**Length:** 500–1200 words.
**Structure:** Same as above.
**Common moves:**
- Pricing audit (what's actually charged today vs. listed?)
- Annual plan default tests
- Hardware → software bundling formalization (for hybrid businesses)
- Storefront / commerce page optimization
- B2B case studies + sales material
- Long-term value pools (data licensing, enterprise expansion) — flagged not executed in 12-month plan
### Unit economics
Required table:
| Metric | Value | Note |
|---|---|---|
| ARPC (avg monthly revenue per customer) | $X | Pulled from Stripe / billing |
| Blended CAC | $X | Includes all marketing costs, not just paid |
| Annual retention rate | X% | 1 − annual churn |
| LTV (rough) | $X | ARPC × 12 / annual churn |
| LTV / CAC | X | Health benchmark: > 3 |
These feed the budget math in Section 10. If any of these are unknown, flag in Section 13 as top open decision.
### Skills + tools
`pricing`, `paywalls`, `sales-enablement`, `revops`, `ab-testing`, etc.
---
## Section 9 — 90-day roadmap
**Purpose:** The tactical execution layer. Every move ships within a named week, with an owner.
**Length:** Tables, not prose. Should fit on one printed page if possible.
**Structure:** Four 2–3-week sprints:
### Weeks 1–2 — Unblock
Highest-confidence, lowest-cost changes. Removing things that are broken.
| Move | Stage | Owner |
|---|---|---|
### Weeks 3–4 — Foundation
Pillar/foundational work. Domain consolidation. First content. First flows shipping. First tests live.
### Weeks 5–8 — Velocity
Compounding work begins. Content cadence. Repeat tests. Channel scaling.
### Weeks 9–12 — Compound
Second-order moves. Layered tactics. 90-day review prep.
---
## Section 10 — 12-month outlook
**Purpose:** Quarterly milestones with explicit funding-stage capability unlocks named, anchored against a defensible growth pattern.
**Length:** Four sub-sections, one per quarter. ~250–400 words each. Plus a short framing paragraph at the top naming the budget method and growth pattern.
### Framing (top of Section 10)
State explicitly:
- **Budget method used.** Method 1 (Revenue-Based 5–40% of ARR) or Method 2 (Goal-Based formula). See `references/budget-planning.md`. Show the math.
- **Annual budget total** + the experimental buffer (+10–20%).
- **Resulting end-of-year ARR goal.** Honest forecast, not a guarantee — see the forecasting reality check in `references/measurement-framework.md`.
- **Growth pattern expected.** Linear (predictable $X MRR added per month), step-function (plateau between deliberate jumps), or layered S-curves. For VC-backed Series A+, anchor against 3-3-2-2-2 and show whether the plan matches it or explicitly chooses a different trajectory. See `references/growth-patterns.md`.
### Structure (per quarter)
#### Q{N} — Months {X}–{Y}
**Funding state:** {tier} per `funding-stage-unlocks.md`
**Focus:** One-sentence focus theme for the quarter.
**Outcomes by end of Q{N}:**
- Bulleted outcome list (5–8 items)
**KPI targets:** 3–5 specific numerical targets.
**Channel/Product/Market S-curve position:** Which curves are growing, which are plateauing, which is the next one being staged for this quarter (see `growth-patterns.md` — layering principle).
---
## Section 11 — Marketing operations stack
**Purpose:** The fCMO differentiator. Show how a small team + agentic tooling executes the plan without hiring at every channel.
**Length:** Tables + brief explanation.
**Structure:**
### The thesis
1–2 paragraphs explaining the principle: small team + marketing-skills library + MCP integrations = output of a larger team.
### Skills mapped to AARRR stages
| Stage | Primary skills | Supporting skills |
|---|---|---|
| Acquisition | (list) | (list) |
| Activation | (list) | (list) |
| Retention | (list) | (list) |
| Referral | (list) | (list) |
| Revenue | (list) | (list) |
| Cross-cutting | (list) | (list) |
### MCPs / APIs mapped to stages
| Stage | Existing connections | fCMO tooling layer |
|---|---|---|
### A concrete example
Pick one operational moment that proves the stack works (e.g., "Customer.io MCP let the non-technical founder draft a flow live on the kickoff call"). Anchor the abstract claim in a specific event.
### Capability unlocks by funding stage
| Stage | Headcount | Tooling | Channels live |
|---|---|---|---|
| (current) | (list) | (list) | (list) |
| (next round) | (delta) | (delta) | (delta) |
| ... | ... | ... | ... |
### Team and agency model (RACI)
Apply the principle from `references/team-and-agency-model.md`: strategy in-house, execution often outsourced.
| Function | Owned by (internal strategic role) | Executed by (IC / contractor / agency) |
|---|---|---|
| Growth marketing (demand engine) | | |
| Product marketing (story engine) | | |
| Content marketing (trust engine) | | |
If the team is missing a strategic owner for one of these functions, the first 90-day move (Section 9) should be the hire — Manager or Lead title, π-shaped if possible, not VP/CMO.
If execution capacity is the gap, name the contractor or small niche agency in the right cell rather than the team's existing IC.
Pull from `references/funding-stage-unlocks.md`.
---
## Section 12 — Tactical idea bank
**Purpose:** Cross-reference all 139 ideas from the `marketing-ideas` skill against AARRR stages, with client-specific status.
**Length:** Long — tables can easily total 150+ rows.
**Structure:**
### Intro paragraph
Explain the cross-reference: Sections 4–8 prescribe what's *being done*. This section maps what's *possible*.
### Status legend
- **Now (Q1)** — already in 90-day plan
- **Q2** — post-foundation layer-in
- **Q3+** — post-seed-close or post-GA expansion
- **Q4+** — long-game
- **Skip / off-brand** — incompatible with brand voice or business model
### 12.1 Acquisition ideas
By status (Now / Q2 / Q3+ / Q4+ / Skip), tables of relevant marketing-ideas by number.
| # | Idea | Client note |
|---|---|---|
### 12.2 Activation ideas
### 12.3 Retention ideas
### 12.4 Referral ideas
### 12.5 Revenue ideas
### 12.6 Cross-cutting / brand foundation ideas
### Idea-bank summary
- Counts per AARRR stage
- Counts skipped, with rationale
- What the plan covers as a % of the available tactical surface area
- What this proves about the client's stage
Use `references/idea-cross-reference.md` as the source-of-truth mapping. Apply client-specific filters during draft (brand voice rules out some; funding stage shifts timing of others).
---
## Section 13 — Measurement, RACI, open decisions, appendix
**Purpose:** Operational close. Define how the plan gets measured, who owns what, what's still TBD, and where to find the deeper docs.
**Structure:**
### Measurement — the metrics that matter
**North star (proposed):** One metric that captures the business-model thesis. For Quietude it was blended-LTV-to-blended-CAC; for a B2B SaaS it might be NRR × NPS; for a marketplace, take-rate × monthly transacting users. Make it specific to the company.
**Leading indicators by AARRR stage:** Table:
| Stage | Leading indicators |
|---|---|
| Acquisition | ... |
| Activation | ... |
| Retention | ... |
| Referral | ... |
| Revenue | ... |
**Review cadence:**
- Weekly: who syncs with whom, on what
- Monthly: who reviews what
- Quarterly: plan recalibration trigger
### RACI
| Domain | Responsible | Accountable | Consulted | Informed |
|---|---|---|---|---|
Common domains: strategic plan, brand voice, app/product implementation, lifecycle, SEO content, App Store, founder-led social, events, ambassadors, B2B sales, pricing, investor narrative, future hires.
### Open decisions blocking the plan
Ranked by impact. Each is: name + impact + what's blocked.
1. (highest impact) ...
2. ...
8. (lowest impact) ...
### Appendix — deep-dive links
**Published in this repo / shared with team:** {relative paths to docs in the shared repo}
**Founder-authored strategic context** (internal knowledge base): {names of docs the team has access to outside the plan repo}
**fCMO working drafts** (not yet published): {names + how to access from author}
---
## Closing line
```markdown
*{Client} Marketing Plan v1. Prepared by {Author}, {Date}. For team review and discussion.*
```
---
## Per-section heuristics for "is this section done?"
- **Section 1** — A non-Quietude reader could understand the company's growth thesis from this alone.
- **Section 2** — Brand voice rules are explicit enough that any new copywriter could follow them.
- **Section 3** — All "in-flight" items have an owner and a blocker named.
- **Sections 4–8** — Each move names a skill (`some-skill`) and a tool (Customer.io MCP / Stripe MCP / Ahrefs / etc.).
- **Section 9** — Every row has an owner.
- **Section 10** — Each quarter names the funding stage explicitly.
- **Section 11** — At least one concrete operational example proves the stack thesis.
- **Section 12** — Skip list has rationale, not just absence.
- **Section 13** — North-star is specific to this company (not generic "ARR growth").
FILE:references/team-and-agency-model.md
# Team and Agency Model — Hire for Strategy, Outsource Execution
The marketing operations stack (Section 11 of every plan) describes *what* gets done. This doc describes *who does it* — the operating principle, the org shape, the first hire, the agency model, and how it evolves as the company scales.
Excerpted and adapted from *Founding Marketing* by Corey Haines.
## The principle
**Strategy lives in-house. Execution can — and often should — be outsourced.**
Two failure modes are common when founders ignore this:
1. **Hire junior tactician first.** Founder hits a milestone, raises a round, hires a junior to "do marketing" (run ads, write blogs, post on social). Six months later: scattered tactics, no coherent strategy, disappointing results.
2. **Hire expensive agency for strategy.** Burns cash while the internal team struggles to execute on recommendations they don't fully understand. Strategic insight gathers dust; tactical needs go unmet.
The traditional advice — "hire full-time for competitive advantages, only use agencies for commoditized work" — made sense when marketing moved slowly and talent stayed for decades. That world is gone. Full-time hires take months to ramp and years to develop deep expertise. The best agencies and contractors deliver results immediately, with cross-industry pattern recognition you couldn't build in-house affordably.
## What stays in-house
The strategic heart of the marketing operation. Specifically:
- **Strategic direction and vision** — the "why" behind every move
- **Customer and market understanding** — only comes from daily immersion in the business
- **Positioning and deep market knowledge** — represents the company's unique place in the market
- **Core product and service delivery** — the heart of the value proposition
- **Long-term institutional knowledge** — the compound interest of experience
These are not delegatable. An external partner can sharpen the articulation, but the underlying conviction must come from the team.
## What's safe to outsource
External expertise shines in specific contexts:
- **Best-in-class implementation of specialized skills** (paid media operators, technical SEO, video production, designers)
- **Burst capacity** — launch sprints, campaign cycles, one-off content production
- **Well-defined strategies** — when the scope, deliverables, and success metrics are clear
- **Fresh eyes on old problems** — external perspective when the team is too close to see clearly
The trick is *defining* what's being outsourced. Vague briefs ("help us with marketing") produce vague results. Specific briefs ("ship 20 RSAs across 4 ad groups by month-end with the CTR benchmarks in the brief") produce shippable work.
## The three core functions
Every marketing engine has three primary functions. Whether you have a team of 1 or 50, the functions exist — even if one person owns several.
### Growth Marketing — the demand engine
- Optimizes campaigns
- Manages the funnel
- Operates distribution channels
- Runs the marketing tech stack
- Data-driven; constantly testing and measuring
Drives quantitative outcomes: leads, signups, paid traffic, conversion rate, CAC.
### Product Marketing — the story engine
- Transforms product benefits into compelling messages
- Powers product launches
- Equips the sales team
- Owns pricing and packaging communication
- Bridges what's built and why people should care
Drives positioning quality, message-market fit, launch impact, sales enablement.
### Content Marketing — the trust engine
- Maintains the brand voice
- Manages the editorial calendar
- Produces content that reaches and teaches the audience
- Proves impact through customer stories
- Shapes industry conversations through thought leadership
- Supports sales with closing content
Drives organic traffic, brand affinity, thought leadership, trust signals.
These three functions are interconnected. Growth without story is performance with no positioning. Story without distribution is a great pitch nobody hears. Trust without demand capture is brand affinity that doesn't compound into revenue.
## The first marketing hire
The most consequential decision in building the marketing engine isn't about channels or technology — it's who leads.
**The first marketing hire should be a strategist, not a tactician.** Counterintuitive when there's a mountain of tactical work to ship. Essential for sustainable growth.
### Look for π-shaped, not T-shaped
The standard advice is to hire a **T-shaped marketer**: broad knowledge across many areas, deep in one. That's fine for a tactical IC role.
For the first strategic hire, look for **π-shaped**: two deep skill sets, plus broad surface-level competency across the rest. The two depths create unique leverage through their combination.
#### High-leverage combinations
**Product Marketing + Growth Marketing**
- Owns positioning *and* drives distribution
- Crafts the message *and* gets it to market
- No gap between planning and doing
- Best for technical products or complex sales
**Product Marketing + Content Marketing**
- Translates product into compelling stories
- Owns voice and positioning together
- Creates content that compounds
- Best for thought-leadership or education-driven markets
**Growth Marketing + Content Marketing**
- Builds the demand engine and the content that fuels it
- Closes the loop between SEO/social distribution and conversion
- Best for content-led growth motions
The wrong shape for a first hire: deep paid media specialist alone, deep SEO specialist alone, deep designer alone. These are tactical depths; they need a strategic owner above them.
### Title and progression — don't inflate
A common mistake: making the first marketing hire a "CMO" or "VP." Creates problems when you actually need to scale the org, because there's no headroom above them.
The right progression:
| Title | Scope |
|---|---|
| **Manager** | Individual contributor, co-manages freelancers |
| **Lead** | Senior IC, manages freelancers/agencies |
| **Director / Head** | Manages ICs and vendors |
| **VP** | Manages Directors |
| **Chief (CMO)** | Manages VPs |
The first hire is almost always **Marketing Manager** or **Marketing Lead**. They should be able to:
- Define positioning — not just describe what you do, but why it matters
- Identify best channels — from data, not intuition
- Create the messaging framework — consistency across touchpoints
- Build the marketing engine — systems that scale beyond any individual
- Manage external resources — get the most from agencies and contractors
Both strategic *and* hands-on. Comfortable setting direction and rolling up sleeves. Most importantly: a **builder** — creates processes, frameworks, and systems that scale beyond their individual capacity.
## The marketing engine — three components
Think of the marketing organization as an engine. Each part has a specific role; the magic is in how they work together.
### The Fuel — Strategy
What powers everything else. Without good fuel, even the best engine sputters.
- Product marketing creates positioning (foundation of all communication)
- Content marketing develops stories (features → benefits that resonate)
- Brand marketing establishes identity (memorable and meaningful)
Quality of the fuel determines efficiency. Poor positioning, weak stories, inconsistent branding waste energy regardless of execution.
### The Engine — Execution
Where strategy turns into action.
- Growth marketing drives distribution (right message to the right people)
- Demand gen creates opportunities (attention → interest)
- Operations maintains systems (everything running smoothly)
Needs to be well-maintained and properly tuned. Right processes, tools, people in place to execute consistently.
### The Dashboard — Analytics
How you know if you're heading in the right direction.
- Metrics track performance (measuring what matters)
- Attribution shows what works (cause and effect)
- Data informs decisions (evidence over opinion)
Without good instrumentation, flying blind. Need both leading and lagging indicators.
## Working with agencies — selection framework
Not all agencies are created equal. Ranked from most appropriate for early-stage to least:
### Individual contractors
- **Most flexible** — adapt quickly to changing requirements
- **Direct relationship** — no account-management layer
- **Often most cost-effective** — pay for pure expertise
- **Best for** specific skills (paid media op, technical SEO, video editor, designer)
For most pre-Series-A companies, this is the right answer for nearly all outsourced work.
### Small niche agencies
- **Specialized expertise** — deep knowledge in specific areas
- **Personal attention** — often working directly with senior team
- **Often founder-led** — experienced practitioners calling the shots
- **Clear focus** — they know what they're good at
- **Best for** specialized needs with some complexity (full SEO program, lifecycle email program, brand identity work)
### Small generalist agencies
- **Broader capabilities** — handle multiple needs
- **More resources** — team approach to problems
- **Multiple skill sets** — cross-functional
- **Usually more expensive** — paying for convenience
- **Best for** companies needing broader support and willing to pay for the simplicity of fewer relationships
### Large agencies (not recommended for most startups)
- Long contracts, high minimums, junior account teams, slow turnaround
- Useful only when the brand spend is large enough to command senior attention
## Setting agencies up for success
The difference between a successful and failed agency relationship usually comes down to structure and management.
### Before starting
- **Define clear objectives** — what specific outcomes are we seeking?
- **Set realistic timelines** — when do we need to see results?
- **Establish communication channels** — how do we stay aligned?
- **Agree on metrics** — what defines success?
- **Document processes** — how do we work together?
### During engagement
- **Regular check-ins** — weekly tactical, monthly strategic
- **Clear feedback loops** — both ways, positive and constructive
- **Data sharing** — give them what they need to succeed
- **Performance reviews** — measure against agreed metrics
- **Strategy alignment** — ensure they're moving with the business
### Red flags
- **Scope creep beyond core expertise** — trying to do too much
- **High team turnover** — losing institutional knowledge
- **Missed deadlines** — failing to deliver as promised
- **Poor communication** — lack of proactive updates
- **Unclear reporting** — can't demonstrate value
The best agency relationships feel like partnership: they understand the business, care about success, bring expertise you couldn't build in-house affordably. Takes work on both sides — clear expectations, open communication, mutual respect.
## Scaling the model by stage
The right ratio of internal to external resources isn't static. It evolves with stage, needs, and market conditions.
### Early stage (pre-product-market-fit)
**Mode:** discovery and iteration
- **Internal:** 1–2 strategic hires leading the charge (often the founder + one π-shaped marketer)
- **External:** specialized contractors for execution (no long-term commitment)
- **Agency relationships:** project-based, testing approaches before bigger investments
- **North star:** solid foundation while keeping fixed costs low
### Growth stage (post-PMF, scaling what works)
**Mode:** optimization
- **Internal:** small but mighty core strategic team that owns marketing direction
- **External:** balanced mix of contractors and agencies, each chosen for specific expertise
- **Agency relationships:** deeper, longer-term — partners who grow with you
- **North star:** double down on channels and approaches that have proven successful
### Scale stage (multi-channel, multi-segment)
**Mode:** coordination
- **Internal:** larger strategic team focused on coordination and oversight (not execution)
- **External:** specialized agencies, each bringing deep expertise in specific areas of the mix
- **Trusted contractor network:** flexibility for variable workloads and special projects
- **North star:** finding efficiencies, improving processes, maximizing return
The metaphor: a symphony orchestra. The internal team conducts. External partners play their instruments with expertise.
## How this informs the plan
| Section | What to include |
|---|---|
| **3 (Current state)** | Team composition — every person who touches marketing, what they own. Identify where the team is π-shaped vs. T-shaped vs. tactical-only. Flag gaps. |
| **9 (90-day roadmap)** | If the team is missing the strategic owner, the first move is the first marketing hire (Lead or Manager). If the team has strategy but no execution capacity, the first move is the first contractor or specialized agency. |
| **10 (12-month outlook)** | Map team evolution against funding-stage capability unlocks (see `funding-stage-unlocks.md`). When does the second hire come in? When does an agency relationship deepen? |
| **11 (Marketing operations stack)** | RACI is more honest with this model: "owned by" = internal strategic role; "executed by" = internal IC, contractor, or agency. The plan should make it explicit who does what. |
| **13 (Open decisions)** | If "first marketing hire" is open, name it as a top-three decision. If "in-house vs agency" for a specific function is open, frame the tradeoff using this doc's heuristics. |
## Operational guardrails
- **Don't title-inflate the first hire.** It paints the org into a corner.
- **Don't outsource positioning.** Even the best agency can articulate it back to you, but only if the conviction came from the team.
- **Don't full-time hire for a six-month sprint.** Use a contractor. The hidden cost of full-time is the months of ramp + the awkwardness of letting them go if the work doesn't compound.
- **Don't agency-hire to delay a strategy conversation.** Agencies execute; they don't replace strategic owners. If the internal team can't tell the agency what to do, the agency can't help.
- **Don't measure team size as a success metric.** Measure output, not headcount. A 4-person team with the right π-shaped leader and great external partners out-performs a 15-person team without strategic clarity.
Bộ 42 skill marketing cho các coding agent, chia 7 nhóm: nội dung, SEO, CRO, kênh, tăng trưởng, thông tin thị trường, bán hàng, kèm 27 công cụ Python.
--- name: "marketing-skills" description: "42 marketing agent skills and plugins for Claude Code, Codex, Gemini CLI, Cursor, OpenClaw, and 6 more coding agents. 7 pods: content, SEO, CRO, channels, growth, intelligence, sales. Foundation context + orchestration router. 27 Python tools (stdlib-only)." version: 2.9.0 author: Alireza Rezvani license: MIT tags: - marketing - seo - content - copywriting - cro - analytics - ai-seo agents: - claude-code - codex-cli - openclaw --- # Marketing Skills Division 42 production-ready marketing skills organized into 7 specialist pods with a context foundation and orchestration layer. ## Quick Start ### Claude Code ``` /read marketing-skill/marketing-ops/SKILL.md ``` The router will direct you to the right specialist skill. ### Codex CLI ```bash codex --full-auto "Read marketing-skill/marketing-ops/SKILL.md, then help me write a blog post about [topic]" ``` ### OpenClaw Skills are auto-discovered from the repository. Ask your agent for marketing help — it routes via `marketing-ops`. ## Architecture ``` marketing-skill/ ├── marketing-context/ ← Foundation: brand voice, audience, goals ├── marketing-ops/ ← Router: dispatches to the right skill │ ├── Content Pod (8) ← Strategy → Production → Editing → Social ├── SEO Pod (5) ← Traditional + AI SEO + Schema + Architecture ├── CRO Pod (6) ← Pages, Forms, Signup, Onboarding, Popups, Paywall ├── Channels Pod (5) ← Email, Ads, Cold Email, Ad Creative, Social Mgmt ├── Growth Pod (4) ← A/B Testing, Referrals, Free Tools, Churn ├── Intelligence Pod (4) ← Competitors, Psychology, Analytics, Campaigns └── Sales & GTM Pod (2) ← Pricing, Launch Strategy ``` ## First-Time Setup Run `marketing-context` to create your `marketing-context.md` file. Every other skill reads this for brand voice, audience personas, and competitive landscape. Do this once — it makes everything better. ## Pod Overview | Pod | Skills | Python Tools | Key Capabilities | |-----|--------|-------------|-----------------| | **Foundation** | 2 | 2 | Brand context capture, skill routing | | **Content** | 8 | 5 | Strategy → production → editing → humanization | | **SEO** | 5 | 2 | Technical SEO, AI SEO (AEO/GEO), schema, architecture | | **CRO** | 6 | 0 | Page, form, signup, onboarding, popup, paywall optimization | | **Channels** | 5 | 2 | Email sequences, paid ads, cold email, ad creative | | **Growth** | 4 | 2 | A/B testing, referral programs, free tools, churn prevention | | **Intelligence** | 4 | 4 | Competitor analysis, marketing psychology, analytics, campaigns | | **Sales & GTM** | 2 | 1 | Pricing strategy, launch planning | | **Standalone** | 4 | 9 | ASO, brand guidelines, PMM strategy, prompt engineering | ## Python Tools (27 scripts) All scripts are stdlib-only (zero pip installs), CLI-first with JSON output, and include embedded sample data for demo mode. ```bash # Content scoring python3 marketing-skill/content-production/scripts/content_scorer.py article.md # AI writing detection python3 marketing-skill/content-humanizer/scripts/humanizer_scorer.py draft.md # Brand voice analysis python3 marketing-skill/content-production/scripts/brand_voice_analyzer.py copy.txt # Ad copy validation python3 marketing-skill/ad-creative/scripts/ad_copy_validator.py ads.json # Pricing scenario modeling python3 marketing-skill/pricing-strategy/scripts/pricing_modeler.py # Tracking plan generation python3 marketing-skill/analytics-tracking/scripts/tracking_plan_generator.py ``` ## Unique Features - **AI SEO (AEO/GEO/LLMO)** — Optimize for AI citation, not just ranking - **Content Humanizer** — Detect and fix AI writing patterns with scoring - **Context Foundation** — One brand context file feeds all 42 skills - **Orchestration Router** — Smart routing by keyword + complexity scoring - **Zero Dependencies** — All Python tools use stdlib only
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]
```
Phương pháp nghiên cứu thị trường: ước lượng TAM/SAM/SOM theo cả hai hướng, tính cỡ mẫu khảo sát và chấm điểm phân khúc theo Kotler.
---
name: market-research
description: Use when doing upstream market-research methodology — sizing a market as TAM/SAM/SOM computed BOTH top-down and bottoms-up (never a single unsourced number), planning a survey sample size with finite-population correction and per-segment minimums, or scoring candidate market segments against Kotler's measurable/substantial/accessible/differentiable/actionable criteria. Outputs always show the method and the assumptions. For market-research analysts and product-marketing at the sizing/survey/segmentation moment. Distinct from marketing-skill (campaign analytics, attribution, demand-gen) — this is the evidence-building methodology, not live-campaign optimization.
version: 2.9.0
author: claude-code-skills
license: MIT
tags: [research-ops, market-research, tam-sam-som, market-sizing, survey, sampling, segmentation, competitive-intelligence]
compatible_tools: [claude-code, codex-cli, cursor, antigravity, opencode, gemini-cli]
---
# market-research
Upstream market-research methodology: market sizing, survey/sampling design, and segmentation. The discipline here is **method + assumptions**: a TAM is never a single number, a survey is never powered only in aggregate, and a segment is never a demographic slice.
## Purpose
Market-research analysts, product marketers, and strategy teams need rigorous evidence *before* anyone optimizes a campaign or sets a strategy. This skill structures three methodology decisions:
Three deterministic tools:
1. `market_sizer.py` — Computes TAM/SAM/SOM by **both** top-down and bottoms-up methods side-by-side, reports the divergence, and flags failed triangulation. Never returns a single number.
2. `sample_size_planner.py` — Survey sample size from confidence, margin of error, and expected proportion, with the finite-population correction and **per-segment minimums** (a survey powered overall is not powered per reported segment).
3. `segmentation_scorer.py` — Scores candidate segments against Kotler's five criteria and enforces a substantiality + accessibility gate; a slice that is too small or unreachable is dropped.
## When to use
Invoke this skill when:
- A board or exec asks "how big is this market?" and you need a defensible, triangulated answer.
- You are fielding a survey and need a sample size that holds up per segment, not just overall.
- You have a list of candidate segments and need to know which are real markets vs demographic slices.
- You are synthesizing competitive intelligence and need a methodological backbone.
**Do NOT use this skill to**: measure a live campaign (attribution, ROAS, CPA → `marketing-skill/campaign-analytics`), build demand-gen / paid-media plans (`marketing-skill/marketing-demand-acquisition`), set positioning / GTM strategy (`marketing-skill/marketing-strategy-pmm`), or set pricing (`commercial/pricing-strategist`).
## Workflow
1. **Write the brief** — Fill `assets/market_research_brief_template.md` (objective, the decision this informs, sizing approach, sampling plan, assumptions register).
2. **Size the market** — Run `market_sizer.py --input market.json --method both --profile {b2b-saas|consumer|enterprise|marketplace|hardware|services}`. Reconcile the top-down/bottoms-up delta before quoting anything.
3. **Plan the survey** — Run `sample_size_planner.py --input survey.json`. Fund the per-segment floors, not just the overall n.
4. **Score the segments** — Run `segmentation_scorer.py --input segments.json --profile <same>`. Drop segments failing the substantiality/accessibility gate.
5. **Assemble the evidence pack** — Combine into a brief. Every number carries its method + assumptions + confidence.
## Scripts
| Script | Purpose | Profiles |
|---|---|---|
| `scripts/market_sizer.py` | TAM/SAM/SOM top-down AND bottoms-up + triangulation flag | b2b-saas, consumer, enterprise, marketplace, hardware, services |
| `scripts/sample_size_planner.py` | Survey n + FPC + per-segment minima | n/a (parameter-driven) |
| `scripts/segmentation_scorer.py` | Kotler 5-criteria scoring + gate | b2b-saas, consumer, enterprise, marketplace, hardware, services |
All three: stdlib-only, `--help`, `--sample`, `--output {human,json}`.
## Onboarding & customization
Run the onboarding questionnaire **once before you start** — it captures your defaults so every tool in this skill is pre-configured. Customization is the point: the answers actually change tool behavior.
```bash
python3 scripts/onboard.py # interactive (also: --defaults, --set key=value, --reset)
python3 scripts/onboard.py --show # see the questions + current effective config
```
Answers are saved to `~/.config/research-ops/market-research.json` (global) or `./.research-ops/market-research.json` (`--scope project`) and are read automatically by `config_loader.py`. They set the default market **profile**, the default survey **confidence** and **margin of error**, and the default **sizing method**. CLI flags always override saved config; `RESEARCH_OPS_NO_CONFIG=1` ignores it.
**The four questions:** market profile · survey confidence · margin of error · sizing method.
## Optimize with autoresearch (opt-in)
This skill ships an **isolated, opt-in** bridge to `engineering/autoresearch-agent`. Only when you ask to "optimize" / "reconcile the sizing" / "run a loop" does an autoresearch experiment iteratively reconcile your market model so top-down and bottoms-up triangulate. `scripts/ar_evaluator.py` is the ground-truth evaluator; it prints `tam_divergence: <fraction>` (**lower** is better).
```bash
/ar:setup --domain custom --name tam-triangulation \
--target market.json \
--eval "python3 ar_evaluator.py --target market.json" \
--metric tam_divergence --direction lower
/ar:loop custom/tam-triangulation
```
Isolated: no hard dependency — autoresearch runs only on demand, and the loop edits `market.json`, never the evaluator.
## References
- `references/market_sizing_canon.md` — TAM/SAM/SOM frameworks (Bessemer, a16z); top-down vs bottoms-up; Fermi estimation; market-model conventions; common sizing fallacies.
- `references/survey_methodology.md` — Cochran *Sampling Techniques*; Dillman *Tailored Design Method*; Groves *Survey Methodology*; question-wording bias (Schuman & Presser); AAPOR standards.
- `references/segmentation_and_ci.md` — Kotler segmentation criteria; needs-based vs firmographic; Porter Five Forces; SCIP ethics; Christensen JTBD; conjoint/MaxDiff primer.
## Assumptions
- The sizer reports both methods but cannot validate your inputs — a top-down "1% of a $40B market" is only as good as the cited source and the serviceable fraction.
- Sample-size uses the conservative p=0.5 (maximum variance) unless you supply an expected proportion.
- Segment scores are inputs you provide; the tool enforces the gates and the weighting, it does not gather the underlying evidence.
- Competitive intelligence must follow the SCIP code of ethics — no misrepresentation, no protected information.
## Anti-patterns
- **A single TAM number with no method.** Always triangulate top-down against bottoms-up.
- **Spurious precision.** Size to the decision's tolerance; "$3.7142B" implies a confidence you do not have.
- **Powering only the total.** Each reported segment needs its own sample floor.
- **Leading or double-barreled survey questions.** Pre-test wording against the bias literature.
- **Calling a demographic slice a segment.** It must be substantial AND accessible.
## Distinct from
| Neighbor | Scope | Difference |
|---|---|---|
| `marketing-skill/campaign-analytics` | Attribution, ROAS, CPA, funnel of a live campaign | That **measures spend deployed**; this is **upstream methodology** |
| `marketing-skill/marketing-demand-acquisition` | Demand-gen, paid media, channel mix | That **runs acquisition**; this **builds the evidence** |
| `marketing-skill/marketing-strategy-pmm` | Positioning, GTM, category | That **sets strategy**; this **sizes and segments the market** |
| `commercial/pricing-strategist` | Pricing model + WTP + packaging | That **sets price**; this **sizes the market** |
| `product-research` (sibling) | User/product discovery methods | That studies **users**; this studies **the market** |
## Quick examples
```bash
python3 scripts/market_sizer.py --sample
python3 scripts/sample_size_planner.py --population 62000 --confidence 0.95 --moe 0.05
python3 scripts/segmentation_scorer.py --sample --output json
```
The sample market triangulates a ~$1.47B top-down SAM against the bottoms-up figure and flags the divergence; the segmentation sample drops the "solopreneurs who might want analytics" slice for failing the substantiality and accessibility gates.
## Forcing-question library (Matt Pocock grill discipline)
Walked one at a time by `/cs:grill-research-ops` or the orchestrator. Recommended answer + canon citation per question. Never bundled.
1. **"Is your TAM top-down or bottoms-up — and have you computed it both ways to triangulate?"**
Recommended: both; reconcile the delta before quoting a number.
Canon: Bessemer / a16z market-sizing; Fermi estimation.
2. **"What decision will this market size actually drive — and at what precision does it matter?"**
Recommended: size to the decision's tolerance, not to a spurious-precision number.
Canon: market-model conventions (Gartner/Forrester); decision-driven analysis.
3. **"What's your target margin of error and confidence — and does your sample clear it per segment, not just overall?"**
Recommended: power each reported segment, not only the total.
Canon: Cochran *Sampling Techniques*; AAPOR standards.
4. **"Are your survey questions free of leading and double-barreled wording?"**
Recommended: pre-test the wording; cite the bias source.
Canon: Schuman & Presser; Dillman *Tailored Design Method*.
5. **"Do your segments pass measurable / substantial / accessible / actionable — or are they just demographic slices?"**
Recommended: drop segments that fail substantiality or accessibility.
Canon: Kotler segmentation criteria.
Walk depth-first. Lock 1-2 before opening 3-5. After all are answered, invoke `market_sizer.py` → `sample_size_planner.py` → `segmentation_scorer.py`.
FILE:assets/market_research_brief_template.md
# Market Research Brief — Template
> Fill this before running the tools. Every number in the final brief must carry its method,
> assumptions, and confidence. Size to the decision's tolerance, not to false precision.
## 1. Objective
- Research question:
- **The decision this informs** (and who makes it):
- Precision required (order-of-magnitude / ±20% / ±5%):
## 2. Market sizing
- Approach: [top-down | bottoms-up | both — recommended both]
- Top-down inputs: total market value + source citation; serviceable fraction; reachable share.
- Bottoms-up inputs: total potential customers + source; annual price; serviceable fraction; realistic adoption.
- Triangulation result (from `market_sizer.py`) + divergence:
## 3. Survey plan (if primary data)
- Population (N) + sampling frame:
- Confidence level / overall margin of error / expected proportion:
- Segments to report + per-segment margin of error:
- Recommended n (overall + per-segment floors, from `sample_size_planner.py`):
- Mode (online panel / phone / mixed) + coverage risk:
## 4. Segmentation
- Candidate segments + scores across measurable / substantial / accessible / differentiable / actionable:
- Verdicts (from `segmentation_scorer.py`): TARGET / WATCH / DROP
## 5. Competitive intelligence
- Sources (public, ethically obtained — SCIP code):
- Five Forces summary:
## 6. Assumptions register
- (List every assumption behind the sizing, sampling, and segmentation. Each must trace to a source or be flagged as an unverified planning assumption.)
## 7. Confidence statement
- Overall confidence in the headline numbers (high / moderate / low) and why:
FILE:references/market_sizing_canon.md
# Market Sizing Canon
Reference for TAM/SAM/SOM. Pairs with `market_sizer.py`.
## The three numbers
- **TAM (Total Addressable Market)** — total revenue if you captured 100% of the market for your category.
- **SAM (Serviceable Addressable Market)** — the portion of TAM you can serve given your geography, segment focus, and product scope.
- **SOM (Serviceable Obtainable Market)** — the realistic, capacity-constrained share of SAM you can win in the planning window.
## Two methods — always do both
- **Top-down**: start from a published total market value (analyst report, government statistic) and apply serviceable and reachable fractions. Fast, but only as good as the source and inherits its biases. The classic failure is "1% of a huge number" — a TAM that sounds enormous and means nothing.
- **Bottoms-up**: start from the number of potential customers × the price they would pay, then apply serviceable and adoption fractions. Slower but grounded in units you can defend. The discipline is that bottoms-up forces you to name customer counts and price points.
When the two methods diverge by more than a tolerance, **triangulation has failed** — you do not yet have a defensible number. The tool flags this rather than averaging the two (averaging hides the disagreement).
## Fermi discipline
Good sizing is Fermi estimation: decompose the unknown into knowable factors, estimate each with a stated assumption, and carry the uncertainty through. A market size is a chain of assumptions; surfacing the chain is the deliverable, not the point estimate.
## Common fallacies
- **Double counting** — summing overlapping segments or counting the same revenue at multiple layers of the value chain.
- **Percent-of-a-big-number** — anchoring on "if we just get 1%" without a bottoms-up cross-check.
- **Confusing TAM growth with your growth** — a growing TAM does not entitle you to a fixed share.
- **Spurious precision** — quoting a TAM to four significant figures when the inputs are order-of-magnitude estimates.
## Sources
1. Bessemer Venture Partners, *State of the Cloud* and market-sizing memos (TAM/SAM/SOM discipline).
2. Andreessen Horowitz (a16z), *The truth about market sizing* and bottoms-up TAM essays.
3. Gartner / Forrester / IDC market-model methodology notes (forecast construction conventions).
4. Weinstein, L., & Adam, J., *Guesstimation* (Princeton, 2008) — Fermi estimation.
5. Blank, S., *The Four Steps to the Epiphany* — market-type and sizing in customer development.
6. Damodaran, A., *Narrative and Numbers* (Columbia, 2017) — disciplining market-size narratives with numbers.
FILE:references/segmentation_and_ci.md
# Segmentation and Competitive Intelligence
Reference for segmentation scoring and competitive-intelligence synthesis. Pairs with `segmentation_scorer.py`.
## What makes a segment useful (Kotler)
A market segment is only useful if it meets five criteria. The scorer weights and gates them:
1. **Measurable** — you can size and identify it.
2. **Substantial** — it is large and profitable enough to be worth serving. (Gate: a tiny slice is not a market.)
3. **Accessible** — you can reach it through channels you can afford. (Gate: an unreachable segment is academic.)
4. **Differentiable** — it responds differently to your offer than other segments do; otherwise it is not a distinct segment.
5. **Actionable** — you can design and execute a program for it.
Substantiality and accessibility are **gates** because they are the two that most often fail silently: teams fall in love with a precisely-described segment that is too small or has no viable channel.
## Bases of segmentation
- **Firmographic** (B2B): industry, size, geography — easy to measure, weak at predicting behavior.
- **Demographic** (B2C): age, income, role — same trade-off.
- **Needs-based / behavioral**: grouping by the job customers are trying to get done. Stronger predictor of response, harder to measure. Christensen's **Jobs-to-be-Done** reframes segmentation around the progress a customer is trying to make, not who they are.
The strongest segmentations pair a needs-based core with a firmographic/demographic proxy you can actually target.
## Competitive intelligence
CI synthesis is structured, ethical analysis of the competitive landscape:
- **Porter's Five Forces** frames structural attractiveness (rivalry, new entrants, substitutes, supplier power, buyer power).
- **SCIP (Strategic and Competitive Intelligence Professionals)** publishes a code of ethics: no misrepresentation of identity, no acquisition of protected/confidential information, full compliance with law. CI is built from public and ethically-obtained sources.
## Advanced preference measurement
When you need to quantify trade-offs, **conjoint analysis** and **MaxDiff** (best-worst scaling) estimate the relative importance of attributes and the willingness to trade one for another — far more reliable than directly asking "how important is X?"
## Sources
1. Kotler, P., & Keller, K., *Marketing Management*, 15th ed. — segmentation criteria.
2. Christensen, Hall, Dillon & Duncan, *Competing Against Luck* (2016) — Jobs-to-be-Done.
3. Porter, M., *Competitive Strategy* (1980) — Five Forces.
4. SCIP, *Code of Ethics for CI Professionals*.
5. Orme, B., *Getting Started with Conjoint Analysis*, 4th ed. (Sawtooth, Research Publishers).
6. Smith, W., *Product Differentiation and Market Segmentation as Alternative Marketing Strategies* — J Marketing 1956 (the founding segmentation paper).
FILE:references/survey_methodology.md
# Survey Methodology
Reference for survey design and sampling. Pairs with `sample_size_planner.py`.
## Sample size from first principles
For estimating a proportion, the required sample is n₀ = z²·p·(1−p)/e², where z is the critical value for the confidence level, p the expected proportion, and e the margin of error. The maximum-variance choice p = 0.5 is the conservative default. When the sample is a meaningful fraction of a finite population N, apply the **finite-population correction**: n = n₀ / (1 + (n₀−1)/N). The planner does both.
The most common analyst error: powering the **overall** sample but then reporting **per-segment** results that the sample cannot support. If you will report three segments at ±8%, each segment needs ~150 respondents — so the survey must be sized to the segment floors, not the aggregate. The planner computes per-segment minimums explicitly.
## The total survey error framework
Sample size only addresses **sampling error**. Groves' total-survey-error framework names the others, often larger:
- **Coverage error** — the sampling frame omits part of the population (e.g., an email panel misses non-users).
- **Non-response error** — those who respond differ systematically from those who don't.
- **Measurement error** — the instrument itself biases answers (question wording, order, scale).
A tight margin of error on a biased frame is precision without accuracy.
## Question design
- **Avoid leading questions** that imply a preferred answer.
- **Avoid double-barreled questions** that ask two things at once ("Is the product fast and reliable?").
- **Watch scale and order effects** — response options and question sequence shift answers.
- **Pre-test** every instrument with a small cognitive-interview pass before fielding.
## Standards
AAPOR (American Association for Public Opinion Research) publishes disclosure standards and the standard definitions for response-rate calculation. Reputable market research follows them so results are comparable and auditable.
## Sources
1. Cochran, W.G., *Sampling Techniques*, 3rd ed. (Wiley, 1977).
2. Dillman, Smyth & Christian, *Internet, Phone, Mail, and Mixed-Mode Surveys: The Tailored Design Method*, 4th ed. (2014).
3. Groves et al., *Survey Methodology*, 2nd ed. (Wiley, 2009) — total survey error.
4. Schuman, H., & Presser, S., *Questions and Answers in Attitude Surveys* (1981) — wording/order effects.
5. AAPOR, *Standard Definitions: Final Dispositions of Case Codes and Outcome Rates for Surveys*.
6. Tourangeau, Rips & Rasinski, *The Psychology of Survey Response* (Cambridge, 2000).
FILE:scripts/ar_evaluator.py
#!/usr/bin/env python3
"""ar_evaluator.py - Autoresearch evaluator for the market-research skill (OPT-IN).
Stdlib-only. The ISOLATED bridge to engineering/autoresearch-agent. It does NOT call
autoresearch; it is the ground-truth evaluator an autoresearch loop runs after editing
the target market model. It reads a market-model JSON, runs market_sizer in "both" mode,
and prints ONE metric line:
tam_divergence: <fraction> (LOWER is better — top-down and bottoms-up should agree)
Optimize a market model so the two sizing methods triangulate (reconcile assumptions),
while the agent edits the target. The user opts in explicitly:
/ar:setup --domain custom --name tam-triangulation \\
--target market.json --eval "python3 ar_evaluator.py --target market.json" \\
--metric tam_divergence --direction lower
Direct use:
python3 ar_evaluator.py --sample
python3 ar_evaluator.py --target market.json --profile enterprise
"""
from __future__ import annotations
import argparse
import json
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import config_loader as cfg # noqa: E402
import market_sizer as ms # noqa: E402
METRIC = "tam_divergence"
def main(argv: list[str] | None = None) -> int:
c = cfg.load_config()
p = argparse.ArgumentParser(description="Autoresearch evaluator: TAM triangulation divergence.")
p.add_argument("--target", help="path to market-model JSON (or env AR_TARGET)")
p.add_argument("--profile", default=None, help="overrides onboarding default_profile")
p.add_argument("--sample", action="store_true")
args = p.parse_args(argv)
profile = args.profile or c.get("default_profile", "b2b-saas")
if args.sample:
data = ms.SAMPLE
else:
target = args.target or os.environ.get("AR_TARGET")
if not target:
print("error: provide --target <market.json> or set AR_TARGET", file=sys.stderr)
return 2
try:
with open(target) as f:
data = json.load(f)
except (OSError, json.JSONDecodeError) as e:
print(f"{METRIC}: N/A")
print(f"error: {e}", file=sys.stderr)
return 1
try:
result = ms.size_market(data, "both", profile)
except ValueError as e:
print(f"{METRIC}: N/A")
print(f"error: {e}", file=sys.stderr)
return 1
div = result.get("tam_divergence")
if div is None:
print(f"{METRIC}: N/A")
print("error: need both top_down and bottoms_up blocks to triangulate", file=sys.stderr)
return 1
print(f"{METRIC}: {div}")
return 0
if __name__ == "__main__":
sys.exit(main())
FILE:scripts/config_loader.py
#!/usr/bin/env python3
"""config_loader.py - Customization loader for the market-research skill.
Stdlib-only. Importable from the skill's other scripts. Precedence (highest wins):
1. Project config: <cwd>/.research-ops/market-research.json
2. Global config: ~/.config/research-ops/market-research.json
3. Built-in DEFAULTS
Onboarding answers (written by onboard.py) live in these files; every tool in this
skill reads them so the user's customization applies automatically.
Set RESEARCH_OPS_NO_CONFIG=1 to ignore saved config.
"""
from __future__ import annotations
import argparse
import json
import os
import sys
from pathlib import Path
from typing import Any
SKILL = "market-research"
GLOBAL_CONFIG_DIR = Path.home() / ".config" / "research-ops"
GLOBAL_CONFIG_PATH = GLOBAL_CONFIG_DIR / f"{SKILL}.json"
PROJECT_CONFIG_DIRNAME = ".research-ops"
DEFAULTS: dict[str, Any] = {
"version": 1,
"skill": SKILL,
"default_profile": "b2b-saas",
"default_confidence": 0.95,
"default_moe": 0.05,
"sizing_method": "both",
"setup_completed_at": None,
}
def project_config_path(cwd: Path | None = None) -> Path:
cwd = cwd or Path.cwd()
return cwd / PROJECT_CONFIG_DIRNAME / f"{SKILL}.json"
def _read_json(path: Path) -> dict[str, Any] | None:
try:
with path.open(encoding="utf-8") as f:
data = json.load(f)
return data if isinstance(data, dict) else None
except (FileNotFoundError, json.JSONDecodeError, OSError):
return None
def _deep_merge(base: dict[str, Any], override: dict[str, Any]) -> dict[str, Any]:
out = dict(base)
for k, v in override.items():
if isinstance(v, dict) and isinstance(out.get(k), dict):
out[k] = _deep_merge(out[k], v)
else:
out[k] = v
return out
def load_config(cwd: Path | None = None) -> dict[str, Any]:
config = dict(DEFAULTS)
if os.environ.get("RESEARCH_OPS_NO_CONFIG") == "1":
return config
global_cfg = _read_json(GLOBAL_CONFIG_PATH)
if global_cfg:
config = _deep_merge(config, global_cfg)
project_cfg = _read_json(project_config_path(cwd))
if project_cfg:
config = _deep_merge(config, project_cfg)
return config
def setup_completed() -> bool:
cfg = _read_json(GLOBAL_CONFIG_PATH) or _read_json(project_config_path())
return bool(cfg and cfg.get("setup_completed_at"))
def write_config(config: dict[str, Any], scope: str = "global", cwd: Path | None = None) -> Path:
path = project_config_path(cwd) if scope == "project" else GLOBAL_CONFIG_PATH
path.parent.mkdir(parents=True, exist_ok=True)
with path.open("w", encoding="utf-8") as f:
json.dump(config, f, indent=2, sort_keys=True)
return path
def main(argv: list[str] | None = None) -> int:
p = argparse.ArgumentParser(description=f"Inspect {SKILL} customization config.")
p.add_argument("--show", action="store_true", help="Print the effective config")
p.add_argument("--status", action="store_true", help="Print setup status + paths")
p.add_argument("--sample", action="store_true", help="Print the built-in defaults")
args = p.parse_args(argv)
if args.sample:
print(json.dumps(DEFAULTS, indent=2, sort_keys=True))
elif args.status:
print(json.dumps({
"skill": SKILL,
"global_config_path": str(GLOBAL_CONFIG_PATH),
"global_config_exists": GLOBAL_CONFIG_PATH.exists(),
"project_config_path": str(project_config_path()),
"project_config_exists": project_config_path().exists(),
"setup_completed": setup_completed(),
}, indent=2))
else:
print(json.dumps(load_config(), indent=2, sort_keys=True))
return 0
if __name__ == "__main__":
sys.exit(main())
FILE:scripts/market_sizer.py
#!/usr/bin/env python3
"""market_sizer.py - Compute TAM / SAM / SOM by BOTH top-down and bottoms-up methods.
Stdlib-only. Deterministic. NO LLM calls. NEVER returns a single number: it computes both
methods side-by-side, reports the delta, and prints a mandatory method + assumptions block.
Top-down: TAM = total_market_value ; SAM = TAM * serviceable_fraction ; SOM = SAM * reachable_share
Bottoms-up: TAM = total_potential_customers * annual_price
SAM = TAM * serviceable_fraction
SOM = SAM * realistic_adoption (capacity-constrained)
If the two TAMs diverge by more than the tolerance, the tool flags it: triangulation failed.
Usage:
python3 market_sizer.py --sample
python3 market_sizer.py --input market.json --method both
python3 market_sizer.py --input market.json --profile b2b-saas --output json
"""
from __future__ import annotations
import argparse
import json
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
try:
import config_loader as _cfg
except ImportError: # pragma: no cover
_cfg = None
# Profiles tune the divergence tolerance and a sanity note.
PROFILES = {
"b2b-saas": {"tolerance": 0.30},
"consumer": {"tolerance": 0.40},
"enterprise": {"tolerance": 0.25},
"marketplace": {"tolerance": 0.40},
"hardware": {"tolerance": 0.30},
"services": {"tolerance": 0.35},
}
SAMPLE = {
"market_name": "Mid-market HR analytics SaaS (US)",
"top_down": {
"total_market_value": 4200000000,
"serviceable_fraction": 0.35,
"reachable_share": 0.04,
},
"bottoms_up": {
"total_potential_customers": 62000,
"annual_price": 18000,
"serviceable_fraction": 0.35,
"realistic_adoption": 0.03,
},
}
def top_down(td: dict) -> dict:
tam = float(td.get("total_market_value", 0.0))
sam = tam * float(td.get("serviceable_fraction", 0.0))
som = sam * float(td.get("reachable_share", 0.0))
return {"method": "top-down", "TAM": round(tam, 0), "SAM": round(sam, 0), "SOM": round(som, 0)}
def bottoms_up(bu: dict) -> dict:
customers = float(bu.get("total_potential_customers", 0.0))
price = float(bu.get("annual_price", 0.0))
tam = customers * price
sam = tam * float(bu.get("serviceable_fraction", 0.0))
som = sam * float(bu.get("realistic_adoption", 0.0))
return {"method": "bottoms-up", "TAM": round(tam, 0), "SAM": round(sam, 0),
"SOM": round(som, 0), "implied_customers_at_SOM": round((sam / price) * float(bu.get("realistic_adoption", 0.0))) if price else None}
def size_market(data: dict, method: str, profile: str) -> dict:
if profile not in PROFILES:
raise ValueError(f"Unknown profile '{profile}'. Choose from {list(PROFILES)}.")
tol = PROFILES[profile]["tolerance"]
out = {"market_name": data.get("market_name", "UNSPECIFIED"), "profile": profile}
td = top_down(data.get("top_down", {})) if method in ("top-down", "both") else None
bu = bottoms_up(data.get("bottoms_up", {})) if method in ("bottoms-up", "both") else None
if td:
out["top_down"] = td
if bu:
out["bottoms_up"] = bu
flags = []
if td and bu and td["TAM"] > 0:
delta = abs(td["TAM"] - bu["TAM"]) / td["TAM"]
out["tam_divergence"] = round(delta, 3)
if delta > tol:
flags.append(f"TRIANGULATION FAILED: top-down and bottoms-up TAM differ by {delta:.0%} "
f"(> {tol:.0%} tolerance). Reconcile before quoting a number.")
else:
flags.append(f"Triangulation OK: TAMs within {delta:.0%} (tolerance {tol:.0%}).")
out["flags"] = flags
out["method_and_assumptions"] = [
"NEVER quote a single TAM number without stating the method and the assumptions below.",
"Top-down TAM = total market value (cite the source: analyst report, gov stat).",
"Bottoms-up TAM = total potential customers x annual price (cite both counts).",
"SAM = TAM x serviceable fraction (geography/segment you can actually serve).",
"SOM = SAM x realistic, capacity-constrained share you can win in the planning window.",
]
return out
def _fmt(n):
return f",.0f" if isinstance(n, (int, float)) else str(n)
def _render_human(r: dict) -> str:
lines = [f"Market Sizing: {r['market_name']} (profile: {r['profile']})", ""]
for key in ("top_down", "bottoms_up"):
if key in r:
m = r[key]
lines.append(f" [{m['method']}] TAM {_fmt(m['TAM'])} | SAM {_fmt(m['SAM'])} | SOM {_fmt(m['SOM'])}")
if m.get("implied_customers_at_SOM") is not None:
lines.append(f" implied customers at SOM: {m['implied_customers_at_SOM']:,}")
if "tam_divergence" in r:
lines.append(f" TAM divergence (top-down vs bottoms-up): {r['tam_divergence']:.1%}")
lines.append("")
for f in r["flags"]:
lines.append(f" ! {f}")
lines.append("")
lines.append("Method & assumptions (must travel with the number):")
for a in r["method_and_assumptions"]:
lines.append(f" - {a}")
return "\n".join(lines)
def main(argv: list[str] | None = None) -> int:
p = argparse.ArgumentParser(description="Compute TAM/SAM/SOM by top-down AND bottoms-up (never a single number).")
p.add_argument("--input", help="Path to JSON with top_down{} and bottoms_up{}")
p.add_argument("--method", choices=["top-down", "bottoms-up", "both"], default=None,
help="overrides onboarding sizing_method")
p.add_argument("--profile", default=None, choices=list(PROFILES),
help="overrides onboarding default_profile")
p.add_argument("--output", choices=["human", "json"], default="human")
p.add_argument("--sample", action="store_true", help="use the embedded sample")
args = p.parse_args(argv)
conf = _cfg.load_config() if _cfg else {}
method = args.method or conf.get("sizing_method", "both")
profile = args.profile or conf.get("default_profile", "b2b-saas")
data = SAMPLE if (args.sample or not args.input) else json.load(open(args.input))
try:
result = size_market(data, method, profile)
except ValueError as e:
print(f"error: {e}", file=sys.stderr)
return 2
if args.output == "json":
print(json.dumps(result, indent=2))
else:
print(_render_human(result))
return 0
if __name__ == "__main__":
sys.exit(main())
FILE:scripts/onboard.py
#!/usr/bin/env python3
"""onboard.py - Onboarding questionnaire for the market-research skill.
Stdlib-only. Asks the user a short set of questions BEFORE they size a market or field
a survey, then writes the answers to a customization config read by every tool in this
skill via config_loader.py. The answers become defaults for profile, survey confidence,
margin of error, and sizing method.
Modes: --show | --defaults | --set key=value (repeatable) | --reset | --scope {global,project}
"""
from __future__ import annotations
import argparse
import datetime as _dt
import json
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import config_loader as cfg # noqa: E402
NUMERIC_KEYS = {"default_confidence", "default_moe"}
QUESTIONS = [
("default_profile",
"1. What market are you researching?",
["b2b-saas", "consumer", "enterprise", "marketplace", "hardware", "services"], str),
("default_confidence",
"2. Default survey confidence level?",
["0.80", "0.85", "0.90", "0.95", "0.99"], float),
("default_moe",
"3. Default survey margin of error (fraction, e.g. 0.05)?",
None, float),
("sizing_method",
"4. Default market-sizing method?",
["top-down", "bottoms-up", "both"], str),
]
def _print_questions() -> None:
print(f"Onboarding questions — {cfg.SKILL}:\n")
for _k, prompt, choices, _c in QUESTIONS:
line = f" {prompt}"
if choices:
line += f" [{' / '.join(choices)}]"
print(line)
def run_interactive(config: dict) -> dict:
print(f"Onboarding — {cfg.SKILL}. Press Enter to keep the current/default value.\n")
for key, prompt, choices, caster in QUESTIONS:
suffix = f" [{'/'.join(choices)}]" if choices else ""
cur = f" (current: {config.get(key)})" if config.get(key) is not None else ""
raw = input(f"{prompt}{suffix}{cur}: ").strip()
if not raw:
continue
try:
config[key] = caster(raw)
except ValueError:
print(f" ! invalid value for {key}, keeping current")
return config
def main(argv: list[str] | None = None) -> int:
p = argparse.ArgumentParser(description=f"Onboarding for the {cfg.SKILL} skill.")
p.add_argument("--show", action="store_true")
p.add_argument("--defaults", action="store_true", help="write built-in defaults, no prompt")
p.add_argument("--set", action="append", default=[], metavar="key=value")
p.add_argument("--reset", action="store_true")
p.add_argument("--scope", choices=["global", "project"], default="global")
args = p.parse_args(argv)
if args.show:
_print_questions()
print("\nCurrent effective config:")
print(json.dumps(cfg.load_config(), indent=2, sort_keys=True))
return 0
if args.reset:
path = cfg.project_config_path() if args.scope == "project" else cfg.GLOBAL_CONFIG_PATH
if path.exists():
path.unlink(); print(f"removed {path}")
else:
print(f"no config at {path}")
return 0
config = cfg.load_config()
if args.set:
for item in args.set:
if "=" not in item:
print(f"error: --set expects key=value, got '{item}'", file=sys.stderr)
return 2
k, v = item.split("=", 1)
if k in NUMERIC_KEYS:
try:
v = float(v)
except ValueError:
pass
config[k] = v
elif not args.defaults:
if sys.stdin.isatty():
config = run_interactive(config)
else:
print("non-interactive shell: use --defaults or --set key=value. Showing questions:\n")
_print_questions()
return 0
config["setup_completed_at"] = _dt.datetime.now(_dt.timezone.utc).isoformat()
path = cfg.write_config(config, scope=args.scope)
print(f"saved {cfg.SKILL} customization -> {path}")
return 0
if __name__ == "__main__":
sys.exit(main())
FILE:scripts/sample_size_planner.py
#!/usr/bin/env python3
"""sample_size_planner.py - Survey sample-size with finite-population correction + per-segment minima.
Stdlib-only. Deterministic. NO LLM calls.
Computes the classic proportion-estimate sample size:
n0 = z^2 * p * (1-p) / e^2
then applies the finite-population correction (FPC) when a population N is given:
n = n0 / (1 + (n0 - 1)/N)
Also computes per-segment minimums and a proportional quota allocation, because a survey
powered overall is NOT powered per reported segment.
Usage:
python3 sample_size_planner.py --sample
python3 sample_size_planner.py --population 62000 --confidence 0.95 --moe 0.05 --proportion 0.5
python3 sample_size_planner.py --input survey.json --output json
"""
from __future__ import annotations
import argparse
import json
import math
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
try:
import config_loader as _cfg
except ImportError: # pragma: no cover
_cfg = None
Z = {0.80: 1.2816, 0.85: 1.4395, 0.90: 1.6449, 0.95: 1.9600, 0.99: 2.5758}
SAMPLE = {
"population": 62000,
"confidence": 0.95,
"margin_of_error": 0.05,
"expected_proportion": 0.5,
"segments": [
{"name": "1-50 employees", "population_share": 0.55},
{"name": "51-250 employees", "population_share": 0.30},
{"name": "251-1000 employees", "population_share": 0.15},
],
"segment_moe": 0.08,
}
def _z(conf: float) -> float:
if conf not in Z:
raise ValueError(f"confidence must be one of {sorted(Z)}.")
return Z[conf]
def base_n(conf: float, moe: float, p: float, population: float | None) -> dict:
if not 0.0 < p < 1.0:
raise ValueError("expected_proportion must be in (0,1).")
if not 0.0 < moe < 1.0:
raise ValueError("margin_of_error must be in (0,1).")
z = _z(conf)
n0 = (z ** 2) * p * (1 - p) / (moe ** 2)
if population and population > 0:
n = n0 / (1 + (n0 - 1) / population)
fpc_applied = True
else:
n = n0
fpc_applied = False
return {
"confidence": conf,
"margin_of_error": moe,
"expected_proportion": p,
"population": population,
"n_unadjusted": math.ceil(n0),
"n_with_fpc": math.ceil(n),
"fpc_applied": fpc_applied,
"z": z,
}
def segment_plan(data: dict, overall: dict) -> dict:
seg_moe = float(data.get("segment_moe", data.get("margin_of_error", 0.05)))
conf = float(data.get("confidence", 0.95))
p = float(data.get("expected_proportion", 0.5))
z = _z(conf)
per_seg_min = math.ceil((z ** 2) * p * (1 - p) / (seg_moe ** 2))
segs = data.get("segments", [])
total_quota = max(overall["n_with_fpc"], per_seg_min * len(segs)) if segs else overall["n_with_fpc"]
out_segs = []
for s in segs:
share = float(s.get("population_share", 0.0))
proportional = math.ceil(total_quota * share)
quota = max(proportional, per_seg_min)
out_segs.append({
"name": s.get("name", "UNNAMED"),
"population_share": share,
"proportional_quota": proportional,
"minimum_for_segment_moe": per_seg_min,
"recommended_quota": quota,
})
return {
"segment_margin_of_error": seg_moe,
"minimum_per_segment": per_seg_min,
"recommended_total_with_segment_floors": sum(s["recommended_quota"] for s in out_segs) if out_segs else total_quota,
"segments": out_segs,
}
def plan(data: dict) -> dict:
overall = base_n(
float(data.get("confidence", 0.95)),
float(data.get("margin_of_error", 0.05)),
float(data.get("expected_proportion", 0.5)),
data.get("population"),
)
result = {"overall": overall}
if data.get("segments"):
result["segmentation"] = segment_plan(data, overall)
result["notes"] = [
"A survey powered overall is NOT powered per reported segment — fund the segment floors.",
"expected_proportion=0.5 is the conservative (maximum-variance) default.",
"FPC matters when the sample is a large fraction of the population (small N).",
]
return result
def _render_human(r: dict) -> str:
o = r["overall"]
lines = ["Survey Sample-Size Plan", "",
f" Confidence: {o['confidence']:.0%} MoE: {o['margin_of_error']:.0%} p: {o['expected_proportion']}",
f" n (unadjusted): {o['n_unadjusted']}",
f" n (with FPC): {o['n_with_fpc']} (population {o['population']}, fpc_applied={o['fpc_applied']})"]
if "segmentation" in r:
s = r["segmentation"]
lines += ["", f" Per-segment MoE: {s['segment_margin_of_error']:.0%} => minimum {s['minimum_per_segment']} per segment",
f" Recommended total with segment floors: {s['recommended_total_with_segment_floors']}", ""]
for seg in s["segments"]:
lines.append(f" {seg['name']:24s} share {seg['population_share']:.0%} "
f"proportional {seg['proportional_quota']} recommended {seg['recommended_quota']}")
lines += ["", "Notes:"]
for n in r["notes"]:
lines.append(f" - {n}")
return "\n".join(lines)
def main(argv: list[str] | None = None) -> int:
p = argparse.ArgumentParser(description="Survey sample size with FPC + per-segment minima.")
p.add_argument("--input", help="Path to JSON survey spec")
p.add_argument("--population", type=float, default=None)
p.add_argument("--confidence", type=float, default=None, help="overrides onboarding default_confidence")
p.add_argument("--moe", type=float, default=None, help="margin of error (overrides onboarding default_moe)")
p.add_argument("--proportion", type=float, default=0.5, help="expected proportion")
p.add_argument("--output", choices=["human", "json"], default="human")
p.add_argument("--sample", action="store_true", help="use the embedded sample")
args = p.parse_args(argv)
conf = _cfg.load_config() if _cfg else {}
confidence = args.confidence if args.confidence is not None else conf.get("default_confidence", 0.95)
moe = args.moe if args.moe is not None else conf.get("default_moe", 0.05)
if args.sample:
data = SAMPLE
elif args.input:
data = json.load(open(args.input))
else:
data = {"population": args.population, "confidence": confidence,
"margin_of_error": moe, "expected_proportion": args.proportion}
try:
result = plan(data)
except ValueError as e:
print(f"error: {e}", file=sys.stderr)
return 2
if args.output == "json":
print(json.dumps(result, indent=2))
else:
print(_render_human(result))
return 0
if __name__ == "__main__":
sys.exit(main())
FILE:scripts/segmentation_scorer.py
#!/usr/bin/env python3
"""segmentation_scorer.py - Score candidate market segments against Kotler's actionability criteria.
Stdlib-only. Deterministic. NO LLM calls.
Each candidate segment is scored 0-100 across the five Kotler criteria for a useful segment:
1. measurable can you size and identify it?
2. substantial is it large/profitable enough to serve?
3. accessible can you reach it through channels?
4. differentiable does it respond differently from other segments?
5. actionable can you design and execute a program for it?
Segments failing the substantiality or accessibility gates are flagged: a demographic slice
that is unreachable or too small is not a market segment.
Usage:
python3 segmentation_scorer.py --sample
python3 segmentation_scorer.py --input segments.json --profile enterprise
python3 segmentation_scorer.py --input segments.json --output json
"""
from __future__ import annotations
import argparse
import json
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
try:
import config_loader as _cfg
except ImportError: # pragma: no cover
_cfg = None
CRITERIA = ["measurable", "substantial", "accessible", "differentiable", "actionable"]
WEIGHTS = {"measurable": 0.15, "substantial": 0.25, "accessible": 0.25,
"differentiable": 0.20, "actionable": 0.15}
GATE_FLOOR = 40.0 # substantiality + accessibility gate
# Profiles nudge the substantiality expectation (enterprise tolerates smaller, higher-value segments).
PROFILES = {
"b2b-saas": 1.0,
"consumer": 1.0,
"enterprise": 0.85,
"marketplace": 1.0,
"hardware": 1.0,
"services": 0.9,
}
SAMPLE = {
"segments": [
{"name": "Mid-market HR teams (51-250 emp)",
"scores": {"measurable": 85, "substantial": 80, "accessible": 75, "differentiable": 70, "actionable": 80}},
{"name": "Solopreneurs who 'might' want analytics",
"scores": {"measurable": 40, "substantial": 30, "accessible": 35, "differentiable": 30, "actionable": 40}},
{"name": "Enterprise CHROs (1000+ emp)",
"scores": {"measurable": 90, "substantial": 95, "accessible": 50, "differentiable": 85, "actionable": 70}},
],
}
def score_segment(seg: dict, sub_mult: float) -> dict:
raw = seg.get("scores", {})
breakdown = {}
composite = 0.0
for c in CRITERIA:
s = float(raw.get(c, 0.0))
if c == "substantial":
s = min(100.0, s / sub_mult) # enterprise: smaller segments still count (divide by <1 raises)
breakdown[c] = round(s, 1)
composite += s * WEIGHTS[c]
flags = []
if breakdown["substantial"] < GATE_FLOOR:
flags.append("FAILS SUBSTANTIALITY GATE: too small/unprofitable to be a target segment.")
if breakdown["accessible"] < GATE_FLOOR:
flags.append("FAILS ACCESSIBILITY GATE: no viable channel to reach it.")
verdict = "DROP" if flags else ("TARGET" if composite >= 65 else "WATCH")
return {
"name": seg.get("name", "UNNAMED"),
"composite": round(composite, 1),
"breakdown": breakdown,
"flags": flags,
"verdict": verdict,
}
def evaluate(data: dict, profile: str) -> dict:
if profile not in PROFILES:
raise ValueError(f"Unknown profile '{profile}'. Choose from {list(PROFILES)}.")
mult = PROFILES[profile]
scored = sorted((score_segment(s, mult) for s in data.get("segments", [])),
key=lambda x: x["composite"], reverse=True)
return {
"profile": profile,
"segments": scored,
"note": "A demographic or firmographic slice is not a segment unless it is substantial AND accessible.",
}
def _render_human(r: dict) -> str:
lines = [f"Segmentation Scoring (profile: {r['profile']})", ""]
for s in r["segments"]:
lines.append(f"[{s['verdict']}] {s['name']} — composite {s['composite']}/100")
for c, v in s["breakdown"].items():
lines.append(f" {c:16s} {v}")
for f in s["flags"]:
lines.append(f" ! {f}")
lines.append("")
lines.append(f"note: {r['note']}")
return "\n".join(lines)
def main(argv: list[str] | None = None) -> int:
p = argparse.ArgumentParser(description="Score market segments against Kotler's 5 criteria.")
p.add_argument("--input", help="Path to JSON with segments[]")
p.add_argument("--profile", default=None, choices=list(PROFILES),
help="overrides onboarding default_profile")
p.add_argument("--output", choices=["human", "json"], default="human")
p.add_argument("--sample", action="store_true", help="use the embedded sample")
args = p.parse_args(argv)
conf = _cfg.load_config() if _cfg else {}
profile = args.profile or conf.get("default_profile", "b2b-saas")
data = SAMPLE if (args.sample or not args.input) else json.load(open(args.input))
try:
result = evaluate(data, profile)
except ValueError as e:
print(f"error: {e}", file=sys.stderr)
return 2
if args.output == "json":
print(json.dumps(result, indent=2))
else:
print(_render_human(result))
return 0
if __name__ == "__main__":
sys.exit(main())