Session memory and autonomy-mode scheduling for Claude Code, backed by the Obsidian vault you already own.
Two stdlib-only Python hooks — sentinel_startup.py (SessionStart) and sentinel_stop.py (Stop) — that connect Claude Code to your existing Obsidian vault. At session start the hooks inject today's daily note, open tasks from your project log, the last checkpoint, and current battery and CPU temperature into the agent's context. At session stop they write a checkpoint back to the vault and merge any pending learnings into your wiki.
An optional Streamlit dashboard (dashboard.py) provides a real-time view of vault metrics, token usage, a context-window progress bar, a file browser, and a D3 force-directed wikilink graph.
No external services. No background processes. No database.
Most Claude Code memory projects fall into two categories: vault-template systems that require you to adopt their folder structure, or database engines that require SQLite, a vector store, and a running worker process.
Sentinel takes a different approach. Unlike vault templates (obsidian-mind) that restructure your notes, or DB engines (claude-mem) that require SQLite and a background process, Sentinel is two stdlib-only Python hooks that read from and write to the Obsidian vault you already own — injecting today's daily note, open tasks, and last checkpoint at startup, and writing learnings back on stop. The autonomy-mode scheduler reports battery and CPU temperature at session start so a scheduled agent can decide to throttle itself based on time-of-day and power state.
Key properties:
- Works with any existing Obsidian vault via the
SENTINEL_VAULTenv variable — no vault restructuring required. - Pure filesystem access — no Obsidian process, no CLI plugin dependency.
- stdlib-only hooks: zero install for the core feature (
piponly needed for the dashboard). - Autonomy-mode schedule:
AUTO MODEduring configured days and night hours;ASSISTANT MODEotherwise. - Battery and CPU-temperature reporting on macOS (
pmset,osx-cpu-temp/sysctl) so an unattended agent has the information it needs to pace itself.
For detailed competitive context see docs/competitive-notes.md.
SessionStart (sentinel_startup.py) runs before every Claude Code session and prints a JSON block that Claude Code injects as additional context:
╔══════════════════════════════════════════╗
║ SENTINEL v2.0 — 2026-06-12 20:14 ║
╚══════════════════════════════════════════╝
MODE : AUTO MODE
INFO : Full autonomy — run projects independently, self-optimize.
BATTERY : 85%; AC attached
TEMP : 42°C
LAST : 2026-06-12T19:55:12 — session_end
── DAILY NOTE (2026-06-12) ──────────────────
## Session start 20:14
Sentinel started. Ready.
── PROJECT LOG (open tasks) ──────────────
- [ ] Ship v1.0 docs
- [ ] Deploy to FileZilla
The mode (AUTO MODE / ASSISTANT MODE) is derived from a day-of-week and hour-of-day schedule configured via env variables (see Configuration below). Battery and CPU temperature are reported from macOS system calls — the hook does not enforce any limits; the agent reads the values and decides how to proceed.
Stop (sentinel_stop.py) runs after every Claude Code session. It:
- Writes
raw/checkpoint.jsonwith the timestamp, last op, and stop reason. - Updates
ui_state.jsonat the vault root. - Merges any content in
raw/pending_learnings.mdintowiki/claude_learnings.md, then deletes the pending file.
It is a no-op when stop_reason is clear or compact.
git clone https://github.com/yourname/claude-code-sentinelVault layout expected (the paths Sentinel reads and writes):
~/ObsidianVault/ ← default, override with SENTINEL_VAULT
├── daily/
│ └── 2026-06-12.md ← created automatically if missing
├── wiki/
│ └── project_log.md ← open tasks injected at startup
├── raw/
│ ├── checkpoint.json ← written by Stop hook
│ └── pending_learnings.md ← merged into wiki on stop (optional)
└── ui_state.json ← written by Stop hook and token_tracker.py
If daily/<today>.md does not exist it is created automatically. If wiki/project_log.md does not exist the startup hook reports "No project_log.md found." and continues without error.
Register the hooks in ~/.claude/settings.json:
{
"hooks": {
"SessionStart": [{"hooks": [{"type": "command",
"command": "python3 /path/to/claude-code-sentinel/sentinel_startup.py"}]}],
"Stop": [{"hooks": [{"type": "command",
"command": "python3 /path/to/claude-code-sentinel/sentinel_stop.py"}]}]
}
}Replace /path/to/claude-code-sentinel with the absolute path where you cloned the repo.
All configuration is via environment variables. Set them in your shell profile or in the command string in settings.json.
| Variable | Default | Description |
|---|---|---|
SENTINEL_VAULT |
~/ObsidianVault |
Absolute path to your Obsidian vault root. |
SENTINEL_AUTO_DAYS |
1,2,3 |
Comma-separated weekday numbers for autonomous mode (Mon=0, Tue=1, …, Sun=6). Default: Tue–Thu. |
SENTINEL_NIGHT_START |
20 |
Hour (0–23) when the night autonomous window begins. |
SENTINEL_NIGHT_END |
8 |
Hour (0–23) when the night autonomous window ends. |
Invalid values (e.g. SENTINEL_NIGHT_START=8am) fall back to the defaults listed above and print a warning to stderr. The agent sees the warning in the Stop hook output but continues normally.
The dashboard is optional and requires Streamlit:
pip install -r requirements.txt
streamlit run dashboard.pyBy default it reads the vault at SENTINEL_VAULT (or ~/ObsidianVault). To point it at a different vault:
SENTINEL_VAULT=/path/to/vault streamlit run dashboard.pyThe dashboard shows:
- Top metrics bar: vault status, wiki file count, today's tokens, session tokens, context-window used, last op.
- Context-window progress bar: visual fill from 0–100% with color coding (green < 70%, amber < 90%, red ≥ 90%).
- System State: raw
ui_state.jsonas formatted JSON. - Token Breakdown: per-folder vault size estimates in tokens (chars / 4).
- Token History: last 8 token-tracker entries with timestamps and operation names.
- Daily Log: today's daily note as an editable text area.
- Vault Tree: folder listing (up to 4 files per subfolder).
- Memory Access: wiki file selector with per-file token estimate.
- Raw Files / Content Output: selectors for
raw/andcontent/Markdown files. - Obsidian Brain — Knowledge Map: D3 force-directed graph of vault files and
[[wikilink]]connections; drag, zoom, hover for labels.
The D3 graph loads from https://d3js.org/d3.v7.min.js and requires an internet connection.
No dependencies beyond the Python standard library:
python3 tests/test_hooks.pyFive tests cover: custom vault path for the startup hook, checkpoint creation on stop, no-op behavior on clear, graceful fallback for invalid schedule env values, and correct AUTO MODE injection with a saturated schedule.
- Battery and CPU-temperature probes are macOS-only. On other platforms the startup hook reports
Unknownfor battery andUnavailablefor CPU temperature and continues normally. - Dashboard D3 graph requires an internet connection to load
d3.v7.min.jsfrom the CDN. - The hooks assume the vault layout described above. Files in unexpected locations are silently skipped.
- The project log marker is in English. Legacy vaults with a Norwegian
Siste sesjon:marker are migrated automatically on the first Stop run.
MIT — see LICENSE.
