PM Cram

Contribute study content

PM Cram's study content is open-source JSON. Anyone can add a question, a case study, a guide or a flashcard by dropping a small JSON file into the repo and opening a pull request. This guide shows you exactly how each content type is shaped, with real, copyable examples.

How contributing works

The content lives as plain JSON under content/ in the Forge-Deck/pmcram repository. There's no CMS and no build step to learn — you edit text files.

  1. Fork the repo on GitHub.
  2. Add or edit a JSON file in the right folder for your content type (content/questions/, content/cases/, and so on). Adding new content? Create a new file (e.g. content/questions/contrib-2026-07-yourhandle.json) rather than editing the big curated banks. Fixing a mistake? Edit the record where it lives.
  3. Open a pull request. CI validates every file against the JSON Schemas automatically, so you'll know within a minute if something's off.
Three things that surprise first-timers

Files are JSON arrays. Every content file is a [ … ] array of records, even if it holds just one. You add content by appending a record to the array (or creating a new file that is a one-element array).

id is optional everywhere. The app derives a stable content-hash id from each record, so you never have to invent or track ids. Only set an id to pin a correctable identity (must be kebab-case) — and never reuse one that already exists.

Every record may carry contributor — your GitHub handle, for attribution. It's optional and never affects grading.

You don't have to run anything locally, but if you want to check your work before pushing, npm install then npm run validate runs the same checks CI does. npm run manifest regenerates the index — but CI regenerates it on merge, so you can skip it.

The golden rule for options

This applies to every question type that has options — practice questions, dynamic pools, and case steps. It's the single most important thing that separates a fair PMP question from a giveaway.

Read this before writing any distractor

1. Distractors must be plausible "right-but-not-best" actions — things a competent PM might genuinely consider, that are wrong on target, sequence, owner, scope or timing, not because they're obviously silly. Common failure modes to lean on:

  • Too narrow — solves part of the problem, misses the rest.
  • Premature solution — jumps to fixing before assessing.
  • Wrong sequence — a real step, but not the first one.
  • Procedural deflection — escalate / raise a change request when you should first investigate.
  • Symptom, not root cause — treats the surface issue.

2. The correct answer must NOT be the longest or most-detailed option. If the key is always the wordiest, length telegraphs it. Keep all options comparable in length and specificity.

3. Never rely on order. Options are assembled and shuffled at runtime — never write "A/B/C/D", "the first option", or "all of the above". The app renders the correct answer plus a random sample of distractors and shuffles them.

No absolutes ("always", "never", "immediately"), no unethical tells, and no self-justifying phrasing in a distractor that gives the game away. If a served set of four options doesn't read as four legitimate PMP moves, it's too easy.

1 · Practice questions

content/questions/ schema: "question/v1"

The workhorse. A single- or multi-select question that the app assembles at runtime: it renders present options made of the correct answer(s) plus a random sample of distractors, then shuffles. That's why you store a pool, not a fixed list.

Required fields

  • domain required — one of People, Process, Business Environment.
  • type requiredsingle (choose one) or multi (choose N).
  • select required — how many the user picks (integer, 1 for single).
  • present required — total options shown. Must be > select and ≤ correct.length + distractors.length. Typically 4.
  • prompts required — an array of one or more equivalent wordings; the app picks one at random.
  • correct required — array of { text, why? }. For single this is a pool of interchangeable correct phrasings (the app shows one); for multi, its length must equal select.
  • distractors required — array of { text, trap? }. Provide more than needed; the app samples present - select of them.

Useful optional fields

difficulty topic subtopic subDomain eco_task explanation references signals trace rules tags group contributor

A bare question (no why/trap/explanation) still works and is scored right/wrong — but the per-option rationale is where most of the study value lives, so add it when you can.

Minimal real example

