Angelo — LLM Agent Guide¶
This file is for AI agents that interact with the angelo codebase. It describes the current storage model, upgrade procedure, and key conventions.
Storage Model (v1.0 — git-canonical)¶
Memory entries are stored as markdown files with YAML frontmatter inside .memory/:
.memory/
config.yaml # format version, migration metadata
project.md # root project node
entries/<id>.md # research tree entries
skills/<name>.md # procedural/pattern knowledge
sessions/<id>.md # session handoff records
active-sessions/ # live session sidecars, gitignored
documents/<id>.md # registered document references
archive/entries/ # vacuumed (archived) entries
Runtime state and derived caches live in the gitignored .angelo/ directory
(.angelo/memory.kgl, .angelo/memory.index.json, .angelo/memory.embeddings.json,
coordinator state, zettelkasten notes). The KGLite cache is disposable and
rebuilt from .memory/ files on startup. The .memory/ directory is the source
of truth. Legacy root-level cache files (pre-.angelo layout) are auto-migrated
into .angelo/ on server startup.
Live sessions are tracked separately from finalized handoffs. While an MCP
process is running, it writes .memory/active-sessions/<session-id>.json with
heartbeat/process metadata and lists of entries created, accessed, and modified.
The dashboard reads these sidecars for live session cards. A daemon heartbeat
keeps idle but healthy MCP sessions fresh; stale sidecars from crashed processes
are shown as stale and are not counted as live.
Commit Policy¶
Entry file writes are committed to git in debounced batches (5-second window) by
the memory-mcp server. These commits are authored as memory-mcp <memory@local>.
Auto-push rule: the server will only push if all unpushed commits on the current branch are authored by memory-mcp. It never pushes user WIP commits.
File-pin commits (for the files parameter in record()) still happen
synchronously and immediately, but the server first classifies the dirty working
tree as clean, memory_only, relevant, unrelated, or risky.
Use the files parameter only when you intentionally want reproducible pinned
file references. Unrelated unstaged work is tolerated and reported as a warning;
unrelated staged work blocks auto-committing dirty requested files with a
DirtyWorkingTreeError. If a pin is refused, commit or unstage the unrelated
work, or omit files and mention paths in the entry body.
After git pull¶
The server auto-syncs: before each tool call it hash-diffs .memory/ against
the last-seen index (at most once per AUTO_SYNC_INTERVAL_SECONDS, default 10s)
and rebuilds the cache when another process or a git pull changed files. Set
MEMORY_AUTO_SYNC=0 to disable.
Manual sync() is still available as a forced, un-throttled rebuild — useful
right after a pull when you don't want to wait out the check interval, or when
auto-sync is disabled.
If the dashboard shows stale or missing memory data after a pull, run sync()
first, then health() to confirm the cache, counts, and git state.
Upgrade Procedure¶
From .kgl-only to .memory/ files¶
- Update the package:
- Update each target repo (every repo where you use Angelo memory):
This copies the latest rule files (.cursor/rules/memory.mdc) and ensures
the MCP server config is current.
-
Restart Cursor (or restart the MCP server) so the new server code loads.
-
On first startup, the server auto-detects the old
.memory.kglfile and migrates it to.memory/files. Migration is verified automatically. Legacy root-level cache files are moved into.angelo/on startup, so the repo root stays clean. -
Commit the new
.memory/directory:
Verifying the migration¶
After restarting, call the health() MCP tool. Check that:
- cache_stale is false
- counts match your expected entry/skill/session counts
- format_version is "1.0"
Maintenance tools¶
Use these tools for file-backed memory maintenance:
| Tool | Purpose |
|---|---|
sync() |
Force-rebuild cache from .memory/ files (the server also auto-syncs external changes before tool calls) |
health() |
Report system health: cache freshness, counts, unpushed commits, install info |
vacuum(days_old?, dry_run?) |
Archive discarded entries older than N days and rebuild the cache |
Live session troubleshooting¶
If the Sessions dashboard does not show the current chat:
- Restart Cursor or the MCP server so the latest memory server code is running.
- Confirm
.memory/active-sessions/contains a sidecar for the live process. - Call
health()to check memory system state. - If the card is stale, the MCP process likely stopped or is old enough that it does not emit heartbeats. Restart the MCP server.
Experiment Artifacts & Cloud Reruns (per-repo)¶
Every repo that uses Angelo gets its own, fully isolated artifact setup. Nothing is shared between repos: each has its own DVC remote, manifests, and job queue.
.memory/artifacts/
manifests/<run-id>.yaml # provenance per run (code SHA, hashes, command, env)
experiments/<family>/runs/<stamp>/ # per-run output files (DVC-tracked, never overwritten)
catalogs/ # human-readable S3 catalog exports
.dvc/config # tracked: remote URL, region, profile name
.dvc/config.local # gitignored: machine-local overrides/secrets
Key facts for agents:
- Per-repo queue: the rerun job queue is derived from that repo's DVC remote
(
<remote URL>/jobs), overridable withANGELO_JOBS_URI. Repos never see each other's jobs. - Runs are a series: runs sharing an
experimentfamily id group into one dashboard card; rerun manifests carryrerun_of,executor,run_stamp, and areplicationverdict (exactwhen output hashes match the original). - Sandbox reruns:
experiment(action='rerun')checks out the original commit into a git worktree under.angelo/sandboxes/, pulls inputs by content hash, runs the manifest command, and writes a new dated run manifest.where="cloud"enqueues for a runner;where="local"executes in-process. - Runner:
angelo-runner --repo <path>polls the queue on any machine with bucket credentials and git push access (one runner process per repo). Installed with the[artifacts]extra (pip install "angelo[artifacts]"). - Backups:
artifact(action='backup', path)is the one-step pattern for "keep my local file but make it restorable anywhere" (dvc add + push + verify). - Setup in a new repo: configure the remote once via the
configure_s3_remoteMCP tool (ordvc remote add), commit.dvc/config, and everything above works.
Key Conventions¶
- One project per repo:
create_projectonly runs once. Use subproject plan nodes for separate workstreams. - Tree hierarchy: Project → Subproject (plan) → Phase (plan) → Entries.
- Entry types: plan, checkpoint, experiment, decision, note, annotation, todo.
- File pinning: pass
filesinrecord()to auto-commit and pin references to a git SHA. - Vacuum: archives discarded entries older than N days, then rebuilds the cache.
- Live sessions:
.memory/active-sessions/is ephemeral runtime state and should stay gitignored. Final session records live in.memory/sessions/.