Repository¶
A Repository CR represents one git remote enrolled in a Project. The operator ingests the repository into the project's memory stack and monitors it for SCM events (push webhooks, issue/PR activity). Each Repository has its own ingest lifecycle, independent of its siblings in the same Project.
Spec¶
| Field | Type | Default | Required | Description |
|---|---|---|---|---|
projectRef | string | - | yes | Name of the parent Project CR in the same namespace |
url | string | - | yes | Full git remote URL (HTTPS or SSH) |
defaultBranch | string | main | no | Branch the operator tracks for ingest and event routing |
ingestEnabled | *bool | true | no | Controls whether ingest Jobs are created for this repository |
semanticIngest | *bool | true | no | Enables Phase 2 LLM semantic entity/relationship extraction in addition to AST parsing; set false for AST-only to reduce per-file LLM cost |
reingestSchedule | string | - | yes | Standard 5-field cron expression (e.g. "0 6 * * *") for periodic catch-up re-ingest, supplementing push webhooks |
reporterLogins | *[]string | nil | no | Override the Project's SCM reporterLogins intake allowlist for this repository only; nil = inherit, [] = open all reporters |
maintainerLogins | *[]string | nil | no | Override the Project's SCM maintainerLogins (maintainer/approver set) for this repository only; nil = inherit, [] = clear all maintainers for this repo |
reingestSchedule validation¶
The field is validated by kubebuilder at admission time against the pattern ^(\S+\s+){4}\S+$ (exactly 5 whitespace-separated fields) with minLength: 9. Kubernetes will reject the CR if the expression does not match. There is no default; omitting the field is an admission error.
Required field with no default
Unlike ingestEnabled and semanticIngest, reingestSchedule has no default and cannot be omitted. A common production schedule is "0 3 * * *" (nightly at 03:00 UTC). Webhooks deliver near-real-time deltas; the cron schedule is a catch-up backstop for missed or out-of-order events.
The pointer pattern¶
ingestEnabled, semanticIngest, reporterLogins, and maintainerLogins are pointer types (*bool or *[]string) rather than plain value types. This enables a three-way distinction that plain booleans and slices cannot express:
| YAML representation | Go value | Semantics |
|---|---|---|
| field omitted entirely | nil pointer | Inherit the project-level setting |
| field set to a value | non-nil pointer | Override for this repository only |
reporterLogins: [] | non-nil pointer to empty slice | Explicitly empty - distinct from inherit |
For *bool fields the operator uses the BoolVal helper to dereference safely:
// BoolVal returns the value of a *bool field, or def when the pointer is nil.
// Use this to dereference IngestEnabled, SemanticIngest, and similar
// +kubebuilder:default=true pointer fields without risking a nil dereference.
func BoolVal(b *bool, def bool) bool {
if b == nil {
return def
}
return *b
}
The kubebuilder +kubebuilder:default=true marker causes the API server to inject true into ingestEnabled and semanticIngest when those fields are omitted in a CREATE request, so a newly created Repository always has a non-nil pointer for those two fields. The *[]string fields do not carry a default and remain nil until explicitly set.
Practical effect on reporterLogins / maintainerLogins
- Omit the field (default): this repository uses the Project's SCM
reporterLogins/maintainerLoginslist unchanged. - Set an explicit list: this repository enforces its own allowlist, narrowing or widening the project default for this repo only.
- Set to an explicit empty list (
[]): forreporterLoginsthis opens intake to any GitHub user for this repository; formaintainerLoginsthis removes the maintainer/approver gate for this repository. Use with care.
Status¶
The operator writes back to status after each reconcile. Inspect with kubectl -n <namespace> describe repository <name>.
| Field | Type | Description |
|---|---|---|
phase | string | Current lifecycle phase: Ingesting, Ingested, or Failed |
lastIngestedCommit | string | SHA of the most recently successfully ingested commit |
lastIngestTime | metav1.Time | Timestamp of the last successful ingest Job completion |
lastScheduledReingest | metav1.Time | Last time the cron expression fired and stamped a reingest-requested annotation; used as the base to compute the next fire time |
ingestFailureCount | int | Count of consecutive ingest Job failures; resets to zero on any success; drives exponential backoff |
lastIngestFailureTime | metav1.Time | Timestamp of the most recent ingest Job failure; used together with ingestFailureCount to compute the next retry deadline |
jobName | string | Name of the currently active (or most recently created) ingest Kubernetes Job |
conditions | []metav1.Condition | Standard Kubernetes conditions map-keyed on type; see below |
Phase lifecycle¶
stateDiagram-v2
direction LR
[*] --> Ingesting : CR created / webhook received / cron fires
Ingesting --> Ingested : Job succeeds
Ingesting --> Failed : Job fails
Failed --> Ingesting : Backoff expires, retry scheduled
Ingested --> Ingesting : New push webhook or cron tick Conditions¶
Conditions follow the standard metav1.Condition contract (type, status, reason, message, lastTransitionTime). The list is keyed on type (+listType=map, +listMapKey=type), meaning each type appears at most once and is updated in-place on each reconcile.
Ingest backoff¶
When an ingest Job terminates with a non-zero exit code the operator increments status.ingestFailureCount and records status.lastIngestFailureTime. On subsequent reconciles the operator computes a backoff window using both fields before creating the next Job. The delay grows exponentially with each consecutive failure.
A successful Job resets ingestFailureCount to zero and clears the backoff, regardless of how many failures preceded it.
Forcing an immediate retry
To bypass backoff and trigger an ingest immediately, annotate the Repository:
The operator detects the annotation on the next reconcile and creates a new Job, resetting the failure counter only if the Job succeeds.
ingestEnabled: false does not cancel a running Job
Setting ingestEnabled to false prevents new Jobs from being created. Any Job already running at the time of the update will complete normally. The phase will reflect the completed Job's outcome.
Annotated example¶
The following manifest shows a fully configured repository with per-repository maintainer and reporter overrides. Inline comments explain each non-obvious field.
apiVersion: tatara.dev/v1alpha1
kind: Repository
metadata:
name: payments-service # (1)!
namespace: tatara
spec:
projectRef: platform # (2)!
url: https://github.com/my-org/payments-service # (3)!
defaultBranch: main # (4)!
ingestEnabled: true # (5)!
semanticIngest: true # (6)!
reingestSchedule: "0 3 * * *" # (7)!
# Per-repository overrides - both are *[]string (pointer-to-slice).
# Omit entirely to inherit from Project.scm.maintainerLogins /
# Project.scm.reporterLogins.
maintainerLogins: # (8)!
- alice
- bob
reporterLogins: # (9)!
- alice
- bob
- charlie
- Must be unique within the namespace. The operator uses this name to construct Job names and metric labels.
- Must match an existing
ProjectCR in the same namespace. The operator will setstatus.phase = Failedand stop reconciling if the referenced Project does not exist. - HTTPS URLs are standard. SSH URLs are supported if the ingest Job has an SSH key mounted via
Project.spec.agent.extraVolumes/extraVolumeMounts. - Kubebuilder default is
main. Override for repositories that use a different trunk branch (e.g.master,develop). trueis the kubebuilder default. Explicitly setting this tofalsesuspends ingest for this repository without deleting the CR or any previously ingested memory data.trueenables Phase 2 LLM extraction (entity + relationship inference per changed file) on top of the Phase 1 AST parse. Setfalsefor large, low-churn repositories to reduce token cost.- Nightly at 03:00 UTC. Push webhooks deliver incremental updates in near-real-time; this cron is a catch-up backstop for events missed during operator downtime or webhook delivery failures.
- Non-nil list: overrides
Project.scm.maintainerLoginsfor this repository. Onlyaliceandbobcan approve tatara tasks opened againstpayments-service. - Non-nil list: overrides
Project.scm.reporterLogins. Only these three accounts can open issues that the operator will act on.
Checking ingest status¶
# Summary columns (Phase and last ingested commit)
kubectl -n tatara get repository payments-service
# NAME PHASE COMMIT
# payments-service Ingested a3f912c
# Full status including conditions and backoff counters
kubectl -n tatara describe repository payments-service
# Watch phase transitions in real time
kubectl -n tatara get repository payments-service -w
To list all repositories and their phases across a namespace: