From 6c0ddd64dcbd5f8bcdcc429cbbe1e4b5b22bccd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C5=ABdolfs=20O=C5=A1i=C5=86=C5=A1?= Date: Wed, 21 Oct 2026 14:46:04 +0200 Subject: [PATCH] Split agent and contributor docs by project --- .claude/skills/radicle-ecosystem/SKILL.md | 53 ------- AGENTS.md | 100 ++++++++++++ CONTRIBUTING.md | 109 +++++++++++++ desktop/AGENTS.md | 42 +---- explorer/AGENTS.md | 179 +++------------------- explorer/CONTRIBUTING.md | 145 ------------------ explorer/README.md | 33 +++- explorer/crates/radicle-httpd/AGENTS.md | 2 +- explorer/tests/support/globalSetup.ts | 2 +- 9 files changed, 264 insertions(+), 401 deletions(-) delete mode 100644 .claude/skills/radicle-ecosystem/SKILL.md create mode 100644 AGENTS.md create mode 100644 CONTRIBUTING.md delete mode 100644 explorer/CONTRIBUTING.md diff --git a/.claude/skills/radicle-ecosystem/SKILL.md b/.claude/skills/radicle-ecosystem/SKILL.md deleted file mode 100644 index bf7ece58b..000000000 --- a/.claude/skills/radicle-ecosystem/SKILL.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -name: radicle-ecosystem -description: Map of the sibling Radicle repositories that radicle-httpd depends on (heartwood, radicle-git, radicle-job, rips, radicle.dev), with the key crates and files to read in each. Use when working on Rust code in radicle-httpd, when you need protocol or domain context, or when a type comes from a crate outside this repo. ---- - -# Radicle ecosystem (sibling repos) - -`radicle-httpd` depends on crates from sibling repositories. Read -source from these paths when working on Rust code. - -## heartwood (`../heartwood`) - -Core Radicle protocol implementation. Key crates used by httpd: -- `radicle` — standard library (storage, identity, COBs, git, node) -- `radicle-cob` — collaborative objects (issues, patches as CRDTs) -- `radicle-crypto` — Ed25519 signing, SSH key handling -- `radicle-core` — fundamental types (`RepoId`, etc.) - -Key files: -- `../heartwood/HACKING.md` — development guide, environment variables -- `../heartwood/ARCHITECTURE.md` — high-level architecture -- `../heartwood/crates/radicle/src/lib.rs` — main library entry point - -## radicle-git (`../radicle-git`) - -Git library wrappers. Key crate: -- `radicle-surf` — code browsing (files, diffs, commits, branches, - tags). This is what httpd uses to serve repository content. - -Key file: `../radicle-git/radicle-surf/src/lib.rs` - -## radicle-job (`../radicle-job`) - -Decentralized job execution (CI/CD) on the Radicle network. -Key file: `../radicle-job/README.md` - -## RIPs — protocol specs (`../rips`) - -- `../rips/0001-heartwood.md` — protocol overview -- `../rips/0002-identity.md` — identity system (DIDs, Ed25519) -- `../rips/0003-storage-layout.md` — git storage layout - -## Radicle documentation (`../radicle.dev`) - -Read these when you need domain context for UI work: -- `../radicle.dev/_guides/user.md` — end-to-end user workflows - (init, clone, seed, issues, patches, code review, private repos) -- `../radicle.dev/_guides/protocol.md` — protocol internals - (gossip, replication, identity documents, COB data model, trust) -- `../radicle.dev/_guides/seeder.md` — seed node operation - (seeding policies, httpd setup, DNS-SD) -- `../radicle.dev/_posts/2025-07-23-using-radicle-ci-for-development.md` — CI integration -- `../radicle.dev/_posts/2025-08-12-canonical-references.md` — canonical refs design diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..070b0d9a6 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,100 @@ +# radicle-gui + +Monorepo for Radicle's graphical interfaces. It holds two independent +projects, each with its own npm package, Cargo workspace, toolchain files, +checks and conventions: + +- **Explorer** (`explorer/`): the Svelte web app for browsing Radicle + repositories, its TypeScript HTTP client, and the `radicle-httpd` and + `radicle-search` backends it talks to. See `explorer/AGENTS.md`. +- **Desktop** (`desktop/`): the Tauri desktop app. See `desktop/AGENTS.md`. + +This file covers what applies to both. Each project's `AGENTS.md` is the +source of truth for anything inside it. + +## Layout + +| Path | What it is | +|---|---| +| `explorer/` | Web app, HTTP client, `radicle-httpd` and `radicle-search` | +| `desktop/` | Tauri app: Svelte frontend in `src/`, Rust in `crates/` | +| `docs/adr/` | Decisions that affect the whole repository | +| `.github/workflows/` | GitHub CI: `explorer-*.yml` for explorer, `desktop-*.yml` for desktop | +| `.buildkite/` | Radicle CI pipelines (explorer only) | +| `.ryph/` | Dev machine image and setup for agents, see `.ryph/environment.md` | + +## Working in this repo + +- Work out which project a change belongs to first, and run every command + from that project's directory. There are no root `npm` or `cargo` + commands. +- A change that touches both projects is two changes: check each project + with its own commands. +- Explorer's components use legacy Svelte syntax (`$:`, stores, + `export let`), desktop's use Svelte 5 runes. +- Record a bigger architectural change as a new ADR, numbered after the last + one and in the same format: in `docs/adr/` if it affects the whole + repository, in the project's own `docs/adr/` otherwise. +- Before opening a patch or tagging a release, read `CONTRIBUTING.md` for + patch labels and release tags. Never create or match the old + `releases/` tags; they predate the monorepo. + +## Shared conventions + +- Prefer `undefined` over `null` +- Do not add comments unless explicitly asked. When writing comments, + use proper English sentences +- Ask before adding new dependencies: each one is a supply-chain risk, and + installs are gated by `min-release-age` and `strict-allow-scripts` +- Use npm, never `yarn` or `pnpm`: the lockfiles and `.npmrc` settings are + npm's +- Run tests through the `npm run` scripts, not `npm test` (neither project + has one), `npx vitest` or `npx playwright test`: the scripts set `TZ=UTC` + and, in explorer, `NODE_CONFIG_ENV`, which the tests rely on +- Use ES private fields (`#field`), not the TypeScript `private` keyword + +### Svelte components + +- CSS: scoped styles with design tokens (`var(--color-text-primary)`, + `var(--txt-body-m-regular)`, `var(--border-radius-sm)`); use `:global()` + for styling slotted or `{@html}` content +- Loading states: `{#await promise}` blocks for inline async; + local `loading` boolean with `try/catch` for imperative fetches + +## Commit messages + +- Imperative mood: "Add feature" not "Added feature" +- Capitalize subject, no trailing period, about 50 chars +- Prefix commits that touch a single component with it: `explorer:`, + `httpd:` or `desktop:`, e.g. "desktop: Add release view". Commits that span + most of the repository have no prefix +- Each commit should be understandable, testable and revertable on its own + +## Radicle ecosystem (sibling repos) + +Both projects build on crates from sibling repositories, which may be +checked out next to this one. If present, read their source when a type +comes from outside this repo or you need protocol context: + +- `../heartwood`: the protocol. Crates `radicle`, `radicle-cob`, + `radicle-crypto` and `radicle-core`. Start with `HACKING.md` and + `ARCHITECTURE.md` +- `../radicle-git`: `radicle-surf`, the code browsing (files, diffs, commits) + that httpd and desktop serve +- `../radicle-job`: CI job COBs +- `../rips`: protocol specs: `0001-heartwood.md`, `0002-identity.md`, + `0003-storage-layout.md` +- `../radicle.dev`: user docs. `_guides/user.md` covers workflows, + `_guides/protocol.md` covers gossip, replication and the COB model, and + `_guides/seeder.md` covers seed nodes and httpd setup + +## Domain glossary + +- **RID** — Repository ID (`rad:z3gqc...`) +- **DID** — Decentralized Identifier, user identity (`did:key:z6Mk...`) +- **NID** — Node ID, the public key in a DID +- **COB** — Collaborative Object (issue, patch, or identity as a Git DAG) +- **Delegate** — authorized repo maintainer; signatures determine canonical state +- **Patch** — pull-request equivalent with immutable revisions and reviews +- **Seed** — hosting/replicating a repo; seed nodes are always-on servers +- **Canonical refs** — branches/tags resolved by delegate quorum diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..3fc419a9f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,109 @@ +# Contributing + +This repository holds two projects, each with its own development guide: +`explorer/README.md` and `desktop/README.md`. This file covers what +applies to both. + +* Before adding any code dependencies, check with the maintainers if this is okay. +* Write properly formatted comments: they should be english sentences, eg: + + // Return the current UNIX time. + +* Follow the guidelines when proposing code changes (see below). +* Write properly formatted git commits (see below). + +## Proposing changes + +When proposing changes via a patch: + +* Isolate changes in separate commits to make the review process easier. +* Don't make unrelated changes, unless it happens to be an obvious improvement to + code you are touching anyway ("boyscout rule"). +* Rebase on `master` when needed. +* Keep your changesets small, specific and uncontroversial, so that they can be + merged more quickly. +* If the change is substantial or requires re-architecting certain parts of the + codebase, write an ADR first, in `docs/adr/` if it affects the whole + repository or in the project's own `docs/adr/` otherwise, and get consensus + on that before proposing the code changes. + +## Writing Git commit messages + +A properly formed git commit subject line should always be able to complete the +following sentence: + + If applied, this commit will _____ + +For example, the following message is well formed: + + Add support for .gif files + +In addition, it should be capitalized and *must not* include a period. Prefix +commits that touch a single component with it: `explorer:` for the web app, +`httpd:` for `radicle-httpd` and `radicle-search`, and `desktop:` for the +desktop app. Commits that span most of the repository have no prefix. Either +way, each commit should be understandable, testable and revertable as one +coherent change. + +When it comes to formatting, here's a model git commit message[1]: + + Capitalized, short (50 chars or less) summary + + More detailed explanatory text, if necessary. Wrap it to about 72 + characters or so. In some contexts, the first line is treated as the + subject of an email and the rest of the text as the body. The blank + line separating the summary from the body is critical (unless you omit + the body entirely); tools like rebase can get confused if you run the + two together. + + Write your commit message in the imperative: "Fix bug" and not "Fixed bug" + or "Fixes bug." This convention matches up with commit messages generated + by commands like git merge and git revert. + + Further paragraphs come after blank lines. + + - Bullet points are okay, too. + + - Typically a hyphen or asterisk is used for the bullet, followed by a + single space, with blank lines in between, but conventions vary here. + + - Use a hanging indent. + +[1]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html + +## Patch labels + +Label every new patch with each component it touches, so reviewers and +filters can tell the projects apart: + +| Label | Covers | +|---|---| +| `explorer` | the web app in `explorer/`: `src/`, `http-client/`, `workers/`, its tests and config | +| `desktop` | anything under `desktop/` | +| `httpd` | `explorer/crates/radicle-httpd/` and `explorer/crates/radicle-search/` | + +A patch that touches several components gets several labels. Changes to +shared files (`.github/`, `.buildkite/`, `.ryph/`, root docs) get the labels +of the components they affect. `git push` can't set labels, so add them +once the patch is open: + +```sh +rad patch label --add explorer --add httpd +``` + +## Releases and tags + +Each project is released on its own. Release tags are +`releases//`; the `refs/tags/releases/*` rule in the +repository's identity decides when they become canonical. + +| Component | How it's released | Tag | +|---|---|---| +| Explorer web app | Deployed continuously, no releases or tags | — | +| `radicle-httpd` + `radicle-search` | Together, one version, see `explorer/RELEASE.md` | `releases/httpd/` | +| Desktop app | `desktop/scripts/release`, see `desktop/README.md` | `releases/desktop/` | + +The older `releases/` tags (httpd 0.22.0–0.29.0, desktop +0.9.0–0.16.0) are left over from before the two repositories were merged. +Never create, match or describe against them; scripts must always match a +component's own prefix. diff --git a/desktop/AGENTS.md b/desktop/AGENTS.md index f68232e20..d9291cc27 100644 --- a/desktop/AGENTS.md +++ b/desktop/AGENTS.md @@ -6,14 +6,12 @@ structs using ts-rs (`crates/radicle-types/`). The app lives in `desktop/` of the radicle-gui monorepo. It is its own npm package and Cargo workspace: run every command here from `desktop/`, and all -paths in this file are relative to it. The repository root holds the Radicle -web explorer, which has its own `CLAUDE.md`. Release tags are -`releases/desktop/`. +paths in this file are relative to it. Conventions shared with explorer +are in the root `AGENTS.md`. -## Tech stack +## Svelte syntax and aliases - Svelte 5 with runes syntax (`$state`, `$derived`, `$props`, `$effect`) -- TypeScript, Vite, Vitest, Playwright - Path aliases: `@app` (src), `@bindings` (crates/radicle-types/bindings), `@tests` ## Commands @@ -21,7 +19,7 @@ web explorer, which has its own `CLAUDE.md`. Release tags are ### Development ```sh -npm run tauri dev # full Tauri dev build with hot reload +npm run dev # full Tauri dev build with hot reload and devtools npm run start:http # test-http-api backend on :8081 (no Tauri runtime) npm start # Vite dev server; in a browser it talks to test-http-api ``` @@ -145,37 +143,16 @@ Ports have full default implementations, so a driver only implements a domain `Service` backed by the SQLite adapter instead of the ports; new lists over large data sets should do the same. -## Domain glossary - -- **NID** — Node ID, the public key in a DID (`did:key:z6Mk...`) -- **COB** — Collaborative Object (issue, patch, or identity as a Git DAG) -- **Delegate** — authorized repo maintainer; signatures determine canonical state -- **Seed** — hosting/replicating a repo; seed nodes are always-on servers -- **Canonical refs** — branches/tags resolved by delegate quorum - ## Code conventions -- Prefer `undefined` over `null` -- Do not add comments unless explicitly asked. When writing comments, - use proper English sentences -- Ask before adding new dependencies -- When proposing a bigger architectural change, record it as a new ADR in - `docs/adr/`, numbered after the last one and in the same format - ### Svelte components - Props use `$props()`: `const { foo, bar = undefined }: Props = $props()` -- CSS: scoped styles with design tokens (`var(--color-text-primary)`, - `var(--txt-body-m-regular)`, `var(--border-radius-sm)`); use `:global()` - for styling slotted or `{@html}` content -- Loading states: `{#await promise}` blocks for inline async; - local `loading` boolean with `try/catch` for imperative fetches ### TypeScript - Import backend types from `@bindings/*` — these are generated by ts-rs, never hand-write interfaces that duplicate them -- Use ES private fields (`#field`), not the TypeScript `private` keyword - Call Tauri commands via `invoke("command_name", { arg })` from `@app/lib/invoke` ### Rust backend @@ -188,14 +165,3 @@ lists over large data sets should do the same. - `rust-toolchain.toml` tracks heartwood's. When bumping the `radicle` crate, check heartwood's toolchain too: an older rustc fails inside the dependency with a confusing error (e.g. E0382 in `cob/identity.rs` for radicle 0.25) - -## Commit messages - -- Imperative mood: "Add feature" not "Added feature" -- Capitalize subject, no trailing period, max 50 chars - -## Do NOT - -- Do not use `npm test` — no default test script exists -- Do not use `yarn` or `pnpm` — use npm -- Do not use `npx vitest` or `npx playwright test` — use the `npm run` scripts diff --git a/explorer/AGENTS.md b/explorer/AGENTS.md index b97667ff4..87dc4f91b 100644 --- a/explorer/AGENTS.md +++ b/explorer/AGENTS.md @@ -1,145 +1,28 @@ -# radicle-gui +# radicle-explorer -Monorepo for Radicle's graphical interfaces. It holds two independent -projects, each with its own npm package, Cargo workspace, toolchain files, -checks and conventions: +The Svelte web app for browsing Radicle repositories, its TypeScript HTTP +client, and the `radicle-httpd` and `radicle-search` backends it talks to. -- **Explorer** (repository root): the Svelte web app for browsing Radicle - repositories, its TypeScript HTTP client, and the `radicle-httpd` and - `radicle-search` backends it talks to. -- **Desktop** (`desktop/`): the Tauri desktop app. Its own `desktop/CLAUDE.md` - is the source of truth for anything under `desktop/`. +The project lives in `explorer/` of the radicle-gui monorepo. It is its own +npm package and Cargo workspace: run every command here from `explorer/`, +and all paths in this file are relative to it. Conventions shared with +desktop are in the root `AGENTS.md`. -## Layout - -| Path | Project | What it is | -|---|---|---| -| `src/`, `public/`, `tests/` | explorer | Svelte web app and its unit, e2e and visual tests | -| `http-client/` | explorer | TypeScript client for the httpd API | -| `crates/radicle-httpd/` | explorer | HTTP daemon serving the API (Rust), with its own `CLAUDE.md` for code conventions | -| `crates/radicle-search/` | explorer | Search service, released together with httpd (Rust) | -| `workers/` | explorer | Cloudflare workers (open-graph images) | -| `scripts/` | explorer | Check, CI and e2e helper scripts | -| `desktop/` | desktop | Tauri app: Svelte frontend in `desktop/src/`, Rust in `desktop/crates/` | -| `.github/workflows/` | both | GitHub CI: `explorer-*.yml` for explorer, `desktop-*.yml` for desktop | -| `.buildkite/` | explorer | Radicle CI pipelines | -| `.ryph/` | both | Dev machine image and setup for agents, see `.ryph/environment.md` | - -## Working in this repo - -- Work out which project a change belongs to first, and run every command - from that project's root: the repository root for explorer, `desktop/` - for desktop. Root `npm` and `cargo` commands never cover `desktop/`, and - the root lint and format checks skip it on purpose. -- The two projects don't share code. A change that touches both is two - changes: check each project with its own commands. -- The rules under "Explorer" below don't apply in `desktop/`. In particular, - explorer uses legacy Svelte syntax while desktop uses Svelte 5 runes. - -### Plan mode - -- Propose the minimal MVP first — no tests, no docs, no speculative extras -- Tests are added only when explicitly requested after MVP review -- Keep plans concise: short bullet points listing what changes and where -- Skip obvious details and boilerplate explanations - -### Shared conventions - -- Prefer `undefined` over `null` -- Do not add comments unless explicitly asked. When writing comments, - use proper English sentences -- Ask before adding new dependencies -- Use npm, never `yarn` or `pnpm` -- Do not use `npm test` — neither project has a default test script -- Do not use `npx vitest` or `npx playwright test` — use the `npm run` scripts - -### Commit messages - -- Imperative mood: "Add feature" not "Added feature" -- Capitalize subject, no trailing period, max 50 chars -- Prefix backend-only commits with `httpd:` - -### Patches - -Label every new patch with each component it touches, so reviewers and -filters can tell the projects apart: - -| Label | Covers | -|---|---| -| `explorer` | the web app at the root: `src/`, `http-client/`, `workers/`, its tests and config | -| `desktop` | anything under `desktop/` | -| `httpd` | `crates/radicle-httpd/` and `crates/radicle-search/` | - -A patch that touches several components gets several labels. Changes to -shared files (`.github/`, `.buildkite/`, `.ryph/`, root docs) get the labels -of the components they affect. `git push` can't set labels, so add them -once the patch is open: - -```sh -rad patch label --add explorer --add httpd -``` - -### Releases and tags - -Each project is released on its own. Release tags are -`releases//`; the `refs/tags/releases/*` rule in the -repository's identity decides when they become canonical. - -| Component | How it's released | Tag | -|---|---|---| -| Explorer web app | Deployed continuously, no releases or tags | — | -| `radicle-httpd` + `radicle-search` | Together, one version, see `RELEASE.md` | `releases/httpd/` | -| Desktop app | `desktop/scripts/release`, see `desktop/README.md` | `releases/desktop/` | - -The older `releases/` tags (httpd 0.22.0–0.29.0, desktop -0.9.0–0.16.0) are left over from before the two repositories were merged. -Never create, match or describe against them; scripts must always match a -component's own prefix. - -### Radicle ecosystem (sibling repos) - -See the `radicle-ecosystem` skill for the map of sibling repositories -(heartwood, radicle-git, radicle-job, rips, radicle.dev) and the key -crates and files in each. - -### Domain glossary - -- **RID** — Repository ID (`rad:z3gqc...`) -- **DID** — Decentralized Identifier, user identity (`did:key:z6Mk...`) -- **NID** — Node ID, public key suffix of a DID -- **COB** — Collaborative Object (issue, patch, or identity as a Git DAG) -- **Delegate** — authorized repo maintainer; signatures determine canonical state -- **Patch** — pull-request equivalent with immutable revisions and reviews -- **Seed** — hosting/replicating a repo; seed nodes are always-on servers -- **Canonical refs** — branches/tags resolved by delegate quorum - -## Explorer (repository root) - -Everything in this section applies to the repository root only. Run all -commands from there. - -### Tech stack - -- Svelte 5 with legacy syntax (`$:`, stores, `export let`). Do not use - Svelte 5 runes (`$state`, `$derived`, `$props`) here -- TypeScript, Vite, Vitest, Playwright, Zod -- Rust for `crates/radicle-httpd` and `crates/radicle-search` - -### Checks and linting (tsc, svelte-check, eslint, prettier) +## Checks and linting (tsc, svelte-check, eslint, prettier) ```sh npm run check npm run format # auto-fix prettier issues ``` -### Unit tests +## Unit tests ```sh npm run test:unit npm run test:http-client:unit ``` -### E2E tests +## E2E tests ```sh npm run test:e2e -- --project chromium @@ -155,7 +38,7 @@ or test fixtures requires a full run. SKIP_SETUP=true npm run test:e2e -- --project chromium ``` -### Rust backend (`crates/`) +## Rust backend (`crates/`) The same commands CI runs: @@ -176,7 +59,7 @@ npm run test:e2e:local -- --project chromium npm run test:http-client:unit:local ``` -### API changes across layers +## API changes across layers Adding or changing an API endpoint typically touches three layers: 1. `crates/radicle-httpd/` — Rust handler (add route, types, logic) @@ -188,49 +71,29 @@ or remove fields/endpoints unless explicitly deprecating. The frontend must handle older nodes gracefully: treat new API fields as optional and fall back when they're absent. -### Pre-push checklist +## Pre-push checklist -`npm run check:ci` runs everything below except the `:local` variants, plus -the build smoke test, from the GitHub workflows, and stops at the first -failure. It logs each step's output, duration and exit code to -`tests/tmp/check-ci.log`. +`npm run check:ci` runs the checks, unit, http-client, e2e and build smoke +tests from the GitHub workflows, and stops at the first failure. It logs +each step's output, duration and exit code to `tests/tmp/check-ci.log`. If +Rust code changed, also run the Rust commands and the `:local` variants +above. -1. `npm run check` -2. `npm run test:unit` -3. `npm run test:http-client:unit` -4. `npm run test:e2e -- --project chromium` -5. If Rust code changed: clippy, fmt, cargo test (see above), - plus `:local` variants of e2e and http-client tests +## Svelte components -### Svelte components - -- Script order (enforced by prettier): `