New to OpenCode? Start with OpenCode setup, model providers and course budget, then return here for your chosen app.
Stop counting tips by hand in a tree figure
Someone sends you a tree file and asks: "which species are in that clade, how old is it, and how well supported?" The figure answers by eye, but it is easy to miscount a tip, read the wrong support value or take a gap for zero. Phylogeny Inspector reads a Newick tree file and a table of tip information, draws the tree exactly as the file says, and lists and exports every tip below the node you click.
A few words first. A tip is one sampled species at the right-hand end of the tree. A node is a branching point; a clade is a node plus everything below it. Support says how strongly the data back a clade. Here it is the bootstrap percentage: in how many of many resampled analyses the clade appeared again. Newick is the plain-text tree format most tree programs export, for example (('A':1.0,'B':1.0)95:2.0,'C':3.0);. Brackets group, the number after : is a branch length, and a number after ) is support. Ma means million years ago.
You will build the app with OpenCode, one request at a time, and check every number yourself. It runs locally in your browser: one file, no installation, no upload. The practice tree is a synthetic teaching tree. It uses 12 real mustard-family species names, but the tree shape, the ages and the support values were invented for this course. It is not a published phylogeny; do not cite it. Your own permitted tree comes in at Step 16.
You will finish with: an app that shows a clade's tips, age and support, writes "–" instead of 0 when support is missing, never reorders the tree, and exports the clade as a CSV file.
First watch the 1:54 result tour. It shows where you are going. The numbered steps below are the lesson: what to click in OpenCode, what to paste, and what must appear before you continue.
Silent, with on-screen explanations. OpenCode scenes are captures from the recorded build; app scenes operate the actual OpenCode-generated app. Captions and highlights were added afterwards. Read the transcript (opens in a new tab) · Download the movie (opens in a new tab).
Use: keep this manual beside OpenCode and your browser. Complete each Success check before continuing. Click any screenshot to enlarge it.
Files: reference kit: working app, three checkpoints, practice tree files and the exact prompts (opens in a new tab). Extract the ZIP first: Windows right-click → Extract All; Mac double-click. Keep it beside your project.
Your personal coach: Step 4 turns your OpenCode session into a one-step-at-a-time guide. For help later, paste the complete coach brief (opens in a new tab) into your project session and tell it your step number.
Files for this journey
Download everything at once as the reference kit (ZIP) (opens in a new tab), or single files as you reach the step that needs them. Save each file into your project folder under exactly this name. If a file opens in the browser instead of downloading, press Ctrl+S (Mac: Command+S) to save it.
| File | First used in |
|---|---|
tree.nwk (opens in a new tab) | Step 2 · Open your project |
tips.csv (opens in a new tab) | Step 2 · Open your project |
broken-tree.nwk (opens in a new tab) | Step 2 · Open your project |
tips-typo.csv (opens in a new tab) | Step 2 · Open your project |
other-units.nwk (opens in a new tab) | Step 2 · Open your project |
other-units-tips.csv (opens in a new tab) | Step 2 · Open your project |
The kit also contains the finished app, the recorded checkpoints (checkpoints/…) and the exact prompts.
1. Get OpenCode readyLink to step
Do
- Open an ordinary website. Complete your university Wi-Fi sign-in if prompted.
- Install OpenCode Desktop: follow Step 1 of Set up OpenCode in the L1 book Start With OpenCode.
- Open OpenCode. For English labels, use Settings → Preferences → Language → English. In German: Einstellungen → Präferenzen → Sprache → English.
Success: OpenCode opens. Continue to the project; choose the model in Step 3.
If different: installation or Wi-Fi failure → use the seminar recovery card.
2. Open your projectLink to step
Do
- In Finder or File Explorer, create a folder named
phylogeny-inspectorin Documents. - Copy the
datafolder from the extracted reference kit intophylogeny-inspector. It holds six small text files:tree.nwk(opens in a new tab) (the practice tree),tips.csv(opens in a new tab) (a table with one row per tip), two deliberately broken copies (broken-tree.nwk(opens in a new tab),tips-typo.csv(opens in a new tab)) and a second small tree for Step 16 (other-units.nwk(opens in a new tab),other-units-tips.csv(opens in a new tab)). - In OpenCode, click Home → Add project.
- Select your
phylogeny-inspectorfolder. Click Select folder. - Click New session.
Success: the new-session screen shows phylogeny-inspector below the message box.
If different: another folder name → return Home and add the correct folder. Open the project before choosing a model.
3. Select a working modelLink to step
Do: click the model name below the message box. Select the model assigned for the seminar. Wait until its name appears below the box.
Success: a model name is displayed. The next step checks that it answers.
If different: no working model or access → ask the instructor to confirm the seminar connection. This recording used Space Bunny Free; free availability is not guaranteed. If the model you need is missing from the list, open Manage models at the bottom of the menu and switch it on.
Agent control: if Plan is visible, select Build before requesting edits. In the recorded interface the agent selector is hidden and Build is the default.
4. Start your OpenCode coachLink to step
Do: click once inside the message box, paste this block and click the upward Send arrow.
Be my patient app-building coach. I am a beginner.
We will build Phylogeny Inspector in this folder, one step at a time.
Use one index.html with inline HTML, CSS and JavaScript,
no packages, server or network calls.
The data folder holds a synthetic teaching tree (tree.nwk) and tips.csv.
Explain in at most four short lines: Do, See, Success, If different.
Wait for my result before continuing.
Never claim to see my browser unless you actually inspected it.
Do not create files yet. Reply:
"Ready. Your project is phylogeny-inspector. Next: read the tree."
Wait: while OpenCode works, Send turns into Stop. Continue only when Stop has disappeared.
Success: OpenCode replies Ready. Your project is phylogeny-inspector. No file is created yet.
If different: an access or quota error → return to Step 3. Do not reinstall OpenCode to fix a model quota.
5. Read the tree: your first screenLink to step
Before drawing anything, the app must read the tree file correctly and match its tips to your table. Open data/tree.nwk (opens in a new tab) in a text editor once. Its first line is a comment in square brackets that names the unit of the branch lengths and the support statistic: [branch_length_unit=million years; support=bootstrap %; …]. Newick itself has no place for units, so this app requires that line. One node in the file has no number after its ): its support is missing, which is not the same as zero support.
Do: paste this into the same session and click Send. Wait for Stop to disappear (about five minutes in the recording).
Create only index.html. Build the first Phylogeny Inspector screen:
inline HTML, CSS and JavaScript, no packages, server or network calls.
Clean light design, dark teal heading, system fonts, labelled controls.
Add a "Load example" button and two file inputs labelled
"Tree file (Newick)" and "Tip metadata (tips.csv)".
Read data/tree.nwk and data/tips.csv now and embed their exact text as
the example, because a double-clicked page cannot read files by itself.
Parse the Newick text with a small recursive parser written by you:
skip [comments], then read nested (children), single-quoted names,
:branch lengths, and a number after ")" as that node's support.
No number after ")" means support is missing (null), never 0.
The first [comment] names branch_length_unit and support: show both.
If that comment is missing, show an error asking for it, and no results.
Unbalanced parentheses: show an error with both counts, and no results.
Match tips to tips.csv (tip_id,common_name,tribe) by exact tip_id.
A tips.csv ID that is not in the tree is an error naming that ID.
A tree tip without a row is listed with "no metadata", not an error.
Show "12 tips · 11 internal nodes" and a table of tips in file order.
Initially show "No tree yet. Click Load example."
No drawing yet. Save index.html, tell me how to open it, then wait.
A recursive parser reads one bracket group and, inside it, calls itself for every smaller group. You do not need to read the code.
Success: OpenCode says index.html is ready and tells you to open it.
If different: code appears only in the chat → send "Save that code as index.html in this project. Tell me the saved path." If a permission request appears, allow the file edit only when it names your project.
6. Open the app and check the tipsLink to step
Do
- In Finder or File Explorer, open
phylogeny-inspectorand double-clickindex.html. If a text editor opens instead, right-click → Open With → your browser. - Click Load example.
Success: the summary reads 12 tips · 11 internal nodes. The unit reads million years and the support bootstrap %. The table starts with Aethionema arabicum and ends with Brassica oleracea. Eutrema salsugineum says no metadata: tips.csv (opens in a new tab) has no row for it.
Check the count yourself: a tree in which every node splits in two always has one internal node fewer than tips (12 − 1 = 11).
If different: 13 tips or a tip named [branch_length_unit… → send "The [comment] line is being read as a tip. Skip everything in square brackets before parsing. Fix only that." Refresh the browser (Ctrl+R, Mac Command+R) and click Load example again.
7. Break the files on purposeLink to step
A lost bracket or a misspelt species name is the most common way a tree file goes wrong. The app must refuse to show results rather than guess.
Do
- Click Tree file (Newick) and choose
data/broken-tree.nwk(opens in a new tab). Click Tip metadata (tips.csv) and choosedata/tips.csv(opens in a new tab). - Then choose
data/tree.nwk(opens in a new tab) as tree anddata/tips-typo.csv(opens in a new tab) as tip metadata.
Success: the broken tree gives Unbalanced parentheses: 11 opening "(" and 10 closing ")" and no table. The typo file gives Tip metadata ID "Capsella rubela" is not in the tree. and no table. Choosing tree.nwk with tips.csv again brings back 12 tips · 11 internal nodes.
If different: a table still appears beside an error → send "While an error is shown, hide the summary and the tip table. Change only that." The recorded build was right first time here.
8. Keep your first working versionLink to step
Do: copy the whole phylogeny-inspector folder beside the original. Name the copy phylogeny-inspector-01-working. Continue working in the original.
Success: there are two folders. Both contain index.html and data.
If stuck: the kit's checkpoints/05-first-screen/index.html is the recorded working version. Copy it into a new recovery folder; keep your own work.
9. Draw the treeLink to step
The drawing is a rectangular phylogram: horizontal lines are as long as the branch lengths, vertical lines only join sister branches. Because the branch lengths here are millions of years, the horizontal axis becomes a time axis: tips today (0 Ma) on the right, the root on the left. The age of a node is how long ago that branching happened.
Do: send:
The example shows 12 tips, and Eutrema salsugineum has no metadata.
Now draw the tree as an inline SVG rectangular phylogram, left to right:
root at the left, tips at the right, horizontal lines proportional to
branch length, vertical lines joining the children.
Keep the file's tip order from top to bottom. Never reorder, re-root
or otherwise change the tree.
Add a time axis under the tree in million years before present (Ma):
tips at 0 on the right, the root at its age on the left.
Node age = deepest root-to-tip distance minus root-to-node distance.
Number internal nodes N1, N2 … in the order they open in the file
(N1 = root) and write each number small beside its node.
Show support at each internal node as a symbol plus the value, with a
legend: filled circle ≥ 95, grey 70–94, white < 70, and "–" for missing.
Missing support is never drawn or written as 0. The root has no support
by definition: draw nothing there. Tip labels: the tip ID in italics.
Keep the tip table below. Save index.html; tell me what to check, then wait.
Wait, refresh the browser and click Load example. Then look at the drawing critically, not just "is there a tree?".
Success: 12 tips in the same order as the table; the root (N1) on the left at 30.8 Ma; N4 shows –, not 0.
In the recording, the shape was right but hard to read: the text was tiny, "47" at N7 and "100" at N6 and N11 touched branch lines, and the axis showed only 30.8, 15.4 and 0. Step 10 fixes that.
If different: the tips are in another order → send "Keep the tips exactly in file order from top to bottom. Do not sort or ladderise."
10. Make the drawing readable, then look againLink to step
Do: describe what you see, with the exact labels, and send:
The tree shape and tip order are right. But at a 1440-pixel-wide window
the drawing uses only part of the page and its text is tiny.
Support values sit on branch lines: "47" at N7 touches the Camelina
sativa branch, and "100" at N6 and N11 lies on the lower branch.
The axis shows only 30.8, 15.4 and 0, which is hard to read off.
Fix only the drawing: use the full width of the card, text at least
13 px, node number and support just left of each node and above its
horizontal line, never on a line. Axis ticks every 5 Ma (0, 5 … 30),
labelled in Ma, plus the root age marked "root 30.8 Ma".
Keep every number, the tip order and the legend.
Save index.html; tell me what to check, then wait.
Refresh and click Load example. The text is now readable and the axis has ticks every 5 Ma. But look where the labels are.
In the recording, every node label had moved about one row up. N3 96 sits on the Aethionema arabicum line, while node N3 is where the Cardamine hirsuta branch and N4 join. A reader would give the support to the wrong clade. A fix can break something else: always recheck.
Success: you can say, for one label, where it sits and where its node really is.
If different: your labels already sit at their nodes → skip Step 11's request, but do its checks.
11. Put the labels back on their nodesLink to step
Do: send:
The text is readable and the axis ticks are right. But now the node
labels float away from their nodes: "N3 96" sits on the Aethionema
arabicum line, far above node N3, which is where the Cardamine hirsuta
branch and N4 join. Every label is about one row too high, so a reader
would attach the support to the wrong clade.
Draw each support symbol exactly on its node: the point where the
node's vertical line meets the branch coming from its parent.
Write the node number and support value immediately left of that
point, just above that incoming branch, touching no other line.
Change only the label positions. Save index.html; tell me what to
check, then wait.
Refresh and click Load example.
Success: every symbol sits where a vertical line meets its incoming branch. Read three ages off the axis and check them in tree.nwk with a calculator. On an ultrametric tree (all tips at 0 Ma, as here), a node's age equals the summed branch lengths from that node down to any of its tips:
| Node | Where | Check from tree.nwk | Age | Support |
|---|---|---|---|---|
| N1 (root) | all 12 tips | Aethionema arabicum branch = 30.8 | 30.8 Ma | none (root) |
| N4 | Boechera stricta + N5 | Boechera stricta branch = 13.9 | 13.9 Ma | – (missing) |
| N9 | Sinapis alba + N10 | Sinapis alba branch = 11.8 | 11.8 Ma | 100 |
If different: a symbol still floats → send "Label [N-number] is drawn at [where you see it]. Its node is where [branch] and [branch] join. Move only that label."
Keep: copy your project as phylogeny-inspector-02-working. Recorded recovery file: checkpoints/08-labels-fix/index.html in the kit.
12. Select a clade and export itLink to step
Do: send:
The tree is drawn with its axis and support legend.
Make every internal node clickable and selectable with the keyboard.
Selecting a node highlights its clade (the node and every branch below it)
and shows a panel: node ID, age in Ma with one decimal, support
(e.g. "88 (bootstrap %)", or "– (not reported in the file)"),
the number of descendant tips, and those tips in tree order with
common name and tribe ("no metadata" where missing).
For N9 expect 4 tips: Sinapis alba, Raphanus sativus, Brassica rapa,
Brassica oleracea; age 11.8 Ma; support 100.
Add "Export clade CSV", disabled until a node is selected. Columns:
node_id,node_age,age_unit,support,support_statistic,tip_id,common_name,tribe
One row per descendant tip. Empty cell where support or metadata is missing.
Quote fields correctly. File name: clade-<node id>.csv.
Selecting must never change the tree. Save index.html;
tell me what to check, then wait.
Refresh, click Load example, then click the dot at N9. With the keyboard: press Tab until N9 is outlined, then Enter.
Success: the N9 clade is highlighted (see the first screenshot at the top). The panel shows N9 · 11.8 Ma · 100 (bootstrap %) · 4 tips: Sinapis alba, Raphanus sativus, Brassica rapa, Brassica oleracea. The tree does not move or reorder.
If different: the tips are listed alphabetically → send "List the selected tips in tree order, top to bottom, not alphabetically."
13. Check a missing value and the export by handLink to step
Do
- Click N4.
- Count the tips below N4 in the drawing yourself. Then compare with the panel.
- Click Export clade CSV and open
clade-N4.csvfrom Downloads in a text editor.
Success: the panel shows 13.9 Ma, support – (not reported in the file) and 5 tips: Boechera stricta, Arabidopsis thaliana, Arabidopsis lyrata, Capsella rubella, Camelina sativa. The file has a header and five rows; each starts with N4,13.9,Ma,,bootstrap %. The empty cell after Ma is the missing support: empty, not 0.
Two more checks by eye: N7 (Capsella rubella + Camelina sativa) shows 47 and N10 shows 64, both with a white circle: weakly supported (below 70). N8 exports Eutrema salsugineum with empty common name and tribe.
If different: the support cell says 0 → send "N4 has no support value in the file. Export an empty cell, never 0. Fix only the export."
Keep: recorded recovery file checkpoints/09-select/index.html.
14. Make it yoursLink to step
Do: send:
N9 lists 4 tips and the export has 4 rows.
Change only the visible heading to "My Phylogeny Inspector".
Keep the browser title consistent.
Do not change parsing, drawing, selection or export.
Save index.html and tell me which lines changed.
Refresh and click Load example.
Success: the heading reads My Phylogeny Inspector. Selecting N9 still shows 11.8 Ma and 4 tips.
If different: anything else changed → ask OpenCode to undo that part, or restore index.html from your latest checkpoint.
15. Leave a README and continue in a fresh sessionLink to step
Do: send:
Read index.html, then create README.md with exact instructions for
opening and using this app: the two files (Newick tree with a first
[comment] naming branch_length_unit and support; tips.csv with
tip_id,common_name,tribe), what counts as an error and what is only
"no metadata", that missing support is shown as "–" and never as 0,
that the app never reorders or re-roots the tree, where data is processed,
and the known checks for the synthetic example: 12 tips, root 30.8 Ma,
N9 = 4 tips at 11.8 Ma with support 100, N4 support missing,
Eutrema salsugineum without metadata.
Record this next task: collapse or expand a selected clade.
Do not implement it. Do not change index.html.
Tell me which file you created, then wait.
Then click New session (the + beside the session tab). Confirm phylogeny-inspector is still the project. If the button says New project, click it, select your original phylogeny-inspector folder and click Select folder. Send:
Read README.md and index.html without editing.
Tell me the app's purpose, how to open it and the recorded next task.
Keep the answer to three bullets.
Success: the new session names the app's purpose, double-clicking index.html, and the collapse/expand task, all from your files.
If different: empty project → check the folder. Wrong facts → correct README.md before continuing; it is your memory between sessions.
16. Test another unit, then try your own permitted treeLink to step
Many trees are not dated. Their branch lengths are substitutions per site: estimated genetic changes per DNA position, not time. Their support may be another statistic, such as SH-aLRT (a fast likelihood-based test). An app that calls every branch length "Ma" would mislabel such a tree. Test that before you load your own file.
Do: choose data/other-units.nwk (opens in a new tab) as tree and data/other-units-tips.csv (opens in a new tab) as tip metadata. Its first line says branch_length_unit=substitutions per site; support=SH-aLRT %.
The recorded build still wrote root 0.09 Ma and Time before present (Ma). Continue in your fresh session and send:
Before I use my own tree I loaded data/other-units.nwk with
data/other-units-tips.csv. Its first line says
branch_length_unit=substitutions per site and support=SH-aLRT %.
The app still writes "root 0.09 Ma" and "Time before present (Ma)",
and the export says age_unit Ma. That is false: these branch lengths
are not times. Always use the unit named in the file.
Only when it is exactly "million years" say "Time before present (Ma)"
and "Age". Otherwise label the axis "Distance from the deepest tip
(<unit>)" with readable ticks, call the node value "Height", show
three decimals, and export the file's unit in age_unit.
The synthetic example must look and export exactly as now.
Change only this. Save index.html; tell me what to check, then wait.
Refresh, choose the two files again and click N2.
Success: no "Ma" anywhere on this tree. The root reads 0.090 substitutions per site; N2 shows Height 0.040 and 91 (SH-aLRT %). Check by hand: the deepest tip is Brassica rapa at 0.090 from the root; N2 is 0.05 from the root, so its height is 0.090 − 0.050 = 0.040. The tips end at different distances because this tree is not dated. Click Load example: the practice tree still shows 30.8 Ma.
Now your own tree
- Use only data you are allowed to use. Never paste unpublished or personal data into a model without permission. The app itself runs in your browser and sends nothing; OpenCode sees only what you paste into it or ask it to read.
- Export your tree as Newick from your tree software (for example IQ-TREE's
.treefile, RAxML or FigTree's Newick export). Work on a copy. - Open the copy in a text editor and add a first line that states the truth, for example
[branch_length_unit=substitutions per site; support=UFBoot %]. Check the unit and statistic in your analysis log; do not guess. - Make a
tips.csvwithtip_id,common_name,tribe, using the tip names exactly as they appear in the tree (underscores included). Save as CSV UTF-8. - Choose both files. Pick one clade you know and count its tips by hand.
Success: the tip count, the clade you know and one support value match your source.
If different: your software writes two support values per node, like 95.2/100 (SH-aLRT/UFBoot). This version keeps only the first number without warning. Do not use its support values; ask OpenCode for that one adaptation first, using a made-up three-tip example rather than your real tree. The legend bands (95, 70) are bootstrap conventions; other statistics use other thresholds.
17. Update the README and let a colleague use itLink to step
Do: the README still says the axis is always in Ma. Send, in the same session:
The unit check works: other-units.nwk now shows "Distance from deepest
tip (substitutions per site)" and the example still shows Ma.
README.md is now out of date: it says "The axis is time before present
in Ma". Update only README.md: replace that with the unit rule you just
implemented. Do not change index.html. Tell me which lines changed,
then wait.
Then give a colleague index.html, README.md and the data folder. Ask them to follow README.md, load the example, and tell you which tips descend from N9 and how old that clade is. Let them click without your help.
Success: they report 4 tips, 11.8 Ma, and can explain why N4 shows "–" rather than 0.
If they stop: add the missing instruction to README.md. Repeat from that instruction.
18. Make your next improvementLink to step
Do: save a working checkpoint. The recorded next task is to collapse or expand a selected clade. Collapsing changes only the view: the file, the node numbers and the export must stay the same. Write your request with this pattern:
Add [one behaviour] so [my user] can [purpose].
Keep [working features].
I will know it works when [visible result].
Tell me which part will change, implement only this improvement,
then wait for me to try it.
For collapsing: with N9 collapsed, the drawing shows one row for 4 tips, and Export clade CSV for N9 still gives 4 rows.
Success: the new behaviour works, and the example still gives 12 tips, root 30.8 Ma, and N9 = 4 tips at 11.8 Ma. Record the next task in README.md.
If stuck: paste this into your coach chat:
I am on step [number].
I did: [exact action].
I expected: [result from the manual].
I see: [actual text/result, or describe a screenshot].
Give me one next action. Wait for my result.
What this app does not do: it does not build, date, root or re-root trees; it only shows the tree it is given. It runs no test of whether a clade is real. Support values are shown as written; a bootstrap percentage is not the probability that a clade is true. Ages are only as good as the dating analysis that produced them. It reads one tree per file, not NEXUS files or FigTree annotations ([&…]), and keeps only the first of two support values. The practice tree is synthetic and must not be cited.
The method behind these steps
Structure it: one tree file that states its units, one tip table, and a visible rule for every mismatch. Understand it: count tips and read ages by hand before trusting the screen, and keep "missing" apart from zero. Choose tools: one offline HTML file, OpenCode as the builder, your eyes and a calculator as the judge. Build it: one request, one check, one checkpoint at a time, with corrections phrased as observations. Read T01-L01 · From Idea to Working Result: The Four-Quadrant Method.













