- TypeScript 76.9%
- Go 17.4%
- HTML 1.7%
- Shell 1.4%
- JavaScript 0.8%
- Other 1.6%
|
All checks were successful
Use one latest deployment per app ordered by attempt creation time so live project updates cannot be masked by older null deployment timestamps. |
||
|---|---|---|
| .agents/skills/react-doctor | ||
| .bob/skills/react-doctor | ||
| .claude | ||
| .forge/workflows | ||
| .forgejo | ||
| .gitea | ||
| .github | ||
| .kiro/skills/react-doctor | ||
| agent | ||
| android | ||
| apps | ||
| docs | ||
| infra | ||
| ios | ||
| npm | ||
| ops/ci-runners | ||
| packages | ||
| patches | ||
| plans | ||
| scripts | ||
| skills | ||
| tooling | ||
| .dockerignore | ||
| .env.example | ||
| .env.production.example | ||
| .forgegraph.yaml | ||
| .gitignore | ||
| .gitleaks.toml | ||
| .npmrc | ||
| .nvmrc | ||
| AGENTS.md | ||
| ARCHITECTURE.md | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| CODE_OF_CONDUCT.md | ||
| CONTEXT.md | ||
| CONTRIBUTING.md | ||
| DESIGN.md | ||
| docker-compose.prod.yml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| FAB_DESIGN.md | ||
| flake.lock | ||
| flake.nix | ||
| LICENSE | ||
| package.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
| SECURITY.md | ||
| STAGES.md | ||
| TODOS.md | ||
| turbo.json | ||
ForgeGraph
Your delivery graph, not your deployment log.
Live instance: forgegraf.com — the control plane runs on Cloudflare
Workers and orchestrates a fleet of Hetzner and homelab nodes. It deploys itself: every commit to
main ships through the pipeline described below.
The full landing page and the documentation site — both served by the app in this repo.
ForgeGraph is a Nix-native delivery and configuration platform. It tracks work items, changesets, and runtime evidence from first draft through production with real evidence — builds, tests, coverage, deployments, health checks, and alerts — all linked by stable work and changeset identity.
Built on Jujutsu's changeset model. Deploys Nix closures. No Docker. No Kubernetes. No YAML.
A self-hosted, Nix-native PaaS for indie hackers and small teams escaping cloud rent — see Positioning for the one-liner, category, differentiation pillars, and who it's not for. ⚠️ Early prototype: the delivery graph and Nix deploys work today; multi-tenancy, billing, and fleet scale are early.
Who is it for? See the Target Segments & ICP Playbook and market positioning — indie developers and small teams shipping web services on machines they own.
Quick Start
1. Bootstrap a node
curl -fsSL https://forgegraf.com/bootstrap | sudo sh
Installs the ForgeGraph agent on any Linux machine with Nix and systemd (Ubuntu, Debian, NixOS). The agent dials outbound only — no inbound ports, no SSH keys held by the control plane.
2. Install the CLI
npm install -g @forgegraph/cli
forge login --server https://forgegraf.com --token YOUR_TOKEN
Or via Nix:
nix run github:gmackorg/ForgeGraph#cli -- login --server https://forgegraf.com
The binary installs as both forge and fg — forge is the preferred name, fg is kept as an
alias for older muscle memory.
3. Deploy
forge deploy create production
Point --server at your own instance if you self-host instead of using
forgegraf.com.
See docs/forge-cli.md for the full CLI reference, including
forge db list, forge db url, and forge db connect for reaching managed Postgres
databases over Tailscale.
Running in production
This is a working system, not a demo. The instance at forgegraf.com currently runs:
| Fleet | 6 registered nodes — 4 Hetzner VPS + 2 homelab machines, meshed over Tailscale |
| Apps | 68 registered, 298 active deployments |
| History | 666 deployments and 2,656 builds since the first deploy on 2026-05-02 |
| Self-hosting | ForgeGraph deploys itself: merges to main ship through its own pipeline |
| Also self-hosted | its Git server (Forgejo), npm registry (Verdaccio + scanning), and Postgres |
It is also its own worst customer — the platform runs the apps that report the bugs that drive the roadmap. Several of the incidents in field reports were found because ForgeGraph broke ForgeGraph.
Features
- Work graph — canonical work items, planning artifacts, and task/decomposition relationships
- Changeset tracking — JJ-native identity that persists through rebases, amendments, and force-pushes
- Delivery evidence — builds, tests, coverage, artifacts, deployments as an append-only graph
- Release gates — evidence-based promotion through staging, canary, production
- Nix deployments — pre-built closures distributed via binary cache, deployed in seconds
- NixOS configuration — visual editor for NixOS system configs with drift detection
- Fleet management — interactive topology view, rolling updates, blue-green deployments
- Real observability — Prometheus metrics, Loki logs, Grafana dashboards
- Alerting — configurable alert rules with Slack/Discord/webhook notifications
- Teams & billing — multi-user with Free/Pro/Enterprise tiers
- Security — AES-256-GCM secret encryption, constant-time token verification
Architecture
The control plane is a Cloudflare Worker. It never connects into your machines: each node runs a small Go agent that polls outbound over HTTPS and holds a WebSocket to the hub for dispatch. That inversion is the core security property — your servers need no inbound ports and the platform holds no SSH keys.
flowchart TB
subgraph cp["Control plane — hosted (Cloudflare Workers)"]
web["Next.js app + tRPC API<br/>forgegraf.com"]
hub["WebSocket hub<br/>ws.forgegraf.com"]
pg[("Postgres<br/>via Hyperdrive tunnel")]
web <--> pg
hub <--> pg
end
subgraph src["Source of truth — also self-hosted"]
forgejo["Forgejo<br/>git.forgegraf.com"]
registry["npm registry<br/>Verdaccio + scanning"]
end
subgraph fleet["Your machines — you own these"]
agent["forgegraph-agent (Go, stdlib only)"]
subgraph sandbox["Per-app sandbox"]
netns["network namespace<br/>veth + DNAT ingress"]
nft["nftables egress policy<br/>default-deny"]
unit["systemd unit<br/>bwrap + Nix closure"]
end
agent --> netns
agent --> nft
agent --> unit
end
web -->|"deploy / job / CI dispatch"| hub
agent -.->|"outbound poll + WebSocket<br/>no inbound ports"| hub
agent -->|"health, metrics, deploy evidence"| web
forgejo -->|"webhooks: push, PR, merge"| web
agent -->|"clone + build Nix closure"| forgejo
agent -->|"publish / consume packages"| registry
Deployment targets. Web apps deploy to Cloudflare Workers; long-running services (Go binaries, workers, bots) deploy to fleet nodes as Nix closures activated by systemd. Both paths report the same evidence back into the delivery graph.
What the agent does on a node: allocates an IP and network namespace per app, wires ingress DNAT (including the hairpin rule for a colocated edge proxy), loads a default-deny nftables egress policy, writes and enables the systemd unit, runs migrations, health-checks, and rolls back on failure. It persists each sandbox's runtime spec to disk so a node reboot reconstructs namespaces, firewall rules, and services without the control plane being reachable.
Engineering notes
Start here: Engineering notes — a written case study of the seven problems that were genuinely hard, what the diagnosis actually looked like, and what changed as a result. Most of them share a shape: the system reported success while doing nothing.
The rest of the written record:
- Architecture — system design, source-of-truth boundaries, non-goals, and the promotion model. CONTEXT.md is the domain glossary.
- Decision records — 90+ ADRs, including the ones that rejected options: no Kubernetes, no Docker, no YAML pipelines.
- Field reports — postmortems written against production incidents: a systemd unit quoting bug that broke deploys fleet-wide, a deploy-observability outage, and broken corepack provisioning on the build agent.
- Design plans — the working design archive (WebSocket hub, Cloudflare Workers deploys, Postgres mesh, sandbox hardening), dated and kept as written rather than tidied after the fact.
A few problems worth reading about, because the diagnosis was harder than the fix: an nftables
egress policy that loaded into the host namespace instead of the app's and silently broke
outbound traffic on the node; a colocated edge proxy whose requests bypassed PREROUTING and so
never hit the sandbox until a hairpin DNAT rule was added; and a Go net/http upload that stalled
against the Cloudflare edge purely as a function of body size, found with GODEBUG=http2debug=1
against the live agent after isolated reproductions all passed.
Install from Nix
{
inputs.forgegraph.url = "github:gmackorg/ForgeGraph";
# The agent
environment.systemPackages = [ inputs.forgegraph.packages.${system}.agent ];
# The CLI
environment.systemPackages = [ inputs.forgegraph.packages.${system}.cli ];
# Backward-compatible alias: inputs.forgegraph.packages.${system}.fg
# ForgeGraph as a NixOS service
imports = [ inputs.forgegraph.nixosModules.default ];
services.forgegraph = {
enable = true;
environmentFile = "/etc/forgegraph/env";
agent.enable = true;
agent.environmentFile = "/etc/forgegraph/agent.json";
};
}
Development
pnpm install # Install dependencies
pnpm dev # Start development server
pnpm build # Production build
cd agent && go build -o forgegraph-agent ./... # Build agent
cd agent && go build -o fg ./cmd/fg # Build CLI (fg)
Contributing
ForgeGraph is early-stage open source (MIT). We want contributors, but we are still hardening reliability — community process is intentional and lightweight.
- How to contribute:
CONTRIBUTING.md - Code of Conduct:
CODE_OF_CONDUCT.md - Good first issues: label
good first issueon the issue tracker - Community / launch policy (maintainers):
docs/community/strategy.mdanddocs/community/MAINTAINERS.md
Primary community surface is the issue tracker (and Discussions when enabled). There is no public Discord/Slack yet — that is deliberate for a small maintainer team.
Stack
| Component | Technology |
|---|---|
| Web | Next.js 16, React 19, Tailwind CSS 4 |
| API | tRPC, Drizzle ORM, PostgreSQL 17 |
| Agent | Go 1.25 (stdlib only, no third-party deps) |
| Deploy | Nix flakes, systemd |
| Monitor | Prometheus, Loki, Grafana |
| Design | Newsreader, Public Sans, IBM Plex Mono |
GTM / positioning
- Positioning:
docs/gtm/POSITIONING.md - Competitive battlecard (v0):
docs/gtm/battlecard-v0.md - Product intent:
docs/PRODUCT_INTENT.md
License
MIT — see also license tradeoffs and relicense guidance in docs/community/strategy.md (pending legal skim).
