Skip to main content

Writing the History of Software

· 8 min read

I have several projects I periodically update now as the sole maintainer. A few are projects I was on from the beginning, so I know the journey they took. One or two are new to me, and the people who carried that history are gone, changed roles, or told me to figure it out. I have the source code. I have the repos. I have all the commits. The source code should speak for itself.

But is source code enough to explain the choices inside it?

This is where I find myself as the project list grows and the maintenance load grows with it. How do I tend this garden of projects without losing the story of why each one became what it is?

The problem

This issue of a better way to tend my garden of projects used to feel casual and theoretical. Now it is immediate. It starts with knowing what is in the source code, but not in some general way and not in some grep/regex way. I need a true, deep understanding of the choices, consistencies, and inconsistencies. Together, they should form the history and choices as well as the current state. From that, I can move forward with changes that do not impair or detract, or worse, unknowingly change the purpose of the project.

Woman at a crossroads holding the project book, ready to choose the path forward

An opportunity to write the history

There is a lot of software out there to help with this brownfield problem space. People come and go in the industry so companies have no choice but to figure it out. There are a few problems the solution would have to tackle but understanding how to determine the guiding principles from the in-the-moment choices is the key. It is similar to determining a book's theme from its scenes and characters.

There are many vector-based solutions that can gobble up the source code, commits, comments, issues. From there you can begin to build the guiding principles and choices.

I turned to AI to help me figure this out and one of the answers pointed me to spec-kit. There is enough internal chatter at Microsoft that I had heard of it before. After comparing options, pairing it with my multi-agent orchestrator (Squad), and looking through a brownfield lens, I had a path forward.

Two steps back

I can use something like spec-kit brownfield extension to come up with the main artifacts, then supplement with Graphify queries to solidify the details of the current state. This may seem like a lot of work, but with agents and skills, this process is quickly completed.

The project book, as a living artifact, should now be ready to review. It becomes the reference guide, the map that ensures every decision keeps the project on track. It should include:

  • Guiding principles - general design, stack and architecture
  • Features - what the project does and did
  • Core team - who they were, what they cared about, what they put off to a future state
  • Edge cases - the bugs reported, the features not quite complete, the dependencies that haven't aged well
  • Concerns - what are the features or class of bugs that need to be immediately reviewed and fixed

As more and more repos are created and many more are abandoned or in maintenance mode, the tools and skills to come into these projects quickly and move fast to understand and prioritize future work without disrupting current state will be important.

At this point in the process, the book is reviewed and the next steps are decided. How do I build using the book?

Relying on the team

I've been using Squad, my team of agents, for so long I can't imagine working without them. They know my own style, choices, and history. They just don't know this new-to-me brownfield project. For this journey on the project, the book is the rules, the road, and the map. My team is the car keeping the project on the road, safely, to get to the next stop on the journey.

Squad has its own history it keeps in decisions, identity, ceremonies, and project context.

The squad has an architect that will manage the book and decide what stays in the Squad and what moves to the book. This is where things can get muddled. And they do in real life. The real-life architect has a push and pull with the engineering team.

Woman at a workbench, carefully sorting decision cards between two containers: one for Squad's operational memory, one for the book's institutional memory

To keep that from becoming chaos, I've started using a few simple guiding principles that create clarity without argument:

  • If it explains why we made a decision, it goes in the book.
  • If it is a temporary way to get through this sprint, it stays in Squad.
  • If a new maintainer would need it to avoid breaking something important, it goes in the book.
  • If it changes every week, it stays in Squad.
  • If it crosses feature boundaries or affects architecture, it goes in the book.

Another way I think about it: Squad is operational memory, the book is institutional memory.

Squad should carry the active context for doing the work today. The book should carry the durable context that keeps the work safe, consistent, and grounded.

When I'm unsure, I run a quick test:

  • Will this still matter in 90 days?
  • Does this capture a non-obvious tradeoff?
  • Would I want this during an incident review?

If two of those are yes, it gets promoted to the book.

That gives the architect and the team a shared rule. Less opinion. Less tug-of-war. More forward motion.

Extending beyond source code

The more I do this, the more obvious it becomes: the software story does not live only in repos.

