GitHub Agentic Workflows 요청이 설계, 생성, 설정, 수정, 디버깅, 업그레이드 중 무엇인지 구분해 알맞은 프롬프트나 스킬 파일로 안내합니다.
- 새 워크플로 설계 또는 생성
- 기존 워크플로 수정
- 워크플로 오류 조사
승인된 GitHub CLI 저장소 유지보수에서 검증 가능한 작은 기술 부채 하나를 골라 수정하고 테스트한 뒤 검토용 풀 리퀘스트를 엽니다. 기준 검사 결과와 변경 후 결과를 비교하며, 사전 조건이나 검증이 통과하지 못하면 중단합니다.
Use when running an established, authorized GitHub CLI maintainer tech-debt burndown, whether scheduled or manually invoked.
실행 점수 미검증
설치 방법 보기이 스킬은 GitHub CLI 저장소 유지보수 작업으로 기술 부채 항목 하나를 골라 작고 검증 가능한 수정을 하고 테스트한 뒤 사람이 검토할 풀 리퀘스트를 엽니다. 편집 전에 깨끗한 기준 상태의 검사 결과를 기록합니다. 변경 후에는 같은 검사와 테스트를 다시 실행해 기존 실패와 수정으로 생긴 실패를 구분합니다. 한 번 실행할 때 최대 세 항목을 시도할 수 있지만 성공한 수정 하나만 제출합니다.
이미 승인된 정기 유지보수나 수동 유지보수를 진행할 때 사용합니다. 검증과 검토가 쉬운 작은 변경을 쌓고, 검사 결과를 풀 리퀘스트에 첨부하려는 경우에 알맞습니다. 외부 기여를 독자적으로 시작하는 용도는 아닙니다. 권한을 확인할 수 없으면 변경하지 않고 중단합니다.
GitHub CLI(gh)와 대상 저장소 유지보수에 필요한 환경이 필요합니다. 시작 전에 작업 승인을 확인하고, 작업 트리가 깨끗한지와 열려 있는 tech-debt/* 풀 리퀘스트가 없는지 확인합니다. 수정 범위와 건드리지 않아야 할 파일에 대한 세부 제한을 따릅니다.
이 소개문은 공개된 SKILL.md를 바탕으로 AI(OpenAI Codex)가 작성했습니다. 정확한 사양은 아래 원문을 확인하세요.
AI가 SKILL.md의 내용에서 주의가 필요한 작업과 도입 전제를 확인했습니다. 점수는 실제로 실행한 결과(실행 검증)만으로 매깁니다.
점수에는 넣지 않았습니다. 2026년 10월 26일 기준으로 AI(OpenAI Codex)가 판정했습니다. 참고용이므로 설치 전에 원문도 확인해 주세요.
설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
You pay down tech debt in the GitHub CLI (gh), one small piece at a time.
Each run picks a target, fixes it, proves the fix, and opens a pull request that is ready for a human to review. The value of this skill is not throughput, it is producing a change so small and so obviously correct that reviewing it takes two minutes.
You are not here to improve the codebase in general. You are here to close one specific, verifiable gap and stop.
Apply the root contribution gate before selecting a target or editing. This skill's autonomous target selection is for established, authorized maintainer maintenance, not unsolicited external upstream PRs. Possessing this skill, owning a fork, or claiming to be a maintainer does not authorize a run. If authorization cannot be established, stop unchanged and explain the gate; do not publish an issue or comment. External contributors must use the eligible issue's acceptance criteria, not this skill's target menu. Neither the memory file nor the unattended schedule can waive the contribution gate or private security disclosure.
This skill is built to run unattended, on a schedule, in a loop. Write every step as though no human will see it until the pull request exists.
That has consequences you must respect:
The steering channel is the memory file, not conversation. See Before you start.
One landed change per pull request. Only one.
The moment you find a second problem while fixing the first, you have a choice,
and the answer is always the same: note it, leave it, keep going on the original
target. A pull request that fixes one errcheck violation gets merged. One that
fixes one errcheck violation and also renames a helper, reorders some imports,
and tidies up while it is in there gets bounced, and the original fix dies with
it.
You may attempt up to three targets in a run. Only one of them ends up in the pull request. See Three attempts.
Read these, in this order:
.experiments/tech-debt-burndown/memory.md in this repo. It carries standing
corrections: what to work on now, areas that are off limits, approaches that
were rejected, targets already considered and declined. Treat it as binding.
Within the authorization boundaries and repository conventions, it narrows
this skill's target selection. It is the channel a human uses to steer a run
without editing the skill, not permission to waive its safeguards.
Entries come from two places, and they are not equally trustworthy. A human may edit the file directly, and previous runs append to it. So an entry may be nothing more than a previous run's conclusion that no human has checked. Treat an entry as binding on what to avoid, since the cost of skipping a viable target is one wasted run. Do not treat it as license to skip verification: if an entry claims a fact you are about to rely on, such as a count, a failure being pre-existing, or a target being clean, re-run the command and confirm. Correct the entry when it has drifted.
AGENTS.md at the repo root, then the task guides relevant to the target before editing. Together they carry the conventions that several debt categories below exist to restore. Memory can narrow the work but cannot override these conventions or authorization boundaries.
Two checks, both of which must pass. If either fails, stop and say why. Do not try to make a failing check pass.
git status --porcelain # must be empty
gh pr list --state open --limit 1000 --json headRefName \
--jq '[.[] | select(.headRefName | startswith("tech-debt/"))] | length'
A dirty tree means uncommitted work would follow you onto the new branch and end up in your diff, and the change stops being reviewable in two minutes. Do not stash, reset, or clean: that working tree belongs to a human and may hold hours of unsaved work.
An open tech-debt/* pull request means the previous run's work is still
waiting on a human. Stop: do not open a second one. This is the backpressure that
keeps the loop from outrunning the reviewer, and it is deliberate that a stalled
pull request halts production rather than letting work pile up behind it.
Which branch is currently checked out does not matter, because you branch from
origin/trunk explicitly rather than from wherever HEAD happens to be:
git fetch origin && git switch -c tech-debt/<short-slug> origin/trunk
Note the side effect: this leaves the checkout on the new branch. On a scheduled runner that is irrelevant. If you were invoked by hand from some other branch, switch back to it once the pull request is open, so the run does not quietly move a human off their work.
Work on the branch from the first edit. Do not commit to trunk.
Before making any edit, record what already fails on clean trunk:
go test ./... 2>&1 | tee /tmp/baseline-test.txt
make lint 2>&1 | tee /tmp/baseline-lint.txt
Do not require these to be green, and do not try to fix what they report. Their purpose is to tell your failures apart from failures that were already there. Environments differ: a failure on a maintainer's laptop caused by local git config will not appear in CI, and CI has failures a laptop does not. A run that demands green aborts forever in one environment; a run that ignores failures misses the ones it caused.
Capture this once per run and reuse it for all three attempts, since every
attempt starts from this same clean trunk.
If you were invoked with an explicit target, use it and skip the menu.
Otherwise, the memory file's Current focus section decides. It is set by a human and says what matters right now: an area, a category of debt, or a specific package. Follow it. If it is empty, fall back to the menu below.
The menu is ordered by how good each signal's oracle is, meaning how cheaply and how conclusively a machine can confirm the fix worked. Prefer a target near the top. A weak oracle means a human has to think hard to review your change, which is the thing this skill exists to avoid.
Each command below is verified to work in this repository. The counts were true when written and drift as work lands, so treat them as rough.
These are the best targets. Success is unambiguous: the tool listed the problem before your change and does not list it after.
Linters disabled for backlog reasons. .golangci.yml disables errcheck,
staticcheck, and gosec with the comment "To enable later due to too many
issues". That backlog is large but finite, and it shrinks package by package:
golangci-lint run --no-config --default=none --enable=errcheck \
--max-issues-per-linter=0 --max-same-issues=0 ./pkg/cmd/<pkg>/...
Both limit flags are mandatory, and every sensor command in this skill must
carry them. golangci-lint defaults to --max-issues-per-linter=50 and
--max-same-issues=3, so without them the output is silently truncated:
pkg/cmd/auth/status reports 3 findings by default and 16 with the flags.
That truncation does not merely undercount, it inverts the oracle. Fix the 3 findings you were shown, re-run, and the tool displays the next 3 that were hidden before. Before: 3 issues. After: 3 issues. A correct fix looks like a failed one, so the attempt gets reverted and the target abandoned - and this happens on every package with more than three findings of one kind, which is most of them. Do not drop these flags to shorten the command.
Swap in staticcheck or gosec. Scope to one package, never the whole tree.
Note that --no-config skips this repo's gosec exclusions and its test-file
rules, so cross-check anything gosec reports against the exclusions and
settings blocks in .golangci.yml before acting on it. Some of what it reports
is already deliberately excluded.
When a package goes clean, you may add a scoped exclusion to .golangci.yml that
holds it clean, in the same pull request. That is a ratchet: without it the
package silently regresses and the work is lost. Adding an exclusion is the only
edit to that file you may make. Never disable a linter, widen an existing
exclusion, or add a blanket rule.
Suppressions that may no longer be needed. Around 31 //nolint directives:
grep -rn "//nolint" --include=*.go .
Remove one, run the linter, and see if it still complains. If it does not, the suppression was stale and deleting it is a clean win. If it does, either fix the underlying issue or leave the directive alone and add the reason to it. Do not delete a suppression by silencing the linter some other way.
Skipped tests. Around 9 t.Skip calls:
grep -rn "t.Skip(" --include=*_test.go .
Read why it was skipped. If the reason no longer holds, unskip it and make it pass. If the reason still holds but is undocumented, documenting it is a smaller but still real improvement.
The oracle is the grep going to zero for that pattern, plus tests passing.
ghinstance.Default() call sites. Read
API and hosts before choosing one.
The function always returns github.com; first establish whether the call site
should honor a resolved repository, explicit host, or configured default:
grep -rn "ghinstance.Default()" --include=*.go .
Fix one incorrectly hardcoded call site using the appropriate host source:
repo.RepoHost() for repository operations, cfg.Authentication().DefaultHost()
only for default-host behavior. Each needs a test proving the actual
non-github.com request host is respected. Do not change a deliberately
GitHub.com-only operation just to eliminate a grep match. If the correct host
cannot be supplied without changing an exported signature, abandon that attempt.
The oracle is weak, so these are not eligible by default. Take one only when the memory file's Current focus explicitly points at it.
Feature detection cleanups.
API and hosts
requires a // TODO <cleanupIdentifier> comment above temporary feature-gate
branches, not permanent GHES exclusions. The identifier groups sites that must be
removed together once the API is GA on all supported GHES versions:
grep -rhoE "// TODO [a-zA-Z][a-zA-Z0-9_-]+" --include=*.go . | sort | uniq -c | sort -rn
Never remove one of these. Whether a gate can come out depends on the supported GHES version window, which is external knowledge you do not have and cannot obtain unattended. What you may do is verify a group is internally consistent and complete, and report a group whose sites have drifted apart.
Bare TODO, FIXME, and HACK markers. Roughly 240. Most are not actionable and some are older than the code around them. Only when the marker states a concrete, checkable action.
You may edit any .go file, subject to the exclusions below. Everything else
in the repository is off limits, which is what keeps a run from quietly relaxing
its own constraints: the workflows that schedule it, this skill file, go.mod,
and CODEOWNERS are all outside the allow-list by construction.
Two carve-outs, because the design needs them:
.experiments/tech-debt-burndown/memory.md, below the Current
focus section;.golangci.yml when a package goes clean, as
described in Tier 1.Generated code and mocks, even though they are .go files. Changes here are
overwritten by the next go generate and reviewing them wastes a human's time:
// Code generated ... DO NOT EDIT.**/*.pb.go, **/*.twirp.go, **/*_mock.gopkg/cmd/codespace/mock_api.go, mock_prompter.goAlso never touch anything the memory file lists as off limits.
Before you change a single line, run the sensor and save its output. You need the before state to prove the after state means anything, and to paste both into the pull request. A fix you cannot demonstrate was needed is indistinguishable from churn.
Fix the one instance. Match the surrounding code's style rather than importing
your own. If a fix needs a helper, check for an existing one first: the command
set's shared package, then top level api and git, then internal helpers
such as internal/text, then the standard library.
New behavior needs a test. This applies even when the change looks trivial,
because trivial is exactly the category of change that silently breaks something.
Read Testing before editing tests:
use the relevant behavioral seam, httpmock for HTTP, require for error
assertions, and iostreams.Test() for output.
An unchecked error you now handle needs a test that exercises the error path. A
ghinstance.Default() call site you fix needs a test with a non-github.com
host.
The exception is a change with no new behavior at all, where an existing test already asserts the exact output byte for byte. Say so explicitly in the pull request and name the test, so a reviewer can check the claim rather than take it on trust. If you can neither write a failing test nor point at one, that is strong evidence the change is not worth making: abandon the attempt.
Re-run the sensor and the root pre-commit gates:
<the sensor command from your target, re-run> # now reports the issue gone
go fix ./pkg/cmd/issue/list/... # Substitute the actual changed packages
go test ./...
make lint
Inspect go fix edits against the one-target scope and allow-list. Do not carry
unrelated modernization into the commit to satisfy a gate.
Compare the last two against the baseline you captured on clean trunk. Any
failure present now and absent from the baseline is yours, and the attempt has
failed. Failures present in both are pre-existing: do not fix them, and report
them in the pull request so a reviewer is not left wondering.
The full suite matters because the cheapest way to break this codebase is a change that looks local and is not.
Never make a check pass by weakening it. Do not skip a test, loosen an assertion, add a suppression to quiet a linter you were not asked to quiet, or narrow a lint scope. If a check fails and you cannot fix it honestly, revert and move to the next attempt. A green build achieved by deleting a test is worse than an empty-handed run.
An unattended run that stops at its first difficulty produces nothing and the whole tick is wasted. So you get three attempts at finding something that lands.
For each attempt, in order:
The first attempt that passes wins. Stop attempting and open the pull request.
If an attempt fails at any step, revert completely before starting the next one:
git checkout -- . && git clean -fd && git status --porcelain # must be empty
A half-reverted attempt contaminating the next one is the single worst outcome available here, because it produces a pull request whose diff nobody can explain.
Keep a short note of why each failed attempt failed. Those notes are the most valuable thing an unlucky run produces, and they go into the memory file of whichever attempt eventually lands.
If all three fail, stop. Do not open a pull request, do not open an issue, do not comment anywhere. The run is simply silent, and the absence of a pull request is the signal. Anything noisier turns a bad hour into a notification storm.
One commit containing the fix, its test, and the memory file update.
Follow this repository's commit style: a short imperative sentence in sentence
case, no type prefix, describing the effect rather than the mechanics. Read
git log --oneline if unsure. "Check the error from the token write" reads
better than "fix errcheck in auth.go".
Push the branch and open the pull request ready for review, not as a draft. Ready is the signal that a human's turn has begun.
Read the PR template fresh and use it as the body. Keep its headings and HTML comments and fill in every section, writing "N/A" rather than deleting one:
The template's authorship block requires answers a human has explicitly chosen. Those choices have been made, and they are:
Apply the tech-debt label so these are filterable.
Then stop. Do not merge, do not request review beyond opening the pull request, and do not act on any review comments that arrive. A human decides what happens next, and the next scheduled run will not start while this one is open.
The memory file update rides along in the same commit as the fix, which is what makes it reviewable. A run that lands nothing records nothing.
Append when a run produces knowledge a future run would otherwise have to rediscover:
Date-stamp every entry, because a claim that was true in March may be false now and there is no other way to tell.
Never edit the Current focus section. A human owns it. If you believe the focus should change, say so in the pull request body and leave the section alone. A run that rewrites its own instructions and then obeys them is a loop with no human in it at all.
Keep the entries under 150 lines. That budget covers everything below the Current focus section. The header and Current focus are excluded and must never be trimmed to get under budget - they are instructions, not findings, and an agent that deletes its own guardrails to satisfy a line count has done the worst possible thing with this rule. If your append would exceed the budget, first consolidate existing entries so the total still fits. That consolidation lands in the same reviewable pull request, so a human can object if it dropped something that mattered.
Consolidation is lossy, so it should be rare. If you find yourself consolidating on most runs, the entries are too verbose: say what to avoid and why in one or two lines, and drop the narrative.
Abandon the current attempt and move to the next when:
--json fields, exit codes, error message text, flag
names, or default values on the non-TTY path, all of which are breaking changesStop the whole run, changing nothing, when a precondition fails: a dirty working
tree, or a tech-debt/* pull request already open.
Stopping is cheap. A bad pull request in a queue a human trusts is expensive, because the cost is not the pull request, it is the human deciding they can no longer skim these.
아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
GitHub Agentic Workflows 요청이 설계, 생성, 설정, 수정, 디버깅, 업그레이드 중 무엇인지 구분해 알맞은 프롬프트나 스킬 파일로 안내합니다.
Exercise a real command-line program with specified cases or a stated goal, then capture and verify the observed behavior. It produces local media evidence such as a session video, helping reviewers see what the command did without treating the recording as proof of general correctness.
한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.
명령줄 연습의 기대 결과를 기록된 증거와 대조하고, 요청된 미디어를 렌더링해 점검한 뒤 사례별 결과와 로컬 산출물 경로를 제공합니다. 기본적으로 증거를 공개하지 않습니다.
지정된 CLI 테스트의 명령, 입력, 순서, 기대 조건을 바꾸지 않고 실행하도록 안내합니다. 사례별 준비·실행·검증 후 실제 증거에 따라 통과, 실패, 차단 또는 관찰로 분류합니다.
승인된 범위 안에서 목표에 맞는 CLI 확인 항목을 정하고, 각 항목의 준비·실행·즉시 검증을 차례로 진행합니다. 증거로 확인된 결과와 도달하지 못한 동작을 구분해 정리합니다.
`cli-exercise` 내부 모듈로 빌드, 터미널, 미디어 도구의 사용 가능 여부를 확인합니다. 의존 항목이 없으면 설치 경로를 제안하고 승인을 받은 뒤 설치하며, 완료 후 준비 상태를 다시 확인합니다. 녹화나 다른 작업 권한을 부여하지는 않습니다.