Rituals
Rituals are VeloGit’s built-in pipeline system. They run automatically on push events, verifying your code and feeding results back into the agent ecosystem.
Configuration
Section titled “Configuration”Rituals are defined in a .velo/rituals.yaml file at the root of your repository. The file has two top-level sections: environment and rituals.
environment: language: go version: "1.25" packages: [ postgresql, redis ]
runner: size: medium # small | medium | large | xlarge
rituals: - name: build on: [ push ] command: "go build -v ./..." critical: true
- name: test on: [ push ] command: "go test -v ./..." critical: true
- name: lint on: [ push ] command: "go fmt ./..."Fields
Section titled “Fields”| Field | Description |
|---|---|
environment.language | Runtime language (e.g., go, node, python) |
environment.version | Language version |
environment.packages | System-level dependencies to provision |
rituals[].name | Unique name for this ritual step |
rituals[].on | Events that trigger this ritual (e.g., push) |
rituals[].branches | Branch glob patterns that trigger this step (e.g., main, release/*). Omit to run on all branches. |
rituals[].command | Shell command to execute (omit for gate steps) |
rituals[].type | command (default) or gate. A gate step has no command; execution pauses until approved or rejected |
rituals[].after | List of step names that must complete (pass or be approved) before this step runs |
rituals[].critical | If true, a failure or rejection stops all subsequent steps |
rituals[].timeout | Max wall-clock time for this command step (Go duration: 30s, 5m, 1h30m). Default: 30m. Ignored on gate steps. |
rituals[].gate_timeout | Max time a gate can be pending before it expires (Go duration: 30m, 8h). Default: 48h. Ignored on command steps. |
rituals[].artifacts | Files produced by this step and uploaded after a successful run. See Artifacts. |
rituals[].needs_artifacts | Names of artifacts to fetch from earlier steps in the same run before this step runs. |
runner.size | Machine size for this repo’s runners: small (default), medium, large, or xlarge |
pipeline.timeout | Max wall-clock time for the full pipeline run (Go duration). Default: 2h. Gate-paused time in earlier segments is not counted — only execution time in the current runner machine. |
Runner Size
Section titled “Runner Size”By default, each ritual run on a small machine. For resource-intensive workloads — large test suites, Docker builds, compilation-heavy projects — you can request a larger machine via the runner block:
runner: size: large| Size | CPU | Memory | Billing multiplier |
|---|---|---|---|
small | 1 vCPU | 256 MB | 1× |
medium | 2 vCPU | 512 MB | 2× |
large | 4 vCPU | 2 GB | 4× |
xlarge | 8 vCPU | 8 GB | 8× |
The runner.size setting applies to all ritual steps in the repository. You cannot set different sizes per step.
Timeouts
Section titled “Timeouts”VeloGit enforces wall-clock limits at three levels:
pipeline: timeout: 45m # whole-pipeline budget (default 2h)
rituals: - name: build on: [ push ] command: "go build ./..." timeout: 10m # per-step cap (default 30m)
- name: integration-tests on: [ push ] command: "./scripts/run-integration.sh" timeout: 20m
- name: approve-deploy on: [ push ] type: gate gate_timeout: 8h # gate expiry (default 48h)All timeout fields accept Go duration strings: 45s, 10m, 1h30m, etc.
Step timeout — each command step is killed when it exceeds its timeout. A timed-out step is reported as failed with output prefixed by Command timed out after <duration>. If the step is critical: true, the rest of the pipeline is skipped.
Gate timeout — each gate step has a gate_timeout (default 48h). If a gate is not approved or rejected within this time, it expires and is treated as a rejection, skipping all subsequent steps.
Pipeline timeout — checked between steps. If the cumulative wall-clock time of the current runner machine exceeds pipeline.timeout, all remaining steps are marked skipped and the run ends. Time spent paused at a gate (with the runner machine destroyed) is not counted.
Timeouts apply equally to remote runs and to velo run executed locally.
Artifacts
Section titled “Artifacts”Steps can produce artifacts — files saved after a step completes successfully and made available to later steps in the same pipeline run, including steps that execute on a fresh machine after a gate approval.
rituals: - name: build on: [ push ] command: "go build -o dist/myapp ./..." critical: true artifacts: - name: binary paths: [ "dist/" ]
- name: integration-test on: [ push ] command: "./dist/myapp --self-test" needs_artifacts: [ binary ] # extracted into the workspace before the command runs critical: true
- name: approve-deploy on: [ push ] type: gate
- name: deploy on: [ push ] command: "./scripts/deploy.sh dist/myapp" needs_artifacts: [ binary ] # fetched onto the fresh post-gate machineHow it works
Section titled “How it works”After a step with artifacts: finishes successfully, the runner walks each paths: entry (literal paths or globs, workspace-relative), tar+gzips the matched files, and uploads the bundle to VeloGit storage tagged with the run ID. When a later step declares needs_artifacts:, the runner downloads each bundle and extracts it into the workspace before the command starts.
This is the canonical solution to the cross-gate workspace problem: ritual machines are destroyed when a gate is reached, so without artifacts a post-gate step would need to rebuild from scratch. With needs_artifacts, the build output flows through the gate transparently.
Limits and safety
Section titled “Limits and safety”| Per-artifact size | 1 GB max (rejected at upload) |
| Symlinks | Skipped at upload; rejected on download to prevent workspace escape |
| Path traversal | Tar entries with absolute paths or .. are rejected |
| Visibility | Org-member only — even on public repos, artifacts are not publicly downloadable |
| Retention | Artifacts cascade-delete with their pipeline run |
| Failed steps | Artifacts are not uploaded when the step itself fails |
Local execution
Section titled “Local execution”velo run ignores artifacts: and needs_artifacts: declarations because the bind-mounted workspace already persists between steps inside the single local container. The fields parse cleanly; they’re just no-ops locally. Remote runs honour them.
Environment available to your commands
Section titled “Environment available to your commands”Ritual steps run in a minimal, sanitised environment. Infrastructure
secrets from the runner process (Zitadel keys, internal API keys, NATS
credentials, data-plane URLs) are deliberately stripped — they would
otherwise leak to any pipeline step via printenv, and a malicious commit
in any repo could exfiltrate them.
What your step does receive:
| Source | Variables |
|---|---|
| System defaults | PATH, HOME, USER, LOGNAME, SHELL, TERM, LANG, LC_*, TZ, PWD, TMPDIR |
| Per-run helpers | VELO_COMMIT_SHA, VELO_BRANCH, VELO_REF, VELO_REPO, VELO_RUN_ID |
| Your org/repo secrets | Everything you’ve configured in Settings → Secrets |
What your step does not receive: anything else from the runner process. If your pipeline needs a credential to call an external service, store it as a repo or org secret rather than relying on an env var being inherited.
Branch Targeting
Section titled “Branch Targeting”By default a ritual step runs on every push regardless of branch. Add a branches field to restrict it to specific branches using glob patterns:
rituals: - name: test on: [ push ] command: "go test ./..." # no 'branches' — runs on every push to every branch
- name: deploy-staging on: [ push ] branches: [ develop ] command: "./scripts/deploy.sh staging" critical: true
- name: deploy-production on: [ push ] branches: [ main, release/* ] command: "./scripts/deploy.sh production" critical: trueGlob patterns follow standard shell rules: * matches any characters within a single path segment (e.g., release/* matches release/1.0 but not release/1.0/hotfix).
Gate Steps
Section titled “Gate Steps”A ritual step can be designated as a gate — a manual checkpoint that pauses the pipeline until a team member explicitly approves or rejects it. Gates are useful for requiring human sign-off before deploying to production.
rituals: - name: build on: [ push ] command: "go build ./..." critical: true
- name: approve-deploy on: [ push ] type: gate # pauses here until approved
- name: deploy on: [ push ] command: "./scripts/deploy.sh production" after: [ approve-deploy ]How gates work under the hood
Section titled “How gates work under the hood”When a pipeline reaches a gate step, the runner machine reports waiting_gate to the data-plane and exits cleanly. No machine is running or billing while the gate is pending.
When a team member approves the gate in the UI, the dispatcher boots a new ephemeral machine that resumes execution from immediately after the approved gate — using the same runner image and commit SHA. If the gate is rejected, all remaining steps are marked skipped and the pipeline closes.
Blocked gates appear in the Pipelines tab of any repository, where members can approve or reject them directly from the UI. The page polls automatically every few seconds, so approve/reject buttons appear without requiring a page refresh.
Re-running Individual Steps
Section titled “Re-running Individual Steps”When a single step fails — a flaky test, a transient registry timeout, an out-of-quota deploy — you can re-run that step in place rather than restarting the whole pipeline. Each command step on a terminal pipeline run (passed, failed, rejected, canceled) has a Retry from here button next to it.
What gets reset
Section titled “What gets reset”The named step and every step transitively downstream of it via After: are reset to pending. Anything upstream keeps its prior result.
Given this pipeline:
rituals: - { name: lint, on: [push], command: "go vet ./..." } - { name: test, on: [push], command: "go test ./...", after: [lint] } - { name: build, on: [push], command: "go build ./bin/app", after: [test] } - { name: publish, on: [push], command: "./scripts/publish.sh", after: [build] }If test failed and you click Retry from here on it:
lintstayspassed(not reset)test,build,publishall reset topending- A fresh runner boots;
testruns first because its dependencylintis already satisfied;buildandpublishfollow naturally
If instead you click Retry from here on build, only build and publish reset — test’s previous passed result is preserved.
How it works under the hood
Section titled “How it works under the hood”- The data-plane reads
.velo/rituals.yamlat the run’s commit SHA — not HEAD. TheAfter:graph in effect at the time of the original run is what’s used to compute the reset set. - Affected
PipelineSteprows have theirstatusset topending, andlogs/started_at/finished_at/approved_bycleared. - The
PipelineRunrow flips back torunning. - A
velo.pipeline.rerunNATS event is published. The dispatcher boots a fresh runner machine with the same runner image, withVELO_PIPELINE_RUN_IDandVELO_RERUN_FROM_STEPset. - The runner enters the same resume code path used for gate approvals.
fetchCompletedStepsreturns only the rows whose status is in{passed, approved, rejected, failed, skipped}— the rows we reset arependingso they’re skipped.readyStepspicks them up in dependency order and runs them.
Limitations
Section titled “Limitations”- The
After:graph is read at the run’s commit. If you rewroterituals.yamlafter the original run but want to retry that older run, you’re retrying with the original dependency graph. To pick up a new graph, push the new yaml and let the next push trigger a fresh run. - Gates can’t be individually retried via this button — they have their own approve/reject affordances. To re-run a gate decision, click Rerun at the run level (whole-pipeline restart from a fresh commit).
- Artifact output from prior runs of a re-run step is overwritten. If a step uploaded an artifact, the new execution replaces it. Steps downstream that
needs_artifacts:get the new version.
Integration with Agents
Section titled “Integration with Agents”Rituals and agents work together. When a ritual completes, it emits a Verification Fragment that is displayed in the Ghost Workspace and on Pull Request timelines alongside any agent code suggestions. This gives reviewers confidence that a proposed change has already been tested before they meld it.
Viewing History
Section titled “Viewing History”The Rituals tab in any repository shows a live-updating history of all pipeline runs, their step-by-step logs, and current status. Active runs poll automatically every few seconds.