Establishes Arbor as a Kubernetes-native git server with event-sourced metadata, designed for AI-assisted software development workflows. Key aspects: - Event sourcing for all metadata (issues, PRs, reviews) - Gitaly-style git storage for horizontal scaling - DDD bounded contexts (Repository, Collaboration, Planning, Identity) - First-class AI integration with structured issue data - Built on Aether and IRIS Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
3.9 KiB
3.9 KiB
Arbor
Kubernetes-native git server with event-sourced metadata, built for AI-assisted software development.
Organization Context
This repo is part of Flowmade. See:
- Organization manifesto - who we are, what we believe
- Vision - what this specific product does
Related Projects
- Aether - Event sourcing runtime (Arbor is built on this)
- IRIS - UI framework (for Arbor's web interface)
- Architecture - AI workflow commands used with Arbor
Setup
git clone git@git.flowmade.one:flowmade-one/arbor.git
cd arbor
go mod download
Requires NATS server for integration tests:
brew install nats-server
nats-server -js
Project Structure
arbor/
├── cmd/
│ └── arbor/ # Main binary
├── internal/
│ ├── domain/ # DDD aggregates and events
│ │ ├── repository/ # Repository aggregate
│ │ ├── issue/ # Issue aggregate
│ │ ├── pullrequest/# PullRequest aggregate
│ │ └── ...
│ ├── git/ # Git storage service
│ ├── api/ # gRPC and HTTP APIs
│ └── projection/ # Read models
├── deploy/
│ └── helm/ # Kubernetes deployment
└── web/ # IRIS-based UI
Development
make build # Build the binary
make test # Run tests
make lint # Run linters
Architecture
Event Sourcing for Metadata
All git metadata (issues, PRs, reviews, comments, milestones) is event-sourced using Aether:
// Issue aggregate
type Issue struct {
aether.AggregateBase
Title string
Description string
State IssueState
Labels []string
}
// Commands produce events
func (i *Issue) HandleCommand(cmd aether.Command) ([]aether.Event, error) {
switch c := cmd.(type) {
case *CreateIssue:
return []aether.Event{&IssueCreated{...}}, nil
case *CloseIssue:
return []aether.Event{&IssueClosed{...}}, nil
}
}
// Events rebuild state
func (i *Issue) ApplyEvent(evt aether.Event) {
switch e := evt.(type) {
case *IssueCreated:
i.Title = e.Title
i.State = Open
case *IssueClosed:
i.State = Closed
}
}
Git Storage Service
Inspired by GitLab's Gitaly - a dedicated service that owns git operations:
- gRPC API for all git operations
- Sharded by consistent hashing on repository path
- Local SSD storage per shard (no NFS)
- Horizontal scaling via StatefulSet
Bounded Contexts
| Context | Aggregates | Events |
|---|---|---|
| Repository | Repository, Branch | RepositoryCreated, BranchCreated, CommitPushed |
| Collaboration | PullRequest, Review | PullRequestOpened, ReviewSubmitted, PullRequestMerged |
| Planning | Issue, Milestone, Release | IssueCreated, IssueClosed, MilestoneCompleted |
| Identity | User, Organization | UserCreated, OrganizationCreated, MemberAdded |
AI Integration Points
Arbor exposes structured data for AI assistants:
// Issues have structured fields AI can parse
type Issue struct {
Title string
Description string
AcceptanceCriteria []Criterion // Testable requirements
AffectedFiles []string // Hint for where to look
Dependencies []IssueRef // What blocks this
VerticalSlice *SliceRef // Parent feature
}
Key Patterns
- Events are truth - All metadata changes are events, never direct mutations
- Git is separate - Git storage is a dedicated service, not part of the domain
- DDD aggregates - Repository, Issue, PullRequest are real aggregates with behavior
- Kubernetes-native - Designed for K8s from day one, not adapted after