How cache-memory Persists Data Across Workflow Runs Using Artifacts in gh-aw
The cache-memory tool in gh-aw persists data across workflow runs by restoring files from GitHub Actions cache at job start, capturing changes as workflow artifacts after the agent finishes, and optionally saving those artifacts back to the cache via a dedicated update job when threat detection is enabled.
The cache-memory tool is a built-in feature of gh-aw (GitHub Agentic Workflows) that provides LLM-driven agents with a persistent file-based knowledge store at /tmp/gh-aw/cache-memory. Understanding how cache-memory persists data across workflow runs using artifacts is essential for building stateful agent workflows that retain context between executions without relying on external databases.
What is cache-memory?
cache-memory is a built-in tool that gives agents a simple file share they can read and write anywhere during a workflow run. The tool creates a directory at /tmp/gh-aw/cache-memory (or /tmp/gh-aw/cache-memory-<id> for custom cache IDs) that acts as shared memory accessible throughout the job. Unlike ephemeral runner storage, this directory's contents survive across workflow runs through a hybrid persistence mechanism combining GitHub Actions cache and workflow artifacts.
The Persistence Architecture: Cache and Artifacts
The persistence mechanism relies on a four-step pipeline that bridges ephemeral runner storage with GitHub's persistent cache and artifact systems. This design works entirely with native GitHub Actions features, requiring no external services.
Step 1: Restoring from GitHub Actions Cache
At the start of each job, the generateCacheMemorySteps function in pkg/workflow/cache.go emits a step using actions/cache/restore@v4. The cache key follows the pattern memory-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }}, with restore keys that omit the run ID to fetch the most recent previous cache. When scope: repo is configured, the code adds a broader restore key that omits the workflow ID entirely, enabling sharing across workflows in the repository.
Step 2: Agent File Operations
During workflow execution, agents read from and write to /tmp/gh-aw/cache-memory. This directory serves as a writable file share that persists throughout the job lifecycle. Agents can store notes, logs, or intermediate state that must survive individual steps within the same run.
Step 3: Artifact Upload
After the agent finishes, the generateCacheMemoryArtifactUpload function injects an actions/upload-artifact@v4 step that runs unconditionally (if: always()). This captures the current state of the cache directory as a workflow artifact, ensuring data survives job completion even if subsequent steps fail. The artifact acts as a bridge between the ephemeral runner and the next workflow run.
Step 4: Cache Update via Dedicated Job
When threat detection is enabled, the compiler adds a special update_cache_memory job via buildUpdateCacheMemoryJob in pkg/workflow/cache.go. This job downloads the artifact, validates file extensions using the Node.js script validate_memory_files.cjs, and executes actions/cache/save@v4 to write the new content back to the Actions cache. This job only runs when the detection step succeeds (needs.detection.outputs.success == 'true'), ensuring that validated agent outputs persist for subsequent runs.
Configuration and Front-Matter Schema
The front-matter configuration is defined by the CacheMemoryToolConfig struct in pkg/workflow/tools_types.go (lines 76-86). Users declare cache-memory requirements in YAML front-matter within their workflow markdown files, which the extractCacheMemoryConfig function processes in pkg/workflow/cache.go.
Minimal configuration with default cache:
---
engine: copilot
tools:
cache-memory: true
---
Multiple named caches with custom retention and scope:
---
engine: copilot
tools:
cache-memory:
- id: notes
description: "Agent notes for the current investigation"
retention-days: 30
scope: repo
- id: logs
description: "Debug logs"
retention-days: 7
---
The scope: repo option enables sharing across workflows but is forbidden in strict mode as enforced by pkg/workflow/strict_mode_validation.go (lines 181-190).
Key Implementation Files
-
pkg/workflow/cache.go— ContainsgenerateCacheMemorySteps,generateCacheMemoryArtifactUpload,buildUpdateCacheMemoryJob, andextractCacheMemoryConfigfunctions that orchestrate the persistence pipeline. -
pkg/workflow/tools_types.go— Defines theCacheMemoryToolConfigstruct that specifies the front-matter schema for cache configuration. -
pkg/workflow/strict_mode_validation.go— Enforces security constraints, specifically forbiddingscope: repowhen strict mode is enabled. -
pkg/workflow/mcp_renderer.go— Filters cache-memory from MCP tool calls, ensuring the tool is handled internally rather than sent to external MCP servers. -
actions/setup/js/create_cache_memory_dir.cjs— Runtime helper script that creates the cache directory structure on the runner.
Summary
- cache-memory provides agents with a persistent file share at
/tmp/gh-aw/cache-memoryduring workflow execution. - Persistence across runs uses a hybrid approach: GitHub Actions cache for initial restoration and workflow artifacts for capturing changes.
- The
generateCacheMemoryStepsfunction orchestrates cache restoration, whilegenerateCacheMemoryArtifactUploadensures artifacts are captured unconditionally. - When threat detection is enabled, the
buildUpdateCacheMemoryJobfunction creates a dedicated job that downloads artifacts and saves them back to the cache usingactions/cache/save@v4. - Configuration occurs via YAML front-matter processed by
extractCacheMemoryConfiginpkg/workflow/cache.go, with schema defined inpkg/workflow/tools_types.go.
Frequently Asked Questions
What is the default cache key format used by cache-memory?
The default cache key follows the pattern memory-${{ env.GH_AW_WORKFLOW_ID_SANITIZED }}-${{ github.run_id }}. The key always includes the workflow ID and run ID to ensure uniqueness, while restore keys omit the run ID to fetch the most recent previous cache. When using scope: repo, the system adds a broader restore key that omits the workflow ID entirely.
Can cache-memory be used without threat detection enabled?
Yes, cache-memory functions without threat detection. When threat detection is disabled, the system relies on the automatic post-action behavior of actions/cache to save the restored cache. However, enabling threat detection adds the explicit update_cache_memory job that provides more reliable persistence by uploading artifacts and explicitly saving them back to the cache after validation.
How does the scope parameter affect cache sharing?
The scope parameter controls cache isolation. The default value workflow isolates the cache to the specific workflow file, preventing data sharing across different workflows. Setting scope: repo allows the cache to be shared across all workflows in the repository by adding a broader restore key that omits the workflow ID. Note that scope: repo is forbidden when strict mode is enabled for security reasons.
What file extensions are allowed in cache-memory?
The system validates file extensions using a Node.js script named validate_memory_files.cjs located in the runtime actions directory. This validation runs during the cache update job to ensure that only approved file types are persisted back to the Actions cache, preventing the storage of potentially dangerous executable files or other restricted content.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →