PoCo: pocket coding for server-side AI agents through mobile messaging entrypoints.
Project description
PoCo
PoCo is a Python-first MVP scaffold for controlling server-side AI agent workflows from mobile messaging entrypoints.
Quick Start
Install from source:
python3 -m pip install -e .
poco config
poco start
Then verify:
poco status
When published, the install command should be:
python3 -m pip install pocket-coding
Current Scope
FastAPIwebhook service- Feishu-first event gateway
- Optional Feishu long-connection intake for local development
- Feishu callback verification token support
- Feishu tenant access token retrieval and text / interactive card send support
- Card-first interaction scaffolding with platform-neutral dispatcher
- Codex-first agent execution path
- Asynchronous background task dispatch
- Feishu task-state push on confirmation wait and terminal states
- Platform-independent task controller
- In-memory task state store
- Stub fallback runner for flow validation
Local Run
Install CLI
Install PoCo once in editable mode so the poco command is available:
python3 -m pip install -e .
Lowest-Friction Start
If you only want to verify that PoCo itself can run on this machine, you can start with no Feishu credentials at all:
poco start
curl http://127.0.0.1:8000/health
In that mode:
- PoCo runs in local/demo mode
- the agent backend can still be checked
- you can still use the local demo HTTP interface
- Feishu callback handling is not ready yet
The /health response will tell you exactly what is missing.
Local Demo Interface
You can exercise the full command flow without Feishu:
curl -X POST http://127.0.0.1:8000/demo/command \
-H 'Content-Type: application/json' \
-d '{"text":"/run Reply with exactly: DEMO_OK"}'
Check task status:
curl http://127.0.0.1:8000/tasks/<task_id>
Approval flow example:
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
PoCo currently plans to support:
- Codex
- Claude Code
- Cursor Agent
Current implementation priority is Codex, and the default backend is codex.
Normal user-facing setup should not require agent-specific shell configuration. In the intended product flow:
- users only need to configure the Feishu bot and start the PoCo service
- project backend is chosen in the DM project-creation card
- backend-specific settings are changed later through Feishu cards
The environment variables below are only server-side defaults and debugging overrides. They are not part of the intended end-user setup flow.
Minimum server-side agent configuration:
export POCO_AGENT_BACKEND="codex"
export POCO_CODEX_COMMAND="codex"
export POCO_CODEX_WORKDIR="/absolute/path/to/your/repo"
Optional server-side defaults for Codex:
export POCO_CODEX_MODEL="gpt-5.4"
export POCO_CODEX_SANDBOX="workspace-write"
export POCO_CODEX_APPROVAL_POLICY="never"
export POCO_CODEX_TIMEOUT_SECONDS="900"
PoCo now runs the codex backend through codex app-server over stdio, so task cards can consume true agentMessage/delta events instead of waiting for a final exec --json message block.
Optional server-side defaults for 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"
Optional server-side defaults for Cursor Agent:
export POCO_CURSOR_COMMAND="cursor-agent"
export POCO_CURSOR_WORKDIR="/absolute/path/to/your/repo"
export POCO_CURSOR_MODEL="gpt-5"
export POCO_CURSOR_MODE="default"
export POCO_CURSOR_SANDBOX="default"
export POCO_CURSOR_TIMEOUT_SECONDS="900"
Use POCO_AGENT_BACKEND=stub only for local flow validation without a real agent backend.
PoCo now supports codex, claude_code, and cursor_agent. coco is still recognized as planned but not implemented yet.
Normal User Flow
The intended startup path is now:
poco config
poco start
poco config prompts for:
- Feishu App ID
- Feishu App Secret
PoCo stores them in a local user config file under ~/.poco/poco.config.json, so normal users do not need to export shell variables.
PoCo now defaults to Feishu longconn, so the normal local/mobile-first path does not require setting an inbound delivery mode explicitly. Only set POCO_FEISHU_DELIVERY_MODE if you intentionally want to force webhook.
Useful lifecycle commands:
poco status
poco shutdown
poco restart
Packaging
Build release artifacts locally:
python3 -m pip install build
python3 -m build
This produces:
dist/*.whldist/*.tar.gz
Advanced server-side overrides only:
export POCO_FEISHU_API_BASE_URL="https://open.feishu.cn"
export POCO_FEISHU_VERIFICATION_TOKEN="xxx"
export POCO_FEISHU_ENCRYPT_KEY="xxx"
export POCO_STATE_BACKEND="sqlite"
export POCO_STATE_DB_PATH="/absolute/path/to/poco.db"
Notes:
POCO_FEISHU_VERIFICATION_TOKENis optional in the current MVP. Leaving it unset reduces setup friction, but also lowers webhook security.- If
POCO_FEISHU_ENCRYPT_KEYis configured, the service expects Feishu signature headers and validates them. - Encrypted callback payload bodies are not supported yet, so keep event encryption disabled for the current MVP.
longconnis now the default inbound mode and removes the need for public inbound webhook access during local development.- The current long-connection implementation now handles both
im.message.receive_v1and card callback traffic for local/mobile-first operation. - Callback token/signature settings apply to webhook delivery. Feishu long-connection inbound events are authenticated by the long-connection session itself.
POCO_STATE_BACKEND=sqliteis now the default runtime path. PoCo persists projects, workspace state and tasks so restart does not lose existing group/workspace tracking.POCO_STATE_DB_PATHdefaults to~/.poco/poco.db.
Manual fallback start:
uvicorn poco.main:app --reload
Health check:
curl http://127.0.0.1:8000/health
The health response now includes:
- current runtime mode:
localorfeishu - chosen Feishu delivery mode:
webhookorlongconn - chosen agent backend and whether it looks ready
- whether the Feishu long-connection listener is actually ready
- which state backend is in use
- whether Feishu callback token verification is enabled
- whether Feishu signature validation is enabled
- what is still missing
- warnings about relaxed safety settings
Card Demo Interface
You can now exercise the first DM card chain locally:
curl http://127.0.0.1:8000/demo/cards/dm/projects
Create a project through the demo card-action endpoint:
curl -X POST http://127.0.0.1:8000/demo/card-actions \
-H 'Content-Type: application/json' \
-d '{
"event": {
"operator": {"open_id": "ou_demo_user"},
"context": {"open_message_id": "om_demo_card"},
"action": {
"value": {
"intent_key": "project.create",
"surface": "dm",
"request_id": "req_demo_project_create_1"
},
"form_value": {
"name": "PoCo",
"backend": "codex"
}
}
}
}'
This currently proves the first card chain:
- DM card action payload ->
ActionIntent - dispatcher -> project handler
IntentDispatchResult-> render instruction- renderer -> card response payload
Real Feishu DM bootstrap is now also wired:
- when PoCo receives a DM message event from Feishu
- it replies with a real Feishu card JSON 2.0 project-list card
- the project-list card now contains real callback buttons such as
Create Project + Group Create Project + Groupnow creates the project and, in real Feishu mode, bootstraps a dedicated group chat in the same action- after the group is created, PoCo also posts the first workspace overview card into that group
- opening a project in DM now lands on a
Project Configcard instead of a bare detail card - current group chats still keep the text-command fallback path
That means the current interaction split is:
DM: control-plane card bootstrap and first project-management actionsGroup: first workspace overview card plus text-command task fallback
Notes about project bootstrap:
- in real Feishu mode,
project.createnow calls the Feishu group-create API and binds the returnedchat_idto the new project - after binding the group, PoCo best-effort posts the first workspace overview card into the new group
- if group bootstrap fails, PoCo rolls the project creation back instead of leaving a half-created project behind
- in local/demo mode without Feishu credentials,
project.createstill works, but no group is created
Feishu Debug Snapshot
When Feishu messages do not get any reply, inspect:
curl http://127.0.0.1:8000/debug/feishu
It shows:
- recent inbound Feishu callbacks
- the reply target PoCo selected for each callback
- recent outbound send attempts, including DM card sends
- recent Feishu send errors
- current long-connection listener status
This is the fastest way to tell whether the problem is:
- Feishu never called PoCo
- PoCo picked the wrong reply target
- PoCo tried to send but Feishu rejected the request
Real Feishu callbacks should target:
POST /platform/feishu/events
Card action callbacks should currently target:
POST /platform/feishu/card-actions
Current interaction model:
- DM messages currently bootstrap a compact home card instead of returning text help
- DM home cards now expose only
NewandManage - DM
Newnow uses a pure-card form to collectproject name, then creates the project and group before returning to the DM home card - DM
Managenow focuses on destructive admin actions; projects can be deleted there without opening a project detail card first, and deletion now cascades through local project state in sqlite/in-memory stores - newly created project groups now receive an initial workspace overview card
- group workspace and task cards now keep
Working Dirselection inside Feishu cards, with both folder browsing and manual path entry - group workspace cards are now intentionally compact: workspace metadata is collapsed into the title, and the body keeps only
Stop,Working Dir, andAgent Agentnow opens a dedicated agent-selection card; applying agent settings returns to the main workspace card- working dir selection now stays inside Feishu cards; no browser page is required
Use Defaultnow updates the in-memory workspace context and becomes the first real write path for group-side workdir stateEnter Pathnow updates the same in-memory workspace context and becomes the second real write path, using manual source- DM
Manage Dir Presetscan now add project-level presets, and groupChoose Presetcan apply them into the current in-memory workspace context - Group text
/runnow resolves the bound project and current workspace workdir, then stamps that into task execution context - Bound group workspaces now also treat ordinary plain-text messages as task prompts by default
- Bound group workspaces now run tasks in a single-project queue: if one task is still active, the next message is queued instead of starting a parallel Codex run
- codex-backed groups now persist the upstream Codex thread id and resume it through
codex app-server, so follow-up messages continue the same Codex conversation instead of starting from a blank context - Group text-created tasks now reply with a single initial
task_statuscard, and later live/terminal updates stay on that same card - Codex execution now prefers the task's
effective_workdirover the global fallback directory - group card
task.submitnow reuses the same task-execution path and inherits the current workspace workdir task.submitnow replaces the current composer card with atask_statuscard and binds that message to the task flow- The webhook request returns quickly after acknowledging the command
- Task execution happens in a background dispatcher
- When a task waits for confirmation, completes, fails, or is cancelled, PoCo now pushes a
task_statuscard to the stored Feishu reply target - Waiting task cards now include
Approve/Rejectactions that resume or cancel the task through card callbacks - Once a task status card has been sent, later task-state notifications now try to update that same card in place before falling back to a new message
- workspace cards now keep a bound message id and will also be refreshed with latest-task changes when task state changes
- task status cards now prefer the agent's raw result over summary text, and long results are paginated instead of being replaced by a summary
- task status cards now collapse task id, status, agent and effective workdir into the title; the body is reserved for model output or confirmation text instead of duplicated metadata
- task status titles now lead with bracketed status, for example
[Running] Task: ... (codex, no working dir), to keep the scan path tighter on mobile - task and workspace cards now prefer direct action buttons over navigation-only buttons; task cards expose
Stop,Working Dir, andAgentinstead ofBack/Refreshstyle controls - workspace cards no longer try to show latest-result body; the title carries status / agent / workdir / current task, and the body stays action-only
- running task cards now show throttled live output updates from the agent, instead of staying at a coarse
runningstate
By default, PoCo runs with longconn inbound delivery:
- inbound message events arrive over Feishu long connection instead of the webhook route
- DM events can now trigger proactive project-list card sends
- group events still reuse the same
InteractionService -> TaskController -> Dispatcher -> Notifierchain - outbound replies still use the Feishu HTTP API
- card callbacks are now also handled through the Feishu long-connection listener
To verify the DM card bootstrap on a real Feishu bot:
- Start
uvicorn poco.main:app --reload - Confirm
/healthshowsfeishu_listener_ready=true - Send any DM message like
hito the bot - The bot should reply with a
PoCo Projectscard - Click
Create Project + Groupand the card should return to the DM home card
Example webhook payload:
{
"token": "verification_token_from_feishu",
"event": {
"sender": {
"sender_id": {
"open_id": "ou_demo_user"
}
},
"message": {
"chat_id": "oc_demo_chat",
"content": "{\"text\":\"/run confirm: review the deployment plan\"}"
}
}
}
Supported Commands
- In a bound project group, you can now send plain text directly and PoCo will treat it as the task prompt.
- Group text-created tasks now reply with a single initial
task_statuscard, and later live/terminal updates stay on that same card. - Running-state card update failures no longer fallback to new-card fanout.
- PoCo now keeps a minimal persisted
active sessionper project, and workspace cards show that session instead of a placeholder. - PoCo now treats each project group as one stable session, instead of exposing multi-session lifecycle controls in the group UI.
- In sqlite-backed runtime, task card message ids are now persisted immediately so follow-up updates do not fan out into fresh cards.
/run <prompt>/status <task_id>/approve <task_id>/reject <task_id>/help
If the prompt starts with confirm:, the stub runner pauses the task at a confirmation checkpoint so the approval flow can be exercised without a real agent backend.
The same confirm: prefix also works for the Codex backend: PoCo will pause before invoking codex, then continue only after /approve <task_id>.
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.4.0.tar.gz.
File metadata
- Download URL: pocket_coding-0.4.0.tar.gz
- Upload date:
- Size: 89.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aa36eed0a34b439a18c972b37973bafc940c5dd0ad6aa60c72d66f649868249e
|
|
| MD5 |
b6c97ceb63a3e4384f78744300d6b3cb
|
|
| BLAKE2b-256 |
ded04a6b107518dd66ca45c306c6f3449d1617847f5a7ee6485915e4246dcd69
|
File details
Details for the file pocket_coding-0.4.0-py3-none-any.whl.
File metadata
- Download URL: pocket_coding-0.4.0-py3-none-any.whl
- Upload date:
- Size: 76.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b9503f5e0ed04293fa6fc6bb2e0ddec8683a0c000dbe410fc67c04531a8eedc3
|
|
| MD5 |
aaa51cd5c9a57a28a94fe84fd8aef71f
|
|
| BLAKE2b-256 |
398a7fb89fc0a59fe07b3289a55fc41ba0dd338fe4744ccbd6de9e64d7ec6a8b
|