polycoding 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. polycoding-0.1.0/.dockerignore +80 -0
  2. polycoding-0.1.0/.env.example +104 -0
  3. polycoding-0.1.0/.gitignore +59 -0
  4. polycoding-0.1.0/AGENTS.md +299 -0
  5. polycoding-0.1.0/Dockerfile +39 -0
  6. polycoding-0.1.0/LICENSE +20 -0
  7. polycoding-0.1.0/Makefile +9 -0
  8. polycoding-0.1.0/PKG-INFO +225 -0
  9. polycoding-0.1.0/README.md +183 -0
  10. polycoding-0.1.0/docs/ARCHITECTURE.md +438 -0
  11. polycoding-0.1.0/docs/CELERY_README.md +333 -0
  12. polycoding-0.1.0/docs/CLI_USAGE.md +330 -0
  13. polycoding-0.1.0/docs/FLOWS.md +493 -0
  14. polycoding-0.1.0/docs/HOOK_ARCHITECTURE.md +330 -0
  15. polycoding-0.1.0/docs/PLUGIN.md +1274 -0
  16. polycoding-0.1.0/docs/QUICKSTART.md +184 -0
  17. polycoding-0.1.0/entrypooint.sh +47 -0
  18. polycoding-0.1.0/pyproject.toml +97 -0
  19. polycoding-0.1.0/src/AGENTS.md +1071 -0
  20. polycoding-0.1.0/src/README.md +99 -0
  21. polycoding-0.1.0/src/bootstrap.py +121 -0
  22. polycoding-0.1.0/src/channels/__init__.py +66 -0
  23. polycoding-0.1.0/src/channels/base.py +50 -0
  24. polycoding-0.1.0/src/channels/dispatcher.py +162 -0
  25. polycoding-0.1.0/src/channels/hooks.py +154 -0
  26. polycoding-0.1.0/src/channels/redis/__init__.py +37 -0
  27. polycoding-0.1.0/src/channels/redis/channel.py +109 -0
  28. polycoding-0.1.0/src/channels/stream/__init__.py +6 -0
  29. polycoding-0.1.0/src/channels/stream/config.py +19 -0
  30. polycoding-0.1.0/src/channels/stream/server.py +162 -0
  31. polycoding-0.1.0/src/channels/stream/server_app.py +62 -0
  32. polycoding-0.1.0/src/channels/types.py +63 -0
  33. polycoding-0.1.0/src/cli/__init__.py +53 -0
  34. polycoding-0.1.0/src/cli/db.py +67 -0
  35. polycoding-0.1.0/src/cli/flow.py +187 -0
  36. polycoding-0.1.0/src/cli/main.py +44 -0
  37. polycoding-0.1.0/src/cli/project.py +166 -0
  38. polycoding-0.1.0/src/cli/server.py +127 -0
  39. polycoding-0.1.0/src/cli/utils.py +70 -0
  40. polycoding-0.1.0/src/cli/worker.py +124 -0
  41. polycoding-0.1.0/src/crews/__init__.py +34 -0
  42. polycoding-0.1.0/src/crews/base.py +86 -0
  43. polycoding-0.1.0/src/crews/conversation_crew/__init__.py +6 -0
  44. polycoding-0.1.0/src/crews/conversation_crew/config/agents.yaml +20 -0
  45. polycoding-0.1.0/src/crews/conversation_crew/config/tasks.yaml +66 -0
  46. polycoding-0.1.0/src/crews/conversation_crew/conversation_crew.py +60 -0
  47. polycoding-0.1.0/src/crews/conversation_crew/types.py +11 -0
  48. polycoding-0.1.0/src/crews/implement_crew/__init__.py +4 -0
  49. polycoding-0.1.0/src/crews/implement_crew/config/agents.yaml +25 -0
  50. polycoding-0.1.0/src/crews/implement_crew/config/tasks.yaml +205 -0
  51. polycoding-0.1.0/src/crews/implement_crew/implement_crew.py +161 -0
  52. polycoding-0.1.0/src/crews/implement_crew/types.py +24 -0
  53. polycoding-0.1.0/src/crews/plan_crew/__init__.py +4 -0
  54. polycoding-0.1.0/src/crews/plan_crew/config/agents.yaml +30 -0
  55. polycoding-0.1.0/src/crews/plan_crew/config/tasks.yaml +78 -0
  56. polycoding-0.1.0/src/crews/plan_crew/plan_crew.py +80 -0
  57. polycoding-0.1.0/src/crews/plan_crew/types.py +36 -0
  58. polycoding-0.1.0/src/crews/ralph_crew/__init__.py +4 -0
  59. polycoding-0.1.0/src/crews/ralph_crew/config/agents.yaml +20 -0
  60. polycoding-0.1.0/src/crews/ralph_crew/config/tasks.yaml +55 -0
  61. polycoding-0.1.0/src/crews/ralph_crew/ralph_crew.py +77 -0
  62. polycoding-0.1.0/src/crews/ralph_crew/types.py +8 -0
  63. polycoding-0.1.0/src/crews/review_crew/__init__.py +4 -0
  64. polycoding-0.1.0/src/crews/review_crew/config/agents.yaml +9 -0
  65. polycoding-0.1.0/src/crews/review_crew/config/tasks.yaml +23 -0
  66. polycoding-0.1.0/src/crews/review_crew/review_crew.py +46 -0
  67. polycoding-0.1.0/src/crews/review_crew/types.py +11 -0
  68. polycoding-0.1.0/src/crews/streaming/__init__.py +19 -0
  69. polycoding-0.1.0/src/crews/streaming/callback.py +103 -0
  70. polycoding-0.1.0/src/crews/streaming/factory.py +49 -0
  71. polycoding-0.1.0/src/crews/streaming/publisher.py +100 -0
  72. polycoding-0.1.0/src/crews/streaming/types.py +45 -0
  73. polycoding-0.1.0/src/crews/test_crew/__init__.py +4 -0
  74. polycoding-0.1.0/src/crews/test_crew/config/agents.yaml +9 -0
  75. polycoding-0.1.0/src/crews/test_crew/config/tasks.yaml +28 -0
  76. polycoding-0.1.0/src/crews/test_crew/test_crew.py +49 -0
  77. polycoding-0.1.0/src/crews/test_crew/types.py +11 -0
  78. polycoding-0.1.0/src/crews/verify_crew/__init__.py +4 -0
  79. polycoding-0.1.0/src/crews/verify_crew/config/agents.yaml +9 -0
  80. polycoding-0.1.0/src/crews/verify_crew/config/tasks.yaml +30 -0
  81. polycoding-0.1.0/src/crews/verify_crew/types.py +11 -0
  82. polycoding-0.1.0/src/crews/verify_crew/verify_crew.py +49 -0
  83. polycoding-0.1.0/src/flows/__init__.py +15 -0
  84. polycoding-0.1.0/src/flows/base.py +245 -0
  85. polycoding-0.1.0/src/flows/protocol.py +30 -0
  86. polycoding-0.1.0/src/flows/ralph/__init__.py +13 -0
  87. polycoding-0.1.0/src/flows/ralph/flow.py +232 -0
  88. polycoding-0.1.0/src/flows/ralph/module.py +41 -0
  89. polycoding-0.1.0/src/flows/ralph/types.py +16 -0
  90. polycoding-0.1.0/src/flows/registry.py +124 -0
  91. polycoding-0.1.0/src/gitcore/__init__.py +38 -0
  92. polycoding-0.1.0/src/gitcore/hooks.py +94 -0
  93. polycoding-0.1.0/src/gitcore/module.py +56 -0
  94. polycoding-0.1.0/src/gitcore/operations.py +346 -0
  95. polycoding-0.1.0/src/gitcore/types.py +73 -0
  96. polycoding-0.1.0/src/github_app/__init__.py +13 -0
  97. polycoding-0.1.0/src/github_app/app.py +224 -0
  98. polycoding-0.1.0/src/github_app/auth.py +137 -0
  99. polycoding-0.1.0/src/github_app/config.py +38 -0
  100. polycoding-0.1.0/src/github_app/installation_manager.py +194 -0
  101. polycoding-0.1.0/src/github_app/label_mapper.py +112 -0
  102. polycoding-0.1.0/src/github_app/models.py +112 -0
  103. polycoding-0.1.0/src/github_app/webhook_handler.py +217 -0
  104. polycoding-0.1.0/src/glm.py +100 -0
  105. polycoding-0.1.0/src/modules/README.md +850 -0
  106. polycoding-0.1.0/src/modules/__init__.py +29 -0
  107. polycoding-0.1.0/src/modules/channels.py +109 -0
  108. polycoding-0.1.0/src/modules/context.py +31 -0
  109. polycoding-0.1.0/src/modules/hooks.py +101 -0
  110. polycoding-0.1.0/src/modules/protocol.py +92 -0
  111. polycoding-0.1.0/src/modules/registry.py +165 -0
  112. polycoding-0.1.0/src/modules/tasks.py +123 -0
  113. polycoding-0.1.0/src/persistence/__init__.py +5 -0
  114. polycoding-0.1.0/src/persistence/config.py +12 -0
  115. polycoding-0.1.0/src/persistence/postgres.py +346 -0
  116. polycoding-0.1.0/src/persistence/registry.py +111 -0
  117. polycoding-0.1.0/src/persistence/tasks.py +178 -0
  118. polycoding-0.1.0/src/project_manager/README.md +668 -0
  119. polycoding-0.1.0/src/project_manager/__init__.py +29 -0
  120. polycoding-0.1.0/src/project_manager/base.py +202 -0
  121. polycoding-0.1.0/src/project_manager/config.py +36 -0
  122. polycoding-0.1.0/src/project_manager/conversation/__init__.py +19 -0
  123. polycoding-0.1.0/src/project_manager/conversation/flow.py +233 -0
  124. polycoding-0.1.0/src/project_manager/conversation/types.py +64 -0
  125. polycoding-0.1.0/src/project_manager/flow_runner.py +160 -0
  126. polycoding-0.1.0/src/project_manager/git_utils.py +30 -0
  127. polycoding-0.1.0/src/project_manager/github.py +367 -0
  128. polycoding-0.1.0/src/project_manager/github_conversation.py +144 -0
  129. polycoding-0.1.0/src/project_manager/github_projects_client.py +329 -0
  130. polycoding-0.1.0/src/project_manager/hooks.py +377 -0
  131. polycoding-0.1.0/src/project_manager/module.py +66 -0
  132. polycoding-0.1.0/src/project_manager/types.py +79 -0
  133. polycoding-0.1.0/src/retro/README.md +432 -0
  134. polycoding-0.1.0/src/retro/__init__.py +23 -0
  135. polycoding-0.1.0/src/retro/analyzer.py +216 -0
  136. polycoding-0.1.0/src/retro/crews/__init__.py +5 -0
  137. polycoding-0.1.0/src/retro/crews/retro_crew/__init__.py +5 -0
  138. polycoding-0.1.0/src/retro/crews/retro_crew/config/agents.yaml +14 -0
  139. polycoding-0.1.0/src/retro/crews/retro_crew/config/tasks.yaml +40 -0
  140. polycoding-0.1.0/src/retro/crews/retro_crew/retro_crew.py +68 -0
  141. polycoding-0.1.0/src/retro/git_notes.py +167 -0
  142. polycoding-0.1.0/src/retro/persistence.py +247 -0
  143. polycoding-0.1.0/src/retro/types.py +67 -0
  144. polycoding-0.1.0/src/tasks/__init__.py +59 -0
  145. polycoding-0.1.0/src/tasks/config.py +102 -0
  146. polycoding-0.1.0/src/tasks/tasks.py +163 -0
  147. polycoding-0.1.0/src/tasks/worker.py +32 -0
  148. polycoding-0.1.0/src/tools/__init__.py +8 -0
  149. polycoding-0.1.0/src/tools/agents_md_loader.py +36 -0
  150. polycoding-0.1.0/src/tools/code_analysis/README.md +84 -0
  151. polycoding-0.1.0/src/tools/code_analysis/__init__.py +179 -0
  152. polycoding-0.1.0/src/tools/code_analysis/context_manager.py +150 -0
  153. polycoding-0.1.0/src/tools/code_analysis/language_support.py +154 -0
  154. polycoding-0.1.0/src/tools/code_analysis/lsp/__init__.py +41 -0
  155. polycoding-0.1.0/src/tools/code_analysis/lsp/base.py +141 -0
  156. polycoding-0.1.0/src/tools/code_analysis/lsp/client_pool.py +358 -0
  157. polycoding-0.1.0/src/tools/code_analysis/lsp/definition_tool.py +173 -0
  158. polycoding-0.1.0/src/tools/code_analysis/lsp/diagnostics_tool.py +222 -0
  159. polycoding-0.1.0/src/tools/code_analysis/lsp/hover_tool.py +136 -0
  160. polycoding-0.1.0/src/tools/code_analysis/lsp/references_tool.py +162 -0
  161. polycoding-0.1.0/src/tools/code_analysis/module.py +159 -0
  162. polycoding-0.1.0/src/tools/code_analysis/tree_sitter/README.md +66 -0
  163. polycoding-0.1.0/src/tools/code_analysis/tree_sitter/base.py +189 -0
  164. polycoding-0.1.0/src/tools/code_analysis/tree_sitter/types.py +131 -0
  165. polycoding-0.1.0/src/tools/code_analysis/types.py +131 -0
  166. polycoding-0.1.0/src/tools/directory_read_tool.py +86 -0
  167. polycoding-0.1.0/src/tools/exec_tool.py +379 -0
  168. polycoding-0.1.0/src/tools/file_read_tool.py +116 -0
  169. polycoding-0.1.0/task_templates/custom_generate_result.md +64 -0
  170. polycoding-0.1.0/task_templates/custom_implement.md +63 -0
  171. polycoding-0.1.0/tests/__init__.py +0 -0
  172. polycoding-0.1.0/tests/test_agents_md_loader.py +69 -0
  173. polycoding-0.1.0/tests/test_flows.py +119 -0
  174. polycoding-0.1.0/tests/test_gitcore.py +109 -0
  175. polycoding-0.1.0/tests/test_github_manager.py +0 -0
  176. polycoding-0.1.0/tests/test_project_manager_plugin.py +96 -0
  177. polycoding-0.1.0/tests/test_retro.py +131 -0
  178. polycoding-0.1.0/uv.lock +4176 -0
