Skip to content

ci: consolidate Gemini + quota-gate + Jules workflows onto master-staging - #75

Merged
timerloggedout-spec merged 18 commits into
master-stagingfrom
feature/workflows-consolidation
Aug 7, 2026
Merged

timerloggedout-spec merged 18 commits into
master-stagingfrom
feature/workflows-consolidation

Conversation

@timerloggedout-spec

@timerloggedout-spec timerloggedout-spec commented Aug 7, 2026 •

Copy link
Copy Markdown
Owner

Summary

ADE consolidation branch — cherry-picks the operational GitHub Actions workflow stack onto master-staging so gates + agent workflows live together, then can be promoted to master for event triggers.

Already on this branch

  • .github/actions/gemini-quota-gate/action.yml — RPD safety margin 900 (not 18/20), midnight Pacific reset, multi-key rotation, graceful skip comment
  • gemini-dispatch.yml — central router (Agent2Agent comments @gemini-cli)
  • gemini-triage.yml / gemini-invoke.yml — quota-aware reusable workflows
  • publish-wiki.yml — from master
  • Existing on base: repo-gate.yml, termux-smoke.yml, agent-feedback, auto-jules

ACTION WORKFLOWS SKIP termux-smoke (different environment function) && SKIP master-staging when ready to merge and test; Must be on master.

Still being pushed (follow-up commits on this branch)

  • gemini-review.yml (session continuation + quota gate) — required before merge (dispatch review job calls it)
  • agent-load-balancer.yml
  • agent-jules-on-issues.yml (from master)

Why not #72 as-is

#72 is mergeable_state: dirty (79 files, conflicts with current master-staging). This PR is workflows-only so it can land cleanly.

After merge to master-staging

  1. Promote the same workflow files to master (event triggers require default branch).
  2. Close/supersede fix(ci): add continue-on-error to Gemini CLI workflows #71 and narrow feat: agent quota throttling, session continuation & load balancing #72.
  3. Open [CLOSED - spliced out] feat(exchanges): dedicated financial exchange connectors (Yobit/KuCoin/Binance) #74 for exchanges extraction.

Test

@gemini-cli /review

on any non-draft PR after promotion to master.

Implements: workflow consolidation for operational Gemini stack
Signed-off-by: Grok (ADE)


Open in Devin Review

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features
    • Added automated AI-assisted issue triage, pull request reviews, and development task handling.
    • Added daily usage safeguards with backup credentials and graceful skipping when limits are reached.
    • Added automatic wiki publishing for supported branch updates.
    • Added coordinated handling for AI requests through issue labels, comments, and status updates.
  • Bug Fixes
    • Improved coordination to prevent overlapping automated work.
  • Tests
    • Added offline connector smoke checks with human-readable and JSON results.
  • Documentation
    • Added guidance for running and tracking connector smoke tests.

@blocksorg

blocksorg Bot commented Aug 7, 2026

Copy link
Copy Markdown

Mention Blocks like a regular teammate with your question or request:

@blocks review this pull request
@blocks make the following changes ...
@blocks create an issue from what was mentioned in the following comment ...
@blocks explain the following code ...
@blocks are there any security or performance concerns?

Run @blocks /help for more information.

Workspace settings | Disable this message

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@vercel

vercel Bot commented Aug 7, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
termux-monorepo Ready Ready Preview, v0 Aug 7, 2026 9:21pm

@gitar-bot

gitar-bot Bot commented Aug 7, 2026 •

Copy link
Copy Markdown

Gitar is working

Gitar

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

@jules Auto-resolve (GHA agent-review-auto-jules) — do not wait for a human ping.
Bot feedback from aikido-pr-checks[bot] on PR #75 (branch feature/workflows-consolidation).
File: .github/workflows/gemini-invoke.yml

Feedback excerpt

**3rd party Github Actions should be pinned** - high severity
A third-party GitHub Action was imported, and is not pinned via a hash. This leaves your CI/CD at risk for potential supply chain attacks, if the affected GitHub Action is compromised.

<details>
<summary>Show fix</summary>

**Remediation:** When using 3rd party Actions in your GitHub Workflow, it is a best practice to pin the version by including the commit hash. You can retrieve the commit hash from the releases tab of the affected GitHub's Action repository. For example:

 The commit hash for https://github.com/actions/setup-node/releases/v4.1.0 is 39370e3970a6d050c480ffad4ff0ed4d3fdee5af. When pinning, the Action's definition would be: - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af.

