Skip to main content

3 posts tagged with "copilot-cli"

View All Tags

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.

I Built the Capture Layer for My Portable Personal Context

· 8 min read

A developer writing the day's notes by lamplight, watercolor illustration

Every session now leaves behind a timestamped note I can review, audit, or delete. No cloud sync. No hidden database. Just files I own.

I built the missing memory half from my personal context blog post.

In Portable Personal Context Across AI Client Surfaces, I separated personal context from memory. Context is the small set of reviewed facts I want tools to trust. Memory is what happened while I worked.

The gap was capture. I needed a way for Copilot CLI sessions to leave behind structured observations I could review later. So I built copilot-cli-log-to-file: a Copilot CLI extension that writes each finished turn to a timestamped file I own.

The result: a reproducible, human-controlled pipeline from raw evidence to trusted rules—without accidental promotions.


Capture the memory feed first

The stronger angle is memory feed, not cross-computer sync.

Sync is useful, but it comes later. What I needed first was a raw feed: timestamped session evidence that could become an observation in the pipeline.

observation  →  candidate  →  [ratification gate]  →  context
(memory) (proposed) (a human decision) (canonical)

A capture file is not context. It can prove that I asked a question, that Copilot answered, and that a tool ran if I opted into tool capture. It should not silently become an instruction. I still want the human gate because one weird session should not rewrite my operating rules.

Extension output

copilot-cli-log-to-file runs after a Copilot CLI turn finishes. By default, it writes a complete YAML document with timestamp, sessionId, prompt, and response.

The default filename pattern is {timestamp}-{prompt30}.yaml, so a log folder looks like this:

copilot-response-log/
2026-07-13T11-21-45Z-list-all-my-files.yaml
2026-07-13T14-05-02Z-explain-this-function.yaml

That filename format mattered more than I expected. I can sort by time, skim the prompt slug, and delete one turn without touching the rest of the history.

I kept enriched capture off by default. If I want more detail, I opt in by category: attachments, reasoning, tool calls, tool results, usage, model changes, skills, subagents, permissions, errors, lifecycle events, turn boundaries, schedules, or notifications. There is also a COPILOT_LOG_CAPTURE_ALL=true override, but I treat that as a deliberate choice because these files can hold private data.

Here is a small capture with usage and tools enabled:

timestamp: "2026-07-14T18:21:45.000Z"
sessionId: "9f4c2a7b12345678"
prompt: |-
Summarize the current branch and suggest the next test to run.
tools:
- toolCallId: "call_abc123"
toolName: "git"
arguments: '{"command":"status --short"}'
success: true
result: "M website/blog/2026-07-17-capture-layer-for-portable-context.md"
usage:
- model: "gpt-5"
inputTokens: 1840
outputTokens: 420
cacheReadTokens: 600
cacheWriteTokens: 0
duration: 1310
finishReason: "stop"
response: |-
The branch has one modified blog post. The next targeted validation is to re-read
the file for frontmatter, link, and YAML-example accuracy before committing.

The toolCalls and toolResults toggles feed one merged tools: block. That was a small design choice, but it keeps the question I care about in one place: what tool ran, with which arguments, and what happened.

Two implementation details saved me from future debugging. Copilot CLI reserves stdout for JSON-RPC, so I use session.log(...) instead of console.log(...). The runtime also provides @github/copilot-sdk; I do not ship it as an npm runtime dependency. js-yaml stays dev-only for tests because the extension has a hand-rolled YAML emitter.

