mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-10-25 14:50:30 +08:00
Split agent and contributor docs by project
This commit is contained in:
@@ -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
|
||||
@@ -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/<version>` 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
|
||||
+109
@@ -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 <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 `explorer/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.
|
||||
+4
-38
@@ -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/<version>`.
|
||||
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<T>("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
|
||||
|
||||
+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