Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions CONTEXT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Cyd

Cyd helps people preserve, inspect, and manage the data associated with their social-media accounts.

## Language

**Bluesky workflow parity**:
Mobile and desktop Cyd offer the same Bluesky account-management capabilities and preserve the same data semantics, while each may use platform-appropriate interfaces and operating-system integrations.
_Avoid_: UI parity, identical clients

**Cyd archive**:
A complete, self-contained, versioned snapshot of an account's saved data and media that supported Cyd clients can exchange without losing its meaning. Version 2 is the first supported Cyd archive format; the earlier unversioned mobile prototype is not a Cyd archive compatibility surface.
_Avoid_: HTML export, database backup

**Interchange database**:
The canonical representation of structured account data inside a Cyd archive. It is independent of each client's private runtime storage.
_Avoid_: runtime database, mobile database

**Bluesky identity**:
A Bluesky account identified durably by its DID, even when its handle changes or separate Cyd installations know it by different local identifiers.
_Avoid_: handle, Cyd UUID

**Local account**:
A client's local representation of a Bluesky identity, identified within Cyd by a UUID and containing that client's settings and saved data.
_Avoid_: Bluesky identity

**Archive import**:
An idempotent recovery merge of a Cyd archive into a matching local account, preserving the union of saved data while collapsing records that share stable Bluesky identifiers. It may restore data previously removed through local deletion.
_Avoid_: replace, synchronize

**Account settings**:
Local preferences governing how Cyd saves and manages a Bluesky identity. An archive can supply defaults for a new local account, but does not silently override an existing local account's preferences or schedules.
_Avoid_: account data, archive state

**Scheduled reminder**:
A prompt to review and start due account-management work. It does not authorize Cyd to perform deletion unattended; clients may use platform-appropriate delivery such as local notifications or server-scheduled push.
_Avoid_: scheduled job, automatic deletion

**Connection**:
A local installation's authorization to act on a Bluesky identity. Connections are established separately on each client and are never part of a Cyd archive.
Disconnecting removes authorization without removing the local account or its saved data.
_Avoid_: account data, imported session, local account

**Saved data**:
The account records and complete media Cyd has preserved locally, including material that may later disappear from Bluesky. When a record is selected for saving, its full media is part of the saved data regardless of the record category.
_Avoid_: live feed, HTML export

**Saved record**:
The latest representation of a Bluesky record observed by Cyd at a stable AT URI, together with its observation timestamps and deletion state. It is not a history of every CID revision.
_Avoid_: record revision, live record

**Browse**:
Inspect saved data inside Cyd without requiring a Bluesky connection or network access.
_Avoid_: view on Bluesky, live feed

**Context snapshot**:
The directly referenced author, reply parent, quoted record, external embed, and other captured information required to render a saved record faithfully without recursively preserving the surrounding social graph.
_Avoid_: full thread, live lookup

**Complete backup**:
A saved dataset or Cyd archive containing every expected asset for its selected records. Missing assets are explicit and make the backup incomplete without invalidating the data that was successfully preserved.
_Avoid_: valid archive, successful export

**Source deletion**:
Removal of a record or relationship from Bluesky while retaining Cyd's saved copy and deletion state.
_Avoid_: local deletion

**Local deletion**:
An explicit removal of saved data from Cyd, independent of whether the source still exists on Bluesky.
_Avoid_: source deletion, stop saving
3 changes: 3 additions & 0 deletions docs/adr/0001-bidirectional-cyd-archive-compatibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Bidirectional Cyd archive compatibility begins with version 2

Cyd mobile and desktop exchange Cyd archives beginning with the canonical version 2 format. The unversioned mobile prototype has no users and is unsupported by both clients; abandoning it avoids coupling the shared contract to Mobile's historical runtime schema. Each client clearly rejects archive versions it does not support so evolving one application does not silently break portability with the other.
3 changes: 3 additions & 0 deletions docs/adr/0002-canonical-archive-interchange-database.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Canonical archive interchange database

The `data.db` inside version 2 and later Cyd archives is a canonical interchange database rather than a copy of either client's runtime database. Mobile and desktop translate between private storage and this versioned schema, allowing their implementations and migrations to evolve independently; neither client maintains an adapter for the unused unversioned mobile prototype.
3 changes: 3 additions & 0 deletions docs/adr/0003-match-bluesky-accounts-by-did.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Match Bluesky accounts by DID

