personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Remove journal path override kludges

Application code must never set _SOLSTONE_JOURNAL_OVERRIDE — it exists
for external callers (tests, Makefile sandboxes) only. Removed:

- cortex.py: no longer sets override when spawning agent subprocesses
- bridge.py: no longer sets override in process environment
- service.py: no longer propagates override into service install files
- heartbeat.py: prompt no longer contains filesystem paths
- heartbeat.md: removed promise about path being in prompt

Added documentation in get_journal() docstring and coding reference
that the env var must never be set from application code.

+17 -37
-8
convey/bridge.py
··· 34 34 } 35 35 36 36 37 - def _ensure_journal_env() -> None: 38 - if state.journal_root and not os.environ.get("_SOLSTONE_JOURNAL_OVERRIDE"): 39 - os.environ["_SOLSTONE_JOURNAL_OVERRIDE"] = state.journal_root 40 - 41 - 42 37 def _broadcast_to_websockets(event: dict) -> None: 43 38 """Broadcast event to all connected WebSocket clients.""" 44 39 msg = json.dumps(event) ··· 83 78 with _WATCH_LOCK: 84 79 if _CALLOSUM_CONNECTION: 85 80 return 86 - 87 - # Ensure journal override is set for child processes 88 - _ensure_journal_env() 89 81 90 82 # Create Callosum connection with callback 91 83 try:
+1 -1
muse/coding/reference/environment.md
··· 2 2 3 3 ## Journal Path 4 4 5 - The journal lives at `journal/` in the project root. `get_journal()` from `think.utils` returns the path. For tests, set `_SOLSTONE_JOURNAL_OVERRIDE` to override. Do not set this in production service files — the default project-root resolution is correct. 5 + The journal lives at `journal/` in the project root. `get_journal()` from `think.utils` returns the path — trust it unconditionally. Never set `_SOLSTONE_JOURNAL_OVERRIDE` from application code, service files, agent prompts, or subprocess environments. The env var exists exclusively for external use: test harnesses (`monkeypatch.setenv`) and Makefile sandboxes. If you think you need to override the journal path, you don't — fix the actual problem instead. 6 6 7 7 ## Service Installation 8 8
-3
muse/heartbeat.md
··· 18 18 This is not a conversation. Do not generate owner-facing output. Read, 19 19 check, maintain, close. 20 20 21 - **Important:** The journal path is provided in the prompt below. Use `sol call` 22 - commands for all journal access — never search the filesystem or guess paths. 23 - 24 21 ## Step 1: Check system health 25 22 26 23 Run `sol health` and check recent health logs with `sol health logs --since 1h`.
+3 -3
tests/test_heartbeat.py
··· 171 171 assert "outcome=success" in content 172 172 173 173 174 - def test_cortex_prompt_includes_journal_path(journal_path, heartbeat_mocks): 175 - """cortex_request receives a prompt containing the journal path.""" 174 + def test_cortex_prompt_does_not_contain_journal_path(journal_path, heartbeat_mocks): 175 + """cortex_request prompt must not leak filesystem paths.""" 176 176 import think.heartbeat as mod 177 177 178 178 captured_kwargs = {} ··· 189 189 mod.main() 190 190 191 191 prompt = captured_kwargs.get("prompt", "") 192 - assert str(journal_path) in prompt, "prompt should contain the journal path" 192 + assert str(journal_path) not in prompt, "prompt must not leak filesystem paths" 193 193 194 194 195 195 def test_recency_check_skips_recent_heartbeat(journal_path, heartbeat_mocks):
+2 -2
tests/test_service.py
··· 101 101 venv_bin = str(Path(sys.executable).parent) 102 102 assert env["PATH"].startswith(venv_bin) 103 103 104 - def test_journal_path_is_absolute(self, monkeypatch, tmp_path): 104 + def test_journal_override_not_propagated(self, monkeypatch, tmp_path): 105 105 monkeypatch.setenv("_SOLSTONE_JOURNAL_OVERRIDE", str(tmp_path)) 106 106 107 107 env = service._collect_env() 108 - assert Path(env["_SOLSTONE_JOURNAL_OVERRIDE"]).is_absolute() 108 + assert "_SOLSTONE_JOURNAL_OVERRIDE" not in env 109 109 110 110 111 111 class TestStatus:
-1
think/cortex.py
··· 276 276 env_overrides = config.get("env") 277 277 if env_overrides and isinstance(env_overrides, dict): 278 278 env.update({k: str(v) for k, v in env_overrides.items()}) 279 - env["_SOLSTONE_JOURNAL_OVERRIDE"] = str(self.journal_path) 280 279 281 280 # Spawn the subprocess 282 281 self.logger.info(f"Spawning {process_type} {agent_id}: {cmd}")
+1 -8
think/heartbeat.py
··· 103 103 pid_file.write_text(str(os.getpid())) 104 104 start_time = time.monotonic() 105 105 106 - # Spawn heartbeat agent with explicit journal path so the cogitate 107 - # agent never needs to discover it via filesystem search. 108 106 agent_id = cortex_request( 109 - prompt=( 110 - f"Run heartbeat check.\n\n" 111 - f"CRITICAL: The journal is at {journal}. " 112 - f"Use `sol call` commands for all journal access. " 113 - f"Do NOT search the filesystem or guess paths." 114 - ), 107 + prompt="Run heartbeat check.", 115 108 name="heartbeat", 116 109 ) 117 110 if agent_id is None:
+5 -10
think/service.py
··· 60 60 def _collect_env() -> dict[str, str]: 61 61 """Collect environment variables for the service file. 62 62 63 - Only captures HOME, PATH (with venv bin), and the journal override. 64 - API keys are NOT written into service files — the supervisor reads 65 - them from journal.json at process startup via setup_cli(). 63 + Only captures HOME and PATH (with venv bin). API keys are NOT written 64 + into service files — the supervisor reads them from journal.json at 65 + process startup via setup_cli(). Never propagate _SOLSTONE_JOURNAL_OVERRIDE 66 + into service files — installed services should use default path resolution. 66 67 """ 67 68 venv_bin = str(Path(sys.executable).parent) 68 69 69 - env = { 70 + return { 70 71 "HOME": str(Path.home()), 71 72 "PATH": f"{venv_bin}:/usr/local/bin:/usr/bin:/bin", 72 73 } 73 - 74 - override = os.environ.get("_SOLSTONE_JOURNAL_OVERRIDE") 75 - if override: 76 - env["_SOLSTONE_JOURNAL_OVERRIDE"] = override 77 - 78 - return env 79 74 80 75 81 76 def _generate_plist(env: dict[str, str], port: int = DEFAULT_SERVICE_PORT) -> bytes:
+5 -1
think/utils.py
··· 100 100 101 101 The journal always lives at ./journal/ relative to the solstone 102 102 project root. Auto-creates the directory if it doesn't exist. 103 + 104 + Trust this function — never bypass it, cache its result, or set 105 + _SOLSTONE_JOURNAL_OVERRIDE from application code. The env var 106 + exists for external use only (tests, Makefile sandboxes). See 107 + ``muse/coding/reference/environment.md``. 103 108 """ 104 - # Internal override for tests 105 109 override = os.environ.get("_SOLSTONE_JOURNAL_OVERRIDE") 106 110 if override: 107 111 os.makedirs(override, exist_ok=True)