I'm a senior tech lead, writing about tech, volunteers, public safety, and collective intelligence. This blog contains articles, tools, code and ideas.
Most people learn by doing. In earlier posts we set up a dev environment and and a small Streamlit prototype. Now let’s use opencode to add a new feature.
This is our fourth tutorial and, so far, we haven’t used opencode at all! Let’s put that right.
We’re going to alter our prototype to implement a very simple data processing pipeline.
That’s a pretty simple application ‘specification’. Its nice and easy to understand, and we can break it down into smaller tasks for a coding assistant2.
We’re going to ask opencode to implement this.
Every time an AI agent does anything, you’ll get a different result - so it’s important to understand what you’re asking for. That way, you can give clear guidelines and
💡 I’m in the habit of preparing my prompts beforehand, and copy/pasting them for the AI assistant. That way I can think them through and craft them carefully before setting it to task.
If you don’t already have it open from our previous work, open Visual Studio Code and open your project folder.
There should be a little opencode icon button that automatically starts it for you: 
If you’ve not spotted the button, you can:
cmd + shift + esc, orcmd + shift + p (opens the palette), type and select “Open opencode”💡 The palette in VS Code is a very useful menu, making it easy to find a lot of tools that just won’t fit anywhere else.
At the opencode prompt, you can press tab to switch between Build and Plan modes.
We’re also going to do a tiny bit of work on the terminal. Again, you could ask opencode to do it for you - but it’s really helpful to get some muscle memory for the basics.
Open a terminal with: ctrl + ` (or the Terminal menu).
Enter your project folder
cd src/your-project-folder
💡 Start typing the name of a folder or file and press
tab. If you’ve typed enough of it, your terminal’s shell may be able to autoc-complete it for you.
Check the status of the repository
git status
If you’re not on the main branch, switch to main
git switch main
Pull the latest on main
git pull
Now create a new branch from there
git switch -c sum-of-two-columns
Branches are often named as a short reference so you know what you’re supposed to be working on, while on that branch.
Great - you’re on a fresh branch. Anything you do here won’t affect main until you’ve added it, commited it, pushed it, make a PR and merged it back to main.
That may sound like a lot of bureaucracy, but it means main is safe from anything we do to experiment - and we can always abandon this branch if we don’t like it. By the time we’re done, this will all be second nature.
I strongly recommend writing your own prompts.
We’re going to start the application, so you can see changes as opencode implements them with you.
streamlit run app.py
| Description | Screenshot |
|---|---|
| After launching the application, I used the internal browser in VS Code to display the app. | ![]() |
First, confirm that you can see changes as they’re applied. Change the title line yourself to:
st.title("My Little Data Prototype")
| Description | Screenshot |
|---|---|
| Streamlit will indicate that it spotted the change, and ask if you want to change every time. | ![]() |
Choose “Always rerun”. This is easiest for us, as we’ll be able to see changes as they’re made.
If opencode breaks the application (even temporarily) you may need to refresh the page after it has finished working to see the new version of the application.
Great! If you can see the new title “My Little Data Prototype”, we’re ready to move on…
Let’s write a prompt to add an upload input and button to the application.
Use tab in the opencode tab to switch to Build mode, and give it a prompt. Hit enter when ready.
Here’s the prompt I’m using, but I recommend3 getting used to writing them, so think about what you’d like to achieve in the first step and prepare one in your own words:
Modify the app so that the user can upload a CSV file. There should be an upload input, where the user can add a CSV file, and a button labelled Upload. When the user clicks upload, the file should be read and validated. Here's what we expect: - The file will contain a column with heading "A", and a column with heading "B" - Each row will either be blank, or contain a number in both columns A and B - There may be other columns. These can be ignored.
| Working… | Complete |
|---|---|
![]() |
![]() |
⚠️ Your coding assistant may attempt to run its own copy of the application to test it, as a part of the exercise. If you already have a running copy, yours will be stopped. Don’t worry, you can start it again afterwards with the same command as before:
streamlit run app.py
It’s very likely that your coding assistant will make mistakes as it goes. It may also spend some time reasoning about whether the code it has written does what it’s supposed to do. This is normal. Some providers (eg. Claude Code) may do a better job of hiding a lot of this ’thinking’ from you - but don’t worry: Making mistakes and correcting them is a part of the process.
You’ll be able to see as it attempts to run the code it has written, read the error messages, interpret them, make corrections, and repeat - until it has delivered something that runs.
It’s also important to understand that it’s very normal for a change in a complex application to have an unexpected impact on other components and other parts of the app. Software developers have some established ways to manage this (including code quality guidelines, automated tests, linters, house coding styles, and more…) We’ll explore those in future tutorials.
The new control should be able to validate a simple CSV table. Here are two samples you can use to test:
After uploading invalid-columns.csv, you should expect to see a warning about the incorrect columns.
| Invalid columns | Valid columns |
|---|---|
![]() |
![]() |
Once satisfied with the first part, press on with the calculation and download part of this implementation.
After the user has uploaded their file, if it is valid, show a button labelled "Calculate sums". When this is pressed: - Read the CSV file into a a DataFrame - Add a column with heading "C" to the DataFrame - The value of column C in each row should be the sum of the values in columns A and B in that row (unless the row is empty) If the calculation is not successful, show an error message indicating what went wrong. If the calculation is successful: - Show a summary with: - "Calculations:" - the number of rows with a value for column C - The first 10 rows (or fewer if fewer are available), shown in a table - Show a button the user can click to download the new DataFrame
| Calculated |
|---|
![]() |
Ok - you’re satisfied with this piece of work. You’ve tested it and it does what you expected. It’s time to complete the task.
First, make a commit.
Add all new files to your commit
git add --all
Create a commit with a simple message explaining the change
git commit -m "Tutorial: Add a feature to upload a CSV and sum columns A, B"
Push your sum-of-two-columns branch to its equivalent on the remote repository
git push --set-upstream origin sum-of-two-columns
💡 If you’d typed
git push, and it was the first push you’d done from this branch, it would have prompted you to use the full form with the--set-upstreamoption.
Create a pull request
Your repository on GitHub has the sum-of-two-columns branch, but you haven’t created a pull request yet. We’ll create one now.
mainGitHub gives you a page for each pull request, and you can add a description there. When ready, press Create pull request
NB. Coding assistants can use commands from the terminal, just like you can. There are commands to add files to staging, create commits, push to a remote branch, and even to create a pull request. You could have asked it to do that for you - but, again, if you’re not familiar with git, it’s good to go through the motions until it’s second nature.
This is where, in a team, another developer would review your code. You’d be expected to understand everything you’re delivering, and be able to justify the decisions you’ve made.
Code should be reviewed with kindness. It’s an opportunity for others to learn, and also for the reviewer to learn.
GitHub allows reviewers to leave notes, and for developers to make modifications based on those notes. You might push several times to a pull request branch before it’s finally approved. That’s normal, and it’s a healthy part of team work that leads to higher code quality.
We’re skipping all of that for now.
Near the bottom of your pull request, there’s a button that will allow you to merge the changes.
⚠️ At the moment, there are no branch protections - so you can go right a head and merge those changes without a review. In a team environment, the repository’s main branches would be protected - and that would ensure that ‘rogue’ changes can’t be accidentally merged into the product.
Congratulations! That’s your first application and pull request 🎉
Today we created new functionality for an app, and used industry standard tools to merge it into our code repository.
We broke up the prompt into two parts, so that you could see the changes as they were implemented. Most coding models can handle work that’s bigger than this - but if you want someone to review your code, it’s helpful to try and keep the changes small and focussed.
Small, tightly focussed, changes give your colleagues the best chance at reviewing it well, and that gives you the best chance of producing good code.
There’s lots more to talk about, including ways to keep your code safe, manage code quality, and reduce the risk of errors and regressions as you continue to work on the code. As a developer, you are ultimately responsible for the code that’s created. If you’re working with user data, you have a responsibility to your users to keep their data safe, too.
We’ll talk about ways to do that in the next tutorial.
In the meantime, go wild! Experiment, and get to know how your coding assistant works. It’s low risk on a free tier.
Modify the app so that the user can upload a CSV file.
There should be an upload input, where the user can add a CSV file, and a button labelled Upload.
When the user clicks upload, the file should be read and validated. Here’s what we expect:
After the user has uploaded their file, if it is valid, show a button labelled “Calculate sums”. When this is pressed:
If the calculation is not successful, show an error message indicating what went wrong.
If the calculation is successful:
Comma Separated Value: It’s a file format that represents a spreadsheet table. Internally, it’s a text file - and you can open a CSV file in VS Code to take a look. Each row in the file represents a row in the table, and each value in the file has cells, separated by commas. (If you need to represent text that contains a comma, in a cell, wrap the whole cell’s text in “inverted commas”.) ↩︎
Although this is a small task, breaking it up is good practice for working on more complex requirements. ↩︎
You’re welcome to copy/paste these prompts into your own opencode session. I recommend getting used to thinking about the problem, and what you’re asking for, so that you can be as specific as you need to get the result you want. ↩︎