> ## Documentation Index
> Fetch the complete documentation index at: https://code.storage/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Load Agent Memory

> Load selected memory files into a sandbox from one exact version, then save changes without losing another update or exposing a private key.

Code Storage enables agent memory with exact reads, safe concurrent changes, and a history that can
be inspected and reverted.

## Choose the repository and exact version

Use a separate memory repository when the information needs its own access rules, storage lifetime,
or delete boundary. You can use one repository per project, user, tenant, or company.

Before the agent reads memory, read the current commit SHA of the branch and store it with the agent
session. This SHA is the pinned revision. It always identifies the same files, so the agent reads
one exact version.

<CodeGroup>
  ```typescript TypeScript theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  const history = await memoryRepo.listCommits({ branch: 'main', limit: 1 });
  const pinnedRevision = history.commits[0].sha;
  ```

  ```python Python theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  history = await memory_repo.list_commits(branch="main", limit=1)
  pinned_revision = history["commits"][0]["sha"]
  ```

  ```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  history, err := memoryRepo.ListCommits(ctx, storage.ListCommitsOptions{
  	Branch: "main",
  	Limit:  1,
  })
  if err != nil {
  	return err
  }
  pinnedRevision := history.Commits[0].SHA
  ```
</CodeGroup>

Use `createTag()` when a person needs a readable name for the version.

## Load only the required files

Give the sandbox a temporary API token for only the memory repository. Keep the organization private
key in trusted product code. See [Authentication & Security](/docs/getting-started/authentication) for
token details.

Use `getArchiveStream` with file patterns to fetch a group of memory files without a `git clone`.
Use `getFileStream` for one file. The sandbox needs no local Git index and no `git push`.

<CodeGroup>
  ```typescript TypeScript theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  const archive = await memoryRepo.getArchiveStream({
    ref: pinnedRevision,
    includeGlobs: ['notes/**'],
  });

  // Send archive.body to the sandbox and extract the compressed response.
  ```

  ```python Python theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  archive = await memory_repo.get_archive_stream(
      ref=pinned_revision,
      include_globs=["notes/**"],
  )

  # Send the response body to the sandbox and extract the compressed response.
  ```

  ```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  archive, err := memoryRepo.ArchiveStream(ctx, storage.ArchiveOptions{
  	Ref:          pinnedRevision,
  	IncludeGlobs: []string{"notes/**"},
  })
  if err != nil {
  	return err
  }
  defer archive.Body.Close()

  // Send archive.Body to the sandbox and extract the compressed response.
  ```
</CodeGroup>

The path above is only an example. Your product chooses the paths and file format.

Use subpaths within one memory repository when every group shares the same access rules, storage
lifetime, and delete boundary. For example, a product can use one subpath for each project. A ref
policy limits Git branches and tags, not file paths, so enforce subpath access in your product.

If the product needs ordinary Git tools, it can create temporary Git URLs instead. See
[Connect a Sandbox](/docs/guides/sandboxes) and [Ref Policies](/docs/guides/ref-policies).

## Save the agent's changes

Set `expectedHeadSha` to the commit SHA that was current before the agent made its change. Code
Storage accepts the save only if the target branch still points to that commit.

<CodeGroup>
  ```typescript TypeScript theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  import { RefUpdateError } from '@pierre/storage';

  try {
    const result = await memoryRepo
      .createCommit({
        author: { email: 'agent@example.com', name: 'Agent' },
        commitMessage: 'Update API conventions',
        expectedHeadSha: pinnedRevision,
        targetBranch: 'main',
      })
      .addFileFromString('notes/api-conventions.md', updatedRecord)
      .send();

    await memoryHeads.set(memoryRepo.id, result.commitSha);
    return { status: 'saved', commitSha: result.commitSha };
  } catch (error) {
    if (error instanceof RefUpdateError) {
      if (error.reason === 'conflict') {
        return { status: 'conflict' };
      }
      if (error.reason === 'precondition_failed') {
        return { status: 'no_changes', commitSha: pinnedRevision };
      }
    }

    throw error;
  }
  ```

  ```python Python theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  from pierre_storage import RefUpdateError

  try:
      result = await (
          memory_repo.create_commit(
              author={"email": "agent@example.com", "name": "Agent"},
              commit_message="Update API conventions",
              expected_head_sha=pinned_revision,
              target_branch="main",
          )
          .add_file_from_string("notes/api-conventions.md", updated_record)
          .send()
      )

      await memory_heads.set(memory_repo.id, result["commit_sha"])
      return {"status": "saved", "commit_sha": result["commit_sha"]}
  except RefUpdateError as error:
      if error.reason == "conflict":
          return {"status": "conflict"}
      if error.reason == "precondition_failed":
          return {"status": "no_changes", "commit_sha": pinned_revision}
      raise
  ```

  ```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  builder, err := memoryRepo.CreateCommit(storage.CommitOptions{
  	Author:          storage.CommitSignature{Email: "agent@example.com", Name: "Agent"},
  	CommitMessage:   "Update API conventions",
  	ExpectedHeadSHA: pinnedRevision,
  	TargetBranch:    "main",
  })
  if err != nil {
  	return SaveResult{}, err
  }

  result, err := builder.
  	AddFileFromString("notes/api-conventions.md", updatedRecord, nil).
  	Send(ctx)
  if err != nil {
  	var refErr *storage.RefUpdateError
  	if errors.As(err, &refErr) {
  		switch refErr.Reason {
  		case storage.RefUpdateReasonConflict:
  			return SaveResult{Status: "conflict"}, nil
  		case storage.RefUpdateReasonPreconditionFailed:
  			return SaveResult{Status: "no_changes", CommitSHA: pinnedRevision}, nil
  		}
  	}
  	return SaveResult{}, err
  }

  if err := memoryHeads.Set(ctx, memoryRepo.ID, result.CommitSHA); err != nil {
  	return SaveResult{}, err
  }
  return SaveResult{Status: "saved", CommitSHA: result.CommitSHA}, nil
  ```