Some of the most important decisions happened in Teams or Slack threads, in meeting transcripts, and in docs that never made it to a pull request. If I only consider code, I get implementation detail. If I include communication and docs, I get intent. This is where the real story emerges.

That means the same book pattern should expand to include:

  • Communication history: decision threads, approvals, reversals, and unresolved debates.
  • Meeting artifacts: transcripts, notes, action items, and who agreed to what.
  • Non-code documentation: design docs, runbooks, incident reviews, architecture diagrams, and policy docs.

The same promotion test still works, just with broader sources.

  • Is this a durable decision?
  • Is this the reason behind the implementation?
  • Would future maintainers need this context to make a safe change?

If yes, it belongs in the book, even if it came from chat and not code.

In practice, I think of this as building a project memory graph, not a code index. Code tells me what exists. Conversations and docs tell me why it exists.

That is the difference between replaying commits and understanding a system.

Operationalizing this

I needed this to be more than a good idea, so I turned it into a repeatable weekly practice. This is where theory becomes practice, where chaos becomes system.

This pattern is bigger than any one product. It fits a growing class of brownfield context tools that turn scattered project signals into usable memory.

  1. Gather sources in a fixed order.
  2. Extract candidate decisions, tradeoffs, and unresolved risks.
  3. Score each item with the promotion test.
  4. Promote what is durable to the book.
  5. Keep execution-only context in Squad.
  6. Review drift and stale entries on a schedule.

For source priority and trust, I use this order:

  1. Decision records and architecture docs.
  2. Incident reports and postmortems.
  3. Meeting summaries with named owners.
  4. Pull requests and issue threads.
  5. Chat threads from Teams or Slack.

Higher-ranked sources are usually cleaner on intent and accountability. Lower-ranked sources still matter, especially when they are the only place a decision was captured, but they need corroboration.

To keep this light, I timebox it.

  • 30 minutes a week for promotion from Squad to the book.
  • 30 minutes a month to prune stale context.
  • 60 minutes each quarter for architecture drift review.

That rhythm gives me a stable memory system without turning documentation into a second full-time job.

Further reading: workflows like Scout, OpenClaw, and similar brownfield context systems can support this pattern.

Summary

I started with a simple question: should source code be enough? For brownfield work, my answer is no.

I treat source as evidence, not the whole story. The story gets written in the book: principles, tradeoffs, features, edge cases, and the things the original team quietly knew.

Squad helps me move quickly through current work. The book keeps that work safe, consistent, and grounded.

When those two stay in sync, maintenance stops feeling like archaeology and starts feeling like stewardship. That is how I keep momentum without losing meaning.

Watercolor image prompts for "Writing the history of software"

· 2 min read

Use these with the same pink-haired woman character across all images.

1) Book and Squad on the same road

Prompt: Watercolor illustration, soft paper texture, expressive brush blooms, a pink-haired woman software architect at a forked road at golden hour, she holds an open field notebook labeled project book filled with tiny architecture sketches, beside her is a modern autonomous car symbolizing Squad, one wooden sign points to quick fixes and another to safe and grounded progress, atmospheric clouds, gentle ink outlines, hand-painted look, editorial storytelling composition, no text overlay, 16:9.

2) From archaeology to stewardship

Prompt: Watercolor diptych style scene with one continuous horizon, same pink-haired woman on both sides, left side shows software archaeology with dusty ruins, fragmented code tablets, tangled cables, faded commit notes, muted earth tones; right side shows software stewardship with a cultivated garden of labeled pathways, healthy branching trees shaped like repo graphs, organized notebooks and living documentation, fresh greens and warm light, loose wet-on-wet washes, subtle linework, no text overlay, 3:2.

3) What stays in Squad and what moves to the book

Prompt: Watercolor studio scene, same pink-haired woman at a workbench sorting glowing index cards into two containers, one transparent container for operational memory and one bound journal for institutional memory, cards imply architecture decisions, sprint tactics, incident lessons, tradeoffs, meeting transcript notes, and chat decisions from Teams and Slack, balanced composition, calm focused mood, layered watercolor washes, visible paper grain, hand-painted editorial style, no text overlay, 4:5.

