Quick Reference

#| include: false
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  eval = FALSE
)

Automerge R Package Quick Reference

One-page reference for the automerge package. See full documentation with ?function_name.

Installation

# From R-universe
install.packages("automerge", repos = "https://posit-dev.r-universe.dev")

# From GitHub
pak::pak("posit-dev/automerge-r")

Document Lifecycle

library(automerge)

# Create
doc <- am_create() # New document
doc <- am_create("fd3ca50687f13477f1f9ea2b216b958a") # With custom actor ID

# Load/Save
bytes <- am_save(doc) # Save to bytes
doc <- am_load(bytes) # Load from bytes

# Actor ID
actor <- am_get_actor(doc) # Get actor ID (raw bytes)
actor_hex <- am_get_actor_hex(doc) # Get actor ID as hex string
am_set_actor(doc, actor_hex) # Set actor ID (raw, hex, or NULL)

# Fork/Merge
doc2 <- am_fork(doc) # Create independent copy
am_merge(doc, doc2) # Merge doc2 into doc1

# Transactions
am_commit(doc, "message") # Commit changes
am_rollback(doc) # Cancel pending changes

# Cleanup
am_close(doc) # Explicitly free resources (optional)

Basic Access (Maps)

# S3 operators
doc[["key"]] <- "value" # Set value
value <- doc[["key"]] # Get value
doc$key <- value # Alternative syntax
value <- doc$key # Alternative syntax

# Functional API
am_delete(doc, AM_ROOT, "key") # Delete key
am_put(doc, AM_ROOT, "key", value) # Set value
value <- am_get(doc, AM_ROOT, "key") # Get value

# Introspection
keys <- names(doc) # Get all keys
keys <- am_keys(doc, AM_ROOT) # Functional version
values <- am_values(doc, AM_ROOT) # Get all values
n <- length(doc) # Number of keys
n <- am_length(doc, AM_ROOT) # Functional version

Nested Objects

# Automatic recursive conversion (recommended)
am_put(
  doc,
  AM_ROOT,
  "user",
  list(
    name = "Alice",
    age = 30L,
    address = list(city = "NYC", zip = 10001L)
  )
)

# Path-based access (simple for deep structures)
am_put_path(doc, c("user", "address", "city"), "Boston")
city <- am_get_path(doc, c("user", "address", "city"))
am_delete_path(doc, c("user", "address"))

# Manual access
user_obj <- am_get(doc, AM_ROOT, "user")
am_put(doc, user_obj, "name", "Bob")
name <- am_get(doc, user_obj, "name")

Lists

# Create list
am_put(doc, AM_ROOT, "items", AM_OBJ_TYPE_LIST)
items <- am_get(doc, AM_ROOT, "items")

# Operations (1-based indexing)
am_insert(doc, items, 1, "first") # Insert at index 1
am_put(doc, items, 1, "FIRST") # Replace at index 1
am_put(doc, items, "end", "append") # Append to end
value <- am_get(doc, items, 1) # Get index 1
am_delete(doc, items, 1) # Delete index 1

# Introspection
n <- am_length(doc, items) # List length

Text Objects

# Text objects use 0-based inter-character positions
# For the text "Hello":
#  H e l l o
# 0 1 2 3 4 5  <- positions (0-based, between characters)

# Create text object
am_put(doc, AM_ROOT, "content", am_text("Hello"))
text_obj <- am_get(doc, AM_ROOT, "content")

# Operations
am_text_splice(text_obj, 5, 0, " World") # Insert at position 5
content <- am_text_content(text_obj) # Get full text

# Update text (ideal for collaborative editing)
old_text <- am_text_content(text_obj)
am_text_update(text_obj, old_text, "Hello Universe") # Computes and applies diff

# Cursors (stable positions)
cursor <- am_cursor(text_obj, 5) # Create cursor at position 5
pos <- am_cursor_position(cursor) # Get current position

# Marks (formatting)
am_mark(text_obj, 0, 5, "bold", TRUE, expand = "none")
marks <- am_marks(text_obj) # Get all marks
marks_at <- am_marks_at(text_obj, 2) # Marks at position 2

