ge.memory

GitHub-backed durable memory for autonomous agent execution.

Three stores exposed as collections.abc facades. GitHub is the single source of truth; a thin per-store local snapshot under .ge/cache/ is a hydrate-only cache (disposable, never authoritative).

  • RoadmapStore — MutableMapping[task_id, TaskRecord] over a roadmap issue whose body holds a markdown task list between <!-- ge:roadmap:begin --> / <!-- ge:roadmap:end --> markers.

  • DecisionLog — append-only Iterable[Decision] backed by decision-tagged comments on an issue or PR.

  • TriageBacklog — MutableMapping[issue_ref, TriageVerdict] spanning multiple repos. Backed by a tracking issue containing a fenced JSON block (<!-- ge:triage:begin --> / end). Cross-repo refs use "owner/repo#N".

The github_memory() factory bundles these into a mall.

Design notes

  • Writes go to GitHub first; the local cache is updated as a side-effect on successful round-trip. A failed write does not poison the cache.

  • check_requirements verifies gh is installed, authenticated, and carries the project scope (needed if the user later switches the triage backend to a GitHub Project).

Functions

github_memory(repo, *[, roadmap_issue, ...])

Bundle the three stores into a "mall" dict keyed by name.

check_requirements(*[, require_project_scope])

Verify external prerequisites for the memory layer.

Classes

TaskState(*values)

Roadmap task lifecycle state.

TaskRecord(id, title[, state, metadata])

A single roadmap task.

TriageVerdict(*values)

Triage classification for an issue.

TriageEntry(ref, verdict[, order, ...])

A cross-repo triage backlog entry.

Decision(summary[, rationale, metadata, ...])

A logged decision (rendered as a tagged comment on an issue/PR).

RoadmapStore(repo, issue_number, *[, cache_dir])

A MutableMapping[task_id, TaskRecord] over a roadmap issue.

DecisionLog(repo, target_number, *[, cache_dir])

Append-only iterable of Decision records.

TriageBacklog(repo, tracking_issue, *[, ...])

Cross-repo triage backlog.

class ge.memory.Decision(summary, rationale='', metadata=<factory>, created_at=None, url=None)[source]

Bases: object

A logged decision (rendered as a tagged comment on an issue/PR).

class ge.memory.DecisionLog(repo, target_number, *, cache_dir=None)[source]

Bases: Iterable

Append-only iterable of Decision records.

Backed by issue/PR comments tagged with <!-- ge:decision --> on a single target (issue or PR). Iteration fetches all comments from GitHub, filters by tag, and yields parsed decisions in chronological order.

Significant choices and course-corrections should be appended here so they survive into future sessions. Micro-decisions belong in local scratch and should be summarised at handover.

append(summary, *, rationale='', metadata=None)[source]

Post a tagged comment recording this decision.

Returns the Decision (with url and created_at populated from the GitHub response on success).

Return type:

Decision

class ge.memory.RoadmapStore(repo, issue_number, *, cache_dir=None)[source]

Bases: MutableMapping

A MutableMapping[task_id, TaskRecord] over a roadmap issue.

Iteration yields task ids in roadmap order. Mutations rewrite the roadmap issue body in place; the local cache is updated on success.

Initialise via github_memory() or directly with (repo, issue). The roadmap issue body should contain (or will be augmented with) a block:

<!-- ge:roadmap:begin -->
- [ ] Task one
- [x] Task two
<!-- ge:roadmap:end -->

Tasks outside the block are ignored.

append(title, *, state=TaskState.todo)[source]

Add a new task to the end of the roadmap.

Return type:

TaskRecord

hydrate()[source]

Refresh the local cache from GitHub and return the current task list.

Return type:

list[TaskRecord]

next_todo()[source]

Return the first todo task in roadmap order, or None.

Return type:

Optional[TaskRecord]

class ge.memory.TaskRecord(id, title, state=TaskState.todo, metadata=<factory>)[source]

Bases: object

A single roadmap task.

id is a stable slug derived from the title. metadata holds any extra agent-attached fields (e.g. links to PRs).

class ge.memory.TaskState(*values)[source]

Bases: str, Enum

Roadmap task lifecycle state.

class ge.memory.TriageBacklog(repo, tracking_issue, *, cache_dir=None)[source]

Bases: MutableMapping

Cross-repo triage backlog.

Keys are issue refs of the form "owner/repo#N"; values are TriageEntry. Iteration order is the agent-chosen resolution order (the order field).

Backed by a tracking issue whose body holds a JSON block between <!-- ge:triage:begin --> / end. This keeps the implementation free of GraphQL/Project dependencies while preserving full cross-repo semantics — fully-qualified refs do the heavy lifting.

Switching to a GitHub Project backend later is a swap of this class’s I/O methods; the public interface stays the same.

class ge.memory.TriageEntry(ref, verdict, order=0, rationale='', metadata=<factory>)[source]

Bases: object

A cross-repo triage backlog entry.

class ge.memory.TriageVerdict(*values)[source]

Bases: str, Enum

Triage classification for an issue.

ge.memory.check_requirements(*, require_project_scope=False)[source]

Verify external prerequisites for the memory layer.

Returns a dict {"ok": bool, "gh": ..., "auth": ..., "scopes": [...], "missing": [...]}. Raises EnvironmentError with actionable install instructions if a hard requirement is missing.

Set require_project_scope=True if you plan to swap the triage backend to a GitHub Project.

Return type:

dict

ge.memory.github_memory(repo, *, roadmap_issue=None, decisions_target=None, triage_issue=None, cache_dir=None)[source]

Bundle the three stores into a “mall” dict keyed by name.

Each store is only constructed if its target was provided. roadmap requires roadmap_issue; decisions requires decisions_target (the issue or PR number where decisions are logged); triage requires triage_issue (the tracking issue holding the JSON block).

Return type:

dict[str, object]

>>> # mall = github_memory('owner/repo', roadmap_issue=1, decisions_target=1)