Skip to content

Derrick

A native Swift macOS desktop agent: chat, just-in-time software (plugins), messaging connectors, scheduled jobs, and human-in-the-loop approvals. Agent work runs in a headless daemon; untrusted code runs in Docker.

License: Apache 2.0

What it does

Area Description
Chat Multi-tab conversations with OpenAI, Gemini, and other configured models. Talk to a named agent profile with $shortName when you want that profile; a mention of the name is not enough.
Just-in-time software Describe the software you need. Derrick builds, reviews, and installs a versioned plugin for that moment — a connector, a skill, or a one-shot tool — instead of shipping a catalog of pre-written apps.
Messaging Installed connectors open as Chat tabs. The host renders the plugin's ui.present tree (default messaging_inbox or a custom HostUI layout). Connectors without a screen are rejected.
Jobs Scheduled and deferred runs that continue after you quit the app.
Tools (MCP) Model Context Protocol tools hosted in the daemon for chat turns.
Scripts Agent-written Go, compiled and run in isolated Docker containers, with a reviewer and approvals.
Policy & HITL Approvals for tools, network access, usage limits, and connector credentials.

Architecture

┌───────────────────────────────────────────────────────────────────┐
│  Derrick.app (UI) — SwiftUI client only                           │
│  Chat · Messaging · Just-in-time software · Settings · Approvals  │
└────────────────────────────────┬──────────────────────────────────┘
                                 │ Mach XPC (signed messages)
┌────────────────────────────────▼──────────────────────────────────┐
│  derrickd (JobKeepAlive Login Item)                               │
│  Agent turns · Job scheduler · MCP tool host · Notifications      │
└───────────────┬─────────────────────────────────┬─────────────────┘
                │ in-process              │ XPC
        ┌───────▼────────┐        ┌───────▼──────────────────┐
        │ SQLite (WAL)   │        │ DockerRunnerHelper XPC │
        │ shared state   │        │ docker CLI + pool      │
        └────────────────┘        └───────────┬────────────┘
                                                │
                                    ┌───────────▼────────────┐
                                    │ Go worker containers     │
                                    │ --network none         │
                                    └────────────────────────┘
  • UI is a client: it does not own agent turns or MCP when the daemon is up.
  • Daemon (derrickd) is the single owner of OS notifications and in-process Agent/Job/MCP modules.
  • Docker runs untrusted Go for script_exec, just-in-time plugin builds, and approved plugin invocations.
  • HostUI (packages/HostUI) paints plugin screens from a declared schema. The host does not invent a default inbox.

See docs/adr-headless-backend.md and docs/services-plan.md.

Security model

Derrick treats model output and guest code as untrusted.

Docker sandbox (Go worker runtime)

  • script_exec, plugins, web crawl, web search, and file extract share one Go worker image derrick-worker:go-v1 (digest-pinned, --network none for guests).
  • Plugin and script sources are compiled inside the worker container (Go 1.27.1 in the image). Users only need Docker Desktop.
  • Canonical I/O types live in packages/Structure/Sources/Contract/Resources/schemas/ and are mirrored to workers/go/internal/contract/schemas/.
  • No net/http, subprocess, filesystem access, or credentials inside the guest.
  • The host dispatches http.request envelopes, attaches secrets, and enforces egress policy.
  • Historical Swift guest notes: docs/adr-swift-script-runtime.md.

Script review agent

Before script_exec writes to disk, a configured LLM reviewer checks:

  • Intent alignment with the user request
  • No secret literals in source
  • Safe handling of fetched content (no raw HTML leakage unless requested)

Rules live in packages/Structure/Sources/Contract/Resources/contracts/script-exec-contract.json (same pattern as connector plugins). A static Go verifier also rejects forbidden APIs.

Egress & network

  • Host-owned HTTP (HostHTTPClient) with egress blacklist (persisted in SQLite).
  • New destinations can require user approval (HITL network access modal).
  • Plugins never receive tokens; PluginDeclaredSecretAttacher adds Bearer/Basic headers on the host.

Secrets

Context Storage
LLM API keys (dev) ui/ui/Resources/.env when UI_SECRET_MODE=dotenv
LLM API keys (release) Keychain
Plugin connector tokens Keychain (PluginSecretKeychain) or .env aliases in dev
Inter-service XPC (debug) MESSAGES_SECRET_KEY in .env
Inter-service XPC (release) Keychain (MessagesSecretKey)

Copy .env.examplenever commit .env.

Human in the loop (HITL)

  • Tool execution approvals
  • Network access requests
  • Plugin credential collection (Keychain save)
  • Policy events (usage limits, content sensitivity)

Policy

  • PolicyEngine — in-process tool-call rules for chat (Structure/Policy/PolicyEngine).
  • PolicyRuntime — persisted rules from SQLite (Structure/Policy/PolicyRuntime); implemented by StoreBacked* evaluators in packages/PolicyRuntime.
  • PolicyInterceptor / ToolRequestInterceptor (MemorySystem) — pipeline hooks that call those policies.

Messaging

Connectors are just-in-time software with role: connector. They must emit a HostUI tree (ui.present) — copy messaging_inbox or compose their own. Messages live in SQLite; sync and send still go through the guest. See docs/messaging-design.md.

Repository layout

Path Role
ui/ macOS app, Login Item daemon, XPC services
packages/DBRepository SQLite schema, migrations, messaging tables
packages/MCPServer MCP bridge, script execution, plugin runtime
packages/Structure Architecture map: wire types, protocols, JSON schemas (AppLayerServices/, Policy/, Plugin/, Contract/, …)
packages/HostUI Schema-driven screens for connectors and plugin present trees
packages/Plugin Just-in-time software factory (builder, reviewer, release)
packages/DerrickBackend Daemon runtime, notifications, HITL polling
packages/DockerRunnerXPC Constrained Docker helper
packages/PolicyRuntime Store-backed policy evaluators (Structure/Policy/PolicyRuntime)
packages/LLMAgentClient Provider clients (OpenAI, Gemini, …)

Quick start

Prerequisites

  • macOS 27 with Xcode 27 (Swift 6.4+)
  • Docker Desktop
  • Apple Developer account (for signing entitlements)

Build & run

  1. Clone the repo.
  2. cp .env.example ui/ui/Resources/.env and add your API keys.
  3. (Forks) cp Config/Signing.xcconfig.example Config/Signing.xcconfig and run ./scripts/configure-signing.sh.
  4. Open derrick.xcworkspace, select the ui scheme, Run (⌘R).
  5. Enable secret hooks:
    git config core.hooksPath .githooks

Or from the terminal: ./scripts/build.sh test

See CONTRIBUTING.md and docs/development.md.

Open-sourcing checklist

We maintain docs/opensource-plan.md for pre-release cleanup (secret audit, personal reference removal, CI).

Verify no secrets in git:

./scripts/verify-no-secrets.sh --history

Documentation

Trademark

“Derrick” is the project name used in this repository. Third-party names (OpenAI, Google, Slack, Docker, etc.) are trademarks of their respective owners.

Agent / contributor notes

See AGENTS.md for conventions used by coding agents working in this repo.

About

Native Swift macOS desktop agent harness: LLM chat, MCP tools, Docker-sandboxed scripts, plugins, jobs, and messaging — with human-in-the-loop approvals.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages