- Clone:
git clone https://github.com/Livepeer-FrameWorks/monorepo.git - Copy secrets:
cp config/env/secrets.env.example config/env/secrets.env - Generate env:
make env - Start stack:
docker-compose up
All lint checks (CI parity):
make lintGo:
make lint-go # Baseline-aware Go lint (same mode as CI go-lint)
make lint-all # Show all Go violations (for cleanup)
make lint-fix # Auto-fix what's possibleFrontend:
pnpm lint # ESLint
pnpm format # Prettier (auto-fix)
pnpm format:check # Check without fixingHooks auto-install on pnpm install via Lefthook. They run:
gofmtandgolangci-linton staged Go files- Prettier and ESLint on staged frontend files
To skip temporarily: git commit --no-verify
- Go: tabs (enforced by
gofmt) - JS/TS/Svelte/JSON/YAML: 2 spaces
- See
.editorconfigfor full settings
Use runes, not old syntax:
$state()notlet$derived()not$:$props()notexport let
Infinite loop gotcha: Reading $state in an $effect condition causes loops even with untrack. Move the condition inside untrack:
// Bad: myState.length outside untrack creates dependency
$effect(() => {
if (newData && myState.length === 0) {
untrack(() => {
myState = newData;
});
}
});
// Good: check inside untrack
$effect(() => {
if (newData) {
untrack(() => {
if (myState.length === 0) myState = newData;
});
}
});make test # All Go tests
cd api_control && go test ./... -v # Specific service
cd website_application && pnpm test # Frontend
make ci-local # Run core CI checks locally
make verify # Pre-commit verification
./scripts/mutation-test.sh pkg/auth/ # Mutation testing (validates test quality)See docs/standards/testing.md for testing philosophy and best practices.
The release pipeline (.github/workflows/release.yml) uses two runner types:
ubuntu-latest(GitHub-hosted): builds linux/amd64 binaries and Docker imagesmacos-arm64-self-hosted(Mac Mini): builds linux/arm64 + darwin/arm64 binaries, handles Apple code signing and notarization
The Mac Mini runner requires:
- GitHub Actions runner agent (configured as LaunchDaemon)
- Go 1.25+
filosottile/musl-cross/musl-cross(Homebrew) for CGO linux cross-compilation- Apple Developer certificate (imported via secrets)
- Docker Desktop (for future arm64 container image builds)
# 1. Edit schema
vim pkg/graphql/schema.graphql
# 2. Run codegen
make graphql
# 3. Implement resolver stub
vim api_gateway/graph/schema.resolvers.go
# 4. Add/update frontend operations
vim pkg/graphql/operations/queries/MyQuery.gql
# 5. If schema changed, update demo generators
vim api_gateway/internal/demo/generators.goSee docs/architecture/analytics-pipeline.md section "Extending Analytics" for the full checklist. Summary:
# 1. Define protobuf message
vim pkg/proto/ipc.proto
# 2. Generate Go code
make proto
# 3. Emit the event from producing service (Helmsman/Foghorn/etc.)
vim api_balancing/internal/triggers/processor.go # or relevant service
# 4. Update ClickHouse schema
vim pkg/database/sql/clickhouse/periscope.sql
# 5. Add ingest handler to write to ClickHouse
vim api_analytics_ingest/internal/handlers/handlers.go
# 6. Add query method if exposing via API
vim api_analytics_query/internal/grpc/server.go
# 7. If exposing to frontend: update GraphQL schema + resolvers + demo generators- Branch from
development - One feature or fix per PR
- Keep PRs under 800 lines where possible — split large changes into reviewable chunks
- Architectural changes require an RFC in
docs/rfcs/first - Fully completed RFC's require merging into generic
/docsarchitectural documents - Fill out the PR template
- Make sure CI passes
AI is part of our toolchain — we use it for development, code review, and issue triage. It's a tool, not an author. Every change goes through the same review and testing process regardless of how it was written.
Contributors are free to use AI tools. Automated commits (e.g., from Codex) carry a Co-Authored-By trailer for transparency.
Significant changes need an RFC first:
- Create
docs/rfcs/your-feature.md(usedocs/rfcs/RFC_TEMPLATE.md) - Open a PR for discussion
- Get approval before implementing
Open a Discussion.