When I start a product, I open ChatGPT before I open a coding agent.

I want to work through the idea before anything starts creating files. Who needs this product? What belongs in the first version? What am I deliberately leaving out? I want to settle those questions while changing my mind still means editing a document.

Then I move between tools: ChatGPT for the requirements, Antigravity for the GitHub backlog, Copilot CLI for implementation, and Claude Code for review. I read the final pull request myself before deciding whether to merge. GitHub Actions carries the work through validation and deployment, with different triggers for previews and production releases.

I also want the same engineering setup when I switch tools or start another product. I use skills for that, and I created dotcraft, my plugin of skills and agents for .NET, Blazor, and MudBlazor. It gives me a reusable starting point instead of another setup to assemble.

My setup:

Work Tool Model or setting
Brainstorming and PRD ChatGPT GPT-6.1 Sol, high reasoning
Initial application logo ChatGPT PRD as context
Everyday work without a model preference GitHub Copilot Copilot Fusion
Epics and child issues Antigravity with GitHub CLI Gemini 3.8 Flash, high reasoning
Epic implementation GitHub Copilot CLI with dotcraft GPT-6.1 Luna (or Copilot Fusion), Max reasoning, YOLO mode
AI review Claude Code app or CLI Claude Opus 5.5
UI work Copilot or Antigravity with the relevant skills A deliberate choice: GPT-6.1 Sol, GPT-6 Astra, or Gemini Flash
Repeatable browser checks Playwright Automated user flows and assertions
Final review Me Read the code and check the behavior
Delivery and releases GitHub Actions CI, development previews, and production deployment

The model names will change. What I want to keep is the context: a decision made during the brainstorm needs to survive all the way to the code I merge.

Lately, Fusion is my default

I don't choose a model manually for every request. Lately, I use Copilot Fusion for most work where I don't already have a reason to pick a particular model. I give it the task and let it handle model selection.

Terminal model picker with Copilot Fusion highlighted and its tier set to Standard.

Copilot Fusion selected at the Standard tier in my model picker.

UI work is an example of when I do have a preference: I might specifically want GPT-6.1 Sol or GPT-6 Astra. That is when I make the choice myself. For the rest, Fusion has been working very well for me, and I have found it helps keep my token costs down. I haven't measured a fixed saving per task.

I switched to Copilot Fusion recently because I was experimenting with it during the Preview (it was called HydraFusion) but I was not enthusiast about the outcomes.

I keep the model and billing details in my GitHub Copilot guide in the Resources section of my website. The named-model handoffs below describe particular parts of my workflow; Fusion is what I increasingly use between those cases.

The PRD carries my decisions between tools

My ChatGPT conversation ends with a product requirements document, or PRD, in the repository. I use GPT-6.1 Sol with high reasoning to work through the scope before asking for that document.

"Users can export their data" is the sort of requirement I want to question here. Which data? Which format? Does it include archived records? If I leave those decisions open, the implementation agent has to make them for me.

I put the PRD somewhere every tool can read it, such as docs/PRD.md. If I change a requirement, I update the file. A decision that exists only in my ChatGPT conversation is missing context for the next session.

The PRD also gives me a starting point for the initial application logo. I use it in ChatGPT to explain the product and audience, ask for a few directions, and choose one before generating the image. At this stage, I care about whether the logo works in an application header and as a small icon.

Sometimes I also use the logo-generator skill by op7418. That is a separate skill I use alongside dotcraft.

Then I open Antigravity and ask Gemini 3.8 Flash with high reasoning to turn the PRD into epics and child issues through the GitHub CLI. In my experience, this step has been accurate and inexpensive. I still check the backlog before implementation starts.

This is a reusable version of the request:

Read docs/PRD.md and the repository instructions. Check existing issues and the applicable issue templates, including account defaults. Use the GitHub CLI to create epics and child issues. Each epic needs a product outcome and scope. Each child issue needs acceptance criteria, dependencies, and a reference to the relevant PRD section. Use native parent/sub-issue relationships. Do not invent requirements or create duplicates. Report unresolved decisions and return the created issue URLs. 

I don't need to create and link every issue by hand. I do need to check that the agent has preserved the scope. A backlog full of clear titles can still describe a different product from the one I intended.

I check all the Epics and Issues anyway and I fix something if I see something that I don't really like so much.\
I like also this approach because if something that AI implement and I don't like it, I can always rework on the single task or epic using the same description and prompt.\
It helps to obtain always the same outcome.

