tx

tx sync

Git-backed JSONL synchronization

Purpose

tx sync manages bidirectional synchronization between the SQLite database and a git-friendly JSONL file. This enables:

  • Version control of task history
  • Team collaboration via git
  • Backup and recovery
  • Cross-machine synchronization

Subcommands

CommandDescription
tx sync exportExport tasks to JSONL file
tx sync importImport tasks from JSONL file
tx sync statusShow sync status
tx sync autoEnable/disable automatic sync
tx sync compactCompact JSONL by deduplicating operations

tx sync export

Export all tasks and dependencies to a JSONL file.

Usage

tx sync export [options]

Options

OptionDescription
--path <path>Output path (default: .tx/tasks.jsonl)
--jsonOutput as JSON with operation count

Examples

# Export to default location
tx sync export

# Export to custom location
tx sync export --path ./backup/tasks.jsonl

# Get operation count
tx sync export --json

Output

Exported 42 operations to .tx/tasks.jsonl

Sync operations are available through the Effect-based core API:

import { createTx, SyncService } from '@jamesaphoenix/tx'
import { Effect } from 'effect'

const tx = createTx()

// Export
await tx.run(
  Effect.gen(function* () {
    const sync = yield* SyncService
    const result = yield* sync.exportToJsonl()
    return result
  })
)

await tx.close()

For most use cases, the CLI commands are recommended for sync operations.

Tool name: tx_sync_export

Arguments:

ArgTypeRequiredDescription
pathstringNoPath to JSONL file (default: .tx/tasks.jsonl)

Example request:

{
  "name": "tx_sync_export",
  "arguments": {}
}
POST /api/sync/export

Body:

{
  "path": ".tx/tasks.jsonl"
}

Example:

curl -X POST http://localhost:3456/api/sync/export \
  -H "Content-Type: application/json" \
  -d '{}'

tx sync import

Import tasks from a JSONL file using timestamp-based merge.

Usage

tx sync import [options]

Options

OptionDescription
--path <path>Input path (default: .tx/tasks.jsonl)
--jsonOutput as JSON

Examples

# Import from default location
tx sync import

# Import from custom location
tx sync import --path ./backup/tasks.jsonl

Merge Strategy

Import uses timestamp-based merge:

  • Newer operations win over older ones
  • Conflicts are resolved by comparing updatedAt timestamps
  • Operations are applied in chronological order

Sync operations are available through the Effect-based core API:

import { createTx, SyncService } from '@jamesaphoenix/tx'
import { Effect } from 'effect'

const tx = createTx()

// Import
await tx.run(
  Effect.gen(function* () {
    const sync = yield* SyncService
    const result = yield* sync.importFromJsonl()
    return result
  })
)

await tx.close()

For most use cases, the CLI commands are recommended for sync operations.

Tool name: tx_sync_import

Arguments:

ArgTypeRequiredDescription
pathstringNoPath to JSONL file (default: .tx/tasks.jsonl)

Example request:

{
  "name": "tx_sync_import",
  "arguments": {}
}
POST /api/sync/import

Body:

{
  "path": ".tx/tasks.jsonl"
}

Example:

curl -X POST http://localhost:3456/api/sync/import \
  -H "Content-Type: application/json" \
  -d '{}'

tx sync status

Show sync status and whether the database has unexported changes.

Usage

tx sync status [options]

Options

OptionDescription
--jsonOutput as JSON

Examples

tx sync status

Output

Sync status:
  Database tasks: 156
  JSONL operations: 312
  Last export: 2025-01-28T10:30:00Z
  Pending changes: 8

Sync operations are available through the Effect-based core API:

import { createTx, SyncService } from '@jamesaphoenix/tx'
import { Effect } from 'effect'

const tx = createTx()

// Get sync status
await tx.run(
  Effect.gen(function* () {
    const sync = yield* SyncService
    const status = yield* sync.status()
    return status
  })
)

await tx.close()

For most use cases, the CLI commands are recommended for sync operations.

Tool name: tx_sync_status

Arguments: None

Example request:

{
  "name": "tx_sync_status",
  "arguments": {}
}
GET /api/sync/status

Example:

curl http://localhost:3456/api/sync/status

Response:

{
  "dbTaskCount": 156,
  "jsonlOpCount": 312,
  "lastExport": "2025-01-28T10:30:00.000Z",
  "lastImport": null,
  "isDirty": true,
  "autoSyncEnabled": false
}

tx sync auto

Enable or disable automatic synchronization on mutations.

Usage

tx sync auto --enable|--disable [options]

Options

OptionDescription
--enableEnable auto-sync
--disableDisable auto-sync
--jsonOutput as JSON

Examples

# Enable auto-sync
tx sync auto --enable

# Disable auto-sync
tx sync auto --disable

When auto-sync is enabled, every task mutation automatically exports to JSONL.

Sync operations are available through the Effect-based core API:

import { createTx, AutoSyncService } from '@jamesaphoenix/tx'
import { Effect } from 'effect'

const tx = createTx()

// Enable auto-sync
await tx.run(
  Effect.gen(function* () {
    const autoSync = yield* AutoSyncService
    yield* autoSync.enable()
  })
)

await tx.close()

For most use cases, the CLI commands are recommended for sync operations.

Auto-sync is typically configured through the CLI. Use tx sync auto --enable or tx sync auto --disable to toggle.

The current auto-sync state is included in the tx_sync_status tool response under the autoSyncEnabled field.

Auto-sync is typically configured through the CLI. The current auto-sync state is included in the sync status response:

curl http://localhost:3456/api/sync/status
# Response includes "autoSyncEnabled": true/false

tx sync compact

Compact the JSONL file by deduplicating operations.

Usage

tx sync compact [options]

Options

OptionDescription
--jsonOutput as JSON

Examples

tx sync compact

Output

Compacted .tx/tasks.jsonl:
  Before: 1,234 operations (256 KB)
  After: 892 operations (189 KB)
  Saved: 27%

Sync operations are available through the Effect-based core API:

import { createTx, SyncService } from '@jamesaphoenix/tx'
import { Effect } from 'effect'

const tx = createTx()

// Compact
await tx.run(
  Effect.gen(function* () {
    const sync = yield* SyncService
    const result = yield* sync.compact()
    return result
  })
)

await tx.close()

For most use cases, the CLI commands are recommended for sync operations.

Tool name: tx_sync_compact

Arguments:

ArgTypeRequiredDescription
pathstringNoPath to JSONL file (default: .tx/tasks.jsonl)

Example request:

{
  "name": "tx_sync_compact",
  "arguments": {}
}
POST /api/sync/compact

Body:

{
  "path": ".tx/tasks.jsonl"
}

Example:

curl -X POST http://localhost:3456/api/sync/compact \
  -H "Content-Type: application/json" \
  -d '{}'

Response:

{
  "before": 1234,
  "after": 892
}

JSONL Format

The export format is newline-delimited JSON:

{"op":"create","id":"tx-abc123","title":"Implement auth","status":"backlog","score":800,"ts":"2025-01-28T10:00:00Z"}
{"op":"update","id":"tx-abc123","status":"active","ts":"2025-01-28T10:30:00Z"}
{"op":"block","taskId":"tx-def456","blockerId":"tx-abc123","ts":"2025-01-28T11:00:00Z"}
{"op":"done","id":"tx-abc123","ts":"2025-01-28T14:00:00Z"}

Operation Types

OperationDescription
createNew task created
updateTask fields updated
deleteTask deleted
blockDependency added
unblockDependency removed
doneTask completed

Git Workflow

# After completing work
tx sync export
git add .tx/tasks.jsonl
git commit -m "Update tasks"
git push

# On another machine
git pull
tx sync import

.gitignore Recommendation

# Track the JSONL, ignore the SQLite database
.tx/tasks.db
.tx/tasks.db-wal
.tx/tasks.db-shm
!.tx/tasks.jsonl

Team Collaboration

Multiple agents or developers can work on the same task database:

  1. Export before pushing: tx sync export && git add .tx/tasks.jsonl
  2. Import after pulling: git pull && tx sync import
  3. Enable auto-sync for real-time updates: tx sync auto --enable

Merge conflicts in the JSONL file can be resolved by keeping both sides (JSONL is append-friendly) and running tx sync compact afterward.

  • tx ready - Get tasks after syncing
  • tx done - Complete tasks (triggers auto-sync if enabled)

On this page