@@ -0,0 +1,80 @@
1
+ # Python
2
+ .tox/
3
+ .venv/
4
+ *.pem
5
+ **/__pycache__
6
+ *.pyc
7
+ *.pyo
8
+ *.pyd
9
+ *.so
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ *.egg-info/
24
+ .installed.cfg
25
+ *.egg
26
+
27
+ node_modules
28
+ **/node_modules
29
+
30
+ # Virtual environments
31
+ venv/
32
+ **/venv/
33
+ env/
34
+ **/env/
35
+ ENV/
36
+ **/ENV/
37
+ .venv/
38
+ **/.venv/
39
+
40
+ .ruff_cache
41
+ .git
42
+ .github
43
+ Dockerfile
44
+
45
+
46
+
47
+ # IDEs
48
+ .vscode/
49
+ .idea/
50
+ *.swp
51
+ *.swo
52
+ *~
53
+
54
+ # Environment variables
55
+ .env
56
+
57
+ # OS
58
+ .DS_Store
59
+ Thumbs.db
60
+
61
+ # CrewAI specific
62
+ crew_output/
63
+
64
+ # Logs
65
+ *.log
66
+
67
+ # Testing
68
+ .pytest_cache/
69
+ .coverage
70
+ htmlcov/
71
+
72
+ # uv
73
+ .python-version
74
+
75
+ *.db
76
+
77
+ deployment
78
+ Makefile
79
+ .gitignore
80
+ tests
@@ -0,0 +1,104 @@
1
+ # CrewAI Configuration
2
+ # Copy this file to .env and fill in your values
3
+
4
+ # OpenAI API Key (or your preferred LLM provider)
5
+ # CrewAI supports multiple providers: OpenAI, Anthropic, Azure, etc.
6
+ # See: https://docs.crewai.com/en/concepts/llms#setting-up-your-llm
7
+ OPENAI_API_KEY=sk-your-api-key-here
8
+
9
+ # Alternative: Anthropic API Key
10
+ # ANTHROPIC_API_KEY=sk-ant-your-api-key-here
11
+
12
+ # Alternative: Azure OpenAI
13
+ # AZURE_API_BASE=https://your-resource.openai.azure.com
14
+ # AZURE_API_KEY=your-azure-api-key-here
15
+ # AZURE_API_VERSION=2024-02-15-preview
16
+ # AZURE_DEPLOYMENT_NAME=gpt-4
17
+
18
+ # Serper API Key (for web search tools, if needed)
19
+ # SERPER_API_KEY=your-serper-api-key-here
20
+
21
+ # CrewAI Settings
22
+ # CREWAI_PROCESS_MODE=sequential
23
+ # CREWAI_VERBOSE=true
24
+
25
+ # Optional: Custom Model Configuration
26
+ # CREWAI_LLM=openai/gpt-4
27
+ # CREWAI_TEMPERATURE=0.7
28
+
29
+ # =============================================================================
30
+ # DATABASE CONFIGURATION
31
+ # =============================================================================
32
+
33
+ # Database URL - supports SQLite and PostgreSQL
34
+ # SQLite (default): file-based, no server required
35
+ DATABASE_URL=sqlite:///./feature_dev.db
36
+
37
+ # PostgreSQL: production-ready, requires running PostgreSQL server
38
+ # Automatically uses JSONB for JSON columns
39
+ # DATABASE_URL=postgresql+psycopg2://user:password@localhost:5432/feature_dev
40
+
41
+ # Enable SQL query logging (useful for debugging)
42
+ # DATABASE_ECHO=true
43
+
44
+ # =============================================================================
45
+ # WEBHOOK CONFIGURATION
46
+ # =============================================================================
47
+
48
+ # Webhook timeout in seconds (default: 10)
49
+ # WEBHOOK_TIMEOUT=10
50
+
51
+ # =============================================================================
52
+ # DATABASE SCHEMA
53
+ # =============================================================================
54
+ #
55
+ # Tables:
56
+ #
57
+ # 1. flow_execution - Main flow run record
58
+ # - id, flow_id (unique), issue_id, task, repo, branch
59
+ # - current_phase, verified, tested
60
+ # - build_cmd, test_cmd, ci_notes, baseline, findings
61
+ # - current_story_id, current_story_title
62
+ # - pr_url, pr_number, review_status, diff
63
+ # - commit_title, commit_message, commit_footer
64
+ # - changes (JSON), tests (JSON)
65
+ # - created_at, updated_at
66
+ #
67
+ # 2. story - Individual user stories
68
+ # - id, story_id, title, description
69
+ # - acceptance_criteria (JSON/JSONB)
70
+ #
71
+ # 3. flow_story - Junction table (stories planned for a flow)
72
+ # - id, flow_id -> flow_execution.id, story_id -> story.id, order
73
+ #
74
+ # 4. completed_story - Junction table (stories completed in a flow)
75
+ # - id, flow_id -> flow_execution.id, story_id -> story.id
76
+ # - completed_at, changes, tests
77
+ #
78
+ # 5. phase_snapshot - State at each phase transition
79
+ # - id, flow_id -> flow_execution.id, phase
80
+ # - state_json (JSON/JSONB), created_at
81
+ #
82
+ # 6. webhook_config - Webhook endpoints
83
+ # - id, name, url, events (JSON list), active
84
+ #
85
+ # =============================================================================
86
+ # WEBHOOK USAGE
87
+ # =============================================================================
88
+ #
89
+ # Webhooks are configured in the database via webhook_config table.
90
+ #
91
+ # Example: Insert a webhook via SQL
92
+ # INSERT INTO webhook_config (name, url, events, active)
93
+ # VALUES ('slack-notify', 'https://hooks.slack.com/services/...', '["review", "create_pr"]', 1);
94
+ #
95
+ # Available phases: setup, plan_task, create_branch, implement_story,
96
+ # test_integration, verify, commit_changes, create_pr, review
97
+ # Use "*" to trigger on all phases
98
+ #
99
+ # Webhook payload format:
100
+ # {
101
+ # "phase": "review",
102
+ # "webhook_name": "slack-notify",
103
+ # "state": { ... full FeatureDevState as dict ... }
104
+ # }
@@ -0,0 +1,59 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+
23
+ # Virtual environments
24
+ venv/
25
+ env/
26
+ ENV/
27
+ .venv
28
+
29
+ # IDEs
30
+ .vscode/
31
+ .idea/
32
+ *.swp
33
+ *.swo
34
+ *~
35
+
36
+ # Environment variables
37
+ .env
38
+
39
+ # OS
40
+ .DS_Store
41
+ Thumbs.db
42
+
43
+ # CrewAI specific
44
+ crew_output/
45
+
46
+ # Logs
47
+ *.log
48
+
49
+ # Testing
50
+ .pytest_cache/
51
+ .coverage
52
+ htmlcov/
53
+
54
+ # uv
55
+ .python-version
56
+
57
+ feature_dev.db
58
+ flow_state.db
59
+ *.db
@@ -0,0 +1,299 @@
1
+ # Polycode — Coding Agent Guidelines
2
+
3
+ Instructions for AI coding agents (Claude Code, Cursor, etc.) working in this repository.
4
+
5
+ ---
6
+
7
+ ## Project Overview
8
+
9
+ Multi-agent software development automation using CrewAI. GitHub App integration for
10
+ webhook-driven workflows across multiple repositories.
11
+
12
+ **Stack:** Python 3.13, CrewAI, FastAPI, Celery, Redis, PostgreSQL, Pydantic
13
+
14
+ ---
15
+
16
+ ## Build / Lint / Test Commands
17
+
18
+ ### Package Management
19
+
20
+ ```bash
21
+ uv sync # Install dependencies
22
+ uv add <package> # Add dependency
23
+ uv lock # Update lock file
24
+ ```
25
+
26
+ ### Linting & Type Checking
27
+
28
+ ```bash
29
+ uv run ruff check . # Lint all files
30
+ uv run ruff check --fix . # Auto-fix lint errors
31
+ uv run ruff format . # Format code
32
+ uv run pyright # Type check (via pre-commit)
33
+ ```
34
+
35
+ ### Testing
36
+
37
+ ```bash
38
+ uv run pytest # Run all tests
39
+ uv run pytest tests/test_github_manager.py # Run single test file
40
+ uv run pytest tests/test_github_manager.py::test_has_label_returns_true_when_label_exists # Single test
41
+ uv run pytest -k "label" # Run tests matching pattern
42
+ uv run pytest -v # Verbose output
43
+ ```
44
+
45
+ ### Running the Application
46
+
47
+ ```bash
48
+ uv run python -m project_manager.cli # CLI entry point
49
+ uv run uvicorn github_app.app:app # FastAPI webhook server
50
+ ```
51
+
52
+ ### Docker
53
+
54
+ ```bash
55
+ make docker # Build and push (uses timestamp as version)
56
+ ```
57
+
58
+ ---
59
+
60
+ ## Code Style Guidelines
61
+
62
+ ### Linting Rules (ruff)
63
+
64
+ - Line length: 79 characters
65
+ - Enabled rules: E, F, I, N, W (E501 ignored)
66
+ - Always run `uv run ruff check --fix .` before committing
67
+
68
+ ### Imports
69
+
70
+ ```python
71
+ """Module docstring."""
72
+
73
+ # 1. Standard library (alphabetical)
74
+ import json
75
+ import logging
76
+ import os
77
+ import re
78
+ from pathlib import Path
79
+ from typing import Optional, TypeVar
80
+
81
+ # 2. Third-party (alphabetical)
82
+ import git
83
+ from crewai import Flow
84
+ from pydantic import BaseModel, Field
85
+
86
+ # 3. Local imports (alphabetical)
87
+ from glm import GLMJSONLLM
88
+ from persistence.postgres import SessionLocal
89
+ from project_manager.types import ProjectConfig
90
+ ```
91
+
92
+ ### Type Annotations
93
+
94
+ Use modern Python 3.10+ syntax:
95
+
96
+ ```python
97
+ # Prefer union syntax
98
+ def get_issue(self, issue_id: int) -> Issue | None:
99
+
100
+ # Over Optional
101
+ def get_issue(self, issue_id: int) -> Optional[Issue]:
102
+
103
+ # List/dict generics without importing from typing
104
+ labels: list[str] = []
105
+ config: dict[str, Any] = {}
106
+ ```
107
+
108
+ ### Pydantic Models
109
+
110
+ ```python
111
+ class ProjectConfig(BaseModel):
112
+ """Configuration for a project manager."""
113
+
114
+ provider: str
115
+ repo_owner: str
116
+ repo_name: str
117
+ project_identifier: str | None = None
118
+ token: str | None = None
119
+ extra: dict[str, Any] = {}
120
+ ```
121
+
122
+ - Always include docstrings for classes
123
+ - Use `Field()` for field descriptions when helpful
124
+ - Use `| None` for optional fields with defaults
125
+
126
+ ### Naming Conventions
127
+
128
+ ```python
129
+ # Classes: PascalCase
130
+ class GitHubProjectManager:
131
+
132
+ # Functions/methods: snake_case
133
+ def get_open_issues(self) -> list[Issue]:
134
+
135
+ # Variables: snake_case
136
+ project_items = []
137
+
138
+ # Constants: UPPER_SNAKE_CASE
139
+ MERGE_REQUIRED_LABEL = "approved"
140
+
141
+ # Private methods: prefix with underscore
142
+ def _prepare_work_tree(self):
143
+
144
+ # Properties for lazy-loaded values
145
+ @property
146
+ def project_id(self) -> str:
147
+ ```
148
+
149
+ ### Error Handling
150
+
151
+ ```python
152
+ # Raise specific exceptions with helpful messages
153
+ if not token:
154
+ raise ValueError(
155
+ "GitHub token must be provided via config or GITHUB_TOKEN env var"
156
+ )
157
+
158
+ # Handle exceptions gracefully, return sensible defaults
159
+ try:
160
+ result = self.projects_client.get_project_id(owner, number)
161
+ except github.UnknownObjectException:
162
+ log.warning(f"Project not found for {owner}")
163
+ return []
164
+
165
+ # Log errors with context
166
+ except Exception as e:
167
+ log.error(f"Failed to update PostgreSQL status: {e}")
168
+ ```
169
+
170
+ ### Logging
171
+
172
+ ```python
173
+ import logging
174
+
175
+ log = logging.getLogger(__name__)
176
+
177
+ # Use emoji prefixes for visual scanning in logs
178
+ log.info(f"🏹 Created worktree at: {worktree_path}")
179
+ log.warning(f"⚠️ No test command, skipping verification")
180
+ log.error(f"🚨 Failed to ensure request exists: {e}")
181
+ ```
182
+
183
+ ### Docstrings
184
+
185
+ ```python
186
+ def get_open_issues(self) -> list[Issue]:
187
+ """Get all open issues from the repository.
188
+
189
+ Returns:
190
+ List of open issues
191
+ """
192
+
193
+ def __init__(self, config: ProjectConfig) -> None:
194
+ """Initialize GitHub project manager.
195
+
196
+ Args:
197
+ config: Project configuration
198
+
199
+ Raises:
200
+ ValueError: If token is not provided
201
+ """
202
+ ```
203
+
204
+ ### Testing Patterns
205
+
206
+ ```python
207
+ """Test module docstring."""
208
+
209
+ from unittest.mock import MagicMock
210
+
211
+ from project_manager.github import GitHubProjectManager
212
+ from project_manager.types import ProjectConfig
213
+
214
+
215
+ def test_has_label_returns_true_when_label_exists():
216
+ """Test that has_label returns True when the label is present."""
217
+ # Arrange
218
+ config = ProjectConfig(
219
+ repo_owner="testowner",
220
+ repo_name="testrepo",
221
+ token="fake_token",
222
+ )
223
+ manager = GitHubProjectManager(config)
224
+ mock_repo = MagicMock()
225
+ mock_pr = MagicMock()
226
+ mock_pr.labels = [MagicMock(name="approved")]
227
+ mock_repo.get_pull.return_value = mock_pr
228
+ manager.github_client.get_repo = MagicMock(return_value=mock_repo)
229
+
230
+ # Act
231
+ result = manager.has_label(123, "approved")
232
+
233
+ # Assert
234
+ assert result is True
235
+ mock_repo.get_pull.assert_called_once_with(123)
236
+ ```
237
+
238
+ - Use descriptive test names: `test_<method>_<scenario>_<expected_result>`
239
+ - AAA pattern: Arrange, Act, Assert
240
+ - Use `unittest.mock` for mocking
241
+
242
+ ---
243
+
244
+ ## Project Structure
245
+
246
+ ```
247
+ polycode/
248
+ ├── src/
249
+ │ ├── project_manager/ # GitHub project management
250
+ │ ├── github_app/ # GitHub App webhook server
251
+ │ ├── celery_tasks/ # Async task processing
252
+ │ ├── persistence/ # Database layer
253
+ │ ├── feature_dev/ # Feature development crew
254
+ │ └── flowbase.py # Base flow classes
255
+ ├── tests/ # Test files
256
+ ├── pyproject.toml # Project config
257
+ └── .env # Environment variables
258
+ ```
259
+
260
+ ---
261
+
262
+ ## Pre-commit Hooks
263
+
264
+ Configured in `.pre-commit-config.yaml`:
265
+
266
+ - trailing-whitespace
267
+ - commitizen (conventional commits with gitmoji)
268
+ - markdownlint
269
+ - pyright (type checking)
270
+
271
+ Run manually: `pre-commit run --all-files`
272
+
273
+ ---
274
+
275
+ ## Environment Variables
276
+
277
+ Required in `.env`:
278
+
279
+ ```
280
+ GITHUB_TOKEN=ghp_...
281
+ DATABASE_URL=postgresql://...
282
+ REDIS_HOST=localhost
283
+ REDIS_PORT=6379
284
+ OPENAI_API_KEY=sk-...
285
+ OPENAI_URL_BASE=http://...
286
+ ```
287
+
288
+ ---
289
+
290
+ ## CrewAI Reference
291
+
292
+ See `src/AGENTS.md` for detailed CrewAI patterns, agent/task configuration, and flows.
293
+
294
+ **Key points:**
295
+
296
+ - Use `crewai.LLM` or string shorthand like `"openai/gpt-4o"`
297
+ - Agents and tasks in YAML configs
298
+ - `@CrewBase` decorator on crew classes
299
+ - `# type: ignore[index]` for config dictionary access
@@ -0,0 +1,39 @@
1
+ # Use the official Python 3.13 slim image as the base
2
+ FROM python:3.13-slim AS base
3
+
4
+ # Set environment variables to avoid interactive prompts during installation
5
+ ENV DEBIAN_FRONTEND=noninteractive
6
+
7
+ # Install system dependencies, Node.js (from NodeSource), and clean up
8
+ RUN apt-get update && apt-get install -y --no-install-recommends \
9
+ git \
10
+ ssh \
11
+ curl \
12
+ ca-certificates \
13
+ && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
14
+ && apt-get install -y nodejs \
15
+ && apt-get clean \
16
+ && rm -rf /var/lib/apt/lists/*
17
+ RUN node --version && npm --version && npm install -g pnpm && pnpm --version
18
+
19
+ FROM base
20
+ WORKDIR /app
21
+
22
+ COPY pyproject.toml uv.lock README.md ./
23
+ RUN pip install --no-cache-dir "crewai[litellm]>=1.10.0b1" && uv sync
24
+
25
+ COPY entrypooint.sh /usr/local/bin/entrypoint.sh
26
+ RUN chmod +x /usr/local/bin/entrypoint.sh
27
+
28
+ # Creates a non-root user and adds permission to access the /app folder
29
+ RUN useradd --create-home appuser \
30
+ && chown -R appuser /app
31
+ USER appuser
32
+
33
+ # Need to whitelist fingerprint of github
34
+ RUN mkdir /home/appuser/.ssh && ssh-keyscan github.com >> /home/appuser/.ssh/known_hosts
35
+
36
+ VOLUME [ "/data" ]
37
+ COPY . .
38
+
39
+ ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
@@ -0,0 +1,20 @@
1
+ Copyright 2026, ChainSquad GmbH
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the “Software”), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
20
+
@@ -0,0 +1,9 @@
1
+ VERSION := $(shell date +%Y%m%d%H%M)
2
+
3
+ docker_build:
4
+ docker build -t ghcr.io/xeroc/polycode:$(VERSION) .
5
+
6
+ docker_push:
7
+ docker push ghcr.io/xeroc/polycode:$(VERSION)
8
+
9
+ docker: docker_build docker_push