CalCalist/CLAUDE.md
randogoth 4854844a72 Cut the README to a getting-started guide; retire SPECS.md and TODO.md
The README had grown to 413 lines and explained as much as it instructed:
someone trying to get calcalist running read past the architecture, the
scheduling-inertness rule and the reasoning behind retarget before reaching
anything they needed to type.

Most of the excess was duplication of SPECS.md, which is now retired along with
TODO.md since the roadmap is finished. That inverted the usual answer — the
rationale could not simply move to the design document, because there would not
be one. Checking what would actually be orphaned: the architecture rationale is
already in the module doc comments, beside the code it governs and where it
cannot drift; the M0-M2 record is history and git keeps it. Two things had no
home: the working agreement that has shaped every commit, and two decisions
that cost real design work to decline and would otherwise be re-proposed from
first principles. Both are now in CLAUDE.md, which is read at the start of every
session rather than filed and forgotten.

What the README keeps is the whole setup path, because none of it exists
anywhere else now: every configuration field, the Google OAuth walkthrough in
full, routing, and the systemd units. What it gains is a short section on what
the tool does to your calendars — deletion propagating to the source is not
something to discover by accident. What it loses is the design commentary.

Also moves `discover` out of the command list and into the CalDAV endpoint
section, since getting the url field right is its entire purpose.

Verified rather than eyeballed: the worked example was extracted and run through
doctor and status, the command table diffed against --help, and every internal
anchor resolved.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-10 16:41:34 +03:00

3.2 KiB

calcalist

Aggregates events between CalDAV, Google Calendar and iCal feeds. README.md is the user-facing guide; the design rationale lives in the module doc comments, beside the code it governs.

These conventions were SPECS.md's, which has been retired now the roadmap is finished. Git history holds it, and TODO.md, if the record is ever wanted.

Development

Use devbox for dependency management and scripts. Use jj for version control (colocated with git).

  • devbox run fmt — format.
  • devbox run check — format check, clippy with warnings denied, and tests. This is the gate; jj has no commit step to hang a hook off, since the working copy is itself a commit.
  • devbox run test — tests only.

Keep /target in .gitignore: jj snapshots the working copy on every command, with no staging step.

The integration tests in tests/ need radicale and pimsync, both of which devbox provides. Outside that shell they report what is missing and pass.

Coding style

  • Simple, readable, idiomatic.
  • Explicit types for public APIs and important fields.
  • Prefer immutable data structures.
  • No global mutable state.
  • No speculative features or dependencies.
  • Keep functions short and single-purpose; extract helpers to avoid nesting.
  • File and module naming: snake_case.rs. Types and traits: PascalCase. Functions, variables and fields: snake_case. Constants: SCREAMING_SNAKE_CASE.
  • Run devbox run check before describing a change.
  • Comment only when intent is not obvious from the code.
  • Prefer composition and traits over deep type hierarchies.

Decisions already taken

Settled after real design work. Reopen only with new information, not from first principles.

No configuration web interface. Designed in full, then dropped. Its audience would be people who find TOML hard — but every user must first create a Google Cloud project, configure a consent screen and put a secret in a keyring, which is a far higher bar than editing the config. Anyone who clears it can edit the file; anyone who cannot never reaches the file. doctor, status and discover cover what the interface was actually for.

Bring-your-own OAuth client, not a shipped verified one. Verification for the Calendar scope needs a domain you own — a github.io address is rejected — and Calendar API quota is per Cloud project, with charges announced for exceeding it. A shipped client would pool every user's syncing into the publisher's project, and their bill. Shipping an unverified shared client is worse still: the 100-new-user cap is permanent for the project's lifetime.

pimsync cannot reach Google, and never will. It has no REST storage, and its config exposes only HTTP Basic auth, which Google's CalDAV endpoint rejected in March 2025. The Google leg is calcalist's own in every design.

The config file is never machine-rewritten. It is the portable, hand-editable artefact. Anything that writes it must preserve comments, ordering and omitted defaults — toml::to_string on the Serialize derive does none of those things.

Known gap

A failing pimsync sync stops the whole CalDAV leg. Unlike the Google side this cannot be narrowed: pimsync is one process covering every pair, and a failure does not say which pair it belongs to.