Repo Memory
Repo memory provides persistent file storage via Git branches with unlimited retention. The compiler auto-configures branch cloning/creation, file access at /tmp/gh-aw/repo-memory-{id}/, commits/pushes, and merge conflict resolution (your changes win).
Enabling Repo Memory
Section titled “Enabling Repo Memory”---tools: repo-memory: true---Creates branch memory/default at /tmp/gh-aw/repo-memory-default/. Files are stored within the branch at the branch name path (memory/default/). Files auto-commit/push after workflow completion.
Advanced Configuration
Section titled “Advanced Configuration”---tools: repo-memory: branch-name: memory/custom-agent-for-aw branch-prefix: tracking # Custom prefix instead of "memory" description: "Long-term insights" file-glob: ["*.md", "*.json"] max-file-size: 1048576 # 1MB (default 100KB) max-file-count: 50 # default 100 max-patch-size: 1048576 # 1MB max (default 10KB) target-repo: "owner/repository" create-orphan: true # default allowed-extensions: [".json", ".txt", ".md"] # Restrict file types (default: empty/all files allowed) format-json: true # Pretty-print .json files (default: false) validation: timeout-minutes: 1 script: | const data = JSON.parse(fs.readFileSync(path.join(memoryRoot, "state.json"), "utf8")); if (!Array.isArray(data.items)) throw new Error("state.json must contain an items array");---branch-prefix changes the default memory prefix and must be 4-32 alphanumeric, hyphen, or underscore characters; it cannot be copilot. allowed-extensions limits which file types can be stored, format-json: true pretty-prints .json files before commit, validation.script runs a custom JavaScript domain validator before persistence, and max-patch-size caps the total diff size for one push (default 10KB, max 1MB) to prevent oversized updates.
Structured Ledger
Section titled “Structured Ledger”Ledgers use tools.ledger, independently of repo-memory file storage. The legacy
tools.repo-memory.ledger declaration is no longer supported. For built-in
state models, declare log, set, map, table, counter, or notes:
---tools: ledger: findings: type: table key: id schema: type: object required: [id, status] properties: id: { type: string } status: { type: string }---Each ledger persists immutable records on its own ledgers/<name> Git branch.
Trusted preparation reconstructs a disposable, read-only SQLite database at
/tmp/gh-aw/ledgers/<name>/ledger.db. Query state for the built-in current
state and records for immutable history. Schemas validate operation values,
not operation envelopes; table requires a string primary-key field.
Configure bounded storage limits and maintenance cadence per ledger:
tools: ledger: findings: type: log schema: .github/schemas/ledger.schema.json max-segment-kb: 100 # default 100 KiB max-record-kb: 32 # default 32 KiB max-patch-kb: 10 # default 10 KiB compaction: schedule: weekly min-segments: 32 max-segments: 128Agents submit mutations only through the configured ledger safe-output tools.
Map ledgers expose ledger_map_put and ledger_map_delete; notes expose
ledger_note_add and ledger_note_vote. Other built-in types use typed
ledger_append operations. Writes are deferred: the immediate
response confirms queuing, not durability. The trusted push_ledger_changes
job validates and reconciles accepted requests against the latest branch state
before pushing. Queued writes are not immediately visible in the run’s projection.
Ledger compaction never runs in the agent or persistence job. Standalone tools.ledger ledgers are compacted by Agentic Maintenance through an untrusted plan job and a trusted apply job; see Ledger compaction.
Custom replay.script, replay.config, and compaction.script settings are
rejected. Use schemas for domain-specific values and the built-in compaction
policy for segment selection. Ordinary repo-memory validation.script
remains supported; it is a separate file-storage validator.
Existing raw-record ledgers can retain their generic projection by omitting
type and querying records.payload with SQLite JSON functions. Adding a
built-in type does not convert historical raw payloads into operations.
See Ledger replay projections for type
semantics and migration guidance.
File Glob Matching Rules:
- Patterns are matched against the relative path within the artifact directory — do not include the branch name.
- Slashless patterns (no
/in the pattern, e.g.*.json,*.md) are matched against the full relative path, so a single*only matches files at the artifact root (depth 0). They do not match files inside subfolders (depth 1+) — use a pattern containing/(e.g.**/*.json) for that. - Patterns containing
/(e.g.metrics/**,data/*.csv) are matched against the full relative path from the artifact root and work as standard glob expressions. - Absolute paths (patterns starting with
/) are not supported and are rejected at compile time and runtime.
Example: with the default filter ["*.json", "*.md"], the root-level file processed-discussions.json is persisted (depth 0 ✓), but discussion-task-miner/processed-discussions.json (depth 1) is not — use ["**/*.json", "**/*.md"] to also match files nested in subfolders.
Multiple Configurations
Section titled “Multiple Configurations”---tools: repo-memory: - id: insights branch-prefix: daily # Creates daily/insights branch file-glob: ["*.md"] - id: state file-glob: ["*.json"] max-file-size: 524288 # 512KB---Mounts at /tmp/gh-aw/repo-memory-{id}/ during workflow execution. The required id determines the folder name, and branch-name defaults to {branch-prefix}/{id} with memory as the default prefix. Files are stored inside the branch under that branch-name path. File globs always match the relative path within the artifact directory, so never include the branch name; slashless patterns such as *.json match only files at the artifact root (depth 0).
Behavior
Section titled “Behavior”Branches auto-create as orphans by default, or clone with --depth 1. After validating file-glob, max-file-size, and max-file-count, gh-aw auto-commits and pushes when changes are present and threat detection passes.
Custom validation
Section titled “Custom validation”Use validation.script when generic storage limits are not enough. The script is a JavaScript body executed with Node.js over the complete configured memory directory after format-json normalization and before artifact upload or branch commit. It runs in the agent job and is re-run in the repo-memory push job as defense in depth.
Available globals are Node.js fs and path, plus memoryRoot/memoryDir, memoryId, and memoryKind ("repo"). The working directory is the memory root. Environment variables available to the validator are intentionally limited to basic runner paths plus GH_AW_MEMORY_ROOT, GH_AW_MEMORY_DIR, GH_AW_MEMORY_ID, and GH_AW_MEMORY_KIND; GitHub tokens and write credentials are not passed to the validator subprocess. Network access follows the workflow runner’s normal network policy. The default timeout is 1 minute and may be set with validation.timeout-minutes (1-5 minutes).
Throw an exception, return false, time out, exit nonzero, or modify a memory file to reject persistence. Validator stdout and stderr are reported separately from built-in storage validation output so agents can distinguish domain-schema validation from size/count checks.
Commits use the GitHub GraphQL createCommitOnBranch mutation, so they are automatically Verified with GitHub’s GPG key and satisfy rulesets that require signed commits.
Comparison with Cache Memory
Section titled “Comparison with Cache Memory”| Feature | Cache Memory | Repo Memory |
|---|---|---|
| Storage | GitHub Actions Cache | Git Branches |
| Retention | 7 days | Unlimited |
| Size Limit | 10GB/repo | Repository limits |
| Version Control | No | Yes |
| Performance | Fast | Slower |
| Best For | Temporary/sessions | Long-term/history |
For fast 7-day caching without version control, see Cache Memory.
Troubleshooting
Section titled “Troubleshooting”- Branch not created: Ensure
create-orphan: trueis enabled, or create the branch manually. - Validation or patch-size failures: Keep changes within
file-glob,max-file-size(100KB default),max-file-count(100 default), andmax-patch-size(10KB default). - Changes not persisting: Confirm the directory path, let the workflow finish, and check the logs for push errors.
- Merge conflicts: Concurrent pushes are replayed onto the latest remote state, so your file changes win.
.jsonlfiles are merged withmerge=union, so rows written by concurrent runs are all kept; other file types keep the local version. - Many runs finishing at once: Pushes are not serialized. Each run commits with a compare-and-swap on the remote branch head and, if another run wins the race, re-reads the head, rebases its change with JSONL union merging, and retries with exponential backoff. To avoid conflicts entirely, have each run write its own file instead of all runs editing the same file, for example
runs/${{ matrix.worker }}.jsonlortargets/${{ matrix.target }}.jsonl. - GH013 — Commits must have verified signatures: This usually means the artifact included a symlink, executable file, or submodule entry, which forced a fallback to plain
git push. Remove the unsupported file type and re-run.
Security
Section titled “Security”Do not store sensitive data in repo memory. It follows repository permissions, so use private repositories when appropriate, avoid secrets, set constraints such as file-glob, max-file-size, max-file-count, and max-patch-size, consider branch protection, and use target-repo when you want isolation.
Examples
Section titled “Examples”See Deep Report and Daily Firewall Report for long-term insights and historical data tracking.
Learn More
Section titled “Learn More”See Cache Memory for 7-day cache storage, Frontmatter for full configuration details, and Safe Outputs for output automation.