Strands: AI That Remembers

an introduction to the strand methodology

A common frustration when developing anything complex is that the agent has to be taught about the project over and over again.

It is tempting to keep a session open so the context is not lost. The cost per turn then climbs, because the whole context goes back up each time you send a message — that is how these agents work. Caching makes the re-read tolerable, but an interruption — lunch! — can be very expensive. If the context gets huge it will be compacted, which is lossy and cannot be edited: there is no reaching into a summary to correct what it got wrong.

Writing documentation might help, but only if the agent reads it, and that is not something you can count on.

Which is where strands come in. A strand (as in a strand of thought) is a line of work, developed over time and kept clear of the others so that it does not tangle with the rest. The memory lives outside the session, in git, written in prose a human can read and edit.

None of which makes the sessions themselves disposable. They are worth keeping, backing up and indexing, and working in strands makes that archive even more useful. They hold a different kind of information, though. A transcript is a record of what happened on one day. A strand is the curated, focused source of truth for an area of work.

An archive of transcripts is mostly noise, and it is easy to conclude from that it is not worth keeping. But how much of it is noise turns out not to predict how well it answers a question. Going back to find when something was decided, or what an error message was, works — the ninety-odd per cent that was filler was never in the way of the part that mattered.

The unit between a repo and a session

A strand is a long-running theme that spans several repositories and gets revisited every week or so. Not a project, not a ticket, and not a chat log: a workstream with a curated memory attached.

Each one is a directory of plain files, itself held in a strands repository:

CLAUDE.md(or the vendor equivalent) The mission. What this strand is, which repos it spans, how a session should open.
STATE.mdThe durable memory. What exists, what is pending, what was decided and why. Deliberately not a log: it gets edited down.
IDEAS.mdAn inbox. Anything can append to it from any machine; it is triaged at the start of the next session.
dirsThe working directories this strand needs open.

Prose, not structure. This is a real entry from the state file of the strand that keeps this website, trimmed to fit:

## Pending / loose ends

- Half of all mywebsite invocations are one poller.
  /calendaralarm/api/rules was 1,436 requests in 24h — almost
  exactly one a minute, against a ~3,000/day total.

  The project is not under active development, but the poller
  is live. Do not read the silence as "safe to switch off":
  something deployed is still calling this every minute.

  Agreed when it is picked up: every 10 minutes by day, off
  at night — a 20x cut. That change belongs to the other
  project's timer, not to this repo.

Ten lines carrying a measurement, a correction from a human with the date attached, a warning aimed at whoever opens the strand next, a decision recorded without being acted on, and the name of whoever actually owns the fix. None of that survives in a conversation.

Because the files are in git, the memory is versioned, diffable and portable. When it is wrong you fix it with an editor.

Keepers and builders

Every strand is one of two kinds, and the distinction changes how a session behaves.

The kind is not a label kept somewhere on the side. It is the first word of the strand's one-line summary: if that word is Keeps, the strand is a keeper, and anything else makes it a builder. Tooling reads it there, and so does a session as it opens — which is why the rule is mechanical rather than a matter of taste.

What they look like in practice

These are real strands, in daily use on one estate:

mywebsiteKeeper. This website: the Lambda behind it, the edge rules in front of it, and everything already measured about both.
astro-pipelineBuilder. Turns raw sensor frames into calibrated, catalogued, quality-scored data, across several machines.
astro-storageKeeper. The storage lifecycle of every camera stream — squash, ship, retain — held as one system rather than per camera.
ansibleBuilder. Changes hosts. Applies fleet configuration and fixes the drift that accumulates between applications.
pifleetKeeper. Who is in the fleet, and whether each always-on host is up.
aifabric-sessionsKeeper. The transcript archive and its search index — the other half of the memory, the one nobody curates.
towhomKeeper. Owns no code at all. Reads across every other strand and holds the whole-estate picture, and the single ordered backlog.

Two things in that list matter more than the names. The strands do not map one-to-one onto repositories — most span several, and the last owns none. And one person runs all of it, which is the point being made: the method is what makes that possible.

Take the first, since you are looking at what it maintains. This site is not what a model assumes a website is. There is no Apache, no nginx, no server at all — every page is assembled on demand by a Lambda function behind API Gateway, and the gallery pages are built at request time from artifacts sitting in S3: last night's exposures, the fleet's status, a stack from a camera that spent the night pointing at cloud. Almost nothing here is a static file waiting to be served.

Which is exactly the kind of project a fresh conversation gets wrong. Told only that it is a website, an agent reaches for the framework it has seen ten thousand times and starts editing files that do not exist. The keeper's state file settles that before the first question is asked, along with what has already been tried, measured and rejected. These pages, the public and private contents split, and the frame-stepping in the video player were all built by it — each in a separate session, none of which remembered the others, all of which read the same STATE.md.

The loop

Say you have an hour and you want to spend it on this site's image caching. You do not open a chat and start explaining what the site is, which framework it is not built on, and what you tried last month. You start the strand that already knows:

$ strand mywebsite

That is the whole entry. The launcher moves into the strand's directory, loads the mission and the state file, opens the repositories this strand works across, and colours the terminal so you can see which one you are in. The agent's first words are what is pending and what was decided last time. The work starts at the second sentence rather than the fiftieth.

From there the cycle is the same every time:

The discipline is in the documenting. A state file that is never pruned decays into a second inbox, and then into noise.

Improving, not degenerating

A long conversation gets worse as it runs. More accumulates, less of it matters, and the part worth having is harder to find. A strand moves the other way. Every visit prunes the state file, so what survives is what turned out to matter, and the strand gets sharper about its own subject each time it is used.

When one area needs more depth than the strand should carry, it can be forked off into a strand of its own. That keeps each of them focused, and keeps material that has no bearing on the question out of the agent's context. Irrelevant detail does not sit there harmlessly; it blunts the answers.

Where the saving comes from

Not from buying a smaller model. It comes from not paying to explain the project again. Most of what makes an agent expensive is rediscovery — working out what this is, what was decided and why, before it can start on anything — and that bill arrives at the top of every fresh conversation. A strand settles it once, from a file, in the first few seconds.

The goal is the cheapest thing that can actually do the job, and the usual advice about how to get there is wrong. That advice is to tier the model down: plan with the expensive one, hand the writing to a cheap one. My experience is that anything below the best model available is a false economy. The work comes back — not always, but often enough to lose the saving and the afternoon with it, and you have then paid for it twice.

The dial that does pay is how hard the model is asked to think. These agents expose it, and it moves cost far more than most people realise. Maximum reasoning for planning, where being wrong is expensive and the output is short. Something middling for carrying the plan out, where the thinking has already been done. Same model throughout, so nothing has to be re-explained at the handover and no work comes back.

This is where the files pay for themselves a second time. Effort is, in the end, the model working out what it has not been told. Give it the architecture, the conventions and the last six decisions in writing, and there is simply less left to derive — so the same task genuinely completes at a lower setting, rather than appearing to and failing later. Context substitutes for reasoning. That is the saving, and it compounds, because the work recurs.

Below all of that sits the rung worth aiming for: no model at all. Anything a strand has learned to do the same way every time can be written down as a script, and then it costs nothing to run.

What the files do buy is freedom of model. The brief is the strand plus the house rules plus the tools and how to use them, and none of that is vendor-specific: the standard setup here is Claude Code, but the same launcher briefs Gemini and Copilot from the same files. So a second backend can be put on the same question — sometimes deliberately adversarially, to argue against the first — and it arrives already knowing what it is looking at. A reviewer who has to be briefed from scratch is not worth the trouble. One who reads the state file and then disagrees with you is.

The end of a keeper

