Skip to content

arch: pick a direction for agents/{name}/history.md vs the governed memory model #1243

Closed as not planned

Description

@tamirdresher

Summary

Squad currently has two parallel paths for an agent to record "I learned X", and they have very different behavior. The runtime supports both without a clear story for which to prefer. This issue asks the maintainers to pick a direction.

The two paths today

Path 1 — append to .squad/agents/{name}/history.md

  • Direct file append; no classification, no audit
  • Loaded in full at every spawn of that agent (subject to the 12KB summarization rule documented at docs/src/content/docs/concepts/memory-and-knowledge.md)
  • Owner-only read (no search, no cross-agent visibility)
  • This is the "Personal history" layer in the three-layer memory model

Path 2 — squad memory write --class LOCAL --author {name} --content "..."

  • Routed through LocalMemoryStore.write() at packages/squad-sdk/src/memory/index.ts:667-861
  • Lands at .squad/memory/local/{author}-{slug}-{id}.md (per destinationPath() at memory/index.ts:1328-1338)
  • Classified, audited, indexed; default loadGuidance: ON-DEMAND (per loadGuidanceFor() at memory/index.ts:428-440)
  • NOT auto-loaded at spawn — only surfaces via memory.search when an agent (or the coordinator) explicitly queries
  • Searchable cross-agent

Side-by-side comparison

Aspect history.md append memory.write --class LOCAL
Auto-loaded at spawn? ✅ Yes, in full (with 12KB summarization) ❌ No (ON-DEMAND)
Classified (FORBIDDEN scan, etc.)? ❌ No ✅ Yes
Audited? ❌ No ✅ Yes (audit log entry)
Searchable? Only by reading the file ✅ Via memory.search
Cross-agent visible? ❌ Owner-only ✅ Yes (via search)
Context cost per spawn High (loaded in full) Zero (until searched)

Why this matters

A user reading the docs writes a directive like "Always run SDK tests before merging". Two things can happen:

  • An agent appends this to its history.md → it's part of every future spawn of that agent (heavy context cost; correct content survives but every other agent doesn't see it)
  • The coordinator calls memory.write --class POLICY → it lands in policy-inbox/, Scribe merges into decisions.md → every agent sees it on next spawn, audited, classified

The runtime supports both. Today there's no rule for which path takes which kind of write. The result:

  • Inconsistent context cost (some agents heavy, others light)
  • Inconsistent governance (some content audited, some not)
  • Inconsistent visibility (some learnings cross-agent, some siloed)
  • No migration story (a team that started before governed memory has heavy history.md files; a team starting after has light ones)

Three concrete options for the maintainers

Option A — Keep both paths as-is, just document the rule

  • history.md stays as the auto-loaded personal context
  • Governed memory stays as the audited, searchable, on-demand layer
  • Document when to use each: history for "this agent's persistent context", governed memory for "team-wide signals + safety governance"
  • No code change. Just docs.

Option B — Derive history from governed memory

  • history.md becomes a generated VIEW of the memory index filtered by author={agent name}
  • All "I learned X" writes go through memory.write --class LOCAL
  • Spawn-time history load = "give me the LOCAL entries authored by this agent, classified ALWAYS"
  • One write path. Governance and audit on every write. Per-author scoping preserved.
  • Code change: rewrite history append, rewrite history read at spawn, migration tooling for existing history.md files

Option C — Make history.md class-aware

  • Each entry in history.md gets a class + loadGuidance via frontmatter
  • Spawn-time read pulls only loadGuidance: ALWAYS entries; surfaces ON-DEMAND on search
  • Massive context-cost reduction per spawn (most "I learned X" is ON-DEMAND, not ALWAYS)
  • Code change: history format, history read path, Scribe summarization rules, possibly the spawn prompt builder

What's NOT being proposed

  • Removing history.md entirely (would break existing agents)
  • Forcing governed memory for everything (some content really is single-agent context)
  • Changing decisions.md behavior (it works; this is about the per-agent layer)

Evidence — code citations

  • Three-layer memory model docs: docs/src/content/docs/concepts/memory-and-knowledge.md (3 layers: Skills / Decisions / History)
  • Governed memory write paths: packages/squad-sdk/src/memory/index.ts:1328-1338 (destinationPath() — never writes to agents/)
  • Load guidance defaults: packages/squad-sdk/src/memory/index.ts:428-440 (loadGuidanceFor() — LOCAL defaults to ON-DEMAND)
  • History.md spawn-time read: packages/squad-sdk/src/tools/index.ts:592 (reads history.md content — separate from memory store)
  • Coordinator spawn template: .github/agents/squad.agent.md "Full Spawn Template" section — instructs to inline charter/history/decisions

Decision needed

This issue isn't blocking anything urgent. But the longer the runtime supports two parallel paths without a documented preference, the more inconsistent team behavior gets — both within a team and across teams adopting Squad at different points in 0.10.x.

What would help:

  • A maintainer comment picking A, B, or C (or a fourth option I missed)
  • If A: a docs PR can follow this issue
  • If B or C: a design discussion before any code change

Activity

  1. tamirdresher commented on Jun 11, 2026

    @tamirdresher
    CollaboratorAuthor

    Docs-precision sub-issue: history.md write paths are dual-owned

    Closing a gap I noticed while tracing the lifecycle for a related architecture review: the source-of-truth table at squad.agent.md:703 is precise about history.md ownership, but the prose elsewhere in the spec (and any external docs that paraphrase it) tends to say "agents append their own history" — which is half the picture.

    Verbatim from L703:

    .squad/agents/{name}/history.md | Derived / append-only. Personal learnings. | Who May Write: Owning agent (append only), Scribe (cross-agent updates, summarization)

    So history.md actually has THREE write paths today:

    # Path Who When What
    1 Direct append Owning agent During its own task execution Personal learnings (verbatim quotes, file:line refs, observations)
    2 Cross-agent propagation Scribe (step 5 of spawn template) After every batch 📌 Team update ({ts}): {summary} — decided by {Name}
    3 Summarization rewrite Scribe (step 6 of spawn template) When file ≥15KB Lossy condensation of historical entries

    This matters for the question this issue is asking — "pick a direction" — because it changes the framing:

    If the team picks memory.write --class LOCAL exclusively: the spec needs an explicit story for cross-agent propagation. Today Scribe sees a merged decision and broadcasts to N affected agents; if learnings live only in governed memory, what triggers cross-agent awareness? Polled memory.search at spawn time? A "subscribe" mechanism on classes?

    If the team picks history.md as primary: the doc precision issue stands — history.md isn't agent-owned, it's agent+Scribe co-owned, and the docs should say so plainly.

    The architecture choice here interacts with the other governance issues filed this week:

    • #1268 (Scribe bypasses governance) — if Scribe writes cross-agent updates through memory.write instead of squad_state_append, the classifier engages on propagation too
    • #1270 (unify state/memory APIs) — proposes folding squad_state_* under memory.*, making the direction question moot at the API level

    So this issue's "pick a direction" question is actually a sub-question of the broader unification question — but the dual-ownership clarification belongs here regardless of which direction is picked.

  2. added
    stalled-initiativeWork area that was started but never completed — cut, close, finish, or reprioritize
    on Aug 30, 2026
  3. bradygaster commented on Sep 24, 2026

    @bradygaster
    Collaborator

    Consolidation direction: #1270 is the canonical architecture issue for the governed-memory versus raw-state API boundary. This issue remains open because it owns a distinct decision: whether history.md is direct authored state, derived from governed memory, or class-aware bounded context. #1268 separately tracks Scribe lifecycle bypasses.

  4. bradygaster commented on Nov 5, 2026

    @bradygaster
    Collaborator

    Consolidated into #2392 during 2.0 board triage (owner decision). The decision and its validation tests are tracked there; original text remains here for reference.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    stalled-initiativeWork area that was started but never completed — cut, close, finish, or reprioritizetriagedIssue has been triagedwave:2-soonWave 2 — next 2-4 weeks

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions