initial commit
All checks were successful
Build & publish Docker images / Build & push all images (push) Successful in 2s
All checks were successful
Build & publish Docker images / Build & push all images (push) Successful in 2s
This commit is contained in:
4
.gitattributes
vendored
Normal file
4
.gitattributes
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
* text=auto
|
||||
Dockerfile text eol=lf
|
||||
*.sh text eol=lf
|
||||
*.py text eol=lf
|
||||
43
.gitea/workflows/docker.yml
Normal file
43
.gitea/workflows/docker.yml
Normal file
@@ -0,0 +1,43 @@
|
||||
name: Build & publish Docker images
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
env:
|
||||
REGISTRY: git.hexadual.io
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build & push all images
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
run: |
|
||||
git clone --depth 1 \
|
||||
https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@git.hexadual.io/${{ github.repository }}.git \
|
||||
.
|
||||
git checkout ${{ github.sha }}
|
||||
|
||||
- name: Log in to registry
|
||||
run: |
|
||||
echo "${{ secrets.REGISTRY_TOKEN }}" | \
|
||||
docker login ${{ env.REGISTRY }} -u ${{ github.actor }} --password-stdin
|
||||
|
||||
- name: Build & push egg
|
||||
run: |
|
||||
docker compose build egg
|
||||
docker compose push egg
|
||||
docker tag ${{ env.REGISTRY }}/rocobo/gcp-dot-egg:latest \
|
||||
${{ env.REGISTRY }}/rocobo/gcp-dot-egg:${{ github.sha }}
|
||||
docker push ${{ env.REGISTRY }}/rocobo/gcp-dot-egg:${{ github.sha }}
|
||||
|
||||
- name: Logout
|
||||
if: always()
|
||||
run: docker logout ${{ env.REGISTRY }} || true
|
||||
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
.env
|
||||
*.db
|
||||
.DS_Store
|
||||
12
Dockerfile
Normal file
12
Dockerfile
Normal file
@@ -0,0 +1,12 @@
|
||||
FROM python:3.14-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY egg.py .
|
||||
|
||||
VOLUME ["/data"]
|
||||
|
||||
CMD ["python", "egg.py"]
|
||||
84
README.md
Normal file
84
README.md
Normal file
@@ -0,0 +1,84 @@
|
||||
# GCP Egg
|
||||
|
||||
Distributed client for the **Global Consciousness Project** — a self-hosted network variance tracker inspired by the [Global Consciousness Project](https://global-mind.org).
|
||||
|
||||
Each "egg" container draws 200 random bits per second from the OS hardware-entropy pool and submits the count of 1-bits to a central server, which runs Stouffer Z-score analysis and displays a live colored dot.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Egg containers (anyone can run)
|
||||
│ POST /api/data (one 200-bit trial per second)
|
||||
▼
|
||||
Server (FastAPI + SQLite)
|
||||
│ Stouffer Z network variance analysis every 60 s
|
||||
▼
|
||||
Website → animated dot + history chart + embeddable iframe
|
||||
```
|
||||
|
||||
The server is maintained separately. This repo contains only the egg client.
|
||||
|
||||
## Run an Egg
|
||||
|
||||
Download the compose file and start it — no building required:
|
||||
|
||||
```bash
|
||||
curl -O https://git.hexadual.io/rocobo/GCP-Dot/raw/branch/main/docker-compose.yml
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Docker will pull the pre-built image from the registry automatically. The egg will immediately start sending one trial per second and persist its ID across restarts.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Default | Description |
|
||||
|---|---|---|
|
||||
| `SERVER_URL` | `https://gcp.hexadual.io` | Server to send trials to |
|
||||
| `EGG_ID` | auto-generated | Override the egg's unique identifier |
|
||||
|
||||
The auto-generated ID is derived from a SHA-256 hash stored at `/data/egg_id` — mount a volume there to keep it stable across restarts.
|
||||
|
||||
## Published Image
|
||||
|
||||
The egg image is built and published automatically on every push to `main`:
|
||||
|
||||
```bash
|
||||
docker pull git.hexadual.io/rocobo/gcp-dot-egg:latest
|
||||
```
|
||||
|
||||
## How the Analysis Works
|
||||
|
||||
The server analyses the past hour of data every 60 seconds:
|
||||
|
||||
1. **Normalise** each trial to a Z-score: `z = (trial − 100) / √50`
|
||||
(Binomial(200, 0.5) has mean = 100, variance = 50)
|
||||
2. **Stouffer Z** per second across all active eggs: `S_t = Σzᵢ / √N`
|
||||
3. **Network variance**: `V = Σ S_t²` — follows χ²(T) under H₀
|
||||
4. **Index** = lower-tail CDF × 100
|
||||
|
||||
### Color Table
|
||||
|
||||
| Color | Index | Meaning |
|
||||
|---|---|---|
|
||||
| Blue | > 95% | Significantly small variance — deep coherence |
|
||||
| Cyan | 90–95% | Small variance — probable coherence |
|
||||
| Green | 40–90% | Normal random behavior |
|
||||
| Yellow | 10–40% | Slightly elevated variance |
|
||||
| Orange | 5–10% | Strongly elevated variance |
|
||||
| Red | < 5% | Significantly large variance |
|
||||
|
||||
## Embed the Dot
|
||||
|
||||
```html
|
||||
<iframe src="https://gcp.hexadual.io/gcp.html"
|
||||
height="48" width="48" scrolling="no" frameborder="0"></iframe>
|
||||
```
|
||||
|
||||
## Server API Reference
|
||||
|
||||
| Endpoint | Description |
|
||||
|---|---|
|
||||
| `POST /api/data` | Submit a trial `{egg_id, timestamp, trial}` |
|
||||
| `GET /api/status` | Latest analysis result |
|
||||
| `GET /api/history?limit=60` | Last N analysis records |
|
||||
| `GET /api/eggs` | Eggs active in the last 2 minutes |
|
||||
12
docker-compose.yml
Normal file
12
docker-compose.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
services:
|
||||
egg:
|
||||
image: git.hexadual.io/rocobo/gcp-dot-egg:latest
|
||||
volumes:
|
||||
- gcp_egg_data:/data
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- SERVER_URL=https://gcp.hexadual.io
|
||||
- PYTHONUNBUFFERED=1
|
||||
|
||||
volumes:
|
||||
gcp_egg_data:
|
||||
71
egg.py
Normal file
71
egg.py
Normal file
@@ -0,0 +1,71 @@
|
||||
import os
|
||||
import time
|
||||
import hashlib
|
||||
import platform
|
||||
|
||||
import requests
|
||||
|
||||
ID_FILE = "/data/egg_id"
|
||||
|
||||
|
||||
def generate_trial():
|
||||
"""Sum of 200 random bits drawn from the OS CSPRNG (hardware entropy pool)."""
|
||||
raw = os.urandom(25) # 25 bytes = 200 bits
|
||||
return sum(bin(b).count("1") for b in raw)
|
||||
|
||||
|
||||
def load_or_create_id():
|
||||
try:
|
||||
with open(ID_FILE) as f:
|
||||
egg_id = f.read().strip()
|
||||
if egg_id:
|
||||
return egg_id
|
||||
except OSError:
|
||||
pass
|
||||
egg_id = hashlib.sha256(os.urandom(32)).hexdigest()[:16]
|
||||
try:
|
||||
os.makedirs("/data", exist_ok=True)
|
||||
with open(ID_FILE, "w") as f:
|
||||
f.write(egg_id)
|
||||
except OSError:
|
||||
pass
|
||||
return egg_id
|
||||
|
||||
|
||||
def main():
|
||||
server_url = os.environ.get("SERVER_URL", "http://localhost:8000").rstrip("/")
|
||||
egg_id = os.environ.get("EGG_ID") or load_or_create_id()
|
||||
|
||||
print(f"GCP Egg id={egg_id} server={server_url} platform={platform.system()}")
|
||||
|
||||
session = requests.Session()
|
||||
errors = 0
|
||||
|
||||
while True:
|
||||
loop_start = time.time()
|
||||
timestamp = int(loop_start)
|
||||
trial = generate_trial()
|
||||
|
||||
try:
|
||||
resp = session.post(
|
||||
f"{server_url}/api/data",
|
||||
json={"egg_id": egg_id, "timestamp": timestamp, "trial": trial},
|
||||
timeout=5,
|
||||
)
|
||||
if resp.status_code == 200:
|
||||
errors = 0
|
||||
else:
|
||||
errors += 1
|
||||
if errors % 10 == 1:
|
||||
print(f"Server returned {resp.status_code} (error #{errors})")
|
||||
except Exception as exc:
|
||||
errors += 1
|
||||
if errors % 10 == 1:
|
||||
print(f"Send error (#{errors}): {exc}")
|
||||
|
||||
elapsed = time.time() - loop_start
|
||||
time.sleep(max(0.0, 1.0 - elapsed))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@@ -0,0 +1 @@
|
||||
requests>=2.32.0
|
||||
Reference in New Issue
Block a user