AGENTS / GITHUB / creel
githubinferredactive

creel

provenance:github:Creel-ai/creel
WHAT THIS AGENT DOES

Creel is a secure AI assistant designed to run tasks involving LLMs while keeping sensitive data safe. It separates the process of fetching data requiring credentials from the LLM's processing, preventing unauthorized access. Users can schedule tasks like daily briefings or interact with the agent through a command-line interface or iMessage. Creel's architecture uses isolated containers for each tool, limiting access to only the necessary credentials. This design significantly reduces the risk of data breaches, even if one component is compromised. It's ideal for individuals and organizations needing automated tasks with access to sensitive information. Creel provides a robust and secure way to leverage LLMs for various applications.

PROBLEM IT SOLVES

Creel solves the problem of securely integrating LLMs with tools and credentials, which is often a security risk in traditional agentic LLM systems. Instead of giving the LLM direct access to everything, Creel isolates tools, preventing prompt injection or compromised tools from accessing sensitive data, making it a safer alternative to manual processes or simpler tools.

View Source ↗First seen 3mo agoNot yet hireable

CAPABILITIES & CONSTRAINTS

TECH & STACK
pythonllmsecurityagentclimacosdockeranthropic
README
# Creel

<p align="center">
  <img src="assets/creel-logo.jpg" alt="Creel" width="400">
</p>

A secure LLM task runner and personal AI assistant that separates credential-bearing data fetching from LLM processing. Supports both scheduled tasks (morning briefings, weather summaries) and interactive agent mode (chat via CLI or iMessage with tool calling).

A creel is a wicker basket usually used for carrying fish or blocks of peat. It is also the fish trap used to catch lobsters and other crustaceans.

## Why

Agentic LLM systems give the model access to tools, credentials, and untrusted input all at once. Creel enforces **per-tool isolation** — each executor runs in its own container with only the credentials it needs:

| Component | Has access to | Does NOT have |
|-----------|--------------|---------------|
| Each executor | Only its own credential (one OAuth scope, one API key) | LLM, other tools' credentials |
| Bridge executors | Scoped HTTP token for one macOS app | LLM, other bridge endpoints |
| LLM Runner | Anthropic API key only | Any tool credentials |
| Orchestrator | All secrets, LLM output | Untrusted external input |

Even if prompt injection occurs (e.g., via a calendar event title), the LLM container has nothing to exfiltrate except its own API key. A compromised executor can only access its one scoped credential — not your email, not your files, not your messages.

## Architecture

```mermaid
flowchart TD
    subgraph orch["Orchestrator"]
        direction TB
        schedule["Scheduler / Agent Loop"]
        guardian["Guardian Pipeline"]
        template["Prompt Builder"]
        output["Output Router"]
    end

    subgraph containers["Docker Executors (isolated)"]
        direction TB
        google["Google Suite\n📅 Calendar · 📧 Gmail · 📁 Drive"]
        web["Web Tools\n🔍 Search · 🌐 Fetch · 🌤 Weather"]
        exec["Shell / Exec\n⚙️ Mounted paths only"]
    end

    subgraph bridge["Host Bridge (macOS native)"]
        direction TB
        bridge_api["FastAPI Server"]
        native["📝 Notes · ✅ Reminders\n📋 Things 3 · 💬 iMessage"]
    end

    subgraph llm_container["LLM Container"]
        llm["Claude\n🔑 Anthropic API key only"]
    end

    subgraph channels["Channels"]
        cli["TUI / CLI"]
        imsg["iMessage"]
    end

    channels -- "message" --> orch
    schedule -- "tool call" --> guardian
    guardian -- "approved" --> containers
    guardian -- "approved" --> bridge_api
    bridge_api --> native
    containers -- "JSON result" --> template
    bridge_api -- "JSON result" --> template
    template -- "prompt\n(no secrets)" --> llm
    llm -- "response" --> output
    output --> channels

    style containers fill:#2d333b,stroke:#f47067,stroke-width:2px,color:#f0f0f0
    style bridge fill:#2d333b,stroke:#fd7e14,stroke-width:2px,color:#f0f0f0
    style llm_container fill:#2d333b,stroke:#f47067,stroke-width:2px,color:#f0f0f0
    style orch fill:#2d333b,stroke:#58a6ff,stroke-width:2px,color:#f0f0f0
    style channels fill:#2d333b,stroke:#3fb950,stroke-width:2px,color:#f0f0f0
```

> **Key insight:** Each red box is a separate security boundary. The LLM never sees credentials. Executors only get their own scoped secret. Even a compromised tool can't reach other tools' data.

### Agent Mode

In agent mode, the same security boundary applies — the LLM requests tool calls, but the orchestrator handles secrets injection and executor execution:

