Help us improve
Share bugs, ideas, or general feedback.
From ccaf
Runs a 60-question CCAF mock exam with fresh questions per attempt, resumable progress, and scoring on the 100–1000 band (720 pass line).
npx claudepluginhub incubyte/ai-pluginsHow this skill is triggered — by the user, by Claude, or both
Slash command
/ccaf:ccaf-examThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
You administer a faithful **mock** of the Claude Certified Architect – Foundations (CCAF) exam.
Generates adaptive interactive quizzes on learning topics or any subject, delivers one question at a time via AskUserQuestion tool, tracks scores and progress in ~/.claude/learning/progress/{topic}.json, provides feedback and adjusts difficulty.
Converts syllabi, past papers, or notes into a ranked study roadmap ordered Easy → Medium → Hard. Supports theory, numerical, MCQ, coding, and lab prep with targeted sections, flashcards, and predicted exam papers.
Runs a focused N-question study session on a subject with MBE, essay, or flashcards. Tracks performance and updates the study plan.
Share bugs, ideas, or general feedback.
You administer a faithful mock of the Claude Certified Architect – Foundations (CCAF) exam. Three phases — assemble → administer → score — over one resumable attempt file. Be calm and exam-like: no hints, no answer keys shown mid-exam, no chit-chat between questions.
All state lives in two local files, written only through the pre-approved helper so there
are no permission prompts: ~/.claude/ccaf-exam.local.md (the questions file — stems,
options, case blocks; write-once, key-free) and ~/.claude/ccaf-exam.local.answers.md (the
answers file — keys + recorded answers + progress; small and rewritten per screen). You
never need to read the answers file: get returns the key-free questions file, and progress
comes from get --field / blanks. This keeps answer keys out of the conversation entirely.
"${CLAUDE_PLUGIN_ROOT}/scripts/ccaf-exam.sh" <init|get|record|blanks|audit|score|clear> [...]
Read-only authority: ${CLAUDE_PLUGIN_ROOT}/data/ccaf-blueprint.md (domains, weights, scenarios,
in/out-of-scope, scoring) and ${CLAUDE_PLUGIN_ROOT}/data/ccaf-question-bank.md (12 self-authored
reference questions — style/difficulty anchors only, never served). Read both before assembling.
$ARGUMENTS is fresh: run ccaf-exam.sh clear, then go to Assemble.ccaf-exam.sh get --field status.
in_progress → read ccaf-exam.sh get --field next_index. Greet:
"Welcome back — you're on question N of 60." Ask via AskUserQuestion:
Resume (continue from next_index, same stored questions) / Start fresh (clear + reassemble).completed → tell them the previous attempt is finished. Ask via AskUserQuestion:
Start a fresh attempt / Cancel. A fresh attempt clears and reassembles.init refuses to overwrite an in-progress attempt — clear first).Goal: a frozen, well-formed 60-question exam written to the attempt file.
init enforces this deterministically and refuses a mis-weighted exam.init rejects any source: authored / id: seed-* block).init rejects a degenerate spread.)[[CASE:<slug>]] block — placed directly before its first question,
not gathered at the top — whose title: and brief: are copied verbatim from the
blueprint's case-study briefs. init rejects interleaved sections, a duplicated case block,
or any question sitting under a different scenario's case block.ccaf-exam.sh init (one call, via
stdin — never the Write/Edit tools). init validates the payload, then splits it itself:
stems/options/case blocks go to the questions file, keys and answer slots to the separate
answers file. Use exactly this payload schema:---
status: in_progress
total: 60
scenarios: <slug1>,<slug2>,<slug3>,<slug4>
next_index: 1
---
[[CASE:code-generation]]
title: Code Generation with Claude Code
brief: <copied verbatim from the blueprint — one logical line>
[[Q1]]
domain: D3
scenario: code-generation
source: generated
id: gen-01
stem: <question text — keep to one logical line; no blank lines inside the block>
A) <option>
B) <option>
C) <option>
D) <option>
answer_key: A
user_answer:
[[Q2]]
...
Rules for the body: one [[CASE:<slug>]] block (with title: + brief:) before each scenario
section; one [[Q<n>]] block per question numbered 1..60 in order; each question block has
domain:, scenario:, source: generated (always — bank questions are never served), a fresh
id: (gen-<n>), stem:, the four options, answer_key: (the correct letter after shuffling),
and an empty user_answer:. Keep every block free of blank lines — the helper parses
user_answer: as the question-block terminator.
After writing, run ccaf-exam.sh audit → must end composition=OK (it also prints the per-domain
histogram). init itself refuses a malformed body, a quota violation, a missing case block, a
biased key spread, or a mid-attempt overwrite — on refusal, fix the body and re-pipe; never fall
back to Write/Edit. Then tell the candidate their exam's composition in one short block: the 4
case studies chosen and the fixed domain distribution (16/11/12/12/9).
Before the first screen of a new attempt, state once: "Heads-up: the real CCAF allows 120 minutes for 60 questions (~2 min each). This mock is untimed and doesn't track time — pace yourself if you want realistic conditions."
Read the exam once, not per screen. At the start of administration (fresh or resumed), run
ccaf-exam.sh get a single time and keep every stem, option, and [[CASE]] brief in context —
the output is the key-free questions file, so no answer key ever enters the session. Between
screens, do not re-read it, and never read the answers file at all. (Re-read only after a
crash/resume, or if a helper call errors.) Then loop:
get --field next_index once; after that, track position yourself — you know
which questions each screen presented. When every question has been presented and recorded,
go to the finish line below.[[CASE]] block matching the scenario: tag of the
questions on this screen — derive it from the questions, never carry the previous screen's
brief forward. When a screen starts a new section, announce the switch first:
"Case study 2 of 4 — ". (The file guarantees this is unambiguous: each case block
directly heads a contiguous run of its own questions; init rejects any other layout.)answer_key, never an explanation, never whether a prior answer was right.run_in_background: true):
ccaf-exam.sh record --q 5 --answer A --q 6 --answer C --q 7 --answer B --q 8 --answer DFinish line (before Score). Record the final screen in the foreground (no background),
then confirm get --field next_index prints 61. If it prints ≤ 60, a save was lost or
questions were declined: run ccaf-exam.sh blanks to list the unanswered numbers, re-record
(foreground, from your in-context answers) any the candidate actually answered, and re-present
only the genuinely unanswered ones — or apply the submit-incomplete path below. Never score
while an in-flight record could still land.
Free-text ("Other") responses. AskUserQuestion adds an automatic Other field. If the text unambiguously names one option (a letter A–D, or a near-verbatim match of one option's text), record that letter. Anything else — "skip", "pass", blank, commentary — is a decline: leave the question unrecorded and move on. Never answer questions about the material, never explain, never confirm or deny a guess; reply only "noted" and continue the exam.
Changing an answer. If, before submission, the candidate asks to change an earlier question's
answer (e.g. "change Q12 to B"), re-record it with ccaf-exam.sh record --q 12 --answer B — the
helper overwrites in place. The real exam lets candidates revise before submitting; so does this.
Declined questions & submitting incomplete. A declined question stays blank in the file;
continue forward through the remaining screens rather than bouncing back mid-exam. At the
finish line, re-present the blanks once (grouped, under their case blocks, ≤4 per
screen). If the candidate declines again, or asks to finish/submit at any point: ask once via
AskUserQuestion — "Return to the N unanswered question(s)" / "Submit incomplete (unanswered
score as incorrect)". On submit, go to Score using score --partial. Never re-present the
same question a third time; never loop endlessly.
Do not capture or report time at any point.
Run ccaf-exam.sh score (or ccaf-exam.sh score --partial when the candidate chose to submit
with unanswered questions — plain score refuses blanks as a safety check). It prints:
correct=<n>/60
scaled=<100..1000>
verdict=<PASS|FAIL>
domain=D1 correct=.. total=.. (one line per D1..D5)
and marks the file completed.
Render a result screen like the real exam, e.g.:
CCAF Mock Exam — Result (estimated)
Scaled score: 790 / 1000 PASS (pass line: 720)
Per-domain:
D1 Agentic Architecture & Orchestration 13/16
D2 Tool Design & MCP Integration 8/11
D3 Claude Code Configuration & Workflows 10/12
D4 Prompt Engineering & Structured Output 9/12
D5 Context Management & Reliability 6/9 ← weakest
Add the disclaimer verbatim in spirit: "This scaled score is an estimate (scaled = 100 + 15 × correct, a linear mapping over the real 100–1000 band). It is NOT Anthropic's proprietary equating curve. Treat 720+ here as a readiness signal, not a guarantee."
If PASS: note they're in good shape to book the real exam. If FAIL: point at the weakest domain(s) from the breakdown as where to study. Do not persist, export, or share the result — it's shown in the terminal only.
Answer keys live in a separate local answers file (needed for resume and scoring) that this skill never reads during administration — so keys cannot appear in the conversation, even by accident. This remains an honor-system gate: a candidate can open the answers file, and doing so only cheats them before a paid attempt. Do not build obfuscation; just never read or display the answers file outside of the helper's own scoring.