<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.3.3">Jekyll</generator><link href="https://www.viviano.ca/feed.xml" rel="self" type="application/atom+xml"/><link href="https://www.viviano.ca/" rel="alternate" type="text/html" hreflang="en"/><updated>2026-05-17T05:37:20+00:00</updated><id>https://www.viviano.ca/feed.xml</id><title type="html">Mode Collapse</title><subtitle>. Based on [*folio](https://github.com/bogoli/-folio) design. </subtitle><entry><title type="html">Agentic Research Best Practices</title><link href="https://www.viviano.ca/blog/2026/agentic-research/" rel="alternate" type="text/html" title="Agentic Research Best Practices"/><published>2026-05-05T00:00:00+00:00</published><updated>2026-05-05T00:00:00+00:00</updated><id>https://www.viviano.ca/blog/2026/agentic-research</id><content type="html" xml:base="https://www.viviano.ca/blog/2026/agentic-research/"><![CDATA[<h1 id="philosophy-behind-agentic-research-vs-agentic-engineering">Philosophy Behind Agentic Research vs. Agentic Engineering</h1> <p>Many of the previous coding best practices now feel archaic and incorrect. Over the past 15 months I have been experimenting with agents and trying to keep up with how engineers are using these tools, and adapting them to my research workflows. This is a collection of notes I’ve settled on in my own experience and with my collaborators at <a href="https://mila.quebec/en">Mila</a>, on the topic of doing <em>research</em> using coding agents. I’m not focused on productivity maximizing engineering practices per se, where the only thing that matters is a robust final product. The ultimate goal of research is to build and transmit <em>understanding</em> of the natural world, so speed is bound by my ability to keep up with the system, to ensure it’s intelligible to myself and others.</p> <p>Research codebases have unique requirements compared to other kinds of software. They don’t have users. They have active developers before the paper is finished, and consumers of a static artifact after the paper is complete. A lot of the default design assumptions of coding agents are therefore miscalibrated for the type of code you would ideally like to write. Your codebase must:</p> <ul> <li>Be highly portable and reproducible - they must reflect exactly what was run to produce the paper.</li> <li>Be easy for others to understand quickly and hack on.</li> <li>Be correct - tests, docs, comments, code, and the paper itself must match precisely.</li> <li><strong>Work in a way you fully understand</strong>.</li> </ul> <p>Your codebase need not be:</p> <ul> <li>Production grade.</li> <li>Full of complex abstractions geared towards maintainability or extensibility over a long lifespan.</li> <li>Concerned with things like API breaks, legacy code paths, or other complexities required to support <em>users</em>.</li> </ul> <p>My workflow is still rapidly evolving, but already it has enabled very large speed ups in idea iteration, somewhere between 2-10x. Sometimes, a pure engineering approach can be taken (the type you see espoused by agent maximalists on X dot com), but only for sub-components of the project, and therefore one needs a good system for working while maintaining understanding and visibility. I am not discussing <em>automating the research process itself</em> - a much more ambitious goal that I don’t think is easily solved on one’s own. I want to talk about how to use these systems to drive research projects more efficiently.</p> <p>This is a high level schematic of the workflow, which will hopefully be clear by the end of the post:</p> <d-figure> <figure> <div class="image-map"> <img src="/assets/img/agent_eng/workflow.png" class="invert-on-dark" alt="A diagram of the iterative multi-agent workflow: high-level planning artifacts feed a codebase agent with limited working memory, with external verification, parallel codebase updates, and subagents handling sub-tasks."/> <a class="hot" href="#design-docs" style="left:2%; top:6%; width:34%; height:5%" title="design_doc.md / paper.tex"></a> <a class="hot" href="#agent-file" style="left:40%; top:6%; width:15%; height:5%" title="AGENT.md"></a> <a class="hot" href="#plans-todos" style="left:4%; top:14%; width:22%; height:13%" title="TODO.md"></a> <a class="hot" href="#testing" style="left:39%; top:13%; width:32%; height:7%" title="Test Agent / external verification"></a> <a class="hot" href="#notes" style="left:55%; top:34%; width:11%; height:7%" title="notes.md"></a> <a class="hot" href="#per-agent-context" style="left:0%; top:65%; width:90%; height:35%" title="Per Agent Context"></a> <a class="hot" href="#external-codebases" style="left:0%; top:38%; width:21%; height:9%" title="External Codebases"></a> </div> <figcaption class="caption"> A Breakdown of the Iterative Workflow with multiple agents. High level project planning exists as LaTeX (<code>paper.tex</code>) / markdown (<code>design_doc.md</code>) descriptions of the goals of the projects, methods, and broader context of the codebase. <code>AGENT.md</code> is high level role information given to <em>every</em> agent, which orients the agent to your project's "database". The <code>design_doc.md</code> can then be broken down into a linear set of objectives / tasks <code>roadmap.md</code>. This can be further broken down into individual <code>task_plan.md</code> with granular details on each implementation. These plans are crucial to give the Agents small enough problems to be solved without filling context. The agent's context will be filled with important information from your codebase, and optionally external reference implementations. During the implementation, external verification of correctness is crucial. These are ideally provided by you or <em>independently</em> by agents not involved in the implementation to reduce the likelihood of test-cheating. During the implementation, discoveries are often made — these can be recorded in <code>notes.md</code>, and if necessary, those notes can be summarized and integrated back into the high-level roadmap periodically. While agents are transient, both text and code should be committed to the repo regularly to make changes / rollbacks easy to achieve. Each agent can also own <em>subagents</em>, which receive their own sub-tasks, enabling more work to happen in parallel in sufficiently small chunks. For example, if you want to generate a report on the current codebase's security vulnerabilities, this is easy to parallelize and you can simply ask for different subagents to handle different modules of the codebase. In addition, you can manage multiple agents to handle multiple parallel issues simultaneously (and each can have their own subagents). These parallel streams of work can synchronize their contexts both via the codebase's state, and the regularly updated <code>notes.md</code> / <code>plans.md</code>. </figcaption> </figure> </d-figure> <h1 id="learn-to-manage-and-transmit-context">Learn to Manage and Transmit Context</h1> <p>Coding agents should be used by every researcher as a best practice - wielded properly, they produce far more robust and trustworthy code. To reap this benefit you will need to learn the skills of a senior researcher: planning of multiple directions in parallel, management of tasks, birds-eye level debugging, clear communication, and comfort with other people’s code. This is not an easy task, but now one can practice them with nearly limitless agents, instead of waiting for real-world supervision or management opportunities, so you can begin now.</p> <p>Assuming <em>zero speedup</em> from the actual act of writing code itself (if you are one of those cracked aliens I keep hearing about), the benefits are still immediate and considerable as they allow you to transmit large volumes of information to yourself (in the future) and others:</p> <ol> <li> <p><strong>Agent context is your context.</strong> Every senior researcher or PI struggles with the cost of task switching. It is a hard skill to master, and limits many people’s ability to do deep work. With agents, you can much more easily switch between contexts that are stored in parallel chats, and offload the systematic, recall-heavy elements of deep work (remembering APIs, reorienting yourself to previous implementation specifics) to your agents. This does not mean you can avoid understanding those specifics <em>ever</em>, but it does mean that during an hour between meetings, you don’t.</p> </li> <li> <p><strong>Agent context is your colleague’s context.</strong> Asking agents to explain recent changes to you is very efficient: they are excellent at navigating git trees and can quickly elaborate on code changes quickly for your colleagues with a few prompts. This is particularly true if the entire team commits to following a rigorous PR workflow with many small commits and detailed commit and PR messages, which your agents can both generate and consume as future context. This means <em>less meetings and a lower documentation burden while working with collaborators</em>. Agents are the right way to parse spaghetti code at 4AM to diagnose an unexpected change in a plot.</p> </li> </ol> <p>In general, when trying to ship information around, agents are an effective way to expand on an idea or query quickly, and after refining, these ideas can be distilled into a document or code. This means another person’s agent can then ingest the reference and reduce it down to the minimum required to satisfy their own understanding.</p> <table class="flow-diagram" style="margin:0 auto; border:none; text-align:center;"> <tr> <td><b>person A</b></td><td>→</td> <td><b>agent A</b></td><td>→</td> <td><b>doc/code</b></td><td>→</td> <td><b>agent B</b></td><td>→</td> <td><b>person B</b></td> </tr> <tr> <td></td><td><i>expand</i></td> <td></td><td><i>distill</i></td> <td></td><td><i>expand</i></td> <td></td><td><i>distill</i></td> <td></td> </tr> </table> <h1 id="agent-file">The Agent File</h1> <p>Keep these short - they’re always in your context, so should only contain universal rules. Context rot is pernicious and large context limits are largely marketing lies. Your agent performs best in the 100-300k token range regardless of context length.</p> <p>I’ve learned to ask for the following:</p> <ul> <li>Do not make assumptions: if my instructions are unclear, ask me as many clarifying questions as required to remove all ambiguity.</li> <li>This is a research codebase. Do <em>not</em> maintain any silent fallbacks as we change the code. Fail loudly.</li> <li>This code should be explicit to the reader. Do not use complex engineering patterns when simple ones will suffice, unless I explicitly ask for modular or scalable solutions.</li> <li>While working, do not remove previous comments unless the underlying logic changes and the comment is incorrect.</li> <li>While designing solutions, please refer to codebase <code class="language-plaintext highlighter-rouge">/path/to/code/a</code> and <code class="language-plaintext highlighter-rouge">/path/to/code/b</code> for examples of good architectural decisions, correct implementations, required features, etc.</li> <li>Prioritize reproducibility and clarity over clever design and efficiency.</li> <li>When designing solutions, ensure they are aligned with the high level project plan in <code class="language-plaintext highlighter-rouge">design_doc.md</code> and <code class="language-plaintext highlighter-rouge">paper.tex</code>.</li> <li>Each TODO item in <code class="language-plaintext highlighter-rouge">TODO.md</code> should be committed separately.</li> </ul> <h1 id="research-context-engineering-as-a-text-based-notion">Research Context Engineering as a Text-based Notion</h1> <p>Producing a clear plan and scaffolding for your agent greatly affects the results. Treat your AI like a junior engineer or researcher: highly capable, given clear instructions and context to succeed. This puts the onus on you to sufficiently understand your problem before you start building, and to take a step back and slow down if you realize you are missing something.</p> <p>One unclear instruction can produce one hundred bad lines of code that contaminate your codebase and creates compounding confusion: without good context management, future agent sessions will not immediately realize that this contaminated code is recently added and therefore suspect if something is going wrong, so it will be on you to hunt it down. In pure engineering, the expected result can be precisely defined with some effort, mitigating the risk of ever generating such code. In research it is generally much harder to provide such a precise requirement for your project, so more weight is placed on the initial instructions provided and your follow up interrogation of the output, before you learn what can be strictly asserted in a test. This is why agents in the hands of amateurs can cause equal parts euphoria and strife.</p> <d-figure> <figure> <img src="/assets/img/agent_eng/pov-0.1x-coworker.png" alt="POV your 0.1x coworker discovers AI."/> <figcaption class="caption"> One bad prompt, one hundred bad lines of code. </figcaption> </figure> </d-figure> <p>I like to think of the research artifacts as a continuum of text files spanning the paper itself <code class="language-plaintext highlighter-rouge">paper.tex</code> and the codebase, with many intermediate documents in between the two. These files all mutate at different rates: the paper rarely or never does, the codebase’s lines of code turn over like cells in the body. This hierarchy of temporal coherence stabilizes the project while allowing the codebase to mutate quickly.</p> <d-figure> <figure> <img src="/assets/img/agent_eng/doc_hierarchy.png" alt="The components and their relative levels of fluidity." class="invert-on-dark"/> <figcaption class="caption"> `paper.tex` and `design_doc.md` provide the relatively static intention for the project. External codebases and verification provide relatively unchanging anchors for the implementation. `TODO.md` and `notes.md` update with to reflect the current knowledge of the project's state, and future needs. The codebase itself and individual plans are updated rapidly. The state of the code itself can be used to periodically update the high level guidance documents to keep everything aligned. </figcaption> </figure> </d-figure> <h2 id="design-docs"><code class="language-plaintext highlighter-rouge">design_doc.md</code> and <code class="language-plaintext highlighter-rouge">paper.tex</code></h2> <p>As an initial step in a project, I like to draft my ideas as either a <code class="language-plaintext highlighter-rouge">design_doc.md</code> or <code class="language-plaintext highlighter-rouge">paper.tex</code>, depending on how formal I want to be. <code class="language-plaintext highlighter-rouge">paper.tex</code>, being the final product of the project, supersedes <code class="language-plaintext highlighter-rouge">design_doc.md</code> in cases where I have both, and often the <code class="language-plaintext highlighter-rouge">design_doc.md</code> is generated from the paper and detailed discussion with a chatbot. In either case, this document captures:</p> <ul> <li>The problem we are trying to solve or question we are trying to ask, the methods we will use to address it, and other relevant details required to structure the project.</li> <li>A linear roadmap of medium and short term objectives required to build out the project.</li> <li>High level project architecture that the agent should respect when designing new features so that you don’t end up with parallel systems providing similar or identical features. This should be provided at a fairly high level of abstraction but can include class signatures etc if you have a desired API or data flow that you want the project to respect. In general, I find it best to copy the architectures of existing reference codebases, allowing the AI to fill in the details.</li> </ul> <p>Usually, I will write the core idea myself, debate it with my agent, and then ask my agent to help me break it down into the roadmap. I review this document very carefully - every decision here has big impacts on the final codebase because <em>this is where the agent is going to draw many of it’s assumptions from</em>.</p> <h2 id="plans-todos"><code class="language-plaintext highlighter-rouge">plan.md</code> and <code class="language-plaintext highlighter-rouge">todo.md</code></h2> <p>From each element of the roadmap in <code class="language-plaintext highlighter-rouge">design_doc.md</code>, one can ask your agent to break each phase down into a plan, perhaps containing a list of concrete todos. The level of granularity here is proportional to the complexity of the project and find myself skipping this layer of abstraction for smaller projects (the TODO and design doc can coexist for those). The purpose of these subtasks is to give each agent a well-scoped feature or item to work on that fits easily in $&lt;20%$ of it’s context window.</p> <p>In order to make sense of your plan during implementation, your agent will <code class="language-plaintext highlighter-rouge">grep</code> around your codebase to find relevant elements. Depending on the structure of your code, this might be an inefficient use of context during implementation. For complex codebases where targeted interventions are required, it is useful to ensure your plan has all of the relevant landmarks in your codebase (line numbers, function / class / attribute / variable names, etc) which will orient the implementation agent directly to the important parts of your codebase.</p> <p>In general, these documents can be generated entirely by AI. They all treat the keyword “plan” as a distinct task - to produce a markdown document. I have a superstition that it’s actually better to do it this way because the plan is more likely to “make sense” to your agent if it’s written in it’s own voice. This is also a good opportunity to ask your agent to ask clarifying questions about the plan while writing it, so ensure you are aligned.</p> <p>Unless a task is simple, I use a unique agent to plan and another to implement, so that only the subset of the relevant planning context is consumed by the implementation agent.</p> <p>I find it a good practice to make each TODO item a single commit.</p> <h2 id="notes"><code class="language-plaintext highlighter-rouge">notes.md</code></h2> <p>On complex projects, while building, discoveries are often made. These might be quirks of the algorithms themselves, limitations of particular libraries, gotchas on particular compute clusters, the result of implementation research of other codebases, etc. These kinds of findings often don’t have a natural home in the plan documents but are important context to agents who are trying to solve problems in-flight. I like to maintain parallel <code class="language-plaintext highlighter-rouge">notes.md</code> files to store this information. These notes should periodically be compacted and maintained to keep track of only the elements which are not yet encoded in the codebase itself (as e.g., comments).</p> <h2 id="treat-git-like-savegames-rely-on-the-commit-history">Treat <code class="language-plaintext highlighter-rouge">git</code> like Savegames, Rely on the Commit History</h2> <p>As mentioned already, each TODO item should be committed separately with clear commit messages. These are your savegames - agents use git more professionally than any researcher I’ve ever worked with, and it’s extremely powerful in the right hands. Ask your agent to use git fastidiously - it’s generally better to let it drive this tool than for you to do it yourself. Ask your agents to produce PRs with detailed messages to add features to your codebase. This provides crucial context for code milestones for future you, your collaborators, and your agents.</p> <p>What this enables is asking your agent:</p> <blockquote> <p>The metrics for this experiment changed drastically in the past two weeks, but I’m not sure why. I have a few theories (insert theories here). Can you look through the history to determine when these changes were made so we can diagnose what change was made that produced this result?</p> </blockquote> <p>Your agent will rapidly traverse the git history, reading the commit messages and code diffs along the way, to help you rapidly converge on the possible causes of your issue. In projects with a few collaborators and many moving parts this can easily save you a day of running in circles in 20-30 minutes.</p> <p>As an aside - this is exactly why having actual tests is the gold standard - the breaking change would never have been allowed to be made in the first place. But since test driven development is inefficient and often too challenging or impossible to do quickly in a research codebase, this workflow serves as a good backup strategy.</p> <p>You can also use <em>worktrees</em> - which allow multiple agents to work in parallel copies of the codebase in a single project, implementing features in parallel on your machine. This is the sort of advanced git tooling that researchers almost never touch due to the complexity, but they can produce big performance unlocks when you let the agents handle the complexity for you. For everything git, it’s probably easier for you to ask your agent to do it directly. It’s worthwhile for researchers to start <a href="https://www.git-tower.com/blog/5-advanced-git-features">experimenting with</a> <a href="https://blog.gitbutler.com/git-tips-and-tricks">advanced features</a> to see how it improves your workflow.</p> <h2 id="per-agent-context">TODOs Manage Per-Agent Context</h2> <p>The planning work done before now allows us to pass each agent tightly scoped context to enable the work the proceed smoothly. For each TODO, I follow a workflow approximating the following:</p> <ol> <li>Pass TODO to agent.</li> <li>Agent implements, and we run verification.</li> <li>If verification turns up something is wrong about our plan, we diagnose together and store any learning in <code class="language-plaintext highlighter-rouge">notes.md</code>. These notes inform future rounds.</li> <li>When the step is done, we have the agent produce a <code class="language-plaintext highlighter-rouge">handoff.md</code> file to pass to the implementation agent for the following TODO. This contains any relevant context from this implementation round that should be useful for the next TODO.</li> <li>The next TODO is handled by a new agent, which consumes the handoff.</li> </ol> <h2 id="testing">Testing</h2> <p>Software engineering practices act as guidance for AI generation and are pretty much required for good results. AI works best when it can verify that it has done the right thing. Ideally, this means you have an executable test that ensures your code is correct. These can be written by independent test agents, provided with specific instructions to produce the correct code behaviour. Agents benefit from working code examples to copy from and verify against - working tests provide this and massively constrain the design space, making test driven development well-suited to agentic R&amp;D.</p> <p>Write simple tests/assertions or ask the model to generate tests verifying specific behaviours for you <em>before</em> asking for code. Use independent test writing and code writing agents, so the tests are less likely to be cheats to make the code pass.</p> <p>Agents also benefit from linting, typing, docstrings, and assertions to verify the code matches intent.</p> <h3 id="tooling-safety-and-environment">Tooling, Safety, and Environment</h3> <p>Don’t trust your AI, they’re mostly correct but have no regrets when making irreversible mistakes, which can often happen when agents are working in parallel and each is not aware of the other’s work.</p> <p>For sensitive tasks like database migrations or large filesystem manipulations, have your agent output a script you can verify and run by hand instead of trusting the full work to the agent directly. You can cross-reference this script with another agent as a sanity check as well. Things that exist only in the agent’s working memory are subject to mutation, things written on disk are static - leverage this.</p> <h1 id="anchoring-your-paper-to-your-code">Anchoring your Paper to your Code</h1> <p>While the final product of your work is typically seen as your paper, the majority of your work lives inside of your code. Throughout this process, we have been having design decisions flow from the paper, through the design docs, into plans and notes, and finally into the code. Discoveries and learning along the way inevitably mean the final product is not exactly that you initially intended - that’s research. So it’s crucial all of those small deviations from the original plan make it back into your paper. Luckily, agents are particularly good at identifying discrepancies between two texts, so this sort of thing works well:</p> <blockquote> <p>Please do a thorough analysis of the methods and results sections of the paper, and compare them against the codebase we have developed. Use a set of subagents to do this work in parallel. Ensure that all methodological details are captured in the paper, and that all results presented arise from the methods as described in the paper, noting any subtle deviations in the math from the current implementation. Don’t edit the paper directly, we can diagnose each deviation together sequentially before committing to a final fix.</p> </blockquote> <p>Then, this corrected document can be uploaded to a platform such as overleaf for a final round of writing with co-authors.</p> <h1 id="putting-it-all-together">Putting it All Together</h1> <p>These practices converge on a specific loop:</p> <ol> <li><strong>Explore:</strong> Ask the AI to read relevant files to strategically fill context. If required, write new findings down in <code class="language-plaintext highlighter-rouge">notes.md</code>.</li> <li><strong>Plan:</strong> Write a high-level specification for some new feature.</li> <li><strong>Linearize the Implementation into TODOs</strong>: Break down the plan into bite-sized chunks of work.</li> <li><strong>Produce Constraints:</strong> This is the step that most distinguishes agentic R&amp;D from ad-hoc prompting. Create tests or assertions, add types, docstrings, and boilerplate (or ask the AI to generate them), spell out explicit DO NOT requests, and pin down any other design requirements in your plan or in code as exactly as possible. Be <em>explicit</em> about everything relevant.</li> <li><strong>Generate:</strong> Ask the model to write the feature.</li> <li><strong>Verify/Repeat:</strong> Run the per-TODO inner loop described in <a href="#todos-manage-context">§TODOs Manage Context</a> — run tests &amp; linters, review the changes, and on verification failure diagnose together and record learnings in <code class="language-plaintext highlighter-rouge">notes.md</code>. Once satisfied, produce a <code class="language-plaintext highlighter-rouge">handoff.md</code> and begin again at step 1–4 with a fresh agent (most often, skipping straight to 4).</li> </ol> <d-figure> <figure> <div class="image-map"> <img src="/assets/img/agent_eng/workflow.png" class="invert-on-dark" alt="A diagram of the iterative multi-agent workflow: high-level planning artifacts feed a codebase agent with limited working memory, with external verification, parallel codebase updates, and subagents handling sub-tasks."/> <a class="hot" href="#design-docs" style="left:2%; top:6%; width:34%; height:5%" title="design_doc.md / paper.tex"></a> <a class="hot" href="#agent-file" style="left:40%; top:6%; width:15%; height:5%" title="AGENT.md"></a> <a class="hot" href="#plans-todos" style="left:4%; top:14%; width:22%; height:13%" title="TODO.md"></a> <a class="hot" href="#testing" style="left:39%; top:13%; width:32%; height:7%" title="Test Agent / external verification"></a> <a class="hot" href="#notes" style="left:55%; top:34%; width:11%; height:7%" title="notes.md"></a> <a class="hot" href="#per-agent-context" style="left:0%; top:65%; width:90%; height:35%" title="Per Agent Context"></a> <a class="hot" href="#external-codebases" style="left:0%; top:38%; width:21%; height:9%" title="External Codebases"></a> </div> <figcaption class="caption"> Recap of the Iterative Workflow with multiple agents. LaTeX (<code>paper.tex</code>) plans feed into markdown (<code>design_doc.md</code>) descriptions of the project. <code>AGENT.md</code> provides global rules <em>every</em> agent. The <code>design_doc.md</code> is linearized into <code>TODO.md</code>, each of which becomes a <code>task_plan.md</code>, and code changes. Agent context is scoped to the important information from your codebase, optionally external reference implementations, and your notes. External verification of correctness happens where possible, provided by you or by <em>independent</em> agents. Discoveries are recorded in <code>notes.md</code>. If necessary, notes are summarized and integrated back into high-level docs. Both text and code should be committed to the repo regularly to make changes / rollbacks easy. Agents can own <em>subagents</em>, which receive their own sub-tasks, enabling small chunks of work to happen in parallel. You can manage multiple agents using worktrees to handle multiple parallel issues simultaneously (each can have their own subagents). These parallel streams of work can cross reference each other's code / docs where required. </figcaption> </figure> </d-figure> <h2 id="a-new-standard-for-research-code">A New Standard for Research Code</h2> <p>We should raise the bar as a community for what constitutes acceptable research code. Before, the below requirements were too strict to allow for a reasonably fast project turnaround time with a small team - but that is rapidly changing.</p> <ol> <li> <p><strong>Projects typically start with a project plan which becomes the paper itself.</strong> This <code class="language-plaintext highlighter-rouge">design_doc.md</code> serves as a crucial starting point for the development of your new codebase, and your agent can consume it to help iterate on implementation ideas. There should therefore be explicit deep connections with the <code class="language-plaintext highlighter-rouge">design_doc.md</code> &amp; <code class="language-plaintext highlighter-rouge">paper.tex</code> throughout your codebase.</p> </li> <li> <p><strong>Typing, Comments, Docstrings, Variable Names</strong> not only helps the coding agents do their jobs, but helps downstream users reason about your code and understand how your paper is reflected in your code. Often deferred until the project’s end or never done at all - there is now a great incentive to do it throughout development as it directly benefits agent performance.</p> </li> <li> <p><strong>Testing</strong> is also a very helpful constraint for your coding agents to ensure they are building within spec, give you confidence in your own results, and also make it much easier for others to build on your work.</p> </li> <li> <p><strong>Thorough Demonstrations</strong> can now be built in a single sitting, which can greatly help the reader understand how your proposals work on real data interactively.</p> </li> </ol> <h1 id="tricks-for-better-performance">Tricks for Better Performance</h1> <h2 id="external-codebases">Warm Start Your Project</h2> <p>Your current codebase is a crucial part of the context used by agents when interpreting the intention of your prompt and the design space. This context constrains the set of possible generations that satisfy your prompt. If the repo is messy or incorrect, performance degrades because the context is <em>misleading</em>. When your repo is empty, performance degrades because the space of possible generations that match your prompt is much larger. You can test this easily by comparing the ease of use designing complicated features for mature libraries vs designing simple projects from scratch entirely using agents.</p> <p>You should never need to start fully from scratch. If you don’t want to build your project using a fork of another project, you can provide reference codebases from which to draw inspiration: these can be specified to guide methodological details or architecture. You can also build from a set of “stubs” - functions / class signatures that provide the high level structure of the architecture with the code details left unimplemented.</p> <h2 id="roles">Roles</h2> <p>I’ve discussed using agents fairly linearly, in a plan -&gt; implement -&gt; verify loop.</p> <p>Most of these individual tasks are best handled by different independent agents. To date I have not found much use for predefined skills for various subtasks - I tend to ask for specific “skills” directly in my prompt while problem solving. Perhaps I will evolve here and add a more structured workflow. In the meantime you can see <a href="https://www.google.com/url?q=https://code.claude.com/docs/en/skills&amp;sa=D&amp;source=docs&amp;ust=1771864382174337&amp;usg=AOvVaw3MVu9JoYrb9XYwBfJuE5mj">Claude’s Skills</a> for examples <a href="https://www.google.com/url?q=https://github.com/anthropics/knowledge-work-plugins&amp;sa=D&amp;source=docs&amp;ust=1771864382156083&amp;usg=AOvVaw1iniVOXlXvVNbKrTZzUXXD">applied to specific domains</a>.</p> <p>The kinds of roles I tend to ask for in one off prompts mostly include:</p> <ol> <li>Correctness reviewer.</li> <li>Test designer (best if done before the functionality is written and the agent is provided with clear requirements).</li> <li>Evaluator of the code’s intention vs the various docs we have written.</li> <li>Comparison of the codebase against external references.</li> <li>Data flow analysis to identify parallel pathways for data flow, and to identify refactoring opportunities to improve extensibility toward a long-term roadmap goal, or implementation simplification.</li> <li>Research: evaluating the literature, or finding discrepancies in the implementation vs. the docs, or subtle changes between two implementations.</li> </ol> <p><a href="https://manus.im/blog/Context-Engineering-for-AI-Agents-Lessons-from-Building-Manus">File Structure as Memory</a> uses skills to keep the core <code class="language-plaintext highlighter-rouge">agent.md</code> file small with only universal rules, and pointers to various <code class="language-plaintext highlighter-rouge">skills.md</code> required for specific tasks. Since agents often only need to do one of these things at a time, context is better scoped this way. For example, asking the agent to implement something points agents to <code class="language-plaintext highlighter-rouge">guidelines/coding.md</code>, and asking the agent to draft a methods section points it to <code class="language-plaintext highlighter-rouge">guidelines/latex.md</code>.</p> <h2 id="generate-clean-code---your-generations-become-your-context">Generate Clean Code - Your Generations Become Your Context</h2> <p>The superhuman speed of code generation makes it easy to get overloaded and stop paying attention. There a few ways I’ve found to manage this.</p> <ol> <li> <p>Constrain the diff. Without explicit scoping, agents will produce overlarge diffs that are tiring for humans to manage and blow up context, miss already-implemented features and reimplement them from scratch, or try to nail every concern in a single pass. Counter all three by being explicit about what to touch and what to reuse:</p> <ol type="a"> <li>Define the exact regions to manipulate, and ask the model to generate only the relevant code.</li> <li>Name the existing pieces it should leverage: “I want to build feature A — please use X, Y, Z to accomplish it, and ensure it passes these tests.”</li> <li>When one-shot success is unlikely, plan the work as two passes — a rough build, then a refactor (<a href="https://en.wikipedia.org/wiki/The_Mythical_Man-Month">plan to throw one away</a>). Often easier than getting it right in one go.</li> </ol> </li> <li> <p>After the code is built, you can ask for a high level summary of how the new additions work with a fresh, unbiased agent. If something is off, you can critique the design at this level of abstraction and fix it before moving on. These sorts of conversations often lead to design decisions worth capturing in your <code class="language-plaintext highlighter-rouge">notes.md</code>, and occasionally are the result of an underspecified <code class="language-plaintext highlighter-rouge">design_doc.md</code>, which should be updated.</p> </li> <li> <p>It is better to correct issues with the implementation through the agent chat, rather than doing it yourself. If you want, you can provide the exact solution you desire in the chat. If you change the code directly, it will not match the agent’s context and this can produce strange behaviour.</p> </li> </ol> <h2 id="managing-costs">Managing Costs</h2> <p>This section is primarily for graduate students and others who do not have expensive plans and want to get the greatest bang for their buck.</p> <ol> <li>Different products count usage differently. It is worth checking how many tokens each tool uses (by comparing them on similar tasks).</li> <li>Managing your context well limits your token usage!</li> <li>Plan &amp; break down into tasks with heaving reasoning models (e.g., Opus), then execute each TODO with cheaper models (e.g., Sonnet).</li> <li>Minimize what you put in your planning docs, regularly compact that information to prevent context bloat.</li> <li>Do rounds of refactoring and simplification on your code to prevent context explosion and running in expensive circles (spend money now to save money later).</li> <li>Restart your chats frequently, but not too frequently. For best <em>performance</em>, try to stay under &lt;40% context usage. For best <em>cost-efficiency</em>, it’s important to remember that each context re-start spends a bunch of tokens getting the agent up to speed on the problem. If you’re solving two related problems in sequence, you can probably avoid the reset.</li> </ol> <h1 id="postscript---game-engine-design-challenge">Postscript - Game Engine Design Challenge</h1> <p>Many research codebases are relatively small, and might not be the best place to practice the finer points of how to effectively wrangle agents. If want to practice the craft and develop your intuition, I suggest building a 3D game engine. There are many open source game engines out there (e.g., <a href="https://github.com/godotengine/godot">godot</a> or <a href="https://o3de.org/">o3de</a>) you can use as a reference, and these engines typically require substantially more code to be written than research libraries. Pick your favorite older game and try to re-create a working prototype or playable level. It’s addictive and will stress your ability to write specific specs, manage context, and come up with clever verification strategies beyond simple tests, because sufficiently sophisticated games are actually quite hard to test and the agent will often incorrectly state they’ve solved a problem when things are wildly wrong. This will sharpen your ability to describe requirements to the system with a tight, interactive feedback loop.</p> <p>Game engines share some similarities with research from a development perspective. Getting the desired behaviour out of what is effectively a physics simulator with game logic bolted on requires a precise description of behaviour that might not be easy to explicitly encode in a test - instead, you will likely playtest the engine to view the results of your recent changes. It also is an amazingly creative endeavour, which opens up a lot of opportunities for experimentation and design.</p> <p>This is my project: a modernization of an <a href="https://youtu.be/0shd5deF3es?t=644">old favourite of mine</a>. It has taught me a lot about effective workflows with codebases easily 10x more complex than what I work with on a typical research project. I’m far from done, but this is an example of the sort of thing I could never have dreamed of pursuing alongside my career before agents.</p> <figure> <video src="/assets/video/darkness.mp4" class="img-fluid rounded z-depth-1" width="100%" height="auto" autoplay="" controls="" loop="" muted="" playsinline=""></video> </figure>]]></content><author><name>Joseph Viviano</name></author><category term="agents"/><summary type="html"><![CDATA[Some notes from myself and the Mila community on how to use agents to do research effectively.]]></summary></entry><entry><title type="html">Continuous GFlowNets, in your browser</title><link href="https://www.viviano.ca/blog/2026/gflownets-continuous/" rel="alternate" type="text/html" title="Continuous GFlowNets, in your browser"/><published>2026-04-20T00:00:00+00:00</published><updated>2026-04-20T00:00:00+00:00</updated><id>https://www.viviano.ca/blog/2026/gflownets-continuous</id><content type="html" xml:base="https://www.viviano.ca/blog/2026/gflownets-continuous/"><![CDATA[<script defer="" src="/assets/js/gflownet-demo.js"></script> <p>Most introductions to GFlowNets target the discrete case. This post walks through the continuous version — sampling real numbers proportional to a reward — using a tiny pretrained policy that runs entirely in your browser. Every plot below is live: drag the temperature slider to rescale the action noise at sampling time, hit <strong>resample</strong> to draw a new batch.</p> <p>The example is adapted from the <a href="https://github.com/GFNOrg/torchgfn/blob/master/tutorials/notebooks/intro_continuous.ipynb">continuous intro notebook</a> in <code class="language-plaintext highlighter-rouge">torchgfn</code>. The training script that produced the models on this page lives at <a href="https://github.com/josephdviviano/josephdviviano.github.io/blob/master/scripts/train_distill_gflownets.py"><code class="language-plaintext highlighter-rouge">scripts/train_distill_gflownets.py</code></a> — run it yourself to regenerate them.</p> <h2 id="the-setup">The setup</h2> <p>The target is a mixture of two Gaussians on the real line. We start from $S_0 = 0$ and take $N = 5$ steps, each adding a scalar action $\Delta x \sim \mathcal{N}(\mu(s), \sigma(s))$ whose parameters come from a small MLP. The state is $(x, t)$ — we carry the step counter so the space stays acyclic.</p> <p>The model is a 2-layer MLP (hidden dim 64), about 4.4K parameters. It emits two numbers per state: a mean and a pre-sigmoid standard deviation that we squash into $[0.1, 1.0]$. Nothing exotic.</p> <p>Here is the reward landscape. Dashed lines mark the modes; the yellow dot is $S_0$:</p> <d-figure> <div class="gfn-demo-mount" data-model-url="" data-env-mus="-1,1" data-env-variances="0.2,0.2" data-env-init="0" data-trajectory-length="5" data-n-trajectories="2000" data-default-temperature="1"></div> </d-figure> <p>Before the real models load you will see samples drawn from a placeholder policy with $\mu = 0, \sigma = 0.3$. Once the ONNX files are deployed, the histogram should concentrate around the two modes.</p> <h2 id="a-happy-case">A happy case</h2> <p>The first model was trained with Trajectory Balance <d-cite key="malkin2022trajectory"></d-cite> on this easy environment, with the <em>correct</em> backward-probability loop (we will get to the bug in a moment). At temperature 1, the histogram of final states should track the reward curve pretty closely.</p> <d-figure> <div class="gfn-demo-mount" data-model-url="/assets/models/gflownets/easy_correct.onnx" data-env-mus="-1,1" data-env-variances="0.2,0.2" data-env-init="0" data-trajectory-length="5" data-default-temperature="1"></div> </d-figure> <p>Slide the temperature down toward 0 and the samples concentrate on the highest-reward regions (this is the GFlowNet-as-argmax limit). Push it past 1 and the distribution flattens — you are effectively doing a noisier version of the learned policy.</p> <h2 id="the-pedagogical-bug">The pedagogical bug</h2> <p>The Trajectory Balance loss requires matching the forward-trajectory log-probability $\log P_F(\tau)$ with the backward $\log P_B(\tau)$:</p> \[\mathcal{L}(\tau) = \left( \log Z_\theta + \sum_t \log P_F(s_{t+1} \mid s_t) - \log R(x) - \sum_t \log P_B(s_t \mid s_{t+1}) \right)^2.\] <p>In our setup the very last backward transition, $S_1 \to S_0$, is <strong>forced</strong> — all trajectories start at the same $S_0$, so under any backward policy that reaches $S_1$, the probability of stepping to $S_0$ is 1, i.e.\ log-probability 0. If you accidentally include that transition in the $\log P_B$ sum, you end up training a backward network to concentrate mass on a specific, arbitrary Δ, which distorts the gradient. The symptom: samples look <em>almost right</em> but skewed.</p> <p>Below is the same environment with a model trained with that bug in the backward loop:</p> <d-figure> <div class="gfn-demo-mount" data-model-url="/assets/models/gflownets/easy_buggy.onnx" data-env-mus="-1,1" data-env-variances="0.2,0.2" data-env-init="0" data-trajectory-length="5" data-default-temperature="1"></div> </d-figure> <p>The fix in the training loop is a one-character change: iterate the backward loop over <code class="language-plaintext highlighter-rouge">range(N, 1, -1)</code> instead of <code class="language-plaintext highlighter-rouge">range(N, 0, -1)</code>. The last (forced) transition then correctly contributes 0 to $\log P_B$ without being sampled.</p> <h2 id="mode-collapse">Mode collapse</h2> <p>Things get harder when the modes are far from $S_0$. Below, the modes are at $\pm 3$, still with trajectory length 5. On-policy training — sampling actions only from the <em>current</em> learned policy — gets stuck early on whichever mode the initial exploration happens to stumble into:</p> <d-figure> <div class="gfn-demo-mount" data-model-url="/assets/models/gflownets/hard_on_policy.onnx" data-env-mus="-3,3" data-env-variances="0.2,0.2" data-env-init="0" data-trajectory-length="5" data-default-temperature="1"></div> </d-figure> <p>The histogram at $T = 1$ should sit almost entirely on one side. Cranking the temperature up diffuses the samples, but it does not rescue the other mode — the policy simply never learned it.</p> <h2 id="off-policy-exploration">Off-policy exploration</h2> <p>The fix is to sample <em>training</em> actions from a noisier distribution than the current policy. Concretely: keep the same learned $(\mu, \sigma)$, but inflate $\sigma$ by a schedule that starts at 2 and linearly decays to 0 over training. The forward log-probability is still evaluated under the learned policy (not the exploration policy — that would bias the gradient), but the sampled trajectories now cover both modes:</p> <d-figure> <div class="gfn-demo-mount" data-model-url="/assets/models/gflownets/hard_off_policy.onnx" data-env-mus="-3,3" data-env-variances="0.2,0.2" data-env-init="0" data-trajectory-length="5" data-default-temperature="1"></div> </d-figure> <p>Same architecture, same number of iterations, just a different sampling distribution during rollout.</p> <h2 id="a-harder-case">A harder case</h2> <p>Four modes with varying scales, $S_0$ closest to the first mode, 10K iterations. This one is deliberately at the edge of what the default hyperparameters can solve — the tallest modes get learned first, and the small, far-away mode often remains undersampled:</p> <d-figure> <div class="gfn-demo-mount" data-model-url="/assets/models/gflownets/four_mode.onnx" data-env-mus="-3,4,6,10" data-env-variances="0.2,0.4,1,0.2" data-env-init="0" data-trajectory-length="5" data-default-temperature="1"></div> </d-figure> <p>Longer trajectories, more iterations, or a non-constant exploration schedule would all help here. The takeaway is that continuous GFlowNets scale with trajectory length, not with the number of modes directly.</p> <h2 id="on-temperature">On temperature</h2> <p>The slider on each demo multiplies the per-step $\sigma$ at sampling time — it has no effect on what was learned, only on how we draw from it. A few things to notice:</p> <ul> <li>At $T = 1$ you get the distribution the policy was trained to represent (ideally, proportional to the reward).</li> <li>At $T \to 0$ the policy becomes deterministic and you see the $\mu(s)$ trajectory repeatedly — effectively a greedy sample of the highest-probability path.</li> <li>At $T &gt; 1$ the per-step variance grows, which compounds across steps: for a trajectory of length $N$, final-state variance scales roughly with $N T^2$ (for a trained policy with similar per-step $\sigma$).</li> <li>For the mode-collapsed model, no temperature can recover the missing mode. Exploration at <em>training</em> time is a separate concern from exploration at sampling time.</li> </ul> <p>Temperature-tempering of a trained GFlowNet is the continuous analogue of the standard tempered-sampling trick. It is cheap, deterministic, and often enough to push a well-trained policy toward whichever end of the exploration-exploitation axis you need at inference.</p>]]></content><author><name>Joseph Viviano</name></author><category term="gflownets"/><summary type="html"><![CDATA[An interactive tour of sampling a continuous mixture distribution with Trajectory Balance — the pedagogical bug, mode collapse, and the off-policy fix.]]></summary></entry></feed>