.
D 2026-10-13T02:27:53.200
L Leaf\sAgent
N text/x-markdown
U dmestas
W 2071
# Leaf Agent
A Go daemon that sits next to a Fossil repo and keeps it synced over NATS.
## Data Flow
``` pikchr
right
R: cylinder "repo.fossil" color white fill 0x3a3a3a width 1.2 height 0.5 rad 3px
move 0.2
arrow color white thick <->
move 0.1
A: box "Leaf Agent" color white fill 0x2a6b3a width 1.5 height 0.5 rad 5px
move 0.2
arrow color white thick "sync request" above
move 0.1
N: cylinder "NATS" color white fill 0x2a4a6b width 1.0 height 0.5 rad 5px
move 0.2
arrow color white thick
move 0.1
B: box "Bridge" color white fill 0x6b5a2a width 1.2 height 0.5 rad 5px
move 0.2
arrow color white thick "HTTP" above
move 0.1
F: box "Fossil" color white fill 0x6b2a2a width 1.2 height 0.5 rad 5px
```
## How It Works
1. Opens a `.fossil` repo — reads project/server codes from SQLite
2. Connects to NATS
3. Polls every 5s (configurable):
- Checks `unsent`/`unclustered` tables
- If new artifacts found, calls `sync.Sync()` via NATS transport
4. `SIGUSR1` triggers immediate sync
5. `SIGINT`/`SIGTERM` graceful shutdown
## Usage
```
leaf-agent --repo /path/to/repo.fossil \
--nats nats://localhost:4222 \
--poll 5s \
--push --pull
```
| Flag | Env Var | Default | Description |
|------|---------|---------|-------------|
| `--repo` | `LEAF_REPO` | (required) | Path to `.fossil` file |
| `--nats` | `LEAF_NATS_URL` | `nats://localhost:4222` | NATS server URL |
| `--poll` | — | `5s` | Poll interval |
| `--user` | `LEAF_USER` | `anonymous` | Sync user |
| `--password` | `LEAF_PASSWORD` | — | Sync password |
| `--push` | — | `true` | Push local artifacts |
| `--pull` | — | `true` | Pull remote artifacts |
| `--prefix` | — | `fossil` | NATS subject prefix |
## Concurrency
The poll goroutine is the sole executor of sync. `SyncNow()` sends on a buffered channel — it never calls sync directly. This avoids concurrent SQLite access.
## See Also
- [Bridge](wiki:Bridge) — the other half
- [Home](wiki:index) — architecture overview
Z 566e7eccd75703e3315e7e8bdb9d4a98