Skip to content
Developer guide

Developer guide

This guide is for people changing PULSE or building against its API.

Repository layout

PathWhat it holds
grpc/The Go backend, module github.com/org-runink/pulse (Go 1.26)
grpc/main.go, grpc/cmd/The Cobra entry point and every service. cmd/serve.go wires everything together.
grpc/api/proto/pulse/v1/The .proto files: pulse.proto, activity.proto, commons.proto
grpc/api/proto-vendor/A verbatim copy of runink/ui/judgement/v1/judgement.proto, resolved but never generated
grpc/api/v1/Generated Go code, committed
grpc/internal/ai, db, scoring, apply, metasearch, openbias, forecast, connector clients (hubspot, github, googleanalytics, googleads, spotify), telephony, voice, webrtc, and more
grpc/agents/Agent parameters (pulse.ini), prompt templates, and guardrail rules
flutter/lib/The Flutter app: core/ (gRPC channel, generated stubs, cache, theme) and features/ (one folder per screen)
website/This documentation site

The platform pieces are not here. Self-healing, the event mesh, secrets and PKI, the object store, the inference engine, the operator, and infrastructure code live in CORE or in the extracted libraries. Never add them to this repository.

Build and test

The backend builds only with the sibling repositories checked out next to pulse/: inference, security, mesh, store, ui, and billing.

cd grpc && go build -o bin/pulse-server .
cd grpc && go test ./...
cd grpc && go vet ./...
cd flutter && flutter analyze
Sibling checkouts may be on another branch. To build against a specific sibling version, add a worktree of it and point a GOWORK file outside the repository at it. Don’t switch the shared checkout.

To run the backend, see Run PULSE locally.

Regenerate the protobuf code

Run both commands from the repository root, and always pass the grpc/api/proto input:

buf generate grpc/api/proto --template grpc/buf.gen.yaml -o grpc   # Go
buf generate grpc/api/proto --template grpc/buf.gen.dart.yaml      # Dart, no -o
  • The Go run needs -o grpc, or the code lands at the repository root.
  • The first command does not generate Dart, and nothing tells you. Skip the second and the app compiles against the old messages, and a new field reads as null on the client.
  • Running buf from inside grpc/ picks up a competing buf.yaml and breaks import resolution.
  • Codegen uses local plugins on your PATH: protoc-gen-go, protoc-gen-go-grpc, and protoc-gen-dart.
  • When ui changes judgement.proto, copy it again into proto-vendor/. grpc/cmd/judgement_vendored_test.go fails until you do.

The app’s backend address

The Flutter client reads PULSE_BACKEND_URL from a --dart-define, default http://localhost:50051. The web build bakes it in at compile time.

Shared UI components

Pages that more than one Runink app shows come from org-runink/ui: design tokens and transport (foundation), billing, datasources, profile, and access. PULSE mounts the Go handler with its own hooks and depends on the Flutter package by path. To try an unmerged ui branch, use a private GOWORK and a gitignored flutter/pubspec_overrides.yaml.

Licence rules for contributions

PULSE is proprietary.

  • New files start with an SPDX header: SPDX-License-Identifier: LicenseRef-Runink-Proprietary.
  • After a dependency change, run scripts/gen-third-party-notices.sh. CI fails on stale notices and on disallowed licences.
  • Release builds stay hardened: Go -trimpath -ldflags="-s -w", Flutter web --no-source-maps.