fix(cli): add agents project switch command to project CLI #11087
No reviewers
Labels
No 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
Bounty
$100
Bounty
$1000
Bounty
$10000
Bounty
$20
Bounty
$2000
Bounty
$250
Bounty
$50
Bounty
$500
Bounty
$5000
Bounty
$750
MoSCoW
Could have
MoSCoW
Must have
MoSCoW
Should have
Needs Feedback
Points
1
Points
13
Points
2
Points
21
Points
3
Points
34
Points
5
Points
55
Points
8
Points
88
Priority
Backlog
Priority
CI Blocker
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Signed-off: Owner
Signed-off: Scrum Master
Signed-off: Tech Lead
Spike
State
Completed
State
Duplicate
State
In Progress
State
In Review
State
Paused
State
Unverified
State
Verified
State
Wont Do
Type
Automation
Type
Bug
Type
Discussion
Type
Documentation
Type
Epic
Type
Feature
Type
Legendary
Type
Refactor
Type
Support
Type
Task
Type
Testing
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
cleveragents/cleveragents-core!11087
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
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.
d2d18306b500211749a2✅ 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.
82f2ba0cbe0276acb4f2Released 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.392b806244811648378b(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:
49a6e7d311a76fb05840a76fb05840d5a8bb36a3(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.
67814bd3a18aa36088eeReview 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 HEAD8aa36088e; 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.8aa36088ee3f15357091✅ 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.
3f15357091d0e685aed4Approved by the controller reviewer stage (workflow 462).