Skip to content

Integrate

Change events

Every general volume can keep an ordered feed of its changes. The mountos event command reads that feed, as a stream on stdout or as a local REST API. Indexers, sync tools, and AI agents follow a volume without walking the tree.

What the feed is

Four event types, create, delete, modify, and rename, cover every change. Each event carries the full path (renames carry the old path too), the inode, the file type, the size, and a capture timestamp. Events are ordered by a per-fork monotonic sequence number, and each fork has its own feed.

From a write to a consumable event
client mountswrites on a general volumedataserv · owning clustercaptures the change feedmountos eventstdout stream · local REST APIregion databasethe retained feedgcservprunes past event retention1 · changes2 · ordered per-fork feed3 · reads by seq cursorretention window

Events surface within a few seconds of the change. Saves that land in quick succession on the same file coalesce, so the feed reports that the file changed, not every write. The feed is near real time, not synchronous.

The feed exists for general volumes only. A feed request against an Iceberg volume is rejected explicitly rather than served an empty feed.

Turn it on

The feed is off by default. One volume field, eventLogRetentionPeriod, controls it. The value is in days, from 0 to 30. It gates capture and sets how long events stay readable. At 0 nothing is captured and nothing accumulates. Events past the window are pruned. The field is set at volume create or later with an edit. The trade-off is storage growth. Longer windows keep more events, so size the window to what consumers actually replay.

await client.volumes.edit(volumeId, {
  eventLogRetentionPeriod: 7,
})

Stream to stdout

The command authenticates with the volume's access key, the same way a mount does. The key pair can also come from MOUNTOS_ACCESS_KEY_ID and MOUNTOS_SECRET_ACCESS_KEY, and the HUB domain from MOUNTOS_DISCOVERY_URL.

sh
# everything retained, oldest first
mountos event -a AKIA... -s

# the last 7 days, then keep tailing
mountos event -a AKIA... -s --since 7d --follow

# one subtree, machine readable
mountos event -a AKIA... -s --path-prefix /docs --json
txt
     SEQ  FORK  TIMESTAMP            EVENT    TYPE            INODE          SIZE  PATH
     101     0  2026-06-10 09:14:02  create   file           524291         18432  /docs/spec.md
     102     0  2026-06-10 09:14:09  modify   file           524291         20480  /docs/spec.md
     103     0  2026-06-10 09:15:11  rename   file           524291         20480  /docs/final.md  <- /docs/spec.md
     104     0  2026-06-10 09:16:40  delete   file           524291             -  /docs/final.md
  • --since floors on time. It takes relative windows (7d, 2h) or timestamps ("2025-01-01 14:30").
  • --start-seq floors on the sequence number instead.
  • --path-prefix filters to a subtree on a path component boundary. /docs matches /docs/spec.md but not /docs2.
  • --follow tails the feed by polling. Without --since or --start-seq it starts at the live end instead of replaying history.
  • --json emits one JSON object per event, the same shape the REST API returns.
  • --fork-name selects a fork's feed. Empty reads the main line.

Serve a local REST API

--http turns the command into a local HTTP server for tools that poll an endpoint instead of owning a process pipe. The server daemonizes (--foreground keeps it attached), binds 127.0.0.1, and listens on the port set by --http-port. It serves the fork it was started against, selected with --fork-name. Exposure beyond loopback requires TLS. --http-no-loopback is rejected without --http-cert and --http-key.

sh
mountos event -a AKIA... -s --http --http-port 9876

Callers never send the secret key. POST /v1/auth takes a signed challenge. The body carries the access key id, a unix timestamp, a single-use nonce, and a signature keyed with the secret. The response is a bearer token.

json
POST /v1/auth
{
  "access_key_id": "<key>",
  "timestamp": 1781083200,
  "nonce": "<random hex, single use>",
  "signature": "<hex of HMAC-SHA256(secret, key:timestamp:nonce)>"
}

{ "token": "<bearer>", "expires_in": 3600 }

GET /v1/events serves the feed. The first request takes since, start_seq, path_prefix, and limit (1 to 1000). Every response carries a continuation_token that encodes the cursor and the filters, so the next request passes only the token. seek_to_end=true returns a token at the live end with no events, the API form of tail-from-now.

sh
curl -s "http://127.0.0.1:9876/v1/events?since=7d&path_prefix=/docs" \
  -H "Authorization: Bearer $TOKEN"
json
{
  "events": [
    {
      "seq": 103,
      "fork_id": 0,
      "incarnation_id": 3,
      "event_ts": 1781082911000000,
      "born_at": 1781082842000000,
      "inode": 524291,
      "event_type": "rename",
      "type": "file",
      "size": 20480,
      "path": "/docs/final.md",
      "from_path": "/docs/spec.md"
    }
  ],
  "continuation_token": "eyJwIjoiL2RvY3MiLCJzIjoxMDMsInQiOjE3ODA0NzgxMTEwMDAwMDAsImYiOjB9",
  "has_more": false
}

Consumer semantics

  • Ordering. Events arrive in per-fork sequence order. seq is the resume cursor. A consumer stores the last sequence it processed, or the continuation token, and picks up where it left off.
  • Latency. Events surface within a few seconds and the CLI tail polls on an interval. Budget seconds, not milliseconds.
  • Coalescing. A file saved many times in quick succession surfaces fewer modify events than writes. The feed reports that the file changed, not every write.
  • Gaps. Each event carries an incarnation_id. A change between consecutive events marks a possible gap. A consumer that needs exactness treats it as a signal to reconcile the affected subtree.
  • Retention. Events older than eventLogRetentionPeriod days are pruned. A consumer that reads at a cadence shorter than the window never loses its place.
  • Timestamps. event_ts is the capture wall clock in microseconds and the canonical feed time. born_at correlates the event with the file's version history.
to navigate to open