
Feedback and requests
Hi! I'm Itai, and I work on [pdd-kit](https://github.com/itai-gendler/pdd-kit), an open-source tool for keeping a product model next to the code. I've mapped TypeRelay's behavior into one. Before opening any pull request, I'd like your opinion: would a model like this be useful to TypeRelay's maintainers and contributors? It's on a branch of my fork, so nothing here changes unless you want it to. **pdd-kit is fully open source (MIT).** The format, the CLI, the agent skills and the report are all in [github.com/itai-gendler/pdd-kit](https://github.com/itai-gendler/pdd-kit). ## Open the model's report The model is on the [`product-model` branch of my fork](https://github.com/itai-gendler/typerelay/tree/product-model/product-model). One command opens its report in your browser; it runs locally: ```sh npx pdd-toolkit view itai-gendler/typerelay --branch product-model ``` ## Why a Product Model The definition of your product already exists, just unstructured, incomplete and scattered across docs, code, tickets, chats and people. Every coding agent reconstructs it from scratch, and differently each time. PDD gives agents and humans a shared product model that is git-tracked, reviewable, and verifiable. ([The problem, in full](https://github.com/itai-gendler/pdd-kit#the-problem)) <a href="https://github.com/itai-gendler/pdd-kit#why-a-product-model-in-the-ai-era"><img alt="Today, every stage of plan, code, review, deploy and operate reconstructs intent from tickets, PRDs, docs, tests, code, chats and people. With Product-Driven Development, those sources feed one defined, versioned, agreed product model, and every stage reads from it, with human approval at plan and review." src="https://raw.githubusercontent.com/itai-gendler/pdd-kit/main/.github/readme/today-and-pdd.webp" width="100%"></a> ## What it would add `product-model/`, a [Product Model](https://pdd-kit.dev/docs/product-model) of TypeRelay: one definition of what the product does, as plain Markdown next to the code. It is made of: - **[Entities](https://pdd-kit.dev/docs/entities) (27):** what the product keeps, and who acts on it (Library, Text snippet, Conflict). - **[Interfaces](https://pdd-kit.dev/docs/interfaces) (8):** how people and systems reach the product (Desktop, Terminal editor, MCP). - **[Domains](https://pdd-kit.dev/docs/domains) (7):** the subject areas the product is split into (Libraries, Sync, Trash). - **[Capabilities](https://pdd-kit.dev/docs/capabilities) (77):** what the product lets someone do (Expand abbreviations, Sync libraries, Resolve conflict). - **[Journeys](https://pdd-kit.dev/docs/journeys) (3):** one goal, carried across several capabilities (Complete two-factor sign-in, Open a new local library, Save recovered mobile content). - **[Business Rules](https://pdd-kit.dev/docs/business-rules) (95):** what must always hold, and who may do what (Private libraries belong to their creator; Concurrent edits conflict by snippet identity; Trash retains content for thirty days). It would be only new files under `product-model/`; no code, build or CI changes. ## Where it fits The model doesn't replace TypeRelay's docs; it lets each of them focus. Today the product definition is spread across these sources, each holding a piece and none holding all of it: | Information source | Its purpose | In TypeRelay | | --- | --- | --- | | **Product Model** | **Defines what the product is** | **`product-model/` (proposed)** | | User docs | Teaches people to use the product | [README](https://github.com/typerelay/typerelay/blob/develop/README.md), [`docs/guide/`](https://github.com/typerelay/typerelay/tree/develop/docs/guide), [`docs/desktop/`](https://github.com/typerelay/typerelay/tree/develop/docs/desktop), [`docs/cli/`](https://github.com/typerelay/typerelay/tree/develop/docs/cli), [`docs/mcp/`](https://github.com/typerelay/typerelay/tree/develop/docs/mcp), [`docs/api/`](https://github.com/typerelay/typerelay/tree/develop/docs/api), [`docs/selfhosted/`](https://github.com/typerelay/typerelay/tree/develop/docs/selfhosted) | | Internal docs | Records architecture, design decisions, and onboarding | [CONTRIBUTING.md](https://github.com/typerelay/typerelay/blob/develop/.github/CONTRIBUTING.md), [AGENTS.md](https://github.com/typerelay/typerelay/blob/develop/AGENTS.md), [`docs/development/`](https://github.com/typerelay/typerelay/tree/develop/docs/development), [`docs/web/`](https://github.com/typerelay/typerelay/tree/develop/docs/web), [`docs/mobile/development.md`](https://github.com/typerelay/typerelay/blob/develop/docs/mobile/development.md), [`docs/extension/development.md`](https://github.com/typerelay/typerelay/blob/develop/docs/extension/development.md) | | Design & architecture | Describes how it should look and work | [`docs/development/panel-architecture.md`](https://github.com/typerelay/typerelay/blob/develop/docs/development/panel-architecture.md) and [`docs/development/templates.md`](https://github.com/typerelay/typerelay/blob/develop/docs/development/templates.md); none in the repository beyond them | | Code & tests | Implements and verifies how it is built | [`apps/server/`](https://github.com/typerelay/typerelay/tree/develop/apps/server) (Express web app and API), [`crates/`](https://github.com/typerelay/typerelay/tree/develop/crates) (Rust core, client and mobile), [`apps/desktop/`](https://github.com/typerelay/typerelay/tree/develop/apps/desktop) (Tauri), [`apps/mobile/`](https://github.com/typerelay/typerelay/tree/develop/apps/mobile), [`apps/extension/`](https://github.com/typerelay/typerelay/tree/develop/apps/extension), [`apps/mcp/`](https://github.com/typerelay/typerelay/tree/develop/apps/mcp), with tests run through Docker Compose | | Tickets, chats & people | Carry context, requests, and undocumented knowledge | [GitHub issues](https://github.com/typerelay/typerelay/issues) | Some of the product isn't written down anywhere. Mapping TypeRelay found product facts that only the code settles. These are just two examples, the most important ones: - **A queued edit whose content already matches the server is not a conflict.** The sync guide says that when the same snippet changed from an older base on two devices, the server keeps the local, base and server versions as a conflict ([`docs/guide/sync.md`](https://github.com/typerelay/typerelay/blob/72c6ab9dc7c31c112eb20bd21dfcbba1bef247d4/docs/guide/sync.md#L63)). In the code, an upload equal to the active server snippet is accepted as already applied, and so is deleting a snippet that is already in Trash; only after those checks does an older base become a conflict ([`Libraries.same`](https://github.com/typerelay/typerelay/blob/72c6ab9dc7c31c112eb20bd21dfcbba1bef247d4/apps/server/services/libraries.js#L413), [`Libraries.upload`](https://github.com/typerelay/typerelay/blob/72c6ab9dc7c31c112eb20bd21dfcbba1bef247d4/apps/server/services/libraries.js#L432-L434)). - **Copying a snippet with an Enter action depends on the client.** The templates guide says Copy and **Fill and copy** report the omitted Enter actions ([`docs/guide/templates.md`](https://github.com/typerelay/typerelay/blob/72c6ab9dc7c31c112eb20bd21dfcbba1bef247d4/docs/guide/templates.md#L45)). The web app, desktop panel and TUI do that. The browser extension and the mobile app refuse to copy and leave the clipboard unchanged ([`popup.js`](https://github.com/typerelay/typerelay/blob/72c6ab9dc7c31c112eb20bd21dfcbba1bef247d4/apps/extension/popup.js#L33), [`main.ts`](https://github.com/typerelay/typerelay/blob/72c6ab9dc7c31c112eb20bd21dfcbba1bef247d4/apps/mobile/src/main.ts#L273)). Only the mobile development notes mention the mobile app's behavior. A contributor needs these, and a user mostly doesn't. Putting them in the user docs turns the docs into a spec; the model gives them their own home, so the docs can stay about teaching. If something isn't in the model, nobody decided it. ## Questions you may have Short answers here; the full ones are in the [PDD FAQ](https://pdd-kit.dev/faq). **We already have docs and an AGENTS.md. Why add this?** They help, and they stay. But user docs hold the part a user needs, and internal docs and AGENTS.md are free-form, each mixing product decisions with design and implementation. The rest lives only in the code, and every agent reconstructs it from scratch, differently each time, with nobody reviewing what it concluded. The model is one structured definition that agents and people read the same way. ([Docs](https://github.com/itai-gendler/pdd-kit/blob/main/docs/faq.md#i-already-have-documentation-why-do-i-need-a-product-model), [AGENTS.md](https://github.com/itai-gendler/pdd-kit/blob/main/docs/faq.md#i-already-have-agentsmd-and-docs-isnt-that-enough)) **Does every contributor need an AI agent?** No. Contributors who don't use agents work exactly as they do today, and updating the model is the same kind of work as updating docs or tests when behavior changes. Those who use an agent can have it done for them: `/pdd-verify` checks the code against the model, reports every gap, and fixes the ones they choose. ([More](https://github.com/itai-gendler/pdd-kit/blob/main/docs/faq.md#why-add-yet-another-tool-to-my-stack)) **Does it add work to every pull request?** Today a behavior change can touch the code, the user docs and the internal docs, each holding part of it in its own way, so they drift. With the model, each fact has one home. It doesn't have to block a pull request either: the model can be updated in the same one, or catch up after changes land. The code references in the model (the links from each file to the code behind it) are optional; if you'd rather not keep them, I'll remove them. ([More](https://github.com/itai-gendler/pdd-kit/blob/main/docs/faq.md#doesnt-keeping-the-model-current-add-work-to-every-pr)) **Does it change how we develop?** No. PDD doesn't touch how you implement: your workflow, coding agents and planning tools stay, and nothing new runs in CI. Asking an agent to implement something works as it always has. How much of it to use is up to you: only `map`, to keep a clear model after changes land, or the full [development loop](https://pdd-kit.dev/docs#the-development-loop), where `/pdd-ideate` records a change in the model first (nothing is written until you approve it), your agent implements it your way, and `/pdd-verify` checks the result when you ask it to. Letting pdd-kit orchestrate implementation, with verify planning the work in phases and checking each one, is [opt-in](https://github.com/itai-gendler/pdd-kit/blob/main/docs/skill-pdd-verify.md#implement-with-verify-opt-in) and off by default. ([More](https://github.com/itai-gendler/pdd-kit/blob/main/docs/faq.md#doesnt-this-lock-me-into-a-new-development-lifecycle)) **How is this different from spec-driven tools or AI-generated docs?** Spec-driven tools such as OpenSpec and spec-kit describe each change; PDD defines the product and leaves the change to whichever tool you use. AI-generated docs such as DeepWiki mix product rules, architecture and configuration; the model draws that boundary explicitly. ([SDD](https://github.com/itai-gendler/pdd-kit/blob/main/docs/faq.md#how-is-this-different-from-sdd), [DeepWiki](https://github.com/itai-gendler/pdd-kit/blob/main/docs/faq.md#how-is-this-different-from-deepwiki-or-ai-generated-docs)) **How would reviewers see a model change?** As a Git diff today, or as a report of any pull request's model with `npx pdd-toolkit view typerelay/typerelay --pr <n>`, without cloning. A visual diff in the report is in progress ([itai-gendler/pdd-kit#19](https://github.com/itai-gendler/pdd-kit/issues/19)). ([More](https://github.com/itai-gendler/pdd-kit/blob/main/docs/faq.md#how-do-reviewers-see-a-model-change)) ## Interesting questions about TypeRelay that the Product Model now answers The report opens on the model's Product Overview: what TypeRelay is, why it exists, and where it stops. Every answer below is read from the model. <img alt="TypeRelay's Product Overview: its description, intent, limitations and product details" src="https://raw.githubusercontent.com/itai-gendler/typerelay/dff121676d77c07febc9cc643036c01e641dbd15/screenshots/0-overview.png" width="100%"> To follow along in the report, the same command as above: ```sh npx pdd-toolkit view itai-gendler/typerelay --branch product-model ``` ### 1. Entities, and which capabilities change them All 27 entities in the TypeRelay model: what the product keeps, and who acts on it. <img alt="Entities list" src="https://raw.githubusercontent.com/itai-gendler/typerelay/dff121676d77c07febc9cc643036c01e641dbd15/screenshots/1a-entities-list.png" width="100%"> Which capabilities create, change or remove each entity, filtered to five sync and editing capabilities: - **Conflict** is created by Sync libraries and by Edit snippet, when a web save is based on an older version of the snippet, and only Resolve conflict changes it. - **Recovered edit** is created only by Sync libraries: when the server rejects a queued change, for example after the person lost access to its library, the device keeps the content instead of dropping it. - **Library** is changed by Enroll library and Disconnect device only in its sync status. Connecting a device uploads nothing, and disconnecting turns synchronized libraries back into local ones without deleting their snippets. <img alt="Changes: which capabilities create, change or remove each entity" src="https://raw.githubusercontent.com/itai-gendler/typerelay/dff121676d77c07febc9cc643036c01e641dbd15/screenshots/1b-entities-changes.png" width="100%"> ### 2. Capabilities, and which interfaces offer them All 77 capabilities in the TypeRelay model: what the product lets someone do. <img alt="Capabilities list" src="https://raw.githubusercontent.com/itai-gendler/typerelay/dff121676d77c07febc9cc643036c01e641dbd15/screenshots/2a-capabilities-list.png" width="100%"> Which interfaces offer each capability, filtered to the Trash domain: - **Desktop** and the **Browser extension** have no Trash at all. Trash is handled in the web app, the terminal editor, the command line, the mobile app and through the API and MCP. - **Mobile** restores and permanently deletes single items, but moves only snippets to Trash: it has no Trash library and no Empty Trash. - **MCP** offers every Trash capability except Expire Trash, which TypeRelay runs on its own after 30 days, on the server and on each device. <img alt="Delivery: which interfaces offer each capability" src="https://raw.githubusercontent.com/itai-gendler/typerelay/dff121676d77c07febc9cc643036c01e641dbd15/screenshots/2b-capabilities-delivery.png" width="100%"> ### 3. Business rules, and where they apply All 95 business rules in the TypeRelay model: what must always hold, and who may do what. <img alt="Business rules list" src="https://raw.githubusercontent.com/itai-gendler/typerelay/dff121676d77c07febc9cc643036c01e641dbd15/screenshots/3a-rules-list.png" width="100%"> Where each business rule is attached, filtered to the Conflict, Image and Invitation entities: - **Concurrent edits conflict by snippet identity:** changes to different snippets in one library merge on their own, and only the same snippet changed in two places becomes a conflict. - **Only current library editors see a library's conflicts**, create them and resolve them. An integration or agent needs the content-writing scope even to list them. - **Images arrive before changed content activates:** a device downloads every image a changed snippet uses before the new content replaces the old, and if a download fails it keeps the content it had. - **Every member, the Owner included, and every pending invitation takes a seat:** an invitation counts against the team's capacity from the moment it is sent until it is accepted, revoked or expires after seven days. <img alt="Attachments: where each business rule is attached" src="https://raw.githubusercontent.com/itai-gendler/typerelay/dff121676d77c07febc9cc643036c01e641dbd15/screenshots/3b-rules-attachments.png" width="100%"> ### 4. An entity: what it keeps, and how its state changes The Library entity, one of the 27, and the information kept about it: - **Shared** and **Assigned editing** decide who uses a library: the creator, and for a shared library the account's Owners and Admins, always manage it; assigned people and groups read it, and edit its snippets only while Assigned editing is on. - **Sync status** and **Device read**, **Device edit** and **Device manage** are kept per device: whether the library is local only, queued for upload or synchronized there, and what that device may do with it as of the last sync. <img alt="Library: the information kept about it" src="https://raw.githubusercontent.com/itai-gendler/typerelay/dff121676d77c07febc9cc643036c01e641dbd15/screenshots/4a-library-overview.png" width="100%"> How it moves through its states, and the capability behind every move: - **Private** is where every library starts: one created in the web app, the terminal editor or through the API and MCP, an imported one, and the starter library a new account gets. - **Shared** is reached only by Share library, and Stop sharing library returns it to Private. Enrolling a library for sync never shares it. - **Trashed** is reached by Trash library and by Merge libraries, which moves the source to Trash once its snippets are in the destination. Restore library returns a library to the state it had, and Empty Trash, Permanently delete library or Expire Trash after 30 days makes it Purged. <img alt="Library: its lifecycle" src="https://raw.githubusercontent.com/itai-gendler/typerelay/dff121676d77c07febc9cc643036c01e641dbd15/screenshots/4b-library-lifecycle.png" width="100%"> ### 5. A capability's scenarios, and one step by step The 6 scenarios of the Sync libraries capability: - **Six scenarios:** a sync the person starts, a background sync every 30 seconds and two seconds after a local edit, a snippet changed in two places, a queued edit whose content already matches the server, a sync while the server can't be reached, and a sync after the person's library access changed. <img alt="Sync libraries: its scenarios" src="https://raw.githubusercontent.com/itai-gendler/typerelay/dff121676d77c07febc9cc643036c01e641dbd15/screenshots/5a-sync-libraries-scenarios.png" width="100%"> One of them, opened step by step: - **Apply changed library access starts on the team's side:** someone who manages a library changes its sharing or assignments, and the person's next sync on desktop, terminal or mobile picks it up. - **The sync updates what the device may read and edit, and removes libraries the person can no longer use** from search and expansion. Their pending edits to those libraries become recovered edits, which the mobile app can reopen as a new draft in a library the person can still edit. <img alt="Apply changed library access: its steps" src="https://raw.githubusercontent.com/itai-gendler/typerelay/dff121676d77c07febc9cc643036c01e641dbd15/screenshots/5b-apply-changed-library-access.png" width="100%"> ## What I'm asking - **Is this useful for TypeRelay?** A yes, a no, or "not yet" all help. - **If it is, I'll open a focused pull request** shaped however you prefer: smaller, split by area, or without the code references. - **If it isn't,** feel free to close this issue. ## How it was made The model was mapped from `develop` with AI agents, and I reviewed it personally. I'll answer questions myself, and I'm happy to take any feedback needed for adoption. **AI assistance:** the model was drafted with Claude Code and Codex, using the `pdd-map` skill. I reviewed it, linted it with `npx pdd-toolkit lint`, and checked each finding above against the code. This issue was drafted with Claude's help and edited by me.
Title says it all, but use Typerelay in ChatGPT and Codex directly
- local only - clear text boundaries - excluding app settings - disabled by default - separate database - no cloud sync
Linux AppImage, deb and rpm currently contain only the desktop panel, while the advertised Omarchy installer installs the engine and TUI separately. Make all three complete desktop packages and retire the separate public installer. Acceptance criteria: - Every package includes the expansion engine, TUI, search panel, tray/menu, sync, settings and update checking. - First launch offers existing user-service/keyboard setup; upgrades refresh the bundled engine and TUI without losing snippets. - Updates use the installed package format; existing standalone installations retain a working update path. - Ghost and README list AppImage first, deb second, rpm third; remove installer instructions. - Verify backend/package tooling; native and frontend checks remain with the user. Related update UX: #8. Implementation complete and pushed: - TypeRelay: 349f4fd (develop) - Shared release tooling: Helpmonks/helpmonks-install-script@5138f58d (master) - Ghost: Helpmonks/ghost@8228b2c (develop) Validation: 24 installer tests, 16 desktop Rust tests, 8 engine CLI tests, 12 release-tooling tests, and 25 shared release/R2 tests passed. Built AppImage, deb and rpm and inspected each: matching engine, TUI, panel 1.2.6, setup CLI and package-specific updater marker present. Desktop Clippy passed with warnings denied; CLI Clippy retains pre-existing warnings in database.rs, clipboard.rs and omarchy.rs. Local Ghost restarted; /apps/ returns HTTP 200 and correct download order inside the container. trw.lan has no DNS/local proxy on this host. Not yet published: signed release artifacts, production Ghost deployment, changelog draft. The internal legacy archive remains only to keep existing standalone installations updating. User verification before closing: - [ ] Install/launch each package; first-launch service/keyboard setup succeeds. - [ ] TUI, tray menu, search/expansion, sync and settings work. - [ ] Upgrade/restart preserves snippets and refreshes engine/TUI; confirm update flow after a signed release is published. - [ ] Verify Ghost desktop/mobile download buttons: AppImage, deb, rpm.
- expand - manage - new snippets
Comments