Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions .planning/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@

**Goal:** Add agent identifier to events and build adapter SDK foundation.

**Plans:** 4 plans in 3 waves

Plans:
- [x] 18-01-PLAN.md — Add agent field to Event proto and Rust types
- [x] 18-02-PLAN.md — Create memory-adapters crate with AgentAdapter trait
- [x] 18-03-PLAN.md — Add contributing_agents to TocNode, --agent CLI filter
- [x] 18-04-PLAN.md — Wire agent through ingest and query paths

**Scope:**
- Add `agent` field to Event proto and storage layer
- Create adapter trait defining common interface
Expand All @@ -22,16 +30,17 @@

**Files to modify:**
- `proto/memory.proto` — Event message, query filters
- `crates/memory-core/src/models/` — Event model
- `crates/memory-storage/src/` — Storage layer agent support
- `crates/memory-types/src/` — Event and TocNode models
- `crates/memory-daemon/src/` — CLI filter support
- `crates/memory-service/src/` — Ingest handler
- `crates/memory-retrieval/src/` — Query filtering types
- New: `crates/memory-adapters/` — Adapter SDK crate

**Definition of done:**
- [ ] Events can be ingested with agent identifier
- [ ] Queries filter by agent when `--agent` specified
- [ ] Default queries return all agents
- [ ] Adapter trait compiles and documents interface
- [x] Events can be ingested with agent identifier
- [x] Queries filter by agent when `--agent` specified
- [x] Default queries return all agents
- [x] Adapter trait compiles and documents interface

---

Expand Down
41 changes: 28 additions & 13 deletions .planning/STATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ See: .planning/PROJECT.md (updated 2026-02-08)
## Current Position

Milestone: v2.1 Multi-Agent Ecosystem
Phase: 18 — Agent Tagging Infrastructure
Plan: Ready for planning
Status: Requirements and roadmap defined
Last activity: 2026-02-08 — Requirements and roadmap created
Phase: 18 — Agent Tagging Infrastructure — COMPLETE
Plan: All 4 plans executed
Status: Phase 18 complete, ready for Phase 19-22 (parallel)
Last activity: 2026-02-08 — Phase 18 executed (4 plans, 3 waves)

Progress v2.1: [░░░░░░░░░░░░░░░░░░░░] 0% (0/6 phases)
Progress v2.1: [███░░░░░░░░░░░░░░░░░] 17% (1/6 phases)

## Milestone History

Expand Down Expand Up @@ -72,18 +72,33 @@ Full decision log in PROJECT.md Key Decisions table.

| Phase | Name | Status |
|-------|------|--------|
| 18 | Agent Tagging Infrastructure | Ready |
| 19 | OpenCode Commands and Skills | Blocked by 18 |
| 18 | Agent Tagging Infrastructure | ✓ Complete |
| 19 | OpenCode Commands and Skills | Ready |
| 20 | OpenCode Event Capture + Unified Queries | Blocked by 19 |
| 21 | Gemini CLI Adapter | Blocked by 18 |
| 22 | Copilot CLI Adapter | Blocked by 18 |
| 21 | Gemini CLI Adapter | Ready |
| 22 | Copilot CLI Adapter | Ready |
| 23 | Cross-Agent Discovery + Documentation | Blocked by 21, 22 |

## Next Steps

1. `/gsd:plan-phase 18` — Plan agent tagging infrastructure
2. Execute Phase 18
3. Phases 19-22 can run in parallel after 18
1. `/gsd:plan-phase 19` — Plan OpenCode commands and skills
2. `/gsd:plan-phase 21` — Plan Gemini CLI adapter (can run parallel with 19)
3. `/gsd:plan-phase 22` — Plan Copilot CLI adapter (can run parallel with 19)

## Phase 18 Summary

**Completed:** 2026-02-08

**Artifacts created:**
- `proto/memory.proto` — Event.agent field, query request agent_filter fields
- `crates/memory-types/src/event.rs` — Event.agent with serde(default)
- `crates/memory-types/src/toc.rs` — TocNode.contributing_agents
- `crates/memory-adapters/` — New crate with AgentAdapter trait, AdapterConfig, AdapterError
- `crates/memory-daemon/src/cli.rs` — --agent filter on teleport and retrieval commands
- `crates/memory-retrieval/src/types.rs` — StopConditions.agent_filter
- `crates/memory-service/src/ingest.rs` — Agent extraction from proto Event

