goga pipeline
Run a goga pipeline by name, or list available pipelines when no name is given.
goga pipeline is a host-side launcher: it assembles a docker run invocation and delegates all in-container work to python -m goga.pipeline. The afm binary runs inside the container — it is not required on the host.
Synopsis
goga pipeline # discovery mode: list available pipelines (in-container)
goga pipeline <name> # run mode: run a pipeline by name (in-container)
Description
The pipeline command is a single Click command (not a group). Its behavior depends on whether a name is given:
- Without
name(discovery mode): launches the goga Docker image runningpython -m goga.pipeline list, which prints theAvailable pipelines:header followed by one pipeline per line. Project pipelines are annotated with(project); user pipelines are printed bare. - With
name(run mode): allocates a free localhost port, writes a private afm-config tmpfile (client.command: <resolved wrapper path>— the absoluteresolve_wrapper_path(config.pipeline.agent)value, never a bare agent name) mounted read-only at the fixed path/home/goga/.afm/config.yaml, ensures a persistent afm state host directory exists (wiping it first when--cleanis set) and mounts it read-write at/home/goga/pipeline, writes a private env-file combiningconfig.pipeline.envwith git identity,extra_env,AFM_DIR=/home/goga/pipeline, the workflow env vars (see Workflow files), and — when a proxy is set — the proxy env vars, prints a workflow log line when a workflow is applied, and launches the goga Docker image runningpython -m goga.pipeline run <name> --port <port>. Credential files for claude/codex/opencode are detected on the host and bind-mounted read-only into the container automatically. Inside the containergoga.pipelineresolves the pipeline to its absolute path, compiles the goga DSL pipeline-file into an afm flow-file at<AFM_DIR>/flow.yml, materializes the four agent prompt files into<AFM_DIR>/prompts/(applying anyagentsoverrides from the pipeline-file header — see Custom agent prompts), and invokesafm run --port <port> <compiled-flow-path>. The container's exit code is propagated viactx.exit.
Pipelines are flat *.yml files (one per pipeline) resolved from two directories, with the project source winning on name conflicts:
| Source | Directory | Origin |
|---|---|---|
| project | <cwd>/.goga/pipelines/ |
Checked into / authored for the current project |
| user | ~/.goga/pipelines/ |
Installed centrally by goga connect (see connect) |
Only top-level *.yml is scanned — subdirectories are ignored, and .yaml files are excluded. Pipeline path resolution and discovery happen inside the container (the host does not resolve pipeline paths).
Prerequisites
Both modes launch a Docker container via the host docker CLI:
docker info
The top-level image field in .goga/config.yml must be set (the command exits with an error mentioning image when it is unset). The afm binary is provided by the container image and is invoked via PATH inside the container — it is not required on the host.
Discovery Mode (goga pipeline)
List available pipeline names by running -m goga.pipeline list in the container. The Available pipelines: header is always printed, even when the list is empty.
goga pipeline
Example output:
Available pipelines:
deploy (project)
build
test
Project pipelines are annotated with (project); user pipelines are printed bare.
Run Mode (goga pipeline <name>)
Run a pipeline by name. Pass the bare name only (no .yml extension); the container resolves the absolute path internally, compiles the goga DSL pipeline-file into an afm flow-file at <AFM_DIR>/flow.yml, materializes the four agent prompt files into <AFM_DIR>/prompts/, and runs that via afm run. A free port is allocated automatically and published on both sides (-p <port>:<port>); afm listens on that port inside the container. When a workflow is applied, a single log line naming it is printed to stdout; otherwise the launcher prints no status line.
goga pipeline deploy --workflow feature-phases
Pipeline running with workflow "feature-phases"
If the name exists in both sources, the project source wins. The container exit code is propagated as the command's exit code.
Custom agent prompts
A pipeline-file header may carry an optional agents block with four fixed keys — planning, implementation, review, summary — each an inline prompt that fully replaces (does not merge with) the corresponding shipped default prompt (goga/assets/afm/prompts/<key>.md):
name: deploy
description: Deploy pipeline
agents:
planning: |
You are the planning agent for this deploy pipeline.
Break the work into reviewable steps.
review: |
Review each change against the deploy checklist.
---
- name: build
title: Build
prompt: Build it
Only those four keys are valid; an unknown key, a non-string value, or a non-mapping agents block is rejected as a structural DSL error at compile time (before any prompt file is written). When the block is absent or empty, the four shipped defaults are used unchanged. The overrides are a goga-side artifact and are not carried into the compiled flow-file.
At run time the four prompt files are materialized into <AFM_DIR>/prompts/ (mounted at /home/goga/pipeline/prompts) before afm starts, and afm reads them through the prompts_dir field in its config. That prompts/ directory is wiped and rebuilt from the defaults plus any agents overrides on every run, so files manually placed there do not persist.
Workflow files
A pipeline run can optionally apply a workflow-file — a declarative YAML document that layers a top-level prompt, per-stage agent/prompt overrides, and loop-expansion on top of the compiled flow-file. Workflow-files live at <cwd>/.goga/workflows/<name>.yml and are project-only (the name must be a bare filename resolved inside that directory; path traversal via .. or an absolute prefix is rejected).
Three invocation modes (mutually exclusive in the explicit cases):
goga pipeline deploy(no flags) — auto-match: if<cwd>/.goga/workflows/deploy.ymlexists it is applied silently; otherwise no workflow. No host-side validation.goga pipeline deploy --workflow custom— apply<cwd>/.goga/workflows/custom.yml. The host validates the file exists before launch (exit 1 if missing).goga pipeline deploy --no-workflow— disable workflow application entirely (writesGOGA_WORKFLOW_DISABLED=1into the container env-file).
When a workflow will actually be applied (explicit --workflow, or an auto-match file that exists), the launcher prints Pipeline running with workflow "<name>" to stdout. When no workflow applies, the launcher prints no workflow line. The previously emitted Web UI: http://localhost:<port> dashboard line has been removed — the launcher now surfaces only the workflow log line and the docker output stream.
The workflow name reaches the container via the env-file (GOGA_WORKFLOW_NAME=<name> for --workflow; GOGA_WORKFLOW_DISABLED=1 for --no-workflow; neither for auto-match). Inside the container goga.pipeline resolves and parses the workflow-file, then forwards it to the compiler, which reconstructs the parsed body: per-stage agent overrides compose the in-container wrapper path into the stage's command slot, per-stage prompt overrides fill its description slot, and a loop: N (N ≥ 2) expands the stage into NAME-1..NAME-N copies with chained internal depends_on (external references are rewritten to the LAST expanded id).
Example workflow-file:
prompt: |
Top-level prompt injected as the first directive of the flow-file.
stages:
propose:
agent: codex
prompt: |
Additional per-stage instruction.
propose-review:
loop: 2
agent: claude
Options
| Option | Type | Default | Description |
|---|---|---|---|
name (positional) |
string | — | Pipeline name without extension. When omitted, runs discovery mode |
-e, --env |
string (repeatable) | — | Additional environment variable (KEY=VALUE) forwarded into the container env-file. Run mode only (ignored in discovery) |
--proxy |
string | config | HTTP/HTTPS proxy URL; overrides pipeline.proxy. Adds HTTP_PROXY/HTTPS_PROXY/NO_PROXY=localhost,127.0.0.1 to the container env-file. Run mode only |
--add-host |
string (repeatable) | -- | Add a docker run --add-host HOST:IP entry; merges on top of pipeline.hosts (CLI wins on key conflict). Effective in both modes |
--clean |
flag | off | Wipe the persistent afm state directory before launch. Run mode only (no-op in discovery) |
--update, -u |
flag | off | Refresh the image before launch (build if a project Dockerfile is declared, else pull). Effective in both modes |
--workflow |
string | — | Apply an explicit workflow at <cwd>/.goga/workflows/<name>.yml. The file must exist on the host (exit 1 if missing). Mutually exclusive with --no-workflow. Run mode only |
--no-workflow |
flag | off | Disable workflow application entirely (writes GOGA_WORKFLOW_DISABLED=1 into the container env-file). Mutually exclusive with --workflow. Run mode only |
Persistent afm state
Run mode mounts a host directory at /home/goga/pipeline inside the container and sets AFM_DIR=/home/goga/pipeline in the env-file, so afm state (flows, run-state) survives across runs of the same pipeline in the same project on the same branch. The host directory is computed as:
~/.goga/runtime/pipelines/<normalized-project-path>/<git-branch>/<name>/
It is created before launch and is not deleted on exit. Use --clean to wipe it before launch when you want a fresh run.
Note that the prompts/ subdirectory inside it is regenerated on every run (wiped and rebuilt from the shipped defaults plus any agents overrides) — it does not persist user-placed content even though the parent directory survives across runs.
Proxy and hosts
--proxy URL (and pipeline.proxy in .goga/config.yml) route the container's traffic through a corporate proxy. When a proxy is resolved, three variables are written to the container env-file: HTTP_PROXY, HTTPS_PROXY, and NO_PROXY=localhost,127.0.0.1 (fixed; cannot be overridden). --add-host HOST:IP (and pipeline.hosts in .goga/config.yml) translate to docker run --add-host HOST:IP flags; CLI entries merge on top of config with the CLI winning on key conflict.
Credential mounts
Credential files for claude (~/.claude/.credentials.json), codex (~/.codex/auth.json), and opencode (~/.local/share/opencode/auth.json) are detected on the host and bind-mounted read-only into the container automatically (no flag). Detection is agent-agnostic; only files that exist are mounted.
Examples
Refresh the image, then run (default skips the refresh):
goga pipeline deploy --update
Route container traffic through a corporate proxy and add a local host entry:
goga pipeline deploy --proxy http://corp:3128 --add-host foo.local:127.0.0.1
Wipe persistent afm state for this pipeline/branch before launch:
goga pipeline deploy --clean
Exit Codes (run mode)
| Code | Meaning |
|---|---|
0 |
The pipeline ran successfully |
1 |
A ClickException before launch: the pipeline section is missing in .goga/config.yml, the named pipeline was not found in either source directory, --workflow and --no-workflow were both set, or an explicit --workflow <name> named a file that does not exist |
126 |
afm was present but could not be invoked (e.g. not executable) |
127 |
The afm binary is missing inside the container |
130 |
Interrupted by SIGINT (128 + 2) |
143 |
Interrupted by SIGTERM (128 + 15) |
| other | The container / afm exit code, propagated unchanged |
On SIGTERM/SIGINT during run mode the running container is killed and the process exits with 128 + signum.
Exit Codes (discovery mode)
| Code | Meaning |
|---|---|
0 |
Always (even when the pipeline list is empty) |
Notes
- Do not expect
lsorrunsubcommands —goga pipelineis a single command. - Do not expect auto-
--helpwhen no name is given — discovery mode prints theAvailable pipelines:header + list instead. - Do not pass a file path or a name ending in
.ymlin run mode — pass the bare pipeline name only. - The host does not import any code from
goga/pipeline; the runtime boundary togoga/pipelineis Docker.