dotcraft is how I keep my setup with me

For my .NET products, I want business logic to live in the application services and component tests to follow the same conventions. Switching from Copilot to Claude Code should not mean explaining those choices again.

That is why I created kasuken/dotcraft. It packages skills I have written, adapted, or curated from other projects, together with agents for implementation, review, and cleanup. I can maintain the shared guidance in one place and reuse it across products.

The dotcraft logo and README tagline describing skills and agents for .NET, Blazor, and MudBlazor across Claude Code, Copilot, and Codex.

One shared setup for the .NET products I build. The repository also credits the skills' upstream sources.

For example, blazor-saas-stack describes my default architecture. bunit-testing provides guidance for component tests. dotnet-validate defines the verification expected before a change is called done. I don't want to paste all of those instructions into every implementation prompt.

The agents give the work separate roles: csharp-expert implements .NET changes, code-reviewer reads the result and reports findings, and janitor handles cleanup in small steps.

The dotcraft README listing the csharp-expert, code-reviewer, and janitor agents and their responsibilities.

The implementation agent is instructed to validate its changes and hand them to the reviewer. Those instructions still need to be checked against what happened in the session.

In Copilot CLI, I install the plugin with:

copilot plugin marketplace add kasuken/dotcraft copilot plugin install dotcraft@dotcraft 

dotcraft also documents installation for Claude Code and Codex. Each client needs its own setup; installing a plugin in Copilot does not configure Antigravity. For Antigravity, I make the relevant skills available in a supported skill location.

The product's own instructions take precedence over dotcraft's defaults. I keep project decisions in AGENTS.md and the instruction files the client recognizes, then check that the client has found them. In Copilot CLI, /instructions and /skills list help me inspect the setup. A skill appearing in the list establishes availability; I still check that it is loaded when the task needs it.

I also maintain kasuken/.github for shared issue and pull request templates. The feature request form asks for the problem before the proposed solution. The PR checklist asks for testing evidence and includes a check that the app still works with billing disabled.
Using this approach, I don't need to configure common things in all my repos and I increase the bootstrapping of a new project.

The shared pull request template's testing section and checklist, including operation with billing disabled.

The shared PR template gives me specific questions to ask of a change, including what happens when paid features are disabled.

GitHub supplies these supported defaults when a repository has no local equivalent. They are not copied into a clone, so a local agent may need to fetch them. I ask for that explicitly rather than assume a PR created through gh will contain the checklist.

DayPulse gave me a useful example

For DayPulse, one of my private projects, GPT-6 Sol produced the PRD and I gave it to Antigravity to create the backlog. The Today Screen epic had two child issues.

The first covered the localized date and the empty state when there was no check-in for the user's local day, with an action leading to /checkin. The second covered the completed check-in summary, including optional metrics, activities, notes, and navigation to edit or view the entry.

DayPulse's check-in screen with Very good +3 selected on the mood control, energy set to 7 out of 10, and bottom navigation.

DayPulse's check-in screen with mood and energy selected. Screenshot from my application.

That local-day requirement is a detail I care about. "Show today's check-in" leaves room for an implementation to use the server's date. Specifying the user's local day gives me something concrete to check in the code and tests. The summary issue also explicitly required disabled metrics to stay hidden.

I handed GPT-6 Luna with Max reasoning the whole epic in one request. I then asked Claude Opus 5.5 to review the implementation across the epic; it reported no findings.

The issue completion notes recorded 253 passing tests after the first child issue and 284 in the final Release validation, with no build warnings or errors. Those are reported validation totals, including existing tests. They are not counts of tests the agent wrote for those two issues.

For me, the useful result was being able to compare the implementation with those specific acceptance criteria. A review with no findings doesn't answer whether I asked for the right product behavior.

I hand Copilot an epic with a clear stopping point

For the explicit-model implementation route described here, I open Copilot CLI with dotcraft installed, select GPT-6 Luna with Max reasoning, and enable YOLO mode. Some single-issue runs have used around 10–15 Copilot credits in my experience; that is a rough observation, not a price to budget against.

My request covers the epic and its child issues, with a separate commit for each issue and one pull request at the end:

Implement the epic at <EPIC_URL> and all its child issues. Read the repository instructions, PRD, and applicable installed skills. Work on a dedicated feature branch and respect issue dependencies. Validate each child issue against its acceptance criteria. Automate repeatable browser flows with Playwright where applicable. Report automated coverage and anything that still needs a manual check. Create a coherent commit for each issue and reference its URL. Record completion and actual validation results on the issues. Close the epic only when every child issue is implemented and validated. Leave blocked work open and explain the blocker. Create a PR using the applicable template, including an issue-to-commit mapping, validation results, and remaining limitations. Do not merge the PR. 

One commit per issue lets me inspect the parts of the epic separately. In this workflow, closing the epic means implementation is ready for review; it does not mean the feature has shipped.

YOLO mode removes repeated approval prompts through Copilot's allow-all permissions. It does not make the commands safe. I am choosing to give the agent that permission, and I remain responsible for what it does.

After Copilot opens the PR, I ask Claude Code to review the implementation across the whole epic. I usually keep review fixes in that PR and rerun the affected checks if the code changes. I need validation for the version I am considering merging.

Then I read the final code myself and check the behavior against the requirements. That is where I decide whether to accept the work.

UI work gets a different route through the same process

For UI work, I want to choose the model myself when I have a particular result in mind. That might mean GPT-6.1 Sol or GPT-6 Astra in Copilot. I also use Antigravity with Gemini Flash, which has given me good UI results. I choose the tool and model for that piece of work, then return to Fusion when I have no reason to keep a specific model selected.

For the "general" UI and Design System I love the skill frontend-design because it helps AI to create the correct UI based on the context of the application and not the typical slop AI.

I bring in skills such as mudblazor-design-system, better-layout, and better-typography to make the request more specific. I also check keyboard and focus behavior. A screenshot helps me judge the layout, but I still need to use the form and see what happens in the empty state.

The requirements stay in the repository and the result still gets reviewed. Changing the tool for UI work should not mean losing the acceptance criteria I already settled.

I automate the repeatable browser checks with Playwright

I try to automate as much of the application testing as I can with Playwright. I don't want to click through the same screens manually after every change when a browser test can repeat the steps and check the result for me.

For a flow like DayPulse's check-in, I want the test to start from the empty Today screen, create an entry, verify the summary, edit the entry, and check that the updated values appear. Opening each page successfully isn't enough; the assertions need to cover the behavior in the acceptance criteria. This is the kind of repeatable journey I want automated as the product grows.

In Brainy, the CI workflow already has a separate Playwright end-to-end test job. It runs against the application with a real SQL Server database and is configured to upload traces and screenshots when tests fail. That gives me something to inspect when a browser test breaks, alongside the agent's explanation.

I still review whether the interface makes sense and explore behavior the tests don't cover. My aim is to spend that time on things that need my judgment, while Playwright handles the checks I would otherwise repeat by hand. I also review the tests: they need to fail when the expected behavior breaks.

I finish the backlog, then check the application as a whole

I repeat the implementation and review loop for the remaining epics in the release scope. Before calling that scope complete, I go back through the parent epics and their child issues. I want to see which PR contains the implementation, what was validated, and whether anything is still blocked or deliberately deferred.

An agent closing an epic is useful bookkeeping, but I still reconcile it with the merged code. If a child issue is incomplete, I leave it open. If I decide a feature belongs in a later release, I update the scope rather than close the issue as though it had been implemented.

I can ask an agent to help with that final pass:

Review the epics in the current release scope against the PRD, their child issues, and the merged pull requests. For each epic, report the implementation PRs, validation evidence, and any unmet acceptance criteria. Check the child issues themselves; do not rely only on the parent's checklist or closed status. Close remaining issues only when the implementation and validation support doing so. Leave blocked or deferred work open and explain why. Report any requirements that are missing from the backlog. 

Then I check the application across those epic boundaries, using automated browser tests for the repeatable journeys and manual checks for the remaining gaps. In DayPulse, the empty Today screen, the check-in form, and the completed summary need to work as one flow. Reviewing each screen separately would leave that journey unchecked.

The same applies to UI changes made late in the process: a better layout still needs to preserve navigation, validation, and the behavior described in the issues. I make corrections through the same issue and PR loop, so the fix gets reviewed too.

GitHub Actions gives me a development preview

I don't want deployment to depend on an agent remembering a sequence of terminal commands. I keep the build, test, and deployment steps in GitHub Actions so that the repository describes how the application gets published.