<sub>Reply `@AikidoSec ignore: [REASON]` to ignore this issue.</sub>
<sub>[More info](https://app.aikido.dev/repositories/2763427/pull_requests/75/latest?groupId=130179)</sub>
</details>

Instructions

  1. Address all open review threads on this PR.
  2. Prefer minimal diffs; preserve Sentinel 0o600/0o700 if touched.
  3. Push commits to branch feature/workflows-consolidation.
  4. Resolve base conflicts if any.
    Agent: Grok · https://x.com/grok

@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@timerloggedout-spec, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 35 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0edfca79-33d9-450d-85bc-13447fda07fc

📥 Commits

Reviewing files that changed from the base of the PR and between 27e0b15 and 8814878.

📒 Files selected for processing (4)
  • .github/workflows/gemini-dispatch.yml
  • .github/workflows/gemini-invoke.yml
  • .github/workflows/gemini-review.yml
  • .github/workflows/gemini-triage.yml
📝 Walkthrough

Walkthrough

Adds quota-gated Gemini workflows, Jules issue automation, wiki publishing, and offline connector smoke checks. The workflows validate requests, coordinate related agent work, select API keys, and route tasks to reusable workflows.

Changes

Gemini automation

Layer / File(s) Summary
Quota gate and exhaustion handling
.github/actions/gemini-quota-gate/action.yml
Tracks daily Gemini usage with Pacific-date cache keys, backup-key selection, skip outputs, counter persistence, and optional issue comments.
Request dispatch and routing
.github/workflows/gemini-dispatch.yml
Validates events and commands, collects related PR context, acknowledges requests, and routes triage, review, and invocation commands.
Gemini execution workflows
.github/workflows/gemini-invoke.yml, .github/workflows/gemini-review.yml, .github/workflows/gemini-triage.yml
Adds reusable Gemini workflows with concurrency, quota checks, key selection, conditional CLI execution, and task-specific prompts.

Jules issue automation

Layer / File(s) Summary
Jules triggers and request handling
.github/workflows/agent-jules-on-issues.yml
Handles qualifying issue labels and authorized comments, acknowledges requests, inventories related agent PRs, and applies the jules label.
Jules API and fallback execution
.github/workflows/agent-jules-on-issues.yml
Invokes Jules with issue context when configured and posts coordination instructions when no API key exists.

Connector smoke checks

Layer / File(s) Summary
Connector validation suite
scripts/ci/termux_smoke/connectors/smoke_connectors.py
Validates connector files, compiles the manager, checks shell syntax, optionally lists connectors, and emits text or JSON results.
Smoke-flow integration and documentation
scripts/ci/termux_smoke.py, scripts/ci/termux_smoke/TRACKING.md, scripts/ci/termux_smoke/connectors/README.md
Runs the connector suite during non-light checks and documents its scope and commands.

Wiki publishing

Layer / File(s) Summary
Wiki synchronization
.github/workflows/publish-wiki.yml
Publishes wiki/ changes to the GitHub Wiki on selected branches or manual dispatch.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GitHubEvent
  participant GeminiDispatch
  participant QuotaGate
  participant GeminiWorkflow
  participant GeminiCLI
  GitHubEvent->>GeminiDispatch: submit supported command
  GeminiDispatch->>GeminiDispatch: validate request and collect related PRs
  GeminiDispatch->>QuotaGate: check daily quota
  QuotaGate-->>GeminiWorkflow: skip or selected API key
  GeminiWorkflow->>GeminiCLI: run task with repository context
Loading

Possibly related issues

  • timerloggedout-spec/termux-monorepo#54: Covers the Gemini dispatch and related workflow additions implemented here.

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.76% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main CI changes involving Gemini, quota-gate, Jules, and the master-staging target.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/workflows-consolidation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copy link
Copy Markdown
Owner Author

ADE status — consolidation complete for core Gemini stack

Branch: feature/workflows-consolidation → base: master-staging
PR: #75

On this PR now

File Status
.github/actions/gemini-quota-gate/action.yml ✅ RPD margin 900, midnight PT, multi-key, graceful skip
gemini-dispatch.yml ✅ User/OWNER-only for @gemini-cli; skips drafts/forks
gemini-review.yml ✅ session continuation + quota gate
gemini-triage.yml ✅ quota gate
gemini-invoke.yml ✅ quota gate
publish-wiki.yml ✅
repo-gate.yml / termux-smoke.yml ✅ already on master-staging

Optional follow-ups (can land after)

  • agent-load-balancer.yml
  • agent-jules-on-issues.yml (still on master only)

Why not merge #72

#72 is dirty (79 files, conflicts). This PR is workflows-only.

Merge sequence (when gates green)

  1. Merge ci: consolidate Gemini + quota-gate + Jules workflows onto master-staging #75 → master-staging
  2. Promote the same workflow files to master (event triggers only fire from default branch)
  3. Close fix(ci): add continue-on-error to Gemini CLI workflows #71 as superseded; narrow or close feat: agent quota throttling, session continuation & load balancing #72
  4. Open [CLOSED - spliced out] feat(exchanges): dedicated financial exchange connectors (Yobit/KuCoin/Binance) #74 for exchanges extraction

Test after promote to master

@gemini-cli /review

Do not merge yet until repo-gate + termux-smoke pass on this PR.

Signed-off-by: Grok (ADE)

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 11 potential issues.

Open in Devin Review

Comment thread .github/actions/gemini-quota-gate/action.yml
Comment thread .github/workflows/gemini-review.yml Outdated
Comment on lines +103 to +117
pr-number: ${{ github.event.pull_request.number || '' }}
command: 'review'
has-backup-key: ${{ secrets.GEMINI_API_KEY_BACKUP != '' }}

- name: Run Gemini CLI PR review
if: |
steps.session.outputs.already_reviewed != 'true' &&
steps.quota.outputs.skip != 'true'
uses: google-github-actions/run-gemini-cli@v0
env:
GEMINI_CLI_TRUST_WORKSPACE: 'true'
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
gemini_api_key: ${{ steps.quota.outputs.use_backup_key == 'true' && secrets.GEMINI_API_KEY_BACKUP || secrets.GEMINI_API_KEY }}
github_pr_number: ${{ github.event.pull_request.number }}

@devin-ai-integration devin-ai-integration Bot Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Requested pull-request reviews are silently skipped once any earlier review exists

When a review is requested by comment, the workflow compares past review notes against an empty commit identifier (c.body?.includes(headSha) at .github/workflows/gemini-review.yml:64), which always matches, so it concludes the code was already reviewed and does nothing.
Impact: Typing @gemini-cli /review on a pull request that has ever been reviewed before produces no review at all, with no visible error.

Mechanism: empty headSha makes String.includes always true

For comment-triggered runs (issue_comment, pull_request_review*) the dispatch workflow calls this reusable workflow, and context.payload.pull_request is undefined, so headSha is '' (.github/workflows/gemini-review.yml:48). String.prototype.includes('') returns true for any string, so the filter at :62-65 reduces to "any comment containing <!-- gemini-review-sha:", setting already_reviewed=true and short-circuiting both the quota gate (:106) and the review step (:115-117).

Secondarily, when the review does run in this path, reviewed_sha is '' (:96), so the trailing marker written by the model is <!-- gemini-review-sha: -->, which then poisons subsequent comparisons.

Fix: skip the already-reviewed check entirely when headSha is empty, and/or fetch the PR head SHA via github.rest.pulls.get using prNumber when the payload lacks a pull_request object.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@blocks fix this

@blocksorg blocksorg Bot Aug 7, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kimi Code: Rate limit or quota exceeded. Please wait before trying again.

Detailserror: failed to run prompt: provider.rate_limit: 429 Your account org-da892ad7697f4eaeb9d8f03819ab836d is suspended due to insufficient balance, please recharge your account or check your plan and billing details
See log: /home/user/.kimi-code/logs/kimi-code.log

View on dashboard

- Minimal-diff preference
- Overlap with other open agent PRs: ${{ inputs.prior_prs }}

${{ steps.session.outputs.changed_files != '' && format('## Changed files since last review\nFocus here:\n{0}', steps.session.outputs.changed_files) || '## Full review (first pass)' }}

@devin-ai-integration devin-ai-integration Bot Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Escaped newlines in format() render literally in the prompt

In a GitHub Actions expression, a single-quoted string literal does not interpret \n as a newline, so the generated prompt contains the literal characters \n instead of line breaks. Cosmetic only (the model will likely still parse it), but if readable prompt formatting matters, use a real multi-line YAML expression or a pre-computed step output.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@blocks fix this

@blocksorg blocksorg Bot Aug 7, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kimi Code: Rate limit or quota exceeded. Please wait before trying again.

Detailserror: failed to run prompt: provider.rate_limit: 429 Your account org-da892ad7697f4eaeb9d8f03819ab836d is suspended due to insufficient balance, please recharge your account or check your plan and billing details
See log: /home/user/.kimi-code/logs/kimi-code.log

View on dashboard

Comment on lines +4 to +8
push:
branches: [master, master-staging]
paths:
- "wiki/**"
- ".github/workflows/publish-wiki.yml"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 No wiki/ directory exists in the repo yet

The repository currently has no top-level wiki/ directory, so the path filter wiki/** will never fire on push; only workflow_dispatch can trigger this. In that case Andrew-Chen-Wang/github-wiki-action is pointed at a non-existent path: wiki, whose behavior (no-op vs. wiping the wiki vs. error) should be verified before relying on it. Also note that including master-staging in the trigger branches means unreviewed staging content can be published to the public wiki, and both branches share one concurrency group so whichever pushes last wins.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The wiki is supposed to be here: https://github.com/timerloggedout-spec/termux-monorepo/wiki
From DeepWiki import or 'symlink' etc...

Comment on lines +102 to +108
else
NEW=$(( CURRENT + 1 ))
echo "$NEW" > "$COUNTER_FILE"
echo "skip=false" >> "$GITHUB_OUTPUT"
echo "remaining=$(( LIMIT - NEW ))" >> "$GITHUB_OUTPUT"
echo "use_backup_key=false" >> "$GITHUB_OUTPUT"
fi

@devin-ai-integration devin-ai-integration Bot Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Quota counter is subject to lost updates across concurrent runs

The daily counter is restored from a shared cache, incremented locally, and saved under a run-unique key (.github/actions/gemini-quota-gate/action.yml:49-56 and :119-125). Two workflow runs that start close together both restore the same value and both write CURRENT+1, so concurrent Gemini invocations are undercounted. Also, the exact key (gemini-quota-<date>) is never written — restoration always relies on prefix matching via restore-keys, which returns the most recently created matching cache; this works but means every run creates a new cache entry, so the day's entries compete for the repo cache eviction budget. Given the 900/day safety margin the drift is probably tolerable, but it is worth knowing the gate is best-effort rather than exact.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@blocks fix this

@blocksorg blocksorg Bot Aug 7, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kimi Code: Rate limit or quota exceeded. Please wait before trying again.

Detailserror: failed to run prompt: provider.rate_limit: 429 Your account org-da892ad7697f4eaeb9d8f03819ab836d is suspended due to insufficient balance, please recharge your account or check your plan and billing details
See log: /home/user/.kimi-code/logs/kimi-code.log

View on dashboard

Comment on lines +55 to +58
const reviewComments = comments.filter(c =>
c.body?.includes('<!-- gemini-review-sha:') &&
c.body?.includes(headSha)
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Session-continuation SHA match can false-positive on unrelated comment text

The already-reviewed check accepts any comment that contains both the marker prefix and the head SHA anywhere in the body, rather than matching the marker's captured SHA. A comment that quotes a different SHA plus the marker (e.g. a re-posted review) could wrongly suppress a review. Matching body.match(/<!-- gemini-review-sha: ([a-f0-9]+) -->/)?.[1] === headSha would be tighter. Also, since reviewed_sha is injected into the prompt for the model to echo back, a model that omits the marker means the same SHA is reviewed again on the next trigger.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +84 to +96
const { data: prs } = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
per_page: 40,
});
const agentHints = ['jules', 'devin', 'coderabbit', 'ecc-tools', 'gemini'];
const relevant = prs.filter(p => {
const u = ((p.user && p.user.login) || '').toLowerCase();
const body = ((p.body || '') + ' ' + (p.title || '')).toLowerCase();
return agentHints.some(a => u.includes(a)) ||
(issueNum && (body.includes('#' + issueNum) || body.includes('issue ' + issueNum)));
}).slice(0, 12);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Prior-PR inventory only scans the first page of open PRs

pulls.list is capped at per_page: 40 with no pagination, so on a repo with more than 40 open PRs the agent-coordination inventory silently misses relevant PRs, weakening the "do not overlap files" guidance passed into every prompt. Consider github.paginate or filtering server-side.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +41 to +43
github.event.sender.type == 'User' &&
startsWith(github.event.comment.body || github.event.review.body || '', '@gemini-cli') &&
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association || github.event.review.author_association || github.event.issue.author_association)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Dispatch gate relies on comment/review payload fields for non-comment events

The third clause of the job condition reads github.event.comment.body || github.event.review.body and the corresponding author associations. For pull_request_review.submitted the comment object is absent (evaluates to null in Actions expressions, so the fallback works), but note that github.event.issue.author_association is used as the last fallback for association — that reflects who opened the issue, not who commented, so on an issue opened by a maintainer any user comment starting with @gemini-cli would pass the association check if comment.author_association were ever empty. In practice comment.author_association is always populated on issue_comment events, so this is defensive-only, but the fallback ordering is fragile.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread .github/workflows/gemini-invoke.yml
Comment thread .github/workflows/gemini-dispatch.yml
…#70 connectors

Layout:
  scripts/ci/termux_smoke/TRACKING.md
  scripts/ci/termux_smoke/connectors/smoke_connectors.py
  scripts/ci/termux_smoke/connectors/README.md

Offline: file presence, py_compile connector_manager, bash -n health_check.sh.
Optional: list connectors if PyYAML present (no network).
Wired into termux_smoke.py --with-optional and as a lightweight required presence check.

Copy link
Copy Markdown
Owner Author

Connectors → termux_smoke tracking (done)

Layout:

scripts/ci/termux_smoke/TRACKING.md
scripts/ci/termux_smoke/connectors/README.md
scripts/ci/termux_smoke/connectors/smoke_connectors.py

Wired into scripts/ci/termux_smoke.py core path (not only --with-optional):

  • file presence for .github/connectors/*
  • py_compile on connector_manager.py
  • bash -n on health_check.sh
  • optional list if PyYAML present (no network)

Previous check runs on this PR: repo-gate ✅ termux-smoke ✅

Waiting for the new commit checks; if still green → MERGE #75.

Signed-off-by: Grok (ADE)

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 4 new potential issues.

Open in Devin Review

Comment thread scripts/ci/termux_smoke/connectors/smoke_connectors.py Outdated
Comment on lines +194 to +215
def check_connectors_suite(report: SmokeReport) -> None:
"""Run scripts/ci/termux_smoke/connectors offline suite (#70 tracking)."""
entry = REPO_ROOT / "scripts/ci/termux_smoke/connectors/smoke_connectors.py"
connectors_dir = REPO_ROOT / ".github" / "connectors"
if not entry.is_file():
if connectors_dir.is_dir():
report.add(
CheckResult(
"connectors-suite",
"FAIL",
"connectors present but scripts/ci/termux_smoke/connectors/smoke_connectors.py missing",
)
)
else:
report.add(CheckResult("connectors-suite", "NOTE", "no connectors tree and no suite entry", required=False))
return
rc, out, err = run_cmd([sys.executable, str(entry)], timeout=45.0)
detail = (out or err or f"rc={rc}").replace("\n", " | ")[:240]
if rc != 0:
report.add(CheckResult("connectors-suite", "FAIL", detail))
else:
report.add(CheckResult("connectors-suite", "PASS", detail or "ok"))

@devin-ai-integration devin-ai-integration Bot Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 New connectors suite runs in the core (required) smoke path, not --with-optional as documented

check_connectors_suite is invoked from the non---light core path, and its CheckResults default to required=True, so a FAIL fails the Core smoke (required) step in .github/workflows/termux-smoke.yml. The suite's own README says it runs "via umbrella smoke: python3 scripts/ci/termux_smoke.py --with-optional" (scripts/ci/termux_smoke/connectors/README.md:6-7), and TRACKING.md calls it "core soft-required" (scripts/ci/termux_smoke/TRACKING.md:8). The three descriptions disagree. I verified the suite currently passes on this checkout, but any branch that removes/renames a file in .github/connectors/ (e.g. the planned #74 exchanges extraction, which would drop exchanges.yaml from REQUIRED_FILES at scripts/ci/termux_smoke/connectors/smoke_connectors.py:21-28) will hard-fail the required gate.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +32 to +44
if: |
(
github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.fork == false &&
github.event.pull_request.draft == false
) || (
github.event_name == 'issues' &&
contains(fromJSON('["opened", "reopened"]'), github.event.action)
) || (
github.event.sender.type == 'User' &&
startsWith(github.event.comment.body || github.event.review.body || '', '@gemini-cli') &&
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association || github.event.review.author_association || github.event.issue.author_association)
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Dispatch gate skips the author-association check for pull_request events but the third clause can be evaluated for reviews

For pull_request_review.submitted the third clause reads github.event.comment.author_association || github.event.review.author_association || github.event.issue.author_association; review.author_association exists so this works, but for pull_request_review_comment.created the payload's comment.author_association is present too. The clause is also evaluated for pull_request/issues events where all three are null — contains(..., '') is false, so it correctly relies on the earlier clauses. No functional problem found, but note that issues.opened unconditionally triggers a triage run with no @gemini-cli opt-in and no author-association check, which means any user opening an issue consumes Gemini quota.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread .github/workflows/gemini-dispatch.yml
Path is scripts/ci/termux_smoke/connectors/smoke_connectors.py →
parents[4] is repo root (was parents[3] → scripts/). Fixes FAIL
looking for scripts/.github/connectors.

Signed-off-by: Grok (ADE)

Copy link
Copy Markdown
Owner Author

ADE fix pushed (76fbb5c)

scripts/ci/termux_smoke/connectors/smoke_connectors.py had wrong REPO_ROOT depth:

  • path: scripts/ci/termux_smoke/connectors/… → needs parents[4]
  • was parents[3] → resolved to scripts/.github/connectors → FAIL

That was the only required failure on agentic termux smoke.

#70 connectors tracking is live on this branch:

  • scripts/ci/termux_smoke/connectors/ suite
  • TRACKING.md registry
  • wired into core termux_smoke.py (not only --with-optional)

Workflow stack on this PR (ready once smoke is green):

  • gemini-quota-gate (RPD 900, midnight PT, multi-key)
  • gemini-dispatch / review / triage / invoke
  • publish-wiki
  • existing: repo-gate, termux-smoke, agent-feedback, auto-jules

After this run goes green → merge #75 → master-staging, then promote same workflow files to master for event triggers.

Supersedes bare continue-on-error in #71; #72 can be narrowed/closed after land.

…ation)

Completes Jules side of the consolidated agent stack on master-staging.

Signed-off-by: Grok (ADE)
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

@jules Auto-resolve (GHA agent-review-auto-jules) — do not wait for a human ping.
Bot feedback from aikido-pr-checks[bot] on PR #75 (branch feature/workflows-consolidation).

Feedback excerpt

(see review threads)

Instructions

  1. Address all open review threads on this PR.
  2. Prefer minimal diffs; preserve Sentinel 0o600/0o700 if touched.
  3. Push commits to branch feature/workflows-consolidation.
  4. Resolve base conflicts if any.
    Agent: Grok · https://x.com/grok

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 10 new potential issues.

Open in Devin Review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 PR does not cite an ITEMS.md id as required by AGENTS.md

AGENTS.md requires Implements: <ITEM-ID> on PRs/commits and forbids work outside docs/proposals/active/<id>/ITEMS.md without adding a row first. The PR body cites Implements: workflow consolidation for operational Gemini stack, which is prose rather than an item id, and no ITEMS.md row is added in this diff. Worth confirming an item row exists (or adding one) before merge.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coderabbitai do this and commit.

Make sure all issues are fixed and committed in this #75 PR high importance merge.

Retarget to master from master-staging

@coderabbitai coderabbitai Bot Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== Repository instructions =='
fd -H -t f '^AGENTS\.md$|^ITEMS\.md$' . | sort
if [ -f AGENTS.md ]; then
  sed -n '1,260p' AGENTS.md
fi

echo '== Active proposal item rows that mention Gemini, workflow, dispatch, quota, or wiki =='
fd -H -t f '^ITEMS\.md$' docs/proposals/active 2>/dev/null \
  | sort \
  | while IFS= read -r file; do
      echo "--- $file"
      rg -n -i -C 2 'gemini|workflow|dispatch|quota|wiki' "$file" || true
    done

echo '== Gemini workflow inventory =='
fd -H -t f '^gemini-.*\.ya?ml$|^agent-load-balancer\.ya?ml$' .github/workflows 2>/dev/null | sort

echo '== Pull request `#75` metadata =='
gh pr view 75 --repo timerloggedout-spec/termux-monorepo \
  --json number,title,body,baseRefName,headRefName,state,url

Length of output: 7626


🏁 Script executed:

#!/bin/bash
set -euo pipefail

for file in \
  .github/workflows/gemini-dispatch.yml \
  .github/workflows/gemini-triage.yml \
  .github/workflows/gemini-review.yml \
  .github/workflows/gemini-invoke.yml \
  .github/workflows/agent-load-balancer.yml
do
  if [ -f "$file" ]; then
    echo "== $file =="
    nl -ba "$file" | sed -n '1,260p'
  fi
done

echo '== Reusable-workflow entry points and invocations =='
rg -n -C 3 \
  'workflow_call|gemini-(dispatch|triage|review|invoke)\.yml|GEMINI_API_KEY|quota' \
  .github/workflows 2>/dev/null || true

Length of output: 939


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== Active proposal registry =='
sed -n '1,260p' docs/proposals/registry.yaml
echo

echo '== Proposal process and PR body process =='
sed -n '1,260p' docs/proposals/PROCESS.md
sed -n '1,260p' docs/PR-SUMMARY-PROCESS.md
echo

echo '== Complete active item lists =='
fd -H -t f '^ITEMS\.md$' docs/proposals/active | sort | while IFS= read -r file; do
  echo "--- $file"
  sed -n '1,260p' "$file"
done
echo

echo '== Gemini and related workflows =='
for file in \
  .github/workflows/gemini-dispatch.yml \
  .github/workflows/gemini-triage.yml \
  .github/workflows/gemini-review.yml \
  .github/workflows/gemini-invoke.yml \
  .github/workflows/agent-load-balancer.yml \
  .github/actions/gemini-quota-gate/action.yml
do
  if [ -f "$file" ]; then
    echo "--- $file"
    sed -n '1,300p' "$file"
  else
    echo "--- MISSING: $file"
  fi
done
echo

echo '== Gemini workflow references =='
rg -n -C 3 \
  'workflow_call|gemini-(dispatch|triage|review|invoke)\.yml|GEMINI_API_KEY|gemini-quota-gate|quota' \
  .github/workflows .github/actions 2>/dev/null || true

Length of output: 59878


@timerloggedout-spec, I found two required fixes and one blocked request.

  1. Add a new P1 work item in docs/proposals/active/chatgpt-critical-eval/ITEMS.md, for example CE-21, for the Gemini workflow stack. Set its status to doing and cite PR #75 as evidence.

  2. Replace the invalid PR citation with Implements: CE-21. A permitted summary editor must update the PR body. docs/PR-SUMMARY-PROCESS.md restricts CodeRabbit to comments, so I cannot rewrite the PR body.

  3. Fix .github/actions/gemini-quota-gate/action.yml. The current daily cache key is immutable. After the first save, later jobs restore the same old counter and cannot persist their increment. The daily quota limit is therefore not reliably enforced. Use a mutable, serialized state mechanism, or redesign the quota gate so it does not rely on updating an existing GitHub Actions cache entry.

  4. Remove the load-balancer statements from .github/workflows/gemini-dispatch.yml, or add and invoke .github/workflows/agent-load-balancer.yml. The workflow is missing from this branch and the dispatch workflow does not call it.

I did not retarget #75 to master. AGENTS.md and docs/proposals/PROCESS.md require integration PRs to target master-staging. They specify promotion to master only after master-staging is healthy. Retargeting now would violate the repository policy. EDIT by Human User: ((This is an Exception))

You are interacting with an AI system.

@timerloggedout-spec timerloggedout-spec Aug 7, 2026 •

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coderabbitai fix 1, 2, 3, and 4. The load balancer must be integrated; use it from the other branch to here immediately.

You create commits and PR's all the time; it's what you do!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== Repository instructions and proposal item lists =='
fd -H -t f '^AGENTS\.md$|^ITEMS\.md$|^PROCESS\.md$|^PR-SUMMARY-PROCESS\.md$' . | sort
for file in AGENTS.md docs/proposals/PROCESS.md docs/PR-SUMMARY-PROCESS.md; do
  if [ -f "$file" ]; then
    echo "--- $file"
    sed -n '1,260p' "$file"
  fi
done

echo '== Active proposal item lists =='
fd -H -t f '^ITEMS\.md$' docs/proposals/active 2>/dev/null | sort | while IFS= read -r file; do
  echo "--- $file"
  sed -n '1,260p' "$file"
done

echo '== Current Gemini workflow/action structure =='
fd -H -t f -e yml -e yaml .github/workflows .github/actions 2>/dev/null \
  | sort \
  | grep -E 'gemini|agent-load-balancer' \
  | while IFS= read -r file; do
      echo "--- $file"
      ast-grep outline "$file" --items all || true
    done

echo '== Relevant current file contents =='
for file in \
  .github/workflows/gemini-dispatch.yml \
  .github/workflows/gemini-triage.yml \
  .github/workflows/gemini-review.yml \
  .github/workflows/gemini-invoke.yml \
  .github/actions/gemini-quota-gate/action.yml
do
  if [ -f "$file" ]; then
    echo "--- $file"
    nl -ba "$file" | sed -n '1,360p'
  fi
done

echo '== References and quota-gate call sites =='
rg -n -C 4 'agent-load-balancer|gemini-quota-gate|GEMINI_API_KEY|workflow_call|quota' \
  .github/workflows .github/actions 2>/dev/null || true

echo '== Pull request and branch inventory =='
gh pr view 75 --repo timerloggedout-spec/termux-monorepo \
  --json number,title,body,baseRefName,headRefName,state,url
gh api "repos/timerloggedout-spec/termux-monorepo/branches?per_page=100" \
  --paginate --jq '.[].name' | sort
git branch -a --no-color | sed -n '1,160p'

echo '== Locate agent-load-balancer.yml in accessible refs =='
for ref in $(git for-each-ref --format='%(refname:short)' refs/remotes refs/heads | sort -u); do
  if git cat-file -e "${ref}:.github/workflows/agent-load-balancer.yml" 2>/dev/null; then
    echo "--- REF: $ref"
    git show "${ref}:.github/workflows/agent-load-balancer.yml"
  fi
done

Length of output: 20000


🏁 Script executed:

#!/bin/bash
set -u

echo '== Pull request `#75` =='
gh pr view 75 --repo timerloggedout-spec/termux-monorepo \
  --json number,title,body,baseRefName,headRefName,state,url \
  || true

echo '== Relevant file inventory =='
fd -H -t f -e yml -e yaml .github 2>/dev/null \
  | grep -Ei '(gemini|agent-load-balancer)' \
  | sort \
  || true

echo '== Dispatch, reusable workflows, and quota action =='
for file in \
  .github/workflows/gemini-dispatch.yml \
  .github/workflows/gemini-triage.yml \
  .github/workflows/gemini-review.yml \
  .github/workflows/gemini-invoke.yml \
  .github/workflows/agent-load-balancer.yml \
  .github/actions/gemini-quota-gate/action.yml
do
  if [ -f "$file" ]; then
    echo "--- $file"
    nl -ba "$file" | sed -n '1,420p'
  else
    echo "--- MISSING: $file"
  fi
done

echo '== All Gemini quota and load-balancer references =='
rg -n -C 5 'agent-load-balancer|gemini-quota-gate|GEMINI_API_KEY|workflow_call|quota' \
  .github 2>/dev/null \
  || true

echo '== Remote branches with candidate names =='
gh api "repos/timerloggedout-spec/termux-monorepo/branches?per_page=100" \
  --paginate --jq '.[].name' 2>/dev/null \
  | grep -Ei 'agent|balanc|gemini|load' \
  | sort \
  || true

echo '== Pull requests with candidate names =='
gh pr list --repo timerloggedout-spec/termux-monorepo --state all --limit 100 \
  --json number,title,headRefName,baseRefName,url \
  --jq '.[] | select((.title + " " + .headRefName) | test("agent|balanc|gemini|load"; "i"))' \
  || true

echo '== Accessible refs containing agent-load-balancer.yml =='
git for-each-ref --format='%(refname:short)' refs/remotes refs/heads 2>/dev/null \
  | sort -u \
  | while IFS= read -r ref; do
      if git cat-file -e "${ref}:.github/workflows/agent-load-balancer.yml" 2>/dev/null; then
        echo "--- $ref"
        git show "${ref}:.github/workflows/agent-load-balancer.yml"
      fi
    done

Length of output: 31676


🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="timerloggedout-spec/termux-monorepo"
source_ref="tembo/agent-quota-loadbalancer"
current_ref="feature/workflows-consolidation"

raw_file() {
  local ref="$1"
  local path="$2"
  echo "--- ${ref}:${path}"
  gh api \
    -H 'Accept: application/vnd.github.raw+json' \
    "repos/${repo}/contents/${path}?ref=${ref}" \
    || true
  echo
}

echo '== Source workflow implementations from PR `#72` branch =='
for path in \
  .github/workflows/agent-load-balancer.yml \
  .github/workflows/gemini-dispatch.yml \
  .github/actions/gemini-quota-gate/action.yml \
  .github/workflows/gemini-triage.yml \
  .github/workflows/gemini-review.yml \
  .github/workflows/gemini-invoke.yml
do
  raw_file "$source_ref" "$path"
done

echo '== Current PR `#75` branch: complete dispatch and quota action =='
for path in \
  .github/workflows/gemini-dispatch.yml \
  .github/actions/gemini-quota-gate/action.yml
do
  raw_file "$current_ref" "$path"
done

echo '== Source-branch workflow references to the load balancer =='
gh api \
  "repos/${repo}/git/trees/${source_ref}?recursive=1" \
  --jq '.tree[] | select(.path | test("^\\.github/(workflows|actions)/.*\\.(yml|yaml)$")) | .path' \
  | while IFS= read -r path; do
      content=$(gh api -H 'Accept: application/vnd.github.raw+json' \
        "repos/${repo}/contents/${path}?ref=${source_ref}" 2>/dev/null || true)
      if printf '%s\n' "$content" | grep -qi 'agent-load-balancer'; then
        echo "--- ${source_ref}:${path}"
        printf '%s\n' "$content" | grep -in -C 5 'agent-load-balancer'
      fi
    done

Length of output: 51045


@timerloggedout-spec, I validated the required changes. I cannot create commits or pull requests. The repository policy also limits CodeRabbit to PR comments. An authorized executor must apply this plan and commit it to feature/workflows-consolidation.

Task: Correct Gemini workflow tracking, quota accounting, and load-balancer routing in #75

  • Keep the PR base as master-staging. It already has the required base.
  • Add CE-21 as the P1 tracking item.
  • Replace the prose Implements: value with Implements: CE-21.
  • Replace immutable cache-based quota state with mutable, serialized state.
  • Add the load-balancer workflow from tembo/agent-quota-loadbalancer, but correct its incompatible behavior before integration.
  • Route all Gemini commands through the load balancer.

The agent-load-balancer.yml from #72 must not be copied unchanged. Its quota probe consumes quota, it uses the obsolete 18 limit, and its Gemini route always invokes gemini-review.yml. That behavior would review an issue or on-demand request instead of triaging or invoking it.

🐇⚙️


  • 📌 Create a pull request with these changes

You are interacting with an AI system.

Comment on lines +101 to +104
- name: Invoke Jules API (optional)
if: ${{ secrets.JULES_API_KEY != '' }}
continue-on-error: true
uses: google-labs-code/jules-invoke@v1

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Jules issue automation fails to start because the workflow file is rejected

Three steps decide whether to run by reading a stored secret directly inside a step condition (if: ${{ secrets.JULES_API_KEY != '' }} at .github/workflows/agent-jules-on-issues.yml:102), which the workflow engine does not allow, so the whole file is rejected and neither Jules job ever runs.
Impact: Labeling an issue jules or mentioning @jules produces an immediately failing run with no acknowledgement, no fallback ping, and no Jules task.

Why `secrets` is not usable in an `if` expression

GitHub's context-availability rules do not include the secrets context for jobs.<job_id>.steps.<step_id>.if (only github, needs, strategy, matrix, job, runner, env, vars, steps, inputs). Using it yields the parse error Unrecognized named-value: 'secrets', which invalidates the whole workflow file, not just the step.

Affected lines: .github/workflows/agent-jules-on-issues.yml:102, .github/workflows/agent-jules-on-issues.yml:138, .github/workflows/agent-jules-on-issues.yml:232.

The usual workaround is to hoist the secret into a job-level env (secrets ARE allowed in env: / with:) and test env.HAS_JULES_KEY != '' in the if, exactly as the sibling workflows already do with has-backup-key: ${{ secrets.GEMINI_API_KEY_BACKUP != '' }} inside with: (.github/workflows/gemini-invoke.yml:38).

Prompt for agents
The three step-level conditions in .github/workflows/agent-jules-on-issues.yml (lines 102, 138, 232) reference the `secrets` context inside `if:`. GitHub Actions does not expose `secrets` to `if` expressions, so the workflow file fails to parse with 'Unrecognized named-value: secrets' and neither job runs at all. Fix by exposing the presence of the key through a context that IS allowed in `if`, e.g. define a job-level `env: HAS_JULES_KEY: ${{ secrets.JULES_API_KEY }}` (or a boolean-ish string) and change the conditions to test `env.HAS_JULES_KEY != ''` / `== ''`. Apply the same fix to both jobs.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coderabbitai high value fix immediately user demand.

@coderabbitai coderabbitai Bot Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

workflow=".github/workflows/agent-jules-on-issues.yml"

printf '%s\n' '--- workflow structure ---'
ast-grep outline "$workflow" --items all || true

printf '%s\n' '--- JULES_API_KEY, environment, and conditional references ---'
rg -n -C 4 'JULES_API_KEY|^\s*env:|^\s*if:' "$workflow"

Length of output: 3340


🏁 Script executed:

#!/bin/bash
set -euo pipefail

workflow=".github/workflows/agent-jules-on-issues.yml"

printf '%s\n' '--- remaining step-level secret conditions ---'
rg -n -U '^\s{6,}- name:.*\n\s+if:\s*\$\{\{\s*secrets\.' "$workflow" && exit 1 || true

printf '%s\n' '--- Jules key condition and environment references ---'
rg -n -C 2 'JULES_API_KEY|^\s+if:' "$workflow"

Length of output: 1031


@timerloggedout-spec, verification failed because the fix is not present on the current branch. The workflow still contains all three invalid secrets.JULES_API_KEY step conditions.

  • Apply the planned workflow change before validation.
  • Do not mark this finding as resolved until Lines 102, 138, and 232 use env.JULES_API_KEY.

🐇⚠️


  • 📌 Commit the changes to this branch

You are interacting with an AI system.

Comment thread .github/workflows/agent-jules-on-issues.yml
Comment thread scripts/ci/termux_smoke.py Outdated
Comment thread scripts/ci/termux_smoke/connectors/smoke_connectors.py Outdated
Comment on lines +15 to +23
on:
issues:
types: [labeled, opened]
issue_comment:
types: [created]

concurrency:
group: jules-issue-${{ github.event.issue.number || github.run_id }}
cancel-in-progress: false

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Workflow subscribes to issues.opened but no job handles it

on.issues.types includes opened (.github/workflows/agent-jules-on-issues.yml:17) yet both jobs gate on github.event.action == 'labeled' or on issue_comment. Every newly opened issue therefore starts a run in which all jobs are skipped — harmless but noisy in the Actions tab. Either drop opened from the trigger or extend the jules-on-label condition to cover issues opened with the label already applied (a common case when issues are created from templates).

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coderabbitai labels are extra.

Fix this so the trigger works.

@coderabbitai coderabbitai Bot Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

workflow=".github/workflows/agent-jules-on-issues.yml"

printf '%s\n' '--- workflow outline ---'
ast-grep outline "$workflow" --items all || true

printf '%s\n' '--- event guards and payload field references ---'
rg -n -C 4 \
  'github\.event\.(action|issue|comment|label)|if:|issues:|issue_comment:' \
  "$workflow"

printf '%s\n' '--- full workflow with line numbers ---'
cat -n "$workflow"

Length of output: 16921


  • Make new issues invoke Jules without a jules label.
  • Keep the existing @jules issue-comment invocation path.
  • Restrict automatic invocation to trusted issue authors.

@timerloggedout-spec, confirmed. Line 29 makes the current issue job label-dependent. The update will invoke Jules when a trusted user opens an issue. It will not require a label.


  • 📌 Create a pull request with these changes

You are interacting with an AI system.

Comment thread .github/actions/gemini-quota-gate/action.yml
Comment thread .github/workflows/agent-jules-on-issues.yml
Comment thread .github/workflows/gemini-dispatch.yml
Comment thread .github/workflows/gemini-dispatch.yml
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

@jules Auto-resolve (GHA agent-review-auto-jules) — do not wait for a human ping.
Bot feedback from coderabbitai[bot] on PR #75 (branch feature/workflows-consolidation).

Feedback excerpt

(see review threads)

Instructions

  1. Address all open review threads on this PR.
  2. Prefer minimal diffs; preserve Sentinel 0o600/0o700 if touched.
  3. Push commits to branch feature/workflows-consolidation.
  4. Resolve base conflicts if any.
    Agent: Grok · https://x.com/grok

Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 5 new potential issues.

Open in Devin Review

Comment thread .github/workflows/agent-jules-on-issues.yml
Comment on lines +49 to +56
- name: Restore quota counter
id: restore
uses: actions/cache/restore@v4
with:
path: /tmp/gemini-quota
key: gemini-quota-${{ steps.date.outputs.key }}
restore-keys: gemini-quota-${{ steps.date.outputs.key }}
enableCrossOsArchive: true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Quota gate never restores the backup counter path correctly after a skip-only run

When the primary counter is exhausted and no backup key is configured, the step sets skip=true and the Save quota counter step is skipped (.github/actions/gemini-quota-gate/action.yml:120). That is fine for the counter itself, but note the backup counter is only ever written, never reset, and both counters live in the same cache entry keyed by date; a day rollover creates a fresh (empty) cache so both reset together — intended behaviour, but only because restore-keys is an exact-date prefix. If someone later loosens restore-keys to gemini-quota- the gate would silently import yesterday's counts and refuse to run all day.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +26 to +34
jules-on-label:
if: |
github.event_name == 'issues' &&
github.event.action == 'labeled' &&
(
github.event.label.name == 'jules' ||
github.event.label.name == 'Jules' ||
github.event.label.name == 'JULES'
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Dispatch gate does not restrict who can label/trigger, despite the security comment

The dispatch condition allows any pull_request opened/synchronize from a non-fork branch, and comment paths are limited to OWNER/MEMBER/COLLABORATOR. However agent-jules-on-issues.yml's label-triggered job has no author-association check at all, so anyone who can add the jules label (triage-permission users) can start API-consuming work, which conflicts with the header comment "Issue triggers are restricted — untrusted openers cannot burn quota" (.github/workflows/agent-jules-on-issues.yml:13). Worth aligning the comment with the actual gating or adding an association check to the label job.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread .github/workflows/agent-jules-on-issues.yml
Comment thread .github/workflows/gemini-dispatch.yml
@timerloggedout-spec

Copy link
Copy Markdown
Owner Author

LOAD BALANCE ≠ or = async sequential and parallelization Optimizations...?

Optimized Runner ≠ Token Rotations.

#75 (comment)

@coderabbitai
@jules
@google-labs-jules
@gemini-cli

From, likely stale, @Vibe-Mistral chat:

bf883d2 ← feat(automation): Convert retroactive trigger to 100% automated (BIUDL! {Built In 
... Development} FnCWAADE)
1960532 ← feat(retroactive): Add comprehensive retroactive triggering system
dbeed4b ← feat(agents): Complete 24/7 autonomous system with cross-platform triggering
4d83529 ← feat(jules): Enhanced Jules API integration with official documentation patterns
6b69d13 ← feat(gemini): Complete automation overhaul with Jules integration & Linear sync
7d91787 ← feat(gemini): Comprehensive workflow improvements and custom commands

Did @jules loop in a Linear operation?

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="timerloggedout-spec/termux-monorepo"

echo "== PR `#75` state =="
gh pr view 75 --repo "$repo" \
  --json url,baseRefName,headRefName,headRefOid,statusCheckRollup \
  --jq '{url,baseRefName,headRefName,headRefOid,checks:[.statusCheckRollup[]|{name:(.name // .context),status,conclusion}]}'

echo
echo "== Cited commits and changed paths =="
for sha in bf883d2 1960532 dbeed4b 4d83529 6b69d13 7d91787; do
  echo "--- $sha ---"
  if gh api "repos/$repo/commits/$sha" --jq '{sha:.sha,message:.commit.message,html_url,files:[.files[].filename]}' 2>/dev/null; then
    :
  else
    echo "NOT FOUND in $repo"
  fi
done

echo
echo "== Current Jules and agent workflow inventory =="
fd -H -t f -e yml -e yaml .github/workflows \
  | sort \
  | while IFS= read -r file; do
      case "$file" in
        *jules*|*agent*|*gemini*|*linear*)
          echo "--- $file ---"
          sed -n '1,360p' "$file"
          ;;
      esac
    done

echo
echo "== Current Linear references with context =="
rg -n -i -C 4 \
  'linear(\.app|[-_ ]?(api|issue|ticket|project)|_API_KEY|_TOKEN)|LINEAR' \
  .github AGENTS.md README.md docs scripts 2>/dev/null || true

echo
echo "== Git history affecting Jules/Linear workflow paths =="
git log --all --oneline -- \
  .github/workflows \
  .github/actions \
  | rg -i 'jules|linear|automation|retroactive|gemini' \
  | head -n 120 || true

Length of output: 4694


🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="timerloggedout-spec/termux-monorepo"

echo "== Workflow files related to Jules, agents, Gemini, and Linear =="
fd . .github/workflows -t f -e yml -e yaml \
  | sort \
  | while IFS= read -r file; do
      case "${file,,}" in
        *jules*|*agent*|*gemini*|*linear*)
          echo "--- $file ---"
          nl -ba "$file" | sed -n '1,420p'
          ;;
      esac
    done

echo
echo "== Linear references in workflow and action definitions =="
rg -n -i -C 5 \
  'sync-linear|linear(\.app|[-_ ]?(api|issue|ticket|project)|_API_KEY|_TOKEN)|LINEAR|workflow_run|workflow_dispatch|repository_dispatch' \
  .github/workflows .github/actions 2>/dev/null || true

echo
echo "== Recent sync-linear workflow runs =="
gh run list --repo "$repo" --workflow "sync-linear" --limit 30 \
  --json databaseId,workflowName,displayTitle,event,headBranch,headSha,status,conclusion,createdAt,url \
  --jq '.[] | {databaseId,workflowName,displayTitle,event,headBranch,headSha,status,conclusion,createdAt,url}' \
  || true

echo
echo "== Triggering details and jobs for the latest sync-linear runs =="
for run_id in $(gh run list --repo "$repo" --workflow "sync-linear" --limit 5 --json databaseId --jq '.[].databaseId'); do
  echo "--- run $run_id ---"
  gh run view "$run_id" --repo "$repo" \
    --json event,displayTitle,headBranch,headSha,jobs,url \
    --jq '{event,displayTitle,headBranch,headSha,url,jobs:[.jobs[]|{name,status,conclusion,steps:[.steps[]|{name,conclusion}]}]}' \
    || true
done

echo
echo "== Jules workflow references to Linear or workflow dispatch =="
jules_files=$(fd -i '.*jules.*\.ya?ml$' .github/workflows -t f || true)
if [ -n "$jules_files" ]; then
  printf '%s\n' "$jules_files" | while IFS= read -r file; do
    echo "--- $file ---"
    rg -n -i -C 5 \
      'linear|workflow_dispatch|repository_dispatch|gh workflow|actions/github-script|jules' \
      "$file" || true
  done
else
  echo "No Jules workflow file found."
fi

Length of output: 2446


🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="timerloggedout-spec/termux-monorepo"

echo "== Linear synchronization workflow =="
if [ -f .github/workflows/agent-feedback-linear-sync.yml ]; then
  cat .github/workflows/agent-feedback-linear-sync.yml
fi

echo
echo "== Jules workflow files =="
fd -i '.*jules.*\.ya?ml$' .github/workflows -t f \
  | sort \
  | while IFS= read -r file; do
      echo "--- $file ---"
      cat "$file"
    done

echo
echo "== References that connect Linear synchronization to other workflows =="
rg -n -i -C 6 \
  'sync-linear|agent-feedback-linear-sync|linear|workflow_dispatch|repository_dispatch|workflow_run' \
  .github/workflows .github/actions 2>/dev/null || true

echo
echo "== Recent sync-linear workflow runs =="
gh run list --repo "$repo" --workflow "sync-linear" --limit 10 \
  --json databaseId,displayTitle,event,headBranch,headSha,status,conclusion,createdAt,url \
  --jq '.[] | {databaseId,displayTitle,event,headBranch,headSha,status,conclusion,createdAt,url}' \
  || true

echo
echo "== Latest sync-linear run job steps =="
for run_id in $(gh run list --repo "$repo" --workflow "sync-linear" --limit 3 --json databaseId --jq '.[].databaseId'); do
  echo "--- run $run_id ---"
  gh run view "$run_id" --repo "$repo" --json event,displayTitle,headBranch,headSha,jobs,url \
    --jq '{event,displayTitle,headBranch,headSha,url,jobs:[.jobs[]|{name,status,conclusion,steps:[.steps[]|{name,conclusion}]}]}' \
    || true
done

Length of output: 33079


@timerloggedout-spec: No direct Jules → Linear loop exists in the current workflow definitions.

The repository does contain a Linear operation:

  • .github/workflows/agent-feedback-linear-sync.yml creates a Linear parent issue and a Linear subtask through https://api.linear.app/graphql.
  • It triggers from pull_request_review and pull_request_review_comment.
  • It runs for qualifying bot feedback from CodeRabbit, Devin, Copilot, or other bot accounts.
  • It does not trigger from a Jules label, a Jules mention, or a Jules workflow dispatch.

The apparent connection is indirect:

  1. A qualifying bot review comment arrives.
  2. agent-feedback-linear-sync.yml creates Linear tracking work.
  3. agent-review-auto-jules.yml can also post an @jules auto-resolve comment for the same review event.
  4. The Linear workflow excludes comments with <!-- agent-auto-jules -->.
  5. Therefore, the generated Jules handoff comment does not re-trigger Linear synchronization.

So, the current behavior is parallel fan-out, not a Jules feedback loop:

Bot review feedback
├─ agent-feedback-linear-sync.yml → Linear issue/subtask
└─ agent-review-auto-jules.yml    → `@jules` handoff comment
                                  └─ excluded from Linear sync

There are still important defects:

  • The Linear issue description includes **Agent: Jules | Grok**, but the Linear workflow itself does not verify that Jules performed the work. This label is misleading.
  • The Linear workflow creates a subtask for each qualifying review event. It has no visible marker-based deduplication for equivalent feedback.
  • The workflow uses actions/github-script@v7, not an immutable commit pin.
  • The workflow copies up to 3,500 characters of review content into Linear. That can transfer untrusted content to an external system.
  • The current PR checks show three successful sync-linear executions. The gh run list --workflow sync-linear query failed because sync-linear is a job ID, while the workflow name is Agent feedback → Linear subtasks.

On terminology:

  • Load balancing selects a worker based on capacity, policy, or queue state.
  • Sequential execution serializes tasks to protect shared state or reduce rate-limit collisions.
  • Parallel execution runs independent tasks concurrently.
  • Runner optimization reduces execution time or cost.
  • Token rotation selects credentials after quota or policy evaluation.

These are separate controls. A concurrency group can serialize Gemini quota updates. It is not a load balancer. API-key rotation is not runner optimization. A valid load balancer must route work to a real fallback executor without consuming quota during a probe.

The cited commit IDs (bf883d2, 1960532, dbeed4b, 4d83529, 6b69d13, and 7d91787) do not exist in this repository. They cannot establish the current workflow behavior.

🐇🔎

You are interacting with an AI system.

Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 new potential issues.

Open in Devin Review

Comment on lines +37 to +40
) || (
github.event_name == 'issues' &&
contains(fromJSON('["opened", "reopened"]'), github.event.action)
) || (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Issue-opened triage bypasses the author-association allowlist

The dispatch condition gates comment-driven commands behind OWNER/MEMBER/COLLABORATOR, but the issues branch (contains(fromJSON('["opened", "reopened"]'), github.event.action)) has no such restriction, so any external user opening an issue triggers a Gemini triage run and consumes a slot of the daily quota. The Jules workflow header claims "Issue triggers are restricted — untrusted openers cannot burn quota"; that claim does not hold for this dispatcher. Consider applying the same author-association filter to the issues branch.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +88 to +95
const agentLogins = ['google-labs-jules[bot]', 'devin-ai-integration[bot]', 'coderabbitai[bot]', 'ecc-tools[bot]'];
const relevant = prs.filter(p => {
const u = (p.user && p.user.login) || '';
const body = (p.body || '') + ' ' + (p.title || '');
return agentLogins.some(a => u.includes(a.split('[')[0])) ||
body.includes(`#${issue}`) ||
body.toLowerCase().includes(`issue ${issue}`);
}).slice(0, 15);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Agent-login matching in the label job strips the bot suffix, widening the filter

agentLogins.some(a => u.includes(a.split('[')[0])) reduces 'google-labs-jules[bot]' to 'google-labs-jules' before substring matching, so the filter is intentionally loose — fine. But note the mention job at .github/workflows/agent-jules-on-issues.yml:203-207 already stores the bare logins and does a plain u.includes(a); the two lists are duplicated with different shapes and will drift. Also both filters look only at p.body/p.title for #<issue>, so a PR referencing the issue only in commit messages or via the linked-issue API is not detected.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread .github/workflows/gemini-dispatch.yml

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
scripts/ci/termux_smoke/connectors/smoke_connectors.py (2)

113-119: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reject invalid list_connectors() results.

The else branch prints type(c).__name__ and exits with status zero. check_list_optional() then records PASS for a non-dictionary result. It also accepts dictionaries with non-list values.

Validate the Dict[str, List[str]] contract from .github/connectors/connector_manager.py Lines [136-154] before printing the result. Raise an error for invalid keys or values so the report does not claim PASS.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/ci/termux_smoke/connectors/smoke_connectors.py` around lines 113 -
119, Update the ConnectorManager smoke-test code in check_list_optional() to
require list_connectors() to return a dictionary whose keys are strings and
whose values are lists of strings. Raise an error for any invalid result instead
of printing its type, while preserving sorted-key output for valid dictionaries
so invalid cases produce a nonzero exit and cannot be reported as PASS.

129-134: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Limit dependency skips to known optional imports.

check_list_optional currently treats every ModuleNotFoundError as optional and reports "PyYAML/requests not installed". If connector_manager imports another internal or missing dependency, this turns a required startup failure into an optional note while the syntax compile step still passes. Use exc.name from the caught import error and skip only optional dependencies such as yaml and requests; add all other errors to Report.failed so the suite does not pass.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/ci/termux_smoke/connectors/smoke_connectors.py` around lines 129 -
134, Update check_list_optional to catch the import failure and inspect
ModuleNotFoundError.name, skipping only known optional dependencies such as yaml
and requests. For any other missing dependency or startup error, add the failure
to Report.failed rather than recording an optional NOTE, while preserving the
existing successful connector-list behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/ci/termux_smoke/connectors/smoke_connectors.py`:
- Around line 78-84: Update the subprocess.run calls in the smoke-check flow to
use check=False and catch subprocess.TimeoutExpired and OSError before report
generation. Record required FAIL results for connector-manager-compile and
health-check-syntax, and an optional NOTE for connectors-list, while preserving
final print/JSON output and returncode inspection for completed processes.

---

Outside diff comments:
In `@scripts/ci/termux_smoke/connectors/smoke_connectors.py`:
- Around line 113-119: Update the ConnectorManager smoke-test code in
check_list_optional() to require list_connectors() to return a dictionary whose
keys are strings and whose values are lists of strings. Raise an error for any
invalid result instead of printing its type, while preserving sorted-key output
for valid dictionaries so invalid cases produce a nonzero exit and cannot be
reported as PASS.
- Around line 129-134: Update check_list_optional to catch the import failure
and inspect ModuleNotFoundError.name, skipping only known optional dependencies
such as yaml and requests. For any other missing dependency or startup error,
add the failure to Report.failed rather than recording an optional NOTE, while
preserving the existing successful connector-list behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 45ecbcb8-9dcf-4226-b66a-62ec59ed5ca5

📥 Commits

Reviewing files that changed from the base of the PR and between 698386f and 27e0b15.

📒 Files selected for processing (3)
  • .github/workflows/agent-jules-on-issues.yml
  • scripts/ci/termux_smoke.py
  • scripts/ci/termux_smoke/connectors/smoke_connectors.py

Comment on lines +78 to +84
proc = subprocess.run(
[sys.executable, "-B", "-c", code, str(path), cfile],
cwd=REPO_ROOT,
capture_output=True,
text=True,
timeout=30,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 5 'subprocess\.run|TimeoutExpired|FileNotFoundError|check=' \
  scripts/ci/termux_smoke/connectors/smoke_connectors.py

Repository: timerloggedout-spec/termux-monorepo

Length of output: 1664


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file size =="
wc -l scripts/ci/termux_smoke/connectors/smoke_connectors.py

echo "== full smoke connectors outline and relevant sections =="
sed -n '1,180p' scripts/ci/termux_smoke/connectors/smoke_connectors.py | cat -n

echo "== imports at top =="
sed -n '1,40p' scripts/ci/termux_smoke/connectors/smoke_connectors.py | cat -n

echo "== exception handling in file =="
rg -n 'except|TimeoutExpired|FileNotFoundError|OSError|sys\.exit|finally|Reporter|Result|report\.' scripts/ci/termux_smoke/connectors/smoke_connectors.py

Repository: timerloggedout-spec/termux-monorepo

Length of output: 10246


Handle subprocess failures before emitting the report.

subprocess.run(..., timeout=...) raises TimeoutExpired, and missing executor paths raise FileNotFoundError; these exceptions can skip the final print/JSON output. Catch TimeoutExpired and OSError at lines 78-84, 100, and 121-126, record required FAIL results for connector-manager-compile and health-check-syntax, and record an optional NOTE for connectors-list. Set check=False for each run before inspection of returncode.

🧰 Tools
🪛 Pylint (4.0.6)

[warning] 78-84: 'subprocess.run' used without explicitly defining the value for 'check'.

(W1510)

🪛 Ruff (0.16.1)

[error] 78-78: subprocess call: check for execution of untrusted input

(S603)


[warning] 78-78: subprocess.run without explicit check argument

Add explicit check=False

(PLW1510)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/ci/termux_smoke/connectors/smoke_connectors.py` around lines 78 - 84,
Update the subprocess.run calls in the smoke-check flow to use check=False and
catch subprocess.TimeoutExpired and OSError before report generation. Record
required FAIL results for connector-manager-compile and health-check-syntax, and
an optional NOTE for connectors-list, while preserving final print/JSON output
and returncode inspection for completed processes.

Source: Linters/SAST tools

…omment triggers

- Dispatch outputs issue_number and passes pr_number to reusable workflows
- Reusable workflows accept pr_number input and prefer it over github.event.*
  so issue_comment / review_comment paths still reach quota-gate + Gemini CLI
- Keeps SHA-pinned run-gemini-cli and existing concurrency/quota behavior

Prepares #75 for merge to master-staging.

Copy link
Copy Markdown
Owner Author

Ready for merge → master-staging

Final commit: 88148782 — plumbs pr_number from gemini-dispatch into gemini-review / gemini-triage / gemini-invoke so comment-trigger paths (issue_comment, pull_request_review_comment) still reach the quota gate + Gemini CLI.

What’s on the branch

Piece Status
gemini-quota-gate (RPD 900 Pacific, multi-key, graceful skip) ✅
gemini-dispatch central router + pr_number output ✅
gemini-review / triage / invoke (SHA-pinned CLI, session bookmark) ✅
agent-jules-on-issues ✅
publish-wiki ✅
termux-smoke + connectors suite (parents[4], tempdir compile) ✅ green
repo-gate / hygiene ✅ green
Aikido non-blocking (third-party pin noise)

After you merge to master-staging

  1. Promote the same workflow files to master (event triggers need the default branch).
  2. Close/supersede fix(ci): add continue-on-error to Gemini CLI workflows #71; narrow feat: agent quota throttling, session continuation & load balancing #72.
  3. Continue exchanges extraction on [CLOSED - spliced out] feat(exchanges): dedicated financial exchange connectors (Yobit/KuCoin/Binance) #74.

You can merge #75 when the new-commit checks settle (repo-gate + termux-smoke expected green). Aikido can stay red.

Comment on lines +125 to +141
prompt: |
You are the free-tier agentic PR reviewer for termux-monorepo.
Read GEMINI.md and AGENTS.md.

Review this pull request for:
- Correctness and regressions
- Security (credentials, session stores, chmod 0o600/0o700)
- Alignment with AGENTS.md (master-staging, gates, no Class 3/4 artifacts)
- Minimal-diff preference
- Overlap with other open agent PRs: ${{ inputs.prior_prs }}

${{ steps.session.outputs.changed_files != '' && format('## Changed files since last review\nFocus here:\n{0}', steps.session.outputs.changed_files) || '## Full review (first pass)' }}

Post a concise review comment. Prefer a comment over formal approve/request-changes.
End your comment with: <!-- gemini-review-sha: ${{ steps.session.outputs.reviewed_sha }} -->

Additional context: ${{ inputs.additional_context }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prompt Injection in GitHub Workflows Action - critical severity
A GitHub Actions workflow contains a AI inference prompt, referencing potentially untrusted GitHub context fields. This may allow malicious input to be injected into the prompt, which makes the output of the prompt highly insecure. If the output is used to execute a command, they could potentially exfiltrate data from the pipeline (e.g. highly privileged secrets).

Show fix

Remediation: Avoid directly passing untrusted GitHub context values into AI inference prompts, especially when those values originate from user-controlled fields such as body, title, head_ref, email, or commit messages. Treat all GitHub context fields as potentially malicious input. Restrict LLM tool and write access.

Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

@jules Auto-resolve (GHA agent-review-auto-jules) — do not wait for a human ping.
Bot feedback from aikido-pr-checks[bot] on PR #75 (branch feature/workflows-consolidation).

Feedback excerpt

(see review threads)

Instructions

  1. Address all open review threads on this PR.
  2. Prefer minimal diffs; preserve Sentinel 0o600/0o700 if touched.
  3. Push commits to branch feature/workflows-consolidation.
  4. Resolve base conflicts if any.
    Agent: Grok · https://x.com/grok

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 5 new potential issues.

Open in Devin Review

Comment on lines +53 to +54
github_pr_number: ${{ inputs.pr_number || github.event.pull_request.number }}
github_issue_number: ${{ inputs.pr_number || github.event.issue.number }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Invoke workflow passes the same number as both PR and issue number

github_pr_number and github_issue_number are both fed from inputs.pr_number (.github/workflows/gemini-invoke.yml:53-54), which dispatch sets from either pull_request.number or issue.number (.github/workflows/gemini-dispatch.yml:83-87). For an issue-comment invoke this passes an issue number as github_pr_number, and for a PR-comment invoke it passes a PR number as github_issue_number. Worth verifying how run-gemini-cli reacts when both are set to a value that is not of the expected kind — it may attempt PR-specific API calls against an issue.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

shell: bash

- name: Save quota counter
if: always() && steps.check.outputs.skip != 'true'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Quota counter is saved even when the gate step itself failed

The save step uses if: always() && steps.check.outputs.skip != 'true'. If the check script aborts (e.g. set -eu trips before any output is written), skip is empty, so the condition holds and the cache is saved — possibly persisting a partially written or unchanged counter directory under a fresh key. Gating on steps.check.outputs.skip == 'false' would be tighter.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +14 to +24
on:
pull_request:
types: [opened, synchronize, ready_for_review]
issues:
types: [opened, reopened]
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
pull_request_review:
types: [submitted]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Dispatch acknowledges every PR push, consuming quota per synchronize

The dispatch job triggers on pull_request.synchronize and routes to the review workflow, so every push to an open non-draft PR consumes one unit of the daily Gemini budget and posts/updates review output. Combined with the session-continuation check keyed on head SHA this is intended, but on busy branches it can burn quota quickly; consider paths-ignore or debouncing if RPD pressure appears.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +108 to +116
prompt: |
You are Jules working on termux-monorepo. Read AGENTS.md and GEMINI.md if present.

## Issue #${{ github.event.issue.number }}: ${{ github.event.issue.title }}

${{ github.event.issue.body }}

## Open agent / related PRs (DO NOT overlap files)
${{ steps.coord.outputs.prior_prs }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟨 Untrusted issue title/body interpolated directly into agent action inputs

.github/workflows/agent-jules-on-issues.yml:111-113 (and :239-244) interpolate github.event.issue.title, github.event.issue.body, and github.event.comment.body directly into the prompt: input of the third-party google-labs-code/jules-invoke@v1 action. These values are fully attacker-controlled by anyone who can open an issue; the label-triggered job only requires that a maintainer applies the jules label, so the content itself is never trusted. An issue body containing agent instructions can steer Jules (which then creates branches/PRs with repo write access) into unintended changes — classic prompt/agent injection. The repository's AGENTS.md places hard constraints on agent behavior (base branch, no Class 3/4 artifacts, no invented work) that injected instructions can attempt to override.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +37 to +40
) || (
github.event_name == 'issues' &&
contains(fromJSON('["opened", "reopened"]'), github.event.action)
) || (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟨 Any user opening an issue can trigger Gemini runs and consume API quota

.github/workflows/gemini-dispatch.yml:37-40 allows any issues.opened/reopened event to dispatch the triage job with no author-association check, unlike the comment path at :41-44 which restricts to OWNER/MEMBER/COLLABORATOR. Anyone (including drive-by accounts) can therefore cause repeated Gemini API calls with issues: write / pull-requests: write permissions, draining the shared free-tier daily budget tracked by .github/actions/gemini-quota-gate/action.yml and denying the capability to maintainers. The Jules workflow header explicitly claims 'Issue triggers are restricted — untrusted openers cannot burn quota', which this dispatch path does not honor.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@timerloggedout-spec
timerloggedout-spec merged commit ace79a6 into master-staging Aug 7, 2026
13 of 21 checks passed
timerloggedout-spec added a commit that referenced this pull request Aug 7, 2026
Workflows-only promote from #75 (master-staging) so event triggers fire on the default branch.
Includes pr_number plumbing for comment triggers and RPD 900 quota gate.

Signed-off-by: Grok (ADE)

This branch was successfully deployed

1 active deployment
Preview — 88148782 Deployed Aug 7, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant