Creel-ai/creel
GitHub: Creel-ai/creel
一个采用容器级凭证隔离的多层安全架构自托管个人 AI 助手,通过将 LLM 处理与工具执行严格分离来防范提示注入风险。
Stars: 0 | Forks: 0
# Creel
.image` | 是 | 容器化模式的 Docker 镜像 |
| `fetch..secrets` | 否 | age 加密的 .env 文件路径 |
| `fetch..args` | 否 | 传递给执行器的键值参数 |
| `prompt` | 是 | 带有 `{name}` 占位符的提示模板 |
| `output.type` | 是 | `imessage`、`stdout` 或 `file` |
| `output.to` | 是 | 电话号码、空字符串或文件路径 |
| `llm.model` | 否 | Anthropic 模型 ID(默认值:`claude-sonnet-4-20250514`) |
| `llm.max_tokens` | 否 | 最大响应 token 数(默认值:300) |
| `llm.secrets` | 否 | 包含 `ANTHROPIC_AUTH_TOKEN` 或 `ANTHROPIC_API_KEY` 的 age 加密 .env 路径 |
`{date}` 占位符始终可用,并解析为当前日期。
### Agent 模式任务
任务可以通过设置 `mode: agent` 使用 agent 循环进行多步工具调用:
```
# tasks/email_triage.yaml
name: email_triage
schedule: "0 8 * * *"
mode: agent
fetch:
gmail:
image: executor-gmail:latest
secrets: secrets/gmail.env.enc
args:
query: "is:unread newer_than:1d"
tools:
trash_email:
executor: gmail_modify
secrets: secrets/gmail_modify.env.enc
description: "Move an email to trash"
parameters:
message_id:
type: string
description: "Gmail message ID"
required: true
fixed_args:
action: "trash"
agent:
max_turns: 10
prompt: |
Triage my unread emails. Trash spam. Summarize what you did.
{gmail}
output:
type: imessage
to: "$PHONE"
llm:
model: claude-sonnet-4-20250514
max_tokens: 1024
secrets: secrets/anthropic.env.enc
```
Agent 模式任务字段(除标准字段外):
| 字段 | 必需 | 描述 |
|-------|----------|-------------|
| `mode` | 否 | `simple`(默认)或 `agent` |
| `tools` | 否 | 工具名称到工具配置的映射 |
| `tools..executor` | 是 | 要执行的执行器(例如 `gmail_modify`) |
| `tools..secrets` | 否 | age 加密的 .env 文件路径 |
| `tools..description` | 是 | 向 LLM 展示的描述 |
| `tools..parameters` | 否 | LLM 可以提供的参数 |
| `tools..fixed_args` | 否 | 始终传递给执行器的参数(覆盖 LLM 输入) |
| `agent.max_turns` | 否 | 最大 agent 循环迭代次数(默认值:10) |
## Agent 配置
全局 agent 配置(`agent.yaml`)定义了交互式聊天模式的工具、LLM 设置、会话行为、通道、工作区记忆和 Guardian 设置:
```
system_prompt: |
You are a personal assistant. Be concise and helpful.
Today is {date}.
tools:
check_weather:
executor: weather
description: "Get current weather and forecast"
parameters:
location:
type: string
description: "City name or coordinates"
required: true
check_email:
executor: gmail_readonly
secrets: secrets/gmail.env.enc
description: "Search Gmail for emails"
parameters:
query:
type: string
description: "Gmail search query"
required: true
# ... see agent.yaml for all tools (calendar, drive, iMessage, etc.)
llm:
model: claude-sonnet-4-20250514
max_tokens: 1024
secrets: secrets/anthropic.env.enc
agent:
max_turns: 15
session:
sessions_dir: sessions
max_history: 50
summarize_on_trim: true
workspace:
path: workspace
timezone: "America/Denver"
memory_days: 2
memory_max_chars: 5000
max_chars_per_file: 20000
channels:
imessage:
listen_to: "$PHONE"
poll_interval: 3
bluebubbles:
server_url: "$BLUEBUBBLES_URL"
password: "$BLUEBUBBLES_PASSWORD"
listen_to:
- "$PHONE"
poll_interval: 3
```
会话作为 JSON 文件存储在 `sessions/`(gitignored)中,并在交互之间保留对话历史。当启用 `summarize_on_trim` 时,旧消息在被修剪之前会被摘要。
**工作区记忆** 提供跨会话的基于文件的记忆:
- `workspace/memory/YYYY-MM-DD.md` —— agent 的 `remember` 工具写入的每日仅追加日志
- `workspace/MEMORY.md` —— 精选的长期记忆
最近的每日日志和长期记忆会自动注入到系统提示中。
### 静默时段
Creel 支持静默时段,以在配置的时间段(例如夜间、工作时间)内抑制主动通知。静默时段在 `agent.yaml` 中配置,仅抑制出站通知 —— 对用户消息的直接回复永远不会被抑制。
```
quiet_hours:
enabled: true
start: "22:00" # 10 PM
end: "08:00" # 8 AM
timezone: "America/Denver"
```
## 执行器
### 天气
使用 [wttr.in](https://wttr.in) - 不需要 API key。
```
weather:
image: executor-weather:latest
args:
location: denver # city name or coordinates
```
### Google 日历
需要一次性 OAuth 设置:
```
# 1. 创建 GCP project,启用 Calendar API,下载 OAuth credentials
# 2. 运行安装脚本(--encrypt 自动加密并删除明文)
python scripts/setup-google-oauth.py gcal --encrypt
```
执行器使用只读 scope(`calendar.readonly`)并使用 refresh token 进行身份验证。
### Gmail(读取)
读取与 Gmail 搜索查询匹配的电子邮件。支持列出电子邮件和按 ID 读取单个邮件。需要一次性 OAuth 设置:
```
# 同一个 GCP project — 启用 Gmail API
python scripts/setup-google-oauth.py gmail --encrypt
```
执行器使用只读 scope(`gmail.readonly`)。配置:
```
gmail_readonly:
image: executor-gmail-readonly:latest
secrets: secrets/gmail.env.enc
args:
query: "is:unread newer_than:1d" # Gmail search syntax
max_results: "20" # max messages to fetch
message_id: "" # set to read a specific email by ID
```
当按 ID 读取单个邮件时,返回完整的解码(优先使用 `text/plain`,通过 BeautifulSoup 回退到 HTML 剥离)。
### Google 日历(写入)
创建日历事件。需要使用 `calendar.events` scope 进行一次性 OAuth 设置:
```
python scripts/setup-google-oauth.py gcal_write --encrypt
```
配置:
```
gcal_write:
image: executor-gcal-write:latest
secrets: secrets/gcal_write.env.enc
args:
summary: "Team standup"
start: "2025-01-15T09:00:00-07:00" # ISO 8601
end: "2025-01-15T09:30:00-07:00"
description: "Daily sync" # optional
location: "Room 42" # optional
```
### Gmail(发送)
发送电子邮件。需要使用 `gmail.send` scope 进行一次性 OAuth 设置:
```
python scripts/setup-google-oauth.py gmail_send --encrypt
```
配置:
```
gmail_send:
image: executor-gmail-send:latest
secrets: secrets/gmail_send.env.enc
args:
to: "recipient@example.com"
subject: "Daily report"
body: "Here is today's summary..."
```
### Gmail(修改)
修改、删除或永久删除 Gmail 邮件。需要使用 `gmail.modify` scope 进行一次性 OAuth 设置:
```
python scripts/setup-google-oauth.py gmail_modify --encrypt
```
配置:
```
gmail_modify:
image: executor-gmail-modify:latest
secrets: secrets/gmail_modify.env.enc
args:
action: "modify" # modify, trash, or delete
message_id: "18f1a2b3c4d5e6f" # Gmail message ID
add_labels: "STARRED" # comma-separated label IDs (modify only)
remove_labels: "UNREAD,INBOX" # comma-separated label IDs (modify only)
```
### Google Drive(读取)
列出和读取 Google Drive 中的文件。需要使用 `drive.readonly` scope 进行一次性 OAuth 设置:
```
python scripts/setup-google-oauth.py drive --encrypt
```
配置:
```
drive:
image: executor-drive:latest
secrets: secrets/drive.env.enc
args:
query: "mimeType='application/pdf'" # Drive search query (optional)
max_results: "20"
```
### Google Drive(写入)
将文件上传到 Google Drive。需要使用 `drive.file` scope 进行一次性 OAuth 设置:
```
python scripts/setup-google-oauth.py drive_write --encrypt
```
配置:
```
drive_write:
image: executor-drive-write:latest
secrets: secrets/drive_write.env.enc
args:
name: "report.txt"
content: "File contents here..."
mime_type: "text/plain" # optional, defaults to text/plain
folder_id: "" # optional Drive folder ID
```
### BlueBubbles(iMessage)
通过 [BlueBubbles](https://bluebubbles.app/) 服务器发送和读取 iMessage。需要运行中的 BlueBubbles 实例。
```
bluebubbles:
image: executor-bluebubbles:latest
secrets: secrets/bluebubbles.env.enc
args:
action: "get_recent_messages" # get_recent_messages, send_message, send_reaction, get_chats
chat_id: "chat123"
limit: "25"
```
内置安全机制:消息数量硬性上限(50)、消息长度(2000 字符)、发送速率限制(10/分钟)以及收件人白名单强制执行。
### Brave Search
通过 [Brave Search API](https://brave.com/search/api/) 进行网络搜索。
```
brave_search:
image: executor-brave-search:latest
secrets: secrets/brave_search.env.enc
args:
query: "latest news on AI safety"
count: "5" # max 20
```
### Fetch URL
使用 BeautifulSoup 从网页提取文本内容。剥离脚本、导航和样板内容。
```
fetch_url:
image: executor-fetch-url:latest
args:
url: "https://example.com/article"
max_chars: "10000"
```
不需要 API key。
### Apple Notes
通过 host bridge 在 Notes.app 中读取和创建笔记。使用 `memo` CLI 工具进行 macOS 集成。
```
apple_notes:
args:
action: "list_notes" # list_notes, search_notes, read_note, create_note
folder: "Notes"
limit: "25"
```
### Apple Reminders
通过 host bridge 在 Reminders.app 中读取和创建提醒事项。使用 `remindctl` CLI 工具进行 macOS 集成。
```
apple_reminders:
args:
action: "list_reminders" # list_reminders, create_reminder, complete_reminder, get_lists
list_name: "Reminders"
```
### Things 3
通过 host bridge 管理 Things 3 中的任务。使用 `things` CLI 工具进行 macOS 集成。
```
things:
args:
action: "list_tasks" # list_tasks, create_task, complete_task, search_tasks
area: "Personal"
limit: "25"
```
### iMessage Bridge
通过 host bridge 发送和读取 iMessage。使用 `imsg` CLI 工具进行 macOS 集成,提供 BlueBubbles 执行器的替代方案。
```
imessage_bridge:
args:
action: "get_recent" # get_recent, send_message, get_chats
limit: "25"
chat_id: "chat123"
```
### Exec
在具有可配置挂载点和网络隔离的沙盒 Docker 容器中执行 shell 命令。
```
exec:
args:
command: "ls -la /workspace"
workdir: "/workspace"
mounts:
- path: "/Users/user/docs"
target: "/workspace"
mode: "ro"
```
## Google 服务设置
所有 Google 服务使用相同的 OAuth2 客户端凭证(来自单个 GCP 项目的客户端 ID + 客户端密钥),但获取具有不同 scope 的 **独立 refresh token**。这意味着:
- 一个 `client_secret.json` 文件适用于所有服务
- 每个服务有自己的 `.env` 文件(例如 `secrets/gcal.env`、`secrets/gmail_send.env`)
- 每个 refresh token 仅限于单个 API 权限
- 撤销一个 token 不影响其他 token
```
# 一次性设置所有服务(自动加密)
python scripts/setup-google-oauth.py --all
# 或设置特定服务
python scripts/setup-google-oauth.py gmail gcal
# 每次 OAuth 流程后使用 age 加密
python scripts/setup-google-oauth.py gmail --encrypt
# 加密 secrets/ 中所有现有 .env 文件(无 OAuth 流程)
python scripts/setup-google-oauth.py --encrypt-all
```
可用服务:`gcal`、`gcal_write`、`gmail`、`gmail_send`、`gmail_modify`、`drive`、`drive_write`。
## 密钥管理
密钥使用 [age](https://github.com/FiloSottile/age) 进行静态加密。Python 端使用 [pyrage](https://pypi.org/project/pyrage/) 进行解密。
```
# 生成 age 密钥对(一次性)
mkdir -p ~/.age
age-keygen -o ~/.age/key.txt 2> ~/.age/key.pub
# 加密 .env 文件
./scripts/encrypt-secret.sh secrets/anthropic.env
# 解密密钥路径默认为 ~/.age/key.txt
# 通过 AGE_IDENTITY 环境变量覆盖
export AGE_IDENTITY=/path/to/key.txt
```
`.env` 格式支持 `KEY=value`、带引号的值和注释:
```
ANTHROPIC_API_KEY=sk-ant-...
GOOGLE_CREDENTIALS_JSON='{"refresh_token": "...", "client_id": "...", "client_secret": "..."}'
```
## 容器模式
对于生产用途,执行器和 LLM runner 在具有受限功能的隔离 Docker 容器中执行。`--containers` 标志适用于任务运行、调度程序作业和守护程序运行时:
```
# 构建容器镜像
docker build -t executor-weather:latest executors/weather/
docker build -t executor-gcal:latest executors/gcal/
docker build -t executor-gcal-write:latest executors/gcal_write/
docker build -t executor-gmail-readonly:latest executors/gmail_readonly/
docker build -t executor-gmail-send:latest executors/gmail_send/
docker build -t executor-gmail-modify:latest executors/gmail_modify/
docker build -t executor-drive:latest executors/drive/
docker build -t executor-drive-write:latest executors/drive_write/
docker build -t executor-bluebubbles:latest executors/bluebubbles/
docker build -t executor-brave-search:latest executors/brave_search/
docker build -t executor-fetch-url:latest executors/fetch_url/
docker build -t llm-runner:latest llm/
# 使用容器运行任务
creel --containers run morning_briefing
# 带有容器的 Scheduler
creel --containers schedule
# 带有容器化 executors 的 Daemon runtime
creel --containers daemon start
```
容器运行时具有:
- `--read-only` 文件系统
- `--cap-drop=ALL`
- `--security-opt=no-new-privileges`
- 内存和 CPU 限制(`256m`、`0.5` CPU)
- 60 秒超时
- 仅包含每个容器所需的密钥
在守护模式下,agent 循环在主机上运行,而每个工具调用(执行器)在其自己的隔离容器中执行。这保留了信任边界:LLM 永远不会看到凭证,执行器代码在沙盒中运行。
## CLI 参考
```
creel [options]
Commands:
run Run a task immediately
schedule Start cron scheduler for all tasks
list List available tasks
validate Validate a task YAML file
daemon ... Manage daemon lifecycle (start|stop|status|install|uninstall)
attach Attach TUI client to running daemon
send Send one message via daemon API
audit Query the guardian audit log
Global options:
-v, --verbose Enable verbose/debug output
--containers Run executors/LLM in Docker containers (all commands)
--tasks-dir PATH Tasks directory (default: tasks/)
--agent-config PATH Path to agent.yaml (default: agent.yaml)
--json-logs Output structured JSON log lines (for production)
--no-judge Disable the LLM judge to save API calls during development
Run options:
--dry Render prompt only, skip LLM and output
Daemon start options:
--socket-path PATH Unix socket path (default: ~/.creel/daemon.sock)
--pid-file PATH PID file path (default: ~/.creel/daemon.pid)
--log-file PATH Daemon log file (default: ~/.creel/daemon.log)
--channel TYPE Channel plugin: none, imessage, bluebubbles
--no-scheduler Disable scheduler in daemon runtime
--label NAME launchd label (default: com.creel.daemon)
--plist-path PATH launchd plist path
Attach options:
--sender-id ID Sender ID/session namespace (default: cli)
--new Start and attach to a new session
--resume ID Attach and resume a specific session
--socket-path PATH Unix socket path (default: ~/.creel/daemon.sock)
Send options:
--sender-id ID Sender ID/session namespace (default: cli)
--session-id ID Resume and send into a specific session
--socket-path PATH Unix socket path (default: ~/.creel/daemon.sock)
--stream Stream response events from daemon SSE endpoint
Audit options:
--tail N Show last N entries (default: 20)
--all Show all entries
--blocked Show only blocked input events
--denied Show only denied action events
--event TYPE Filter by event type (screen_input, validate_action, tool_result)
--tool NAME Filter by tool name
--since DATE Show entries since date (YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS)
```
## OpenClaw 迁移脚本
使用迁移脚本将 OpenClaw 工作区/配置/历史导入此仓库。
```
# 完整 dry-run(默认阶段 1-2)
python scripts/migrate-openclaw.py --source /path/to/openclaw
# Apply migration
python scripts/migrate-openclaw.py --source /path/to/openclaw --apply
# 显式包含 skills migration(阶段 3)
python scripts/migrate-openclaw.py --source /path/to/openclaw --phases 1,2,3 --apply
# 仅运行一个阶段
python scripts/migrate-openclaw-phase1.py --source /path/to/openclaw --apply
python scripts/migrate-openclaw-phase2.py --source /path/to/openclaw --apply
python scripts/migrate-openclaw-phase3.py --source /path/to/openclaw --apply
```
关键标志:
- `--phases 1,2` 选择要运行的阶段(阶段 3 是可选的)
- `--apply` 写入文件(不加此项为 dry-run)
- `--overwrite/--no-overwrite` 文件冲突行为
- `--apply-agent-config` 将合并的 `agent.migrated.yaml` 写回 `agent.yaml`
- `--report-json ` 写入机器可读的迁移报告
## 项目结构
```
creel/
├── agent.yaml # Global agent config (tools, channels, sessions, guardian)
├── pyproject.toml
├── tasks/ # Task definitions (YAML)
├── policies/ # Guardian policy rules
├── secrets/ # Encrypted .env files (gitignored)
├── scripts/ # Utility scripts (encryption, OAuth setup)
├── src/
│ ├── creel/
│ │ ├── cli.py # creel CLI entrypoint
│ │ ├── daemon/ # Daemon service, API, client contracts
│ │ ├── chat.py # Agent/session router
│ │ ├── tui.py # Textual TUI client
│ │ ├── scheduler.py # APScheduler integration
│ │ ├── session.py # JSON file-backed conversation sessions
│ │ └── channels/ # iMessage + BlueBubbles channel plugins
│ ├── bridge/
│ │ └── server.py # Host bridge HTTP API for macOS-native tools
│ ├── executors/ # Tool executors (weather, Google, Notes, etc.)
│ ├── guardian/ # Prompt-injection + policy protection pipeline
│ └── llm/ # Containerized LLM runner
├── tests/
├── approvals/ # Pending approval queue (gitignored)
└── workspace/ # Agent workspace memory (gitignored)
```
## 开发
需要 [pyenv](https://github.com/pyenv/pyenv) 和 [uv](https://github.com/astral-sh/uv)。
```
# 首次设置
pyenv install 3.12.12 # .python-version pins this
uv venv # creates .venv using pyenv's Python
source .venv/bin/activate
uv pip install -e ".[dev]"
# 启用共享 git hooks(pre-commit 时运行 ruff lint + format)
git config core.hooksPath scripts/hooks
# 可选:live ONNX export + classifier smoke tests 所需
uv pip install -e ".[guardian]"
# 运行测试
pytest
```
标签:AI 代理, Anthropic, CIS基准, CLI 工具, CNCF毕业项目, DLL 劫持, DNS 反向解析, Docker, iMessage 集成, Python, Web报告查看器, 个人助理, 人工智能, 任务编排, 任务自动化, 凭证隔离, 大语言模型, 安全代理, 安全防御评估, 容器隔离, 提示注入防御, 无后门, 智能体安全, 最小权限原则, 沙箱技术, 源代码安全, 用户模式Hook绕过, 端侧 AI, 网络安全, 自托管, 请求响应过滤, 请求拦截, 逆向工具, 隐私保护, 零信任架构, 零日漏洞检测