[
  {
    "schema": "question/v1",
    "domain": "Process",
    "subDomain": "Schedule Management",
    "difficulty": "medium",
    "topic": "Critical Path",
    "type": "single",
    "select": 1,
    "present": 4,
    "prompts": [
      "Two weeks into execution, an activity on the critical path slips by three days. What should the project manager do first?"
    ],
    "correct": [
      { "text": "Analyse the schedule impact and identify options such as fast-tracking or crashing before committing.",
        "why": "You assess the impact and evaluate compression options before choosing a response." }
    ],
    "distractors": [
      { "text": "Crash the delayed activity by adding resources to recover the three days.",
        "trap": "Premature solution — crashing adds cost and should follow impact analysis, not precede it." },
      { "text": "Update the baseline finish date to reflect the three-day slip.",
        "trap": "Changing the baseline without change control hides the variance instead of managing it." },
      { "text": "Report the slippage to the sponsor and ask how to proceed.",
        "trap": "Procedural deflection — escalating before you have analysed options and a recommendation." }
    ],
    "explanation": "First quantify the impact on the critical path, then evaluate compression options; act, escalate or re-baseline only after that.",
    "references": ["PMBOK Guide, Schedule Management"],
    "contributor": "your-github-handle"
  }
]
Tips
  • Notice the correct answer isn't the longest — the "crash" distractor is just as detailed.
  • Every distractor's trap names the exact failure mode (premature solution, no change control, procedural deflection).
  • Want "choose 2 of 6"? Set type:"multi", select:2, present:6, put exactly 2 items in correct, and give ≥4 distractors.

2 · Static vs dynamic questions

These are the same question/v1 schema — there is no separate "dynamic" type. The difference is entirely in how much pool you author.

  • Static — one prompt, one correct phrasing, just enough distractors. Every exposure is identical. Great for crisp factual recall.
  • Dynamic — a pool: multiple prompts, several interchangeable correct phrasings, and extra distractors. The engine draws one prompt + one correct + a sample of distractors and shuffles, so each exposure feels fresh.

Use group to tie variants of one concept together. Questions that share a group are treated as phrasings of the same idea, so a mock or focused batch never serves two of them at once.

Per-draw length parity

Because only one correct answer and a sample of distractors appear together, the correct answer must never be the longest of the four shown. Rule of thumb: at most two distractors may be shorter than the longest correct phrasing — keep them all comparable.

[
  {
    "schema": "question/v1",
    "id": "dyn-single-point-of-accountability",
    "domain": "People",
    "subDomain": "Lead Project Team",
    "type": "single",
    "select": 1,
    "present": 4,
    "group": "raci-accountable-count",
    "prompts": [
      "A team is confused about a deliverable because two people are both marked Accountable on the RACI chart. What is the core problem?",
      "On a RACI chart, one task lists two names in the Accountable column. Why is this a defect?"
    ],
    "correct": [
      { "text": "Each task should have exactly one Accountable person, so a single owner can be held answerable.",
        "why": "RACI allows many Responsible, but only one Accountable per task — otherwise ownership is ambiguous." },
      { "text": "Accountability must sit with a single person per task; two 'A's leaves no clear owner.",
        "why": "The defining RACI rule is one Accountable per row." }
    ],
    "distractors": [
      { "text": "Both names should be moved to the Responsible column so the work is shared.",
        "trap": "Fixes the symptom by reshuffling letters but ignores the one-Accountable rule." },
      { "text": "The Consulted and Informed roles are missing, which is what causes the confusion.",
        "trap": "Wrong target — the defect is the duplicate Accountable, not the C/I columns." },
      { "text": "A RACI chart is the wrong tool here; a responsibility histogram would be clearer.",
        "trap": "Deflects to another tool instead of correcting the accountability error." },
      { "text": "The task simply needs a deadline added so the two owners know when to deliver.",
        "trap": "Adds an unrelated attribute; timing was never the issue." }
    ],
    "explanation": "RACI permits multiple Responsible parties but exactly one Accountable per task; two 'A's is the defect."
  }
]

Same schema as example 1 — it just carries more prompts, more correct, more distractors, and a group key.

3 · Case studies

content/cases/ schema: "case/v1"

One shared scenario plus a steps array (2–8 steps). Each step is a mini-question with its own options. The app pins the scenario, reveals one step at a time, and only unlocks the next step once the current one is answered — so later steps can't spoil earlier ones. The golden rule for options applies to every step.

Fields

  • scenario required — the shared situation, shown above every step.
  • steps required — 2–8 mini-questions. Each step needs prompt, correct[], distractors[]; optional per-step label, type, select, present, domain, topic, explanation, references.
  • Optional top level: title domain topic difficulty tags contributor
