Module: Brainiac::Plugins::Basecamp::EpicMemory
- Defined in:
- lib/brainiac/plugins/basecamp/epic_memory.rb
Overview
Epic-level shared memory.
Unlike per-card memory (agent-specific, gitignored), epic memory is shared across all agents working the epic AND persisted to git. It accumulates architectural decisions, patterns established, gotchas discovered, and cross-task learnings.
The epic review agent writes to this file after each task completes. All task agents and gate agents read it as part of their context.
Location: ~/.brainiac/brain/knowledge/epics/epic-
This is under knowledge/ (not memory/) because:
- memory/ is gitignored — per-card, per-agent, ephemeral
- knowledge/ is synced to git — shared, permanent, valuable
- Epic learnings should persist and be searchable via qmd
Constant Summary collapse
- BRAINIAC_DIR =
ENV.fetch("BRAINIAC_DIR", File.join(Dir.home, ".brainiac"))
- EPIC_MEMORY_DIR =
File.join(BRAINIAC_DIR, "brain", "knowledge", "epics")
Class Method Summary collapse
-
.append_section(todolist_id, section:, content:) ⇒ Object
Append a section to the epic memory.
-
.build_context(todolist_id) ⇒ String?
Build context injection for an agent prompt.
-
.cleanup(todolist_id, archive: true) ⇒ Object
Clean up epic memory after epic completes.
-
.ensure_directory! ⇒ Object
Ensure the epic memory directory exists.
-
.ensure_exists_for(epic) ⇒ Object
Ensure epic memory exists for an epic (creates if missing).
-
.exists?(todolist_id) ⇒ Boolean
Check if epic memory exists.
-
.initialize_for(epic) ⇒ Object
Initialize epic memory with the epic title and initial context.
-
.path_for(todolist_id) ⇒ String
Path to the epic memory file for a given epic.
-
.read(todolist_id) ⇒ String?
Read the epic memory content, if it exists.
Class Method Details
.append_section(todolist_id, section:, content:) ⇒ Object
Append a section to the epic memory. Used by the epic review agent after each task completes.
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/brainiac/plugins/basecamp/epic_memory.rb', line 121 def append_section(todolist_id, section:, content:) ensure_directory! path = path_for(todolist_id) existing = File.exist?(path) ? File.read(path) : "" = Time.now.strftime("%Y-%m-%d %H:%M") new_section = <<~MARKDOWN --- ## #{section} _Updated: #{}_ #{content.strip} MARKDOWN File.write(path, existing + new_section) LOG.info "[Basecamp:EpicMemory] Appended section '#{section}' to epic #{todolist_id}" if defined?(LOG) rescue StandardError => e LOG.error "[Basecamp:EpicMemory] Failed to append: #{e.}" if defined?(LOG) end |
.build_context(todolist_id) ⇒ String?
Build context injection for an agent prompt. Returns a formatted string with the epic memory, or nil if none exists.
149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/brainiac/plugins/basecamp/epic_memory.rb', line 149 def build_context(todolist_id) content = read(todolist_id) return nil unless content <<~CONTEXT ## Epic Memory (Shared Knowledge) The following is shared knowledge accumulated across this epic. Reference this when making implementation decisions. #{content} CONTEXT end |
.cleanup(todolist_id, archive: true) ⇒ Object
Clean up epic memory after epic completes. Optionally archives to a different location rather than deleting.
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/brainiac/plugins/basecamp/epic_memory.rb', line 168 def cleanup(todolist_id, archive: true) path = path_for(todolist_id) return unless File.exist?(path) if archive archive_dir = File.join(EPIC_MEMORY_DIR, "archived") FileUtils.mkdir_p(archive_dir) archive_path = File.join(archive_dir, "epic-#{todolist_id}-#{Time.now.strftime('%Y%m%d')}.md") FileUtils.mv(path, archive_path) LOG.info "[Basecamp:EpicMemory] Archived epic memory to #{archive_path}" if defined?(LOG) else FileUtils.rm(path) LOG.info "[Basecamp:EpicMemory] Deleted epic memory for #{todolist_id}" if defined?(LOG) end rescue StandardError => e LOG.warn "[Basecamp:EpicMemory] Cleanup failed: #{e.}" if defined?(LOG) end |
.ensure_directory! ⇒ Object
Ensure the epic memory directory exists.
36 37 38 |
# File 'lib/brainiac/plugins/basecamp/epic_memory.rb', line 36 def ensure_directory! FileUtils.mkdir_p(EPIC_MEMORY_DIR) unless File.directory?(EPIC_MEMORY_DIR) end |
.ensure_exists_for(epic) ⇒ Object
Ensure epic memory exists for an epic (creates if missing). Called on resume for epics that started before the feature existed.
67 68 69 70 71 |
# File 'lib/brainiac/plugins/basecamp/epic_memory.rb', line 67 def ensure_exists_for(epic) return if exists?(epic["basecamp_todolist_id"]) initialize_for(epic) end |
.exists?(todolist_id) ⇒ Boolean
Check if epic memory exists.
59 60 61 |
# File 'lib/brainiac/plugins/basecamp/epic_memory.rb', line 59 def exists?(todolist_id) File.exist?(path_for(todolist_id)) end |
.initialize_for(epic) ⇒ Object
Initialize epic memory with the epic title and initial context. Called when an epic starts.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/brainiac/plugins/basecamp/epic_memory.rb', line 77 def initialize_for(epic) ensure_directory! path = path_for(epic["basecamp_todolist_id"]) # Don't overwrite existing memory (in case of resume) return if File.exist?(path) && !File.read(path).strip.empty? initial_content = <<~MARKDOWN # Epic Memory: #{epic['title']} Epic started: #{epic['started_at']} Orchestrating agent: #{epic['agent']} --- ## Architectural Decisions (No decisions recorded yet) ## Patterns Established (No patterns recorded yet) ## Gotchas & Learnings (No learnings recorded yet) ## Cross-Task Notes (No notes recorded yet) MARKDOWN File.write(path, initial_content) LOG.info "[Basecamp:EpicMemory] Initialized memory for epic #{epic['id']}" if defined?(LOG) rescue StandardError => e LOG.error "[Basecamp:EpicMemory] Failed to initialize: #{e.}" if defined?(LOG) end |
.path_for(todolist_id) ⇒ String
Path to the epic memory file for a given epic.
31 32 33 |
# File 'lib/brainiac/plugins/basecamp/epic_memory.rb', line 31 def path_for(todolist_id) File.join(EPIC_MEMORY_DIR, "epic-#{todolist_id}.md") end |
.read(todolist_id) ⇒ String?
Read the epic memory content, if it exists.
44 45 46 47 48 49 50 51 52 53 |
# File 'lib/brainiac/plugins/basecamp/epic_memory.rb', line 44 def read(todolist_id) path = path_for(todolist_id) return nil unless File.exist?(path) content = File.read(path).strip content.empty? ? nil : content rescue StandardError => e LOG.warn "[Basecamp:EpicMemory] Failed to read epic memory: #{e.}" if defined?(LOG) nil end |