Run the maclocal-api (AFM/MLX) test suite — automated assertions and smart analysis. Use when asked to test, validate, regression-check, or benchmark AFM before release, after code changes, or for model onboarding.
Instalação
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Run the maclocal-api (AFM/MLX) test suite — automated assertions and smart analysis. Use when asked to test, validate, regression-check, or benchmark AFM before release, after code changes, or for model onboarding.
test-macafm
Run the maclocal-api test suite: automated pass/fail assertions and smart analysis (the smart
suite's AI judge is opt-in — default off; ask the user before enabling it).
Triggers
Use this skill when the user asks to:
Test or validate the server (e.g., "run the tests", "test AFM", "validate the build")
Regression check after code changes
Onboard a new model (verify it works correctly with the server)
Release check before tagging or pushing
Benchmark or profile model performance
First Questions to Ask
Model — Which model to test? (Ask if not specified. Default: whatever's loaded.)
Tier — smoke / standard / full? (Suggest based on context.)
Binary path — Default .build/release/afm. Ask if user has a custom build location.
Port — Default 9998. Ask if user's server is on a different port.
Server running? — Is the server already running, or should tests start it?
Tier Decision Tree
Tier
Time
When to use
What runs
smoke
~2 min
Quick sanity check, any small model, CI
test-assertions.sh --tier smoke
standard
~15 min
After feature changes, mid-size model
test-assertions.sh --tier standard
full
~60 min
Release validation, production model
test-assertions.sh --tier full + mlx-model-test.sh (smart suite; AI judge opt-in — ask the user) with test-llm-comprehensive.txt + promptfoo agentic evals
Quick guide:
"Just run a quick test" → smoke
"Test before merging" → standard
"Full release validation" or "onboard new model" → full
User doesn't specify → suggest standard
Execution Workflow
1. Build Check
# Ensure release build is current
swift build -c release
2. Start Server (if not running)
MACAFM_MLX_MODEL_CACHE=/Volumes/edata/models/vesta-test-cache \
.build/release/afm mlx -m MODEL --port 9998 \
--tool-call-parser afm_adaptive_xml \
--enable-prefix-caching \
--enable-grammar-constraints &
# Wait for server to be readyuntil curl -sf http://127.0.0.1:9998/v1/models >/dev/null 2>&1; dosleep 1; done
Recommended flags for testing:
--tool-call-parser afm_adaptive_xml — best tool call parser with JSON-in-XML fallback
--enable-prefix-caching — 67-79% prompt token savings on repeated requests
--enable-grammar-constraints — EBNF constrained decoding forces valid XML tool calls, improving success from 60% to 100% on realistic workloads
3. Run Automated Assertions
./Scripts/test-assertions.sh --tier TIER --model MODEL --port 9998
Interpret results immediately. If any FAIL, investigate before proceeding.
4. Run Smart Analysis (full tier only)
The smart analysis harness manages its own server (port 9877) — do NOT pass --port.
It uses test-llm-comprehensive.txt which has an [all] baseline prompt and [@ label]
template sections.
The AI judge is OPT-IN — default OFF. By default, run the smart suite WITHOUT an AI
judge: it executes every prompt and records the model's raw outputs to the report for
manual review, with no claude/codex scoring. Before running, ask the user (e.g.
via AskUserQuestion) whether to enable the AI judge — it adds latency/cost and invokes an
external CLI:
"Run the smart suite with an AI judge (claude) scoring each response, or without it
(just record outputs for manual review)? Default: without."
Default — no AI judge (records outputs only; omit --smart entirely):
AFM_BIN=.build/release/afm ./Scripts/mlx-model-test.sh \
--model MODEL \
--prompts Scripts/test-llm-comprehensive.txt
Only if the user opts in — append --smart 1:claude (the --smart flag accepts a batch
mode prefix and tool list):
Smart analysis options (only when the AI judge is enabled):
--smart claude or --smart codex — batch mode 0 (one big swoop, may fail on large test suites)
--smart 1:claude or --smart 1:codex — batch mode 1 (test-by-test, more reliable)
--smart 1:claude,codex — run multiple AI judges
--tests 1,5,10 — run only specific test numbers (1-indexed)
Note: The [all] prompt runs for every test variant. With high max_tokens (e.g., 32768
on code tests), thinking models may generate very long reasoning for the baseline prompt.
Total run time for full suite: ~45-90 min depending on model speed.
5. Run GPU Shader Profile (full tier, or when investigating perf)
Generates an interactive HTML report with measured DRAM bandwidth, GPU utilization/power
timelines, and per-kernel Metal shader names from xctrace Shader Timeline.
One-time setup (creates custom Instruments template with Shader Timeline enabled):
python3 Scripts/create-shader-template.py
Run the profile (no server needed — uses single-prompt mode):
Zero overhead when header not sent (one string lookup per request)
Works for both streaming (SSE event before [DONE]) and non-streaming
What to look for:
gpu_power_peak_w ~28W during decode on M3 Ultra (matches mactop)
est_bandwidth_gbs ~170-180 GB/s for Qwen3.5-35B-A3B-4bit (21% of 800 GB/s theoretical)
Short requests (<300ms): at least 1 sample (timer first-fires at 100ms)
afm_profile absent from response when header not sent (no null pollution)
6. Run Promptfoo Agentic Evals (full tier, or when validating tool calling / structured output)
The promptfoo agentic eval suite tests AFM's tool-calling and structured-output across multiple server configurations and real-world agent framework schemas. It manages its own server lifecycle.
Prerequisites:promptfoo CLI must be installed (npm install -g promptfoo).
Run the full suite:
AFM_MODEL=MODEL \
AFM_BINARY=.build/arm64-apple-macosx/release/afm \
MACAFM_MLX_MODEL_CACHE=/Volumes/edata/models/vesta-test-cache \
./Scripts/feature-promptfoo-agentic/run-promptfoo-agentic.sh all
Run individual suites:
# Just structured output tests
./Scripts/feature-promptfoo-agentic/run-promptfoo-agentic.sh structured
# Just tool calling (all 3 parser profiles)
./Scripts/feature-promptfoo-agentic/run-promptfoo-agentic.sh toolcall
# Just grammar constraint validation (8 server phases)
./Scripts/feature-promptfoo-agentic/run-promptfoo-agentic.sh grammar-constraints
# Just one agent framework
./Scripts/feature-promptfoo-agentic/run-promptfoo-agentic.sh opencode
Known patterns where AI judges score incorrectly (see references/interpreting-scores.md):
Stop sequences truncating output scored as "low quality" — truncation IS the expected behavior
Empty content when stop fires on first visible token — correct behavior
JSON mode not constraining thinking models — prompt injection, not grammar-constrained
"Missing reasoning" when model doesn't support <think> — correct, not a bug
Thinking model consuming entire max_tokens budget on reasoning with empty visible content — model behavior, not a server bug
[all] baseline prompt scored low when it runs with a code/math test's high max_tokens and system prompt — irrelevant context for the baseline prompt
Promptfoo Eval Failures
Category
Typical pass rate
What failures mean
structured, structured-stress
100%
Server bug in response_format pipeline — investigate immediately
toolcall (all profiles)
100%
Server bug in tool call parsing — investigate immediately
toolcall-quality
~80%
Model chose wrong tool or missed when-to-call — model quality, not server
grammar-schema / grammar-tools (non-concurrent)
100%
Grammar constraint enforcement broken — server bug
grammar-schema / grammar-tools (concurrent)
~50-70%
Known race condition in --concurrent 2 grammar path — not release blocker
grammar-header / grammar-mixed
100%
X-Grammar-Constraints header or mixed-strict wiring broken — server bug
agentic
~75-100%
Multi-turn failures are usually model quality; 0% pass = server bug
frameworks
100%
Framework tool shapes must parse correctly — server bug if failing
opencode
~70-80%
Complex 37-tool scenarios; model can't always pick correct tool — model quality
pi
~80-90%
Model prompt injection resistance varies — model quality
openclaw
~80-85%
Model quality on OpenClaw-specific schemas
hermes
~90-100%
Hermes format failures on adaptive-xml profiles = parser difference, not bug
Key rule:structured, toolcall, grammar-* (non-concurrent), frameworks suites should be 100% pass. Any failure there is a server bug. Everything else has model-quality variance.
Post-run failure classification (optional): Run judges/classify-failures.mjs on any result JSON to get AI-based afm_bug vs model_quality vs harness_bug classification.
When to Escalate
SDPA regression: NaN or garbage in long-context tests → check MLX version, see MEMORY.md
Tool call format mismatch: Unknown format → check ToolCallFormat.infer() and model's config.json
Build failure: Vendor patch conflict → run Scripts/apply-mlx-patches.sh --check
Concurrency Benchmark
Full-harness concurrency sweep that starts the server, runs warmup, tests all concurrency levels, collects GPU metrics via mactop, saves JSON results, and generates a comparison chart.
Script
Scripts/benchmarks/benchmark_afm_vs_mlxlm.py
Usage
# AFM-only concurrency sweep (recommended for quick benchmarks)
python3 Scripts/benchmarks/benchmark_afm_vs_mlxlm.py --afm-only
# Full AFM vs mlx-lm comparison (both servers, fair A/B)
python3 Scripts/benchmarks/benchmark_afm_vs_mlxlm.py
# Re-generate graph from existing results
python3 Scripts/benchmarks/benchmark_afm_vs_mlxlm.py --graph
python3 Scripts/benchmarks/benchmark_afm_vs_mlxlm.py --graph Scripts/benchmark-results/FILE.json