Consistency notes

  • Keep the same character design, hair color, and face shape in all three images.
  • Keep watercolor as the primary medium: wet-on-wet gradients, soft edges, and paper texture.
  • Keep a warm, reflective mood that matches the article voice.
  • Keep the theme centered on safety, consistency, and grounding, not speed alone.

From Natural Language to Autonomous Actions

· 12 min read

A pink-haired working with scientific equipment

You've built a workflow that works. But automating it requires engineering. Now you're stuck.

You know exactly how the process should run—you do it repeatedly, correctly, and it saves your team real time. But the moment you try to automate it, you hit a wall: write a script (and maintain it forever), hire engineers (and lose control to the project backlog), or give up and do it manually. None of these are wins.

There's a better way. What if you could capture your workflow in plain language, test it out, refine it, and gradually promote it to automation—keeping ownership the whole time? No developers required until you're absolutely sure the workflow is stable.

This is the progressive promotion model. Domain expertise starts as a natural language skill. You run it, refine it, test it. When repeated correct outcomes prove the flow is deterministic, the stable parts move behind MCP tools—reusable logic anyone can call. Then the skill can run autonomously. Ownership stays with the person who understands the process the whole time.


The automation tradeoff changed

The old tradeoff was simple: business value or engineering time. Only high-value workflows got built. Mid-tier work died in the backlog because no developer had bandwidth. The domain expert had to describe the process, hand it to a team, and wait months for the software to arrive.

This model shifts that cost to zero. The domain expert writes and runs the workflow in a skill right now, while they work. When the process proves reliable through repeated correct outcomes, the stable parts move behind MCP tools without a full rewrite. Cached tool definitions and typed contracts mean even small workflows can graduate.

The payoff is ownership. You hone your own process, keep control of your decisions, and run it yourself while it matures.


The four layers

Here is the path at a high level. The model puts each concern in its own layer. MCP stands for Model Context Protocol. In this post, an MCP tool is the typed interface that lets a skill, agent, or CI job call code in a predictable way:

LayerWhat it doesWho uses it
ScriptThe actual logic (API calls, file operations, data transforms)Everything below
MCP toolTyped interface around the script (JSON input → JSON output)Skills, agents, CI, other tools
SkillNatural language orchestration (when to call which MCP tool, in what order)Human-driven sessions
AgentAutonomous driver (same skill logic, but it decides when to run)Cron, webhooks, event triggers

The script is the logic. The MCP tool wraps it in a typed interface. The skill decides when to call which MCP tools. The agent runs the skill without you. Each layer has one job.

The key move: pull the script out of the skill and put it behind the MCP tool. Now any consumer can call it—another skill, an agent, a CI pipeline, an external system. The script is no longer locked inside one skill.

01 Script In Skill To Mcp Tool

The resulting stack looks like this:

02 Resulting Stack

The script gets written once, wrapped in a typed tool once, and then only the driver changes during promotion from interactive to autonomous.


How work naturally evolves

Start in natural language. Let the domain expert hone the process. Promote only after repeated correct outcomes prove the flow.

Here's how that progression works in practice:

A new skill starts with the LLM doing everything inline. Your instructions might say "query the GitHub API for recent releases, then compare against our changelog." The first version is written in plain language, not code. You stay in control.

Correctness matters more than speed here. You run the skill, adjust the instructions, and decide if the outcome matches your judgment. Repeat it several times until it consistently produces the right result.

Phase B: Determinism emerges

After a few runs, you spot a pattern. Step 2 is always the same. Same API call, same parsing, same output format. The LLM isn't adding judgment here—it's just following a mechanical procedure that you've already validated.

This is your signal to move. When the same API calls and parsing steps keep showing up, and the outcomes have been consistently correct, that part is ready to extract.

Phase C: Extract to MCP (not script-in-skill)

Now make the move. Extract the deterministic logic into a typed MCP tool instead of keeping it inside the skill. You still control the workflow through the skill. The stable, reusable part moves behind a typed interface.

03 Wrong Vs Right Path

