Wire the existing merge engine over the network so the everyday config
(local + hub_url) syncs through a hub. Transport ratified = axum HTTP/JSON
(tech-spec §6.1, §12).
- heph-core: SyncCursors model + Store::sync_state/record_sync over the
sync_state table (per-peer push/pull HLC cursors). Incremental, so each
exchange transfers only the tail.
- hephd::sync: the hub router (POST /sync/push, GET /sync/pull?after=<hlc>)
served from the shared LocalStore, and sync_once — a spoke's pull-then-
merge, then push-tail exchange, advancing the cursors. Idempotent: a
re-pushed op the hub already has is a no-op.
- Daemon carries optional hub config; sync.now/sync.status handled at the
daemon (they need the hub transport the store can't reach). conflicts.
list/resolve now reachable over the unix socket too.
- main: --mode local|server, --hub-url, --http-addr. server mode binds the
hub HTTP endpoint on the same store; a local+hub_url spoke background-
syncs on a 30s interval.
- tests/sync_http.rs: two spokes converge through a real-HTTP hub on an
ephemeral port — node propagation and a divergent-scalar conflict.
Unauthenticated/single-owner for now; OIDC + per-user scoping is slice 10,
client mode + RemoteStore is 9b. 100 tests green; clippy -D warnings + fmt
+ prek clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace last-writer-wins for node bodies with the yrs text CRDT, so
concurrent edits to different regions of a body merge instead of one
clobbering the other (tech-spec §5, §12).
- New crate::crdt module wraps yrs: a device authors under a stable
client_id derived from its sync origin; a whole-buffer write is diffed
(common prefix/suffix, char-boundary safe) into the doc and the yrs
delta is captured; merge is commutative/idempotent.
- nodes::create/update/journal maintain the body_crdt BLOB and put the
yrs delta in the node.create/node.set op payload (body_crdt field).
Recurrence's local checklist reset goes through the same path to keep
body and body_crdt consistent (still records no op, as before).
- apply::node_upsert merges the body delta through the CRDT regardless of
HLC order and drops body-conflict recording; titles + task scalars stay
LWW with the conflict queue.
- convergence test now asserts disjoint concurrent body edits both survive
and enqueue no conflict.
97 tests green; clippy -D warnings + fmt + prek clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Record what's built and the resume order for the next context session:
heph-core + hephd local mode + CLI/export + local query surface + the
sync engine (HLC, op-log, converging merge/conflict-queue) are done;
resume at yrs body-CRDT → network sync → OIDC auth → heph.nvim.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
First sync slice. Ratifies yrs for body merge in the tech-spec.
- hlc module: Hlc (physical, counter, origin) with a fixed-width encoding
whose lexical order equals causal order; HlcClock generator (tick/update)
— clock-injected, strictly monotonic. Unit + 2 proptests.
- meta table (migration v3) holds the stable per-device `origin` and the
last HLC. next_hlc() does a read-modify-write inside the caller's
transaction (store is single-writer, so no race), replacing the
timestamp placeholder. Every node write is now stamped with a real,
monotonic, causally-ordered HLC.
4 stamping integration tests (monotonic under stalled/regressed clock;
origin shared + persists across reopen; HLC resumes from persisted state).
89 tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolve the open tensions surfaced in the pre-Phase-1 second pass over
design.md and tech-spec.md:
- Context items: Fork A index model — body markdown is the source of
truth; context items are a locally-derived, non-synced index;
identity is pinned at promotion. Dissolves the body-CRDT vs.
extraction convergence problem.
- Recurrence: roll-forward in place; drop task_occurrences and
is_template; advance to next RRULE instance after now (skip misses).
- Identity: deterministic ids for journal/tag (offline-convergent);
ULID for content nodes and project.
- Mode/sync: orthogonal hub_url spoke capability; everyday device is
local + hub_url, not server.
- Auth/owner: nullable oidc_sub, friction-free local user, hub-
authoritative identity, one-time pre-first-sync adoption rewrite.
- Ranking: do_date is a boolean candidacy filter only; late_on is the
sole urgency signal (global tier); FIFO tiebreak; order expressed as
a reorderable named-dimension list.
- Modes are plugin-side compositions; add list() and log.tail().
- Frame v1 as a single deliberate C1; misc cleanups (export, health,
CI nvim runner, README license).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace "distributed from day one" with a targetable Store backend that
supports the full spectrum from local-only to distributed by configuration:
- Store trait with LocalStore (direct SQLite, exclusive lock) and
RemoteStore (RPC to a server)
- three hephd runtime modes: local / server / client
- exclusive-lock handoff so the same SQLite file can pass between local and
server mode; client mode is thin and online-only
- offline remains a property of local-backed replicas syncing via the hub
Local-only is now a first-class configuration. Build order starts at local
mode. Updates docs/reference/tech-spec.md (§1, §3.1, §11) and
docs/explanation/design.md (§9, §11) to match.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Customize the generated repo (rename Dagger module to hephaestus_ci /
HephaestusCi, set docs baseUrl, add All-Rights-Reserved LICENSE, update
README/AGENTS), and add the project's foundational design documentation:
- docs/explanation/design.md — rationale + decision-history record
- docs/reference/tech-spec.md — implementation-ready technical spec
These define hephaestus as a self-hosted, client/server + offline-first
system unifying a markdown knowledge base with task management: typed node
graph, the lived priority discipline ("what is next?"), recurrence with
fresh-per-occurrence checklists, op-log/CRDT sync with conflict resolution,
OIDC/Authentik auth, the heph.nvim surface, and a TDD strategy.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>