Compare commits

...

32 Commits

Author SHA1 Message Date
HAL9000 31d01638e5 docs: add installation and setup guide 2026-04-19 04:02:54 +00:00
freemo 435e409df9 build: moved all sonnet agents to haiku
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / push-validation (push) Successful in 32s
CI / helm (push) Failing after 42s
CI / build (push) Successful in 3m59s
CI / lint (push) Successful in 4m10s
CI / quality (push) Successful in 4m37s
CI / typecheck (push) Successful in 4m48s
CI / security (push) Successful in 4m57s
CI / e2e_tests (push) Successful in 7m13s
CI / integration_tests (push) Successful in 10m40s
CI / unit_tests (push) Successful in 11m47s
CI / docker (push) Failing after 46s
CI / coverage (push) Successful in 14m54s
CI / status-check (push) Failing after 3s
CI / helm (pull_request) Successful in 37s
CI / push-validation (pull_request) Successful in 22s
CI / build (pull_request) Successful in 4m0s
CI / lint (pull_request) Successful in 4m37s
CI / quality (pull_request) Successful in 4m37s
CI / typecheck (pull_request) Successful in 4m55s
CI / security (pull_request) Successful in 5m23s
CI / integration_tests (pull_request) Successful in 8m16s
CI / e2e_tests (pull_request) Successful in 8m20s
CI / unit_tests (pull_request) Successful in 9m27s
CI / docker (pull_request) Successful in 1m48s
CI / coverage (pull_request) Successful in 15m1s
CI / status-check (pull_request) Successful in 3s
2026-04-18 12:33:27 -04:00
freemo 59a2a83328 build: fixed pr-merge filtering to avoid non-mergable PRs
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / push-validation (push) Successful in 28s
CI / helm (push) Successful in 45s
CI / build (push) Successful in 4m2s
CI / lint (push) Successful in 4m14s
CI / quality (push) Successful in 4m31s
CI / typecheck (push) Successful in 4m55s
CI / security (push) Successful in 5m14s
CI / e2e_tests (push) Successful in 7m17s
CI / integration_tests (push) Successful in 8m0s
CI / unit_tests (push) Successful in 9m18s
CI / docker (push) Failing after 46s
CI / coverage (push) Successful in 14m52s
CI / status-check (push) Failing after 4s
2026-04-18 01:41:40 -04:00
freemo bcf58f0703 build: being even more explicit about loading scripts
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / push-validation (push) Successful in 26s
CI / helm (push) Successful in 30s
CI / build (push) Successful in 3m51s
CI / lint (push) Successful in 4m4s
CI / quality (push) Successful in 4m27s
CI / typecheck (push) Successful in 4m43s
CI / security (push) Successful in 4m45s
CI / integration_tests (push) Successful in 6m51s
CI / e2e_tests (push) Successful in 7m23s
CI / unit_tests (push) Successful in 8m51s
CI / docker (push) Failing after 44s
CI / coverage (push) Successful in 14m47s
CI / status-check (push) Failing after 4s
2026-04-17 18:26:54 -04:00
freemo 37402e83c2 build: fixed some typos regarding script loading via skills
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / build (push) Failing after 42s
CI / lint (push) Failing after 48s
CI / typecheck (push) Failing after 50s
CI / helm (push) Failing after 26s
CI / quality (push) Failing after 55s
CI / push-validation (push) Failing after 27s
CI / security (push) Failing after 57s
CI / coverage (push) Has been skipped
CI / e2e_tests (push) Failing after 59s
CI / unit_tests (push) Failing after 1m3s
CI / docker (push) Has been skipped
CI / integration_tests (push) Failing after 1m3s
CI / status-check (push) Failing after 4s
2026-04-17 17:59:04 -04:00
freemo 7c13643441 build: final tweaks to get gpt5-nano working for pr-merge
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / lint (push) Failing after 43s
CI / typecheck (push) Failing after 38s
CI / security (push) Failing after 38s
CI / build (push) Failing after 34s
CI / quality (push) Failing after 46s
CI / coverage (push) Has been skipped
CI / integration_tests (push) Failing after 51s
CI / unit_tests (push) Failing after 55s
CI / e2e_tests (push) Failing after 53s
CI / docker (push) Has been skipped
CI / helm (push) Failing after 18s
CI / push-validation (push) Failing after 21s
CI / status-check (push) Failing after 5s
2026-04-17 17:44:25 -04:00
freemo 4e7bb5ae4e build: more explicit on how to run the script
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / lint (push) Failing after 39s
CI / typecheck (push) Failing after 42s
CI / build (push) Failing after 40s
CI / security (push) Failing after 48s
CI / quality (push) Failing after 49s
CI / coverage (push) Has been skipped
CI / e2e_tests (push) Failing after 53s
CI / integration_tests (push) Failing after 1m1s
CI / unit_tests (push) Failing after 1m1s
CI / docker (push) Has been skipped
CI / helm (push) Failing after 21s
CI / push-validation (push) Failing after 23s
CI / status-check (push) Waiting to run
2026-04-17 17:27:11 -04:00
freemo 47d630599a build: further clarified how to get the PRs using the scripts
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / push-validation (push) Successful in 12s
CI / helm (push) Failing after 18s
CI / lint (push) Successful in 23s
CI / build (push) Failing after 34s
CI / quality (push) Failing after 41s
CI / e2e_tests (push) Failing after 47s
CI / typecheck (push) Successful in 50s
CI / security (push) Successful in 50s
CI / coverage (push) Has been skipped
CI / integration_tests (push) Failing after 50s
CI / unit_tests (push) Successful in 3m22s
CI / docker (push) Has been skipped
CI / status-check (push) Failing after 1s
2026-04-17 17:07:58 -04:00
freemo 6153da8deb build: trying to improve skill comprehension of scripts
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / quality (push) Successful in 23s
CI / build (push) Failing after 30s
CI / lint (push) Failing after 39s
CI / typecheck (push) Failing after 41s
CI / helm (push) Failing after 18s
CI / push-validation (push) Successful in 21s
CI / security (push) Successful in 47s
CI / coverage (push) Has been skipped
CI / e2e_tests (push) Successful in 3m30s
CI / unit_tests (push) Successful in 7m22s
CI / docker (push) Has been skipped
CI / integration_tests (push) Successful in 7m25s
CI / status-check (push) Failing after 1s
2026-04-17 16:53:33 -04:00
freemo e8f06fa433 build: made invocation of scripts more explicit
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / lint (push) Successful in 20s
CI / helm (push) Failing after 21s
CI / push-validation (push) Failing after 24s
CI / typecheck (push) Successful in 34s
CI / security (push) Successful in 34s
CI / build (push) Failing after 37s
CI / quality (push) Failing after 44s
CI / coverage (push) Has been skipped
CI / unit_tests (push) Failing after 51s
CI / docker (push) Has been skipped
CI / integration_tests (push) Failing after 59s
CI / e2e_tests (push) Failing after 59s
CI / status-check (push) Failing after 1s
2026-04-17 16:32:37 -04:00
freemo 17bbe20376 Revert "build: adding auto-agents-system as a task as well as a skill."
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / build (push) Successful in 21s
CI / helm (push) Successful in 20s
CI / quality (push) Successful in 22s
CI / push-validation (push) Failing after 21s
CI / security (push) Failing after 43s
CI / lint (push) Failing after 44s
CI / typecheck (push) Failing after 44s
CI / coverage (push) Has been skipped
CI / unit_tests (push) Failing after 49s
CI / docker (push) Has been skipped
CI / e2e_tests (push) Successful in 3m18s
CI / integration_tests (push) Has been cancelled
CI / status-check (push) Has been cancelled
This reverts commit 5c8b5a84d2.
2026-04-17 16:28:28 -04:00
freemo 5c8b5a84d2 build: adding auto-agents-system as a task as well as a skill.
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / quality (push) Successful in 21s
CI / build (push) Failing after 30s
CI / lint (push) Failing after 40s
CI / typecheck (push) Failing after 40s
CI / push-validation (push) Failing after 19s
CI / security (push) Successful in 46s
CI / coverage (push) Has been skipped
CI / helm (push) Successful in 31s
CI / e2e_tests (push) Successful in 3m39s
CI / unit_tests (push) Successful in 7m23s
CI / integration_tests (push) Successful in 7m25s
CI / docker (push) Has been skipped
CI / status-check (push) Failing after 3s
2026-04-17 16:19:00 -04:00
freemo fe95acb856 build: added more clarification for loading scripts
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / lint (push) Successful in 22s
CI / quality (push) Successful in 22s
CI / typecheck (push) Successful in 45s
CI / security (push) Successful in 46s
CI / build (push) Successful in 26s
CI / helm (push) Successful in 32s
CI / push-validation (push) Successful in 22s
CI / e2e_tests (push) Successful in 3m58s
CI / unit_tests (push) Successful in 7m45s
CI / integration_tests (push) Successful in 7m42s
CI / docker (push) Successful in 56s
CI / coverage (push) Successful in 9m48s
CI / status-check (push) Successful in 1s
2026-04-17 16:02:21 -04:00
freemo 6ed9dbc2e7 build: expanded capabilities (permissions) of the git rebaser subagent
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / lint (push) Successful in 22s
CI / quality (push) Successful in 21s
CI / typecheck (push) Successful in 42s
CI / security (push) Successful in 42s
CI / build (push) Successful in 27s
CI / helm (push) Successful in 32s
CI / push-validation (push) Successful in 21s
CI / e2e_tests (push) Successful in 3m37s
CI / unit_tests (push) Successful in 7m53s
CI / integration_tests (push) Successful in 7m44s
CI / docker (push) Successful in 54s
CI / coverage (push) Successful in 9m57s
CI / status-check (push) Successful in 1s
2026-04-17 15:45:54 -04:00
freemo 555509c609 build: tweaked reasoning level on pr-merge related agents
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / lint (push) Successful in 20s
CI / quality (push) Successful in 18s
CI / typecheck (push) Successful in 44s
CI / security (push) Successful in 43s
CI / build (push) Successful in 27s
CI / helm (push) Successful in 32s
CI / push-validation (push) Successful in 21s
CI / e2e_tests (push) Successful in 3m51s
CI / unit_tests (push) Successful in 7m41s
CI / docker (push) Successful in 12s
CI / integration_tests (push) Successful in 7m41s
CI / coverage (push) Has been cancelled
CI / status-check (push) Has been cancelled
2026-04-17 15:34:56 -04:00
freemo aaeecd1616 build: reduced cost of models for merging by picking cheaper models
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / lint (push) Successful in 22s
CI / quality (push) Successful in 21s
CI / security (push) Successful in 47s
CI / build (push) Successful in 28s
CI / helm (push) Successful in 31s
CI / push-validation (push) Successful in 21s
CI / typecheck (push) Successful in 4m0s
CI / e2e_tests (push) Successful in 3m37s
CI / unit_tests (push) Successful in 7m23s
CI / integration_tests (push) Successful in 7m28s
CI / coverage (push) Has been cancelled
CI / docker (push) Has been cancelled
CI / status-check (push) Has been cancelled
2026-04-17 15:26:49 -04:00
freemo 868fdeff8a build: seperated out the actual rebase and conflict resolution to its own specialized subagent
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / push-validation (push) Successful in 16s
CI / lint (push) Successful in 21s
CI / typecheck (push) Successful in 33s
CI / security (push) Successful in 34s
CI / build (push) Successful in 37s
CI / helm (push) Successful in 40s
CI / quality (push) Successful in 48s
CI / e2e_tests (push) Successful in 3m38s
CI / coverage (push) Successful in 5m58s
CI / integration_tests (push) Successful in 7m0s
CI / unit_tests (push) Successful in 11m1s
CI / docker (push) Successful in 1m19s
CI / status-check (push) Successful in 1s
2026-04-17 15:03:24 -04:00
HAL9000 66850665b7 fix(sandbox): split oversized step file and update CONTRIBUTORS.md
CI / push-validation (pull_request) Successful in 10s
CI / helm (pull_request) Successful in 33s
CI / lint (pull_request) Successful in 44s
CI / quality (pull_request) Successful in 48s
CI / security (pull_request) Successful in 54s
CI / e2e_tests (pull_request) Successful in 3m14s
CI / build (pull_request) Successful in 3m25s
CI / typecheck (pull_request) Successful in 4m1s
CI / integration_tests (pull_request) Successful in 6m33s
CI / unit_tests (pull_request) Successful in 7m48s
CI / docker (pull_request) Successful in 55s
CI / coverage (pull_request) Successful in 5m58s
CI / status-check (pull_request) Successful in 2s
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / push-validation (push) Successful in 13s
CI / lint (push) Successful in 19s
CI / helm (push) Successful in 24s
CI / build (push) Successful in 31s
CI / quality (push) Successful in 39s
CI / typecheck (push) Successful in 42s
CI / security (push) Successful in 43s
CI / e2e_tests (push) Successful in 3m20s
CI / unit_tests (push) Successful in 3m36s
CI / integration_tests (push) Successful in 4m34s
CI / docker (push) Successful in 1m38s
CI / coverage (push) Successful in 9m25s
CI / status-check (push) Successful in 1s
Split checkpoint_manager_coverage_steps.py (692 lines) into three
focused modules to comply with the 500-line file limit:

- checkpoint_manager_coverage_steps.py: model, protocol, manager init,
  create_checkpoint, _snapshot_directory, and _cleanup_snapshot steps
  (408 lines)
- checkpoint_manager_rollback_steps.py: rollback_to, list_checkpoints,
  and delete_checkpoint branch steps (283 lines)
- checkpoint_manager_bug7488_steps.py: Bug #7488 sandbox_path
  auto-stored-in-metadata steps (59 lines)

Also updated CONTRIBUTORS.md to document HAL 9000's contribution for
bug fix #7488 as required by CONTRIBUTING.md guidelines.

ISSUES CLOSED: #7488
2026-04-17 18:34:16 +00:00
HAL9000 beceb183d0 fix(sandbox): store sandbox_path in checkpoint metadata to enable rollback
CheckpointManager.create_checkpoint() computed sandbox_path from
sandbox.context.sandbox_path but never stored it in the metadata dict.
This caused rollback_to() to always find metadata.get('sandbox_path')
returning None, silently skip the rollback, and return False.

The fix adds sandbox_path to the metadata dict immediately after it is
resolved from the sandbox context, before the SandboxCheckpoint is
constructed. rollback_to() can now retrieve the path and correctly
restore the sandbox filesystem state.

Added two new BDD scenarios to checkpoint_manager_coverage.feature:
- Verifies sandbox_path is automatically stored in metadata on create
- Verifies rollback succeeds without manually supplying sandbox_path

ISSUES CLOSED: #7488
2026-04-17 18:33:39 +00:00
freemo d6fca18c01 build: broke the 4 stage pr merge cycle into a 6 stage cycle and eliminating PRs that arent stale and need review
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / push-validation (push) Successful in 30s
CI / lint (push) Successful in 38s
CI / build (push) Successful in 40s
CI / helm (push) Successful in 42s
CI / typecheck (push) Successful in 47s
CI / quality (push) Successful in 58s
CI / e2e_tests (push) Successful in 3m44s
CI / security (push) Successful in 4m17s
CI / coverage (push) Successful in 5m59s
CI / integration_tests (push) Successful in 10m34s
CI / unit_tests (push) Successful in 10m41s
CI / docker (push) Successful in 57s
CI / status-check (push) Successful in 1s
2026-04-17 14:20:40 -04:00
CoreRasurae 0c5b140d29 fix(database): include alembic files in package distribution
CI / push-validation (pull_request) Successful in 18s
CI / lint (pull_request) Successful in 26s
CI / helm (pull_request) Successful in 38s
CI / build (pull_request) Successful in 48s
CI / quality (pull_request) Successful in 54s
CI / security (pull_request) Successful in 55s
CI / typecheck (pull_request) Successful in 57s
CI / e2e_tests (pull_request) Successful in 4m48s
CI / unit_tests (pull_request) Successful in 8m5s
CI / integration_tests (pull_request) Successful in 9m23s
CI / docker (pull_request) Successful in 1m23s
CI / coverage (pull_request) Successful in 12m29s
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / status-check (pull_request) Successful in 1s
CI / push-validation (push) Successful in 12s
CI / helm (push) Successful in 29s
CI / build (push) Successful in 3m23s
CI / lint (push) Successful in 3m38s
CI / quality (push) Successful in 3m40s
CI / security (push) Successful in 4m3s
CI / typecheck (push) Successful in 4m5s
CI / e2e_tests (push) Successful in 6m42s
CI / unit_tests (push) Successful in 10m7s
CI / integration_tests (push) Successful in 10m13s
CI / docker (push) Successful in 1m46s
CI / coverage (push) Successful in 10m58s
CI / status-check (push) Successful in 2s
Move alembic configuration and migration files from repository root into the
Python package structure to ensure they are included in the wheel distribution.

This fix resolves the FileNotFoundError when running `agents init` in Docker
containers or any environment using the built wheel distribution.

Changes:
- Move alembic/ directory from repo root to
  src/cleveragents/infrastructure/database/migrations/
- Move alembic.ini to the same new location and update script_location setting
- Update MigrationRunner._find_alembic_ini() to search from the new canonical
  location within the package
- Update create_template_db.py to point to the new alembic.ini location
- Update documentation references to reflect new migration file locations
- Create __init__.py for migrations package

- The env.py file is imported when running tests that verify all modules can be
  imported without errors. However, context.config is only available when alembic
  is actually running migrations, not during normal module imports. This caused
  an AttributeError when the test tried to import the migrations.env module.

- Fix by using getattr() with a default value to safely access context.config,
  and guard all code that uses config with None checks. This allows the module
  to be safely imported while still functioning correctly during migrations.

Testing:
- Verified MigrationRunner can locate alembic.ini in new location
- Tested agents init succeeds in creating project with database
- Template database creation works correctly
- All migration tests should pass without changes

Alembic files now follow standard Python packaging conventions, making them
automatically included in wheel distributions without special configuration.