The skill now calls detect_releases instead of embedding the logic. The MCP tool has a JSON input schema, a JSON output schema, and error handling. It's independently testable. Any consumer—another skill, an agent, a CI pipeline, or an external system—can call it.

Phase D: Promote to agent

When the process is reliable and you want it to run without you, promote to autonomous execution. The agent uses the same MCP tools. The only difference is who drives: you (interactive) or the agent (autonomous).

04 Phase C Phase D Promotion

The MCP server does not change. The tools do not change. The scripts do not change. Only the driver changes.


Where my first design stopped

My forty-skill portfolio showed me where this breaks if you stop too early. My original approach was:

  1. Write a skill (natural language instructions)
  2. Notice a pattern is deterministic (same inputs → same outputs)
  3. Extract that logic into a script inside the skill
  4. Done

The problem is step 4. The skill works. The script works. But only that skill can use it. No other skill can call it. No agent can use it. No CI pipeline can run it. When you need that logic elsewhere, you copy-paste the whole thing.

After forty skills, I had forty pieces of scattered process knowledge with scripts locked inside individual skills, no typed contracts, no reusability, and no clear path to autonomous execution. The scripts weren't going anywhere.

Why MCP tools instead of scripts-in-skills

The decision to extract into MCP rather than keep scripts inside skills comes down to three things:

Reusability

A script locked inside one skill is only callable by that skill. An MCP tool is callable by any skill, any agent, any CI pipeline, and any external system. Reuse changes everything.

Typed contracts

A script takes string arguments. An MCP tool has a JSON input schema and JSON output schema. The LLM knows exactly what to send and what to expect back. No parsing surprises.

Prompt caching

The cost reason is direct: MCP tool definitions live in the system prompt and get cached at a 50-90% discount. Every time you spawn an agent fresh, you lose that cache.

WhatCostCache
Skill instructions~0Part of system prompt (cached)
MCP tool definitions~400-1600Part of system prompt (cached)
Agent spawn~10-25K per runFresh context (uncached)

Using MCP tools instead of spawning fresh agents cut uncached tokens by roughly 90%.


The decision point

When you find yourself writing a script inside a skill, ask one question:

Will anything other than this skill ever need to call this logic?

  • If yes → extract to MCP immediately
  • If maybe someday → extract to MCP (future reuse is cheaper than a later move)
  • If truly never (one-off, will be deleted soon) → script-in-skill is fine

In my forty-skill portfolio, the answer was almost always yes.


What promotion looks like in practice

I have a content pipeline called Echo that detects new SDK releases, generates documentation metadata, and produces content reports. It started as a Squad agent spawning fresh context every time.

After extracting to MCP + skill:

BeforeAfter
~25K uncached tokens per run~1-2K uncached tokens per run
Squad agent spawned freshSkill in cached system prompt
Two separate context windowsOne cached context window
Scripts locked inside agentTools callable by anything

The scripts themselves didn't change. The structured JSON output envelopes they produced already matched MCP tool responses—same schema, different transport.

Before: Script → JSON file → next skill reads file from disk
After: Script → JSON → MCP protocol → any consumer gets it directly


The cost model across stages

Each stage changes the driver but reuses the same tools. Costs drop because the driver changes:

StagePer-run costDriverWhat saves
Skill + MCP~1-2K uncachedYou, interactivelyLowest token use. Tools cached. Only I/O is new.
Agent + MCP~5-10K uncachedAgent, autonomouslyAgent charter is fresh, but tools stay cached.
CI/CD0 tokensGitHub ActionNo LLM at all for deterministic steps.
Agent spawn (old way)~25K uncachedSquad coordinatorTwo fresh windows every time. Highest token use.

As work matures, it needs less LLM reasoning per run, until CI/CD needs none at all.


Context occupation cost of MCP

MCP tools have lower per-token cost when cached, but they occupy context window space every turn, even when unused. A 4-tool server adds ~600-1600 tokens to every conversation.

Control this with grouping and toggling:

StrategyHow it works
Group by workflowCombine related tools into one server (content-pipeline-mcp for all content work)
Toggle per taskEnable the server when doing that work, disable when doing something else
Skill as gatekeeperThe skill reminds you to enable MCP if it's off

