Skip to content

Track 4 — Platform Operations

A capability that runs on your laptop is not the same as a capability that runs in production. This track covers the operational layer:

  • Linting in CI to keep specs deterministic and consistent
  • The Control Port for health, metrics, and traces
  • Binds that swap across dev, staging, and prod

Prerequisites. A working capability from Track 1, plus Polychro installed.

📂 Source files referenced in this track:


Lesson 1 — Lint before you ship

Run Polychro on every capability change. The bundled polychro:governance ruleset catches:

  • Missing required descriptions on tools and operations
  • Namespace collisions across adapters
  • Trailing-slash and query-string-in-path mistakes
  • Port collisions across multiple exposes
  • Insecure descriptions (raw <script> or eval( patterns)
polychro lint capabilities/*.naftiko.yml \
  --ruleset polychro:governance \
  --ruleset polychro:ai-safety

Try it against a tutorial capability:

curl -L -o step-3-shipyard-auth.yml \
  https://raw.githubusercontent.com/naftiko/ikanos/main/ikanos-docs/tutorial/step-3-shipyard-auth.yml

polychro lint step-3-shipyard-auth.yml \
  --ruleset polychro:governance \
  --ruleset polychro:ai-safety

In GitHub Actions

# .github/workflows/lint.yml
name: Lint capabilities
on: [push, pull_request]

jobs:
  polychro:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: naftiko/polychro@v1
        with:
          paths: 'capabilities/*.naftiko.yml'
          rulesets: 'polychro:governance,polychro:ai-safety'

The action emits SARIF, so violations surface in the GitHub Code Scanning UI. The action source is at naftiko/polychro/action.yml.

See Components → Polychro → Getting Started for the full ruleset reference and the legacy MegaLinter setup.


Lesson 2 — The Control Port

Every Ikanos process can declare a type: control adapter that exposes operational endpoints:

exposes:
  - type: control
    port: 9090
    namespace: control
    observability:
      tracing:
        exporter: otlp
        endpoint: http://otel-collector:4317
      metrics:
        exporter: prometheus

This activates:

Endpoint Purpose
GET /health Liveness + readiness, suitable for Kubernetes probes
GET /metrics Prometheus scrape (RED metrics — rate, errors, duration)
GET /status Runtime diagnostics — adapters, ports, configuration digest
GET /traces Recent in-memory trace summary (for development)

OpenTelemetry traces are emitted automatically with one span per consumed HTTP call and one parent span per exposed operation. Connect to any OTLP collector (Tempo, Honeycomb, Datadog Agent) and you have end-to-end visibility.

Try it

Add the snippet above to any tutorial capability (or copy step-3-shipyard-auth.yml and append the type: control block under exposes:), then:

ikanos validate step-3-shipyard-auth.yml
ikanos serve    step-3-shipyard-auth.yml &

# Probe the four control endpoints
curl http://localhost:9090/health
curl http://localhost:9090/metrics
curl http://localhost:9090/status
curl http://localhost:9090/traces

Lesson 3 — Multi-environment binds

The same capability YAML should run unchanged across dev, staging, and prod. Achieve that by externalizing every secret and environment-specific value through binds.

# capability.yml — committed to git
binds:
  - namespace: env
    location: "${BINDS_LOCATION}"   # resolved at startup
    keys:
      REGISTRY_TOKEN: registry-token
      REGISTRY_BASEURI: registry-baseuri

capability:
  consumes:
    - namespace: registry
      type: http
      baseUri: "{{REGISTRY_BASEURI}}"
      authentication:
        type: bearer
        token: "REGISTRY_TOKEN"

In dev, point BINDS_LOCATION at a file:

# Provision a dev binds file
mkdir -p secrets
cat > secrets/dev.yaml <<'EOF'
registry-token: "dev-registry-token"
registry-baseuri: "https://mocks.naftiko.net/rest/naftiko-shipyard-maritime-registry-api/1.0.0-alpha3"
EOF

BINDS_LOCATION="file:///./secrets/dev.yaml" ikanos serve capability.yml

In production, point it at a vault URI:

BINDS_LOCATION="vault://kv/data/shipyard/prod" ikanos serve capability.yml

The capability YAML never changes — only the resolved values do.


Recap

You now have:

  • Pre-commit / CI linting for every spec change
  • Health, metrics, and traces through the Control Port
  • One spec, many environments through externalized binds

That's the operational floor for running capabilities in production. For fleet-wide governance — policy enforcement across many capabilities and clusters — see Components → Skipper (planned).