Use git.flowmade.one (Gitea) as source of truth during development
Eventually dogfood by self-hosting
Related
Aether: git.flowmade.one/flowmade-one/aether
IRIS: git.flowmade.one/flowmade-one/iris
Current Gitea setup on git.flowmade.one
NATS infrastructure already deployed
KEDA already in cluster for runner scaling
This issue captures a discussion about building a Kubernetes-native git server.
## Overview
Proposal to build a modern, Kubernetes-native git server that could:
1. Replace our current Gitea instance
2. Serve as an open-source project to build awareness for Flowmade One
3. Prove our stack (Aether + IRIS) in a real application
## Architecture Alignment
This proposal aligns with our [architecture beliefs](./manifesto.md#architecture-beliefs):
| Belief | Pattern | How This Applies |
|--------|---------|------------------|
| Auditability by default | Event Sourcing | Full event-sourced domain: `RepositoryCreated`, `PullRequestOpened`, etc. Complete history for every repo and PR. |
| Business language in code | Domain-Driven Design | Aggregates map to git concepts: `Repository`, `PullRequest`, `User`, `Organization`. Ubiquitous language shared with users. |
| Independent evolution | Event-driven communication | NATS pub/sub enables real-time UI updates and CI runners without coupling. New features subscribe to existing events. |
| Explicit over implicit | Commands and Events | Clear separation: `CreateRepository` (command) → `RepositoryCreated` (event). Intent and outcome are distinct. |
See [software-architecture.md](./software-architecture.md) for full pattern documentation.
## Why Build This?
| Feature | GitHub | GitLab | Gitea | Proposed |
|---------|--------|--------|-------|----------|
| Self-hosted | ❌ Enterprise | ✅ | ✅ | ✅ |
| Cloud option | ✅ | ✅ | Limited | ✅ |
| K8s native | ❌ | Partial | ❌ | ✅ Native |
| Horizontal scale | N/A | Complex | ❌ Single | ✅ Built-in |
| Runner scaling | Manual | Manual | Manual | ✅ KEDA native |
| Event sourcing | ❌ | ❌ | ❌ | ✅ Full audit |
| Single dependency | N/A | PG+Redis+... | PostgreSQL | NATS only |
| Real-time UI | Polling | Polling | Polling | ✅ WebSocket |
## Technical Background
### How Git Servers Work
- Git itself has almost no access control - just transport (SSH/HTTP) and hooks
- Gitea/GitHub/GitLab add: users, permissions, PRs, issues, branch protection - all stored in a database
- Gitea shells out to the git binary for every operation (no persistent git daemon)
- This means storage I/O directly impacts performance
### Why Gitea Doesn't Scale Horizontally
Multiple Gitea replicas all need access to the same git repositories on disk:
- Requires RWX shared filesystem
- NFS overhead kills performance (~233 file opens per README render)
- Git's lock files create contention
- Each instance has separate caches (stale data)
GitLab solved this with **Gitaly** - a dedicated gRPC service that owns git operations, so web/API instances are stateless.
## Proposed Architecture
```
Ingress
┌───────────────────────┼───────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────┐ ┌───────────┐ ┌───────────┐
│ IRIS │ │ Git SSH │ │ Git HTTP │
│ (WASM) │ │ Gateway │ │ Gateway │
└────┬────┘ └─────┬─────┘ └─────┬─────┘
│ │ gRPC │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────┐
│ Git Server Domain │
│ │
│ Aggregates: Projections: │
│ ├── Repository ├── repo-list │
│ ├── PullRequest ├── pr-list │
│ ├── User ├── permissions │
│ └── Organization └── ssh-key-lookup │
└─────────────────────────────────────────────────────────┘
│
built on
│
┌─────────────────────────────────────────────────────────┐
│ Aether │
│ git.flowmade.one/flowmade-one/aether │
│ │
│ - Aggregate lifecycle - Cluster primitives │
│ - Event store - Sharding │
│ - Projections framework - Leader election │
└─────────────────────────────────────────────────────────┘
│
powered by
│
┌─────────────────────────────────────────────────────────┐
│ NATS JetStream │
│ (implementation detail managed by Aether) │
└─────────────────────────────────────────────────────────┘
Separate concern:
┌─────────────────────────────────────────────────────────┐
│ Git Storage Service (StatefulSet) │
│ - gRPC API wrapping git operations │
│ - Sharded by consistent hashing │
│ - Local SSD or hcloud-volumes per shard │
└─────────────────────────────────────────────────────────┘
CI/CD:
┌─────────────────────────────────────────────────────────┐
│ Action Runners │
│ - KEDA ScaledJob based on NATS queue depth │
│ - Pull jobs from NATS, stream logs back │
└─────────────────────────────────────────────────────────┘
```
## Bounded Contexts
Following DDD patterns, the git server has these contexts:
| Context | Aggregates | Responsibility |
|---------|------------|----------------|
| **Repository** | Repository, Branch, Commit | Git storage, branches, commits, files |
| **Collaboration** | PullRequest, Review, Comment | PRs, reviews, discussions |
| **Identity** | User, Organization, SSHKey | Users, orgs, permissions, keys |
| **CI/CD** | Pipeline, Job, Artifact | Runners, jobs, logs, artifacts |
Each context owns its aggregates and publishes events for cross-context communication.
## Key Design Decisions
### 1. Built on Aether
The git server is an **Aether application**. Domain logic uses Aether's primitives:
```go
type Repository struct {
aether.AggregateBase
Name string
Owner string
Visibility Visibility
}
func (r *Repository) HandleCommand(cmd aether.Command) ([]aether.Event, error) {
switch c := cmd.(type) {
case *CreateRepository:
return []aether.Event{&RepositoryCreated{...}}, nil
}
}
func (r *Repository) ApplyEvent(evt aether.Event) {
switch e := evt.(type) {
case *RepositoryCreated:
r.Name = e.Name
}
}
```
This proves Aether works in a real application before betting the low-code platform on it.
### 2. NATS as Infrastructure (via Aether)
NATS is an implementation detail managed by Aether, not a direct dependency:
- Event store (JetStream streams)
- Read models (KV buckets)
- Service communication
- Job queues for CI
- Real-time pub/sub to UI
### 3. IRIS for Frontend
WASM-based UI with reactive signals. WebSocket connection for real-time updates.
### 4. Kubernetes-Native Deployment
```bash
helm install gitserver flowmade/gitserver \
--set domain=git.company.com \
--set auth.oidc.issuer=https://dex.company.com
```
## Components to Build
| Component | Effort | Notes |
|-----------|--------|-------|
| Domain model | Low | Go structs, Aether aggregates |
| Git Storage Service | Medium-High | gRPC wrapper around git |
| SSH Gateway | Medium | Auth + route to storage |
| HTTP Git Gateway | Low | Standard smart protocol |
| IRIS UI | High | File browser, PR view, diff, etc. |
| Runner integration | Medium | NATS queue + KEDA |
**Already available:**
- Aether (`git.flowmade.one/flowmade-one/aether`) - ES runtime
- IRIS (`git.flowmade.one/flowmade-one/iris`) - UI framework
## Open Questions
### Naming
- Need a name recognizable as a git server
- Need available domain
- Options: Gitquay, Githarbor, Gitkeep, Gitledger, etc.
- Should it be under Flowmade One brand or separate identity?
### Positioning
- Is Flowmade One the product name or company with separate products?
- Git server as part of "One platform" vs separate product?
- Cloud version: git.flowmade.one? Separate domain?
### Strategy
- Open-source to build awareness for Flowmade One low-code SaaS
- Self-hosted option + cloud offering (open core model)
- Use git.flowmade.one (Gitea) as source of truth during development
- Eventually dogfood by self-hosting
## Related
- Aether: `git.flowmade.one/flowmade-one/aether`
- IRIS: `git.flowmade.one/flowmade-one/iris`
- Current Gitea setup on git.flowmade.one
- NATS infrastructure already deployed
- KEDA already in cluster for runner scaling
---
*This issue captures a discussion about building a Kubernetes-native git server.*
This proposal now aligns with a core belief added to the manifesto:
Resource Efficiency
Software should run well on modest hardware
Cloud cost and energy consumption matter
ARM64-native where possible - better performance per watt
Bloated software is a sign of poor engineering, not rich features
GitLab fails this principle. Gitea fails on scalability. Building our own solves both.
Specific Pain Points with Gitea/Forgejo
Forgejo CLI gaps - No action runner support in CLI, had to switch to Gitea
Gitea CLI gaps - Had to fork and maintain tea to add runner features
HA doesn't work - RWX shared filesystem (Longhorn) kills performance due to git's file access patterns (~233 file opens per README render)
GitLab solved it but too heavy - Gitaly is the right architecture, but GitLab's resource appetite is a disqualifier
Reframed Purpose
This isn't just "build a git server" - it's:
Prove the stack - Validate ES primitives, NATS-only, IRIS in a real application before betting the low-code platform on them
Scratch our own itch - Real pain that isn't going away
Live our values - Resource-efficient, ARM64-native, K8s-native
## Additional Context
### Manifesto Alignment
This proposal now aligns with a core belief added to the manifesto:
**Resource Efficiency**
- Software should run well on modest hardware
- Cloud cost and energy consumption matter
- ARM64-native where possible - better performance per watt
- Bloated software is a sign of poor engineering, not rich features
GitLab fails this principle. Gitea fails on scalability. Building our own solves both.
### Specific Pain Points with Gitea/Forgejo
1. **Forgejo CLI gaps** - No action runner support in CLI, had to switch to Gitea
2. **Gitea CLI gaps** - Had to fork and maintain tea to add runner features
3. **HA doesn't work** - RWX shared filesystem (Longhorn) kills performance due to git's file access patterns (~233 file opens per README render)
4. **GitLab solved it but too heavy** - Gitaly is the right architecture, but GitLab's resource appetite is a disqualifier
### Reframed Purpose
This isn't just "build a git server" - it's:
1. **Prove the stack** - Validate ES primitives, NATS-only, IRIS in a real application before betting the low-code platform on them
2. **Scratch our own itch** - Real pain that isn't going away
3. **Live our values** - Resource-efficient, ARM64-native, K8s-native
Used 'aether' instead of 'eskit' for the ES library
Renamed internal components for clarity (lyra→designer, aether-backend→server)
The 'Arcadia Monorepo Impact' and 'Potential Repo Split' sections of this issue are now complete. The remaining content about the git server architecture is still relevant if this project moves forward.
## Update: Monorepo Split Complete
The split discussed in this issue has been completed via #54. Here's what was done:
**Created external repos (Apache 2.0):**
- `git.flowmade.one/flowmade-one/iris` - WASM reactive UI framework
- `git.flowmade.one/flowmade-one/aether` - Distributed actor/ES primitives (was proposed as 'eskit')
**Aether includes:**
- Event/EventStore interfaces
- Memory and JetStream store implementations
- NATS event bus
- Cluster primitives (consistent hashing, leader election, sharding)
- EventStorming model types
**Arcadia (proprietary) keeps:**
- `pkg/adl/` - ADL compiler
- `pkg/aether/` - Runtime layer (imports external aether)
- `cmd/server/` - Backend entry point
- `web/designer/` - EventStorming canvas UI
**Naming:**
- Used 'aether' instead of 'eskit' for the ES library
- Renamed internal components for clarity (lyra→designer, aether-backend→server)
The 'Arcadia Monorepo Impact' and 'Potential Repo Split' sections of this issue are now complete. The remaining content about the git server architecture is still relevant if this project moves forward.
The architecture repository now documents our beliefs and patterns in software-architecture.md. This proposal aligns well with our organizational approach:
Beliefs → Patterns → This Proposal
Belief
Pattern
How This Proposal Applies
Auditability by default
Event Sourcing
Full event-sourced domain: RepositoryCreated, PullRequestOpened, etc. Complete history for every repo and PR.
Business language in code
Domain-Driven Design
Aggregates map to git concepts: Repository, PullRequest, User, Organization. Ubiquitous language shared with users.
Independent evolution
Event-driven communication
NATS pub/sub enables real-time UI updates and CI runners without coupling. New features subscribe to existing events.
Explicit over implicit
Commands and Events
Clear separation: CreateRepository (command) → RepositoryCreated (event). Intent and outcome are distinct.
Bounded Contexts (Proposed)
Following DDD patterns, the git server could have these contexts:
## Architecture Alignment Update
The architecture repository now documents our beliefs and patterns in `software-architecture.md`. This proposal aligns well with our organizational approach:
### Beliefs → Patterns → This Proposal
| Belief | Pattern | How This Proposal Applies |
|--------|---------|---------------------------|
| Auditability by default | Event Sourcing | Full event-sourced domain: `RepositoryCreated`, `PullRequestOpened`, etc. Complete history for every repo and PR. |
| Business language in code | Domain-Driven Design | Aggregates map to git concepts: `Repository`, `PullRequest`, `User`, `Organization`. Ubiquitous language shared with users. |
| Independent evolution | Event-driven communication | NATS pub/sub enables real-time UI updates and CI runners without coupling. New features subscribe to existing events. |
| Explicit over implicit | Commands and Events | Clear separation: `CreateRepository` (command) → `RepositoryCreated` (event). Intent and outcome are distinct. |
### Bounded Contexts (Proposed)
Following DDD patterns, the git server could have these contexts:
- **Repository** - git storage, branches, commits, files
- **Collaboration** - pull requests, reviews, comments
- **Identity** - users, organizations, SSH keys, permissions
- **CI/CD** - runners, jobs, logs, artifacts
Each context owns its aggregates and publishes events for cross-context communication.
### Reference
See [software-architecture.md](./software-architecture.md) for full pattern documentation and [manifesto.md](./manifesto.md#architecture-beliefs) for the underlying beliefs.
NATS becomes an implementation detail that Aether manages. The git server is an Aether application with domain-specific aggregates and projections.
This also fulfills the stated goal of "proving the stack" - real usage of Aether reveals API gaps before betting the low-code platform on it.
## Clarification: Built on Aether
The git server should be **built on Aether**, not extract primitives from it or use NATS directly.
Since the monorepo split (#54), Aether exists as `git.flowmade.one/flowmade-one/aether` with:
- Event/EventStore interfaces
- JetStream store implementation
- Cluster primitives (consistent hashing, leader election, sharding)
- NATS event bus
### Updated Architecture View
```
┌─────────────────────────────────────────────────────────┐
│ Git Server Domain │
│ │
│ Aggregates: Projections: │
│ ├── Repository ├── repo-list │
│ ├── PullRequest ├── pr-list │
│ ├── User ├── permissions │
│ └── Organization └── ssh-key-lookup │
└─────────────────────────────────────────────────────────┘
│
built on
│
┌─────────────────────────────────────────────────────────┐
│ Aether │
│ │
│ - Aggregate lifecycle - Cluster primitives │
│ - Event store - Sharding │
│ - Projections framework - Leader election │
└─────────────────────────────────────────────────────────┘
│
powered by
│
┌─────────────────────────────────────────────────────────┐
│ NATS JetStream │
└─────────────────────────────────────────────────────────┘
```
NATS becomes an implementation detail that Aether manages. The git server is an **Aether application** with domain-specific aggregates and projections.
This also fulfills the stated goal of "proving the stack" - real usage of Aether reveals API gaps before betting the low-code platform on it.
The vision and initial structure have been established. Work will continue in that repo.
Proposal has been turned into a dedicated repository: https://git.flowmade.one/flowmade-one/arbor
The vision and initial structure have been established. Work will continue in that repo.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Overview
Proposal to build a modern, Kubernetes-native git server that could:
Architecture Alignment
This proposal aligns with our architecture beliefs:
RepositoryCreated,PullRequestOpened, etc. Complete history for every repo and PR.Repository,PullRequest,User,Organization. Ubiquitous language shared with users.CreateRepository(command) →RepositoryCreated(event). Intent and outcome are distinct.See software-architecture.md for full pattern documentation.
Why Build This?
Technical Background
How Git Servers Work
Why Gitea Doesn't Scale Horizontally
Multiple Gitea replicas all need access to the same git repositories on disk:
GitLab solved this with Gitaly - a dedicated gRPC service that owns git operations, so web/API instances are stateless.
Proposed Architecture
Bounded Contexts
Following DDD patterns, the git server has these contexts:
Each context owns its aggregates and publishes events for cross-context communication.
Key Design Decisions
1. Built on Aether
The git server is an Aether application. Domain logic uses Aether's primitives:
This proves Aether works in a real application before betting the low-code platform on it.
2. NATS as Infrastructure (via Aether)
NATS is an implementation detail managed by Aether, not a direct dependency:
3. IRIS for Frontend
WASM-based UI with reactive signals. WebSocket connection for real-time updates.
4. Kubernetes-Native Deployment
Components to Build
Already available:
git.flowmade.one/flowmade-one/aether) - ES runtimegit.flowmade.one/flowmade-one/iris) - UI frameworkOpen Questions
Naming
Positioning
Strategy
Related
git.flowmade.one/flowmade-one/aethergit.flowmade.one/flowmade-one/irisThis issue captures a discussion about building a Kubernetes-native git server.
Additional Context
Manifesto Alignment
This proposal now aligns with a core belief added to the manifesto:
Resource Efficiency
GitLab fails this principle. Gitea fails on scalability. Building our own solves both.
Specific Pain Points with Gitea/Forgejo
Reframed Purpose
This isn't just "build a git server" - it's:
Update: Monorepo Split Complete
The split discussed in this issue has been completed via #54. Here's what was done:
Created external repos (Apache 2.0):
git.flowmade.one/flowmade-one/iris- WASM reactive UI frameworkgit.flowmade.one/flowmade-one/aether- Distributed actor/ES primitives (was proposed as 'eskit')Aether includes:
Arcadia (proprietary) keeps:
pkg/adl/- ADL compilerpkg/aether/- Runtime layer (imports external aether)cmd/server/- Backend entry pointweb/designer/- EventStorming canvas UINaming:
The 'Arcadia Monorepo Impact' and 'Potential Repo Split' sections of this issue are now complete. The remaining content about the git server architecture is still relevant if this project moves forward.
Architecture Alignment Update
The architecture repository now documents our beliefs and patterns in
software-architecture.md. This proposal aligns well with our organizational approach:Beliefs → Patterns → This Proposal
RepositoryCreated,PullRequestOpened, etc. Complete history for every repo and PR.Repository,PullRequest,User,Organization. Ubiquitous language shared with users.CreateRepository(command) →RepositoryCreated(event). Intent and outcome are distinct.Bounded Contexts (Proposed)
Following DDD patterns, the git server could have these contexts:
Each context owns its aggregates and publishes events for cross-context communication.
Reference
See software-architecture.md for full pattern documentation and manifesto.md for the underlying beliefs.
Clarification: Built on Aether
The git server should be built on Aether, not extract primitives from it or use NATS directly.
Since the monorepo split (#54), Aether exists as
git.flowmade.one/flowmade-one/aetherwith:Updated Architecture View
NATS becomes an implementation detail that Aether manages. The git server is an Aether application with domain-specific aggregates and projections.
This also fulfills the stated goal of "proving the stack" - real usage of Aether reveals API gaps before betting the low-code platform on it.
Proposal has been turned into a dedicated repository: https://git.flowmade.one/flowmade-one/arbor
The vision and initial structure have been established. Work will continue in that repo.