The pattern: skill triggers workflow (zero idle cost) → skill activates MCP (cost only when needed) → tools do work (cached calls). The MCP stays enabled only when you're using it.


Running autonomously with Copilot CLI

Once a skill is promoted to an agent, the next need is running it without a human session. Copilot CLI supports this today:

# Simplest autonomous run
copilot -p "Run the echo pipeline" --yolo --silent

# With specific agent and model
copilot -p "Execute" \
--agent echo-pipeline \
--autopilot --no-ask-user \
--yolo --silent \
--model gpt-5.4

# Sealed sandbox: only specific tools available
copilot -p "Sync releases" \
--additional-mcp-config @workflows/echo-sync/mcp-config.json \
--available-tools='content-pipeline-mcp/*' \
--no-ask-user --autopilot --silent

The key flags:

FlagWhat it does
-p "prompt"Non-interactive mode (exits after completion)
--agent nameUse a specific .agent.md file
--autopilotAgent continues without asking permission
--no-ask-userDisable all user questions
--yoloApprove all tools, paths, and URLs
--available-tools='...'Only these tools exist (sealed sandbox)
--silentOutput only the agent's response

For CI/CD, authenticate with a fine-grained PAT:

COPILOT_GITHUB_TOKEN=github_pat_xxx copilot -p "Run pipeline" \
--agent echo-pipeline --yolo --silent --no-auto-update

The sealed sandbox

When something runs autonomously, the context must be fully specified at launch and locked in place. The agent gets exactly the tools it needs and nothing extra. The glass bell jar is boring on purpose.

A sealed sandbox manifest specifies:

  1. Identity: who the agent is
  2. Available tools: exhaustive list—nothing else exists
  3. Execution plan: exact steps, no deviation
  4. Error handling: complete rules, no improvisation
  5. Output routing: where results go
  6. Boundaries: hard constraints (violation = immediate exit)

Copilot CLI does this through --available-tools and the "tools" allowlist in MCP config. The MCP server might have twenty tools. The agent only sees three.

{
"mcpServers": {
"content-pipeline": {
"command": "node",
"args": ["./mcp-servers/content-pipeline/index.js"],
"tools": ["detect_releases", "generate_metadata", "analyze_impact"]
}
}
}

Similar progressions appear in other domains under different names:

SourceTheir patternMaps to this model
Anthropic, "Building Effective Agents"Start simple, increase complexityAugmented LLM → Workflows → Agents
Claude Agent SDKPermission modes as autonomy dialplanacceptEditsdontAsk
MCP Skills Working GroupProgressive disclosureTools → Skills → Agents
SAE J3016 (autonomous vehicles)L0–L5 autonomy levelsHuman-in-loop → human-on-loop → human-out-of-loop
SRERunbook → Automation → Self-HealingManual → scripted → autonomous
LangGraphinterrupt() architectureRemove interrupts = autonomous

The pattern exists in pieces across many domains. What was missing: a practical "Skill → MCP → Agent → CI" progression with extraction checklists and validation gates, tailored specifically for domain experts who want to keep ownership.


The rule I use now

When a process proves repeatable, reusable logic moves to an MCP tool. Scripts-in-skills are prototype code.

Ask three questions: Who owns this? How stable is it? What driver does it need now?

If the work is...Use...
Still being figured outSkill (cheap exploration)
Repeatable and deterministicMCP tool (reusable, typed)
Needs to run without youAgent (autonomous driver)
Fully deterministic, no judgmentCI/CD (no LLM at all)

What's next

Echo is the pilot. Once the content-pipeline MCP server wraps Echo's three scripts and the /echo-sync skill drives them interactively, validation has two parts: the process still produces the right output, and the token savings are real.

Then come Finn, the reporting tools, and the rest one by one.

The pattern is straightforward: Start with the person who owns the domain knowledge. Capture the workflow in a skill. Run it until the outcomes are consistently correct. Move the repeatable parts behind MCP tools. Change the driver only when autonomy helps.

Ownership stays with the person who understands the process. The system matures around that expertise.

CLI version

CLI examples written for GitHub Copilot CLI v1.0.77. Flag names and behavior may change in later releases.