ISSUES CLOSED: #4180
2026-04-17 17:40:00 +00:00
freemo 11ba77cf73 build: fix to get mroe predicatable behavior out of pr-merge-worker
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / lint (push) Successful in 29s
CI / typecheck (push) Successful in 50s
CI / security (push) Successful in 57s
CI / helm (push) Successful in 23s
CI / push-validation (push) Successful in 18s
CI / quality (push) Successful in 3m41s
CI / e2e_tests (push) Successful in 3m28s
CI / build (push) Successful in 3m41s
CI / integration_tests (push) Successful in 4m47s
CI / unit_tests (push) Successful in 6m31s
CI / docker (push) Successful in 26s
CI / coverage (push) Successful in 13m29s
CI / status-check (push) Successful in 1s
2026-04-17 13:35:25 -04:00
freemo 5762f92583 build: tweaked the pr-merge agents to ensure they use the skill scripts more consistently
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / push-validation (push) Successful in 23s
CI / build (push) Successful in 24s
CI / helm (push) Successful in 32s
CI / lint (push) Successful in 39s
CI / security (push) Successful in 53s
CI / typecheck (push) Successful in 1m1s
CI / e2e_tests (push) Successful in 3m10s
CI / quality (push) Successful in 3m46s
CI / integration_tests (push) Successful in 3m49s
CI / unit_tests (push) Successful in 5m44s
CI / docker (push) Successful in 54s
CI / coverage (push) Successful in 11m46s
CI / status-check (push) Successful in 1s
2026-04-17 13:00:24 -04:00
freemo afa4ebd19b build: fixed up the systems skill so it now provides better access to information about scripts to ensure more consistent usage
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / helm (push) Successful in 18s
CI / lint (push) Successful in 20s
CI / quality (push) Successful in 38s
CI / push-validation (push) Successful in 21s
CI / typecheck (push) Successful in 44s
CI / security (push) Successful in 44s
CI / e2e_tests (push) Successful in 3m12s
CI / build (push) Successful in 3m16s
CI / unit_tests (push) Successful in 3m35s
CI / docker (push) Successful in 8s
CI / integration_tests (push) Successful in 4m5s
CI / coverage (push) Has been cancelled
CI / status-check (push) Has been cancelled
2026-04-17 12:50:46 -04:00
hamza.khyari 1663750b78 Merge pull request 'fix(checkpoint): wire CheckpointManager into PlanExecutor execution path' (#4218) from bugfix/checkpoint-wiring into master
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / push-validation (push) Successful in 16s
CI / lint (push) Successful in 20s
CI / helm (push) Successful in 38s
CI / build (push) Successful in 39s
CI / quality (push) Successful in 40s
CI / typecheck (push) Successful in 44s
CI / security (push) Successful in 45s
CI / unit_tests (push) Successful in 3m33s
CI / integration_tests (push) Successful in 4m6s
CI / docker (push) Successful in 1m16s
CI / e2e_tests (push) Successful in 6m47s
CI / coverage (push) Successful in 7m6s
CI / status-check (push) Successful in 1s
Reviewed-on: #4218
Reviewed-by: Jeffrey Phillips Freeman <jeffrey.freeman@cleverthis.com>
2026-04-17 11:58:50 +00:00
hamza.khyari bdd1ea4f3a fix(checkpoint): wire CheckpointManager into PlanExecutor execution path
CI / push-validation (pull_request) Successful in 10s
CI / build (pull_request) Successful in 16s
CI / helm (pull_request) Successful in 16s
CI / typecheck (pull_request) Successful in 30s
CI / lint (pull_request) Successful in 35s
CI / quality (pull_request) Successful in 35s
CI / security (pull_request) Successful in 50s
CI / integration_tests (pull_request) Successful in 4m3s
CI / e2e_tests (pull_request) Successful in 4m14s
CI / unit_tests (pull_request) Successful in 5m13s
CI / docker (pull_request) Successful in 8s
CI / coverage (pull_request) Successful in 11m2s
CI / status-check (pull_request) Successful in 1s
CheckpointManager was never wired into PlanExecutor — the CLI factory
constructed PlanExecutor without a checkpoint_manager (defaulted to
None), silently skipping all checkpoint hooks.

Fix:
- Register CheckpointManager as Singleton in DI container
- Resolve container singleton in _get_plan_executor() and pass to
  PlanExecutor constructor
- Bridge infra→domain: _try_create_checkpoint() now persists
  last_checkpoint_id on the plan via _commit_plan(), raises PlanError
  if persistence fails
- Default checkpointable=True for writable+sandboxable resources and
  write-capable tools (model_validators on ResourceCapabilities and
  ToolCapability)
- Validate that non-writable/non-sandboxable resources cannot be
  checkpointable (ValueError guard)
- Add post-execute A2A facade notification using plan.status to avoid
  duplicate execute→execute transition errors

Tests:
- 10 Behave scenarios covering DI wiring, singleton identity, checkpoint
  creation, plan metadata update, rollback, graceful fallback, no-arg
  constructor, capability defaults (positive + 2 negative)
- Updated consolidated_resource, consolidated_skill, and Robot
  helper_skill_flatten for new checkpointable defaults

ISSUES CLOSED: #1253
2026-04-17 11:46:38 +00:00
hurui200320 e2b127b7e5 fix(e2e): replace naive OpenAI key-presence check with live API probe in E2E suite setups
CI / lint (pull_request) Successful in 37s
CI / typecheck (pull_request) Successful in 1m18s
CI / security (pull_request) Successful in 56s
CI / quality (pull_request) Successful in 48s
CI / build (pull_request) Successful in 30s
CI / helm (pull_request) Successful in 41s
CI / push-validation (pull_request) Successful in 28s
CI / integration_tests (pull_request) Successful in 4m32s
CI / e2e_tests (pull_request) Successful in 4m42s
CI / coverage (pull_request) Successful in 13m24s
CI / unit_tests (pull_request) Successful in 3m13s
CI / docker (pull_request) Successful in 1m36s
CI / status-check (pull_request) Successful in 1s
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / push-validation (push) Successful in 12s
CI / build (push) Successful in 15s
CI / helm (push) Successful in 16s
CI / lint (push) Successful in 43s
CI / typecheck (push) Successful in 51s
CI / security (push) Successful in 51s
CI / e2e_tests (push) Successful in 2m14s
CI / quality (push) Successful in 3m44s
CI / integration_tests (push) Successful in 7m0s
CI / unit_tests (push) Successful in 8m33s
CI / coverage (push) Successful in 6m21s
CI / docker (push) Successful in 1m31s
CI / status-check (push) Successful in 2s
The existing actor-selection logic in several E2E suite setups checked only
whether OPENAI_API_KEY was present (non-empty). A valid key that has hit its
quota limit passes that check but fails at runtime with HTTP 429, causing the
test to fail even though Anthropic credits are available.

Changes:
- Add robot/e2e/check_openai_key.py: stdlib-only (urllib.request) script that
  sends a minimal chat-completion request ('Hi', max_tokens=1, gpt-4o-mini) to
  the OpenAI API. Exits 0 on HTTP 200; exits 1 for quota (429), auth (401),
  network errors, or any other failure.
- Add 'Resolve LLM Actor' keyword to robot/e2e/common_e2e.resource: runs the
  probe script via ${PYTHON} and returns the openai_model argument (default
  openai/gpt-4o) on success, or the anthropic_model argument (default
  anthropic/claude-sonnet-4-20250514) on failure. Skips the probe entirely when
  OPENAI_API_KEY is not set.
- Update m6_acceptance.robot, wf04_multi_project.robot, wf05_db_migration.robot,
  wf07_cicd.robot, and wf16_devcontainer.robot to use 'Resolve LLM Actor'
  instead of the inline has_openai boolean check.

No production source code (src/) is modified. The decision to fall back to
Anthropic is made once per suite setup, before any test runs.

Closes #10198
2026-04-17 18:00:47 +08:00
hurui200320 80c8636c4a Revert "feat: add fallback to Anthropic Sonnet when OpenAI quota is exhausted"
This reverts commit f5712787e0.
2026-04-17 18:00:47 +08:00
hurui200320 8a89a5d5a6 Revert "debug: upgrade logging levels for fallback diagnostics"
This reverts commit 51472c0b37.
2026-04-17 18:00:46 +08:00
hurui200320 ed7276773e Merge branch 'master' into fix/plan-diff-correction-stub
CI / lint (pull_request) Successful in 27s
CI / typecheck (pull_request) Successful in 31s
CI / security (pull_request) Successful in 33s
CI / quality (pull_request) Successful in 32s
CI / build (pull_request) Successful in 24s
CI / helm (pull_request) Successful in 23s
CI / push-validation (pull_request) Successful in 19s
CI / e2e_tests (pull_request) Successful in 3m42s
CI / unit_tests (pull_request) Successful in 10m13s
CI / integration_tests (pull_request) Successful in 10m51s
CI / docker (pull_request) Successful in 1m15s
CI / coverage (pull_request) Successful in 10m55s
CI / status-check (pull_request) Successful in 1s
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / lint (push) Successful in 16s
CI / build (push) Successful in 16s
CI / typecheck (push) Successful in 35s
CI / security (push) Successful in 36s
CI / helm (push) Successful in 19s
CI / quality (push) Successful in 43s
CI / push-validation (push) Successful in 10s
CI / e2e_tests (push) Successful in 2m42s
CI / integration_tests (push) Successful in 7m7s
CI / unit_tests (push) Successful in 8m28s
CI / docker (push) Successful in 1m20s
CI / coverage (push) Successful in 12m10s
CI / status-check (push) Successful in 1s
2026-04-17 09:38:13 +00:00
hurui200320 1fda56b778 fix(cli): implement plan diff --correction to show real correction attempt diff
CI / lint (pull_request) Successful in 29s
CI / typecheck (pull_request) Successful in 58s
CI / quality (pull_request) Successful in 29s
CI / security (pull_request) Successful in 1m11s
CI / build (pull_request) Successful in 24s
CI / push-validation (pull_request) Successful in 21s
CI / helm (pull_request) Successful in 41s
CI / integration_tests (pull_request) Successful in 4m22s
CI / e2e_tests (pull_request) Successful in 4m39s
CI / unit_tests (pull_request) Successful in 9m51s
CI / coverage (pull_request) Successful in 13m30s
CI / docker (pull_request) Successful in 1m23s
CI / status-check (pull_request) Successful in 2s
Implement spec-compliant correction diff output for `agents plan diff
--correction <CORRECTION_ATTEMPT_ID>`. Fixes the following issues from
the cycle-1 PR review:

- C1/M1: Replace direct `unit_of_work.correction_attempts` access with
  the proper `unit_of_work.transaction()` context manager, eliminating
  the AttributeError crash and the resource (session) leak.
- C2: Add `unit_of_work: UnitOfWork | None = None` constructor parameter
  to `PlanApplyService` and wire it in `_get_apply_service()` via
  `container.unit_of_work()`, removing the illegal `get_container()`
  call inside the method body (ADR-003 DI violation).
- C3: Replace metadata serialization stub with a three-section structured
  diff (Correction Diff summary, Comparison table, Patch Preview) as
  specified in §agents plan diff of the specification.
- C4/M2: Add `features/plan_correction_diff.feature` with 6 BDD
  scenarios covering all 4 output formats plus plan-not-found and
  correction-not-found error paths.
- C5: Update the three existing BDD scenarios that tested old stub
  behavior to mock `_get_apply_service()` and assert the new output.
- C6: Rename branch to `bugfix/m4-plan-diff-correction-stub` per
  CONTRIBUTING.md convention.
- C7: Amend commit message with body and ISSUES CLOSED footer.
- C8: Narrow `except Exception` to `except CorrectionAttemptNotFoundError`
  to avoid masking programming errors.
- M3: Add `robot/plan_correction_diff.robot` and
  `robot/helper_plan_correction_diff.py` integration test covering rich,
  plain, and JSON formats and the not-found error path.
- M4: Type `_build_correction_diff_dict` parameter as
  `CorrectionAttemptRecord` instead of `Any`.
- M5: Change `fmt: str` to `fmt: Literal["rich", "plain", "json", "yaml"]`
  on both `diff()` and `correction_diff()`, with a `cast()` call in the
  CLI layer where Typer supplies a plain `str`.
- M6: Add `ValueError` guards for empty `plan_id` and
  `correction_attempt_id` at the top of `correction_diff()`.
- M7: Add blank line between `diff()` and `correction_diff()` method
  definitions.
- M8: Update PR description to reflect actual implementation.
- m1: Remove unused `plan` variable in `correction_diff()`.
- m2: Reduce three blank lines to two between top-level definitions in
  `plan_apply_service.py`.
- n1: Remove trailing whitespace from blank line in `plan.py`.

Quality gates: lint (ruff), typecheck (pyright strict), unit_tests
(Behave 632 features / 0 failures) all pass.

ISSUES CLOSED: #9085
2026-04-17 08:34:33 +00:00
hurui200320 8953449dc2 fix(actor): validate v3 YAML via ActorConfigSchema in agents actor add CLI
CI / lint (pull_request) Successful in 30s
CI / typecheck (pull_request) Successful in 1m15s
CI / security (pull_request) Successful in 1m18s
CI / quality (pull_request) Successful in 30s
CI / build (pull_request) Successful in 37s
CI / helm (pull_request) Successful in 29s
CI / push-validation (pull_request) Successful in 26s
CI / e2e_tests (pull_request) Successful in 3m58s
CI / integration_tests (pull_request) Successful in 6m49s
CI / unit_tests (pull_request) Successful in 8m39s
CI / docker (pull_request) Successful in 1m23s
CI / coverage (pull_request) Successful in 13m32s
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / status-check (pull_request) Successful in 1s
CI / lint (push) Successful in 25s
CI / typecheck (push) Successful in 1m1s
CI / quality (push) Successful in 55s
CI / security (push) Successful in 1m9s
CI / build (push) Successful in 24s
CI / helm (push) Successful in 30s
CI / push-validation (push) Successful in 20s
CI / e2e_tests (push) Successful in 5m13s
CI / integration_tests (push) Successful in 7m17s
CI / unit_tests (push) Successful in 8m50s
CI / docker (push) Successful in 1m30s
CI / coverage (push) Successful in 11m57s
CI / status-check (push) Successful in 2s
- schema.py: provider field changed to Optional[str] with model validator
  validate_provider_required_for_llm_graph() that requires it only for LLM
  and GRAPH actor types; TOOL actors do not require provider
- schema.py: is_v3_yaml() uses version_str == "3" or version_str.startswith("3.")
  to avoid false positives from "30" or "300" version strings
- schema.py: tool namespace validation uses strict 2-part split to reject
  empty namespace or empty name (e.g. "/tool", "ns/", "a/b/c")
- cli/commands/actor.py: schema_version extraction uses raw_version pattern
  (no # type: ignore[assignment]) for clean static typing
- actor/__init__.py: is_v3_yaml removed from __all__ and _LAZY_IMPORTS
  since it is a module-private helper, not a public API
- robot/actor_add_v3_schema_validation.robot: YAML fixtures for 'Reject v3
  LLM Actor Without Model Field' and 'Reject v3 TOOL Actor Without Tools
  Field' now include required provider field (and model for TOOL fixture)
- robot/helper_actor_add_v3_schema_validation.py: except clauses unified to
  catch (subprocess.TimeoutExpired, FileNotFoundError) in both add_actor()
  and update_actor() functions
- features/actor_add_v3_schema_validation.feature: 'Update a v3 actor with
  valid YAML succeeds' scenario now includes 'And the actor should be
  validated via ActorConfigSchema'; error assertions tightened to exact
  messages (e.g. "Input should be 'llm', 'tool' or 'graph'", "Node ID must
  be alphanumeric", "must be namespaced")
- features/steps/actor_add_v3_schema_validation_steps.py: step_run_actor_update
  now spies on ActorConfigSchema.model_validate; failure paths assert
  isinstance(result.exception, SystemExit)

ISSUES CLOSED: #5869
2026-04-17 16:28:45 +08:00
215 changed files with 8888 additions and 1887 deletions
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.2
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#E74C3C"
permission:
"*": deny
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.2
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
permission:
"*": deny
"doom_loop": deny
+1
View File
@@ -10,6 +10,7 @@ mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
permission:
"*": deny
"doom_loop": deny
@@ -7,7 +7,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: warning
permission:
"*": deny
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
permission:
"*": deny
"doom_loop": deny
@@ -7,7 +7,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.3
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: primary
permission:
"*": deny
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.3
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
permission:
"*": deny
"doom_loop": deny
+2 -1
View File
@@ -5,7 +5,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.2
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: success
permission:
"*": deny
@@ -6,6 +6,7 @@ mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#DC2626"
permission:
"*": deny
+1
View File
@@ -6,6 +6,7 @@ mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#DC2626"
permission:
"*": deny
+1
View File
@@ -8,6 +8,7 @@ mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#DC2626"
permission:
"*": deny
+1
View File
@@ -7,6 +7,7 @@ mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#DC2626"
permission:
"*": deny
+2 -1
View File
@@ -5,7 +5,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: error
permission:
"*": deny
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
permission:
"*": deny
"doom_loop": deny
+1
View File
@@ -7,6 +7,7 @@ mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#6B7280"
permission:
"*": deny
+1
View File
@@ -7,6 +7,7 @@ mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: info
permission:
"*": deny
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.3
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#9B59B6"
permission:
"*": deny
+2 -1
View File
@@ -5,7 +5,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.3
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
permission:
"*": deny
"doom_loop": deny
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.2
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: accent
permission:
"*": deny
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.2
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
permission:
"*": deny
"doom_loop": deny
+2 -1
View File
@@ -5,7 +5,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.2
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: info
permission:
"*": deny
+2 -1
View File
@@ -4,7 +4,8 @@ description: >
CI failure resolution and review feedback handling. User-facing.
mode: primary
temperature: 0.2
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#059669"
permission:
"*": deny
+2 -1
View File
@@ -7,7 +7,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#9B59B6"
permission:
"*": deny
@@ -7,6 +7,7 @@ mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#6B7280"
permission:
"*": deny
+1
View File
@@ -7,6 +7,7 @@ mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#10B981"
permission:
"*": deny
+188
View File
@@ -0,0 +1,188 @@
---
description: >
Git rebase helper. Rebases a branch onto a target branch (usually master)
and resolves any merge conflicts that arise. Ensures the rebase completes
fully by running git rebase --continue for every conflicting commit. Does
NOT push — the caller is responsible for pushing after this agent exits.
mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#F59E0B"
permission:
"*": deny
"doom_loop": deny
question: deny
"sequential-thinking*": allow
read: "allow"
grep: "allow"
glob: "allow"
edit:
"*": deny
"/tmp/**": allow
external_directory:
"/tmp/**": allow
webfetch: allow
websearch: allow
codesearch: allow
bash:
"*": deny
"git *": allow
"git push *": deny
"git * --force *": deny
"ls *": allow
"cat *": allow
"find *": allow
"grep *": allow
# Block ALL commands that could hit the label creation endpoints
"*api/v1/orgs/*/labels*": deny
"*api/v1/repos/*/labels*": deny
"*https://git.cleverthis.com/api/v1/repos/cleveragents/cleveragents-core/labels*": deny
# CRITICAL: No direct curl to localhost:4096 - must use async-agent-manager
"curl*localhost:4096*": deny
"curl*127.0.0.1:4096*": deny
task:
"*": deny
---
# Git Rebase Helper
You rebase a branch onto a target branch and resolve any merge conflicts that arise. You do not push — your caller handles that after you exit.
## What You Receive
Your prompt includes:
- **working_directory** — absolute path to the git clone
- **branch** — the feature branch to rebase (the branch whose history is rewritten)
- **base_branch** — the branch to rebase onto (usually `master` or `origin/master`)
- **git email** and **git name** — git author identity (optional; configure if provided)
## Rebase Procedure
Follow these steps exactly:
### 1. Prepare
```bash
# Optionally configure identity if provided
git -C "$WORK_DIR" config user.name "$GIT_USER_NAME"
git -C "$WORK_DIR" config user.email "$GIT_USER_EMAIL"
# Fetch the latest state of all branches
git -C "$WORK_DIR" fetch origin
# Switch to the feature branch
git -C "$WORK_DIR" checkout "$BRANCH"
# Confirm current state before starting
git -C "$WORK_DIR" log --oneline -5
git -C "$WORK_DIR" status
```
### 2. Start the rebase
```bash
git -C "$WORK_DIR" rebase "origin/$BASE_BRANCH"
```
If the rebase exits cleanly with no conflicts, skip to step 5 (Verify).
### 3. Resolve conflicts (repeat for every conflicting commit)
When the rebase pauses due to conflicts:
**a. Identify all conflicted files:**
```bash
git -C "$WORK_DIR" diff --name-only --diff-filter=U
```
**b. For each conflicted file:**
Read the file to understand what both sides changed:
```bash
cat "$WORK_DIR/$FILE"
```
The conflict markers look like:
```
<<<<<<< HEAD
(incoming from base_branch)
=======
(original from the rebased commit)
>>>>>>> <commit-sha> (<commit message>)
```
Study the recent git history on both sides to understand the intent:
```bash
# What changed on the base branch around this file
git -C "$WORK_DIR" log --oneline "HEAD..origin/$BASE_BRANCH" -- "$FILE"
git -C "$WORK_DIR" show "origin/$BASE_BRANCH" -- "$FILE"
# What this rebased commit intended to change
git -C "$WORK_DIR" show ORIG_HEAD -- "$FILE"
```
Use the `edit` tool to resolve the conflict. Remove all `<<<<<<<`, `=======`, and `>>>>>>>` markers. Produce a result that correctly incorporates both sets of changes, preserving the intent of the rebased commit against the current state of `base_branch`.
**c. Stage the resolved file:**
```bash
git -C "$WORK_DIR" add "$WORK_DIR/$FILE"
```
Repeat (b)(c) for every conflicted file in this commit.
**d. Continue the rebase:**
```bash
GIT_EDITOR=true git -C "$WORK_DIR" rebase --continue
```
`GIT_EDITOR=true` prevents git from opening an interactive editor for the commit message — the original commit message is preserved as-is.
**e. Check if more conflicts remain:**
If the rebase pauses again, return to step (a). Repeat until `git rebase --continue` completes without error.
**CRITICAL:** If a conflict cannot be resolved safely (e.g. a file was deleted on one side and heavily modified on the other, and the correct resolution is ambiguous), never abort the rebase, make a best effort and report accordingly when done.
### 4. Verify completion
After the rebase finishes cleanly:
```bash
# Confirm clean working tree (no conflict markers, nothing unstaged)
git -C "$WORK_DIR" status
# Show the rebased commits relative to base
git -C "$WORK_DIR" log --oneline "origin/$BASE_BRANCH..HEAD"
# Confirm no conflict markers remain in any file
git -C "$WORK_DIR" diff --check
```
If `git diff --check` reports any remaining conflict markers, find and fix them before returning.
## Return Value
Always return a structured summary to your caller:
- Final status of `git status`
- Short log of commits that were rebased (`git log --oneline origin/$BASE_BRANCH..HEAD`)
- List of files where conflicts were resolved (and a brief description of how each was resolved)
- Confirmation that the branch is ready to push
## **CRITICAL** Rules
1. **Never push.** Your job ends when the rebase is complete and verified. Pushing is the caller's responsibility.
2. **Never use `git rebase --skip`.** Skipping a commit silently discards its changes. If a commit cannot be applied, make a best effort.
3. **Never use `--force` git operations.** You are not pushing, so this does not apply, but do not run any destructive git commands not required by the rebase procedure.
4. **Always remove all conflict markers.** A file containing `<<<<<<<`, `=======`, or `>>>>>>>` that was staged would corrupt the commit. Run `git diff --check` to confirm all markers are gone.
5. **Preserve the intent of both sides.** When resolving a conflict, do not silently drop either side's changes without justification. If you cannot safely combine them, abort.
6. **Never work in `/app`.** The working directory provided by your caller must be inside `/tmp/`. Refuse and report an error if it is not.
7. **One task, then exit.** Do not look for more work, do not loop, do not sleep.
8. **Apply labels via `forgejo-label-manager`.** Never apply labels directly or using the Forgejo MCP/task. All label operations must go through `forgejo-label-manager`.
9. **Exhaustive pagination for all list results.** Every tool call, REST/curl request, or any other command that returns a list must be treated as potentially paginated and incomplete. Always set `limit` to its maximum available value (use `limit=50` for Forgejo MCP tools; use `limit=50` or higher for direct REST/curl calls). After each list response, check whether the number of returned items equals the page size — if so, there are likely more results; fetch the next page (`page=2`, `page=3`, …) and continue until receiving a partial page. Never assume the first response is the complete result. This rule applies to every list-returning call without exception. *Examples specific to this agent (not exhaustive):* `git diff --name-only --diff-filter=U` listing conflicted files must be fully processed — do not stop at an assumed cutoff; `git log` output during history inspection may be long — use `--no-pager` or explicit `--max-count` limits and be aware the output may be truncated; any future REST/curl calls returning JSON arrays must be paginated.
+2 -1
View File
@@ -7,7 +7,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#95A5A6"
permission:
"*": deny
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
permission:
"*": deny
"doom_loop": deny
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.3
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#3498DB"
permission:
"*": deny
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.3
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
permission:
"*": deny
"doom_loop": deny
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: info
permission:
"*": deny
+1
View File
@@ -7,6 +7,7 @@ mode: subagent
hidden: true
temperature: 0.0
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: info
permission:
"*": deny
@@ -6,6 +6,7 @@ mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#8B5CF6"
permission:
"*": deny
+1
View File
@@ -6,6 +6,7 @@ mode: subagent
hidden: true
temperature: 0.3
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: info
permission:
"*": deny
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.2
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: warning
permission:
"*": deny
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.2
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#9B59B6"
permission:
"*": deny
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: warning
permission:
"*": deny
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.0
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#9B59B6"
permission:
"*": deny
@@ -6,6 +6,7 @@ mode: subagent
hidden: true
temperature: 0.3
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: secondary
permission:
"*": deny
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#10B981"
permission:
"*": deny
+2 -1
View File
@@ -5,7 +5,8 @@ description: >
agents for specific operations. User-facing.
mode: all
temperature: 0.2
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#6366F1"
permission:
"*": deny
+22 -9
View File
@@ -7,7 +7,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-sonnet-4-6
model: openai/gpt-5-nano
reasoningEffort: "high"
color: "#059669"
permission:
"*": deny
@@ -20,11 +21,13 @@ permission:
external_directory:
"/tmp/**": allow
webfetch: deny
websearch: deny
codesearch: deny
bash:
"*": deny
"sleep *": allow
"jq *": allow
"npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/*": allow
"npx --yes tsx *.opencode/skills/auto-agents-system/scripts/*": allow
# Block ALL commands that could hit the label creation endpoints
"*api/v1/orgs/*/labels*": deny
"*api/v1/repos/*/labels*": deny
@@ -48,6 +51,12 @@ permission:
You are a supervisor that monitors open PRs for merge readiness, verifies all criteria are met, rebases stale PRs, resolves conflicts, and merges them. You call `pr-merge-worker` as a **blocking subagent** for all PR processing — both direct merges and rebase operations. Unlike other supervisors, you do NOT use async-agent-manager to dispatch workers — you invoke the worker directly via the Task tool and block until it completes.
## Do first
**Always** do the following things first before anything else:
- Load the `auto-agents-system` skill and from it learn how to use the scripts with the following names: `list_prs_ready_to_merge`, `list_prs_stale_clean`, `list_prs_stale_conflicts`, `list_prs_needs_review_stale_clean`, and `list_prs_needs_review_stale_conflicts`. Once you have queried the skill to fully understand these scripts you should understand what arguments it takes, what arguments are valid, how to call it, and what output you expect in return.
## What You Receive
Your prompt will include:
@@ -67,21 +76,23 @@ Every worker prompt must include:
- Whether the PR is stale (merge_base != base.sha)
- Current review status (any approvals? any unresolved REQUEST_CHANGES?)
- Current CI status if known
- If the PR has conflicts.
- Repository info, Forgejo PAT, git identity
- Credentials: PAT, username, password, git name, git email
## Main Loop
Before starting the main loop below be sure to create your status tracking ticket (see the tracking section below). Also, before starting the below main loop ensure you have enabled the `auto-agents-system` skill.
Before starting the main loop below be sure to create your status tracking ticket (see the tracking section below). Also, before starting the below main loop ensure you have loaded the `auto-agents-system` skill.
In an infinite loop do the following each cycle:
1. If at least 10 minutes has passed since the last time you updated your automation tracking status ticket, or if you never created/updated one, (see tracking section below) then update your tracking ticket using the `automation-tracking-manager` subagent according to the details provided in the section labeled "tracking" below.
2. Use the script `list_prs_ready_to_merge` from the `auto-agents-system` skill, if the list is empty skip to the next step, however, if it has one or more PR in it then sequentially dispatch a single `pr-merge-worker` subagent for each PR in the group and then start the cycle over at #1 (skipping the rest of the steps in this cycle)
3. Use the script `list_prs_stale_clean` from the `auto-agents-system` skill, if the list is empty skip to the next step, however, if it has one or more PR in it then sequentially dispatch a single `pr-merge-worker` subagent for each PR in the group and then start the cycle over at #1 (skipping the rest of the steps in this cycle)
4. Use the script `list_prs_stale_conflicts` from the `auto-agents-system` skill, if the list is empty skip to the next step, however, if it has one or more PR in it then sequentially dispatch a single `pr-merge-worker` subagent for each PR in the group and then start the cycle over at #1 (skipping the rest of the steps in this cycle)
5. Use the script `list_prs_needs_review` from the `auto-agents-system` skill, if the list is empty skip to the next step, however, if it has one or more PR in it then sequentially dispatch a single `pr-merge-worker` subagent for each PR in the group and then start the cycle over at #1 (skipping the rest of the steps in this cycle)
6. Sleep for 5 minutes using `bash("sleep 300", timeout=360000)`.
7. Loop through the cycle indefinately by starting at step 1 above again.
2. Run via bash tool the script named `list_prs_ready_to_merge` from the `auto-agents-system` skill which you must load and query how to use the mentioned skill, if the list is empty skip to the next step, however, if it has one or more PR in it then sequentially dispatch a single `pr-merge-worker` subagent for each PR in the group and then start the cycle over at #1 (skipping the rest of the steps in this cycle)
3. Run via bash tool the script named `list_prs_stale_clean` from the `auto-agents-system` skill which you must load and query how to use the mentioned skill, if the list is empty skip to the next step, however, if it has one or more PR in it then sequentially dispatch a single `pr-merge-worker` subagent for each PR in the group and then start the cycle over at #1 (skipping the rest of the steps in this cycle)
4. Run via bash tool the script named `list_prs_stale_conflicts` from the `auto-agents-system` skill which you must load and query how to use the mentioned skill, if the list is empty skip to the next step, however, if it has one or more PR in it then sequentially dispatch a single `pr-merge-worker` subagent for each PR in the group and then start the cycle over at #1 (skipping the rest of the steps in this cycle)
5. Run via bash tool the script named `list_prs_needs_review_stale_clean` from the `auto-agents-system` skill which you must load and query how to use the mentioned skill, if the list is empty skip to the next step, however, if it has one or more PR in it then sequentially dispatch a single `pr-merge-worker` subagent for each PR in the group and then start the cycle over at #1 (skipping the rest of the steps in this cycle)
6. Run via bash tool the script named `list_prs_needs_review_stale_conflicts` from the `auto-agents-system` skill which you must load and query how to use the mentioned skill, if the list is empty skip to the next step, however, if it has one or more PR in it then sequentially dispatch a single `pr-merge-worker` subagent for each PR in the group and then start the cycle over at #1 (skipping the rest of the steps in this cycle)
7. Sleep for 5 minutes using `bash("sleep 300", timeout=360000)`.
8. Loop through the cycle indefinately by starting at step 1 above again.
## Tracking
@@ -106,3 +117,5 @@ Supervisor: PR Merge Pool | Agent: pr-merge-pool-supervisor
3. **Apply labels via `forgejo-label-manager`.** Never apply labels directly or using the Forgejo MCP/task. All label operations must go through `forgejo-label-manager`.
4. **Exhaustive pagination for all list results.** Every tool call that returns a list must be treated as potentially paginated. Always set `limit=50` for Forgejo MCP tools. After each list response, check whether the number of returned items equals the page size — if so, fetch the next page. Never assume the first response is the complete result. This applies to: `forgejo_list_repo_pull_requests` (must paginate ALL pages — missing a page means a ready PR never gets merged), `forgejo_list_pull_reviews` (paginate to see all review rounds), `forgejo_list_issue_comments` (paginate when updating linked issues post-merge).
5. **Never close or change the label of a PR's issue** The issue for a PR will automatically be closed and the grooming agent will update its labels. Never close the originating issue directly or change its state.
6. **Never try to access Forgejo directly** All access to forgejo will occur through the scripts provided by the `auto-agents-system` skill and provide all the access to Forgejo you need, **never** try to call the Forgejo API directly.
7. **Never ask questions or give up** Under no circumstances should you ask questions for clarification, you must operate fully autonomously. You have all the resources you need to succeed at your task, do not give up and give it your best possible effort, any questions you may have just use your best judgement.
+25 -16
View File
@@ -6,7 +6,7 @@ description: >
mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-sonnet-4-6
model: openai/gpt-5-nano
permission:
"*": deny
"doom_loop": deny
@@ -18,9 +18,11 @@ permission:
"external_directory":
"/tmp/**": allow
webfetch: deny
websearch: deny
codesearch: deny
bash:
"*": deny
"git *": allow
"git status *": allow
"mkdir *": allow
"rm -rf *": allow
"sleep *": allow
@@ -36,7 +38,7 @@ permission:
"*": deny
"repo-isolator": allow
"git-commit-helper": allow
"forgejo-label-manager": allow
"git-rebase-helped": allow
skill:
"*": deny
"auto-agents-system": allow
@@ -46,30 +48,35 @@ permission:
You perform a single rebase operation on a PR branch, resolve any conflicts, and then exit. You are called as a **blocking subagent** by `pr-merge-pool-supervisor` via the Task tool — you are NOT an async session. The supervisor blocks until you finish and return your results.
## **CRITICAL** Running scripts from skills
## Do First
When running any scripts from skills use `npx --yes tsx <script_path> <args>` for example `npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/foo.ts --arg value`.
**Always** do the following things first before anything else:
- Load the `auto-agents-system` skill and from it learn how to use the scripts with the following names: `merge_pr`, and `rebase_pr`.
## Procedure
Your prompt tells you which PR to rebase. First you must determine if the PR has conflicts.
**CRITICAL**: Always follow this procedure exactly unless explicitly stated otherwise. You need to strictly adhere to these steps exactly as laid out whenever called except when clearly and explicitly stated in your prompt to deviate.
Before starting the below main loop ensure you have loaded the `auto-agents-system` skill.
Your prompt tells you which PR to rebase. Your prompt will tell you all the information you need, no need to investigate the PR for more information.
If the PR is stale and has conflicts then do the following:
1. Create an isolated clone using the `repo-isolator` subagent ensuring you pass it the branch used by the PR. Make sure all work is done within this clone's directory.
2. Rebase it onto the base branch (usually `master`).
3. Resolve any conflicts that arise by reviewing the recent git history and using that to fix the conflicts
4. Force-push with lease using `git-commit-helper`
5. Clean up the clone.
6. load the skill `auto-agents-system` and run the script `merge_pr` to initiate the merge (or at least auto-schedule it).
7. Report back with any relevant details.
2. Call the `git-rebase-helper` subagent and pass it the directory of the isolated and cloned repo, the base branch as master, and the name of the branch to be rebased, instruct it to conduct the rebase and conflict resolution, and finish any rebase operation, but not to push.
3. Pass the correct branch, and repo directory in the prompt, and instruct `git-commit-helper` subagent to force-push the branch with lease
4. Clean up the clone.
5. load the skill `auto-agents-system` and run, via the bash tool, the script named `merge_pr` from the skill to initiate the merge (or at least auto-schedule it).
6. Report back with any relevant details.
If the PR does **not** have any conflicts but is stale:
1. Load the skill `auto-agents-system` and run the script `rebase_pr` to initiate an on-server rebase.
2. load the skill `auto-agents-system` and run the script `merge_pr` to initiate the merge (or at least auto-schedule it).
1. Load the skill `auto-agents-system` and run, via the bash tool, the script named `rebase_pr` from the skill to initiate an on-server rebase.
2. load the skill `auto-agents-system` and run, via the bash tool, the script named `merge_pr` from the skill to initiate the merge (or at least auto-schedule it).
3. Report back with any relevant details.
If the PR is **not** stale (and therefore wouldnt have any conflicts either):
1. load the skill `auto-agents-system` and run the script `merge_pr` to initiate the merge (or at least auto-schedule it).
1. load the skill `auto-agents-system` and run, via the bash tool, the script named `merge_pr` to initiate the merge (or at least auto-schedule it).
2. Report back with any relevant details.
## **CRITICAL** Rules
@@ -80,4 +87,6 @@ If the PR is **not** stale (and therefore wouldnt have any conflicts either):
4. **Apply labels via `forgejo-label-manager`.** Never apply labels directly or using the Forgejo MCP/task. All label operations must go through `forgejo-label-manager`.
5. **Exhaustive pagination for all list results.** Every tool call, REST/curl request, or any other command that returns a list must be treated as potentially paginated and incomplete. Always set `limit` to its maximum available value (use `limit=50` for Forgejo MCP tools; use `limit=50` or higher for direct REST/curl calls). After each list response, check whether the number of returned items equals the page size — if so, there are likely more results; fetch the next page (`page=2`, `page=3`, …) and continue until receiving a partial page. Never assume the first response is the complete result. This rule applies to every list-returning call without exception. *Examples specific to this agent (not exhaustive):* `git log` listing commits during conflict resolution must be fully read; any future REST/curl calls returning JSON arrays must be paginated.
6. **Never close or change the label of a PR's issue** The issue for a PR will automatically be closed and the grooming agent will update its labels. Never close the originating issue directly or change its state.
7. **CRITICAL** Never wait for CI quality gates or merges to finish, merge, when set, will be scheduled to occur automatically when tests complete.
7. **CRITICAL** Never wait for CI quality gates or merges to finish, merge, when set, will be scheduled to occur automatically when tests complete.
8. **Never try to access Forgejo directly** All access to forgejo will occur through the scripts provided by the `auto-agents-system` skill and provide all the access to Forgejo you need, **never** try to call the Forgejo API directly.
9. **Never ask questions or give up** Under no circumstances should you ask questions for clarification, you must operate fully autonomously. You have all the resources you need to succeed at your task, do not give up and give it your best possible effort, any questions you may have just use your best judgement.
@@ -7,7 +7,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: info
permission:
edit: deny
+2 -1
View File
@@ -7,7 +7,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.2
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: warning
permission:
"*": deny
+1
View File
@@ -6,6 +6,7 @@ mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#3B82F6"
permission:
"*": deny
+4 -1
View File
@@ -5,7 +5,8 @@ description: >
and reports status. Never does implementation work itself.
mode: primary
temperature: 0.1
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: primary
permission:
"*": deny
@@ -14,6 +15,8 @@ permission:
"sequential-thinking*": allow
edit: deny
webfetch: deny
websearch: deny
codesearch: deny
bash:
"*": deny
"echo $*": allow
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: info
permission:
"*": deny
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.2
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: primary
permission:
"*": deny
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.3
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#8E44AD"
permission:
"*": deny
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.3
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
permission:
"*": deny
"doom_loop": deny
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.0
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: error
permission:
"*": deny
+1
View File
@@ -7,6 +7,7 @@ mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#6B7280"
permission:
"*": deny
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.0
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: info
permission:
"*": deny
+1
View File
@@ -7,6 +7,7 @@ mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#6B7280"
permission:
"*": deny
+2 -1
View File
@@ -5,7 +5,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.0
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: info
permission:
"*": deny
@@ -7,7 +7,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.2
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#9B59B6"
permission:
"*": deny
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.2
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
permission:
"*": deny
"doom_loop": deny
+2 -1
View File
@@ -5,7 +5,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.0
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: warning
permission:
"*": deny
+1
View File
@@ -9,6 +9,7 @@ mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: accent
permission:
"*": deny
@@ -7,7 +7,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#E74C3C"
permission:
"*": deny
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
permission:
"*": deny
"doom_loop": deny
@@ -7,7 +7,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.2
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#2ECC71"
permission:
"*": deny
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.2
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
permission:
"*": deny
"doom_loop": deny
+1
View File
@@ -6,6 +6,7 @@ mode: subagent
hidden: true
temperature: 0.0
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
permission:
"*": deny
"doom_loop": deny
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: "#2ECC71"
permission:
"*": deny
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.1
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
permission:
"*": deny
"doom_loop": deny
+2 -1
View File
@@ -7,7 +7,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.3
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
color: success
permission:
"*": deny
+2 -1
View File
@@ -6,7 +6,8 @@ description: >
mode: subagent
hidden: true
temperature: 0.3
model: anthropic/claude-sonnet-4-6
model: anthropic/claude-haiku-4-5
reasoningEffort: "max"
permission:
"*": deny
"doom_loop": deny
@@ -1,70 +0,0 @@
# Async Agent Manager Migration Summary
## Problem Identified
The `async-agent-starter` subagent was failing because it tried to use bash with curl commands, but the environment was restricting these operations. The error message showed:
> "I don't currently have the ability to run the required shell or HTTP commands from this environment"
## Solution Implemented
### 1. Created New `async-agent-manager.md`
- Renamed from `async-agent-starter` to better reflect its expanded responsibilities
- Enhanced to handle all async agent operations:
- Starting async agents
- Getting session status
- Retrieving session messages
- Searching sessions by tag
- Closing/cleanup sessions
- Monitoring session health
- Properly configured with explicit curl permissions to localhost:4096
- Includes detailed curl command examples that have been tested and verified to work
### 2. Updated All Agents Using Async Operations
#### Primary Agent Updated:
- **product-builder.md**:
- Removed direct curl permissions to localhost:4096
- Added permission to use `async-agent-manager` subagent
- Updated `launch_supervisor` function to use async-agent-manager instead of direct curl
- Updated all session status queries to use async-agent-manager
- Updated session conversation retrieval to use async-agent-manager
#### Pool Supervisors Updated:
- **implementation-orchestrator.md**: Updated all references from async-agent-starter to async-agent-manager
- **uat-tester.md**: Added async-agent-manager permission and updated worker launch code
- **test-infra-improver.md**: Added async-agent-manager permission and updated worker launch code
- **continuous-pr-reviewer.md**: Added async-agent-manager permission and updated reviewer dispatch code
- **bug-hunter.md**: Added async-agent-manager permission (already structured for worker dispatch)
#### Other Agents Updated:
- **subtask-loop.md**: Updated all references from async-agent-starter to async-agent-manager
- **async-agent-monitor.md**: Updated to use async-agent-manager for restart operations
- **system-watchdog.md**: Added async-agent-manager permission and updated dispatch_one_off function
- **async-agent-cleanup.md**: Removed direct curl permissions, added async-agent-manager permission
- **async-agent-cleanup-all.md**: Removed direct curl permissions, added async-agent-manager permission
### 3. Key Design Principles
1. **Single Point of Control**: Only `async-agent-manager` has permission to curl to localhost:4096
2. **Consistent Interface**: All agents use the same Task tool interface to interact with async operations
3. **Proper Error Handling**: The manager returns structured JSON responses for all operations
4. **Security**: Properly escapes all inputs to prevent injection attacks
5. **Comprehensive Operations**: Handles the full lifecycle of async sessions
### 4. Testing
Created and ran a test script that verified:
- Session listing works correctly
- Session status retrieval works correctly
- Session creation returns proper session IDs
- Async agent launch returns HTTP 204 (success)
- Session deletion works correctly
## Benefits
1. **Centralized Management**: All async operations go through a single, well-tested agent
2. **Better Error Handling**: Structured responses make it easier to handle failures
3. **Improved Security**: Only one agent needs curl permissions to the API
4. **Easier Maintenance**: Changes to the API only need to be updated in one place
5. **Consistent Patterns**: All agents use the same interface for async operations
## Migration Complete
All agents that previously used direct curl commands or async-agent-starter have been updated to use the new async-agent-manager. The old async-agent-starter.md file has been removed.
+283 -10
View File
@@ -5,21 +5,100 @@
"packages": {
"": {
"dependencies": {
"@opencode-ai/plugin": "1.3.17"
"@opencode-ai/plugin": "1.4.8"
}
},
"node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz",
"integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz",
"integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz",
"integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz",
"integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz",
"integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz",
"integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@opencode-ai/plugin": {
"version": "1.3.17",
"resolved": "https://registry.npmjs.org/@opencode-ai/plugin/-/plugin-1.3.17.tgz",
"integrity": "sha512-N5lckFtYvEu2R8K1um//MIOTHsJHniF2kHoPIWPCrxKG5Jpismt1ISGzIiU3aKI2ht/9VgcqKPC5oZFLdmpxPw==",
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/@opencode-ai/plugin/-/plugin-1.4.8.tgz",
"integrity": "sha512-arbggGAwR7vE6d5a/Ra8A7yECXYcOAPyRbJHzkofLLiVzyclsThFaL2SSCZw/UNJJTtt3L7JGl95phFodJq8tQ==",
"license": "MIT",
"dependencies": {
"@opencode-ai/sdk": "1.3.17",
"@opencode-ai/sdk": "1.4.8",
"effect": "4.0.0-beta.48",
"zod": "4.1.8"
},
"peerDependencies": {
"@opentui/core": ">=0.1.96",
"@opentui/solid": ">=0.1.96"
"@opentui/core": ">=0.1.100",
"@opentui/solid": ">=0.1.100"
},
"peerDependenciesMeta": {
"@opentui/core": {
@@ -31,16 +110,24 @@
}
},
"node_modules/@opencode-ai/sdk": {
"version": "1.3.17",
"resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-1.3.17.tgz",
"integrity": "sha512-2+MGgu7wynqTBwxezR01VAGhILXlpcHDY/pF7SWB87WOgLt3kD55HjKHNj6PWxyY8n575AZolR95VUC3gtwfmA==",
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-1.4.8.tgz",
"integrity": "sha512-DTN0TwRxuBxdm2JvJO3Dg7Vp9/j8PFpTS/26qD6Mzi6UPI5+NBxgcDVkozKygi55Goj3AAQGJPp63qzbdc+8ag==",
"license": "MIT",
"dependencies": {
"cross-spawn": "7.0.6"
}
},
"node_modules/@standard-schema/spec": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
"integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
"license": "MIT"
},
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
@@ -51,19 +138,164 @@
"node": ">= 8"
}
},
"node_modules/detect-libc": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
"license": "Apache-2.0",
"optional": true,
"engines": {
"node": ">=8"
}
},
"node_modules/effect": {
"version": "4.0.0-beta.48",
"resolved": "https://registry.npmjs.org/effect/-/effect-4.0.0-beta.48.tgz",
"integrity": "sha512-MMAM/ZabuNdNmgXiin+BAanQXK7qM8mlt7nfXDoJ/Gn9V8i89JlCq+2N0AiWmqFLXjGLA0u3FjiOjSOYQk5uMw==",
"license": "MIT",
"dependencies": {
"@standard-schema/spec": "^1.1.0",
"fast-check": "^4.6.0",
"find-my-way-ts": "^0.1.6",
"ini": "^6.0.0",
"kubernetes-types": "^1.30.0",
"msgpackr": "^1.11.9",
"multipasta": "^0.2.7",
"toml": "^4.1.1",
"uuid": "^13.0.0",
"yaml": "^2.8.3"
}
},
"node_modules/fast-check": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.6.0.tgz",
"integrity": "sha512-h7H6Dm0Fy+H4ciQYFxFjXnXkzR2kr9Fb22c0UBpHnm59K2zpr2t13aPTHlltFiNT6zuxp6HMPAVVvgur4BLdpA==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/dubzzz"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fast-check"
}
],
"license": "MIT",
"dependencies": {
"pure-rand": "^8.0.0"
},
"engines": {
"node": ">=12.17.0"
}
},
"node_modules/find-my-way-ts": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/find-my-way-ts/-/find-my-way-ts-0.1.6.tgz",
"integrity": "sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA==",
"license": "MIT"
},
"node_modules/ini": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz",
"integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==",
"license": "ISC",
"engines": {
"node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"license": "ISC"
},
"node_modules/kubernetes-types": {
"version": "1.30.0",
"resolved": "https://registry.npmjs.org/kubernetes-types/-/kubernetes-types-1.30.0.tgz",
"integrity": "sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q==",
"license": "Apache-2.0"
},
"node_modules/msgpackr": {
"version": "1.11.9",
"resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.9.tgz",
"integrity": "sha512-FkoAAyyA6HM8wL882EcEyFZ9s7hVADSwG9xrVx3dxxNQAtgADTrJoEWivID82Iv1zWDsv/OtbrrcZAzGzOMdNw==",
"license": "MIT",
"optionalDependencies": {
"msgpackr-extract": "^3.0.2"
}
},
"node_modules/msgpackr-extract": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz",
"integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"dependencies": {
"node-gyp-build-optional-packages": "5.2.2"
},
"bin": {
"download-msgpackr-prebuilds": "bin/download-prebuilds.js"
},
"optionalDependencies": {
"@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3",
"@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3",
"@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3",
"@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3",
"@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3",
"@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3"
}
},
"node_modules/multipasta": {
"version": "0.2.7",
"resolved": "https://registry.npmjs.org/multipasta/-/multipasta-0.2.7.tgz",
"integrity": "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA==",
"license": "MIT"
},
"node_modules/node-gyp-build-optional-packages": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz",
"integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==",
"license": "MIT",
"optional": true,
"dependencies": {
"detect-libc": "^2.0.1"
},
"bin": {
"node-gyp-build-optional-packages": "bin.js",
"node-gyp-build-optional-packages-optional": "optional.js",
"node-gyp-build-optional-packages-test": "build-test.js"
}
},
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/pure-rand": {
"version": "8.4.0",
"resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-8.4.0.tgz",
"integrity": "sha512-IoM8YF/jY0hiugFo/wOWqfmarlE6J0wc6fDK1PhftMk7MGhVZl88sZimmqBBFomLOCSmcCCpsfj7wXASCpvK9A==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/dubzzz"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fast-check"
}
],
"license": "MIT"
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"license": "MIT",
"dependencies": {
"shebang-regex": "^3.0.0"
@@ -74,13 +306,39 @@
},
"node_modules/shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/toml": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/toml/-/toml-4.1.1.tgz",
"integrity": "sha512-EBJnVBr3dTXdA89WVFoAIPUqkBjxPMwRqsfuo1r240tKFHXv3zgca4+NJib/h6TyvGF7vOawz0jGuryJCdNHrw==",
"license": "MIT",
"engines": {
"node": ">=20"
}
},
"node_modules/uuid": {
"version": "13.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz",
"integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"license": "MIT",
"bin": {
"uuid": "dist-node/bin/uuid"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
@@ -92,6 +350,21 @@
"node": ">= 8"
}
},
"node_modules/yaml": {
"version": "2.8.3",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz",
"integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==",
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
},
"engines": {
"node": ">= 14.6"
},
"funding": {
"url": "https://github.com/sponsors/eemeli"
}
},
"node_modules/zod": {
"version": "4.1.8",
"license": "MIT",
File diff suppressed because it is too large Load Diff
@@ -44,7 +44,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
└── system-watchdog-worker ← dispatched by AUTO-WDOG
```
---
## Pool Supervisor Detailed Reference
@@ -66,7 +65,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
**Never dispatches to**: PRs that are already in mergeable state (passing CI + approval)
---
### 2. PR Review Pool (`AUTO-REV-SUP`)
@@ -80,7 +78,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
**Special**: Receives `FORGEJO_REVIEWER_PAT/USERNAME/PASSWORD` instead of primary credentials.
---
### 3. PR Merge Pool (`AUTO-PRMRG-SUP`)
@@ -90,11 +87,10 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
**Workers**: `pr-merge-worker` via **blocking Task tool call** (not async)
**Worker tag pattern**: NONE — no `[AUTO-PRMRG-N]` sessions ever exist
**Role**: Merges approved PRs. Verifies seven merge criteria. Handles pre-merge rebasing.
**Role**: Merges approved PRs. Verifies merge criteria. Handles pre-merge rebasing.
**⚠️ Special**: Does NOT use async-agent-manager. Calls `pr-merge-worker` directly as a Task subagent and blocks until it completes. When the supervisor is busy executing its worker, it appears as a normal busy session — this is correct behavior. Product-builder and system-watchdog must NOT flag the absence of `[AUTO-PRMRG-N]` sessions as a problem.
---
### 4. UAT Test Pool (`AUTO-UAT-SUP`)
@@ -106,31 +102,28 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
**Role**: Specification-driven user acceptance testing. Discovers testable feature areas from the spec, dispatches workers to test each area, files bug issues for gaps. Only assigns Priority/Critical bugs to the active milestone (scope guard).
---
### 5. Bug Hunt Pool (`AUTO-BUG-SUP`)
**Definition**: `bug-hunt-pool-supervisor`
**Worker count**: N_QUARTER
**Sleep**: 900 seconds (15 minutes)
**Workers**: `bug-hunt-worker` (async sessions, use Gemini 2.5 Pro for large context)
**Workers**: `bug-hunt-worker` (async sessions)
**Worker tag pattern**: `[AUTO-BUG-N]`
**Role**: Proactive bug detection. Maps source modules, dispatches workers for deep code analysis combined with specification comparison.
---
### 6. Test Infrastructure Pool (`AUTO-INF-SUP`)
**Definition**: `test-infra-pool-supervisor`
**Worker count**: N_QUARTER
**Sleep**: 900 seconds (15 minutes)
**Workers**: `test-infra-worker` (async sessions, use Gemini 2.5 Pro)
**Workers**: `test-infra-worker` (async sessions)
**Worker tag pattern**: `[AUTO-INF-N]`
**Role**: Testing infrastructure improvement. Analyzes CI timing, coverage gaps, test architecture. Never disables or weakens existing checks — only proposes additions and optimizations.
---
### 7. Architecture (`AUTO-ARCH`)
@@ -142,7 +135,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
**Role**: Specification authoring and module boundary definition. **The most consequential agent** — bad architecture cascades everywhere. Major changes go through PRs with `needs feedback` label for human approval.
---
### 8. Epic Planning (`AUTO-EPIC`)
@@ -154,7 +146,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
**Role**: Decomposes architecture into Forgejo Epics and Issues. Monitors for milestones without issues, epics without children. Creates dependency chains and metadata.
---
### 9. Human Liaison (`AUTO-HUMAN`)
@@ -166,7 +157,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
**Role**: Bridge to humans. Monitors all human activity on Forgejo. Has full triage authority. Responds to new issues, comments, PR reviews, and label changes.
---
### 10. Agent Evolution (`AUTO-EVLV`)
@@ -178,7 +168,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
**Role**: Monitors agent effectiveness. Identifies failure patterns. Proposes agent definition modifications in `.opencode/agents/`. All changes require human-approved PRs with `needs feedback` label.
---
### 11. Architecture Guard (`AUTO-GUARD`)
@@ -190,7 +179,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
**Role**: Aggressive codebase coherence checking. Scans for pattern drift, duplicate code, module coupling, API inconsistencies, and technical debt.
---
### 12. Spec Update (`AUTO-SPEC`)
@@ -202,7 +190,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
**Role**: Compares implementation against spec after merges. Updates spec where implementation found a better approach. Creates issues where implementation deviates incorrectly.
---
### 13. Backlog Grooming (`AUTO-GROOM`)
@@ -214,7 +201,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
**Role**: Continuously scans all open Forgejo issues and PRs for quality problems. Detects duplicates, orphans, stale issues, missing labels, priority mismatches. Works entirely via Forgejo API — no clone needed.
---
### 14. Documentation (`AUTO-DOCS`)
@@ -226,7 +212,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
**Role**: Documentation generation at milestone boundaries. Generates API docs, architecture overviews, README updates, changelogs.
---
### 15. Timeline Update (`AUTO-TIME`)
@@ -238,7 +223,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
**Role**: Monitors project progress and updates `docs/timeline.md` with milestone status, schedule adherence, and PlantUML gantt chart entries.
---
### 16. Project Owner (`AUTO-OWNR`)
@@ -250,7 +234,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
**Role**: Autonomous strategic decision-maker. Triages unverified issues, assigns priority and scope labels, makes strategic decisions, and engages with developers. For the label system and ticket lifecycle this agent uses, see `cleveragents-contributing` and `cleverthis-guidelines` skills.
---
### 17. System Watchdog (`AUTO-WDOG`)
@@ -265,7 +248,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
**Special**: Has the broadest view — monitors ALL other agents and their tracking issues.
---
## Utility Subagents (No Session Tags)
@@ -6,7 +6,6 @@ The CleverAgents system runs as an OpenCode session (using `@opencode-ai/plugin`
**Critical rule**: Only `async-agent-manager` is permitted to make HTTP calls to `localhost:4096`. All other agents have this explicitly denied in their permissions. This centralises all async operations through a single, well-tested gateway.
---
## Why prompt_async Exists
@@ -25,7 +24,6 @@ Pool supervisors cannot use synchronous calls for workers because:
`prompt_async` solves this: the supervisor dispatches a worker, gets a 204 response immediately, and continues its main loop. Workers signal completion through Forgejo activity (comments, PRs, issue state changes) — the supervisor detects this by checking session status and Forgejo state on subsequent cycles.
---
## OpenCode Server API Reference
@@ -139,7 +137,6 @@ curl -s -X DELETE "http://localhost:4096/session/${SESSION_ID}"
Returns `true` with HTTP 200 on success.
---
## Session Naming Convention
@@ -194,7 +191,6 @@ All sessions follow the format: `[TAG] display-name`
| `AUTO-OWNR` | `[AUTO-OWNR-N]` | `[AUTO-OWNR-8]` |
| `AUTO-WDOG` | `[AUTO-WDOG-N]` | `[AUTO-WDOG-2]` |
---
## Common Operations (via async-agent-manager)
@@ -229,7 +225,6 @@ Workers completing normally is expected — they do their task and exit. The sup
Supervisors periodically prune completed worker sessions using async-agent-cleanup.
---
## Error Handling
@@ -4,7 +4,6 @@
Multiple agents may discover the same work item simultaneously. Without coordination, two agents might work on the same issue/PR concurrently, leading to conflicts. The system uses a **comment-based claiming protocol** on Forgejo issues and PRs to prevent this.
---
## Claim Protocol
@@ -85,7 +84,6 @@ Reason: completed | failed | timeout | error
**Automated by CleverAgents Bot**
```
---
## PR Work Coordination
@@ -102,7 +100,6 @@ When multiple agents may work on the same PR (e.g., implementation pool fixes a
**Wait policy**: If another agent has been working < 15 minutes → wait 5 minutes and retry. If > 15 minutes → they may be stuck; proceed anyway.
---
## Session-Level Deduplication (Supervisor Responsibility)
@@ -114,7 +111,6 @@ Beyond claim-level coordination, supervisors prevent duplicate dispatch by check
This tag-based deduplication is the PRIMARY mechanism. The claim protocol is a secondary safeguard for cases where the tag search might miss something.
---
## System Watchdog Monitoring of Coordination
@@ -127,7 +123,6 @@ The system-watchdog monitors for coordination violations:
When violations are detected, the watchdog dispatches a `system-watchdog-worker` to clean up and may create an announcement.
---
## Startup Deduplication
@@ -138,7 +133,6 @@ Product-builder prevents duplicate supervisors:
This prevents supervisor accumulation across restarts. Supervisors recover their state from Forgejo tracking issues, so stopping them causes no data loss.
---
## Bot Signatures
@@ -159,13 +153,12 @@ Agent: implementation-worker
This identifies automated content, helps humans understand which agent made a change, and is used by the coordination protocols to distinguish automated from human comments.
---
## Announcement Relevancy Matrix
The full canonical cross-agent attention table is in **SKILL.md** under the
"Which announcements should I consume?" decision tree. It lists every supervisor
prefix with its complete source-and-minimum-priority matrix.
The full canonical cross-agent attention table lives in
[`../tracking-system/announcement-matrix/`](../tracking-system/announcement-matrix/).
It lists every supervisor prefix with its complete source-and-minimum-priority matrix.
For dynamic lookup: use `agent-prefix-info` with `GET_RELEVANCY_MATRIX` to get
the table for any specific prefix programmatically.
@@ -31,7 +31,6 @@ git remote get-url origin
# → FORGEJO_REPO = cleveragents-core
```
---
## Credential Hierarchy
@@ -49,7 +48,6 @@ git commits, Forgejo API calls, etc.
**Key principle**: Every level explicitly passes ALL needed credentials to the next level. Nothing is inferred from environment variables after product-builder's initial read.
---
## The Two Bot Accounts
@@ -73,7 +71,6 @@ Credentials: `FORGEJO_REVIEWER_PAT`, `FORGEJO_REVIEWER_USERNAME`, `FORGEJO_REVIE
**Note**: product-builder detects this special case and passes reviewer credentials to `pr-review-pool-supervisor` instead of the primary credentials.
---
## Worker Credential Rules
@@ -101,7 +98,6 @@ The supervisor's prompt to the worker must include:
If a supervisor omits any of these, the worker cannot proceed. Supervisors are responsible for passing everything explicitly.
---
## Worker Count Configuration
@@ -121,7 +117,6 @@ Product-builder computes these values at startup and passes the appropriate coun
| If N = 16: | N_FULL=16, N_HALF=8, N_QUARTER=4 |
| If N = 1: | N_FULL=1, N_HALF=1, N_QUARTER=1 (minimums enforced) |
---
## Security Notes
@@ -0,0 +1,97 @@
# Operational Parameters — Key Numbers and Thresholds
All timing, sizing, and threshold values used across the autonomous agent system.
For the *complete* supervisor details (role descriptions, worker types, worker tag
patterns) see [`../agent-registry/`](../agent-registry/).
## Supervisor Registry — Quick Lookup Table
| # | Prefix | Agent Definition | Workers | Sleep | Tracking Prefix |
|---|--------|-----------------|---------|-------|-----------------|
| 0 | `AUTO-PROD-BLDR` | product-builder | N/A (monitors, not a pool) | 60 s | `AUTO-PROD-BLDR` |
| 1 | `AUTO-IMP-SUP` | implementation-pool-supervisor | N_FULL | 120 s | `AUTO-IMP-POOL` |
| 2 | `AUTO-REV-SUP` | pr-review-pool-supervisor | N_HALF | 30 s | `AUTO-REV-SUP` |
| 3 | `AUTO-PRMRG-SUP` | pr-merge-pool-supervisor | 0 (blocking subagent) | 300 s | `AUTO-PRMRG-SUP` |
| 4 | `AUTO-UAT-SUP` | uat-test-pool-supervisor | N_QUARTER | 600 s | `AUTO-UAT-SUP` |
| 5 | `AUTO-BUG-SUP` | bug-hunt-pool-supervisor | N_QUARTER | 900 s | `AUTO-BUG-SUP` |
| 6 | `AUTO-INF-SUP` | test-infra-pool-supervisor | N_QUARTER | 900 s | `AUTO-INF-SUP` |
| 7 | `AUTO-ARCH` | architecture-pool-supervisor | 1 | 1800 s | `AUTO-ARCH` |
| 8 | `AUTO-EPIC` | epic-planning-pool-supervisor | 1 | 600 s | `AUTO-EPIC` |
| 9 | `AUTO-HUMAN` | human-liaison-pool-supervisor | 1 | 120 s | `AUTO-HUMAN` |
| 10 | `AUTO-EVLV` | agent-evolution-pool-supervisor | 1 | 1800 s | `AUTO-EVLV` |
| 11 | `AUTO-GUARD` | architecture-guard-pool-supervisor | 1 | 600 s | `AUTO-GUARD` |
| 12 | `AUTO-SPEC` | spec-update-pool-supervisor | 1 | 900 s | `AUTO-SPEC` |
| 13 | `AUTO-GROOM` | grooming-pool-supervisor | 1 | 300 s | `AUTO-GROOM` |
| 14 | `AUTO-DOCS` | documentation-pool-supervisor | 1 | 1800 s | `AUTO-DOCS` |
| 15 | `AUTO-TIME` | timeline-update-pool-supervisor | 1 | 3600 s | `AUTO-TIME` |
| 16 | `AUTO-OWNR` | project-owner-pool-supervisor | 1 | 300 s | `AUTO-OWNR` |
| 17 | `AUTO-WDOG` | system-watchdog-pool-supervisor | 1 | 300 s | `AUTO-WATCHDOG` |
> **⚠️ `AUTO-WDOG` tracking prefix exception:** The session tag is `[AUTO-WDOG]` but
> the tracking issue prefix is `AUTO-WATCHDOG`. Don't confuse the two.
> **⚠️ `AUTO-PRMRG-SUP` worker count exception:** This supervisor calls
> `pr-merge-worker` as a **blocking Task subagent** — there are no `[AUTO-PRMRG-N]`
> async sessions. Worker count = 0 means "no async worker sessions", not "no work".
### Sleep Timeout Rule
Always set bash timeout to `sleep_duration × 1.5` minimum:
```bash
bash("sleep 300", timeout=450000) # 5 min sleep → 7.5 min timeout
bash("sleep 120", timeout=180000) # 2 min sleep → 3 min timeout
```
Never let the bash timeout be less than the sleep duration — the call will be
killed before the sleep completes.
## Worker Count Formula
Controlled by the `CA_MAX_PARALLEL_WORKERS` environment variable (default: 4).
Product-builder reads this at startup and passes the computed values to each supervisor.
```
N = CA_MAX_PARALLEL_WORKERS
N_FULL = N
N_HALF = max(1, N ÷ 2) # integer division; minimum 1
N_QUARTER = max(1, N ÷ 4) # integer division; minimum 1
```
| If N = 1 | N_FULL=1, N_HALF=1, N_QUARTER=1 | (minimums enforced) |
|----------|----------------------------------|---------------------|
| If N = 4 | N_FULL=4, N_HALF=2, N_QUARTER=1 | |
| If N = 8 | N_FULL=8, N_HALF=4, N_QUARTER=2 | |
| If N = 16 | N_FULL=16, N_HALF=8, N_QUARTER=4 | |
## Key Numbers — All Thresholds and Timings
| Parameter | Value | Context |
|-----------|-------|---------|
| `CA_MAX_PARALLEL_WORKERS` default | 4 | Set via environment variable |
| N_FULL | N | Implementation pool only |
| N_HALF | max(1, N ÷ 2) | PR review pool only |
| N_QUARTER | max(1, N ÷ 4) | UAT, Bug Hunt, Test Infra |
| Work claim expiry | 2 hours | Without heartbeat — see `references/coordination/` |
| Heartbeat interval | 10 minutes | Must send to maintain a claim |
| Rolling average formula | 0.90 × old + 0.10 × actual | Cycle interval smoothing |
| Status issue limit | 1 per prefix at a time | Older ones closed when new one created |
| Human escalation trigger | Opus tier × 3 same-problem failures | Apply `needs feedback` label |
| Forgejo API timeout | 30 seconds | Per individual HTTP request |
| Git operation timeout | 5 minutes | Local git commands |
| Test execution timeout | 15 minutes | Full test suite runs |
| Worker stuck threshold | 15 minutes idle | No new messages → classified as `stuck` |
| Product-builder fast cycle | 60 seconds | Liveness check + question-answering |
| Product-builder deep inspection | Every 5 fast cycles (~5 min) | Message reading, anti-pattern detection |
| Product-builder worker health check | Every 5 fast cycles (~5 min) | Pool count vs expected |
| Product-builder hourly cycle | Every ~60 fast cycles | Full verification + status ticket |
| Watchdog staleness threshold | 2 × estimated_cycle_interval | If tracking issue older → supervisor frozen |
| Supervisor max downtime | ≤ 60 seconds | product-builder fast cycle detects crash |
| Worker max downtime before re-dispatch | Supervisor's sleep interval | 2 min (IMP) to 60 min (TIME) |
| Max temp dir age | 24 hours | Cleaned automatically by repo-isolator |
| Forgejo MCP page limit | 50 per page | Always paginate exhaustively |
| Supervisor crash offline thresholds | < 30 min → light recovery | Resume from state |
| | 30120 min → moderate recovery | Re-verify key Forgejo state |
| | > 120 min → full re-scan | Treat as fresh start with hints |
@@ -12,7 +12,6 @@ Layer 3 — each supervisor monitors its own workers (every cycle)
No layer depends on another to detect problems — if product-builder is distracted or slow, system-watchdog independently detects frozen supervisors via Forgejo. If a supervisor's pool drains, product-builder notices the undercount before system-watchdog checks in.
---
## Layer 1: Product-Builder Monitoring
@@ -73,7 +72,6 @@ Product-builder manages its own context window explicitly:
**Critical limit**: product-builder itself has no external watcher. If it crashes or exhausts its context, a human must restart it. This is the only single point of failure in the system. All supervisor-level crashes self-heal; product-builder-level crashes require human intervention.
---
## Layer 2: System Watchdog
@@ -119,7 +117,6 @@ System-watchdog monitors supervisors but does NOT restart them. It creates:
Product-builder is responsible for actually relaunching failed supervisors.
---
## Layer 3: Supervisor Self-Monitoring of Workers
@@ -165,7 +162,6 @@ Each pool supervisor maintains a sliding window of active workers:
- The pool is continuously filled, not batch-dispatched
- A supervisor that stops filling its pool triggers product-builder's worker health check and gets relaunched
---
## State Persistence: The Foundation of Self-Healing
@@ -219,7 +215,6 @@ Self-healing only works because all state is externalized to Forgejo. No state l
8. New worker starts from the appropriate resumption point
```
---
## The Two Independent Health Signals
@@ -232,7 +227,6 @@ Understanding which signal catches which failure:
Together they provide complete coverage. A session can appear `busy` in OpenCode while being completely stuck (no Forgejo output) — only the staleness check catches this. A session can stop posting to Forgejo because it crashed — only the OpenCode check catches this.
---
## Detecting Specific Failure Modes
@@ -249,7 +243,6 @@ Together they provide complete coverage. A session can appear `busy` in OpenCode
| Multiple supervisors down | product-builder: repeated relaunch failures; system-watchdog: multiple stale tracking issues | product-builder: Priority/Critical announcement; human intervention |
| product-builder itself crashed | No automatic detection | Human must restart |
---
## The async-agent-monitor Subagent
@@ -267,7 +260,6 @@ Classifies sessions as:
The 15-minute threshold is configurable by the caller via `idle_threshold_minutes`. For short-cycle supervisors (120s sleep) this may be set lower; for long-cycle supervisors (1800s sleep) the default may be appropriate.
---
## Redundancy Gaps and Limitations
@@ -0,0 +1,103 @@
# Scripts Reference
Helper scripts for interacting with the Forgejo API. All scripts are written
in TypeScript and executed via `npx --yes tsx`. They require Node.js ≥ 18 and
zero external npm dependencies.
**Scripts directory:** [`scripts/`](../../scripts/)
## Available Scripts
### PR Listing Scripts
Six scripts that classify every open PR into one of six mutually exclusive
buckets. Together they cover the complete PR pipeline used by
`pr-merge-pool-supervisor` and `pr-review-pool-supervisor`.
| Script | One-liner |
|--------|-----------|
| [`list_prs`](./list_prs/) | General-purpose PR lister — all filter options (`--stale`, `--ci-status`, `--min-approvals`, …), importable as a module by the six wrappers below |
| [`list_prs_ready_to_merge`](./list_prs_ready_to_merge/) | Open PRs with ≥ 1 approval, already current with their base branch, **and CI passing** — merge immediately |
| [`list_prs_stale_clean`](./list_prs_stale_clean/) | Open PRs with ≥ 1 approval, behind their base branch, no conflicts, any CI status — server-side rebase then merge |
| [`list_prs_stale_conflicts`](./list_prs_stale_conflicts/) | Open PRs with ≥ 1 approval, behind their base branch, merge conflicts present, any CI status — local clone, resolve, force-push, then merge |
| [`list_prs_needs_review_not_stale`](./list_prs_needs_review_not_stale/) | Open PRs with zero approvals, current with their base branch, any CI status — review only needed |
| [`list_prs_needs_review_stale_clean`](./list_prs_needs_review_stale_clean/) | Open PRs with zero approvals, stale but conflict-free, any CI status — review + server-side rebase needed |
| [`list_prs_needs_review_stale_conflicts`](./list_prs_needs_review_stale_conflicts/) | Open PRs with zero approvals, stale with conflicts, any CI status — review + local conflict resolution needed |
### PR Action Scripts
| Script | One-liner |
|--------|-----------|
| [`rebase_pr`](./rebase_pr/) | Triggers a Forgejo server-side rebase on a single stale, conflict-free PR — no local clone required |
| [`merge_pr`](./merge_pr/) | Initiates a rebase-style merge (with automerge scheduling) on a single PR, handling open issue dependencies before calling the merge endpoint |
## The Six-Bucket Pipeline
The six listing scripts define a complete, non-overlapping classification of
open PRs. The two approval states (approved vs needs review) are each split
by three staleness states, giving six buckets in total. **Bucket 1 additionally
requires CI to be passing**; approved + not-stale PRs with failing or pending CI
are held out of all buckets until their CI resolves.
```
Every open PR belongs to exactly one bucket at any moment
(or is temporarily absent if CI is blocking it from Bucket 1):
── Approved (≥ 1 non-dismissed approval) ──────────────────────────────────
Bucket 1 — list_prs_ready_to_merge (approved + not stale + CI passing)
Bucket 2 — list_prs_stale_clean (approved + stale, no conflicts, any CI)
Bucket 3 — list_prs_stale_conflicts (approved + stale, has conflicts, any CI)
── Needs Review (0 approvals) ─────────────────────────────────────────────
Bucket 4 — list_prs_needs_review_not_stale (no approvals + not stale, any CI)
Bucket 5 — list_prs_needs_review_stale_clean (no approvals + stale, no conflicts, any CI)
Bucket 6 — list_prs_needs_review_stale_conflicts (no approvals + stale, has conflicts, any CI)
── Temporarily absent (not in any bucket) ─────────────────────────────────
• stale_state == stale_unknown → Forgejo still computing conflict status; appears shortly
• approved + not stale + CI failing/pending/unknown → held out of Bucket 1 until CI passes
```
Typical action sequence per bucket:
```
Bucket 1: merge_pr (CI already green — safe to merge immediately)
Bucket 2: rebase_pr → merge_pr
Bucket 3: clone → rebase locally → resolve conflicts → force-push → merge_pr
Bucket 4: (dispatch reviewer → on approval, moves to Bucket 1 if CI passes)
Bucket 5: (dispatch reviewer → on approval, moves to Bucket 2)
Bucket 6: (dispatch reviewer → on approval, moves to Bucket 3)
```
## Quick Invocation Reference
All scripts share the same four connection flags:
```bash
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/<script>.ts \
--url <forgejo-base-url> \ # e.g. https://git.example.com
--pat <personal-access-token> \
--owner <repo-owner-or-org> \
--repo <repo-name>
```
`merge_pr` and `rebase_pr` additionally require `--pr <number>`.
`merge_pr` has an optional `--dep error|delete|reverse` flag.
The six `list_prs_*` wrappers accept **only** the four connection flags —
their filter parameters are hard-coded and cannot be overridden on the CLI.
`list_prs` itself accepts optional filter flags: `--state`, `--min-approvals`,
`--max-approvals`, `--mergeable`, `--stale`, and `--ci-status`.
**`--ci-status`** accepts a comma-separated whitelist of CI states to include:
`passing`, `failing`, `pending`, `unknown` (any combination). Omit to include
all CI states. Example: `--ci-status passing,pending`
Each PR object in all outputs now includes a `ci_status` field
(`passing` | `failing` | `pending` | `unknown`) derived from the Forgejo
combined commit-status endpoint for the PR's head SHA.
All scripts write JSON to **stdout** and progress/diagnostics to **stderr**.
Exit code `0` = success, `1` = error.
@@ -0,0 +1,310 @@
# list_prs — General Forgejo PR Listing Script
**Script name:** `list_prs`
**Script location:** [`scripts/list_prs.ts`](../../../scripts/list_prs.ts)
**Invoke:**
```bash
npx --yes tsx .opencode/skills/auto-agents-system/scripts/list_prs.ts \
--url URL --pat TOKEN --owner OWNER --repo REPO \
[--state open|closed|all] [--min-approvals N] [--max-approvals N] \
[--mergeable true|false] [--stale not_stale|stale_no_conflicts|stale_with_conflicts|stale_unknown] \
[--ci-status passing|failing|pending|unknown[,...]]
```
**CRITICAL:** Always invoke the script using bash and the format noted above. **Never** try to use the skill as a task, or invoke it through any other method than by directly calling bash with a command of the form listed above under "Invoke:".
## Synopsis
```
list_prs.ts --url URL --pat TOKEN --owner OWNER --repo REPO [OPTIONS]
```
Fetches all pull requests from a Forgejo repository, enriches each one with a
computed approval count, a staleness classification, and a priority rank, then
filters and sorts the results before writing a JSON array to stdout.
`list_prs.ts` is both a standalone CLI tool and the **importable core module**
used by the four thin wrapper scripts
(`list_prs_needs_review`, `list_prs_ready_to_merge`, `list_prs_stale_clean`,
`list_prs_stale_conflicts`). When imported, it exports `listPRs` and
`parseConnectionArgs` for use by those wrappers.
## Arguments
### Required
| Flag | Type | Description |
|------|------|-------------|
| `--url URL` | string | Forgejo base URL, **no trailing slash** (e.g. `https://git.example.com`) |
| `--pat TOKEN` | string | Personal Access Token with read access to the repository |
| `--owner OWNER` | string | Repository owner or organisation name |
| `--repo REPO` | string | Repository name |
All four required flags must be present. Any missing flag causes an immediate
exit with code 1 and an error message to stderr.
### Optional Filters
All filter flags default to "no filter" (i.e. all values pass) when omitted.
| Flag | Type | Default | Description |
|------|------|---------|-------------|
| `--state open\|closed\|all` | string | `open` | Filter by PR state |
| `--min-approvals N` | integer ≥ 0 | (none) | Include only PRs with **≥ N** non-dismissed approvals |
| `--max-approvals N` | integer ≥ 0 | (none) | Include only PRs with **≤ N** non-dismissed approvals |
| `--mergeable true\|false` | boolean | (none) | Filter by Forgejo's raw `PR.mergeable` field |
| `--stale VALUE` | string | (none) | Filter by computed `stale_state` (see Stale States below) |
| `--ci-status VALUE[,...]` | string | (none) | Comma-separated whitelist of CI statuses to include (see CI Status below). Omit to include all CI statuses. |
| `-h`, `--help` | — | — | Print usage to stderr and exit 0 |
### Argument Validity Rules
- `--min-approvals` and `--max-approvals` may be used together; both constraints apply simultaneously (logical AND).
- `--min-approvals 1 --max-approvals 0` is logically impossible and will return an empty result set — the script does not reject it, it simply matches nothing.
- `--mergeable` filters on the raw API field, not on the computed `stale_state`. Use `--stale` for the semantically richer classification.
- `--ci-status` accepts a comma-separated list of values from `passing`, `failing`, `pending`, `unknown`. A PR must match **any one** of the listed values (logical OR within the list). Multiple `--ci-status` flags are not supported — put all desired values in one comma-separated argument.
- Any unknown flag causes exit code 1 and a usage message.
- `--state` only accepts the three literal values `open`, `closed`, `all`; any other value is passed to the API which may behave unexpectedly (this is not validated client-side).
## Output
Written to **stdout** as a pretty-printed JSON array. Each element is the full
Forgejo PR object as returned by the API, augmented with four additional fields:
| Field | Type | Description |
|-------|------|-------------|
| `approvals_count` | integer | Count of distinct non-dismissed `APPROVED` reviews. Per-reviewer: only the reviewer's most recent review is counted; if they later submitted `REQUEST_CHANGES`, that supersedes the approval and it is not counted. |
| `stale_state` | string | One of five stale states (see below) |
| `ci_status` | string | One of four CI status values (see CI Status below) |
| `priority_rank` | integer | 0 = `Priority/CI Blocker` (highest), …, 5 = `Priority/Backlog`, 6 = unlabelled |
| `priority_label` | string \| null | The matched `Priority/*` label name, or `null` if none present |
The array is **sorted ascending by `priority_rank`** so the most urgent PRs appear
first within the result set.
### Stale States
| `stale_state` value | Meaning |
|---------------------|---------|
| `not_stale` | `PR.merge_base == base branch HEAD` — PR is fully up-to-date |
| `stale_no_conflicts` | Base has advanced AND `PR.mergeable == true` — clean auto-rebase possible |
| `stale_with_conflicts` | Base has advanced AND `PR.mergeable == false` — manual resolution required |
| `stale_unknown` | Base has advanced AND `PR.mergeable == null` — Forgejo is still computing |
| `compute_error` | `PR.merge_base` or base HEAD SHA is missing; classification impossible |
### CI Status
Derived from `GET /api/v1/repos/{owner}/{repo}/commits/{head_sha}/status` — the Forgejo combined commit-status endpoint. The `state` field of that response is mapped as follows:
| `ci_status` value | Forgejo combined state | Meaning |
|-------------------|----------------------|---------|
| `passing` | `success` | All status checks have reported success |
| `failing` | `failure` \| `error` \| `warning` | At least one check has failed or errored |
| `pending` | `pending` | Checks are queued or still running |
| `unknown` | `""` \| `unknown` | No status checks have been reported for this commit |
Use `--ci-status passing` to restrict to PRs where all CI has passed. Use `--ci-status passing,pending` to include both passing and still-running PRs. Omit `--ci-status` entirely to return PRs regardless of their CI state.
### Priority Rank Table
| `priority_rank` | Label |
|----------------|-------|
| 0 | `Priority/CI Blocker` |
| 1 | `Priority/Critical` |
| 2 | `Priority/High` |
| 3 | `Priority/Medium` |
| 4 | `Priority/Low` |
| 5 | `Priority/Backlog` |
| 6 | (no `Priority/*` label present) |
## Diagnostics / stderr
Progress messages are written to stderr during execution (not to stdout, so
they do not contaminate the JSON output):
```
Fetching PRs from https://git.example.com/org/repo (state=open)...
Fetched 42 PR(s). Enriching and filtering...
Fetching HEAD SHAs for 3 unique base branch(es)...
Fetching reviews for 42 PR(s) concurrently (limit=20)...
Fetching CI status for 42 PR(s) concurrently (limit=20)...
Result: 12/42 PR(s) matched the filter criteria.
```
Warnings about individual failures (e.g. a branch API error for one PR) are
also written to stderr. The script continues processing the remaining PRs
rather than aborting.
## Exit Codes
| Code | Meaning |
|------|---------|
| 0 | Success — JSON array written to stdout (may be empty `[]`) |
| 1 | Fatal error — message written to stderr |
## Errors the Script May Throw
| Condition | Behaviour |
|-----------|-----------|
| Missing required `--url`, `--pat`, `--owner`, or `--repo` | Exit 1 with descriptive message |
| Unknown CLI flag | Exit 1 with usage message |
| API returns non-2xx for the PR list | Throws; script exits 1 with the HTTP status and body |
| API returns non-2xx for a base branch HEAD | Logs a warning to stderr; marks affected PRs as `compute_error`; continues |
| API returns non-2xx for a PR's reviews | Logs a warning; treats that PR as having 0 approvals; continues |
| Network timeout (30 s per request) | Throws; script exits 1 |
## Performance Notes
The script uses concurrent fetch chains to minimise wall-clock time:
- **PR pages** are fetched in parallel batches of 6 pages at a time.
- **Base-branch HEAD SHAs** are fetched simultaneously for all unique branches (cached: one call per unique branch regardless of how many PRs share it).
- **Reviews** are fetched with up to 20 concurrent in-flight requests at once.
For a repository with ~326 PRs, this reduces review-fetching from ~230 s
(sequential) to ~1.7 s.
## When to Use This Script
Use `list_prs.ts` directly when you need **custom filter combinations** not
served by one of the four wrapper scripts:
- List all closed PRs: `--state closed`
- Find PRs with exactly 2 approvals: `--min-approvals 2 --max-approvals 2`
- Find approved PRs that are still pending Forgejo's conflict check: `--min-approvals 1 --stale stale_unknown`
- List all PRs regardless of state: `--state all`
- Find open PRs ready to merge (approved, not stale, CI passing): `--min-approvals 1 --stale not_stale --ci-status passing`
- Find PRs with broken CI: `--ci-status failing`
- Find PRs with passing or pending CI: `--ci-status passing,pending`
For the four standard operating buckets used by `pr-merge-pool-supervisor`,
prefer the thin wrappers — they are self-documenting and require fewer flags.
## Usage Examples
```bash
# List all open PRs (no filters — returns everything)
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo
# List open PRs with at least 1 approval that are not stale
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
--min-approvals 1 \
--stale not_stale
# List open PRs awaiting a first review (0 approvals)
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
--max-approvals 0
# List all closed PRs (for audit/history purposes)
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
--state closed
# Extract just PR numbers from the result using jq
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs.ts \
--url https://git.example.com --pat ghp_XXXX \
--owner my-org --repo my-repo --min-approvals 1 \
| jq '[.[].number]'
```
## Agent Usage Examples
### pr-merge-pool-supervisor
The supervisor does **not** call `list_prs.ts` directly. It calls the four
purpose-built wrapper scripts to populate its four work queues each cycle.
It would only call `list_prs.ts` directly if it needed a custom filter
combination not covered by those wrappers (e.g. investigating `stale_unknown`
PRs to determine if Forgejo is lagging).
### pr-merge-worker
The worker does **not** call `list_prs.ts`. It receives a specific PR number
from the supervisor and operates on that single PR. However, a worker
implementing complex decision logic could import `listPRs` programmatically
to inspect the state of all PRs before deciding how to proceed.
### system-watchdog-pool-supervisor
The watchdog could use `list_prs.ts` with `--state all` or custom filter
combinations to audit the full PR pipeline — for example, to detect PRs
that have been open for an unusually long time, or to count approved PRs
that are not progressing through the merge pipeline.
### implementation-pool-supervisor
The implementation supervisor might use `list_prs.ts` with
`--min-approvals 0 --max-approvals 0` (or equivalently `list_prs_needs_review`)
to check whether any of its submitted PRs are awaiting a first review, so it
can decide whether to dispatch more implementation workers or wait for review
capacity to clear.
## Module API (when imported)
```typescript
import { listPRs, parseConnectionArgs } from './list_prs.ts';
// Config object
const config: Config = {
url: 'https://git.example.com',
pat: 'ghp_XXXX',
owner: 'my-org',
repo: 'my-repo',
};
// Filters object (all fields optional)
const filters: Filters = {
state: 'open',
minApprovals: 1,
stale: 'not_stale',
ciStatus: ['passing'], // only PRs with all CI checks passing
};
// ciStatus accepts any combination:
// ciStatus: ['passing'] — CI must have passed
// ciStatus: ['pending'] — CI still running
// ciStatus: ['failing'] — CI has failed
// ciStatus: ['passing', 'pending'] — CI passed or still running
// (omit ciStatus entirely) — any CI state passes through
const prs: AugmentedPR[] = await listPRs(config, filters);
```
The exported `parseConnectionArgs(argv)` function parses only the four
connection flags (`--url`, `--pat`, `--owner`, `--repo`) and is used by the
four wrapper scripts. It rejects any unknown flag with an informative error.
## Dependencies
- Node.js ≥ 18 (native `fetch` API, stable since v21; available unflagged since v18)
- `npx tsx` for TypeScript execution (auto-installed by `npx --yes tsx`)
- Zero external npm packages — uses only Node.js built-ins
@@ -0,0 +1,242 @@
# list_prs_needs_review_not_stale — Open PRs With No Approvals, Up-to-Date
**Script name:** `list_prs_needs_review_not_stale`
**Script location:** [`scripts/list_prs_needs_review_not_stale.ts`](../../../scripts/list_prs_needs_review_not_stale.ts)
**Invoke:**
```bash
npx --yes tsx .opencode/skills/auto-agents-system/scripts/list_prs_needs_review_not_stale.ts \
--url URL --pat TOKEN --owner OWNER --repo REPO
**CRITICAL:** Always invoke the script using bash and the format noted above. **Never** try to use the skill as a task, or invoke it through any other method than by directly calling bash with a command of the form listed above under "Invoke:".
```
## Synopsis
```
list_prs_needs_review_not_stale.ts --url URL --pat TOKEN --owner OWNER --repo REPO
```
Returns all **open** pull requests that have **zero non-dismissed approvals**
and are **not stale** — i.e. the PR's `merge_base` already matches the current
HEAD of its base branch. The PR is fully up-to-date and requires no rebase
before merging.
These are the simplest PRs in the "needs review" set: once a reviewer approves
them, they can be merged immediately without any additional rebase or conflict
resolution step.
This script is a thin wrapper around [`list_prs`](../list_prs/). It
hard-codes the following filters and delegates all logic to that script:
```
state: 'open'
maxApprovals: 0
stale: 'not_stale'
(no ciStatus filter — all CI states are included)
```
## Arguments
All four arguments are **required**. No optional filter arguments exist — the
filters are baked in and cannot be changed.
| Flag | Type | Description |
|------|------|-------------|
| `--url URL` | string | Forgejo base URL, **no trailing slash** (e.g. `https://git.example.com`) |
| `--pat TOKEN` | string | Personal Access Token with read access to the repository |
| `--owner OWNER` | string | Repository owner or organisation name |
| `--repo REPO` | string | Repository name |
| `-h`, `--help` | — | Print usage to stderr and exit 0 |
Any flag other than these five is **rejected** with exit code 1 and an error
message: `ERROR: Unknown argument: <flag>`. Filter parameters are hard-coded
and cannot be overridden via CLI flags on this wrapper script.
### Invalid Argument Combinations
There are no valid filter-combination errors since no optional filters exist.
However, passing any filter-style flag (e.g. `--min-approvals`, `--stale`, etc.)
will cause an immediate exit 1 — those flags are not accepted by this wrapper.
## Hard-Coded Filters
| Filter | Value | Meaning |
|--------|-------|---------|
| `state` | `open` | Only open PRs are returned |
| `maxApprovals` | `0` | PRs with zero non-dismissed `APPROVED` reviews |
| `stale` | `not_stale` | `PR.merge_base` equals the current base branch HEAD |
**"Not stale"** means `PR.merge_base == current base branch HEAD`: the base
branch has not advanced since the PR's head was last reconciled, so no rebase
is needed.
**"Zero approvals"** means: no reviewer has an active (non-dismissed) `APPROVED`
review as their most recent review. A reviewer who approved and then later
submitted `REQUEST_CHANGES` is not counted as an approver.
## Output
Written to **stdout** as a pretty-printed JSON array sorted by `priority_rank`
(highest priority first). Each element is the full Forgejo PR object augmented
with four fields:
| Field | Type | Description |
|-------|------|-------------|
| `approvals_count` | integer | Will always be `0` for results of this script |
| `stale_state` | string | Will always be `not_stale` for results of this script |
| `ci_status` | string | `passing`, `failing`, `pending`, or `unknown`**not filtered**; any CI state is included |
| `priority_rank` | integer | 0 (highest) through 6 (unlabelled) |
| `priority_label` | string \| null | Matched `Priority/*` label name, or `null` |
An **empty array** `[]` is a valid and common result — it means all open
up-to-date PRs already have at least one approval.
See [`list_prs`](../list_prs/) for the full output schema documentation.
## Diagnostics / stderr
Progress messages are written to stderr and do not affect the JSON output:
```
Fetching PRs from https://git.example.com/org/repo (state=open)...
Fetched 42 PR(s). Enriching and filtering...
Fetching HEAD SHAs for 3 unique base branch(es)...
Fetching reviews for 42 PR(s) concurrently (limit=20)...
Fetching CI status for 42 PR(s) concurrently (limit=20)...
Result: 8/42 PR(s) matched the filter criteria.
```
## Exit Codes
| Code | Meaning |
|------|---------|
| 0 | Success — JSON array written to stdout (may be `[]`) |
| 1 | Fatal error — message written to stderr |
## Errors the Script May Throw
| Condition | Behaviour |
|-----------|-----------|
| Missing `--url`, `--pat`, `--owner`, or `--repo` | Exit 1: `ERROR: --<flag> is required` |
| Any unknown flag passed | Exit 1: `ERROR: Unknown argument: <flag>` |
| Forgejo API non-2xx on PR list | Exit 1 with HTTP status and body detail |
| Forgejo API failure for a single branch or review | Warning to stderr; processing continues |
| Network timeout (30 s per request) | Exit 1 with error message |
## When to Use This Script
Use `list_prs_needs_review_not_stale` when you want to identify PRs that are
**waiting for a first review and are already current with their base branch**.
Typical use cases:
- **`pr-review-pool-supervisor`** uses this as its highest-priority review
bucket: once approved, these PRs merge cleanly with no further action.
- A **review dispatcher** agent can prioritise these over stale PRs since
reviewing them provides immediate merge readiness.
- A **monitoring agent** can track this bucket to detect a backlog of fresh
PRs waiting for review.
### Position in the Six-Bucket System
```
Every open PR belongs to exactly one bucket at any moment:
Bucket 1 — list_prs_ready_to_merge (approved + not stale)
Bucket 2 — list_prs_stale_clean (approved + stale, no conflicts)
Bucket 3 — list_prs_stale_conflicts (approved + stale, has conflicts)
Bucket 4 — list_prs_needs_review_not_stale (no approvals + not stale) ← THIS SCRIPT
Bucket 5 — list_prs_needs_review_stale_clean (no approvals + stale, no conflicts)
Bucket 6 — list_prs_needs_review_stale_conflicts (no approvals + stale, has conflicts)
Exception: PRs with stale_state == stale_unknown are transiently absent from
all buckets while Forgejo computes conflict status. They appear shortly.
```
Workflow for a PR in this bucket once approved:
```
Reviewer approves → PR moves to list_prs_ready_to_merge → merge_pr
```
## Usage Examples
```bash
# Standard usage
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_not_stale.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo
# Count how many fresh PRs are waiting for a first review
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_not_stale.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
| jq 'length'
# Get just the PR numbers and titles
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_not_stale.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
| jq '[.[] | {number, title}]'
# Get only the highest-priority PR needing review
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_not_stale.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
| jq 'first'
```
## Agent Usage Examples
### pr-review-pool-supervisor
The supervisor can call this script to find its highest-priority review
targets — PRs that will merge immediately after approval. It dispatches
`pr-reviewer` workers for each result.
```bash
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_not_stale.ts \
--url $FORGEJO_URL \
--pat $FORGEJO_PAT \
--owner $REPO_OWNER \
--repo $REPO_NAME
```
### pr-merge-pool-supervisor
The merge supervisor uses this to surface PRs waiting for review that will
have the simplest post-approval workflow. An empty result here (combined with
non-empty stale buckets) suggests review bandwidth is being absorbed by PRs
that still have pending rebase work.
### human-liaison-pool-supervisor
The human liaison can filter by `created_at` to identify PRs that have been
waiting for a first review for too long, then post reminder comments or alert
human reviewers.
## Dependencies
- Node.js ≥ 18 (native `fetch` API)
- `npx tsx` for TypeScript execution
- Zero external npm packages
@@ -0,0 +1,238 @@
# list_prs_needs_review_stale_clean — Open PRs With No Approvals, Stale, No Conflicts
**Script name:** `list_prs_needs_review_stale_clean`
**Script location:** [`scripts/list_prs_needs_review_stale_clean.ts`](../../../scripts/list_prs_needs_review_stale_clean.ts)
**Invoke:**
```bash
npx --yes tsx .opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_clean.ts \
--url URL --pat TOKEN --owner OWNER --repo REPO
```
**CRITICAL:** Always invoke the script using bash and the format noted above. **Never** try to use the skill as a task, or invoke it through any other method than by directly calling bash with a command of the form listed above under "Invoke:".
## Synopsis
```
list_prs_needs_review_stale_clean.ts --url URL --pat TOKEN --owner OWNER --repo REPO
```
Returns all **open** pull requests that have **zero non-dismissed approvals**,
are **stale** (the base branch has advanced since the PR was last synced), and
have **no merge conflicts** (`PR.mergeable == true`). These PRs need a first
review AND will require a server-side rebase before or after approval — but no
conflict resolution will be required.
This script is a thin wrapper around [`list_prs`](../list_prs/). It
hard-codes the following filters and delegates all logic to that script:
```
state: 'open'
maxApprovals: 0
stale: 'stale_no_conflicts'
(no ciStatus filter — all CI states are included)
```
## Arguments
All four arguments are **required**. No optional filter arguments exist — the
filters are baked in and cannot be changed.
| Flag | Type | Description |
|------|------|-------------|
| `--url URL` | string | Forgejo base URL, **no trailing slash** (e.g. `https://git.example.com`) |
| `--pat TOKEN` | string | Personal Access Token with read access to the repository |
| `--owner OWNER` | string | Repository owner or organisation name |
| `--repo REPO` | string | Repository name |
| `-h`, `--help` | — | Print usage to stderr and exit 0 |
Any flag other than these five is **rejected** with exit code 1 and an error
message: `ERROR: Unknown argument: <flag>`. Filter parameters are hard-coded
and cannot be overridden via CLI flags on this wrapper script.
### Invalid Argument Combinations
There are no valid filter-combination errors since no optional filters exist.
However, passing any filter-style flag (e.g. `--min-approvals`, `--stale`, etc.)
will cause an immediate exit 1 — those flags are not accepted by this wrapper.
## Hard-Coded Filters
| Filter | Value | Meaning |
|--------|-------|---------|
| `state` | `open` | Only open PRs are returned |
| `maxApprovals` | `0` | PRs with zero non-dismissed `APPROVED` reviews |
| `stale` | `stale_no_conflicts` | Base has advanced AND `PR.mergeable == true` |
**"Stale no conflicts"** means two things are simultaneously true:
1. `PR.merge_base != current base branch HEAD` — the base branch has been pushed to since the PR was last synced.
2. `PR.mergeable == true` — Forgejo has determined that rebasing the PR's commits onto the new base would succeed without any merge conflicts.
**"Zero approvals"** means: no reviewer has an active (non-dismissed) `APPROVED`
review as their most recent review.
## Output
Written to **stdout** as a pretty-printed JSON array sorted by `priority_rank`
(highest priority first). Each element is the full Forgejo PR object augmented
with four fields:
| Field | Type | Description |
|-------|------|-------------|
| `approvals_count` | integer | Will always be `0` for results of this script |
| `stale_state` | string | Will always be `stale_no_conflicts` for results of this script |
| `ci_status` | string | `passing`, `failing`, `pending`, or `unknown`**not filtered**; any CI state is included |
| `priority_rank` | integer | 0 (highest) through 6 (unlabelled) |
| `priority_label` | string \| null | Matched `Priority/*` label name, or `null` |
An **empty array** `[]` is a valid and common result — it means no open
stale-but-clean PRs are currently awaiting a first review.
See [`list_prs`](../list_prs/) for the full output schema documentation.
## Diagnostics / stderr
Progress messages are written to stderr and do not affect the JSON output:
```
Fetching PRs from https://git.example.com/org/repo (state=open)...
Fetched 42 PR(s). Enriching and filtering...
Fetching HEAD SHAs for 3 unique base branch(es)...
Fetching reviews for 42 PR(s) concurrently (limit=20)...
Fetching CI status for 42 PR(s) concurrently (limit=20)...
Result: 5/42 PR(s) matched the filter criteria.
```
## Exit Codes
| Code | Meaning |
|------|---------|
| 0 | Success — JSON array written to stdout (may be `[]`) |
| 1 | Fatal error — message written to stderr |
## Errors the Script May Throw
| Condition | Behaviour |
|-----------|-----------|
| Missing `--url`, `--pat`, `--owner`, or `--repo` | Exit 1: `ERROR: --<flag> is required` |
| Any unknown flag passed | Exit 1: `ERROR: Unknown argument: <flag>` |
| Forgejo API non-2xx on PR list | Exit 1 with HTTP status and body detail |
| Forgejo API failure for a single branch or review | Warning to stderr; processing continues |
| Network timeout (30 s per request) | Exit 1 with error message |
## When to Use This Script
Use `list_prs_needs_review_stale_clean` when you want to identify PRs that are
**waiting for a first review and will need a server-side rebase before
merging** (but no conflict resolution). Typical use cases:
- **`pr-review-pool-supervisor`** uses this as a medium-priority review
bucket. After approving one of these PRs, the merge workflow is:
`rebase_pr` then `merge_pr` — no local clone required.
- A **review dispatcher** can distinguish these from `not_stale` PRs to
inform the review prioritisation strategy.
- A **monitoring agent** can track a growing bucket here as a signal that
the base branch is advancing faster than reviewers are approving PRs.
### Position in the Six-Bucket System
```
Every open PR belongs to exactly one bucket at any moment:
Bucket 1 — list_prs_ready_to_merge (approved + not stale)
Bucket 2 — list_prs_stale_clean (approved + stale, no conflicts)
Bucket 3 — list_prs_stale_conflicts (approved + stale, has conflicts)
Bucket 4 — list_prs_needs_review_not_stale (no approvals + not stale)
Bucket 5 — list_prs_needs_review_stale_clean (no approvals + stale, no conflicts) ← THIS SCRIPT
Bucket 6 — list_prs_needs_review_stale_conflicts (no approvals + stale, has conflicts)
Exception: PRs with stale_state == stale_unknown are transiently absent from
all buckets while Forgejo computes conflict status. They appear shortly.
```
Workflow for a PR in this bucket once approved:
```
Reviewer approves → PR moves to list_prs_stale_clean → rebase_pr → merge_pr
```
## Usage Examples
```bash
# Standard usage
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_clean.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo
# Count stale-clean PRs awaiting first review
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_clean.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
| jq 'length'
# Get PR numbers, titles, and their base branches
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_clean.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
| jq '[.[] | {number, title, base: .base.ref}]'
# Get the highest-priority stale-clean PR awaiting review
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_clean.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
| jq 'first'
```
## Agent Usage Examples
### pr-review-pool-supervisor
The supervisor dispatches `pr-reviewer` workers for PRs found in this bucket.
After approval, the merge supervisor's `list_prs_stale_clean` script will pick
them up for server-side rebase and merge.
```bash
result=$(npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_clean.ts \
--url $FORGEJO_URL --pat $FORGEJO_PAT --owner $REPO_OWNER --repo $REPO_NAME)
# If non-empty → dispatch pr-reviewer for each PR
```
### pr-merge-pool-supervisor
The merge supervisor can use the combined sizes of this bucket and
`list_prs_needs_review_not_stale` to understand total review demand. A large
combined backlog relative to approved buckets signals under-capacity in the
review pool.
### system-watchdog-pool-supervisor
A growing `list_prs_needs_review_stale_clean` bucket over consecutive watchdog
cycles — while PRs in `list_prs_stale_clean` (approved) are being processed
normally — suggests that review capacity is insufficient to keep pace with
incoming PRs.
## Dependencies
- Node.js ≥ 18 (native `fetch` API)
- `npx tsx` for TypeScript execution
- Zero external npm packages
@@ -0,0 +1,244 @@
# list_prs_needs_review_stale_conflicts — Open PRs With No Approvals, Stale, With Conflicts
**Script name:** `list_prs_needs_review_stale_conflicts`
**Script location:** [`scripts/list_prs_needs_review_stale_conflicts.ts`](../../../scripts/list_prs_needs_review_stale_conflicts.ts)
**Invoke:**
```bash
npx --yes tsx .opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_conflicts.ts \
--url URL --pat TOKEN --owner OWNER --repo REPO
```
**CRITICAL:** Always invoke the script using bash and the format noted above. **Never** try to use the skill as a task, or invoke it through any other method than by directly calling bash with a command of the form listed above under "Invoke:".
## Synopsis
```
list_prs_needs_review_stale_conflicts.ts --url URL --pat TOKEN --owner OWNER --repo REPO
```
Returns all **open** pull requests that have **zero non-dismissed approvals**,
are **stale** (the base branch has advanced since the PR was last synced), and
**have merge conflicts** (`PR.mergeable == false`). These PRs need a first
review AND require manual conflict resolution — they have the most complex
path to merge of any PR awaiting review.
This script is a thin wrapper around [`list_prs`](../list_prs/). It
hard-codes the following filters and delegates all logic to that script:
```
state: 'open'
maxApprovals: 0
stale: 'stale_with_conflicts'
(no ciStatus filter — all CI states are included)
```
## Arguments
All four arguments are **required**. No optional filter arguments exist — the
filters are baked in and cannot be changed.
| Flag | Type | Description |
|------|------|-------------|
| `--url URL` | string | Forgejo base URL, **no trailing slash** (e.g. `https://git.example.com`) |
| `--pat TOKEN` | string | Personal Access Token with read access to the repository |
| `--owner OWNER` | string | Repository owner or organisation name |
| `--repo REPO` | string | Repository name |
| `-h`, `--help` | — | Print usage to stderr and exit 0 |
Any flag other than these five is **rejected** with exit code 1 and an error
message: `ERROR: Unknown argument: <flag>`. Filter parameters are hard-coded
and cannot be overridden via CLI flags on this wrapper script.
### Invalid Argument Combinations
There are no valid filter-combination errors since no optional filters exist.
However, passing any filter-style flag (e.g. `--min-approvals`, `--stale`, etc.)
will cause an immediate exit 1 — those flags are not accepted by this wrapper.
## Hard-Coded Filters
| Filter | Value | Meaning |
|--------|-------|---------|
| `state` | `open` | Only open PRs are returned |
| `maxApprovals` | `0` | PRs with zero non-dismissed `APPROVED` reviews |
| `stale` | `stale_with_conflicts` | Base has advanced AND `PR.mergeable == false` |
**"Stale with conflicts"** means two things are simultaneously true:
1. `PR.merge_base != current base branch HEAD` — the base branch has been pushed to since the PR was last synced.
2. `PR.mergeable == false` — Forgejo has determined that rebasing the PR's commits onto the new base would produce merge conflicts that cannot be resolved automatically.
**"Zero approvals"** means: no reviewer has an active (non-dismissed) `APPROVED`
review as their most recent review.
## Output
Written to **stdout** as a pretty-printed JSON array sorted by `priority_rank`
(highest priority first). Each element is the full Forgejo PR object augmented
with four fields:
| Field | Type | Description |
|-------|------|-------------|
| `approvals_count` | integer | Will always be `0` for results of this script |
| `stale_state` | string | Will always be `stale_with_conflicts` for results of this script |
| `ci_status` | string | `passing`, `failing`, `pending`, or `unknown`**not filtered**; any CI state is included |
| `priority_rank` | integer | 0 (highest) through 6 (unlabelled) |
| `priority_label` | string \| null | Matched `Priority/*` label name, or `null` |
An **empty array** `[]` is a valid and common result — it means no open
conflicted PRs are currently awaiting a first review.
See [`list_prs`](../list_prs/) for the full output schema documentation.
## Diagnostics / stderr
Progress messages are written to stderr and do not affect the JSON output:
```
Fetching PRs from https://git.example.com/org/repo (state=open)...
Fetched 42 PR(s). Enriching and filtering...
Fetching HEAD SHAs for 3 unique base branch(es)...
Fetching reviews for 42 PR(s) concurrently (limit=20)...
Fetching CI status for 42 PR(s) concurrently (limit=20)...
Result: 2/42 PR(s) matched the filter criteria.
```
## Exit Codes
| Code | Meaning |
|------|---------|
| 0 | Success — JSON array written to stdout (may be `[]`) |
| 1 | Fatal error — message written to stderr |
## Errors the Script May Throw
| Condition | Behaviour |
|-----------|-----------|
| Missing `--url`, `--pat`, `--owner`, or `--repo` | Exit 1: `ERROR: --<flag> is required` |
| Any unknown flag passed | Exit 1: `ERROR: Unknown argument: <flag>` |
| Forgejo API non-2xx on PR list | Exit 1 with HTTP status and body detail |
| Forgejo API failure for a single branch or review | Warning to stderr; processing continues |
| Network timeout (30 s per request) | Exit 1 with error message |
## When to Use This Script
Use `list_prs_needs_review_stale_conflicts` when you want to identify the
**highest-complexity PRs awaiting review** — those that need both a reviewer
AND conflict resolution before they can merge. Typical use cases:
- **`pr-review-pool-supervisor`** uses this as its lowest-priority review
bucket (these PRs have the most work remaining after review).
- A **human-liaison agent** can use this to surface a conflict-backlog report:
"These N PRs are not yet reviewed AND already have conflicts — they need
author attention to resolve the conflicts first."
- A **monitoring agent** can track a growing bucket here as a compound health
signal: both review bandwidth AND code divergence are problems.
### Position in the Six-Bucket System
```
Every open PR belongs to exactly one bucket at any moment:
Bucket 1 — list_prs_ready_to_merge (approved + not stale)
Bucket 2 — list_prs_stale_clean (approved + stale, no conflicts)
Bucket 3 — list_prs_stale_conflicts (approved + stale, has conflicts)
Bucket 4 — list_prs_needs_review_not_stale (no approvals + not stale)
Bucket 5 — list_prs_needs_review_stale_clean (no approvals + stale, no conflicts)
Bucket 6 — list_prs_needs_review_stale_conflicts (no approvals + stale, has conflicts) ← THIS SCRIPT
Exception: PRs with stale_state == stale_unknown are transiently absent from
all buckets while Forgejo computes conflict status. They appear shortly.
```
Workflow for a PR in this bucket once approved:
```
Reviewer approves → PR moves to list_prs_stale_conflicts
→ clone repo → rebase locally → resolve conflicts → force-push → merge_pr
```
Note: Conflict resolution may need to happen **before** review if the PR
author is asked to fix their branch first. Whether review comes before or after
conflict resolution is a project workflow decision — this script surfaces the
set of PRs where both are pending.
## Usage Examples
```bash
# Standard usage
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_conflicts.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo
# Count conflicted PRs awaiting first review
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_conflicts.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
| jq 'length'
# Get PR numbers, titles, and head/base branches (useful for conflict resolution planning)
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_conflicts.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
| jq '[.[] | {number, title, head_branch: .head.ref, base_branch: .base.ref}]'
# Get the highest-priority conflicted PR awaiting review
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_conflicts.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
| jq 'first'
```
## Agent Usage Examples
### pr-review-pool-supervisor
The supervisor dispatches `pr-reviewer` workers for PRs in this bucket as
lowest priority. The reviewer is informed that conflicts also exist and may
note this in their review feedback.
```bash
result=$(npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_conflicts.ts \
--url $FORGEJO_URL --pat $FORGEJO_PAT --owner $REPO_OWNER --repo $REPO_NAME)
# If non-empty → dispatch pr-reviewer for each PR (note conflict state in prompt)
```
### human-liaison-pool-supervisor
The liaison can filter results by `created_at` to identify PRs stuck in this
worst-case state for an extended period — no review AND conflicts — and post
a comment pinging the PR author to fix the conflicts first, making the PR
easier to review.
### system-watchdog-pool-supervisor
A growing `list_prs_needs_review_stale_conflicts` bucket is a compound health
signal: it indicates that neither the review pipeline nor the conflict
resolution pipeline is keeping pace with incoming work. The watchdog should
create a `Priority/High` announcement if this bucket exceeds a threshold.
## Dependencies
- Node.js ≥ 18 (native `fetch` API)
- `npx tsx` for TypeScript execution
- Zero external npm packages
@@ -0,0 +1,242 @@
# list_prs_ready_to_merge — Open PRs Approved, Up-to-Date, and CI Passing
**Script name:** `list_prs_ready_to_merge`
**Script location:** [`scripts/list_prs_ready_to_merge.ts`](../../../scripts/list_prs_ready_to_merge.ts)
**Invoke:**
```bash
npx --yes tsx .opencode/skills/auto-agents-system/scripts/list_prs_ready_to_merge.ts \
--url URL --pat TOKEN --owner OWNER --repo REPO
```
**CRITICAL:** Always invoke the script using bash and the format noted above. **Never** try to use the skill as a task, or invoke it through any other method than by directly calling bash with a command of the form listed above under "Invoke:".
## Synopsis
```
list_prs_ready_to_merge.ts --url URL --pat TOKEN --owner OWNER --repo REPO
```
Returns all **open** pull requests that have **at least 1 non-dismissed
approval**, are **not stale** (the PR's head branch is already current with
its base branch), and have **passing CI** (all commit status checks have
succeeded). These PRs are ready to be merged immediately — no rebase,
conflict resolution, or CI wait is required.
This script is a thin wrapper around [`list_prs`](../list_prs/). It
hard-codes the following filters and delegates all logic to that script:
```
state: 'open'
minApprovals: 1
stale: 'not_stale'
ciStatus: ['passing']
```
## Arguments
All four arguments are **required**. No optional filter arguments exist — the
filters are baked in and cannot be changed.
| Flag | Type | Description |
|------|------|-------------|
| `--url URL` | string | Forgejo base URL, **no trailing slash** (e.g. `https://git.example.com`) |
| `--pat TOKEN` | string | Personal Access Token with read access to the repository |
| `--owner OWNER` | string | Repository owner or organisation name |
| `--repo REPO` | string | Repository name |
| `-h`, `--help` | — | Print usage to stderr and exit 0 |
Any flag other than these five is **rejected** with exit code 1 and an error
message: `ERROR: Unknown argument: <flag>`. Filter parameters are hard-coded
and cannot be overridden via CLI flags on this wrapper.
### Invalid Argument Combinations
No optional filter arguments are accepted on this script. Passing any
filter-style flag (e.g. `--min-approvals`, `--stale`, `--state`, etc.) causes
immediate exit 1 — those flags are not accepted by this wrapper.
## Hard-Coded Filters
| Filter | Value | Meaning |
|--------|-------|---------|
| `state` | `open` | Only open PRs are returned |
| `minApprovals` | `1` | At least one non-dismissed `APPROVED` review required |
| `stale` | `not_stale` | `PR.merge_base == current base branch HEAD` |
| `ciStatus` | `['passing']` | All CI checks must have succeeded (`ci_status == 'passing'`) |
**"Not stale"** means `PR.merge_base` (the common ancestor SHA between the PR
head and the base) equals the current HEAD of the base branch. In other words,
the base branch has not advanced since the PR was last synced — the PR can be
merged into the base branch without a rebase.
**"At least 1 approval"** means at least one reviewer has their most recent
review in `APPROVED` state (non-dismissed). A reviewer who approved then later
submitted `REQUEST_CHANGES` is not counted.
**"CI passing"** means the Forgejo combined commit-status for the PR's head
SHA returned `state == 'success'`. PRs with `pending` CI (still running),
`failing` CI (at least one check failed), or `unknown` CI (no checks reported)
are excluded. This prevents merging code before the full test suite has
confirmed it is safe.
## Output
Written to **stdout** as a pretty-printed JSON array sorted by `priority_rank`
(highest priority first). Each element is the full Forgejo PR object augmented
with four fields:
| Field | Type | Description |
|-------|------|-------------|
| `approvals_count` | integer | Will always be ≥ 1 for results of this script |
| `stale_state` | string | Will always be `not_stale` for results of this script |
| `ci_status` | string | Will always be `passing` for results of this script |
| `priority_rank` | integer | 0 (highest) through 6 (unlabelled) |
| `priority_label` | string \| null | Matched `Priority/*` label name, or `null` |
An **empty array** `[]` means no open PR currently satisfies both conditions.
See [`list_prs`](../list_prs/) for the full output schema documentation.
## Diagnostics / stderr
Progress messages are written to stderr and do not affect the JSON output:
```
Fetching PRs from https://git.example.com/org/repo (state=open)...
Fetched 42 PR(s). Enriching and filtering...
Fetching HEAD SHAs for 3 unique base branch(es)...
Fetching reviews for 42 PR(s) concurrently (limit=20)...
Fetching CI status for 42 PR(s) concurrently (limit=20)...
Result: 5/42 PR(s) matched the filter criteria.
```
## Exit Codes
| Code | Meaning |
|------|---------|
| 0 | Success — JSON array written to stdout (may be `[]`) |
| 1 | Fatal error — message written to stderr |
## Errors the Script May Throw
| Condition | Behaviour |
|-----------|-----------|
| Missing `--url`, `--pat`, `--owner`, or `--repo` | Exit 1: `ERROR: --<flag> is required` |
| Any unknown flag passed | Exit 1: `ERROR: Unknown argument: <flag>` |
| Forgejo API non-2xx on PR list | Exit 1 with HTTP status and body detail |
| Forgejo API failure for a single branch or review | Warning to stderr; processing continues |
| Network timeout (30 s per request) | Exit 1 with error message |
## When to Use This Script
Use `list_prs_ready_to_merge` when you need a list of PRs that can be merged
**right now** without any intermediate steps. Typical use cases:
- **`pr-merge-pool-supervisor`** calls this as the **first and highest-priority
step** in its cycle. Processing these PRs first ensures that already-approved,
current PRs are never delayed while rebase or review work is happening.
- A **monitoring agent** can use this as a health indicator: a consistently
non-empty result that never shrinks suggests the merge process is blocked.
- A **deployment pipeline** trigger could use this to determine whether any
code is ready for release.
### Priority in the Four-Bucket System
```
pr-merge-pool-supervisor processes buckets in this order:
1. list_prs_ready_to_merge ← THIS SCRIPT (highest priority)
2. list_prs_stale_clean
3. list_prs_stale_conflicts
4. list_prs_needs_review
When this bucket is non-empty, the supervisor dispatches workers for
ALL PRs in it and then restarts the cycle at step 1.
```
## Usage Examples
```bash
# Standard usage
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_ready_to_merge.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo
# Count ready-to-merge PRs
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_ready_to_merge.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
| jq 'length'
# Extract PR numbers for iteration
READY_PRS=$(npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_ready_to_merge.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
| jq '[.[].number]')
# Get only the top-priority ready PR
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_ready_to_merge.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
| jq 'first'
```
## Agent Usage Examples
### pr-merge-pool-supervisor
The supervisor calls this script as **step 2** (the first work step) of its
main cycle. If the list is non-empty, it dispatches `pr-merge-worker`
sequentially for each PR and then restarts the cycle from step 1.
```bash
result=$(npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_ready_to_merge.ts \
--url $FORGEJO_URL --pat $FORGEJO_PAT --owner $REPO_OWNER --repo $REPO_NAME)
# If non-empty → iterate and dispatch pr-merge-worker for each PR number
```
The supervisor passes each PR's full JSON object (number, title, head SHA,
base branch, staleness, approval count, etc.) in the `pr-merge-worker` prompt.
Since results come from this script, the worker knows the PR is already
approved and not stale — it calls [`merge_pr`](../merge_pr/) directly without
needing to rebase first.
### pr-merge-worker
When dispatched for a PR found by `list_prs_ready_to_merge`, the worker's
decision tree is simple: the PR is approved and current, so it calls
[`merge_pr`](../merge_pr/) immediately without checking for staleness or
conflicts.
### system-watchdog-pool-supervisor
The watchdog could call this periodically to verify that the merge pipeline
is healthy. A PR that appears in `list_prs_ready_to_merge` for many
consecutive watchdog cycles without being merged indicates the
`pr-merge-pool-supervisor` may be stuck or absent.
## Dependencies
- Node.js ≥ 18 (native `fetch` API)
- `npx tsx` for TypeScript execution
- Zero external npm packages
@@ -0,0 +1,237 @@
# list_prs_stale_clean — Open PRs Approved, Behind Base, No Conflicts
**Script name:** `list_prs_stale_clean`
**Script location:** [`scripts/list_prs_stale_clean.ts`](../../../scripts/list_prs_stale_clean.ts)
**Invoke:**
```bash
npx --yes tsx .opencode/skills/auto-agents-system/scripts/list_prs_stale_clean.ts \
--url URL --pat TOKEN --owner OWNER --repo REPO
```
**CRITICAL:** Always invoke the script using bash and the format noted above. **Never** try to use the skill as a task, or invoke it through any other method than by directly calling bash with a command of the form listed above under "Invoke:".
## Synopsis
```
list_prs_stale_clean.ts --url URL --pat TOKEN --owner OWNER --repo REPO
```
Returns all **open** pull requests that have **at least 1 non-dismissed
approval**, are **stale** (the base branch has advanced since the PR was last
synced), and have **no merge conflicts** (`PR.mergeable == true`). These PRs
are approved and almost ready — they just need a server-side rebase to bring
them current before merging.
This script is a thin wrapper around [`list_prs`](../list_prs/). It
hard-codes the following filters and delegates all logic to that script:
```
state: 'open'
minApprovals: 1
stale: 'stale_no_conflicts'
(no ciStatus filter — all CI states are included)
```
## Arguments
All four arguments are **required**. No optional filter arguments exist — the
filters are baked in and cannot be changed.
| Flag | Type | Description |
|------|------|-------------|
| `--url URL` | string | Forgejo base URL, **no trailing slash** (e.g. `https://git.example.com`) |
| `--pat TOKEN` | string | Personal Access Token with read access to the repository |
| `--owner OWNER` | string | Repository owner or organisation name |
| `--repo REPO` | string | Repository name |
| `-h`, `--help` | — | Print usage to stderr and exit 0 |
Any flag other than these five is **rejected** with exit code 1:
`ERROR: Unknown argument: <flag>`. Filter parameters are hard-coded and cannot
be overridden via CLI flags on this wrapper.
### Invalid Argument Combinations
No optional filter arguments are accepted. Passing any filter-style flag
(e.g. `--min-approvals`, `--stale`, `--state`) causes immediate exit 1.
## Hard-Coded Filters
| Filter | Value | Meaning |
|--------|-------|---------|
| `state` | `open` | Only open PRs are returned |
| `minApprovals` | `1` | At least one non-dismissed `APPROVED` review required |
| `stale` | `stale_no_conflicts` | Base has advanced AND `PR.mergeable == true` |
**"Stale no conflicts"** means two things are simultaneously true:
1. `PR.merge_base != current base branch HEAD` — the base branch has been pushed to since the PR was last synced.
2. `PR.mergeable == true` — Forgejo has determined the PR's commits can be rebased/merged on top of the new base without producing conflicts.
This combination means the rebase can be triggered automatically via the
Forgejo server-side rebase API (`POST /pulls/{index}/update?style=rebase`)
without any manual intervention. See [`rebase_pr`](../rebase_pr/).
## Output
Written to **stdout** as a pretty-printed JSON array sorted by `priority_rank`
(highest priority first). Each element is the full Forgejo PR object augmented
with four fields:
| Field | Type | Description |
|-------|------|-------------|
| `approvals_count` | integer | Will always be ≥ 1 for results of this script |
| `stale_state` | string | Will always be `stale_no_conflicts` for results of this script |
| `ci_status` | string | `passing`, `failing`, `pending`, or `unknown`**not filtered**; any CI state is included |
| `priority_rank` | integer | 0 (highest) through 6 (unlabelled) |
| `priority_label` | string \| null | Matched `Priority/*` label name, or `null` |
An **empty array** `[]` means no open PR currently matches all three conditions.
See [`list_prs`](../list_prs/) for the full output schema documentation.
## Diagnostics / stderr
Progress messages are written to stderr and do not affect the JSON output:
```
Fetching PRs from https://git.example.com/org/repo (state=open)...
Fetched 42 PR(s). Enriching and filtering...
Fetching HEAD SHAs for 3 unique base branch(es)...
Fetching reviews for 42 PR(s) concurrently (limit=20)...
Fetching CI status for 42 PR(s) concurrently (limit=20)...
Result: 3/42 PR(s) matched the filter criteria.
```
## Exit Codes
| Code | Meaning |
|------|---------|
| 0 | Success — JSON array written to stdout (may be `[]`) |
| 1 | Fatal error — message written to stderr |
## Errors the Script May Throw
| Condition | Behaviour |
|-----------|-----------|
| Missing `--url`, `--pat`, `--owner`, or `--repo` | Exit 1: `ERROR: --<flag> is required` |
| Any unknown flag passed | Exit 1: `ERROR: Unknown argument: <flag>` |
| Forgejo API non-2xx on PR list | Exit 1 with HTTP status and body detail |
| Forgejo API failure for a single branch or review | Warning to stderr; processing continues |
| Network timeout (30 s per request) | Exit 1 with error message |
## When to Use This Script
Use `list_prs_stale_clean` when you need to identify approved PRs that can be
**brought up-to-date automatically** (no human conflict resolution needed).
Typical use cases:
- **`pr-merge-pool-supervisor`** calls this as **step 3** of its cycle (after
processing ready-to-merge PRs). For each result it dispatches a
`pr-merge-worker` to trigger a server-side rebase, then re-checks step 2
before continuing — because a successful rebase moves the PR from this
bucket into `list_prs_ready_to_merge`.
- A **rebase automation** script could use this as its sole input to keep all
approved PRs current without any merge logic.
- A **monitoring agent** could track this bucket's size over time as a
measure of base-branch churn.
### Position in the Four-Bucket System
```
pr-merge-pool-supervisor processes buckets in this order:
1. list_prs_ready_to_merge
2. list_prs_stale_clean ← THIS SCRIPT (second priority)
3. list_prs_stale_conflicts
4. list_prs_needs_review
Workflow for a PR in this bucket:
rebase_pr → moves PR to list_prs_ready_to_merge → merge_pr
```
## Usage Examples
```bash
# Standard usage
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_stale_clean.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo
# Count stale-but-clean PRs awaiting rebase
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_stale_clean.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
| jq 'length'
# Get PR numbers and their base branches (useful for batch rebase planning)
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_stale_clean.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
| jq '[.[] | {number, title, base: .base.ref}]'
# Get the top-priority stale-clean PR
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_stale_clean.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
| jq 'first'
```
## Agent Usage Examples
### pr-merge-pool-supervisor
The supervisor calls this script as **step 3** of its main cycle. If the
list is non-empty, it dispatches `pr-merge-worker` sequentially for each PR
and then restarts the cycle at step 1.
```bash
result=$(npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_stale_clean.ts \
--url $FORGEJO_URL --pat $FORGEJO_PAT --owner $REPO_OWNER --repo $REPO_NAME)
# If non-empty → dispatch pr-merge-worker for each PR
```
The worker receives the PR's `stale_state == stale_no_conflicts` in its
prompt and follows the "stale, no conflicts" path: call
[`rebase_pr`](../rebase_pr/) first, then call [`merge_pr`](../merge_pr/).
### pr-merge-worker
When dispatched for a PR from this bucket, the worker:
1. Calls [`rebase_pr`](../rebase_pr/) — triggers server-side rebase
2. Calls [`merge_pr`](../merge_pr/) — schedules the merge
The worker does **not** need to clone the repo or resolve conflicts — the
`stale_no_conflicts` state guarantees the server can do it automatically.
### system-watchdog-pool-supervisor
The watchdog can compare the sizes of the `list_prs_stale_clean` and
`list_prs_stale_conflicts` buckets over time. A growing `stale_clean`
bucket paired with a shrinking `list_prs_ready_to_merge` bucket suggests
the merge supervisor is running but rebases are not completing successfully.
## Dependencies
- Node.js ≥ 18 (native `fetch` API)
- `npx tsx` for TypeScript execution
- Zero external npm packages
@@ -0,0 +1,253 @@
# list_prs_stale_conflicts — Open PRs Approved, Stale, and Conflicted
**Script name:** `list_prs_stale_conflicts`
**Script location:** [`scripts/list_prs_stale_conflicts.ts`](../../../scripts/list_prs_stale_conflicts.ts)
**Invoke:**
```bash
npx --yes tsx .opencode/skills/auto-agents-system/scripts/list_prs_stale_conflicts.ts \
--url URL --pat TOKEN --owner OWNER --repo REPO
```
**CRITICAL:** Always invoke the script using bash and the format noted above. **Never** try to use the skill as a task, or invoke it through any other method than by directly calling bash with a command of the form listed above under "Invoke:".
## Synopsis
```
list_prs_stale_conflicts.ts --url URL --pat TOKEN --owner OWNER --repo REPO
```
Returns all **open** pull requests that have **at least 1 non-dismissed
approval**, are **stale** (the base branch has advanced since the PR was last
synced), and **have merge conflicts** (`PR.mergeable == false`). These PRs have
been reviewed and approved but cannot progress without manual conflict
resolution by the PR author or an agent with a local clone.
This script is a thin wrapper around [`list_prs`](../list_prs/). It
hard-codes the following filters and delegates all logic to that script:
```
state: 'open'
minApprovals: 1
stale: 'stale_with_conflicts'
(no ciStatus filter — all CI states are included)
```
## Arguments
All four arguments are **required**. No optional filter arguments exist — the
filters are baked in and cannot be changed.
| Flag | Type | Description |
|------|------|-------------|
| `--url URL` | string | Forgejo base URL, **no trailing slash** (e.g. `https://git.example.com`) |
| `--pat TOKEN` | string | Personal Access Token with read access to the repository |
| `--owner OWNER` | string | Repository owner or organisation name |
| `--repo REPO` | string | Repository name |
| `-h`, `--help` | — | Print usage to stderr and exit 0 |
Any flag other than these five is **rejected** with exit code 1:
`ERROR: Unknown argument: <flag>`. Filter parameters are hard-coded and cannot
be overridden via CLI flags on this wrapper.
### Invalid Argument Combinations
No optional filter arguments are accepted. Passing any filter-style flag
(e.g. `--min-approvals`, `--stale`, `--state`) causes immediate exit 1.
## Hard-Coded Filters
| Filter | Value | Meaning |
|--------|-------|---------|
| `state` | `open` | Only open PRs are returned |
| `minApprovals` | `1` | At least one non-dismissed `APPROVED` review required |
| `stale` | `stale_with_conflicts` | Base has advanced AND `PR.mergeable == false` |
**"Stale with conflicts"** means two things are simultaneously true:
1. `PR.merge_base != current base branch HEAD` — the base branch has been pushed to since the PR was last synced.
2. `PR.mergeable == false` — Forgejo has determined that rebasing the PR's commits onto the new base would produce conflicts that cannot be resolved automatically.
This combination requires manual intervention. The resolution path is:
1. Clone the repository locally (or use `repo-isolator`).
2. Rebase the head branch against the latest base branch.
3. Resolve all merge conflicts.
4. Force-push with lease (`--force-with-lease`).
5. Request re-review if the original approvals are now considered stale.
6. Call [`merge_pr`](../merge_pr/) to initiate the merge.
The server-side rebase endpoint (`POST /pulls/{index}/update?style=rebase`,
used by [`rebase_pr`](../rebase_pr/)) **cannot** be used for these PRs — it
requires `mergeable == true`.
## Output
Written to **stdout** as a pretty-printed JSON array sorted by `priority_rank`
(highest priority first). Each element is the full Forgejo PR object augmented
with four fields:
| Field | Type | Description |
|-------|------|-------------|
| `approvals_count` | integer | Will always be ≥ 1 for results of this script |
| `stale_state` | string | Will always be `stale_with_conflicts` for results of this script |
| `ci_status` | string | `passing`, `failing`, `pending`, or `unknown`**not filtered**; any CI state is included |
| `priority_rank` | integer | 0 (highest) through 6 (unlabelled) |
| `priority_label` | string \| null | Matched `Priority/*` label name, or `null` |
An **empty array** `[]` means no open PR currently matches all three conditions.
See [`list_prs`](../list_prs/) for the full output schema documentation.
## Diagnostics / stderr
Progress messages are written to stderr and do not affect the JSON output:
```
Fetching PRs from https://git.example.com/org/repo (state=open)...
Fetched 42 PR(s). Enriching and filtering...
Fetching HEAD SHAs for 3 unique base branch(es)...
Fetching reviews for 42 PR(s) concurrently (limit=20)...
Fetching CI status for 42 PR(s) concurrently (limit=20)...
Result: 2/42 PR(s) matched the filter criteria.
```
## Exit Codes
| Code | Meaning |
|------|---------|
| 0 | Success — JSON array written to stdout (may be `[]`) |
| 1 | Fatal error — message written to stderr |
## Errors the Script May Throw
| Condition | Behaviour |
|-----------|-----------|
| Missing `--url`, `--pat`, `--owner`, or `--repo` | Exit 1: `ERROR: --<flag> is required` |
| Any unknown flag passed | Exit 1: `ERROR: Unknown argument: <flag>` |
| Forgejo API non-2xx on PR list | Exit 1 with HTTP status and body detail |
| Forgejo API failure for a single branch or review | Warning to stderr; processing continues |
| Network timeout (30 s per request) | Exit 1 with error message |
## When to Use This Script
Use `list_prs_stale_conflicts` to identify approved PRs that are **blocked by
conflicts** and need manual or agent-driven resolution. Typical use cases:
- **`pr-merge-pool-supervisor`** calls this as **step 4** of its cycle, after
processing ready-to-merge and stale-clean PRs. For each result it dispatches
a `pr-merge-worker` to perform a local clone, resolve conflicts, force-push,
and then trigger the merge.
- A **human-liaison agent** could use this to generate a "conflict backlog"
report, listing PRs that require author attention.
- A **monitoring alert** could trigger when this bucket grows beyond a
threshold, signalling that the codebase is accumulating merge debt.
### Position in the Four-Bucket System
```
pr-merge-pool-supervisor processes buckets in this order:
1. list_prs_ready_to_merge
2. list_prs_stale_clean
3. list_prs_stale_conflicts ← THIS SCRIPT (third priority)
4. list_prs_needs_review
Workflow for a PR in this bucket (requires local clone):
clone repo → rebase locally → resolve conflicts → force-push
→ merge_pr
```
## Usage Examples
```bash
# Standard usage
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_stale_conflicts.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo
# Count conflicted approved PRs
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_stale_conflicts.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
| jq 'length'
# Get PR numbers, titles, and head branches (for conflict resolution planning)
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_stale_conflicts.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
| jq '[.[] | {number, title, head_branch: .head.ref, base_branch: .base.ref}]'
# Get the highest-priority conflicted PR
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_stale_conflicts.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
| jq 'first'
```
## Agent Usage Examples
### pr-merge-pool-supervisor
The supervisor calls this script as **step 4** of its main cycle. If the
list is non-empty, it dispatches `pr-merge-worker` sequentially for each PR
and then restarts the cycle at step 1.
```bash
result=$(npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_stale_conflicts.ts \
--url $FORGEJO_URL --pat $FORGEJO_PAT --owner $REPO_OWNER --repo $REPO_NAME)
# If non-empty → dispatch pr-merge-worker for each PR (conflict resolution path)
```
The worker receives `stale_state == stale_with_conflicts` in its prompt and
follows the conflict-resolution path: clone via `repo-isolator`, rebase
locally, resolve conflicts, force-push via `git-commit-helper`, then call
[`merge_pr`](../merge_pr/).
### pr-merge-worker
When dispatched for a PR from this bucket, the worker cannot use the server-
side rebase shortcut. Instead it must:
1. Use `repo-isolator` to create a local clone with the PR branch.
2. Run `git rebase <base>` locally.
3. Inspect conflict markers; use recent git history to inform resolutions.
4. Stage resolved files and continue the rebase.
5. Use `git-commit-helper` to force-push with lease.
6. Call [`merge_pr`](../merge_pr/) to schedule the merge.
### human-liaison-pool-supervisor
The liaison could filter this script's output by `created_at` to identify
PRs that have been stuck in conflict state for more than N days, then post
a comment pinging the PR author to resolve the conflict.
### system-watchdog-pool-supervisor
A growing `list_prs_stale_conflicts` bucket over consecutive watchdog cycles
(while the merge supervisor is running) indicates that conflict resolution
is failing — possibly because the automated resolver is not capable of
handling the specific type of conflict. The watchdog should create a
`Priority/High` announcement.
## Dependencies
- Node.js ≥ 18 (native `fetch` API)
- `npx tsx` for TypeScript execution
- Zero external npm packages
@@ -0,0 +1,322 @@
# merge_pr — Initiate a Rebase-Style Merge (with Automerge) on a PR
**Script name:** `merge_pr`
**Script location:** [`scripts/merge_pr.ts`](../../../scripts/merge_pr.ts)
**Invoke:**
```bash
npx --yes tsx .opencode/skills/auto-agents-system/scripts/merge_pr.ts \
--url URL --pat TOKEN --owner OWNER --repo REPO --pr NUMBER \
[--dep error|delete|reverse]
```
**CRITICAL:** Always invoke the script using bash and the format noted above. **Never** try to use the skill as a task, or invoke it through any other method than by directly calling bash with a command of the form listed above under "Invoke:".
**CRITICAL:** All attempts to merge pull requests **must** use this script.
## Synopsis
```
merge_pr.ts --url URL --pat TOKEN --owner OWNER --repo REPO --pr NUMBER
[--dep error|delete|reverse]
```
Calls the Forgejo REST API to merge a pull request using the `rebase` merge
style with `merge_when_checks_succeed=true`. If all CI checks and review
requirements are already satisfied, the PR merges immediately. Otherwise,
Forgejo queues it for automatic merging once those conditions are met — the
script does not wait; it returns as soon as the merge request is accepted.
The script also detects and handles **open blocking issue dependencies** before
calling the merge endpoint, since Forgejo silently ignores merge requests when
a PR has open dependencies (returns HTTP 200 but does nothing).
## Arguments
### Required
| Flag | Type | Description |
|------|------|-------------|
| `--url URL` | string | Forgejo base URL, **no trailing slash** (e.g. `https://git.example.com`) |
| `--pat TOKEN` | string | Personal Access Token with **merge permission** on the repository |
| `--owner OWNER` | string | Repository owner or organisation name |
| `--repo REPO` | string | Repository name |
| `--pr NUMBER` | positive integer | Pull request number to merge |
### Optional
| Flag | Type | Default | Description |
|------|------|---------|-------------|
| `--dep STRATEGY` | string | `error` | How to handle open blocking issue dependencies (see below) |
| `-h`, `--help` | — | — | Print usage to stderr and exit 0 |
### Dependency Strategy (`--dep`)
Forgejo PRs can declare issue dependencies. When a PR has **open** (unresolved)
dependencies, Forgejo silently ignores merge requests — it returns HTTP 200 but
the PR is never actually merged. This script detects open dependencies first
and handles them according to `--dep`:
| Value | Behaviour |
|-------|-----------|
| `error` | **(default)** Abort with exit code 1 and list all open blocking dependencies. State is never modified. Safe for read-before-write workflows. |
| `delete` | Delete each open dependency link from the PR, then proceed with the merge. The dependent issues are unaffected; only the link is removed. |
| `reverse` | Delete each open dependency link, then create a new reversed link (the formerly-blocking issue now depends on the PR instead of the other way around). Useful when the intent is "merge this PR, then finish the related issue". |
### Argument Validity Rules
- `--pr` must be a positive integer. Floats, zero, and negatives are rejected
with exit code 1.
- `--dep` must be exactly `error`, `delete`, or `reverse`. Any other value
causes exit code 1.
- All five named arguments are required (except `--dep` which defaults to
`error`). Any missing required argument causes exit code 1.
- Unknown flags cause exit code 1.
## What the Script Does
The script executes these steps in order:
1. **Fetch the PR** — verifies it is open and not already merged.
2. **Fetch all dependencies** (exhaustively paginated) — filters to open ones.
3. **Handle open dependencies** per `--dep` strategy (error / delete / reverse).
4. **POST to the merge endpoint**:
```
POST /api/v1/repos/{owner}/{repo}/pulls/{index}/merge
{
"Do": "rebase",
"merge_when_checks_succeed": true,
"head_commit_id": "<current HEAD SHA>"
}
```
The `head_commit_id` acts as an **optimistic lock** — if someone pushed to
the branch between the script reading the PR and calling merge, Forgejo
returns HTTP 409, preventing a stale-read merge.
5. **Re-fetch the PR** — inspects `merged` flag to determine the outcome.
6. **Return JSON result** with `status: "merged"` or `status: "auto_merge_scheduled"`.
## Output
Written to **stdout** on success as a pretty-printed JSON object:
```json
{
"status": "merged" | "auto_merge_scheduled",
"pr_number": 42,
"pr_title": "feat: add new feature",
"head_sha": "abc123...",
"merge_commit_sha": "<sha>" | null,
"merged_at": "2026-04-17T12:00:00Z" | null,
"deps_handled": [
{
"action": "deleted" | "reversed",
"dep_number": 10,
"dep_title": "Related issue title",
"dep_repo": "owner/repo"
}
],
"message": "PR #42 merged immediately using rebase style."
}
```
| Field | Type | Description |
|-------|------|-------------|
| `status` | string | `merged` — PR merged immediately; `auto_merge_scheduled` — Forgejo accepted the request and will merge when checks pass |
| `pr_number` | integer | The PR number that was processed |
| `pr_title` | string | The PR title at the time of the call |
| `head_sha` | string | The head commit SHA that was submitted for merge |
| `merge_commit_sha` | string \| null | Non-null only when `status == "merged"` |
| `merged_at` | string \| null | ISO 8601 timestamp, non-null only when `status == "merged"` |
| `deps_handled` | array | Zero or more dependency actions taken (empty if no open deps existed) |
| `message` | string | Human-readable summary of the outcome |
## Diagnostics / stderr
All progress information is written to stderr:
```
Fetching PR #42 from https://git.example.com/org/repo...
PR #42: "feat: add new feature"
State: open
Head SHA: abc123def456...
Mergeable: true
Fetching dependencies for PR #42...
Total dependencies: 2 (1 open / blocking)
BLOCKING: #10 [owner/repo] "Related issue"
Handling 1 open dependency(ies) with strategy 'delete'...
DELETE dependency: PR #42#10 (owner/repo)
Deleted OK (HTTP 200)
POST https://git.example.com/api/v1/repos/owner/repo/pulls/42/merge
Do=rebase merge_when_checks_succeed=true head_commit_id=abc123def456…
Response: HTTP 200
Merge request accepted. Re-fetching PR to determine state...
merged=false state=open
PR #42 not yet merged — auto-merge is pending checks/approvals.
```
## Exit Codes
| Code | Meaning |
|------|---------|
| 0 | Merge initiated — `status` is `merged` or `auto_merge_scheduled` |
| 1 | Any failure — descriptive error on stderr with machine-readable error code |
## Errors the Script May Throw
| Error Code | HTTP Status | Condition |
|------------|-------------|-----------|
| `PR_MERGED` | — | PR is already merged; nothing to do |
| `PR_NOT_OPEN` | — | PR is closed (not open) |
| `OPEN_DEPENDENCIES` | — | Open deps found and `--dep=error` (default); lists all blockers |
| `DEP_DELETE_FAILED` | varies | DELETE of a dependency link returned non-200 |
| `DEP_REVERSE_FAILED` | varies | POST of the reversed dependency returned non-201 |
| `MERGE_FORBIDDEN` | 403 | The PAT lacks merge access to the repository |
| `MERGE_NOT_ALLOWED` | 405 | Branch protection disallows the `rebase` merge style, or automerge is disabled |
| `MERGE_CONFLICT` | 409 | Merge conflicts present, or `head_commit_id` mismatch (concurrent push between read and merge call); re-run to retry with fresh HEAD |
| `MERGE_UNPROCESSABLE` | 422 | PR is a draft, already merged, or otherwise not mergeable |
| `HTTP_NNN` | NNN | Any other unexpected HTTP response from the merge endpoint |
A special case: HTTP 409 with the message `"already scheduled to auto merge"`
is treated as **success** (not an error). This happens when the script is run
twice on the same PR; the second run detects the already-scheduled automerge
and returns `status: "auto_merge_scheduled"`.
## Important Behaviours and Caveats
### Automerge State Is Not Directly Readable
Forgejo provides no read-only endpoint to confirm automerge is scheduled. The
script infers `status: "auto_merge_scheduled"` from the combination of a 200
response from the merge endpoint plus `merged=false` on the re-fetched PR.
This is the authoritative signal — it means Forgejo has accepted the request.
### Optimistic Locking
The `head_commit_id` field in the merge request body is an optimistic lock. If
someone pushes to the PR branch between when the script fetches the PR (step 1)
and when it calls the merge endpoint (step 4), Forgejo returns HTTP 409
(`MERGE_CONFLICT`). Simply re-running the script resolves this.
### No Waiting for CI
The script returns immediately after Forgejo accepts the merge request. It does
**not** poll for the merge to complete. When `status: "auto_merge_scheduled"`,
the caller should expect the PR to eventually close on its own once CI passes.
This is intentional — agents should never block waiting for CI.
### Rebase Merge Style
The `Do: "rebase"` merge style rewrites the PR's commits linearly on top of
the base branch HEAD. No merge commit is created. This produces a clean,
linear history. Other merge styles (`merge`, `squash`, `rebase-merge`) are
not used by this script.
## When to Use This Script
Use `merge_pr` whenever you want to **initiate a merge on a specific PR**:
- After [`rebase_pr`](../rebase_pr/) has brought a stale PR current.
- After manual conflict resolution and force-push on a conflicted PR.
- Directly on a PR returned by [`list_prs_ready_to_merge`](../list_prs_ready_to_merge/).
- Any time you need to queue a PR for automerge once its CI finishes.
Do **not** use this script if the PR is still stale — call
[`rebase_pr`](../rebase_pr/) first (if `stale_no_conflicts`) or resolve
conflicts locally (if `stale_with_conflicts`).
## Usage Examples
```bash
# Merge PR #42 (default: abort if open dependencies exist)
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/merge_pr.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
--pr 42
# Merge PR #42, deleting any open dependency links first
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/merge_pr.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
--pr 42 \
--dep delete
# Merge PR #42, reversing dependency links (issue now depends on PR)
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/merge_pr.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
--pr 42 \
--dep reverse
# Parse just the status from the output
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/merge_pr.ts \
--url https://git.example.com --pat ghp_XXXX \
--owner my-org --repo my-repo --pr 42 \
| jq -r '.status'
# Check if the merge was immediate or scheduled
result=$(npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/merge_pr.ts \
--url https://git.example.com --pat ghp_XXXX \
--owner my-org --repo my-repo --pr 42)
status=$(echo "$result" | jq -r '.status')
if [ "$status" = "merged" ]; then
echo "Merged immediately"
else
echo "Queued for automerge"
fi
```
## Agent Usage Examples
### pr-merge-worker
The worker is the **primary caller** of this script. It always calls
`merge_pr` as the final step after any necessary rebase or conflict resolution:
```
# After rebase_pr (stale_no_conflicts path):
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/merge_pr.ts \
--url $FORGEJO_URL --pat $FORGEJO_PAT \
--owner $REPO_OWNER --repo $REPO_NAME \
--pr $PR_NUMBER --dep delete
# After local conflict resolution (stale_with_conflicts path):
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/merge_pr.ts \
--url $FORGEJO_URL --pat $FORGEJO_PAT \
--owner $REPO_OWNER --repo $REPO_NAME \
--pr $PR_NUMBER --dep delete
# For a ready-to-merge PR (not stale, already approved):
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/merge_pr.ts \
--url $FORGEJO_URL --pat $FORGEJO_PAT \
--owner $REPO_OWNER --repo $REPO_NAME \
--pr $PR_NUMBER
```
The worker uses `--dep delete` by default for the stale buckets because those
PRs have already been verified to meet all quality gates; open dependency links
at that point are likely stale metadata rather than genuine blockers.
### pr-merge-pool-supervisor
The supervisor does **not** call this script directly. It dispatches
`pr-merge-worker` subagents, which call this script as part of their procedure.
### implementation-worker
An implementation worker creating a PR would never call this script — that
would be outside its responsibility. However, it might call it after creating
a PR if the project's workflow involves self-merging after CI passes (unusual
but possible with `--dep error` for safety).
## Dependencies
- Node.js ≥ 18 (native `fetch` API)
- `npx tsx` for TypeScript execution
- Zero external npm packages
@@ -0,0 +1,322 @@
# rebase_pr — Trigger a Server-Side Rebase on a Stale, Conflict-Free PR
**Script name:** `rebase_pr`
**Script location:** [`scripts/rebase_pr.ts`](../../../scripts/rebase_pr.ts)
**Invoke:**
```bash
npx --yes tsx .opencode/skills/auto-agents-system/scripts/rebase_pr.ts \
--url URL --pat TOKEN --owner OWNER --repo REPO --pr NUMBER
```
**CRITICAL:** Always invoke the script using bash and the format noted above. **Never** try to use the skill as a task, or invoke it through any other method than by directly calling bash with a command of the form listed above under "Invoke:".
## Synopsis
```
rebase_pr.ts --url URL --pat TOKEN --owner OWNER --repo REPO --pr NUMBER
```
Calls the Forgejo REST API to rebase a pull request's head branch onto the
latest commit of its base branch — **entirely server-side, without a local
git clone**. The PR's commits are rewritten on top of the current base branch
HEAD, bringing the PR fully up-to-date.
The script enforces three strict pre-flight conditions before calling the
rebase endpoint. If any condition fails, the script exits with code 1 and a
descriptive error; it **never proceeds blindly**.
## Arguments
All five arguments are **required**. There are no optional arguments beyond
`--help`.
| Flag | Type | Description |
|------|------|-------------|
| `--url URL` | string | Forgejo base URL, **no trailing slash** (e.g. `https://git.example.com`) |
| `--pat TOKEN` | string | Personal Access Token with **write access** to the repository |
| `--owner OWNER` | string | Repository owner or organisation name |
| `--repo REPO` | string | Repository name |
| `--pr NUMBER` | positive integer | Pull request number to rebase |
| `-h`, `--help` | — | Print usage to stderr and exit 0 |
### Argument Validity Rules
- `--pr` must be a **positive integer**. Floats, zero, and negatives are
rejected with exit code 1: `ERROR: --pr must be a positive integer`.
- All five arguments are required. Any missing argument causes exit code 1.
- Unknown flags cause exit code 1.
### Invalid Argument Combinations
There are no multi-flag combinations to validate — the five arguments are
independent. However the following are logically invalid and will be caught
by the pre-flight checks (not by argument parsing):
- Passing the number of an already-merged PR → `PR_MERGED` error
- Passing a PR that is not stale → `PR_NOT_STALE` error (informational, not a bug)
- Passing a PR with conflicts → `PR_HAS_CONFLICTS` error
## Pre-Flight Conditions
The script enforces **all three** of the following before calling the Forgejo
rebase endpoint. Failing any one causes an immediate exit 1:
| Condition | Check | Error Code if Failed |
|-----------|-------|---------------------|
| PR must be open | `PR.state == "open"` AND `PR.merged == false` | `PR_MERGED` / `PR_NOT_OPEN` |
| PR must be stale | `PR.merge_base != current base-branch HEAD SHA` | `PR_NOT_STALE` (informational — no rebase needed) |
| PR must have no conflicts | `PR.mergeable == true` | `MERGEABLE_UNKNOWN` (null) or `PR_HAS_CONFLICTS` (false) |
The staleness check requires one additional API call to fetch the current HEAD
SHA of the base branch. This is cached internally but requires the PAT to have
read access to branches.
## What the Script Does
1. **Fetch the PR** — reads `state`, `merged`, `mergeable`, `merge_base`,
`base.ref`, `head.sha`.
2. **Guard: PR must be open and not merged.**
3. **Fetch the current base-branch HEAD SHA** via
`GET /api/v1/repos/{owner}/{repo}/branches/{branch}`.
4. **Guard: PR must be stale** (`merge_base != base HEAD`).
5. **Guard: PR must have no conflicts** (`mergeable == true`; rejects `null` and `false`).
6. **POST to the rebase endpoint**:
```
POST /api/v1/repos/{owner}/{repo}/pulls/{index}/update?style=rebase
```
No request body; the `style=rebase` query parameter selects the rebase
strategy (as opposed to `style=merge` which creates a merge commit).
7. **Re-fetch the PR** — captures the new head SHA to confirm the rebase applied.
8. **Return JSON result** with the old and new SHAs.
## Output
Written to **stdout** on success as a pretty-printed JSON object:
```json
{
"success": true,
"message": "PR #42 successfully rebased onto 'master'.",
"pr_number": 42,
"base_branch": "master",
"old_merge_base": "abc123def456...",
"new_head_sha": "xyz789abc012..."
}
```
| Field | Type | Description |
|-------|------|-------------|
| `success` | boolean | Always `true` on a successful exit |
| `message` | string | Human-readable summary |
| `pr_number` | integer | The PR number that was rebased |
| `base_branch` | string | The base branch the PR was rebased onto |
| `old_merge_base` | string | The `merge_base` SHA before the rebase (documents what changed) |
| `new_head_sha` | string | The PR's new head SHA after the rebase |
## Diagnostics / stderr
All progress information is written to stderr:
```
Fetching PR #42 from https://git.example.com/org/repo...
PR #42: "feat: add new feature"
State: open
Base: master
Head: feature/my-feature
Merge base: abc123def456...
Mergeable: true
Fetching current HEAD of base branch 'master'...
Base HEAD: def789abc123...
PR is stale: merge_base (abc123def4…) != base HEAD (def789abc1…).
No conflicts detected (mergeable=true). Triggering server-side rebase...
POST https://git.example.com/api/v1/repos/org/repo/pulls/42/update?style=rebase
Response: HTTP 200
Rebase triggered. Fetching updated PR details...
New head SHA: xyz789abc012...
New merge_base: (pending — Forgejo will compute shortly)
```
## Exit Codes
| Code | Meaning |
|------|---------|
| 0 | Rebase triggered successfully — JSON result written to stdout |
| 1 | Any failure — descriptive error on stderr with machine-readable error code |
## Errors the Script May Throw
| Error Code | Condition |
|------------|-----------|
| `PR_MERGED` | The PR is already merged; nothing to rebase |
| `PR_NOT_OPEN` | The PR is closed (not open) |
| `MERGE_BASE_MISSING` | `PR.merge_base` is null — Forgejo hasn't set it yet; retry shortly |
| `PR_NOT_STALE` | `PR.merge_base == base HEAD` — PR is already up-to-date; no rebase needed (informational, not a bug) |
| `MERGEABLE_UNKNOWN` | `PR.mergeable == null` — Forgejo hasn't finished computing the conflict status; retry in a few seconds |
| `PR_HAS_CONFLICTS` | `PR.mergeable == false` — PR has merge conflicts; server-side rebase cannot proceed; manual resolution required |
| `BASE_HEAD_UNKNOWN` | The branch API did not return a commit id for the base branch |
| `FORBIDDEN` | HTTP 403 — the PAT lacks write access to the head repository |
| `NOT_FOUND` | HTTP 404 — the PR or repository was not found |
| `REBASE_CONFLICT` | HTTP 409 — conflicts were detected during the rebase itself despite `mergeable=true` pre-flight check (race condition: concurrent push between pre-flight and rebase call); re-run |
| `ALREADY_UP_TO_DATE` | HTTP 422 — PR was already current by the time the rebase was called (race condition: another process rebased it first); treat as success and proceed |
| `HTTP_NNN` | Any other unexpected HTTP response from the update endpoint |
### Race Condition Notes
Two race conditions are possible between the pre-flight check and the rebase call:
1. **`REBASE_CONFLICT` (HTTP 409)**: Another agent pushed to the base branch
between your staleness check (step 3) and the rebase call (step 6), causing
newly introduced conflicts. Resolution: re-run the script; if conflicts
persist, the PR needs manual resolution.
2. **`ALREADY_UP_TO_DATE` (HTTP 422)**: Another process rebased the PR first.
This should be treated as a success — proceed to call
[`merge_pr`](../merge_pr/).
## Important Behaviours and Caveats
### Server-Side Only
This script uses Forgejo's built-in rebase capability. It does **not**
clone the repository, run `git` locally, or require git to be installed.
This is only possible because `PR.mergeable == true` guarantees there are
no conflicts for the server to stumble on.
### `mergeable == null` Is Not Processed
Forgejo computes `PR.mergeable` asynchronously after a PR is created or
updated. If the value is `null`, the script exits with `MERGEABLE_UNKNOWN`
rather than guessing. Retry after a few seconds.
### After the Rebase
The re-fetched PR may show `merge_base` as still `null` or a stale value —
Forgejo computes the new `merge_base` asynchronously after the rebase. The
`new_head_sha` field in the output is the reliable indicator that the rebase
applied. The next call to a `list_prs_*` script will see the updated state
once Forgejo catches up (typically within seconds).
### This Script Does Not Merge
`rebase_pr` only brings the PR up-to-date. To actually merge it after rebasing,
call [`merge_pr`](../merge_pr/).
## When to Use This Script
Use `rebase_pr` when you have a PR whose `stale_state` is `stale_no_conflicts`
(i.e. [`list_prs_stale_clean`](../list_prs_stale_clean/) returns it). This is
the correct and only safe use of this script.
Do **not** use this script for:
- PRs with `stale_state == stale_with_conflicts` — use a local clone instead.
- PRs with `stale_state == stale_unknown` — wait for Forgejo to compute the
conflict status, then retry.
- PRs with `stale_state == not_stale` — they are already current; call
[`merge_pr`](../merge_pr/) directly.
## Usage Examples
```bash
# Rebase PR #42 onto its base branch
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/rebase_pr.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
--pr 42
# Check the new head SHA after a successful rebase
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/rebase_pr.ts \
--url https://git.example.com \
--pat ghp_XXXX \
--owner my-org \
--repo my-repo \
--pr 42 \
| jq -r '.new_head_sha'
# Rebase then immediately queue for merge (full pipeline for stale-clean PRs)
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/rebase_pr.ts \
--url https://git.example.com --pat ghp_XXXX \
--owner my-org --repo my-repo --pr 42 \
&& \
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/merge_pr.ts \
--url https://git.example.com --pat ghp_XXXX \
--owner my-org --repo my-repo --pr 42
# Handle PR_NOT_STALE gracefully in a shell script
output=$(npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/rebase_pr.ts \
--url https://git.example.com --pat ghp_XXXX \
--owner my-org --repo my-repo --pr 42 2>&1)
exit_code=$?
if [ $exit_code -ne 0 ]; then
if echo "$output" | grep -q "PR_NOT_STALE"; then
echo "PR is already current — proceeding to merge"
# call merge_pr
else
echo "Rebase failed: $output"
exit 1
fi
fi
```
## Agent Usage Examples
### pr-merge-worker
The worker is the **primary caller** of this script, specifically on the
`stale_no_conflicts` path:
```
# Step 1: Server-side rebase (stale_no_conflicts path)
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/rebase_pr.ts \
--url $FORGEJO_URL --pat $FORGEJO_PAT \
--owner $REPO_OWNER --repo $REPO_NAME \
--pr $PR_NUMBER
# Step 2: Immediately schedule the merge
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/merge_pr.ts \
--url $FORGEJO_URL --pat $FORGEJO_PAT \
--owner $REPO_OWNER --repo $REPO_NAME \
--pr $PR_NUMBER --dep delete
```
The worker does **not** call `rebase_pr` for the `stale_with_conflicts` path —
that path requires a local clone with manual conflict resolution.
### pr-merge-pool-supervisor
The supervisor never calls this script directly. It dispatches `pr-merge-worker`
subagents (via the Task tool, blocking), which call this script as part of
the stale-clean processing path.
### system-watchdog-pool-supervisor
The watchdog would not normally call `rebase_pr`. However, it could be
used in an emergency intervention workflow to manually rebase a PR that the
merge supervisor has been unable to process.
### grooming-pool-supervisor
The grooming supervisor focuses on issue/PR metadata and would not normally
call `rebase_pr`. However, it might verify that `rebase_pr` is available
and runnable as part of a pipeline health check.
## Dependencies
- Node.js ≥ 18 (native `fetch` API)
- `npx tsx` for TypeScript execution
- Zero external npm packages
@@ -13,7 +13,6 @@ The system uses four model tiers for implementation work, ordered by cost and ca
All tiers have `max_tokens: 200000`.
---
## How Tier Selectors Work
@@ -41,7 +40,6 @@ This applies to any agent that uses tier-based execution. The same `tier-*` sele
- `typecheck-fixer`, `lint-fixer`, `test-fixer`
- `coverage-improver`
---
## Progressive Escalation
@@ -84,7 +82,6 @@ Steps:
3. **Stop dispatching workers** for this item until `needs feedback` is removed
4. Create announcement: `[{prefix}] Announce: Human escalation needed for issue/PR #N` at Priority/High
---
## Default Model Assignments
@@ -147,7 +144,6 @@ Several agents switch to **Gemini 2.5 Pro** at runtime for large context windows
- `test-infra-worker` → Gemini 2.5 Pro
- `architecture-guard-worker` → Gemini 2.5 Pro
---
## Escalation Path Reference
@@ -9,7 +9,6 @@ The CleverAgents system has no shared memory between agents. All coordination ha
| **Status issue** | Current agent state — what it's doing, health, progress | Replaced each cycle (old one closed) | `[{PREFIX}] Status: {Type} (Cycle N)` |
| **Announcement issue** | Persistent signals to other agents | Persists until explicitly closed | `[{PREFIX}] Announce: {Message}` |
---
## Status Tracking Issues
@@ -65,7 +64,6 @@ Any agent that wants to find another agent's current status can:
2. The most recent open issue is the current cycle
3. Read its body and comments for detailed state
---
## Announcement Issues
@@ -116,7 +114,6 @@ Agents read others' announcements via `READ_ANNOUNCEMENTS`:
- High: process before starting next work cycle
- Medium/Low: opportunistically when convenient
---
## System-Specific Labels
@@ -150,7 +147,6 @@ For complete label rules — forbidden operations (`forgejo_create_label` etc.),
- **`cleverthis-guidelines` skill** — company-wide label and priority hierarchy definitions
- **`forgejo-api` skill** — curl patterns for all Forgejo API operations including label endpoints (`forgejo-label-manager` loads this skill automatically)
---
## automation-tracking-manager Operations Summary
@@ -0,0 +1,228 @@
# Announcement Relevancy Matrix
Which agents consume announcements from which other agents, and at what
minimum priority threshold.
For context on the announcement system itself (how to create, read, and close
announcements) see [`../`](../) (the tracking-system reference).
For dynamic programmatic lookup use the `agent-prefix-info` subagent with
operation `GET_RELEVANCY_MATRIX`.
## Universal Baseline — Applies to ALL Agents Without Exception
```
Priority/CI-Blocker from ANY agent → consume immediately, always
```
No agent is exempt from this rule. CI-Blocker signals block all other work.
## Per-Agent Relevancy Table
### `AUTO-PROD-BLDR` — product-builder (process supervisor)
| Source | Min Priority | Rationale |
|--------|-------------|-----------|
| ALL agents | Priority/Low+ | Monitors everything; must see all signals |
### `AUTO-WDOG` — system-watchdog
| Source | Min Priority | Rationale |
|--------|-------------|-----------|
| ALL agents | Priority/Low+ | Must observe the full system to audit it |
### `AUTO-HUMAN` — human-liaison
| Source | Min Priority | Rationale |
|--------|-------------|-----------|
| ALL agents | Priority/High+ | Relays important events to humans |
### `AUTO-EVLV` — agent-evolution
| Source | Min Priority | Rationale |
|--------|-------------|-----------|
| ALL agents | Priority/Medium+ | Needs broad pattern detection across all pools |
### `AUTO-IMP-SUP` — implementation pool (primary code producer)
| Source | Min Priority | Rationale |
|--------|-------------|-----------|
| `AUTO-WDOG` | Priority/Critical+ | System alerts that may block implementation work |
| `AUTO-EPIC` | Priority/High+ | New issues created and ready to implement |
| `AUTO-REV-SUP` | Priority/High+ | Review feedback requiring code fixes |
| `AUTO-PRMRG-SUP` | Priority/High+ | Merge status, rebase failures affecting PR work |
| `AUTO-ARCH` | Priority/High+ | Architectural decisions affecting implementation approach |
| `AUTO-OWNR` | Priority/High+ | Priority and scope changes |
| `AUTO-HUMAN` | Priority/High+ | Human requests relayed by liaison |
| `AUTO-GROOM` | Priority/Medium+ | Issue quality corrections affecting work items |
| `AUTO-GUARD` | Priority/Medium+ | Pattern drift warnings to apply to new code |
| `AUTO-SPEC` | Priority/Medium+ | Spec changes affecting implementation approach |
| All others | Priority/Critical+ | Universal baseline |
### `AUTO-REV-SUP` — PR review pool
| Source | Min Priority | Rationale |
|--------|-------------|-----------|
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
| `AUTO-IMP-SUP` | Priority/High+ | New PRs available for review |
| `AUTO-ARCH` | Priority/High+ | Architecture decisions affecting review criteria |
| `AUTO-PRMRG-SUP` | Priority/High+ | Merge status of previously reviewed PRs |
| `AUTO-GUARD` | Priority/Medium+ | Pattern standards to check for in reviews |
| `AUTO-SPEC` | Priority/Medium+ | Spec alignment criteria updates |
| All others | Priority/Critical+ | Universal baseline |
### `AUTO-PRMRG-SUP` — PR merge pool
| Source | Min Priority | Rationale |
|--------|-------------|-----------|
| `AUTO-WDOG` | Priority/Critical+ | CI-Blocker alerts, system health |
| `AUTO-REV-SUP` | Priority/High+ | Review approvals that enable merging |
| `AUTO-IMP-SUP` | Priority/High+ | New PRs entering the merge pipeline |
| `AUTO-GROOM` | Priority/Medium+ | PR quality corrections before merge |
| All others | Priority/Critical+ | Universal baseline |
### `AUTO-UAT-SUP` — UAT test pool
| Source | Min Priority | Rationale |
|--------|-------------|-----------|
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
| `AUTO-IMP-SUP` | Priority/High+ | New code merged and ready for UAT |
| `AUTO-SPEC` | Priority/High+ | Spec changes requiring retesting |
| `AUTO-ARCH` | Priority/High+ | Behavioral changes affecting test scope |
| `AUTO-PRMRG-SUP` | Priority/Medium+ | Merged PRs triggering retest cycles |
| All others | Priority/Critical+ | Universal baseline |
### `AUTO-BUG-SUP` — bug hunt pool
| Source | Min Priority | Rationale |
|--------|-------------|-----------|
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
| `AUTO-IMP-SUP` | Priority/High+ | New code to analyze for bugs |
| `AUTO-UAT-SUP` | Priority/Medium+ | Test failures that may reveal underlying bugs |
| `AUTO-SPEC` | Priority/Medium+ | Spec changes affecting analysis scope |
| All others | Priority/Critical+ | Universal baseline |
### `AUTO-INF-SUP` — test infrastructure pool
| Source | Min Priority | Rationale |
|--------|-------------|-----------|
| `AUTO-WDOG` | Priority/Critical+ | CI pipeline failures |
| `AUTO-IMP-SUP` | Priority/High+ | CI changes, test additions requiring infra update |
| `AUTO-BUG-SUP` | Priority/Medium+ | Test reliability issues affecting infrastructure |
| `AUTO-UAT-SUP` | Priority/Medium+ | Test infrastructure problems discovered during UAT |
| All others | Priority/Critical+ | Universal baseline |
### `AUTO-ARCH` — architecture
| Source | Min Priority | Rationale |
|--------|-------------|-----------|
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
| `AUTO-IMP-SUP` | Priority/High+ | Implementation discoveries affecting spec |
| `AUTO-SPEC` | Priority/High+ | Spec evolution feedback requiring arch input |
| `AUTO-GUARD` | Priority/High+ | Pattern drift requiring architectural response |
| `AUTO-HUMAN` | Priority/High+ | Human architectural feedback |
| `AUTO-EPIC` | Priority/Medium+ | Planning gaps needing spec coverage |
| All others | Priority/Critical+ | Universal baseline |
### `AUTO-EPIC` — epic planning
| Source | Min Priority | Rationale |
|--------|-------------|-----------|
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
| `AUTO-ARCH` | Priority/High+ | Architecture to decompose into epics/issues |
| `AUTO-OWNR` | Priority/High+ | Priority and scope decisions affecting planning |
| `AUTO-HUMAN` | Priority/High+ | Human requests for work breakdown |
| `AUTO-SPEC` | Priority/Medium+ | Spec changes affecting issue planning |
| `AUTO-IMP-SUP` | Priority/Medium+ | Implementation progress affecting future plans |
| All others | Priority/Critical+ | Universal baseline |
### `AUTO-GUARD` — architecture guard
| Source | Min Priority | Rationale |
|--------|-------------|-----------|
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
| `AUTO-ARCH` | Priority/High+ | Architecture pattern standards to enforce |
| `AUTO-IMP-SUP` | Priority/High+ | New code merges that may introduce pattern drift |
| `AUTO-SPEC` | Priority/Medium+ | Spec changes affecting acceptable patterns |
| All others | Priority/Critical+ | Universal baseline |
### `AUTO-SPEC` — spec update
| Source | Min Priority | Rationale |
|--------|-------------|-----------|
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
| `AUTO-ARCH` | Priority/High+ | Architecture changes to reflect in spec |
| `AUTO-IMP-SUP` | Priority/High+ | Implementation divergences from spec |
| `AUTO-HUMAN` | Priority/High+ | Human feedback on spec content |
| `AUTO-PRMRG-SUP` | Priority/Medium+ | Merges triggering spec-vs-implementation comparison |
| All others | Priority/Critical+ | Universal baseline |
### `AUTO-GROOM` — backlog grooming
| Source | Min Priority | Rationale |
|--------|-------------|-----------|
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
| `AUTO-OWNR` | Priority/High+ | Priority corrections from project owner |
| `AUTO-IMP-SUP` | Priority/High+ | PR quality issues surfaced during implementation |
| `AUTO-HUMAN` | Priority/High+ | Human requests about specific issues |
| `AUTO-EPIC` | Priority/Medium+ | New epics with children needing grooming |
| All others | Priority/Critical+ | Universal baseline |
### `AUTO-DOCS` — documentation
| Source | Min Priority | Rationale |
|--------|-------------|-----------|
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
| `AUTO-ARCH` | Priority/High+ | Architecture changes to document |
| `AUTO-SPEC` | Priority/High+ | Spec changes requiring documentation updates |
| `AUTO-IMP-SUP` | Priority/Medium+ | New features completed and ready to document |
| `AUTO-UAT-SUP` | Priority/Medium+ | Test examples suitable for documentation |
| `AUTO-PRMRG-SUP` | Priority/Medium+ | Milestone completions triggering doc cycle |
| All others | Priority/Critical+ | Universal baseline |
### `AUTO-TIME` — timeline update
| Source | Min Priority | Rationale |
|--------|-------------|-----------|
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
| `AUTO-IMP-SUP` | Priority/Medium+ | Progress data for timeline entries |
| `AUTO-PRMRG-SUP` | Priority/Medium+ | Merged PRs to record in timeline |
| `AUTO-PROD-BLDR` | Priority/Medium+ | Milestone status updates |
| All others | Priority/Critical+ | Universal baseline |
### `AUTO-OWNR` — project owner
| Source | Min Priority | Rationale |
|--------|-------------|-----------|
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
| `AUTO-HUMAN` | Priority/High+ | Human requests and feedback |
| `AUTO-EPIC` | Priority/High+ | New epics and scope changes |
| `AUTO-IMP-SUP` | Priority/High+ | Implementation progress affecting priority decisions |
| `AUTO-GROOM` | Priority/Medium+ | Issue quality reports requiring owner action |
| `AUTO-UAT-SUP` | Priority/Medium+ | Test results affecting priority decisions |
| All others | Priority/Critical+ | Universal baseline |
## Rule of Thumb
When in doubt, **lower the threshold** (consume more). Missing an important
announcement is always worse than reading a slightly irrelevant one.
@@ -3,7 +3,6 @@
These rules apply to **every** agent in the CleverAgents system without exception.
No agent, at any tier or role, is exempt from any of these rules.
---
## Rule 1 — Exhaustive Pagination
@@ -51,7 +50,6 @@ causing incorrect escalation decisions, duplicate filings, or incomplete
audits. The cost of an extra API call is always less than the cost of
a missed item.
---
## Rule 2 — Label Management via `forgejo-label-manager`
@@ -90,7 +88,6 @@ All labels applied by agents must exist at the **organization level**. Labels
are defined once at the org level and inherited by all repos. Repo-level labels
are not used by the autonomous agent system.
---
## Rule 3 — Bot Signature on All Forgejo Content
@@ -119,7 +116,6 @@ after code blocks, after any closing notes. Never buried in the middle.
**Values:** Use the values given in your system prompt. Do not invent or guess
the pool name or agent name — they are always provided in context.
---
## Rule 4 — Credential Flow: Workers Never Read Environment Variables
@@ -160,7 +156,6 @@ workers use credentials
**If a supervisor omits any of these, the worker cannot proceed.** Supervisors
bear full responsibility for including complete credentials in every worker prompt.
---
## Rule 5 — localhost:4096 Restriction
@@ -19,6 +19,10 @@
// USAGE (as CLI):
// list_prs.ts --url URL --pat TOKEN --owner OWNER --repo REPO [OPTIONS]
//
// Notable filter options:
// --stale not_stale|stale_no_conflicts|stale_with_conflicts|stale_unknown
// --ci-status passing|failing|pending|unknown (comma-separated, any combination)
//
// USAGE (as module, imported by the four wrapper scripts):
// import { listPRs, parseConnectionArgs } from './list_prs.ts';
// =============================================================================
@@ -35,6 +39,13 @@ export type StaleState =
| 'stale_unknown' // base advanced; mergeable=null (Forgejo pending)
| 'compute_error'; // missing data or branch API failure
// CIStatus — combined commit-status result for the PR head SHA
// 'passing' — all checks reported success (Forgejo combined state == 'success')
// 'failing' — at least one check failed/errored (state == 'failure'|'error'|'warning')
// 'pending' — checks are queued or still running (state == 'pending')
// 'unknown' — no checks have been reported yet (state == ''|'unknown')
export type CIStatus = 'passing' | 'failing' | 'pending' | 'unknown';
export interface Config {
url: string; // Forgejo base URL, no trailing slash
pat: string; // Personal Access Token
@@ -48,6 +59,7 @@ export interface Filters {
maxApprovals?: number; // approvals_count <= N
mergeable?: boolean; // filter on PR.mergeable directly
stale?: StaleState; // filter on computed stale_state
ciStatus?: CIStatus[]; // whitelist: PR's ci_status must be one of these values
}
// Raw shape of a Forgejo pull request object (only the fields we use).
@@ -55,6 +67,7 @@ export interface Filters {
interface RawPR {
number: number;
title: string;
head: { sha: string };
base: { ref: string };
merge_base?: string | null;
mergeable: boolean | null;
@@ -65,6 +78,7 @@ interface RawPR {
export interface AugmentedPR extends RawPR {
approvals_count: number;
stale_state: StaleState;
ci_status: CIStatus;
priority_rank: number; // 0 = CI Blocker (highest), higher = lower; PRIORITY_NONE if unlabelled
priority_label: string | null; // matched Priority/* label name, or null if none
}
@@ -80,6 +94,10 @@ interface BranchInfo {
commit: { id: string };
}
interface CombinedStatus {
state: string; // 'success' | 'pending' | 'failure' | 'error' | 'warning' | '' | 'unknown'
}
// ─────────────────────────────────────────────────────────────────────────────
// CONSTANTS
// ─────────────────────────────────────────────────────────────────────────────
@@ -271,6 +289,17 @@ function computeStaleState(
return 'stale_unknown';
}
// ─────────────────────────────────────────────────────────────────────────────
// mapCIState — translate Forgejo's combined commit-status state string into
// our canonical CIStatus enum value
// ─────────────────────────────────────────────────────────────────────────────
function mapCIState(state: string): CIStatus {
if (state === 'success') return 'passing';
if (state === 'pending') return 'pending';
if (state === 'failure' || state === 'error' || state === 'warning') return 'failing';
return 'unknown'; // '' | 'unknown' | anything else → no checks reported
}
// ─────────────────────────────────────────────────────────────────────────────
// listPRs — fetch, enrich, filter, and return matching PRs
//
@@ -347,12 +376,34 @@ export async function listPRs(
REVIEW_CONCURRENCY,
);
// ── Step 4: Compute fields, apply filters, collect results ────────────────
// ── Step 4: Fetch CI (combined commit-status) for every PR concurrently ───
// Uses GET /api/v1/repos/{owner}/{repo}/commits/{sha}/status which returns
// the aggregated combined state for all status checks on the head commit.
log(`Fetching CI status for ${rawPRs.length} PR(s) concurrently (limit=${REVIEW_CONCURRENCY})...`);
const allCIStatuses = await pLimit<CIStatus>(
rawPRs.map(pr => async () => {
try {
const combined = await apiGet<CombinedStatus>(
`${repoBase}/commits/${encodeURIComponent(pr.head.sha)}/status`,
config.pat,
);
return mapCIState(combined.state ?? '');
} catch {
log(`WARNING: Could not fetch CI status for PR #${pr.number}; treating as 'unknown'`);
return 'unknown' as CIStatus;
}
}),
REVIEW_CONCURRENCY,
);
// ── Step 5: Compute fields, apply filters, collect results ────────────────
const results: AugmentedPR[] = [];
for (let i = 0; i < rawPRs.length; i++) {
const pr = rawPRs[i];
const approvalsCount = countApprovals(allReviews[i]);
const ciStatus = allCIStatuses[i];
const baseHead = branchCache.get(pr.base?.ref ?? '') ?? null;
const staleState = computeStaleState(
pr.merge_base ?? null,
@@ -365,12 +416,14 @@ export async function listPRs(
if (filters.maxApprovals !== undefined && approvalsCount > filters.maxApprovals) continue;
if (filters.mergeable !== undefined && pr.mergeable !== filters.mergeable) continue;
if (filters.stale !== undefined && staleState !== filters.stale) continue;
if (filters.ciStatus !== undefined && !filters.ciStatus.includes(ciStatus)) continue;
const { rank: priorityRank, label: priorityLabel } = prPriority(pr);
results.push({
...pr,
approvals_count: approvalsCount,
stale_state: staleState,
ci_status: ciStatus,
priority_rank: priorityRank,
priority_label: priorityLabel,
});
@@ -444,11 +497,12 @@ function parseFullArgs(argv: string[]): { config: Config; filters: Filters } {
case '--pat': config.pat = val; i++; break;
case '--owner': config.owner = val; i++; break;
case '--repo': config.repo = val; i++; break;
case '--state': filters.state = val as Filters['state']; i++; break;
case '--min-approvals': filters.minApprovals = Number(val); i++; break;
case '--max-approvals': filters.maxApprovals = Number(val); i++; break;
case '--mergeable': filters.mergeable = val === 'true'; i++; break;
case '--stale': filters.stale = val as StaleState; i++; break;
case '--state': filters.state = val as Filters['state']; i++; break;
case '--min-approvals': filters.minApprovals = Number(val); i++; break;
case '--max-approvals': filters.maxApprovals = Number(val); i++; break;
case '--mergeable': filters.mergeable = val === 'true'; i++; break;
case '--stale': filters.stale = val as StaleState; i++; break;
case '--ci-status': filters.ciStatus = val.split(',').map(s => s.trim()) as CIStatus[]; i++; break;
case '-h':
case '--help':
printUsage();
@@ -473,6 +527,7 @@ function printUsage(): void {
process.stderr.write(`\
Usage:
list_prs.ts --url URL --pat TOKEN --owner OWNER --repo REPO [OPTIONS]
[--ci-status passing|failing|pending|unknown[,...]]
REQUIRED:
--url URL Forgejo base URL, no trailing slash (e.g. https://git.example.com)
@@ -487,11 +542,20 @@ OPTIONAL FILTERS (all default to no filter):
--mergeable true|false Filter on PR.mergeable field
--stale not_stale|stale_no_conflicts|stale_with_conflicts|stale_unknown
Filter on computed staleness state
--ci-status passing|failing|pending|unknown[,...]
Comma-separated whitelist of CI statuses to include.
passing = all checks succeeded (Forgejo state: success)
failing = at least one check failed/errored (failure|error|warning)
pending = checks are queued or running (state: pending)
unknown = no checks reported yet (state: ''|unknown)
Multiple values: --ci-status passing,pending
Omit flag entirely to include all CI statuses.
OUTPUT (stdout): JSON array sorted by priority (highest first); each object is
the full Forgejo PR plus:
.approvals_count integer distinct non-dismissed APPROVED review count
.stale_state string one of the stale states listed above
.ci_status string passing|failing|pending|unknown (see --ci-status above)
.priority_rank integer 0=CI Blocker, 1=Critical, 2=High, 3=Medium,
4=Low, 5=Backlog, 6=none (unlabelled)
.priority_label string|null matched Priority/* label name, or null
@@ -1,54 +0,0 @@
#!/usr/bin/env -S npx --yes tsx
// =============================================================================
// list_prs_needs_review.ts — Open PRs with no approvals yet ("everything else")
//
// Part of: .opencode/skills/auto-agents-system/scripts/
//
// Delegates to list_prs.ts with hard-coded filters.
//
// Returns all OPEN pull requests that:
// • have zero review approvals (approvals_count == 0)
//
// These are the "everything else" bucket — PRs that have not received any
// approvals from any reviewer yet, regardless of their staleness state.
// They need a first review before any merge decision can be made.
//
// Why this is "everything else":
// The three complementary scripts together cover every open PR that has at
// least one approval, split by staleness state:
// list_prs_ready_to_merge → approved + not stale
// list_prs_stale_clean → approved + stale (no conflicts)
// list_prs_stale_conflicts → approved + stale (with conflicts)
// This script covers the remaining bucket: PRs awaiting a first review.
//
// Note: PRs with approvals but stale_state == stale_unknown (Forgejo has not
// yet finished computing the conflict status) are a brief transient state that
// will resolve shortly. They are intentionally absent from all four scripts
// during that window and will appear in one of the approved scripts once
// Forgejo finishes.
//
// Hard-coded filters (not configurable):
// state: 'open' only open PRs are considered
// maxApprovals: 0 PRs with no approvals whatsoever
//
// USAGE:
// list_prs_needs_review.ts --url URL --pat TOKEN --owner OWNER --repo REPO
//
// OUTPUT (stdout): JSON array — same schema as list_prs.ts
// DEPENDENCIES: Node.js >= 18 (native fetch), npx tsx (for TypeScript execution)
// =============================================================================
import { listPRs, parseConnectionArgs } from './list_prs.ts';
async function main(): Promise<void> {
const config = parseConnectionArgs(process.argv);
const prs = await listPRs(config, {
state: 'open',
maxApprovals: 0,
});
process.stdout.write(JSON.stringify(prs, null, 2) + '\n');
}
main().catch((err: unknown) => {
process.stderr.write(`ERROR: ${err instanceof Error ? err.message : String(err)}\n`);
process.exit(1);
});
@@ -0,0 +1,57 @@
#!/usr/bin/env -S npx --yes tsx
// =============================================================================
// list_prs_needs_review_not_stale.ts — Open PRs with no approvals, up-to-date
//
// Part of: .opencode/skills/auto-agents-system/scripts/
//
// Delegates to list_prs.ts with hard-coded filters.
//
// Returns all OPEN pull requests that:
// • have zero review approvals (approvals_count == 0)
// • are NOT stale (stale_state == not_stale)
// i.e. the PR's merge_base matches the current HEAD of its base branch —
// the PR is fully up-to-date and requires no rebase before merging.
//
// These are PRs that need only a first review — no rebase or conflict
// resolution will be required when they are eventually approved.
//
// Why this bucket exists:
// Together with list_prs_needs_review_stale_clean and
// list_prs_needs_review_stale_conflicts, these three scripts partition every
// open PR with zero approvals into three actionable sub-buckets based on
// what additional work will be required after a reviewer approves:
// list_prs_needs_review_not_stale → review only; merge immediately on approval
// list_prs_needs_review_stale_clean → review + server-side rebase; no conflicts
// list_prs_needs_review_stale_conflicts → review + local rebase; conflicts present
//
// Note: PRs with zero approvals and stale_state == stale_unknown are
// transiently absent while Forgejo computes conflict status; they will appear
// in stale_clean or stale_conflicts once Forgejo finishes.
//
// Hard-coded filters (not configurable):
// state: 'open' only open PRs are considered
// maxApprovals: 0 PRs with no approvals whatsoever
// stale: 'not_stale' PR is current with its base branch
//
// USAGE:
// list_prs_needs_review_not_stale.ts --url URL --pat TOKEN --owner OWNER --repo REPO
//
// OUTPUT (stdout): JSON array — same schema as list_prs.ts
// DEPENDENCIES: Node.js >= 18 (native fetch), npx tsx (for TypeScript execution)
// =============================================================================
import { listPRs, parseConnectionArgs } from './list_prs.ts';
async function main(): Promise<void> {
const config = parseConnectionArgs(process.argv);
const prs = await listPRs(config, {
state: 'open',
maxApprovals: 0,
stale: 'not_stale',
});
process.stdout.write(JSON.stringify(prs, null, 2) + '\n');
}
main().catch((err: unknown) => {
process.stderr.write(`ERROR: ${err instanceof Error ? err.message : String(err)}\n`);
process.exit(1);
});
@@ -0,0 +1,60 @@
#!/usr/bin/env -S npx --yes tsx
// =============================================================================
// list_prs_needs_review_stale_clean.ts — Open PRs with no approvals, stale, no conflicts
//
// Part of: .opencode/skills/auto-agents-system/scripts/
//
// Delegates to list_prs.ts with hard-coded filters.
//
// Returns all OPEN pull requests that:
// • have zero review approvals (approvals_count == 0)
// • are stale but have NO merge conflicts (stale_state == stale_no_conflicts)
// i.e. the base branch has advanced since the PR was last synced,
// but rebasing/merging would succeed without any conflict resolution.
//
// These are PRs that need a first review AND will also need a server-side
// rebase before they can be merged — but no conflict resolution will be
// required. Once approved, the workflow is:
//
// rebase_pr → (wait for approval if not yet given) → merge_pr
//
// Why this bucket exists:
// Together with list_prs_needs_review_not_stale and
// list_prs_needs_review_stale_conflicts, these three scripts partition every
// open PR with zero approvals into three actionable sub-buckets based on
// what additional work will be required after a reviewer approves:
// list_prs_needs_review_not_stale → review only; merge immediately on approval
// list_prs_needs_review_stale_clean → review + server-side rebase; no conflicts
// list_prs_needs_review_stale_conflicts → review + local rebase; conflicts present
//
// Note: PRs with zero approvals and stale_state == stale_unknown are
// transiently absent while Forgejo computes conflict status; they will appear
// here or in stale_conflicts once Forgejo finishes.
//
// Hard-coded filters (not configurable):
// state: 'open' only open PRs are considered
// maxApprovals: 0 PRs with no approvals whatsoever
// stale: 'stale_no_conflicts' PR is behind base but conflict-free
//
// USAGE:
// list_prs_needs_review_stale_clean.ts --url URL --pat TOKEN --owner OWNER --repo REPO
//
// OUTPUT (stdout): JSON array — same schema as list_prs.ts
// DEPENDENCIES: Node.js >= 18 (native fetch), npx tsx (for TypeScript execution)
// =============================================================================
import { listPRs, parseConnectionArgs } from './list_prs.ts';
async function main(): Promise<void> {
const config = parseConnectionArgs(process.argv);
const prs = await listPRs(config, {
state: 'open',
maxApprovals: 0,
stale: 'stale_no_conflicts',
});
process.stdout.write(JSON.stringify(prs, null, 2) + '\n');
}
main().catch((err: unknown) => {
process.stderr.write(`ERROR: ${err instanceof Error ? err.message : String(err)}\n`);
process.exit(1);
});
@@ -0,0 +1,60 @@
#!/usr/bin/env -S npx --yes tsx
// =============================================================================
// list_prs_needs_review_stale_conflicts.ts — Open PRs with no approvals, stale, with conflicts
//
// Part of: .opencode/skills/auto-agents-system/scripts/
//
// Delegates to list_prs.ts with hard-coded filters.
//
// Returns all OPEN pull requests that:
// • have zero review approvals (approvals_count == 0)
// • are stale AND have merge conflicts (stale_state == stale_with_conflicts)
// i.e. the base branch has advanced since the PR was last synced,
// and rebasing/merging would produce conflicts that cannot be resolved
// automatically (PR.mergeable == false).
//
// These are PRs that need BOTH a first review AND manual conflict resolution
// before they can be merged. The conflict resolution path requires a local
// clone or repo-isolator since the Forgejo server-side rebase endpoint
// (POST .../update?style=rebase) cannot handle conflicted PRs.
//
// Why this bucket exists:
// Together with list_prs_needs_review_not_stale and
// list_prs_needs_review_stale_clean, these three scripts partition every
// open PR with zero approvals into three actionable sub-buckets based on
// what additional work will be required after a reviewer approves:
// list_prs_needs_review_not_stale → review only; merge immediately on approval
// list_prs_needs_review_stale_clean → review + server-side rebase; no conflicts
// list_prs_needs_review_stale_conflicts → review + local rebase; conflicts present
//
// Note: PRs with zero approvals and stale_state == stale_unknown are
// transiently absent while Forgejo computes conflict status; they will appear
// in stale_clean or here once Forgejo finishes.
//
// Hard-coded filters (not configurable):
// state: 'open' only open PRs are considered
// maxApprovals: 0 PRs with no approvals whatsoever
// stale: 'stale_with_conflicts' PR is behind base AND has conflicts
//
// USAGE:
// list_prs_needs_review_stale_conflicts.ts --url URL --pat TOKEN --owner OWNER --repo REPO
//
// OUTPUT (stdout): JSON array — same schema as list_prs.ts
// DEPENDENCIES: Node.js >= 18 (native fetch), npx tsx (for TypeScript execution)
// =============================================================================
import { listPRs, parseConnectionArgs } from './list_prs.ts';
async function main(): Promise<void> {
const config = parseConnectionArgs(process.argv);
const prs = await listPRs(config, {
state: 'open',
maxApprovals: 0,
stale: 'stale_with_conflicts',
});
process.stdout.write(JSON.stringify(prs, null, 2) + '\n');
}
main().catch((err: unknown) => {
process.stderr.write(`ERROR: ${err instanceof Error ? err.message : String(err)}\n`);
process.exit(1);
});
@@ -1,6 +1,6 @@
#!/usr/bin/env -S npx --yes tsx
// =============================================================================
// list_prs_ready_to_merge.ts — Open PRs approved and up-to-date with base
// list_prs_ready_to_merge.ts — Open PRs approved, up-to-date, and CI passing
//
// Part of: .opencode/skills/auto-agents-system/scripts/
//
@@ -9,15 +9,22 @@
// Returns all OPEN pull requests that:
// • have at least 1 review approval (approvals_count >= 1)
// • are NOT stale (stale_state == not_stale)
// • have passing CI (ci_status == 'passing')
//
// These PRs are ready to be merged immediately — they are approved and their
// branch is already up-to-date with the base branch, so no rebase or conflict
// resolution is required before merging.
// These PRs are ready to be merged immediately — they are approved, their
// branch is already up-to-date with the base branch, and all CI checks have
// passed. No rebase, conflict resolution, or CI wait is required.
//
// CI filter rationale: merging a PR with failing or pending CI would push
// broken code to the base branch. Only 'passing' is accepted here. PRs
// with 'pending' or 'failing' CI appear in none of the approved buckets
// until their CI resolves, preventing premature merges.
//
// Hard-coded filters (not configurable):
// state: 'open' only open PRs are considered
// minApprovals: 1 at least one non-dismissed approval required
// stale: 'not_stale' PR head must be current with its base branch
// state: 'open' only open PRs are considered
// minApprovals: 1 at least one non-dismissed approval required
// stale: 'not_stale' PR head must be current with its base branch
// ciStatus: ['passing'] all CI checks must have succeeded
//
// USAGE:
// list_prs_ready_to_merge.ts --url URL --pat TOKEN --owner OWNER --repo REPO
@@ -33,6 +40,7 @@ async function main(): Promise<void> {
state: 'open',
minApprovals: 1,
stale: 'not_stale',
ciStatus: ['passing'],
});
process.stdout.write(JSON.stringify(prs, null, 2) + '\n');
}
+62 -8
View File
@@ -7,6 +7,45 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
### Fixed
- **Actor v3 YAML Schema Validation in CLI** (#5869): The `agents actor add --config`
command now validates v3 YAML files using `ActorConfigSchema`, ensuring proper
schema compliance including cycle detection for GRAPH actors, required field
validation, and enum validation. v3 YAML is detected by the presence of ANY
`type` field (any value — invalid type values are then rejected by schema
validation) or a `version` field whose string value starts with `"3"` (e.g.
`"3"`, `"3.0"`, `"3.0.0"`). Configs with `type: null` are not treated as v3.
Invalid v3 actors are rejected with clear error messages before registration.
- **Alembic Files Missing from Wheel Distribution** (#4180): Alembic configuration
(`alembic.ini`) and migration files are now part of the Python package structure
at `src/cleveragents/infrastructure/database/migrations/`. Previously, when
`agents init` was run in Docker containers or any wheel-based installation,
`FileNotFoundError` was raised because alembic files were stored at the
repository root and excluded from the wheel distribution. Now alembic files
follow standard Python packaging conventions and are automatically included.
`MigrationRunner._find_alembic_ini()` has been updated to search the new package
location as the primary anchor point. This fix enables `agents init` to work
correctly in all deployment modes: Docker containers, local pip installs
(wheel or editable), and development environments.
- **TDD Non-AssertionError Guard Visibility** (#8294): `apply_tdd_inversion` in
`features/environment.py` now emits its non-assertion exception guard warning to
both the structured logger and `stderr` via a new `_warning_with_stderr` helper.
This makes the guard firing visible in standard Behave console output and CI log
snippets where the structured logging sink may not be displayed. BDD infrastructure
coverage added: a new scenario in `tdd_expected_fail_infrastructure.feature`
asserts that the warning is emitted to stderr when a non-AssertionError exception
is encountered in an `@tdd_expected_fail` scenario, and a second scenario asserts
the warning is NOT emitted when the exception is an `AssertionError`. The
`CONTRIBUTING.md` now documents that `@tdd_expected_fail` step definitions must
signal expected failures via `AssertionError`.
- **Parallel Behave Runner Log Noise Reduction** (#8351): The parallel behave
runner now suppresses captured stdout/stderr for passing worker chunks and
only replays diagnostics for failed, errored, or crashed chunks. This makes
failure output significantly easier to spot in CI and local runs. A worker
crash (unhandled exception) is detected via an all-zero summary and the
captured traceback is always surfaced.
- **Automation Profile Silent Fallback** (#8232): `_resolve_profile_for_plan` in
`PlanLifecycleService` now raises a clear `ValidationError` when a plan's
automation profile name is not a known built-in profile, instead of silently
@@ -15,6 +54,15 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
message listing available built-in profiles. The resolved profile name is also
logged at debug level for observability.
- **CheckpointManager rollback_to always returned False** (#7488): Fixed a data
integrity bug in `CheckpointManager.create_checkpoint()` where `sandbox_path`
was computed from `sandbox.context.sandbox_path` but never stored in the
checkpoint metadata. As a result, `rollback_to()` always found
`checkpoint.metadata.get("sandbox_path")` returning `None` and silently
skipped the rollback, returning `False`. The fix adds `sandbox_path` to the
metadata dict before constructing the `SandboxCheckpoint`, enabling
`rollback_to()` to correctly restore the sandbox filesystem state.
### Added
- **TDD Issue-Capture Test Activation** (#7025): Replaced 234 bare `@skip` tags
@@ -69,14 +117,6 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
Priority-based filtering (Critical/High/Medium/Low) reduces noise. Backlog-groomer
performs intelligent cleanup with age thresholds by priority.
- **OpenAI Quota Fallback to Anthropic Haiku** (#10042): Implemented graceful degradation
for E2E robot integration tests when OpenAI API hits quota limit errors (429, insufficient_quota,
rate_limit). The `StrategyActor` now detects quota-specific errors and automatically falls back
to Anthropic Haiku for strategy decisions, ensuring CI/CD pipelines complete E2E tests even
when the primary provider hits capacity limits. Improved pipeline reliability and reduced false
negatives caused by provider-specific quota issues. Added comprehensive logging for quota error
detection and provider fallback, plus E2E test scenarios for fallback verification.
- **PR Agent Reorganization**: All PR-related agents renamed and reorganized to follow
the `*-pool-supervisor` naming pattern. New agents added: `pr-editor` (safe PR editing
with description preservation), `pr-manager` (unified PR interface), and
@@ -201,6 +241,20 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
`pr-merge-pool-supervisor` to the product-builder's supervisor launch list (18 total
supervisors). Updated all numeric references, pre-flight checklists, and validation logic.
- `ActionRepository.update()` now uses explicit bulk `sa_delete()` + `session.flush()`
before re-inserting child rows for `action_arguments` and `action_invariants`, fixing
a `sqlite3.IntegrityError: UNIQUE constraint failed` crash when `agents plan use` was
called on an action that already had arguments registered via `action create`. (#4197)
- Fixed CheckpointManager not wired into PlanExecutor — checkpoints were
never created during plan execution because `_get_plan_executor()` in
the CLI constructed PlanExecutor without a CheckpointManager (defaulted
to None, silently skipping all checkpoint hooks). `_get_plan_executor()`
now resolves the container singleton so CLI `plan execute` and `plan
rollback` share the same registry, and `_try_create_checkpoint()` raises
`PlanError` if checkpoint metadata cannot be persisted. Writable sandboxable
resources and write-capable tools now default to `checkpointable=True`, and
new Behave scenarios cover DI wiring, rollback, and capability defaults. (#1253)
---
## [3.8.0] — 2026-04-05
+2
View File
@@ -19,5 +19,7 @@ Below are some of the specific details of various contributions.
* HAL 9000 has contributed concurrency safety improvements, including thread-safe context tier management (issue #7547) for parallel plan execution.
* HAL 9000 has contributed the plan concurrency race-condition fix (#7989): wired `LockService` into the plan lifecycle, guarding `execute_plan()` and `apply_plan()` with plan-level advisory locks and unique per-invocation owner identities to prevent silent concurrent state corruption.
* HAL 9000 has contributed the plugin entry point security hardening fix (#7476): enforced entry point allowlist validation before importing plugin modules to prevent malicious plugin loading.
* Rui Hu has contributed the v3 actor YAML schema validation fix (#5869): added `ActorConfigSchema` validation to the `agents actor add --config` CLI command, covering cycle detection, required field validation, and enum validation for v3 YAML actor definitions.
* HAL 9000 has contributed automated bug fixes, including fix #7488 (store sandbox_path in checkpoint metadata to enable rollback).
* This project was made possible thanks to considerable donation of time, money, and resources by CleverThis, Inc.
* HAL 9000 has contributed automated bug fixes, CLI output formatting improvements, and ongoing maintenance as part of the CleverAgents automation system.

Some files were not shown because too many files have changed in this diff Show More