Menu

#133 feat(classifier): compact Apple Intelligence system prompt (SKILL.applefm.md)

closed
nobody
released (243)
2026-06-02
2026-06-02
Anonymous
No

Originally created by: Akarsh-Hegde

Design artifact for KAN-154 — adds one inert prompt file. Nothing loads it yet; the Apple-FM backend that consumes it is the remaining KAN-154 work (gated on #112/#114/#116). Base is main since the file itself is standalone.

What

A standalone, compact classifier system prompt for the Apple Intelligence (on-device FoundationModels) tier — the zero-RAM last-resort backend for Macs too small to run any MLX model. The full SKILL.md (~4.85k tokens) overflows Apple FM's ~4k-token window on its own; this trims to the essentials.

services/skills/activity/task-classifier/SKILL.applefm.md (~4,037 chars):

  • Keeps: 3-step decision tree (overhead/untracked/task), output JSON contract, category taxonomy, a brief prose session_summary spec (~8–12 sentences), hard rules.
  • Drops: the long good/bad examples, the 12-point SDLC checklist, the length table, the scoring tables, and the (Apple-FM-useless) sqlite DB-access section.
  • Used without SYSTEM_CONTEXT (saves ~640 tok; its DB instructions are irrelevant to Apple FM).

Naming

Dot-named SKILL.applefm.md, not the SKILL-<mode>.md pattern — load_skill_addendum(name, mode) matches SKILL-<mode>.md and would append it to the full SKILL.md, reintroducing the exact overflow we're avoiding. This file is a replacement prompt, loaded directly by the (future) Apple-FM backend.

Spike validation (apple_fm_sdk 0.1.x, macOS 26.5)

  • Real sessions classify in-window and return parseable JSON (all 9 fields) via free-form output + lenient parse — the SDK's json_schema structured mode is broken (GenerationError … CodingKeys), so we use the Hermes path's lenient-parse precedent.
  • The cap (recorded on KAN-154): 4096 window − 640 output reserve − ~1,153 system − 256 margin ⇒ ~7,164-char user-message budget, fed to PR [#116]'s build_user_message(char_budget=…).
  • Honest caveat: task/category matching is solid; session_summary is mediocre/variable (the ~3B ceiling) — to be quantified by a goldens eval. Apple FM also raised GuardrailViolationError on some input — the backend must handle refusals gracefully.

Not in this PR (KAN-154 [#3]/#4)

The backend wiring — selector enablement (apple_intelligence=True), a separate apple_fm inference branch in run_task_linker_mlx/server.py, parse-failure/guardrail guards, and an Apple-FM eval strategy — depends on #112/#114/#116 and lands separately. This PR is just the prompt that work will load.

Confirmed runtime settings for the consuming backend (KAN-154 [#3])

A cross-model benchmark on real sessions surfaced two Apple-FM failures that turned out to be missing SDK options, not model limits — both empirically fixed. The backend that loads this prompt MUST apply them:

from apple_fm_sdk import (LanguageModelSession, SystemLanguageModel,
                          SystemLanguageModelGuardrails, GenerationOptions)

# Fix 1 — avoids GuardrailViolationError on real screen OCR (code/errors/etc.)
model = SystemLanguageModel(guardrails=SystemLanguageModelGuardrails.PERMISSIVE_CONTENT_TRANSFORMATIONS)
session = LanguageModelSession(instructions=<SKILL.applefm.md>, model=model)

# Fix 2 — bounds the output reserve so input fits the ~4k window
#          (the unbounded default reservation caused ExceededContextWindowSizeError);
#          temperature=0.0 makes classification deterministic, matching the MLX path
opts = GenerationOptions(temperature=0.0, maximum_response_tokens=640)
result = await session.respond(user_msg, options=opts)

Verified: with these, the two failing sessions (guardrail block + context overflow) both parse, and their verdicts match the MLX models. Still required in the backend: try/except GuardrailViolationError backstop, and post-parse validation that category ∈ taxonomy / task_key ∈ candidates. Full benchmark + analysis on KAN-154.

🤖 Generated with Claude Code

Related

Tickets: #116
Tickets: #3

Discussion

  • Anonymous

    Anonymous - 2026-06-02

    Ticket changed by: adityaharishch

    • status: open --> closed
     
  • Anonymous

    Anonymous - 2026-06-02

    Originally posted by: adityaharishch

    🎉 This PR is included in version 1.17.0 🎉

    The release is available on:

    Your semantic-release bot 📦🚀

     

Log in to post a comment.