GitHub · 项目涌现

Arthur-Ficial/apfel

二〇二六年六月六日·★ 5,263·⑂ 203·Swift·MIT ·最新发布 v1.3.3 · 2026-04-27 · GitHub 原仓库

apfel 是 MIT 许可的 Swift 6.3 工具,将 Apple Silicon Mac 上的 Apple FoundationModels 暴露为 UNIX CLI 和本地 OpenAI-compatible server,支持 `apfel --chat`、tool calling、MCP、本地 4096-token context,要求 macOS 26 Tahoe+、Apple Intelligence,可用 Homebrew 安装。

apfel

Mac 上已有的免费 AI。

版本 1.3.3 Swift 6.3+ macOS 26 Tahoe+ 无需 Xcode 许可证:MIT 100% 端侧运行 网站 #agentswelcome

Apple Silicon Mac 通过 Apple FoundationModels 内置了一个 LLM。apfel 将它暴露为一个 UNIX 工具和本地 OpenAI-compatible server。100% 端侧运行。无需 API key,无需 cloud。

模式 命令 你会得到什么
UNIX 工具 apfel "prompt" / echo "text" | apfel 适合 pipe 的回答、文件附件、JSON 输出、exit code
OpenAI-compatible server apfel --serve 可直接替换使用的本地 http://localhost:11434/v1 backend,适配 OpenAI SDK

apfel --chat - 交互式 REPL。

Tool calling 可在所有上下文中使用。4096-token context。

apfel CLI

要求与安装

macOS 26 Tahoe+、Apple Silicon (M1+)、已启用 Apple Intelligence

brew install apfel

更新:

brew upgrade apfel

从源码构建(带 macOS 26.4 SDK / Swift 6.3 的 Command Line Tools,无需 Xcode):

git clone https://github.com/Arthur-Ficial/apfel.git && cd apfel && make install

Nix、same-day tap、Mint、mise、故障排查:docs/install.md。

快速开始

UNIX 工具

在 zsh/bash 中,带 ! 的 prompt 请用单引号包裹(避免 history expansion):apfel 'Hello, Mac!'

# Single prompt
apfel "What is the capital of Austria?"

# Permissive mode - reduces guardrail false positives for creative/long prompts
apfel --permissive "Write a dramatic opening for a thriller novel"

# Stream output
apfel --stream "Write a haiku about code"

# Pipe input
echo "Summarize: $(cat README.md)" | apfel

# Attach file content to prompt
apfel -f README.md "Summarize this project"

# Attach multiple files
apfel -f old.swift -f new.swift "What changed between these two files?"

# Combine files with piped input
git diff HEAD~1 | apfel -f CONVENTIONS.md "Review this diff against our conventions"

# JSON output for scripting
apfel -o json "Translate to German: hello" | jq .content

# System prompt
apfel -s "You are a pirate" "What is recursion?"

# System prompt from file
apfel --system-file persona.txt "Explain TCP/IP"

# Quiet mode for shell scripts
result=$(apfel -q "Capital of France? One word.")

OpenAI-compatible server

apfel --serve                              # foreground
brew services start apfel                  # background (like Ollama)
brew services stop apfel
APFEL_TOKEN=$(uuidgen) APFEL_MCP=/path/to/tools.py brew services start apfel
curl http://localhost:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"apple-foundationmodel","messages":[{"role":"user","content":"Hello"}]}'
from openai import OpenAI
client = OpenAI(base_url="http://localhost:11434/v1", api_key="unused")
resp = client.chat.completions.create(
    model="apple-foundationmodel",
    messages=[{"role": "user", "content": "What is 1+1?"}],
)
print(resp.choices[0].message.content)

后台服务详情:docs/background-service.md。

快速测试 chat

apfel --chat 是一个用于测试 prompt 或 MCP server 的小型 REPL。GUI chat app 见 apfel-chat

apfel --chat
apfel --chat -s "You are a helpful coding assistant"
apfel --chat --mcp ./mcp/calculator/server.py      # chat with MCP tools
apfel --chat --debug                                # debug output to stderr

Ctrl-C 退出。Context 会自动裁剪(docs/context-strategies.md)。

Demos

demo/ 中的 shell scripts:

cmd - 自然语言转 shell command:

demo/cmd "find all .log files modified today"
# $ find . -name "*.log" -type f -mtime -1

demo/cmd -x "show disk usage sorted by size"   # -x = execute after confirm
demo/cmd -c "list open ports"                   # -c = copy to clipboard

Shell function 版本 - 添加到你的 .zshrc,即可在任何位置使用 cmd

# cmd - natural language to shell command (apfel). Add to .zshrc:
cmd(){ local x c r a; while [[ $1 == -* ]]; do case $1 in -x)x=1;shift;; -c)c=1;shift;; *)break;; esac; done; r=$(apfel -q -s 'Output only a shell command.' "$*" | sed '/^```/d;/^#/d;s/\x1b\[[0-9;]*[a-zA-Z]//g;s/^[[:space:]]*//;/^$/d' | head -1); [[ $r ]] || { echo "no command generated"; return 1; }; printf '\e[32m$\e[0m %s\n' "$r"; [[ $c ]] && printf %s "$r" | pbcopy && echo "(copied)"; [[ $x ]] && { printf 'Run? [y/N] '; read -r a; [[ $a == y ]] && eval "$r"; }; return 0; }
cmd find all swift files larger than 1MB     # shows: $ find . -name "*.swift" -size +1M
cmd -c show disk usage sorted by size        # shows command + copies to clipboard
cmd -x what process is using port 3000       # shows command + asks to run it
cmd list all git branches merged into main
cmd count lines of code by language

oneliner - 用自然语言生成复杂 pipe 链:

demo/oneliner "sum the third column of a CSV"
# $ awk -F',' '{sum += $3} END {print sum}' file.csv

demo/oneliner "count unique IPs in access.log"
# $ awk '{print $1}' access.log | sort | uniq -c | sort -rn

mac-narrator - 你的 Mac 的内心独白:

demo/mac-narrator              # one-shot: what's happening right now?
demo/mac-narrator --watch      # continuous narration every 60s

demo/ 中还有:

更长的 walkthrough:docs/demos.md。

MCP Tool 支持

使用 --mcp 连接 Model Context Protocol server。apfel 会发现、调用并返回结果。

apfel --mcp ./mcp/calculator/server.py "What is 15 times 27?"
mcp: ./mcp/calculator/server.py - add, subtract, multiply, divide, sqrt, power    ← stderr
tool: multiply({"a": 15, "b": 27}) = 405                                          ← stderr
15 times 27 is 405.                                                                ← stdout

使用 -q 可隐藏 tool 信息。

apfel --mcp ./server_a.py --mcp ./server_b.py "Use both tools"
apfel --serve --mcp ./mcp/calculator/server.py
apfel --chat --mcp ./mcp/calculator/server.py

随附一个计算器,位于 mcp/calculator/(docs/mcp-calculator.md)。

Remote MCP servers(Streamable HTTP,MCP spec 2025-03-26):

apfel --mcp https://mcp.example.com/v1 "what tools do you have?"

# bearer token - prefer env var (flag is visible in ps aux)
APFEL_MCP_TOKEN=mytoken apfel --mcp https://mcp.example.com/v1 "..."

# mixed local + remote
apfel --mcp /path/to/local.py --mcp https://remote.example.com/v1 "..."

**安全:**优先使用 APFEL_MCP_TOKEN,不要用 --mcp-token(会出现在 ps aux 中)。apfel 拒绝通过明文 http:// 传输 bearer token。

apfel-run:可选配置层

apfel 本身没有配置文件——像任何 UNIX 工具一样使用 flags + env vars。如果你想要 TOML 配置(多个 MCP、profiles、git 中的团队配置),apfel-run 是一个 MIT wrapper,通过 execve drop-in 添加配置能力。

brew install Arthur-Ficial/tap/apfel-run
apfel-run config init                 # starter ~/.config/apfel/config.toml
alias apfel=apfel-run                 # optional, every apfel flag still works

OpenAI API 兼容性

Base URL: http://localhost:11434/v1

Feature Status Notes
POST /v1/chat/completions 支持 Streaming + non-streaming
GET /v1/models 支持 返回 apple-foundationmodel
GET /health 支持 Model 可用性、context window、languages
GET /v1/logs, /v1/logs/stats 仅 debug 需要 --debug
Tool calling 支持 Native ToolDefinition + JSON detection。见 docs/tool-calling-guide.md
response_format: json_object 支持 System-prompt injection;从输出中剥离 markdown fences
temperature, max_tokens, seed 支持 映射到 GenerationOptions。省略 max_tokens 时使用剩余 context window(可直接替换 OpenAI semantics)- 见 默认响应上限
stream: true 支持 SSE;仅当 stream_options: {"include_usage": true} 时发送最终 usage chunk(按 OpenAI spec)
finish_reason 支持 stop, tool_calls, length
Context strategies 支持 x_context_strategy, x_context_max_turns, x_context_output_reserve 扩展字段
CORS 支持 使用 --cors 启用
POST /v1/completions 501 不支持 legacy text completions
POST /v1/embeddings 501 Embeddings 在端侧不可用
logprobs=true, n>1, stop, presence_penalty, frequency_penalty 400 明确拒绝。n=1logprobs=false 会作为 no-op 接受
Multi-modal (images) 400 拒绝并给出清晰错误
Authorization header 支持 设置 --token 时必须提供。见 docs/server-security.md

完整 API spec:openai/openai-openapi

默认响应上限(max_tokens

省略 max_tokens 时,CLI 和 OpenAI-compatible server 行为一致:该值作为 nil 传递,model 使用 4096-token context window 中剩余的空间。这是可直接替换的 OpenAI semantics——没有任意 fallback constant。

端侧 model 有一个 4096-token context window,input 和 output 合计占用。如果生成触顶,response 会以 finish_reason: "length" 干净结束,并返回 partial content(server:HTTP 200;CLI:exit 0 并在 stderr 给出 warning)。当你希望更严格的 latency budget 或 client 需要已知上限时,请显式传入 max_tokens

示例

# Omitted: uses remaining window, finish_reason: "stop" or "length"
curl -sS http://localhost:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"apple-foundationmodel",
       "messages":[{"role":"user","content":"Reply SKIP, MOVE, or RENAME."}]}'

# Explicit cap (recommended for tight latency budgets)
curl -sS http://localhost:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"apple-foundationmodel","max_tokens":128,
       "messages":[{"role":"user","content":"Summarise: ..."}]}'

如何选择取值

使用场景 max_tokens
单词 / 分类回复 16 - 32
单行指令 64 - 128
短段落 256 - 512
长段落 / 结构化 JSON 1024 - 2048
尽可能用满 context window 省略

input_tokens + max_tokens 舒适地低于 4096。如果 prompt 本身超过窗口,generation 无法开始,请求会以 [context overflow] 失败(HTTP 400 / CLI exit 4)。Validator 会拒绝非正值(max_tokens <= 0)。

CLI 一致性

CLI 和 server 共用一条规则:省略 = 使用剩余窗口。没有可能漂移的常量。可用 --max-tokens NAPFEL_MAX_TOKENS=N 覆盖。

apfel "Reply SKIP."                    # uses remaining window
apfel --max-tokens 64 "Reply SKIP."    # explicit cap
APFEL_MAX_TOKENS=2048 apfel "..."      # via env var

Server 的 permissive guardrails

apfel --serve --permissive 会让 server 对进程处理的每个请求使用 Apple 的 .permissiveContentTransformations guardrails。该 flag 与 CLI 的 --permissive 语义相同(docs/PERMISSIVE.md)。没有 per-request override——由 server operator 为整个进程决定。

apfel --serve --permissive             # every request uses permissive guardrails

限制

约束 详情
Context window 4096 tokens(input + output 合计)
Platform 仅 macOS 26+、Apple Silicon
Model 单一 model(apple-foundationmodel),不可配置
Guardrails Apple 的 safety system 可能会阻止良性 prompt。--permissive 可减少 false positives(docs/PERMISSIVE.md)
Speed 端侧运行,不是 cloud-scale——每次 response 需要数秒
无 embeddings / vision 端侧不可用

