KISS personal assistant agent harness for Discord.
Catty is the project/harness. The actual durable memory, agent name, and personality live in the end-user workspace MEMORY.qmd.
brew install buape/tap/cattyRun Catty once to create the default config and empty workspace memory file, then exit:
cattyCatty creates:
- Config:
~/.catty/config.toml - Workspace:
~/.catty/workspace - Workspace files:
AGENTS.md,MEMORY.qmd
Fill out the generated config, then restart Catty. Memory starts empty for now.
At minimum, set the Discord bot token:
[discord]
token = "your-discord-bot-token"Full config reference: docs/config.md
Catty wraps pi's ChatGPT/Codex OAuth flow, so users do not need to open pi directly.
catty auth loginFollow the printed device-code instructions. Credentials are stored in pi's normal auth store, usually:
~/.pi/agent/auth.json
For launchd/systemd, run catty auth login as the same OS user that runs the service.
cattyNamed agent namespace:
catty --name workThis uses ~/.catty/work/config.toml, ~/.catty/work/workspace, and separate service/log names. Catty does not allow mixing unnamed root ~/.catty/config.toml / ~/.catty/workspace with named default-layout agents; explicit --config plus explicit pi.workspace can opt out. Manage its service with the same name flag:
catty --name work service install
catty --name work service logs --followCustom config path:
catty --config /path/to/config.tomlStart a fresh pi session instead of resuming the latest one:
catty --newCreated under ~/.catty/workspace by default:
AGENTS.md— workspace operating rules.MEMORY.qmd— durable user context, preferences, reusable notes, agent name, and personality; indexed by QMD for memory search/retrieval..gitignore— ignores Catty internal workspace state.- Migration artifacts may be staged under
_migrated/; post-migration side sessions organize durable content intoMEMORY.qmdwithout condensing it. HEARTBEAT.md— optional heartbeat prompt source when enabled.skills/— pi skills..pi/extensions/— pi extensions.
Catty's own harness system prompt is embedded in code at src/prompt.ts.
- By default, one Catty process uses one shared pi session.
- On startup, Catty resumes the most recent pi session for the workspace, or creates one if none exists. Pass
--newto force a fresh pi session. - Discord messages are queued through that one session by default. Set
[pi].channelSessions = trueto give each Discord channel its own persistent pi session and queue so channels can run simultaneously. - Reply context is included when a Discord message replies to another message.
- User-provided Discord content is wrapped in per-message untrusted begin/end blocks before pi sees it.
- Catty uses Discord typing indicators while pi is working instead of sending
Thinking…. - Verbose logs show received Discord messages, the exact prompt sent to pi, pi status/events, and final responses.
- Optional heartbeat prompts run from
HEARTBEAT.mdonly when[heartbeat].enabled = trueis set; they use a dedicated separate in-memory pi session by default unless[heartbeat].session = "main". - The built-in
memorytool uses QMD to update/search/get/append/embedMEMORY.qmd; its local SQLite index lives at.internal/qmd.sqliteinside the workspace. QMD query-expansion and embedding models are predownloaded at startup.
Templates:
- macOS launchd:
services/com.catty.agent.plist - Linux systemd:
services/catty.service
The macOS template assumes the Homebrew binary path and ~/.catty/config.toml. Edit paths before installing it. For multiple service agents, install/manage each one with catty --name NAME service ....
For development services, pass --dev while installing. The generated service runs bun start -- ... from ~/Developer/catty instead of the installed Catty binary:
catty --dev --name work service installFor local development from source:
bun install
bun run typecheck
bun run lint
bun run build
bun run build:binaryGitHub releases and Homebrew tap publishing are tag-driven. See docs/releases.md.