Files
arbor/CLAUDE.md
Hugo Nijhuis 84509c19e0 Add initial vision and project context
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>
2026-01-10 19:10:44 +01:00

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:

  • 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