PoCo: pocket coding for server-side AI agents through mobile messaging entrypoints.
Project description
PoCo
PoCo is a Python-first scaffold for driving server-side coding agents from chat surfaces (Feishu today, Slack since this release). Projects, workspaces, sessions, and tasks all live in PoCo; the chat bot is a thin interactive front-end for them.
Supported Platforms
- Feishu — DM control plane + per-project group chat, over webhook or long connection (
longconn, default). - Slack — DM control plane + per-project channel, over Socket Mode (default) or HTTP webhooks. Slash command
/pocoopens the same project-list card the DM surface renders.
Both platforms run simultaneously when configured. Every Task / Project remembers which platform it was created from, and replies are routed back to the originating surface by PlatformRoutingTaskNotifier.
Supported Agent Backends
codex(default) — runs throughcodex app-serverover stdio; streams realagentMessage/deltaevents into task cards.claude_codecursor_agentcoco(Trae CLI)stub— local flow validation only.
Backend per project is picked from the DM project-creation card. Environment variables are server-side defaults only.
Quick Start
python3 -m pip install -e .
poco config # interactive prompt for Feishu credentials
poco start
poco status
poco config writes ~/.poco/poco.config.json. Environment variables override file values at runtime. To run with no chat platform at all (just the HTTP demo surface and agent runner), skip poco config and start directly:
poco start
curl http://127.0.0.1:8000/health
/health explicitly lists what is missing for each platform.
Configuration
PoCo reads config from three layers, in decreasing precedence:
POCO_*environment variables- Flat keys in
~/.poco/poco.config.json(same name as the env var) - Sectioned keys in the same file, e.g.
{"feishu": {"app_id": "..."}, "slack": {"bot_token": "..."}}
Feishu
| Key | Purpose |
|---|---|
POCO_FEISHU_APP_ID / POCO_FEISHU_APP_SECRET |
Required to enable the Feishu integration. |
POCO_FEISHU_DELIVERY_MODE |
longconn (default) or webhook. |
POCO_FEISHU_VERIFICATION_TOKEN |
Optional webhook token. Lowers friction when unset, lowers security too. |
POCO_FEISHU_ENCRYPT_KEY |
Enables signature validation on webhook callbacks. Encrypted payload bodies are not supported yet. |
POCO_FEISHU_API_BASE_URL |
Defaults to https://open.feishu.cn. |
Long-connection mode authenticates inbound events via the long-connection session itself and routes both message events and card callbacks over the same listener. Callback token/signature settings only apply to webhook delivery.
Slack
| Key | Purpose |
|---|---|
POCO_SLACK_BOT_TOKEN |
xoxb-… bot token. Required. |
POCO_SLACK_SIGNING_SECRET |
Required for HTTP webhook signature verification. |
POCO_SLACK_APP_TOKEN |
xapp-… app-level token. Required when POCO_SLACK_DELIVERY_MODE=socket. |
POCO_SLACK_DELIVERY_MODE |
socket (default) or webhook. |
Slack is considered enabled when bot token + signing secret (+ app token, for socket mode) are all set. /poco slash command posts the project-list card as an ephemeral reply.
Agent backend (server-side)
Minimum:
export POCO_AGENT_BACKEND="codex"
export POCO_CODEX_COMMAND="codex"
export POCO_CODEX_WORKDIR="/absolute/path/to/your/repo"
Optional per-backend tuning:
# Codex
export POCO_CODEX_MODEL="gpt-5"
export POCO_CODEX_SANDBOX="workspace-write"
export POCO_CODEX_APPROVAL_POLICY="never"
export POCO_CODEX_TIMEOUT_SECONDS="900"
export POCO_CODEX_TRANSPORT_IDLE_SECONDS="1800"
# Claude Code
export POCO_CLAUDE_COMMAND="claude"
export POCO_CLAUDE_WORKDIR="/absolute/path/to/your/repo"
export POCO_CLAUDE_MODEL="sonnet"
export POCO_CLAUDE_PERMISSION_MODE="default"
export POCO_CLAUDE_TIMEOUT_SECONDS="900"
# Cursor Agent
export POCO_CURSOR_COMMAND="cursor-agent"
export POCO_CURSOR_WORKDIR="/absolute/path/to/your/repo"
export POCO_CURSOR_MODEL="auto"
export POCO_CURSOR_MODE="default"
export POCO_CURSOR_SANDBOX="default"
export POCO_CURSOR_TIMEOUT_SECONDS="900"
# Trae CLI (coco)
export POCO_COCO_COMMAND="traecli"
export POCO_COCO_WORKDIR="/absolute/path/to/your/repo"
export POCO_COCO_MODEL="GPT-5"
export POCO_COCO_APPROVAL_MODE="default"
export POCO_COCO_TIMEOUT_SECONDS="900"
State backend
export POCO_STATE_BACKEND="sqlite" # default
export POCO_STATE_DB_PATH="~/.poco/poco.db"
SQLite is the default runtime path. It persists projects, workspace context, sessions, and tasks so a restart does not lose group/workspace bookkeeping.
Interaction Model
- DM: control plane.
Newcreates a project and its bound group;Managelists projects and exposes delete. DM inbound messages always render the project-list card. - Group: workspace card with
Stop/Working Dir/Agentactions, plus plain-text task submission.Working Dirselection (folder browse, manual entry, recent directories, and project-level presets) stays inside cards.Agentopens a dedicated selection card.
Group behavior:
- Plain text in a bound group is a task prompt.
- Tasks in a project run in a single-project queue — a new message is queued while another task is still active.
- Codex groups persist the upstream thread id and resume it via
codex app-server, so follow-up messages continue the same Codex conversation. - Task cards show bracketed status in the title (e.g.
[Running] Task: … (codex, /srv/api)), and live-stream throttled agent output. - Waiting task cards expose
Approve/Reject; later state transitions update the same card in place before falling back to a new message. - Workspace cards are refreshed when the latest task changes and keep a bound
message_idacross updates.
HTTP Surface
Core endpoints:
| Path | Purpose |
|---|---|
GET /health |
Runtime readiness + missing/warn summary for both platforms. |
GET /tasks, GET /tasks/{task_id} |
Raw task state. |
GET /debug/feishu, GET /debug/slack |
Recent inbound events, outbound attempts, errors, listener snapshot for the respective platform. |
GET /debug/env |
Presence/length of whitelisted env keys (no values are returned). |
Feishu endpoints:
POST /platform/feishu/eventsPOST /platform/feishu/card-actions
Slack endpoints:
POST /platform/slack/events(JSON body,X-Slack-Signatureverified)POST /platform/slack/interactive(form-encodedpayload=…)POST /platform/slack/commands(form-encoded slash command)
Demo endpoints (platform-agnostic):
POST /demo/command—{"text":"/run …"}POST /demo/tasks/{task_id}/approvePOST /demo/tasks/{task_id}/rejectGET /demo/cards/dm/projectsPOST /demo/card-actions
Supported text commands
In a bound project group, any plain text is treated as a task prompt. The explicit commands are still accepted:
/run <prompt>— start a task./status <task_id>/approve <task_id>//reject <task_id>/help
If the prompt starts with confirm:, the stub runner and the Codex backend pause at a confirmation checkpoint; /approve <task_id> resumes.
Local Demo Example
Without any chat platform configured:
curl -X POST http://127.0.0.1:8000/demo/command \
-H 'Content-Type: application/json' \
-d '{"text":"/run Reply with exactly: DEMO_OK"}'
curl http://127.0.0.1:8000/tasks/<task_id>
Approval flow:
curl -X POST http://127.0.0.1:8000/demo/command \
-H 'Content-Type: application/json' \
-d '{"text":"/run confirm: Reply with exactly: APPROVED"}'
curl -X POST http://127.0.0.1:8000/demo/tasks/<task_id>/approve
CLI
poco config # interactive Feishu credential prompt
poco start # starts uvicorn in the background, pid in ~/.poco/poco.pid
poco status # pid + /health summary
poco restart
poco shutdown
Manual fallback:
uvicorn poco.main:app --reload
Packaging
python3 -m pip install build
python3 -m build
# produces dist/*.whl and dist/*.tar.gz
When published, installation will be:
python3 -m pip install pocket-coding
Debugging Reply Issues
When a chat message does not get a reply, compare /debug/feishu or /debug/slack against the expected flow:
- If there are no recent inbound entries: the platform never reached PoCo (check long-connection/socket-mode listener status under
listener, or the public webhook route). - If inbound entries exist but there are no outbound attempts: PoCo dropped the message (e.g. unbound group, ignored bot message).
- If outbound attempts exist but errors accumulate: the platform rejected the send (scope/permission issues usually).
/health also surfaces listener readiness for both platforms plus the current agent backend readiness.
Project details
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 pocket_coding-0.5.0.tar.gz.
File metadata
- Download URL: pocket_coding-0.5.0.tar.gz
- Upload date:
- Size: 158.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a00cbd2a9332268e3c20cc58517f8578f98aabd8788d6b17c572fc9ba2e0e99a
|
|
| MD5 |
3aa4e4fa735c13ee0d6f367e56ada65d
|
|
| BLAKE2b-256 |
f6404a8417d748fe77408655285e333b6dc26df779a13d1e770686572dff05e9
|
File details
Details for the file pocket_coding-0.5.0-py3-none-any.whl.
File metadata
- Download URL: pocket_coding-0.5.0-py3-none-any.whl
- Upload date:
- Size: 132.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b5a2aa0d6b04ccb8aed74718bc702148471b4bb5908d216bd0db1b286d832412
|
|
| MD5 |
1679e99c09d55bcd4fad0efa20de2cec
|
|
| BLAKE2b-256 |
98574010a10b2152a783bed1bcb32540286dffceb7da1bbc0004b1cb3ea0d520
|