Sync your Factory Droid coding sessions to OpenSync in real-time.
npm install -g droid-sync# Configure credentials and register hooks
droid-sync login
# Verify connection
droid-sync statusFactory Droid → hooks (stdin JSON) → CLI parses → SyncClient → Convex Backend
| File | Purpose |
|---|---|
src/cli.ts |
CLI entry point: login, logout, status, verify, hook <event> |
src/hooks.ts |
Event handlers (primary: Stop) |
src/api.ts |
SyncClient class - HTTP requests to Convex backend |
src/config.ts |
Configuration loading/saving |
src/transcript.ts |
JSONL transcript parsing, incremental message extraction |
src/types.ts |
TypeScript type definitions |
The plugin uses the Stop event for all syncing:
- Stop → Creates/updates session with metadata (project, git branch, model, tokens, duration), parses transcript, syncs new messages
- SessionEnd → Clears local sync state (synced message ID cache)
When Factory Droid triggers a hook, it:
- Invokes
droid-sync hook <EventName>as a subprocess - Pipes JSON context to stdin (sessionId, transcriptPath, cwd, etc.)
- The CLI reads stdin, parses JSON, dispatches to the appropriate handler
Example hook registration in ~/.factory/settings.json:
{
"hooks": {
"Stop": [
{ "hooks": [{ "type": "command", "command": "droid-sync hook Stop" }] }
]
}
}Note: Only the
Stophook is required.SessionEndonly clears local cache.
The plugin transforms Factory Droid's internal schema to the backend's expected format:
Plugin receives → Backend expects
───────────────────────────────────────────────────
sessionId → externalId
messageId → externalId
content → textContent
tool_use blocks → parts[{ type: "tool_use", content: {...} }]
assistantActiveTimeMs → durationMs
tokenUsage.inputTokens → tokenUsage.input
tokenUsage.outputTokens → tokenUsage.output
This mapping happens in transformSession() and transformMessage() methods in src/api.ts.
Messages are synced incrementally to avoid duplicates:
- On each
Stopevent, parse the transcript JSONL file - Load previously synced message IDs from state file
- Extract only new messages not in the synced set
- Sync new messages via batch API
- Save updated message IDs to state file
State files: ~/.config/droid-sync/state/{sessionId}.json
| Location | Purpose |
|---|---|
~/.config/droid-sync/config.json |
Primary config (convexUrl, apiKey, sync options) |
~/.factory/settings.json |
Hook registrations |
~/.config/droid-sync/state/ |
Per-session sync state (synced message IDs) |
| Environment variables | Override config (DROID_SYNC_*) |
droid-sync login # Configure credentials and register hooks
droid-sync logout # Clear credentials
droid-sync status # Show connection status
droid-sync verify # Test connectivity
droid-sync config # Show configuration
droid-sync version # Show version
Config file: ~/.config/droid-sync/config.json
{
"convexUrl": "https://your-project.convex.cloud",
"apiKey": "osk_your_api_key",
"autoSync": true,
"syncToolCalls": true,
"syncThinking": false
}MIT