mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-11-15 19:30:38 +08:00
Split agent and contributor docs by project
This commit is contained in:
+21
-158
@@ -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 <patch-id> --add explorer --add httpd
|
||||
```
|
||||
|
||||
### Releases and tags
|
||||
|
||||
Each project is released on its own. Release tags are
|
||||
`releases/<component>/<version>`; 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/<version>` |
|
||||
| Desktop app | `desktop/scripts/release`, see `desktop/README.md` | `releases/desktop/<version>` |
|
||||
|
||||
The older `releases/<version>` 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): `<script context="module">`,
|
||||
`<script lang="ts">`, `<style>`, markup
|
||||
- Optional props use `export let foo: T = undefined`, not `?:`
|
||||
- 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
|
||||
|
||||
### `{@html}` and untrusted data (XSS)
|
||||
## `{@html}` and untrusted data (XSS)
|
||||
|
||||
- Avoid `{@html}` with backend-derived data (branch/ref names, aliases,
|
||||
descriptions); when unavoidable, its argument must be DOMPurify-sanitized
|
||||
(`sanitizeConfig` in `src/lib/markdown.ts`) or built from `escape()`'d
|
||||
parts, in the component that renders it.
|
||||
|
||||
### TypeScript / HTTP client
|
||||
## TypeScript / HTTP client
|
||||
|
||||
- Derive types from Zod schemas (`z.infer<typeof fooSchema>`), never
|
||||
hand-write interfaces that duplicate a schema
|
||||
- Schema naming: `fooSchema` (camelCase + Schema suffix) → type `Foo`
|
||||
- Use ES private fields (`#field`), not the TypeScript `private` keyword
|
||||
- API timestamps are in seconds; multiply by 1000 for JS `Date`
|
||||
- Relative imports inside `http-client/` use `.js` extension (ESM)
|
||||
|
||||
## Desktop (`desktop/`)
|
||||
|
||||
See `desktop/CLAUDE.md`. In short: Tauri with a Svelte 5 frontend that uses
|
||||
runes, a hexagonal Rust backend in `desktop/crates/`, and its own checks
|
||||
(`npm run check:ci` from `desktop/`).
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
# CONTRIBUTING
|
||||
|
||||
Contributions are very welcome. When contributing code, please follow these
|
||||
simple guidelines.
|
||||
|
||||
* Make sure you run `npm run check` for code formatting problems.
|
||||
* Run our test suite `npm run test:*` to avoid regressions or bugs.
|
||||
* 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).
|
||||
|
||||
Running Tests
|
||||
-------------
|
||||
|
||||
The test suite includes end-to-end (e2e) tests that run against the built
|
||||
application.
|
||||
|
||||
**Basic usage:**
|
||||
|
||||
npm run test:e2e
|
||||
|
||||
**Skipping setup:**
|
||||
|
||||
The test suite performs setup operations before running tests:
|
||||
* Building the application bundle
|
||||
* Creating test fixtures (repositories with test data)
|
||||
|
||||
On subsequent test runs, you can skip this setup to save time:
|
||||
|
||||
SKIP_SETUP=true npm run test:e2e
|
||||
|
||||
Use this when:
|
||||
* You haven't changed any source code since the last test run
|
||||
* The test fixtures are already created
|
||||
* You want to iterate quickly on test development
|
||||
|
||||
**Note:** If you've made code changes or are getting unexpected test failures,
|
||||
remove the `SKIP_SETUP` flag to ensure tests run against the latest build.
|
||||
|
||||
**Common usage patterns:**
|
||||
|
||||
* First time run: `npm run test:e2e -- --project chromium`
|
||||
* Subsequent runs (no code changes): `SKIP_SETUP=true npm run test:e2e -- --project chromium`
|
||||
* Single test by line number: `SKIP_SETUP=true npm run test:e2e -- tests/e2e/repo/commits.spec.ts:90 --project chromium`
|
||||
|
||||
**Testing with local radicle-httpd build:**
|
||||
|
||||
If you're developing radicle-httpd and want to test changes locally:
|
||||
|
||||
npm run test:e2e:local
|
||||
|
||||
This will:
|
||||
1. Compile radicle-httpd from the `radicle-httpd/` directory
|
||||
2. Run the full test suite against the locally compiled binary
|
||||
|
||||
**Running e2e tests in Docker:**
|
||||
|
||||
If your host OS isn't supported by Playwright's browser builds (e.g. a very
|
||||
new or unusual Linux distribution), run the suite inside a container instead.
|
||||
Requires Docker with the Compose plugin.
|
||||
|
||||
scripts/test-e2e-docker
|
||||
|
||||
Any arguments are forwarded to `npm run test:e2e` (defaulting to
|
||||
`--project chromium` when none are given):
|
||||
|
||||
scripts/test-e2e-docker tests/e2e/repo.spec.ts
|
||||
scripts/test-e2e-docker --project chromium -g "some test name"
|
||||
|
||||
`SKIP_SETUP=true` is forwarded the same as for the native runner:
|
||||
|
||||
SKIP_SETUP=true scripts/test-e2e-docker
|
||||
|
||||
To test against a radicle-httpd you compile from source (the equivalent of
|
||||
`npm run test:e2e:local`), pass `--local`:
|
||||
|
||||
scripts/test-e2e-docker --local
|
||||
|
||||
Notes:
|
||||
* The first image build is slow (it downloads Chromium); subsequent runs are
|
||||
cached. `--local` additionally installs a Rust toolchain and compiles
|
||||
radicle-httpd on first use.
|
||||
* The repo is bind-mounted, so test artifacts and the binary/fixture cache
|
||||
land on the host as usual. `node_modules`, the cargo cache, and httpd's
|
||||
build directory live in container-private volumes, leaving your host copies
|
||||
untouched.
|
||||
|
||||
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 a proposal in english first, 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.
|
||||
|
||||
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
|
||||
+28
-5
@@ -188,12 +188,35 @@ git clone https://seed.example.com/heartwood.git
|
||||
```
|
||||
|
||||
|
||||
## Development
|
||||
|
||||
Run `npm run check` before proposing a patch, along with the test suites:
|
||||
`npm run test:unit`, `npm run test:http-client:unit` and `npm run test:e2e`.
|
||||
|
||||
E2E tests build the app and create fixtures before running. If neither the
|
||||
source nor the fixtures changed since the last run, skip that with
|
||||
`SKIP_SETUP=true`:
|
||||
|
||||
```sh
|
||||
npm run test:e2e -- --project chromium
|
||||
SKIP_SETUP=true npm run test:e2e -- tests/e2e/repo/commits.spec.ts:90 --project chromium
|
||||
```
|
||||
|
||||
When changing `radicle-httpd`, `npm run test:e2e:local` compiles it from
|
||||
`crates/radicle-httpd/` and runs the suite against that build instead of
|
||||
the released binary.
|
||||
|
||||
If Playwright's browsers don't support your OS, `scripts/test-e2e-docker`
|
||||
runs the suite in a container (Docker with the Compose plugin). It forwards
|
||||
its arguments and `SKIP_SETUP` to `npm run test:e2e`, and `--local` tests
|
||||
against httpd built from source. The first run downloads Chromium and is
|
||||
slow.
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
* For detailed contribution guidelines, refer to the [CONTRIBUTING.md][con]
|
||||
file
|
||||
* To propose changes, open an [issue][iss] or submit a [patch][pat] using
|
||||
Radicle
|
||||
See [CONTRIBUTING.md][con] for how to propose changes and write commit
|
||||
messages. Open an [issue][iss] or a [patch][pat] using Radicle.
|
||||
|
||||
|
||||
## Getting in touch
|
||||
@@ -209,7 +232,7 @@ The UI is distributed under the terms of GPLv3. See [LICENSE][lic] for details.
|
||||
|
||||
|
||||
[app]: https://radicle.network
|
||||
[con]: ./CONTRIBUTING.md
|
||||
[con]: ../CONTRIBUTING.md
|
||||
[def]: ./config/default.json
|
||||
[env]: ./config/custom-environment-variables.json
|
||||
[iss]: https://radicle.network/nodes/iris.radicle.network/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5/issues
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# radicle-httpd
|
||||
|
||||
Rust backend for the Radicle web explorer, released together with
|
||||
`radicle-search` (see `RELEASE.md` at the repository root).
|
||||
`radicle-search` (see `RELEASE.md` in `explorer/`).
|
||||
|
||||
## Code conventions
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ export default async function globalSetup(): Promise<() => void> {
|
||||
|
||||
// Evaluated once at startup; captured by async setup operations.
|
||||
// Set SKIP_SETUP=true to skip both build and fixture creation on subsequent runs.
|
||||
// See CONTRIBUTING.md for details.
|
||||
// See README.md for details.
|
||||
const shouldSetup = !process.env.SKIP_SETUP;
|
||||
|
||||
if (shouldSetup) {
|
||||
|
||||
Reference in New Issue
Block a user