A keeper that does its job well can eventually stop needing to be an agent at all. Once the subject is understood well enough, what the strand does can be written down as a deterministic script and added to the tools, where it runs the same way every time and costs nothing to call. The strand is then archived rather than deleted, and can be revived if the subject turns out to have more in it.

Being replaced by a script is a success for a keeper. Anything that can run deterministically should.

Running them

What this needs is a terminal coding agent — Claude Code, or Gemini's equivalent — rather than an assistant living inside an editor. That is a working requirement, not a preference, and it follows from wanting more than one strand at a time.

An agent embedded in an IDE is singular by construction: one window, one project, one conversation, and a second one means a second window pretending to be a second you. A terminal agent is just a process. Seven can run at once, each already in its own directory, on its own mission, in its own colour — and none of them waiting on the others.

It also puts the tools the right way round. The agent is not a panel inside the editor; the editor is one of the things the agent can open. It brings up a file it wants you to look at, an image viewer on the frames it has just produced, a browser at the page it has just deployed. Anything you can start from a shell is available to it, which is a much larger set than any plugin interface offers.

Several strands at once wants a board. Each live strand is a labelled pane, so you can see which are working and drop into any of them. Work is not serialised behind one conversation.

And they talk to each other. A strand can send another a message: a spool that persists until the recipient next opens, and a doorbell that wakes one that is already running. That matters because work constantly turns up things belonging somewhere else. Routing a finding to the strand that owns it beats leaving it in a transcript, where it dies.

The launcher and the board are conveniences, not requirements. A few terminal windows and the files themselves are a perfectly good first step, and the method works before any of the tooling does.

Letting the operating system do the guarding

Agent tools ask you to approve actions one at a time. In practice that is a bad bargain: either you read every prompt, which is laborious and slows the work to a crawl, or you stop reading them, which is worse — and the usual endpoint is turning permissions off altogether. Neither a prompt you no longer read nor a bypassed check is a boundary.

Order makes something better possible. Because a strand is a durable, named unit rather than an ephemeral conversation, an identity can be attached to it — and then the operating system does the guarding, with file ownership and sudo deciding what an agent can reach. That is fine-grained, standard, auditable, and it holds whether or not anyone is paying attention.

So a strand can run as its own operating-system user rather than as you. Its processes, caches, temporary files and uncommitted working state are its own, so one strand cannot quietly disturb another's, and whatever it does is attributable in the process table.

Groups are deliberately coarser than accounts. A group marks a trust zone, not a project: everything personal in one, anything confidential in another. Per-project groups were considered and rejected — they add synchronisation friction, leak internal names into shared tooling, and buy almost nothing over a clean boundary between zones.

The identifiers are allocated from one registry and shared between machines, so a file carried from one estate to another keeps its ownership instead of arriving as somebody else's.

Opt-in per launch at present, not yet the default: this is the daily launcher, and a regression there would cost every session on the desk.

The tools around it

The files are the method. A set of small tools keeps the habit cheap enough to actually follow, and most of them do one thing.

Running a strand
aicliOpens a strand: moves into its directory, loads the mission and state, opens its working directories, colours the terminal.
strandsLists them, marking which are live, and creates new ones from a template.
strand-psWhich strands are running, and where.
panedeck, paneThe board: every live strand as a labelled pane, and the verbs to drive one from another.
forktermForks a session into a peer in its own window, either warm or briefed cold into another strand.
Working in one
ideaSpools a thought into a strand's inbox from anywhere, without stopping what you are doing. It commits and pushes itself, so nothing is lost to a closed terminal.
dcpDocument, commit, push. One command at a checkpoint: update the state file, commit, push.
resumeWrites the standing summary at the top of a state file, so a fresh session knows where it came in.
Talking between them
strand-mailboxThe spool. A message waits here until the recipient next opens, which is the half that survives a closed session.
dingThe doorbell. Wakes a strand that is already running, for when the moment matters more than the durability.
Remembering
sessionsEvery transcript indexed into an OpenSearch database, searchable long after the conversation that produced it is gone.
backupState lives in git repositories with remotes; the transcript archive is held on a server of its own. The memory outlives any one machine.
Guarding
strand-accountsProvisions the per-strand user accounts and zone groups described above.
leak scansCheck transcripts and repositories for anything that should not travel, before it does.
Across all of them
backlogOne ordered list for the whole estate. Anyone adds to the bottom; one strand does the ranking, being the only one that sees across them all.
proposalsThe drawer of arguments about what to build next, with an index that will not let one be quietly forgotten.

A sketch rather than a manual; each of these deserves its own page.

Scalable, dependable strands

A state file is the single source of truth for its area, continuously reviewed and improved as the work goes on. An LLM can read it, a person can read it, and both can edit it.

That is where the dependability comes from. A compacted conversation that has picked something up wrong cannot be reached into and corrected, and it goes on quietly steering the answers. A state file is text you can fix.

It scales because each strand carries only its own area, so adding another does not make the existing ones heavier. Sessions get cheaper too: a fresh one that reads a good state file is useful straight away, so there is no reason to keep a long conversation going past its useful life.

The tools described here are in daily use rather than written up as theory.

Putting this to work in a team

Everything above is one person's estate. The method was built there, but the problem it solves is worse in a team: several people teaching the same agent the same codebase, none of them able to see what the others' sessions concluded, and every good decision ending up in a transcript nobody else will ever open. A strand is memory the whole team can read, review and correct — in a pull request, like everything else you already trust.

The shape that fits a team is two layers. Each person keeps their own strands, because the work is theirs and the judgement in a state file is personal. Alongside them sits a team strand holding what turned out to be shared: the architecture everyone builds against, the conventions, the decisions nobody should have to rediscover. The shared layer is factored out of the personal ones rather than written first — when the same fact has been stated in three people's state files, it belongs in one place and gets promoted there. That is the prune-and-promote discipline described above, applied one level up.

What that buys, beyond not writing the same paragraph three times, is that disagreement becomes visible. Two developers holding different beliefs about the same system is normal, and usually stays invisible until something breaks. Here both beliefs are prose in git, about a named subject — so they can be compared, and a contradiction between a personal strand and the shared one is worth flagging the moment it appears. Either the shared file has gone stale or somebody is working from something that stopped being true, and both are better found on a Tuesday afternoon than during an incident.

The two-layer split is a design rather than something already running: one person's estate has no second layer to factor out of it. It is the first thing I would build with a team that wanted it.

I take consultancy work setting this up. In practice that means finding where the strand boundaries in your system actually fall, writing the first state files alongside the people who own each area, putting in the launcher and the commit habit that keep them current, and deciding what an agent is allowed to reach. It is a small amount of tooling and a large amount of judgement about what is worth writing down.

If your team is spending real money on agents and getting inconsistent work back, that is the symptom this addresses. Tell me what you are running and I will tell you whether it would help.

You need nothing from me to start, and I would rather you tried it first. Open three terminal windows. Give each one a directory, a file saying what that piece of work is and which repositories it touches, and a second file saying where it has got to. Point an agent at each. At the end of every session, make it write down what changed and what is still pending, commit that, and clear the context. Come back tomorrow and start from the file rather than from the beginning. That is the whole method — everything above is what it turns into once you have lived with it for a year.

If you would rather start from something already written down, the cut-down version is public: github.com/PeterGrecian/ai-strands. It holds the idea and its anatomy, the three files a strand needs as a template, and strand-new — about fifty lines of bash with no dependencies. Nothing in it is specific to my machines.

This page is a deliberate cut-down, and so is that repository. A running estate also grows messaging between live sessions, a way of forking one into a new terminal with a briefing, families of strands under a parent, a dictation index that maps misheard words back to house nouns, and a fair amount of arithmetic about what a context window costs. None of it is load-bearing for the method, and all of it makes more sense after a month of doing the simple version.

peter@petergrecian.co.uk · LinkedIn