galangal-orchestrate 0.6.3__tar.gz → 0.12.15__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.
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/.gitignore +2 -1
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/PKG-INFO +173 -11
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/README.md +172 -10
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/docs/local-development/workflow-pipeline.md +1 -1
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/__init__.py +1 -1
- galangal_orchestrate-0.12.15/src/galangal/ai/__init__.py +167 -0
- galangal_orchestrate-0.12.15/src/galangal/ai/base.py +159 -0
- galangal_orchestrate-0.12.15/src/galangal/ai/claude.py +352 -0
- galangal_orchestrate-0.12.15/src/galangal/ai/codex.py +370 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/ai/gemini.py +5 -2
- galangal_orchestrate-0.12.15/src/galangal/ai/subprocess.py +254 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/cli.py +101 -171
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/commands/__init__.py +1 -16
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/commands/complete.py +56 -19
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/commands/github.py +48 -62
- galangal_orchestrate-0.12.15/src/galangal/commands/init.py +77 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/commands/prompts.py +5 -14
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/commands/reset.py +1 -3
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/commands/resume.py +1 -1
- galangal_orchestrate-0.12.15/src/galangal/commands/skip.py +62 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/commands/start.py +93 -23
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/commands/status.py +5 -30
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/config/defaults.py +26 -26
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/config/loader.py +41 -2
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/config/schema.py +63 -32
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/core/artifacts.py +11 -1
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/core/state.py +423 -32
- galangal_orchestrate-0.12.15/src/galangal/core/tasks.py +454 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/core/utils.py +8 -8
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/core/workflow/core.py +272 -100
- galangal_orchestrate-0.12.15/src/galangal/core/workflow/engine.py +781 -0
- galangal_orchestrate-0.12.15/src/galangal/core/workflow/tui_runner.py +1322 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/github/client.py +22 -12
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/github/images.py +23 -24
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/github/issues.py +24 -12
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/logging.py +6 -4
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/prompts/builder.py +210 -67
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/prompts/defaults/qa.md +1 -21
- galangal_orchestrate-0.12.15/src/galangal/prompts/defaults/review.md +90 -0
- galangal_orchestrate-0.12.15/src/galangal/prompts/defaults/review_codex.md +99 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/prompts/defaults/security.md +0 -20
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/results.py +18 -6
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/ui/console.py +1 -3
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/ui/tui/app.py +40 -43
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/ui/tui/mixins.py +2 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/ui/tui/modals.py +11 -20
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/ui/tui/widgets.py +1 -2
- galangal_orchestrate-0.12.15/src/galangal/validation/runner.py +1072 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/tests/conftest.py +18 -3
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/tests/test_ai_claude.py +79 -20
- galangal_orchestrate-0.12.15/tests/test_ai_codex.py +426 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/tests/test_commands.py +159 -68
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/tests/test_config.py +1 -15
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/tests/test_discovery_qa.py +1 -12
- galangal_orchestrate-0.12.15/tests/test_docs_sync.py +169 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/tests/test_results.py +5 -6
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/tests/test_tui.py +9 -3
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/tests/test_validation_runner.py +80 -20
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/tests/test_workflow_core.py +34 -23
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/tests/test_workflow_integration.py +31 -152
- galangal_orchestrate-0.6.3/src/galangal/ai/__init__.py +0 -6
- galangal_orchestrate-0.6.3/src/galangal/ai/base.py +0 -63
- galangal_orchestrate-0.6.3/src/galangal/ai/claude.py +0 -334
- galangal_orchestrate-0.6.3/src/galangal/commands/approve.py +0 -196
- galangal_orchestrate-0.6.3/src/galangal/commands/init.py +0 -175
- galangal_orchestrate-0.6.3/src/galangal/commands/skip.py +0 -185
- galangal_orchestrate-0.6.3/src/galangal/commands/stats.py +0 -155
- galangal_orchestrate-0.6.3/src/galangal/core/metrics.py +0 -264
- galangal_orchestrate-0.6.3/src/galangal/core/tasks.py +0 -241
- galangal_orchestrate-0.6.3/src/galangal/core/workflow/tui_runner.py +0 -1329
- galangal_orchestrate-0.6.3/src/galangal/prompts/defaults/review.md +0 -85
- galangal_orchestrate-0.6.3/src/galangal/validation/runner.py +0 -645
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/.github/workflows/publish.yml +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/LICENSE +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/docs/local-development/README.md +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/docs/local-development/architecture.md +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/docs/local-development/cli-commands.md +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/docs/local-development/configuration.md +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/docs/local-development/extending.md +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/docs/local-development/prompt-system.md +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/docs/local-development/state-management.md +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/docs/local-development/validation-system.md +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/docs/local-development/versioning.md +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/docs/pypi/RELEASE.md +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/pyproject.toml +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/__main__.py +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/commands/list.py +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/commands/pause.py +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/commands/switch.py +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/config/__init__.py +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/core/__init__.py +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/core/workflow/__init__.py +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/core/workflow/pause.py +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/exceptions.py +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/github/__init__.py +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/prompts/__init__.py +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/prompts/defaults/benchmark.md +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/prompts/defaults/contract.md +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/prompts/defaults/design.md +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/prompts/defaults/dev.md +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/prompts/defaults/docs.md +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/prompts/defaults/migration.md +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/prompts/defaults/pm.md +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/prompts/defaults/pm_questions.md +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/prompts/defaults/preflight.md +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/prompts/defaults/test.md +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/ui/__init__.py +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/ui/tui/__init__.py +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/ui/tui/adapters.py +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/ui/tui/entry.py +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/ui/tui/styles/app.tcss +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/ui/tui/styles/modals.tcss +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/ui/tui/types.py +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/src/galangal/validation/__init__.py +0 -0
- {galangal_orchestrate-0.6.3 → galangal_orchestrate-0.12.15}/tests/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: galangal-orchestrate
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.15
|
|
4
4
|
Summary: AI-driven development workflow orchestrator
|
|
5
5
|
Project-URL: Homepage, https://github.com/Galangal-Media/galangal-orchestrate
|
|
6
6
|
Project-URL: Repository, https://github.com/Galangal-Media/galangal-orchestrate
|
|
@@ -97,7 +97,7 @@ galangal status
|
|
|
97
97
|
| **PREFLIGHT** | Environment validation | PREFLIGHT_REPORT.md |
|
|
98
98
|
| **DEV** | Implementation | Code changes |
|
|
99
99
|
| **MIGRATION*** | Database migration checks | MIGRATION_REPORT.md |
|
|
100
|
-
| **TEST** | Test implementation | TEST_PLAN.md |
|
|
100
|
+
| **TEST** | Test implementation | TEST_PLAN.md, TEST_SUMMARY.md |
|
|
101
101
|
| **CONTRACT*** | API contract validation | CONTRACT_REPORT.md |
|
|
102
102
|
| **QA** | Quality assurance | QA_REPORT.md |
|
|
103
103
|
| **BENCHMARK*** | Performance validation | BENCHMARK_REPORT.md |
|
|
@@ -107,6 +107,15 @@ galangal status
|
|
|
107
107
|
|
|
108
108
|
*Conditional stages - skipped automatically if not relevant
|
|
109
109
|
|
|
110
|
+
### Validation Artifacts
|
|
111
|
+
|
|
112
|
+
When validation commands run (tests, linters, etc.), Galangal creates debugging artifacts:
|
|
113
|
+
|
|
114
|
+
- **VALIDATION_REPORT.md** - Full output from all validation commands, useful for debugging failures
|
|
115
|
+
- **TEST_SUMMARY.md** - Concise test results (pass/fail counts, failed test names, coverage) included in downstream stage prompts
|
|
116
|
+
|
|
117
|
+
These artifacts help you understand what failed without digging through logs, and give downstream stages (QA, REVIEW) context about test results without bloating prompts with verbose output.
|
|
118
|
+
|
|
110
119
|
## Task Types
|
|
111
120
|
|
|
112
121
|
Choose the right workflow for your task:
|
|
@@ -114,9 +123,9 @@ Choose the right workflow for your task:
|
|
|
114
123
|
| Type | Stages | When to Use |
|
|
115
124
|
|------|--------|-------------|
|
|
116
125
|
| **Feature** | All stages | New functionality |
|
|
117
|
-
| **Bug Fix** | PM → DEV → TEST → QA | Fixing bugs |
|
|
118
|
-
| **Refactor** | PM → DESIGN → DEV → TEST | Code restructuring |
|
|
119
|
-
| **Chore** | PM → DEV → TEST | Config, dependencies |
|
|
126
|
+
| **Bug Fix** | PM → PREFLIGHT → DEV → TEST → QA | Fixing bugs |
|
|
127
|
+
| **Refactor** | PM → DESIGN → PREFLIGHT → DEV → TEST | Code restructuring |
|
|
128
|
+
| **Chore** | PM → PREFLIGHT → DEV → TEST | Config, dependencies |
|
|
120
129
|
| **Docs** | PM → DOCS | Documentation only |
|
|
121
130
|
| **Hotfix** | PM → DEV → TEST | Critical fixes |
|
|
122
131
|
|
|
@@ -167,6 +176,32 @@ After analyzing your task, the PM stage outputs a `STAGE_PLAN.md` recommending w
|
|
|
167
176
|
|
|
168
177
|
The progress bar updates dynamically to show only relevant stages.
|
|
169
178
|
|
|
179
|
+
### Workflow Preview
|
|
180
|
+
|
|
181
|
+
After PM approval, you'll see a preview showing exactly which stages will run and why others are skipped:
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
Workflow Preview
|
|
185
|
+
|
|
186
|
+
Stages to run:
|
|
187
|
+
PM → DESIGN → PREFLIGHT → DEV → TEST → QA → REVIEW → DOCS
|
|
188
|
+
|
|
189
|
+
Skipping:
|
|
190
|
+
MIGRATION (no files match: **/migrations/*)
|
|
191
|
+
CONTRACT (no files match: **/api/*, **/openapi.*)
|
|
192
|
+
BENCHMARK (task type: bug_fix)
|
|
193
|
+
SECURITY (PM: simple UI change, no security impact)
|
|
194
|
+
|
|
195
|
+
Controls during execution:
|
|
196
|
+
^N Skip stage ^B Back ^E Pause for edit ^I Interrupt
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Skip reasons include:
|
|
200
|
+
- **Task type** - Based on the workflow template (e.g., bug fixes skip DESIGN)
|
|
201
|
+
- **Config** - Stages listed in `stages.skip` configuration
|
|
202
|
+
- **PM recommendation** - From STAGE_PLAN.md analysis
|
|
203
|
+
- **skip_if condition** - No changed files match the glob pattern
|
|
204
|
+
|
|
170
205
|
## Commands
|
|
171
206
|
|
|
172
207
|
| Command | Description |
|
|
@@ -403,6 +438,9 @@ validation:
|
|
|
403
438
|
- name: "Integration tests"
|
|
404
439
|
command: "pytest tests/integration"
|
|
405
440
|
optional: true # Don't fail if integration tests missing
|
|
441
|
+
# Use array form for paths with spaces or special characters
|
|
442
|
+
- name: "Task-specific tests"
|
|
443
|
+
command: ["pytest", "{task_dir}/tests"] # {task_dir} is substituted
|
|
406
444
|
|
|
407
445
|
# Contract stage (API compatibility)
|
|
408
446
|
contract:
|
|
@@ -458,21 +496,37 @@ ai:
|
|
|
458
496
|
# Default backend to use
|
|
459
497
|
default: claude
|
|
460
498
|
|
|
461
|
-
# Available backends
|
|
499
|
+
# Available backends with customizable CLI flags
|
|
462
500
|
backends:
|
|
463
501
|
claude:
|
|
464
|
-
command: claude
|
|
465
|
-
args:
|
|
466
|
-
- "-p"
|
|
467
|
-
- "{prompt}"
|
|
502
|
+
command: claude # CLI command to invoke
|
|
503
|
+
args: # Arguments with {placeholder} substitution
|
|
468
504
|
- "--output-format"
|
|
469
505
|
- "stream-json"
|
|
470
506
|
- "--verbose"
|
|
507
|
+
- "--max-turns"
|
|
508
|
+
- "{max_turns}" # Replaced with max_turns value
|
|
509
|
+
- "--permission-mode"
|
|
510
|
+
- "bypassPermissions"
|
|
471
511
|
max_turns: 200 # Maximum conversation turns per stage
|
|
512
|
+
read_only: false # If true, backend cannot write files
|
|
513
|
+
|
|
514
|
+
codex:
|
|
515
|
+
command: codex
|
|
516
|
+
args:
|
|
517
|
+
- "exec"
|
|
518
|
+
- "--full-auto"
|
|
519
|
+
- "--output-schema"
|
|
520
|
+
- "{schema_file}" # Replaced with schema file path
|
|
521
|
+
- "-o"
|
|
522
|
+
- "{output_file}" # Replaced with output file path
|
|
523
|
+
max_turns: 50
|
|
524
|
+
read_only: true # Codex runs in read-only sandbox
|
|
472
525
|
|
|
473
526
|
# Use different backends for specific stages
|
|
474
527
|
stage_backends:
|
|
475
|
-
|
|
528
|
+
REVIEW: codex # Use Codex for code review
|
|
529
|
+
# QA: gemini # Use Gemini for QA (when supported)
|
|
476
530
|
|
|
477
531
|
# =============================================================================
|
|
478
532
|
# DOCUMENTATION CONFIGURATION
|
|
@@ -569,6 +623,112 @@ stage_context:
|
|
|
569
623
|
- Secrets must use environment variables
|
|
570
624
|
```
|
|
571
625
|
|
|
626
|
+
## AI Backend Customization
|
|
627
|
+
|
|
628
|
+
Galangal invokes AI backends (like Claude Code CLI) using configurable commands and arguments. This allows you to customize CLI flags without modifying code.
|
|
629
|
+
|
|
630
|
+
### Default Behavior
|
|
631
|
+
|
|
632
|
+
By default, Galangal invokes Claude with:
|
|
633
|
+
```bash
|
|
634
|
+
cat prompt.txt | claude --output-format stream-json --verbose --max-turns 200 --permission-mode bypassPermissions
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
### Customizing CLI Flags
|
|
638
|
+
|
|
639
|
+
Override any flags in `.galangal/config.yaml`:
|
|
640
|
+
|
|
641
|
+
```yaml
|
|
642
|
+
ai:
|
|
643
|
+
backends:
|
|
644
|
+
claude:
|
|
645
|
+
command: claude
|
|
646
|
+
args:
|
|
647
|
+
- "--output-format"
|
|
648
|
+
- "stream-json"
|
|
649
|
+
- "--verbose"
|
|
650
|
+
- "--max-turns"
|
|
651
|
+
- "{max_turns}"
|
|
652
|
+
- "--permission-mode"
|
|
653
|
+
- "bypassPermissions"
|
|
654
|
+
- "--model" # Add custom flags
|
|
655
|
+
- "opus"
|
|
656
|
+
max_turns: 300 # Increase max turns
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
### Placeholder Reference
|
|
660
|
+
|
|
661
|
+
Arguments can include placeholders that are substituted at runtime:
|
|
662
|
+
|
|
663
|
+
| Placeholder | Backend | Description |
|
|
664
|
+
|-------------|---------|-------------|
|
|
665
|
+
| `{max_turns}` | claude | Maximum conversation turns |
|
|
666
|
+
| `{schema_file}` | codex | Path to JSON schema file |
|
|
667
|
+
| `{output_file}` | codex | Path for structured output |
|
|
668
|
+
|
|
669
|
+
### Common Customizations
|
|
670
|
+
|
|
671
|
+
**Use a specific model:**
|
|
672
|
+
```yaml
|
|
673
|
+
ai:
|
|
674
|
+
backends:
|
|
675
|
+
claude:
|
|
676
|
+
args:
|
|
677
|
+
- "--output-format"
|
|
678
|
+
- "stream-json"
|
|
679
|
+
- "--model"
|
|
680
|
+
- "sonnet" # Use Sonnet instead of default
|
|
681
|
+
- "--max-turns"
|
|
682
|
+
- "{max_turns}"
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
**Increase turn limit for complex tasks:**
|
|
686
|
+
```yaml
|
|
687
|
+
ai:
|
|
688
|
+
backends:
|
|
689
|
+
claude:
|
|
690
|
+
max_turns: 500 # Default is 200
|
|
691
|
+
args:
|
|
692
|
+
- "--output-format"
|
|
693
|
+
- "stream-json"
|
|
694
|
+
- "--max-turns"
|
|
695
|
+
- "{max_turns}" # Will use 500
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
**Use different backends per stage:**
|
|
699
|
+
```yaml
|
|
700
|
+
ai:
|
|
701
|
+
default: claude
|
|
702
|
+
stage_backends:
|
|
703
|
+
REVIEW: codex # Use Codex for code review
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
### Adding a Custom Backend
|
|
707
|
+
|
|
708
|
+
Define any CLI tool as a backend:
|
|
709
|
+
|
|
710
|
+
```yaml
|
|
711
|
+
ai:
|
|
712
|
+
backends:
|
|
713
|
+
my-backend:
|
|
714
|
+
command: my-ai-tool
|
|
715
|
+
args:
|
|
716
|
+
- "--prompt-file"
|
|
717
|
+
- "-" # Read from stdin
|
|
718
|
+
- "--json-output"
|
|
719
|
+
max_turns: 100
|
|
720
|
+
read_only: true # Cannot write files directly
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
Then use it:
|
|
724
|
+
```yaml
|
|
725
|
+
ai:
|
|
726
|
+
default: my-backend
|
|
727
|
+
# Or per-stage:
|
|
728
|
+
stage_backends:
|
|
729
|
+
QA: my-backend
|
|
730
|
+
```
|
|
731
|
+
|
|
572
732
|
## Customizing Prompts
|
|
573
733
|
|
|
574
734
|
Galangal uses a layered prompt system:
|
|
@@ -712,6 +872,8 @@ If the TEST stage keeps retrying instead of rolling back to DEV:
|
|
|
712
872
|
2. If tests fail due to implementation bugs, the AI should report FAIL (not try to fix the code)
|
|
713
873
|
3. Check that test commands exit with proper exit codes (0 for success, non-zero for failure)
|
|
714
874
|
|
|
875
|
+
**Note:** As of v0.12.0, when artifact markers are unclear (missing PASS/FAIL), Galangal prompts you to manually approve or reject instead of retrying indefinitely. You'll see the artifact content and can make the decision yourself.
|
|
876
|
+
|
|
715
877
|
### "Galangal has not been initialized" Error
|
|
716
878
|
|
|
717
879
|
Run `galangal init` in your project root before using other commands.
|
|
@@ -61,7 +61,7 @@ galangal status
|
|
|
61
61
|
| **PREFLIGHT** | Environment validation | PREFLIGHT_REPORT.md |
|
|
62
62
|
| **DEV** | Implementation | Code changes |
|
|
63
63
|
| **MIGRATION*** | Database migration checks | MIGRATION_REPORT.md |
|
|
64
|
-
| **TEST** | Test implementation | TEST_PLAN.md |
|
|
64
|
+
| **TEST** | Test implementation | TEST_PLAN.md, TEST_SUMMARY.md |
|
|
65
65
|
| **CONTRACT*** | API contract validation | CONTRACT_REPORT.md |
|
|
66
66
|
| **QA** | Quality assurance | QA_REPORT.md |
|
|
67
67
|
| **BENCHMARK*** | Performance validation | BENCHMARK_REPORT.md |
|
|
@@ -71,6 +71,15 @@ galangal status
|
|
|
71
71
|
|
|
72
72
|
*Conditional stages - skipped automatically if not relevant
|
|
73
73
|
|
|
74
|
+
### Validation Artifacts
|
|
75
|
+
|
|
76
|
+
When validation commands run (tests, linters, etc.), Galangal creates debugging artifacts:
|
|
77
|
+
|
|
78
|
+
- **VALIDATION_REPORT.md** - Full output from all validation commands, useful for debugging failures
|
|
79
|
+
- **TEST_SUMMARY.md** - Concise test results (pass/fail counts, failed test names, coverage) included in downstream stage prompts
|
|
80
|
+
|
|
81
|
+
These artifacts help you understand what failed without digging through logs, and give downstream stages (QA, REVIEW) context about test results without bloating prompts with verbose output.
|
|
82
|
+
|
|
74
83
|
## Task Types
|
|
75
84
|
|
|
76
85
|
Choose the right workflow for your task:
|
|
@@ -78,9 +87,9 @@ Choose the right workflow for your task:
|
|
|
78
87
|
| Type | Stages | When to Use |
|
|
79
88
|
|------|--------|-------------|
|
|
80
89
|
| **Feature** | All stages | New functionality |
|
|
81
|
-
| **Bug Fix** | PM → DEV → TEST → QA | Fixing bugs |
|
|
82
|
-
| **Refactor** | PM → DESIGN → DEV → TEST | Code restructuring |
|
|
83
|
-
| **Chore** | PM → DEV → TEST | Config, dependencies |
|
|
90
|
+
| **Bug Fix** | PM → PREFLIGHT → DEV → TEST → QA | Fixing bugs |
|
|
91
|
+
| **Refactor** | PM → DESIGN → PREFLIGHT → DEV → TEST | Code restructuring |
|
|
92
|
+
| **Chore** | PM → PREFLIGHT → DEV → TEST | Config, dependencies |
|
|
84
93
|
| **Docs** | PM → DOCS | Documentation only |
|
|
85
94
|
| **Hotfix** | PM → DEV → TEST | Critical fixes |
|
|
86
95
|
|
|
@@ -131,6 +140,32 @@ After analyzing your task, the PM stage outputs a `STAGE_PLAN.md` recommending w
|
|
|
131
140
|
|
|
132
141
|
The progress bar updates dynamically to show only relevant stages.
|
|
133
142
|
|
|
143
|
+
### Workflow Preview
|
|
144
|
+
|
|
145
|
+
After PM approval, you'll see a preview showing exactly which stages will run and why others are skipped:
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
Workflow Preview
|
|
149
|
+
|
|
150
|
+
Stages to run:
|
|
151
|
+
PM → DESIGN → PREFLIGHT → DEV → TEST → QA → REVIEW → DOCS
|
|
152
|
+
|
|
153
|
+
Skipping:
|
|
154
|
+
MIGRATION (no files match: **/migrations/*)
|
|
155
|
+
CONTRACT (no files match: **/api/*, **/openapi.*)
|
|
156
|
+
BENCHMARK (task type: bug_fix)
|
|
157
|
+
SECURITY (PM: simple UI change, no security impact)
|
|
158
|
+
|
|
159
|
+
Controls during execution:
|
|
160
|
+
^N Skip stage ^B Back ^E Pause for edit ^I Interrupt
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Skip reasons include:
|
|
164
|
+
- **Task type** - Based on the workflow template (e.g., bug fixes skip DESIGN)
|
|
165
|
+
- **Config** - Stages listed in `stages.skip` configuration
|
|
166
|
+
- **PM recommendation** - From STAGE_PLAN.md analysis
|
|
167
|
+
- **skip_if condition** - No changed files match the glob pattern
|
|
168
|
+
|
|
134
169
|
## Commands
|
|
135
170
|
|
|
136
171
|
| Command | Description |
|
|
@@ -367,6 +402,9 @@ validation:
|
|
|
367
402
|
- name: "Integration tests"
|
|
368
403
|
command: "pytest tests/integration"
|
|
369
404
|
optional: true # Don't fail if integration tests missing
|
|
405
|
+
# Use array form for paths with spaces or special characters
|
|
406
|
+
- name: "Task-specific tests"
|
|
407
|
+
command: ["pytest", "{task_dir}/tests"] # {task_dir} is substituted
|
|
370
408
|
|
|
371
409
|
# Contract stage (API compatibility)
|
|
372
410
|
contract:
|
|
@@ -422,21 +460,37 @@ ai:
|
|
|
422
460
|
# Default backend to use
|
|
423
461
|
default: claude
|
|
424
462
|
|
|
425
|
-
# Available backends
|
|
463
|
+
# Available backends with customizable CLI flags
|
|
426
464
|
backends:
|
|
427
465
|
claude:
|
|
428
|
-
command: claude
|
|
429
|
-
args:
|
|
430
|
-
- "-p"
|
|
431
|
-
- "{prompt}"
|
|
466
|
+
command: claude # CLI command to invoke
|
|
467
|
+
args: # Arguments with {placeholder} substitution
|
|
432
468
|
- "--output-format"
|
|
433
469
|
- "stream-json"
|
|
434
470
|
- "--verbose"
|
|
471
|
+
- "--max-turns"
|
|
472
|
+
- "{max_turns}" # Replaced with max_turns value
|
|
473
|
+
- "--permission-mode"
|
|
474
|
+
- "bypassPermissions"
|
|
435
475
|
max_turns: 200 # Maximum conversation turns per stage
|
|
476
|
+
read_only: false # If true, backend cannot write files
|
|
477
|
+
|
|
478
|
+
codex:
|
|
479
|
+
command: codex
|
|
480
|
+
args:
|
|
481
|
+
- "exec"
|
|
482
|
+
- "--full-auto"
|
|
483
|
+
- "--output-schema"
|
|
484
|
+
- "{schema_file}" # Replaced with schema file path
|
|
485
|
+
- "-o"
|
|
486
|
+
- "{output_file}" # Replaced with output file path
|
|
487
|
+
max_turns: 50
|
|
488
|
+
read_only: true # Codex runs in read-only sandbox
|
|
436
489
|
|
|
437
490
|
# Use different backends for specific stages
|
|
438
491
|
stage_backends:
|
|
439
|
-
|
|
492
|
+
REVIEW: codex # Use Codex for code review
|
|
493
|
+
# QA: gemini # Use Gemini for QA (when supported)
|
|
440
494
|
|
|
441
495
|
# =============================================================================
|
|
442
496
|
# DOCUMENTATION CONFIGURATION
|
|
@@ -533,6 +587,112 @@ stage_context:
|
|
|
533
587
|
- Secrets must use environment variables
|
|
534
588
|
```
|
|
535
589
|
|
|
590
|
+
## AI Backend Customization
|
|
591
|
+
|
|
592
|
+
Galangal invokes AI backends (like Claude Code CLI) using configurable commands and arguments. This allows you to customize CLI flags without modifying code.
|
|
593
|
+
|
|
594
|
+
### Default Behavior
|
|
595
|
+
|
|
596
|
+
By default, Galangal invokes Claude with:
|
|
597
|
+
```bash
|
|
598
|
+
cat prompt.txt | claude --output-format stream-json --verbose --max-turns 200 --permission-mode bypassPermissions
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
### Customizing CLI Flags
|
|
602
|
+
|
|
603
|
+
Override any flags in `.galangal/config.yaml`:
|
|
604
|
+
|
|
605
|
+
```yaml
|
|
606
|
+
ai:
|
|
607
|
+
backends:
|
|
608
|
+
claude:
|
|
609
|
+
command: claude
|
|
610
|
+
args:
|
|
611
|
+
- "--output-format"
|
|
612
|
+
- "stream-json"
|
|
613
|
+
- "--verbose"
|
|
614
|
+
- "--max-turns"
|
|
615
|
+
- "{max_turns}"
|
|
616
|
+
- "--permission-mode"
|
|
617
|
+
- "bypassPermissions"
|
|
618
|
+
- "--model" # Add custom flags
|
|
619
|
+
- "opus"
|
|
620
|
+
max_turns: 300 # Increase max turns
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
### Placeholder Reference
|
|
624
|
+
|
|
625
|
+
Arguments can include placeholders that are substituted at runtime:
|
|
626
|
+
|
|
627
|
+
| Placeholder | Backend | Description |
|
|
628
|
+
|-------------|---------|-------------|
|
|
629
|
+
| `{max_turns}` | claude | Maximum conversation turns |
|
|
630
|
+
| `{schema_file}` | codex | Path to JSON schema file |
|
|
631
|
+
| `{output_file}` | codex | Path for structured output |
|
|
632
|
+
|
|
633
|
+
### Common Customizations
|
|
634
|
+
|
|
635
|
+
**Use a specific model:**
|
|
636
|
+
```yaml
|
|
637
|
+
ai:
|
|
638
|
+
backends:
|
|
639
|
+
claude:
|
|
640
|
+
args:
|
|
641
|
+
- "--output-format"
|
|
642
|
+
- "stream-json"
|
|
643
|
+
- "--model"
|
|
644
|
+
- "sonnet" # Use Sonnet instead of default
|
|
645
|
+
- "--max-turns"
|
|
646
|
+
- "{max_turns}"
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
**Increase turn limit for complex tasks:**
|
|
650
|
+
```yaml
|
|
651
|
+
ai:
|
|
652
|
+
backends:
|
|
653
|
+
claude:
|
|
654
|
+
max_turns: 500 # Default is 200
|
|
655
|
+
args:
|
|
656
|
+
- "--output-format"
|
|
657
|
+
- "stream-json"
|
|
658
|
+
- "--max-turns"
|
|
659
|
+
- "{max_turns}" # Will use 500
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
**Use different backends per stage:**
|
|
663
|
+
```yaml
|
|
664
|
+
ai:
|
|
665
|
+
default: claude
|
|
666
|
+
stage_backends:
|
|
667
|
+
REVIEW: codex # Use Codex for code review
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
### Adding a Custom Backend
|
|
671
|
+
|
|
672
|
+
Define any CLI tool as a backend:
|
|
673
|
+
|
|
674
|
+
```yaml
|
|
675
|
+
ai:
|
|
676
|
+
backends:
|
|
677
|
+
my-backend:
|
|
678
|
+
command: my-ai-tool
|
|
679
|
+
args:
|
|
680
|
+
- "--prompt-file"
|
|
681
|
+
- "-" # Read from stdin
|
|
682
|
+
- "--json-output"
|
|
683
|
+
max_turns: 100
|
|
684
|
+
read_only: true # Cannot write files directly
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
Then use it:
|
|
688
|
+
```yaml
|
|
689
|
+
ai:
|
|
690
|
+
default: my-backend
|
|
691
|
+
# Or per-stage:
|
|
692
|
+
stage_backends:
|
|
693
|
+
QA: my-backend
|
|
694
|
+
```
|
|
695
|
+
|
|
536
696
|
## Customizing Prompts
|
|
537
697
|
|
|
538
698
|
Galangal uses a layered prompt system:
|
|
@@ -676,6 +836,8 @@ If the TEST stage keeps retrying instead of rolling back to DEV:
|
|
|
676
836
|
2. If tests fail due to implementation bugs, the AI should report FAIL (not try to fix the code)
|
|
677
837
|
3. Check that test commands exit with proper exit codes (0 for success, non-zero for failure)
|
|
678
838
|
|
|
839
|
+
**Note:** As of v0.12.0, when artifact markers are unclear (missing PASS/FAIL), Galangal prompts you to manually approve or reject instead of retrying indefinitely. You'll see the artifact content and can make the decision yourself.
|
|
840
|
+
|
|
679
841
|
### "Galangal has not been initialized" Error
|
|
680
842
|
|
|
681
843
|
Run `galangal init` in your project root before using other commands.
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"""AI backend abstractions and factory functions."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import shutil
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
from galangal.ai.base import AIBackend
|
|
9
|
+
from galangal.ai.claude import ClaudeBackend
|
|
10
|
+
from galangal.ai.codex import CodexBackend
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from galangal.config.schema import AIBackendConfig, GalangalConfig
|
|
14
|
+
from galangal.core.state import Stage
|
|
15
|
+
|
|
16
|
+
# Registry of available backends
|
|
17
|
+
BACKEND_REGISTRY: dict[str, type[AIBackend]] = {
|
|
18
|
+
"claude": ClaudeBackend,
|
|
19
|
+
"codex": CodexBackend,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
# Default fallback chain: backend -> fallback
|
|
23
|
+
DEFAULT_FALLBACKS: dict[str, str] = {
|
|
24
|
+
"codex": "claude",
|
|
25
|
+
"gemini": "claude",
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def get_backend(
|
|
30
|
+
name: str,
|
|
31
|
+
config: GalangalConfig | None = None,
|
|
32
|
+
) -> AIBackend:
|
|
33
|
+
"""
|
|
34
|
+
Factory function to instantiate backends by name.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
name: Backend name (e.g., "claude", "codex")
|
|
38
|
+
config: Optional project config to get backend-specific settings
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
Instantiated backend with configuration
|
|
42
|
+
|
|
43
|
+
Raises:
|
|
44
|
+
ValueError: If backend name is unknown
|
|
45
|
+
"""
|
|
46
|
+
backend_class = BACKEND_REGISTRY.get(name.lower())
|
|
47
|
+
if not backend_class:
|
|
48
|
+
available = list(BACKEND_REGISTRY.keys())
|
|
49
|
+
raise ValueError(f"Unknown backend: {name}. Available: {available}")
|
|
50
|
+
|
|
51
|
+
# Get backend-specific config if available
|
|
52
|
+
backend_config: AIBackendConfig | None = None
|
|
53
|
+
if config:
|
|
54
|
+
backend_config = config.ai.backends.get(name.lower())
|
|
55
|
+
|
|
56
|
+
return backend_class(backend_config)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def is_backend_available(
|
|
60
|
+
name: str,
|
|
61
|
+
config: GalangalConfig | None = None,
|
|
62
|
+
) -> bool:
|
|
63
|
+
"""
|
|
64
|
+
Check if a backend's CLI tool is available on the system.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
name: Backend name (e.g., "claude", "codex")
|
|
68
|
+
config: Optional project config to get custom command names
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
True if the backend's CLI is installed and accessible
|
|
72
|
+
"""
|
|
73
|
+
# Check config for custom command name
|
|
74
|
+
cmd: str | None
|
|
75
|
+
if config and name.lower() in config.ai.backends:
|
|
76
|
+
cmd = config.ai.backends[name.lower()].command
|
|
77
|
+
else:
|
|
78
|
+
# Fallback to default command names
|
|
79
|
+
cli_commands = {
|
|
80
|
+
"claude": "claude",
|
|
81
|
+
"codex": "codex",
|
|
82
|
+
"gemini": "gemini", # Future
|
|
83
|
+
}
|
|
84
|
+
cmd = cli_commands.get(name.lower())
|
|
85
|
+
|
|
86
|
+
if not cmd:
|
|
87
|
+
return False
|
|
88
|
+
return shutil.which(cmd) is not None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def get_backend_with_fallback(
|
|
92
|
+
name: str,
|
|
93
|
+
fallbacks: dict[str, str] | None = None,
|
|
94
|
+
config: GalangalConfig | None = None,
|
|
95
|
+
) -> AIBackend:
|
|
96
|
+
"""
|
|
97
|
+
Get a backend, falling back to alternatives if unavailable.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
name: Primary backend name
|
|
101
|
+
fallbacks: Optional custom fallback mapping. Defaults to DEFAULT_FALLBACKS.
|
|
102
|
+
config: Optional project config for backend settings
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
The requested backend if available, otherwise the fallback backend
|
|
106
|
+
|
|
107
|
+
Raises:
|
|
108
|
+
ValueError: If neither primary nor fallback backends are available
|
|
109
|
+
"""
|
|
110
|
+
fallbacks = fallbacks or DEFAULT_FALLBACKS
|
|
111
|
+
|
|
112
|
+
if is_backend_available(name, config):
|
|
113
|
+
return get_backend(name, config)
|
|
114
|
+
|
|
115
|
+
# Try fallback
|
|
116
|
+
fallback_name = fallbacks.get(name.lower())
|
|
117
|
+
if fallback_name and is_backend_available(fallback_name, config):
|
|
118
|
+
return get_backend(fallback_name, config)
|
|
119
|
+
|
|
120
|
+
# Last resort: try claude if it exists
|
|
121
|
+
if name.lower() != "claude" and is_backend_available("claude", config):
|
|
122
|
+
return get_backend("claude", config)
|
|
123
|
+
|
|
124
|
+
raise ValueError(f"Backend '{name}' not available and no fallback found")
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def get_backend_for_stage(
|
|
128
|
+
stage: Stage,
|
|
129
|
+
config: GalangalConfig,
|
|
130
|
+
use_fallback: bool = True,
|
|
131
|
+
) -> AIBackend:
|
|
132
|
+
"""
|
|
133
|
+
Get the appropriate backend for a specific stage.
|
|
134
|
+
|
|
135
|
+
Checks config.ai.stage_backends for stage-specific overrides,
|
|
136
|
+
otherwise uses config.ai.default.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
stage: The workflow stage
|
|
140
|
+
config: Project configuration
|
|
141
|
+
use_fallback: If True, fall back to alternative backends if primary unavailable
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
The configured backend for the stage
|
|
145
|
+
"""
|
|
146
|
+
# Check for stage-specific backend override
|
|
147
|
+
stage_key = stage.value.upper()
|
|
148
|
+
if stage_key in config.ai.stage_backends:
|
|
149
|
+
backend_name = config.ai.stage_backends[stage_key]
|
|
150
|
+
else:
|
|
151
|
+
backend_name = config.ai.default
|
|
152
|
+
|
|
153
|
+
if use_fallback:
|
|
154
|
+
return get_backend_with_fallback(backend_name, config=config)
|
|
155
|
+
return get_backend(backend_name, config)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
__all__ = [
|
|
159
|
+
"AIBackend",
|
|
160
|
+
"ClaudeBackend",
|
|
161
|
+
"CodexBackend",
|
|
162
|
+
"BACKEND_REGISTRY",
|
|
163
|
+
"get_backend",
|
|
164
|
+
"get_backend_for_stage",
|
|
165
|
+
"get_backend_with_fallback",
|
|
166
|
+
"is_backend_available",
|
|
167
|
+
]
|