Archive import matches a Bluesky account by DID, not by handle or Cyd UUID. Handles can change and separate installations can assign different UUIDs to the same Bluesky identity; UUIDs remain local-account identifiers and are preserved when possible, while DID matching prevents duplicate local accounts for one Bluesky identity. A matching DID keeps the existing local UUID; a new DID adopts the archive UUID when it is unused, or receives a newly generated UUID with a reported remapping when the archive UUID already belongs to another identity.
3 changes: 3 additions & 0 deletions docs/adr/0004-merge-archive-imports-idempotently.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Merge archive imports idempotently

Importing a Cyd archive merges it with the matching local account rather than replacing local data. Records match on stable Bluesky identifiers such as AT URIs, richer or newer representations can update older ones, data absent from the archive is retained, and importing the same archive repeatedly has no further effect; this supports safe cross-device transfer without sacrificing data collected independently on either device. Because import is an explicit recovery action, it may restore locally deleted records, and its preview reports that restoration rather than relying on permanent deletion tombstones that would suppress older backups.
3 changes: 3 additions & 0 deletions docs/adr/0005-exclude-credentials-from-archives.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Exclude credentials from Cyd archives

Cyd archives never contain OAuth tokens, private keys, session state, or other reusable credentials. Imported accounts are immediately available for offline browsing, but each installation must establish its own Bluesky connection before it can refresh data or perform account actions, preventing a portable archive from becoming an account-control credential.
3 changes: 3 additions & 0 deletions docs/adr/0006-offline-first-in-app-browsing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Make in-app browsing offline-first

The Cyd browser reads the local saved dataset rather than depending on live Bluesky APIs or generated HTML. Posts, reposts, likes, bookmarks, and chats remain inspectable offline even after their source becomes unavailable; live Bluesky links are optional enhancements rather than dependencies.
3 changes: 3 additions & 0 deletions docs/adr/0007-save-complete-media-for-selected-records.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Save complete media for selected records

When a Bluesky record is selected for saving, Cyd downloads every media asset needed to reproduce it offline, including full video. This applies consistently to the user's posts and to other enabled categories such as likes; users control storage through category selection rather than receiving an incomplete backup whose videos can disappear with the live Bluesky source.
3 changes: 3 additions & 0 deletions docs/adr/0008-own-the-archive-contract-in-cyd.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Own the shared archive contract in cyd

The normative Cyd archive specification, format-version history, and canonical compatibility fixtures live in the `cyd` repository. Mobile and desktop may maintain implementation-specific types, but both must validate against this shared contract so compatibility is not inferred from either application's current runtime schema.
3 changes: 3 additions & 0 deletions docs/adr/0009-bound-context-preservation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Bound contextual data preservation

A saved Bluesky record includes snapshots of the directly referenced data needed to render it faithfully, including its author, reply parent, quoted record, external embed, facets, and media. Cyd does not recursively crawl entire threads or social graphs; related records that are independently saved are linked through stable AT URIs, keeping backups complete for selected records without unbounded expansion.
3 changes: 3 additions & 0 deletions docs/adr/0010-make-each-archive-self-contained.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Make each Cyd archive self-contained

Every Cyd archive is a complete snapshot of the local account's saved data and media at export time rather than an incremental delta that depends on earlier archives. Individual archives may be larger, but any one of them remains sufficient for recovery or cross-device transfer and can be merged idempotently on import.
3 changes: 3 additions & 0 deletions docs/adr/0011-ship-v2-archives-without-encryption.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Ship version 2 archives without encryption

Version 2 Cyd archives are plaintext ZIP packages while the initial cross-platform contract is established. Passphrase encryption is deferred to a later format version; clients must not imply that version 2 archives protect sensitive saved data such as chats, and exports should communicate that limitation clearly.
3 changes: 3 additions & 0 deletions docs/adr/0012-validate-v2-archive-integrity-before-import.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Validate version 2 archive integrity before import

Version 2 archives include a manifest listing every payload file's path, byte size, and SHA-256 digest, and export captures a point-in-time-consistent database and media snapshot. Import validates the complete manifest before mutating local data and applies the merge transactionally, preventing corrupt or partial packages from producing partially imported accounts.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Export recoverable incomplete backups honestly

Cyd may export a valid archive when the local saved dataset already lacks expected assets, preserving everything recoverable rather than blocking export indefinitely. The interchange database records expected assets and their availability, export reports incompleteness, import retains those statuses, and browsing renders unavailable media explicitly; only archives containing every expected asset may be described as complete backups.
3 changes: 3 additions & 0 deletions docs/adr/0014-use-local-reminders-for-desktop-scheduling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Use local reminders for desktop scheduling

Desktop Bluesky scheduling is reminder-driven: Cyd uses local operating-system notifications to prompt the user to review and start due work, without server push notifications or unattended deletion. Desktop notifications are a future capability tracked separately, so initial Bluesky support must not imply that scheduled actions run automatically while Cyd is closed.
3 changes: 3 additions & 0 deletions docs/adr/0015-share-contracts-not-runtime-code.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Share contracts rather than a runtime package

The first desktop Bluesky implementation does not introduce a runtime package shared with Cyd Mobile. Desktop ports platform-neutral behavior behind desktop-native interfaces, while the applications share the normative archive specification, canonical fixtures, and behavioral contract tests; this preserves semantic parity without coupling their runtimes and release cadence.
3 changes: 3 additions & 0 deletions docs/adr/0016-replace-the-unused-desktop-bluesky-model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Replace the unused desktop Bluesky model

The dormant desktop `blueskyAccount` model is unused and is not a compatibility surface, so the new Bluesky implementation starts from a clean domain and persistence model rather than preserving its settings shape. A forward migration removes obsolete tables, links, and unreachable rows while retaining historical migration history; no adapter is required for the abandoned desktop model.
3 changes: 3 additions & 0 deletions docs/adr/0017-key-desktop-account-storage-by-uuid.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Key desktop Bluesky storage by local UUID

Each desktop Bluesky local account owns a private runtime database and media directory keyed by its Cyd UUID, with the Bluesky DID stored as the durable social identity and the mutable handle kept as account data. Handle changes therefore require no filesystem move, and each account remains an isolated unit for browsing and archive translation.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Use OAuth and OS-protected credential storage

Desktop connects to Bluesky through OAuth rather than app passwords and stores session material outside the account database and media directory through Cyd's desktop-wide credential facility. That facility uses OS-protected storage on macOS and Windows and prefers libsecret or KWallet on Linux; when neither Linux backend is available, it may use Electron/Chromium's `basic_text` fallback only with clear disclosure. Disconnecting deletes the local connection while retaining saved data; deleting the local account removes both its connection and local data, and archive creation never traverses credential storage. Building and remediating the shared credential facility is tracked separately in issue #671 rather than as part of desktop Bluesky platform support.
3 changes: 3 additions & 0 deletions docs/adr/0019-store-the-latest-observed-record.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Store the latest observed record

Version 2 represents the latest observation of each Bluesky record at its stable AT URI, including observation timestamps and deletion state, rather than retaining every historical CID revision. Import selects the newer observation and does not replace populated fields with absent data; complete revision history is outside the initial parity scope.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Do not use the archive filename for validation

Version 2 archive filenames are friendly suggestions and may be changed by users without affecting import. Clients determine identity, format support, and integrity from validated internal metadata, schema, and manifest content rather than a handle-bearing filename; the unused unversioned mobile prototype receives no filename-based compatibility exception.
3 changes: 3 additions & 0 deletions docs/adr/0021-use-at-protocol-apis-directly.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Use AT Protocol APIs directly

Desktop Bluesky saving and deletion use authenticated AT Protocol APIs, matching Cyd Mobile's integration model. Browser or OAuth-window interaction is limited to authorization; Bluesky webview scraping, request interception, and MITM automation are outside the implementation boundary because they add X-specific fragility where supported APIs exist.
3 changes: 3 additions & 0 deletions docs/adr/0022-run-save-and-delete-as-durable-jobs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Run save and delete as durable resumable jobs

Desktop Bluesky save and delete operations are durable, resumable, and idempotent. They commit progress incrementally, expose rate-limit backoff, and recover after restart without silently duplicating work; destructive jobs require explicit review and confirmation before their first execution, while safe retries of that confirmed job do not require per-item confirmation.
3 changes: 3 additions & 0 deletions docs/adr/0023-stage-and-resume-archive-jobs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Stage and resume archive jobs

