This guide explains how to add new services to the A.R.C. service catalog.
Adding a new service involves:
- Define the service in
services.yaml - Create a Docker Compose template
- Create config file templates (if needed)
- Define dependencies
- Test and validate
Edit pkg/catalog/data/services.yaml:
services:
# Use a unique codename (lowercase, can include hyphens)
my-service:
codename: my-service
technology: MyTech # The underlying technology
role: Infrastructure # One of: Infrastructure, Data, AI, Observability
description: "Short description of what the service does."
version: "1.0"
image: "myorg/myimage:v1.0"
# Port mappings
ports:
- host: 8080
container: 8080
protocol: tcp # tcp or udp
description: "HTTP API"
# Dependencies on other services (by codename)
dependencies:
- oracle
- sonic
# Environment variables
environment:
- name: MY_VAR
default: "value"
required: false
description: "Description of the variable"
- name: SECRET_KEY
required: true
description: "Required secret"
# Volume mounts
volumes:
- host: "./.arc/data/myservice"
container: "/data"
description: "Data storage"
read_only: false
# Config files needed
config_files:
- "myservice.yml"
# Alternative names for lookup
aliases:
- mytech
- myaliasChoose the appropriate role:
| Role | Description |
|---|---|
Infrastructure |
Core platform services (gateway, auth, messaging) |
Data |
Data storage (databases, caches, object storage) |
AI |
AI/ML services (agents, models, guardrails) |
Observability |
Monitoring (metrics, logs, traces) |
- Avoid conflicts with existing services
- Use standard ports where applicable (5432 for PostgreSQL, etc.)
- Document each port's purpose
Create pkg/catalog/templates/docker-compose/<codename>.yml.tmpl:
# {{ .Service.Codename }} ({{ .Service.Technology }}) - {{ .Service.Description }}
{ { .Service.Codename } }:
image: { { .Service.Image } }
container_name: arc-{{ .Service.Codename }}
restart: unless-stopped
{ { - if .Service.Ports } }
ports:
{ { - range .Service.Ports } }
- "{{ .Host }}:{{ .Container }}"
{ { - end } }
{ { - end } }
environment:
- MY_VAR={{ default "default" .Vars.my_var }}
- SECRET_KEY=${SECRET_KEY}
{ { - if .Service.Dependencies } }
depends_on:
{ { - range .Service.Dependencies } }
- { { . } }
{ { - end } }
{ { - end } }
volumes:
- { { .Workspace.DataDir } }/myservice:/data
networks:
- {{ .Workspace.Network }}
labels:
- "arc.service={{ .Service.Codename }}"
- "arc.technology={{ .Service.Technology }}"
- "arc.role={{ .Service.Role }}"
healthcheck:
test: [ "CMD", "curl", "-f", "http://localhost:8080/health" ]
interval: 30s
timeout: 10s
retries: 3Available in templates:
| Variable | Description |
|---|---|
.Service.Codename |
Service codename |
.Service.Technology |
Technology name |
.Service.Image |
Docker image |
.Service.Role |
Service role |
.Service.Ports |
Port mappings |
.Service.Dependencies |
Dependency list |
.Workspace.Name |
Workspace name |
.Workspace.DataDir |
Data directory path |
.Workspace.ConfigDir |
Config directory path |
.Workspace.Network |
Docker network name |
.Vars.<name> |
User-provided variables |
| Function | Description | Example |
|---|---|---|
default |
Default value | {{ default "value" .Vars.key }} |
quote |
Quote string | {{ quote .Vars.name }} |
env |
Env var reference | {{ env "VAR" "default" }} |
toYAML |
Convert to YAML | {{ .Data | toYAML }} |
indent |
Indent lines | {{ indent 4 .Content }} |
lower |
Lowercase | {{ lower .Name }} |
upper |
Uppercase | {{ upper .Name }} |
If your service needs configuration files, create them under:
pkg/catalog/templates/configs/<service>/
Example: pkg/catalog/templates/configs/myservice/myservice.yml.tmpl
# {{ .Service.Codename }} Configuration
server:
port: 8080
host: 0.0.0.0
database:
url: postgresql://{{ default "arc" .Vars.postgres_user }}:${POSTGRES_PASSWORD}@oracle:5432/mydb
logging:
level: { { default "info" .Vars.log_level } }Run tests to validate your changes:
# Run catalog tests
go test ./pkg/catalog/... -v
# Verify service loads
go build -o /tmp/arc-test ./cmd/arc
/tmp/arc-test services info my-service
# Check for port conflicts
/tmp/arc-test services ports
# Verify dependencies
/tmp/arc-test services deps my-serviceIf you modified existing services or templates:
go test ./pkg/catalog/... -update-golden- Unique Codenames: Choose memorable, themed codenames
- Clear Descriptions: Explain what the service does
- Document Ports: Describe what each port is for
- Minimal Dependencies: Only require what's necessary
- Sensible Defaults: Provide defaults for optional vars
- Health Checks: Always include a healthcheck
Here's a complete example of adding a new service:
jarvis-jr:
codename: jarvis-jr
technology: OAuth2Proxy
role: Infrastructure
description: "The Intern. Handles OAuth2 authentication proxying."
version: "7.5"
image: "quay.io/oauth2-proxy/oauth2-proxy:v7.5"
ports:
- host: 4180
container: 4180
protocol: tcp
description: "Proxy port"
dependencies:
- jarvis
environment:
- name: OAUTH2_PROXY_CLIENT_ID
required: true
description: "OAuth2 client ID"
- name: OAUTH2_PROXY_CLIENT_SECRET
required: true
description: "OAuth2 client secret"
aliases:
- oauth2-proxy
- proxy# jarvis-jr (OAuth2Proxy) - OAuth2 authentication proxy
jarvis-jr:
image: { { .Service.Image } }
container_name: arc-jarvis-jr
restart: unless-stopped
ports:
- "4180:4180"
environment:
- OAUTH2_PROXY_CLIENT_ID=${OAUTH2_PROXY_CLIENT_ID}
- OAUTH2_PROXY_CLIENT_SECRET=${OAUTH2_PROXY_CLIENT_SECRET}
- OAUTH2_PROXY_OIDC_ISSUER_URL=http://jarvis:4433
depends_on:
- jarvis
networks:
- { { .Workspace.Network } }
healthcheck:
test: [ "CMD", "curl", "-f", "http://localhost:4180/ping" ]
interval: 30s
timeout: 10s
retries: 3