How to Use GitHub as Long-Term Memory for Coding Agents
Claude Code and every other coding agent forget everything between sessions. Long-term memory management, choosing what the next session reads, and the GitHub artifacts that hold it.
When you begin a fresh coding session, it knows nothing of what you did before. The model stores no trace of the project, of prior choices, or of work done yesterday. Whatever linked the previous effort together must be reconstructed. Achieving that demands an agentic coding skill using an issue tracking system, like GitHub or Beads.
The skill here is long-term memory management. Deciding what the model’s next session reads, what stays stored until it starts and what you’ll have to provide in the conversation then.
Here I demonstrate the practical side. I explain what must be stored in a saved memory so that a history-free session can run it, which choices belong in the repository, and how the work indicates completion. Once you master the technique you can launch a session that resumes exactly where the previous one left off, deploy multiple agents on a single repository without interference, and keep a loop alive while the work stays intact.
My code-generation pipeline for go-unix-utils runs in discrete rounds, each round launching a fresh session that reads the project state from a file. One time, mid-execution the planner suggested building a package the same run had already finished two hours earlier. No error was raised. A lingering entry kept the package marked as pending, and for a session without any memory, pending is the only reality. In an interactive chat I would have caught it with a single line, “we already did that,” and I would have skipped over the fact that my correction was the system’s sole recollection of what was previously done.
That one-line correction is one of four jobs you perform without noticing whenever you work through chat. You serve as memory, coordinator between code generation tasks, shared context, and stop condition. You act as a stateful wrapper around a stateless engine. I didn’t fully realize this when I built a specification-driven development pipeline. I had assumed the model performed the work while I guided it. When I stepped back, executed the pipeline 46 times, and observed all four jobs disappear, I realized those functions had been mine.
Industry calls the step of removing yourself “loop engineering.” Boris Cherny, creator of Claude Code, now says he stops prompting the model, “my job is to write loops” [7]. Addy Osmani describes the practice as “replacing yourself as the person who prompts the agent” [7]. Both point to the human as the bottleneck, yet neither explain what that bottleneck did all day. It spent its day on the four jobs. For loop engineering to work, that work has to be transferred somewhere else.
What I describe is akin to the blackboard systems of the 1980s, where independent specialists read from and write to a shared structure while a control component selects the next worker [10] [11]. Here the agents are the specialists and GitHub functions as the blackboard. The control component is you.
Figure 1. The blackboard. Every agent session reads and writes one shared structure and none of them talk to each other. The state lives in the issues, the specs and contracts live in the repository, and the control component deciding who works next is you.
The memory loss between sessions is only half the problem. LLMs also act non-deterministically. The same prompt with the same parameters can produce different results, and hidden serving conditions push them further apart [1] [2]. When a conversation lengthens, the drift builds; the model’s replies retain the same confident façade, giving no hint that it has strayed. Only you, in the dialogue, notice and pull it back.
The textual records I present here constitute a stable record of what the model is meant to be working on.
What a saved issue looks like
Each ticket in my repositories is produced by a model, then I sign it off before it reaches the tracker. The machine records its own memory. What stays human is the format, the decision about what the next session must load, what must survive in writing, and what may die with the conversation. Below is a working issue from the go-unix-utils tracker, condensed.
required_reading:
- docs/specs/software-requirements/srd003-format.yaml
- pkg/format/humansize.go (contract stub from a prior task)
files:
- path: pkg/format/humansize.go
action: modify
note: implement HumanSize with binary and SI unit conversion
requirements:
- id: R1
text: convert int64 bytes to a human-readable string with K/M/G/T
suffixes; 1024-based units when Binary is true, 1000-based otherwise
design_decisions:
- id: D4
text: may import pkg/sys; must not import any cmd/ package
acceptance_criteria:
- id: AC1
text: go build ./pkg/format/... succeeds with no errors
- id: AC3
text: HumanSize(1024, HumanSizeOpts{Binary:true}) returns "1.0Ki"
Each field encodes a decision about what may occupy the new context window. I store the data in YAML to enable programmatic reading of the issues. The required reading tells which files the next session will pull in. Files and design choices carry constraints that are not to be revisited, the import ban among them. Completion is measured against acceptance criteria, expressed as concrete commands and observable behaviour. Anything beyond these fields in a drafting discussion is left out on purpose. I arrived at the set of fields by trial and error, and several trace back to failed code generation jobs.
The commands are the issue’s lifecycle
Four commands shepherd an issue through its life. make-work proposes it, reading the repository and the tracker, and a human approves it before it exists. gh-issue-push writes it into the tracker, in the format above. gh-issue-pop splits it into sub-issues on a worktree branch of its own. do-work executes the sub-issues one at a time, reading only the issue bodies and the repository, and merging the pull request closes it. The loop engineering article shows how to run the commands.
The long-term memory management skill is organized into four steps, one for each of the four jobs you may be doing in a chat. Each step shifts whatever you were doing in chat into an artifact that the next session can read.
Step 1: Replace your memory with the issue tracker
Memory across sessions is the first job. When gh-issue-push logs a task, the issue body captures each file the task touches, the acceptance criteria, and the job’s size, because the executing session reads only the issue. That is the test of a working memory. Could an outsider run the task using just the body. The planner is make-work, and it looks solely at open issues, so “done” ceases to be a judgment call. Done now equals closed. Before proposing anything new, make-work also verifies the tracker’s claims against the code, so a lingering entry cannot fool it the way one fooled the run this article opened with.
The reading half is composed of gh-issue-pop and do-work. Pop splits an issue into sub-issues on a worktree branch, and do-work runs each sub-issue one at a time, using only the issue bodies and the repository. No trace of the planning conversation remains, and none is needed. Merging the pull request closes the issue.
Figure 2. State lives in the tracker. The planner sees only open issues. A fresh session reads the issue body and nothing else, the pull request merges, and closed is what the next planning pass reads as done. A closed issue is never proposed again.
I discovered this step is needed when the planner started re-proposing finished work. The project description marked every package pending and gave no completion signal, so the planner spawned tasks for packages the run had already built. In chat you reply immediately, “we already did that,” while your mind retains the project state. Left unattended, nothing retains it.
The pipeline is cobbler-scaffold. Six weeks of instrumented execution yielded 320,000 lines of Go [5] [6]. Its logs reveal that almost three-quarters of planning cycles suggested work that was already complete, and about half of the generation cost of a single run was spent recreating the same artifact. When the tracker became the state, the re-proposals dropped to zero.
Step 2: Replace your coordination with contracts
The second job is coordination between code generation tasks. In a chat setting the interfaces exist only in your mind. When you put them on paper, coordination requires two artifacts located in two spots. The sequence is stored in the tracker. Every shared package receives a contract issue; any implementation issue that depends on it records that dependency, guaranteeing the contract task runs first. make-work then proposes the batch in that sequence, and the dependency is attached to the issues themselves.
The contract resides in the code base, not in the issue record. The contract task commits stub files that contain the public types and signatures, the implementation issues list those stubs as required reading, and any implementation that diverges from them fails to compile. The agent cannot guess at an interface already defined, so the destructive alternative vanishes.
Figure 3. The contract lands before the code. Without a contract, two isolated tasks invent incompatible interfaces and the second erases the first’s working code to compile. With a contract issue pushed first, both tasks read the same public types and the destructive option disappears.
I discovered this step is needed when two tasks collided. Each coding task executed in isolation, and when two of them produced the same shared package, each built its own interface. Faced with the type mismatch, the later task overwrote the earlier task’s functional code so compilation could succeed. In a chat diff you see, “Wait, that function already exists with a different signature,” and you become the conduit between the task and the broader codebase. This pattern is not unique to me. Misalignment among agents ranks among the most frequent failure modes in the MAST taxonomy of multi-agent failures [3], and SWE-Bench Pro supplies agents with explicit interface specifications because, absent them, even correct solutions emit interfaces the tests never anticipate [4].
My logs show tasks that lack contracts consume 20 to 34 API turns, and they sometimes break working code along the way. With contracts, the count drops to 4 to 10 turns. I served as the contract. Now the specification fills that slot.
Step 3: Replace your mental map with the repository
The third job is the shared context, the map of what already exists. The map lives in files inside the repository, the same files a saved issue lists under its required reading. Three records carry it. Shared protocols list cross-cutting patterns, package contracts define the shared APIs, and dependency declarations note which modules import which packages. Before proposing any new work, make-work consults this map first. Treating project knowledge as infrastructure rather than documentation is the route others have taken as well [12].
Figure 4. The map lives in the repository. Shared protocols, package contracts, and dependency declarations are read first by the planner and by every fresh session, so the code that already exists gets reused. Duplicated lines at the eight-utility mark fell from 297 to 18.
I discovered this step is needed when the duplicates piled up. A signal handler appeared in eight packages and test boilerplate in seven, 297 duplicate lines, seven percent of the code written to that point. In a discussion you are the one who says “we already have that in pkg/utils,” and without you the agent rebuilds everything, because nothing signals that anything can be reused. With the three records in place, the next run produced 18 duplicated lines. The mental map has left my head and now lives in the repo.
Step 4: Replace yourself as the stop condition
The fourth job is the stop condition, the most easily overlooked of the four; in a chat it appears the moment you close the tab. The tests now enforce it. Every requirement carries acceptance criteria written as commands, and execution halts when each requirement has cleared its test and the planner offers no proposal that links to an unresolved item. That is the exit rule of do-work. A unit is not deemed landed until it passes all its checks.
Figure 5. The tests decide when the run ends. Every requirement carries acceptance criteria that run as commands. The run continues while requirements fail or proposals trace to open ones, and it ends when neither holds. Not the agent’s call, and not your tab to close.
I discovered this step is needed when a run refused to end. My logs record the planner averaging 3.4 extra improvement cycles after every requirement had been met, with better error handling, more edge-case tests, tighter naming, each proposal reasonable and each draining tokens without bound. In chat this is the moment you close the tab. Declining feels like abandoning quality, so you push forward, and you stop building. You begin to orbit. Completion is a property of the requirements and their test results, both stored in the repository for the next run to examine.
Replacing yourself is harder than seeing yourself
When the four jobs appear, the natural step is to log them and let each run alone. The work then stretched across weeks, and nothing resembled the original description.
Three passes were required to nail the scope filter. The opening pass sliced too far, obscuring work that was only partially completed. The following pass swung the other way, surfacing finished tasks under other labels. The final pass landed correctly; it logged each requirement individually instead of by package, a bookkeeping-style tweak that became the decisive factor.
Contracts demanded a new specification format. In the first trial the interface definitions were embedded as comments in the task description, and the agent treated them as optional hints. In the second trial the definitions were placed in separate files; the agent read them, yet sometimes disregarded them when the code seemed to call for a different solution. In the third trial the contracts became part of the compilation pipeline, so any implementation that violated its contract caused compilation to stop, and that restriction remained in force.
The termination rule fired early, on two occasions. In the first strategy the run halted the moment every test succeeded, although some requirements never received a test. The second strategy held the process until each requirement displayed a passing test, yet the agent occasionally logged a requirement as tested on a negligible case. The third strategy compared test coverage to the complexity of each requirement. Close enough.
The four roles stayed fluid in chat, shaped by context that never required explicit definition. When I transferred them to a document, the underlying logic emerged, and the gap between “I know it when I see it” and “here is a rule that captures it” proved wider than I had expected. I spent a month failing to automate myself, uncovered the components of my judgment calls, and eventually reproduced them well enough that the pipeline operates without my intervention most of the time. Not all of the time. Most.
Where the memory lives
Anyone who tries to scale loop engineering meets the same recurring roles. One founder calls coding agents “fast interns who never remember yesterday” and ships a memory server that persists their state on disk [13]. I add no new infrastructure; the tracker and the repository were already there. A Pragmatic Engineer survey of developer loops repeatedly notes the same things. Agents drift, budgets spike, and results lift when a human remains in the loop [7]. At the AI Engineer World’s Fair, critics landed on “the hype is outrunning the discipline” [8]. Cherny’s adoption ladder likewise marks the human as the bottleneck at every rung [9]. In reality the whole practice boils down to four jobs. The loop engineering article shows how to run the loop; this one shows what the loop remembers.
Figure 6. The four jobs and the artifacts that took them over. Each job you do invisibly in chat becomes a durable artifact a fresh session can read. The left column is you. The right column is the tracker and the repository.
The model keeps drifting. Determinism appears only when you control the serving stack [1], and an API never hands you that control. What you can set is the input for the next session. Choosing it is long-term memory management, the human skill that endures. The model does the writing. State resides in the issue tracker, where “done” means “closed”. Contracts and specifications live in the repository. Termination shows up in the test results. Together they form an agent’s long-term memory. The repository remembers what you used to.
REFERENCES
[1] Thinking Machines Lab (2025). “Defeating Nondeterminism in LLM Inference.” https://thinkingmachines.ai/blog/defeating-nondeterminism-in-llm-inference/
[2] arxiv.org (2025). “Understanding and Mitigating Numerical Sources of Nondeterminism in LLM Inference.” https://arxiv.org/abs/2506.09501
[3] Cemri, M. et al. (2025). “Why Do Multi-Agent LLM Systems Fail?” arXiv:2503.13657. https://arxiv.org/abs/2503.13657
[4] Scale AI (2025). “SWE-Bench Pro: Can AI Agents Solve Long-Horizon Software Engineering Tasks?” https://arxiv.org/pdf/2509.16941
[5] Djukic, P. (2026). “Dude, Where’s My Code?” Mesh Intelligence. https://meshintelligence.substack.com/p/dude-wheres-my-code
[6] Djukic, P. (2026). “What Does $33 of AI Code Generation Buy You?” Mesh Intelligence. https://meshintelligence.substack.com/p/what-does-33-of-ai-code-generation
[7] Orosz, G. (2026). “What is ‘loop engineering?’” The Pragmatic Engineer.
[8] Latent.Space (2026). “AIEWF Daily Dispatch: The great loops debate and the state of AI engineering.”
[9] Cherny, B. (2026). “Steps of AI Adoption.” LinkedIn. https://www.linkedin.com/posts/bcherny_steps-of-ai-adoption-activity-7483695059843043328-LBg_
[10] Hayes-Roth, B. (1985). “A Blackboard Architecture for Control.” Artificial Intelligence, 26(3), 251-321. https://doi.org/10.1016/0004-3702(85)90063-3
[11] Nii, H. P. (1986). “The Blackboard Model of Problem Solving and the Evolution of Blackboard Architectures.” AI Magazine, 7(2), 38-53. https://doi.org/10.1609/aimag.v7i2.537
[12] Mayer, U. M. (2026). “Scaling your coding agent’s context beyond a single AGENTS.md-file.” AI - the Deep, the Curious and the Fun.
[13] Kipnis, A. (2026). “Your AI forgets everything between sessions. I built the backend that remembers.” Substack.
The research and the ideas here are mine. I draft with AI assistance, then revise the text and verify every factual claim against its source. My full process is written up in How to Build a Writing Pipeline. I stand behind all of it.