The capture layer transforms a CLI turn into structured data. A turn contains two key outputs: the assistant response (Copilot's answer) and events (the structured record of what happened—tool calls, model usage, and other metadata). Both flow into the timestamped YAML file.

Copilot CLI capture layer architecture

Promote observations only after review

The previous blog post's pipeline feels less abstract now that I have real files on disk.

copilot-response-log/*.yaml

observation

candidate

[ratification gate]

portable personal context repo

The YAML file is the observation. A candidate is the proposed durable fact I might extract from one or more observations. The context repo is where the approved rule lives.

For example, a few sessions might suggest that I prefer targeted validation before full-suite validation for docs-only work. That is still only evidence. I decide whether it belongs in process/quality-bar.md, decisions/_active.md, or nowhere.

Pipeline stageSourceStatusExample
ObservationYAML captureRaw evidence"This session used a targeted validation step."
CandidateExtracted proposalNot authoritative"Maybe targeted validation is preferred."
RatificationHuman reviewDecision point"Yes, make this a workflow rule."
ContextMarkdown repoCanonical"For docs-only changes, re-read the edited file first."

Boring is good here. The capture layer does not promote anything by itself. That keeps mistakes, one-off exceptions, and prompt-injection garbage out of my canonical context unless I approve them.

Observation to context ratification pipeline

Keep the feed in files I can inspect

I chose files because I wanted the memory feed to stay under my control—fully inspectable and modifiable.

A hidden store might be easier for a product team to manage. It is less helpful when I want to understand what happened. With YAML files, I can open a turn, grep the folder, parse a subset, redact a bad capture, or delete a whole day.

ChoiceWhy I used it
YAML documentsA parser can load each file directly. I can still read it.
One file per turnI can archive or delete one capture without editing a combined log.
Configurable folderI can keep logs local or point them at a private synced location.
Plain text optionI can choose readability when structured ingestion is not the goal.

I do not need a private service to prove the idea. I need a folder that my tools can read and that I can clean up when a log catches something I do not want to keep.

Treat logs as private-tier data

These logs hold my secrets if I let them.

A prompt can include file paths, pasted snippets, internal project names, tool arguments, tool results, permission prompts, errors, and final responses. Enriched capture defaults to off because the safe default is a small capture. When I turn on tools or usage, I am choosing to record more evidence.

So I treat copilot-response-log like the private tier from my personal context blog post:

  • I keep raw captures local unless I have a private sync policy.
  • I scrub before committing any log-derived material.
  • I do not point every AI surface at the raw folder.
  • I enforce trust tiers before retrieval.

That last point is the security boundary. If an untrusted surface can read my raw logs, filtering the final answer is too late.

Private-tier boundary for raw Copilot CLI logs

Sync across computers only after the capture layer exists

Once the feed is files, cross-computer sync becomes straightforward. I can point the extension at a folder backed by git, OneDrive, or another private file-sync tool.

That still does not make every surface smarter. Each surface needs wiring, and I do not want most surfaces reading raw logs anyway.

Computer A: Copilot CLI → copilot-response-log/*.yaml
Computer B: Copilot CLI → same synced folder
Review step: observations → candidates → approved context
Wired surfaces: read approved context, not raw logs by default

The central second brain is not the log folder. It is the loop: capture evidence, review candidates, then promote the facts I trust into portable context. The raw feed stops useful session evidence from vanishing. The curated repo stops tools from relearning the same facts twice.

Keep the next step boring

This is not automatic yet. Ratification is still human. Candidate extraction still needs review. Each AI surface still needs its own way to read approved context. There is no shared $AI_CONTEXT_PATH that every tool honors.

That is okay for this step. I built one small piece: a Copilot CLI extension that captures my missing memory feed as structured files. Now the architecture from my personal context blog post has something concrete to promote.

What's next: candidate extraction and ratification

The capture layer answers "how do I collect evidence?" The next piece is "how do I turn evidence into trusted rules?"

That means three things:

  1. Candidate extraction — Tooling that reads a week of captures and proposes facts worth considering. "You ran targeted validation before full-suite validation in 5 docs-only sessions. Is this a pattern?"
  2. Ratification interface — A simple review UI where I approve, reject, or refine each candidate before it becomes canonical. No auto-promotion. No surprises.
  3. Context repo publishing — Once approved, a candidate becomes a rule in the portable personal context repo. Then every surface that reads that repo knows about it.

Until then, the captures sit in their folder as raw evidence. They prove what happened. They don't decide anything. That's the safety boundary I chose to keep.

Next session, I'll build the ratification loop.

Exploring Copilot CLI Session Management to Improve Squad

· 13 min read

I've been using Squad, an AI team framework built on top of Copilot CLI, and I kept wondering: Copilot CLI already tracks everything that happens in a session — could that data make Squad's agents smarter? I spent some time digging into how both systems manage session data, and I think there's an untapped opportunity.

This post is my investigation notes — what I found, how the two systems compare, and where I think they could be combined for more value.

My working theory: Copilot is your diary (what happened). Squad is your playbook (what to do about it). Right now they're like two lighthouses on opposite shores of Bellingham Bay — both useful, but no bridge between them.

Two lighthouses on opposite shores of Bellingham Bay, their beams not quite connecting

What I Found: Two Memory Systems

Copilot CLI: The Raw Record

Copilot CLI records every session — prompts, responses, tool calls, file changes, and checkpoints. I discovered it powers:

  • /resume — pick up where you left off in any previous session
  • /chronicle — generate standup reports, get personalized tips, improve your custom instructions
  • /session — view and manage your sessions directly from the CLI

Session data lives in ~/.copilot/session-state/ as files and in ~/.copilot/session-store.db as a structured SQLite database.

What Copilot remembers: Everything that happened in every session — the full transcript.

What it doesn't do: Extract meaning. Copilot stores the raw conversation, not the conclusions you drew from it.

Squad: The Distilled Knowledge

Squad's memory is different — and this is where I see the gap. It's not a transcript — it's distilled knowledge, stored as markdown files in your repo:

WhatFilePurpose
Team decisions.squad/decisions.mdShared brain — every agent reads this
Agent memory.squad/agents/{name}/history.mdPersonal learnings per agent
Skills.copilot/skills/{name}/SKILL.mdRepeatable tasks with everything needed to execute
Session state.squad/sessions/*.jsonResume data (gitignored by default)
Scribe logs.squad/log/*.mdSession summaries (gitignored by default)

What Squad remembers: Decisions, patterns, preferences, and skills — the things that should change how agents behave next time.

What it doesn't do: Record the full conversation. That's Copilot's job.

The Gap I See

The two systems complement each other, but right now they're completely disconnected — like looking across Deception Pass and seeing the other side but having no way to cross.

Water rushing through a rocky gorge at Deception Pass — two cliff faces close together with no bridge between them

Here's where each system shines:

QuestionWhere to look
"What did I do last Tuesday?"Copilot — /session or /chronicle standup
"What did the team decide about auth?"Squad — .squad/decisions.md
"Have I worked on this file before?"Copilot — /session to browse past sessions
"How do we run a content audit?"Squad — .copilot/skills/content-audit/SKILL.md
"What went wrong last time I tried this?"Copilot — session transcript via /resume
"What does this agent know about TypeSpec?"Squad — .squad/agents/{name}/history.md

This separation works, but it's manual. You have to be the bridge — ferrying insights across the water yourself. That's the opportunity I'm investigating.

Where I Think Session Data Could Improve Squad

Squad has a built-in skill called reskill ("team, reskill") that audits agent charters and histories, extracts shared patterns into skills, and compresses bloated files. Think of it as sorting the morning catch on a Bellingham dock — keeping what's valuable, tossing the rest back.

Fisherman on a Bellingham dock sorting the morning catch into labeled crates

But reskill today is purely file-based — it reads .squad/ markdown and looks for textual duplication. It has no idea what actually happened in sessions.

Here's what I think session data could add:

Signal from Copilot sessionsWhat Squad could do with it
Agent X was spawned 40 times but only useful 25 timesRefine charter to reduce misfires
Agent Y always gets the same 3 files as inputBake those into charter's "What I Own"
Users keep correcting the same mistakeExtract as anti-pattern in a skill
An agent never gets spawnedFlag for removal during reskill
Two agents always get spawned togetherSuggest merging or formalizing the pairing
Certain skills are read but never appliedDeprecate during reskill
Session durations spike after charter changesDetect regressions from past reskills

There are two existing proposals in the Squad repo that go in this direction — tiered memory (#600, open) for hot/cold/wiki context layers, and reflect (#621, closed PR — not merged) for in-session learning capture. Neither one references Copilot CLI session data though. They're both Squad-internal. The bridge between Copilot's behavioral data and Squad's knowledge system doesn't exist yet.

Ideas I'm Exploring

The theme here is a feedback loop — raw session data flows downstream, gets refined into knowledge, and that knowledge shapes the next session. Like the Nooksack River circling back toward the mountains that feed it.

The Nooksack River looping back toward Mount Baker, papers transforming into books at the bend

1. Feed /chronicle into Reskill

After a productive session, Squad agents already extract the important parts:

  • Decisions go to .squad/decisions.md
  • Learnings go to agents/{name}/history.md
  • Reusable patterns become skills

But what if reskill could also query Copilot's session store to find patterns agents missed? /chronicle improve already analyzes session history to suggest custom instruction improvements. That same analysis could feed into Squad's skill extraction pipeline — Copilot finds the behavioral pattern, Squad encodes it permanently.

2. Use /chronicle for Behavioral Analysis

Copilot's /chronicle improve analyzes session history to find where agents struggled or needed correction. I'm thinking about how to make this a systematic input to Squad:

  • Run /chronicle improve periodically
  • Take the suggestions and apply them to agent charters or team directives
  • This creates a feedback loop: Copilot finds the pattern, Squad encodes it permanently

Today this is manual. I'd love to see a squad reskill --from-chronicle that automates the loop.

3. Use /session for Context

When starting work on something you've touched before, use /session to browse previous sessions and find relevant context:

"Before starting, check /session for any previous sessions 
that touched these files. Summarize what was done and any issues."

This gives agents a head start without you having to remember and re-explain.

4. Use Squad for Cross-Agent Memory

Copilot's session history is per-user. Squad's memory is per-team. When Agent A discovers something that Agent B needs to know, Squad's shared files make that happen:

  • Scribe writes cross-agent updates to affected agents' history.md
  • Decisions in decisions.md are read by every agent at spawn time
  • Skills are shared — any agent can use any skill

The Gitignore Decision

Squad gitignores session-related files by default. Here's what that means and when to change it:

FileDefaultChange when
.squad/sessions/GitignoredCommit if you need session transcripts in git (training repos, research)
.squad/log/GitignoredCommit if you want Scribe's summaries as an audit trail
.squad/orchestration-log/GitignoredCommit if you want agent routing history preserved
.squad/decisions.mdCommittedNever gitignore — this is the team's shared brain
.squad/agents/*/history.mdCommittedNever gitignore — this is each agent's knowledge
.copilot/skills/CommittedNever gitignore — these are your reusable patterns

The recommended hybrid: Keep sessions gitignored, but commit Scribe's logs for a lightweight audit trail. Remove .squad/log/ and .squad/orchestration-log/ from .gitignore to enable this.

⚠️ One caveat: If your org requires audit trails of AI interactions, git probably isn't the right system of record — no retention policies, no redaction, no legal hold. Worth checking before treating committed sessions as a compliance solution.

Under the Hood (Skip Unless Debugging)

Copilot CLI stores session data in two places: file-based events in ~/.copilot/session-state/{session-id}/events.jsonl and a searchable SQLite database at ~/.copilot/session-store.db. The database powers /chronicle and /session — you need "experimental": true in ~/.copilot/config.json to enable these features. Without experimental mode, /chronicle won't be available — enable it with /experimental on in any session.

Each session folder contains the event stream (every tool call, message, and model metric), workspace metadata, and checkpoint snapshots that /resume uses to reconstruct context. The session.shutdown event in events.jsonl is worth finding — it shows your token usage, cache hit rates, and code changes in one place.

The SQLite database (~59 MB after ~770 sessions in my case) holds structured records across seven tables: sessions, turns, checkpoints, session_files, session_refs, and an FTS5 search index. Records persist even after session directories are cleaned up. Don't delete the .db-wal file while Copilot is running — you'll lose recent writes.

What's in the .squad Session Files

If you're using Squad to orchestrate AI agents, there's a parallel session storage layer inside .squad/ in your repo. While .copilot/ tracks platform sessions, .squad/ accumulates session-by-session team memory.

Session-Scoped Files (Created Per Session)

These files can be traced back to a specific session:

FileWhat It Contains
orchestration-log/{timestamp}-{agent}.mdWho was spawned, why, what they did. Append-only audit trail.
log/{timestamp}-{topic}.mdScribe's session summary.
decisions/inbox/{agent}-{slug}.mdEphemeral drop-box — agents write decisions here during a session. Scribe merges them into decisions.md afterward.
identity/now.mdUpdated each session with current focus. Every agent reads this at spawn so they hit the ground running.

Running-State Files (Modified Across Sessions)

These files accumulate changes but don't track which session changed them:

FileHow It Changes
agents/*/history.mdGrows each session as agents record learnings. Scribe summarizes when it exceeds ~15 KB.
agents/*/charter.mdUpdated if an agent's role evolves. No session linkage.
skills/{name}/SKILL.mdCreated or updated when agents discover reusable patterns.
decisions.mdThe canonical decision ledger — grows each session, entries are dated.
team.md, routing.mdUpdated when members join or leave.
casting/registry.jsonNew agent names registered here. Persistent.

The distinction matters: session files are created per session and disposable. Running-state files are your team's accumulated intelligence — they compound over time.

The Two-Layer Model

Together, .copilot/ and .squad/ form a complete session memory system — like Whatcom County's geology, where buildings sit on the visible surface but the real water supply flows through the aquifer below.

Cross-section of Whatcom County geology — buildings on the surface, aquifer below, a well connecting them

LayerLocationScopeWhat it tracks per session
Platform~/.copilot/Per-user, cross-projectEvents, turns, tool calls, model metrics
Team.squad/ (in repo)Per-project, cross-sessionOrchestration logs, agent memory, decisions, focus

The platform layer is invisible infrastructure — you don't commit it, you query it. The team layer is committed to the repo — it travels with the code and survives across machines, sessions, and team members. Surface and aquifer, both feeding the same ecosystem.

Try This

Ready to explore your own session data? Here are three things you can do right now:

  1. Browse your sessions: Open ~/.copilot/session-state/ and look at the events.jsonl from your most recent session. Search for session.shutdown to see your token usage and cache hit rates.

  2. Query your history: In any Copilot CLI session, try /session to browse your past sessions. Use /resume to jump back into a previous session with full context.

  3. Feed Copilot into Squad: Run /chronicle improve and review the suggestions. Pick one that matches a recurring pattern and say: "Make that a skill" or "Add that to decisions."

If you're not using Squad yet, #1 and #2 still work — they're pure Copilot CLI. The session data is there whether you browse it or not.

If You're Building an Agent on Top of Copilot

This investigation was Squad-specific, but the underlying insight applies to anyone building on Copilot CLI: there's a lake of session data sitting right there in ~/.copilot/ — and most agents ignore it completely.

The good news is the plumbing already exists. The Copilot SDK (@github/copilot-sdk) exposes session listing, full event history, and real-time event subscriptions. You can filter sessions by repo or branch, pull every tool call and assistant response, and subscribe to events as they happen. The data access is there — what's missing is the intelligence layer on top.

Here are three ideas I keep coming back to — none of them Squad-specific:

1. Adaptive Prompt Tuning Based on Tool Failure Rates

I noticed in my own session data that certain tool calls fail repeatedly — grep with regex that doesn't match the codebase's naming conventions, for example. An agent could watch for these patterns and silently adjust its strategy — switching to glob patterns, broadening search terms, adding fallback chains — without me ever asking. Like a fishing guide who notices you keep casting into the wrong current and quietly repositions the boat.

2. Cross-Session Onboarding for New Repos

When I open a new repository for the first time, the agent has zero context about how I work. But my session history from other repos is right there — it shows whether I prefer TypeScript or JavaScript, whether I write tests first, which frameworks I reach for. An agent could mine that cross-project session data to bootstrap a developer profile, skipping the cold-start problem. First day in a new codebase, but the agent already knows your habits.

3. Drift Detection Between Intent and Outcome

Session data captures both what I asked for and what the agent actually did — tool calls, file edits, test results. Over time, an agent could spot drift: I keep correcting the same kind of CSS suggestion, or certain requests consistently take multiple follow-up turns. Imagine the agent saying, "You frequently adjust my styling — want me to follow a specific style guide?" That turns passive logs into active self-improvement.

The common thread: session data isn't just a transcript — it's telemetry. Any agent that treats it as a feedback signal rather than a static log has a real advantage, like reading the tides instead of just watching the water.

The Bottom Line

Use both memory systems intentionally:

  • Copilot handles the raw history. Let it. Don't try to replicate session transcripts in Squad files.
  • Squad handles the distilled knowledge. Invest here — decisions, history, and skills are what compound.
  • Feed insights from Copilot back into Squad via /chronicle improve, directives, and skill creation.
  • Start with the default gitignore. The valuable stuff is already being committed. Relax later if you need session trails.

Your agents get smarter not because they remember every conversation, but because the important conclusions persist in the right place. The river keeps flowing — what matters is what settles into the riverbed.