Thank you for your interest in contributing. This document covers everything you need to get started.
- Read the Code of Conduct. All contributors are expected to follow it.
- For significant changes, open an issue first to discuss the approach before writing code.
- For bug fixes and small improvements, a pull request is sufficient.
git clone https://github.com/Ezedike-Evan/stellar-intel.git
cd stellar-intel
npm install
cp .env.example .env.local
npm run devSee README.md for full setup instructions and environment variable reference.
Anyone can pick up an issue labelled help-wanted or good-first-issue
without asking first — comment that you're starting it and open a PR when
it's ready. For anything else, ask to be assigned before you start, so two
people don't end up duplicating the same work.
Comment on the issue and say what you plan to do. A request that includes a short plan — the approach you'll take, which files it touches, how you'll verify it — carries more weight than a bare "can I take this?" and gets assigned faster, since it shows the issue is understood rather than just claimed.
A maintainer assigns the issue to you once your comment makes it clear you understand the scope. If nobody responds within a few days, it's fine to open the PR directly and reference the issue — a working PR is itself a form of claim.
An assignment is released after 14 days of inactivity (no commits, no linked PR, no update comment). If you're still working on it but need more time, a comment saying so before the window closes keeps it yours. Once released, the issue reopens to anyone, including you if you want to pick it back up.
-
Fork the repository and create a branch from
main. -
Name branches descriptively:
feat/sep24-fee-fetching,fix/anchor-rate-display,docs/readme-update. -
Make your changes. Keep commits focused — one logical change per commit.
-
Run checks before pushing. The one-liner is:
npm run test:release # format:check + lint + typecheck + test + buildThat covers the whole
checkCI job except the two generated-file drift gates, which are separate and catch people out:npm run emit-openapi && git diff --exit-code -- public/openapi.jsonpublic/openapi.jsonis committed, and CI regenerates it and fails on any diff. If you changed an API route or a schema, regenerate and commit the spec in the same commit.The same applies to the docs corpus served at
/llms-full.txt:npm run emit-llms-full && git diff --exit-code -- lib/seo/llms-full.generated.txtIt is generated from
docs/, so editing any doc in the corpus means committing the regenerated file too.npm run buildregenerates it for you (it runs inprebuild), so afternpm run test:releasethe file is already updated in your working tree — just commit it.If your change touches Rust, Python or a workspace package, see Per-surface checks below — the root commands do not cover them.
-
Open a pull request against
main. Fill in the PR description template.
- Strict mode is enabled. All code must pass
npm run typecheckwith zero errors. - Prefer explicit types over
any. Useunknownwhen the type is genuinely unknown. - Export types from
types/— do not inline complex types in component files.
- One component per file.
- Components live in
components/. UI primitives live incomponents/ui/. - Keep components focused. If a component exceeds ~150 lines, consider splitting it.
- Use SWR hooks from
hooks/for client-side data fetching. - Network calls belong in
lib/— not inside components or hooks. - No mock data in production code. If real data is unavailable, surface an error state.
- Tailwind CSS v4 only. No inline
styleprops unless absolutely necessary. - Follow the existing class ordering convention (layout → spacing → typography → colour).
Follow the Conventional Commits format:
feat: add SEP-24 fee fetching for Cowrie anchor
fix: correct exchange rate computation for NGN corridor
docs: update environment variable reference
refactor: extract anchor TOML resolution into lib/sep1.ts
Types: feat, fix, docs, refactor, test, chore, ci.
- All documentation files in
docs/must carry a**Last reviewed:** YYYY-MM-DDline near the top of the file (immediately after the main heading or header block). - Maintainers and contributors should update this date whenever making non-trivial documentation updates or re-verifying accuracy.
Anchors are defined in constants/anchors.ts (re-exported via constants/index.ts). To add a new anchor:
- Add an entry to
KNOWN_ANCHORSwith the anchor'sid,name,domain,supportedCountries,supportedCurrencies, anddepositMethods. - The anchor must have a publicly resolvable
stellar.tomlathttps://{domain}/.well-known/stellar.toml. - The
stellar.tomlmust expose a transfer server —TRANSFER_SERVER_SEP0024(SEP-24) orTRANSFER_SERVER(SEP-6). SEP-6-only anchors are supported; see docs/ANCHOR_ONBOARDING.md. - Verify the anchor's
/feeendpoint returns live data before submitting the PR.
This repository is no longer a single Next.js app. It spans a TypeScript app, a
Soroban contract, a no_std Rust consumer crate, a Python SDK, and three npm
workspaces — and the root npm scripts cover only the first. Run the block
for whatever you touched.
npm run format:check # prettier, and it covers **/*.md too
npm run lint # eslint --max-warnings 0
npm run typecheck # tsc --noEmit
npm run test # vitest
npm run build
npm run check:registry # anchor registry ⊆ transfer-capable set
npm run emit-openapi && git diff --exit-code -- public/openapi.json
npm run emit-llms-full && git diff --exit-code -- lib/seo/llms-full.generated.txtMirrors the soroban contract (reputation) CI job exactly:
cargo fmt --manifest-path contracts/reputation/Cargo.toml --check
cargo clippy --manifest-path contracts/reputation/Cargo.toml --all-targets -- -D warnings
cargo test --manifest-path contracts/reputation/Cargo.toml --locked
cargo build --manifest-path contracts/reputation/Cargo.toml \
--target wasm32-unknown-unknown --releaseclippy runs with -D warnings, so a warning is a build failure.
cargo test --manifest-path crates/stellar-intel-reputation/Cargo.toml --locked
cargo doc --manifest-path crates/stellar-intel-reputation/Cargo.toml --no-deps
cargo publish --manifest-path crates/stellar-intel-reputation/Cargo.toml --dry-run --lockedThe --dry-run publish is in CI, so bumping the crate version means committing
the regenerated Cargo.lock alongside it.
This crate is #![no_std] and is linked into wasm32 contracts. Do not add a
dependency that needs std — reqwest, tokio and friends will not compile
here, and feature-gating them poisons the dependency graph for the contract
authors this crate exists for.
cd packages/python-sdk
pip install -e ".[dev]"
pytest
mypy srcMost of this package is generated. src/stellarintel/api/,
models/, client.py and types.py come from openapi-python-client generate
against public/openapi.json. Only wrapper.py is hand-written. Editing a
generated file means your change disappears on the next regeneration — change
the spec, or change the wrapper.
npm workspaces. Root npm run test picks up packages/*/tests/** automatically
(vitest.config.mts excludes only tests/e2e/**), so their unit tests run with
the root suite. Building the publisher is a prerequisite of the root typecheck
and is wired into pretypecheck/prebuild, so you rarely invoke it directly:
npm run build --workspace=@stellarintel/publisher| You changed… | Run |
|---|---|
app/, components/, lib/, hooks/ |
Root block |
| An API route or a zod schema | Root block including the OpenAPI gate |
constants/anchors.ts |
Root block including check:registry |
contracts/reputation/ |
Root block + contract block |
crates/stellar-intel-reputation/ |
Consumer crate block |
packages/publisher/, packages/mcp/ |
Root block (their tests run with it) |
packages/python-sdk/ |
Python block |
Any *.md |
npm run format:check — prettier covers docs |
-
npm run test:releasepasses (format, lint, typecheck, test, build) -
npm run emit-openapiproduces no diff, or the regenerated spec is committed -
npm run emit-llms-fullproduces no diff, or the regenerated corpus is committed - Rust:
cargo fmt --check,cargo clippy -- -D warnings,cargo testpass for every crate touched - Python:
pytestandmypypass, and no generated file was hand-edited - Documentation files in
docs/carry an updated**Last reviewed:** YYYY-MM-DDdate - No
isMock,// MOCK, or hardcoded rate values added - New anchor entries include a verified
stellar.tomldomain - Exactly one
Closes #Nkeyword — reference other issues without one - PR description explains what changed and why
This repo uses several namespaces to organise work across waves, modules, and documentation debt. Understanding them helps you navigate the issue tracker and write PRs that auto-link correctly.
| Prefix | Range | Purpose |
|---|---|---|
#001–#250 |
Main tracker | Wave-scoped engineering tickets (see docs/ROADMAP.md). |
#B001–#B100 |
Batch 2 | Supplementary issues from issues-batch-2.md. |
#W1.1–W7.x |
Wave issues | Per-workstream milestone issues from WAVE_ISSUES.md. |
#D001–D999 |
Doc/infra debt | Documentation gaps, infra improvements, and technical-debt tickets that don't fit a wave. Sometimes referenced as #D047 inline in code comments. |
#N/A |
Meta | Issues opened against the issue tracker itself (template improvements, workflow changes). |
A PR title like fix: correct exchange rate computation for NGN corridor will
auto-close an issue when the body contains Closes #NNN.
Labels are the single source of truth for issue triage. They are defined in
.github/labels.yml and synced to GitHub by
.github/workflows/label-sync.yml. The taxonomy follows these rules:
- Lower-case, hyphenated, namespaced with
/— e.g.module/oracle,epic/reputation. - One concern per namespace. A label belongs to exactly one category (type, state, difficulty, wave, epic, module).
- State labels are flat —
blocked,help-wanted,design-review.
| Category | Examples | Purpose |
|---|---|---|
| Type | bug, feature, docs, chore, refactor, test |
What kind of change the issue represents. Every issue has exactly one type label. |
| State | blocked, help-wanted, good-first-issue, design-review, needs-triage |
Workflow status. Applied and removed as the issue progresses. |
| Difficulty | difficulty/good-first-issue, difficulty/intermediate, difficulty/hard |
Estimated effort. Set by a maintainer during triage. |
| Wave | wave/1.0, wave/2.0, wave/2.1 |
Which milestone the issue belongs to. Maps to docs/ROADMAP.md. |
| Epic | epic/execution-layer, epic/reputation, epic/agents, epic/anchor-integration, epic/ui, epic/docs-community |
High-level theme the issue contributes to. |
| Module | module/oracle, module/router, module/reputation, module/mcp, module/api, module/ui, module/sep10, module/sep24, module/sep38 |
Which subsystem the change lands in. Helps route PRs to the right reviewer. |
| Meta | release, dependencies, size/xs–size/xl |
Release tracking, dependency updates, and PR size estimation. |
D-prefixed issues (#D001, #D002, …) track documentation gaps and
infrastructure improvements that are not visible to end users but affect
contributor experience, maintainability, or operator workflows. They follow
the same triage process as numbered issues but live in a separate namespace
so they can be planned independently of feature work.
Examples from the codebase:
#D002— Uptime probe ledger#D005— Quote-latency probe#D006— Quote-drift probe#D014— Sentry / dead-letter alert sink#D035— SEP-24 live execution flow e2e test#D047— Rate-limit audit follow-up#D060/#746— Plausible analytics integration
When referencing a D-issue in code, use the pattern:
// ─── Uptime / quote-latency probe ledger (Issue #D002 / #D005) ────────────────Branches should be named descriptively:
feat/<short-description>— new capabilitiesfix/<short-description>— bug fixesdocs/<short-description>— documentation changeschore/<short-description>— build, tooling, depsrefactor/<short-description>— code structure changes with no behaviour change
Every PR must link exactly one issue with a closing keyword (Closes,
Fixes, Resolves). This ensures:
- Issues auto-close on merge.
- The changelog generator picks up a clean mapping.
- Reviews stay scoped.
If a change genuinely spans multiple issues (rare), close the primary issue
and reference the others in the PR body. Never leave a Closes # line
unfilled or filled with an example number.
Open an issue with the question label.