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.
Installation
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
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