DayPulse is a concrete example. Its workflow runs a Release build and the test suite before the deployment job can start. For pull requests from the same repository, it is configured to publish the Blazor WebAssembly application to an Azure Static Web Apps preview environment. That gives me a development preview associated with the PR, before the change reaches production.

This is where I can check the published application in the browser. DayPulse is also a PWA, so I need to check installation, offline reload, and upgrades against a published build. The local development server alone doesn't cover those behaviors.

After I accept and merge the change, the push to main triggers DayPulse's build, test, and deployment workflow for production. Closing the PR also triggers cleanup of its preview environment. The automation handles the repeated publishing steps; I still check the workflow result and the deployed application.

Production releases have an explicit trigger

My server-hosted SaaS applications use a different production path. For Brainy, LearnStack, MoneyBrain, and Needly, I maintain a shared release workflow in kasuken/.github. Each application calls it from a small workflow in its own repository.

For these applications, merging to main runs CI without automatically deploying to production. I choose when to cut a release; GitHub Actions then handles the deployment. The distinction matters to me because several reviewed epics can belong to one release.

The release instructions let me choose a patch, minor, or major bump. For example, this starts a patch release for Brainy:

gh workflow run release.yml -R kasuken/Brainy -f bump=patch gh run watch -R kasuken/Brainy 

For that new-release path, the workflow resolves the next version, waits for passing CI on the commit being released, and builds a versioned application package. It deploys that package to Azure App Service through the GitHub production environment, using OIDC for Azure authentication.

Database changes are part of that delivery path too. Needly's migrations run before deployment; the other applications in this shared setup apply them on startup. I need to account for that difference when reviewing a release, especially if I might need to restore an earlier application version.

The workflow then checks the readiness endpoint, any configured extra pages, and the HTTP-to-HTTPS redirect. On the workflow-dispatched new-release path, it creates the version tag and GitHub release only after deployment and those smoke checks succeed. It uses the matching changelog section for the notes when one exists, or generates notes from the merged PRs.

That is another part of the setup I want to maintain once. An improvement to the shared workflow can serve several products, while the application repositories supply their own project paths and deployment targets.

After deployment, I still have a product to check

A passing readiness check tells me the application responds. I also want evidence that the user flow I intended to release still works. I use automated checks where that behavior is covered and focus my manual review on the remaining gaps. For DayPulse, the Today and check-in journey, including the local-day behavior, remains the reference for what needs checking in the published application.

If I find a problem, it goes back into an issue with reproduction steps and the behavior I expected. I can give that bounded task to an agent, review the correction, and send it through the same delivery process. The backlog remains useful after the initial implementation.

For applications using my shared release workflow, I can redeploy an earlier version tag when I need to roll back. That restores the earlier application code; it does not reverse database migrations. I need to check that the older version still works with the current schema before choosing that route.

This is where the workflow reaches a release: the code has been reviewed, the intended version has been deployed, and I have checked the relevant behavior in the running application. Closing all the epics gets me to that final check; it doesn't replace it.

I like working this way in Omarchy

In Omarchy, I keep the browser full-screen on one workspace and three or four terminals tiled on another. Copilot can be working in one terminal while I inspect tests or Git history in another. Switching workspaces and moving focus with the keyboard lets me keep those layouts in place.

Omarchy desktop with a browser, terminal, system monitor, and file manager arranged in four tiled windows.

Four-way tiling, shown in the official Omarchy navigation manual. This is the manual's example desktop.

I have tried to reproduce the same behavior on Windows. Getting the tiling, workspace switching, and window focus to feel the way I want has taken more effort there. On Omarchy, I spend less time rearranging the desktop.

The searchable clipboard history is useful when I am carrying an issue URL or prompt between tools. I also like the themes running through the terminal and supported agent clients. I like sitting down at this machine, and that matters when it is where I build my products.

Omarchy clipboard history filtered by the word reminder, with a matching command and its text preview.

Searching copied text, from the official Omarchy clipboard manual. The example shows how a copied command can be found again.

I still spend attention on the scope, the backlog, and the final review. dotcraft saves me from rebuilding the engineering setup, and GitHub Actions handles the repeated release steps. Neither can decide whether DayPulse should show that metric or whether a feature belongs in the first release. Those decisions are still mine, and I want to see them reflected in the application I publish.