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
2 changes: 2 additions & 0 deletions codex-rs/core/src/memories/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ mod tests {
use codex_state::Stage1Output;
use codex_state::ThreadMetadataBuilder;
use pretty_assertions::assert_eq;
use std::path::PathBuf;
use std::sync::Arc;
use tempfile::TempDir;

Expand Down Expand Up @@ -402,6 +403,7 @@ mod tests {
.expect("valid source_updated_at timestamp"),
raw_memory: "raw memory".to_string(),
rollout_summary: "rollout summary".to_string(),
cwd: PathBuf::from("/tmp/workspace"),
generated_at: chrono::DateTime::<Utc>::from_timestamp(124, 0)
.expect("valid generated_at timestamp"),
};
Expand Down
4 changes: 4 additions & 0 deletions codex-rs/core/src/memories/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ async fn rebuild_raw_memories_file(root: &Path, memories: &[Stage1Output]) -> st
memory.source_updated_at.to_rfc3339()
)
.map_err(|err| std::io::Error::other(format!("format raw memories: {err}")))?;
writeln!(body, "cwd: {}", memory.cwd.display())
.map_err(|err| std::io::Error::other(format!("format raw memories: {err}")))?;
writeln!(body)
.map_err(|err| std::io::Error::other(format!("format raw memories: {err}")))?;
body.push_str(memory.raw_memory.trim());
Expand Down Expand Up @@ -138,6 +140,8 @@ async fn write_rollout_summary_for_thread(
memory.source_updated_at.to_rfc3339()
)
.map_err(|err| std::io::Error::other(format!("format rollout summary: {err}")))?;
writeln!(body, "cwd: {}", memory.cwd.display())
.map_err(|err| std::io::Error::other(format!("format rollout summary: {err}")))?;
writeln!(body)
.map_err(|err| std::io::Error::other(format!("format rollout summary: {err}")))?;
body.push_str(&memory.rollout_summary);
Expand Down
3 changes: 3 additions & 0 deletions codex-rs/core/src/memories/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use codex_protocol::ThreadId;
use codex_state::Stage1Output;
use pretty_assertions::assert_eq;
use serde_json::Value;
use std::path::PathBuf;
use tempfile::tempdir;

#[test]
Expand Down Expand Up @@ -65,6 +66,7 @@ async fn sync_rollout_summaries_and_raw_memories_file_keeps_latest_memories_only
source_updated_at: Utc.timestamp_opt(100, 0).single().expect("timestamp"),
raw_memory: "raw memory".to_string(),
rollout_summary: "short summary".to_string(),
cwd: PathBuf::from("/tmp/workspace"),
generated_at: Utc.timestamp_opt(101, 0).single().expect("timestamp"),
}];

