15 KiB
TODO
- investigate https://automerge.org/docs/tutorial/local-sync/
Features
- implement general way to fetch Documents (esp. PDFs) from URLs
Display content size in documents view
- Description:
BlobRefwill gain asize_bytes: u64field and a newArtifactReftype will carry asize_bytesfield, both as part of the document sync protocol (seedocs/document-sync.md). Once those fields exist, surface the total content size per document in both the document list (as a compact e.g. "4.2 MB") and the document detail screen. - Details: Add
total_blob_bytesandtotal_artifact_bytesaggregates to theDocumentStorequery; expose them throughDocumentDisplayin the GUI and AndroidDocumentDisplayModel. Show "—" or hide the field for documents with no blobs or artifacts. - fix issue in GUI with document import happening on main ui thread
- Pins: a generic cross-agent piece of functionality for marking a Document as something to go through next ( could be implemented with Edges)
Type Generation & FFI
-
Fix tls in kotlin - see https://github.com/rustls/rustls-platform-verifier/pull/193 which is probably a necessary prereq
-
in NativeLib.kt, use sub-objects rather than namespacing by string name of function
Android/Kotlin Improvements
Add node name editing to Android UI
- Description: The desktop GUI and CLI now support changing the node's human-readable name
(stored in
Settings::node_name) and broadcasting the change via gossip. The Android app needs a matching settings screen. - Details: Add a text field in the Android settings UI that reads/writes
node_namevia the existingSettingsStoreFFI. When saved, trigger a gossip re-announce so peers learn the new name. The Rust-sideP2PNode::update_node_namemethod already handles this.
Fix UUID Serialization Inconsistency
- Description: Current Kotlin code expects UUID as
List<Int>but Rust serializes with compact format - Details: Align UUID serialization between Rust and Kotlin, potentially using string representation for consistency
Audit Android color scheme usage
- Description: Review all color usages across the Android UI and ensure they are consistent and aesthetically coherent
- Details: Audit every hardcoded color and every
MaterialTheme.colorScheme.*token used in Compose screens; verify that semantic tokens (primary, secondary, surface, error, etc.) are applied to the right purposes and that the overall palette looks good together
Improve Error Handling in NativeLib
- Description: Currently some exceptions are caught but not re-thrown in
NativeLib.initialize() - Details: Decide on proper error handling strategy for native library initialization failures
Use Result<T> return types in NativeLib for all fallible FFI calls
-
Description: Every
#[uniffi::export]Rust function that returnsResult<T, SyncError>generates a Kotlin function annotated@Throws(SyncException::class). Kotlin does not enforce checked exceptions at the language level, so callers silently forget to handle errors and the app crashes at runtime. -
Details: Change every
NativeLibwrapper method that calls a fallible uniffi function to returnResult<T>viarunCatching { uniffi.synchronicity.foo(...) }. Callers then use.getOrNull(),.fold(onSuccess, onFailure),.onFailure { log }, etc. The return-type change causes a compile error at every affected call site, so the migration is compiler-guided. Methods whereSyncException.NotFoundmeans "does not exist" (rather than a bug) should return a nullable type directly (T?) rather thanResult<T>, so callers get idiomatic null-safety instead of error handling. -
Use the DocumentList component consistently any time another component needs a picker; in particular the podcast view should use this.
Key Management & Identity
Consider SLIP-0039 instead of BIP39
Consider a human-input secret derivation path using Argon2id
- Description: Node and ensemble key derivation now uses HKDF-SHA256, which is
correct because the inputs are already high-entropy (128-bit random seeds or validated
diceware material). The
argon2crate is still a dependency in case we want a separate mechanism for deriving high-entropy keys from genuinely low-entropy human-chosen inputs — e.g. an encryption passphrase for at-rest node secrets, or a user-chosen PIN guarding access to a delegation cert. - Details: Argon2id is the right primitive for that job (memory-hard, tunable
cost, designed exactly for password stretching). If/when such a path is needed, design
it as a separate module rather than re-introducing it to
Secret::to_keypair. Pick parameters appropriate for mobile (where the CPU/memory cost matters most) and store a per-secret random salt with the ciphertext.
Design a robust manifold key rotation scheme
- Description: The current design has no mechanism for rotating the manifold (master) keypair if it is compromised. This is a known deliberate omission for the bootstrap phase.
- Details: Evaluate options including:
- PKI / chain-of-trust anchor that vouches for the new key
- Social recovery via threshold signatures across trusted nodes (e.g. M-of-N)
- Timestamped revocation records published to the DHT under the old key
- Whether
iroh's existing infrastructure provides any useful primitives here
- See
docs/KEY_MANAGEMENT.mdfor full context on the current design. - this also needs to apply to the PkarrKeypair
Testing
Integration test: cold-start-after-total-outage bootstrap
- Description: Write an integration test that exercises the scenario where all nodes go offline long enough for the DHT entry to expire, then come back online one by one.
- Details:
- Will need a fake/mock DHT whose state can be controlled from the test harness (e.g. inject entries, clear entries, simulate expiry)
- Verify: first node back online detects no DHT record and publishes its own
- Verify: second node discovers first via DHT, both join gossip, node IDs propagate
- Verify: subsequent nodes bootstrap successfully via gossip without needing DHT
- See
docs/BOOTSTRAPPING.mdfor the full design
Core Functionality
Implement Preliminary P2P System using Iroh
- Description: Add proof-of-concept peer-to-peer networking for decentralized document synchronization
- Details:
- Add
irohdependencies torust/lib/Cargo.toml - Implement basic iroh node setup and endpoint creation
- Create FFI bindings to expose p2p functionality to Android
- Add device discovery and connection capabilities
- Implement document sync using
iroh-blobsfor artifacts andiroh-docsfor metadata - Add basic UI for device pairing and connection status
- Test synchronization of documents between two devices on local network
- Add
- Benefits: Foundation for true decentralized document exchange, eliminates need for central server, enables offline-first synchronization
- consider some key management ideas inspired by FOKS the Federated Open Key Service https://foks.pub/#roadmap
Set up Rich Podcast episode experience
- create a rust data structure that can represent transcript, sections, etc.
- and also display them in the UI
- Linux Unplugged is a good model to use for a podcast that supports these
Add Podcast Episode Management
- Description: Currently only podcast subscription is implemented
- Details: Add functionality to manage individual podcast episodes, including download, playback position tracking
- make sure that you can handle podcasts (e.g. Linux Unplugged) that have chapter metadata
Implement Document Search
- Description: Add search functionality across all document types
- Details: Extend
DocumentStorewith full-text search capabilities
Reliability
- the app needs to not have unclear user-facing errors under conditions of network unreliability or deliberately cutting off the network
- there should be tests for this
Agent Display
Make agent sidebar order user-configurable
- Description: Currently activity agents are sorted alphabetically at the top of the sidebar and control agents alphabetically at the bottom. The order should eventually be configurable by the user.
- Details: Allow users to drag-reorder agents within each group, or provide a settings UI to reorder them. The ordering preference should be persisted per-node and synced across nodes.
UX / CLI
Show authoritative document type strings in CLI help
- Description: The
--filterflag ondocs listcurrently has a hand-written list of type names in its help text. This will drift as newDocumentTypevariants are added. - Details:
DocumentTypealready derives strum'sIntoStaticStrandEnumStringwithserialize_all = "snake_case", so the canonical string for each variant is already machine-readable viastrum::IntoEnumIterator(needs theEnumIterderive added)- Generate the accepted values string at runtime (e.g. in a
lazy_staticorOnceLock) fromDocumentType::iter().map(|t| t.type_name())and inject it into the bpaf help string via a custom parser or ahelp()override - This ensures the help text is always an exact and complete reflection of what the parser will accept, with no manual maintenance required
CLI/daemon protocol versioning
- Description: The CLI has no way to detect that the running daemon was compiled from an older version of the code, leading to opaque "failed to parse daemon response" errors when the protocol changes.
- Details:
- Add a protocol version constant (e.g.
DAEMON_PROTOCOL_VERSION: u32) tosyn-daemon - Expose it via a
GET /versionendpoint (no auth needed, no command dispatch) - On startup,
ensure_daemon_running(or a newcheck_daemon_versionhelper incli-app/src/client.rs) queries/versionand compares against the compiled-in constant - If the versions differ, automatically stop the stale daemon and start a fresh one before proceeding with the command
- The version should be bumped whenever a breaking change is made to
DaemonCommandorCommandResponse; a CI lint or build script could enforce this
- Add a protocol version constant (e.g.
Unified "waiting on network" indicator
- Description: Any time the CLI blocks on a network operation it should show a
consistent spinner so the user knows the process is alive and waiting, not stuck.
The current
spinner::with_spinnerin the CLI covers the pkarr publish and member fetch calls; the pattern should be applied everywhere a blocking network call occurs. - Details:
- P2P ping dispatched via daemon (
syn p2p ping) — the daemon round-trip itself is fast, but the underlying iroh connection attempt can take several seconds - Any future
syn syncor document-fetch commands - Consider whether Android needs an analogous loading indicator in Compose (e.g. a
CircularProgressIndicatorwhilefetchEnsembleMembersorstartP2PNodeare in flight) - The spinner style is defined in
cli-app/src/spinner.rs; keep all call sites consistent with that helper rather than writing ad-hoc prints
- P2P ping dispatched via daemon (
Build & Development
Improve Build Process
- Description: Streamline the build process between Rust library and Android app
- Details: Consider using cargo-ndk or similar tools for better Android build integration
- find a way to make sure typeshare is installed before attempting a build
- investigate https://github.com/mozilla/uniffi-rs and see if there's any way to use this to make the build process better
Make relay/DNS infrastructure configurable and self-hostable
- Currently the P2P layer relies entirely on n0's public infrastructure:
- Relay servers:
*.relay.n0.iroh-canary.iroh.linkfor NAT traversal - pkarr DNS:
dns.iroh.linkfor publishing/resolving node addresses by public key
- Relay servers:
- Both are open source (
iroh-relay,iroh-dns-server) and designed to be self-hosted - Options to investigate:
- Allow configuring custom relay URLs and DNS server in
Settings - Ship a bundled
iroh-relaymode so a node can optionally act as a relay for others - Investigate the Mainline DHT path (
DhtAddressLookup) as a fully decentralized fallback that requires no trusted server at all. The Mainline DHT is the BitTorrent DHT — ~20M nodes, running continuously since ~2005, maintained "for free" by the existence of BitTorrent. BEP 44 (a BitTorrent extension from ~2014) added support for storing arbitrary signed data in it, not just torrent hashes. pkarr builds on BEP 44: you sign a packet of DNS-like resource records (IP addresses, relay URLs) with your Ed25519 secret key and publish them indexed by your public key. The records are self-authenticating — DHT nodes can't forge them without your key. iroh'sPkarrPublishercurrently usesdns.iroh.linkas an HTTP relay to the DHT (convenient but centralized);DhtAddressLookupparticipates in the DHT directly with no intermediary. - Consider mDNS (
address_lookup::mdns) for local-network discovery with no infrastructure dependency
- Allow configuring custom relay URLs and DNS server in
Explore alternatives to JSON for daemon protocol
- Current JSON over Unix socket is human-readable and easy to debug, but has overhead
- Consider MessagePack or CBOR for compact binary encoding with the same serde support
- Consider a typed IDL (Cap'n Proto, Flatbuffers) for schema evolution and zero-copy reads
- Postcard is a good no-std-friendly option if Android nodes ever speak directly to the daemon
Add Documentation
- Description: Add comprehensive documentation for the FFI layer and type sharing
- Details: Document the interface between Rust and Kotlin, especially around serialization formats
Code Editing & Version Control
Implement Code Editing Features
- Description: Add support for code editing and version control integration
- Details:
- Integrate with Radicle DVCS for decentralized version control
- Add support for both Git and Jujutsu VCS
- Implement code editing capabilities with syntax highlighting
- Add diff viewing and conflict resolution tools
- Support for collaborative editing features
Functionality to add
- bulk storage backend using s3
Other Agents to Implement
comic/manga readermusicpomodoro timer- something like https://github.com/RackulaLives/Rackula/
Notes Functionality
- the notes app should start up immediately
- consider something like * look at https://github.com/gpanakkal/incremental-reading-obsidian
- consider https://github.com/pop-os/cosmic-text for note editing
Music Functionality
- see ideas in https://unformeddelta.wiki/ihe0bEPXK5ip/metadata-patterns-not-accounted-for-by-music-apps
- also see ideas for UI from Empeg, from Cathode Ray Dude video (e.g. waveform visualization seek tool)
Done
### Switch to cargo-nextest for Rust tests
- Install
cargo-nextestand update thejustrecipes and CLAUDE.md to usecargo nextest runinstead ofcargo test - nextest offers better output, parallel execution, and per-test timeouts
Audit manual FromStr implementations for strum replacement
- Description: The
HashAlgorithmenum was initially written with a manualFromStrimpl that was trivially replaced by strum'sEnumStringderive. There may be other enums in the codebase with similar unnecessary manual implementations. - Details: Search for
impl FromStr foracross the Rust code and evaluate whether each can be replaced with#[derive(EnumString)](andDisplaywhere applicable).