Coolify can't volume-mount local files, so COPY them into the image
at build time. Identity files go to ~/.pocketpaw/identity/ and
paw.yaml goes to ~/paw.yaml for easy import.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rewrite IDENTITY.md and INSTRUCTIONS.md to be concise, human, no em dashes
- Rewrite discord.md behavior layer with message awareness and context rules
- Add paw.yaml soul-protocol config for persistent AI personality
- Enable soul by default in .env.example with import instructions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rewrite IDENTITY.md and INSTRUCTIONS.md to emphasize selective,
low-noise behavior. The bot should default to silence, prefer
reactions over replies, and only participate when it genuinely
improves the conversation. Adds a clear decision order (do nothing,
react, reply, thread) and concrete good/bad examples.
- Add POCKETPAW_CLAUDE_CODE_OAUTH_TOKEN config and pass it through to
the Claude CLI subprocess as CLAUDE_CODE_OAUTH_TOKEN
- Create ~/.claude.json marker file in Dockerfile (fixes "login to
start" prompt even when credentials exist)
- Pre-create ~/.claude dir with correct ownership and set HOME env var
- Document Option E (setup-token) and Option F (interactive login)
in .env.example
Add discord_conversation_all_channels config to enable auto-conversation
in all server channels without needing /converse per channel. Scoped to
allowed_guild_ids so unauthorized servers can't abuse it.
Pin Node.js to 22.14.0 in both Dockerfiles. Upgrade Discord Dockerfile
to full-featured with all extras, Playwright, Codex, and OCR support.
* feat(discord): replace discord.py with discli subprocess adapter
Replace the direct discord.py library dependency with discord-cli-agent (discli),
a subprocess-based adapter that communicates via JSONL over stdin/stdout. This
gives the agent full Discord superpowers: reactions, threads, message search,
DMs, and channel management via the new DiscordCLITool.
- Rewrite DiscordAdapter as DiscliAdapter (subprocess bridge to discli serve)
- Add DiscordCLITool wrapping discli CLI for agent-initiated Discord actions
- Replace discord.py with discord-cli-agent in all pyproject.toml extras
- Update dependency checks in headless.py and dashboard_state.py
- Register discord_cli tool in builtin tools and tool policy
- Rewrite test suite for new adapter API (46 tests passing)
- Update deploy identity/instructions with new capabilities (reactions, threads, search)
* fix(tests): update extras install test for discord-cli-agent
Update test_check_installed_dep assertion from discord.py to
discord-cli-agent to match the dependency change.
* fix(tests): update extras install test for discli module name
* fix(tests): update media attachment tests for DiscliAdapter
* fix(discord): drain stderr and clean up process on startup failure
Two fixes for the dashboard showing stuck "starting" status:
1. Add _drain_stderr() task to continuously read discli's stderr pipe.
Without this, if discord.py logs warnings to stderr the pipe buffer
fills up and the process blocks, preventing the ready event from
being emitted on stdout.
2. Call _on_stop() before raising on startup timeout so the subprocess
and background tasks are properly cleaned up instead of leaking.
* feat(discord): add thread/poll to system prompt and tool description
- Add Discord section to default instructions with thread/poll examples
- Update DiscordCLITool description with thread create and poll create
- Mark /resume target param as optional
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(discord): inject discord.md instructions when on Discord channel
- Create bootstrap/discord.md with full Discord capability docs
(messages, DMs, threads, polls, channels, roles, members, server)
- Context builder loads channel-specific instruction files and injects
them into the system prompt only when on that channel
- Inject discord_username and discord_guild_id from message metadata
so the LLM knows who it's talking to and can DM them
- Pass metadata through from agent loop to context builder
- Remove Discord section from default_provider.py (now in discord.md)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: bump discord-cli-agent dependency to >=0.6.0
Requires v0.6.0 for the complete serve action registry
(threads, polls, DMs, channels, roles, members, server).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(discord): propagate bot token to parent env for CLI tool
DiscordCLITool spawns separate discli processes that need
DISCORD_BOT_TOKEN, but the token was only set in the serve
subprocess env. Now also sets it in os.environ so all child
processes (including discord_cli tool calls) inherit it.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: register DiscordCLITool in tools CLI dispatcher
discord_cli was missing from the CLI registry, so all agent calls
via `python -m pocketpaw.tools.cli discord_cli '...'` failed with
"Unknown tool". This is why the bot couldn't DM, create threads,
or do any Discord operations through the Claude SDK backend.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: background channel startup, CLI auth bypass, converse tests
- Dashboard: start slow adapters (Discord) in background so HTTP
response returns fast; frontend polls until running
- Claude SDK: skip API key check when claude CLI is available
(handles OAuth auth internally)
- Tests: add converse slash command enable/disable tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(discord): add slash commands, user mentions, and admin-gate converse
Add rename/backend/model/tools/delete/backends slash commands to the
Discord adapter, include sender_id in context, document user mention
syntax (<@ID>), restrict /converse to admins, and update /help output.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(security): patch command injection, temp leak, and deprecated API
- DiscordCLITool: replace create_subprocess_shell with
create_subprocess_exec + shlex.split to prevent shell injection
- Clean up slash config temp file on adapter stop
- Use asyncio.get_running_loop() instead of deprecated get_event_loop()
- Convert conversation_channel_ids from list to set
- Scope Claude CLI auth bypass to claude_code provider only
- Add is_admin to converse test events
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(discord): MCP server, permission fix, and system prompt overhaul
- Add pocketpaw-discord MCP server that wraps discli, exposing Discord
operations (send messages, polls, threads, reactions, roles, etc.)
as native MCP tools for all backends (codex_cli, google_adk, etc.)
- Auto-register the MCP server when the Discord adapter starts
- Fix /converse permission check: accept Manage Server in addition to
Administrator, use interaction.permissions (Discord payload) instead
of guild_permissions (member cache) via discli 0.6.4
- Rewrite discord.md system prompt: hide internal tool names from users,
add context-based reaction guidance, keep responses conversational
- Fix [NO_RESPONSE] marker leaking through streaming responses
- Handle rate_limit_event from Anthropic API in stateless query path
- Update docs and CLAUDE.md for discli adapter and MCP integration
- Remove stale /allowchannel /allowuser references from dashboard UI
* fix(dependencies): update discord-cli-agent to version 0.6.4
* style: format discord_server and discord_adapter
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: Discord adapter reply, typing indicator, /kill, and edge cases
- Reply to user messages using message.reply() instead of channel.send()
- Add typing indicator that shows while agent is processing (8s refresh)
- Add /kill slash command to cancel in-flight requests
- Handle stale interaction tokens (15min expiry) with channel.send fallback
- Handle deleted source messages with graceful fallback
- Track buffer overflow to prevent duplicate overflow sends during edits
- Clean up typing/source state on [NO_RESPONSE] discard and stream end
- 10 new tests covering reply, typing, stale interaction, and overflow
* fix: tighten conversation mode and update Discord bot identity
- Update IDENTITY.md with proper PocketPaw project context and role
- Update INSTRUCTIONS.md with explicit [NO_RESPONSE] rules and examples
- Make engaged mode [NO_RESPONSE] prompt much more explicit for weaker models
- Remove overly aggressive "bot in last 3 messages" response trigger
- Bot now only engages when: directly addressed, immediately previous speaker,
or a question is asked with bot active in last 4 messages
* fix: add project links to Discord bot identity
Website, docs, GitHub, issues, Discord invite, and Twitter links
added to both IDENTITY.md and INSTRUCTIONS.md so the bot can
point users to the right resources.
* feat(discord): native Discord UX improvements
- Add thinking reaction (brain emoji) on user message, removed when
response starts streaming
- Slash command autocomplete for /resume (session names), /backend
(registered backends), and /tools (tool profiles)
- Dynamic presence: shows "Helping N users" when actively processing
- Extract large code blocks (>800 chars) as file attachments instead
of pasting inline
- Pass user display name and Discord roles in inbound metadata
- 3 new tests for reactions and code block extraction
* fix(discord): remove hardcoded thinking reaction
Reactions should be contextual/intelligent, not a fixed brain emoji
on every message. Removed all reaction add/remove logic and tests.
* feat(discord): add heuristic emoji reactions in conversation channels
When the bot skips a message (decides not to respond), it now reacts
with contextual emoji based on simple pattern matching:
- Thumbs up for "thanks/ty" (only if bot was the previous speaker)
- Wave for greetings (hi, hey, gm)
- Laugh for lol/lmao/haha
- Party for celebrations (lfg, pog, yay)
- Pensive for sadness (rip, oof, bruh)
- Mind blown for wow/insane/wild
Skips questions to avoid implying the bot will respond. One reaction
max per message. Zero LLM cost, just regex matching.
* revert: remove heuristic reactions, will add agent-driven react tool later