```mermaid
flowchart TD
    CH["Channels\nstdin | iMsg | BB"] -- "incoming message" --> SM["Session Manager\n(JSON files)"]
    SM -- "message + history" --> AL["Agent Loop"]
    AL --> LLM["LLM call"]
    LLM --> TU{"tool_use?"}
    TU -- no --> resp["Response"]
    TU -- yes --> EX["Execute via executor\n(secrets injected)"]
    EX --> TR["tool_result"] --> AL
```

Scheduled tasks can also use agent mode by setting `mode: agent` in the task YAML.

### Guardian

The guardian layer screens inputs and validates tool calls before they execute. All stages are optional and independently configurable in `agent.yaml`:

```mermaid
flowchart TD
    A["Incoming message"] --> B["screen_input(text)\n← before session history"]
    B --> FC["FastClassifier\nDeBERTa/ONNX, ~10ms"]
    B --> LJ["LLMJudge\nHaiku, ~300ms, off by default"]
    FC --> blocked{"blocked?"}
    LJ --> blocked
    blocked -- yes --> reject["Return rejection,\nskip agent loop"]
    blocked -- no --> agent["Agent loop → LLM returns tool_use"]
    agent --> VA["validate_action(tool, args)\n← before execute_tool_call"]
    VA --> PE["PolicyEngine\nYAML rules, <1ms"]
    VA --> CC["CoherenceCheck\nHaiku, ~300ms"]
    PE -- allow --> execute["Execute"]
    PE -- review --> approval["Human approval\nor auto_approve"]
    PE -- deny --> err1["Return error to LLM"]
    CC -- coherent --> execute
    CC -- incoherent --> err2["Return error to LLM"]
```

**Stages:**

| Stage | Component | What it does |
|-------|-----------|--------------|
| 1 | Fast classifier | Local DeBERTa model scores prompt-injection likelihood against a confidence threshold |
| 2 | LLM judge | Secondary Haiku-based check (disabled by default) |
| 3 | Policy engine | `fnmatch` rules in `policies/default.yaml` map tool names to allow/review/deny |
| 4 | Coherence check | LLM-based check that tool calls match the user's original intent (catches prompt injection causing unrelated actions) |

**Policy rules** (`policies/default.yaml`):

```yaml
allow:  [check_weather, check_calendar, check_email, read_email, check_drive, check_messages, get_chats, react_imessage]
review: [send_*, upload_*, create_*, mark_*, trash_*]
deny:   [delete_*]

# Tools that match 'review' rules but can skip human approval
auto_approve:
  - mark_read
  - react_imessage
```

Deny wins over review, review wins over allow. Unknown tools default to review. Tools listed in `auto_approve` skip the human confirmation prompt even when matched by a review rule.

**Human-in-the-loop review:** Tools matching `review` rules prompt the user for approval before executing. In the TUI, this appears as an inline confirmation dialog. A configurable timeout (default 60s) denies the action if no response is received.

**Audit logging** writes to `guardian_audit.jsonl` with hashed inputs (never raw text), tool names, arg keys (not values), verdicts, and confidence scores.

**Configuration** in `agent.yaml`:

```yaml
guardian:
  enabled: true
  review:
    timeout_seconds: 60
    default_on_timeout: deny
  fast_classifier:
    enabled: true
    threshold: 0.95
    model_name: protectai/deberta-v3-base-prompt-injection-v2
  llm_judge:
    enabled: false
  coherence:
    enabled: true
    model: claude-haiku-4-5-20251001
    max_tokens: 256
  policy:
    enabled: true
    policy_file: policies/default.yaml
  audit:
    enabled: true
    log_file: guardian_audit.jsonl
```

## Host Bridge

For macOS-specific tools (Apple Notes, Apple Reminders, Things 3, iMessage), Docker containers can't directly execute AppleScript or access macOS applications. The host bridge solves this by running a FastAPI server on the host system that provides authenticated HTTP endpoints for containerized executors.

**Why**: Docker containers are sandboxed and can't access the macOS scripting bridge or application APIs that tools like Notes, Reminders, and Things 3 require.

**How**: A FastAPI server (`python -m bridge.server`) runs as a host process and exposes REST endpoints at `/notes/*`, `/reminders/*`, `/things/*`, and `/imessage/*`. Containerized executors make HTTP requests to these endpoints with scoped authentication tokens.

**Security**: Each executor receives a scoped token that only grants access to its specific tool endpoints. For example, the `apple_notes` executor can only call `/notes/*` endpoints, not `/reminders/*` or `/things/*`.

**CLI Integration**: The bridge server delegates to command-line tools:
- **Apple Notes**: `memo` CLI for reading/writing notes
- **Apple Reminders**: `remindctl` CLI for managing rem

[truncated…]

PUBLIC HISTORY

First discoveredMar 23, 2026

IDENTITY

inferred

Identity inferred from code signals. No PROVENANCE.yml found.

Is this yours? Claim it →

METADATA

platformgithub
first seenFeb 5, 2026
last updatedMar 22, 2026
last crawled2 months ago
version

README BADGE

Add to your README:

![Provenance](https://getprovenance.dev/api/badge?id=provenance:github:Creel-ai/creel)