Reputo is a privacy-preserving, modular reputation-and-voting platform inspired by Snapshot.
- Apps & Packages
- Quick Start
- Prerequisites
- Project Structure
- Algorithm Development
- Contributing
- License
- Team
| Path | Stack | Status | Links |
|---|---|---|---|
apps/api |
✅ Ready | 📚 README · 📖 API Docs | |
apps/ui |
✅ Ready | 📚 README · 🌐 App | |
apps/workflows |
✅ Ready | 📚 README | |
packages/reputation-algorithms |
✅ Ready | 📚 README | |
packages/algorithm-validator |
✅ Ready | 📚 README | |
packages/database |
✅ Ready | 📚 README | |
packages/storage |
✅ Ready | 📚 README | |
packages/deepfunding-portal-api |
✅ Ready | 📚 README |
# Install dependencies
pnpm install
# Build project
pnpm build
# Run all services in parallel
pnpm dev
# Run individual services
pnpm -F @reputo/api dev # API only# Basic local development setup
docker compose -f docker/docker-compose.dev.yml up --build- Node.js: 20.x or higher
- pnpm: 10.12.4 or higher
- Docker: For containerized development
- Git: With Lefthook for git hooks
- Docker & Docker Compose: Container orchestration
- Traefik: Reverse proxy
- Domain & DNS: For SSL certificate generation
- Cloudflare API Token: For DNS challenge
reputo/
├── apps/
│ ├── api/ # NestJS API server
│ ├── ui/ # Next.js frontend
│ └── workflows/ # Temporal workflows & algorithm workers
├── packages/
│ ├── algorithm-validator/ # Shared Zod validation library
│ ├── reputation-algorithms/ # Algorithm definitions registry
│ ├── storage/ # Framework-agnostic S3 utilities
│ └── database/ # Mongoose database layer
├── scripts/
│ ├── create-algorithm.ts # Unified algorithm creation CLI
│ └── validate-algorithms.ts # Algorithm sync validation CLI
├── docker/
│ ├── docker-compose.yml # Production/staging setup
│ ├── docker-compose.dev.yml # Local development
│ ├── docker-compose.preview.yml # PR preview environments
│ ├── Dockerfile # Multi-stage build
│ └── traefik.yml # Reverse proxy config
├── .github/
│ ├── workflows/ # CI/CD pipelines
│ └── PULL_REQUEST_TEMPLATE.md
├── coverage/ # Test coverage reports
├── node_modules/ # pnpm workspace dependencies
├── package.json # Root workspace config
├── pnpm-workspace.yaml # Workspace definition
├── biome.json # Linting & formatting
├── lefthook.yml # Git hooks
├── vitest.config.ts # Test runner config
├── tsconfig.vitest.json # Vitest TS config
└── commitlint.config.mjs # Commit message linting
We follow a three-tier deployment strategy with automated promotion:
- Trigger: Adding
pullpreviewlabel to PRs - Infrastructure: AWS Lightsail
- URL: Dynamic subdomain generated per PR
- Cleanup: Auto-expires after 48h or PR closure
- Trigger: Merge to
mainbranch (automated) - URL:
- UI: staging.logid.xyz
- API: api-staging.logid.xyz
- Traefik: traefik-staging.logid.xyz/dashboard
- Deployment: Watchtower auto-pulls
stagingtagged images
- Trigger: Manual workflow dispatch with commit SHA
- URL:
- UI: logid.xyz
- API: api.logid.xyz
- Traefik: traefik.logid.xyz/dashboard
- Process: Promotes staging images with
productiontags
This section guides you through creating, configuring, and implementing reputation algorithms.
Algorithms in Reputo consist of two parts:
-
Algorithm Definition - A JSON schema that describes the algorithm's metadata, inputs, outputs, and runtime configuration. Located in
packages/reputation-algorithms/src/registry/. -
Activity Implementation - TypeScript code that executes the algorithm logic. Located in
apps/workflows/src/activities/typescript/algorithms/.
Use the unified CLI to create both the definition and activity scaffold in one command:
pnpm algorithm:create <key> <version>Example:
pnpm algorithm:create proposal_engagement 1.0.0This creates:
packages/reputation-algorithms/src/registry/proposal_engagement/1.0.0.json- Algorithm definitionapps/workflows/src/activities/typescript/algorithms/proposal-engagement/compute.ts- Activity implementationapps/workflows/src/activities/typescript/algorithms/proposal-engagement/index.ts- Activity export
Requirements:
keymust besnake_case(e.g.,voting_engagement,proposal_score)versionmust be valid SemVer (e.g.,1.0.0,2.1.0-beta)
Edit the generated JSON file to define your algorithm's schema:
{
"key": "proposal_engagement",
"name": "Proposal Engagement",
"category": "Engagement",
"description": "Calculates user engagement based on proposal interactions",
"version": "1.0.0",
"inputs": [
{
"key": "proposals",
"label": "Proposals CSV",
"type": "csv",
"csv": {
"hasHeader": true,
"columns": [
{ "key": "user_id", "type": "string" },
{ "key": "proposal_id", "type": "string" },
{
"key": "action",
"type": "enum",
"enum": ["view", "vote", "comment"]
}
]
}
}
],
"outputs": [
{
"key": "engagement_scores",
"label": "Engagement Scores",
"type": "csv",
"csv": {
"columns": [
{ "key": "user_id", "type": "string" },
{ "key": "score", "type": "number" }
]
}
}
],
"runtime": "typescript"
}Key fields:
| Field | Description |
|---|---|
inputs |
Define expected input data schema (CSV columns, types, constraints) |
outputs |
Define output data schema |
runtime |
The runtime environment for the algorithm (e.g., typescript) |
Edit the generated activity file to implement your algorithm:
// apps/workflows/src/activities/typescript/algorithms/proposal-engagement/compute.ts
export async function computeProposalEngagement(
snapshot: Snapshot,
storage: Storage
): Promise<AlgorithmResult> {
const { inputs } = snapshot.algorithmPresetFrozen
// 1. Get input data
const inputKey = getInputValue(inputs, 'proposals')
const buffer = await storage.getObject({ bucket, key: inputKey })
const rows = parse(buffer.toString('utf8'), { columns: true })
// 2. Implement your algorithm logic
const scores = computeEngagementScores(rows)
// 3. Serialize and upload output
const outputCsv = stringify(scores, { header: true })
const outputKey = generateKey('snapshot', snapshotId, `${algorithmKey}.csv`)
await storage.putObject({
bucket,
key: outputKey,
body: outputCsv,
contentType: 'text/csv',
})
// 4. Return output locations
return {
outputs: {
engagement_scores: outputKey,
},
}
}Ensure all algorithm definitions have corresponding activity implementations:
pnpm algorithm:validateThis checks:
- Every definition has a matching algorithm directory with
compute.ts - Every algorithm is registered in the dispatcher
- Every algorithm is exported in the algorithms index
# Validate and build the algorithms package
pnpm --filter @reputo/reputation-algorithms build
# Build the workflows package
pnpm --filter @reputo/workflows build
# Run tests
pnpm testTo add a new version of an existing algorithm:
pnpm algorithm:create voting_engagement 2.0.0This creates a new version file. The activity implementation is shared across versions unless you need version-specific logic.
| Command | Description |
|---|---|
pnpm algorithm:create <key> <version> |
Create algorithm definition + activity scaffold |
pnpm algorithm:validate |
Validate definitions and activities are in sync |
pnpm --filter @reputo/reputation-algorithms algorithm:create <key> <version> |
Create definition only |
-
Create feature branch from
maingit checkout -b feature/your-feature-name
-
Open Pull Request to
main- Add
pullpreviewlabel for preview deployment - Ensure CI passes
- Request review from maintainers
- Add
-
Merge after approval
Released under the GPL-3.0 license. See LICENSE file for details.
![]() |
![]() |
![]() |
|---|---|---|
| Cyrille Derche | Mohammad Khaki | Behzad Rabiei |