Value Types

# NULL
am_put(doc, AM_ROOT, "null", NULL)

# Boolean
am_put(doc, AM_ROOT, "bool", TRUE)

# Integer
am_put(doc, AM_ROOT, "int", 42L)

# Double
am_put(doc, AM_ROOT, "float", 3.14)

# String
am_put(doc, AM_ROOT, "str", "text")

# Raw bytes
am_put(doc, AM_ROOT, "bytes", raw(10))

# Timestamp
am_put(doc, AM_ROOT, "time", Sys.time())

# Counter
am_put(doc, AM_ROOT, "score", am_counter(0))
am_counter_increment(doc, AM_ROOT, "score", 10)
value <- am_get(doc, AM_ROOT, "score")

# Unsigned 64-bit integer (for cross-platform interop)
am_put(doc, AM_ROOT, "id", am_uint64(12345))

# Explicit type constructors
am_put(doc, AM_ROOT, "items", am_list()) # Empty list
am_put(doc, AM_ROOT, "config", am_map()) # Empty map
am_put(doc, AM_ROOT, "notes", am_text()) # Text object

Synchronization (High-Level)

# Bidirectional sync (auto-converge)
# Documents are modified in place
rounds <- am_sync(doc1, doc2)
cat("Converged in", rounds, "rounds\n")

# One-way merge
am_merge(doc1, doc2) # Merge doc2 into doc1

Synchronization (Low-Level)

# Create sync state
sync_state <- am_sync_state_new()

# Encode/decode messages
msg <- am_sync_encode(doc, sync_state)
am_sync_decode(doc, sync_state, msg)

# Manual sync loop
repeat {
  msg1 <- am_sync_encode(doc1, sync1)
  if (is.null(msg1)) {
    break
  }
  am_sync_decode(doc2, sync2, msg1)

  msg2 <- am_sync_encode(doc2, sync2)
  if (is.null(msg2)) {
    break
  }
  am_sync_decode(doc1, sync1, msg2)
}

History & Changes

# Get heads
heads <- am_get_heads(doc)

# Get changes
changes <- am_get_changes(doc, NULL) # All changes
changes <- am_get_changes(doc, heads) # Since specific heads

# Apply changes
am_apply_changes(doc, changes)

# Full history
history <- am_get_history(doc)

Conversion

# R → Automerge
doc <- as_automerge(list(name = "Alice", age = 30L))

# Automerge → R
r_list <- from_automerge(doc)

r_list <- as.list(doc) # S3 method for documents
text_str <- as.character(text_obj) # S3 method for text objects

Pipe-Friendly Style

doc <- am_create() |>
  am_put(AM_ROOT, "name", "Alice") |>
  am_put(AM_ROOT, "age", 30L) |>
  am_commit("Initial data")

File Operations

# Save to file
writeBin(am_save(doc), "document.automerge")

# Load from file
doc <- am_load(readBin("document.automerge", "raw", 1e6))

Constants

AM_ROOT # Root object (NULL)
AM_OBJ_TYPE_LIST # "list"
AM_OBJ_TYPE_MAP # "map"
AM_OBJ_TYPE_TEXT # "text"

AM_MARK_EXPAND_NONE # "none" (mark doesn't expand at boundaries)
AM_MARK_EXPAND_BEFORE # "before" (expands when text inserted before start)
AM_MARK_EXPAND_AFTER # "after" (expands when text inserted after end)
AM_MARK_EXPAND_BOTH # "both" (expands at both boundaries)

Getting Help

# Function help
?am_create
?am_put
?am_sync

# Package help
?automerge
help(package = "automerge")

# Vignettes
vignette("automerge", "automerge")
vignette("crdt-concepts", "automerge")
vignette("sync-protocol", "automerge")
vignette(package = "automerge") # List all

System Requirements

Resources


Note: This is a quick reference. See full vignettes for detailed examples and explanations.



Try the automerge package in your browser

Any scripts or data that you put into this service are public.

automerge documentation built on Feb. 5, 2026, 5:08 p.m.