</CodeGroup>

A conflict means that another agent saved first. Do not send the old file content again. Load the
current files, apply the intended change to them, and save again with the new commit SHA.

An identical file set returns `precondition_failed`; the branch still points at the pinned revision.
Treat it as success with no new commit.

After a timeout, the save can still have succeeded. Do not resend the same request. Read the current
head again, apply the intended change to the current files, and save with the new head as
`expectedHeadSha`.

## Combine changes from separate branches

A product can give each agent session its own branch. Check the merge first, then require `main` to
remain at the commit that you checked.

<CodeGroup>
  ```typescript TypeScript theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  const sourceBranch = `sessions/${sessionId}`;
  const preview = await memoryRepo.previewMerge({
    sourceBranch,
    targetBranch: 'main',
  });

  if (preview.status === 'clean') {
    await memoryRepo.merge({
      sourceBranch,
      targetBranch: 'main',
      expectedTargetSha: preview.targetTipSha,
      strategy: 'merge',
    });
  }
  ```

  ```python Python theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  source_branch = f"sessions/{session_id}"
  preview = await memory_repo.preview_merge(
      source_branch=source_branch,
      target_branch="main",
  )

  if preview["status"] == "clean":
      await memory_repo.merge(
          source_branch=source_branch,
          target_branch="main",
          expected_target_sha=preview["target_tip_sha"],
          strategy="merge",
      )
  ```

  ```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  sourceBranch := fmt.Sprintf("sessions/%s", sessionID)
  preview, err := memoryRepo.PreviewMerge(ctx, storage.PreviewMergeOptions{
  	SourceBranch: sourceBranch,
  	TargetBranch: "main",
  })
  if err != nil {
  	return err
  }

  if preview.Status == "clean" {
  	_, err = memoryRepo.Merge(ctx, storage.MergeOptions{
  		SourceBranch:      sourceBranch,
  		TargetBranch:      "main",
  		ExpectedTargetSHA: preview.TargetTipSHA,
  		Strategy:          storage.MergeStrategyMerge,
  	})
  }
  ```
</CodeGroup>

If the check finds a conflict, load the listed files. Decide in code how to combine both changes
before you save again. If the merge itself fails because `main` moved after the check, run the check
again on the new head.

## Inspect and undo a change

Use `listCommits` to show file history and `getCommitDiff` to show one change.

<CodeGroup>
  ```typescript TypeScript theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  const history = await memoryRepo.listCommits({
    branch: 'main',
    path: 'notes/api-conventions.md',
    limit: 1,
  });
  const selected = history.commits[0];
  const diff = await memoryRepo.getCommitDiff({ sha: selected.sha });
  ```

  ```python Python theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  history = await memory_repo.list_commits(
      branch="main",
      path="notes/api-conventions.md",
      limit=1,
  )
  selected = history["commits"][0]
  diff = await memory_repo.get_commit_diff(sha=selected["sha"])
  ```

  ```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  history, err := memoryRepo.ListCommits(ctx, storage.ListCommitsOptions{
  	Branch: "main",
  	Path:   "notes/api-conventions.md",
  	Limit:  1,
  })
  if err != nil {
  	return err
  }
  selected := history.Commits[0]
  diff, err := memoryRepo.GetCommitDiff(ctx, storage.GetCommitDiffOptions{SHA: selected.SHA})
  ```
</CodeGroup>

Use `restoreCommit` to create a new commit from an earlier version. The new commit keeps the undo
action in history.

<CodeGroup>
  ```typescript TypeScript theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  const branchHistory = await memoryRepo.listCommits({ branch: 'main', limit: 2 });
  const currentHeadSha = branchHistory.commits[0].sha;

  const restored = await memoryRepo.restoreCommit({
    targetBranch: 'main',
    targetCommitSha: branchHistory.commits[1].sha,
    expectedHeadSha: currentHeadSha,
    commitMessage: 'Restore memory files',
    author: { email: 'operator@example.com', name: 'Operator' },
  });
  ```

  ```python Python theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  branch_history = await memory_repo.list_commits(branch="main", limit=2)
  current_head_sha = branch_history["commits"][0]["sha"]

  restored = await memory_repo.restore_commit(
      target_branch="main",
      target_commit_sha=branch_history["commits"][1]["sha"],
      expected_head_sha=current_head_sha,
      commit_message="Restore memory files",
      author={"email": "operator@example.com", "name": "Operator"},
  )
  ```

  ```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  branchHistory, err := memoryRepo.ListCommits(ctx, storage.ListCommitsOptions{
  	Branch: "main",
  	Limit:  2,
  })
  if err != nil {
  	return err
  }
  currentHeadSHA := branchHistory.Commits[0].SHA

  restored, err := memoryRepo.RestoreCommit(ctx, storage.RestoreCommitOptions{
  	TargetBranch:    "main",
  	TargetCommitSHA: branchHistory.Commits[1].SHA,
  	ExpectedHeadSHA: currentHeadSHA,
  	CommitMessage:   "Restore memory files",
  	Author:          storage.CommitSignature{Email: "operator@example.com", Name: "Operator"},
  })
  ```
</CodeGroup>

This example restores every file from the commit before the newest commit. To restore one file, read
its earlier content and save it with a normal file commit.

## Related workflow

Use [Manage Product Files](/docs/guides/manage-product-files) when people edit a complete file set
through a product interface. That workflow validates and applies each change before it becomes
active.
