Modern development often starts with good intentions: a quick script, a prototype, maybe an action to automate one small thing. But as projects evolve, those early efforts can become brittle. What if you could bring clarity and structure to those projects without slowing down your momentum?
This tutorial shows how we used GitHub Copilot coding agent to refactor and enhance a personal GitHub Actions project called validate-file-exists
. What started as a patchwork utility became well-structured, test-covered, documented, and set up for success with Copilot agent mode and coding agent.
We’ll walk through my example of:
- Updating Copilot custom instructions for better task alignment.
- Creating the
copilot-setup-steps.yaml
file to give the coding agent the needed tools in its environment. - Working with Copilot to identify technical debt.
- Collaborating with Copilot in pull requests.
- Partnering with Copilot to iteratively improve the UI on a separate project.
The GitHub Action that started it all
Back in November 2024, I created a small GitHub Action called validate-file-exists
. I wanted to ensure certain files (like a dependabot.yml
file, or .github/copilot-instructions.md
) were present in a repository. If not, then the GitHub Actions workflow would fail. It supported comma-separated inputs and was meant to be part of a larger “baseline” of quality gates I use across projects.
It was functional, but I could have improved it further. It was missing docs, had inconsistent metadata, some gaps in input validation, and didn’t have Copilot custom instructions or Copilot setup steps to help set Copilot up for success. Time to fix that—with help from Copilot agent mode in VS Code.
Step one: Improve custom instructions
Before bringing in the agent, I reviewed the existing copilot-instructions.md
. It was sparse, without any description of the repository’s purpose, usage, or structure, nor any clear guidance for Copilot.
Action:
I based the instructions on best practices for using Copilot to work on tasks, by providing the sample custom instructions file in my prompt, and asking Copilot to update based on the codebase. In other words, I wanted it to provide:
- A clear summary of the repository/codebase and what the action does.
- Contribution guidelines (how to build, format, lint, and test the codebase, including expectations before committing).
- Project structure overview.
- Key technical principles (strict TypeScript, incorporating TSDoc, and focused and manageable functions).
Result:
Copilot had the right context on my expectations to guide it toward meaningful contributions. You can find the latest version here, but here’s a snapshot below:
# Validate File Exists Action
This is a TypeScript-based GitHub Action that validates whether specified files
exist in a repository. It takes a comma-separated list of files and validates
their existence, failing the workflow if any files are missing. Please follow
these guidelines when contributing:
## Code Standards
### Required Before Each Commit
- Run `npm run format:write` to ensure consistent code formatting with Prettier
- Run `npm run lint` to check for ESLint violations
- Run `npm run test` to ensure all tests pass
- Run `npm run local-action` to test the action locally with a `.env` file
### Development Flow
- Build: `npm run package` (compiles TypeScript and bundles with ncc)
- Test: `npm run test` or `npm run ci-test`
- Coverage: `npm run coverage` (generates coverage badge)
- Full check: `npm run all` (format, lint, test, coverage, package)
- Local testing: `npm run local-action` (test action locally with .env file)
## Repository Structure
- `src/`: Core TypeScript source code
- `main.ts`: Main entry point and action orchestration
- `fileValidator.ts`: Core file validation logic
- `index.ts`: Action entrypoint that calls run()
- `types.ts`: TypeScript type definitions
- `__tests__/`: Jest unit tests for all source files
- `dist/`: Compiled and bundled JavaScript output (generated)
- `action.yml`: GitHub Action metadata and interface definition
- `script/`: Release automation scripts
- `badges/`: Generated coverage and status badges
## Key Guidelines
1. Follow TypeScript strict mode and best practices
1. Use clear, descriptive variable and function names
1. Add TSDoc comments for all public methods and classes
1. Write comprehensive unit tests using Jest for all new functionality
1. Keep functions focused and manageable (generally under 50 lines)
1. Use consistent error handling with @actions/core.setFailed()
1. Validate inputs and provide meaningful error messages
1. Use @actions/core for all GitHub Actions integrations (inputs, outputs,
logging)
1. Maintain backwards compatibility for action inputs/outputs
Step two: Add copilot-setup-steps.yaml
Like any of us developers, Copilot coding agent needs a proper environment to work. That means setting up any required frameworks, installing dependencies, and making sure Copilot has access to the right tools to get the job done.
Action:
I created .github/copilot-setup-steps.yaml
using the GitHub docs on customizing the development environment for Copilot coding agent. The example checks out the code, sets up Node.js, and installs the needed dependencies. Given this is a TypeScript action, that’s pretty much all I needed!
I made one minor change to the workflow: changing the node-version to be sourced from the .node-version
file, to be consistent with my CI workflow:
- name: Setup Node.js
id: setup-node
uses: actions/setup-node@v4
with:
node-version-file: .node-version
cache: npm
Result:
Copilot coding agent has the needed dependencies and tools to build, lint, and test the codebase. As it makes changes to the codebase, it will be able to check for quality (as requested in our custom instructions) using the tools that were installed in the copilot-setup-steps.yml
.
Step three: Let Copilot find technical debt
With the setup steps and custom instructions in place, it was time to find a task. So of course, I turned to Copilot. Using Copilot Chat in VS Code, we asked Copilot:
“What technical debt exists in this project? Please give me a prioritized list of areas we need to focus on. I would like to create a GitHub Issue with the top 2 or 3 items. Please include a brief problem statement, a set of acceptance criteria, and pointers on what files need to be added/updated.”
Within minutes, it explored the codebase and came back with a list of suggestions:
- Inconsistent package metadata.
- README mismatches (wrong input names).
- No validation for empty or malformed inputs.
Notice how we asked for a problem statement, acceptance criteria, and guidance on the files to add/update? These come from the best practices for using Copilot to work on tasks. In other words, make sure your issues are well-scoped!
Action:
I asked Copilot to write an issue that addresses those three items. Once I created the issue, I assigned it to Copilot.
Step four: Copilot coding agent in action
Once assigned, the agent kicked off a new pull request. Here’s what it did, asynchronously:
- Explored the contents of the repository to build up its understanding of the problem.
- Created a plan based on its exploration.
- Fixed the
package.json
name, description, URLs, and author field. - Updated the README usage examples to match the code.
- Added input validation logic:
- Reject empty or whitespace-only strings.
- Reject inputs that are just commas.
- Wrote four new tests for these edge cases.
- Confirmed linting, formatting, and coverage were intact.
- Updated the pull request body with a checklist of work completed.
As I delegated the task to Copilot, it freed me up to explain to the audience what it was doing, and how the Copilot setup steps and instructions work in the context of the agent’s session.
Result:
Copilot completed all tasks in just over 11 minutes. After a review of the agent’s approach, I approved the CI workflow so that it could run the standard quality checks on the codebase. The workflow failed, but through no fault of Copilot. I had some additional Markdown linting checks in the CI that weren’t in the instructions.
Real-time debugging and linting fixes
While I could have fixed it manually, it was a good opportunity to show how we can iterate on changes with Copilot. I added a new comment to the pull request, and asked Copilot:
“Our GitHub Action had a linting error for the markdown, can you fix that please?” (Also pasting the error from the GitHub Actions workflow.)
A few minutes later, it updated the code, pushed a new commit, and the pull request passed. And while Copilot was working on my task in the background, I was able to wrap up the stream.
Bonus: Making UI changes with Copilot coding agent and the Playwright MCP server
While Copilot worked on the initial code changes for the GitHub Action, I showed off a second project: a Trend Radar visualisation app (here’s the repository) that I built using Next.js and Tailwind CSS.
Problem:
Users had to manually input point data into forms. I wanted to:
- Let users click on the radar to place a point.
- Enable drag-and-drop repositioning to change a point’s category or likelihood.
Solution:
I filed a GitHub issue describing the UX, acceptance criteria, and references.
After a few iterations of comments by working through the pull request, Copilot coding agent:
- Implemented click-to-place logic.
- Added drag-and-drop support.
- Wrote unit tests.
- Took screenshots and attached them to the pull request.
- Updated the pull request (and responded with comments) with summaries of the work that had been completed
Playwright is now installed by default with the Copilot coding agent, which lets Copilot validate visual behaviors too.
Final thoughts
This wasn’t just a cleanup session. It was a lesson in modern software collaboration. Copilot coding agent is our new teammate.
By structuring our repositories with context and intent, we invite Copilot to contribute meaningfully.
If you haven’t tried Copilot coding agent yet, think through your existing projects:
- Clean up an old GitHub Action.
- Refactor a neglected repository.
- Add validations and tests.
You might be surprised how much progress you can make in an afternoon.
- Write clear, concise
copilot-instructions.md
to steer the agent. - Use
copilot-setup-steps.yaml
to give the agent the tools it needs. - Setting a clear and well-scoped piece of work is important when working with Copilot.
- Copilot now has access to a browser, thanks to the Playwright MCP server – enabling it to interact with web pages, and add screenshots to the pull request.
- You don’t have to work on new projects to try out Copilot and its agentic capabilities. Which existing project could you get started on?
Ready to explore more? See how the GitHub billing team uses the coding agent to continuously burn down technical debt >
The post From chaos to clarity: Using GitHub Copilot agents to improve developer workflows appeared first on The GitHub Blog.
Source: Read MoreÂ