I have been using a simple workflow for coding with AI agents.

The basic loop is:

idea

GitHub issue

implementation

pull request

independent review

squash merge

delete branch

repeat

The important part is that I use a fresh agent session for each step.

One session creates the issue.

Another session implements it.

Another session reviews the pull request.

GitHub becomes the shared memory between them.

Why I like this

I used to give an agent a task and let one long conversation handle everything.

That works, but the context slowly becomes messy.

The agent remembers its own decisions, assumptions, and mistakes. When it reviews its own code in the same session, it also knows what it meant to write.

Using separate sessions changes this.

The issue maker only needs to understand the request.

The solver starts from the issue and the repository.

The reviewer starts from the issue, the pull request, and the code.

Each role gets a clean context.

This costs some extra tokens because the repository has to be understood again, but I think the separation is usually worth it.

The three commands

My workflow has three commands:

/issue add keyboard shortcuts to the editor
 
/solve 42
 
/review 57

They correspond to three roles.

1. Issue maker

The first agent turns a rough idea into a small GitHub issue.

I want the issue to describe the goal and the definition of done without designing the implementation too early.

---
description: Turn a task request into a well-scoped GitHub issue
argument-hint: "<task description>"
---
 
Turn the following request into a GitHub issue for this repository:
 
$ARGUMENTS
 
Before creating the issue:
 
- Inspect only enough of the repository to understand the relevant area and existing conventions.
- Check open issues briefly to avoid creating an obvious duplicate.
- Preserve the user's intent. Do not invent unrelated requirements or expand the scope unnecessarily.
 
Write a concise issue with:
 
- A clear, specific title.
- Context / goal: what should change and why.
- Scope: what is and is not part of this task when useful.
- Acceptance criteria: observable conditions that make the issue complete.
- Constraints / implementation notes only when supported by the request or repository.
 
Keep simple tasks simple. Prefer concrete acceptance criteria over implementation prescriptions unless a particular implementation is required.
 
Create the issue with GitHub CLI. Then report the issue number, title, and URL.
 
Do not modify code, create a feature branch, or start implementing the issue in this session.

The last line matters.

The issue maker should not become the implementer.

Its job ends when the issue exists.

2. Issue solver

Then I start a fresh session.

The solver receives only an issue number.

---
description: Implement a GitHub issue and open a pull request
argument-hint: "<issue-number>"
---
 
Implement GitHub issue #$1 and open a pull request that resolves it.
 
Work autonomously, but keep the change narrowly scoped to the issue.
 
1. Read the issue and relevant repository context before editing. Treat the issue's acceptance criteria as the definition of done.
2. Inspect the relevant code, tests, and project instructions. Do not perform broad repository exploration unless needed.
3. Check the working tree. Never discard or overwrite unrelated local changes.
4. Fetch the latest remote state and base the work on the repository's current default branch. Create a dedicated branch with a concise issue-related name.
5. Implement the smallest coherent solution that fully satisfies the issue. Avoid unrelated refactors and dependency changes.
6. Add or update tests when appropriate. Run the relevant formatter, linter, type checker, tests, build, or other checks used by this repository. Fix failures caused by the change.
7. Review the final diff for correctness, accidental changes, debug artifacts, and unnecessary complexity.
8. Commit the completed work, push the branch, and create a non-draft GitHub pull request.
 
The pull request should:
 
- Link the issue using `Closes #$1`.
- Summarize what changed and why.
- List the verification/checks that were run.
- Mention any meaningful limitation or follow-up, if one genuinely exists.
 
Do not merge the pull request in this session.
 
If the issue cannot be completed safely because of a genuine blocker or materially ambiguous requirement, stop rather than guessing or creating a misleading completed PR. Explain the blocker concisely.

Again, there is a clear stopping point.

The solver creates the pull request but does not merge it.

3. Code reviewer

Finally, I start another fresh session.

This agent did not write the implementation.

Its job is to distrust it a little.

---
description: Independently review, fix, and squash-merge a pull request
argument-hint: "<pr-number>"
---
 
Independently review GitHub pull request #$1. Do not assume the implementation is correct just because another agent created it.
 
1. Read the PR, its linked issue(s), and the complete diff. Identify the intended behavior and acceptance criteria from the issue rather than trusting only the PR description.
2. Inspect enough surrounding code and tests to evaluate the change in context.
3. Review for:
   - Correctness and completeness against the linked issue.
   - Regressions and edge cases.
   - Missing or incorrect tests.
   - Unnecessary complexity or unrelated changes.
   - Error handling, security, concurrency, data-loss, or compatibility risks when relevant.
4. Fetch the latest remote state and check whether the PR cleanly integrates with its base branch.
5. If there are merge conflicts, resolve them on the PR branch while preserving both the current base-branch behavior and the issue's intent. Do not discard unrelated upstream changes.
6. If you find minor, clearly correct problems, fix them directly on the PR branch, add/update tests as needed, commit, and push the fixes. Then review the resulting diff again.
7. Run the relevant repository checks after any fixes and confirm required CI/checks are passing before merging. Do not bypass required checks.
 
Do not merge if you find a substantial design problem, unresolved correctness issue, ambiguous requirement that materially affects behavior, or failing required checks. Leave a concise PR comment explaining the blocker and report it to the user instead.
 
If the PR is correct after review/fixes and all required checks pass:
 
- Approve the PR if GitHub permits approval from the authenticated account. If GitHub disallows self-approval, do not treat that alone as a failure when approval is not required for merging.
- Squash-merge the PR.
- Delete the PR branch after the successful merge.
- Return the merged PR number and a short summary of any review fixes you made.

The reviewer is allowed to fix small problems.

But it should not quietly redesign a bad implementation and merge it anyway.

If there is a larger problem, the pull request stays open.

GitHub as shared memory

I think this is the main idea behind the workflow.

The agents do not need to share a conversation.

They share artifacts:

request

issue       ← intent

pull request ← implementation

review       ← verification

main

The issue explains why.

The pull request shows what changed.

The repository shows how the system currently works.

This gives each new agent enough information to continue without inheriting the previous agent’s entire context.

Is this overkill?

Sometimes.

For a typo or a one-line configuration change, creating an issue, opening a pull request, and starting three agents is probably unnecessary.

For those tasks I can use a shorter path.

small fix → PR → merge

But for changes that I care about, I like the longer loop.

issue → solve → review → merge

It gives me a useful history, clean agent contexts, and a natural checkpoint before code reaches the main branch.

There are more token-efficient ways to work.

For now, I prefer spending some extra tokens in exchange for clearer boundaries.

The workflow is boring, repeatable, and easy to understand.

That is probably why I keep using it.