Use this skill when CI feedback is too expensive and the current task needs a focused GitHub Actions signal instead of automatic full CI.
The preferred mechanism is the formal workflow_dispatch input in .github/workflows/ci.yaml:
gh workflow run ci.yaml --ref <branch> -f 'ci_filter=<filter>'
Do not temporarily hack workflow jobs just to get partial CI unless the formal filter cannot express the target.
1 Filter Syntax
full
job_id
job_a,job_b
job_id[dimension=value]
job_id[dimension=value|other_value,other_dimension=value]
job_a,job_b[dimension=value]
fullor*runs the normal full CI plan.job_idruns the whole job, including its full matrix if it has one.job_id[...]runs only matching matrix entries.- Bracket filters currently require
dimension=value. - Commas outside brackets combine multiple jobs.
- Explicit
dimension=valueconditions inside brackets are ANDed. |means OR within one dimension.- Matrix dimensions include direct keys such as
image,package,device,api-level,sanitizer,platforms, and nestedmatrix.infokeys such asplatform,target,version. - Numeric matrix values are matched as strings, e.g.
api-level=35. - Values may contain spaces, e.g. iOS simulator device names.
- Unknown jobs, unknown dimensions, malformed filters, and filters matching no matrix entries fail in the
Plan :: CIjob.
2 Manual Dispatch Label
Use the ci-manual-dispatch PR label when an agent or human wants to prevent automatic PR CI from running the full surface while iterating.
gh pr edit <pr-number> --add-label ci-manual-dispatch
With the label present:
- normal PR-triggered CI produces an empty plan for the heavy jobs
workflow_dispatchremains available for explicit focused runs- the PR must not be treated as merge-ready from partial runs alone
Before final readiness:
gh pr edit <pr-number> --remove-label ci-manual-dispatch
Then let the normal full CI surface run. Removing the label triggers PR CI because the workflow listens to labeled and unlabeled pull request events.
3 Manual Dispatch PR Comment
Manual workflow_dispatch runs of .github/workflows/ci.yaml comment from Plan :: CI on the matching open PR with the selected ci_filter and run link; normal push and pull_request runs do not comment.
4 Local Planning
Before dispatching an expensive manual run, smoke the filter locally:
./frb_internal plan-ci --filter 'test_dart_web[package=frb_example--pure_dart_pde]'
The command emits a GitHub Actions output line:
plan={...}
The workflow consumes it with paths like:
fromJSON(needs.plan_ci.outputs.plan).test_dart_web.enable
fromJSON(needs.plan_ci.outputs.plan).test_dart_web.matrix
That output shape is intentional; each CI job has its own top-level entry containing enable, and matrix jobs also contain matrix.
5 Repeated Precise Validation
Use repeated precise validation when a flaky fix needs several independent executions of one CI job or matrix entry on exactly the same commit.
- Fix the commit: Push the branch once, record its SHA, and do not move the branch until all runs finish.
- Smoke the filter: Run
./frb_internal plan-ci --filter '<filter>'before dispatching. - Dispatch independently: Create five separate
workflow_dispatchruns, not one run with five matrix copies and not five attempts of one run. - Keep the filter identical: Pass the same exact
ci_filterto every dispatch. - Verify the SHA: Confirm every selected run reports the recorded
headSha; a branch name alone is not evidence that queued runs used the same commit. - Count target jobs: Count the conclusion of the selected job or matrix entry, not the workflow conclusion or skipped jobs.
- Preserve every run link: Report all five run URLs, the fixed SHA, the filter, and the target-job result.
- Do not move or cancel: A new commit invalidates the comparison; cancellation does not count as a completed validation.
Record the immutable input:
branch=codex/example-fix
expected_sha=$(git rev-parse HEAD)
filter='test_dart_web[package=frb_example--pure_dart]'
git push -u origin "$branch"
Dispatch five independent runs. Manual dispatches use unique concurrency groups, so these runs do not cancel one another:
for run_number in 1 2 3 4 5; do
gh workflow run ci.yaml --ref "$branch" -f "ci_filter=$filter"
done
List the candidate runs once, then select the five runs created for this validation window:
gh run list \
--workflow ci.yaml \
--branch "$branch" \
--event workflow_dispatch \
--limit 10 \
--json databaseId,createdAt,headSha,status,conclusion,url
For each selected run:
- Confirm
headSha == expected_sha. - Confirm
Plan :: CIcreates only the requested job or matrix entry. - Wait for the target job to complete.
- If it fails, archive and inspect that job's complete log.
- Report a result only after all five target jobs finish.
Do not claim “5/5” from any of these shapes:
- One workflow run containing five matrix entries.
- One workflow run rerun five times.
- Five workflow runs whose
headShavalues differ. - Five workflow conclusions where the target job was skipped, cancelled, or never started.
- Fewer than five completed target jobs plus queued or in-progress jobs.
6 Examples
These examples are protected by tools/frb_internal/test/ci_plan_test.dart; update that test whenever adding or changing examples here.
Full CI:
gh workflow run ci.yaml --ref <branch> -f 'ci_filter=full'
One non-matrix job:
gh workflow run ci.yaml --ref <branch> -f 'ci_filter=lint_dart_primary'
Several whole jobs:
gh workflow run ci.yaml --ref <branch> -f 'ci_filter=lint_dart_primary,test_dart_web'
One non-matrix job plus one matrix entry:
gh workflow run ci.yaml --ref <branch> -f 'ci_filter=lint_dart_primary,test_dart_web[package=frb_example--pure_dart]'
One Dart web package:
gh workflow run ci.yaml --ref <branch> -f 'ci_filter=test_dart_web[package=frb_example--pure_dart_pde]'
Two Dart web packages:
gh workflow run ci.yaml --ref <branch> -f 'ci_filter=test_dart_web[package=frb_dart|frb_example--pure_dart_pde]'
Two Dart web packages plus one non-matrix job:
gh workflow run ci.yaml --ref <branch> -f 'ci_filter=test_dart_web[package=frb_dart|frb_example--pure_dart_pde],lint_rust_primary'
Two precise matrix tuples in the same job:
gh workflow run ci.yaml --ref <branch> -f 'ci_filter=test_rust[image=ubuntu-latest,version=nightly],test_rust[image=ubuntu-latest,version=1.85.0]'
One Dart native package on Linux:
gh workflow run ci.yaml --ref <branch> -f 'ci_filter=test_dart_native[image=ubuntu-24.04,package=tools--frb_internal]'
Rust tests on selected toolchains:
gh workflow run ci.yaml --ref <branch> -f 'ci_filter=test_rust[image=ubuntu-latest,version=nightly|1.85.0]'
One Flutter desktop package on Linux:
gh workflow run ci.yaml --ref <branch> -f 'ci_filter=test_flutter_native_desktop[platform=linux,package=frb_example--gallery]'
One Android emulator matrix entry:
gh workflow run ci.yaml --ref <branch> -f 'ci_filter=test_flutter_native_android[package=frb_example--flutter_via_create,device=pixel,api-level=35]'
One iOS simulator matrix entry:
gh workflow run ci.yaml --ref <branch> -f 'ci_filter=test_flutter_native_ios[device=iPhone 16 Pro Max Simulator (18.6),package=frb_example--rust_ui_counter--ui]'
One codegen command-generate entry:
gh workflow run ci.yaml --ref <branch> -f 'ci_filter=generate_run_frb_codegen_command_generate[image=ubuntu-24.04,package=frb_example--integrate_third_party]'
One OHOS command-integrate entry:
gh workflow run ci.yaml --ref <branch> -f 'ci_filter=generate_run_frb_codegen_command_integrate[platforms=ohos]'
One sanitizer entry:
gh workflow run ci.yaml --ref <branch> -f 'ci_filter=test_dart_sanitizer[sanitizer=asan,package=frb_example--pure_dart]'
One benchmark runner:
gh workflow run ci.yaml --ref <branch> -f 'ci_filter=bench_dart_native[image=ubuntu-24.04]'
7 Choosing Evidence
For intentional red reproduction PRs:
- Run only the single job or matrix entry that proves the reported bad behavior.
- State the exact
ci_filterin the PR body. - State the expected failure text or behavior.
- Do not treat the narrowed red run as fix readiness evidence.
For ordinary iteration branches:
- Prefer the smallest filter that exercises the changed behavior.
- Say in PR status/comments when only filtered CI has run.
- Before final review or merge readiness, remove
ci-manual-dispatchand run normal CI.
8 Validation
Before pushing changes to the filter mechanism or examples:
cd tools/frb_internal
dart test test/ci_plan_test.dart
Useful smoke check:
./frb_internal plan-ci --filter 'test_dart_web[package=frb_example--pure_dart_pde]'