[
  {
    "schema": "case/v1",
    "title": "Vendor slippage on a hybrid rollout",
    "domain": "Process",
    "difficulty": "medium",
    "scenario": "You are leading a hybrid CRM rollout. A key integration vendor has quietly fallen two sprints behind, and your sponsor has just heard about it from a stakeholder rather than from you.",
    "steps": [
      {
        "label": "First response",
        "prompt": "What should you do first now that the sponsor knows about the delay?",
        "correct": [
          { "text": "Gather the facts on the vendor's actual status and schedule impact before responding.",
            "why": "You investigate and quantify the impact before communicating or acting." }
        ],
        "distractors": [
          { "text": "Apologise to the sponsor and promise to recover the two sprints.",
            "trap": "Commits to a recovery you have not yet analysed." },
          { "text": "Issue a formal notice to the vendor threatening penalty clauses.",
            "trap": "Escalates contractually before establishing the facts." },
          { "text": "Add the delay to the risk register and continue as planned.",
            "trap": "Logs the symptom but takes no action on a risk that has already occurred." }
        ],
        "domain": "Process"
      },
      {
        "label": "Governance",
        "prompt": "Analysis confirms the delay threatens a contractual go-live date. What is the best next move?",
        "correct": [
          { "text": "Raise it through integrated change control with impact options for the sponsor to decide.",
            "why": "A schedule-baseline threat with contractual stakes belongs in change control." }
        ],
        "distractors": [
          { "text": "Quietly fast-track internal tasks to absorb the vendor's slippage.",
            "trap": "Hides a governance-level issue and absorbs risk without authority." },
          { "text": "Replace the vendor immediately to protect the go-live date.",
            "trap": "Premature and disproportionate before options are weighed." }
        ],
        "domain": "Business Environment"
      }
    ]
  }
]

4 · Sequencing

content/sequences/ schema: "sequence/v1"

A drag-to-order question. You store the steps in the correct order; the app shuffles them and the user drags them back. 3–8 steps. Each step is { text, note? } — the optional note is a one-line rationale shown on review for that step's position.

  • prompt required — the instruction.
  • steps required — 3–8 steps in correct order.
  • Optional: domain topic difficulty explanation tags contributor
[
  {
    "schema": "sequence/v1",
    "prompt": "Order the steps of the Perform Integrated Change Control flow after a change request is raised.",
    "domain": "Business Environment",
    "topic": "Change Control",
    "steps": [
      { "text": "Record the change request in the change log", "note": "Every request is logged before it is assessed." },
      { "text": "Assess the impact on scope, schedule, cost and risk", "note": "Evaluate before deciding." },
      { "text": "Submit the analysed request to the change control board", "note": "The CCB, not the PM alone, decides." },
      { "text": "Communicate the decision and update the affected plans", "note": "Approved changes update baselines; rejected ones are still recorded." }
    ],
    "explanation": "Log, assess, decide via the CCB, then communicate and update — a request is never actioned before impact analysis."
  }
]

5 · Interactives / figuregen

content/figuregen/ schema: "figuregen/v1"

The advanced one. A figuregen record is a template, not a fixed question: it declares random variables and the app's figuregen engine rolls a fresh randomised variant each time it's served. Many numeric fields are expression strings evaluated against the rolled scope (e.g. "30 + i*60"). The engine draws the figure and grades taps/drags/choices against those expressions.

Every record needs schema ("figuregen/v1"), id (kebab-case), kind, domain, viewBox ([w, h]) and prompt. The kind is one of hotspot · choice · dragdrop · gantt · pareto · assign.

Start from a template, not a blank file

Figuregen is expression-driven and genuinely complex — draw ops, chart styles, guards, derived values. Rather than authoring one from scratch, open an existing file in content/figuregen/, copy the closest kind, and adapt its numbers and text. The worked templates there are the real reference.

The simplest kind is choice — a multiple-choice question about a small figure. Its answer block is choices[], each { text, correct, why? }, where correct is an expression that is true for the right option:

[
  {
    "schema": "figuregen/v1",
    "id": "network-float-choice",
    "kind": "choice",
    "domain": "Process",
    "topic": "Critical Path",
    "viewBox": [280, 160],
    "prompt": "Activity B has an early start of 4 and a late start of 9. How much total float does it have?",
    "vars": { "es": { "sampleInt": [2, 6] }, "slack": { "sampleInt": [3, 7] } },
    "derived": { "ls": "es + slack" },
    "draw": [
      { "op": "rect", "x": 40, "y": 50, "w": 60, "h": 40 },
      { "op": "text", "x": 70, "y": 75, "text": "B" }
    ],
    "choices": [
      { "text": "slack", "correct": true, "why": "Total float = late start minus early start." },
      { "text": "es", "correct": false, "why": "That is the early start, not the float." },
      { "text": "ls", "correct": false, "why": "That is the late start, not the float." },
      { "text": "0", "correct": false, "why": "Zero float would put the activity on the critical path." }
    ]
  }
]

A hotspot template swaps choices for regions[] ({ id, x, y, w, h, correct, label?, why? }) so the user taps the correct area; dragdrop adds tokens[] dragged onto those regions. Again — copy a real one from content/figuregen/.

6 · Guides

content/guides/ schema: "guide/v1"

Read-and-absorb study material — mindset, agile, strategy, cheat sheets. A guide is identified by its title (a natural key that dedupes case-insensitively), a category, and an array of sections.

  • title required, category required, sections required.
  • Each section: heading + body required; optional tip, figure, blocks, signals, trace, rules, kicker.
  • Give every guide a punchy intro (the card teaser in the Guides list) and a summary.
Body formatting (no markdown)

body is plain text with two rules only: a blank line starts a new paragraph, and a line starting with - becomes a bullet. There is no markdown parser, so don't use #, **bold**, or links in body.

For richer layout, a section can carry blocks — ordered structured blocks of kind tip · steps · cards · table · terms · formulas. Figures are inline svg (single-quoted attributes, currentColor for theming) or a raster image path.

[
  {
    "schema": "guide/v1",
    "title": "Reading Earned Value at a Glance",
    "category": "Formulae",
    "summary": "Turn EV, PV and AC into a one-look health check.",
    "intro": "CV and SV tell you where you stand; CPI and SPI tell you how fast the gap is growing. Learn to read all four in seconds.",
    "sections": [
      {
        "heading": "The four numbers that matter",
        "body": "Earned value analysis compares what you planned, what you did, and what it cost.\n\n- PV — the budgeted cost of work planned by now\n- EV — the budgeted cost of work actually completed\n- AC — what that completed work really cost",
        "tip": "Variances (CV, SV) are money and schedule differences; indices (CPI, SPI) are ratios. Negative variance and an index below 1.0 both mean 'behind'.",
        "blocks": [
          {
            "kind": "formulas",
            "title": "Core EVM formulas",
            "lines": [
              "CV = EV - AC",
              "SV = EV - PV",
              "CPI = EV / AC",
              "SPI = EV / PV"
            ]
          }
        ]
      }
    ]
  }
]

7 · Exam tips

content/guides/ schema: "guide/v1" category: "Exam"

Exam tips aren't a separate type — they're just guides with "category": "Exam". The app surfaces those in its dedicated Exam Prep tab and keeps them out of the main Guides list. Keep them tactical and heuristic: quick decision rules, trap-spotting, time management.

[
  {
    "schema": "guide/v1",
    "title": "When in doubt, investigate first",
    "category": "Exam",
    "summary": "The single most reliable PMP tie-breaker.",
    "intro": "Stuck between two good options? PMI almost always rewards understanding the situation before acting on it.",
    "sections": [
      {
        "heading": "The investigate-first heuristic",
        "body": "When two answers both look reasonable, prefer the one that gathers facts or assesses impact over the one that acts, escalates, or blames.\n\n- 'Meet with the team to understand the cause' usually beats 'reassign the work'\n- 'Assess the impact' usually beats 'submit a change request'\n- Escalation is rarely the first step",
        "tip": "Watch for absolutes in the options — 'always', 'never', 'immediately' are usually traps."
      }
    ]
  }
]

Not sure your JSON is right?

Fill in a short form and get a valid question/v1 record you can paste straight into a file.

Try the JSON builder →