Anthropic’s write-up gives a great bird’s-eye view, but real headaches usually pop up the moment theory meets an actual codebase. So, in this article we’ll tackle a single, humble project together – starting small and layering on each best practice one step at a time. Every tip is tied to runnable code, so you can see the trade-offs, stumble into (and fix) the same pitfalls, and watch the project grow just like real software does. By the end, you’ll have not only read the guidelines – you’ll have a living, working reference you can drop straight into your own stack.
Reading their article first is highly recommended. However, I will be mentioning some of their explanations and recommendations in this article as well, even though, the focus here is on a practical hands-on guide for how to use and implement everything.
The Project
What better way to learn every concept that Anthropic touched on than to actually start using them in a real-life project! This is what we will attempt to do here.
The project used to showcase all the techniques in this article is a small expense tracker with manual data entry and basic categorization that we try to grow into comprehensive financial management system with:
A quick heads-up: this guide assumes you already speak “developer.” I won’t be pausing to teach Python, JavaScript, or any other language, walk you through installing toolchains, or coach you on virtual-env gymnastics. Likewise, I’ll take it for granted that you know your way around MCPs, LLMs, and the general AI plumbing behind them. If you’re brand-new to those topics, you might want to bookmark this article for later and grab a primer first – because here we’ll be diving straight into the project work, not the classroom basics.
Concepts and Techniques to be Covered
Anthropic touched on the following beginner and advanced concepts/techniques in agentic coding, all of which we will try to cover with a practical example:
Customizing the Setup
Creating Claude.md files
Tuning the Claude.md files & prompt improver
Curating Claude’s list of allowed tools
Installing the GitHub CLI (if GitHub is being used)
Custom Slash Commands
Providing More Tools for Claude
Bash Tools
Claude + MCP
Trying out Common Workflows
The “Explore, plan, code, commit” workflow
“Write tests, commit; code, iterate, commit”
“Write code, screenshot result, iterate”
“Safe YOLO mode”
“Codebase Q&A”
Using Claude to interact with git and/or GitHub
Using Claude to work with Jupyter Notebooks
Workflow Optimization
Specific instructions
Providing images to Claude
Mention files for Claude to work with explicitly
Give URLs to Claude
Course correct early and often
Keep the context focused
Checklist and Scratchpads for complex workflows
Passing Data into Claude
Headless Mode and Infra Automation
Issue Triage
Linter
Multi-Claude Workflows
Claude A writing code; Claude B verifying code
Multiple checkouts of a repository
Git Worktrees
Headless mode with custom harness
Some of these tricks are quick wins – think tweaking your Claude.md or adding a couple of custom slash commands – while others take a bit more elbow grease, like wiring up a head-less multi-Claude CI harness or juggling multiple git worktrees. The cool part is that every step up the ladder pays off: the easy stuff gives you faster feedback right away, and the heavyweight setups unlock tighter loops, richer context, and cleaner code down the line. Even if you only adopt a handful, each one stacks on the last, turning Claude from “handy helper” into a full-on force multiplier for planning, building, and polishing your projects.
Simple Claude Usage
What we mean by simple claude usage is how a naive user would start using the tool – by just explaining what we want. This is not a terrible approach per se and we believe Anthropic intends to make the tool be used in this exact way, allowing English to become the ultimate programming language. However,
The initial prompt (you will find all my prompts formatted in a similar fashion):
Using Python as the backend and React.js as the frontend, create a simple expense tracker with manual data entry and basic categorization.
Branch: #001
It will ask for approval on on every command it attempts to run for the first time:
After it was done:
At the end of this command, this is the structure Claude provided for us (and going forward, this will be in every branch, in the directory-listing.txt file at the root of the repository):
We will not be stopping to take a deeper look at what was generated for us, but if you wish you could find every milestone pushed to a branch of its own – that is now sitting in the #001 branch.
Interact with Git
To showcase interacting with git, let’s ask Claude to commit and push the changes into our repository. For consistency, we will use this throughout every step of the article even though it will not be explicitly mentioned.
Notice how we were asked to approve the use of the “git commit” bash command. This can easily become annoying, especially if you, like me, tend to give Claude a command and look away for some time while Claude is cooking. This blends nicely into the next concept we are going to cover.
Claude List of Allowed Tools
As per Anthropic’s article, Claude is deliberately designed with a conservative approach in mind to prioritize safety. What this means for us, is that we will be often asked to approve Claude’s actions which can easily become annoying. Let’s pick one of the four ways to curate Claude’s list of allowed tools – we consider the /allowed-tools slash command to be the easiest way to achieve your goals (alternative would be to just choose always allow when prompted by Claude, but this approach is more collaboration-friendly as you will see).
It allows for “Allow” and “Deny” type of rules to be added – actions that will automatically be accepted or rejected by Claude. Let’s add an Allow rule for “git commit”. You will be asked to save this rule in either Local Project Settings or Project Settings. The Project Settings option will be chosen here, since it is a great way to check this into source control and make it available to the whole team.
As of today (26 Apr 2025), I have found that this method of adding the settings is not creating the settings.json file for me in the .claude folder. However, by the time you are reading this article this bug may be patched so make sure you attempt to do it this way. As a workaround, we will be manually creating the .claude folder with the setting.json file inside. Equivalently, it will have a content as follows:
Note that going forward in the article, different tools may be added in either section (as allowed or denied tools), but they won’t be explicitly mentioned in the article. If you want to track them look at this file in the different branches, as it will be added to the versioning.
Codebase Q&A
All good so far! But we have not even seen what Claude generated for us. Let’s run the code! And since Claude never told us how to, let’s ask it to find out:
How to start this project locally?
That’s awesome! The frontend seems to be running without any issue by just following these instructions and this is what it looks like:
However, the backend doesn’t seem to be working correctly. Under python version 3.12, the following error is observed:
ImportError: cannot import name 'url_quote' from 'werkzeug.urls'
This is fine! Now we have a chance to take a look at some other Claude Code techniques.
Safe YOLO Mode
Let’s use the safe YOLO mode as our first common workflow. In the end, our code has never even been ran successfully, what’s there to lose? There’s also the protective layer we get from using source control – if anything goes south, we could just revert the changes.
Don’t get me wrong…It is still highly recommended, and probably always will be, to use this mode only in a container that has no internet access. However, we are here to showcase how it could be leveraged and we won’t be bothered with having security in mind. I marked it as Level 1. That is, if you decide to work in the isolated container, which would require some effort from your side.
To use the safe YOLO mode you simply start Claude in a slightly different way:
claude --dangerously-skip-permissions
You then have to accept the risks you will be warned about.
Awesome! With this out of the way, we could continue on our Agentic Code journey. Let’s ask Claude to fix the error we’ve seen earlier:
My backend project is not running, I am getting the following error: ImportError: cannot import name 'url_quote' from 'werkzeug.urls'. Look at the code and implement a fix - do not stop until it runs successfully.
Branch: #003
Claude came after a short period and it actually has fixed the issue by changing the requirements.txt file – I could tell by looking at the git changes. That is one issue out of the way, but I am now observing a different error on my frontend: “Origin http://localhost:3000 is not allowed by Access-Control-Allow-Origin. Status code: 403”.
To be honest with you, I am sick of it! I still cannot run the code I got generated and it’s already getting late at night (you could tell by my console turning black). As I am writing this article, I wish to park this for tomorrow, which gave me the idea to check another checkbox – using Claude to interact with GitHub.
Interact with GitHub
Since Anthropic advertise Claude as being able to interact with GitHub, let’s ask Claude to open an Issue on the GitHub repository, so that I can remember what to pick up tomorrow.
While running both the backend and the frontend projects, I am getting the following error in the console of the frontend project: "Origin http://localhost:3000 is not allowed by Access-Control-Allow-Origin. Status code: 403". Create a GitHub issue about this, so an engineer can come and fix it later.
Note that this requires having GitHub CLI as a prerequisite, which is not a focus of this article, and if you are to use it, have to set it up on your own.
Claude had some back and forth, and created three issues until it got it right which it cleaned up after. In the end we are left with what we wanted – an issue describing our error, which I will pick up tomorrow with another Agentic Code workflow to fix. Since our repository is public, you could see it as well: https://github.com/Ulpia-Tech/Agentic-Coding-via-Claude-Code/issues/3
Custom Slash Commands
Awesome! It’s a new day and I want to pick where we left off. I figured it’s a good place for us to create our first custom slash command – very useful for repeatable tasks. In this case I would like to be able to quickly tell Claude to pick up an Issue (from GitHub) and resolve it.
How you add a custom slash command is: you create a new subfolder in the .claude folder called “commands”. Inside you put an .md file, for example ours will be fix-issue.md. The name of the file turns out to be the command itself. Since this sits at a project level your custom slash command will be /project:fix-issue – which will be checked in the repository for the whole team to use.
For the command prompt we will use a slightly customized version of the one in Anthropic’s example:
Find and fix GitHub issue #$ARGUMENTS. Use GH CLI to find the issue. Follow these steps:
1. Understand the issue described in the ticket
2. Locate the relevant code in our codebase
3. Implement a solution that addresses the root cause
The special $ARGUMENTS keyword is used, which will be replaced with the value we will pass in at usage. After reloading Claude in the Terminal, we are able to see the custom command is added:
Let’s now take our new command for a spin!
/project:fix-issue 3
Branch: #004
Running the project now, I could verify it’s all working out correctly. I even added a few expenses to see how it all looks like in the end:
Creating Claude.md Files
We are finally at a state where our project is working. This seems like a good time to create our Claude.md file for the project. Let’s do so by running the /init command. And remember that where you run this command matters. I will be doing it in the root of the repository which means the prompt in the file will always be loaded in, while using Claude. However, creating two separate Claude.md files for the frontend and backend projects is still valid approach. I want to check this file into the repository to make it available for the whole team working on this project, so the file will be “Claude.md” – if you wished to create some instructions for your personal usage only, you would call the file “Claude.local.md” which is typically git ignored.
This is the file we got. As you see, it’s not too fancy, but it will ensure that going forward all agents or subagents we use will adhere to common coding standards – so it will kind of eliminate the temperature we get from LLMs.
Tuning Claude.md Files
I am pretty happy with how the Claude.md file turned out. However, I would like to add a line for the backend to tell Claude I want it to write unit tests for all the subsequent changes it will make on the codebase.
Note in the CLAUDE.md that I want unit tests to be written for the backend.
Branch: #005
Note that tuning the Claude.md files is iterative and continuous process. We may silently improve the Claude.md file as we progress through the article. So keep an eye on the file in the repository.
Have one Claude Write Code; Use Another Claude to Verify
Let’s get away from the basics and really start improving the project. We will do so by using the technique of two Claude’s working on the same codebase, where one of them will write code, and the other will verify it.
We could achieve this by opening Claude in a new Terminal instance, or simply clearing the context and providing the new instructions. According to Anthropic, this separation yields better results than having a single Claude instance do all the work. I fully support this statement. In my experience with LLMs they work best when provided a single task for them to focus on with not too much description (depending on the model – especially for reasoning models I have found that letting them fill in some gaps works out much better).
Read the sections below going back and forth between terminal A and B (branch names under the prompts indicate when to switch reading in the other terminal):
Terminal A (Code Writer)
Add functionality for storing my receipts on the application - uploaded as PNG files. On the UI think of a good way to separate this from the main page we have already - a tab/page dedicated to this sounds like a good option
Branch: #006
Take into consideration the feedback from our engineering team lead in ./claude/reviews/receipts-review.md, implement the suggested changes and fix the critical issues. Leave the "Future Enhancements" for now.
Branch: #008
Terminal B (Code Reviewer)
Do NOT perform any code changes. Write a review of the code that our engineers have written, given that the task was to be able to store and view receipts - as PNG files, while enabling the UI to work with these changes. Make sure that: - Unit tests exist for the backend - Code on both backend and frontend projects adheres to the best coding standards - write feedback if needed - The project is properly separated in logical units - code structure is not neglected
Write your review in the .claude/reviews folder and call it "receipts-review".
Modify the review, leaving only the recommendations and action items on what needs to be changed.
Branch: #007
Before pushing the commit changes, it’s a good idea, to actually run the tests. So I have switched to terminal B for one last time and asked it to run the tests (and Claude was smart enough to also check if the review it wrote was taken into consideration). The prompt used was simply:
Ensure the unit tests pass correctly
This is how the functionality we got looks like in the end (click to enlarge):
As you can see it turned out to be exactly what we wished for, and is now backed up by unit tests!
Using Git Worktrees (or Have Multiple Checkouts of Your Repo)
These two methods are essentially the same since both provide you with a way to work on multiple features with Claude, without interfering one another. This is similar to how few different engineers would pick up unique tasks and work on them in isolated branches, only to merge the work into the dev branch later.
Since these two methods are considered equivalent, I will only pick one and implement it – let’s use Git Worktrees as I find it more elegant approach.
I want to focus on three additional features for our expenses tracker:
Better and more dashboards.
Budgets – being able to set a limit for let’s say Transport at $150 per month/week.
Subscription tracker – being able to track subscriptions and anticipate their costs; remind about upcoming payments.
I’ve created separate branches for these features which will later be merged into the #009-final branch.
Above commands are executed in the root of our repository.
You will see the conversations with each different Claude sequentially in this article, but in reality this was performed in parallel by looping through the three Terminal tabs and responding if Claude needed my attention. I just found it to be easier to read if the conversations were provided separately than in three columns.
Write Code, Screenshot Result, Iterate
What better occasion to try the workflow of writing code, screenshotting the result and iterating than with the use case of building dashboards. I will also sneak in a functionality in here to be able to change between dark and light theme on the UI. In order to save both myself and you a lot of annoyance, let’s actually give Claude the ability to do the browser screenshots itself. This is easily achievable by providing Claude with access to a Puppeteer MCP server. I will not jump into details about what Puppeteer is and how it works, but if you are not familiar with it you should know that Puppeteer is a JavaScript library which provides a high-level API to control Chrome or Firefox in a headless (no visible UI – this is the default behavior) browser window.
First, let’s setup our MCP server connection on Claude. I want to do this on project level – meaning that this will be shared with all contributors to the project. To achieve this, we will be creating a .mcp.json file in the root of the repository to Claude will be able to load it. I won’t dive into too much details, but this is the MCP server for Puppeteer that I will use – Puppeteer MCP Server.
So I will be cloning the repository, installing the npm dependencies and starting the project.
The content of our .mcp.json file to allow connection to this server will be:
Then to make sure our setup is complete (you have to restart Claude by exiting and starting it again), you have to run the /mcp command. If all is good, something similar will appear:
Using puppeteer to take screenshots and verify, add a light and dark theme to our application. Add more and advanced dashboards - if needed to a separate page. Add backend functionality to support this, if needed.
I chose to use this approach by just providing Claude with a general direction of what we want to achieve, but this works out best if we actually sent in a screenshot mockup of the design we wish as part of the prompt. That way, it could use Puppeteer to continuously take screenshots and verify against our mockup until we get the desired result.
Here are some screenshots of the results I got after this initial prompt:
You could probably tell that I am not happy with the results of the dark theme. So let’s go and fix that:
The dark theme doesn't provide enough readability for some of the texts, use puppeteer screenshots to find them out and fix this.
Branch: #009-advanced-dashboards
Write tests, commit; code, iterate, commit
Let’s try yet another workflow – asking Claude to first write tests based on the expected input/output pairs, then confirm these tests are currently failing and commit them, followed by asking Claude to generate the code to make the tests pass (some iterations may be needed, and/or usage of subagents to verify that Claude is not writing overfitting code for the tests).
No one can explain better why this approach works out perfectly than Anthropic’s team:
Claude performs best when it has a clear target to iterate against—a visual mock, a test case, or another kind of output. By providing expected outputs like tests, Claude can make changes, evaluate results, and incrementally improve until it succeeds.
– Part of the article “Claude Code: Best practices for agentic coding”
Using this approach, we will tackle the subscriptions tracking feature.
We are doing Test-Driven-Development. We want to add the functionality to start tracking subscription expenses, so make sure to create unit tests for that feature. Do not add any actual functionality at this point, just ensure tests are covering all and they fail at this stage
Since the tests are written and we are happy with them, they are all failing too, it is great time to commit. Then ask Claude to start implementing the actual logic to pass the tests.
Without modifying the tests, write the actual logic for both the backend and the frontend to make the feature complete. All tests should pass successfully. Using independent subagents, verify that the implementation is not overfitting the unit tests.
Branch: #009-subscriptions
This is what we got as a result of these prompts, turned out pretty good. Let’s tackle the next thing we discussed – budgets.
Explore, plan, code, commit
Let’s jump right in and explain later:
ultrathink about this problem: Do NOT write any code yet, but come up with a plan how to approach this solution. I want to implement budgets functionality in my application. Write your plan to a .MD file. You may use subagents to explore current project state and find the best way to achieve this
The idea behind this is to, first of all, leverage the extra compute that Claude can use, which is triggered by a system of trigger words: “think” < “think hard” < “think harder” < “ultrathink”.
We’ve asked Claude to write the plan to a file so that if we do not like the implementation of it, we can revert all changes, clear the context, and ask Claude to implement it from ground up again, possibly achieving a result more of our liking. I will leave the BUDGET_IMPLEMENTATION_PLAN.md file it wrote in the repository so you could check it if you wish.
Based on the plan in BUDGET_IMPLEMENTATION_PLAN.md, implement the solution in code. Make sure to verify the reasonableness of the solution as you implement it
This works nicely for Claude and it created the following checkpoints/todos for itself:
We’re letting Claude cook and ready to verify the results ourselves:
As you can see, we got a pretty decent page, doing exactly what we wanted. We also have a manage budgets subpage to do CRUD on the budgets.
Use Claude with MCP
You could use Claude as both a client and a server of the MCP side. We have already seen how to make use of an MCP server, we will not go into the details of how you could build your own MCP server now, but another neat trick Claude Code offers is it can act as a MCP server itself.
To start Claude as an MCP server, use the command: claude mcp serve. This is well described in Anthropic’s documentation: https://docs.anthropic.com/en/docs/claude-code/tutorials#use-claude-code-as-an-mcp-server. Don’t get confused that you’re not seeing any output in the terminal upon running the command. You probably already know what using an MCP server means for an agent. To quickly demonstrate what we get from Claude as MCP, I loaded it into another Claude instance and asked what it could do (I called it software_engineer):
We might dive in more details on how to practically use this in our favor in an upcoming article.
Claude in Headless Mode
Headless mode opens the door for many new possibilities with Claude Code via the non-interactive contexts like Continuous Integration, pre-commit hooks, build scripts and automation, linting, issue triage and much more.
It handles “large migrations or analyses (e.g., analyzing sentiment in hundreds of logs or analyzing thousands of CSVs)”. This is where the true power of Agentic coding with Claude comes. This has a lot of practical applications but let’s look at an oversimplified example so that we all understand how it functions and what this is.
First, I asked Claude to generate a python script which will traverse through the folders and files of the project. Then, I asked it to run a command via cmd on every file. You could probably already tell where this is going. We are going to run Claude in headless mode (for ease of use also with the “–dangerously-skip-permissions” option). Finally, I asked for the script to let me choose between the frontend and the backend. You can see the python script it came up with in the respective branch.
Branch: #011
Let’s now take this script up for a spin! I will run it executing the following command:
python3 headless_claude.py
then choose the backend and ask Claude to summarize every single file it gets it hands to in a new file called “BackendDocs”. For your reference, my prompt was:
Summarize what the role of this file is in the project. Write the documentation in a file called BackendDocs.md, if it already exists append to it in new section - start
Branch: #012
Claude has successfully traversed through all 15 files in my backend and has done exactly what I asked for. You could see the result in the respective branch.
Now this is a very simple example, but it helps us start thinking in the direction of how could we leverage this to boost our productivity ten fold. This technique could be used for migrating from framework A to framework B, writing unit tests, ensuring each file is passed through with given prompt. This is especially useful for huge projects where the files may be in the thousands. The possibilities are virtually unlimited!
Conclusion
While maintaining your engineering skills up to date remains essential for the success of your coding operations, we could conclude that we are now observing a trend emerging, where highly-skilled engineers will transition to highly-skilled operators (or call them orchestrators if you wish) – by performing more or less of the techniques in this article, could supervise the work of multiple Claude instances and begin to automate more and more of the work that would usually take several people to complete. It’s arguable if the code is of the greatest quality and all possible security threats are handled, but it is sure that agentic coding will improve and tools like Claude Code are here to stay!
Contact us
Get in touch and ask us anything. We're happy to answer every single one of your questions.
This site uses cookies deliver its services and to analyze traffic. Privacy Policy
Functional
Always active
The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
Preferences
The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
Statistics
The technical storage or access that is used exclusively for statistical purposes.The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
Marketing
The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.