Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .dev.vars.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
GITHUB_APP_ID=
GITHUB_APP_INSTALLATION_ID=
GITHUB_APP_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
WORKFLOW_WEBHOOK_SECRET=
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
node_modules/
.wrangler/
.dev.vars
dist/
coverage/
.DS_Store

# Keep the approved asset; local design exploration renders remain untracked.
design/explorations/
design/concepts/
design/approved/*runtime-preview.png
147 changes: 145 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,145 @@
# EverOS-Bot
Contributor recognition and community automation bot for EverOS.
# EverOS Bot

Contributor recognition and community automation for
[EverOS](https://github.com/EverMind-AI/EverOS).

The first release generates a **First Engram** card when a real contributor
opens their first issue or has their first pull request merged. The card is
stored as an immutable PNG and posted back to the originating GitHub thread by
a GitHub App.

![EverOS First Engram contributor card](design/approved/everos-contributor-card-v1.png)

## Architecture

This project follows the webhook service boundary used by
[`nexu-io/open-design-contributor-card`](https://github.com/nexu-io/open-design-contributor-card):

```text
EverOS GitHub event
thin GitHub Actions relay ── HMAC-SHA256 ──▶ Cloudflare Worker
┌──────────────────────────────┼────────────────────┐
▼ ▼ ▼
GitHub App API D1 R2
stats + issue comment contributor state generated PNG
```

- The workflow never checks out or executes pull-request code.
- `POST /api/github/events` verifies the exact raw body with
`X-EverOS-Signature`.
- D1 stores contributor state, delivery-level ingestion records, and card
events.
- R2 stores immutable generated PNG cards.
- A hidden comment marker makes GitHub posting recoverable after partial
failures.
- GitHub notifications provide the email delivery path; the Worker does not
collect contributor email addresses.

## V1 behavior

- Supported events: `issues.opened` and merged `pull_request_target.closed`.
- Bot accounts and missing actors are ignored.
- The first qualifying event posts one welcome card.
- Later events update points and statistics without posting another welcome.
- GitHub search results use an event floor so a just-opened issue or just-merged
PR is represented even during search-index propagation delay.
- Points: first merged PR `30`, later merged PRs `12`, opened issue `5`.

## Local setup

Requirements: Node.js 20+, pnpm 10, Wrangler, and a Cloudflare account.

```bash
pnpm install
pnpm build:card-base
pnpm typecheck
pnpm test
```

Create local resources and apply the migration:

```bash
pnpm wrangler d1 create everos-bot
pnpm wrangler r2 bucket create everos-bot-card-assets
pnpm wrangler r2 bucket create everos-bot-card-assets-preview
pnpm wrangler d1 migrations apply everos-bot --local
```

Replace the placeholder D1 IDs in `wrangler.jsonc`, then:

```bash
cp .dev.vars.example .dev.vars
pnpm dev
```

## GitHub App

Create a GitHub App and install it on `EverMind-AI/EverOS`.

Repository permissions:

- Issues: **Read and write**
- Pull requests: **Read**
- Metadata: **Read**

Set Worker secrets:

```bash
pnpm wrangler secret put GITHUB_APP_ID
pnpm wrangler secret put GITHUB_APP_INSTALLATION_ID
pnpm wrangler secret put GITHUB_APP_PRIVATE_KEY
pnpm wrangler secret put WORKFLOW_WEBHOOK_SECRET
```

Deploy with `pnpm deploy`, then add these Actions secrets to the EverOS repo:

- `EVEROS_BOT_WEBHOOK_URL`: Worker origin, without a trailing slash
- `EVEROS_BOT_WEBHOOK_SECRET`: same value as the Worker secret

Copy
[`examples/everos-repository/.github/workflows/everos-bot-relay.yml`](examples/everos-repository/.github/workflows/everos-bot-relay.yml)
into the EverOS repository.

## Relay contract

The relay posts JSON to `POST /api/github/events`:

```json
{
"repository": "EverMind-AI/EverOS",
"eventName": "issues",
"action": "opened",
"deliveryId": "123456789-1",
"triggeredAt": "2026-07-22T10:00:00Z",
"payload": {}
}
```

The raw body is signed with `WORKFLOW_WEBHOOK_SECRET`; the header format is
`X-EverOS-Signature: sha256=<hex>`.

## Card assets

- Approved reference: `design/approved/everos-contributor-card-v1.png`
- Runtime base: `assets/card/everos-contributor-card-base.png`
- Rebuild command: `pnpm build:card-base`

Dynamic fields are the GitHub avatar, username, archive number, points, merged
PR count, and issue count. The four-curve EverMind logo and the GitHub Primer
Octicons are part of the locked base artwork.

## Validation

```bash
pnpm validate
```

## Attribution

The service boundary was informed by the Apache-2.0 licensed
[`nexu-io/open-design-contributor-card`](https://github.com/nexu-io/open-design-contributor-card).
GitHub contribution symbols use
[`primer/octicons`](https://github.com/primer/octicons), MIT licensed.
Binary file added assets/card/everos-contributor-card-base.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/card/git-pull-request-16.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/card/issue-opened-16.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/card/star-fill-16.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added design/approved/everos-contributor-card-v1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 48 additions & 0 deletions examples/everos-repository/.github/workflows/everos-bot-relay.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: EverOS Bot Relay

on:
issues:
types: [opened]
pull_request_target:
types: [closed]

permissions:
contents: read

jobs:
relay:
# The Worker handles the final event check too. This avoids sending unmerged PRs.
if: github.event_name != 'pull_request_target' || github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- name: Build signed relay envelope
env:
EVENT_NAME: ${{ github.event_name }}
EVENT_ACTION: ${{ github.event.action }}
REPOSITORY: ${{ github.repository }}
DELIVERY_ID: ${{ github.run_id }}-${{ github.run_attempt }}
WEBHOOK_SECRET: ${{ secrets.EVEROS_BOT_WEBHOOK_SECRET }}
run: |
jq -n \
--arg repository "$REPOSITORY" \
--arg eventName "$EVENT_NAME" \
--arg action "$EVENT_ACTION" \
--arg deliveryId "$DELIVERY_ID" \
--arg triggeredAt "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--slurpfile payload "$GITHUB_EVENT_PATH" \
'{repository:$repository,eventName:$eventName,action:$action,deliveryId:$deliveryId,triggeredAt:$triggeredAt,payload:$payload[0]}' \
> relay.json

digest="$(openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" relay.json | awk '{print $NF}')"
printf 'SIGNATURE=sha256=%s\n' "$digest" >> "$GITHUB_ENV"

- name: Relay event to EverOS Bot
env:
WEBHOOK_URL: ${{ secrets.EVEROS_BOT_WEBHOOK_URL }}
run: |
curl --fail-with-body --silent --show-error \
--retry 3 --retry-all-errors \
-X POST "$WEBHOOK_URL/api/github/events" \
-H 'content-type: application/json' \
-H "x-everos-signature: $SIGNATURE" \
--data-binary @relay.json
43 changes: 43 additions & 0 deletions migrations/0001_init.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
CREATE TABLE IF NOT EXISTS contributors (
id INTEGER PRIMARY KEY AUTOINCREMENT,
login TEXT NOT NULL UNIQUE COLLATE NOCASE,
avatar_url TEXT,
points INTEGER NOT NULL DEFAULT 0,
prs_merged INTEGER NOT NULL DEFAULT 0,
issues_opened INTEGER NOT NULL DEFAULT 0,
welcome_delivery_id TEXT,
welcomed_at TEXT,
last_seen_at TEXT NOT NULL,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);

CREATE TABLE IF NOT EXISTS card_events (
event_id TEXT PRIMARY KEY,
delivery_id TEXT NOT NULL UNIQUE,
contributor_id INTEGER NOT NULL,
recipient_login TEXT NOT NULL,
surface TEXT NOT NULL,
thread_number INTEGER NOT NULL,
comment_url TEXT,
card_object_key TEXT NOT NULL,
points INTEGER NOT NULL,
prs_merged INTEGER NOT NULL,
issues_opened INTEGER NOT NULL,
created_at TEXT NOT NULL,
FOREIGN KEY (contributor_id) REFERENCES contributors(id)
);

CREATE INDEX IF NOT EXISTS idx_card_events_recipient_created_at
ON card_events(recipient_login, created_at DESC);

CREATE TABLE IF NOT EXISTS ingestion_events (
delivery_id TEXT PRIMARY KEY,
event_name TEXT NOT NULL,
action TEXT,
actor_login TEXT,
outcome TEXT NOT NULL,
card_event_id TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
34 changes: 34 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "everos-bot",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"build:card-base": "node scripts/build-card-base.mjs",
"preview:card": "tsx scripts/render-card-preview.ts",
"dev": "wrangler dev",
"deploy": "wrangler deploy",
"check": "wrangler deploy --dry-run",
"typegen": "wrangler types",
"typecheck": "tsc --noEmit",
"test": "vitest run",
"validate": "tsc --noEmit && vitest run && wrangler deploy --dry-run"
},
"dependencies": {
"@resvg/resvg-wasm": "^2.6.2",
"jose": "^6.1.0",
"react": "^19.2.0",
"satori": "^0.12.1"
},
"devDependencies": {
"@cloudflare/workers-types": "^5.20260722.1",
"@types/node": "^24.0.0",
"@types/react": "^19.2.0",
"sharp": "^0.34.3",
"tsx": "^4.20.0",
"typescript": "^5.9.0",
"vitest": "^3.2.4",
"wrangler": "^4.26.0"
},
"packageManager": "pnpm@10.13.1"
}
Loading