feat(memory): add memory CLI command group and project memory ADRs

- Add docs/adr/ADR-001-workplan-convention.md (formalises existing convention)
- Add docs/adr/ADR-002-project-memory-convention.md (file location, structure,
  session protocols, opt-out, CLI interface)
- Implement `kaizen-agentic memory` command group: show, init, brief, clear
  - Memory stored at .kaizen/agents/<name>/memory.md in project root
  - `init` scaffolds the standard memory template with YAML frontmatter
  - `brief` lists all agent memories + note that coach synthesis is pending T13
  - `clear` deletes with confirmation prompt

WP-0002 T07 and T08 done.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-18 23:25:48 +00:00
parent eff77973a1
commit 4b4b1ff1f1
4 changed files with 312 additions and 2 deletions

View File

@@ -0,0 +1,57 @@
---
id: ADR-001
title: Workplan Convention
status: accepted
date: "2026-03-18"
---
# ADR-001 — Workplan Convention
## Status
Accepted
## Context
kaizen-agentic needs a way to track planned work that is version-controlled,
visible to the state-hub, and authoritative when the two diverge.
## Decision
Work items originate as Markdown files in `workplans/` **before** being
registered in the state-hub DB. The file is always authoritative; the DB is
a read/query model derived from it.
**File naming:** `workplans/kaizen-agentic-WP-NNNN-<slug>.md`
**ID prefix:** `KAIZEN-WP`
### Required YAML frontmatter
```yaml
---
id: KAIZEN-WP-NNNN
type: workplan
title: "..."
domain: custodian
repo: kaizen-agentic
status: active | completed | archived
owner: kaizen-agentic
topic_slug: custodian
state_hub_workstream_id: <uuid>
created: "YYYY-MM-DD"
updated: "YYYY-MM-DD"
---
```
### Task tracking
Tasks use `- [ ]` / `- [x]` checkboxes with a `T##` code prefix. A
`## State Hub Task IDs` table at the end of each workplan maps codes to
DB UUIDs so status can be synced without a list_tasks lookup.
## Consequences
- File is the source of truth; DB drift is auto-fixable via
`check_repo_consistency(fix=True)`.
- Tasks must be created in the file first, then registered in the hub.
- C-12 warnings are expected when the DB host has not yet seen local changes.

View File

@@ -0,0 +1,119 @@
---
id: ADR-002
title: Project Memory Convention
status: accepted
date: "2026-03-18"
---
# ADR-002 — Project Memory Convention
## Status
Accepted
## Context
kaizen-agentic agents are stateless by default — each session starts from
scratch with no knowledge of what has been tried, what worked, or what the
project's recurring patterns are. This makes agents less useful over time
and forces the operator to re-supply context that the agent itself
accumulated.
## Decision
Each agent deployed into a project may maintain a **project-scoped memory
file**. Memory files are written at session close and read at session start.
### File location
```
<project-root>/.kaizen/agents/<agent-name>/memory.md
```
The `.kaizen/` directory is the kaizen-agentic ecosystem's project-level
state directory, analogous to `.claude/` for Claude Code.
### Memory file structure
```markdown
---
agent: <agent-name>
project: <project-root or slug>
last_updated: <ISO date>
session_count: <n>
---
## Project Context
<!-- What this agent knows about the project it works in -->
## Accumulated Findings
<!-- Patterns, recurring issues, key decisions encountered -->
## What Worked
<!-- Approaches that produced good results in this project -->
## Watch Points
<!-- Recurring risks, traps, or areas requiring extra care -->
## Open Threads
<!-- Things noticed but not yet acted on -->
## Session Log
<!-- One-line entry per session: date · summary · outcome -->
```
### Session-start protocol (all memory-enabled agents)
1. Check for `.kaizen/agents/<name>/memory.md` in the project root.
2. If present, read it before beginning work.
3. Acknowledge the memory in the opening brief.
### Session-close protocol (all memory-enabled agents)
1. Update `## Accumulated Findings`, `## What Worked`, `## Watch Points`
as needed.
2. Append one line to `## Session Log`.
3. Bump `last_updated` and `session_count`.
### Agent opt-out
An agent may declare `memory: disabled` in its YAML frontmatter to opt out.
Default is enabled. Stateless utility agents (e.g. `keepaTodofile`) should
opt out.
### CLI interface
```
kaizen-agentic memory show <agent> # Print agent memory for current project
kaizen-agentic memory init <agent> # Scaffold empty memory file
kaizen-agentic memory brief <agent> # Run coach, print orientation for agent
kaizen-agentic memory clear <agent> # Wipe memory (with confirmation prompt)
```
`memory init` creates the `.kaizen/agents/<name>/memory.md` file with the
standard structure and populates the frontmatter.
### Coaching meta-agent
A dedicated `agent-coach.md` (category: `meta`) reads across all
`.kaizen/agents/*/memory.md` files in a project and:
- Synthesises a cross-agent brief (shared patterns, cross-domain risks)
- Produces a new-agent orientation targeted at a specific agent about to
be deployed for the first time
- Maintains its own memory covering meta-level fleet observations
`kaizen-agentic memory brief <agent>` invokes the coach to produce this
orientation.
## Consequences
- Agents accumulate project-specific knowledge and arrive in later sessions
informed rather than blank.
- The `.kaizen/` directory should be added to `.gitignore` by default;
teams may choose to commit it for shared context.
- Memory files are human-readable and can be manually edited or reviewed.
- The coach agent provides a single synthesised view across all agent
memories — reducing the operator's burden of re-supplying context.
- Agents with `memory: disabled` remain fully stateless and require no
`.kaizen/` setup.

