From b1a2ba84609705053b8f19d79853a5bbff16a359 Mon Sep 17 00:00:00 2001 From: Eran Cohen Date: Mon, 3 Aug 2026 09:49:31 +0300 Subject: [PATCH 1/2] OSAC-3557: Add AI-assisted development infrastructure to mono-repo Add root CLAUDE.md/AGENTS.md with cross-cutting project coordination (component table, change order, git workflow, deployment, enhancement proposals, Jira conventions). Add .claude/ infrastructure (settings, 4 auto-loaded rules, session hooks) and tools/bootstrap.sh to install flightctl/ai-workflows. OSAC-specific skills will be installed from a separate repo. Assisted-by: Claude Code Signed-off-by: Eran Cohen --- .claude/hooks/statusline.sh | 46 +++++++++++++++ .claude/hooks/update-ai-context.sh | 51 +++++++++++++++++ .claude/rules/architecture-patterns.md | 58 +++++++++++++++++++ .claude/rules/cli-ux.md | 20 +++++++ .claude/rules/networking-design-alignment.md | 3 + .claude/rules/request-path-tracing.md | 17 ++++++ .claude/settings.json | 43 ++++++++++++++ .gitignore | 9 +++ AGENTS.md | 60 ++++++++++++++++++++ CLAUDE.md | 1 + tools/bootstrap.sh | 54 ++++++++++++++++++ 11 files changed, 362 insertions(+) create mode 100755 .claude/hooks/statusline.sh create mode 100755 .claude/hooks/update-ai-context.sh create mode 100644 .claude/rules/architecture-patterns.md create mode 100644 .claude/rules/cli-ux.md create mode 100644 .claude/rules/networking-design-alignment.md create mode 100644 .claude/rules/request-path-tracing.md create mode 100644 .claude/settings.json create mode 100644 AGENTS.md create mode 100644 CLAUDE.md create mode 100755 tools/bootstrap.sh diff --git a/.claude/hooks/statusline.sh b/.claude/hooks/statusline.sh new file mode 100755 index 0000000000..d441b72b89 --- /dev/null +++ b/.claude/hooks/statusline.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# Project statusline: extends user statusline with osac + ai-workflows sync status + +input=$(cat) + +project_dir="${1:-}" + +if command -v jq >/dev/null 2>&1 && [[ -f "${HOME}/.claude/settings.json" ]]; then + USER_STATUSLINE_CMD=$(jq -r '.statusLine.command // empty' "${HOME}/.claude/settings.json" 2>/dev/null) + if [[ -n "${USER_STATUSLINE_CMD}" ]]; then + printf "%s\n" "$input" | bash -c "${USER_STATUSLINE_CMD}" + fi +fi + +GREEN='\033[32m' +YELLOW='\033[33m' +GRAY='\033[90m' +RESET='\033[0m' + +log_info() { printf '%b%s%b' "$GREEN" "$1" "$RESET"; } +log_warning() { printf '%b%s%b' "$YELLOW" "$1" "$RESET"; } +log_muted() { printf '%b%s%b' "$GRAY" "$1" "$RESET"; } + +repo_status() { + local dir="$1" name="$2" + [[ -d "$dir" ]] || { log_muted "$name: not found"; return; } + + local branch behind + branch=$(git -C "$dir" branch --show-current 2>/dev/null) || branch="detached" + [[ -n "$branch" ]] || branch="detached" + behind=$(git -C "$dir" rev-list HEAD..origin/main --count 2>/dev/null) || { log_muted "$name: $branch ?"; return; } + + if [[ "$behind" -eq 0 ]]; then + log_info "$name: $branch ✓" + else + log_warning "$name: $branch ↓${behind} behind" + fi +} + +REPO_DIR="${project_dir:-$(printf '%s' "$input" | jq -r '.workspace.project_dir // empty' 2>/dev/null)}" +AI_DIR="${HOME}/.ai-workflows" + +ws=$(repo_status "$REPO_DIR" "osac") +ai=$(repo_status "$AI_DIR" "ai-workflows") + +printf '%b %b %b\n' "$ws" "${GRAY}|${RESET}" "$ai" diff --git a/.claude/hooks/update-ai-context.sh b/.claude/hooks/update-ai-context.sh new file mode 100755 index 0000000000..8a4014de8a --- /dev/null +++ b/.claude/hooks/update-ai-context.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +# SessionStart hook: fetch+rebase osac (if on main) and ai-workflows +# so the AI agent always has the latest CLAUDE.md, rules, and skills. + +REPO_DIR="${CLAUDE_PROJECT_DIR:-$(cd "$(dirname "$0")/../.." && pwd)}" + +fetch_and_rebase() { + local dir="$1" name="$2" only_on_main="${3:-false}" + [[ -d "$dir" ]] || return 0 + + local branch + branch="$(git -C "$dir" branch --show-current 2>/dev/null)" || return 0 + + if [[ "$only_on_main" == "true" && "$branch" != "main" ]]; then + git -C "$dir" fetch origin -q 2>/dev/null || true + local behind + behind=$(git -C "$dir" rev-list HEAD..origin/main --count 2>/dev/null || echo "?") + if [[ "$behind" == "0" ]]; then + echo "$name: on '$branch', up to date with main" + else + echo "$name: on '$branch', $behind commits behind main — consider running: git rebase origin/main" + fi + return 0 + fi + + if ! git -C "$dir" fetch origin -q 2>/dev/null; then + echo "$name: fetch failed" + return 0 + fi + + local head_before head_after + head_before="$(git -C "$dir" rev-parse HEAD)" + + trap 'git -C "$dir" rebase --abort 2>/dev/null || true' INT TERM + + if git -C "$dir" rebase origin/main --autostash -q >/dev/null 2>&1; then + head_after="$(git -C "$dir" rev-parse HEAD)" + if [[ "$head_before" == "$head_after" ]]; then + echo "$name: up to date" + else + echo "$name: updated" + fi + else + git -C "$dir" rebase --abort 2>/dev/null || true + echo "$name: rebase conflict, skipped" + fi + trap - INT TERM +} + +fetch_and_rebase "$REPO_DIR" "osac" true +fetch_and_rebase "${HOME}/.ai-workflows" "ai-workflows" diff --git a/.claude/rules/architecture-patterns.md b/.claude/rules/architecture-patterns.md new file mode 100644 index 0000000000..a4eb14d925 --- /dev/null +++ b/.claude/rules/architecture-patterns.md @@ -0,0 +1,58 @@ +# Architecture Patterns + +## Multi-tenancy + +Tenant-scoped resources include tenant isolation metadata: +- `metadata.annotations["osac.openshift.io/tenant"]` for tenant scoping +- `metadata.annotations["osac.openshift.io/owner-reference"]` for resource hierarchy +- OPA policies enforce isolation at runtime +- Never skip tenant isolation metadata in new tenant-scoped resources +- Use annotations for owner references, not separate fields +- Provider-defined resources (NetworkClass, ExternalIPPool) are exempt — tenants do not interact with them directly + +## Resource Hierarchy + +```text +Cluster Resources: + ClusterOrder → provisions OpenShift clusters via Hosted Control Planes + +Compute Resources: + ComputeInstance → KubeVirt VM, attached to Subnets + SecurityGroups + +Networking Resources: + NetworkClass (platform-defined, read-only for tenants) + └── VirtualNetwork (tenant L2 network with CIDR) + ├── Subnet (CIDR range within VirtualNetwork) + ├── SecurityGroup (firewall rules scoped to VirtualNetwork) + └── NATGateway (SNATs egress traffic through an ExternalIP) + +External IP Resources: + ExternalIPPool (platform-defined, external IP ranges) + ├── ExternalIP (allocated from pool) + └── ExternalIPAttachment (binds ExternalIP to ComputeInstance) + +Tenant Resources: + Tenant → namespace and resource isolation +``` + +Parent-child relationships use owner reference annotations (`osac.openshift.io/owner-reference`). + +## Service Stack (fulfillment-service) + +- PostgreSQL for persistent storage +- gRPC with grpc-gateway for REST/JSON support +- Controller-runtime for Kubernetes integration +- OPA for authorization policies +- Prometheus for metrics + +## Integration Testing (fulfillment-service) + +- Kind clusters (named "fulfillment-service-it") +- TLS with SNI routing via Envoy Gateway +- Keycloak for authentication +- Requires `/etc/hosts` entries: + - `127.0.0.1 keycloak.keycloak.svc.cluster.local` + - `127.0.0.1 fulfillment-api.osac.svc.cluster.local` + - `127.0.0.1 fulfillment-internal-api.osac.svc.cluster.local` +- Use `IT_KEEP_KIND=true` to preserve cluster for debugging +- Clean up with: `kind delete cluster --name fulfillment-service-it` diff --git a/.claude/rules/cli-ux.md b/.claude/rules/cli-ux.md new file mode 100644 index 0000000000..c4fb8e932f --- /dev/null +++ b/.claude/rules/cli-ux.md @@ -0,0 +1,20 @@ +# CLI UX Guidelines + +The OSAC CLI (`fulfillment-service/internal/cmd/cli/`) is a tenant-facing tool for managing infrastructure resources. It is NOT a Kubernetes admin tool - end users should not need to know k8s. + +## Design Inspiration + +- **Primary reference**: kubectl - OSAC APIs are modeled after k8s, so the CLI naturally follows kubectl patterns +- **Per-feature reference**: when implementing new commands, also look at cloud CLIs (AWS, GCP, Rafay, VCD) for inspiration on how they solved the same problem +- The goal is not to copy any single CLI, but to use kubectl as the default and evaluate alternatives per-feature + +## Existing Verbs + +`create`, `get`, `describe`, `edit`, `delete`, `annotate`, `label`, `login`, `logout`, `lookup`, `console`, `whoami`, `version` + +## When Adding New CLI Commands + +- Check if kubectl has an equivalent command and follow its UX patterns +- If kubectl doesn't have one, survey cloud CLIs (az, gcloud, aws) for the closest equivalent +- Keep commands non-interactive and scriptable by default +- All new commands must work without assuming k8s knowledge from the user diff --git a/.claude/rules/networking-design-alignment.md b/.claude/rules/networking-design-alignment.md new file mode 100644 index 0000000000..4f08da4273 --- /dev/null +++ b/.claude/rules/networking-design-alignment.md @@ -0,0 +1,3 @@ +# Networking Design Alignment + +When working on networking-related tasks (Connectivity&Fabric component, networking resources like VirtualNetwork/Subnet/SecurityGroup/ExternalIP/NATGateway/NetworkClass, NICs, ports, interfaces, network attachments, VLANs, fabric/K8s managers, dispatcher, MetalLB, DNS, CIDR, DNAT/SNAT, peering, metering/QoS), read `.design/context/networking-decisions.md` before planning, implementing, or reviewing. For deep context, read the full designs linked from that file. diff --git a/.claude/rules/request-path-tracing.md b/.claude/rules/request-path-tracing.md new file mode 100644 index 0000000000..da94ceb0d4 --- /dev/null +++ b/.claude/rules/request-path-tracing.md @@ -0,0 +1,17 @@ +# Request Path Tracing + +When designing or implementing features triggered by external requests (API endpoints, CLI commands), trace the request path from the user-facing entry point to the handler before writing code. List each layer the request passes through (REST gateway, gRPC interceptors, middleware, server). Any layer that transforms, filters, or routes the request is an affected component - even if its code doesn't change. + +A layer that silently drops or ignores the feature's input is a bug that unit tests at the handler level won't catch. + +## OSAC Example + +The fulfillment-service REST gateway uses grpc-gateway with `DefaultHeaderMatcher`, which only forwards permanent HTTP headers and `Grpc-Metadata-*` prefixed headers to gRPC metadata. Custom HTTP headers are silently dropped. When a feature relies on a custom header reaching the gRPC server, the gateway's header matcher configuration must be checked and updated. + +Request path for REST API calls: + +```text +HTTP client → REST gateway (grpc-gateway mux) → gRPC interceptors → server handler +``` + +Check `fulfillment-service/internal/cmd/service/start/restgateway/start_rest_gateway_cmd.go` for gateway configuration when adding new headers. diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000000..0a41274885 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,43 @@ +{ + "permissions": { + "allow": [ + "Bash(date:*)", + "Bash(echo:*)", + "Bash(cat:*)", + "Bash(ls:*)", + "Bash(mkdir:*)", + "Bash(wc:*)", + "Bash(head:*)", + "Bash(tail:*)", + "Bash(sort:*)", + "Bash(grep:*)", + "Bash(tr:*)", + "Bash(git add:*)", + "Bash(git commit:*)", + "Bash(git status:*)", + "Bash(git log:*)", + "Bash(git diff:*)", + "Bash(git tag:*)", + "Bash(jira issue list:*)", + "Bash(jira issue view:*)" + ] + }, + "hooks": { + "SessionStart": [ + { + "hooks": [ + { + "type": "command", + "command": "bash \"${CLAUDE_PROJECT_DIR}/.claude/hooks/update-ai-context.sh\"", + "timeout": 20 + } + ] + } + ] + }, + "statusLine": { + "type": "command", + "command": "input=$(cat); command -v jq >/dev/null || exit 0; dir=$(printf '%s' \"$input\" | jq -r '.workspace.project_dir'); [ -n \"$dir\" ] || exit 0; printf '%s' \"$input\" | bash \"$dir/.claude/hooks/statusline.sh\" \"$dir\"" + }, + "enabledPlugins": {} +} diff --git a/.gitignore b/.gitignore index f3883faa25..9d2dea141f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,12 @@ +# AI workflows and skills (installed by tools/bootstrap.sh) +skills/ +.ai-workflows/ +.claude/skills +.claude/commands +.claude/agents +.cursor/ +.gemini/ + # Binaries for programs and plugins *.exe *.exe~ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..1c44735b09 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,60 @@ +# OSAC Mono-Repo + +OSAC (Open Sovereign AI Cloud) is a fulfillment system for provisioning Kubernetes clusters, compute instances, bare-metal hosts, and networking. This mono-repo contains six components, each with its own `CLAUDE.md`/`AGENTS.md` — **read the component's docs before making changes in it** (progressive disclosure). + +## Components + +| Component | Description | +|-----------|-------------| +| `fulfillment-service/` | gRPC/REST API server + `osac` CLI (PostgreSQL, OPA) | +| `osac-operator/` | Kubernetes operator for CRDs (ClusterOrder, ComputeInstance, Tenant, networking) | +| `osac-aap/` | Ansible playbooks for infrastructure provisioning | +| `osac-installer/` | Helm-based three-phase deployment orchestrator | +| `bare-metal-fulfillment-operator/` | Kubernetes operator for bare-metal host pools | +| `osac-csi-driver/` | CSI meta-driver aggregating vendor storage drivers | + +External repos (clone as siblings for cross-repo workflows): + +| Repo | Path | +|------|------| +| [osac-test-infra](https://github.com/osac-project/osac-test-infra) | `../osac-test-infra/` | +| [osac-ui](https://github.com/osac-project/osac-ui) | `../osac-ui/` | +| [enhancement-proposals](https://github.com/osac-project/enhancement-proposals) | `../enhancement-proposals/` | +| [docs](https://github.com/osac-project/docs) | `../osac-docs/` | + +## Cross-Component Changes + +All components share this mono-repo — a feature spanning any of them lands in a single branch and PR. Apply changes in this order: + +1. **fulfillment-service** — Update proto definitions, regenerate +2. **osac-operator** — Update CRD types, controller logic, `buf generate` +3. **osac-aap** — Update Ansible roles/playbooks +4. **osac-installer** — Update RBAC if needed + +## Git Workflow + +- **Fork-based**: push to `fork` remote, never to `origin`. PRs go from `fork/` to `origin/main` +- **Branch naming**: `/` (e.g., `feat/OSAC-23607`, `fix/duplicate-aap-jobs`) +- **DCO sign-off**: `git commit -s` on all commits +- **AI attribution**: `Assisted-by: Claude Code ` — never `Co-Authored-By` for AI tools (Red Hat attribution standard) +- **Commit message**: `OSAC-XXXXX: description` (Jira key) or `NO-ISSUE: description` + +## Deployment Coordination + +`osac-installer/scripts/sync-image-tags.sh` computes each component's SHA-based image tag and writes it into Helm values files. Since all components share this mono-repo, run `sync-image-tags.sh --fix` in the same PR if it touches values files. External dependencies that still need explicit bumps: + +- **osac-ui** — OCI chart + image, version-tagged +- **osac-csi-driver** — git submodule under `osac-installer/base/` + +## Enhancement Proposals + +PRD and design workflows publish to the separate `enhancement-proposals` repo (clone as sibling at `../enhancement-proposals/`). Feature directory: `enhancements/-/` with `prd.md` and `design.md`. Push to `fork` remote. + +## Jira Conventions + +- OSAC uses Jira **Tasks** (not Stories) for implementation work +- Use `jira` CLI for Jira access (e.g., `jira issue view OSAC-1234 --plain`), not Jira MCP + +## AI-Assisted Workflows + +Run `tools/bootstrap.sh` to install [flightctl/ai-workflows](https://github.com/flightctl/ai-workflows) (bugfix, implement, prd, design, e2e). OSAC-specific skills will be installed from a separate repo. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..43c994c2d3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/tools/bootstrap.sh b/tools/bootstrap.sh new file mode 100755 index 0000000000..9028b122eb --- /dev/null +++ b/tools/bootstrap.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# Install AI workflow skills for this repo. +# +# Usage: tools/bootstrap.sh +# +# This script: +# 1. Clones or updates flightctl/ai-workflows (prefers ~/.ai-workflows) +# 2. Installs workflows (bugfix, implement, prd, design, e2e) +# +# Re-run anytime to update to latest main. +set -euo pipefail + +SCRIPT_DIR="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" +PROJECT_ROOT="$(realpath "${SCRIPT_DIR}/..")" + +AI_WORKFLOWS_REPO="flightctl/ai-workflows" +AI_WORKFLOWS_DIR="" + +# --- ai-workflows (flightctl) --- + +if [[ -d "${HOME}/.ai-workflows" ]]; then + AI_WORKFLOWS_DIR="$(readlink -f "${HOME}/.ai-workflows")" + echo "Updating ai-workflows (${AI_WORKFLOWS_DIR})..." + if ! (cd "$AI_WORKFLOWS_DIR" && git fetch origin -q); then + echo " Fetch failed for ai-workflows. Skipping update." + elif ! (cd "$AI_WORKFLOWS_DIR" && git rebase origin/main --autostash -q); then + (cd "$AI_WORKFLOWS_DIR" && git rebase --abort 2>/dev/null || true) + echo " Rebase failed for ai-workflows. Resolve manually: cd $AI_WORKFLOWS_DIR && git rebase origin/main" + else + echo " ai-workflows up to date" + fi +elif [[ -d "${PROJECT_ROOT}/.ai-workflows" ]]; then + AI_WORKFLOWS_DIR="${PROJECT_ROOT}/.ai-workflows" + echo "Updating ai-workflows (.ai-workflows)..." + if ! (cd "$AI_WORKFLOWS_DIR" && git fetch origin -q); then + echo " Fetch failed. Skipping update." + elif ! (cd "$AI_WORKFLOWS_DIR" && git rebase origin/main --autostash -q); then + (cd "$AI_WORKFLOWS_DIR" && git rebase --abort 2>/dev/null || true) + echo " Rebase failed. Resolve manually: cd $AI_WORKFLOWS_DIR && git rebase origin/main" + else + echo " ai-workflows up to date" + fi +else + AI_WORKFLOWS_DIR="${PROJECT_ROOT}/.ai-workflows" + echo "Cloning ai-workflows..." + git clone "https://github.com/${AI_WORKFLOWS_REPO}.git" "${AI_WORKFLOWS_DIR}" +fi + +echo "Installing ai-workflows skills..." +AI_WORKFLOWS="bugfix,implement,prd,design,e2e" +"${AI_WORKFLOWS_DIR}/install.sh" all --project "${PROJECT_ROOT}" --workflows "${AI_WORKFLOWS}" + +echo "" +echo "AI workflows installed." From 131809c0e470adf800a05b37d51131d6b45e2e0b Mon Sep 17 00:00:00 2001 From: Eran Cohen Date: Mon, 3 Aug 2026 13:53:26 +0300 Subject: [PATCH 2/2] =?UTF-8?q?OSAC-3557:=20Slim=20AGENTS.md=20per=20revie?= =?UTF-8?q?w=20=E2=80=94=20components,=20external=20repos,=20change=20orde?= =?UTF-8?q?r=20only?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove git workflow, Jira conventions, deployment coordination, enhancement proposals, and bootstrap instructions. Add descriptions to external repos table. Assisted-by: Claude Code Signed-off-by: Eran Cohen --- .claude/hooks/statusline.sh | 5 +++ .claude/hooks/update-ai-context.sh | 24 ++------------ AGENTS.md | 53 +++++++----------------------- 3 files changed, 19 insertions(+), 63 deletions(-) diff --git a/.claude/hooks/statusline.sh b/.claude/hooks/statusline.sh index d441b72b89..6690eba183 100755 --- a/.claude/hooks/statusline.sh +++ b/.claude/hooks/statusline.sh @@ -1,8 +1,13 @@ #!/bin/bash # Project statusline: extends user statusline with osac + ai-workflows sync status +# Opt out: set CLAUDE_REPO_STATUSLINE_DISABLED=1 in .claude/settings.local.json env input=$(cat) +if [[ "${CLAUDE_REPO_STATUSLINE_DISABLED:-}" == "1" ]]; then + exit 0 +fi + project_dir="${1:-}" if command -v jq >/dev/null 2>&1 && [[ -f "${HOME}/.claude/settings.json" ]]; then diff --git a/.claude/hooks/update-ai-context.sh b/.claude/hooks/update-ai-context.sh index 8a4014de8a..1695dd0268 100755 --- a/.claude/hooks/update-ai-context.sh +++ b/.claude/hooks/update-ai-context.sh @@ -1,28 +1,11 @@ #!/usr/bin/env bash -# SessionStart hook: fetch+rebase osac (if on main) and ai-workflows -# so the AI agent always has the latest CLAUDE.md, rules, and skills. - -REPO_DIR="${CLAUDE_PROJECT_DIR:-$(cd "$(dirname "$0")/../.." && pwd)}" +# SessionStart hook: fetch+rebase ai-workflows so the AI agent +# always has the latest skills and workflow phases. fetch_and_rebase() { - local dir="$1" name="$2" only_on_main="${3:-false}" + local dir="$1" name="$2" [[ -d "$dir" ]] || return 0 - local branch - branch="$(git -C "$dir" branch --show-current 2>/dev/null)" || return 0 - - if [[ "$only_on_main" == "true" && "$branch" != "main" ]]; then - git -C "$dir" fetch origin -q 2>/dev/null || true - local behind - behind=$(git -C "$dir" rev-list HEAD..origin/main --count 2>/dev/null || echo "?") - if [[ "$behind" == "0" ]]; then - echo "$name: on '$branch', up to date with main" - else - echo "$name: on '$branch', $behind commits behind main — consider running: git rebase origin/main" - fi - return 0 - fi - if ! git -C "$dir" fetch origin -q 2>/dev/null; then echo "$name: fetch failed" return 0 @@ -47,5 +30,4 @@ fetch_and_rebase() { trap - INT TERM } -fetch_and_rebase "$REPO_DIR" "osac" true fetch_and_rebase "${HOME}/.ai-workflows" "ai-workflows" diff --git a/AGENTS.md b/AGENTS.md index 1c44735b09..5c93370451 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,6 @@ # OSAC Mono-Repo -OSAC (Open Sovereign AI Cloud) is a fulfillment system for provisioning Kubernetes clusters, compute instances, bare-metal hosts, and networking. This mono-repo contains six components, each with its own `CLAUDE.md`/`AGENTS.md` — **read the component's docs before making changes in it** (progressive disclosure). +OSAC (Open Sovereign AI Cloud) is a fulfillment system for provisioning Kubernetes clusters, compute instances, bare-metal hosts, and networking. This mono-repo contains six components, each with its own `CLAUDE.md`/`AGENTS.md` — **read the component's docs before making changes in it**. ## Components @@ -13,48 +13,17 @@ OSAC (Open Sovereign AI Cloud) is a fulfillment system for provisioning Kubernet | `bare-metal-fulfillment-operator/` | Kubernetes operator for bare-metal host pools | | `osac-csi-driver/` | CSI meta-driver aggregating vendor storage drivers | -External repos (clone as siblings for cross-repo workflows): +## External Repos -| Repo | Path | -|------|------| -| [osac-test-infra](https://github.com/osac-project/osac-test-infra) | `../osac-test-infra/` | -| [osac-ui](https://github.com/osac-project/osac-ui) | `../osac-ui/` | -| [enhancement-proposals](https://github.com/osac-project/enhancement-proposals) | `../enhancement-proposals/` | -| [docs](https://github.com/osac-project/docs) | `../osac-docs/` | +Clone as siblings for cross-repo workflows: -## Cross-Component Changes - -All components share this mono-repo — a feature spanning any of them lands in a single branch and PR. Apply changes in this order: - -1. **fulfillment-service** — Update proto definitions, regenerate -2. **osac-operator** — Update CRD types, controller logic, `buf generate` -3. **osac-aap** — Update Ansible roles/playbooks -4. **osac-installer** — Update RBAC if needed - -## Git Workflow - -- **Fork-based**: push to `fork` remote, never to `origin`. PRs go from `fork/` to `origin/main` -- **Branch naming**: `/` (e.g., `feat/OSAC-23607`, `fix/duplicate-aap-jobs`) -- **DCO sign-off**: `git commit -s` on all commits -- **AI attribution**: `Assisted-by: Claude Code ` — never `Co-Authored-By` for AI tools (Red Hat attribution standard) -- **Commit message**: `OSAC-XXXXX: description` (Jira key) or `NO-ISSUE: description` - -## Deployment Coordination - -`osac-installer/scripts/sync-image-tags.sh` computes each component's SHA-based image tag and writes it into Helm values files. Since all components share this mono-repo, run `sync-image-tags.sh --fix` in the same PR if it touches values files. External dependencies that still need explicit bumps: +| Repo | Description | +|------|-------------| +| [osac-test-infra](https://github.com/osac-project/osac-test-infra) | E2E pytest tests against the fulfillment-service gRPC API | +| [osac-ui](https://github.com/osac-project/osac-ui) | Web console (React, PatternFly 6) | +| [enhancement-proposals](https://github.com/osac-project/enhancement-proposals) | PRDs and design documents (two-stage EP flow) | +| [docs](https://github.com/osac-project/docs) | Architecture docs and guides | -- **osac-ui** — OCI chart + image, version-tagged -- **osac-csi-driver** — git submodule under `osac-installer/base/` - -## Enhancement Proposals - -PRD and design workflows publish to the separate `enhancement-proposals` repo (clone as sibling at `../enhancement-proposals/`). Feature directory: `enhancements/-/` with `prd.md` and `design.md`. Push to `fork` remote. - -## Jira Conventions - -- OSAC uses Jira **Tasks** (not Stories) for implementation work -- Use `jira` CLI for Jira access (e.g., `jira issue view OSAC-1234 --plain`), not Jira MCP - -## AI-Assisted Workflows +## Cross-Component Changes -Run `tools/bootstrap.sh` to install [flightctl/ai-workflows](https://github.com/flightctl/ai-workflows) (bugfix, implement, prd, design, e2e). OSAC-specific skills will be installed from a separate repo. +A feature spanning multiple components lands in a single branch and PR. Apply changes in dependency order: fulfillment-service (proto) → osac-operator (CRDs, controllers) → osac-aap (playbooks) → osac-installer (RBAC, Helm). For deployment coordination (image tags, submodules), see `osac-installer/AGENTS.md`.