**Tests:** 61 memory-types + 19 memory-adapters + 53 memory-retrieval = 133 tests passing

---
*Updated: 2026-02-08 after requirements and roadmap creation*
*Updated: 2026-02-08 after Phase 18 execution*
189 changes: 189 additions & 0 deletions .planning/phases/18-agent-tagging-infrastructure/18-01-PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
---
phase: 18-agent-tagging-infrastructure
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- proto/memory.proto
- crates/memory-types/src/event.rs
autonomous: true

must_haves:
truths:
- "Events can be ingested with optional agent identifier"
- "Old events without agent field deserialize correctly"
- "Proto Event message includes optional agent field"
artifacts:
- path: "proto/memory.proto"
provides: "Event message with agent field"
contains: "optional string agent"
- path: "crates/memory-types/src/event.rs"
provides: "Event struct with agent field"
contains: "pub agent: Option<String>"
key_links:
- from: "crates/memory-types/src/event.rs"
to: "proto/memory.proto"
via: "Proto code generation"
pattern: "agent.*Option<String>"
---

<objective>
Add the `agent` field to Event in both proto and Rust types.

Purpose: Enable tracking which AI agent (Claude, OpenCode, Gemini, Copilot) produced each event. This is the foundational change for multi-agent memory unification.

Output: Updated proto schema and Rust Event struct with backward-compatible agent field.
</objective>

<execution_context>
@/Users/richardhightower/.claude/get-shit-done/workflows/execute-plan.md
@/Users/richardhightower/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/18-agent-tagging-infrastructure/18-RESEARCH.md

# Source files to modify
@proto/memory.proto
@crates/memory-types/src/event.rs
</context>

<tasks>

<task type="auto">
<name>Task 1: Add agent field to Event proto message</name>
<files>proto/memory.proto</files>
<action>
Add optional agent field to the Event message in proto/memory.proto.

Location: Find the Event message (around line 151) and add after field 7 (metadata):

```protobuf
// Phase 18: Agent identifier for multi-agent memory
// Common values: "claude", "opencode", "gemini", "copilot"
// Empty/absent means legacy event or unknown source
optional string agent = 8;
```

Use `optional` keyword per proto3 semantics for fields that may be absent.
Field number 8 is the next available after metadata (7).

Do NOT modify any other messages - only the Event message.
</action>
<verify>
Run `cargo build -p memory-service` to verify proto compiles and generates Rust code.
Check generated code in `target/debug/build/memory-service-*/out/memory.rs` contains `agent` field.
</verify>
<done>
Event message in proto/memory.proto has optional string agent field at position 8.
Proto compiles without errors.
</done>
</task>

<task type="auto">
<name>Task 2: Add agent field to Rust Event struct</name>
<files>crates/memory-types/src/event.rs</files>
<action>
Add agent field to the Event struct in crates/memory-types/src/event.rs.

Follow the Phase 16 pattern for backward compatibility (see salience fields in TocNode).

1. Add the field to Event struct after metadata:

```rust
/// Agent that produced this event.
///
/// Common values: "claude", "opencode", "gemini", "copilot".
/// Default: None for pre-phase-18 events (backward compatible).
#[serde(default)]
pub agent: Option<String>,
```

2. Update Event::new() to initialize agent to None:
In the Self { ... } block, add: `agent: None,`

3. Add builder method after with_metadata():

```rust
/// Set the agent identifier for this event.
pub fn with_agent(mut self, agent: impl Into<String>) -> Self {
self.agent = Some(agent.into());
self
}
```

4. Add backward compatibility test:

```rust
#[test]
fn test_event_backward_compat_no_agent() {
// Simulate pre-phase-18 serialized event (no agent field)
let v200_json = r#"{
"event_id": "01HN4QXKN6YWXVKZ3JMHP4BCDE",
"session_id": "session-123",
"timestamp": 1704067200000,
"event_type": "user_message",
"role": "user",
"text": "Hello, world!"
}"#;

let event: Event = serde_json::from_str(v200_json).unwrap();

// Verify default agent is None
assert!(event.agent.is_none());
// Verify other fields loaded correctly
assert_eq!(event.event_id, "01HN4QXKN6YWXVKZ3JMHP4BCDE");
}

#[test]
fn test_event_with_agent() {
let event = Event::new(
"01HN4QXKN6YWXVKZ3JMHP4BCDE".to_string(),
"session-123".to_string(),
Utc::now(),
EventType::UserMessage,
EventRole::User,
"Hello, world!".to_string(),
)
.with_agent("claude");

assert_eq!(event.agent, Some("claude".to_string()));
}
```
</action>
<verify>
Run `cargo test -p memory-types` - all tests pass including new backward compat tests.
Run `cargo clippy -p memory-types` - no warnings.
</verify>
<done>
Event struct has agent: Option<String> field with serde(default).
with_agent() builder method exists.
Backward compatibility test passes for events without agent field.
Test for events with agent field passes.
</done>
</task>

</tasks>

<verification>
1. `cargo build --workspace` compiles successfully
2. `cargo test -p memory-types` passes all tests
3. `cargo clippy -p memory-types` has no warnings
4. Proto regenerates without errors on next memory-service build
</verification>

<success_criteria>
- Event proto message has `optional string agent = 8`
- Event Rust struct has `agent: Option<String>` with `#[serde(default)]`
- Old events without agent field deserialize with agent = None
- New events can be created with agent identifier using with_agent()
- All existing tests continue to pass
</success_criteria>

<output>
After completion, create `.planning/phases/18-agent-tagging-infrastructure/18-01-SUMMARY.md`
</output>
91 changes: 91 additions & 0 deletions .planning/phases/18-agent-tagging-infrastructure/18-01-SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Plan 18-01 Summary: Add Agent Field to Event

**Status:** COMPLETE
**Date:** 2026-02-08
**Phase:** 18-agent-tagging-infrastructure

## Objective

Add the `agent` field to Event in both proto and Rust types to enable tracking which AI agent (Claude, OpenCode, Gemini, Copilot) produced each event.

## Tasks Completed

### Task 1: Add agent field to Event proto message

**File Modified:** `proto/memory.proto`

Added optional agent field to Event message at position 8:

```protobuf
// Phase 18: Agent identifier for multi-agent memory
// Common values: "claude", "opencode", "gemini", "copilot"
// Empty/absent means legacy event or unknown source
optional string agent = 8;
```

**Verification:** Proto syntax validated with protoc (no errors).

### Task 2: Add agent field to Rust Event struct

**File Modified:** `crates/memory-types/src/event.rs`

Changes made:
1. Added `agent: Option<String>` field with `#[serde(default)]` for backward compatibility
2. Updated `Event::new()` to initialize `agent: None`
3. Added `with_agent()` builder method
4. Added two backward compatibility tests

**Code Added:**

```rust
/// Agent that produced this event.
///
/// Common values: "claude", "opencode", "gemini", "copilot".
/// Default: None for pre-phase-18 events (backward compatible).
#[serde(default)]
pub agent: Option<String>,
```

```rust
/// Set the agent identifier for this event.
pub fn with_agent(mut self, agent: impl Into<String>) -> Self {
self.agent = Some(agent.into());
self
}
```

## Verification Results

| Check | Result |
|-------|--------|
| `cargo build -p memory-types` | PASS |
| `cargo test -p memory-types` | PASS (58 tests, including 2 new) |
| `cargo clippy -p memory-types` | PASS (no warnings) |
| Proto syntax check | PASS |

**Note:** `cargo build -p memory-service` failed due to local C++ toolchain issues (esaxx-rs, librocksdb-sys build failures) unrelated to the proto changes. The proto file changes are syntactically correct.

## New Tests Added

1. `test_event_backward_compat_no_agent` - Verifies pre-phase-18 events (without agent field) deserialize correctly with `agent = None`
2. `test_event_with_agent` - Verifies `with_agent()` builder method works correctly

## Files Modified

- `/Users/richardhightower/clients/spillwave/src/agent-memory/proto/memory.proto` (lines 174-177)
- `/Users/richardhightower/clients/spillwave/src/agent-memory/crates/memory-types/src/event.rs` (lines 90-95, 116, 126-130, 190-223)

## Success Criteria Met

- [x] Event proto message has `optional string agent = 8`
- [x] Event Rust struct has `agent: Option<String>` with `#[serde(default)]`
- [x] Old events without agent field deserialize with agent = None
- [x] New events can be created with agent identifier using `with_agent()`
- [x] All existing tests continue to pass

## Next Steps

This plan completes the foundational infrastructure for Phase 18. The agent field is now available for:
- Plan 18-02: memory-adapters crate with agent-specific adapters
- Plan 18-03: claude adapter implementation
- Plan 18-04: opencode adapter implementation
Loading