Synchronization¶
pytaskwarrior supports two synchronization modes via the default
TaskChampionAdapter — no task binary required.
| Mode | Config key | When to use |
|---|---|---|
| Remote | sync.server.origin |
Sync across machines via a taskchampion HTTP server |
| Local | sync.local.server_dir |
Sync via a shared directory (NFS, SMB, Dropbox, …) |
Both modes expose the same Python API: tw.synchronize() and tw.is_sync_configured().
Runtime configuration
Sync settings can be modified at any time without recreating the adapter. See the Runtime Configuration guide for step-by-step instructions.
Prerequisites¶
taskchampion-py >= 3.0.1.1built from the fork intmp/taskchampion-py-fork/(installed automatically withuv sync)- Local sync requires the fork to be built with the
server-localfeature (enabled by default in this repository'spyproject.toml)
Remote sync¶
Remote sync uses the taskchampion sync protocol over HTTPS to a compatible server such as taskchampion-sync-server.
.taskrc configuration¶
sync.server.origin=https://taskchampion.example.com
sync.server.client_id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
sync.encryption.secret=my-passphrase
| Key | Required | Description |
|---|---|---|
sync.server.origin |
yes | Full URL of the sync server |
sync.server.client_id |
no | UUID identifying this client. Auto-generated and persisted if absent. |
sync.encryption.secret |
recommended | Passphrase used to encrypt tasks at rest on the server |
Automatic client ID
If sync.server.origin is set but sync.server.client_id is absent, pytaskwarrior
generates a stable UUID on first use and writes it to .taskrc automatically.
The same client ID is then reused in subsequent sessions.
Python usage¶
from taskwarrior import TaskWarrior
tw = TaskWarrior() # sync config is read from ~/.taskrc automatically
tw.synchronize() # push local changes, pull remote changes
print(tw.is_sync_configured()) # True
Direct TaskChampionAdapter usage¶
from taskwarrior.adapters.taskchampion_adapter import TaskChampionAdapter
adapter = TaskChampionAdapter(
data_location="~/.task",
sync_server_url="https://taskchampion.example.com",
sync_client_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
sync_encryption_secret="my-passphrase",
)
adapter.synchronize()
Local directory sync¶
Local sync stores operations in a plain directory that acts as the server. Both clients must have access to the same directory (e.g. via a network share).
.taskrc configuration¶
| Key | Required | Description |
|---|---|---|
sync.local.server_dir |
yes | Path to the shared server directory. Created if absent. |
Python usage¶
from taskwarrior import TaskWarrior
tw = TaskWarrior()
# sync.local.server_dir is read from ~/.taskrc automatically
tw.synchronize()
Direct TaskChampionAdapter usage¶
from taskwarrior.adapters.taskchampion_adapter import TaskChampionAdapter
adapter = TaskChampionAdapter(
data_location="~/.task",
sync_local_server_dir="/path/to/shared/taskserver",
)
adapter.synchronize()
Local vs remote precedence
When both sync_local_server_dir and sync_server_url are supplied,
local sync takes precedence.
Python API reference¶
TaskWarrior.synchronize()¶
Runs a full sync cycle (push local operations, pull remote operations).
Raises TaskSyncError if:
- No sync backend is configured (neither remote nor local)
- The sync operation fails (network error, invalid credentials, server unavailable)
TaskWarrior.is_sync_configured()¶
Returns True if at least one sync backend is configured in the active adapter.
ConfigStore.get_sync_config()¶
Returns all sync.* keys currently stored in the taskrc file as a plain dict.
ConfigStore.set_sync_config()¶
Write-symmetric counterpart of get_sync_config().
Replaces the entire sync.* section of the taskrc file in one call:
- Keys provided in config are written (upserted) to the file.
- Keys currently in the file but absent from config are deleted.
- A value of
Noneexplicitly removes that key (no-op when absent). - Keys may be provided with or without the
"sync."prefix — it is added automatically.
The in-memory config cache is refreshed automatically after the write.
Example — switch to remote sync:
tw.config_store.set_sync_config({
"sync.server.origin": "https://taskchampion.example.com",
"sync.server.client_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"sync.encryption.secret": "my-passphrase",
})
Example — switch to local sync (removes any previous remote keys):
Example — wipe all sync configuration:
.taskrc key reference¶
| Key | Mode | Description |
|---|---|---|
sync.server.origin |
Remote | URL of the taskchampion HTTP sync server |
sync.server.client_id |
Remote | Client UUID (auto-generated if absent) |
sync.encryption.secret |
Remote | Encryption passphrase for at-rest data |
sync.local.server_dir |
Local | Path to the shared server directory |
Differences vs task sync CLI¶
When using the TaskWarriorAdapter (CLI mode via TaskWarrior(task_cmd="task")),
tw.synchronize() delegates to task sync, which uses TaskWarrior's built-in sync
configuration.
| Aspect | TaskChampionAdapter (default) |
TaskWarriorAdapter (CLI) |
|---|---|---|
| Binary required | ❌ | ✅ |
| Remote sync server | ✅ sync_to_remote |
✅ via task sync |
| Local directory sync | ✅ sync_to_local |
✅ via task sync |
| Config key names | TW 3.x standard | TW 3.x standard |
is_sync_configured() |
Reads .taskrc |
Reads .taskrc |
Config key names changed in pytaskwarrior 3.0
Earlier pre-releases of pytaskwarrior 3.0 read sync.server.url and
sync.client.id. These were incorrect. The standard TaskWarrior 3.x keys
sync.server.origin and sync.server.client_id are now used.
Troubleshooting¶
TaskSyncError: No sync server configured¶
No sync keys were found in .taskrc (or the resolved taskrc file).
- Check that
TASKRCenvironment variable points to the correct file. - Verify at least one of
sync.server.originorsync.local.server_diris set. - Run
tw.config_store.get_sync_config()to inspect what keys are detected:
TaskSyncError: Sync failed: …¶
The underlying sync_to_remote or sync_to_local call raised an error.
Common causes:
| Symptom | Likely cause |
|---|---|
connection refused / unable to connect |
Wrong URL or server down |
401 Unauthorized |
Wrong client_id or encryption_secret |
invalid UUID |
sync.server.client_id is not a valid UUID v4 |
No such file or directory |
sync.local.server_dir path does not exist |
permission denied |
No write access to sync.local.server_dir |
Sync works from CLI (task sync) but not from Python¶
If task sync works but tw.synchronize() raises:
- The CLI adapter uses the TaskWarrior binary's sync (different code path).
- pytaskwarrior reads config from
.taskrcdirectly — verify the keys match the TW 3.x names (sync.server.origin, notsync.server.url). - Check that
TASKRCandTASKDATAenv vars, if set, point to the same files used by the CLI.
sync_to_local not available¶
The server-local feature may not be compiled into your taskchampion-py build.
Rebuild the fork with the feature enabled:
The repository's pyproject.toml already includes server-local in the maturin
features list.