Expand All @@ -83,4 +85,5 @@ async fn sync_rollout_summaries_and_raw_memories_file_keeps_latest_memories_only
.expect("read raw memories");
assert!(raw_memories.contains("raw memory"));
assert!(raw_memories.contains(&keep_id));
assert!(raw_memories.contains("cwd: /tmp/workspace"));
}
11 changes: 8 additions & 3 deletions codex-rs/core/templates/memories/consolidation.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ Primary inputs (always read these, if exists):
Under `{{ memory_root }}/`:
- `raw_memories.md`
- mechanical merge of `raw_memories` from Phase 1;
- source of rollout-level metadata needed for MEMORY.md header annotations;
you should be able to find `cwd` and `updated_at` there.
- `MEMORY.md`
- merged memories; produce a lightly clustered version if applicable
- `rollout_summaries/*.md`
Expand Down Expand Up @@ -129,8 +131,8 @@ Rules:
Clustered schema:
---
rollout_summary_files:
- <file1.md> (<a few words annotation such as "success, most useful" or "uncertain, no user feedback">)
- <file2.md> (<annotation>)
- <file1.md> (<annotation that includes status/usefulness, cwd, and updated_at, e.g. "success, most useful architecture walkthrough, cwd=/repo/path, updated_at=2026-02-12T10:30:00Z">)
- <file2.md> (<annotation with cwd=/..., updated_at=...>)
description: brief description of the shared tasks/outcomes
keywords: k1, k2, k3, ... <searchable handles (tool names, error names, repo concepts, contracts)>
---
Expand All @@ -141,6 +143,9 @@ keywords: k1, k2, k3, ... <searchable handles (tool names, error names, repo con
Schema rules (strict):
- Keep entries compact and retrieval-friendly.
- A single note block may correspond to multiple related tasks; aggregate when tasks and lessons align.
- In `rollout_summary_files`, each parenthesized annotation must include
`cwd=<path>` and `updated_at=<timestamp>` copied from that rollout summary metadata.
If missing from an individual rollout summary, recover them from `raw_memories.md`.
- If you need to reference skills, do it in the BODY as bullets, not in the header
(e.g., "- Related skill: skills/<skill-name>/SKILL.md").
- Use lowercase, hyphenated skill folder names.
Expand Down Expand Up @@ -338,4 +343,4 @@ Use `rg` for fast retrieval while consolidating:
- Search across memory tree:
`rg -n -i "<pattern>" "{{ memory_root }}" | head -n 50`
- Locate rollout summary files:
`rg --files "{{ memory_root }}/rollout_summaries" | head -n 200`
`rg --files "{{ memory_root }}/rollout_summaries" | head -n 200`
5 changes: 5 additions & 0 deletions codex-rs/state/src/model/memories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use chrono::Utc;
use codex_protocol::ThreadId;
use sqlx::Row;
use sqlx::sqlite::SqliteRow;
use std::path::PathBuf;

use super::ThreadMetadata;

Expand All @@ -14,6 +15,7 @@ pub struct Stage1Output {
pub source_updated_at: DateTime<Utc>,
pub raw_memory: String,
pub rollout_summary: String,
pub cwd: PathBuf,
pub generated_at: DateTime<Utc>,
}

Expand All @@ -23,6 +25,7 @@ pub(crate) struct Stage1OutputRow {
source_updated_at: i64,
raw_memory: String,
rollout_summary: String,
cwd: String,
generated_at: i64,
}

Expand All @@ -33,6 +36,7 @@ impl Stage1OutputRow {
source_updated_at: row.try_get("source_updated_at")?,
raw_memory: row.try_get("raw_memory")?,
rollout_summary: row.try_get("rollout_summary")?,
cwd: row.try_get("cwd")?,
generated_at: row.try_get("generated_at")?,
})
}
Expand All @@ -47,6 +51,7 @@ impl TryFrom<Stage1OutputRow> for Stage1Output {
source_updated_at: epoch_seconds_to_datetime(row.source_updated_at)?,
raw_memory: row.raw_memory,
rollout_summary: row.rollout_summary,
cwd: PathBuf::from(row.cwd),
generated_at: epoch_seconds_to_datetime(row.generated_at)?,
})
}
Expand Down
3 changes: 3 additions & 0 deletions codex-rs/state/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2093,8 +2093,10 @@ WHERE kind = 'memory_stage1'
assert_eq!(outputs.len(), 2);
assert_eq!(outputs[0].thread_id, thread_id_b);
assert_eq!(outputs[0].rollout_summary, "summary b");
assert_eq!(outputs[0].cwd, codex_home.join("workspace-b"));
assert_eq!(outputs[1].thread_id, thread_id_a);
assert_eq!(outputs[1].rollout_summary, "summary a");
assert_eq!(outputs[1].cwd, codex_home.join("workspace-a"));

let _ = tokio::fs::remove_dir_all(codex_home).await;
}
Expand Down Expand Up @@ -2163,6 +2165,7 @@ VALUES (?, ?, ?, ?, ?)
assert_eq!(outputs.len(), 1);
assert_eq!(outputs[0].thread_id, thread_id_non_empty);
assert_eq!(outputs[0].rollout_summary, "summary");
assert_eq!(outputs[0].cwd, codex_home.join("workspace-non-empty"));

let _ = tokio::fs::remove_dir_all(codex_home).await;
}
Expand Down
4 changes: 4 additions & 0 deletions codex-rs/state/src/runtime/memories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ LEFT JOIN jobs
///
/// Query behavior:
/// - filters out rows where both `raw_memory` and `rollout_summary` are blank
/// - joins `threads` to include thread `cwd`
/// - orders by `source_updated_at DESC, thread_id DESC`
/// - applies `LIMIT n`
pub async fn list_stage1_outputs_for_global(
Expand All @@ -191,7 +192,10 @@ LEFT JOIN jobs
let rows = sqlx::query(
r#"
SELECT so.thread_id, so.source_updated_at, so.raw_memory, so.rollout_summary, so.generated_at
, COALESCE(t.cwd, '') AS cwd
FROM stage1_outputs AS so
LEFT JOIN threads AS t
ON t.id = so.thread_id
Comment thread
jif-oai marked this conversation as resolved.
WHERE length(trim(so.raw_memory)) > 0 OR length(trim(so.rollout_summary)) > 0
ORDER BY so.source_updated_at DESC, so.thread_id DESC
LIMIT ?
Expand Down
Loading