View File

@@ -756,6 +756,140 @@ def remove(name: str, target: str):
click.echo(f"❌ Extension not found: {name}")
@cli.group()
def memory():
"""Manage project-scoped agent memory (.kaizen/agents/<name>/memory.md)."""
pass
@memory.command("show")
@click.argument("agent_name")
@click.option("--target", "-t", default=".", help="Project root (default: current)")
def memory_show(agent_name: str, target: str):
"""Print agent memory for the current project."""
memory_path = _memory_path(target, agent_name)
if not memory_path.exists():
click.echo(f"No memory found for agent '{agent_name}'.")
click.echo(f" Expected: {memory_path}")
click.echo(f" Run: kaizen-agentic memory init {agent_name}")
return
click.echo(memory_path.read_text())
@memory.command("init")
@click.argument("agent_name")
@click.option("--target", "-t", default=".", help="Project root (default: current)")
def memory_init(agent_name: str, target: str):
"""Scaffold an empty memory file for an agent."""
memory_path = _memory_path(target, agent_name)
if memory_path.exists():
click.echo(f"Memory file already exists: {memory_path}")
return
memory_path.parent.mkdir(parents=True, exist_ok=True)
project_name = Path(target).resolve().name
content = f"""---
agent: {agent_name}
project: {project_name}
last_updated: {_today()}
session_count: 0
---
## Project Context
<!-- What this agent knows about the project it works in -->
## Accumulated Findings
<!-- Patterns, recurring issues, key decisions encountered -->
## What Worked
<!-- Approaches that produced good results in this project -->
## Watch Points
<!-- Recurring risks, traps, or areas requiring extra care -->
## Open Threads
<!-- Things noticed but not yet acted on -->
## Session Log
<!-- One-line entry per session: date · summary · outcome -->
"""
memory_path.write_text(content)
click.echo(f"Initialized memory for '{agent_name}': {memory_path}")
@memory.command("brief")
@click.argument("agent_name")
@click.option("--target", "-t", default=".", help="Project root (default: current)")
def memory_brief(agent_name: str, target: str):
"""Print a coach-synthesised orientation for an agent.
Reads this agent's memory and all other agent memories in the project.
Coach agent integration is pending (T13 — see KAIZEN-WP-0002).
Currently prints the agent's own memory as a starting orientation.
"""
memory_path = _memory_path(target, agent_name)
kaizen_dir = Path(target).resolve() / ".kaizen" / "agents"
click.echo(f"=== Agent Brief: {agent_name} ===\n")
# Show own memory
if memory_path.exists():
click.echo(f"--- Memory: {agent_name} ---")
click.echo(memory_path.read_text())
else:
click.echo(f"No memory file found for '{agent_name}'. Run: memory init {agent_name}")
# List other agents with memory in this project
other_agents = []
if kaizen_dir.exists():
for agent_dir in kaizen_dir.iterdir():
if agent_dir.is_dir() and agent_dir.name != agent_name:
mf = agent_dir / "memory.md"
if mf.exists():
other_agents.append(agent_dir.name)
if other_agents:
click.echo(f"\n--- Other agents with memory in this project: {', '.join(other_agents)} ---")
click.echo("(Coach synthesis not yet available — use 'memory show <agent>' to read each)")
else:
click.echo("\nNo other agent memories found in this project.")
click.echo("\nNote: Full coach synthesis will be available once agent-coach is implemented (KAIZEN-WP-0002 T12-T13).")
@memory.command("clear")
@click.argument("agent_name")
@click.option("--target", "-t", default=".", help="Project root (default: current)")
@click.confirmation_option(prompt="This will permanently delete the agent memory. Continue?")
def memory_clear(agent_name: str, target: str):
"""Wipe agent memory for the current project."""
memory_path = _memory_path(target, agent_name)
if not memory_path.exists():
click.echo(f"No memory found for agent '{agent_name}' — nothing to clear.")
return
memory_path.unlink()
click.echo(f"Cleared memory for '{agent_name}': {memory_path}")
# Remove empty parent directory
if not any(memory_path.parent.iterdir()):
memory_path.parent.rmdir()
def _memory_path(target: str, agent_name: str) -> Path:
return Path(target).resolve() / ".kaizen" / "agents" / agent_name / "memory.md"
def _today() -> str:
from datetime import date
return date.today().isoformat()
def _get_registry() -> AgentRegistry:
"""Get the agent registry."""
# Try to find agents directory

View File

@@ -138,8 +138,8 @@ kaizen-agentic memory clear <agent> # Wipe memory (with confirmation)
### Tasks
**Memory convention and tooling**
- [ ] T07 — Write ADR: project memory convention (file location, structure, lifecycle)
- [ ] T08 — Implement `memory` CLI command group (show, init, brief, clear)
- [x] T07 — Write ADR: project memory convention (file location, structure, lifecycle)
- [x] T08 — Implement `memory` CLI command group (show, init, brief, clear)
- [ ] T09 — Add session-start and session-close protocol sections to agent template /
contributor guide