Skip to content

Agent decisions written with memory.write class decision end up in memory/local instead of decisions/inbox #2314

Closed

Description

@joslat

While digging into how governed memory works, I noticed that decisions agents record the way the coordinator template tells them to never make it into decisions.md.

The template (templates/squad.agent.md.template:549, and the coordinator-response-mode skill at line 91) says to use memory.write with class decision, in lowercase. The enum is uppercase and nothing normalizes the value, so:

  • the call succeeds and the agent gets back "Stored decision memory ..."
  • the file goes to .squad/memory/local/ instead of .squad/decisions/inbox/
  • index.json records class: "decision" with no load guidance (the front matter literally says loadGuidance: [undefined])
  • Scribe only merges the inbox, so the decision never reaches decisions.md

Repro

With a local-backend .squad, call memory.write through squad_state with:

{ "content": "We decided to use Vitest.", "title": "Use Vitest", "author": "dallas", "class": "decision" }

decisions/inbox stays empty and the file shows up in memory/local. Same result with "Decision", " decision " and even "decisions".

Why it happens

squad_state uses the low-level MCP Server, which doesn't validate arguments against inputSchema, so the enum in the tool schema (packages/squad-sdk/src/tools/index.ts:1000) isn't enforced. The handler passes args.class straight through, and LocalMemoryStore.classify uses it as is (packages/squad-sdk/src/memory/index.ts:608). The class gates are exact matches (FORBIDDEN at :623, TRANSIENT at :631, COPILOT_MEMORY at :682), and the routing only knows DECISION and POLICY (:1331-1337).

The CLI already upper-cases and validates the class (packages/squad-cli/src/cli/commands/memory.ts:59-66). The MCP path just never got the same treatment.

Also: lowercase forbidden, transient and copilot_memory get stored as well, while their uppercase versions are rejected.

Suggested fix

Normalize (trim and upper-case) and validate the class once in LocalMemoryStore.classify, return a proper failure from the memory.* tools for unknown names, and fix the spelling in the template copies. Entries that were already misfiled can be moved with memory.promote <id> DECISION.

I put up #2315 with a fix.

Activity

  1. added a commit that references this issue on Oct 25, 2026
    c364b8b
  2. changed the title [-]memory.write with class `decision` (lowercase, as the coordinator template instructs) misfiles agent decisions in memory/local[/-] [+]Agent decisions written with memory.write class `decision` end up in memory/local instead of decisions/inbox[/+] on Oct 25, 2026
  3. added a commit that references this issue on Oct 25, 2026
    18db112
  4. added a commit that references this issue on Oct 26, 2026
    5d77879
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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions