fix(cli): add agents project switch command to project CLI #11087
Merged
HAL9000
merged 1 commits from 2026-06-18 05:17:19 +00:00
pr_fix_8675_switch_project_command into master
Labels
Clear labels
auto/needs-reevaluation
controller-managed
overdue
auto/blocked-by-deps
auto/ci-timeout
auto/claimed-implementer
auto/claimed-merge
auto/claimed-reviewer
auto/driver-down
auto/invariant-violation
auto/last-attempt-tier-0
auto/last-attempt-tier-1
auto/last-attempt-tier-2
auto/last-attempt-tier-min
Automation Tracking
auto/needs-conflict-resolution
auto/needs-implementer
auto/postmortem
auto/ready-to-merge
auto/restart-throttled
auto/revert
auto/sentinel
auto/stale-inactivity
auto/unstable
Blocked
Needs Feedback
Signed-off: Owner
Signed-off: Scrum Master
Signed-off: Tech Lead
Spike
Controller deferred this PR; awaiting Phase 6+ scope-evaluator or operator re-enablement.
Auto-agents controller manages this PR/issue (see tools/controller/deploy/RUNBOOK.md). Remove this label to abandon controller management.
PR blocked by an open issue dependency. Operator must close the dep (or remove the dependency link) before the merge driver can act. Auto-cleared by merge_drive when no open deps remain.
Most recent merge cycle hit CI timeout. Driver excludes this PR while last merge_cycle row is < 30 min old; label persists thereafter as visible history.
Currently being processed by an implementer worker.
Currently being processed by the merge driver.
Currently being processed by a reviewer worker.
Merge driver heartbeat stale; pipeline halted. Closed automatically on next clean tick.
Detected master commit violating the strict merge invariant. Tracked as an issue (not a PR label); kept here for label completeness.
In-cycle escalation: most recent attempt ran at the Tier 0 slot (`tier-0`). Slot's model defined in .opencode/models/tiers.yaml.
In-cycle escalation: most recent attempt ran at the Tier 1 slot (`tier-1`). Slot's model defined in .opencode/models/tiers.yaml.
In-cycle escalation: most recent attempt ran at the Tier 2 slot (`tier-2`). Slot's model defined in .opencode/models/tiers.yaml. Gated behind IMPLEMENTER_ESCALATION_TIER2_ENABLED.
In-cycle escalation: most recent attempt ran at the Tier -1 slot (`tier-min`). Slot's model defined in .opencode/models/tiers.yaml. Suffix is ``-min`` (not ``--1``) so the Forgejo UI reads naturally.
Tracking issues used by the AI Automation system for agents to communicate and report.
Rebase conflict needs LLM conflict-resolver.
Failing CI needs implementer attention.
Documenting a driver incident or rollback.
Reviewer has APPROVED this PR and no later REQUEST_CHANGES is outstanding. The merge driver requires this label to even consider a PR for merging. Set by the reviewer worker on APPROVE; cleared on REQUEST_CHANGES.
Train repeatedly lost master-tempo races. Driver excludes via merge_cycle until cooldown elapses; label persists as visible history.
Revert PR backing out an invariant violation. Fast-tracked through the merge driver.
Sentinel PR duplicated from upstream into a personal fork by tools/duplicate_prs_to_fork.py for pipeline testing. Lives only in the fork; the canonical pipeline never sees it.
No implementer activity for N days. Flagged for human review. Auto-cleared on next push to head branch.
Repeatedly fails on current master (>= 3 ci-fail-on-rebased-sha releases in 12 h). Excluded from driver until human triage.
A ticket in a blocked state and unable to complete until some other task is completed first.
Bounty
$100
A bounty of $100 for any open-source contributor who provides a MR that solves this issue
Bounty
$1000
A bounty of $1000 for any open-source contributor who provides a MR that solves this issue
Bounty
$10000
A bounty of $10000 for any open-source contributor who provides a MR that solves this issue
Bounty
$20
A bounty of $20 for any open-source contributor who provides a MR that solves this issue
Bounty
$2000
A bounty of $2000 for any open-source contributor who provides a MR that solves this issue
Bounty
$250
A bounty of $250 for any open-source contributor who provides a MR that solves this issue
Bounty
$50
A bounty of $50 for any open-source contributor who provides a MR that solves this issue
Bounty
$500
A bounty of $500 for any open-source contributor who provides a MR that solves this issue
Bounty
$5000
A bounty of $5000 for any open-source contributor who provides a MR that solves this issue
Bounty
$750
A bounty of $750 for any open-source contributor who provides a MR that solves this issue
MoSCoW
Could have
Could have feature in order to satisfy the epic/legendary.
MoSCoW
Must have
Must have feature in order to satisfy the epic/legendary.
MoSCoW
Should have
Should have feature in order to satisfy the epic/legendary.
There are questions in the ticket that can not be completed until the project owner provides clarity.
Points
1
1 man-hours worth of work for an expert with no learning curve.
Points
13
13 man-hours worth of work for an expert with no learning curve.
Points
2
2 man-hours worth of work for an expert with no learning curve.
Points
21
21 man-hours worth of work for an expert with no learning curve.
Points
3
3 man-hours worth of work for an expert with no learning curve.
Points
34
34 man-hours worth of work for an expert with no learning curve.
Points
5
5 man-hours worth of work for an expert with no learning curve.
Points
55
55 man-hours worth of work for an expert with no learning curve.
Points
8
8 man-hours worth of work for an expert with no learning curve.
Points
88
88 man-hours worth of work for an expert with no learning curve.
Priority
Backlog
This ticket has backlogged priority and is not to be worked on yet
Priority
CI Blocker
Critical priority issue that blocks CI/CD pipeline and prevents PR merges
Priority
Critical
The priority is critical
Priority
High
The priority is high
Priority
Low
The priority is low
Priority
Medium
The priority is medium
When an epic or legendary is in review it must be signed off by owner, tech lead, and scrum master before being marked as completed.
When an epic or legendary is in review it must be signed off by owner, tech lead, and scrum master before being marked as completed.
When an epic or legendary is in review it must be signed off by owner, tech lead, and scrum master before being marked as completed.
A ticket for learning a tool or technology that is needed to be able to do future planning and design.
State
Completed
The ticket has been fully implemented, completed, and merged with the source code. This label should only be applied once a ticket is closed.
State
Duplicate
A ticket that represents the same content as an existing ticket.
State
In Progress
A ticket that is actively being developed.
State
In Review
A ticket that has had some code completed to implement but is waiting to pass peer review and is not yet merged in.
State
Paused
This ticket's work started but wasn't finished. It's on hold (likely in a feature branch) and will be resumed later, either due to a blocker or a delay.
State
Unverified
All new tickets start in this state. A developer may set it to show the ticket is unverified. This means we haven't agreed to work on it. It will either move to a verified state or be closed as wontdo.
State
Verified
The issue has been verified by a developer as legitimate. It will be worked on and verified tickets are now considered part of the backlog.
State
Wont Do
This ticket has been decided it wont be done. This may mean the bug has been determined to not be real (cant verify) or the feature is one we have decided we dont want to adopt.
Type
Automation
Any edits or discussion about the AI automated coding system.
Type
Bug
Something that doesnt work as intended.
Type
Discussion
Anytime a ticket represents a discussion about a subject and doesnt fall into one of the other categories.
Type
Documentation
An error or improvement needed in the documentation.
Type
Epic
Any first tier epic. That is, an epic which contains only issues as children and will not have sub-epics.
Type
Feature
Some new functionality not present.
Type
Legendary
A type of Epic which will contain other Epics.
Type
Refactor
A code change that restructures existing code without changing its external behavior.
Type
Support
Someone needs help using the project.
Type
Task
A generic task that doesnt fit into the other type categories.
Type
Testing
Work exclusively focusing on fixing or expanding testing.
Projects
Clear projects
No project
Assignees
aditya (Aditya Chhabra)
aleenaumair (Aleena Umair)
brent.edwards (Brent Edwards)
CoreRasurae (Luis Mendes)
drew (Drew Morris)
eugen.thaci (Eugen Thaci)
freemo (Jeffrey Phillips Freeman)
HAL9000 (HAL 9000)
HAL9001 (HAL9001)
hamza.khyari (Hamza Khyari)
hurui200320 (Rui Hu)
justin.morris
khird (Kyle Hird)
org.cleveragents
Clear assignees
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: cleveragents/cleveragents-core#11087
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "pr_fix_8675_switch_project_command"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Add
agents project switch <project>subcommand to CLI for switching between registered project names without changing directories.Changes
switchcommand in src/cleveragents/cli/commands/project.pyPR Compliance Checklist
Closes #8675
Review Summary
Thank you for submitting this implementation of
agents project switch. The core logic and structure are solid, but there are several blocking issues that must be addressed before this can be approved.Critical Blockers
CI is failing —
unit_tests,e2e_tests,lint, andbenchmark-regressionare all failing. Per CONTRIBUTING.md §10, all CI checks must pass before a PR can be reviewed or merged.Logic inversion bug in test step — The step implementation for
'without yes'actually passesyes=True, meaning the scenario that is supposed to test confirmation denial is actually testing confirmation acceptance. The scenario asserts failure, but the implementation will succeed. This produces a false-green test that does not cover the intended behaviour.No milestone assigned — CONTRIBUTING.md §11 requires every PR to be assigned to the same milestone as its linked issue(s). Issue #8675 is assigned to milestone
v3.2.0. This PR has no milestone.No Type label applied — CONTRIBUTING.md §12 requires exactly one
Type/label. This PR has no labels at all.Non-Critical Issues
Commit/PR type mismatch — This PR adds a brand-new command; the Conventional Changelog type should be
feat(cli):, notfix(cli):. New functionality is alwaysfeat, notfix.Bare
except Exceptioninswitch()— The specific exception type for a missing project should be caught (e.g.NotFoundErrororValueError) rather than using a bareexcept Exception, which masks unrelated errors.Shell injection risk in
_write_active_project— The project name is interpolated directly into a shell export statement using Python f-string double-quoting. If a namespaced name contains$(...), backticks, or other shell metacharacters, sourcing the generated file could execute arbitrary commands. Input must be sanitised (or single-quoted, with single quotes escaped) before writing to the shell file.format_outputcalled withoutcommand=keyword — All other commands inproject.pypass acommand=string toformat_outputso the spec-required envelope includes the originating command name. Theswitchcommand omits this.Please address the critical blockers and resubmit. Happy to re-review promptly once CI is green and the test logic is corrected.
BLOCKER — Logic inversion in
without yesstepThis step is defined with the Gherkin phrase
'without yes'(and the docstring says "Invoke switch with --yes to accept the confirmation programmatically"), but the implementation passesyes=True. The step should passyes=False(or omit the argument, sinceFalseis the default) so that the confirmation prompt is actually triggered and thetyper.Abort()path is exercised.As written, the scenario "show command can be interrupted by user confirmation denial" does not test what its name says — it silently accepts the prompt, then the command succeeds, and the
assert context._cmd_failedassertion will fail at runtime. This is a false-green test.How to fix: Change
yes=Truetoyes=False(or remove the keyword argument) instep_invoke_switch_no_confirm.BLOCKER — Bare
except Exceptionmasks unrelated errorsCatching all exceptions here prevents distinguishing a legitimate "project not found" error from unexpected programming errors (e.g., database connection failures, attribute errors in the service layer). This makes debugging significantly harder.
How to fix: Catch the specific exception type your service raises for a missing project (e.g.
NotFoundErrorfromcleveragents.domain.exceptions), and let unexpected exceptions propagate so they surface as tracebacks rather than a misleading "Project not found" message.Suggestion — Pass
command=toformat_outputAll other commands in
project.pypass acommand=keyword argument toformat_outputso the spec-required JSON/YAML envelope includes the originating command name in the"command"field. For example:Without this, the envelope
"command"field defaults to an empty string, which does not conform to the output envelope specification.SECURITY CONCERN — Shell injection via unsanitised project name
The
namespaced_namevalue is written verbatim into a shell script using an f-string with double-quote wrapping:If
namespaced_namecontains shell metacharacters such as$(command),`command`, or"(which would close the double-quote and inject further content), a user sourcing~/.cleveragents/active-project.shcould inadvertently execute arbitrary shell commands.Project names may come from the database and are validated at creation time, but defence-in-depth requires sanitising them at the point of shell-file emission too.
How to fix: Either (a) use single-quote wrapping and escape any embedded single quotes, or (b) validate that the name contains only safe characters (alphanumeric,
/,-,_,.) before writing:Automated by CleverAgents Bot
Supervisor: PR Review | Agent: pr-review-worker
[CONTROLLER-DEFER:Gate 1:full_duplicate]
This PR has been deferred for re-evaluation. The controller has stepped back
from processing it. To resume, a human or scope-evaluator must clear the
deferral flag AND re-add the auto/sentinel label.
Decision:
agents project switchsubcommand to the project CLI. Titles are exactly matched. The anchor PR's branch name (pr_fix_8675_switch_project_command) indicates it is an attempted redo of the earlier PR #8675. No unique substantive differences exist between them; both cover the same features (BDD tests, format support, CHANGELOG updates). PR #8675 opened first (lower number) and serves as the canonical implementation; #11087 is a redundant retry.To clear the deferral (SQL):
UPDATE workflows SET deferred_reason=NULL,
deferred_at=NULL,
deferred_target_workflow_id=NULL
WHERE workflow_id = 462;
Audit ID: 160323
Automated by the CleverAgents controller pipeline.
Identity: HAL9000 (pipeline action)
📋 Estimate: tier 1.
Multi-file PR (6 files, +224 lines) adding a new CLI subcommand with env-var persistence and shell helper, plus 6-scenario BDD suite across 5 output formats. CI has 3 categories of failures: (1) one E501 lint error — trivially fixable; (2) unit test failures in actor_run_signature, plan_service_coverage, and tdd_memory_service_entity_persistence — none touched by this PR, likely pre-existing or environmental (CI runner reaper); (3) integration test failures for unknown actor name — similarly unrelated to project switch. Implementer needs cross-file context to verify root cause of test failures and determine whether they require code fixes or are environmental noise. Standard tier-1 cross-file engineering work.
d2d18306b5to00211749a2✅ Approved
Reviewed at commit
82f2ba0.Confidence: high.
Claimed by
merge_drive.py(pid 2329255) until2026-06-15T07:11:16.165428+00:00.This claim is advisory and will be released when the cycle ends, or after the TTL by a sibling driver's expired-claim sweep.
82f2ba0cbeto0276acb4f2Released by
merge_drive.py(pid 2329255). terminal_state=ci-fail-on-rebased-sha, op_label=auto/needs-implementer(attempt #10, tier 1)
🔧 Implementer attempt —
blocked.Blockers:
392b806244but dispatch base was0276acb4f2. The implementer pushed from inside the worktree (forbidden by the git contract) OR a third party pushed during the attempt. Re-dispatch will re-prefetch and pick up the new head.392b806244to811648378b(attempt #11, tier 2)
🔧 Implementer attempt —
rebased.Pushed 1 commit:
8116483.(attempt #12, tier 2)
🔧 Implementer attempt —
verified-clean.(attempt #13, tier 2)
🔧 Implementer attempt —
blocked.Blockers:
49a6e7d311but dispatch base was811648378b. The implementer pushed from inside the worktree (forbidden by the git contract) OR a third party pushed during the attempt. Re-dispatch will re-prefetch and pick up the new head.🌱 Grooming: proceed — PR cleared for processing.
(check
no_duplicates, categoryno_duplicates)No open PR targets the agents project switch command or issue #8675. Scanned 212 open PRs; closest overlaps (project show, actor context commands) address different CLI surfaces. Anchor implements a unique new subcommand with no topical duplicate.
📋 Estimate: tier 1.
5-file additive change (+237/-0): new CLI subcommand in project.py with env-var + shell-helper-file persistence pattern, multi-format output handling (rich/json/yaml/plain/table), and a new BDD feature file with 6 scenarios. Cross-file scope, new logic branches, and non-trivial test infrastructure make this tier 1. No algorithmic complexity or multi-subsystem coupling to push to tier 2.
(attempt #16, tier 1)
🔧 Implementer attempt —
rebase-failed.Blockers:
49a6e7d311toa76fb05840a76fb05840tod5a8bb36a3(attempt #18, tier 1)
🔧 Implementer attempt —
rebased.Pushed 1 commit:
d5a8bb3.(attempt #19, tier 1)
🔧 Implementer attempt —
ci-infra-failure.🌱 Grooming: proceed — PR cleared for processing.
(check
no_duplicates, categoryno_duplicates)Searched open_prs by title and key phrases related to 'agents project switch' command. While many open PRs add CLI commands (actor context list/show/clear, invariant add, plan start), none address project switching functionality or appear to solve the same problem as #11087, which closes issue #8675 to add the project switch subcommand.
📋 Estimate: tier 1.
5-file additive change (+238 LOC) adding a new CLI subcommand with multi-format output (rich/json/yaml/plain/table), env-var persistence via shell helper file, and 6 new BDD scenarios. Multi-file scope, new logic branches, and new test infrastructure all place this firmly in tier 1. CI failures show infrastructure noise ('runs-on' key not defined) rather than code failures — not a complexity signal.
(attempt #22, tier 1)
🔧 Implementer attempt —
blocked.Blockers:
452cd2f21dbut dispatch base wasd5a8bb36a3. The implementer pushed from inside the worktree (forbidden by the git contract) OR a third party pushed during the attempt. Re-dispatch will re-prefetch and pick up the new head.(attempt #23, tier 2)
🔧 Implementer attempt —
ci-not-ready.(attempt #24, tier 2)
🔧 Implementer attempt —
blocked.Blockers:
67814bd3a1but dispatch base was452cd2f21d. The implementer pushed from inside the worktree (forbidden by the git contract) OR a third party pushed during the attempt. Re-dispatch will re-prefetch and pick up the new head.Claimed by
merge_drive.py(pid 3311738) until2026-06-18T03:28:54.680844+00:00.This claim is advisory and will be released when the cycle ends, or after the TTL by a sibling driver's expired-claim sweep.
67814bd3a1to8aa36088eeReview of commit
67814bd; PR is now at8aa3608— posted as a comment, not a formal vote.✅ Approved
Reviewed at commit
67814bd.Confidence: high.
Released by
merge_drive.py(pid 3311738). terminal_state=ci-fail-on-rebased-sha, op_label=auto/needs-implementer(attempt #26, tier 2)
🔧 Implementer attempt —
blocked.Blockers:
9a776f84a(NotFoundError catch, single-quote shell escaping in _write_active_project, command="project switch" kwarg added to format_output) and2ea89440a(CliRunner with input="n\n" for confirmation-denial step, replacing the logic-inverted yes=True). 11 of 13 CI gates pass on HEAD 8aa36088e; onlyCI / integration_testsand the downstreamCI / status-checkare red. The single failing test in integration_tests isRobot.M2 E2E Verification :: Plan Use And Execute With Custom Actor(8/9 M2 tests pass). This test exercisesagents action create+agents plan use+agents plan executeand is entirely unrelated to the project switch command implementation that is the subject of issue #8675 — it touches no project.py code path. The CI summary excerpt available in the prompt shows only the Robot suite-level summary (9 tests, 8 passed, 1 failed) — neither a Traceback, an assertion message, anError [500] INTERNALline, nor any other actionable error marker is captured.ci_fetch_pr_failure_logsreturnedfetch_error: log:AttributeErrorfor both failing jobs, and the local-gate wrapper (/tmp/local_tools/tools/local_ci_gate.sh) is not present in this worker's /tmp, so I cannot re-run the failing test locally to capture the assertion. The PR diff has expanded to 109 files / +11,364 / −2,143 (well beyond the original project-switch scope), so the regression source is non-obvious without the actual test output. The most-recent reviewer output on disk (reviewer_output.json) is verdict=approve at sha67814bd3a1— a controller-reviewer has already approved the work; the fourchore: re-trigger CIcommits on HEAD landed after that approval. Tier 2 (top implementer tier) with no actionable error and an approved reviewer verdict warrants OPERATOR_ATTENTION to triage whether (a) this is a CI flake to re-trigger, (b) the PR scope needs to be split to isolate the unrelated breakage, or (c) the failing test needs to be re-run with verbose output capture so the assertion error can be read.8aa36088eeto3f15357091✅ Approved
Reviewed at commit
3f15357.Confidence: high.
Claimed by
merge_drive.py(pid 3311738) until2026-06-18T06:27:43.366877+00:00.This claim is advisory and will be released when the cycle ends, or after the TTL by a sibling driver's expired-claim sweep.
3f15357091tod0e685aed4Approved by the controller reviewer stage (workflow 462).