Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Production readiness checklist for AppFolio integrations. Trigger: "appfolio production checklist".
.claude/skills/jeremylongshore-appfolio-prod-checklist/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 85% | 0% |
| case-08 | ✗→✓ | ▲ Improved | -13% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 17% | 0% |
| case-10 | ✗→✓ | ▲ Improved | -11% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 34% | 0% |
AppFolio manages properties, tenants, leases, and work orders for real estate operations. A production integration handles sensitive tenant PII, financial transactions, and maintenance workflows. Failures here mean missed rent collections, unprocessed work orders, or tenant data exposure under CCPA. This checklist ensures your AppFolio API integration is resilient, compliant, and observable.
APPFOLIO_API_KEY stored in secrets manager (not environment files)https://api.appfolio.com/v1)typescriptasync function checkAppFolioReadiness(): Promise<void> { const checks: { name: string; pass: boolean; detail: string }[] = []; const baseUrl = process.env.APPFOLIO_BASE_URL || 'https://api.appfolio.com/v1'; // API connectivity try { const res = await fetch(`${baseUrl}/properties?limit=1`, { headers: { Authorization: `Bearer ${process.env.APPFOLIO_API_KEY}` }, }); checks.push({ name: 'API Connectivity', pass: res.ok, detail: res.ok ? 'Connected' : `HTTP ${res.status}` }); } catch (e: any) { checks.push({ name: 'API Connectivity', pass: false, detail: e.message }); } // Credentials present checks.push({ name: 'API Key Set', pass: !!process.env.APPFOLIO_API_KEY, detail: process.env.APPFOLIO_API_KEY ? 'Present' : 'MISSING' }); // Work order endpoint try { const res = await fetch(`${baseUrl}/work_orders?limit=1`, { headers: { Authorization: `Bearer ${process.env.APPFOLIO_API_KEY}` }, }); checks.push({ name: 'Work Orders', pass: res.ok, detail: res.ok ? 'Accessible' : `HTTP ${res.status}` }); } catch (e: any) { checks.push({ name: 'Work Orders', pass: false, detail: e.message }); } for (const c of checks) console.log(`[${c.pass ? 'PASS' : 'FAIL'}] ${c.name}: ${c.detail}`); } checkAppFolioReadiness();
| Check | Risk if Skipped | Priority | |-------|----------------|----------| | API key rotation | Expired keys halt property sync | P1 | | Payment sync failure | Missed rent collections | P1 | | Tenant PII exposure | CCPA violation, legal liability | P1 | | Work order duplication | Duplicate maintenance dispatch | P2 | | Rate limit handling | 429 errors during bulk property import | P3 |
See appfolio-security-basics for tenant data protection and access control.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-04 | pass→pass | 15,319 | 11,669 | -24% | 1 | 1 | 0% | 2,277 | 2,810 | +23% | 0 | 0 | — |
case-01 | fail→pass | 18,927 | 26,524 | +40% | 1 | 1 | 0% | 3,192 | 5,899 | +85% | 0 | 0 | — |
case-02 | fail→fail | 20,017 | 18,091 | -10% | 1 | 1 | 0% | 3,814 | 4,332 | +14% | 0 | 0 | — |
case-03 | fail→fail | 17,578 | 24,813 | +41% | 1 | 1 | 0% | 3,019 | 5,643 | +87% | 0 | 0 | — |
case-05 | pass→pass | 17,528 | 21,512 | +23% | 1 | 1 | 0% | 3,893 | 5,701 | +46% | 0 | 0 | — |
case-06 | pass→pass | 21,373 | 25,392 | +19% | 1 | 1 | 0% | 5,059 | 7,104 | +40% | 0 | 0 | — |
case-07 | pass→pass | 19,564 | 3,235 | -83% | 1 | 1 | 0% | 1,787 | 1,484 | -17% | 0 | 0 | — |
case-08 | fail→pass | 8,395 | 1,277 | -85% | 1 | 1 | 0% | 1,418 | 1,234 | -13% | 0 | 0 | — |
case-09 | fail→pass | 12,543 | 9,486 | -24% | 1 | 1 | 0% | 2,308 | 2,711 | +17% | 0 | 0 | — |
case-10 | fail→pass | 10,972 | 3,760 | -66% | 1 | 1 | 0% | 1,804 | 1,598 | -11% | 0 | 0 | — |
case-11 | fail→pass | 12,174 | 9,860 | -19% | 1 | 1 | 0% | 1,916 | 2,575 | +34% | 0 | 0 | — |
case-12 | fail→pass | 9,604 | 2,159 | -78% | 1 | 1 | 0% | 1,591 | 1,329 | -16% | 0 | 0 | — |
case-13 | pass→pass | 16,108 | 11,572 | -28% | 1 | 1 | 0% | 2,542 | 2,879 | +13% | 0 | 0 | — |
case-14 | fail→pass | 11,686 | 12,232 | +5% | 1 | 1 | 0% | 1,974 | 3,196 | +62% | 0 | 0 | — |
case-15 | fail→pass | 5,690 | 3,165 | -44% | 1 | 1 | 0% | 1,000 | 1,491 | +49% | 0 | 0 | — |
case-16 | pass→pass | 12,415 | 8,842 | -29% | 1 | 1 | 0% | 2,156 | 2,746 | +27% | 0 | 0 | — |
case-17 | pass→pass | 10,586 | 9,532 | -10% | 1 | 1 | 0% | 1,884 | 2,579 | +37% | 0 | 0 | — |
case-18 | fail→pass | 5,910 | 2,368 | -60% | 1 | 1 | 0% | 926 | 1,395 | +51% | 0 | 0 | — |
case-19 | pass→pass | 6,842 | 2,043 | -70% | 1 | 1 | 0% | 1,163 | 1,265 | +9% | 0 | 0 | — |
case-20 | pass→pass | 10,861 | 4,602 | -58% | 1 | 1 | 0% | 1,757 | 1,794 | +2% | 0 | 0 | — |
case-21 | pass→pass | 7,494 | 3,325 | -56% | 1 | 1 | 0% | 1,255 | 1,447 | +15% | 0 | 0 | — |
case-22 | pass→pass | 12,918 | 3,738 | -71% | 1 | 1 | 0% | 2,016 | 1,573 | -22% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +41 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.