参考文档

从 Python、Node.js、Ruby、PHP、Bash/curl、Zsh、AppleScript、Swift、Perl、AWK 使用 apfel 的指南——见 docs/guides/index.md。已通过实测;可运行的证明在 apfel-guides-lab

架构

CLI (single/stream/chat) ──┐
                           ├─→ FoundationModels.SystemLanguageModel
HTTP Server (/v1/*) ───────┘   (100% on-device, zero network)
                                ContextManager → Transcript API
                                SchemaConverter → native ToolDefinitions
                                TokenCounter → real token counts (SDK 26.4)

Swift 6.3 strict concurrency。三个 target:ApfelCore(纯逻辑、可做 unit test,也作为 Swift Package product 提供——见 docs/swift-library.md)、apfel(CLI + server)和 apfel-tests(纯 Swift runner,不使用 XCTest)。

构建与测试

make test                                # release build + all unit/integration tests
make preflight                           # full release qualification
make install                             # build release + install to /usr/local/bin
make build                               # build release only
make version                             # print current version
make release                             # patch release
make release TYPE=minor                  # minor release
make release TYPE=major                  # major release
swift build                              # quick debug build (no version bump)
swift run apfel-tests                    # unit tests
python3 -m pytest Tests/integration/ -v  # integration tests
apfel --benchmark -o json                # performance report

.version 是唯一事实来源。只有 make release 会提升版本。Local build 不会改变版本。

apfel tree

基于 apfel 构建的项目。每个项目都有自己的 repo + Homebrew formula。

Project 作用 安装
apfel 根项目。端侧 FoundationModels CLI + OpenAI-compatible server。 brew install apfel
apfel-chat macOS chat client:streaming markdown、speech I/O、Apple Vision image analysis。 brew install Arthur-Ficial/tap/apfel-chat
apfel-clip 菜单栏剪贴板 AI actions:summarize、translate、rewrite。 brew install Arthur-Ficial/tap/apfel-clip
apfel-quick 即时 AI overlay:按下按键、提问、获得回答、关闭。 brew install Arthur-Ficial/tap/apfel-quick
apfelpad Formula notepad——把端侧 AI 作为 inline cell function。 brew install Arthur-Ficial/tap/apfelpad
apfel-mcp 为 4096 window 做 token budget 优化的 MCP:url-fetchddg-searchsearch-and-fetch brew install Arthur-Ficial/tap/apfel-mcp
apfel-gui SwiftUI debug inspector:request timeline、MCP protocol viewer、TTS/STT。 brew install Arthur-Ficial/tap/apfel-gui
apfel-run UNIX wrapper,在 apfel 之上添加持久 MCP registry + TOML config。 brew install Arthur-Ficial/tap/apfel-run
apfel-server-kit 面向生态工具的 Swift package:发现、启动本地 apfel --serve,并从中 stream。 Swift Package

社区项目

基于 apfel 做了东西?开一个 issue,可以添加到这里。

Project 作用 Links
apfelclaw by @julianYaman 本地 AI agent,通过只读工具读取文件、日历、邮件和 Mac 状态 github - site
fruit-chat by @bhaskarvilles 基于浏览器的 chat UI,通过 OpenAI-compatible API 与 apfel --serve 通信 github
local-claude by @lucaspwo Claude Code wrapper,通过一个小型 Anthropic-OpenAI proxy 将 apfel 替换为本地 backend github
apfeller by @hasit 围绕 apfel 构建的本地 shell apps 管理器 github - site - catalog

贡献

欢迎在任何 Arthur-Ficial/apfel* repo 提 issue 和 PR。

#agentswelcome - 接受 AI agent PR。请阅读 repo 的 CLAUDE.md,运行测试,并在 Co-Authored-By trailer 中标注所用工具。标准与人类相同:代码干净、测试通过、如实说明限制。最适合 agent 上手的入口:apfel-mcp贡献规则)。

License

MIT

译自 GitHub · 项目涌现 · 录于 二〇二六年六月六日