Configuration
Shipyard reads one YAML file at startup — .shipyard.yaml in the working directory, or the path given with -config. Restart Shipyard after editing it by hand; projects added in the console are written to the file and take effect at once.
-config also accepts an HTTPS URL. Shipyard downloads the file at startup and treats it as read-only: the console cannot add projects to it. If the server needs a token, put it in SHIPYARD_CONFIG_TOKEN; it is sent as a bearer token.
SHIPYARD_CONFIG_TOKEN=… shipyard -config https://config.example.com/shipyard.yaml
Unknown keys, duplicate keys, a second YAML document and files over 1 MiB are rejected at startup. Errors name the offending line.
Minimal file
listen: 127.0.0.1:8080
projects:
- id: my-app
repository: you/my-app
enabled: true
issue_label: agent-ready
release_interval: 48h
content:
interval: 168h
publish_mode: pull_request
Everything else has a default.
Server and access
| Key | Default | Meaning |
|---|---|---|
listen |
— | Address and port, e.g. 127.0.0.1:8080. |
runtime.api_token_env |
— | Name of the environment variable holding the API token. |
runtime.embedded_worker |
false |
Run the queue worker inside the server process. |
Without a token the console is read-only, and Shipyard only starts on a loopback address. With a token:
- queuing, cancelling and retrying runs require it;
- reading runs, logs, pipelines and
/metricsrequires it too.
If api_token_env names a variable that is not set, Shipyard refuses to start.
Projects
projects:
- id: my-app
repository: you/my-app
enabled: true
issue_label: agent-ready
auto_merge: false
release_interval: 48h
models:
verification: code
content:
enabled: true
interval: 168h
min_score: 70
target: blog
topics: [Go, static sites]
publish_mode: pull_request
| Key | Meaning |
|---|---|
id |
Unique ID: letters, digits, ., _, -. |
repository |
owner/name. |
enabled |
Only enabled projects accept runs. |
issue_label |
Label that marks issues ready for automated work. |
auto_merge |
Must be false: every change goes through review. |
release_interval |
Release cadence as a duration, e.g. 48h. |
models |
Per-project override of the AI role routing below. |
content.interval |
How often content is reviewed, e.g. 168h. |
content.min_score |
Score from 0 to 100 a topic needs before an article is drafted. |
content.publish_mode |
pull_request: articles are proposed as pull requests. |
runs_on |
Labels such as arch=arm64; runs go to a ship that carries all of them. See Ships. |
AI providers and models
ai:
providers:
primary:
type: openai-compatible
base_url: https://api.openai.com/v1
api_key_env: OPENAI_API_KEY
timeout: 120s
local:
type: openai-compatible
base_url: http://127.0.0.1:11434/v1
models:
code:
provider: primary
model: your-coding-model-id
max_output_tokens: 8192
researcher:
provider: local
model: your-local-model-id
tasks:
coding: code
research: researcher
writing: code
verification: code
release_notes: code
- Providers —
type: openai-compatibleworks with OpenAI and with local servers that speak the same API (Ollama, vLLM, LM Studio).base_urldefaults to OpenAI; it must be HTTPS, or HTTP on loopback.timeoutdefaults to120s. - Credentials — set exactly one of
api_key_env(environment variable),api_key_file(file such as/run/secrets/openai_key, up to 64 KiB) orapi_key(inline; keep that file private). Local servers need none. - Models — an alias names a provider and the provider's model ID.
max_output_tokensdefaults to 4096. - Roles —
tasksmaps the rolescoding,research,writing,verificationandrelease_notesto model aliases. A project'smodelsoverrides them. A role without a model fails the run instead of silently using another one.
Keys are read when a run needs them, so the server starts without AI credentials.
Storage, logs and retention
| Key | Default | Meaning |
|---|---|---|
storage.path |
./data/shipyard.db |
SQLite database: queue, history, audit. |
logging.directory |
./data/logs |
One JSONL log per run attempt. |
logging.max_run_size_mb |
50 |
Log size cap per run. |
retention.logs_days |
30 |
Delete run logs after this many days. |
retention.completed_runs_days |
90 |
Delete finished runs after this many days. |
retention.audit_days |
365 |
Delete audit entries and alert records after this many days. |
retention.max_disk_size_mb |
2048 |
When the log directory reaches this size, new runs are refused until retention frees space. |
Keep both paths on a local disk. logs_days cannot exceed completed_runs_days. Details in Monitoring and retention.
Monitoring and alerts
| Key | Default | Meaning |
|---|---|---|
observability.metrics |
false |
Serve Prometheus metrics on /metrics. |
observability.otel_endpoint |
— | OTLP/HTTP collector for traces, e.g. http://127.0.0.1:4318. |
prometheus.<name>.url |
— | Prometheus server for prometheus pipeline steps. |
prometheus.<name>.query |
— | The PromQL instant query the step runs. |
prometheus.<name>.token_env |
— | Optional bearer token variable for that server. |
alerts.token_env |
— | Token variable Alertmanager must send. |
alerts.project_label |
shipyard_project |
Alert label that names the project. |
alerts.enqueue_diagnostics |
false |
Queue a diagnostic run for each firing alert. |
Fleet
| Key | Default | Meaning |
|---|---|---|
fleet.listen |
— | Address of the ship endpoint, e.g. 0.0.0.0:8443. Unset means no ships. |
fleet.address |
— | host:port ships dial; used in join commands. |
fleet.hosts |
— | DNS names and IPs written into the endpoint's certificate. |
fleet.directory |
<storage dir>/fleet |
Where the fleet certificate authority is kept. Back it up: losing it means re-joining every ship. |
The fleet requires runtime.api_token_env. Setup is described in Ships and docks.
Pipelines
pipelines:
project-check:
steps:
- id: config
type: diagnostic
timeout: 30s
A pipeline has 1 to 20 steps with unique IDs. Step types and examples are in Pipelines.
Secrets in logs
Configured API keys and tokens are masked in run logs and errors, together with text that looks like token=…, password: … or an Authorization header. Do not put other secrets into run input.