Skip to content

adpena/fmtools

Repository files navigation

FMTools

On-device Apple Foundation Models tools with three distinct product surfaces:

  • fmtools: Python toolkit and developer CLI
  • FMRuntime: Swift runtime and FFI layer under runtime/
  • FMChat: standalone local macOS chat app under standalone/fmchat/

This repo is no longer just a single Python framework. The toolkit, runtime, and app share infrastructure, but they are different install paths and should be documented that way.

Requirements

  • macOS 26+ on Apple Silicon
  • Python 3.13+
  • local Foundation Model availability for inference features

Products

fmtools — Python toolkit

The Python toolkit is the main import surface today.

It includes:

  • @local_extract, stream_extract, and pipeline APIs
  • the internal fmtools developer CLI
  • caching, debugging, adapters, Polars, DSPy, and watcher surfaces
  • quality/evaluation workflows such as support-ticket and medical-triage optimization
  • transcript export/resume helpers for backend-portable history workflows

Install:

uv venv --python 3.13 .venv
source .venv/bin/activate
uv pip install -U fmtools
fmtools doctor

If you do not want to activate a virtual environment, use uv run fmtools ... from the repo root instead of assuming fmtools is on PATH.

Local development from this repo:

uv sync --all-groups
uv run fmtools check

FMRuntime — Swift runtime

The runtime package lives under runtime/.

It currently provides:

  • FMRuntimeCore
  • FMRuntimeFFI
  • structured generation over FFI
  • transcript carry-over and resume over FFI
  • runtime availability probing
  • structured runtime error payloads

Build it with:

./scripts/build_fmruntime.sh

FMChat — standalone desktop app

The standalone chat app is a separate product surface.

Install:

brew tap adpena/fmtools https://github.com/adpena/homebrew-fmtools
brew install fmchat
fmchat

Backends

The Python toolkit has a real backend layer now.

Backend Default Status Notes
apple_sdk yes stable Uses the official apple-fm-sdk Python SDK
ffi no advanced Uses the Swift runtime through the compiled dylib

Use the optional runtime path with:

FMTOOLS_BACKEND=ffi uv run python your_script.py

The FFI backend is only selected when the dylib loads and the runtime availability probe succeeds. Otherwise FMTools stays on the official Apple SDK path.

The loader auto-discovers the runtime library only when it exists under runtime/.build/... relative to the repo checkout. If you are using the FFI backend from another location, set FMTOOLS_RUNTIME_LIB=/absolute/path/to/libFMRuntimeFFI.dylib.

Quality Workflows

FMTools now has a dedicated evaluation/optimization layer instead of only demos.

Current shipped verticals:

  • auditor quality review
  • support-ticket extraction
  • medical-triage extraction

Each workflow follows the same loop:

  1. reviewed eval dataset
  2. deterministic metric
  3. DSPy/GEPA optimization
  4. saved artifact
  5. runtime consumption through FMTools helpers

Examples:

uv run python examples/auditor_quality.py
uv run python examples/support_ticket_quality.py
uv run python examples/medical_triage_quality.py

Transcript Workflows

FMTools now exposes transcript helpers at the toolkit layer:

  • export_transcript_dict(session)
  • export_transcript_json(session)
  • resume_session_from_transcript(transcript, *, model=None)

For task-local resumed workflows, use:

from fmtools._context import session_scope_from_transcript

Example:

uv run python examples/transcript_session_workflow.py

Quick Start

import asyncio
import apple_fm_sdk as fm
from fmtools import local_extract


@fm.generable()
class SupportTicket:
    category: str = fm.guide(anyOf=["Billing", "Technical", "Account", "Other"])
    urgency: str = fm.guide(anyOf=["LOW", "MEDIUM", "HIGH", "CRITICAL"])
    summary: str = fm.guide(description="One-sentence summary of the issue")


@local_extract(schema=SupportTicket)
async def classify_ticket(email_text: str) -> SupportTicket:
    """Classify a customer support email by category, urgency, and summary."""


async def main():
    ticket = await classify_ticket("I was charged twice and need a refund immediately.")
    print(ticket.model_dump())


asyncio.run(main())

Developer Commands

uv run fmtools doctor
uv run fmtools test
uv run fmtools check
uv run fmtools example --list
uv run fmtools chat

Docs

Current State

Shipped and usable now:

  • Python toolkit + CLI
  • Swift runtime package + FFI backend
  • FMChat app mirror
  • support-ticket and medical-triage quality workflows

Still in progress:

  • fully separate shipped Swift runtime CLI product
  • fuller docs migration out of the old README style
  • broader optimized verticals beyond support tickets and medical triage

About

Foundation Models toolkit for structured extraction, streaming pipelines, and local AI workflows on Apple Silicon.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors