# Team Memory

Minions agents share knowledge through a layered memory system. Before an agent does any independent research — web searches, broad codebase exploration, external doc reading — it is expected to check what the team already knows.

This document describes the four-tier read order the engine enforces in dispatch prompts, the rationale, and the constraint that `knowledge/` is **sweep-write-only**.

## Why team memory exists

Multiple agents work the same repository in parallel and across days. Without shared memory:

- Agents re-research the same questions (cost, time, context churn).
- Agents re-litigate decisions the team already made (drift, regressions).
- Human-flagged warnings (e.g., "do not self-approve PRs") get ignored because they live outside the prompt.

Team memory closes the loop. The engine injects pinned context and recent team notes into every dispatch prompt automatically, and the playbooks instruct agents to consult `knowledge/` and `notes/inbox/` on disk before going wider. This keeps work cheap, decisions sticky, and prior learnings reusable.

## The four-tier read order

Every agent prompt (built by `engine/playbook.js`) is rendered with the rule: **check team memory first, then look outside.** The canonical read order (from `playbooks/shared-rules.md`) is:

1. **`pinned.md`** — critical context flagged by the human teammate. **READ FIRST.**
2. **`knowledge/`** — categorized KB entries written by the consolidation sweep.
3. **`notes.md`** — consolidated team knowledge, decisions, and rolling context.
4. **`notes/inbox/`** — recent agent findings not yet consolidated.

Agents are also encouraged, after the four primary tiers, to skim `agents/*/live-output.log` for related tasks and the `resultSummary` of prior completed work items on the same topic. Only after exhausting team memory should an agent fall back to web search, broad codebase exploration, or external docs.

### 1. `pinned.md` — human-flagged critical context

`pinned.md` lives at the Minions root (`MINIONS_DIR/pinned.md`). It holds notes the human teammate has explicitly pinned through the dashboard — short, high-signal rules and warnings that **must** be visible to every agent on every dispatch.

The engine injects the file verbatim into the prompt under a "Pinned Context (CRITICAL — READ FIRST)" heading and caps it at 4 KB to protect the prompt budget.

Typical contents include credential constraints (e.g., shared `gh` auth means PR self-approval is blocked), workflow policies (e.g., merging policy, TDD requirement), and active setup state. If pinned context contradicts a playbook instruction, pinned context wins for the duration of the dispatch.

### 2. `knowledge/` — categorized KB entries (sweep-write-only)

`knowledge/` is the long-form team knowledge base. Files are grouped by category:

- `knowledge/architecture/` — design decisions, system overviews
- `knowledge/conventions/` — coding patterns, repo norms, standards
- `knowledge/project-notes/` — per-project context and observations
- `knowledge/build-reports/` — CI/build investigation results
- `knowledge/reviews/` — PR review findings and rationale
- `knowledge/agents/<agentId>.md` — per-agent personal memory (curated by the sweep)

Filenames follow the `YYYY-MM-DD-<agent>-<slug>.md` convention so chronological sorting just works.

Agents read `knowledge/` directly with grep/glob/view. They **do not** write to it. See [Sweep-write-only constraint](#sweep-write-only-constraint) below.

### 3. `notes.md` — consolidated team notes

`notes.md` is the rolling team notebook. The consolidation sweep periodically merges high-signal findings from the inbox into dated `### YYYY-MM-DD` sections at the top of `notes.md`, with links back to the underlying KB entries.

The engine injects `notes.md` into every prompt under a "Team Notes (MUST READ)" heading. When the file exceeds `ENGINE_DEFAULTS.maxNotesPromptBytes`, the engine keeps the most recent 10 sections, truncates the body, and appends a footer noting how many older sections live on disk so agents can read the full file when they need depth.

### 4. `notes/inbox/` — fresh agent findings

`notes/inbox/` holds the freshest, un-consolidated learnings. Every agent writes exactly one inbox file at the end of a successful task to a path the playbook supplies (`notes/inbox/<agent>-<work-item-id>-<date>-<time>.md`). The file always begins with a YAML frontmatter block (`id`, `agent`, `date`) so the consolidation sweep can track it.

Inbox notes are the canonical place to record:

- New patterns or conventions discovered while implementing.
- Gotchas, warnings, or repro recipes for future agents.
- File-and-line citations supporting any claims.

The consolidation sweep is what eventually promotes inbox notes into `knowledge/` and `notes.md`. Until then, agents should grep the inbox themselves for very recent findings on adjacent work.

#### Failure-path exception

Inbox writes are **success artifacts only**. If a task fails, is blocked, is cancelled, or ends partial, the agent must **not** create an inbox note — the failure is reported through the completion JSON, the PR/work-item comment, or the task-specific failure channel instead. This keeps the inbox a clean signal and prevents noise from drowning out durable findings.

## Rationale

The read order is deliberately ordered by **trust × recency**:

- `pinned.md` is human-curated and authoritative — it overrides everything else.
- `knowledge/` is curated by the sweep from validated agent findings — high-signal but slightly delayed.
- `notes.md` mirrors `knowledge/` in summarized form, optimized for prompt injection.
- `notes/inbox/` is raw, recent, and unverified — useful for the freshest context but treat critically.

Following this order achieves two goals:

1. **Avoid re-research.** If another agent already investigated the same module, fix, or design question, the answer is somewhere in this stack. Reading saves a costly round-trip.
2. **Respect team decisions.** Pinned policies and consolidated conventions encode prior agreement (often with the human). Skipping team memory and acting on first principles is how regressions and drift happen.

## Sweep-write-only constraint

**Agents must never delete, move, or overwrite files in `knowledge/`.** Only the consolidation sweep (`engine/consolidation.js`) writes to `knowledge/`. This rule is restated in every dispatch prompt under a "Knowledge Base Rules" heading.

Why:

- The sweep classifies inbox notes into the right category, generates the canonical filename, and updates the `notes.md` summary in lockstep with the `knowledge/` write. Manual edits skip those side effects and desync the system.
- Agents work in parallel. Letting any agent rewrite `knowledge/` entries makes consolidation non-deterministic and makes blame attribution impossible.
- Knowledge base entries are referenced by date-stamped path. Rewriting an entry breaks every existing link.

If an agent thinks a `knowledge/` file is wrong, the correct response is to **note the disagreement in the agent's own inbox file**. The sweep will pick up the note on the next consolidation cycle and either supersede or correct the existing entry.

The same constraint applies to `knowledge/agents/<agentId>.md` — those are curated by the sweep and should not be hand-edited.

## Session State vs. Persistent Memory

The PRD that introduced sliding-window memory (W-mq07b8do000nc86a) referenced two distinct write paths — `update_session_state()` and `update_memory()` — borrowed from agent frameworks that model agents as long-lived in-process objects. Minions has neither method because it doesn't model agents that way; understanding the mapping prevents fruitless searches for non-existent APIs.

**Session state** = the dispatch's worktree + child process. Each Minions agent runs as a fresh OS process spawned by `engine.js → engine/spawn-agent.js` inside a per-work-item git worktree (`work/<wi-id>` by default; see `shared.deriveWorkItemBranchName`). When the dispatch ends, the engine deletes the worktree and the child exits. There is no persistent "session" object to update — ephemeral state lives in process memory and disk paths under the worktree, both of which are reclaimed automatically. No code is needed to "clear" session state; it never persists in the first place.

**Persistent memory** = `knowledge/agents/<agentId>.md`, the per-agent file appended to by `engine/consolidation.js` during the inbox sweep. This is the analog of `update_memory()` in PRD terms. It is written only by the consolidation sweep (the [sweep-write-only constraint](#sweep-write-only-constraint) applies), is injected into every subsequent dispatch's prompt for that same agent ID via `engine/playbook.js`, and is bounded by two complementary cuts plus an optional summary pass:

| Tunable (under `engine.*` in `config.json`)             | Default | Behavior                                                                                                          |
|---------------------------------------------------------|---------|-------------------------------------------------------------------------------------------------------------------|
| `agentMemoryMaxEntries`                                 | `300`   | Sliding-window entry-count cap. Older non-summary sections evicted oldest-first when exceeded.                    |
| (built-in) `AGENT_MEMORY_BUDGET_BYTES`                  | `25000` | Hard byte ceiling for prompt-injection safety. Always wins when both caps bind. Sticky summary sections obey it.  |
| `agentMemorySummaryEnabled`                             | `false` | Master switch for the LLM-driven compression pass. Off by default to avoid surprise Haiku spend.                  |
| `agentMemorySummaryThreshold`                           | `30`    | When the summary pass fires, fold this many oldest entries into one summary section.                              |
| `agentMemorySummaryDays`                                | `30`    | Age trigger: if the oldest entry is older than this, fold even when under the entry cap.                          |

The summary pass runs fire-and-forget after every successful `appendToAgentMemory` write inside `classifyToKnowledgeBase`. It re-reads outside the lock, calls Haiku, then re-acquires the lock and verifies the same oldest sections are still in place (stale-candidate guard) before swapping. Any failure — disabled, no trigger, LLM unavailable, race detected — is a silent no-op; the consolidation pipeline is never blocked on the LLM.

The compressed summary is wrapped in an `<UNTRUSTED-INPUT source="agent-memory-summary:agent=...">` fence on disk. The source material was the inbox bodies of evicted entries, which are themselves untrusted; without the fence, any imperative laundered through summarization could later be executed by an agent reading its own memory.

Summary sections are **sticky** under the entry-count cap — they represent compressed knowledge that should outlive ordinary inbox entries. They are detected by their title prefix `Earlier learnings summary` and only the byte budget can evict them.

**Default-off rationale.** `agentMemorySummaryEnabled` defaults to `false` (intentional deviation from PRD wording that implies "always on"). Enabling it commits operators to per-agent Haiku spend on every consolidation cycle; the entry-count cap on its own already prevents unbounded growth. Operators who have weighed the cost set `engine.agentMemorySummaryEnabled: true` in `config.json` to opt in.

## Quick reference for agents

```
1. pinned.md           ← critical, human-flagged. Read first.
2. knowledge/          ← categorized KB. Read, never write.
3. notes.md            ← consolidated team notes. Read.
4. notes/inbox/        ← fresh, unconsolidated findings. Read; write one on success.
```

After the four tiers, optionally consult `agents/*/live-output.log` and prior `resultSummary` fields. Only then go outside.

## See also

- `playbooks/shared-rules.md` — the canonical instruction injected into every dispatch.
- `engine/playbook.js` — where `pinned.md`, `notes.md`, and per-agent memory get spliced into prompts.
- `engine/consolidation.js` — the sweep that promotes inbox notes into `knowledge/` and `notes.md`.