Import and export are checkpointed, resumable jobs capable of continuing validation, hashing, media copying, and merge preparation after interruption. Import staging remains isolated from the live local account until final commit; cancellation or unrecoverable failure leaves existing account data untouched and safely removes staged artifacts.
3 changes: 3 additions & 0 deletions docs/adr/0024-deduplicate-media-within-each-account.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Deduplicate media within each local account

Desktop stores media content-addressably within each UUID-keyed local account, and saved records reference those assets rather than owning duplicate files. Version 2 archives likewise package each unique asset once and map record references through the interchange database; cross-account deduplication is deferred so deleting or exporting one account does not depend on another account's storage.
3 changes: 3 additions & 0 deletions docs/adr/0025-never-treat-save-settings-as-retention-rules.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Never treat save settings as retention rules

Disabling a save category affects future collection but never deletes previously saved records or media. Source deletion retains the local backup, while local deletion requires a separate explicit action with a preview; media garbage collection removes only unreferenced assets created by that explicit local deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Export portable account data, not operational state

Version 2 archives include account identity and captured profile, saved records and media, source-deletion state, asset-completeness state, and portable save/delete rule defaults. They exclude credentials, schedules, pending or historical jobs, logs, analytics, error reports, temporary files, caches, and UI state because those are client-local operations whose transfer could duplicate work or trigger unintended behavior.
3 changes: 3 additions & 0 deletions docs/adr/0027-preserve-captured-author-context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Preserve captured author context

The local Bluesky account profile advances to the latest observed profile for its DID, while each saved record and context snapshot retains the author representation captured with that observation. Browsing may link a captured author DID to its current profile, but handle or display-name changes do not rewrite historical snapshots.
3 changes: 3 additions & 0 deletions docs/adr/0028-roll-out-archive-readers-before-writers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Roll out archive readers before writers

Archive format changes ship readers before writers: Mobile and Desktop first gain and verify version 2 import, and version 2 export is enabled only after compatible readers are released. Version 2 is the first supported archive format; neither client imports or exports the unused unversioned mobile prototype.
3 changes: 3 additions & 0 deletions docs/adr/0029-minimize-bluesky-diagnostics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Minimize Bluesky diagnostics

Automatic Bluesky telemetry and error reports contain only operational metadata such as job type, stage, counts, error class, and application or archive-format version. They exclude record and chat content, media, handles, DIDs, credentials, and local paths; any diagnostic bundle containing user data requires an explicit preview and consent before submission.
3 changes: 3 additions & 0 deletions docs/adr/0030-encrypt-credentials-not-saved-content.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Encrypt credentials, not saved content

The initial desktop Bluesky release does not add application-level encryption for runtime databases, chats, or media; saved content relies on operating-system account permissions and disk encryption, and Cyd must not create broader file permissions. OAuth credentials remain the exception and require protected persistence as defined separately, because they authorize account control rather than merely exposing a local backup.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Gate releases on semantic archive contract tests

Bluesky releases must pass canonical compatibility tests for bidirectional version 2 exchange, repeated and mixed-device merges, offline full-video playback, all record categories and direct context, integrity and adversarial failures, supported and unsupported version handling, DID/UUID collisions, and settings differences. The unused unversioned mobile prototype is outside the compatibility matrix. Tests compare normalized records, relationships, asset digests, completeness, and source-deletion state rather than byte-identical ZIP or SQLite layouts.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Stream and defensively validate archive imports

Archive import streams into an isolated staging root and rejects path traversal, symlinks, unexpected file types, forged manifest entries, and unsafe entry counts or metadata. It verifies declared sizes and digests while writing and monitors total expansion against available storage; large legitimate video archives have no small absolute size cap, but crossing conservative resource thresholds requires explicit confirmation.
6 changes: 6 additions & 0 deletions docs/agents/issue-tracker.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ Issues and PRDs for this repo live as GitHub issues. Use the `gh` CLI for all op

## Conventions

Every issue, pull request, or comment written by an agent must end with this exact authorship disclosure:

```md
_(This was written by an LLM.)_
```

- **Create an issue**: `gh issue create --title "..." --body "..."`. Use a heredoc for multi-line bodies.
- **Read an issue**: `gh issue view <number> --comments`, filtering comments by `jq` and also fetching labels.
- **List issues**: `gh issue list --state open --json number,title,body,labels,comments --jq '[.[] | {number, title, body, labels: [.labels[].name], comments: [.comments[].body]}]'` with appropriate filters.
Expand Down
Loading