Skip to content

Git Sync

Git Sync synchronizes local DAG files and agent memory files with a remote Git repository.

Tracked Files And Item IDs

Git Sync tracks items by itemId (path without extension).

Local fileTracked askind
my-dag.yamlmy-dagdag
subdir/report.ymlsubdir/reportdag
memory/MEMORY.mdmemory/MEMORYmemory
memory/dags/my-dag/MEMORY.mdmemory/dags/my-dag/MEMORYmemory

Rules implemented by internal/gitsync/service.go:

  • Remote scan includes .yaml, .yml, .md.
  • .md is accepted only when the item is under memory/.
  • Local untracked scan includes root-level .yaml / .yml files.
  • Local untracked scan includes any .md file under memory/ (recursive).

Configuration

yaml
git_sync:
  enabled: true
  repository: github.com/your-org/dags
  branch: main
  path: ""  # subdirectory in repo (empty = root)
  push_enabled: true

  auth:
    type: token
    token: ${GITHUB_TOKEN}

  auto_sync:
    enabled: true
    on_startup: true
    interval: 300

  commit:
    author_name: Boltbase
    author_email: boltbase@localhost

Defaults applied when git_sync.enabled: true:

  • branch: main
  • push_enabled: true
  • auth.type: token
  • auto_sync.on_startup: true
  • auto_sync.interval: 300
  • commit.author_name: Boltbase
  • commit.author_email: boltbase@localhost

Authentication

HTTPS token

yaml
git_sync:
  repository: github.com/your-org/dags
  branch: main
  auth:
    type: token
    token: ${GITHUB_TOKEN}
bash
export BOLTBASE_GITSYNC_AUTH_TYPE=token
export BOLTBASE_GITSYNC_AUTH_TOKEN=ghp_xxxxxxxxxxxx

SSH key

Use SSH repository format, for example git@github.com:org/repo.git.

yaml
git_sync:
  repository: git@github.com:your-org/dags.git
  branch: main
  auth:
    type: ssh
    ssh_key_path: /home/user/.ssh/id_ed25519
    ssh_passphrase: ${SSH_PASSPHRASE}
bash
export BOLTBASE_GITSYNC_AUTH_TYPE=ssh
export BOLTBASE_GITSYNC_AUTH_SSH_KEY_PATH=/home/user/.ssh/id_ed25519
export BOLTBASE_GITSYNC_AUTH_SSH_PASSPHRASE=your-passphrase

CLI

bash
boltbase sync status
boltbase sync pull

Publish one item or all modified/untracked items:

bash
boltbase sync publish my-dag -m "Update dag"
boltbase sync publish memory/MEMORY -m "Update global memory"
boltbase sync publish --all -m "Batch update"

Discard one item:

bash
boltbase sync discard my-dag
boltbase sync discard memory/dags/my-dag/MEMORY

Status Values

statusmeaning
syncedlocal content matches last synced content
modifiedlocal content differs from lastSyncedHash
untrackedlocal item exists but has no synced baseline
conflictlocal item is modified and remote changed since last sync

REST API

Endpoints

MethodEndpointNotes
GET/api/v1/sync/statusReturns overall status and items[]
POST/api/v1/sync/pullPull from remote
POST/api/v1/sync/publish-allPublish selected itemIds or all modified/untracked if omitted
POST/api/v1/sync/test-connectionTest repository/auth access
GET/api/v1/sync/configGet sync config
PUT/api/v1/sync/configUpdate sync config
GET/api/v1/sync/items/{itemId}/diffGet local vs remote diff for one item
POST/api/v1/sync/items/{itemId}/publishPublish one item
POST/api/v1/sync/items/{itemId}/discardDiscard local changes for one item

itemId is a path parameter. If the ID contains /, URL-encode it.

Example:

  • raw item ID: memory/MEMORY
  • path segment: memory%2FMEMORY

Get Status Example

bash
curl "http://localhost:8080/api/v1/sync/status"

Example response shape:

json
{
  "enabled": true,
  "summary": "pending",
  "items": [
    {
      "itemId": "my-dag",
      "filePath": "my-dag.yaml",
      "displayName": "my-dag.yaml",
      "kind": "dag",
      "status": "modified"
    },
    {
      "itemId": "memory/MEMORY",
      "filePath": "memory/MEMORY.md",
      "displayName": "memory/MEMORY.md",
      "kind": "memory",
      "status": "untracked"
    }
  ],
  "counts": {
    "synced": 10,
    "modified": 1,
    "untracked": 1,
    "conflict": 0
  }
}

Implementation details from API handler (internal/service/frontend/api/v1/sync.go):

  • items are sorted by filePath.
  • for kind=dag, filePath is itemId + ".yaml".
  • for kind=memory, filePath is itemId + ".md".
  • displayName currently equals filePath.

Diff Example (Memory Item)

bash
curl "http://localhost:8080/api/v1/sync/items/memory%2FMEMORY/diff"

Publish One Item

bash
curl -X POST "http://localhost:8080/api/v1/sync/items/memory%2FMEMORY/publish" \
  -H "Content-Type: application/json" \
  -d '{"message":"Update global memory","force":false}'

Publish Selected Items

bash
curl -X POST "http://localhost:8080/api/v1/sync/publish-all" \
  -H "Content-Type: application/json" \
  -d '{
    "message":"Batch publish",
    "itemIds":["my-dag","memory/MEMORY"]
  }'

Publish All Modified/Untracked Items

bash
curl -X POST "http://localhost:8080/api/v1/sync/publish-all" \
  -H "Content-Type: application/json" \
  -d '{"message":"Publish all pending"}'

Discard One Item

bash
curl -X POST "http://localhost:8080/api/v1/sync/items/memory%2FMEMORY/discard"

Permissions

API permission checks for sync endpoints:

  • /sync/status, /sync/config, and /sync/test-connection return non-error responses even when sync is not configured.
  • /sync/items/{itemId}/diff requires sync service configuration.
  • write operations (/sync/pull, /sync/publish-all, /sync/items/{itemId}/publish, /sync/items/{itemId}/discard) require server.permissions.write_dags.
  • authenticated users on write operations must satisfy Role.CanWrite() (admin or manager).
  • write operations are blocked when Git Sync is read-only (git_sync.enabled=true and push_enabled=false).
  • Config update (PUT /sync/config): admin only.

Data On Disk

pathpurpose
{dags_dir}/local DAG and memory files
{data_dir}/gitsync/state.jsonsync state
{data_dir}/gitsync/repo/local Git checkout cache

state.json top-level fields:

  • version
  • repository
  • branch
  • lastSyncAt
  • lastSyncCommit
  • lastSyncStatus
  • lastError
  • dags (map[itemId]DAGState)

DAGState fields:

  • status (synced|modified|untracked|conflict)
  • kind (dag|memory)
  • baseCommit
  • lastSyncedHash
  • lastSyncedAt
  • modifiedAt
  • localHash
  • remoteCommit
  • remoteAuthor
  • remoteMessage
  • conflictDetectedAt

Released under the MIT License.