Move project memory from .g3/ to analysis/ for version control

Project memory is now stored at analysis/memory.md instead of .g3/memory.md.
This change enables:
- Shared memory across git worktrees (studio agent sessions)
- Version-controlled memory that persists across clones
- Memory changes tracked in git history and reviewable in PRs

Changes:
- crates/g3-core/src/tools/memory.rs: Update get_memory_path() to use analysis/
- crates/g3-cli/src/project_files.rs: Update read_project_memory() path
- crates/g3-core/src/prompts.rs: Update documentation references (2 occurrences)
- analysis/memory.md: Add memory file (copied from .g3/memory.md)
This commit is contained in:
Dhanji R. Prasanna
2026-01-12 10:20:33 +05:30
parent 21ecbb3fb8
commit d508ddd508
4 changed files with 174 additions and 7 deletions

167
analysis/memory.md Normal file
View File

@@ -0,0 +1,167 @@
# Project Memory
> Updated: 2026-01-12T04:44:39Z | Size: 9.9k chars
### Remember Tool Wiring
- `crates/g3-core/src/tools/memory.rs` [0..5000] - `execute_remember()`, `get_memory_path()`, `merge_memory()`
- `crates/g3-core/src/tool_definitions.rs` [11000..12000] - remember tool definition in `create_core_tools()`
- `crates/g3-core/src/tool_dispatch.rs` [48] - dispatch case for "remember"
- `crates/g3-core/src/prompts.rs` [4200..6500] - Project Memory section in native prompt
- `crates/g3-cli/src/lib.rs` [1472..1495] - `read_project_memory()` loads memory at startup
### Context Window & Compaction
- `crates/g3-core/src/context_window.rs` [0..815] - `ContextWindow`, `reset_with_summary()`, `should_compact()`, `thin_context()`
- `crates/g3-core/src/lib.rs` [0..132483] - `Agent` struct, `force_compact()`, `stream_completion_with_tools()`
### Session Storage & Continuation
- `crates/g3-core/src/session_continuation.rs` [0..541] - `SessionContinuation`, `save_continuation()`, `load_continuation()`
- `crates/g3-core/src/paths.rs` [0..133] - `get_session_logs_dir()`, `get_thinned_dir()`, `get_session_file()`
- `crates/g3-core/src/session.rs` - Session logging utilities
### Tool System
- `crates/g3-core/src/tool_definitions.rs` [0..544] - `create_core_tools()`, `create_tool_definitions()`, `ToolConfig`
- `crates/g3-core/src/tool_dispatch.rs` [0..73] - `dispatch_tool()` routing
### CLI Argument Parsing
- `crates/g3-cli/src/lib.rs` [270..380] - `Cli` struct with clap derive macros
- `crates/g3-cli/src/lib.rs` [1700..2200] - `run_interactive()` with `/` command handlers
### Streaming Markdown Formatter
- `crates/g3-cli/src/streaming_markdown.rs` [21500..22500] - `format_header()` processes headers with inline formatting
- `crates/g3-cli/tests/streaming_markdown_test.rs` - Tests for markdown formatting including `test_bold_inside_header`, `test_italic_inside_header`, `test_code_inside_header`, `test_mixed_formatting_inside_header`
### Auto-Memory Feature
- `crates/g3-core/src/lib.rs` [1459..1522] - `send_auto_memory_reminder()` sends reminder to LLM after tool calls
- `crates/g3-core/src/lib.rs` [1451..1454] - `set_auto_memory()` enables/disables auto-memory
- `crates/g3-core/src/lib.rs` [116] - `tool_calls_this_turn: Vec<String>` tracks tools called per turn
- `crates/g3-cli/src/lib.rs` [393] - `auto_memory: bool` CLI flag definition
- `crates/g3-cli/src/lib.rs` [641..642, 684..685] - Flag applied to agent in console/machine modes
- `crates/g3-cli/src/lib.rs` [1340..1350, 1394..1404] - Auto-memory reminder called in single-shot mode
- `crates/g3-cli/src/lib.rs` [1758, 1931, 2216] - Auto-memory reminder called in interactive mode
### Tool Call Tracking
- `crates/g3-core/src/lib.rs` [2843..2855] - `execute_tool_in_dir()` tracks all tool calls for auto-memory
### Agent Mode
- `crates/g3-cli/src/lib.rs` [695..910] - `run_agent_mode()` handles specialized agent execution with custom prompts
- `crates/g3-cli/src/lib.rs` [820..835] - Agent creation with `Agent::new_with_custom_prompt()`
- `crates/g3-cli/src/lib.rs` [837] - `agent.set_agent_mode()` enables agent-specific session tracking
### CLI Entry Points and Modes
- `crates/g3-cli/src/lib.rs` [0..140000] - `run()` main entry, `run_agent_mode()`, `run_flock_mode()`, `run_accumulative_mode()`, `run_autonomous()`, `run_interactive()`, `run_interactive_machine()`
- `crates/g3-cli/src/lib.rs` - `execute_task()` (~line 1990), `execute_task_machine()` (~line 2262) - duplicated retry logic
### Retry Infrastructure
- `crates/g3-core/src/retry.rs` [0..12000] - `execute_with_retry()`, `retry_operation()`, `RetryConfig`, `RetryResult` - used by g3-planner but not g3-cli
### UI Abstraction Layer
- `crates/g3-core/src/ui_writer.rs` [0..4500] - `UiWriter` trait, `NullUiWriter`
- `crates/g3-cli/src/ui_writer_impl.rs` [0..14000] - `ConsoleUiWriter` implementation
- `crates/g3-cli/src/machine_ui_writer.rs` [0..4000] - `MachineUiWriter` implementation
- `crates/g3-cli/src/simple_output.rs` [0..1200] - `SimpleOutput` helper (separate from UiWriter)
### Feedback Extraction
- `crates/g3-core/src/feedback_extraction.rs` [0..22000] - `extract_coach_feedback()`, `try_extract_from_session_log()`, `try_extract_from_native_tool_call()`
### Streaming Utilities
- `crates/g3-core/src/streaming.rs` [0..10000] - `truncate_line()`, `truncate_for_display()`, `log_stream_error()`, `is_connection_error()`
### Background Process Management
- `crates/g3-core/src/background_process.rs` [0..3000] - `BackgroundProcessManager`, `start()`, `list()`, `is_running()`, `get()`, `remove()`
- Design: No `stop()` method - processes are stopped via shell tool using `kill <pid>`
### Unified Diff Application
- `crates/g3-core/src/utils.rs` [5000..15000] - `apply_unified_diff_to_string()`, `parse_unified_diff_hunks()`
- Handles multi-hunk diffs, CRLF normalization, range constraints
### Error Classification
- `crates/g3-core/src/error_handling.rs` [0..567 lines] - `classify_error()`, `ErrorType`, `RecoverableError`
- Priority order: rate limit > network > server > busy > timeout > token limit > context length
- Note: "Connection timeout" classifies as NetworkError (not Timeout) due to "connection" keyword priority
### CLI Module Extractions
- `crates/g3-cli/src/metrics.rs` [0..5416] - `TurnMetrics`, `format_elapsed_time()`, `generate_turn_histogram()`
- `crates/g3-cli/src/project_files.rs` [0..5577] - `read_agents_config()`, `read_project_readme()`, `read_project_memory()`, `extract_readme_heading()`
- `crates/g3-cli/src/coach_feedback.rs` [0..4025] - `extract_from_logs()` for coach-player loop feedback extraction
### Context Compaction
- `crates/g3-core/src/compaction.rs` [0..11213] - `perform_compaction()`, `CompactionResult`, `CompactionConfig`, `calculate_capped_summary_tokens()`, `should_disable_thinking()`, `build_summary_messages()`, `apply_summary_fallback_sequence()`
- Unified compaction used by both `force_compact()` and auto-compaction in `stream_completion_with_tools()`
### Streaming Markdown Formatter (Code Blocks)
- `crates/g3-cli/src/streaming_markdown.rs` [693..735] - `flush_incomplete()` handles unclosed blocks at end of stream
- `crates/g3-cli/src/streaming_markdown.rs` [654..675] - `emit_code_block()` joins block_buffer and highlights code
- `crates/g3-cli/src/streaming_markdown.rs` [439..462] - `process_in_code_block()` detects closing fence on newline
- Bug fix: closing ``` without trailing newline must be detected in flush_incomplete(), not just process_in_code_block()
### ACD (Aggressive Context Dehydration)
- `crates/g3-core/src/acd.rs` [0..22000] - `Fragment`, `Fragment::new()`, `Fragment::save()`, `Fragment::load()`, `generate_stub()`, `list_fragments()`, `get_latest_fragment_id()`
- `crates/g3-core/src/tools/acd.rs` [0..8500] - `execute_rehydrate()` tool implementation
- `crates/g3-core/src/paths.rs` [3200..3400] - `get_fragments_dir()` returns `.g3/sessions/<session_id>/fragments/`
- `crates/g3-core/src/compaction.rs` [195..240] - ACD integration in `perform_compaction()`, creates fragment and stub when `acd_enabled`
- `crates/g3-core/src/context_window.rs` [10100..10700] - `reset_with_summary_and_stub()` adds stub before summary
- `crates/g3-cli/src/lib.rs` [157..161] - `--acd` CLI flag
- `crates/g3-cli/src/lib.rs` [1476..1525] - `/fragments` and `/rehydrate` commands
### ACD Fragment Storage Format
```json
{
"fragment_id": "abc123",
"created_at": "2026-01-11T...",
"messages": [...],
"message_count": 47,
"user_message_count": 23,
"assistant_message_count": 24,
"tool_call_summary": {"read_file": 4, "shell": 5},
"estimated_tokens": 18500,
"topics": ["implemented auth", "fixed bug"],
"preceding_fragment_id": "xyz789"
}
```
### UTF-8 Safe String Slicing Pattern
**Problem**: Rust string slices (`&s[..n]`) use byte indices, not character indices. Multi-byte UTF-8 characters (emoji, bullets `•`, `×`, `⚡`) cause panics if sliced mid-character.
**Solution**: Use `char_indices()` to find byte boundaries:
```rust
// Get byte index of the Nth character
let byte_idx = s.char_indices()
.nth(char_limit)
.map(|(i, _)| i)
.unwrap_or(s.len());
let truncated = &s[..byte_idx];
// For length checks, use chars().count() not len()
if s.chars().count() <= max_len { ... }
```
**Danger zones**: Display truncation, ACD stubs, user input handling, any string with non-ASCII characters.
### CLI Module Structure (Post-Refactor)
- `crates/g3-cli/src/lib.rs` [0..415] - Entry point, `run()`, mode dispatch, config loading
- `crates/g3-cli/src/cli_args.rs` [0..133] - `Cli` struct with clap derive macros, argument parsing
- `crates/g3-cli/src/autonomous.rs` [0..785] - `run_autonomous()`, `run_flock_mode()`, coach-player feedback loop
- `crates/g3-cli/src/agent_mode.rs` [0..284] - `run_agent_mode()` specialized agent execution
- `crates/g3-cli/src/accumulative.rs` [0..343] - `run_accumulative_mode()` iterative requirements
- `crates/g3-cli/src/interactive.rs` [0..851] - `run_interactive()`, `run_interactive_machine()`, REPL with `/` commands
- `crates/g3-cli/src/task_execution.rs` [0..212] - `execute_task_with_retry()`, `OutputMode` enum - unified retry logic
- `crates/g3-cli/src/utils.rs` [0..91] - `display_welcome_message()`, `get_workspace_path()`
### Studio - Multi-Agent Workspace Manager
- `crates/studio/src/main.rs` [0..12500] - `cmd_run()`, `cmd_status()`, `cmd_accept()`, `cmd_discard()`, `extract_session_summary()`
- `crates/studio/src/session.rs` - `Session`, `SessionStatus`, session metadata management
- `crates/studio/src/git.rs` - `GitWorktree`, git worktree management for isolated agent sessions
**Session log format**: Session logs are stored at `<worktree>/.g3/sessions/<session_id>/session.json` with structure:
```json
{
"context_window": {
"conversation_history": [{"role": "...", "content": "..."}],
"percentage_used": 45.2,
"total_tokens": 200000,
"used_tokens": 90400
},
"session_id": "...",
"status": "...",
"timestamp": "..."
}
```

View File

@@ -64,10 +64,10 @@ pub fn read_project_readme(workspace_dir: &Path) -> Option<String> {
None
}
/// Read project memory from .g3/memory.md in the workspace directory.
/// Read project memory from analysis/memory.md in the workspace directory.
/// Returns formatted content with emoji prefix and size info, or None if not found.
pub fn read_project_memory(workspace_dir: &Path) -> Option<String> {
let memory_path = workspace_dir.join(".g3").join("memory.md");
let memory_path = workspace_dir.join("analysis").join("memory.md");
if !memory_path.exists() {
return None;

View File

@@ -99,7 +99,7 @@ Do not explain what you're going to do - just do it by calling the tools.
# Project Memory
Project memory is automatically loaded at startup alongside README.md and AGENTS.md. It contains an index of features -> code locations, patterns, and entry points. If you need to re-read memory from disk (e.g., after another agent updates it), use `read_file .g3/memory.md`.
Project memory is automatically loaded at startup alongside README.md and AGENTS.md. It contains an index of features -> code locations, patterns, and entry points. If you need to re-read memory from disk (e.g., after another agent updates it), use `read_file analysis/memory.md`.
**IMPORTANT**: After completing a task where you discovered code locations, you **MUST** call the `remember` tool to save them..
@@ -321,7 +321,7 @@ If you can complete it with 1-2 tool calls, skip TODO.
# Project Memory
Project memory (if available) is automatically loaded at startup. It contains feature locations and patterns discovered in previous sessions. If you need to re-read memory from disk (e.g., after another agent updates it), use `read_file .g3/memory.md`.
Project memory (if available) is automatically loaded at startup. It contains feature locations and patterns discovered in previous sessions. If you need to re-read memory from disk (e.g., after another agent updates it), use `read_file analysis/memory.md`.
**ALWAYS** call `remember` at the END of your turn when you discovered:
- A feature's location (file + char range + function/struct names)

View File

@@ -14,12 +14,12 @@ use crate::ToolCall;
use super::executor::ToolContext;
/// Get the path to the memory file.
/// Memory is stored at `.g3/memory.md` in the working directory.
/// Memory is stored at `analysis/memory.md` in the working directory (version controlled).
fn get_memory_path(working_dir: Option<&str>) -> PathBuf {
let base = working_dir
.map(PathBuf::from)
.unwrap_or_else(|| std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")));
base.join(".g3").join("memory.md")
base.join("analysis").join("memory.md")
}
/// Format the file size in a human-readable way.
@@ -45,7 +45,7 @@ pub async fn execute_remember<W: UiWriter>(
let memory_path = get_memory_path(ctx.working_dir);
// Ensure .g3 directory exists
// Ensure analysis directory exists
if let Some(parent) = memory_path.parent() {
std::fs::create_dir_all(parent)?;
}