Pennyworth — a dignified butler-engineer AI companion you talk to. The open-source core.
Project description
Pennyworth
Pennyworth — a dignified butler-engineer for your codebase. He reads, writes, and reviews code, navigates architecture, runs your terminal, and learns your domain — in the unflappable voice of a proper manservant.
Pennyworth is the open-source project, the Python package, and the assistant you
talk to. His full name is Alfred Pennyworth, the gentleman's butler — but he goes by
Pennyworth. You install the package and run the pennyworth command (alfred still
works as an alias).
Under the hood, Pennyworth drives a host coding agent (the Claude Code CLI by default) with a carefully assembled system prompt — his "brain". Your code, chats, and knowledge stay on your machine.
Why Pennyworth
- 🗣️ A plain-language pair. Ask in English — he explains, writes, reviews, and fixes across your repositories, streaming his reasoning as he goes.
- 🧠 He learns your domain. The Knowledge panel injects your glossary, conventions, and architecture into every turn — no fine-tuning, no code change.
- 🖥️ A real desktop app. A native window with streaming chat, visible extended thinking, an embedded terminal, multi-chat, per-chat model / persona / effort, and custom themes.
- 🦇 He knows your repos. Point him at your repositories; he works in them directly and shows each one's git state at a glance.
- 🧩 Yours to extend. Teachable skills, personas, and MCP tools — and a pack makes him fluent in an entire platform (team, CI, tooling, and all).
- 🔒 Local and private. Your profile, chats, settings, and knowledge live on your machine; nothing is sent anywhere except your own agent.
Quickstart
You need Python 3.11+ and the Claude CLI signed in (claude auth login).
The desktop app is macOS; the command line runs anywhere.
pipx install 'pennyworth-ai[app]' # install Pennyworth, with the desktop app
pennyworth app # launch the app (command is still `pennyworth`)
A window opens to the welcome screen — type a request like "explain this codebase" or "review my changes", and Pennyworth replies. New here? → Getting started.
Prefer the terminal? The command line ships in the same package:
pennyworth "explain this repo" # one-shot, answered in character
pennyworth chat # interactive session
Documentation
- Getting started — prerequisites, install, first run.
- Desktop app tour — every panel, the terminal, models, themes.
- Teach Pennyworth your domain — the Knowledge panel.
- Build a pack — make Pennyworth fluent in your whole platform.
- Architecture — how the brain is assembled, and the one rule.
- Contributing — how to help.
The one rule
The brain is clean by construction. With no pack attached, the assembled prompt
contains zero platform specifics — no platform name, no repository, no teammate, no
tool. Everything a platform contributes flows through its pack and only through its
pack. A test (tests/test_clean_brain.py) enforces it. This is what lets the project
be open while a company's specifics stay in a private pack.
Build a pack
A pack teaches Pennyworth a whole platform — its identity, repositories, team, CI, and
tools. It's a directory with a manifest; see examples/acme for a
complete one.
# pennyworth-pack.toml
[pack]
name = "acme"
platform_name = "the Acme platform"
platform_blurb = "A Python + React monorepo with a REST API and a Postgres store."
[ci]
provider = "GitHub Actions"
host = "https://github.com/acme/acme/actions"
[[repos]]
name = "acme-api"
path = "~/code/acme-api"
description = "The REST API service."
[[hands]] # an MCP tool server Pennyworth operates the platform through
name = "github"
summary = "Pull requests, issues, and CI status."
command = "npx"
args = ["-y", "@modelcontextprotocol/server-github"]
Attach it from the CLI, and detach to return to the generic butler:
pennyworth pack attach ./my-pack
pennyworth pack list
pennyworth pack detach
Each piece fills a seam in the brain — persona, principal, attribution, skills, team, repositories, hands (MCP), CI — and is simply absent when the pack omits it. A pack may be private: open-source core, closed-source pack is a supported shape.
How it fits together
- Core (this repo) — the persona, the prompt assembly, the pack loader, the agent runner, and the surfaces (desktop app + CLI). Platform-agnostic; depends on no pack.
- Packs — what teach Pennyworth a specific platform.
See docs/architecture.md for the design.
Status & roadmap
v0.1.0 — runnable today. The desktop app works end to end: streaming chat with visible thinking, the embedded terminal, per-chat model/persona/effort, configured repositories, the repo-focused Batcave, Claude usage, custom themes, saved chats, and the Knowledge panel. The first-cut pack contract is complete and guarded by the clean-brain test; CI runs lint, format, and the test suite across Python 3.11–3.13.
Honest about the edges: a few panels are graceful stubs — Connectors (MCP management), Scheduled firing, and slash commands — and the desktop app is macOS-only for now. On the roadmap: those stubs and multi-provider support (OpenAI and local LLMs behind the runner seam, alongside Claude).
Contributing
Contributions are very welcome — see CONTRIBUTING.md. Fork,
branch, and open a pull request; sign off your commits (git commit -s) to certify
you wrote the change (a one-line DCO, no CLA).
Good first steps: try the app, file what feels rough, or pick up a roadmap item.
License & credits
Created by Haim Elbaz, with contributions from the Morning R&D team.
Licensed under the Apache License 2.0 — free to use, modify, and
redistribute, including commercially, provided you keep the copyright notice and the
NOTICE attribution. The names "Pennyworth" and "Alfred" and the branding
are reserved — see TRADEMARK.md.
Pennyworth is written in admiration of the classic gentleman's-butler tradition. "Batman", "Alfred Pennyworth", and "Batcave" are trademarks of DC Comics / Warner Bros., referenced here purely as an affectionate homage — this project is independent and not affiliated with or endorsed by them. See TRADEMARK.md.
Copyright © 2026 Haim Elbaz.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pennyworth_ai-0.1.1.tar.gz.
File metadata
- Download URL: pennyworth_ai-0.1.1.tar.gz
- Upload date:
- Size: 1.0 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
61370c3c8e63e354a5ce1c5d4da7e7df535bf2f9f1fd75e0e45cf613977da3f3
|
|
| MD5 |
29f06b0f931b99bbf7741d3c1f6f3227
|
|
| BLAKE2b-256 |
8598766fd9f7a9f6c241c92accc0820edc1441651ca991a63d26e02cf680b506
|
Provenance
The following attestation bundles were made for pennyworth_ai-0.1.1.tar.gz:
Publisher:
release.yml on elbazon/pennyworth
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pennyworth_ai-0.1.1.tar.gz -
Subject digest:
61370c3c8e63e354a5ce1c5d4da7e7df535bf2f9f1fd75e0e45cf613977da3f3 - Sigstore transparency entry: 1941922548
- Sigstore integration time:
-
Permalink:
elbazon/pennyworth@af38349b6429916deb687f68b59d7bbbefa50737 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/elbazon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@af38349b6429916deb687f68b59d7bbbefa50737 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pennyworth_ai-0.1.1-py3-none-any.whl.
File metadata
- Download URL: pennyworth_ai-0.1.1-py3-none-any.whl
- Upload date:
- Size: 1.0 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
63cfd2abb985fd759309f0861becfcb3a62094e46dc59f5bf58f941af0afb020
|
|
| MD5 |
8619f2a3978a5e57a328d132132235d6
|
|
| BLAKE2b-256 |
d6bcfeea6857e7dc7b37682a36a3af226a0b2e5238987d19b277600218378967
|
Provenance
The following attestation bundles were made for pennyworth_ai-0.1.1-py3-none-any.whl:
Publisher:
release.yml on elbazon/pennyworth
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pennyworth_ai-0.1.1-py3-none-any.whl -
Subject digest:
63cfd2abb985fd759309f0861becfcb3a62094e46dc59f5bf58f941af0afb020 - Sigstore transparency entry: 1941922624
- Sigstore integration time:
-
Permalink:
elbazon/pennyworth@af38349b6429916deb687f68b59d7bbbefa50737 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/elbazon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@af38349b6429916deb687f68b59d7bbbefa50737 -
Trigger Event:
push
-
Statement type: