{"id":50533177,"url":"https://github.com/daedalus/pupy","last_synced_at":"2026-06-03T15:30:27.994Z","repository":{"id":355085814,"uuid":"1226718107","full_name":"daedalus/pupy","owner":"daedalus","description":"pu.py — Python port of pu.sh with multi-provider AI support (Anthropic, OpenAI, OpenCode)","archived":false,"fork":false,"pushed_at":"2026-05-01T18:53:59.000Z","size":1066,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-05-01T20:26:50.516Z","etag":null,"topics":["agentic-harness","opencode","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/daedalus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-01T18:48:13.000Z","updated_at":"2026-05-01T19:11:05.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/daedalus/pupy","commit_stats":null,"previous_names":["daedalus/pupy"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/daedalus/pupy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daedalus%2Fpupy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daedalus%2Fpupy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daedalus%2Fpupy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daedalus%2Fpupy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/daedalus","download_url":"https://codeload.github.com/daedalus/pupy/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daedalus%2Fpupy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33872297,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-03T02:00:06.370Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agentic-harness","opencode","python"],"created_at":"2026-06-03T15:30:25.418Z","updated_at":"2026-06-03T15:30:27.981Z","avatar_url":"https://github.com/daedalus.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pu.py\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"logos/logo.png\" alt=\"pu.py\" width=\"300\"\u003e\n\u003c/p\u003e\n\n**Portable agentic harness** — A Python port of [pu.sh](https://github.com/NahimNasser/pu) that provides an intelligent coding assistant with tool-calling capabilities.\n\n## Features\n\n✅ **Feature parity with pu.sh** — All original pu.sh features are implemented:\n- Multi-provider support (Anthropic, OpenAI, OpenCode)\n- Agentic tools (bash, read, write, edit, grep, find, ls)\n- Interactive mode with commands (/model, /effort, /login, /logout, /flush, /compact, /export, /session, /skill:name, /template)\n- Pipe mode for CI/automation\n- Token \u0026 cost tracking with real-time monitoring\n- Session persistence and history\n- Context management with automatic compaction\n- Skill system (`/skill:name`)\n- Template system (`/template-name`)\n- Session export to markdown (`/export`)\n- Setup wizard (`/login`)\n- Log replay functionality\n\n**Additional pu.py features:**\n- Thread-safe token tracking\n- Prompt-based tool calling for non-native models (OpenCode)\n- Structured Python code with proper error handling\n\n## Implementation Details\n\n| Aspect | pu.sh (Original) | pu.py (Python Port) |\n|--------|-------------------|---------------------|\n| Lines of code | 392 | 1640+ |\n| Language | Bash + awk + curl | Python 3 |\n| Dependencies | sh, curl, awk (standard Unix tools) | Python standard library |\n| File size | 43.1K | 54.5K+ |\n\n### Key Differences\n\n**pu.py adds:**\n- OpenCode provider support (big-pickle, qwen, glm, minimax, kimi)\n- Thread-safe token tracking with TOKEN_LOCK\n- Prompt-based tool calling for models without native tool support\n- Python structured code with classes (ParsedResponse)\n- Better error handling with try/except blocks\n\n**pu.sh advantages:**\n- More compact (392 lines vs 1640+)\n- No Python dependency\n- Uses standard Unix tools (curl, awk)\n- Custom JSON parsing without external dependencies\n\n## Quick Start\n\n```bash\n# Make executable\nchmod +x pu.py\n\n# Run with a task\n./pu.py \"list all Python files in this directory\"\n\n# Interactive mode\n./pu.py\n\n# Pipe mode (for CI/automation)\necho \"review this code\" | ./pu.py --pipe\n\n# Show cost tracking\n./pu.py --cost \"optimize this function\"\n```\n\n## Configuration\n\nCreate `~/.pu.env` for persistent configuration:\n\n```bash\nexport ANTHROPIC_API_KEY=\"your-key-here\"\nexport OPENAI_API_KEY=\"your-key-here\"\nexport OPENCODE_API_KEY=\"public\"\nexport AGENT_PROVIDER=\"anthropic\"        # or \"openai\", \"opencode\"\nexport AGENT_MODEL=\"claude-opus-4-7\"     # or \"gpt-5.5\", \"big-pickle\"\nexport AGENT_EFFORT=\"medium\"              # low, medium, high, xhigh, max\nexport AGENT_MAX_STEPS=\"100\"\nexport AGENT_MAX_TOKENS=\"4096\"\nexport AGENT_CONTEXT_LIMIT=\"400000\"\nexport AGENT_VERBOSE=\"1\"\n```\n\n## Environment Variables\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `ANTHROPIC_API_KEY` | Anthropic API key | - |\n| `OPENAI_API_KEY` | OpenAI API key | - |\n| `OPENCODE_API_KEY` | OpenCode API key | `public` |\n| `AGENT_PROVIDER` | AI provider | auto-detect |\n| `AGENT_MODEL` | Model to use | provider-specific |\n| `AGENT_EFFORT` | Reasoning effort | `medium` |\n| `AGENT_MAX_STEPS` | Max agent steps | `100` |\n| `AGENT_MAX_TOKENS` | Max tokens per response | `4096` |\n| `AGENT_CONTEXT_LIMIT` | Context window size | `400000` |\n| `AGENT_LOG` | Event log file | `.pu-events.jsonl` |\n| `AGENT_HISTORY` | History file | `.pu-history.json` |\n| `AGENT_VERBOSE` | Verbose output | `1` |\n| `AGENT_CONFIRM` | Confirmation mode | `0` |\n| `AGENT_RESERVE` | Token reserve | `16000` |\n| `AGENT_KEEP_RECENT` | Recent tokens to keep | `80000` |\n| `AGENT_TOOL_TRUNC` | Tool output truncation | `100000` |\n| `AGENT_READ_MAX` | Max file read size | `1000000` |\n| `AGENT_PRICE_IN_PER_MTOK` | Input token price | `0` |\n| `AGENT_PRICE_OUT_PER_MTOK` | Output token price | `0` |\n\n## Interactive Commands\n\nWhen running in interactive mode, use these commands:\n\n- `/model [name]` — Switch AI model\n- `/effort` — Change reasoning effort\n- `/login` / `/logout` — Manage API keys\n- `/flush` — Clear conversation history\n- `/compact` — Compact context\n- `/export` — Export conversation\n- `/session` — Show session info\n- `/quit` — Exit\n- `!cmd` — Run shell command directly\n\n## Supported Models\n\n### Anthropic\n- `claude-opus-4-7` (default for Anthropic)\n- `claude-sonnet-4-6`\n- `claude-opus-4-6`\n- `claude-opus-4-5`\n\n### OpenAI\n- `gpt-5.5` (default for OpenAI)\n- `o1`, `o3`, `o4` series\n\n### OpenCode\n- `big-pickle` (default for OpenCode)\n- `minimax`\n- `glm`\n- `qwen`\n- `kimi`\n\n## Technical Comparison\n\n### Context Management\n\n**pu.sh:**\n- Custom awk-based context compaction (`_ctx_entries()`, `_ctx_tail_start()`, etc.)\n- Local memory compaction with `_ctx_local_memory()`\n- Multiple fallback strategies\n\n**pu.py:**\n- Python-based context management\n- Token-based tracking with `CTX_LIMIT`, `AGENT_RESERVE`, `AGENT_KEEP_RECENT`\n- Automatic compaction based on context size\n\n### Threading \u0026 Spinners\n\n**pu.sh:**\n- Background process spinner using `\u0026` and process management\n- Uses `tput` for terminal control\n\n**pu.py:**\n- Python `threading` module for spinner\n- `TOKEN_LOCK` for thread safety\n- Cleaner terminal output handling\n\n### JSON Parsing\n\n**pu.sh:**\n- Custom JSON parsing using awk (`jp()`, `jb()`, `each_tool_use()`, `o_items()`)\n- Handles Unicode escapes, nested objects, arrays\n- No external JSON parser dependency\n\n**pu.py:**\n- Uses Python's built-in `json` module\n- `extract_json()` helper for extracting JSON from text\n- `ParsedResponse` class for structured response handling\n\n### Token \u0026 Cost Tracking\n\n**pu.sh:**\n- Shell-based arithmetic for token counting\n- Awk-based cost calculation\n- `track_tokens()` function\n\n**pu.py:**\n- Thread-safe token tracking with `TOKEN_LOCK`\n- `track_tokens()` with support for both Anthropic and OpenAI formats\n- Price calculation using `AGENT_PRICE_IN_PER_MTOK` and `AGENT_PRICE_OUT_PER_MTOK`\n\n### Error Handling\n\n**pu.sh:**\n- Uses `set -u` for undefined variable detection\n- Custom `_kill_tree()` for process cleanup\n- Signal handling with `trap`\n\n**pu.py:**\n- Try/except blocks\n- `subprocess` module for command execution\n- Signal handling with `signal` module\n\n## Requirements\n\n- Python 3.7+\n- Internet connection\n- API key for your chosen provider\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaedalus%2Fpupy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdaedalus%2Fpupy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaedalus%2Fpupy/lists"}